Skip to content

fix(knowledge-graph): 修复 KG 构建管线四项级联缺陷(事务/端点流失/日志/退避) - #536

Merged
ThreeFish-AI merged 2 commits into
feature/1.x.xfrom
ThreeFish-AI/fix-kg-build-log-issues-v1
May 13, 2026
Merged

fix(knowledge-graph): 修复 KG 构建管线四项级联缺陷(事务/端点流失/日志/退避)#536
ThreeFish-AI merged 2 commits into
feature/1.x.xfrom
ThreeFish-AI/fix-kg-build-log-issues-v1

Conversation

@ThreeFish-AI

Copy link
Copy Markdown
Owner

背景

  • 本次变更要解决的问题:一次完整 KG 构建(corpus 43bacd7e,20 chunks,6.5 分钟)日志暴露出四项级联缺陷:① 社区摘要 A transaction is already begun on this Session 异常使终态降级为 completed_with_errors;② 75 条原始关系经 resolving 后 34 条端点 unresolved(45% 流失)集中指向被合并实体的 32-hex hash id(如 entity:57cff7c895... 出现 15 次);③ build_run_updated 日志 run_id=<UUID PK> 与外层 run_id=build-xxx-ts 双身份割裂;④ Cloudflare 502 错误返回 retry_after: 60 但应用层只按指数退避 1.1s 立刻重试。
  • 关联上下文 / Issue / 文档ISSUE-085 / docs/knowledge-graph.md(GraphRAG + LightRAG + Fellegi-Sunter 理论沉淀)/ docs/agents/browser-validation.md

核心变更

  • 缺陷 1 · 社区摘要事务冲突service.py B3 阶段从 shared_session 剥离,使用独立 AsyncSessionLocal() 会话承载 corpus 配置查询与 summarizer 调用;community_summarizer.py 移除三处内部 db.commit(),事务边界回归调用方("事务边界单一来源"原则)。
  • 缺陷 2 · 关系端点 45% unresolvedentity_resolver.py ResolutionResult 新增 id_merge_map: dict[str, str](old_entity_id → surviving_entity_id),Exact / Token / ANN 三阶段同步维护;ANN 阶段返回签名变更为 tuple[set[int], dict[str, str]],命中 DB 既有实体时记录跨表 UUID 映射;新增 _flatten_chain 工具函数统一展平 label / id 两条链路的传递映射;service.py _resolve_ref 重写为"ID 直查 → 已是存留 id → 标签级 fallback"四级优先级,删除旧的 len(ref) == 32 and all hex 启发式分支。
  • 缺陷 3 · 日志 run_id 双身份repository.py update_build_run 新增可选 human_run_id 形参;build_run_created / build_run_updated / build_run_update_skipped_by_state_guard 三处日志统一输出 run_uuid=<DB PK> + run_id=<人类可读> 双字段,串联跨日志条目语义;service.py 全部 update_build_run 调用点传入 human_run_id=run_id
  • 缺陷 4 · LLM retry_after 失尊extractors.py 新增 _extract_retry_after_seconds 同时支持 JSON body('retry_after': N)与 HTTP header(Retry-After: N)双源解析;_compute_retry_backoff 仅对 502 / 503 / 429 / bad gateway / rate limit / too many requests 等瞬时故障启用 retry_after,叠加 floor(≥ 默认指数退避防反向加速)与 cap(≤ 120s 防超长阻塞)+ jitter(防羊群),参考 RFC 9110 §10.2.3。

风险与回滚

  • 主要风险
    • 缺陷 1 修复改变了 B3 阶段的 session 生命周期;若用户环境的 AsyncSessionLocal 配置异常(连接池耗尽 / DSN 不可达),独立 session 创建可能失败——已通过 try/except 包裹整个 B3 阶段并回退到 warning + 兜底 shared_session.rollback() 兜底;
    • 缺陷 2 修复使 id_merge_map 成为关系端点的权威映射;若 EntityResolver 三 stage 之一漏建 id 映射,会回到旧的标签级 fallback(保留原行为)但不会引入新的 unresolved;
    • 缺陷 3 仅新增可选参数与扩展日志字段,无行为变更;
    • 缺陷 4 仅对错误体含 retry_after 提示的 502/503/429 类错误生效,普通错误退避不变。
  • 回滚方式git revert 04e88d57 单 commit 即可还原全部四项修复;ISSUE-085 详细记录每项的根因 / 修复 / 测试,便于二次审视。

验证证据

  • 单元测试
    • 新增 test_extractors_retry_backoff.py 18 例:覆盖 JSON / HTTP header 解析、502+retry_after 尊重、429 cap 120s、retry_after=1 不加速(floor 防御)、400 非瞬时故障不被错误延长、524 优先级高于 retry_after;
    • 新增 test_entity_resolver.py::TestEntityResolverIdMergeMap 6 例:Exact / Token / ANN 三 stage 各自 id 映射 + ANN→DB UUID 跨表 + 多跳传递链展平 + 空输入 / 无合并空字典;
    • 新增 TestFlattenChain 5 例:单跳 / 二跳 / 三跳 / 环路防御 / 空字典;
    • 适配既有 test_resolve_ref.py 结构断言(id_merge_map 引用 + 移除 relation_endpoint_hash_unresolved 断言)与 test_entity_resolver_token_overlap.py 3-tuple 解包;
    • 范围内 158 项断言全过,KG 单元测试目录 788/788 通过(1 个 pre-existing 失败 test_extraction_llm_plan::test_build_llm_invocation_plan_returns_none_when_serialization_fails 与本次修复完全无关,已通过 git stash 验证)。
  • 集成测试:未涉及(本次为单元级修复 + 结构断言)。
  • E2E / Workflow:未在 agent 上下文中执行——按 browser-validation 协议 端到端浏览器回归需用户在自有 Chrome 主 profile 触发同一 corpus 重建。
  • 覆盖率 / 关键指标对比
指标 修复前(日志) 修复后(目标)
unresolved_endpoints / raw_count 34 / 75 ≈ 45% < 5%
community_summary_failed 警告 1 0
终态 status completed_with_errors completed
build_run_updated 字段一致性 单字段 run_id=UUID 双字段 run_uuid + run_id

影响范围

  • 前端:无变更(仅日志字段调整不影响前端已订阅的 SSE / latest endpoint 数据契约)。
  • 后端apps/negentropy/src/negentropy/knowledge/graph/ 五个核心模块(service / entity_resolver / community_summarizer / repository / extractors);tests/unit_tests/knowledge/ 四个测试文件 + 一个新增;ABC GraphRepository.update_build_run 签名扩展(向后兼容,新增可选形参)。
  • GitHub Actions / 文档docs/issue.md 新增 ISSUE-085 完整摘要(表因 / 根因 / 处理方式 / 验证证据 / 后续防范 / 同类问题影响),符合 CLAUDE.md 工程纪律。

Next Best Action

  • 必做:用户在自有 Chrome 主 profile 触发同一 corpus(如日志中的 43bacd7e)重建,对照"指标对比"表验证 unresolved_endpoints 占比 < 5% 与终态 completed;按 gh pr review 走 ultrareview。
  • 建议(与本 PR 正交):① 社区检测 resolution 调优(62 节点产 28/25/25 太密,下一轮单独 PR 参数化 + 按图规模自适应);② 前端 /build-runs/latest 轮询替换为 SSE / EventSource,消除构建期 ~100 次/run 的 DB 压力;③ Stage 2 (ANN) borderline LLM 验证实装(entity_resolver.py:364 注释明确"留给后续迭代")。

🤖 Generated with Claude Code

…etry_after 失尊;

针对一次完整 KG 构建日志暴露的多处缺陷做系统性修复(详见 ISSUE-085):

1. 社区摘要事务冲突:B3 阶段从 shared_session 剥离,使用独立 AsyncSessionLocal
   会话承载 corpus 配置查询与 summarizer 调用;同时移除 summarizer 内部三处
   db.commit(),事务边界回归调用方(解决 "A transaction is already begun on
   this Session" 异常)。

2. 关系端点 unresolved 45% 流失:EntityResolver.ResolutionResult 新增
   id_merge_map(old_entity_id → surviving_entity_id),Exact / Token / ANN
   三阶段同步维护;新增 _flatten_chain 工具函数展平传递链;service.py
   _resolve_ref 重写为优先 ID 直查(含 ANN→DB UUID 跨表场景),删除旧的
   "32 位 hex hash unresolved" 启发式分支。

3. 日志 run_id 双身份:repository.update_build_run 新增 human_run_id 参数;
   build_run_updated / build_run_created / state_guard 三处日志统一输出
   run_uuid(DB PK)+ run_id(人类可读 build-xxx-ts)双字段;service.py
   所有调用点传入 human_run_id=run_id。

4. LLM retry_after 失尊:新增 _extract_retry_after_seconds 支持 JSON body
   与 HTTP header 双源解析;_compute_retry_backoff 仅对 502/503/429 等瞬时
   故障启用 retry_after,叠加 floor(≥ 默认指数)与 cap(≤ 120s)+ jitter。

测试覆盖:新增 test_extractors_retry_backoff.py 18 例、
TestEntityResolverIdMergeMap 6 例、TestFlattenChain 5 例;适配既有
test_entity_resolver_token_overlap.py 与 test_resolve_ref.py 结构断言;
范围内 158 例全过,KG 单元测试目录 788/788 通过。

🤖 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>
…语义反转 / DB UUID 关系静默丢失;

1. 消除 _compute_retry_backoff 双重 jitter:提取无 jitter 的 base_backoff 作为
   retry_after floor 计算基线,避免 [0,2) 的超宽 jitter 范围;收紧测试断言
   至单层 jitter 区间。

2. 修正 _ann_stage primary_keys 语义:从 remaining_indices(存留实体)填充
   survivor_keys,从已合并 secondary 经 prior_id_merge_map 回溯填充
   secondary_survivor_keys;排除 normalize_label 碰撞导致的自合并
   (如 "OpenAI" vs "OpenAI Inc.");同步维护 merge_map(label→label)
   以支持下游标签级 fallback。

3. 修复 ANN→DB UUID 关系持久化静默丢失:_resolve_ref 对 id_merge_map 返回的
   DB UUID 做可达性检查,通过 db_uuid_to_label 反向映射转写为标签,确保
   _create_relation_with_session 和 sync_relation 均能正确处理;无 label
   映射时标记 unresolved 保持计数器可见性;sync_relation edge_dicts 构建
   补充 db_uuid_to_label fallback。

KG 单元测试 792/793 通过(1 个预存失败与本次无关)。

🤖 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 5f6a2a8 into feature/1.x.x May 13, 2026
7 checks passed
@ThreeFish-AI
ThreeFish-AI deleted the ThreeFish-AI/fix-kg-build-log-issues-v1 branch May 13, 2026 13:33
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