大模型怎么学会调用工具?Function Calling 从原理到生产实战

大模型怎么学会调用工具?Function Calling 从原理到生产实战 做 Agent 应用绕不开一个能力让大模型去调用外部工具。查个天气、算个费用、拉个数据库模型本身做不到但可以安排程序去做。Function Calling函数调用就是这套机制的名字。我自己在项目里踩了不少坑这篇从原理到可运行的代码把 Function Calling 讲清楚。一、什么时候需要 Function Calling让模型获取实时信息模型的训练数据是有截止时间的查今天天气、实时股价必须靠工具让模型执行确定性计算算费用、算面积这类数学运算模型容易算错交给代码保证正确让模型操作业务系统发邮件、创建工单、更新数据库需要调用真实业务接口做多步 Agent先查订单状态再判断是否退款最后执行退款——每一步都对应一次工具调用核心需求一句话模型负责理解意图、做决策程序负责真正执行。二、原理模型是怎么调用工具的先说清楚一个容易误解的点模型并没有真正执行任何代码。整个机制分三步你告诉模型有哪些工具可用通过tools参数把每个工具的名字、参数 SchemaJSON Schema 格式、用途描述发给模型模型在回复里表示想调用模型分析用户问题后如果判断需要工具会返回一个tool_calls字段里面是工具名和参数 JSON——注意到这里模型只是提议调用没有真执行你的程序执行并回传结果你解析tool_calls在自己的代码里真正调用那个函数把执行结果作为新的消息追加回对话让模型基于结果继续回答关键点模型生成的是调用指令执行权始终在你自己手里。这既是灵活性也是安全边界——你可以决定要不要执行、执行前做不做校验。工具定义长这样以查询订单为例tools [{ type: function, function: { name: query_order, description: 查询订单的当前状态, parameters: { type: object, properties: { order_id: {type: string, description: 订单号} }, required: [order_id] } } }]三、实战一单次工具调用跑通全流程用 OpenAI 兼容接口DeepSeek、通义等国产模型的 API 也遵循这个格式写一个查询订单的完整流程。import json from openai import OpenAI client OpenAI() # 设置好 api_key 和 base_url tools [{ type: function, function: { name: query_order, description: 查询订单的当前状态, parameters: { type: object, properties: { order_id: {type: string, description: 订单号} }, required: [order_id] } } }] def query_order(order_id: str) - str: # 这里真正去查数据库/调业务接口demo 用假数据 data {1001: 已发货, 1002: 待支付, 1003: 已取消} return data.get(order_id, 未找到该订单) messages [{role: user, content: 帮我查一下订单1001的状态}] response client.chat.completions.create( modelgpt-4o, messagesmessages, toolstools, ) # 模型可能返回 tool_calls也可能直接回答 if response.choices[0].message.tool_calls: call response.choices[0].message.tool_calls[0] func_name call.function.name args json.loads(call.function.arguments) result query_order(**args) # 真正执行 # 把执行结果回传给模型让它基于结果组织语言回答 messages.append(response.choices[0].message) messages.append({ role: tool, tool_call_id: call.id, content: result, }) answer client.chat.completions.create( modelgpt-4o, messagesmessages, toolstools, ) print(answer.choices[0].message.content)这段跑下来模型会输出类似订单1001当前状态为已发货。核心就一句话执行结果必须通过role: tool和对应的tool_call_id回传否则模型无法继续对话。tool_call_id对应关系不能错这是最容易踩的坑。四、实战二多工具 循环让 Agent 自己想几步真实场景通常有多个工具而且可能需要连续调用多次Agent 循环。写一个可复用的循环def run_agent_with_tools(user_input, tools, tool_dispatch): messages [{role: user, content: user_input}] client OpenAI() for _ in range(8): # 限制最多 8 轮防止死循环 resp client.chat.completions.create( modelgpt-4o, messagesmessages, toolstools) msg resp.choices[0].message messages.append(msg) if not msg.tool_calls: # 模型不再要求调用工具直接结束 return msg.content for call in msg.tool_calls: fn call.function result tool_dispatch[fn.name](**json.loads(fn.arguments)) messages.append({ role: tool, tool_call_id: call.id, content: result, }) # 注册两个工具 tool_dispatch { query_order: query_order, calculate_refund: calculate_refund, }一个典型的多步对话是查询订单1001如果已发货就不用管否则计算退款金额——模型会先调query_order根据结果决定要不要调calculate_refund。循环的退出条件就是模型返回没有tool_calls的纯文本回复。五、实战三结构化输出与可靠性兜底Function Calling 还有一个兄弟能力结构化输出Structured Outputs。当你不需要调用工具只想要稳定的 JSON时用response_format配合 JSON Schema 约束比让模型自然输出 JSON可靠得多response client.chat.completions.create( modelgpt-4o, messages[{role: user, content: 从这句话里提取实体张三今天在深圳签了合同}], response_format{ type: json_schema, json_schema: { name: entity_extract, strict: True, schema: { type: object, properties: { person: {type: string}, location: {type: string}, action: {type: string}, }, required: [person, location, action], additionalProperties: False, } } }, )几个生产环境的兜底经验参数校验不能省模型生成的参数是看起来合理的不一定合法。执行前自己再做一次类型/取值范围校验工具描述决定成功率description写得越清楚模型越知道什么时候该用、参数怎么填。描述含糊是工具调不准的主要原因兜底 JSON 解析个别情况下arguments可能带些不标准格式解析失败要能降级提示模型重来或直接返回错误别让整个流程崩掉权限与确认写操作发邮件、删数据、转账在真正执行前加上确认或白名单校验——模型提议不等于允许执行六、总结Function Calling 的本质是把决策和执行分离模型负责理解意图、挑选工具、生成参数你的程序负责真正干活并把结果喂回去。理解它之后很多 Agent 项目的神秘感就消失了——不过是一层tools定义、一次tool_calls解析、一个循环。真正决定工程质量的是工具描述质量、参数校验和权限控制这些代码之外的功夫。把这三点做好你的 Agent 离生产可用就不远了。本文示例基于 OpenAI 兼容接口各厂商在字段细节上略有差异请以对应平台最新文档为准。