AI Agent中的function call详解

下面把 AI Agent 里的 function call(函数调用 / 工具调用)从原理到工程实践讲清楚。

一、核心概念:模型不执行函数,只"申请"调用

很多人最大的误解是以为大模型自己运行了代码。实际上 function call 的本质是:模型在判断需要外部能力时,不直接输出自然语言回答,而是输出一段结构化的调用请求(通常是 JSON),说明"我想调用哪个函数、传什么参数"。真正的执行由你的应用程序(宿主代码)完成,执行结果再喂回给模型,模型据此生成最终回答。

这一步把大模型从一个"只会写字的文本生成器"变成了"能调动外部世界的 Agent"。模型本身受限于训练数据、无法获取实时信息、无法操作数据库或发邮件,而 function call 正是打通这层隔阂的桥梁。

二、整个调用回路

一次完整的 function call 通常经历这样的循环:

  1. 开发者注册工具:把可用函数的"说明书"(schema)随用户问题一起发给模型。
  2. 模型决策 :模型读取用户意图,判断是直接回答还是调用工具。若需调用,输出 tool_use 块(OpenAI 叫 tool_calls),包含函数名和参数。
  3. 宿主执行:你的代码解析这个 JSON,实际去调 API、查数据库等。
  4. 回传结果 :把执行结果作为 tool_result 再次发给模型(连同之前的对话历史)。
  5. 生成回答:模型结合工具返回的数据,产出自然语言答复;或判断还需调用别的工具,回到第 2 步,形成多轮 agentic loop。

关键在于第 4、5 步会循环------这正是"Agent"区别于"单次问答"的地方:观察 → 思考 → 行动(调工具)→ 观察结果 → 再思考,直到任务完成。

三、工具定义(Schema)是重中之重

模型完全靠你提供的工具描述来决定"用不用、怎么用",所以 schema 的质量直接决定调用准确率。一个工具定义一般包含三部分:

  • name:函数名,简洁明确。
  • description:自然语言描述功能与使用时机。这是模型决策的主要依据,要写清"什么情况下该用它",而不只是"它是什么"。
  • parameters:用 JSON Schema 描述每个参数的类型、是否必填、枚举值、含义。

以 Anthropic 的格式为例:

json 复制代码
{
  "name": "get_weather",
  "description": "查询指定城市的当前天气。当用户询问天气、是否带伞、气温等问题时使用。",
  "input_schema": {
    "type": "object",
    "properties": {
      "city": {
        "type": "string",
        "description": "城市名称,例如'北京'、'上海'"
      },
      "unit": {
        "type": "string",
        "enum": ["celsius", "fahrenheit"],
        "description": "温度单位,默认摄氏度"
      }
    },
    "required": ["city"]
  }
}

模型决定调用时会返回类似:

json 复制代码
{
  "type": "tool_use",
  "name": "get_weather",
  "input": { "city": "北京", "unit": "celsius" }
}

你执行后,把结果以 tool_result 形式回传,模型再生成"北京现在 25°C,晴"这样的回答。

四、为什么模型"知道"该调用

模型并非靠规则匹配,而是经过专门的微调/对齐训练,学会了在合适时机输出结构化调用而非纯文本。在解码层面,有的实现还会用约束解码(constrained decoding) 保证输出严格符合 schema,避免生成不合法的 JSON 或不存在的参数。

五、几个进阶机制

并行调用(parallel tool calls):一次回复里模型可同时发起多个独立调用,比如同时查三个城市的天气,宿主并发执行后一起回传,减少往返延迟。

工具选择策略(tool choice) :可以设为 auto(模型自行决定)、any(必须调某个工具)、或强制指定某个具体工具。强制调用在结构化数据抽取场景很有用------你其实是借 function call 让模型输出固定格式的 JSON。

多步 agentic loop:复杂任务里模型会连续调用多个工具,前一个的结果决定下一步调什么。这就是 ReAct 等 Agent 范式的底层实现。

MCP(Model Context Protocol):近来流行的标准,把工具以协议化的方式暴露给模型,让工具的定义和接入更可复用,而不必每个应用重写一遍 schema。

六、工程实践中的坑

需要特别注意几点:模型可能幻觉参数 ------传入不存在的字段或编造的值,所以宿主侧必须做参数校验,不能盲目信任。错误处理 也很关键:工具执行失败时,应把错误信息也以 tool_result 回传,让模型有机会重试或换方案,而不是直接崩溃。

安全方面要警惕提示注入:如果工具返回的内容(比如抓取的网页)里藏了恶意指令,可能诱导模型执行危险操作,因此对有副作用的工具(删数据、转账、发邮件)应加权限确认和沙箱隔离。此外,工具太多会稀释模型的选择准确率,通常控制在合理数量,或按场景动态裁剪可用工具集。


总结:function call 是 Agent 的"手脚",它让模型从"会想"变成"能做"。理解它的关键是抓住那个结构化请求---宿主执行---结果回传---再决策的循环。如果你想深入某一块------比如具体某家 API 的实现差异、如何设计多工具的 Agent 编排、或 MCP 的接入方式------我可以再展开。