设计参数修复 Pipeline 需要注意什么

QVeris · 技术实践
背景
之前我们做过一轮工具调用失败分析,重点解决的是一个基础问题:Agent调用工具失败后,能不能根据失败日志判断原因,并给出更合理的参数修复建议。
这件事很有价值,因为真实世界里的工具调用失败,并不总是"工具坏了"或者"用户用错了"。很多时候,用户意图是对的,工具也是可用的,只是模型生成的参数没有完全对齐 provider 的要求。
比如股票行情工具里,用户想查一组股票行情,这个意图很清楚。但工具可能要求:多个股票代码必须是英文逗号分隔的字符串,不能是 list;
股票代码要带 .SH / .SZ / .BJ 后缀;指标字段只能使用工具定义好的枚举值,不能随便传中文指标名。
围绕这个问题,我们设计了一套参数修复 pipeline。它会针对不同工具整理失败记录、总结工具专属经验,并在修复参数时尽量同时做到两件事:一是让参数符合工具真实可执行的 schema,二是尽可能保留用户原始意图。
也就是说,这套 pipeline 不只是让模型解释"为什么失败",而是进一步把工具经验总结、参数修复和意图对齐串成一个可验证的流程。
模型会解释错误,但解释不等于修复成功
只让模型分析失败原因,然后输出一个建议参数,听起来已经不错了。但在真实工具调用里,这还不够。
有些建议看起来合理,实际调用会失败。比如在实时行情工具里,模型可能会建议把 indicators 改成 basic。这个词看起来像是一个更基础、更安全的指标集合,但真实调用后仍然可能返回 API error: no data.说明问题在indicators以外。
有些建议能调用成功,但已经偏离了用户原始意图。比如用户原本想查境外指数,如果模型把它替换成 A 股指数,工具也许能成功返回数据,但这不应该算作一次高质量修复。
还有些建议会删掉用户原始条件。比如用户给了一个复杂选股策略,模型为了提高成功率,把条件大幅缩短。这样可能能命中结果,但也可能已经丢掉了用户真正关心的筛选逻辑。
这说明,Agent Reliability 不能只靠模型自信地解释,还需要真实工具调用结果来校验。
我们做了什么
这次我们把工具调用修复流程整理成了一套 pipeline。
它的大致流程是:
1.读取真实失败工具调用记录。
2.提取工具 ID、原始参数、错误信息、状态码、parameter help 等上下文。
3.调用 LLM 分析失败原因。
4.对每条失败记录生成最多 3 个候选修复参数。
5.把每个候选参数都拿去调用真实工具执行接口。
6.记录每个候选的成功、失败、reason code、耗时、成本和返回结果。
7.再根据真实 recall 结果,总结哪些规则值得写回工具 prompt。
为什么要生成多个候选
单候选的问题是风险太高。模型只给一个答案时,我们很难判断它是保真修复、轻度改写,还是兜底替换。
所以现在我们要求每条失败 case 尽量生成 3 类候选:
- 第一类是最保真的修复。它只改字段名、类型、格式、后缀、枚举值这类明确错误,尽量不改变用户原始意图。
- 第二类是轻度改写。它会保留主要意图,但把表达方式改成工具更容易理解的形式。
- 第三类是兜底放宽。它用于原始意图很难直接恢复的情况,但必须明确说明这是语义放宽,不能把它当成完整保真修复。
这样做之后,我们不只是得到一个"答案",而是得到一个可以比较的候选集合。真实工具 recall 会告诉我们:哪个候选真的能跑,哪个候选虽然看起来合理但会失败,哪个候选虽然成功但已经放宽了语义。
真实 case:行情工具的参数修复
以一个实时行情工具为例,我们看到了一类很典型的问题:indicators 字段不适配。
有的原始请求会传:
indicators=f2,f3,f8,f10,...
这些字段很像东方财富的 F 参数表,但并不适用于当前工具。
还有的请求会传:
indicators=最新价,涨跌额,涨跌幅,...
这类中文指标名从用户角度很好理解,但工具本身并不支持这种自定义指标列表。
模型分析后给出的更稳定修复是:保留原始 codes,把 indicators 统一改成 common,真实 recall 也验证了这一点。
另一个典型问题是股票代码缺少后缀。
比如原始输入是:
codes=301531,603407,...,920012,002902,301696,920200
这种写法对人来说很容易理解,但工具需要明确市场后缀。修复时不能机械地全部补 .SH 或 .SZ,而要按代码段判断:301/300/001 通常补 .SZ,603/688 补 .SH,920xxx 要优先补 .BJ。
真实重试后,补齐后缀并把 indicators 改成 common 的候选可以成功返回行情数据。
这类 case 说明,结构化工具的修复重点是"是严格对齐工具 schema:字段名、字段类型、枚举值、代码后缀,每一个都需要照顾到。
真实 case:选股工具的自然语言改写
另一个自然语言选股工具的问题不太一样。它的失败往往不是字段格式问题,而是表达方式问题。
比如有一个原始输入是:
120分钟均线金叉MA5MA34
这个表达对懂技术分析的人来说能看懂,但对工具来说偏短、偏公式化,直接调用容易失败或返回空结果。
我们把它改成:
120分钟K线 MA5上穿MA34 均线金叉
并指定 searchtype=stock,真实调用后成功。
这说明,对自然语言选股工具来说,不一定要把条件翻译成更复杂的公式。相反,把公式化表达改成工具更容易识别的中文描述,反而更有效。
还有一个更复杂的策略:用户想筛选"近 1 个月涨停或倍量、长期横盘或上涨初期、长上影线试探前高、成交量放大、底部承接强"的股票。
在测试中,我们没有继续把条件堆成长句,而是保留其中最核心的形态特征,改成一个更短的查询:
- 涨停回调 长上影线 试探前高 成交量放大
这个版本成功返回了可解释的结果,命中的条件包括:曾涨停、长上影线、最高价创新高、成交量环比增长。
这类结果虽然不一定覆盖原始策略里的每一个细节,但相比直接返回空结果,它至少保留了用户最关心的核心形态,并给出了可以继续判断的候选结果。对用户来说,这通常比简单告诉他"没有结果"更有价值。
一组小规模数据
我们用前 20 条原始失败记录做了一轮测试。
由于每条记录会生成 2 到 3 个候选修复参数,最终一共产生了 51 次真实工具 recall 调用。其中 48 次成功,3 次失败,候选级成功率为 94.12%。
从耗时看,主要时间花在模型分析阶段,真实工具 recall 本身的额外开销相对可控。
这个结果说明,在已有分析流程上增加真实 recall,可以帮助我们判断修复方案到底能不能跑通。
更重要的是,它能帮助我们筛掉两类不适合直接沉淀为规则的候选:一种是看起来合理但实际失败的候选,比如某些 basic 指标;另一种是调用成功但语义已经放宽的候选,比如把原始查询目标换成更容易成功的示例参数。
成功率不是唯一指标
这轮实验最大的收获,不是某个 case 成功了,而是我们更清楚地看到了"调用成功"和"修复正确"之间的差别。
一个候选参数成功返回结果,并不一定说明它是好的修复。我们还需要看:
-
是否保留了用户原始标的
-
是否保留了用户原始筛选条件
-
是否只是换成了样例参数
-
是否删除了关键约束
-
是否把精确主题放宽成了上位概念
结尾
一个更可靠的 Agent,需要在工具调用之外具备持续修复的能力:看懂失败轨迹,给出参数调整方案,再通过真实工具执行结果来验证方案是否有效。
我们正在做的,就是把工具调用、失败反馈、参数修复、真实重试和经验更新串成一个闭环。当这些过程能够被记录、总结和迭代时,Agent 对工具的使用就会从一次次孤立调用,逐步变成一套可以积累经验的工程流程。
**
**
**
**
**
**
