Memory Tool:memory_20250818 实现跨会话持久记忆的完整机制
第二十六章:Context Editing:上下文注入、修改与精确控制
26.1 上下文是 Claude 的全部世界
对于 Claude 而言,它所知道的一切来源于它在当前调用中收到的信息:系统提示(system prompt)、对话历史(messages)、工具调用结果(tool results)。这些内容共同构成了 Claude 的"感知世界"。
**上下文工程(Context Engineering)**正是对这个感知世界的精确设计。它不是简单地向 Claude 堆砌信息,而是精心决策:什么时候注入什么信息、以什么格式呈现、放在什么位置。
Context Editing 与 Memory Tool 的区别在于:
- Memory Tool 关注跨会话的知识持久化
- Context Editing 关注单次会话内对 Claude 信息环境的精准控制
26.2 上下文的四个维度
维度一:位置(Position)
Claude 对消息的位置非常敏感。Anthropic 的研究显示,信息在上下文中的位置影响其被"注意"的程度:
- System prompt 最开头:最高优先级的全局指令
- System prompt 末尾:动态注入的实时信息(如当前时间、用户身份)
- 对话历史早期:背景设定、长期上下文
- 对话历史末尾(最近消息):Claude 注意力最集中的区域
- Assistant turn 开头:可以预填充来引导输出格式
维度二:格式(Format)
信息的格式决定 Claude 如何解析和使用它:
<!-- XML 标签格式:结构清晰,适合多块内容 -->
<user_profile>
<name>张伟</name>
<expertise>Python, FastAPI, PostgreSQL</expertise>
<preference>简洁风格,不需要过多解释</preference>
</user_profile>
<current_task>
重构认证模块,要求符合 JWT 最佳实践
</current_task>
# 当前会话上下文
## 用户信息
- 姓名:张伟
- 技术栈:Python, FastAPI, PostgreSQL
- 偏好:简洁风格,不需要过多解释
## 当前任务
重构认证模块,要求符合 JWT 最佳实践
XML 标签适合多类型信息混合注入,Markdown 格式在代码和文档生成任务中更自然。
维度三:时机(Timing)
什么时候注入信息与注入什么同样重要:
| 时机 | 注入内容 | 方式 |
|---|---|---|
| 会话初始化 | 用户画像、项目背景、记忆预取 | System prompt |
| 工具调用后 | 工具执行结果 | Tool result |
| 用户消息前 | 实时数据(股价、天气、数据库查询) | 注入到 user message |
| 长对话中间 | 上下文压缩摘要 | 替换历史消息 |
维度四:密度(Density)
上下文越多不等于越好。信息密度过高会导致"迷失在中间"(Lost in the Middle)问题——Claude 会更关注头部和尾部,中间部分的信息被忽视。
原则:只注入当前任务真正需要的信息。
26.3 系统提示的结构化设计
一个设计良好的系统提示应当分层组织:
import anthropic
from datetime import datetime
def build_system_prompt(
user: dict,
memories: list[dict],
current_tools: list[str],
domain: str = "general"
) -> str:
"""构建分层系统提示"""
sections = []
# 第一层:角色与核心原则(固定)
sections.append("""## 角色定义
你是 YiteAI 的智能助手,专注于帮助用户提高工作效率。
你的回复应当:
- 简洁直接,避免冗长解释
- 优先使用代码示例而非文字描述
- 遇到不确定的信息,明确标注而非猜测""")
# 第二层:用户上下文(动态)
if user:
user_ctx = f"""## 用户信息
- 姓名:{user.get('name', '未知')}
- 技术栈:{', '.join(user.get('skills', []))}
- 语言偏好:{user.get('language', 'Chinese')}"""
sections.append(user_ctx)
# 第三层:持久化记忆(动态)
if memories:
mem_lines = [f"- [{m['category']}] {m['content']}" for m in memories[:5]]
sections.append("## 历史记忆\n" + "\n".join(mem_lines))
# 第四层:可用工具说明(按需)
if current_tools:
tool_desc = "## 可用能力\n你可以使用以下工具:" + ", ".join(current_tools)
sections.append(tool_desc)
# 第五层:实时上下文(最后注入)
realtime = f"""## 当前状态
- 时间:{datetime.now().strftime('%Y-%m-%d %H:%M')} (CST)
- 领域:{domain}"""
sections.append(realtime)
return "\n\n".join(sections)
26.4 上下文注入技术
技术一:用户消息前缀注入
在用户消息前插入相关数据,而不污染系统提示:
def inject_realtime_data(user_message: str, context: dict) -> str:
"""在用户消息前注入实时数据"""
injections = []
if "stock_query" in context:
stock = context["stock_query"]
injections.append(
f"[实时数据] {stock['symbol']} 当前价格: {stock['price']}, "
f"涨跌: {stock['change']:+.2f}%"
)
if "db_results" in context:
results = context["db_results"]
injections.append(
f"[数据库查询结果]\n```json\n{json.dumps(results, ensure_ascii=False, indent=2)}\n```"
)
if injections:
prefix = "\n".join(injections) + "\n\n---\n\n"
return prefix + user_message
return user_message
# 使用示例
client = anthropic.Anthropic()
user_msg = "分析一下公司的用户增长趋势"
enriched_msg = inject_realtime_data(user_msg, {
"db_results": {
"monthly_users": [1200, 1450, 1680, 1920, 2310],
"churn_rate": 0.032,
"period": "2025-01 to 2025-05"
}
})
response = client.messages.create(
model="claude-opus-4-5",
max_tokens=1024,
messages=[{"role": "user", "content": enriched_msg}]
)
技术二:Assistant 预填充(Prefill)
通过预填充 assistant 的开头,精确控制输出格式:
def get_structured_output(prompt: str, output_template: str) -> str:
"""使用预填充引导结构化输出"""
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-opus-4-5",
max_tokens=2048,
messages=[
{"role": "user", "content": prompt},
# 预填充 assistant 回复的开头
{"role": "assistant", "content": output_template}
]
)
# 完整输出 = 预填充部分 + 生成部分
return output_template + response.content[0].text
# 示例:强制输出 JSON
result = get_structured_output(
prompt="分析以下代码的时间复杂度:\n\n```python\ndef bubble_sort(arr):\n n = len(arr)\n for i in range(n):\n for j in range(n-i-1):\n if arr[j] > arr[j+1]:\n arr[j], arr[j+1] = arr[j+1], arr[j]\n```",
output_template='{"time_complexity": "'
)
# 输出类似:{"time_complexity": "O(n²)", "space_complexity": "O(1)", "explanation": "..."}
技术三:多轮历史的精确修改
在某些情况下,需要修改历史对话以纠正错误或注入新信息:
class ConversationEditor:
"""精确控制对话历史的编辑器"""
def __init__(self):
self.messages: list[dict] = []
def append(self, role: str, content: str):
self.messages.append({"role": role, "content": content})
def inject_after_turn(self, turn_index: int, role: str, content: str):
"""在指定轮次后注入新消息"""
# turn_index 是 assistant/user 对的索引
msg_index = turn_index * 2 + 1
self.messages.insert(msg_index, {"role": role, "content": content})
def replace_last_assistant(self, new_content: str):
"""替换最后一条 assistant 消息(纠正输出)"""
for i in range(len(self.messages) - 1, -1, -1):
if self.messages[i]["role"] == "assistant":
self.messages[i]["content"] = new_content
return
def trim_to_last_n_turns(self, n: int):
"""保留最近 N 轮对话,截断早期历史"""
# 每轮包含 user + assistant 两条消息
keep = n * 2
if len(self.messages) > keep:
self.messages = self.messages[-keep:]
def inject_system_reminder(self, reminder: str):
"""在最后一条用户消息前注入提醒(模拟 system 注入)"""
# 找到最后一条 user 消息
for i in range(len(self.messages) - 1, -1, -1):
if self.messages[i]["role"] == "user":
# 在内容前添加提醒
original = self.messages[i]["content"]
if isinstance(original, str):
self.messages[i]["content"] = f"[系统提醒: {reminder}]\n\n{original}"
return
def get_messages(self) -> list[dict]:
return self.messages.copy()
技术四:动态 System Prompt 拼接
对于需要根据任务类型切换角色的 Agent,动态拼接系统提示比维护多个固定提示更灵活:
class DynamicPromptBuilder:
"""动态系统提示构建器"""
ROLE_BLOCKS = {
"code_reviewer": """
## 代码审查模式
你现在是一位严格的代码审查专家。重点关注:
- 安全漏洞(SQL 注入、XSS、越权)
- 性能问题(N+1 查询、内存泄漏)
- 代码可维护性(命名规范、函数长度)
每个问题必须标注严重程度:[CRITICAL/HIGH/MEDIUM/LOW]""",
"architect": """
## 架构设计模式
你现在是一位系统架构师。重点关注:
- 可扩展性:系统在 10x 负载下是否仍然可靠
- 解耦程度:各组件是否可以独立部署和替换
- 数据一致性:分布式场景下的一致性保证
使用架构图(用文字描述 C4 Model 各层)说明设计""",
"writer": """
## 技术写作模式
你现在是一位技术文档专家。重点关注:
- 读者背景:假设读者是高级工程师
- 结构清晰:使用标题、列表、代码块组织内容
- 示例驱动:每个概念配备可运行的代码示例"""
}
def build(self, base_prompt: str, roles: list[str],
extra_context: str = "") -> str:
blocks = [base_prompt]
for role in roles:
if role in self.ROLE_BLOCKS:
blocks.append(self.ROLE_BLOCKS[role])
if extra_context:
blocks.append(f"## 额外上下文\n{extra_context}")
return "\n\n".join(blocks)
26.5 长对话的上下文管理策略
当对话超过数十轮时,上下文管理成为核心挑战。
滑动窗口策略
def sliding_window_messages(messages: list[dict],
max_tokens: int = 150000,
min_keep_turns: int = 5) -> list[dict]:
"""
保持对话历史在 token 预算内。
始终保留最近 min_keep_turns 轮。
较早的历史按 token 成本从最旧开始裁剪。
"""
import anthropic
# 粗略估算:每个字符约 0.4 token(中文约 0.8)
def estimate_tokens(msg: dict) -> int:
content = msg.get("content", "")
if isinstance(content, str):
return len(content) // 2
return 100
# 必须保留的最近消息
must_keep = messages[-(min_keep_turns * 2):]
optional = messages[:-(min_keep_turns * 2)]
# 从最新开始,贪心选取可选消息
selected_optional = []
remaining_budget = max_tokens - sum(estimate_tokens(m) for m in must_keep)
for msg in reversed(optional):
cost = estimate_tokens(msg)
if remaining_budget - cost > 0:
selected_optional.insert(0, msg)
remaining_budget -= cost
else:
break
return selected_optional + must_keep
摘要注入策略
当早期历史需要丢弃时,先生成摘要再注入:
async def summarize_and_inject(
client: anthropic.Anthropic,
old_messages: list[dict],
current_messages: list[dict]
) -> list[dict]:
"""将早期历史压缩为摘要,注入到新对话开头"""
history_text = "\n".join([
f"{m['role'].upper()}: {m['content'][:500]}"
for m in old_messages
])
summary_response = client.messages.create(
model="claude-haiku-4-5", # 用便宜模型做摘要
max_tokens=512,
messages=[{
"role": "user",
"content": f"请用 3-5 句话摘要以下对话的关键信息和决策:\n\n{history_text}"
}]
)
summary = summary_response.content[0].text
summary_injection = {
"role": "user",
"content": f"[早期对话摘要]\n{summary}\n\n---"
}
summary_ack = {
"role": "assistant",
"content": "已理解早期对话上下文,请继续。"
}
return [summary_injection, summary_ack] + current_messages
26.6 上下文质量的评估
如何判断上下文设计是否有效?以下是几个实用指标:
指令遵循率
对于关键格式要求,通过程序化验证检查 Claude 是否遵循:
def evaluate_context_quality(
client: anthropic.Anthropic,
system: str,
test_cases: list[dict]
) -> float:
"""测量系统提示在测试集上的指令遵循率"""
pass_count = 0
for case in test_cases:
response = client.messages.create(
model="claude-haiku-4-5",
max_tokens=512,
system=system,
messages=[{"role": "user", "content": case["input"]}]
)
output = response.content[0].text
# 检查所有必须满足的条件
if all(checker(output) for checker in case["checks"]):
pass_count += 1
return pass_count / len(test_cases)
# 使用示例
test_cases = [
{
"input": "分析冒泡排序的时间复杂度",
"checks": [
lambda r: "O(n" in r, # 必须包含大O表示
lambda r: r.startswith("{"), # 必须是JSON格式
]
}
]
quality = evaluate_context_quality(client, system_prompt, test_cases)
print(f"指令遵循率: {quality:.1%}")
小结
Context Editing 是 Claude 工程实践中最精细的技术之一。通过精确控制信息的位置、格式、时机和密度,可以显著提升 Claude 的任务表现和输出一致性。
核心技术点:
- 分层系统提示:角色定义 → 用户上下文 → 历史记忆 → 工具说明 → 实时状态
- 消息前缀注入:在不污染系统提示的前提下动态添加实时数据
- Assistant 预填充:强制引导输出格式,特别适合 JSON/代码生成
- 滑动窗口 + 摘要注入:在长对话中保持上下文质量
- 动态 system prompt 拼接:根据任务类型灵活组合角色模块
下一章将介绍 Claude 内置的上下文压缩(Compaction)机制——当上下文窗口快要填满时,如何自动完成摘要与无损延续。