5.7 KiB
5.7 KiB
法规对话模块优化设计文档
日期: 2026-05-20
状态: 已批准,实施中
背景
当前法规对话模块存在以下问题:
compliance.py/compliance/chat/{segment_id}返回硬编码 Mock 数据rag.py/rag/chat返回硬编码 Mock 数据(前端实际调用/agent/chat/stream,此路由可统一)- 前端快速问题列表硬编码在
rag.ts,未调用后端 - 仅有 Dense 向量检索(COSINE),无 BM25 混合检索与精排
- LLM 输出的
[1][2]引用编号未在前端内联高亮 - 会话存储仅为内存(100条上限,30分钟过期)
方案:分层优先(4个阶段)
Phase 1 — 接入真实服务(Week 1)
目标:消灭所有 Mock,让系统真正可用。
后端变更
backend/app/schemas/compliance.py
ComplianceChatRequest新增segment_context: str | None = None
backend/app/api/routes/compliance.py
- 移除
get_mock_compliance_chat_response导入 /compliance/chat/{segment_id}接入get_agent_conversation_service().stream_chat()- 将
segment_context拼接到 query 前缀作为上下文 - 将 agent
content事件翻译为{"type":"chunk","text":"..."}格式,保持前端兼容
backend/app/api/routes/rag.py
- 移除
get_mock_retrieval、get_mock_rag_answer导入 /rag/chat接入get_agent_conversation_service().stream_chat()- 翻译 agent 事件为 rag 格式(
retrieved/chunk/done)
backend/app/schemas/rag.py
RagChatRequest新增session_id: str | None = None,filters: str | None = None
前端变更
frontend/src/api/rag.ts
getQuickQuestions()改为真实调用GET /api/v1/rag/quick-questions,失败时降级为本地数组
frontend/src/api/compliance.ts
complianceChat()新增第三个参数segmentContext: string | undefined,传入 request body
frontend/src/pages/Compliance/CompliancePage.tsx
sendChatMessage()中构建segmentContext(intent + content 摘要 + 法规名)- 传给
complianceChat()
Phase 2 — 混合检索 + Reranking(Week 2-3)
目标:提升召回质量(BM25 + dense RRF融合)+ 精排。
2a — Cross-Encoder Reranking(优先,无需 schema 变更)
- 新增端口
backend/app/domain/retrieval/ports.py:RerankerABC - 新增适配器
backend/app/infrastructure/vectorstore/cross_encoder_reranker.py- 调用 OpenAI-compatible reranker API(BAAI/bge-reranker-v2-m3)
- 修改
KnowledgeRetrievalService:先 retrieve top-20,再 rerank 到 top-5 - 新增 settings:
reranker_enabled: bool = False,reranker_model: str,reranker_top_k: int = 5
2b — Milvus Sparse BM25(需 schema 迁移)
- Milvus collection 新增
sparse_embedding SPARSE_FLOAT_VECTOR字段 - 新增端口
SparseEmbeddingProvider(sparse embed 接口) - 适配器优先使用 BGE-M3 API(同时输出 dense + sparse),不可用时降级为 TF-IDF keyword weights
MilvusVectorIndex.upsert()同时写入 sparse 向量MilvusVectorIndex.search()改为 hybrid search(WeightedRanker或RRFRanker)- 提供一次性迁移脚本:dump 所有 chunks → recreate collection → re-embed → re-insert
Phase 3 — 引用溯源 + 筛选 UI(Week 4)
目标:答案文本中 [1][2] 可点击跳转原文片段;法规类型/版本可筛选。
引用内联解析
- 新增 React 组件
CitedAnswer:接受text+sources[]- 用正则
/\[(\d+)\]/g拆分文本,将[N]渲染为可点击<cite>元素 - 点击高亮/滚动到来源面板对应条目
- 用正则
RagChatPage.tsx将 assistant 消息改用CitedAnswer组件渲染- 来源面板各条目加
id="source-N"属性
法规筛选 UI
RagChatPage.tsx在输入框上方加筛选栏:regulation_type下拉 +version输入- 筛选值作为
filters参数传到/agent/chat/stream MilvusVectorIndex.search()解析filters字符串为 Milvus expr(如regulation_type == "GB")
快速问题动态化
- 后端
/rag/quick-questions改为从 settings 或配置文件加载,不硬编码 - 前端已在 Phase 1 中改为调用后端
Phase 4 — 会话持久化 + 上下文压缩(Week 5)
目标:长对话不丢失;上下文过长时智能压缩。
PostgreSQL 会话存储
- 新增
backend/app/infrastructure/session/postgres_conversation_store.py- 实现
ConversationStoreport - 复用现有 PostgreSQL 连接
- DDL:
conversation_sessions+conversation_messages两张表
- 实现
- 新增 settings:
conversation_store_backend: str = "memory" bootstrap.py按 settings 切换实现
上下文压缩
- 在
AgentConversationService中,当对话轮数 > N 时,将早期消息用 LLM 摘要- 摘要替换为一条
system消息"对话摘要:..."
- 摘要替换为一条
- 新增
AnswerGenerator.summarize(messages) -> str方法
关键设计决策
| 决策 | 选择 | 原因 |
|---|---|---|
| BM25 实现 | Milvus sparse vectors | 不引入新服务,Milvus 2.4+ 原生支持 |
| Reranking | API-based cross-encoder | 复用现有 OpenAI-compatible 接口 |
| 会话持久化 | PostgreSQL | 复用现有 PostgreSQL 基础设施 |
| 引用解析 | 前端纯客户端 | LLM 已输出 [N] 编号,无需后端改动 |
| segment_context | 前端构建传后端 | 合规结果存在前端状态,无需后端持久化 |
验证标准
- Phase 1: 合规对话面板返回真实法规检索结果,不再固定响应
- Phase 2: 相同 query 在 hybrid 模式下比 dense-only 召回更相关结果
- Phase 3: 点击答案中的
[1]能跳转到来源面板第一条 - Phase 4: 刷新页面后历史对话仍可恢复