跳到正文
docai.cc

DOCAI · 课程 · L3 · 35 分钟

给模型一个工具,让它自己用

定义一个函数、把它的结构告诉模型、执行模型返回的调用、再把结果发回去:亲手跑一遍工具调用的完整回合。

你将学会

  • 能定义一个模型可调用的工具并跑通一次调用
  • 能读懂模型返回的工具调用结构
  • 能给循环设步数上限和人工确认点

先分清谁在执行

模型只输出「我要调 get_weather,参数是上海」。真正发请求的是你的代码。

这条边界想清楚,后面所有权限与安全问题都好谈。概念见什么是工具调用。

第一步:定义工具

tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "查询指定城市的当前天气",
        "parameters": {
            "type": "object",
            "properties": {"city": {"type": "string", "description": "城市名"}},
            "required": ["city"],
        },
    },
}]

description 写清楚「什么时候该用」,模型靠它选工具。

第二步:发出请求,看返回

resp = client.chat.completions.create(
    model=MODEL,
    messages=[{"role": "user", "content": "上海现在多少度?"}],
    tools=tools,
)
call = resp.choices[0].message.tool_calls[0]
print(call.function.name, call.function.arguments)  # get_weather {"city":"上海"}

注意:arguments 是字符串,要自己 json.loads 并校验字段。

第三步:执行并回传

result = get_weather(**json.loads(call.function.arguments))
messages.append(resp.choices[0].message)
messages.append({"role": "tool", "tool_call_id": call.id, "content": json.dumps(result)})
final = client.chat.completions.create(model=MODEL, messages=messages, tools=tools)

tool_call_id 必须对上,否则服务端不知道这是哪次调用的结果。

加上循环与边界

  • 步数上限:比如 6 步,到了就停并返回已有结果。
  • 写操作要确认:发邮件、下单、删数据,先给人看一遍。
  • 执行前校验参数:模型给的参数不一定合法。
  • 记录每一步:调了什么、返回什么,出问题才有得查。

需要接现成工具时,看什么是 MCP;需要多步自主决策时,那才是Agent。

自测

  1. 模型会不会自己执行 get_weather?为什么这个区别很重要?
  2. 忘记回传 tool_call_id 会发生什么?
  3. 为什么「步数上限」是 agent 的必需件而不是可选项?

涉及的概念