返回博客

多步工具调用|数据主权接入

人工智能8993
多步工具调用|数据主权接入

这一期聊一个 Agent 落地时最容易被低估的缺口:多步工具调用。我是 4sapi,做 API 中转站这几年,见过太多「单步 function calling 跑得飞快、一连串调用就崩」的项目,而数据主权法规正在把这种场景推到公共机构面前。

一、多步调用一多,开源模型就掉链子

先讲现象。单个工具调用,也就是「模型识别意图 → 生成一个调用 → 拿到结果」这一趟,主流开源模型已经做得不错。但真实业务几乎不会只调一次:查企业登记信息、核验材料、提交申请、查进度,每一步的输出都是下一步的输入,链路一长,问题就来了。

公共机构的数据主权约束下,模型必须是开源的、本地部署的,还要在真实政府 API 上串联多次工具调用。多步(multi-step)场景下,开源模型持续表现不佳:有的在第二步就把参数写成字符串,有的提前结束调用链直接编答案,有的反复调用同一个工具直到配额被打爆。而当时没有任何基准能量化这个差距,团队只能靠感觉选模型,上线之后靠人肉兜底。

二、为什么多步工具调用这么难

多步调用的难点不在单步,而在状态与误差累积。

第一是状态跟踪。每一步工具返回的结果都要塞回上下文,模型要记住「已经查到什么、还差什么、下一步该调谁」。上下文一长,位置靠前的关键信息容易被稀释,模型会基于残缺信息做决策。

第二是工具选择与参数生成。真实 API 的工具往往十几个,参数有必填、有枚举、有格式约束。步数越多,选错工具、填错参数的概率越高,而且错误会沿着链路传播。

第三是错误恢复。真实 API 会超时、会拒绝、会返回业务错误。模型需要根据错误内容修正重试,而不是原样再调一次。这一步对推理能力的要求远超单步调用。

第四是结果聚合。链路末端要把多个工具的返回整合成一份可交付的结果,模型的归纳能力直接决定输出质量。

每一步都是自回归决策,误差随步数累积——这就是多步调用难的底层原因。可以做一个直观的算术:假设单步成功率 95%,五步链路的总成功率只剩 77%;单步降到 90% 时,五步只剩 59%。开源模型在长链路上的单步成功率往往更接近后者,结果就是整条任务大概率半途而废。

三、数据主权:把部署形态彻底改写

数据主权法规的要求很明确:公共机构的数据不出域,模型本地化部署,使用开源 LLM Agent。这意味着几件事同时成立:

具体落到架构上,通常是三件套:内网里的推理服务跑开源模型,API 网关负责鉴权与限流,任务编排层把函数定义、调用链、审计日志串起来。模型权重、数据、日志三者都不能出境,这是硬约束,不是偏好。

这些约束叠加在一起,把「能力缺口」直接变成「业务故障」。数据主权需求(本地部署 + 开源模型)与多步工具调用能力之间的落差,就是 Agent 落地的真实缺口——这也是我判断 KOPA-Bench 这类工作价值的原因。

四、云端、本地还是混合:一张对比表

先横向对比三种部署形态:

对比维度云端闭源 API本地开源部署混合架构
部署位置服务商机房机构内网/专属服务器内网为主、云端兜底
数据出境是(默认)敏感数据不出域
模型能力强,多步调用稳参差不齐,多步易断关键链路本地、复杂链路云端
多步调用表现中低(缺数据补强)视路由策略而定
单 token 成本中高低(硬件成本为主)
合规风险高(数据主权场景)低(需严格路由控制)
适用场景非敏感、快速验证政务、医疗等数据敏感域分级数据场景

结论很清楚:数据主权场景下,本地开源是唯一合规的底座,但多步调用能力必须靠数据与工程补强;云端模型可以用在非敏感环节做对照和校验。混合架构的关键在路由策略:敏感字段命中就走本地,非敏感且需要强推理的环节才允许出域。路由规则的颗粒度要细到「哪个字段、哪个工具、哪段链路」,并且路由决策本身也要进审计日志。

五、KOPA-Bench:把能力差距量化

能力差距存在,但没有尺子,等于没法管理。KOPA-Bench 解决的正是这个问题:一个包含 145 个真实任务的多步工具调用基准。

真实任务意味着它不用玩具级场景充数——任务来自真实政府业务,调用的是真实 API,链路动辄三步以上,每一步都有明确的成功标准。用它评估模型,得到的是「能不能在真实业务里把活干完」的分数,而不是单轮问答的指标。

跑基准的具体姿势:把 145 个任务按工具链长度分组,分别统计端到端成功率与「卡在第几步」的分布。哪个模型在第 3 步开始崩、崩在选错工具还是参数错误,一目了然,直接指导该补哪块数据。

对我这类做接入的人来说,基准最大的价值是选型依据:换模型、换路由、调提示词之后,跑一遍 KOPA-Bench 看多步成功率,比拍脑袋靠谱得多。

六、EDGE:用执行结果补数据

基准回答了「差多少」,EDGE 回答「怎么补」。开源模型能力不足时,最通用的补数据思路就是 execution-grounded(基于执行)的数据合成。

核心做法不复杂:不要凭空编对话样本,而是先把任务真实执行一遍——调用 API、拿到返回、记录错误、观察状态变化,然后以执行结果作为监督信号,生成训练数据。模型学到的是「这一步真实返回了什么、下一步应该怎么调」,而不是模型自己想象中的世界。

一条典型的 EDGE 流水线:先从真实 API 收集任务与执行轨迹,再把轨迹里的每一步(请求参数、返回结果、是否出错)整理成监督样本,最后用这些样本微调开源模型。相比人工写对话数据,执行数据自带正确性,因为样本里的每一步都真实发生过。

这个思路是通用的:缺哪一段能力,就构造哪一段的执行闭环数据。对本地开源模型来说,用真实 API 的执行日志合成数据,比堆通用语料更能直接提升多步调用成功率。

七、接入教程:多步 function calling 的完整落地

先说明合规前提:这里只讨论合法接入——只对接已授权、已开放的政府公开 API 或机构内网关,走正规鉴权;用 API 网关统一做身份认证、限流、审计;全程记录调用日志。数据主权场景的合规接入,核心是「授权、可审计、不出域」三件事,任何绕开授权的通道都不在讨论范围内。

接入层面,4sapi(https://4sapi.com)这类 API 中转站可以充当统一网关:把 base_url 指向 https://4sapi.com/v1,模型请求自动走负载均衡,按实际 token 计费,失败自动重试。下面用 openai 库写一条完整的多步 function calling 循环:

python
import json
from openai import OpenAI

client = OpenAI(
    api_key="sk-xxxx",
    base_url="https://4sapi.com/v1",
)

TOOLS = [
    {
        "type": "function",
        "function": {
            "name": "query_company_info",
            "description": "按统一社会信用代码查询企业登记信息",
            "parameters": {
                "type": "object",
                "properties": {
                    "credit_code": {"type": "string"}
                },
                "required": ["credit_code"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "check_materials",
            "description": "按登记信息核验变更材料清单,返回缺失项",
            "parameters": {
                "type": "object",
                "properties": {
                    "company_id": {"type": "string"}
                },
                "required": ["company_id"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "submit_application",
            "description": "提交变更登记申请,返回受理单号",
            "parameters": {
                "type": "object",
                "properties": {
                    "company_id": {"type": "string"},
                    "change_items": {"type": "array", "items": {"type": "string"}}
                },
                "required": ["company_id", "change_items"]
            }
        }
    }
]

def call_tool(name, args):
    # 对接已授权的政府开放 API 或内网网关,返回 JSON
    return {"ok": True, "受理单号": "SQ20260908001"}

messages = [{"role": "user", "content": "为企业 91310000MA1FL1XXXX 办理经营范围变更登记"}]

for step in range(8):  # 步数上限,防止失控循环
    resp = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=messages,
        tools=TOOLS,
        tool_choice="auto",
    )
    msg = resp.choices[0].message
    if not msg.tool_calls:
        break  # 没有工具调用,链路结束
    messages.append(msg)  # 把 assistant 的 tool_calls 放回上下文
    for tc in msg.tool_calls:
        result = call_tool(tc.function.name, json.loads(tc.function.arguments))
        messages.append({
            "role": "tool",
            "tool_call_id": tc.id,
            "content": json.dumps(result, ensure_ascii=False),
        })
        print(f"[{step}] 调用 {tc.function.name} -> {result}")

print(messages[-1].content)  # 最终聚合结果

这段代码的关键在循环里:assistant 的 tool_calls 与工具返回按 tool_call_id 一一对应放回上下文,模型才能基于真实执行结果决定下一步。对本地开源模型,把同样的循环跑在 KOPA-Bench 任务上,就能量化每一步的失效率。

八、请求流与调用链

把上面的例子画成调用链:

任务: 办理企业变更登记


工具1: 查询企业登记信息(信用代码)
  │  → 返回: 登记状态 / 法人 / 经营范围

工具2: 核验材料完整度(登记信息)
  │  → 返回: 缺失项列表

工具3: 提交变更申请(补齐后的变更项)
  │  → 返回: 受理单号

工具4: 查询办理进度(受理单号)
  │  → 返回: 办结

结果聚合 → 生成办理摘要

每一步的箭头上都带着「上一步的真实返回」,这就是 execution-grounded 的含义——模型决策始终锚定在执行结果上,而不是记忆里的模板。

九、成本与风险提示

多步调用最容易被忽略的是 token 放大效应。每一步都把历史工具返回带回上下文,调用链越长,每次请求的输入 token 越多,总成本近似随步数线性增长。三个计费优化方向:

另一个容易踩的坑是让模型直接吞掉整份工具返回再决定下一步,几轮下来上下文里全是噪音,效果和成本双输。正确的做法是先把返回裁剪成摘要再放回消息队列。

风险侧有四件事要盯:真实 API 要限流,防止 Agent 循环调用打爆配额;工具返回可能带敏感字段,输出前要过滤;全链路写审计日志,每步可追溯;本地模型要设兜底规则,连续失败 N 次必须停。

十、检查清单

上线前逐项过一遍:

总结

这一期聊了三件事:数据主权约束把本地开源 LLM Agent 推上台前,而多步工具调用是开源模型最真实的短板;KOPA-Bench 用 145 个真实任务把这个差距量化,EDGE 用 execution-grounded 数据合成给出补强路径;落到接入层面,合规网关 + 步数受限的 function calling 循环 + 全链路审计,是数据主权场景的标准姿势。能力落差是缺口,也是机会——谁能把开源模型的多步调用补起来,谁就拿下 Agent 落地的下一批场景。4sapi 会持续跟进这类基准与数据方法,把可落地的接入经验整理出来。欢迎在评论区发表想法/聊聊。

标签:多步工具调用数据主权KOPA-Bench本地部署Function Calling

推荐阅读

探索更多前沿洞察与行业干货。