177 lines
7.8 KiB
Markdown
177 lines
7.8 KiB
Markdown
|
|
# Memory 能力差距文档
|
|||
|
|
|
|||
|
|
> 面向回忆录生产的素材检索与事实组织系统 — 当前实现状态与待完成项。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 一、定位与目标(来自架构计划)
|
|||
|
|
|
|||
|
|
本项目中的 `memory` 定义为:
|
|||
|
|
|
|||
|
|
- **面向回忆录生产的可检索素材资产**
|
|||
|
|
- **可持续抽取、修正、确认的结构化事实层**
|
|||
|
|
- **为章节生成和追问生成提供 grounding 的 RAG 基础设施**
|
|||
|
|
|
|||
|
|
明确不做:
|
|||
|
|
|
|||
|
|
- 通用「记住这个」的终端用户指令式记忆
|
|||
|
|
- 聊天助手式 persona memory
|
|||
|
|
- 面向终端用户的自然语言 `forget that`
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 二、当前已就绪部分
|
|||
|
|
|
|||
|
|
### 2.1 数据模型(`features/memory/models.py`)
|
|||
|
|
|
|||
|
|
| 表 | 状态 | 说明 |
|
|||
|
|
|----|------|------|
|
|||
|
|
| `memory_sources` | ✅ | 原始素材主记录,含 source_type、raw_text、conversation_id、speaker、captured_at |
|
|||
|
|
| `memory_chunks` | ✅ | 检索单元,含 content、embedding(pgvector)、content_tsv(FTS)、chunk_index、is_excluded |
|
|||
|
|
| `memory_summaries` | ✅ | 会话/滚动/主题摘要,含 source_chunk_ids 追溯 |
|
|||
|
|
| `memory_facts` | ✅ | 候选/已确认事实,含 fact_type、subject、predicate、source_chunk_id |
|
|||
|
|
| `timeline_events` | ✅ | 时间线事件,含 event_year、source_fact_ids |
|
|||
|
|
| `memory_curation_actions` | ✅ | 操作轨迹(exclude/restore/correct/confirm/reject) |
|
|||
|
|
|
|||
|
|
### 2.2 接口与依赖
|
|||
|
|
|
|||
|
|
| 组件 | 状态 | 说明 |
|
|||
|
|
|------|------|------|
|
|||
|
|
| `MemoryService` 类 | ✅ | 门面已定义,`ingest_transcript`、`retrieve` 签名就绪 |
|
|||
|
|
| `MemoirService.get_evidence()` | ✅ | 通过注入 `MemoryService` 调用 retrieve |
|
|||
|
|
| `MemoirService` 注入 `MemoryService` | ✅ | `deps.py` 已配置 |
|
|||
|
|
| `EmbeddingProvider` port | ✅ | OpenAI adapter 已实现 |
|
|||
|
|
| `get_embedding_provider()` | ✅ | `core/dependencies.py` 已注册 |
|
|||
|
|
|
|||
|
|
### 2.3 骨架文件
|
|||
|
|
|
|||
|
|
| 文件 | 状态 | 说明 |
|
|||
|
|
|------|------|------|
|
|||
|
|
| `chunker.py` | 骨架 | `chunk_transcript()` 未实现 |
|
|||
|
|
| `repo.py` | 骨架 | 无具体 CRUD |
|
|||
|
|
| `retriever.py` | 骨架 | `HybridRetriever.retrieve()` 未实现 |
|
|||
|
|
| `extractor.py` | 骨架 | `extract_facts()` 未实现 |
|
|||
|
|
| `summarizer.py` | 骨架 | `generate_session_summary`、`generate_rolling_summary` 未实现 |
|
|||
|
|
| `timeline.py` | 骨架 | 无具体逻辑 |
|
|||
|
|
| `curation.py` | 骨架 | 无具体逻辑 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 三、待完成能力(按优先级)
|
|||
|
|
|
|||
|
|
### 3.1 写入路径(Ingest)
|
|||
|
|
|
|||
|
|
**目标**:对话结束后,将 transcript 沉淀为 memory 资产,并异步补齐 embedding、summary、fact。
|
|||
|
|
|
|||
|
|
| 步骤 | 当前状态 | 待实现 |
|
|||
|
|
|------|----------|--------|
|
|||
|
|
| 1. `MemoryService.ingest_transcript()` | `raise NotImplementedError` | 写入 `memory_sources`、切块写入 `memory_chunks`、提交主事务 |
|
|||
|
|
| 2. 触发异步任务 | 无 | Celery 任务:embedding 生成、summary 生成、fact 提取、timeline 构建 |
|
|||
|
|
| 3. `chunker.chunk_transcript()` | `raise NotImplementedError` | 按 max_tokens/overlap 切分,支持 speaker 边界 |
|
|||
|
|
| 4. `memory/repo.py` | 空 | `create_source()`、`create_chunks()`、`update_chunk_embedding()` 等 |
|
|||
|
|
| 5. `memory_tasks.py` | 无 | 新增 `enrich_memory_source` 等 Celery 任务 |
|
|||
|
|
|
|||
|
|
**接入点**:`conversation/ws/router.py` 中 `END_CONVERSATION` 分支,在 `process_conversation_segments` 之后调用 `MemoryService.ingest_transcript()`。需从 segments 聚合 transcript 文本。
|
|||
|
|
|
|||
|
|
### 3.2 读取路径(Retrieve)
|
|||
|
|
|
|||
|
|
**目标**:混合检索(metadata + FTS + vector)生成 evidence bundle,供 memoir 章节生成使用。
|
|||
|
|
|
|||
|
|
| 步骤 | 当前状态 | 待实现 |
|
|||
|
|
|------|----------|--------|
|
|||
|
|
| 1. `HybridRetriever.retrieve()` | `raise NotImplementedError` | metadata filter → FTS 查询 → 向量检索 → score fusion |
|
|||
|
|
| 2. `MemoryService.retrieve()` | 返回空 dict | 调用 `HybridRetriever`,按 token budget 组装 evidence bundle |
|
|||
|
|
| 3. `memory/repo.py` | 空 | `search_chunks_fts()`、`search_chunks_vector()`、`get_summaries()`、`get_facts()` |
|
|||
|
|
| 4. `memory_chunks.content_tsv` | 模型有列 | 需 Alembic 迁移:generated tsvector 列 + GIN index |
|
|||
|
|
| 5. `memory_chunks.embedding` | 模型有列 | 需异步任务写入,pgvector 索引已由 pgvector 扩展支持 |
|
|||
|
|
|
|||
|
|
**Evidence Bundle 结构**(已定义于 `memory/schemas.py`):
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
{
|
|||
|
|
"relevant_chunks": [...],
|
|||
|
|
"relevant_summaries": [...],
|
|||
|
|
"relevant_facts": [...],
|
|||
|
|
"timeline_hints": [...],
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3.3 消费端接入
|
|||
|
|
|
|||
|
|
**目标**:章节生成必须优先使用 evidence bundle(规则 26)。
|
|||
|
|
|
|||
|
|
| 消费端 | 当前状态 | 待实现 |
|
|||
|
|
|--------|----------|--------|
|
|||
|
|
| `process_conversation_segments` | 未调用 ingest | 无(ingest 在 END_CONVERSATION 时由 router 触发) |
|
|||
|
|
| `process_memoir_segments`(Celery) | 未使用 evidence | 在生成章节前调用 `MemoryService.retrieve()` 或通过 MemoirService 传入 |
|
|||
|
|
| `generate_chapter_content`(Celery) | 未使用 evidence | 同上 |
|
|||
|
|
| `MemoirGenerator.generate_narrative` | 仅用 slots + content | 增加 evidence 参数,拼入 prompt |
|
|||
|
|
| `get_narrative_prompt` | 无 evidence 参数 | 增加 `evidence_bundle: dict` 参数,格式化后注入 prompt |
|
|||
|
|
|
|||
|
|
**注意**:Celery 任务为同步,需通过 `get_sync_db()` 获取 session,并调用 `MemoryService` 的同步版本或封装。当前 `MemoryService` 为 async,需考虑:
|
|||
|
|
- 方案 A:在 Celery 中 `asyncio.run(memory_service.retrieve(...))`
|
|||
|
|
- 方案 B:定义 `MemoryServiceSync` 或 `retrieve_sync` 供 Celery 使用
|
|||
|
|
|
|||
|
|
### 3.4 辅助能力(二期可延后)
|
|||
|
|
|
|||
|
|
| 能力 | 文件 | 说明 |
|
|||
|
|
|------|------|------|
|
|||
|
|
| fact extraction | `extractor.py` | LLM 抽取结构化事实 |
|
|||
|
|
| session summary | `summarizer.py` | 会话摘要、滚动摘要 |
|
|||
|
|
| timeline build | `timeline.py` | 按 event_year 组织时间线 |
|
|||
|
|
| curation | `curation.py` | exclude/restore/correct 操作 |
|
|||
|
|
| reranker | `ports/reranker.py` | 可选 cross-encoder 重排 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 四、实现顺序建议
|
|||
|
|
|
|||
|
|
1. **Phase 1:写入路径**
|
|||
|
|
- 实现 `chunk_transcript()`
|
|||
|
|
- 实现 `memory/repo.py` 的 `create_source`、`create_chunks`
|
|||
|
|
- 实现 `MemoryService.ingest_transcript()`
|
|||
|
|
- 在 END_CONVERSATION 时调用 ingest(需聚合 segments 的 transcript)
|
|||
|
|
|
|||
|
|
2. **Phase 2:异步补齐**
|
|||
|
|
- 新增 `memory_tasks.py`,Celery 任务:embedding 生成、写入 `memory_chunks.embedding`
|
|||
|
|
- 可选:summary、fact 提取(可后续迭代)
|
|||
|
|
|
|||
|
|
3. **Phase 3:读取路径**
|
|||
|
|
- 实现 `repo.search_chunks_fts()`、`search_chunks_vector()`(需 FTS 迁移)
|
|||
|
|
- 实现 `HybridRetriever.retrieve()`(metadata + FTS + vector + 融合)
|
|||
|
|
- 实现 `MemoryService.retrieve()` 调用 HybridRetriever
|
|||
|
|
|
|||
|
|
4. **Phase 4:消费端接入**
|
|||
|
|
- 修改 `get_narrative_prompt` 增加 evidence 参数
|
|||
|
|
- 修改 `MemoirGenerator.generate_narrative` 接收 evidence
|
|||
|
|
- 修改 `process_memoir_segments`、`generate_chapter_content` 在生成前获取 evidence 并传入
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 五、Alembic 迁移待办
|
|||
|
|
|
|||
|
|
| 迁移 | 说明 |
|
|||
|
|
|------|------|
|
|||
|
|
| `memory_chunks` FTS | 需 `content_tsv` 使用 `tsvector` generated column + GIN index,或应用层维护 |
|
|||
|
|
| 若已有 `create_all` 建表 | 需 `alembic revision --autogenerate` 生成与当前 models 一致的迁移,或手写等效 DDL |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 六、依赖规则
|
|||
|
|
|
|||
|
|
- `conversation` / `memoir` 不得直接读写 memory 表,只能调用 `MemoryService`
|
|||
|
|
- `agents/` 不得直接读写 memory 表,只能消费 evidence bundle
|
|||
|
|
- `memory` 不得直接 import `adapters`,只依赖 `EmbeddingProvider` port
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 七、预估工作量
|
|||
|
|
|
|||
|
|
| 阶段 | 预估 | 说明 |
|
|||
|
|
|------|------|------|
|
|||
|
|
| Phase 1 写入路径 | 1–1.5 天 | chunker、repo、ingest、END_CONVERSATION 接入 |
|
|||
|
|
| Phase 2 异步补齐 | 0.5–1 天 | Celery 任务、embedding 写入 |
|
|||
|
|
| Phase 3 读取路径 | 1–1.5 天 | FTS、vector、HybridRetriever、MemoryService.retrieve |
|
|||
|
|
| Phase 4 消费端接入 | 1 天 | prompt、MemoirGenerator、Celery 任务 |
|
|||
|
|
| **合计** | **约 3.5–5 人天** | 视测试与联调深度而定 |
|