《读懂 Token》你给 Agent 的每个工具,每一轮都在交税 你给 Agent 的每个工具每一轮都在交一笔「看不见的税」系列第 10 篇 · 工程实战篇一句话把“MCP 工具怎么用”的啰嗦说明从每次请求都要重发的系统提示里挪到按需加载的 Skill 文件里——工具越多省得越多。前提说明这一篇是第二篇**开关 6「工具定义延迟加载」**的完整展开。上一篇我们讲了MCP 服务端怎么用「过滤—聚合—分页—缓存」四件套把返回值压薄。但省 Token 这件事是双向的你发给模型的工具说明书和模型返回给你的响应同样在烧钱。一个被严重低估的事实是——工具定义schema description在 Agent 每一轮对话里都是“固定税”。你给 Agent 配 10 个 MCP 工具每个工具的参数、字段、用法说明写得越细每一轮上下文里就要重复带一次。更糟糕的是很多开发者不仅把工具 schema 塞进去还会在系统提示里反复补一段「用这个工具时记得加 LIMIT」「返回 500 错就重试一次」「查用户表时永远带上 deleted_at IS NULL」……这些「工具用法说明」和 schema 一起每一轮都在重复计费。这一篇讲一个优雅的解法把这些重复的用法说明封装成可复用的 Skill 文件——元数据常驻细节按需加载。一、先算一笔账固定税到底多重以一个典型的数据库查询 MCP 工具为例开发者为了让 Agent 用得对通常会在工具定义里写完整的参数说明类型、必填、可选、默认值、取值范围返回值结构字段名、类型、含义8~10 条“重要提醒”加 LIMIT、用表别名、SELECT 列不要 SELECT *、时间范围过滤、错误码含义……然后在系统提示里再写一遍使用流程先看 information_schema再 COUNT 估计规模再取数据最后先总结再展示把这些全塞进工具 description 和 system prompt我用 tiktokencl100k_base实测单个工具就吃掉约 720 token再加每轮必带的用法说明约 430 token3 个工具一轮约 2,600 token、10 个工具一轮约 8,300 token——这还没算用户问题和对话历史。 关键问题工具的详细用法在 80% 的轮次里根本用不上。你这一轮问“今天天气如何”数据库查询工具那 700 多 token 的 schema 和用法完完全全是白付的钱。二、什么是 Skill把「用法说明」从每轮必带变成按需加载Skill技能不是新概念——Claude Code、Cursor、Cline 等主流 Agent 客户端都支持类似机制。本质上它是一个独立的 Markdown 文件结构大概是这样skills/ └── db-query/ ├── SKILL.md # 技能主体什么时候用、怎么用、错误怎么处理 └── references/ # 深度参考可选字段字典、示例 SQL 等而你在 Agent 的系统提示里只放所有技能的一句话元数据索引大概长这样- db-query: Query production database safely. Use when: need to look up data, inspect tables, run SQL. Load for: detailed patterns, error codes, response format.核心逻辑三段式装载层级内容何时加载典型大小L1 元数据技能名 一句话用途 触发条件每轮常驻所有技能~40 tok / 技能L2 精简 Schema工具名 核心参数 返回值概括每轮常驻所有工具~80 tok / 工具L3 SKILL.md完整用法、工作流、规则、错误处理仅在命中该技能时加载一次~800 tok / 技能L4 references/字段字典、SQL 模板、示例仅在深度需要时加载2,000 tok / 技能关键在于模型自己决定要不要加载。当它判断“这一轮需要用数据库查询”时主动读 SKILL.md不需要时那 800 字的用法说明压根不会出现在上下文里。即使在需要用到的那一轮SKILL.md 在多轮对话里也会被 Prompt Cache 命中它内容稳定不变后续轮次以1/10 的价格被读取。三、改造前后的真实对比❌ 改造前工具定义里塞一切全量常驻{name:query_database,description:Execute a SQL query against the production database. Parameters: - sql (string, required): The SQL query to execute. Must be a SELECT statement. Use parameterized queries with $1, $2 for user input. - database (string, required): Target database. Options: users, orders, products, logs, analytics. - timeout_ms (integer, optional): Query timeout in ms, default 5000, max 30000. - max_rows (integer, optional): Maximum rows to return, default 100, max 1000. Returns: JSON array of row objects with column_name: value pairs. Also returns execution_time_ms, row_count, and query_id. Important notes: 1. Always add LIMIT clause to prevent too many rows 2. For time-range queries, always filter on created_at column 3. Never use SELECT *, always explicitly list needed columns 4. When joining tables, explicitly specify table aliases 5. For large aggregations, use GROUP BY with appropriate filters 6. If query times out, try adding more specific WHERE conditions 7. Check query_id in the response; errors have error_code and error_message 8. Common error codes: E101 (timeout), E102 (syntax error), E103 (permission), E201 (too many rows) ,parameters:{...}# 完整 JSON Schema}tiktoken 实测721 token/工具加上系统提示里的用法说明 427 token3 个工具一轮 2,590 token10 个工具一轮 8,356 token。。✅ 改造后精简 Schema Skill 文件按需加载工具定义常驻压到极简{name:query_database,description:Execute SQL query. Params: sql (required), database (users|orders|products|logs|analytics), max_rows (default 100, max 1000). Returns rows execution_time_ms. See skill db-query for full usage.,parameters:{...}# 参数Schema保留这是必须的}80 token / 工具仅保留“能让模型判断何时调用它”的最小信息量。然后在skills/db-query/SKILL.md里命中时才加载# DB Query Skill ## When to use - Need to retrieve data from any production database - User asks about orders / users / products / logs / analytics ## Workflow 1. Check columns: SELECT column_name FROM information_schema.columns WHERE table_name? 2. Estimate size: SELECT COUNT(*) ... with the same WHERE clause 3. Fetch data with explicit column list, always LIMIT ## Critical rules - Always WHERE deleted_at IS NULL for user/order queries - Default time range: last 30 days unless specified otherwise - SELECT * is forbidden; list columns explicitly - Use table aliases in JOINs ## Error handling - E101 timeout: add more WHERE filters, reduce time range - E102 syntax: check quotes and parameter placeholders ($1, $2) - E201 truncated: tell user results are partial, offer to refine ## Response format - Summarize findings in 1-2 sentences first - Then show key data points - Format numbers with thousand separators780 token但只有 20% 的轮次会真正加载。按 20% 命中率加权计算3 工具场景常驻 80×3 1203 个元数据 360 tok加权均摊 360 780×20% 516 tok原 2,590省 80%10 工具场景常驻 80×10 120 920 tok加权均摊 920 780×20% 1,076 tok原 8,356省 87%⚠️ 注意10 个工具场景下只加载本轮真正要用的那 1 个 Skill其他 9 个技能的用法说明永远不会进入上下文。工具越多这个不对称优势越大。四、什么样的内容适合封装成 Skill不是所有说明都值得做成 Skill。判断标准只有一个“这段说明是不是在大部分轮次里都用不上”适合封装的典型内容类别示例为什么不常驻工作流程“先 COUNT 再 SELECT”、“先查 schema 再写 SQL”只有真正调用该工具时才需要领域规则“用户查询永远加 deleted_at IS NULL”、“订单默认查近 30 天”不调用该工具时完全无关错误处理E101/E102/E201 各自怎么处理没出错时不需要输出格式“先总结再展示数字数字带千分位”展示层细节不属于工具本身反模式清单“禁止 SELECT *”、“禁止不带 LIMIT”和规则一起下沉参数化示例防 SQL 注入的写法示例属于参考材料按需看不应该封装的内容工具名、参数名、参数类型、必填/可选——这些是模型决定“要不要调、怎么调”的最小信息必须保留在 schema 里否则它连调用都不会。五、SKILL.md 的推荐结构经过实测下面这个 6 段式结构最好用——AI 读起来快、人维护起来也清楚# Skill 名称 ## When to use 触发场景3 行以内。告诉模型什么时候该加载我——这是最重要的一节 ## Workflow 标准操作步骤编号列表3~7 步。模型按步执行 ## Critical rules 硬性规则必须遵守。每一条都是一行不要长篇大论 ## Error handling 错误码 → 应对动作。表格或列表形式 ## Response format 怎么把结果呈现给用户 ## Examples可选 1~2 个完整示例放 references/ 里更省几条写作原则面向行动。写“先 COUNT 再 SELECT”不写“COUNT 查询可以帮助估计结果集规模从而避免性能问题”800 token 以内。超过了就把细节搬到references/下SKILL.md 只放索引保持稳定。内容稳定才能命中 Prompt Cache不要放时间戳、版本号、轮次号不重复 schema。参数类型、默认值这些已经在工具 schema 里有了别再重复写一遍六、团队月度成本账按 Claude Sonnet 4 公开定价输入 $3/MTok、缓存读取 $0.3/MTok假设 50% Prompt Cache 命中率、每个开发者每天 50 轮对话、每月 22 个工作日10 工具、20 人团队从 $212/月降到 $28/月每月省 $184——看起来不多但这是纯靠“挪一下说明文字的位置”换来的不改一行工具逻辑、不牺牲任何回答质量。工具越多、团队越大数字越夸张50 工具、20 人团队每月可以省近$600。年省 7000 美元。七、落地四步走数一下跑一遍 tiktoken看你当前工具 schema 系统提示里的工具用法总共有多少 token。数字会让你吃惊。砍一遍把所有“使用流程/错误处理/输出格式/领域规则”类内容从 schema 和 system prompt 里摘出来分别写成独立的 SKILL.md。压一下工具 description 压到 100 token 以内——只保留“做什么 核心参数 一句 skill 指引”。验证一下跑 10 个典型任务看 Agent 是不是在需要时主动加载了对应 Skill、是不是没有因为信息下沉而出错。通常不会——模型对“按需读取”这件事的适应度比你以为的高得多。八、常见的三❌ 误区 1把 Skill 写成另一个 System Promptmpt**Skill 的核心是“按需”。如果你把所有 Skill 的 SKILL.md 都在启动时一次性塞进上下文那就退化成了“又一份臃肿的系统提示”省不到钱。真正的节省来自“不加载的就别加载”。❌ 误区 2Schema 全砍光精简不等于删除。参数名、类型、必填项、枚举值这些必须留在工具定义里——模型靠它们构造调用。砍掉的是“教程”和“注意事项”不是“接口定义”。❌ 误区 3一个大 Skill 解决所有问题按工具类别拆数据库查询一个、文件系统一个、HTTP 调用一个。拆得越细单次加载越小按需收益越大。一个 5000 token 的“万能 Skill”本质就是把臃肿换了个地方放。这一篇和上一篇合起来完成了 MCP 双向省 Token 的闭环上一篇解决服务端“返回太多”响应压薄这一篇解决客户端“说太多”说明书按需加载。下一篇预告MCP 双向瘦身做完之后有一个问题会浮出水面为什么我明明已经让缓存命中了账单还是没有明显下降答案往往是——缓存根本没有真正命中。提示缓存是最阴险的一类问题它不报错、不告警只是静默失效。一个时间戳、一个轮次计数器、会话中途切一次模型都可能让整段前缀作废账单打回原形。下一篇《谁在偷偷让你的提示缓存失效》——从两个真实事故日账单 $6 飙到 $20 万、一次升级让命中率从 97% 跌到 3%讲起拆解 10 个静默失效陷阱给一份 60 秒自检脚本以及可以直接贴进团队规范的“缓存友好”写法清单。