给 agent 写工具,和给人写 API 不一样
写过几个 MCP server 之后,最深的体会是:给 agent 的工具,设计原则和给人用的 SDK 几乎相反。
工具描述是提示词,不是文档
人看 API 文档会跳着读,看到参数名大概就懂了。模型不会——它只有你写的那段描述。所以描述里要写的不是「这个函数做什么」,而是「什么时候该调它、什么时候不该」。
我给一个 PE 分析工具写的描述从「解析 PE 文件结构」改成「当你拿到 .exe/.dll 且需要知道它的节表、导入表或是否加壳时使用;只做静态分析,不执行文件」,误调用率立刻降下来了。反触发条件比正向描述更重要。
错误信息要让 agent 能自己救回来
人看到 Invalid argument 会去翻文档。agent 只会重试,或者放弃。
所以错误返回里必须带下一步:参数错了就写清楚哪个参数、期望什么格式、给一个正确示例;前置条件没满足就写清楚该先调哪个工具。把错误当成一次微型提示词来写,成功率的差别很明显。
粒度:太细比太粗更糟
早期我把一个分析流程拆成七八个工具,想着组合更灵活。实际结果是模型经常漏掉中间某一步,或者顺序搞反。
后来合并成两三个「完成一件事」的工具,内部把流程走完,返回结构化结果。灵活性是给人的价值,确定性才是给 agent 的价值。
会话状态要显式
有状态的工具(比如需要先登录、再操作)很容易让 agent 迷路,因为它不记得自己处在哪一步。解决办法是每次返回里都带上当前状态摘要,让下一轮的上下文里始终有这个信息,而不是指望模型自己记住。