iT邦幫忙

2025 iThome 鐵人賽

DAY 19
1

昨天提到 Prompt function calling 跟 FC (native) 的差別。最後決定要走 FC,因為簡單、省 token,而且在 agentic domain 上分數直接碾壓。
今天就來實際分享一下我怎麼改 Reasoning state,把 open ai 的 FC 用進來。


Function calling

https://ithelp.ithome.com.tw/upload/images/20251003/20128319BQ33igk2wo.png

拿 openai 的圖來解釋,反正 function calling 就是透過提供固定 format 的 tools,讓 llm 根據prompt去選擇要選擇使用哪些 tools。


MCP tool list vs OpenAI tools 格式差異

由於之後還是打算把 mcp server 帶進來,所以先理解一下 MCP tool list 的格式
首先要解釋一下,MCP (multi-component protocol) 的 tool list 跟 open ai 的 tools 參數格式其實不一樣。

  • MCP tool list:通常會包含比較多 metadata,例如:

      {
        name: string;          // Unique identifier for the tool
        description?: string;  // Human-readable description
        inputSchema: {         // JSON Schema for the tool's parameters
          type: "object",
          properties: { ... }  // Tool-specific parameters
        }
      }
    

    ref: https://modelcontextprotocol.info/docs/concepts/tools/
    可以看到它的 schema key 是 inputSchema

  • OpenAI tools 格式
    定義:
    https://ithelp.ithome.com.tw/upload/images/20251003/201283191bl3vo3dDh.png

小小例子

{
   "type": "function",
   "name": "get_weather",
   "description": "Retrieves current weather for the given location.",
   "parameters": {
       "type": "object",
       "properties": {
           "location": {
               "type": "string",
               "description": "City and country e.g. Bogotá, Colombia"
           },
           "units": {
               "type": "string",
               "enum": ["celsius", "fahrenheit"],
               "description": "Units the temperature will be returned in."
           }
       },
       "required": ["location", "units"],
       "additionalProperties": false
   },
   "strict": true
}

ref: https://platform.openai.com/docs/guides/function-calling


是否有現成的轉換 package?

是有看到一些 adapter 的 repo,但感覺有點小眾 就不貼了。

看樣子是有人想要整合 function 的格式呢XD
Unified Tool Integration for LLMs: A Protocol-Agnostic Approach to Function Calling

Code & Reasoning State 改寫

接下來就是改 code。
我寫了一個 get_response function,用來呼叫 open ai,然後 parse 出工具調用:

async def get_response(model_name: str, messages: list[Message], tools: list[dict] | None = None):
    respone = await client.chat.completions.create(model=model_name, messages=messages, tools=tools)
    tool_raw_infos = respone.choices[0].message.tool_calls
    tool_infos = (
        [
            {"name": tool_call.function.name, "args": json.loads(tool_call.function.arguments)}
            for tool_call in tool_raw_infos
            if tool_call.type == "function"
        ]
        if tool_raw_infos
        else None
    )
    return (
        respone.choices[0].message.content,
        tool_infos,
    )

然後在 ReasoningState 裡就就改呼叫 get_response

class ReasoningState(State):
    async def run(self, memory: "Memory") -> AsyncIterator[str]:
        messages = await get_messages(memory)
        content, tools = await get_response(
            model_name=REASONING_MODEL, messages=messages, tools=mcp_to_openai_tools(memory.list_tools())
        )
        if content:
            for chunk in content:
                yield chunk
            await memory.update([Message(role=Role.ASSISTANT, content=content)])

        yield str(tools)

        if tools:
            memory.next_actions = [Action(**tool) for tool in tools]

    async def next_state(self, memory: "Memory") -> Enum:
        if memory.next_actions:
            return ReAct.ACTION
        return ReAct.ANSWER

function calling 格式是不是每間都不一樣?

答案是 Yes

  • OpenAI → 用 tools,裡面是 function + parameters
  • Anthropic → 叫做 tool_choice,定義方式又不一樣。
  • Gemini → 用 function_declarations
    所以要做 multi-provider agent 的話,幾乎都要做一層 adapter,把各家 format normalize 起來。

結語

明天真的就會跑跑看 toolhop dataset,看 react 的分數了...


上一篇
Day 18: native function calling vs prompt function calling (一)
下一篇
Day 20: 測試 agent brain
系列文
agent-brain: 從 0 開始打造一個 python package20
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言