
1. 派发子 Agent 的提示词一交错KV Cache 前缀就断了最近在排查 Multi-Agent 工作流的 token 账单时我发现一个很隐蔽的问题TL 派发子 Agent 的 prompt 里稳定调度指令、工具白名单、输出格式和动态技术方案文档交错排列。这里的 Key 我走 TaoToken先到 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentprefix_intro 创建Base URL 用 https://taotoken.net/api。表面看只是 prompt 排版问题实际会让 Prompt Cache 的前缀匹配在第一个动态字段处断裂服务商每轮都要重新计算后续 token 的 K/Vinput token 被重复计费。本文只讲可复现的提示词重排把稳定指令与动态内容分离让 KV Cache 尽可能复用。我们团队的工作流是 1 个 TL 加 6 个子 Agent覆盖需求分析、方案设计、前后端并行实现、测试执行、视觉校验和代码审查。跑一个中等需求经常要经历 5 到 6 个 Wave、20 多次子 Agent 派发、数百轮工具调用。规模一上来成本就像滚雪球系统提示词、工具 Schema、工具返回、历史消息、动态文档、重复加载的 Skill全都在会话里反复计费。以前我们只知道账单高不知道高在哪后来把每轮工具调用与 token 用量上报到 AgentLens 类平台按 TraceId 和 SessionId 拆开看才发现“重复前缀”是最容易被忽视的一类消耗。更准确地说问题不是模型单价而是请求结构。LLM 每生成一个 token都要对它之前的所有 token 做注意力计算过程中产生 K 和 V 两个中间矩阵合称 KV Cache。如果本次请求的前缀和上次完全一致服务商可以直接复用之前算好的 KV 矩阵跳过重复计算只按缓存读取的低价计费。反过来只要前缀中间插入了一个动态变量后面所有内容都要重新计算。很多 Multi-Agent 工作流的 prompt 恰好就是“稳定指令 动态文档 稳定指令 动态目标”交错排列缓存命中率自然上不去。这也是为什么“稳定前缀重排”应该排在成本治理的前面。它不需要删功能不需要换模型也不需要重写整个 Agent 架构只需要把请求序列重新组织一遍稳定的放前面动态的放后面并且让同一角色的多次派发尽量共享同一段前缀。TaoToken 提供 Key 和统一 Base URL让子 Agent 调用走同一个入口但缓存能不能复用仍取决于你自己是否把前缀排稳。下面我把可复现的模板、配置和对比方法拆开讲。2. 稳定前缀重排的四个区段系统、工具、项目约束、动态任务先给结论一次子 Agent 调用最理想的顺序是“系统身份 → 工具白名单 → 项目级稳定约束 → 本次动态任务”。动态内容必须后置而且不要插在稳定区中间。如果某个字段每次派发都会变比如 wave_id、目标文件、技术方案路径、验收标准它就不应该出现在系统提示词前半段。很多人的派发 prompt 长这样你是 backend-dev 子 Agent。 技术方案文档{{design_doc_path}} 输出格式必须是 JSON。 工具白名单read_file, write_file, search_content。 项目规则Node 20pnpm目录 apps/api。 目标文件{{target_files}} 验收标准{{acceptance_criteria}}这里design_doc_path一出现后面的“输出格式”“工具白名单”“项目规则”就全部失去了前缀复用机会。正确做法是把动态字段抽到最后稳定区保持字节级一致[稳定区 A角色与边界] 你是 backend-dev 子 Agent。 只处理后端目录不修改前端、测试与视觉基线文件。 遇到不确定项时输出 BLOCKED并说明缺少的输入。 [稳定区 B工具白名单] 可用工具read_file, write_file, search_content, run_shell。 未列出的 MCP 工具不可见、不可调用。 命令统一走项目脚本不直接拼接数据库连接串。 [稳定区 C输出协议] 先输出 JSON 摘要再输出变更文件列表。 JSON 字段固定顺序status, files, tests, risks。 [稳定区 D项目约束] 技术栈版本{{pinned_versions}} 目录约定{{stable_layout}} 本地命令入口dev-env.sh 状态文件目录.agent/state/ [动态区 E本次任务] 任务 ID{{wave_id}} 目标文件{{target_files}} 技术方案文档路径{{design_doc_path}} 验收标准{{acceptance_criteria}}注意{{pinned_versions}}和{{stable_layout}}如果每次任务都变也应该移到动态区。稳定区的定义是“同一角色、同一版本、同一项目阶段下不会变”不是“看起来像配置”。如果角色本身不同不要硬塞进同一段 system prompt而是拆成 backend-dev、frontend-dev、test-runner 各自的 system prompt。这样每个子 Agent 的系统提示词都能独立形成稳定前缀缓存命中不会互相干扰。还有一个容易忽略的细节工具 Schema 的顺序也要稳定。很多 Agent 框架会用 map 或 set 存工具序列化时顺序可能变化。工具列表一旦在前缀中重新排序缓存直接失效。建议在 Agent 定义中显式固定工具顺序并在日志里打印工具 Schema 的 hash。模型名、温度、最大输出 token 这些参数也尽量固定不要在同一条高频链路上来回切换。从缓存复用视角看稳定前缀重排的本质是“把请求变成版本化模板”。每个子 Agent 有一套版本化的 system prompt版本号写入 state 文件TL 派发时只追加动态任务块。这样同一 Wave 内多次调用、修复循环中的重试、同类需求的不同 Wave都有机会复用同一段 KV 前缀。省下来的不是一次推理的时间而是每一轮重复打包 input token 的成本。3. TaoToken Key 与 Base URLClaude Code / Codex / CC Switch 配置在派发子 Agent 前调用模型时先去 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentbefore_dispatch 创建 Key。Base URL 统一用https://taotoken.net/apiKey 占位符用YOUR_API_KEY。下面分三种常用接入方式写配置注意 Claude Code 用ANTHROPIC_*和settings.jsonCodex 用config.toml不要把ANTHROPIC_*套到 Codex。Claude Code 可以用环境变量方式export ANTHROPIC_BASE_URLhttps://taotoken.net/api export ANTHROPIC_API_KEYYOUR_API_KEY也可以写进~/.claude/settings.json{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_API_KEY: YOUR_API_KEY } }Codex 使用~/.codex/config.toml走 OpenAI 兼容式配置时不要填ANTHROPIC_*model_provider taotoken model 你的模型名 [model_providers.taotoken] name TaoToken base_url https://taotoken.net/api env_key TAOTOKEN_API_KEY wire_api chat对应环境变量export TAOTOKEN_API_KEYYOUR_API_KEY如果你用 CC Switch 管理多套供应商按“三件套”填即可配置项填写内容供应商名称TaoTokenBase URLhttps://taotoken.net/apiAPI KeyYOUR_API_KEY模型从控制台可用模型中选择按角色分层时再分别绑定配置完成后先跑一次最小对话验证 Key 和 Base URL 是否生效再去改 Multi-Agent 的派发逻辑。建议把 TL、backend-dev、frontend-dev、test-runner 的模型配置分开管理TL 需要较强规划能力编码角色需要稳定代码能力测试与视觉校验这类规则性强、修复轮次多的角色可以走更便宜的模型。模型分层不要一上来就做先把稳定前缀重排做完否则你无法判断成本下降来自缓存复用还是模型替换。TaoToken 官网控制台也可以作为统一入口https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentkey_config 。在这里创建 Key 后把同一套 Base URL 配到 Claude Code、Codex 或 CC Switch。注意 Base URL 不要带 UTM 参数工具里只填https://taotoken.net/apiUTM 链接用于浏览器访问和 Key 管理。4. 可复现模板把派发提示词改成“前稳后动”下面给一个更工程化的重排模板。核心原则是系统提示词按角色固定项目约束按版本固定动态任务只出现在最后一条 user 消息里。这样同一子 Agent 在修复循环中反复调用时前面大段前缀可以重复命中缓存。from openai import OpenAI client OpenAI( api_keyYOUR_API_KEY, base_urlhttps://taotoken.net/api, ) STABLE_SYSTEM_BACKEND 你是 backend-dev 子 Agent。 只处理后端目录不修改前端、测试与视觉基线文件。 遇到不确定项时输出 BLOCKED并说明缺少的输入。 可用工具read_file, write_file, search_content, run_shell。 未列出的 MCP 工具不可见、不可调用。 输出 JSON 摘要字段顺序固定status, files, tests, risks。 STABLE_RULES_BACKEND 项目约束 - 运行时Node 20 - 包管理器pnpm - 后端目录apps/api - 本地命令入口dev-env.sh - 状态文件目录.agent/state/ - 不直接拼接数据库连接串参数交给本地脚本处理。 def build_backend_messages(task_payload: str): return [ {role: system, content: STABLE_SYSTEM_BACKEND}, {role: user, content: STABLE_RULES_BACKEND}, {role: user, content: task_payload}, ] def dispatch_backend(task_payload: str): resp client.chat.completions.create( model你的模型名, messagesbuild_backend_messages(task_payload), temperature0, ) return resp动态任务块建议只放真正变化的内容并且字段顺序也固定{ wave_id: wave-3, target_files: [apps/api/src/order/service.ts], design_doc_path: .agent/design/order.md, acceptance_criteria: [下单接口返回 201, 库存扣减幂等], state_file: .agent/state/wave-3.json }这里有一个反直觉的点动态任务块本身也可以做“半稳定”。比如同一个 Wave 内派发多个后端任务wave_id、design_doc_path、state_file是不变的变的只有target_files和acceptance_criteria。你可以把不变的部分放前把真正每次不同的放最后进一步延长可复用前缀。缓存匹配是前缀级别的越靠前的内容越值钱。另一个模板是 TL 派发消息。以前 TL 的派发 prompt 里塞满稳定调度规则现在把稳定规则迁移到子 Agent 的 system promptTL 只发两行动态内容[TL 派发消息] 子 Agentbackend-dev 任务参数 - wave_id: wave-3 - target_files: apps/api/src/order/service.ts - design_doc_path: .agent/design/order.md - acceptance_criteria: 下单接口返回 201库存扣减幂等 - 完成后更新 .agent/state/wave-3.json这不仅能提高缓存命中还能减少 TL 自身的上下文膨胀。TL 不再需要记住每个子 Agent 的完整工具规则它只需要知道“派给谁、参数是什么、结果写到哪”。5. 缓存命中前后对比从 usage 字段看 input token 去哪了提示词重排之后怎么验证有效不要只看账单总额要看每次请求的 usage 字段。不同服务商字段名可能不同常见有cached_tokens、cache_read_input_tokens、prompt_cache_hit_tokens等以你实际接入的服务商文档为准。重点观察三件事稳定前缀长度、缓存读取 token 占比、单轮 input 计费变化。下面是我在本地复现时的示例记录具体数值会随模型、服务商策略和任务内容变化你应以自己的 usage 日志为准观察项重排前重排后说明稳定前缀长度约 1.2K token约 3.4K token系统、工具、项目约束连续放置动态内容位置第 2 段开始出现最后一段 user 消息避免前缀在早期断裂缓存读取占比约 8%15%约 60%80%同一子 Agent 连续调用时更明显单次派发 input 计费基准 1.0x约 0.55x0.70x修复循环轮次越多收益越大会话恢复方式回放历史进度看板读 state 文件减少历史中的重复稳定内容重排前后最明显的变化往往不是第一次调用而是第二次以后的调用。第一次调用需要建立缓存收益有限第二次、第三次、修复循环重试时如果 system prompt、工具 Schema、项目约束完全一致服务商可以直接复用前面的大段 KV。此时 input token 中有一部分按缓存读取计价整体成本就下来了。排障时按这个清单逐项检查1. system prompt 是否每次变化是否混入了时间戳、随机 ID、完整进度看板 2. 工具 Schema 顺序是否稳定是否因 map 序列化导致顺序漂移 3. 模型名、温度、最大 token 是否在同一条链路上频繁切换 4. 动态文档是否被放在了稳定指令之前 5. 同一子 Agent 是否重复加载了已经在主 Agent 加载过的 Skill 6. 历史消息里是否反复输出完整状态导致历史无法压缩 7. 每次派发是否重新生成 system prompt而不是复用角色模板如果缓存读取占比仍然很低优先看第 1 和第 4 条。很多情况下不是服务商不支持而是 prompt 中间有一个变量把前缀打碎了。把动态内容后置通常是最快见效的一步。6. 多 Agent 场景下其它重复上下文治理状态外化、子 Agent 摘要、CLI 输出压缩稳定前缀重排解决的是“重复前缀”问题但 Multi-Agent 工作流里还有几类重复上下文会破坏缓存或拖长会话。它们不一定要一次性全做但可以按收益排序逐步推进。第一状态外化。TL 以前每个阶段切换都在对话里输出完整进度看板历史越堆越长而且每次派发都带着整块看板。后来改成把进度写到.agent/state/wave-x.jsonTL 被唤醒时先读文件阶段切换只输出单行Wave 1 done - Wave 2 started。这样历史消息更短派发 prompt 也更容易保持稳定前缀。会话中断后直接读 state 文件恢复现场不需要回放几十轮历史。第二数据获取子 Agent 化。需求分析阶段要读 TAPD 需求、Figma 设计稿如果 TL 自己调 MCP原始 payload 会留在生命周期最长的上下文里。几千字需求描述、上万行设计稿节点 JSON后续几十轮工具调用都要反复计费。改成 tapd-req-analyzer、figma-design-analyzer 子 Agent各自只返回结构化摘要TL 只拿摘要。实测中同一工作流单轮 input token 从 1,030,000 降到 634,905降幅约 38.4%。首次调用两种方式差不多收益主要来自后续多轮不再携带原始 payload。第三长期记忆按需索引。知识沉淀 Skill 不要一次性把所有候选文档读进 context。加一层INDEX.md先读目录索引筛选出最相关的 2 到 3 篇再read_file正文。索引通常只有几十到一两百行比全量加载几十篇文档便宜得多。相关度低于阈值的文档根本不进候选列表从源头减少“加载了但用不上”的常驻 token。第四CLI 输出压缩。git status、npm test、docker ps这类命令输出噪音很大在修复循环里反复出现。可以接入 rtk 这类 CLI 代理在命令执行前把输出重写为压缩版本。这里有两个坑一是某些 IDE 的 PreToolUse Hook 字段名可能是updatedInput而代理要求modifiedInput字段名不一致会静默失效二是评估效果时不要用“同一需求跑两遍开关对比”因为大模型执行路径本身不确定噪声可能比压缩收益还大。更可靠的方式是用rtk gain统计或直接命令行对比因为文本压缩与模型决策无关可复现性更高。第五工具调用并行化。TAPD 摘要和 Figma 摘要没有先后依赖应该在同一轮消息内并行派发两个子 Agent而不是等一个完成再发另一个。测试用例执行也一样Playwright CLI 可以一次接收多个 spec内置多 worker 并行跑LLM 侧只需要一次调用加一次读汇总结果。判断原则很简单后一次调用不需要前一次的输出作为输入就应该并行。串行不仅多等时间还会让前面所有轮次的历史被重新打包计费。第六能用 CLI 就不用 MCP。MCP 工具每次调用往往要消耗一次完整推理轮次点击一个按钮就是一次调用加一次模型推理十步操作就是十轮对话。把“理解用例并生成 spec”和“实际执行测试”拆开模型只负责生成 spec 文件Playwright CLI 负责批量执行。前者需要语义理解后者完全不需要token 和耗时都会明显下降。这些优化和稳定前缀重排是互相加强的。状态外化减少历史动态内容子 Agent 摘要避免原始 payload 进入长生命周期 contextCLI 压缩减少工具返回噪音并行化减少重复打包轮次。它们共同让“稳定前缀”更容易保持稳定也让缓存复用从一次调用的技巧变成工作流的默认属性。7. 落地检查表先重排再拆分最后才谈模型分层如果现在就要动手我建议按这个顺序推进不要一上来就换模型或重写整个 Agent 框架。先建度量。找到每轮请求的 usage 字段至少能看到 input token、output token、缓存读取 token。没有度量后面所有优化都只能凭感觉。做稳定前缀重排。把每个子 Agent 的 system prompt、工具白名单、输出协议、项目约束固定下来动态任务统一后置。状态外化。把进度看板、阶段状态从对话历史移到 state 文件TL 唤醒后读文件不再回放历史。子 Agent 专属配置。每个角色独立 system prompt、独立工具白名单、独立模型配置避免所有 MCP 工具 Schema 都塞进每个子 Agent。排查无依赖调用改并行。需求摘要、设计稿摘要、多测试用例执行能同一轮发起的不要串行。CLI 替代 MCP。确定性操作交给脚本和 CLI模型只做语义理解、生成 spec、汇总结果。接入 CLI 输出压缩。先做命令行对比再做全局 Hook注意字段名不一致导致的静默失效。代码图谱替代盲搜。用 AST 和语义索引先锁定文件范围再read_file减少探索轮次和冗余文件内容进入 context。长期记忆索引化。用INDEX.md先筛文档再读正文避免全量加载。模型分层。等前面几步稳定后再把测试、视觉对比这类规则性强、轮次多的角色换成更低成本模型否则无法归因。还有一个前置判断是否需要拆多 Agent。拆分本身有成本多个子 Agent 并行意味着多份 system prompt 同时在计费。小需求走单 Agent 直接处理中大型需求才进入多 Agent 调度。拆分真正的收益是切断滚雪球短生命周期子 Agent 跑完即销毁历史不会无限增长同时为稳定前缀、工具裁剪、子 Agent 化、模型分层打开空间。这也是为什么先做规模预判再做架构拆分。落地过程中最容易看到效果的是“度量 稳定前缀重排 状态外化”。这三步一个下午就能试点而且不需要改业务逻辑。接下来再逐步做子 Agent 专属配置、CLI 替代 MCP、代码图谱和长期记忆索引。官网入口可以放在这里作为统一 Key 管理https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentchecklist 。创建 Key 后把 Claude Code、Codex、CC Switch 的 Base URL 都指向https://taotoken.net/api再按角色拆分模型和工具白名单。8. 小结缓存复用不是玄学是请求结构工程回到最初的问题Multi-Agent 工作流成本高不一定是功能太多也不一定是模型太贵很多时候是请求结构没有为缓存复用设计。稳定指令和动态内容交错会让 KV Cache 前缀不断断裂历史里反复输出完整状态会让每一轮都带着重复上下文计费子 Agent 各自重新加载同一份 Skill会让最贵的信息被重复发现多次。稳定前缀重排的核心只有一句话把同一角色、同一版本下不会变的内容放在最前面把每次派发才变化的内容放到最后。系统提示词、工具 Schema、项目约束、输出协议都属于稳定区wave_id、目标文件、技术方案路径、验收标准属于动态区。动态区越短、越靠后缓存可复用的前缀就越长。配合 TaoToken 的 Key 和统一 Base URL你可以把 Claude Code、Codex、CC Switch 都接到同一套入口再按角色做模型分层和工具裁剪。但请记住TaoToken 解决的是调用入口和 Key 管理缓存复用仍需要你在请求结构上做工程化。先把 prompt 排稳再谈多 Agent 拆分、CLI 替代 MCP、代码图谱和长期记忆索引收益会更可控。如果你也在跑 Multi-Agent 工作流建议从下一次派发开始做 A/B同一子 Agent 连续调用两次第一次用交错 prompt第二次用“前稳后动”模板对比 usage 里的缓存读取 token 和 input 计费。你会很直观地看到省下来的不是某个魔法参数而是每一轮被重复计算的那段前缀。想快速验证效果可以按这个路径走先到 模型对话 试一轮最小请求如果准备长期跑子 Agent看 Coding Plan然后到 API Keys 创建YOUR_API_KEYClaude Code 的配置细节参考 Claude Code 文档。统一 Base URL 用https://taotoken.net/api也可以从 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentfinal_cta 进入控制台统一管理 Key。