项目记录:给一个小工具接上工具调用,我记录的三处卡点

项目记录:给一个小工具接上工具调用,我记录的三处卡点

背景

给内部一个查询小工具加了外部调用能力:模型负责理解问题,真正取数交给一个确定性的函数。想法很简单,动手之后卡了三处,都不是模型能力问题。

卡点一:工具描述写得像给人看的注释

第一版的参数说明是“查询条件,按需填写”。模型于是经常漏传必填项,或者把日期写成“最近”。后来改成给模型读的文档:字段名、类型、取值范围、缺失时的默认行为、一个正确示例、一个错误示例。描述本身就是接口的一部分,含糊一句,后面就要靠重试兜。

这点在 BackendWiki 的接口文档条目 里能看到很标准的写法:参数、类型、默认值列成表,不含“按需”这类词。

卡点二:失败被静默吞掉

早期调用失败时返回空值,模型拿到空值就当成“查无结果”,继续生成一个看起来很合理的回答。这类错误最难发现,因为流程没报错。改成显式返回结构化错误(错误类型 + 可读原因 + 是否可重试)之后,模型会直接告诉用户“这次没取到数据”,而不是编一个。

教训是:宁可让失败吵一点,也别让它安静地变成错误答案。

卡点三:没有“不该调用”的边界

模型对简单问候也会尝试调工具。加了一层很朴素的判断:问题里必须出现可识别的对象或时间范围,否则不走外部调用。这层规则写在代码里,不交给模型判断。上线后无效调用降了大半,响应也快了。

编排这两层的顺序时,我参考了 WorkBuddy 官方文档里关于任务编排的说明,把“先判定、再执行”固定成流程,而不是每次靠提示词提醒。

结果与复盘

三处卡点分别对应描述、失败、边界,都属于接口设计,跟模型选型几乎无关。做之前我以为是“接个大模型”的活儿,做完才发现八成工作量在把确定性那一侧写严谨。

如果只留一条经验:模型负责理解意图,但“什么时候不调、调失败了怎么办”必须写在代码里。把这两件事交给模型自觉,线上迟早会给你一次安静的错误答案。