docs(debug): r3 缺陷记录文档(13 项+复测 4 项+部署 6 缺口,含根因/修复/时间/验证)

This commit is contained in:
2026-09-10 20:38:11 +08:00
parent 39120b985f
commit 206f92e275
+142
View File
@@ -0,0 +1,142 @@
# 缺陷记录(Debug Record):176 手工测试修复轮(r3)
- 记录范围:176 部署机手工测试《PlantAI-rag-new知识问答部分测试问题一览_20260909.xlsx》13 项缺陷 + 复测发现的 4 项 + 176 部署中暴露的 6 项环境/数据缺口
- 修复组织:TL 拉起 agent 团队(测试 agent → Debug-1 前端 / Debug-2 后端并行 → 测试 agent 复测 → 缺陷回改 → 定点复测 → TL 逐项回归验收)
- 代码基线:feature/bioflow-conversation-orchestration @ f463194(2026-09-09)→ 终态 @ 39120b9(2026-09-10 20:10,已 push),tag `bugfix-r3-20260910`
- 验收依据:`docs/acceptance-r3.md`(测试 agent 编制,S1=175 dev / S2=176 终验)
- 修复日期:2026-09-10(单日内完成;时间为该日 24 小时制)
## 复现与修复时间线(提交序)
| 时间 | commit | 内容 |
|---|---|---|
| 14:44 | c53fe9e | 测试 agent:13 项验收测试用例落库(acceptance-r3.md) |
| 15:34 | 21063af | 部署 agent:DEPLOY_FLOW §5c MinerU CPU 裸部署 + §5d embedding 裸部署 |
| 16:17 | 671783e | Debug-1:前端 10 项缺陷修复(首次提交) |
| 16:46 | 772c7cd | Debug-2:后端 7 项缺陷修复(首次提交) |
| 18:01 | 53069d4 | Debug-1 回改:r3-07-01 跳过按钮 / r3-52-02 终态文案 / b3 测试债 |
| 18:03 | ad248cf | Debug-2 回改:r3-47-01 DOCX 塌缩 / r3-42-01 内置模板回退 |
| 18:13 | b497aec | 测试 agent:定点复测结论附录(4 项复测通过) |
| 18:23 | 2150b28 / 6cddda7 | TL 合并 debug/frontend + debug/backend 至 feature 分支 |
| 19:38 | 2fbbd3e | 176 部署暴露:补入 run_methodology_batch.py(LLM 方法学提取阶段缺失) |
| 20:09 | f7188be | 176 部署暴露:索引脚本校验段按标签+属性过滤(按名匹配永远为空) |
| 20:10 | 39120b9 | 176 部署暴露:DEPLOY_FLOW §5c 补设备模式开关/LLM 阶段四键/8093 主上游提醒 |
---
## 一、13 项手工测试缺陷(问题清单 Excel)
### #7 答案揭示动画「标题章节没有序号,且超时」
- **根因**(三处):①`ui/src/stores/chat.js` revealText 加速分支只放大步长、定时器间隔仍写死 30ms → 5000 字符实际约 150s,远超 8s 上限;②`ui/src/components/chat/markdown.js` heading 无编号注入;③BFF `sdk/app/services/sse_relay.py` complete 帧前串行等待图片注入(每 PMCID 5s 外网超时,4 篇可拖 20s)。
- **修复**:前端长文按 tick 预算反推 interval(总时长严格 ≤8s,≤2000 字符保持 30ms/字符);markdown.js 注入「一、/1.1/1.2.3」编号(已有序号跳过,层级归零),新增 renderMarkdownPlain 供文档预览/私有块(防编号写回正本);后端图片注入加总预算 `FIGURE_INJECT_BUDGET_MS`(默认 2500ms)+top3 裁剪+逐篇均分截断。
- **验证**:单测 5+7 项;S1 跳过点击 2439 字立即定格;S2 真机 4785 字揭示 **7.9s**(≤8.5s)、BFF 日志「预取图片超时(833ms)静默降级」×3。
### #27 会话级聚合「聚合后文献 id 对应不上,会往后+1」
- **根因**:前端 `ui/src/stores/bench.js` 对后端已聚合结果二次聚合,徽标显示去重下标+1 而非真实 paper_id。
- **修复**:删除前端重复聚合,会话域直接透传后端结果;徽标显示真实 paper_id(截断+悬浮);高亮定位与 chip 跳转改 paper_id key(chip 编号契约不变)。
- **验证**:单测 3 项;S1 28 行 API 去重与徽标完全一致,无「+1」。
### #28 空态「检索显示超时,应提示没有检索到此问题的有效回答」
- **根因**:BFF `/search` 未注 `native_chain_enabled` → 检索模式仍跑 16.4M 边图链+CPU 嵌入,破 120s 超时 → 504 被前端显示为超时报错;空结果路径本身正常。
- **修复**:BFF /search 注入 `native_chain_enabled:false`;search 模式 ReadTimeout 降级返回 **200 空结果体**(degraded:true,reason:TIMEOUT);QA 侧 use_llm=false 双保险;前端新增「没有检索到此问题的有效回答」/「检索超时,未获取到有效回答(已降级返回)」双文案。
- **验证**:黑洞上游捕获请求体注入参数;S2 真机 120.03s 超时返 200 降级体契约逐字段吻合。
### #31 节点详情「点击图节点无法显示实体属性,弹出频率异常」
- **根因**:KgEntityDetail fetchExtra 无请求序号守卫(迟到响应覆盖新点击);KgGraphView pointerdown 即 setPointerCapture 吞掉节点 click(拖动也产生 click);KgPane 详情组件无 :key 复用。
- **修复**:fetchSeq 请求序号守卫;`:key="nodeKey"` 强制重建;pointer 重构(pointerdown 只记起点,位移>4px 才标记拖拽,click 时 dragging 直接 return)。
- **验证**:单测 3 项;S1 单击 0.1s 出全量属性、连点 A→B 始终 1 面板内容=B、拖拽不弹详情;S2 真机同过。
### #32 实体搜索「输入水稻响应超时」
- **根因**:normalized 实例(Entity/ASSERTS)无 name_norm 索引,前缀查询全扫(等值 2.9s)破 10s 超时转 503;代码注释明确 TODO(A3) 适配层未实现。
- **修复**:neo4j.py 实现 normalized 分支(search_entities/entity/neighborhood/_resolve_id),canonical 分支零改动;超时/不可用分流(Neo4jTimeout→504 / Neo4jUnavailable→503);新增 `deploy/qa-db/create_neo4j_indexes.sh` 幂等索引脚本。
- **验证**:S2 真机 BFF 图谱搜索 **0.069s**(阈值<1s)、直查 0.0046s 走索引;「水稻」0.011s 空态正常(库为英文数据,全库仅 33 个 CJK 实体名,非缺陷)。
### #37/#38 PDF 上传提取「No such file or directory: mineru」
- **根因**:`DEFAULT_MINERU_CMD` 默认拼 175 机 conda 路径(176 不存在);GF_PYTHON_ENV 默认值同为 175 路径;figures.py 两常量硬编码;176 无 GPU 会撞 nvidia-smi 预检。
- **修复**:mineru/GF python 路径 X_OK 预检→中文可读错误(含「请在 prod.env 配 MINERU_CMD」指引);`PLANTAI_GF_PYTHON_ENV` 覆盖 GF 路径;figures.py 两常量 env 化;`METHODOLOGY_MINERU_DEVICE_MODE` 设备模式注入(cpu 时清空 CUDA);stdin-EOF 陷阱规避(stdin=DEVNULL + MINERU_API_SHUTDOWN_ON_STDIN_EOF=0);GPU_PREFLIGHT 开关(176 设 0)。
- **验证**:S1 预检四项直测全过;S2 缺失路径可读错误端到端、MinerU CPU 全链 completed 100%。
### #39 运行日志「日志无法刷新加载」
- **根因**:ExtractionPane toggleLog 只在首次打开且为空时拉一次,无轮询无刷新按钮。
- **修复**:打开总是重拉;「刷新日志」按钮;logOpen 且有 running 任务时 5s 独立轮询(onBeforeUnmount 清理)。
- **验证**:S1 每次打开重拉/刷新按钮/5s 双周期/终态停止 16s 无新请求。
### #40 轮询刷新「tab 内容没有刷新」
- **根因**:setActiveTab 仅离开 extract 才暂停(其他离开场景漏);切 TAB 组件销毁导致详情/日志展开态(局部 ref)丢失。
- **修复**:任何离开 extract 的切换都 pausePolling+stopPolling,进入恢复;详情/日志状态提升 store(detailOpenId/logOpen/runLog),切回保留。
- **验证**:单测 4 项;S1 切走暂停 14s 无请求、切回恢复、展开态保留。
### #42 模板选择「UI 中没有模板选择选项」
- **根因**:后端能力齐(/library?as_template=true、generate 支持 template_id),前端三层断链:Composer 不传、sendDocgen payload 无 template_id、无组件调 listLibrary。
- **修复**:Composer docgen 模式模板下拉(自动推荐+7 内置+库内资料,懒加载+失败降级);payload 带 template_id(空省略走自动推荐);清理 docgen.js 死赋值。
- **验证**:S1 下拉 9 项、选「申报材料」产物 template_key=application。
### #47a 导出 DOCX「格式不一致」
- **根因**:DOCX 走 md2docx markdown 直转(不经过模板渲染),PDF 走 render_html+CSS 同源——两条路径天生不一致。用户决策:**HTML 同源转换**。
- **修复**:新增 `sdk/app/services/docgen/html2docx.py`(BS4 递归遍历自家 render_html 产物→python-docx;红头红字居中 22pt 黑体、标题分级、表格 Table Grid+表头灰底、图片内嵌/alt 降级);export docx 分支与 PDF 同构,异常回退 md2docx(env DOCGEN_DOCX_VIA_HTML=1 默认开);依赖补 beautifulsoup4(175 venv 装+176 离线 wheel)。
- **验证**:S2 真机 DOCX 70KB:568 段/102 标题/1 表格,红头 CENTER+FF0000+22pt 加粗,表头完整。
### #47b 红头残留「删除红头文件对话内容后仍占用文档界面」
- **根因**:docgen.resetSession() 存在但全仓零调用;selectSession 只 resetBenchData。
- **修复**:selectSession 追加动态 import 调 useDocgenStore().resetSession()(只清不丢,DocCard 可重开)。
- **验证**:S1 会话切换文档不残留、切回可重开。
### #52 上传资料后「没办法进行对话」
- **根因**:带附件的 docgen 同步长请求锁 busy(最长 600s),期间无法对话。用户决策:**异步任务化**。
- **修复**:后端 generate 拆快路径(校验链不变→插任务行→asyncio.create_task 后台跑→**立即 202**);新增 docgen_tasks 表+轮询端点(含节级 progress)+Semaphore 并发控制(默认 2,满 429)+启动中断标记(「服务重启,任务中断,请重试」);前端 202 后**释放 busy 锁**(生成期间可继续对话)、2s 轮询、「生成中 x/y 节」、done 挂 artifact 块+落库、error 可重试、会话恢复续轮询。
- **验证**:S1 202(0.44s)+queued→running→done+progress、**生成期间可继续发 QA 问题**;S2 BFF 重启任务不挂「生成中」。
### #55 文档 TAB 占用「上传的资料无法正常显示」
- **根因**:DocPane 仅 `!activeArtifact` 才渲染 PrivateLibraryPane;生成成功强制 adoptArtifact+切 TAB 后资料列表永不可见;close() 无 UI 入口。
- **修复**:docgen store 加 viewMode('doc'|'library');DocPane 头部「资料库/关闭文档」按钮;主条件改 `!activeArtifact || viewMode==='library'` 渲染资料库。
- **验证**:S1/S2 视图切换往返正常、上传资料列表可见。
---
## 二、复测发现的 4 项缺陷(测试 agent 复测→回改→定点复测通过)
| 缺陷号 | 发现时间 | 现象 | 根因 | 修复(commit) | 验证 |
|---|---|---|---|---|---|
| r3-07-01 (P1) | 17:0x 复测 | 揭示动画「跳过」按钮无反应 | skip-reveal 事件在 MessageList→ChatPanel 链路断裂(store.skipReveal 本身可用) | 补齐事件转发链(53069d4) | 真实 vite+9090:点击→光标/shimmer/按钮立即消失、2906 字定格 |
| r3-47-01 (P1) | 17:0x 复测 | 导出 DOCX 正文塌缩只剩 1 段(HTML 源 60p/8h2/32h3/13table) | html2docx 只遍历 `<main>` 直接子元素,未处理真实产物 `<div class="doc-body">` 包裹层 | _walk_blocks 递归遍历重写(ad248cf) | 用复测方证据 html1.json 过转换:计数精确对应;S2 真机 568 段/102 标题/1 表格 |
| r3-52-02 (P2) | 17:0x 复测 | docgen done 后第 4 步 desc 残留「生成中 8/9 节」 | 轮询 tick done 分支未还原默认文案 | done 分支还原「按大纲逐节生成正文」(53069d4) | 两阶段 mock 单测+浏览器实测 |
| r3-42-01 (P2) | 17:0x 复测 | 内置模板 key(如 official)在 vstore 无条目时回落自动推荐,产物与所选不符 | _pick_template 只在 vstore 结果按 id 匹配;且 pipeline step3 无条件 classify 覆盖 template_key | 内置 key 直解析为 builtin 模板(vstore 仅非内置 key)+step3 仅无 key 才 classify(ad248cf) | 9090 真实生成:「方案」+official → template_key=official 不再回落 plan |
---
## 三、176 部署中暴露的 6 项缺口(部署阶段发现,已修复并固化)
| # | 发现时间 | 现象 | 根因 | 修复 |
|---|---|---|---|---|
| D-1 | 19:2x | MinerU CPU 全链失败:预检报 175 路径 mineru 不存在,且任务跑在 8093 | **extraction 主上游是 legacy-rag 8093**(BFF 8000 不存在时回落 8093),而 MinerU env 七键只加给了 methodology 8092 的 prod.env | 两个 prod.env 都加七键;DEPLOY_FLOW §5c 写明 8093 主上游提醒(39120b9) |
| D-2 | 19:4x | MinerU 实际执行但 exit 1,卡 Layout Predict(日志 CUDA_VISIBLE_DEVICES=0) | **CPU 设备模式控制键是 `METHODOLOGY_MINERU_DEVICE_MODE`**;直读键 MINERU_DEVICE_MODE 被 build_mineru_runtime 忽略,仍注入 CUDA=0 | 两 env 加 METHODOLOGY_MINERU_DEVICE_MODE=cpu;DEPLOY_FLOW 生效时序段更新(39120b9) |
| D-3 | 19:3x | MinerU 过后 LLM 阶段失败:GF Python 指向 175 venv 路径 | 新仓从未携带 run_methodology_batch.py(旧仓 200 个脚本只移植了服务启动脚本);GF 默认值+DeepSeek 键+catalog 路径均 175 化 | 补入两树 scripts(2fbbd3e);env 加 PLANTAI_GF_PYTHON_ENV+DEEPSEEK×3+BBAV5_CAPABILITY_CATALOG(改 176 路径);catalog 36K 数据文件 rsync 至部署根 data/ |
| D-4 | 19:2x | create_neo4j_indexes.sh 建索引时 Entity.name_norm 索引 FAILED | **一条 9271 字节脏数据实体**(cent_cb6298cdc26491e7e8cc,entity_type=gene identifier 但 name_norm 塞满论文正文)超 neo4j RANGE 索引 8KB 硬限制 | 176 上 DETACH DELETE 脏实体→DROP 失败索引→重建全 ONLINE;已写进文档 |
| D-5 | 20:0x | 索引脚本校验段永远空输出 | neo4j 自动命名索引(如 index_889b0432),脚本按固定名匹配永远为空 | 校验改按标签+属性过滤(Entity.name_norm / ASSERTS.relation_category)(f7188be) |
| D-6 | 20:0x | BFF 手动重启后 kg 全挂(neo4j 上游 ok:false、kg/status 500) | S2-7 测试中手动 kill+uvicorn 重启 BFF 未 source sdk/.env → BFF_NEO4J_* 键全丢 | 走 start_all.sh 重启恢复(脚本内含 `set -a; . sdk/.env`);教训记入 DEPLOY_FLOW(手动重启必须走 start_all) |
---
## 四、验证账与终态
- 测试账:后端 pytest **286/286**;前端 vitest 全套 **373/373**;S1 复测 13 项全过(4 项回改后定点复测通过);**S2 终验 9/9 全过**(176 真机:图谱搜索 0.069s、检索降级 200 契约、MinerU CPU 全链 completed 100%、可读错误端到端、DOCX 70KB 结构完整、长文揭示 7.9s、BFF 重启任务不挂、图片注入 833ms×3 静默降级、「水稻」空态 0.011s)。
- 176 终态:五服务+11 端口全监听,BFF health ok 五上游全 true,nginx 80 200;MinerU 裸环境 /srv/plantai/mineru-cpu(8.1G,无 conda 无 docker);embedding=Ollama 裸服务 bge-m3:567m。
- 回归矩阵:chat.js 动画改动→知识库 #6-12;docgen 异步化→#41-53 全量;html2docx→导出用例;neo4j 适配→图谱 #32-35(canonical 分支零改动原则);轮询→#39/#40+历史轮询用例——全部通过。
## 附:关键修复文件索引
- 前端:`ui/src/stores/{chat,bench,docgen}.js`、`ui/src/components/chat/{markdown.js,Composer.vue,MessageList.vue,ChatPanel.vue}`、`ui/src/components/bench/{SourcesPane,SourceRow,ExtractionPane,KgPane,KgEntityDetail,KgGraphView,DocPane}.vue`、`ui/src/i18n/{labels,docgen}.js`、`ui/src/api/docgen.js`
- 后端:`sdk/app/routers/{docgen,qa,kg}.py`、`sdk/app/services/{sse_relay,figures,neo4j}.py`、`sdk/app/services/docgen/{html2docx.py(新),converter.py,pipeline.py}`、`sdk/app/db.py`、`sdk/pyproject.toml`、`agent/{methodology,legacy-rag}/api/methodology_routes.py`、`agent/qa/src/rag/qa_v1_1_73/api.py`、`deploy/qa-db/create_neo4j_indexes.sh(新)`、`docs/{DEPLOY_FLOW.md,API.md,acceptance-r3.md}`