环境
- Yuxi 版本:v0.7.2.beta1(部署分支,含 ARQ worker 异步索引链路;代码中已存在
knowledge_chunks.tags jsonb 列)
- 部署:docker compose(api + worker + postgres + redis + minio + milvus)
- 向量库:Milvus(默认库,非
yuxi db)
- 数据库:PostgreSQL 库
yuxi,表 knowledge_bases.additional_params(jsonb,内含 stats)
现象
知识库(kb_id=kb_u452jh75s0)上传 8 篇 PDF 并全部完成索引后,additional_params.stats 缓存与真实数据严重不一致:
| 统计项 |
stats 缓存(错误) |
真实数据 |
chunk_count |
0 |
158(knowledge_chunks 计数) |
pending_index_count |
8 |
0(knowledge_files 全部 indexed) |
token_count |
0 |
> 0 |
真实数据核验(均可复现):
knowledge_files:8 个文件 status 全部为 indexed
knowledge_chunks:158 行
- Milvus collection
kb_u452jh75s0:flush 后 num_entities = 158,与 PG 一致
- 语义检索正常(评估运行 recall@5 = 1.0)
即:数据层完全健康,只有 stats 投影过期。该缓存被 UI 列表 / 依赖库状态的逻辑读取,导致界面显示"待索引/0 分块",并会让依赖库状态的功能(如评估基准生成前的状态判断)产生误判。
根因分析(基于源码定位,供参考)
manager.py 已有刷新封装 _refresh_database_stats()(KnowledgeBaseRepository.update_stats 行锁内写回 additional_params["stats"])以及 _run_with_stats_refresh()(执行文件操作并刷新,异常路径也刷新)——但这些服务的是同步文件操作(删除/改名/更新等)。
- 上传 → MinerU/OCR 解析 → 切块 → 向量化 → 写
knowledge_chunks + Milvus 是 ARQ worker 异步链路(run_worker.py)。从调用点检索看,这条异步路径在任务完成后没有保证触发 _refresh_database_stats;一旦 worker 任务中断、异常、或批量处理部分失败,stats 就永远停在旧值,且无自愈机制。
- 维护者已知该缺口:
base.py / manager.py 提供了 repair_missing_file_stats(kb_id)(逐文件重算 chunk/token 并写回 + 刷新库级 stats),说明存在"修复"入口,但索引完成路径未自动调用,UI 也无该入口。
期望行为
- 索引链路完成后
additional_params.stats 与 knowledge_chunks / knowledge_files 真实计数保持一致(至少最终一致);
- 任何把文件状态从 pending → indexed 的异步任务结束(无论成功或异常)都触发一次 stats 刷新;
- 当 stats 与真实数据不一致时可自愈(读取时校验 / 定时 reconcile / UI 暴露"修复统计")。
建议修复方向
- 在 worker 索引任务收尾统一刷新:复用
_run_with_stats_refresh 的思路,在 parse/index 任务的成功与异常路径都调用 _refresh_database_stats(kb_id)(注意与 update_stats 的行锁/kb_config_cache_lock 配合,避免与并发操作互踩)。
- 自愈兜底:列表/详情读取 stats 时做轻量一致性校验(例如:文件全部
indexed 但 chunk_count==0 时触发一次 refresh),或提供定时 reconcile 任务。
- 暴露修复入口:UI 或 API 提供
repair_missing_file_stats 的调用入口(当前只能内部调用),便于用户自愈。
附注
- 我们现场用内部调用
repair_missing_file_stats(kb_id) 已成功修复该库(stats 回到 chunk_count=158 / pending=0),证明数据无损、纯投影过期。
- 触发路径暂未能 100% 复现(当前环境为已完成的批量上传场景),如维护者需要更多日志或复现用例,我们可配合提供(worker 日志、上传时序等)。
环境
knowledge_chunks.tagsjsonb 列)yuxidb)yuxi,表knowledge_bases.additional_params(jsonb,内含stats)现象
知识库(kb_id=
kb_u452jh75s0)上传 8 篇 PDF 并全部完成索引后,additional_params.stats缓存与真实数据严重不一致:chunk_countknowledge_chunks计数)pending_index_countknowledge_files全部indexed)token_count真实数据核验(均可复现):
knowledge_files:8 个文件 status 全部为indexedknowledge_chunks:158 行kb_u452jh75s0:flush 后num_entities = 158,与 PG 一致即:数据层完全健康,只有 stats 投影过期。该缓存被 UI 列表 / 依赖库状态的逻辑读取,导致界面显示"待索引/0 分块",并会让依赖库状态的功能(如评估基准生成前的状态判断)产生误判。
根因分析(基于源码定位,供参考)
manager.py已有刷新封装_refresh_database_stats()(KnowledgeBaseRepository.update_stats行锁内写回additional_params["stats"])以及_run_with_stats_refresh()(执行文件操作并刷新,异常路径也刷新)——但这些服务的是同步文件操作(删除/改名/更新等)。knowledge_chunks+ Milvus 是 ARQ worker 异步链路(run_worker.py)。从调用点检索看,这条异步路径在任务完成后没有保证触发_refresh_database_stats;一旦 worker 任务中断、异常、或批量处理部分失败,stats 就永远停在旧值,且无自愈机制。base.py/manager.py提供了repair_missing_file_stats(kb_id)(逐文件重算 chunk/token 并写回 + 刷新库级 stats),说明存在"修复"入口,但索引完成路径未自动调用,UI 也无该入口。期望行为
additional_params.stats与knowledge_chunks/knowledge_files真实计数保持一致(至少最终一致);建议修复方向
_run_with_stats_refresh的思路,在 parse/index 任务的成功与异常路径都调用_refresh_database_stats(kb_id)(注意与update_stats的行锁/kb_config_cache_lock配合,避免与并发操作互踩)。indexed但chunk_count==0时触发一次 refresh),或提供定时 reconcile 任务。repair_missing_file_stats的调用入口(当前只能内部调用),便于用户自愈。附注
repair_missing_file_stats(kb_id)已成功修复该库(stats 回到 chunk_count=158 / pending=0),证明数据无损、纯投影过期。