Agent Memory Demo

一个最小可运行、可观察、可验证的记忆型 Agent Demo。

技术栈:

  • LangChain + LangGraph ReAct Agent
  • 文件系统 Memory Store(长期 / 会话 / 每日 / 日志)
  • FastAPI + 前端单页聊天界面

本项目的重点不是“聊天壳子”,而是 memory 的工程化设计:

  • 记忆如何分层
  • 如何用 message_id 做锚点检索
  • 如何窗口扩展上下文
  • 工具调用如何持久化并在前端回放

完整项目可以在Github获取。

Memory 设计总览

1. 分层模型

user_id 隔离,核心数据位于 memory/{user_id}/

1
2
3
4
5
6
7
8
9
10
memory/
{user_id}/
memory.md # 长期记忆(整份文本)
conversations.json # 会话列表索引(title + updated_at)
sessions/
{session_id}.jsonl # 会话短期记忆
daily/
YYYY-MM-DD.jsonl # 当日记忆
logs/
llm_dialogue.jsonl # 每轮完整日志(含工具调用)

分层职责:

  • 长期记忆(memory.md):稳定偏好、长期事实。
  • 会话记忆(sessions/*.jsonl):当前对话线程上下文。
  • 每日记忆(daily/*.jsonl):跨会话的当天信息聚合。
  • 日志(logs/llm_dialogue.jsonl):可追溯审计,记录每轮输入、上下文、输出、工具轨迹。

2. 统一消息结构

sessiondaily 均使用 JSONL 单行消息,字段统一:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"ts": "2026-04-08T10:00:00",
"role": "assistant",
"content": "回复内容",
"tags": ["session"],
"meta": {
"tool_calls": [
{
"name": "search_session",
"input": "找工作",
"output": "#11 ..."
}
]
},
"message_id": 12
}

关键点:

  • message_id 在单个文件内单调递增(从 1 开始),作为检索锚点。
  • 历史老数据若缺失 message_id,读取时会自动标准化补齐。
  • assistant 消息会持久化 tool_callsmeta,前端刷新后仍可回放工具调用。

3. 检索策略:锚点 + 窗口

核心不是“搜到一条就结束”,而是两段式:

  1. 搜索:
  • search_session(keyword)
  • search_daily(keyword, day)

返回命中消息及 message_id

  1. 扩展:
  • get_session_window(message_id, before, after)
  • get_daily_window(message_id, before, after, day)

围绕锚点拉取前后文,解决“答案在下一条 / 上一条”的问题。

4. 上下文组装策略

当前 chat 默认上下文策略:

  • 注入最近 3 轮 session 摘要(实现中按 6 条消息)
  • 默认不直接注入 daily(daily_limit=0),由 Agent 按需调用工具检索
  • 长期记忆来自 memory.md 全文

Agent 系统提示词明确要求:

  • 优先用工具,能调用就调用
  • 只有工具确实无法解决时才允许不调用
  • 对可验证问题禁止猜测回答

5. 可观测性与前端回放

每轮 /api/chat 返回:

  • reply
  • memory_hits
  • title
  • tool_calls

同时 tool_calls 会持久化:

  • 写入 session/daily 消息 meta.tool_calls
  • 写入 logs/llm_dialogue.jsonl

历史加载 /api/conversations/{session_id}/messages 时会返回每条消息的 tool_calls,前端展示为可折叠工具面板,支持刷新后继续查看。

核心流程(单轮对话)

  1. 用户消息写入 session + daily
  2. 读取并构建 memory context
  3. Agent 按提示词优先调用检索工具
  4. 生成回复 + 工具轨迹
  5. assistant 消息(含工具轨迹)写入 session + daily
  6. 追加 llm_dialogue 日志
  7. 更新 conversations.jsonupdated_at

API

  • POST /api/chat

    • 入参:user_id, session_id, message
    • 出参:reply, memory_hits, title, tool_calls
  • POST /api/conversations

    • 入参:user_id
    • 出参:session_id
  • GET /api/conversations?user_id=...

    • 返回会话列表(来源于 conversations.json,按 updated_at 倒序)
  • GET /api/conversations/{session_id}/messages?user_id=...

    • 返回会话消息历史(含 message_idtool_calls

快速开始

  1. 安装依赖
1
python -m pip install -e .[dev]
  1. 配置 LLM

编辑 config/llm.yaml

1
2
3
4
llm:
api_key: "your_key"
model: "gpt-4o-mini"
base_url: "https://api.openai.com/v1"

api_key 为空时,系统会使用 fallback 回复逻辑,便于本地验证 memory 流程。

  1. 启动服务
1
uvicorn agent_memory_demo.app:app --reload
  1. 打开页面
1
http://127.0.0.1:8000

测试

1
pytest -q

适合继续扩展的方向

  • 将长期记忆从全文注入升级为结构化条目 + 检索排序。
  • 增加“记忆冲突检测”与合并策略(偏好变更追踪)。
  • 将工具调用日志做成可筛选时间线(按工具名/关键词过滤)。
  • 引入向量召回并与当前关键词检索做 hybrid rerank。