先记住这个答案
工具调用闭环中,模型根据用户请求和工具描述决定调用哪个工具,生成包含工具名和参数的 tool_use 块;应用代码执行该工具并产生结果,再以 tool_result 块回传给模型;模型读取结果后继续生成最终回复或发起下一轮调用。整个过程围绕消息序列展开,职责清晰:模型不直接执行代码,运行时也不替模型做决策。
- 模型只产结构化调用,不执行代码
- 运行时负责执行工具并回传结果
- 结果需放入 tool_result 块继续对话
从文本到函数调用的结构化转换
当用户请求需要外部数据或操作时,模型在给定工具列表中选择一个工具,生成包含 id、name 和 input 的 tool_use 内容块。这个块不是自然语言,而是符合工具 input_schema 的 JSON 对象。例如,get_weather 工具需要 location 字符串,模型输出 {"location":"San Francisco, CA"}。
应用检测到 stop_reason 为 tool_use 后,解析出工具名和参数,执行对应的实际函数。执行完毕后,应用构造一个 tool_result 内容块,包含 tool_use_id(与之前的 ```tool_use块匹配)和结果内容(如字符串或 JSON)。然后将其作为新的user` 消息的一部分发送给模型,模型读取结果并继续生成回复或再次调用工具。
// 模拟模型输出工具调用
const assistantMessage = {
role: 'assistant',
content: [{ type: 'tool_use', id: 'tool_1', name: 'get_weather', input: { location: 'San Francisco' } }]
};
// 运行时执行工具
function executeTool(name, input) {
if (name === 'get_weather') return "15°C,多云";
throw new Error(`未知工具: ${name}`);
}
// 回传结果
const toolUse = assistantMessage.content[0];
const result = executeTool(toolUse.name, toolUse.input);
const userMessage = {
role: 'user',
content: [{ type: 'tool_result', tool_use_id: toolUse.id, content: result }]
};
console.log(JSON.stringify({ assistantMessage, userMessage }, null, 2));查看输出与解释
{
"assistantMessage": {
"role": "assistant",
"content": [
{
"type": "tool_use",
"id": "tool_1",
"name": "get_weather",
"input": {
"location": "San Francisco"
}
}
]
},
"userMessage": {
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "tool_1",
"content": "15°C,多云"
}
]
}
}展示客户端工具的核心三步:模型输出tool_use,运行时执行,回传tool_result。
查询天气并回答的工程实现
假设 Agent 需要回答“旧金山天气如何”,提供了 get_weather 工具,schema 要求 location 必需。用户请求缺少具体城市时,模型可能推断默认值或询问。实际场景中,模型生成工具调用,应用从响应中提取 tool_use,调用天气 API,获取温度字符串,然后作为工具结果回传。
处理时需注意:1) 确保 tool_use_id 正确映射,避免并行调用时混淆;2) 结果内容不能是超大对象,应简洁;3) 如果工具执行失败,需在 tool_result 中传递错误内容,让模型决定下一步,而非直接抛出异常导致断链。
闭环失效的边界条件
模型可能输出非法工具名或参数,例如 get_weather 的 location 传成数字。此时运行时校验失败,若直接报错中断,模型无法得知原因。正确做法是将错误信息作为 tool_result 内容返回,例如 content: "参数错误:location 必须是字符串",让模型根据错误修正调用。
此外,当模型一次输出多个 tool_use 且调用之间有依赖时,运行时必须等待前一个结果再调用后一个。若忽略顺序并行执行,可能因参数缺失而失败。还需注意每次工具调用都会消耗 token,结果过大需截断,否则上下文长度超限导致后续调用失败。
容易答错的地方
- 认为模型会直接执行工具
- 模型只生成结构描述,不执行任何代码或访问真实系统。所有副作用必须由应用层代码实现,否则工具只是空壳。
- 忽略工具结果回传格式
- 工具结果必须包装成
tool_result块并关联tool_use_id,若直接以文本形式拼接在用户消息里,模型可能无法关联结果与调用,导致语义混淆。
面试官还会怎么问?
并行工具调用时如何匹配结果?
每个 tool_use 有唯一 id,对应 tool_result 必须携带该 id。运行时按响应中的多个块分别执行,并按 id 回传,可乱序执行但结果要准确地与调用对应。
工具执行结果超长怎么办?
需要截断或压缩,例如只取前 N 字符、提取摘要或保留关键字段。或者采用专门的结果处理工具,避免阻塞上下文。
工具调用失败如何告知模型?
不要抛出异常导致中断,而是将错误信息放在 tool_result 的 content 中,可能并用 is_error: true 标记,模型会理解并尝试修正或转换策略。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。