Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions KNOWLEDGE_RAG_STAGE12.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,16 +64,20 @@ KnowledgeDocument -> chunk -> embed -> candidate retrieve -> rerank -> citation
## 实际结果

- 修复前基线:阶段 11 定向命令 `python -m pytest tests/test_knowledge_pipeline.py tests/test_knowledge_rag.py -q --disable-warnings` 为 `13 passed`;其中 10 条作业知识点只读取前 8 条,唯一匹配的第 10 条证据被漏掉。
- 修复后定向命令:`python -m pytest tests/test_knowledge_pipeline.py tests/test_knowledge_vector_store.py tests/test_knowledge_eval.py tests/test_knowledge_rag.py -q --disable-warnings` 为 `19 passed`,退出码 0,37.94s。
- 评审要求的评估命令:`python -m pytest tests/test_knowledge_eval.py -q --disable-warnings` 为 `4 passed`,退出码 0,0.24s;`python -m pytest tests/test_knowledge_eval.py tests/test_knowledge_rag.py -q --disable-warnings` 为 `15 passed`,退出码 0,37.89s。
- 全量回归:`python -m pytest -q --disable-warnings` 为 `681 passed`,退出码 0,13:26;warnings 为既有项目噪音和测试环境输出,本次没有失败用例。
- 固定评估命令:`python -m services.knowledge_eval`;5 个固定问题,4 个有标注问题,按“每题前 k 个去重文档命中数 / 该题相关文档数”计算 Recall@1=0.875、Recall@k=0.875;模式为 3 次 vector、1 次 keyword fallback、1 次 no-result,期望模式不匹配数为 0。
- 固定评估的普通问题耗时:切分/索引构建 mean 0.381ms、P95 1.701ms;查询 mean 0.051ms、P95 0.103ms;合计 mean 0.433ms、P95 1.762ms。
- 固定 64 文档性能样本、64 个切片、100 次查询、top-k=8:构建 0.901ms;查询 mean 0.418ms、P95 0.493ms;总耗时 42.745ms,按运行摊销 0.427ms/次。
- 本次审查指定定向命令:`python -m pytest tests/test_knowledge_eval.py tests/test_knowledge_vector_store.py tests/test_knowledge_rag.py -q --disable-warnings` 为 `19 passed`,退出码 0,47.06s。
- 全量回归(前一提交 `d370b5f`):`python -m pytest -q --disable-warnings` 为 `681 passed`,退出码 0,13:26;该结果未在本次标签修订后重跑,warnings 为既有项目噪音和测试环境输出。
- 固定评估命令:`python -m services.knowledge_eval`;5 个固定问题,4 个有标注问题,最后一题的两个相关文档现在均为真实的数组下标文档(`array-boundary`、`array-indexing`),不再把排序稳定性文档误标为相关文档。按“每题前 k 个去重文档命中数 / 该题相关文档数”计算 Recall@1=0.875、Recall@k=0.875;模式为 3 次 vector、1 次 keyword fallback、1 次 no-result,期望模式不匹配数为 0;共索引 16 个切片。
- 固定评估的普通问题耗时:切分/索引构建 mean 0.507ms、P95 2.239ms;查询 mean 0.061ms、P95 0.119ms;合计 mean 0.570ms、P95 2.326ms。
- 固定 64 文档性能样本、64 个切片、100 次查询、top-k=8:构建 1.096ms;查询 mean 0.463ms、P95 0.473ms;总耗时 47.388ms,按运行摊销 0.474ms/次。
- 行为回归:查询第 10 条唯一知识点时从旧的“前 8 条漏检”变为返回 `assignment-kp:10`;最终结果仍最多 8 条。超过 64 条时第 65 条及以后保持明确的资源边界。
- 故障实验:向量 embedding 抛出异常时返回 `KNOWLEDGE_RETRIEVAL_UNAVAILABLE`,学生端继续 answer-only,不暴露内部异常或伪造引用。
- `git diff --check`:通过。

### 维护者抽查答复

- ID10 能命中、ID70 不能进入结果,是因为 `MAX_INDEX_DOCUMENTS=64` 控制从数据库读取并建立索引的候选文档数:ID10 在前 64 条范围内,ID70 超出范围会被有意截断。`MAX_EVIDENCE=8` 是另一层边界,只控制最终返回给调用方的证据最多 8 条;它不决定是否建立索引。
- 查询“数据库迁移”时,空索引走 `no_result`,返回 `NO_KNOWLEDGE_EVIDENCE`,保持原有 answer-only 回退;索引含数组/指针文档但没有匹配时走 `priority_fallback`,按稳定优先级返回已有证据,避免有作业知识记录时把学生端结果突然变成无证据。只有索引为空时才进入 no-result 分支。

## 事实、推断与未解决问题

- 已确认事实:索引只存在于单次调用创建的 `HybridKnowledgeIndex`;未写入数据库、磁盘、Redis 或跨请求全局缓存;候选读取上限为 64,最终证据上限为 8;固定集和回归测试均在无生产凭据的隔离环境运行。
Expand Down
9 changes: 8 additions & 1 deletion tests/fixtures/knowledge_rag_eval.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@
"content": "稳定排序会保持相等元素的原有相对顺序。",
"source_type": "offline-eval",
"priority": 1
},
{
"document_id": "array-indexing",
"title": "数组下标",
"content": "数组下标从零开始,访问元素前确认索引合法。",
"source_type": "offline-eval",
"priority": 1
}
],
"queries": [
Expand Down Expand Up @@ -50,7 +57,7 @@
},
{
"query": "下标",
"relevant_document_ids": ["array-boundary", "sorting-stability"],
"relevant_document_ids": ["array-boundary", "array-indexing"],
"expected_mode": "vector",
"top_k": 1
}
Expand Down
4 changes: 4 additions & 0 deletions tests/test_knowledge_eval.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ def test_fixed_knowledge_eval_reports_vector_fallback_and_no_result_modes():
assert metrics["mean_total_latency_ms"] >= metrics["mean_query_latency_ms"]
assert metrics["performance_sample"]["document_count"] == 64
assert metrics["performance_sample"]["chunk_count"] == 64
assert metrics["case_results"][-1]["retrieved_document_ids"] == [
"array-boundary"
]
assert metrics["case_results"][-1]["recall_at_k"] == 0.5


def _write_fixture(tmp_path, documents, queries):
Expand Down