Claude Code团队分享:Context Engineering最佳实践与高价值Prompt模板解析
和大模型聊过天的同学都知道,它“记性”差得离谱:
- 聊着聊着就把前面的需求忘了
- 一旦对话超过 4k token,回答就开始“跑偏”
- 把 A 项目的接口文档塞进去,结果它把 B 项目的代码也混在一起
这些“上下文灾难”归根结底是Context Engineering(上下文工程)没做好。Claude Code 团队在过去 8 个月、累计 200+ 内部插件的迭代里,把上下文管理从“拍脑袋”打磨成一套可复制的工程套路。下面把踩过的坑、验证过的模板、能跑的代码一次性放出来,方便大家直接抄作业。
1. 为什么上下文工程决定 AI 交互的生死
- 大模型没有真正的“长记忆”,它只认当前输入的 token 序列。
- 上下文=“提示词+历史对话+外部知识”,一旦冗余或缺失,就会触发:
- 幻觉:把过期信息当成事实
- 指令漂移:用户改一次需求,模型却沿用旧指令
- 性能雪崩:token 翻倍 → 延迟翻倍 → 费用翻倍
一句话:上下文管理不是锦上添花,是生死线。
2. 三种主流方案对比:全量记忆 vs 滑动窗口 vs 关键信息提取
| 方案 | 优点 | 缺点 | 适用场景 | |---|---|---|---|---| | 全量记忆
(把历史对话一股脑塞进去) | 实现简单,不丢信息 | 超过上下文上限就爆炸,延迟高 | 一次性脚本、<10 轮的小工具 | | 滑动窗口
(只保留最近 N 轮) | 内存可控,延迟稳定 | 容易丢失“远古”关键指令 | 客服、闲聊 | | 关键信息提取
(动态提炼摘要/实体) | 长度可控,信息密度高 | 需要额外模型或规则,实现复杂 | 生产环境最推荐 |
Claude Code 内部组合了 2+3:用滑动窗口保证“近期细节”,用关键信息提取保留“全局指令”,下面详解。
3. Claude Code 验证有效的 Prompt 模板结构
团队把模板拆成 5 段,每段用特殊标记包裹,方便正则解析与动态替换:
===SYSTEM=== 你是一名安全审计员,只回答与安全相关的问题,拒绝任何无关请求。 ===GLOBAL_FACT=== 项目语言: Python 主分支: main 依赖文件: requirements.txt, poetry.lock ===EPHEMERAL=== {用户刚刚说的话} ===HISTORY=== {最近 3 轮对话摘要} ===TASK=== {本次具体任务,由用户在 EPHEMERAL 中触发}- SYSTEM:全局角色,永不更改。
- GLOBAL_FACT:跨会话静态知识,项目配置、API 密钥名(不含值)。
- EPHEMERAL:用户最新输入,生命周期仅一次请求。
- HISTORY:滑动窗口+摘要,每轮请求后更新。
- TASK:零拷贝引用,避免重复描述需求。
优先级按从上往下递减,模型注意力天然靠前,重要的事放前头。
4. Python 实现:上下文感知对话系统
下面给出最小可运行版本,含异常处理 + 内存优化,依赖tiktoken做 token 计数,openai库可无缝换成 Claude 官方 SDK。
import tiktoken, json, os from typing import List, Dict ENC = tiktoken.get_encoding("cl100k_base") MAX_TOKEN = 8000 # 模型最大窗口 RESERVE_TOKEN = 500 # 给回答留余量 class ContextManager: def __init__(self, system: str, global_fact: str): self.system = system self.global_fact = global_fact self.history: List[Dict[str,str]] = [] # {"user": "..", "assistant": ".."} # --- 对外唯一入口 ------------------------------------ def make_prompt(self, user_input: str) -> str: ephemeral = user_input.strip() history_text = self._compress_history() task = self._extract_task(ephemeral) prompt = f"""===SYSTEM===\n{self.system}\n===GLOBAL_FACT===\n{self.global_fact}\n===EPHEMERAL===\n{ephemeral}\n===HISTORY===\n{history_text}\n===TASK===\n{task}""" # 如果仍然超长,按 token 优先级逐段裁剪 prompt = self._fit_token_limit(prompt) return prompt # --- 内部工具 ---------------------------------------- def _compress_history(self, n_round=3) -> str: """只保留最近 n_round 轮,且对每轮做 1 句话摘要""" recent = self.history[-n_round:] summary = [] for turn in recent: user, bot = turn["user"], turn["assistant"] summary.append(f"User:{user[:50]}... Assistant:{bot[:50]}...") return "\n".join(summary) def _extract_task(self, user_input: str) -> str: """简单示范:把用户输入里第一个动词短语当任务""" words = user_input.split() return " ".join(words[:6]) # 取前 6 个词 def _fit_token_limit(self, prompt: str) -> str: """按行逆序丢弃 HISTORY,直到满足 token 限制""" lines = prompt.splitlines() while len(ENC.encode("\n".join(lines))) > MAX_TOKEN - RESERVE_TOKEN: # 找到第一个 HISTORY 行并删除 for idx, line in enumerate(lines): if line.startswith("===HISTORY==="): del lines[idx+1] # 删除内容行 break else: break # 删无可删 return "\n".join(lines) # --- 请求完成后回调,更新历史 ------------------------- def update_history(self, user_input: str, assistant_output: str): self.history.append({"user": user_input, "assistant": assistant_output}) # 内存友好:持久化到磁盘,防止进程重启丢失 with open("context_cache.jsonl", "a", encoding="utf-8") as f: f.write(json.dumps({"user": user_input, "assistant": assistant_output}, ensure_ascii=False) + "\n")异常处理示例
- 如果
_fit_token_limit删到 HISTORY 为空仍超限,抛ContextOverflowError,上游捕获后走“长文档分段”策略。 - 磁盘写入失败捕获
OSError,降级到内存队列,保证主流程不崩。
5. 性能考量:别让上下文成为延迟刺客
- token ∝ 延迟
Claude 3 实测:输入 1k→10k token,首 token 延迟从 0.3s 线性涨到 2.1s。 - 多轮内存管理
- 每轮请求后把
update_history增量写入jsonl,进程重启可热加载。 - 对 GLOBAL_FACT 做懒加载:首次用到才读文件,常驻程并发场景减少 30% 内存。
- 每轮请求后把
- 并行场景
多用户共用一台推理节点时,给每个session_id维护独立ContextManager实例,用完即del,防止 Python 循环引用堆积。
6. 生产环境避坑指南
上下文污染预防
- 不同项目用不同的
GLOBAL_FACT文件,CI 自动校验“是否交叉引用”。 - 上线前跑回归用例:把过去 100 条真实提问重放,检测答案是否混入其他项目文件名。
- 不同项目用不同的
敏感信息过滤
- 在
_compress_history里加正则:r"sk-[a-zA-Z0-9]{48}"替换成<REDACTED>。 - 对上传日志开白名单字段,其余字段一律打
***。
- 在
对话状态持久化
- 用
jsonl而不是sqlite,方便tail -f实时观察,也避免锁竞争。 - 设置 7 天 TTL,定时
cron清理过期文件,符合 GDPR “可遗忘”要求。
- 用
7. 开放讨论:如何平衡上下文丰富度与系统性能?
Claude Code 团队内部也还没找到银弹:
- 摘要模型太小,丢细节;太大,延迟又上去。
- 把上下文全扔给向量库做检索增强,结果召回 Top5 不一定覆盖当前任务。
你在业务里怎么选?
- 用滑动窗口还是摘要?
- 是否愿意牺牲一点准确率,把 token 压到 2k 以内换 50% 的延迟下降?
欢迎留言交流,一起把“上下文”这件小事做成真正可工程化的基础设施。