导读:本期聚焦于徐致远创作的《Function Call执行结果如何回传给大模型?工具结果注入推理上下文的完整实践》,敬请观看详情。大模型通过Function Call调用外部工具后,拿到工具的执行结果,下一步该怎么做?许多开发者第一次接入推理API时,容易在这里卡住:结果应该放在哪个字段里,消息角色填什么,历史消息要不要重复携带。本文围绕工具结果注入推理上下文这一核心环节展开,讲解role为tool的消息结构、tool_call_id的匹配规则、多工具并行调用时的结果组织方式,以及循环调用中上下文膨胀的治理思路。文章附带完整的请求报文示例和常见报错的排查方法,帮助你在智能客服、数据查询、代码执行等场景中跑通完整的工具调用闭环,适合正在开发Agent或对话系统的工程师参考。

大模型决定调用某个工具只是整个流程的一半,真正决定应用效果的是工具执行结果如何回到模型手里。不少团队在接入推理API时,把Function Call的参数解析做得很完善,却在结果回传这一步踩坑:有人把结果直接拼进用户消息,有人忘记填tool_call_id导致接口直接报错,有人在多轮循环调用中把上下文塞得越来越大,最终token费用失控。本文以主流推理API的通用规范为基础,把结果注入推理上下文的机制讲清楚,并给出可直接落地的请求示例。

Function Call执行结果如何回传给大模型?工具结果注入推理上下文的完整实践

一、结果回传的基本消息结构:role为tool的消息

当模型返回一条带tool_calls的assistant消息后,客户端执行完工具,需要把结果组装成一条新的消息追加到对话历史中,再次发起请求。这条消息的核心特征是角色为tool,而不是常见的user或assistant。以广泛兼容的Chat Completions风格接口为例,回传消息包含三个关键字段:role固定为tool,tool_call_id必须与模型上次返回的某个工具调用id完全一致,content承载工具执行的结果文本。

一个典型的完整请求体如下,注意assistant消息要原样保留在历史里,否则模型无法对应它当初发起的调用:

{
  "model": "your-model-name",
  "messages": [
    {
      "role": "user",
      "content": "帮我查一下北京今天的气温"
    },
    {
      "role": "assistant",
      "content": null,
      "tool_calls": [
        {
          "id": "call_abc123",
          "type": "function",
          "function": {
            "name": "get_weather",
            "arguments": "{\"city\":\"北京\"}"
          }
        }
      ]
    },
    {
      "role": "tool",
      "tool_call_id": "call_abc123",
      "content": "{\"temperature\": 18, \"condition\": \"晴\"}"
    }
  ],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "查询指定城市当前天气",
        "parameters": {
          "type": "object",
          "properties": {
            "city": {"type": "string"}
          },
          "required": ["city"]
        }
      }
    }
  ]
}

这里有几个容易出错的细节。第一,tool_call_id是模型侧生成的随机标识,不是你自己编的,必须从上一轮响应里原样复制,多一个空格都会导致400错误。第二,assistant消息中的tool_calls数组在回传时要完整保留,哪怕content为null也不能删掉这条消息,因为它是模型判断上下文连续性的依据。第三,工具结果不一定非要是纯文本,多数接口支持JSON字符串,结构化数据反而更利于模型准确提取字段。

二、多工具并行调用的结果组织与匹配

能力较强的模型经常在一次响应中同时发起多个工具调用,比如用户问“对比上海和深圳的房价”,模型可能返回两个tool_calls,分别查询两个城市。这种情况下,回传时必须为每一个调用id都提供一条对应的tool消息,不能合并成一条。各厂商接口对此要求略有差异,有的允许把多条结果合并到一个消息里用数组表达,有的则严格一一对应,采用一一对应的写法兼容性最好。

{
  "role": "tool",
  "tool_call_id": "call_001",
  "content": "{\"city\": \"上海\", \"avg_price\": 58200}"
},
{
  "role": "tool",
  "tool_call_id": "call_002",
  "content": "{\"city\": \"深圳\", \"avg_price\": 61500}"
}

除了并行调用,还有一种更复杂的情况是循环调用:模型拿到第一批结果后,发现信息不足,会再次发起tool_calls。这实际上构成了一个“模型发起调用、客户端执行、结果回传、模型再决策”的循环。工程上建议用一个while循环实现,终止条件是模型返回的finish_reason为stop且不再包含tool_calls。每次循环都要把新产生的assistant消息和tool消息追加进messages数组,而不是替换,模型的推理依赖完整的调用链条。

循环调用还有一个隐蔽的坑:如果工具执行失败,比如数据库连接超时,千万不要直接中断流程,也不建议返回空字符串。正确做法是把错误信息如实写进tool消息的content,例如返回“查询超时,请稍后重试”这样的描述,让模型有机会决定是换个参数重试还是向用户说明情况。直接抛异常中断会让模型失去决策机会,用户侧表现就是对话莫名其妙结束。

三、上下文膨胀治理与结果裁剪策略

结果回传机制天然会导致消息历史快速增长。假设一个数据分析Agent每轮调用返回几KB的查询结果,十几轮对话后上下文轻松突破模型窗口限制,即使没有超限,token费用也相当可观。治理思路主要有三种,可以组合使用。

第一种是结果裁剪。工具返回的数据往往远超模型实际需要的部分,比如查订单列表返回了50个字段,模型只需要订单号和状态。可以在客户端加一层裁剪逻辑,只把相关字段回传。第二种是摘要压缩,对于长文本类结果,可以先调用一次轻量模型做摘要,再把摘要作为tool消息回传。第三种是滑动窗口,当历史超过阈值时,把早期的工具结果替换为一句简短的占位描述,例如“此前已查询过订单列表,结果已省略”。需要注意的是,最近一轮的tool消息不要省略,否则模型会因为缺失关键信息而重复调用工具。

def trim_tool_result(result: dict, keep_fields: list) -> str:
    # 只保留模型需要的字段,减少回传token
    trimmed = {k: result.get(k) for k in keep_fields if k in result}
    return json.dumps(trimmed, ensure_ascii=False)

# 使用示例:订单查询结果只回传关键字段
raw = {"order_id": "A88231", "status": "已发货", "raw_log": "..." * 2000}
msg = {
    "role": "tool",
    "tool_call_id": "call_009",
    "content": trim_tool_result(raw, ["order_id", "status"])
}

最后补充一点工程实践建议:给整个调用链路加上请求日志,记录每次tool_call_id、执行耗时和结果长度,排查线上问题时这些日志能帮你快速定位到底是模型没发起调用、工具执行出错,还是结果格式不对。同时建议对content长度做上限保护,超过阈值的工具结果强制截断并附加提示,避免一次异常的超大返回把整个会话拖垮。把结果回传这一环做扎实,Function Call才能真正形成可靠的业务闭环。

Function Call推理API上下文注入修改时间:2026-09-14 14:37:01

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260914/56744.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。