Claude 的 tool_use 为什么不是最终答案:tool_result 回传与循环边界
来源:17golang原创
时间:2026-07-22 14:31:58 368浏览 收藏
用Go开发后台服务对接Anthropic Messages API做工具调用的时候,不少开发者刚上手第一反应会直接把 tool_use 当成模型返回的最终答案。实际上它只是Claude给到对接侧的明确信号:请运行这个指定的工具,再根据对应的ID把运行结果回传回来。要是漏掉 stop_reason、错配 tool_use_id,或是直接把工具抛出的错误当成普通文本处理,整个调用链路就会出现空回复、重复查询相同内容甚至无限循环的异常问题。
把一次完整的工具调用拆成两段消息往返理解:模型先返回
tool_use,Go 服务执行预配置的白名单工具,再用同一个tool_use_id发送tool_result;每一轮交互都要检查模型的停止标识,同时提前配置好最大轮数限制。
要点速览
stop_reason=tool_use代表应用需要主动运行指定工具,绝对不能直接把这一轮返回的内容当成最终回复展示给用户。tool_use_id是工具请求和对应结果的关联标识,回传的时候必须原样匹配,不能自行修改生成。- 工具结果要放在下一条 user 角色消息的
tool_result内容块里回传,无论执行成功还是失败都要带上明确的状态标识。 - 工具白名单、参数校验、接口超时控制、最大循环轮数限制,是服务上线前必须完成的基础边界配置。
先认清 Messages API 的两次交互停顿
一个“查询北京实时天气”的用户请求,至少包含两次模型交互过程。第一次模型根据提前传入的工具描述生成 tool_use 内容块;应用侧执行完 get_weather 后,把工具运行的结果追加到整体消息历史中;第二次调用模型,才会拿到模型整理好的面向普通用户的自然语言回复。
type messageResponse struct {
StopReason string `json:"stop_reason"`
Content []contentPart `json:"content"`
}
type contentPart struct {
Type string `json:"type"`
ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Input map[string]interface{} `json:"input,omitempty"`
Text string `json:"text,omitempty"`
}
解析响应的时候不要只取 content[0].text 直接展示。模型返回的内容可能同时包含工具请求和补充文本说明;真正决定后续流程走向的是 stop_reason。常见的 end_turn 取值代表模型已经结束本轮生成,tool_use 出现则代表当前流程要切换给应用层接管,执行一次工具调用。

工具描述要精简,应用执行器的校验规则要更严格
工具定义里的 input_schema 能让模型明确知道生成参数的格式规范,但这不代表应用侧要放开全部授权。比如天气查询工具只允许查询有限的城市和日期范围,Go 服务侧仍然要主动校验传入的城市字符串合法性、日期格式和调用频次,绝对不能把模型生成的参数直接拼接到任意外部接口地址中。
type toolSpec struct {
Name string `json:"name"`
Description string `json:"description"`
InputSchema map[string]interface{} `json:"input_schema"`
}
var weatherTool = toolSpec{
Name: "get_weather",
Description: "查询一个城市当天的天气摘要",
InputSchema: map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"city": map[string]string{"type": "string"},
},
"required": []string{"city"},
},
}
真正执行工具请求之前要再做一次白名单判断,例如只允许 北京、上海 和 广州 三类操作,同时给对接的外部天气服务设置较短的超时时间。工具描述解决的是“模型该怎么正确发起工具请求”的问题,执行器层的规则解决的是“服务本身允许做什么操作”的问题,两者不能混为一谈。
用同一个 tool_use_id 把结果送回去
收到模型返回的工具请求后,应用要完整保留上一条 assistant 角色的全部内容,再追加一条 user 角色的消息,里面放入 tool_result 内容块。关联标识必须直接复用模型返回的 tool_use_id,不能自己生成一个新的ID来回传。
type toolResultPart struct {
Type string `json:"type"`
ToolUseID string `json:"tool_use_id"`
Content string `json:"content"`
IsError bool `json:"is_error,omitempty"`
}
func makeToolResult(id string, value string, failed bool) map[string]interface{} {
return map[string]interface{}{
"type": "tool_result",
"tool_use_id": id,
"content": value,
"is_error": failed,
}
}
工具执行成功时,content 可以是结构轻量化的JSON或者格式化的稳定文本;工具执行失败时设置 is_error,把可以对外展示的安全错误原因交给模型处理。不要把数据库连接串、内部服务地址和完整调用堆栈这类敏感信息塞进工具结果里。

把完整往返封装成有限循环
工具调用流程通常需要一个轻量循环:发起模型请求、判断当前停止标识、运行对应工具、追加新的消息片段,再次发起模型请求。循环必须设置硬上限阈值,一方面防止模型反复请求同一个工具,另一方面也避免外部服务异常导致的请求一直占用长连接资源。
func askWithTools(ctx context.Context, messages []map[string]interface{}) (string, error) {
for round := 0; round
示例里的四轮只是常规保护阈值,不是API本身的固定限制。如果业务逻辑里单个请求只需要一次天气查询,工具结果回传之后仍然收到第二次完全相同的工具调用请求,就应该直接记录上下文信息进入排查流程,而不是盲目调高循环上限。
工具失败要返回可理解的错误,不要伪造成功
外部天气服务超时、传入参数不合法或是请求的城市不存在时,应用有两种可选处理路径:把错误作为 is_error=true 的工具结果直接回传给模型,让模型生成友好提示告知用户当前无法查询;或是直接结束本次业务请求,交给上层重试机制处理。无论选择哪种方案,都不要把错误的JSON强行伪装成正常的天气结果返回。
- 参数错误:不做重试,直接返回可供模型生成校正提示的信息。
- 短暂网络故障:配置有限次重试次数,多次重试仍然失败就回传工具错误。
- 权限或配额错误:记录告警信息,避免循环重试耗尽配额。
- 工具返回结果过大:优先裁剪字段,只保留模型完成回答必须的摘要内容。
常见问题
tool_use 返回后可以直接展示给用户吗?
通常不可以。这部分内容是生成给应用执行器处理的工具请求,最终展示给用户的回复,一般要等工具结果回传之后由模型生成。
tool_use_id 不匹配会怎样?
模型无法把回传的结果和之前的原始请求做关联,整轮消息可能被直接拒绝,或是返回完全不符合预期的内容。要把ID当成不透明的关联标识,原样保存原样回传就好。
工具调用为什么会出现无限循环?
常见诱因包括工具结果格式不符合模型预期、执行侧抛出的错误没有做失败标记,或是应用侧无上限放开循环次数限制。出现这类问题先记录stop_reason、调用的工具名和当前循环轮数,再依次排查执行器逻辑和结果回传逻辑。
工具调用的稳定性来自边界,而不是更长的提示词
用Go接入Messages API的tool_use能力时,先把 stop_reason 当成状态机的入口节点,再用 tool_use_id 串联起assistant的请求和user侧的结果;执行器层做好白名单校验和超时控制,循环层做好最大轮数限制,错误场景做好显式回传。这样哪怕工具临时出现故障,整个系统也能停在一个可解释的状态,不会把空答案或是错误结果直接传递给终端用户。
-
202 收藏
-
243 收藏
-
195 收藏
-
186 收藏
-
333 收藏
-
419 收藏
-
280 收藏
-
科技周边 · 人工智能 | 4天前 | 异步任务 · 人工智能 · jsonl · AI工程化 · Batch API · 结果对账 · JSONL 大模型批量任务 OpenAI Batch API custom_id AI 离线处理 结果对账113 收藏
-
149 收藏
-
432 收藏
-
科技周边 · 人工智能 | 5天前 | 安全 · oauth · 人工智能 · mcp · 工具调用 · MCP 401 MCP 403 MCP OAuth mcp resource_metadata MCP scope MCP token audience443 收藏
-
科技周边 · 人工智能 | 6天前 | 前端 · 人工智能 · 用户体验 · 可访问性 · 流式输出 · AI对话 AbortController AbortSignal 流式输出 aria-live 停止生成425 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习