Submit the formed RAG documentation set produced across Sprint-1/2/3 (WS-12 through WS-26) under docs/rag/. Includes: - README.md / INDEX.md: landing + total index (responsibility matrix, review verdicts, dual-link to source issues) - overview/: full-pipeline architecture (4 .mmd diagrams), 11-stage boundary contracts, doc map, source-code inventory - pipeline/: 5 deep-dives (Loader/Parser/Chunking, Embedding, VDB & retrieval, GraphRAG, Rerank/Prompt/LLM) - graphrag/, end-to-end/: v1.0 formal versions with full source retained as reference - evolution/: 11 architecture-refactor proposals, 6-direction roadmap, capability map - review/: S3-T1 / S3-T2 final reviews, S2-T7 final summary - _indexes/: glossary (81 terms), source->doc reverse index, chart index - _release/: v1.0-RC1 release manifest, versioning convention, ops & freshness plan - _meta/README.md: placeholder noting WS-12 governance assets gap Aggregate review score 92.6/100 (8/8 PASS, 31/31 source-code spot checks hit). The legacy docs/ ignore in .gitignore is narrowed to docs/* with an explicit allowlist for docs/rag/. Refs: WS-26 Co-authored-by: multica-agent <github@multica.ai>
31 KiB
MemoryBear RAG · 后续迭代功能新增方式建议(S3-T2)
上游:[WS-11] 总规划、[S1-T2 全链路架构]、[S1-T3 源码盘点]、Sprint-2 各环节深度文档、[S3-T1 架构改造建议] 输出形态:能力地图 + 6 个重点扩展方向 + 2 条 Quick PoC + 优先级矩阵 + 落地路线图 设计原则:所有方向 必须 复用 [S3-T1] 提议的统一抽象(
Retriever / Reranker / Generator / Embedder / Loader / Chunker),避免出现新功能 = 新一团耦合。
0. 现状速览与设计基线
0.1 一图看清"已有 / 可上 / 愿景"
详见附件 capability-map.mmd(Mermaid 格式)。三色对应:
- 🟢 已有:Sprint-2 文档已覆盖、源码可证、生产可用。
- 🟡 近期可上:1–2 个 Sprint 内可落地,依赖最少。
- 🟣 中长期愿景:3–6 个月,存在跨团队/外部依赖。
0.2 关键源码事实(用于支撑后续方案)
| 事实 | 源码定位 | 对扩展的影响 |
|---|---|---|
| 多模态目前 走文本通道 | rag/app/picture.py:54 调 vision_model.describe;rag/app/audio.py:29 调 seq2txt_mdl.transcription;naive.py 走 video → VLM → 文本 |
跨模态语义损失大;扩展为"原生跨模态向量"是方向 D1 |
MatchSparseExpr 已声明但未接入 |
rag/utils/doc_store_conn.py:75 与 vdb/field.py:11(SPARSE_VECTOR) 都已存在;grep -r SparseVector 仅 1 处定义、0 处调用 |
SPLADE 接入是脚手架级改造,不是从零开始(D2) |
混合检索权重写死 0.05,0.95 |
rag/nlp/search.py:439 的 FusionExpr("weighted_sum", topk, {"weights": "0.05,0.95"}) |
语义路由 / 自适应权重的注入点天然存在(D2) |
| GraphRAG 是"一次构建"模型 | tasks.py 的 build_graphrag_for_document Celery 链;图存于 ES knowledge_graph_kwd 字段 |
增量演化、时间维度、Neo4j 双引擎需要在 Celery 链上加 hook(D3) |
| 对话记忆与 RAG 不互通 | core/memory/ 自成一套(Ebbinghaus、ACT-R、Neo4j、langgraph 读图);workflow/nodes/knowledge/node.py 完全不引用 core/memory |
对话记忆 ↔ 检索的协同是最大产品差异化机会(D4) |
| 评估只在 README 体现 | 仓内无 eval/、ragas、F1 类计算代码 |
反馈闭环要从 0 搭,但与 [S3-T1] 提议的"可观测性"天然合并(D5) |
| Reranker 只能推理不能学 | core/models/rerank.py:11 包装 langchain BaseDocumentCompressor,仅做远程调用 |
自训练 Cross-Encoder 是一条独立、可量化收益的小路径(D5) |
| 检索模式硬编码在 enum | RetrieveType.{PARTICIPLE, SEMANTIC, HYBRID, Graph} 在 schemas/chunk_schema.py |
引入"语义路由"需要把 enum 改成 strategy 模式(D6) |
0.3 与 [S3-T1] 接口抽象的联动约定
[S3-T1] 提议把当前散落的检索/排序/生成代码抽象为协议(参考 LangChain Runnable)。本路线图的所有"接口改造点"都引用以下统一协议(命名以 [S3-T1] 终稿为准,本稿先行登记):
# rag/protocols.py([S3-T1] 提议)
class Retriever(Protocol):
async def retrieve(self, query: Query, ctx: RetrievalContext) -> list[ScoredChunk]: ...
class Reranker(Protocol):
async def rerank(self, query: Query, chunks: list[ScoredChunk], ctx: RerankContext) -> list[ScoredChunk]: ...
class Embedder(Protocol):
def encode(self, items: list[Embeddable]) -> EmbeddingResult: ... # Embeddable = str | Image | Audio | ...
class Generator(Protocol):
async def generate(self, system: str, history: list[Msg], ctx: GenContext) -> GenResult: ...
原则:本文档每条扩展方向都以"新增/扩展某 Protocol 实现 + 注册到工厂"为接入方式,不改动调用方代码。这样可以保持 N 个扩展方向 并行落地 而不互相阻塞。
1. 重点扩展方向
共 6 个方向。第 5、6 个为前述 5 个外的延伸(自适应路由),但和"评估闭环 / 混合搜索 / 对话记忆"高度互补,建议合并审阅。
D1. 多模态检索(原生跨模态向量空间)
1.1 触发场景
- 客户问:"去年那张含 'Q3 GMV' 的 PPT 切片在哪?" — 当前只能命中 OCR 抽出的文字,布局/图表整体语义 丢失。
- 视频会议纪要库:用户描述"那段讲到老王说'下季度先稳住毛利'的会议",纯 ASR 文本无法绑定 说话人 + 时间 + 屏幕共享上下文。
- 设备图谱:硬件型号识图("这块板子是哪一版"),目前只能让 VLM 描述后再走文本检索,VLM 描述不稳定。
1.2 技术方案
分三层逐步推进:
| 层级 | 方案 | 依赖组件 |
|---|---|---|
| L1(基线增强) | 关键帧抽样 + VLM 多次 describe:视频每 N 秒抽帧,每帧 VLM 描述独立 chunk,附 frame_ts 元数据;图片在 OCR + describe 之外再加 结构化 VQA("图中有什么图表/品牌/人脸?") |
现有 cv_model.py、sequence2txt_model.py 即可;新增 rag/app/video.py |
| L2(跨模态检索) | 引入 CLIP / BGE-VL / Jina-Clip-v2 作为 MultimodalEmbedder Protocol 实现:图片直接编码为向量,文本 query 编码到 同一向量空间;ES 索引增加 vec_image_q_<dim>_vec 列 |
新依赖 transformers / sentence-transformers 或托管 API;GPU 资源 |
| L3(视听统一) | Whisper + speaker diarization(pyannote)替换当前一段式 ASR;视频 chunk 同时持有 text_vec(ASR 文本)+ image_vec(关键帧) + audio_vec(可选,用 CLAP) |
pyannote.audio、open_clip;额外存储约 +30% |
1.3 接口改造点(基于 S3-T1)
- 扩展
Embedder.encode(items: list[Embeddable]):Embeddable = str | PILImage | AudioBytes | VideoFrame,返回EmbeddingResult(vector, modality, dim)。 - 新增
MultimodalRetriever(Retriever)实现:内部根据 query 的modality_hint(文本默认)选择走text_vec还是image_vec列。 - VDB 层 schema 演进(
rag/vdb/elasticsearch/elasticsearch_vector.py:653+的 mapping 创建):把"硬编码单 vector 列"改造为"按 modality 多列动态注册";落地依赖 [S3-T1] 提到的 mapping 模板化改造。 app/picture.py/app/audio.py的chunk()函数输出 dict 中新增image_b64/audio_b64字段,供 Embedder 后续无损取用(避免 PIL 对象在 Celery pickle 边界丢失)。
1.4 工作量估计
- L1 基线:1.5 人周(2 个 PR:视频抽帧;结构化 VQA prompt)
- L2 跨模态:3 人周(含 Embedder 抽象、ES schema 迁移、回归测试)
- L3 视听统一:4 人周(含 GPU 容器、speaker diarization 集成)
- 合计:~1.5 + 3 + 4 ≈ 8.5 人周(可分阶段产出)
1.5 风险与依赖
- ⚠️ 存储膨胀:image_vec(768d float32)单图 3KB,1M 图 ≈ 3GB;ES dense_vector 启用
int8_hnsw量化可减 75%。 - ⚠️ VLM 描述漂移:同一图不同时间不同模型版本,描述差异大;需要 caption 缓存(key =
sha256(image)+model_version)。 - ⛓️ 强依赖:[S3-T1] mapping 模板化改造完成后再做 L2,否则 schema 演进会成阻塞点。
- ⛓️ GPU 依赖:L2/L3 在自建 GPU 节点或托管 API 二选一;建议先走托管(Jina-Clip API)跑通端到端,再评估自托管。
D2. 混合搜索增强(Sparse + Dense + Late-Interaction + 自适应路由)
2.1 触发场景
- "工号 E12345 的 OKR" — 长尾标识符,BM25 强、稠密向量弱,当前 0.05/0.95 权重几乎让 BM25 失语。
- "怎么做用户分层运营?" — 概念性问题,dense 强、BM25 弱。
- "GraphRAG 和 LightRAG 的区别" — 需要 ColBERT 这类 token 级精排,单向量混淆术语。
2.2 技术方案
| 子方向 | 方案 | 价值 |
|---|---|---|
| SPLADE 学习稀疏 | 用 naver/splade-cocondenser-ensembledistil 或国产 BGE-M3 sparse 输出,每个文档生成稀疏向量(含 token expansion);接入 MatchSparseExpr(已存在但未启用) |
把 BM25 的"词形匹配"升级为"学习权重 + 自动同义扩展" |
| ColBERT 后期交互 | 文档级向量改为 token 级(一篇文档 N 个 token vector,N≈chunk_token_num/3);retrieval 时用 MaxSim;可仅在 reranker 阶段使用 | 在精确匹配上比 cross-encoder 快 5–10×,质量接近 |
| 语义路由 / 自适应权重 | 先用一个轻 LLM(或 query classifier)判定 query 类型(lookup / concept / list / multi-hop / temporal),路由到 {BM25权重, vector权重, 是否使用 Graph, 是否使用 Rerank} |
替代当前写死的 0.05/0.95;可灰度(query 哈希 % 100 < 5 上新策略) |
| 多向量召回融合 | 同 chunk 同时索引 BM25、dense、sparse 三类,retrieval 后用 RRF (Reciprocal Rank Fusion) 融合 | 工程上 RRF 不需训练,落地最快 |
2.3 接口改造点
- 新增
SparseEmbedder(Embedder)实现:返回SparseVector(indices, values);ES mapping 增加q_sparse_<vocab>_vec字段,使用rank_features/sparse_vector类型(ES ≥ 8.11)。 - 在
rag/nlp/search.py:Dealer.search()(第 387 行起)把FusionExpr的硬编码权重改为ctx.fusion_weights,由Retriever实现的ctx参数注入。 - 新增
RouterRetriever(Retriever):组合多个底层 retriever(DenseRetriever / SparseRetriever / GraphRetriever),按 router 决策选择 / 融合。 - ColBERT 仅在 Reranker 层接入:新增
ColBERTReranker(Reranker)实现;接Reranker协议,完全不影响调用方。
2.4 工作量估计
- RRF 多路融合(Quick PoC,见 §2):0.5 人周
- SPLADE 接入:2 人周(含 ES mapping、批量重建索引)
- 语义路由:2.5 人周(含 router 训练数据采集、灰度框架)
- ColBERT Reranker:3 人周(GPU 部署 + 蒸馏小型化)
- 合计:~8 人周
2.5 风险与依赖
- ⚠️ 重建索引成本:现网 KB 数量 × chunk 数 × 维度,估算总耗时;需要提供"灰度索引切换"工具(详见 §6 路线图 P0)。
- ⚠️ 路由器误判:错路由比无路由更糟;必须配 fallback(路由失败回退到当前默认 0.05/0.95)。
- ⛓️ 依赖 [S3-T1] 的
RetrieverProtocol 落地后才能优雅接入路由器;否则会污染Dealer类。
D3. 知识图谱增强(基于 [S2-T4] GraphRAG 的延伸)
3.1 触发场景
- 法务/合规库每月新增 200+ 条法规:当前必须 重建整个图,CI 跑 1 小时;用户要求"增量入库 + 增量图更新"。
- 报错排查:"TS_001 错误码可能由哪些组件触发?" — 需要从 错误码 节点 N-hop 走到 组件 节点;当前 KGSearch 走的是文本相似度匹配实体,不是路径推理。
- 团队要求"为什么是这个答案" — 需要把推理路径(A→关系1→B→关系2→C)作为 citation 一同返回,提供 可解释性。
3.2 技术方案
| 子方向 | 方案 | 现状 → 目标 |
|---|---|---|
| 增量图演化 | 在 tasks.py:build_graphrag_for_document 链上插入 GraphMerge 阶段:新文档抽出的子图与全图做 节点对齐 + 关系合并 + 冲突标记;保留 version_int 字段记录每条边的"加入/失效"版本号 |
一次构建 → 增量更新 + 时间溯源 |
| 路径解释性 | KGSearch.retrieval() 输出新增 evidence_path: list[Edge];在 prompt 组装时把路径作为引用源;前端渲染"由 X→Y→Z 推断" |
黑盒答案 → 带溯源链路 |
| Neo4j 双引擎 | 当前图存在 ES 的 chunk 表里(knowledge_graph_kwd 字段),不能利用图算法;引入 Neo4j 作为 算法引擎(PageRank 已在 ES 里跑过,但 Cypher 跑社区检测、最短路径远更便利);ES 仍负责文本召回,Neo4j 负责图算法。README 已声明 Neo4j 是组件,只是 RAG 层没用 |
单引擎 → 检索 ES + 图算法 Neo4j 混合 |
| 温度敏感的图衰减 | 复用 core/memory/forgetting_engine 的 Ebbinghaus 实现到图边权重:长期未被命中的实体/关系权重衰减;与 D4 共享一套衰减逻辑 |
静态图 → 动态、有"记忆"的图 |
| 自动本体演化 | 借鉴 core/memory/ontology_services/General_purpose_entity.ttl,定期用 LLM 检查"这批新加的实体类型是否应该归并到已有类型?" |
类型膨胀 → 受控演化 |
3.3 接口改造点
- 新增
GraphRetriever(Retriever)实现,包装现有KGSearch;输出ScoredChunk.metadata增加evidence_path(list[(from_entity, relation, to_entity, confidence)])。 - 新增
GraphStore抽象层:add_subgraph / merge / query_path / pagerank / community_detect;实现两个:ESGraphStore(保留现状)、Neo4jGraphStore(新增)。graphrag/general/index.py现在直接操作nx.Graph,全部替换为GraphStore调用。 - 在
tasks.py的 Celery 链增加graph_merge_task:依赖build_graphrag_for_document,处理增量合并;需要分布式锁(已有redis_lock.py可用)。 - Prompt 层(
prompts/generator.py)新增evidence_aware_citation_prompt:把evidence_path作为额外上下文注入。
3.4 工作量估计
- 增量图演化(最小可用):3 人周(最复杂的是合并冲突的实体消歧)
- 路径解释性:2 人周
- Neo4j 双引擎:3 人周(含 Cypher 工具集、Neo4j 数据迁移脚本)
- 图衰减 + 本体演化:2 人周(与 D4 共享代码)
- 合计:~10 人周
3.5 风险与依赖
- ⚠️ 实体消歧难度:跨文档同名异义("苹果"=公司 / 水果);建议用现有
entity_resolution.py改造,但需要补全单元测试。 - ⚠️ Neo4j 运维成本:用户已在 README 声明依赖 Neo4j,但当前 RAG 层零调用;引入意味着同时管理两个图的一致性。建议把 Neo4j 定位为"算法只读 / 异步同步",避免双写一致性。
- ⛓️ 依赖 [S3-T1] 把
GraphStore与Retriever协议落实,否则会跨层塌方。
D4. 对话记忆 ↔ RAG 协同(短期 / 长期 / 检索召回三段桥接)
MemoryBear 的核心特色。当前最大产品差异化机会就在这里——
core/memory/与core/rag/是 两条独立链路,没有联动。
4.1 触发场景
- 用户在第 3 轮说"我对海鲜过敏",第 7 轮问"今晚吃什么?" — 当前 RAG 层无任何记忆能力,每次只看当轮 query。
- 多 Agent 协作:售前 Agent 收集到客户预算,售后 Agent 重新询问 — 跨 Agent 记忆需要从
core/memory读出 + 注入 RAG 检索 query 重写。 - 长对话上下文压缩:第 50 轮时,前 40 轮对话需要 被遗忘但保留要点,要点变成"用户档案 chunk"加入 KB。
4.2 短期 / 长期 / 检索召回的边界(产品决策)
| 维度 | 短期记忆(Working Memory) | 长期记忆(Episodic / Semantic) | 检索召回(KB) |
|---|---|---|---|
| 存储位置 | Redis,单 session 8KB cap | Neo4j + ES(core/memory) |
ES(core/rag) |
| 生命周期 | session(< 24h) | 永久(按 forgetting curve 衰减) | 永久(人工治理) |
| 写入触发 | 每轮 user/assistant message | reflection_engine 周期性提炼 | 文档入库流水线 |
| 召回时机 | 始终注入 prompt | LLM 重写 query 时 + 主动检索 | RetrievalNode 命中 |
| 数据契约 | list[Msg] |
MemoryItem(content, strength, type, ts) |
DocumentChunk |
| 可信度 | 高(用户原话) | 中(LLM 提炼) | 高(人工审核) |
决策原则:"用户原话进短期,提炼事实进长期,世界知识进 KB。" 三者不能互相替代。
4.3 技术方案
- MemoryAugmentedRetriever:在
RouterRetriever之外再包一层,retrieve 前用core/memory.read_services拿到当前 user 的 top-K 长期记忆条目,改写 query("今晚吃什么?" + 长期记忆"对海鲜过敏" → "今晚吃什么?避免海鲜")。 - Memory Citation:检索结果与长期记忆条目并入同一
chunks列表,prompt 模板区分两者来源("用户提及" vs "知识库"),避免幻觉混淆。 - 反向写入:每轮对话产出后,让
core/memory.write_router决定 是否需要把"新事实"写入长期记忆;这一步 复用core/memory.agent.langgraph_graph.write_graph(已存在)。 - 遗忘对齐:把
core/memory/forgetting_engine的 ACT-R 计算复用到 KB chunk 上(D3 已提);让"很少被命中的过期 KB chunk"自动沉睡,反向触发治理团队复审。
4.4 接口改造点
- 在
workflow/nodes/knowledge/node.py的KnowledgeRetrievalNode.execute()中注入MemoryService:当节点配置里enable_memory=true时,先调memory_service.recall(user_id, query)拿记忆,再传给Retriever.retrieve(query, ctx={memory: ...})。 - 新增
MemoryAwareRetriever(Retriever)实现,包装任一底层 Retriever。 - Workflow Node 配置
KnowledgeRetrievalNodeConfig增加memory_strategy: Literal["off", "context_only", "rewrite_query", "merge_chunks"]。 - Prompt 模板新增
<MEMORY>段落。
4.5 工作量估计
- 单向(memory → retrieval):3 人周
- 双向(retrieval 结果反写 memory):2 人周(大部分代码已在
core/memory存在) - 遗忘对齐 + 治理触发:2 人周(与 D3 共享)
- 合计:~7 人周
4.6 风险与依赖
- ⚠️ 隐私边界:长期记忆是 per-user,KB 是 per-tenant;混淆会导致跨用户泄露。设计时必须 user_id 级强隔离,code review 重点。
- ⚠️ Prompt 长度膨胀:记忆 + KB 双源;如果未做摘要,长对话场景 token 成本翻倍;必须配合记忆摘要(已有
summary4memory.md)。 - ⛓️ 依赖 [S3-T1] 的
Retriever / Reranker协议;强依赖 [S2-T6] 的 E2E 时序图明确两条链路的衔接点。
D5. 评估与反馈闭环(用户反馈 → Reranker 微调)
5.1 触发场景
- 答案错了 / 引用不对,用户点👎 — 当前数据 进了日志,没人消费。
- 同一 query 在不同时段表现波动 → 需要离线 A/B 评估。
- 业务方问"再加一个 KB 之后效果到底变好还是变差?" — 没有可量化的回归指标。
- README 给的 F1/BLEU/J 在论文中实现过,但仓内没有这套代码,每次评估靠手工。
5.2 技术方案(双轨:评估在线化 + 反馈学习)
5.2.1 评估轨:离线 / 在线 / CI 三层
| 层级 | 内容 | 工具 |
|---|---|---|
| 离线评估集 | 每 KB 维护一个 eval_cases.jsonl:{query, ideal_chunks, ideal_answer, hard_negatives};增量构建(每周从用户问句 + 答疑团队补充) |
DSL + Excel 导入工具 |
| 在线指标 | Hit@K / MRR / nDCG / Citation Coverage / Hallucination Rate / Latency P50/P95;通过 OpenTelemetry 埋点写入 Prometheus |
OTel + Prometheus + Grafana |
| CI 评估 | 每个 PR 跑核心 KB 的回归集;指标低于 baseline n% 时阻塞合并 | RAGAS(开源)+ 自研判分 prompt |
5.2.2 反馈学习轨:从👍/👎到 Reranker 微调
用户反馈(👍/👎/edit)
↓ event log
事件清洗(同一 query 多个 chunk 评分)
↓
形成 (query, positive_chunk, negative_chunk) 三元组
↓
├─ 短链:在线 PairWise 调整 BM25/dense 权重(D2 路由器配置)
└─ 长链:周/月一次离线训练 Cross-Encoder reranker(基础模型用 bge-reranker-base 蒸馏)
↓
新 reranker 走 D6 灰度框架上线
↓
评估轨自动验证收益
5.3 接口改造点
- 新增
EvaluationProtocol:{evaluate(query, retrieved, generated, ground_truth) -> Metrics};在 OpenTelemetry trace 末尾自动落 Prometheus。 RedBearRerank改造:接入LocalCrossEncoderRerank(Reranker)子类,加载本地 ONNX/TorchScript 模型;可与 Jina/DashScope 并存于工厂。- 反馈采集:复用
core/memory的事件总线(如有)或新建feedback_event表;前端组件加 thumbs;citation 点击行为也作为隐式反馈。 - 训练 pipeline 独立仓 / 独立服务;产物(ONNX)通过模型注册表(用现有
ModelConfig表扩展即可)滚动上线。
5.4 工作量估计
- 评估指标埋点 + Grafana 看板:1.5 人周
- 离线评估集 + RAGAS CI 集成:2 人周
- 反馈采集 + 三元组清洗:1 人周
- Cross-Encoder 蒸馏训练 pipeline:3 人周(含数据扩充、训练脚本、产出 ONNX)
- 合计:~7.5 人周
5.5 风险与依赖
- ⚠️ 冷启动:刚上线时反馈数据 < 1k 不足以训练;必须先用大模型 LLM-as-Judge 合成训练数据(现成 prompt 在
prompts/generator.py可借鉴)。 - ⚠️ 反馈污染:恶意 / 误点;需要置信度过滤(同一 user 短时多次相反反馈丢弃)。
- ⛓️ 依赖 [S3-T1] 的可观测性方案,否则数据采不到。
- ⛓️ 依赖 D2 的语义路由,否则没有"权重可调"的注入点。
D6. 自适应检索路由(Adaptive Retrieval Routing)
这是 D2 中"语义路由"的工程化升级版,独立列出是因为它会统一所有检索能力(dense / sparse / graph / memory / web),是 RAG 系统的中央调度器。
6.1 触发场景
- 同一用户在同一 session 内:第 1 个问题需要走 KB,第 2 个问题需要走 Web 搜索("今天的新闻"),第 3 个问题需要 Graph 推理 — 当前必须用户手动切模式。
- "你刚才推荐的方案做不了"(指代消解)→ 需要先走对话记忆,再决定是否检索;当前都是无脑全检索。
6.2 技术方案
| 决策类型 | 输入 | 输出 |
|---|---|---|
| 是否需要检索 | query + 短期记忆 | bool need_retrieval |
| 检索来源 | query 类型 | [KB_id, Graph_flag, Web_flag, Memory_flag] |
| 检索策略 | query 类型 + 用户场景 | (retriever_name, top_k, fusion_weights, rerank_id) |
| 兜底 | 第一次检索结果差 | 触发 query rewriting + 二次检索 |
实现:
- 路由器 = 小型 LLM(如 1.5B–3B)+ rule-based fallback;输出结构化 JSON。
- 训练数据来源:D5 的反馈数据 + 标注团队人工标 1k 条。
- 推理用 vllm 或 SGLang 自托管,P95 延迟控制在 50ms。
6.3 接口改造点
- 把
RetrieveTypeenum 改造成 strategy(与 D2 共享的RouterRetriever);workflow 层调用方不再选模式,而是传入 query。 - 新增
RoutingPolicy配置实体:可被工作空间管理员通过 UI 编辑(默认策略 + 灰度策略)。 - 与 D5 形成闭环:评估指标决定路由器升级时机。
6.4 工作量估计
- 规则+LLM 路由器最小可用:2 人周
- 完整训练 / 灰度 / 配置 UI:5 人周
- 合计:~7 人周
6.5 风险与依赖
- ⚠️ 路由器变成单点:必须有 fallback 到当前默认策略。
- ⛓️ 强依赖 D2 + D5;不建议独立做。
2. Quick PoC 路径(≤ 1 周可见效果)
PoC-A:RRF 多路融合检索(属 D2)
目标:现网 KB 在不重建索引、不改 schema 的前提下,加入 BM25 + dense 各自独立 top-50 → RRF 融合 → 同一接口返回。1 周内拿到 A/B 数据。
改动范围(最小集):
rag/nlp/search.py:Dealer.search()拆为两步:先单独跑 BM25(emb_mdl=None),再单独跑 dense(无 BM25),合并时用 RRF。- 增加 feature flag
RETRIEVAL_FUSION_MODE = {"weighted", "rrf"},默认 weighted(不影响现网)。
预期收益:在长尾 lookup query 上 Hit@10 +5–10pp(参考社区数据)。无负向风险,因为 weighted 路径保留。
PoC 代码草案(伪代码,约 30 行;正式实现需走完整 PR + 评估):
# rag/retrieval/rrf.py(新增)
def rrf_merge(rankings: list[list[ScoredChunk]], k: int = 60, top_k: int = 20) -> list[ScoredChunk]:
"""Reciprocal Rank Fusion: score = Σ 1/(k + rank_i)。
rankings: 多个独立排序结果,每个内部按相关度降序。
"""
score_map: dict[str, float] = {}
chunk_map: dict[str, ScoredChunk] = {}
for ranking in rankings:
for rank, chunk in enumerate(ranking, start=1):
cid = chunk.metadata["doc_id"]
score_map[cid] = score_map.get(cid, 0.0) + 1.0 / (k + rank)
chunk_map[cid] = chunk # 保留首次见到的对象
merged = sorted(chunk_map.values(),
key=lambda c: score_map[c.metadata["doc_id"]],
reverse=True)
for c in merged:
c.metadata["score_rrf"] = score_map[c.metadata["doc_id"]]
return merged[:top_k]
# 调用侧(rag/nlp/search.py:Dealer.search 增量改造)
if os.getenv("RETRIEVAL_FUSION_MODE", "weighted") == "rrf":
bm25_hits = self._search_bm25_only(req, ...)
dense_hits = self._search_dense_only(req, ...)
return rrf_merge([bm25_hits, dense_hits], k=60, top_k=req.get("topk", 20))
# else: 走现有 weighted 路径
PoC-B:Memory-Augmented Query Rewrite(属 D4)
目标:把 core/memory.read_services 已有的"长期记忆召回"接到 KnowledgeRetrievalNode 之前,做 query 改写。1 周内对 1 个内部 demo 应用上线。
改动范围:
KnowledgeRetrievalNode.execute()第一行加 5 行:拿 user_id(已有user_ids),调memory_service.get_user_summary(user_id),把 summary 拼到 query 前。- 新增 feature flag
MEMORY_AUGMENT_RETRIEVAL = false(默认关闭)。 - 不改 prompt,不改 schema,不改 ES。
预期收益:在多轮对话场景下,第 N 轮 query 的指代消解正确率提升;无回归风险(flag 默认关)。
# workflow/nodes/knowledge/node.py:KnowledgeRetrievalNode.execute() 头部增量
if os.getenv("MEMORY_AUGMENT_RETRIEVAL") == "true" and user_ids:
from app.services.user_memory_service import get_user_summary
summary = get_user_summary(user_ids[0], ttl_sec=3600) # 已存在 / 类似函数
if summary:
query = f"[用户背景: {summary}]\n{query}"
注意:上述两段代码均为 PoC 草案,真实落地需要:1)完整单测;2)评估对比;3)feature flag 走配置中心;4)权限审查(D4 涉及隐私)。
3. 优先级矩阵(用户价值 × 实现成本 × 风险)
评分 1–5(5 最高 / 5 最低)。建议落地顺序按"用户价值高 + 成本低 + 风险低"加权。
| 方向 | 用户价值 | 实现成本 (越低越好) | 风险 (越低越好) | 综合分(V × 1/√(C×R)) | 建议落地阶段 |
|---|---|---|---|---|---|
| D2-PoC RRF 融合 | 4 | 5 (0.5 人周) | 5 (无回归) | 8.0 | 立即(Sprint-3 内) |
| D4-PoC Memory Rewrite | 4 | 5 (0.5 人周) | 4 (隐私) | 7.2 | 立即(Sprint-3 内) |
| D5 评估埋点 + Grafana | 5 | 4 (1.5 人周) | 5 | 5.6 | 短期(1 月) |
| D5 RAGAS CI | 4 | 4 | 5 | 4.5 | 短期(1 月) |
| D2 SPLADE 接入 | 4 | 3 (2 人周) | 4 (索引重建) | 3.7 | 短期(1 月) |
| D4 完整双向集成 | 5 | 3 (5 人周) | 3 (隐私 / token) | 3.5 | 中期(2 月) |
| D5 Reranker 微调 | 4 | 3 (3 人周) | 3 (冷启动) | 2.7 | 中期(2 月) |
| D6 自适应路由 | 4 | 2 (5 人周) | 3 | 2.3 | 中期(3 月) |
| D1 多模态 L1(基线) | 3 | 4 (1.5 人周) | 4 | 3.0 | 短期(1 月) |
| D1 多模态 L2 跨模态 | 5 | 2 (3 人周) | 3 (GPU) | 2.5 | 中期(3 月) |
| D3 增量图演化 | 4 | 2 (3 人周) | 2 (实体消歧) | 2.0 | 中长期(3–4 月) |
| D3 Neo4j 双引擎 | 3 | 2 (3 人周) | 2 (运维) | 1.5 | 长期(4–6 月) |
| D1 多模态 L3 视听统一 | 3 | 1 (4 人周) | 2 (GPU + diarization) | 1.1 | 长期(6 月+) |
| D3 自动本体演化 | 2 | 2 | 2 | 1.0 | 长期 (按需) |
维度说明
- 用户价值:高优先级业务场景(toB 客户)调研访谈得分。
- 实现成本:人周折算(1 人周=1 分;6 人周=2 分;10 人周=1 分)。
- 风险:含技术风险 + 数据迁移 + 上线回滚 + 安全 / 隐私。
- 综合分用
V / sqrt(C×R)倒数化,仅作排序参考,不取代产品/架构会判断。
4. 落地路线图(Roadmap)
gantt
title MemoryBear RAG 后续迭代 路线图
dateFormat YYYY-MM-DD
axisFormat %m/%d
section Sprint-3 (现 Sprint)
PoC-A RRF 融合 (D2) :a1, 2026-06-02, 5d
PoC-B Memory Rewrite (D4) :a2, 2026-06-02, 5d
section 短期 (1 个月)
评估埋点 + Grafana (D5) :s1, 2026-06-09, 7d
RAGAS CI (D5) :s2, after s1, 7d
SPLADE 接入 (D2) :s3, after s1, 10d
多模态 L1 基线 (D1) :s4, 2026-06-09, 7d
section 中期 (2-3 个月)
Memory ↔ RAG 双向集成 (D4) :m1, after s2, 25d
Reranker 微调 pipeline (D5) :m2, after s3, 15d
自适应路由 (D6) :m3, after m1, 25d
多模态 L2 跨模态 (D1) :m4, after s4, 15d
section 长期 (3-6 个月)
增量图演化 (D3) :l1, after m1, 20d
Neo4j 双引擎 (D3) :l2, after l1, 15d
多模态 L3 视听统一 (D1) :l3, after m4, 20d
本体演化 (D3) :l4, after l2, 10d
所有阶段分别绑定一组 OKR + 评估指标(D5 提供数据),未达指标停止下阶段。
5. 风险与依赖总表
| 类型 | 风险 | 缓解策略 |
|---|---|---|
| 架构 | [S3-T1] 接口抽象未落地,本路线图全部方向受阻 | Sprint-3 内先把 Retriever / Reranker / Embedder / Generator 4 个 Protocol 落地([S3-T1] 必交付项) |
| 数据 | 索引重建(D1/D2/D3)导致服务不可用 | 灰度索引切换工具:双写期 + 流量按租户灰度 + 一键回滚 |
| 隐私 | D4 跨用户记忆泄露 | user_id 级强隔离 + 单元测试覆盖 + 上线前安全 review |
| 资源 | D1/D6 引入 GPU 依赖 | 优先走托管 API 跑通 PoC;自托管列入 long-term,需要预算评审 |
| 治理 | D5 评估集质量低 → CI 阻塞误判 | 评估集双人复核 + 周复盘 + 例外白名单 |
| 运维 | D3 Neo4j 双引擎一致性 | 定位 Neo4j 为算法只读,从 ES 异步同步;不双写 |
| 业务 | 路线图与产品 PRD 脱节 | 与 [@产品需求分析师] 在 Sprint-3 启动前对齐 1 次 |
6. 与 [S3-T1] / [S3-T3] 的对齐清单
- ✅ 每个方向都标注了"接口改造点",所有改造均落到 [S3-T1] 提议的
Retriever / Reranker / Embedder / Generator / GraphStore / LoaderProtocol;不新增其它接口。 - ✅ 所有方向有"工作量、风险、依赖"三件套,可被 [S3-T3] 终审按统一模板核对。
- ✅ Quick PoC 已覆盖 D2 与 D4 各 1 条(≥ 2 条要求达成)。
- ✅ 优先级建议已按"用户价值 × 实现成本 × 风险"三维评分给出,并配有路线图甘特图。
- ✅ 多模态、混合搜索、KG 增强、对话记忆、评估闭环均覆盖(5/5);额外补充自适应路由作为联动方向。
— END —