LLM 是如何学会调用外部工具的?
前言: • 预训练让模型学会语言,但不会天然学会可执行的工具调用。 • SFT 让模型见过标准工具调用样本,学会按 schema 输出结构化 tool_calls。 • RLHF/RLAIF 让模型学会边界感:该调才调,不该调就直接回答。
前言:
• 预训练让模型学会语言,但不会天然学会可执行的工具调用。
• SFT 让模型见过标准工具调用样本,学会按 schema 输出结构化 tool_calls。
• RLHF/RLAIF 让模型学会边界感:该调才调,不该调就直接回答。
• 上线运行时,模型只负责决策;真正执行工具的是你的应用代码。
一、它不是“学会用 API”,而是“学会写调用单”
很多人一听工具调用,就以为模型真的拿到了浏览器、数据库、支付接口的执行权。其实不是。模型本质上还是在生成文本,只不过这次生成的不是普通聊天内容,而是一段机器能看懂的结构化调用请求。
可以把工具调用理解成外卖系统:用户说“帮我点杯拿铁”,大模型不是自己去咖啡店买,而是写出一张订单:商品是拿铁、数量是 1、地址是某处。真正下单、支付、配送的是外卖平台的程序。
所以工具调用最关键的分工是:模型负责理解意图和写调用单;代码负责校验调用单、执行工具、拿回结果,再把结果交给模型总结。
二、预训练为什么不够?
预训练阶段的目标很简单:给模型一大段文本,让它预测下一个 token。这个过程能让模型学会语言、知识和推理模式,但它并不知道你的生产系统里有哪些函数,也不知道这些函数的参数格式。
即使模型在互联网上见过很多 API 文档,也不等于它会稳定输出你的系统要求的 JSON。因为工具调用不是“懂 API 名字”这么简单,而是要做到三件事:识别何时需要工具、选对工具、按严格格式填对参数。
这就是为什么光靠参数规模不够。工具调用能力需要专门训练,也需要运行时约束。小林面试笔记这章也强调:工具调用不是大模型自然涌现出来的能力,而是通过 SFT、RLHF 和 Function Calling 机制组合出来的能力。
三、SFT:先让模型“见过正确答案”
SFT 可以理解成带答案的模仿学习。你给模型看很多标准样本:用户怎么问、系统有哪些工具、正确的 tool_calls 应该怎么写、工具结果回来后应该怎么回答。模型看多了,就学会了这种固定套路。
它解决的是“会不会调”的问题。比如看到“北京今天天气怎么样”,模型要学会这不是普通常识问答,而是需要实时数据,于是输出 get_weather 的调用请求,而不是编一个天气。
一条高质量训练样本,通常不是一问一答,而是一整段轨迹:System 工具说明、User 用户问题、Assistant 结构化调用、Tool 工具结果、Assistant 最终回答。
四、训练样本里的关键:正确答案不是一句话,而是 tool_calls
如果训练答案只是“我需要调用天气接口”,程序还是没法执行。真正有用的是下面这种结构化结果:
JSON:模型应该输出的调用请求
{
"tool_calls": [
{
"name": "get_weather",
"arguments": {
"city": "北京",
"unit": "celsius"
}
}
]
}
这段 JSON 的价值在于:宿主程序能稳定读到函数名和参数,然后走白名单、鉴权、参数校验,最后才真正执行 API。
五、RLHF / RLAIF:教模型建立边界感
SFT 有一个天然问题:它让模型学会了调用工具,但容易把模型训练得过于积极。别人问“1+1 等于几”,它也可能想调用计算器;别人让它写一段祝福语,它也可能想调用搜索。
这就需要 RLHF 或 RLAIF。它们的核心不是再教格式,而是用反馈告诉模型:哪种行为更合理。该直接回答的时候直接回答,该查实时数据的时候才查工具,工具失败时要诚实说明,而不是继续硬编。
如果说 SFT 是“新员工看模板学会填工单”,那 RLHF 就是“主管不断点评,告诉他什么时候该走流程,什么时候别浪费流程”。
SFT 解决格式问题,RLHF/RLAIF 解决边界问题。
六、Function Calling:训练好之后,运行时怎么落地?
上线以后,模型不是带着所有工具到处跑。每一次请求,应用程序都会把当前允许使用的工具说明传给模型。模型根据用户问题和工具说明,决定是否输出 tool_calls。
当模型输出 tool_calls 后,它的工作就暂停了。接下来由宿主程序解析 JSON,检查工具是否在白名单内,检查参数是否合法,检查当前用户有没有权限。通过后,程序才真正调用 API、数据库、搜索或代码执行环境。
工具结果返回后,宿主程序把结果作为 tool_result 放回对话,再让模型组织成人能看懂的回答。这套“模型决策、代码执行、结果回传”的链路,就是 Function Calling 的运行时机制。
七、工具 Schema 要写清楚,模型才不容易乱用
Schema 可以理解为工具说明书。它告诉模型:这个工具叫什么、什么时候用、需要哪些参数、参数范围是什么。OpenAI 文档里也建议 strict 模式,让函数调用更可靠地遵守 schema;Structured Outputs 文档还强调,schema 约束比普通 JSON mode 更能保证结构一致。
JSON:一个更规范的工具定义
{
"type": "function",
"function": {
"name": "get_weather",
"description": "查询指定城市的实时天气。只在用户询问当前天气时使用。",
"strict": true,
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称,例如:北京、上海"
},
"unit": {
"type": [
"string",
"null"
],
"enum": [
"celsius",
"fahrenheit",
null
]
}
},
"required": [
"city",
"unit"
],
"additionalProperties": false
}
}
}
八、到底什么时候该调工具?
判断逻辑可以很简单:如果问题依赖实时信息、外部系统、精确计算或业务动作,就倾向于调用工具;如果是稳定知识、解释、创作和简单问答,就直接回答。
工具调用不是越多越好。每一次工具调用都会增加成本、延迟和失败概率。一个成熟的 Agent,不是疯狂调工具,而是该调时稳准狠,不该调时安静回答。
九、运行时代码必须兜底,不能完全相信模型输出
下面这段伪代码展示了正确思路:模型输出只是建议,真正执行前必须经过白名单、参数校验、权限校验和异常处理。
Python:工具执行前的最小安全兜底
ALLOWED_TOOLS = {
"get_weather": get_weather
}
REQUIRED_ARGS = {
"get_weather": ["city", "unit"]
}
def execute_tool_call(tool_call, user):
name = tool_call["name"]
args = tool_call.get("arguments", {})
if name not in ALLOWED_TOOLS:
raise ValueError("tool is not allowed")
for key in REQUIRED_ARGS[name]:
if key not in args:
raise ValueError(f"missing argument: {key}")
if not user.can_use(name):
raise PermissionError("no permission to call this tool")
try:
return ALLOWED_TOOLS[name](**args)
except TimeoutError:
return {"error": "tool timeout, please try again later"}这才是生产系统里最关键的一层:不要让模型直接碰数据库、支付接口、文件系统或生产环境。它只负责输出结构化意图,执行权必须握在代码手里。
十、常见翻车点和治理办法
工具调用项目真正难的地方,往往不是模型能不能输出 JSON,而是上线以后能不能稳定、可控、可追踪。下面这些问题非常常见。
十一、工程落地清单
第一,工具描述要清楚。尤其是 description,要写明“什么时候用”和“什么时候不要用”,否则模型很容易误触发。
第二,schema 要严格。尽量使用 required、enum、additionalProperties=false、strict=true 等约束,降低模型瞎填参数的空间。
第三,工具数量要控制。一次性塞给模型几十个相似工具,会明显增加选错工具的概率。可以按场景动态注入工具。
第四,所有高风险动作都要二次确认。发邮件、删除文件、转账、下单、改配置等动作,不能让模型一句话直接执行。
第五,必须做日志和评估。记录每次问题、工具选择、参数、工具结果、最终回答和失败原因,后续才能复盘优化。
十二、一个最简单的判断示例
同样是用户提问,有些问题不需要工具,有些必须工具。把边界讲清楚,模型才会更稳。
示例:该直接答就直接答,该调用才调用
# 不需要工具 |
十三、面试怎么回答最稳?
如果面试官问:LLM 是如何学会调用外部工具的?不要只回答 Function Calling。Function Calling 是运行时机制,不是训练方法。完整答案要同时讲训练层和运行层。
训练层:SFT 用工具调用样本教模型输出格式,RLHF/RLAIF 用反馈教模型建立边界感。
运行层:应用把工具 schema 传给模型,模型输出 tool_calls,宿主程序执行工具,再把 tool_result 回传给模型生成最终回答。
关键认知:模型不是执行器,模型是决策器。真正执行工具、控制权限、处理异常的,永远是宿主程序。
要点速读
前言: • 预训练让模型学会语言,但不会天然学会可执行的工具调用。 • SFT 让模型见过标准工具调用样本,学会按 sc
- 前言: • 预训练让模型学会语言,但不会天然学会可执行的工具调用
- • SFT 让模型见过标准工具调用样本,学会按 sc
- 更多细节仍在持续更新中