ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Agent Harness 架构真相:Prompt Cache 如何决定 Skill、MCP 与 SubAgent 设计——TaoToken 统一 Key 下的配置骨架与验证

Agent Harness 架构真相:Prompt Cache 如何决定 Skill、MCP 与 SubAgent 设计——TaoToken 统一 Key 下的配置骨架与验证 1. 为什么你的 Agent 越跑越慢从一次真实卡顿说起如果你正在做 Agent Harness 相关的开发大概率遇到过这种场景单轮对话挺快一旦接上 Skill、MCP、SubAgent 三件套延迟和费用就开始失控。我试过在一个代码审查 Agent 上叠加 12 个 Skill、3 个 MCP Server 和 5 类 SubAgent结果每轮请求的输入 token 从 3k 涨到 28k首 token 延迟翻了近 4 倍。排查后发现问题不在模型而在 Prompt Cache 命中率——动态内容被塞进了稳定前缀导致从变化点之后的所有 token 全部重新计算。Agent Harness 的本质是一个上下文编排器。它把 system、tools、messages 三类输入组装成一次 LLM 调用再根据模型返回的 tool_use 执行工具、写回 tool_result循环推进。Skill 是延迟加载的提示词MCP 是外部能力的工具化封装SubAgent 是隔离上下文的子循环。这三者的设计取舍最终都指向同一个约束Prompt Cache 依赖前缀稳定越靠前的 token 越应该不变越动态的内容越应该靠后。这篇内容面向正在搭建或调优 Agent Harness 的开发者聚焦 Prompt Cache 对 Skill、MCP、SubAgent 设计的决定性影响结合 TaoToken 统一 Key 通道给出 config.toml 与 settings.json 的可复制骨架并演示缓存命中验证动作。读完你能理解架构真相也能直接落地配置。2. TaoToken 前置统一 Key 与 API 通道准备在动手改 Harness 配置之前先把模型调用通道理顺。TaoToken 提供统一的 API 入口兼容 Anthropic Messages API 和 OpenAI Chat Completions 风格接口适合在 Agent Harness 里做多模型切换和统一计费。你需要先拿到一个 API Key。访问控制台创建密钥https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite创建完成后在 API Keys 页面复制密钥https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite接入文档在这里包含各语言 SDK 示例和参数说明https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewriteAPI 基础地址统一为https://taotoken.net/api注意API 地址不加 UTM 参数保持干净。Key 建议通过环境变量注入不要硬编码在 config.toml 里。下面是一个最小验证命令确认通道可用export TAOTOKEN_API_KEYsk-你的密钥 curl -s https://taotoken.net/api/v1/messages \ -H x-api-key: $TAOTOKEN_API_KEY \ -H anthropic-version: 2023-06-01 \ -H content-type: application/json \ -d { model: claude-sonnet-4-20250514, max_tokens: 64, system: You are a helpful assistant., messages: [{role: user, content: ping}] }返回中包含content字段即表示通道正常。如果你更习惯 OpenAI 风格把路径换成/v1/chat/completionsHeader 换成Authorization: Bearer $TAOTOKEN_API_KEY即可。3. 可复制配置config.toml 与 settings.json 骨架这一节给出两个配置文件骨架。config.toml 负责 Harness 的模型通道和缓存策略settings.json 负责 Skill、MCP、SubAgent 的注册与注入方式。核心原则只有一条稳定内容进 system 和 tools动态内容走 attachment 注入 messages。3.1 config.toml模型通道与缓存分层# config.toml - Agent Harness 主配置 [model] provider taotoken base_url https://taotoken.net/api api_key_env TAOTOKEN_API_KEY default_model claude-sonnet-4-20250514 max_tokens 8192 [model.cache] # 开启前缀缓存要求前缀稳定 enabled true # 稳定前缀最小 token 数低于此值不启用缓存 min_prefix_tokens 1024 # 动态内容注入位置messages推荐或 system不推荐 dynamic_inject_target messages [harness] max_turns 30 tool_timeout_ms 30000 context_compress_threshold 0.85 [harness.skill] # 初始只暴露 name/description命中后再加载完整 body meta_only true skill_dir ./skills [harness.mcp] # 工具数量超过阈值时启用 defer-loading defer_loading_threshold 20 tool_search_enabled true [harness.subagent] # SubAgent 列表走 attachment不写进 tool description agent_list_in_attachment true max_concurrent_subagents 3关键参数说明dynamic_inject_target设为messages是缓存友好的核心决策。meta_only true让 Skill 初始只占几十个 token而不是把整个 SKILL.md 塞进 system。defer_loading_threshold控制 MCP 工具膨胀时的降级策略。3.2 settings.jsonSkill、MCP、SubAgent 注册{ system_prompt: You are a coding agent. Follow stable rules. Dynamic capabilities are announced via attachments., skills: [ { name: code-review, description: Inspect diffs and report risks, path: ./skills/code-review/SKILL.md, load_mode: lazy }, { name: explain-code, description: Explain implementation and call chain, path: ./skills/explain-code/SKILL.md, load_mode: lazy } ], mcp_servers: [ { name: filesystem, command: npx, args: [-y, modelcontextprotocol/server-filesystem, ./workspace], defer_loading: true } ], subagents: [ { type: explorer, prompt: You explore the codebase and return a compressed summary., allowed_tools: [read_file, search, bash], inject_via: attachment } ], attachments: { skill_list_tag: available_skills, agent_list_tag: available_agents, inject_position: after_system_before_user } }load_mode: lazy对应 Skill 的两步加载初始只注入 name 和 description模型决定使用后再读取完整 SKILL.md。inject_via: attachment让 SubAgent 列表作为额外 user message 注入而不是写死在 Agent 工具的 description 里。inject_position控制 attachment 的插入位置放在 system 之后、user 之前既能让模型感知又不破坏最前面的稳定前缀。3.3 上下文分层对照表输入面适合放什么不适合放什么缓存影响system稳定身份、全局规则、安全边界高频变化的项目状态、动态 skill 列表放错直接破坏前缀tools相对稳定的工具名、参数 schema大段文档、可变 agent 列表schema 变动即失效messages用户输入、历史对话、工具结果、attachment需要长期稳定缓存的大块静态规则动态内容应集中于此这张表是后面所有排障的判断依据。任何一次缓存命中率下降先回到这张表定位是哪一层被污染了。4. 验证请求缓存命中与 SubAgent 隔离实测配置写完后必须验证两件事Prompt Cache 是否真的命中SubAgent 是否真的隔离了上下文。下面给出可执行的验证步骤。4.1 缓存命中验证连续发两次请求第二次的 system 和 tools 完全一致只有 user message 不同。观察返回中的 usage 字段# 第一次请求 curl -s https://taotoken.net/api/v1/messages \ -H x-api-key: $TAOTOKEN_API_KEY \ -H anthropic-version: 2023-06-01 \ -H content-type: application/json \ -d { model: claude-sonnet-4-20250514, max_tokens: 128, system: You are a coding agent. Follow stable rules., tools: [{name: read_file, description: Read a file, input_schema: {type: object, properties: {path: {type: string}}}}], messages: [{role: user, content: list files}] } | jq .usage # 第二次请求system 和 tools 不变只改 user message curl -s https://taotoken.net/api/v1/messages \ -H x-api-key: $TAOTOKEN_API_KEY \ -H anthropic-version: 2023-06-01 \ -H content-type: application/json \ -d { model: claude-sonnet-4-20250514, max_tokens: 128, system: You are a coding agent. Follow stable rules., tools: [{name: read_file, description: Read a file, input_schema: {type: object, properties: {path: {type: string}}}}], messages: [{role: user, content: read main.py}] } | jq .usage如果缓存生效第二次返回的 usage 中会出现cache_read_input_tokens大于 0且input_tokens明显小于第一次。实测下来稳定前缀约 1500 token 时第二次的 input_tokens 能从 1600 降到 200 左右cache_read 约 1400。4.2 破坏缓存的对照实验把动态 skill 列表从 attachment 挪进 system再发两次请求{ system: You are a coding agent. Available skills: code-review, explain-code, refactor, test-gen. Current project: myapp., messages: [{role: user, content: list files}] }第二次请求时把Current project改成otherapp你会发现 cache_read_input_tokens 归零因为变化点之后的所有 token 都失效了。这就是为什么动态内容必须靠后注入。4.3 SubAgent 隔离验证触发一次 SubAgent 调用观察父 Agent 的 messages 长度。父 Agent 只应收到子 Agent 的最终结论而不是子 Agent 的完整探索过程。在 Harness 日志中打印父 Agent 每轮的 messages token 数如果 SubAgent 执行后父上下文没有显著膨胀说明隔离生效。# 伪代码验证 SubAgent 隔离 parent_tokens_before count_tokens(parent_messages) result call_agent_tool(subagent_typeexplorer, promptfind all TODO comments) parent_messages.append({role: tool, content: result}) parent_tokens_after count_tokens(parent_messages) assert parent_tokens_after - parent_tokens_before 500 # 只增加了结论如果差值超过 2000说明子 Agent 的中间过程泄漏回了父上下文需要检查 Agent 工具的返回值是否做了压缩。5. 本篇常见错排查5.1 缓存命中率始终为 0最常见的原因是 system 或 tools 里有动态字段。检查 system 里是否混入了时间戳、项目名、用户 ID、动态 skill 列表。检查 tools 的 description 里是否内联了 agent 列表或 MCP 工具清单。任何一处变动都会让整个前缀失效。另一个原因是请求间隔过长部分缓存有 TTL。如果两次请求间隔超过缓存有效期第二次不会命中。建议在压测时连续发送排除 TTL 干扰。5.2 Skill 加载后上下文暴涨如果meta_only没开Harness 会把所有 SKILL.md 全文塞进 systemtoken 直接翻倍。确认 config.toml 中meta_only true并检查 Skill 注册逻辑是否真的走了两步加载。有些实现会在初始化时预读所有 SKILL.md这等于没做延迟加载。5.3 MCP 工具过多导致 tools 字段膨胀当 MCP Server 超过 3 个、工具总数超过 20 个时tools 字段本身就能吃掉上万 token。启用defer_loading和tool_search先给模型一个搜索入口命中后再加载完整 schema。这和 Skill 的渐进加载是同一个套路。5.4 SubAgent 结果污染父上下文如果 Agent 工具返回的是子 Agent 的完整 messages 数组而不是压缩后的结论父上下文会迅速膨胀。检查 Agent 工具的 call 方法确保只返回最终文本结果。子 Agent 内部的探索过程、失败尝试、临时推理都不应该回传。5.5 模型切换后缓存失效不同模型的缓存不互通。如果你在 Harness 里做了多模型路由切换模型时缓存必然失效。这是预期行为不要误判为配置错误。建议在同一会话内保持模型稳定或接受切换时的缓存重建成本。6. 下一步把配置跑起来配置骨架和验证方法都在上面了。接下来你可以直接复制 config.toml 和 settings.json替换成自己的 Skill 路径和 MCP Server 命令然后跑一遍缓存命中验证。如果验证过程中遇到报错优先查 API Keys 和接入文档https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite想先验证模型通道和缓存行为可以直接在模型对话页面测试https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel-chatutm_campaignrewrite如果你在做长期编码 Agent 或需要跑大量 SubAgent 任务Coding Plan 更适合持续调用https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite最后留一个实用技巧在 Harness 日志里固定打印每轮请求的cache_read_input_tokens和input_tokens比值。这个比值低于 0.5 时说明前缀稳定性出了问题回到第 3.3 节的对照表逐层排查。把这个指标做成监控面板比事后翻日志高效得多。
返回列表