Skip to content

fix(knowledge-base): 修复 Corpus chunks 计数虚高与摄取写入路径非幂等导致的孤儿数据累积 - #488

Merged
ThreeFish-AI merged 7 commits into
feature/1.x.xfrom
ThreeFish-AI/fix-corpus-chunk-count
May 10, 2026
Merged

fix(knowledge-base): 修复 Corpus chunks 计数虚高与摄取写入路径非幂等导致的孤儿数据累积#488
ThreeFish-AI merged 7 commits into
feature/1.x.xfrom
ThreeFish-AI/fix-corpus-chunk-count

Conversation

@ThreeFish-AI

@ThreeFish-AI ThreeFish-AI commented May 10, 2026

Copy link
Copy Markdown
Owner

背景

  • 历史版本 ingest_text/file/url 不幂等——同一 (corpus_id, source_uri) 多次摄取纯 INSERT 不清理旧 chunks,导致 chunks 数量虚高(如 849 vs 预期 84)
  • Corpus 列表/详情页的 knowledge_count 统一为全量行数,hierarchical 切分下无法区分用户感知的 chunks 与实际参与检索的 vectors

核心变更

  • 原子 DELETE+INSERT:新增 replace_knowledge_by_source 方法,同事务内完成删除旧数据+插入新数据,消除孤儿 chunks 累积;_ingest_text_with_tracker 新增 persist_mode 参数(replace/append/auto),所有摄取入口统一走 replace 路径
  • 双口径计数_top_level_role_expr 单一事实源过滤 child 子块,list_corpora_with_counts / get_corpus_with_counts 返回 top-level + total 双计数,前端展示 "X chunks · Y vectors"(仅 hierarchical 场景下两数不同时展示)
  • 孤儿清理工具:CLI 脚本 cleanup_orphan_chunks.py(干跑默认 + backup CSV)+ 管理 API 端点 POST /base/{corpus_id}/admin/cleanup-orphans,按 created_at 时间聚类识别多批次摄取,保留最新完整批次
  • Pipeline Tracker 增强get_stage_output 读取已完成 stage 输出,合成 delete stage 保持前端时间轴语义一致

风险与回滚

  • 主要风险:replace_knowledge_by_source 在同事务内 DELETE+INSERT,并发同 source_uri 摄取可能导致数据翻倍(但窗口比旧方案显著缩小)
  • 回滚方式:revert 本 PR,恢复旧的分步 delete-then-ingest 流程

验证证据

  • 单元测试:test_cleanup_orphans.py(聚类算法)、test_corpus_count_semantics.py(persist_mode 行为)、test_repository_replace.py(repository 辅助方法)
  • Dashboard 计数统一为 top-level 口径,与 corpus 列表、document chunks 页一致

影响范围

  • 前端:CorpusList.tsxpage.tsxknowledge-api.ts(双数字展示)
  • 后端:repository.pyservice.pyapi.pyschemas.py(原子写入 + 双口径计数 + 清理端点)
  • 新增脚本:cleanup_orphan_chunks.py

Next Best Action

  • 对存量 corpus 执行一次 cleanup_orphan_chunks.py --apply 清理历史孤儿数据
  • 观察 hierarchical 场景下双数字展示是否符合用户预期

ThreeFish-AI and others added 4 commits May 10, 2026 15:48
根因:
1. ingest_text/file/url 不幂等——同一 (corpus_id, source_uri) 多次摄取纯 INSERT,旧 chunks 残留
2. replace_source/sync_source 等的 DELETE+INSERT 分属独立事务,异常时旧删新未插
3. list_corpora 的 chunks 计数含 hierarchical child,与 document chunks 页口径不一致

修复(三层防线):
- Repository 新增 replace_knowledge_by_source(同事务 DELETE→INSERT,async with db.begin() 原子回滚)
- Service _ingest_text_with_tracker 注入 persist_mode(replace/append),按 source_uri 自动决定语义
- 7 个 replace/sync pipeline 统一切到原子方法,消除两段式事务
- list_corpora/get_corpus/dashboard 切换为 top-level 口径(排除 child),新增 chunk_count_total 辅字段
- 前端 CorpusList 展示 "14 chunks · 70 vectors" 双数字(仅 hierarchical 时显示 vectors)

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
- cleanup_orphan_chunks CLI: 按 created_at 时间聚类识别重复摄取批次,保留最新批次,物理删除孤儿 chunks(默认 dry_run)
- POST /base/{corpus_id}/admin/cleanup-orphans 管理端点: 支持 dry_run 查询参数
- 14 个单元测试覆盖:时间聚类算法、chunk_index 完整性校验、persist_mode 语义、PipelineTracker stage output
- 修复 _cluster_by_time 中 datetime.total_seconds() 误判导致的聚类失效(hasattr 检查对象错误)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
page.tsx 中的 corpus 卡片也需展示 chunk_count_total,
与 CorpusList.tsx 保持一致,修复遗漏的渲染点。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
回退到 clusters[-2] 后重新检查 chunk_index 连续性,
与 CLI 脚本行为对齐,防止 dry_run=False 时保留不完整批次。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
@ThreeFish-AI ThreeFish-AI changed the title placeholder fix(knowledge-base): 修复 Corpus chunks 计数虚高与摄取写入路径非幂等导致的孤儿数据累积 May 10, 2026
- FakeRepository 补充 get_corpus_by_id 与 replace_knowledge_by_source,
  使 rebuild pipeline 测试 RuntimeError 从正确位置抛出而非 AttributeError
- test_pipeline_tracker 断言从 delete stage 更新为 persist stage(原子化后 delete 已合并)
- KnowledgeBasePage UI 测试断言从 "chunks: 3" 更新为 "3 chunks"

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
集成测试的 FakeRepository 缺少 replace_knowledge_by_source 方法,
导致 ingest_text(source_uri 非空 → effective_mode=replace)触发 AttributeError。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
原 _cleanup 函数仅收集扁平 ID 列表传给 _write_backup_csv,
导致 CSV 除 id 外所有列(source_uri、chunk_index、role、created_at)均为空,
无法支撑脚本文档声称的"可手工恢复"。

修复:
- all_deleted_ids → all_deleted_chunks,收集完整 chunk 字典
- _get_chunks_for_source 返回值补充 source_uri 字段
- _write_backup_csv 优先使用 per-chunk source_uri

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
@ThreeFish-AI
ThreeFish-AI merged commit 71a109a into feature/1.x.x May 10, 2026
12 checks passed
@ThreeFish-AI
ThreeFish-AI deleted the ThreeFish-AI/fix-corpus-chunk-count branch May 10, 2026 13:51
ThreeFish-AI added a commit that referenced this pull request Jul 5, 2026
…-2026-4372 处置) (#1057)

* fix(deps): ts-deepmerge 补丁地板至 8.0.0 修复 GHSA-87mf-gv2c-c62c (#481);

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(negentropy): pydantic-settings 升 2.14.2 + joserfc>=1.6.7 补丁地板修复 #482/#488;

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(cognizes): joserfc/msgpack/python-socketio/python-engineio 补丁地板修复 #483/#486/#487/#490/#491;

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* docs(perceives): ISSUE-092 增补 CVE-2026-4372 威胁模型;transformers 钉 4.x + dismiss #492(marker 5.x 不兼容实测);

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant