← 返回知识库
AI AgentFunction CallingTool Calling工具调用JSON Schema

Function Calling 与工具调用

工具调用的完整往返机制:tools 定义、tool_calls 响应、结果回传循环,以及失败处理与安全边界。

Function Calling 与工具调用

一句话:把工具的「说明书」(名称/描述/参数 JSON Schema)随 prompt 发给模型 → 模型不直接执行,而是输出结构化的「我要调 tool_x,参数是 {...}」→ 程序解析并执行真实函数 → 把结果以 tool 消息回传 → 模型基于结果继续生成。

完整往返(OpenAI/DeepSeek 兼容格式,背熟)

① 请求messages 数组里追加 tools 参数(工具定义,JSON Schema):

{
  "model": "deepseek-chat",
  "messages": [
    {"role": "system", "content": "你是门店助手,可调用工具查天气"},
    {"role": "user", "content": "明天广州会下雨吗?"}
  ],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "weather_query",
        "description": "查询指定城市的天气",
        "parameters": {
          "type": "object",
          "properties": {
            "city": {"type": "string", "description": "城市名"},
            "days": {"type": "integer", "enum": [1, 3, 7]}
          },
          "required": ["city"]
        }
      }
    }
  ]
}

② 模型响应(它不会直接答,而是要求调工具):

{
  "choices": [{
    "message": {
      "role": "assistant",
      "content": null,
      "tool_calls": [
        {
          "id": "call_abc123",
          "type": "function",
          "function": {
            "name": "weather_query",
            "arguments": "{\"city\": \"广州\", \"days\": 1}"
          }
        }
      ]
    }
  }]
}

③ 程序执行真实工具,把结果以 role: "tool" 回传(tool_call_id 与 ② 对应)。

④ 模型拿到工具结果后,才组织最终回答:"明天广州有小雨,记得提醒门店做雨天促销。"

Python 侧循环(核心代码,能默写)

def run_with_tools(messages, tools):
    resp = client.chat.completions.create(model="deepseek-chat", messages=messages, tools=tools)
    msg = resp.choices[0].message

    # 有 tool_call → 执行 → 回传 → 再请求(循环直到无 tool_call/达到上限)
    while msg.tool_calls:
        messages.append(msg)                    # 把 assistant 的 tool_call 请求加进历史
        for tc in msg.tool_calls:               # 允许一次多个工具调用
            result = exec_tool(tc.function.name, json.loads(tc.function.arguments))
            messages.append({"role": "tool", "tool_call_id": tc.id, "content": json.dumps(result)})
        resp = client.chat.completions.create(model="deepseek-chat", messages=messages, tools=tools)
        msg = resp.choices[0].message
    return msg.content

Tool 定义包含哪些要素

名称、功能描述(让模型知道何时用)、入参 JSON Schema(含类型/必填/枚举)、出参格式、调用示例。Schema 不清 → 模型大概率 1/10 场景输出格式错误 JSON。

为什么 LLM 能「选对」工具:靠的是描述写得好(什么时候用哪个、参数规则写成 if-then),不是模型有魔法。

关键工程点(面试加分)

  • 模型只「提议」不执行:安全边界——真正执行在程序侧(可加白名单/审批)
  • arguments 是 JSON 字符串:必须 json.loads 解析,解析失败/参数非法走降级(不崩流水线)
  • 历史必须完整回传:assistant 的 tool_call 和 tool 的结果都要进 messages,否则模型「失忆」
  • 循环上限:tool_calls 可能连环触发,要设最大轮数(防死循环烧 token)
  • 多工具并行:一次响应可带多个 tool_calls,逐个执行后一起回传

工具调用失败怎么处理(结构化错误)

不能裸抛异常让模型看到堆栈。做法:对工具调用 try-catch,返回结构化错误信息{error_code, message, 是否可重试}),模型看到错误后自主决定重试/换工具/降级/告知用户。

安全硬隔离:工具层是信任边界——LLM 生成参数不可信,必须做 schema 校验、权限校验、敏感操作需确认。

为什么用 Function Calling(好处,必答)

  1. 突破知识截止:工具能取实时数据(天气/库存/竞品/用户画像)
  2. 突破能力边界:模型只会生成文本,Function Calling 让 LLM 变成「指挥中枢」,执行交给程序
  3. 准确可信:参数由 JSON Schema 结构化约束,输出可解析、可校验,不会幻觉出假数据
  4. 安全可管控:「模型只提议、程序才执行」,执行前可过白名单/权限/HITL 审批
  5. 可观测可留痕:每次 tool_call 的参数和结果都能落事件日志,可回放、可追责
  6. 组合能力:Agent = LLM 决策 + Function Calling 执行 + 循环控制——没有 Function Calling 就没有真正的 Agent