【Claude Code-System Prompt实测】System Prompt 跨模型处理与缓存命中总论:Claude Code 请求前缀治理

非线智能API经验 [Claude Code-System Prompt实测] 第8篇

摘要

Claude Code 接入非 Anthropic 模型或第三方 LLM gateway 时,system prompt 不是一段可以随手搬运的普通提示词。它更像一段请求前缀资产:Claude Code 内置 agent 指令、工具定义、MCP 描述、项目上下文、CLAUDE.md、beta 能力开关、cache control,以及归属指纹块都会影响模型看到的开头内容、网关转换后的请求结构和 prompt cache 命中率。

这个方向的核心目标不是“提示词优化”,而是请求前缀治理:把 Claude Code 发出的稳定前缀转换成不同模型和网关都能接受的结构,同时剥离或归一化动态噪声,固定工具和 MCP 描述排序,统计 token 构成,观测每轮 prefix diff,并明确哪些内容可缓存、哪些内容必须留在动态窗口。

如果这一层不处理,跨模型兼容会同时遇到三类问题。第一是协议不兼容:Anthropic Messages API 的起始系统指令使用顶层 system 字段,而 OpenAI-compatible 生态长期使用 messages / instructions 表达系统级指令;把 system role 直接塞进 Anthropic messages 数组,可能触发严格角色校验。第二是缓存命中率崩塌:Claude Code attribution block 可能包含动态 prompt fingerprint,自定义 gateway 如果按完整 request body 或完整 prompt 前缀缓存,会把本该稳定的前缀打碎。第三是上下文不可控:工具定义、MCP 描述和项目规则持续膨胀,会提高 token 成本,也会稀释模型对当前任务的注意力。

本文是方向总论。后续六篇文章分别展开每个证据点和规划点:

1、Anthropic / OpenAI system 结构差异:解释为什么顶层 systemmessages[0].role=system 不能机械互转。
2、Claude Code attribution block 与第三方缓存 miss:分析动态归属指纹如何破坏自定义 gateway 的 cache key。
3、归属指纹块与兼容端保留关键字错误:处理 x-anthropic-billing-header 进入 provider 校验链路后的 400 风险。
4、CLAUDE.md、工具定义与 MCP 描述的上下文膨胀:拆解初始上下文增长和 token budget。
5、归属指纹块剥离与前缀稳定化:给出 strip / normalize、canonicalization 和 cache segment 设计。
6、请求前缀可观测性:设计 token profile、prefix diff、HMAC 日志和 cache miss 归因。

数据来源:非线智能Nonlinear 官网

证据强度分层

这类问题必须区分“官方规格”“工程案例”和“社区逆向观察”。

证据类型 适合证明什么 使用方式
官方文档 API 结构、环境变量、gateway 行为、prompt caching 语义 作为文章的规格依据
GitHub issue / PR 具体版本、具体网关、具体错误信息 作为工程案例,不等同于长期规格
第三方网关文档 企业接入方式、观测和治理需求 说明真实部署形态
逆向分析 / 社区讨论 system prompt 构造、工具描述体积、缓存体验 作为观察线索,不当作官方事实来源

一个关键修正是:不要简单写成“CLAUDE.md 被注入 system prompt”。Claude Code 官方 memory 文档的说法更精确:CLAUDE.md 会进入初始上下文 / project context,并且其内容在 system prompt 之后作为 user message 提供。对缓存和 token 成本来说,它仍然属于请求前缀治理范围;但对协议转换来说,它不一定属于 Anthropic 顶层 system 字段。

另一个关键修正是:不要写成“attribution block 会破坏 Anthropic 官方 prompt cache”。Claude Code 官方 LLM gateway 和环境变量文档说明,Anthropic 自家 API 会在处理前剥离该 block,因此 Anthropic API caching 不受影响。问题主要发生在自定义 ANTHROPIC_BASE_URL、第三方 gateway、本地模型网关,或任何按完整 request body / 完整 prompt 前缀做缓存的实现中。

结构差异:顶层 system 不是 messages 里的普通角色

Anthropic Messages API 的起始系统指令应放在请求顶层 system 字段中。这个字段可以是字符串,也可以是 content block 数组;在 prompt caching 场景下,顶层 system 还可以携带 cache breakpoint。Anthropic 的对话 messages 序列主要承载 userassistant 消息。

OpenAI-compatible 生态则长期把系统级指令表达为消息序列中的 role: "system" 或更新接口里的 instructions / developer 指令。这个差异不是字段名不同,而是请求 AST 不同:Anthropic 把系统前缀作为请求级字段,OpenAI-compatible 多数实现把它看成消息流的一部分。

错误转换通常长这样:

{
  "messages": [
    {
      "role": "system",
      "content": "You are Claude Code..."
    },
    {
      "role": "user",
      "content": "fix this bug"
    }
  ]
}

如果这个请求被发往严格的 Anthropic-compatible endpoint,messages[].role 中的 system 可能被拒绝,因为该位置只接受 user / assistant。vLLM issue 和相关论坛讨论中就出现过 Claude Code 新版本把 system / ctx / msg 等 role 放入 Anthropic Messages API 的 messages 数组后,vLLM 侧报 Input should be 'user' or 'assistant' 的案例。类似问题也出现在 Claude Code 社区 issue 中,报错指向 messages[n].role must be either 'user' or 'assistant'

兼容层因此不能只做 role 字符串映射,而应先把请求解析成内部结构:

type PromptPrefixIR = {
  system: PromptBlock[];
  projectContext: PromptBlock[];
  toolDefinitions: ToolDefinitionIR[];
  mcpDescriptors: McpDescriptorIR[];
  dynamicHeaders: PromptBlock[];
  conversation: ConversationMessageIR[];
  cacheHints: CacheHint[];
};

渲染到 Anthropic 时,system 应回到顶层 system 字段,conversation 只渲染合法消息角色;渲染到 OpenAI-compatible 时,再按目标 profile 决定使用 messages[0].role = "system"developer role、instructions 字段,还是把部分上下文折叠进普通 user message。这样才能避免把某一家 API 的表面格式误认为通用聊天格式。

动态归属指纹:缓存命中率的隐形破坏点

Claude Code 官方文档说明,Claude Code 可能在 system prompt 前加入 attribution block,包含 client version 和 prompt fingerprint。社区中观察到的形式大致类似:

x-anthropic-billing-header: cc_version=<version>; cc_entrypoint=cli; cch=<fingerprint>;

在直连 Anthropic API 时,这个 block 会被服务端处理前剥离,因此不会影响 Anthropic 自家的 prompt cache。但第三方 gateway 往往没有这层特殊处理。尤其在 ANTHROPIC_BASE_URL 指向自定义服务时,gateway 可能直接把完整 body、完整 prompt 或完整 system prefix 作为 cache key。此时 attribution block 如果位于请求前缀第一位,且 fingerprint 随会话或首条用户 prompt 变化,就会导致稳定前缀从第一个 token 开始不同。

这对 prompt cache 是致命的。prefix cache 的基本前提是“开头相同”。一旦开头第一段每次不同,后面的 Claude Code 内置指令、工具定义、MCP 描述、项目规则即使完全一致,也无法复用同一个前缀缓存。anthropics/claude-code #50085 把这个问题落到 ANTHROPIC_BASE_URL 下的 cache miss;claude-code-router 的相关 PR 则采用设置 CLAUDE_CODE_ATTRIBUTION_HEADER=0 的方式避免动态 header 破坏缓存。

这个 block 还可能触发兼容端错误。anthropics/claude-code #24168 的 issue reporter 在 Claude Code + Bedrock 场景中观察到:x-anthropic-billing-header 被作为 system prompt text block 发送后,触发 400 x-anthropic-billing-header is a reserved keyword。这说明 attribution block 不只是缓存问题,也可能成为 provider 关键字、保留字段和安全校验问题;但这个具体报错是工程案例,不是 AWS 官方规格。

前缀稳定化策略

兼容层应把前缀稳定化放在请求进入模型网关之前,而不是等 cache miss 后再分析日志。

第一步是识别动态块。默认规则应覆盖:

动态来源 识别方式 默认处理
x-anthropic-billing-header attribution block system prompt 开头的固定 header 名 剥离,或归一化为固定占位
时间戳 ISO 时间、Unix time、日期字符串 移出 stable prefix
UUID / 随机 ID UUID v4、短 hash、session id 移出 stable prefix 或规范化
动态路径 临时目录、workspace session path 改成稳定相对路径
工具顺序抖动 每轮工具数组顺序不同 按稳定 key 排序
MCP 描述顺序抖动 server / tool 枚举无序 按 server name、tool name、schema hash 排序

第二步是建立前缀分层。不要让所有上下文自然堆叠在同一个消息数组里:

分层 内容 缓存策略
Stable System Claude Code 内置指令、兼容层约束、稳定安全规则 长周期缓存
Stable Capabilities 工具定义、MCP 工具描述、模型 capability profile schema 或能力变化才失效
Project Context CLAUDE.md、项目规则、仓库摘要 中周期缓存,带文件 hash
Task State 当前目标、关键决策、近期文件摘要 短周期缓存
Live Window 最新用户消息、工具结果、错误反馈 高频变化,不追求长缓存
Dynamic Metadata attribution、trace id、session id、计费标签 不进入 cacheable prefix

第三步是让 cache key 显式化:

type PrefixCacheKey = {
  provider: "anthropic" | "openai-compatible" | "bedrock" | "vllm" | "local";
  model: string;
  systemHash: string;
  toolSchemaHash: string;
  mcpDescriptorHash: string;
  projectContextHash: string;
  adapterVersion: string;
};

trace_idsession_id、用户本轮 prompt、最新工具输出不应进入这个 key。它们可以进入审计日志,也可以作为 gateway header 参与观测,但不能污染 cacheable prefix。

对 Anthropic 这类支持显式 cache breakpoint 的后端,兼容层可以把 cache hint 渲染成 provider 原生 cache_control。对 vLLM、本地模型或普通 OpenAI-compatible gateway,则应降级为内部 prefix cache key 或 KV reuse hint,而不是把 cache_control 当成自然语言塞回 prompt。

type CacheSegment = {
  id: string;
  type: "system" | "tools" | "mcp" | "project_context" | "task_state" | "live_window";
  stability: "static" | "semi_static" | "dynamic";
  tokenEstimate: number;
  hash: string;
  providerPolicy: "anthropic_cache_control" | "gateway_prefix_cache" | "kv_reuse_hint" | "none";
};

请求前缀可观测性

没有观测,前缀治理会退化成“感觉 prompt 好像变大了”。这里的可观测对象是完整请求前缀;system prompt token 只是其中一个 segment。兼容层应给每轮请求输出一份 prefix profile:

{
  "request_id": "req_...",
  "provider": "vllm",
  "model": "qwen3-coder",
  "tokens": {
    "total_input": 48231,
    "system": 12980,
    "claude_code_builtin": 7210,
    "project_context": 2840,
    "claude_md": 1630,
    "tools": 15440,
    "mcp": 6150,
    "task_state": 2760,
    "live_window": 11051,
    "dynamic_uncacheable": 20
  },
  "cache": {
    "cacheable_prefix_tokens": 30270,
    "uncacheable_dynamic_tokens": 20,
    "stable_prefix_hmac": "hmac-sha256:...",
    "changed_segments": ["live_window"]
  },
  "stability_score": 0.94
}

指标至少应覆盖:

指标 目的
system prompt token 数 判断系统级指令是否膨胀
Claude Code 内置 prompt token 数 区分平台固定成本和项目成本
CLAUDE.md / project context token 数 发现项目规则是否失控
工具定义 token 数 发现工具 schema / description 是否过长
MCP 描述 token 数 发现 MCP server 暴露过多能力
cacheable prefix token 数 判断可复用前缀规模
uncacheable dynamic token 数 判断动态噪声是否进入前缀
prefix diff 定位每轮变化来自哪里
cache hit / miss / write token 观察真实缓存效果
首 token 延迟 验证缓存是否带来延迟收益
role rewrite count 发现跨协议转换是否在频繁修正非法角色
stripped attribution block count 判断动态归属块是否仍在入口出现
prefix churn ratio 衡量可缓存前缀中有多少 token 发生变化

稳定性评分可以先用可解释的启发式,而不是黑盒模型:

stability_score = 100
  - 40 * cacheable_churn_ratio
  - 20 * dynamic_prefix_ratio
  - 15 * ordering_instability
  - 15 * role_rewrite_risk
  - 10 * cache_boundary_risk

其中 cacheable_churn_ratio 是本轮可缓存前缀中发生变化的 token 占比,dynamic_prefix_ratio 是第一个缓存边界之前的动态 token 占比,ordering_instability 反映工具 / MCP canonicalization 前后的顺序抖动,role_rewrite_risk 反映非法 role 或跨协议降级风险,cache_boundary_risk 反映 cache breakpoint 是否被放在动态块之后。评分不是为了追求绝对准确,而是为了让工程团队能在版本升级、MCP 增加、工具描述改写后立刻看到“为什么缓存掉了”。

Prefix diff:只暴露结构,不泄露 prompt

system prompt 可观测有一个现实风险:日志本身可能泄露项目规则、工具参数、路径、密钥或用户上下文。因此 prefix diff 不应默认记录完整 prompt 原文。推荐记录结构化摘要和 hash:

{
  "segment": "tools",
  "before_hmac": "hmac:aaa",
  "after_hmac": "hmac:bbb",
  "token_delta": 840,
  "change_type": "tool_added",
  "examples_redacted": [
    {
      "tool_name": "deploy_prod",
      "schema_hmac": "hmac:..."
    }
  ]
}

对需要深度排障的环境,可以启用短期原文采样,但必须有保留周期、脱敏规则和访问控制。默认观测应遵循三个原则:hash 可比对,token 可计量,原文不可见。

生产环境更稳妥的做法是使用带环境 salt 的 HMAC,而不是裸 SHA。裸 hash 在固定 prompt、常见工具描述或公开 system prompt 场景中可能被字典反推;HMAC 可以保留“同一环境内可比较”的能力,同时降低跨环境泄露风险。prompt telemetry 也应设置 TTL:长期保留聚合指标,短期保留调试事件,不把原始 prompt 或脱敏片段送入长期分析仓库。

跨模型渲染器设计

最终落地应是一个 prefix compiler,而不是一组字符串替换规则:

Claude Code request
  -> parse to PromptPrefixIR
  -> classify stable / project / task / live / dynamic
  -> normalize dynamic blocks
  -> sort tools and MCP descriptors
  -> compute token profile and prefix hashes
  -> render by ProviderProfile
  -> attach cache_control / headers / observability metadata
  -> send to model gateway

ProviderProfile 至少应表达:

type ProviderProfile = {
  systemMode: "top_level_system" | "messages_system" | "instructions" | "developer_message";
  allowedMessageRoles: string[];
  supportsSystemContentBlocks: boolean;
  supportsCacheControl: boolean;
  supportsToolChoice: boolean;
  reservedKeywords: string[];
  maxSystemTokens?: number;
  cacheBoundaryPolicy: "anthropic_cache_control" | "gateway_prefix_hash" | "none";
};

Anthropic profile 会把起始系统指令渲染到顶层 system,并保留合法 cache control。OpenAI-compatible profile 会根据具体接口选择 system / developer / instructions。Bedrock profile 要避开保留关键字和供应商限制。vLLM Anthropic-compatible profile 要严格保证 messages 中只出现 endpoint 接受的角色。Local model profile 则要特别关注 KV cache:即使没有商业 prompt caching,也要避免动态前缀导致本地推理服务重复处理完整 prompt。

失败模式

失败模式 触发原因 修复策略
Anthropic-compatible endpoint 返回 400 system role 被塞进 messages 使用顶层 system,按 profile 渲染合法角色
prompt cache hit rate 接近 0 attribution fingerprint 或 session id 位于前缀开头 剥离、归一化或设置 CLAUDE_CODE_ATTRIBUTION_HEADER=0
Bedrock 报 reserved keyword x-anthropic-billing-header 被当作 prompt text 发送 provider profile 过滤保留关键字
工具 schema 每轮 hash 不同 工具或 MCP 描述顺序不稳定 稳定排序,schema canonicalization
system token 持续上涨 CLAUDE.md、MCP、工具描述无边界增长 token budget、分层加载、按需暴露工具
观测日志泄露 prompt prefix diff 记录原文 默认记录 hash、token delta 和结构化变更

验证清单

• 构造 Anthropic Messages 请求,确认 messages 中不会出现非法 system role。
• 构造 OpenAI-compatible 请求,确认系统级指令按目标接口落到 system / developer / instructions 中。
• 连续发送两轮同任务请求,确认剥离 attribution 后 stable prefix hash 不变。
• 增减一个工具,确认变化只反映到 toolSchemaHash,而不是整段 system 随机变化。
• 打乱 MCP server 返回顺序,确认 canonicalized descriptor hash 不变。
• 在 Bedrock / vLLM / local gateway profile 下跑保留关键字和角色校验测试。
• 开启 cache 指标,比较归一化前后的 cache hit rate、cache read tokens、cache write tokens 和首 token 延迟。
• 对 prefix diff 日志做 secret scan,确认不会记录原始密钥、完整 prompt 或敏感路径。

工程落地顺序

1、先实现 PromptPrefixIR,把 system、project context、tools、MCP、dynamic metadata 和 conversation 分开。
2、实现 provider profile,把 Anthropic 顶层 system、OpenAI-compatible system message / instructions、Bedrock / vLLM 限制都收敛到渲染层。
3、默认剥离或归一化 attribution block,并提供等效 CLAUDE_CODE_ATTRIBUTION_HEADER=0 的网关策略。
4、对工具定义、MCP 描述和 project context 做 canonicalization:稳定排序、稳定 JSON 序列化、hash 化。
5、接入 token counting 和 prefix profile,输出 system、tools、MCP、project context、live window 的 token 构成。
6、实现 prefix diff 和稳定性评分,默认只记录 hash、token delta 和结构化变更。
7、最后接入真实 cache 指标,用 hit rate、write/read tokens、首 token 延迟和 400 错误率做灰度验收。

结论

Claude Code 的 system prompt 跨模型处理,本质上是 agent runtime 的请求前缀治理。Anthropic、OpenAI-compatible、Bedrock、vLLM、本地模型网关对 system、messages、tools、cache control 和保留关键字的处理并不等价;而 Claude Code 自身又会把内置 prompt、工具定义、MCP、项目上下文和 attribution metadata 组合成一个很长的初始上下文。

稳健的兼容层应该把这段前缀当作可编译、可审计、可缓存的数据结构:先拆成 IR,再按 provider profile 渲染;先剥离动态噪声,再计算稳定 hash;先统计 token 构成,再谈成本优化。只有这样,跨模型 Claude Code 才不会在角色校验、动态 header、上下文膨胀和 cache miss 之间反复踩坑。

参考链接

Claude Code Environment Variables
Claude Code LLM Gateway
Claude Code Memory
Claude Code Modifying system prompts
Anthropic Using the Messages API
Anthropic Prompt Caching
Anthropic Mid-conversation system messages
Anthropic Token Counting
Anthropic Define Tools
Anthropic Engineering: Effective context engineering for AI agents
AWS Bedrock Anthropic Claude Messages API
vLLM Claude Code Integration
vllm-project/vllm #44000
anthropics/claude-code #24168
anthropics/claude-code #50085
anthropics/claude-code #63469
musistudio/claude-code-router #1220
Prompt Cache: Modular Attention Reuse
CacheProbe
On the Use of Agentic Coding Manifests
Decoding the Configuration of AI Coding Agents
Dive into Claude Code

本文由非线智能API Claude Code 行业专家整理编写