源文件:chapter3/user-memory-evaluation/README.md 用户记忆评测框架 一套用于测试 AI Agent 记忆能力的综合评测框架,涵盖三个递进复杂度的层级。本框架使用贴近真实的业务对话场景,评估 Agent 能否有效地从用户交互中存储、检索并利用信息。 概览 框架通过三个不同层级评估 Agent 的记忆系统: 第 1 层:基础召回与直接检索 测试 Agent 能否准确存储并检索单次对话中明确、无歧义的信息,例如账号、确认码、预约详情等。 第 2 层:上下文推理与消歧 评估 Agent 处理模糊请求的能力——需要从多次对话中检索全部相关信息,并识别何时需要澄清。Agent 必须理解上下文,避免主观臆断。
源文件:chapter3/user-memory-evaluation/README.md
一套用于测试 AI Agent 记忆能力的综合评测框架,涵盖三个递进复杂度的层级。本框架使用贴近真实的业务对话场景,评估 Agent 能否有效地从用户交互中存储、检索并利用信息。
框架通过三个不同层级评估 Agent 的记忆系统:
测试 Agent 能否准确存储并检索单次对话中明确、无歧义的信息,例如账号、确认码、预约详情等。
评估 Agent 处理模糊请求的能力——需要从多次对话中检索全部相关信息,并识别何时需要澄清。Agent 必须理解上下文,避免主观臆断。
评估 Agent 能否随时间跨多次对话综合信息、识别关键关联,并在未被明确要求时提供主动协助。
本仓库最核心的用途是对比记忆系统在该三层
套件上的表现,并读出一张打分表。它完全离线(无需 API 密钥),
使用 keyword-recall 指标计算 fixtures/ 中预制 fixture 的结果:
python main.py --mode compare --metric keyword-recall
真实输出(8 个带标注测试用例,四种记忆配置):
Memory System Comparison (Keyword Recall, 0.000-1.000) ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━┓ ┃ Layer ┃ full_ctx ┃ json_card ┃ simple_nt ┃ no_memry ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━┩ │ Layer 1 · Basic Recall │ 1.000 │ 1.000 │ 0.417 │ 0.000 │ │ Layer 2 · Disambiguation │ 1.000 │ 1.000 │ 0.333 │ 0.000 │ │ Layer 3 · Proactive Synthesis │ 1.000 │ 1.000 │ 0.125 │ 0.000 │ │ Overall │ 1.000 │ 1.000 │ 0.323 │ 0.000 │ └───────────────────────────────┴───────────┴───────────┴───────────┴──────────┘
这些分数由 recall 指标从 fixtures/system_responses.example.json 计算得出(而非
手写);它们复现了书中的观察:Simple Notes 能通过大多数第 1 层
召回用例,但在需要消歧和跨会话综合的第 2/3 层用例上急剧退化,而
Advanced JSON Cards 在三层上都保持稳健。
fixtures/gold_facts.json — 每个回答必须召回的关键事实,逐字test_cases/*.yaml 中的对话(无任何捏造值)。fixtures/system_responses.example.json — 四种配置下的示例回答。把它{system_name: {test_id: answer}})即可对标评测。pip install -r requirements.txt
cp env.example .env # 编辑 .env,填入你的 API 凭证
CLI 自带中文 --help;运行 python main.py --help 查看完整
列表。关键参数:
| 参数 | 含义 |
|---|---|
--mode {interactive,demo,batch,compare} |
运行模式(默认 interactive) |
--metric {llm-judge,keyword-recall} |
打分器:LLM-as-judge(需 API)或离线关键事实召回 |
--responses PATH |
回答 JSON(batch:{test_id: ans};compare:{system: {test_id: ans}}) |
--gold PATH |
keyword-recall 的金标准标注(默认 fixtures/gold_facts.json) |
--category {layer1,layer2,layer3} |
仅限定某一层 |
--test-cases-dir PATH |
替代的测试用例(数据集)目录 |
--evaluator {kimi,openai} / --model NAME |
llm-judge 的裁判后端 / 模型覆盖 |
--output PATH |
报告输出文件 |
--list |
离线:列出全部测试用例后退出 |
# 离线、确定性(无需 API): python main.py --mode compare --metric keyword-recall --output compare.txt # 仅最难的一层: python main.py --mode compare --metric keyword-recall --category layer3 # 对相同系统做 LLM-as-judge 打分(需要 API 密钥): python main.py --mode compare --metric llm-judge --evaluator kimi
运行交互式评测界面:
python main.py --mode interactive
它提供一个菜单驱动的界面来:
查看带示例回答的示例评测:
python main.py --mode demo
以编程方式评测多个测试用例:
python main.py --mode batch --responses agent_responses.json
JSON 文件应将测试 ID 映射到 Agent 回答:
{ "layer1_01_bank_account": "Your checking account number is 4429853327.", "layer1_02_insurance_claim": "Your claim number is CLM-2024-894327..." }
from framework import UserMemoryEvaluationFramework # 初始化框架 framework = UserMemoryEvaluationFramework() # 列出测试用例 test_cases = framework.list_test_cases(category="layer1") # 获取某测试的对话历史 histories = framework.get_conversation_histories("layer1_01_bank_account") # 获取用户问题 question = framework.get_user_question("layer1_01_bank_account") # 提交 Agent 回答进行评测 result = framework.submit_and_evaluate( test_id="layer1_01_bank_account", agent_response="Your checking account number is 4429853327.", extracted_memory=None # 可选 ) # 查看结果 print(f"Reward: {result.reward:.3f}") # 0.0 到 1.0 的连续分数 print(f"Passed: {result.reward >= 0.6}") # reward >= 0.6 即通过 print(f"Reasoning: {result.reasoning}")
每个测试用例包含:
第 1 层示例:
第 2 层示例:
第 3 层示例:
两个可互换的打分器产生 [0.0, 1.0] 区间的连续 reward:
keyword-recall(离线、确定性)关键事实召回:reward = (# 答案中找到的金标准事实) / (# 金标准事实),
采用归一化的子串匹配(大小写 / 空白不敏感;一个事实可列出
多种可接受的表层形式)。无需 API 密钥,因此驱动了离线
对比表。金标准事实存放在 fixtures/gold_facts.json。
llm-judge(LLM-as-judge,需 API)使用裁判 LLM(Kimi 或 OpenAI)依据测试用例的evaluation_criteria 和 expected_behavior 对语义质量打分,考虑:
编辑 config.py 或 .env 文件:
# 评测器 LLM 设置 KIMI_API_KEY=your_key_here DEFAULT_EVALUATOR=kimi # 或 openai MAX_RETRIES=3 REQUEST_TIMEOUT=60
在对应的类别文件夹中创建 YAML 文件:
test_id: layer1_new_case category: layer1 title: New Test Case Title conversation_histories: - conversation_id: conv_001 timestamp: "2024-11-20 10:00:00" messages: - role: user content: "User message" - role: assistant content: "Assistant response" # ... 50+ 轮 user_question: "What information should I retrieve?" evaluation_criteria: description: "What to evaluate" required_information: - "Key piece of information" success_indicators: - "Signs of success" expected_behavior: "Ideal response"
扩展 LLMEvaluator 类:
class CustomEvaluator(LLMEvaluator): def evaluate(self, test_case, agent_response, extracted_memory=None): # 自定义评测逻辑 return EvaluationResult(...)
MIT License - 详情见 LICENSE 文件
欢迎贡献!可改进的方向:
如果在研究中使用本框架,请引用:
User Memory Evaluation Framework A comprehensive testing suite for AI agent memory systems https://github.com/your-repo/user-memory-evaluation
This experiment now supports a universal OpenRouter fallback for its chat LLM.
MOONSHOT_API_KEY / KIMI_API_KEY / OPENAI_API_KEY / DOUBAO_API_KEY …) is present, behavior is unchanged.OPENROUTER_API_KEY is set, the chat LLM is automatically routed through OpenRouter (https://openrouter.ai/api/v1). Model names are mapped automatically: gpt-*/o1-* → openai/…, claude-* → anthropic/claude-opus-4.8, kimi-* → moonshotai/kimi-k2.6, ids already containing / are kept as-is, and other provider-native ids (e.g. doubao-*) fall back to openai/gpt-5.6-luna. Set OPENROUTER_MODEL to force a specific OpenRouter model id.Add OPENROUTER_API_KEY=... to your .env (see env.example) to enable it.