【Claude Code-System Prompt实测】归属指纹块剥离与前缀稳定化:从 prompt 字符串到 cacheable prefix
非线智能API经验 [Claude Code-System Prompt实测] 第13篇
摘要
前缀稳定化是 Claude Code 跨模型缓存命中的工程核心。Claude Code 的请求前缀里既有稳定内容,也有动态内容:内置 system prompt、工具定义、MCP 描述、项目上下文相对稳定;attribution fingerprint、trace id、session id、时间戳、临时路径和最新工具结果高度动态。兼容层的任务是把两者分开,让稳定内容形成可缓存前缀,让动态内容留在 metadata 或 live window。
本文聚焦前缀稳定化落地:默认识别并剥离 x-anthropic-billing-header attribution block,或将其归一化为固定内容;支持客户端通过 CLAUDE_CODE_ATTRIBUTION_HEADER=0 上游禁用;检测 system prompt 早段的时间戳、UUID、随机 ID、动态路径;固定工具列表和 MCP 描述排序;输出前缀稳定性评分。
数据来源:非线智能Nonlinear 官网
PrefixStabilizer 的输入与输出
输入不应是一个字符串,而应是已经拆分过的 IR:
type PromptPrefixIR = {
system: PromptBlock[];
tools: ToolSpecIR[];
mcp: McpDescriptorIR[];
projectContext: PromptBlock[];
taskState: PromptBlock[];
liveWindow: PromptBlock[];
metadata: Record<string, unknown>;
};
输出是稳定化后的前缀和风险报告:
type StabilizedPrefix = {
cacheableSegments: CacheSegment[];
dynamicSegments: CacheSegment[];
strippedMetadata: Record<string, unknown>;
stablePrefixHash: string; // internal cache key material
stablePrefixHmac: string; // telemetry-safe identifier
stabilityScore: number;
findings: PrefixFinding[];
};
attribution block 的三种策略
| 策略 | 行为 | 推荐场景 |
|---|---|---|
strip |
从 prompt 中删除,不进入模型上下文 | 第三方 gateway / local model 默认 |
normalize |
替换为固定占位,例如 claude_code_attribution_present |
需要保留来源信号 |
preserve_as_metadata |
移出 prompt,进入 metadata / 审计事件 | 需要成本归因 |
直连 Anthropic API 会在处理前剥离 attribution block,因此问题主要发生在第三方 ANTHROPIC_BASE_URL、LLM gateway、本地模型,或按完整 body / prefix 做 cache key 的实现中。strip 不应丢失计费和审计信息,默认应配合 preserve_as_metadata 写入结构化 metadata。
CLAUDE_CODE_ATTRIBUTION_HEADER=0 是 Claude Code 客户端侧配置。gateway 如果只是接收请求,不能真正控制客户端是否生成该 block;它只能做服务端 strip / normalize / preserve_as_metadata。因此推荐双层防御:客户端可用环境变量上游禁用,gateway 仍在入口层做 sanitizer,处理旧客户端或代理链路残留。
动态块检测
默认检测范围应聚焦在已解析的 system prompt 早段、metadata、known attribution block 和 known session fields,不要全文粗暴正则,否则容易误删用户 prompt、代码片段、schema enum 或文件 hash。
| 动态来源 | 示例 | 处理 |
|---|---|---|
| attribution header | x-anthropic-billing-header |
strip / metadata |
| UUID | 550e8400-e29b-41d4-a716-446655440000 |
移出 stable prefix |
| 时间戳 | 2026-06-12T09:30:00Z |
移出或归一化 |
| session id | session_abc123 |
metadata |
| 临时路径 | /var/folders/.../tmp/... |
相对路径或占位 |
| 随机 hash | 短 hex / base64 id | 只标记风险,不自动删除 |
canonicalization:让语义相同的工具得到相同 hash
工具和 MCP 描述最常见的抖动不是内容变化,而是顺序变化。稳定化层应做 canonicalization:
1、工具按 source_type + namespace + name + version + schema_hmac 排序。
2、MCP server 优先按稳定 server id 排序;没有稳定 id 时按 server name,再用 descriptor HMAC 做 fallback。
3、同一 server 下工具按 tool name 排序;同名工具用 schema HMAC 做 tie-breaker。
4、JSON Schema 使用 canonical JSON:字段排序、去掉无意义空字段、稳定序列化。
5、description 不做语义改写,只做换行和 whitespace 规范化。
type CanonicalToolSpec = {
key: string;
name: string;
description: string;
schemaCanonicalJson: string;
schemaHash: string;
schemaHmac: string;
};
cache segment 规划
稳定化层应输出 cache segment,而不是只输出一个总 hash:
type CacheSegment = {
id: string;
type: "system" | "tools" | "mcp" | "project_context" | "task_state" | "live_window";
stability: "static" | "semi_static" | "dynamic";
hash: string;
hmac: string;
tokenEstimate: number;
cacheable: boolean;
};
内部 cache key 可以使用 hash;生产遥测和日志应输出带环境 salt 的 HMAC,避免固定 prompt、工具名或公开 schema 被离线字典反推。
推荐分层:
| Segment | 是否 cacheable | 失效条件 |
|---|---|---|
| system.base | 是 | Claude Code / adapter 版本变化 |
| tools.core | 是 | schema hash 变化 |
| mcp.enabled | 是 | server/tool/schema 变化 |
| project.context | 半稳定 | CLAUDE.md / 项目规则 hash 变化 |
| task.state | 半稳定 | 用户目标或摘要变化 |
| live.window | 否 | 每轮变化 |
| metadata.dynamic | 否 | 不进入 prompt cache |
稳定性评分
score = 100
- 40 * cacheable_churn_ratio
- 20 * dynamic_prefix_ratio
- 15 * ordering_instability
- 15 * role_rewrite_risk
- 10 * cache_boundary_risk
解释:
• cacheable_churn_ratio:可缓存 segment 中变化的 token 占比。
• dynamic_prefix_ratio:第一个 cache boundary 之前的动态 token 占比。
• ordering_instability:canonicalization 前后工具 / MCP 顺序变化比例。
• role_rewrite_risk:system role 是否需要跨协议修正。
• cache_boundary_risk:cache breakpoint 是否被放在动态块之后。
评分用于告警和趋势,不用于决定是否发送请求。低分应触发诊断报告。
失败模式
| 失败模式 | 触发原因 | 修复策略 |
|---|---|---|
| 误删用户代码或 hash | 对全文做动态正则替换 | 只处理已解析 system 早段、metadata 和 known fields |
| 审计归因丢失 | strip 后不保存 metadata |
默认配合 preserve_as_metadata |
| telemetry 泄露工具名 | 日志输出裸 hash 或内部 tool name | 生产日志只输出 HMAC,名称走 allowlist |
| 工具排序仍抖动 | 同名工具缺少 tie-breaker | 使用 schema HMAC 做稳定排序 |
| gateway 误以为能控制客户端 | 把 env var 当服务端能力 | 区分客户端 env var 和 gateway sanitizer |
验证清单
| 测试 | 输入 | 期望 |
|---|---|---|
| attribution 变化 | 两个不同 fingerprint | strip 后 hash 相同 |
| 工具顺序变化 | 同一工具数组乱序 | canonical hash 相同 |
| 工具 schema 变化 | 新增参数 | tool hash 不同 |
| MCP 顺序变化 | server 返回顺序不同 | mcp hash 相同 |
| 动态路径 | tmp path 变化 | stable hash 不变 |
| cache boundary 错位 | 动态块在 breakpoint 前 | stability score 降低 |
参考链接
• Claude Code Environment Variables
• Claude Code LLM Gateway
• Anthropic Prompt Caching
• Anthropic Mid-conversation system messages
• anthropics/claude-code #50085
• musistudio/claude-code-router #1220
• Prompt Cache: Modular Attention Reuse
本文由非线智能API Claude Code 行业专家整理编写