-
Notifications
You must be signed in to change notification settings - Fork 41
Description
Claude Sonnet 4.5 的记忆与上下文管理
学习如何使用 Claude 的记忆工具和上下文编辑功能构建能够跨对话学习和改进的 AI 智能体。
目录
设置
VSCode 用户
# 1. 创建虚拟环境
python -m venv .venv
# 2. 激活虚拟环境
source .venv/bin/activate # macOS/Linux
# 或者: .venv\Scripts\activate # Windows
# 3. 安装依赖
pip install -r requirements.txt
# 4. 在 VSCode 中:选择 .venv 作为内核(右上角)
API 密钥
cp .env.example .env
# 编辑 .env 并添加你的 ANTHROPIC_API_KEY
从这里获取你的 API 密钥:https://console.anthropic.com/
1. 简介:为什么记忆很重要 {#introduction}
本教程演示了Effective context engineering for AI agents中描述的上下文工程模式的实际实现。该文章涵盖了为什么上下文是有限资源、注意力预算如何工作,以及构建有效智能体的策略——这些技术你将在这里看到实际应用。
问题
大型语言模型具有有限的上下文窗口(Claude 4 为 200k 个令牌)。虽然这看起来很大,但会出现几个挑战:
- 上下文限制:长对话或复杂任务可能超出可用上下文
- 计算成本:处理大型上下文很昂贵 - 注意力机制呈二次方扩展
- 重复模式:跨对话的相似任务每次都需要重新解释上下文
- 信息丢失:当上下文填满时,早期的重要信息会丢失
解决方案
Claude Sonnet 4.5 引入了两个强大的功能:
-
记忆工具 (
memory_20250818
):启用跨对话学习- Claude 可以记录学到的内容以供将来参考
- 基于文件的系统,位于
/memories
目录下 - 客户端实现让你完全控制
-
上下文编辑 (
clear_tool_uses_20250919
):自动管理上下文- 当上下文增长过大时清除旧的工具结果
- 保留最近的上下文同时保存记忆
- 可配置的触发器和保留策略
好处
构建随时间在特定任务上变得更好的 AI 智能体:
- 会话 1:Claude 解决问题,记录模式
- 会话 2:Claude 立即应用学到的模式(更快!)
- 长会话:上下文编辑保持对话可管理
可以把它想象成给 Claude 一个笔记本来记笔记并回顾——就像人类做的那样。
2. 使用场景 {#use-cases}
记忆和上下文管理启用了强大的新工作流程:
🔍 代码审查助手
- 从过去的审查中学习调试模式
- 在未来会话中立即识别相似的错误
- 构建团队特定的代码质量知识
- 生产就绪:与 claude-code-action 集成进行 GitHub PR 审查
📚 研究助手
- 在多个会话中积累主题知识
- 连接不同研究线程的见解
- 维护参考书目和来源跟踪
💬 客户支持机器人
- 学习用户偏好和沟通风格
- 记住常见问题和解决方案
- 从交互中构建产品知识库
📊 数据分析助手
- 记住数据集模式和异常
- 存储有效的分析技术
- 随时间构建领域特定见解
支持的模型:Claude Opus 4 (claude-opus-4-20250514
)、Claude Opus 4.1 (claude-opus-4-1-20250805
)、Claude Sonnet 4 (claude-sonnet-4-20250514
) 和 Claude Sonnet 4.5 (claude-sonnet-4-5-20250929
)
本教程专注于代码审查助手,因为它清楚地演示了记忆(学习模式)和上下文编辑(处理长审查)。
3. 快速入门示例 {#quick-start}
让我们通过简单的示例看看记忆和上下文管理的实际应用。
设置
首先,安装依赖并配置你的环境:
# 安装所需包
# 选项 1:从 requirements.txt
# %pip install -q -r requirements.txt
# 选项 2:直接安装
%pip install -q anthropic python-dotenv ipykernel
.env
文件:
# 复制 .env.example 到 .env 并添加你的 API 密钥
cp .env.example .env
然后编辑 .env
添加你从 https://console.anthropic.com/ 获得的 Anthropic API 密钥
import os
from typing import Any, cast
from anthropic import Anthropic
from dotenv import load_dotenv
# 加载环境变量
load_dotenv()
API_KEY = os.getenv("ANTHROPIC_API_KEY")
MODEL = os.getenv("ANTHROPIC_MODEL")
if not API_KEY:
raise ValueError(
"未找到 ANTHROPIC_API_KEY。"
"复制 .env.example 到 .env 并添加你的 API 密钥。"
)
if not MODEL:
raise ValueError(
"未找到 ANTHROPIC_MODEL。"
"复制 .env.example 到 .env 并设置模型。"
)
MODEL = cast(str, MODEL)
client = Anthropic(api_key=API_KEY)
print("✓ API 密钥已加载")
print(f"✓ 使用模型:{MODEL}")
示例 1:基本记忆使用
让我们看看 Claude 如何使用记忆来存储信息以供将来参考。
辅助函数
这些示例使用来自 demo_helpers.py
的辅助函数:
-
run_conversation_loop()
:处理 API 对话循环- 调用启用了记忆工具的 Claude API
- 执行工具使用(记忆操作)
- 继续直到 Claude 停止使用工具
- 返回最终响应
-
run_conversation_turn()
:单轮对话(在示例 3 中使用)- 与上面相同,但在一次 API 调用后返回
- 当你需要细粒度控制时很有用
-
print_context_management_info()
:显示上下文清理统计- 显示节省的令牌、清除的工具使用
- 帮助可视化上下文编辑何时触发
以下单元格清除所有记忆文件,为此演示提供干净的起点。这对于多次运行笔记本以查看一致结果很有用。
在生产应用中,你应该仔细考虑是否清除所有记忆,因为这会永久删除学到的模式。考虑使用选择性删除或将记忆组织到项目特定的目录中。
# 导入辅助函数
from memory_demo.demo_helpers import run_conversation_loop, run_conversation_turn, print_context_management_info
from memory_tool import MemoryToolHandler
# 初始化
client = Anthropic(api_key=API_KEY)
memory = MemoryToolHandler(base_path="./demo_memory")
# 清除任何现有记忆以重新开始
print("🧹 清除之前的记忆...")
memory.clear_all_memory()
print("✓ 记忆已清除\n")
# 加载带有竞态条件错误的示例代码
with open("memory_demo/sample_code/web_scraper_v1.py", "r") as f:
code_to_review = f.read()
messages = [
{
"role": "user",
"content": f"我正在审查一个多线程网络爬虫,它有时返回的结果比预期少。计数在运行间不一致。你能找到问题吗?\n\n```python\n{code_to_review}\n```"
}
]
print("=" * 60)
print("📝 会话 1:从错误中学习")
print("=" * 60)
# 运行对话循环
response = run_conversation_loop(
client=client,
model=MODEL,
messages=messages,
memory_handler=memory,
system="你是一个代码审查员。",
max_tokens=2048,
max_turns=5,
verbose=True
)
print("\n" + "=" * 60)
print("✅ 会话 1 完成!")
print("=" * 60)
发生了什么?
- Claude 检查了它的记忆(首次运行时为空)
- 识别了错误:竞态条件 - 多个线程在没有同步的情况下修改共享状态(
self.results
和self.failed_urls
) - 在记忆中存储了并发模式以供将来参考
现在让我们看看魔法 - Claude 在新对话中应用这个学到的模式:
示例 2:跨对话学习
开始一个全新的对话 - 记忆持续存在!
# 新对话(空消息)
# 加载具有类似并发问题的 API 客户端代码
with open("memory_demo/sample_code/api_client_v1.py", "r") as f:
code_to_review = f.read()
messages = [
{
"role": "user",
"content": f"审查这个 API 客户端代码:\n\n```python\n{code_to_review}\n```"
}
]
print("=" * 60)
print("🚀 会话 2:应用学到的模式")
print("=" * 60)
# 运行对话循环
response = run_conversation_loop(
client=client,
model=MODEL,
messages=messages,
memory_handler=memory,
system="你是一个代码审查员。",
max_tokens=2048,
max_turns=5,
verbose=True
)
print("\n" + "=" * 60)
print("✅ 会话 2 完成!")
print("=" * 60)
注意区别:
- Claude 立即检查记忆并找到了线程安全/并发模式
- 立即识别了异步代码中的类似问题,无需重新学习
- 响应更快,因为它应用了关于共享可变状态的存储知识
这就是跨对话学习的实际应用!
示例 3:在保留记忆的同时清除上下文
在有许多代码文件的长审查会话中会发生什么?
- 上下文被之前审查的工具结果填满
- 但记忆(学到的模式)必须持续存在!
让我们触发上下文编辑来看看 Claude 如何自动管理这个。
配置说明: 我们使用 clear_at_least: 50
个令牌,因为记忆工具操作的结果很小(每个约 50-150 个令牌)。在生产环境中,对于更大的工具结果(如网络搜索或代码执行),你会使用更高的值,如 3000-5000 个令牌。
# 配置上下文管理以便演示时积极清除
CONTEXT_MANAGEMENT = {
"edits": [
{
"type": "clear_tool_uses_20250919",
"trigger": {"type": "input_tokens", "value": 5000}, # 更低的阈值以更快触发清除
"keep": {"type": "tool_uses", "value": 1}, # 只保留最后一个工具使用
"clear_at_least": {"type": "input_tokens", "value": 50}
}
]
}
# 从之前的会话继续 - 记忆持续存在!
# 添加多个代码审查以建立上下文
print("=" * 60)
print("📚 会话 3:带上下文清除的长审查会话")
print("=" * 60)
print()
# 审查 1:数据处理器(更大的文件)
with open("memory_demo/sample_code/data_processor_v1.py", "r") as f:
data_processor_code = f.read()
messages.extend([
{
"role": "user",
"content": f"审查这个数据处理器:\n\n```python\n{data_processor_code}\n```"
}
])
print("📝 审查 1:数据处理器")
response = run_conversation_turn(
client=client,
model=MODEL,
messages=messages,
memory_handler=memory,
system="你是一个代码审查员。",
context_management=CONTEXT_MANAGEMENT,
max_tokens=2048,
verbose=True
)
# 将响应添加到消息中
messages.append({"role": "assistant", "content": response[1]})
if response[2]:
messages.append({"role": "user", "content": response[2]})
print(f" 📊 输入令牌:{response[0].usage.input_tokens:,}")
context_cleared, saved = print_context_management_info(response[0])
print()
# 审查 2:添加 SQL 代码
with open("memory_demo/sample_code/sql_query_builder.py", "r") as f:
sql_code = f.read()
messages.extend([
{
"role": "user",
"content": f"审查这个 SQL 查询构建器:\n\n```python\n{sql_code}\n```"
}
])
print("📝 审查 2:SQL 查询构建器")
response = run_conversation_turn(
client=client,
model=MODEL,
messages=messages,
memory_handler=memory,
system="你是一个代码审查员。",
context_management=CONTEXT_MANAGEMENT,
max_tokens=2048,
verbose=True
)
messages.append({"role": "assistant", "content": response[1]})
if response[2]:
messages.append({"role": "user", "content": response[2]})
print(f" 📊 输入令牌:{response[0].usage.input_tokens:,}")
context_cleared, saved = print_context_management_info(response[0])
print()
print("=" * 60)
print("✅ 会话 3 完成!")
print("=" * 60)
刚才发生了什么?
随着多次审查期间上下文的增长:
- 上下文清除自动触发,当输入令牌超过 5,000 时
- 旧的工具结果被移除 - 清除了 2 个工具使用,每次节省约 66 个令牌
- 记忆文件保持完整 - Claude 仍然可以查询学到的模式
- 令牌使用继续增长,但由于清除而增长速度较慢
这演示了关键好处:
- 短期记忆(带工具结果的对话上下文)→ 清除以节省空间
- 长期记忆(
/memories
中存储的模式)→ 跨会话持续存在
为什么令牌节省这么少? 记忆工具操作返回紧凑的结果(文件路径、成功消息)。str_replace
操作只返回"文件编辑成功"加上元数据。在具有更大工具结果(返回完整文章的网络搜索、具有长输出的代码执行)的生产用例中,上下文清除将节省数千个令牌。
让我们验证记忆在清除后仍然存在:
# 验证记忆在上下文清除后持续存在
import os
print("📂 demo_memory/ 中的记忆文件:")
print()
for root, dirs, files in os.walk("./demo_memory"):
# 计算显示的相对路径
level = root.replace("./demo_memory", "").count(os.sep)
indent = " " * level
folder_name = os.path.basename(root) or "demo_memory"
print(f"{indent}{folder_name}/")
sub_indent = " " * (level + 1)
for file in files:
file_path = os.path.join(root, file)
size = os.path.getsize(file_path)
print(f"{sub_indent}├── {file} ({size} 字节)")
print()
print("✅ 尽管上下文清除,所有学到的模式都得到保留!")
4. 工作原理 {#how-it-works}
记忆工具架构
记忆工具是客户端的 - 你控制存储。Claude 进行工具调用,你的应用程序执行它们。
记忆工具命令
命令 | 描述 | 示例 |
---|---|---|
view |
显示目录或文件内容 | {"command": "view", "path": "/memories"} |
create |
创建或覆盖文件 | {"command": "create", "path": "/memories/notes.md", "file_text": "..."} |
str_replace |
替换文件中的文本 | {"command": "str_replace", "path": "...", "old_str": "...", "new_str": "..."} |
insert |
在行号处插入文本 | {"command": "insert", "path": "...", "insert_line": 2, "insert_text": "..."} |
delete |
删除文件或目录 | {"command": "delete", "path": "/memories/old.txt"} |
rename |
重命名或移动文件 | {"command": "rename", "old_path": "...", "new_path": "..."} |
查看 memory_tool.py
了解包含路径验证和安全措施的完整实现。
理解演示代码
来自 code_review_demo.py
的关键实现细节:
class CodeReviewAssistant:
def __init__(self, memory_storage_path="./memory_storage"):
self.client = Anthropic(api_key=API_KEY)
self.memory_handler = MemoryToolHandler(base_path=memory_storage_path)
self.messages = []
def review_code(self, code, filename, description=""):
# 1. 添加用户消息
self.messages.append({...})
# 2. 带工具执行的对话循环
while True:
response = self.client.beta.messages.create(
model=MODEL,
system=self._create_system_prompt(),
messages=self.messages,
tools=[{"type": "memory_20250818", "name": "memory"}],
betas=["context-management-2025-06-27"],
context_management=CONTEXT_MANAGEMENT
)
# 3. 执行工具使用
tool_results = []
for content in response.content:
if content.type == "tool_use":
result = self._execute_tool_use(content)
tool_results.append({...})
# 4. 如果有工具使用则继续,否则完成
if tool_results:
self.messages.append({"role": "user", "content": tool_results})
else:
break
关键模式:在有工具使用时持续调用 API,执行它们并将结果反馈回去。
Claude 实际学到了什么
这就是记忆强大的原因 - 语义模式识别,而不仅仅是语法:
会话 1:基于线程的网络爬虫
# 错误:竞态条件
class WebScraper:
def __init__(self):
self.results = [] # 共享状态!
def scrape_urls(self, urls):
with ThreadPoolExecutor() as executor:
for future in as_completed(futures):
self.results.append(future.result()) # 竞态!
Claude 在记忆中存储的内容(示例文件:/memories/concurrency_patterns/thread_safety.md
):
当 Claude 遇到这种模式时,它将以下见解存储到其记忆文件中:
- 症状:并发操作中的不一致结果
- 原因:多个线程修改的共享可变状态(列表/字典)
- 解决方案:使用锁、线程安全数据结构或返回结果
- 红旗:线程回调中的实例变量、未使用的锁、计数器增量
会话 2:异步 API 客户端(新对话!)
Claude 首先检查记忆,找到线程安全模式,然后:
- 识别异步代码中的类似模式(协程也可以交错)
- 立即应用解决方案(无需重新学习)
- 解释并参考存储的知识
# Claude 立即发现这个:
async def fetch_all(self, endpoints):
for coro in asyncio.as_completed(tasks):
self.responses.append(await coro) # 相同模式!
为什么这很重要:
- ❌ 语法检查器完全错过竞态条件
- ✅ Claude 学习架构模式并跨上下文应用它们
- ✅ 跨语言:模式也适用于 Go、Java、Rust 并发
- ✅ 变得更好:每次审查都会添加到知识库中
示例代码文件
演示使用这些示例文件(都有并发/线程安全错误):
memory_demo/sample_code/web_scraper_v1.py
- 竞态条件:线程修改共享状态memory_demo/sample_code/api_client_v1.py
- 异步上下文中的类似并发错误memory_demo/sample_code/data_processor_v1.py
- 长会话演示的多个并发问题
让我们看看其中一个:
memory_demo/sample_code/web_scraper_v1.py
"""
具有竞态条件错误的并发网络爬虫。
多个线程在没有同步的情况下修改共享状态。
"""
import time
from concurrent.futures import ThreadPoolExecutor, as_completed
from typing import List, Dict
import requests
class WebScraper:
"""并发获取多个 URL 的网络爬虫。"""
def __init__(self, max_workers: int = 10):
self.max_workers = max_workers
self.results = [] # 错误:多个线程访问的共享可变状态!
self.failed_urls = [] # 错误:另一个竞态条件!
def fetch_url(self, url: str) -> Dict[str, any]:
"""获取单个 URL 并返回结果。"""
try:
response = requests.get(url, timeout=5)
response.raise_for_status()
return {
"url": url,
"status": response.status_code,
"content_length": len(response.content),
}
except requests.exceptions.RequestException as e:
return {"url": url, "error": str(e)}
def scrape_urls(self, urls: List[str]) -> List[Dict[str, any]]:
"""
并发爬取多个 URL。
错误:self.results 被多个线程访问而没有锁定!
这会导致结果丢失或损坏的竞态条件。
"""
with ThreadPoolExecutor(max_workers=self.max_workers) as executor:
futures = [executor.submit(self.fetch_url, url) for url in urls]
for future in as_completed(futures):
result = future.result()
# 竞态条件:多个线程同时向 self.results 追加
if "error" in result:
self.failed_urls.append(result["url"]) # 竞态条件
else:
self.results.append(result) # 竞态条件
return self.results
错误:多个线程在没有锁定的情况下修改 self.results
和 self.failed_urls
!
Claude 将:
- 识别竞态条件
- 在
/memories/concurrency_patterns/thread_safety.md
中存储模式 - 在会话 2 中将此并发模式应用于异步代码
演示概述
我们构建了一个完整的代码审查助手。实现在 memory_demo/code_review_demo.py
中。
运行交互式演示:
python memory_demo/code_review_demo.py
演示展示了:
- 会话 1:审查带有错误的 Python 代码 → Claude 学习模式
- 会话 2:审查类似代码(新对话)→ Claude 应用模式
- 会话 3:长审查会话 → 上下文编辑保持可管理性
7. 最佳实践与安全 {#best-practices}
记忆管理
应该做的:
- ✅ 存储任务相关模式,而不是对话历史
- ✅ 使用清晰的目录结构组织
- ✅ 使用描述性文件名
- ✅ 定期审查和清理记忆
不应该做的:
- ❌ 存储敏感信息(密码、API 密钥、PII)
- ❌ 让记忆无限增长
- ❌ 不加选择地存储所有内容
安全:路径遍历保护
关键:始终验证路径以防止目录遍历攻击。查看 memory_tool.py
了解实现。
安全:记忆中毒
缓解策略:
- 内容清理:在存储前过滤危险模式
- 记忆范围隔离:按用户/按项目隔离
- 记忆审计:记录和扫描所有记忆操作
- 提示工程:指示 Claude 忽略记忆中的指令
查看 memory_tool.py
了解完整的安全实现,以及 tests/
中的测试。
下一步
资源
- API 文档:Claude API 参考
- 使用文档:记忆工具
- GitHub Action:claude-code-action
- AWS/Bedrock 实现:AWS 上的 Anthropic 记忆功能 - Bedrock 特定实现
- 支持:support.claude.com
反馈
记忆和上下文管理目前处于测试阶段。分享你的反馈以帮助我们改进!