Peri Code 的工具分层——LLM 面对 50 个工具时会停止调用工具

Peri Code 的工具分层------LLM 面对 50 个工具时会停止调用工具

Peri Code --- 用 Rust 写的开源 Coding Agent,兼容 Claude Code 生态。curl -fsSL https://raw.githubusercontent.com/konghayao/peri/main/scripts/install.sh | bash

接入 MCP 之后,Peri Code 的行为开始变奇怪。

工具列表膨胀到 50 个出头,DeepSeek、GLM、Qwen 的 tool 调用命中率明显下降。不是选错了工具------是完全不调用工具,直接凭记忆回答,Bash 不执行,文件不读写,该搜索的不搜索。工具越多,LLM 越懒。这不是某个模型的特例,三个不同提供商都复现了。

Peri Code 的答案是只给 LLM 看 14 个工具,剩下的按需发现、代理执行。

工具列表越长,命中率越低

这个结论有点反直觉,但可以解释。

LLM 做工具调用本质上是在所有选项里挑一个最合适的。选项越多,「不调用」也是一个合理的选择,而且是回避风险最安全的选择。50 个工具摆在那里,模型好像在一张巨大的菜单面前选择直接背菜单,而不是点菜。

还有一个更硬的问题是缓存。工具列表是每轮 API 请求的一部分,也是 Prompt Cache 前缀的组成部分。50 个工具的完整 schema 大概要吃掉上万 token,如果工具列表每轮内容不一致,缓存前缀就断了,所有命中全部失效,这万 token 每次都要重新传输。一个中等规模的 MCP 服务器接进来,工具列表动辄多出十几二十个,而且连接状态可能在会话中变化------缓存根本稳不住。

工具列表不应该无限膨胀,而且膨胀本身就是在破坏系统。

固定的 12 个核心工具

一个 Coding Agent 真正高频用到的工具并不多。文件读写 6 个(Read、Write、Edit、Glob、Grep、folder_operations),执行 1 个(Bash),Web 2 个(WebFetch、WebSearch),交互 2 个(Agent、AskUserQuestion),管理 1 个(TodoWrite)------总共 12 个,覆盖编码场景的绝大多数需求。

这 12 个工具始终对 LLM 可见,每轮请求都在工具列表里,顺序固定,缓存前缀稳定。

剩下的是长尾------Cron 定时任务、各种 MCP 外部服务(Slack、GitHub、Notion 等)、LSP 工具等。一次会话可能只用其中一个,也可能一个都不用。这些工具不该出现在工具列表里,但不能就此消失,需要能找到和执行它们。

这就是另外 2 个元工具的职责------SearchExtraToolsExecuteExtraTool

Agent 是怎么知道要填什么参数的

这是这套方案里最关键的一环,值得展开说清楚。

当 Agent 需要调用一个不在工具列表里的能力时,整个流程分两步走。

第一步是搜索。 Agent 调用 SearchExtraTools,传入一段自然语言描述,比如「发送 Slack 消息」。搜索引擎在所有延迟工具里检索,返回匹配度最高的几个结果。但这里的关键是------返回的不只是工具名,而是完整的工具定义,包括这个工具接受哪些参数、每个参数是什么类型、哪些是必填、每个参数的含义是什么。Agent 拿到的信息和这个工具「挂在工具列表里」时完全一样。

这就解决了「怎么知道填什么」的问题。Agent 不是靠猜,是读到了工具的完整规格书之后再决定怎么填的。如果搜到的工具不是它想要的,或者参数不够用,它可以继续搜索其他工具,或者直接告诉用户它没找到合适的。

第二步是执行。 确认了要调用哪个工具、参数是什么,Agent 调用 ExecuteExtraTool,把工具名和填好的参数打包传过去。框架在内部注册表里找到对应工具,透传参数执行,把结果原样返回给 Agent。整个过程 Agent 只需要两次工具调用,从外部看就是「搜索 + 执行」,比直接调用多一步,但信息是完整的。

这个设计有一个很重要的性质------它不依赖 Agent 事先知道工具的存在。Agent 只需要知道自己想做什么,搜索会负责把候选项找出来,工具定义会负责告诉 Agent 怎么用。

为什么不动态注册

搜到工具之后,把它动态加到 LLM 的工具列表里不就省事了,下次直接调用?

不行,原因还是缓存。工具列表是 Prompt Cache 前缀的一部分,这一轮 14 个工具,下一轮变成 15 个,前缀就断了,之前积累的缓存命中全部失效。代理执行多一次工具调用,换来的是工具列表永远稳定在 14 个,缓存前缀从不变动。这个交换是值得的。

MCP 服务器后续连接时,新工具会加入搜索索引,但不会出现在 LLM 的工具列表里。MCP 工具也不会出现在会话开始时注入的工具摘要里,因为 MCP 连接状态可能在会话中途变化,注入进去反而会让系统提示词不稳定,同样破坏缓存。

这套框架天然支持动态工具

延迟加载的架构有一个附带的好处------工具的注册和 LLM 的工具列表完全解耦。

Peri Code 的工具注册表是一张运行时可写的全局表。中间件在启动时往里注册工具,MCP 服务器连接时往里加工具,后续如果支持插件自定义工具,也是往同一张表里注册。工具进了注册表,搜索索引会自动更新,Agent 下次搜索就能找到它------全程不需要重启,不需要改工具列表,也不需要通知 LLM 有新东西进来了。

这意味着后续要支持用户自定义工具、工作流节点、甚至让 Agent 自己生成工具并注册,都可以建在同一套机制上------注册进来,能搜到,能执行,就完成了接入。LLM 侧看到的工具列表永远是那 14 个,不管后端挂了多少扩展。

工具少,LLM 反而更敢用

接入 MCP 之后,Peri Code 的工具总数没变,但 LLM 每轮看到的还是 14 个固定的工具。tool_choice 命中率回来了。

这件事有点像工作台整理------工具全摆出来,每次要找什么都要在一堆东西里翻,反而什么都不想动;工作台上只放常用的几件,需要特殊工具的时候去工具箱里拿,效率反而更高。

工具少不是功能少,是决策空间干净。

项目地址:github.com/konghayao/p...

相关推荐
装不满的克莱因瓶2 小时前
了解 LangChain 中的 LLM 与 ChatModel 的差异
人工智能·python·ai·langchain·llm·agent·chatmodel
黑马师兄3 小时前
RAG混合检索深度解析:让AI真正找到你要的内容
java·人工智能·ai·agent·rag·ai-native
阿里云云原生3 小时前
Agentic AICon【智能体基础设施与 AgentOps 专场】精彩回顾 & PPT 下载
agent
货拉拉技术4 小时前
面向 Agent Skill 的 CLI/SSO 鉴权体系:安全、无感、可追溯
前端·agent
小马哥讲AI4 小时前
给 Agent 选记忆引擎:我为什么选了 Hindsight
agent
小七-七牛开发者5 小时前
本地模型为什么能跑起来?从 llama.cpp 量化说起
agent·llama·模型部署·ollama·本地模型
后端小肥肠5 小时前
不会做视频的我,用 Codex 跑通口播 + 自动剪辑,获客 20+
人工智能·aigc·agent
Flynt6 小时前
LangGraph多Agent踩坑实录:不是每个Agent都需要大模型
agent
搬砖的码农6 小时前
造一个 Agent 运行时 #01:我决定开干,顺便把坑都写下来
前端·agent·ai编程