fix(boundary): 修复多库边界问题、版本管理及删除清理

多库检索与存储修复:
- RRF 融合去重改用 (collection, chunk_id) 复合键,修复同名文件结果被吞
- DocStore 存储路径加 collection 前缀,修复跨库同名切片数据覆盖
- search_multiple 去重改用复合键
- chunk_id 解析改用 rsplit 兼容下划线文件名

上传与版本管理修复:
- 同名文件上传改为覆盖模式,自动清理旧切片
- 修复首次上传不创建版本记录
- 修复覆盖上传版本号回退到 v1
- sync ADDED 分支改用动态版本号生成
- _generate_version_id 改为基于全部版本递增
- 废止/恢复操作同步 SQLite 版本记录
- mark_document_as_superseded 改为仅更新 SQLite

删除清理修复:
- 删除文档时同步清理 SQLite 版本记录和变更日志
- 删除向量库时同步清理该库所有版本记录
- cleanup 改为清理 SQLite 记录而非 ChromaDB

测试:
- test_version_management.py: 27 条版本管理单元测试
- test_edge_cases.py: 28 条边界用例测试
- test_upload_dedup.py: 5 条上传去重测试
- e2e_risk_test.py: 27 条端到端风险测试

文档:
- 新增风险边界问题修复注意事项.md(面向后端的对接文档)
- 新增向量库边界风险分析.md
- 更新多篇现有文档
This commit is contained in:
lacerate551
2026-06-04 23:58:44 +08:00
parent a1a0814633
commit cb75b9b274
50 changed files with 6385 additions and 6248 deletions

View File

@@ -5,11 +5,27 @@
---
### Phase 0基线建立 + 评估基础设施
### 实施进度总览(更新于 2026-06
| 阶段 | 内容 | 状态 | 说明 |
|------|------|------|------|
| Phase 0 | 基线建立 + 评估基础设施 | **部分实施** | `scripts/eval_e2e.py` 已创建,但 `data/eval_dataset.json``baseline.json` 尚未生成 |
| Phase 1 | Rerank 分数传递与上下文过滤 | **已实施** | `RERANK_CONTEXT_MIN_SCORE` 已配置,`_order_text_contexts_for_prompt` 已接受 `min_score` 参数 |
| Phase 2 | Token 预算控制 | **已实施** | `CONTEXT_MAX_CHARS=8000` / `CONTEXT_SOFT_LIMIT=6000` 已配置,`_build_context_with_budget()` 已实现 |
| Phase 3 | 上下文扩展精细化 | **已实施** | `EXPANSION_SCORE_THRESHOLD=0.3` / `MAX_EXPANDED_NEIGHBORS=4` 已配置,`_expanded_from_score` 元数据已记录 |
| Phase 4 | 置信度兜底 | **已实施** | `CONFIDENCE_WARN_THRESHOLD=0.15` / `CONFIDENCE_CAUTION_THRESHOLD=0.30` 已配置,`confidence_score` 已通过 SSE 输出 |
| Phase 5 | 上下文排序优化 | **部分实施** | `_build_context_with_budget()` 实现了通用排序逻辑,但列举类查询仍走独立的 `_is_enum_query` 分支 |
| Phase 6 | 引用标注改进 | **已实施** | 已迁移到 `core/agentic_citation.py`,支持动态阈值(短段落 0.55 / 长段落 0.45)和每段最多 2 引用 |
> **注**:下文各 Phase 中引用的具体函数名、行号为文档撰写时的快照,经多次迭代后已偏移。实际位置请以当前代码为准。
---
### Phase 0基线建立 + 评估基础设施 `部分实施`
**目标**:在改动任何代码之前,先有量化基线和自动化评估手段。
**现状**`scripts/evaluate_rag.py` 只评估检索层Recall/MRR/nDCG不评估端到端回答质量。`data/eval_dataset.json` 不存在
**现状**`scripts/eval_e2e.py` 已创建但尚未运行基线评估。`data/eval_dataset.json``data/eval_results/baseline.json` 尚未生成
**工作内容**
@@ -42,13 +58,19 @@
---
### Phase 1Rerank 分数传递与上下文过滤
### Phase 1Rerank 分数传递与上下文过滤 `已实施`
**目标**:让 Rerank 分数在 chat_routes 的上下文构建中发挥作用,过滤低分切片。
**目标**:让 Rerank 分数在上下文构建中发挥作用,过滤低分切片。
**改动范围**`api/chat_routes.py`,不涉及 engine.py。
**改动范围**`api/chat_routes.py` + `config.py`
**具体改动**
**实施说明**
- `config.py` 已新增 `RERANK_CONTEXT_MIN_SCORE = 0.05`
- `_order_text_contexts_for_prompt()` 已接受 `min_score` 参数(当前位于 `api/chat_routes.py` 第 188 行)
- 调用处已传入 `min_score=RERANK_CONTEXT_MIN_SCORE`(当前位于第 1750-1751 行)
- SSE `context_built` 事件已包含 `min_score_filter``score_stats``confidence_top3` 等调试字段
**原始设计**
1.`contexts.append` 时已有 score 字段,确认它包含 Rerank 分数(当前 `scores` 来自 `search_result.get('scores')`,是 RRF 融合分数还是 Rerank 分数需要确认)
@@ -88,13 +110,18 @@
---
### Phase 2Token 预算控制
### Phase 2Token 预算控制 `已实施`
**目标**:用字数/token 预算替代纯计数截断,避免上下文过长稀释 LLM 注意力。
**改动范围**`api/chat_routes.py` + `config.py`。
**具体改动**
**实施说明**
- `config.py` 已新增 `CONTEXT_MAX_CHARS = 8000`、`CONTEXT_SOFT_LIMIT = 6000`、`DIRECT_CONTEXT_MAX_CHARS = 2000`
- `api/chat_routes.py` 已新增 `_build_context_with_budget()` 函数(当前第 312 行),按 Rerank 分数降序逐个加入直到预算满
- 列举类 / 对比类查询走独立分支,保持原始顺序直接拼接(当前第 1754-1758 行)
**原始设计**
1. 在 `config.py` 新增:
```python
@@ -132,17 +159,24 @@
---
### Phase 3上下文扩展精细化
### Phase 3上下文扩展精细化 `已实施`
**目标**Rerank 后的上下文扩展只对高置信度切片执行,避免低分切片引入噪声邻居。
**改动范围**`core/engine.py` 的 `_expand_contiguous_chunks` 及其调用处。
**改动范围**`core/engine.py` 的 `_expand_contiguous_chunks`(当前第 1089 行)及其调用处。
**具体改动**
**实施说明**
- `config.py` / `engine.py` 已新增 `EXPANSION_SCORE_THRESHOLD = 0.3`、`MAX_EXPANDED_NEIGHBORS = 4`
- 扩展时传入 `min_score=EXPANSION_SCORE_THRESHOLD` 过滤低分切片
- 邻居切片 metadata 已记录 `_expanded_from_score`(种子分数)
- `MAX_EXPANDED_NEIGHBORS` 限制每个种子的邻居数量
- 上下文扩展同时在 `chat_routes.py`(第 281 行)和 `engine.py` 中实现,参数由 `CONTEXT_EXPANSION_ENABLED/BEFORE/AFTER/MAX_CHUNKS` 控制
1. MMR 前的扩展(第 573 行)保持不变——它的目的是防止邻居被 MMR 误删
**原始设计**(行号为撰写时快照,已偏移):
2. Rerank 后的扩展(第 615 行)增加条件:
1. ~~MMR 前的扩展(第 573 行)保持不变~~ —— 已重构,实际位置见 `core/engine.py`
2. ~~Rerank 后的扩展(第 615 行)增加条件~~ —— 已实施,`EXPANSION_SCORE_THRESHOLD` 控制
```python
# 只对 Rerank 分数 > EXPANSION_SCORE_THRESHOLD 的切片扩展邻居
EXPANSION_SCORE_THRESHOLD = 0.3
@@ -169,13 +203,19 @@
---
### Phase 4置信度兜底
### Phase 4置信度兜底 `已实施`
**目标**:当检索质量整体偏低时,在 prompt 中告知 LLM 谨慎回答,减少幻觉。
**改动范围**`api/chat_routes.py`prompt 层面,不改检索逻辑)。
**改动范围**`api/chat_routes.py`prompt 层面 + SSE 输出)。
**具体改动**
**实施说明**
- `config.py` 已新增 `CONFIDENCE_WARN_THRESHOLD = 0.15`、`CONFIDENCE_CAUTION_THRESHOLD = 0.30`
- `generate()` 内已计算 `_confidence_score`top-3 平均 Rerank 分数,当前第 1760-1762 行)
- 根据分数在 prompt 中注入不同的置信度提示(当前第 1821-1827 行)
- SSE `finish` 事件已附带 `confidence_score` 字段(当前第 1926 行)
**原始设计**
1. 在上下文构建完成后(`context_text` 已生成),检查 top-3 切片的平均 Rerank 分数:
```python
@@ -218,13 +258,18 @@
---
### Phase 5上下文排序优化
### Phase 5上下文排序优化 `部分实施`
**目标**:对所有查询类型(不仅是列举类)都做同章节聚合排序,保证同一文件同一章节的切片连续排列。
**改动范围**`api/chat_routes.py` 的 `_order_text_contexts_for_prompt`。
**改动范围**`api/chat_routes.py` 的 `_order_text_contexts_for_prompt`(当前第 188 行)
**具体改动**
**当前状态**
- `_build_context_with_budget()`(第 312 行)已实现了通用的分数排序 + 预算控制逻辑
- 但列举类查询(`_is_enum_query`)和对比类查询仍走独立分支(第 1754 行),直接拼接不做预算截断
- 尚未将"同章节聚合排序"推广为所有查询类型的默认行为
**原始设计**
1. 将当前只对 `_is_enum_query` 执行的排序逻辑推广为所有查询类型的默认行为
@@ -245,13 +290,19 @@
---
### Phase 6引用标注改进
### Phase 6引用标注改进 `已实施`
**目标**:提升 `_attach_citations` 的匹配精度,支持多引用。
**目标**:提升引用匹配精度,支持多引用。
**改动范围**`api/chat_routes.py` `_attach_citations` 函数
**改动范围**已迁移至 `core/agentic_citation.py`(独立模块),原 `api/chat_routes.py` 中也保留了 `_attach_citations`(第 393 行)作为备用
**具体改动**
**实施说明**
- 动态阈值已实现:短段落(< 50 字)使用 overlap 阈值 0.55,长段落 0.45
- 每段最多匹配 2 个 chunk
- 引用标记格式 `[ref:chunk_id]`,前端 `extractCitations` 已支持多个引用
- `agentic_citation.py` 中 `_attach_citations` 方法(第 220 行)为 agentic 模式提供独立的引用标注
**原始设计**
1. 动态阈值:短段落(< 50 字)使用更高的 overlap 阈值0.55),长段落保持 0.45
@@ -273,19 +324,19 @@
### 阶段依赖关系
```
Phase 0 (基线+评估)
Phase 0 (基线+评估) [部分实施]
Phase 1 (Rerank分数传递) ← 风险最低,收益最直接
Phase 1 (Rerank分数传递) [已实施] ← 风险最低,收益最直接
Phase 2 (Token预算) ← 依赖 Phase 1 的分数传递
Phase 2 (Token预算) [已实施] ← 依赖 Phase 1 的分数传递
Phase 3 (扩展精细化) ← 依赖 Phase 1 的分数信息
Phase 3 (扩展精细化) [已实施] ← 依赖 Phase 1 的分数信息
Phase 4 (置信度兜底) ← 依赖 Phase 1 的分数信息
Phase 4 (置信度兜底) [已实施] ← 依赖 Phase 1 的分数信息
Phase 5 (上下文排序) ← 独立,可与 Phase 4 互换顺序
Phase 5 (上下文排序) [部分实施] ← 独立,可与 Phase 4 互换顺序
Phase 6 (引用标注) ← 独立,放在最后因为改动面较大
Phase 6 (引用标注) [已实施] ← 独立,已迁移至独立模块
```
### 回退策略