ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Agent 开发降本增效:Skills、子代理与工具调用的系统性瘦身实践

2026/9/23 22:04:57 拓冰建站 浏览量
Agent 开发降本增效:Skills、子代理与工具调用的系统性瘦身实践 1. 别急着堆功能Agent 复杂度失控的真实代价做 Agent 开发的人大概都有过这么一个阶段一开始只想让它帮忙查个资料、写段代码后来觉得“再加个联网搜索吧”“再加个长期记忆吧”“再加个自动反思循环吧”功能列表越拉越长Prompt 越写越厚工具注册表从三五个膨胀到二三十个。结果呢跑一次任务烧掉的额度比预期多出两三倍响应速度肉眼可见地变慢最要命的是——成功率反而下降了。这不是个别现象。我在过去大半年里先后搭过七八个不同形态的 Agent 项目从最简单的单轮问答到带子代理编排的复杂工作流都试过。踩坑踩得多了慢慢总结出一条反直觉的经验Agent 的能力上限往往不取决于你给它加了多少东西而取决于你砍掉了多少不必要的东西。标题里说的“额度提高至少 20%”不是靠什么黑科技而是靠对 Skills、子代理和工具调用这三层做系统性的瘦身和优化。这篇文章面向的是已经在用 Agent 干活、但感觉“越用越贵、越用越慢”的开发者。如果你还在纠结要不要入坑这里的内容也能帮你从一开始就避开那些让复杂度失控的陷阱。核心思路就一句话把复杂度花在刀刃上别为用不上的能力买单。2. 先搞清楚钱花在哪Agent 额度消耗的三大黑洞2.1 Token 消耗的构成拆解很多人以为 Agent 贵是因为模型本身贵其实模型单价只是其中一个变量。真正吃掉额度的是上下文膨胀。一个典型的 Agent 单次任务Token 消耗大致分四块系统提示词角色设定、行为规范、输出格式要求通常 500 到 2000 Token 不等工具定义每个工具的 name、description、参数 schema一个工具少则 80 Token多则 300 Token对话历史每一轮的工具调用结果都会追加到上下文里越滚越大实际推理模型真正用来“思考”的部分我实测过一个案例一个注册了 18 个工具的 Agent光工具定义就占了系统提示词的 60% 以上。更离谱的是其中 12 个工具在整个任务流程里压根没被调用过。这意味着每次请求都在为这些“僵尸工具”付费。2.2 工具数量与调用准确率的负相关这里有个很多人没意识到的规律工具越多模型选错工具的概率越高。当工具数量超过 10 个以后模型在工具选择上的准确率会明显下滑尤其是当几个工具的功能描述存在语义重叠时。比如你同时注册了search_web和query_knowledge_base模型经常会在该查知识库的时候去搜网页。选错工具的直接后果是多一轮无效调用、多一轮错误结果、多一轮纠正对话。每一轮都是真金白银。我做过对比测试把工具从 15 个精简到 6 个之后同一个任务的平均调用轮次从 7.3 轮降到了 4.1 轮额度消耗直接少了将近一半。2.3 子代理编排的隐性开销子代理Sub-agent是个好东西能把复杂任务拆解给专门的执行单元。但它的开销是隐性的主代理需要生成子代理的调用指令、子代理需要独立的系统提示词和工具集、子代理的结果需要回传给主代理做汇总。这一来一回Token 消耗是单代理模式的 2 到 3 倍。更麻烦的是如果子代理的职责划分不清晰会出现“主代理不知道该派谁去干”的情况导致反复试探性调用。我见过最夸张的一个案例一个任务触发了 5 个子代理其中 3 个返回的结果高度重复纯粹是浪费。提示在决定引入子代理之前先问自己一个问题——这个子任务是否真的需要独立的上下文和工具集如果只是简单的步骤拆分用 Skills 或者直接在主代理里用条件分支处理成本会低得多。3. Skills 层优化让能力按需加载而不是常驻内存3.1 Skills 的本质是什么Skills 这个概念最近很火但很多人对它的理解有偏差。Skills 不是插件不是工具而是一种按需注入的能力描述。它的核心价值在于把“怎么做某件事”的知识从系统提示词里剥离出来只在需要的时候才加载进上下文。举个例子。假设你的 Agent 需要支持“生成周报”这个功能。传统做法是在系统提示词里写一大段周报格式规范、注意事项、示例模板大概 800 Token每次请求都带着。用 Skills 的做法是系统提示词里只留一句“当用户需要生成周报时加载 weekly-report skill”实际那 800 Token 的详细内容只在用户真的要求生成周报时才注入。这个差异在单次任务里可能不明显但 Agent 通常是多轮对话每轮都省 800 Token十轮下来就是 8000 Token 的差距。3.2 Skills 的粒度怎么切切 Skills 粒度是个手艺活。切得太粗起不到按需加载的效果切得太细管理成本高而且模型可能不知道该加载哪个。我的经验是按“用户意图”切而不是按“功能模块”切。比如“代码审查”这个场景不要切成check-syntax、check-style、check-security三个 Skill而是合成一个code-reviewSkill里面用条件分支处理不同检查项。因为用户说“帮我审查这段代码”的时候意图是一个整体拆成三个 Skill 反而会让模型困惑。反过来如果两个 Skill 的使用场景完全不重叠比如generate-chart和write-sql那就应该分开。判断标准很简单如果用户在一个任务里大概率会同时用到它们就合并如果基本不会同时出现就分开。3.3 Skills 的加载策略与缓存Skills 加载有两种策略预加载和懒加载。预加载是在对话开始时就把所有 Skill 的摘要注入上下文模型知道有哪些能力可用但详细内容不展开。懒加载是连摘要都不给模型通过一个load_skill工具来动态获取。我推荐的做法是摘要预加载 详情懒加载。摘要控制在每个 Skill 20 Token 以内只写“Skill 名称 一句话用途”。这样即使有 20 个 Skill摘要总共也就 400 Token模型能知道有什么能力可用但不会占用太多上下文。当模型判断需要某个 Skill 时再通过工具调用把详细内容拉进来。这里有个实操细节Skill 的详细内容加载后要在后续轮次里及时清理。很多框架默认会把加载过的 Skill 内容一直留在上下文里这是浪费。如果当前任务已经完成了 Skill 相关的部分应该主动把它从上下文中移除。具体实现方式取决于你用的框架但思路是通用的。3.4 一个真实的 Skills 瘦身案例我手上有一个做技术文档问答的 Agent最初的设计是把所有文档格式规范、术语表、常见问题都写在一个巨大的系统提示词里总共约 3500 Token。优化后拆成了 4 个 SkillSkill 名称用途摘要 Token详情 Tokendoc-format文档格式规范18620terminology术语一致性检查15480faq-handler常见问题应答20750citation引用格式处理16390系统提示词从 3500 Token 降到了 900 Token 左右含 Skill 摘要。在实际使用中平均每个任务只会触发 1 到 2 个 Skill也就是说平均每轮请求的上下文比原来少了 2000 Token 以上。按我们当时的调用量算月度额度消耗下降了约 28%。4. 子代理层优化什么时候该拆什么时候不该拆4.1 子代理的适用边界子代理不是越多越好它有明确的适用边界。我总结下来只有同时满足以下两个条件时才值得引入子代理子任务需要独立的工具集且这些工具在主代理中注册会造成干扰子任务需要独立的上下文窗口主代理的上下文已经接近容量上限如果只满足其中一个优先考虑用 Skills 或条件分支解决。两个都不满足那就老老实实在主代理里顺序执行。举个反例。我之前见过一个项目把“搜索资料”和“总结资料”拆成了两个子代理。但实际上这两个步骤用的是同一套工具上下文也可以共享拆开之后反而多了一轮结果传递的开销。后来合并成一个代理额度消耗直接降了 35%。4.2 子代理的上下文隔离策略如果确实需要子代理上下文隔离是必须做好的。核心原则是子代理只接收完成任务所必需的最小上下文不要把它当成主代理的“克隆”。具体做法是主代理在调用子代理时只传递任务描述和必要的输入数据不传递完整的对话历史。子代理执行完毕后只返回结果摘要不返回完整的执行过程。这样能把子代理的 Token 消耗控制在主代理的 30% 到 50% 之间。注意有些框架默认会把主代理的完整上下文传给子代理这是额度杀手。如果你用的框架有这个行为一定要在配置里关掉或者手动构造精简的调用参数。4.3 子代理的退出与回收子代理执行完毕后要及时回收。我遇到过一个问题子代理执行完成后它的上下文没有被清理导致后续主代理的请求里还带着子代理的残留信息。这不仅浪费 Token还可能干扰主代理的判断。正确的做法是子代理返回结果后主代理只保留结果摘要子代理的完整上下文立即释放。如果你的框架支持显式的子代理销毁操作一定要在结果返回后调用。如果不支持至少要在构造下一次请求时确保不包含子代理的历史消息。4.4 子代理编排的常见反模式反模式问题正确做法为每个步骤创建一个子代理开销成倍增加结果传递损耗大合并同类步骤只在工具集冲突时拆分子代理继承主代理全部工具工具冗余选择准确率下降子代理只注册自己需要的工具子代理返回完整执行日志上下文膨胀主代理难以消化只返回结构化结果摘要子代理嵌套子代理调用链过长错误排查困难嵌套不超过两层优先扁平化5. 工具层优化少而精的工具集才是王道5.1 工具定义的瘦身技巧工具定义是 Token 消耗的大头但很多人写工具定义的时候特别“大方”。一个search工具的描述能写 200 字参数 schema 里每个字段都配一段说明。这些在开发阶段看着很清晰但运行时全是成本。我的做法是工具描述控制在 50 Token 以内参数说明能省则省。模型对工具的理解主要靠名称和参数名描述只是辅助。比如{ name: search_docs, description: 搜索技术文档库返回相关段落, parameters: { query: { type: string, description: 搜索关键词 }, limit: { type: integer, description: 返回条数默认5 } } }这个定义总共不到 60 Token但模型完全能理解怎么用。相比之下我见过把description写成一段小作文的光一个工具就 300 Token纯属浪费。5.2 工具合并与抽象多个功能相似的工具应该合并。比如你有get_user_name、get_user_email、get_user_role三个工具完全可以合并成一个get_user_info通过参数指定要获取的字段。这样工具数量从 3 个变成 1 个Token 消耗减少模型选择也更简单。合并的原则是如果两个工具的参数结构高度相似只是操作对象或返回字段不同就考虑合并。但要注意合并后的工具不能太“万能”否则模型反而不知道怎么用。一个工具最好只做一类事情只是把同类事情的不同变体收进来。5.3 工具调用的结果压缩工具返回的结果也是 Token 消耗的重要来源。很多工具返回的是原始数据比如一个搜索工具返回 10 条结果每条 200 字一次调用就是 2000 Token。但模型真正需要的可能只是每条结果的一句话摘要。解决办法是在工具层面做结果压缩。具体来说搜索结果只返回标题 摘要 链接不返回全文数据库查询只返回需要的字段不返回整行API 调用结果做一层过滤去掉模型不需要的元数据我实测过一个搜索工具做结果压缩后单次调用的返回 Token 从 1800 降到了 400 左右而且模型的使用体验没有明显下降。5.4 工具调用的缓存与去重同一个任务里模型可能会重复调用同一个工具、传相同的参数。这种情况在复杂任务里很常见尤其是当模型“忘记”自己已经查过某个信息时。解决办法是在工具层加一层缓存。具体实现是对工具名 参数做哈希如果命中缓存就直接返回上次的结果不再实际执行。这不仅能省 Token还能省工具本身的调用成本比如搜索 API 的调用次数。提示缓存的有效期要根据工具的性质来定。查询类工具可以缓存整个会话周期但涉及实时数据的工具比如股票价格就不适合缓存或者只缓存很短时间。6. 实操从零搭建一个低复杂度高额度的 Agent6.1 整体架构设计说了这么多理论下面用一个具体例子串起来。假设我们要搭一个“技术博客助手”Agent功能包括查资料、写草稿、检查格式、生成配图建议。优化前的设计常见做法系统提示词 2500 Token包含所有格式规范和写作要求注册 12 个工具搜索、网页抓取、文件读写、格式检查、图片搜索、图片生成、代码高亮、链接检查、字数统计、敏感词过滤、标题生成、摘要生成2 个子代理一个负责查资料一个负责写草稿优化后的设计系统提示词 600 Token只保留核心角色设定和 Skill 索引注册 5 个工具search合并了搜索和抓取、write_file、check_format合并了格式检查和字数统计、suggest_image、load_skill1 个子代理只负责资料搜集因为它的工具集搜索和主代理的其他工具差异较大4 个 Skillsblog-structure、code-highlight、seo-check、image-prompt6.2 关键配置与参数系统提示词的核心部分大概长这样你是一个技术博客助手。你可以使用以下 Skills - blog-structure: 博客结构规范 - code-highlight: 代码高亮格式 - seo-check: SEO 检查清单 - image-prompt: 配图提示词生成 当任务涉及以上领域时使用 load_skill 工具加载详细规范。工具定义方面search工具合并了原来的搜索和抓取{ name: search, description: 搜索技术资料可选抓取全文, parameters: { query: { type: string }, fetch_full: { type: boolean, default: false } } }子代理的调用参数只传任务描述不传对话历史{ task: 搜集关于 Agent 工具优化的技术资料, max_results: 5, return_format: summary }6.3 优化前后的额度对比我用同一个任务集20 个典型的博客写作任务做了对比测试结果如下指标优化前优化后变化平均每任务 Token 消耗18,50011,200-39%平均工具调用轮次8.24.6-44%任务成功率82%91%9%平均响应时间23s14s-39%额度消耗下降了 39%远超标题说的 20%。而且成功率还提升了因为工具少了、上下文干净了模型的选择更准确。6.4 落地步骤清单如果你想在自己的项目里复现这套优化可以按以下步骤来盘点现有工具列出所有注册的工具统计每个工具在过去 100 次任务中的调用次数。调用次数为 0 或极低的直接下线。合并同类工具把参数结构相似的工具合并目标是把工具数量控制在 8 个以内。瘦身工具定义每个工具的 description 控制在 50 Token 以内参数说明只保留必要的。抽取 Skills把系统提示词里的大段规范、模板、示例抽成 Skill系统提示词只留索引。审查子代理检查每个子代理是否真的需要独立上下文和工具集不需要的合并回主代理。加缓存层对查询类工具加结果缓存避免重复调用。做 A/B 测试优化前后各跑 20 个任务对比 Token 消耗和成功率。7. 常见问题与排查技巧实录7.1 工具调用失败的高频原因现象可能原因排查方法模型不调用工具直接回答工具描述不清晰或系统提示词没强调要用工具检查工具 description 是否说明了“什么时候用”调用了错误的工具工具功能重叠描述语义相近合并重叠工具或在描述里明确区分场景工具参数传错参数 schema 太复杂或参数名不直观简化参数结构用更直白的参数名工具调用后不继续返回结果格式模型无法解析统一返回 JSON 格式加明确的字段说明重复调用同一工具模型“忘记”已调用过或缓存未生效加缓存层或在系统提示词里提醒“先检查已有结果”7.2 额度突然飙升的排查思路如果你发现某天额度消耗突然涨了按以下顺序排查检查是否有新工具上线新工具的定义和调用可能带来额外开销检查是否有 Skill 加载后未释放加载的 Skill 内容如果一直留在上下文里每轮都在烧钱检查子代理是否失控子代理是否被频繁触发返回结果是否过大检查对话历史是否过长是否缺少历史截断机制导致上下文无限增长检查是否有异常循环模型是否陷入了“调用-失败-重试”的死循环7.3 独家避坑技巧技巧一给工具加“使用频率”标记。在工具描述里加一句“此工具使用频率较低请确认真的需要时再调用”。这能有效减少模型的试探性调用。技巧二用“工具分组”代替“工具全量注册”。如果工具确实很多可以按场景分组每组只在特定意图下才注册。比如“写作模式”下只注册写作相关工具“分析模式”下只注册分析工具。技巧三定期做“工具审计”。每个月跑一次工具调用统计把连续两周零调用的工具下线。工具集应该像花园一样定期修剪而不是只种不剪。技巧四子代理返回结果用结构化格式。不要让子代理返回自然语言段落而是返回 JSON主代理解析后只取需要的字段。这样能大幅减少结果传递的 Token 消耗。技巧五系统提示词里加“节约指令”。明确告诉模型“优先使用已有信息避免重复查询”“工具返回结果足够时立即停止调用”。模型对这类指令的遵从度比想象中高。7.4 关于 Codex 等工具的 Skills 生态最近 Codex 相关的 Skills 生态发展很快社区里有很多现成的 Skill 包可以直接用。我的建议是不要一股脑全装上。每个 Skill 即使不加载详情摘要也会占用上下文。装 30 个 Skill光摘要就 600 Token 起步。正确的做法是按需安装只装当前项目真正会用到的用不到的及时卸载。另外社区 Skill 的质量参差不齐有些 Skill 的详情内容写得非常冗长加载一次就上千 Token。使用前最好先看看它的内容长度超过 800 Token 的 Skill 要考虑是否值得。8. 持续优化的节奏感Agent 优化不是一锤子买卖而是一个持续的过程。我的习惯是每两周做一次“额度复盘”看看这两周里哪些工具调用最频繁、哪些 Skill 加载次数最多、哪些子代理触发后效果不好。根据数据做调整而不是凭感觉。还有一点很重要不要为了省额度而牺牲任务质量。优化的目标是“去掉不必要的开销”而不是“把该花的钱也省掉”。如果一个工具虽然调用频率低但每次调用都解决了关键问题那就该留着。判断标准是“这个工具是否在关键路径上”而不是单纯的调用次数。我自己的项目从最初的“什么都想加”到现在的“能不加就不加”走了不少弯路。最大的体会是Agent 的复杂度应该像洋葱一样一层一层剥开每一层都有明确的存在理由。剥掉任何一层都会导致功能缺失那这层就是必要的如果剥掉之后任务照样能完成那这层从一开始就不该存在。