tool_calls 需要回传给大模型吗?

tool_calls 必须回传,少了会出大问题。 tool_calls 是对话协议的强约束部分,丢了模型会"失忆"或直接报错。

一句话回答

tool_callsassistant 上一轮"我决定要调这些工具"的承诺凭证 ,下一轮你必须把它原样回传 ,并紧跟着用 role: tool 消息把结果配对 回给模型。少传或漏配,模型会报错或行为异常

必须回传的核心理由

1️⃣ tool 消息必须 通过 tool_call_id 配对到上一轮的 tool_calls

OpenAI 协议要求 role: tool 消息必须带 tool_call_id,这个 id 必须能在前一条 assistant 消息的 tool_calls 数组中找到

python 复制代码
# 上一轮 assistant 必须保留 tool_calls
{"role": "assistant", "content": "", "tool_calls": [
    {"id": "call_xxx", "function": {"name": "bash", "arguments": "..."}}
]}

# 紧接着的 tool 消息必须引用这个 id
{"role": "tool", "tool_call_id": "call_xxx", "content": "ls 输出..."}

如果丢了 tool_calls ,模型/服务端找不到 call_xxx 的来源,会报:

csharp 复制代码
400: messages with role 'tool' must be a response to a preceding message with 'tool_calls'

(OpenAI 官方报错原文,几乎所有兼容服务都一样)

2️⃣ 模型靠它知道"自己上一轮干了啥"

模型本身是无状态 的,每轮都重新读完整 messages 推理。如果你删掉 tool_calls

模型看到的对话变成:

vbnet 复制代码
user:      "看下当前目录有啥"
assistant: ""                          ← 啥都没说?
tool:      "file1.txt file2.txt"       ← 这哪冒出来的?
user:      "再看下文件大小"

模型一脸懵:"我没调工具啊,怎么有 tool 结果?" 行为不可预测,可能:

  • 重复调一次刚才的工具
  • 忽略 tool 消息凭空乱编
  • 直接报 schema 错误

3️⃣ 多 tool_calls 时必须全部配对回传

一次 assistant 可以并行调多个工具:

python 复制代码
"tool_calls": [
    {"id": "call_a", "function": {"name": "bash", "arguments": "{\"command\":\"ls\"}"}},
    {"id": "call_b", "function": {"name": "bash", "arguments": "{\"command\":\"pwd\"}"}}
]

下一轮你必须对每一个回传 tool 消息:

python 复制代码
{"role": "tool", "tool_call_id": "call_a", "content": "file1.txt..."},
{"role": "tool", "tool_call_id": "call_b", "content": "/Users/..."}

少一个模型会报:

csharp 复制代码
400: 'tool_calls' must be followed by tool messages responding to each tool_call_id

简单例子

python 复制代码
# 1) 保留 tool_calls 到 assistant 消息
assistant_turn = {"role": "assistant", "content": msg.get("content") or ""}
if msg.get("tool_calls"):
    assistant_turn["tool_calls"] = msg["tool_calls"]   # ← 关键
messages.append(assistant_turn)

# 2) 对每个 tool_call 都回传一条 tool 消息(用 id 配对)
for call in msg["tool_calls"]:
    ...
    messages.append({
        "role": "tool",
        "tool_call_id": call["id"],   # ← 关键
        "content": output,
    })

这两步缺一不可,你都做了。

完整一轮长这样

python 复制代码
[
  # 1. 用户提问
  {"role": "user", "content": "看下当前目录有啥"},

  # 2. 模型决定调工具(这条必须保留 tool_calls)
  {"role": "assistant",
   "content": "",
   "tool_calls": [
     {"id": "call_a", "function": {"name": "bash", "arguments": "{\"command\":\"ls\"}"}}
   ]},

  # 3. 你执行后回传结果(必须带 tool_call_id 配对)
  {"role": "tool",
   "tool_call_id": "call_a",          ← 必须等于上面的 "call_a"
   "content": "file1.txt\nfile2.txt"},

  # 4. 模型基于工具结果给出最终回答
  {"role": "assistant", "content": "目录里有 file1.txt 和 file2.txt"}
]

对比:哪些字段要回传

字段 来源 要回传吗 为什么
role message 必传 协议必填
content message 必传 (可以是 "" 协议必填
tool_calls message 必传(如果有) 配对锚点,丢了 400
reasoning_content message ❌ 不要传 思考草稿,浪费 token
thoughtSignature message ❌ 不要传 厂商扩展,无意义
index choice 层 不是 message 的一部分
finish_reason choice 层 不是 message 的一部分

常见踩坑

❌ 坑 1:删 tool_calls 想"省 token"

python 复制代码
# 错误:以为思考过程会污染上下文,把 tool_calls 也一起删
assistant_turn = {"role": "assistant", "content": msg["content"] or ""}
# 没传 tool_calls → 下一条 tool 消息找不到锚点 → 400

❌ 坑 2:tool 消息少传一条

python 复制代码
# 模型一次返回 3 个 tool_calls,你只执行了前 2 个
for call in msg["tool_calls"][:2]:    # ← 漏掉第 3 个
    ...
# 第 3 个 call 没有对应 tool 消息 → 400

正确做法:要么全部执行,要么对失败/跳过的也补一条 tool 消息

python 复制代码
{"role": "tool", "tool_call_id": "call_skipped", "content": "Error: skipped by user"}

❌ 坑 3:tool_call_id 写错

python 复制代码
{"role": "tool", "tool_call_id": "call_xyz", ...}   # ← id 拼错
# → 找不到对应的 tool_call → 400

永远用 call["id"] 取值,不要硬编码

❌ 坑 4:tool 消息和 assistant 消息顺序颠倒

python 复制代码
[
  {"role": "tool", ...},      ← tool 不能在 assistant 之前
  {"role": "assistant", "tool_calls": [...]}
]

正确顺序: assistant(tool_calls)tooltoolassistant → ...

简单记忆口诀

字段 口诀
tool_calls 承诺:assistant 说"我要调这些工具",必须留着
tool_call_id 凭证:tool 结果靠它"对账"
reasoning_content 草稿:用完就扔,别带回家

一句话总结

tool_calls 必须原样回传 ,因为它是 tool 消息找回家的"户口本"。一旦丢失,模型会因为 tool_call_id 找不到上家而直接 400 报错 ,或者上下文断裂胡乱编造。你脚本已经正确处理了,无需改动

reasoning_content 别传、tool_calls 必传 ------ 这就是构造 agent loop 消息历史的两条铁律。

相关推荐
闵孚龙1 小时前
Claude Code 工具提示词全拆解:AI Agent、Prompt Engineering、工具调用、上下文工程、自动化编程的底层逻辑
人工智能·自动化·prompt
白鲸开源1 小时前
杀疯了!SeaTunnel AI CLI 解锁数据集成新玩法
大数据·人工智能·github
王_teacher1 小时前
GRU (Gated Recurrent Unit,门控循环单元) 原理详解 并且手写GRU模型
人工智能·gru·llm·nlp
AI医影跨模态组学1 小时前
Cancer Letters(IF=10.1)中山大学附属第六医院等团队:基于治疗前MRI影像的RCMIX模型预测MRI定义的cT4期直肠癌T分期下降
人工智能·机器学习·论文·医学·医学影像·影像组学
技术落地手记1 小时前
把AI塞进测试环节,我踩出了一条能用的路
人工智能·测试
xixixi777771 小时前
AI的“账号”与“钱包”:AWS与Circle同日出手,AI正从工具进化
人工智能·安全·ai·大模型·云计算·aws
目黑live +wacyltd2 小时前
算法备案:常见驳回原因与应对策略
人工智能·算法
新知图书2 小时前
销售资料包智能生成(使用千问)
人工智能·ai助手·千问·高效办公
Cosolar2 小时前
大模型应用开发面试 • 第4期|A2A、复杂挑战与具身智能
人工智能·后端·面试