第 7 章 记忆与会话系统¶
本章学习目标 - 深入理解 Agent 记忆模式的分类维度(短期/长期、语义/情景/程序、向量 vs 结构化) - 掌握 TTD 的四层记忆架构(Working / Profile / Episodic / Correction)与认知科学对应 - 深度理解 SQL 语义缓存与动态 Few-Shot 自学习的工程实现 - 对比 MemGPT/Letta 自治记忆与 TTD 触发式记忆的取舍 - 理解记忆形成、衰减、TTL 的生命周期理论 - 认清当前记忆系统的工程权衡与改进方向
前置知识:第 4 章 Agent 编排、第 5 章 RAG 检索 关联代码:
backend/app/memory/(facade/formation/long_term/short_term/sql_cache/dynamic_few_shot/term_mapping)
7.1 背景与动机¶
7.1.1 为什么 Agent 需要记忆¶
没有记忆的 Agent 是"金鱼"——每次对话从零开始,无法记住用户偏好、历史成功模式、被纠正的错误。在 NL2SQL 场景,记忆的价值尤其明显:
| 记忆类型 | 价值 | 例子 |
|---|---|---|
| 用户偏好 | 减少重复澄清 | "我习惯看折线图"、"我常查华东区" |
| 成功交互 | 复用经验 | 上次"GMV 同比"查得很好 → 类似问题复用 |
| 纠正记录 | 避免重蹈覆辙 | 用户上次纠正了"GMV 不含退款" → 以后别再错 |
| SQL 复用 | 大幅降延迟 | 相同问题直接复用已验证 SQL |
7.1.2 Agent 记忆模式分类¶
AI Agent 理论关联:Agent 记忆模式
Agent 记忆有多种分类维度,理解这些维度是设计记忆系统的基础:
按时间维度: - 短期记忆(Working Memory):当前上下文,容量有限(context window),随会话结束消失。对应人类的"工作记忆"。 - 长期记忆(Long-term Memory):跨会话持久化,容量大,需主动检索。对应人类的"长期记忆"。
按内容维度(认知科学经典分类): - 语义记忆(Semantic Memory):事实与知识——"用户偏好折线图"、"GMV 定义是 SUM(amount)"。 - 情景记忆(Episodic Memory):具体经历——"上次查 GMV 同比成功了"、"用户上周问过退货率"。 - 程序记忆(Procedural Memory):如何做事——"这种查询走这条路"、"术语消歧应该这样纠正"。
按实现维度: - 向量记忆:把记忆存为 embedding,用相似度检索。适合模糊召回。 - 结构化记忆:把记忆存为结构化记录(KV/关系表),用精确查询。适合事实查询。 - 混合记忆:两者结合。
代表性记忆架构: - MemGPT / Letta:分层记忆 + 自治记忆管理。LLM 通过 function call 自主决定何时读/写/遗忘记忆。类比操作系统的内存分级:main context(工作记忆,在 context window 内)、external context(归档记忆,在 context window 外,需检索调入)、recall memory(对话历史)。详见 arxiv.org/abs/2310.08560。 - Generative Agents(斯坦福小镇):情景记忆 + 反思(reflection)。定期从情景记忆中抽象出高层次的语义记忆("用户偏好折线图"是从多次选折线图的情景中反思出来的)。详见 arxiv.org/abs/2304.03442。 - LangGraph Store:基于 namespace 的 KV 存储 + 语义搜索,开发者手动调用 API 读写。
TTD 的四层记忆融合了这些思想:Working 是短期,Profile 是语义记忆,Episodic 是情景记忆,Correction 是程序记忆(纠正如何做对)。形成策略采用触发式而非 MemGPT 的自治式——这是安全敏感场景的取舍。
7.2 设计原理¶
7.2.1 四层记忆架构¶
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#e8f0fe','primaryTextColor':'#202124','primaryBorderColor':'#1a73e8','lineColor':'#5f6368','secondaryColor':'#e0f2f1','tertiaryColor':'#f8f9fa'}}}%%
graph LR
subgraph Personalized["Personalized Memory(per-user 隔离)"]
direction LR
W["Working Memory<br/>LangGraph Checkpointer<br/>会话作用域"]
P["Profile Memory<br/>长期偏好<br/>365d TTL"]
E["Episodic Memory<br/>成功交互摘要<br/>90d TTL"]
C["Correction Memory<br/>已接受纠正<br/>180d TTL"]
W -->|"跨轮传递"| P
P -->|"情景积累"| E
E -->|"纠正沉淀"| C
end
subgraph Shared["Shared Optimization(非用户记忆)"]
direction LR
SC["SQL Cache<br/>pgvector<br/>semlayer.sql_cache"]
FS["Dynamic Few-Shot<br/>pgvector<br/>approved"]
MC["Metadata Cache<br/>进程内<br/>TTL 24h"]
end
Q[用户问题] --> W
W -->|"会话上下文"| Pipeline["Agent Pipeline<br/>Router → Retrieval → SQL Gen"]
P -->|"用户偏好/默认值"| Pipeline
E -->|"历史交互摘要"| Pipeline
C -->|"已接受纠正"| Pipeline
SC -->|"语义匹配 SQL<br/>sim ≥ 0.92"| Router["Router · 快速路径"]
FS -->|"注入 Prompt"| Pipeline
classDef bpData fill:#e0f2f1,stroke:#0d7377,stroke-width:2px,color:#202124
classDef bpInfo fill:#f3e8fd,stroke:#9334e6,stroke-width:2px,color:#202124
classDef bpProcess fill:#e8f0fe,stroke:#1a73e8,stroke-width:2px,color:#202124
classDef bpDecision fill:#fef7e0,stroke:#f9ab00,stroke-width:2px,color:#202124
class W,P,E,C,SC,FS,MC bpData
class Q,Pipeline,Router bpProcess
class C bpInfo
| 层 | 存储 | 生命周期 | 用途 | 认知科学对应 |
|---|---|---|---|---|
| Working | LangGraph Checkpointer (PG) | 请求/会话作用域 | 当前对话上下文,最近 N 轮 | 短期记忆 |
| Profile | ttd_memory_records (kind=profile) |
长期 365 天 TTL(初始估算值) | 稳定偏好:常用指标、偏好维度、图表风格 | 语义记忆 |
| Episodic | ttd_memory_records (kind=episodic) |
中期 90 天 TTL(初始估算值)+ 衰减 | 成功交互摘要、已接受澄清 | 情景记忆 |
| Correction | ttd_memory_records (kind=correction) |
中长期 180 天 TTL(初始估算值) | 用户批准的纠正:术语消歧、SQL 修复模式 | 程序记忆 |
TTL 值为初始估算
上述 365/90/180 天 TTL 与衰减率(episodic 0.02/天、profile 0.005/天)均为初始估算值,项目尚未运行足够长时间以验证这些参数的合理性。改进方向:基于实际记忆访问模式与命中率数据校准 TTL(第 16 章)。
7.2.2 共享优化层(非用户记忆)¶
| 机制 | 存储 | 作用 |
|---|---|---|
| SQL Cache | semlayer.sql_cache (pgvector) |
问题相似度 ≥ 0.92 命中,复用已验证 SQL |
| Dynamic Few-Shot | semlayer.dynamic_few_shot_cache (pgvector) |
从修复成功自学习,approved 后注入 RAG Engine D |
| Metadata Cache | 进程内 | TTL 24h,减少 PG 元数据查询 |
这些是跨用户的共享优化,不属于个人记忆——SQL Cache 对所有用户共享,Dynamic Few-Shot 是系统级学习成果。
7.3 实现详解¶
7.3.1 Working Memory(短期上下文)¶
| 属性 | 值 |
|---|---|
| 存储 | LangGraph Checkpointer (PostgreSQL) |
| 窗口 | 最近 5 轮(TTD_SHORT_TERM_WINDOW=5) |
| 格式 | list[dict],每轮含 user/assistant message |
| 压缩 | Context Compactor(token budget 3000,最近 3 轮原样保留) |
# backend/app/memory/short_term.py
def trim_history(messages, *, window=5):
"""保留系统消息 + 最近 window 轮对话。"""
thread_id=session_id 实现 LangGraph Checkpointer 的多轮会话状态持久化——每一步的状态快照按 thread_id 隔离。stream.py 启动时从 SessionManager.get_turns() 加载历史注入 short_term_memory。
Context Compactor 是 Advanced RAG 的 compress 模块——当历史超过 token 预算时,压缩早期对话为摘要,保留最近 3 轮原样。
7.3.2 Profile / Episodic / Correction Memory¶
通过统一的 MemoryFacade 访问,支持路由感知预算——不同路由对各类记忆设不同上限,避免记忆注入过多稀释当前查询的上下文:
# backend/app/memory/facade.py
class MemoryFacade:
async def retrieve(self, *, user_id, query, route_decision, ...) -> MemoryContext
async def write_candidate(self, *, user_id, kind, summary_text, ...) -> str | None
async def upsert(self, *, memory_id, user_id, ...) -> bool
async def suppress(self, *, memory_id, user_id, ...) -> bool
async def delete_for_user(self, *, user_id, ...) -> int
路由预算(Route Budgets)——KPI 直查不需要太多记忆,深度分析需要更多历史经验:
| Route | Profile | Episodic | Correction |
|---|---|---|---|
nl2sql_query |
5 | 2 | 5 |
kpi_lookup |
2 | 0 | 1 |
business_knowledge_qa |
3 | 1 | 1 |
deep_analysis_workflow |
8 | 8 | 4 |
7.3.3 记忆形成(Memory Formation)¶
记忆候选项从已持久化的 turn 中提取,而非内联于生成过程——这与 Generative Agents 的反思机制类似,但触发方式不同:
# backend/app/memory/formation.py
class MemoryFormationService:
async def process_turn(self, *, user_id, turn_id, ...) -> list[str]
async def process_feedback(self, *, user_id, rating, ...) -> list[str]
高信号写入策略:仅在有明确偏好信号、被接受的澄清、重复选择模式、或评估器确认的成功交互时写入。带衰减(episodic 0.02/天,profile 0.005/天)和 TTL。
AI Agent 理论关联:自治记忆 vs 触发式记忆
MemGPT/Letta 采用自治记忆——LLM 通过 function call 自主决定何时读/写/遗忘记忆。LLM 可以调用 core_memory_append、archival_memory_insert、archival_memory_search 等函数管理自己的记忆。优势是灵活,LLM 能根据当前需要动态管理记忆;劣势是不可控(LLM 可能遗忘重要信息或记住噪声)。
TTD 采用触发式记忆——记忆形成由明确信号(成功交互、反馈、澄清)触发,而非 LLM 自主决定。优势是可审计、可预测(每条记忆的形成都有明确原因);劣势是可能遗漏隐式信号(如用户连续三次选折线图但未点"赞")。
取舍:安全敏感的 NL2SQL 场景需要可审计性,自治记忆不可控。但 TTD 可以向"受控自治"演进——LLM 在受限范围内提议记忆,经审批后写入。
与 Generative Agents 反思的关系:Generative Agents 定期从情景记忆中反思出语义记忆("用户偏好折线图"从多次行为中抽象)。TTD 的 formation service 是简化版——从成功 turn 提取 profile/episodic 候选,但缺少系统性的反思抽象。改进方向见 7.4。
7.3.4 记忆记录 Schema¶
所有长期记忆(Profile/Episodic/Correction)统一存储在 ttd_memory_records 表(backend/app/db/models.py 的 MemoryRecord ORM)。以下是完整字段:
# backend/app/db/models.py(MemoryRecord,表 ttd_memory_records)
class MemoryRecord:
memory_id: str # 主键,String(64)
user_id: str # 用户隔离,String(256)
session_id: str | None # 来源会话
turn_id: str | None # 来源轮次
trace_id: str | None # Langfuse 追踪 ID
kind: MemoryKind # working / profile / episodic / correction
scope: str # "global" 默认
namespace: str # "default" 默认
summary_text: str # 记忆摘要文本
payload_json: dict # 结构化载荷(如 correction_sql)
source_route: str | None # 来源路由
source_agent: str | None # 来源 Agent
confidence: float # 置信度,默认 0.5
salience: float # 显著性,默认 0.5
status: MemoryStatus # candidate / active / suppressed / expired / deleted
embedding: list # JSONB 向量(待迁移 pgvector)
pii_level: MemoryPIILevel # none / low / medium / high
redaction_level: MemoryRedactionLevel # full / summary / reference_only
created_at: datetime
last_seen_at: datetime
last_accessed_at: datetime
expires_at: datetime | None
四类记忆(MemoryKind)与生命周期状态(MemoryStatus)枚举:
| MemoryKind | 用途 | 典型 payload_json |
|---|---|---|
working |
短期上下文(实际由 Checkpointer 承载,此枚举预留) | — |
profile |
用户稳定偏好 | {"preferred_chart": "line", "common_dimensions": ["time"]} |
episodic |
成功交互摘要 | {"question": "GMV 同比", "route": "nl2sql_query", "success": true} |
correction |
用户纠正记录 | {"correction_sql": "SELECT COUNT(*)...", "comment": "GMV 不含退款"} |
| MemoryStatus | 含义 |
|---|---|
candidate |
新写入候选,尚未激活 |
active |
已激活,参与检索 |
suppressed |
被抑制(如冲突消解时降级) |
expired |
TTL 过期 |
deleted |
软删除 |
记忆检索通过 MemoryFacade.retrieve() 返回 MemoryContext DTO,按路由预算填充三槽:
# backend/app/memory/facade.py
class MemoryContext:
"""注入 Agent 状态的记忆上下文。"""
profile: list[MemoryResult] # 用户偏好
episodic: list[MemoryResult] # 历史交互
correction: list[MemoryResult] # 纠正记录
MemoryContext 写入 LangGraph 状态的 state["memory_context"] 字段(backend/app/agents/state.py)。
7.3.5 Correction Memory 完整循环¶
Correction Memory 是"从用户纠正中学习"的机制。以下是完整的 before/after 循环:
形成阶段(backend/app/memory/formation.py 的 process_feedback):
# 用户对一条 SQL 结果给出"踩"并附纠正 SQL
await formation.process_feedback(
user_id="u_123",
rating="dislike",
correction_sql="SELECT SUM(price) FROM gold_hm.fact_transaction WHERE price > 0",
comment="GMV 不含退款,要过滤 price > 0",
)
# → 写入 MemoryRecord(kind=correction, payload_json={"correction_sql": ..., "comment": ...},
# confidence=0.8, status="candidate")
检索阶段(MemoryFacade.retrieve):
# 下次该用户提问类似问题时
ctx = await facade.retrieve(user_id="u_123", query="本月 GMV", route_decision="nl2sql_query")
# ctx.correction = [MemoryResult(summary="GMV 不含退款,过滤 price > 0", confidence=0.8)]
诚实声明:Correction Memory 尚未接入 SQL 生成
基于当前代码事实,Correction Memory 已持久化但尚未端到端接入 SQL 生成。具体状态:
- 已实现:
process_feedback写入 correction 记录;MemoryFacade.retrieve能检索 correction 层;MemoryContext.correctionDTO 与state["memory_context"]状态槽已预留。 - 未连通:SQL 生成节点(
sql_generation.py)当前仅消费long_term_context(Profile 偏好,通过LongTermMemory.get_preferences()注入assemble_sql_prompt的user_preferences参数)。MemoryFacade.retrieve()在请求路径中未被调用——state["memory_context"]的 correction 槽虽存在但无数据填充。
这意味着:用户纠正的 SQL 当前会被记录,但不会自动影响后续 SQL 生成。Correction Memory 的端到端连通是明确的改进项(第 16 章)。此处的循环描述为目标设计,非当前运行行为。
7.3.6 SQL 语义缓存¶
| 属性 | 值 |
|---|---|
| 存储 | semlayer.sql_cache 表 (pgvector) |
| 匹配 | cosine similarity > 0.92(TTD_SQL_CACHE_SIMILARITY) |
| TTL | 15 分钟(TTD_SQL_CACHE_TTL_MINUTES) |
| 缓存内容 | 仅 SQL 文本,不缓存执行结果 |
数据新鲜度
SQL Cache 只缓存生成的 SQL 语句。执行结果始终从数据面实时获取,确保返回最新数据。这是 ADR-10 的核心决策——宁愿命中缓存仍执行 SQL,也不要返回脏数据。
命中流程:Router 检测 question_embedding 与缓存 SQL 的 embedding 相似度 ≥ 0.92 → 直接跳转 guardrails_agent,跳过检索与生成。
SQL 缓存 vs 结果缓存 vs 通用语义缓存
- SQL-Only Cache(TTD):只缓存 SQL 文本,每次仍执行。数据新鲜,但对"慢查询"加速有限(省的是生成时间,不是执行时间)。
- 结果缓存:缓存查询结果,命中即返回。加速最大,但有脏数据风险,不适合实时数据。
- 通用语义缓存(如 GPTCache):缓存任意 LLM 响应(不只 SQL),用语义相似度匹配。通用但不可控。
- TTD 选 SQL-Only 是数据敏感场景的正确取舍——对历史报表等低新鲜度场景,可演进为分级缓存(ADR-10 改进)。
7.3.7 动态 Few-Shot 缓存¶
从 SQL 修复成功案例自动学习 {question, final_sql} 对,作为实时 few-shot 补充手工策划的 semantic-plane/few_shots/。这是 Engine D 的数据源,实现了"系统从自己的成功中学习"的闭环。
三步审批工作流(质量控制):
record_success() → review_status = 'pending_review'
(新条目不参与 RAG,等待审核)
↓
Admin 审批 (/admin/few-shots) → approve / reject
↓
search_similar() → 仅返回 approved + sim ≥ 0.95 + confidence ≥ 0.9 + fail_count ≤ 3
| 属性 | 值 |
|---|---|
| 存储 | semlayer.dynamic_few_shot_cache (pgvector + review 状态) |
| RAG 注入条件 | approved AND sim ≥ 0.95 AND confidence ≥ 0.9 AND fail_count ≤ 3 |
| 自动过期 | 30 天,或 fail_count > 3 |
| YAML 导出 | approved 条目可导出为 semantic-plane/few_shots/ 一致的 YAML,晋升为正式资产 |
class DynamicFewShotCache:
async def record_success(question, final_sql, *, intent_type, grounded_tables,
question_embedding, confidence) -> None
async def search_similar(question_embedding, *, top_k=3,
min_confidence=0.9, min_similarity=0.95) -> list[dict]
async def approve(entry_id, reviewer) -> bool
async def reject(entry_id, reviewer) -> bool
7.3.8 会话管理¶
| 配置 | 默认值 | 说明 |
|---|---|---|
TTD_SESSION_TTL_HOURS |
24 | 会话过期时间 |
TTD_SESSION_MAX_TURNS |
20 | 单会话最大轮次 |
TTD_CLEANUP_INTERVAL_MINUTES |
60 | 清理循环间隔 |
新对话标题自动取自第一条用户消息(LATERAL JOIN 查询)。后台 asyncio.Task 定期执行过期会话清理。
7.3.9 Correction Memory 连通方案¶
7.3.5 已说明 Correction Memory 当前已持久化但未接入 SQL 生成。本节给出一个可执行的连通方案设计(非"改进方向"),供贡献者直接落地。
目标¶
让用户的纠正 SQL 在下次类似查询时自动影响 SQL 生成——通过 Prompt 注入 correction 记录,引导 LLM 避免重复错误。
实现步骤¶
# backend/app/agents/sub_agents/sql_generation.py(修改点)
async def sql_generation(state: AgenticBIState) -> dict:
# ... 现有逻辑 ...
# 新增:从 state["memory_context"] 提取 correction 记录
memory_ctx = state.get("memory_context") or {}
corrections = memory_ctx.get("correction", [])
# 新增:将 correction 摘要拼接为 repair_hint 风格的提示
correction_hints = _format_correction_hints(corrections, user_question)
# 现有:user_preferences 来自 long_term_context
user_preferences = _format_preferences(state.get("long_term_context"))
# 修改:将 correction_hints 追加到 user message(与 repair_hint 同级)
user_msg = f"{user_question}\n{repair_hint}\n{semantic_hint}\n{correction_hints}"
messages = assemble_sql_prompt(retrieval_results, graph_context, user_msg,
user_preferences=user_preferences)
# ...
def _format_correction_hints(corrections: list, question: str) -> str:
"""将相关 correction 记录格式化为 Prompt 提示。"""
if not corrections:
return ""
lines = ["[历史纠正提示] 该用户曾对类似查询做过纠正,请参考:"]
for c in corrections[:3]: # 最多注入 3 条
payload = c.payload_ref or {}
comment = payload.get("comment", "")
lines.append(f"- {comment}")
return "\n".join(lines)
前置改动¶
上述方案的前提是在请求路径中调用 MemoryFacade.retrieve() 填充 state["memory_context"]。当前 chats.py 未调用它,需增加:
# backend/app/api/chats.py(修改点,send_message 内)
memory_ctx = await MemoryFacade(store).retrieve(
user_id=user_id, query=user_message, route_decision=route_decision
)
initial_state["memory_context"] = memory_ctx.to_dict()
预期效果(假设)¶
| 指标 | 连通前 | 连通后(预期) | 说明 |
|---|---|---|---|
| 重复错误率 | 基线 | 降低 30-50% | 用户纠正过的错误不再重复 |
| SQL 首次正确率 | 基线 | 提升 5-10% | correction hint 引导 LLM 避坑 |
| Prompt token 增量 | — | +100-300 token | 最多 3 条 correction 摘要 |
预期效果为假设值
上表数字为基于经验的假设,未经实测验证。连通后应通过 第 15 章 的 A/B 评估量化真实效果——对比"有 correction 注入"与"无 correction 注入"两组的 SQL 正确率。
7.3.10 记忆冲突消解¶
当新记忆与旧记忆冲突时(如用户改了偏好:"我喜欢折线图" → "我喜欢柱状图"),当前无自动消解,可能导致矛盾记忆共存。本节给出具体的冲突检测算法与合并策略。
冲突检测算法¶
# backend/app/memory/formation.py(新增)
def detect_conflict(new_memory: MemoryRecord, existing: list[MemoryRecord]) -> ConflictResult:
"""检测新记忆是否与已有同类记忆冲突。"""
# 1. 同类筛选:相同 kind + 相同 namespace + 相同 scope
candidates = [m for m in existing
if m.kind == new_memory.kind
and m.namespace == new_memory.namespace
and m.scope == new_memory.scope]
# 2. 语义相似度检测:embedding cosine > 0.85 视为"同一主题"
for m in candidates:
sim = cosine(new_memory.embedding, m.embedding)
if sim > 0.85:
# 3. 内容冲突检测:payload 的同名字段值不同
if _payload_conflicts(new_memory.payload_json, m.payload_json):
return ConflictResult(conflict_with=m, similarity=sim)
return ConflictResult(no_conflict=True)
合并策略¶
| 冲突类型 | 策略 | 示例 |
|---|---|---|
| 偏好覆盖(profile) | 新覆盖旧,旧记忆 status → suppressed |
"折线图" → "柱状图":旧的 suppressed |
| 纠正迭代(correction) | 保留两者,按时间排序,Reranker 取最新 | 用户先纠正 A,后又纠正 B → 两条都保留,检索时 latest 优先 |
| 情景并存(episodic) | 不视为冲突,共存 | 不同时间的成功交互互不冲突 |
| 矛盾且无法自动消解 | 触发 HITL,让用户选择 | 两条 profile 都说"偏好图表"但值完全相反 |
7.3.11 记忆可视化¶
下图展示某用户经过 20 轮对话后,四层记忆的状态及它们如何影响当前查询:
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#e8f0fe','primaryTextColor':'#202124','primaryBorderColor':'#1a73e8','lineColor':'#5f6368','secondaryColor':'#e0f2f1','tertiaryColor':'#f8f9fa'}}}%%
flowchart TB
subgraph Q["当前查询"]
Q1["用户问题<br/>「本月线上 GMV 趋势」"]
end
subgraph M["四层记忆状态(20 轮会话后)"]
direction LR
W["Working Memory<br/>最近 5 轮上下文<br/>含上轮 GMV 查询"]
P["Profile(3 条 active)<br/>· 偏好图表:折线图<br/>· 常用维度:时间、渠道<br/>· 常用指标:GMV"]
E["Episodic(2 条 active)<br/>· GMV 同比查询成功<br/>· 退货率查询成功"]
C["Correction(1 条 candidate<br/>尚未接入生成)<br/>· GMV 不含退款"]
end
Q1 -->|"问题 + embedding"| Prompt["SQL Prompt<br/>组装注入"]
W -->|"注入最近上下文"| Prompt
P -->|"注入 user_preferences"| Prompt
C -.->|"连通后注入<br/>(见 7.3.9)"| Prompt
E -.->|"提升路由置信度<br/>GMV 问题走 nl2sql_query"| Router["Router"]
Prompt --> SG["SQL Generator"]
classDef bpData fill:#e0f2f1,stroke:#0d7377,stroke-width:2px,color:#202124
classDef bpInfo fill:#f3e8fd,stroke:#9334e6,stroke-width:2px,color:#202124
classDef bpProcess fill:#e8f0fe,stroke:#1a73e8,stroke-width:2px,color:#202124
classDef bpDecision fill:#fef7e0,stroke:#f9ab00,stroke-width:2px,color:#202124
class W,P,E,C bpData
class Q1 bpProcess
class Prompt,Router,SG bpProcess
class C bpInfo
| 记忆层 | 影响当前查询的方式 | 状态 |
|---|---|---|
| Working | 最近上下文注入 Prompt("上轮查了 GMV 同比,本轮可能延续") | 已生效 |
| Profile | user_preferences 注入 Prompt(偏好折线图 → 可视化推荐直接选折线) |
已生效 |
| Episodic | 历史成功交互提升路由置信度(GMV 类问题走 nl2sql_query) | 已生效 |
| Correction | 预期注入 Prompt("GMV 不含退款") | 未连通(见 7.3.9) |
7.4 方案选型对比¶
7.4.1 记忆架构对比¶
| 维度 | TTD 触发式四层 | MemGPT/Letta 自治 | LangGraph Store |
|---|---|---|---|
| 记忆管理 | 触发式(明确信号写入) | 自治(LLM 决定读写遗忘) | 手动 API |
| 可控性 | 高 | 低 | 高 |
| 灵活性 | 低 | 高 | 中 |
| 可审计 | 高 | 低 | 中 |
| 实现复杂度 | 中 | 高 | 低 |
| TTD 选择理由 | 安全敏感场景需可审计,自治记忆不可控 |
7.4.2 记忆形成策略对比¶
| 策略 | 代表 | 优势 | 劣势 | TTD 状态 |
|---|---|---|---|---|
| 明确信号触发 | TTD | 可控、可审计 | 遗漏隐式信号 | |
| 行为反思抽象 | Generative Agents | 能发现隐式偏好 | 反思质量依赖 LLM | |
| 自治 function call | MemGPT | 灵活 | 不可控 |
性能与质量指标(设计目标)
以下为记忆系统的设计目标值,TTD 尚未进行系统化实测:
| 指标 | 设计目标 | 说明 |
|---|---|---|
| Profile/Episodic 检索延迟 | < 20ms | 按置信度+显著性排序,路由预算截断 |
| SQL Cache 命中延迟 | < 5ms | pgvector cosine 相似度 + TTL 检查 |
| SQL Cache 命中率 | ≥ 0.3 | 相似问题复用比例(未实测) |
| Dynamic Few-Shot 注入率 | ≥ 0.1 | approved 条目参与 RAG 的比例(未实测) |
| 记忆形成延迟 | < 500ms | 后台异步,不阻塞主路径 |
当前实现可改进之处
- 记忆形成策略单一:只在明确信号(成功/反馈/澄清)时写入,会遗漏隐式偏好。例如用户连续三次选择折线图但未点"赞",系统不会形成"偏好折线图"的记忆。改进:引入行为信号挖掘——从交互模式(连续选择、停留时长)提取隐式偏好,参考 Generative Agents 的反思机制。
- 缺记忆冲突消解:当新记忆与旧记忆冲突时(如用户改了偏好),无自动消解机制,可能导致矛盾记忆共存。改进:写入时检查同类记忆,新记忆覆盖或合并旧记忆。
- 动态 Few-Shot 审批瓶颈:所有自学习条目需人工审批,规模化后审批成为瓶颈。改进:引入置信度自动晋升——高置信度(sim ≥ 0.98 + 多次成功)的条目自动 approved,仅边缘案例人工审核。
- SQL Cache 阈值固定:0.92 是全局固定阈值,对不同业务域的语义粒度不敏感。改进:按域或按表组动态调整阈值。
改进方向
记忆系统的演进方向是更自治、更智能的形成与遗忘。短期:补隐式信号挖掘与冲突消解。长期:向 MemGPT 式自治记忆靠拢——让 LLM 在可控范围内自主决定记忆读写,配合审批门控保证质量。动态 Few-Shot 应建立"置信度自动晋升 + 边缘人工审核"的分级机制,打破审批瓶颈。
7.5 小结与延伸阅读¶
本章要点:
- 四层记忆:Working(短期)/ Profile(语义)/ Episodic(情景)/ Correction(程序),对应认知科学分类。
- 共享优化层:SQL 语义缓存(仅缓存 SQL 不缓存结果)、动态 Few-Shot(自学习 + 三步审批)、元数据缓存。
- 记忆形成是触发式(非 MemGPT 自治),路由感知预算控制各类记忆注入量。
- 动态 Few-Shot 实现"从成功中学习"的闭环,经审批后注入 RAG Engine D。
- SQL-Only Cache 是数据敏感场景的正确取舍——新鲜度优先于速度。
延伸阅读:
- MemGPT: Towards LLMs as Operating Systems — arxiv.org/abs/2310.08560
- Generative Agents: Interactive Simulacra of Human Behavior — arxiv.org/abs/2304.03442
- Letta(原 MemGPT)— docs.letta.com
- GPTCache — github.com/zilliztech/GPTCache
下一章:第 8 章 工具调用与代码解释器——ML 工具集、代码沙箱、GraphRAG、可视化推荐引擎如何作为 Agent 的"手脚"。