# 发现报告 — PlantAI RAG BFF 上游探测 > 探测日期:2026-08-24 至 2026-08-25(远程机 `100.109.52.26`,SSH 用户 xzq) > 本文件为团队事实基线。所有结构均来自真实探测响应或源码/OpenAPI,不是猜测。 > 未能确认的事项集中在第 6 节,明确标注,勿当作事实使用。 --- ## 1. 摘要与关键结论 1. **Neo4j 选型:`neo4j-plant-srt-direct-v1-full`**(bolt `bolt://127.0.0.1:18788`,HTTP `http://127.0.0.1:18575`,db `neo4j`,用户 `neo4j`,密码 ``)。 - 这是 QA 服务 7920 实际使用的实例(进程 `/proc/2586988/environ` 中 `NEO4J_URI=bolt://127.0.0.1:18788`),是权威答案。 - 该实例 schema 为 **canonical**(`QA_V1_GRAPH_SCHEMA=canonical`):实体标签 `SRT2CanonicalEntity`(3,820,996 节点),断言标签 `SRT2CanonicalAssertion`(8,246,875),关系 `SRT2_CANONICAL_ASSERTS` / `SRT2_SUPPORTED_BY`(共 16,449,159 条边)。 - **任务书假设的 `:Entity` / `[:RELATION]` / `entity_name_ftx` 全文索引在本实例不存在**。名字检索走 `name_norm` RANGE 索引(`srt2_canonical_entity_name_norm`),实测 0.09–0.10s。全文检索需求用 `STARTS WITH`/`CONTAINS` + name_norm 索引即可。 2. **抽取接口 8000 可用**:`/health` 返回 `{"status":"healthy"}`。`extract-jobs` 有 49 个历史任务(22 completed / 27 failed)。状态枚举为 `queued → running → completed/failed`(stage 相应为 `queued → mineru → llm → completed/failed`)。**注意:`processing-status`、`progress`、`summary` 均返回 `{"rows":[]}`**(因为当前 `METHODOLOGY_BATCH_DIR` 默认指向 `methodology_batch_llm` 目录且该目录不存在,见第 6 节)。`run-log` 返回 JSON `{"text":""}`(不是纯文本)。 3. **QA 7920 检索接口正常**:search 返回 31 个顶层键(见第 4 节),一次检索耗时约 91.9s(其中 88.8s 是 native_graph_chain_retrieval)。**当前 LLM 余额不足(DeepSeek HTTP 402 Insufficient Balance)**,`degraded_execution=true`,所有 LLM 阶段走 deterministic recovery,`answer` 为空或为 fallback 文案。这影响 chat/stream 的最终答案质量,但不影响 retrieval-only search 的证据输出。 4. **SSE 阶段序列(有序,五阶段 UI 映射基准)**: `understanding_started → entities_identified → related_search_started → concepts_found → subquestion_retrieved → agent_review_started → evidence_accepted → answer_generation_started → completed`,随后 `event: complete` + 完整 JSON(与 search 同构)。有 `: keepalive` 注释帧(实测 2 次)。 5. **端口 8090、5180 空闲**。node v18.19.1 / npm 9.2.0,`npm ping` 通(573ms),Playwright chromium 下载可行(约 150MB,未实际下载)。 6. **7900 是加密打包容器**(`plantai-protected-rag-1`,镜像 `plantai-rag-protected:1.0.0`),其 `/api/v1/kg/*` 路由指向空的 `plantai-protected-neo4j-1`(0 节点),kg/stats 全零、kg/query 空结果——**7900 的 kg 路由目前实质不可用**。其 methodology 路由可用但数据为空。 --- ## 2. Neo4j 实例探测 ### 2.1 对比表 | 属性 | `neo4j-plant-srt-pc2025-v3-20260817-normalized` | `neo4j-plant-srt-direct-v1-full` | `plantai-protected-neo4j-1` | |---|---|---|---| | bolt | 127.0.0.1:19788 | 127.0.0.1:18788 | 127.0.0.1:17687 | | http | 127.0.0.1:19575 | 127.0.0.1:18575 | 127.0.0.1:17474 | | 镜像 | neo4j:5.15.0-community | neo4j:5.15.0-community | neo4j:5.15.0-community | | 用户名/密码 | neo4j / `` | neo4j / ``(容器 NEO4J_AUTH 原始值为 `password`,运行中已被改) | neo4j / `test1234` | | 数据卷 | `/home/xzq/phase2b-5090-staging-20260823T191150Z/plant_srt_pc2025_merge_20260817_v3_normalized/databases/neo4j/data` | `/home/xzq/home/wutx/gene-family-mas-v2/data/neo4j_plant_srt_direct_v1_docker/data` | docker 匿名卷 `/var/lib/docker/volumes/68af.../` + `/home/xzq/5090/PlanAI-cooperate/hsj-workspace/encryption-test/.../service_data/neo4j` | | heap 设置 | initial 16G / max 32G / pagecache 64G | initial 4G / max 12G / pagecache 24G | 无自定义(默认) | | 标签 | `Entity`(6,316,654), `Paper`(96,648) | `SRT2CanonicalEntity`(3,820,996), `SRT2CanonicalAssertion`(8,246,875), `SRT2Paper`(31,207) | **空库(0 节点)** | | 关系类型 | `ASSERTS`(12,963,472), `SUPPORTED_BY`(13,012,368) | `SRT2_CANONICAL_ASSERTS`, `SRT2_SUPPORTED_BY`(合计 16,449,159) | 无 | | 名字索引 | 无 name_norm 索引(CONTAINS 全扫 0.19s;name_norm 等值 6.81s——**很慢**) | `srt2_canonical_entity_name_norm` RANGE 索引(等值 0.10s / 前缀 0.09s) | 无 | | 全文索引 `entity_name_ftx` | **不存在** | **不存在** | 不存在 | | QA 7920 是否使用 | 否 | **是(bolt://127.0.0.1:18788)** | 否 | | 上游所属 | normalized 版(phase2b staging) | gene-family-mas-v2 直接版(QA 生产) | 加密保护产品线(空) | ### 2.2 节点与关系真实属性 **direct-v1-full(当选实例)** - `SRT2CanonicalEntity` 节点属性:`entity_type`(gene/gene_family/phenotype/process/protein/experimental_material/method/compound/sequence_feature/genotype/trait/… 共 24+ 类)、`canonical_id`(`cent_*`)、`name`、`name_norm`(小写规范化)、`rule`(如 `exact_name_norm_same_type`、`alias_config_exact`)、`support_count`。 - `SRT2CanonicalAssertion` 节点属性(BFF 证据核心,样例见下): `assertion_id`(`cass_*`)、`source`、`source_type`、`source_canonical_id`、`target`、`target_type`、`target_canonical_id`、`relation_norm`、`relation_category`、`best_evidence`、`best_paper_id`、`best_score`、`support_count`、`paper_count`、`title`、`doi`、`pmid`、`publication_year`、`journal`。 - `SRT2_CANONICAL_ASSERTS` 关系属性:`assertion_id`、`best_score`、`relation_category`、`relation_norm`、`support_count`、`paper_count`。 - `SRT2_SUPPORTED_BY` 关系:**无属性**(`{}`)。 - `SRT2Paper` 节点属性:`paper_id`、`title`、`doi`、`pmid`、`journal`、`publication_year`、`metadata_lookup_status`、`metadata_sources`、`metadata_checked_at`。 - 数据库列表:仅 `neo4j`(默认库)+ `system`。 **normalized(备选实例)** - `Entity`:`entity_type`、`name`、`name_norm`、`canonical_id`、`layer`。 - `ASSERTS` 关系属性:仅 `source_system`、`assertion_id`、`relation_category`、`relation_norm`、`layer`(**没有 evidence/pubmed/paper_id/confidence 等属性**,证据信息挂在 `SRT2CanonicalAssertion` 同构的节点/或需 join Paper 节点,未深挖)。 - `SUPPORTED_BY` 关系:`support_id`、`assertion_id`、`layer`。 > 任务书预期的 `evidence/section/pubmed_id/paper_id/confidence/claim_scope/output_layer` 属性在**两个实例的关系上都未出现**;这些字段实际出现在 QA 服务返回的 `sources[].raw` 里(QA 服务在应用层拼装),图库关系本身不携带。 ### 2.3 选型理由(当选:`neo4j-plant-srt-direct-v1-full`) 1. **权威性**:QA 7920 服务(产生可用的图谱证据)的进程环境明确指向 `bolt://127.0.0.1:18788`(= direct-v1-full)。BFF 直接复用该实例能保证与 QA 检索结果一致。 2. **schema 匹配**:QA 服务的 Cypher(`direct_flow_retriever.py`、`graph_path_chain.py` 等)全部使用 `SRT2Canonical*` 标签,只存在于 direct 实例。 3. **检索性能**:名字检索走 `name_norm` RANGE 索引,等值 0.10s / 前缀 0.09s;canonical_id 一跳扩展 0.16s。normalized 实例无 name_norm 索引(等值 6.81s),不适合交互式 BFF。 4. **数据规模**:实体 382 万 + 断言 824 万 + 边 1644 万,远大于 protected(空)。 5. **normalized 不满足** `entity_name_ftx` 要求(两库都没有该索引);`Entity` 标签虽存在且更大(631 万),但 QA 不用它,且其关系无证据属性。 **回退顺序**:① direct-v1-full(首选)→ ② normalized(`neo4j/`,bolt 19788,schema 不同,需单独的 Cypher 适配层)→ ③ protected(空库,仅在需要读保护线数据时用,密码 `test1234`,bolt 17687)。 ### 2.4 三条可用的 BFF Cypher(已对当选实例实测) **(a) 实体名检索(精确 + 前缀,走 name_norm 索引)** ```cypher MATCH (e:SRT2CanonicalEntity) WHERE e.name_norm = $q_norm OR e.name_norm STARTS WITH $q_norm RETURN e.canonical_id, e.name, e.entity_type, e.support_count LIMIT 20 ``` 参数:`q_norm = toLower(用户输入)`。实测 0.09s。(模糊检索可加 `CONTAINS`,但注意 CONTAINS 不走索引;替代方案是先 `STARTS WITH` 取候选再应用层过滤。) **(b) 获取单个实体属性** ```cypher MATCH (e:SRT2CanonicalEntity {canonical_id: $canonical_id}) RETURN e {.*} ``` 实测 0.10s(canonical_id 有唯一约束索引 `srt2_canonical_entity_id`)。名字定位:`MATCH (e:SRT2CanonicalEntity {name_norm: $name_norm}) RETURN e LIMIT 5`。 **(c) 有界邻域扩展(深度 N、节点/边上限,一跳实测 0.16s)** ```cypher MATCH (s:SRT2CanonicalEntity {canonical_id: $seed_id}) OPTIONAL MATCH (s)-[r1:SRT2_CANONICAL_ASSERTS]-(n1:SRT2CanonicalEntity) WITH s, r1, n1 ORDER BY coalesce(r1.paper_count,0) DESC, coalesce(r1.support_count,0) DESC WITH s, collect(DISTINCT n1)[..$max_nodes] AS level1, collect(DISTINCT r1)[..$max_edges] AS edges1 OPTIONAL MATCH (n1)-[r2:SRT2_CANONICAL_ASSERTS]-(n2:SRT2CanonicalEntity) WHERE n1 IN level1 WITH s, level1, edges1, collect(DISTINCT n2)[..$max_nodes] AS level2, collect(DISTINCT r2)[..$max_edges] AS edges2 RETURN s {.*} AS start, [n IN (level1 + level2) | n {.*}] AS nodes, [r IN (edges1 + edges2) | r {.*}] AS edges ``` 要点:每跳分别 cap 并 `ORDER BY paper_count DESC` 优先取高质量边;`OPTIONAL MATCH` 保证孤立节点不丢;深度 >2 时按同模式追加。注意 `[...]` 截取语法在 cap 前的排序至关重要,否则超度节点(hub)会吃满预算。一跳带全属性实测 0.16s,两跳约 13s(可接受,但建议 BFF 先只做一跳 + 按需第二跳)。 --- ## 3. 抽取接口真实结构(`http://127.0.0.1:8000`,fallback `7900`) 服务由 `/home/xzq/5090/PlantAI-rag/scripts/start_methodology_api_8000.sh` 启动:conda `gfpy312`,工作目录 `/home/xzq/5090/PlantAI-rag`,`uvicorn api.main:app --host 0.0.0.0 --port 8000`。启动脚本自带 health 检查和 PID 文件(`runtime/methodology_api/methodology_api_8000.pid`)。当前存活,**不要重启**。 ### 3.1 `GET /api/v1/methodology/extract-jobs`(及 `?limit=N`) 响应形状:`{"jobs": [...], "count": N}`(`limit` 默认 50;`?limit=5` 会截断 jobs 数组,count 仍是截断后的条数)。item 字段(全部实测出现): | 字段 | 类型 | 说明/示例 | |---|---|---| | `job_id` | str | 12 位 hex,如 `2943168e9c48` | | `status` | str | 枚举:`queued` / `running` / `completed` / `failed`(磁盘上 49 个任务只有 completed 22 + failed 27) | | `stage` | str | 与 status 同步:`queued` / `mineru` / `llm` / `completed` / `failed` | | `substage` | str | completed 时为 `done`,failed 时为 null | | `message` | str | 中文进度描述 | | `updated_at` | str | `2026-08-07T09:42:17`(无时区) | | `paper_id` / `family` | str | 如 `demo_paper` / `""` | | `source_filename` / `source_path` | str | 上传文件名与绝对路径 | | `output_dir` / `batch_dir` | str | 结果目录 | | `stage_count` / `species_count` / `figure_table_caption_count` / `figure_table_stage_count` | int | 提取统计 | | `config_url` | str | `/api/v1/methodology/extract-jobs/{id}/bbav5-config` | | `methodology_plan_url` | str | `/api/v1/methodology/extract-jobs/{id}/plan` | | `methodology_sandbox_requested` | bool | | | `methodology_sandbox_status` / `_dir` / `_registry` / `_collection` | str | 沙箱相关 | ### 3.2 `GET /api/v1/methodology/extract-jobs/{job_id}` 单个 job 的扁平 JSON(无包裹):与列表 item 同字段 + 额外 `content_list`(mineru 结果路径)、`figure_table_files`(object,含 `figure_table_inventory`/`figure_table_inventory_csv`/`figure_table_audit`/`reproduction_plan_preview` 四个路径)、`figure_table_warning`、`figure_table_inventory_url`、`reproduction_plan_preview_url`、`log_path`(failed 时)。样例(`2943168e9c48`,已截断): ```json {"updated_at":"2026-08-07T09:42:17","job_id":"2943168e9c48","status":"completed","stage":"completed","substage":"done","message":"MinerU+LLM 方法学提取完成","source_path":"/home/xzq/5090/PlantAI-rag/data/evaluation/methodology_upload_jobs/2943168e9c48/upload/wang2019.pdf","content_list":".../mineru/wang2019/txt/wang2019_content_list.json","output_dir":".../methodology_batch_demo_paper_2943168e9c48","paper_id":"demo_paper","family":"","stage_count":6,"species_count":1,"figure_table_caption_count":9,"figure_table_stage_count":12,"figure_table_warning":"","figure_table_files":{...},"config_url":"...","methodology_plan_url":"...","figure_table_inventory_url":"...","reproduction_plan_preview_url":"..."} ``` 未完成时(非 completed)访问 `bbav5-config`/`plan` 会返回 **409** + `{"detail":"Extraction job is not completed: ..."}`;job 不存在返回 404。 ### 3.3 `GET /api/v1/methodology/extract-jobs/{job_id}/plan` 顶层:`plan_id`、`paper_id`、`gene_family`、`source_batch_dir`、`stages[]`。每个 stage 含: `observation_id`、`literature_stage`(如 `gene_family_identification`)、`literature_tools[]`(`tool_name/version/role/url/parameters`)、`method_components[]`(`component_type/tool/tools/parameters/evidence_sentence`)、`literature_parameters[]`(`component_type/component_tool/parameter_name/parameter_value/parameter_type/evidence_sentence`)、`inputs[]`、更多字段被截断。这是执行计划的完整结构,BFF 的 plan 视图可直接透传。 ### 3.4 `processing-status` / `progress` / `summary` / `run-log` | 接口 | 实测响应 | Content-Type | |---|---|---| | `GET .../processing-status` | `{"rows":[]}` | JSON | | `GET .../progress` | `{"rows":[]}` | JSON(正常时 rows 为 progress.jsonl 的逐行 JSON 对象) | | `GET .../summary` | `{"rows":[]}` | JSON(rows 为 summary.csv 的 dict 行) | | `GET .../run-log` | `{"text":""}` | JSON(**不是文本流**;text 内是日志文件原文) | **空的原因是** `BATCH_DIR_NAME` 默认 `methodology_batch_llm`(目录不存在)。8000 进程环境里没有 `METHODOLOGY_BATCH_DIR` 覆盖。若 BFF 需要这些接口有数据,须用 `METHODOLOGY_BATCH_DIR=methodology_batch_demo_paper_*` 之类实际存在的目录重启服务——**此动作需团队决策,本探测未执行**。 ### 3.5 `GET /api/v1/methodology/sandbox/example-batches` ```json {"success":true,"sandbox_root":"/home/xzq/5090/PlantAI-rag/data/evaluation/methodology_qa_sandbox","batches":[{"name":"methodology_batch_Ft_spl","path":"/home/xzq/5090/PlantAI-rag/methodology_batch_Ft_spl","has_plan":false,"has_preview":false},{"name":"methodology_batch_pecan_spl",...},{"name":"methodology_batch_sunflowers_spl",...}]} ``` ### 3.6 `POST /api/v1/methodology/extract-upload`(未实际上传,来源:OpenAPI + 源码) multipart/form-data,**必填字段仅 `file`**: | 字段 | 类型 | 默认 | 说明 | |---|---|---|---| | `file` | UploadFile | (必填) | PDF 或 `*_content_list.json` | | `paper_id` | str(form) | `uploaded_paper` | 只保留 `[0-9A-Za-z._-]`,否则替换为 `_` | | `family` | str(form) | `""` | | | `output_name` | str(form) | `""` | 输出目录名基名,最终为 `{output_name}_{job_id}` | | `llm_model` | str(form) | `deepseek-v4-flash` | | | `llm_request_timeout` | int(form) | `75` | 秒 | | `sandbox` | bool(form) | `false` | | | `sandbox_run_id` | str(form) | `""` | | 成功响应:`{"success": true, "job_id": "<12hex>", "status_url": "/api/v1/methodology/extract-jobs/"}`。任务在 FastAPI BackgroundTasks 中异步执行;状态流转:`queued` →(MinerU)`running/stage=mineru` →(LLM 提取)`running/stage=llm` → `completed`(含 `config_url`/`methodology_plan_url`/统计字段/沙箱字段)或 `failed`(`message` 为异常文本,含 `log_path`)。失败样例原因:MinerU 路径不存在(`/home/xia-lab/miniconda3/envs/minerupy311/bin/mineru`)——历史 27 个 failed 任务多为这种环境问题。 ### 3.7 7900 上的同构接口 7900(容器 `plantai-protected-rag-1`)暴露同样的 `/api/v1/methodology/*` 路由(51 条路径,`extract-upload`/`extract-jobs` 均存在),但 `extract-jobs` 返回 `{"jobs":[],"count":0}`(容器内数据目录独立)。另有 `/api/v1/kg/*`(stats/families/species/query/search)指向空 Neo4j,**全部为空结果**,BFF 不应依赖 7900 的 kg 路由。源码在容器内是编译过的 `.so`(`api/kg_routes.cpython-311-x86_64-linux-gnu.so`),无法读源码,以 OpenAPI + 实测为准。 --- ## 4. QA 服务响应结构(`http://127.0.0.1:7920`) 服务:`uvicorn scripts.qa_v1_1_73_server:app`,app-dir `/home/xzq/5090/PlanAI-cooperate/RAG/rag-qa-v1_1_73`,conda `gfpy312`,版本 `1.1.73-assertion-anchored`。启动脚本:`docs/legacy_startup_scripts/start_qa_v1_1_73_*.sh`(注意 legacy 脚本里写的 NEO4J_URI 是 17687,**与运行中进程的 18788 不一致**,以进程环境为准)。LLM:`https://api.deepseek.com` + `deepseek-v4-flash`,**当前 402 Insufficient Balance**。 ### 4.1 `POST /api/v1/qa-v1-1-73/search`(实测 2026-08-25,1.78MB 响应,329 sources) **顶层键完整清单(31 个)**: | 键 | 类型 | 说明 | |---|---|---| | `success` | bool | true | | `version` | str | `"1.1.73"` | | `query_id` | str | `"20260825_000715_49f801a9"` | | `question` | str | 原问题 | | `answer` | str | retrieval-only 时为空串 | | `citation_validation` | dict | `{valid, cited_pmids[], unknown_pmids[]}` | | `sources` | list[329] | 证据条目(见下) | | `source_count` | int | 329 | | `evidence_chain_top30` | list[30] | 与 sources 同构(top30 精选) | | `provisional_answer` | str | 空 | | `retrieval_hypothesis` | dict | `{question_type, direct_question_entities[], hypothesized_entities[], relation_intents[], concept_queries[], answer_slots[], atomic_claims[], negative_constraints[], parse_status}` | | `query_plan` | dict | `{queries{}, alias_audit{}, agentic_plan{14}, retrieval_options{29}}` | | `retrieval_audit` | dict | `{qdrant[], seed_extraction{}, neo4j[], dedup{}, options{}, neo4j_status:"enabled", bounded_graph_backend{12}, public_citation_filter{}}` | | `graph_evidence_quota_audit` | dict | `{policy, top_k_for_llm, graph_min_requested, graph_candidates_available, non_graph_candidates_available, graph_selected, non_graph_selected, graph_quota_satisfied, note}` | | `graph_knowledge_chains` | dict | `{mode:"neo4j_native_path", chain_policy, chains[305], chain_count, audit{35}, summary{note, used_for_answer_generation}}` | | `native_graph_chains` | list[305] | 图链(见下) | | `native_graph_chain_audit` | dict | 35 个审计键(enabled/chain_source/max_hops/beam_width/top_k_chains/seed_ids/…) | | `assertion_anchored_graph_chains` | list | 本次为 `[]` | | `assertion_anchored_graph_audit` | dict | `{enabled, status, error, fallback_required, hop_policy}` | | `endpoint_path_audit` | dict | `{enabled:false, status:"not_attempted", fallback_to_native_seed_expansion:false}` | | `native_seed_policy_audit` | dict | 20 键(policy/seed_top_k_after_bge/canonical_ids/names/…) | | `agentic_controller_audit` | dict | `{enabled, status, strict_review_accepted, fallback_reason, attempt_count, replan_count, attempts[], final_plan{}}` | | `agentic_review` | dict | `{decision, accepted_evidence_ids[], accepted_chain_ids[], problems[], final_handoff, strict_review_decision, review_fallback_used, fallback_reason}` | | `question_decomposition` | dict | search 时为 `{}` | | `runtime_recovery_audit` | list | 每次 LLM 失败一条:`{stage, mode, degraded:true, error}` | | `degraded_execution` | bool | **true**(LLM 402) | | `subquestion_evidence_groups` | list | `[]`(search 时) | | `subquestion_retrieval_audit` | list | `[]` | | `cluster_audit` | list[106] | `{cluster_id, cluster_key[], representative_assertion_id, representative_srt{source,relation,target}, member_count, member_assertion_ids[], member_paper_ids[], ...}` | | `rerank_audit` | list[80] | `{rank, evidence_id, source, relation, target, rrf_score, bge_score, final_score}` | | `timings` | dict | 秒,float:`{provisional_answer, structured_planner, question_decomposition, agentic_retrieval_plan, retrieval, cluster_bge_rerank_and_select, native_graph_chain_retrieval, final_answer, total}`(本次 total 91.9s) | | `flow` | list[17] | 管道阶段名有序列表 | **一条 `sources[]` 的全字段(26 个键,S1 实例)**: | 键 | 类型 | 示例值 | |---|---|---| | `evidence_id` | str | `"S1"` | | `kb` | str | `"V16/V15"` | | `source` | str | `"SPL gene family"` | | `relation` | str | `"characterized_in"` | | `target` | str | `"Oryza sativa"` | | `evidence` | str | markdown 段落(`## Phylogenetic analysis of the PeSPL genes ...`,可长) | | `paper_id` | str | `"PMC5488377_12864_2017_Article_3882"` | | `title` | str | 论文标题 | | `pmid` | str | `"28655295"` | | `pmcid` | str | `"PMC5488377"` | | `doi` | str | `"10.1186/s12864-017-3882-4"` | | `species` | str | 常为空串 | | `section` | str | 常为空串 | | `output_layer` | str | `"main_kg"` | | `claim_scope` | str | 常为空串 | | `relation_id` | str | `"cass_d12f62f9abffbd903b97"`(= assertion_id) | | `retrieval_methods` | list[str] | `["qdrant_vector"]` | | `retrieval_queries` | list[str] | 3 条查询串 | | `vector_score` | float | 0.714 | | `rrf_score` | float | 1.114 | | `rerank_score` | float | 0.989 | | `final_score` | float | 0.982 | | `cluster_id` | str | `"clu_0f8da21642adc4f0"` | | `cluster_member_count` | int | 3 | | `cluster_member_assertion_ids` | list[str] | 3 个 cass_* | | `cluster_member_paper_ids` | list[str] | 2 个 | | `cluster_member_pmids` | list[str] | 1 个 | | `raw` | dict | 28 键,完整断言原样:`kb_version, source_system, assertion_id, relation_id, source, source_type, source_canonical_id, relation, relation_norm, relation_category, target, target_type, target_canonical_id, evidence, best_evidence, paper_id, best_paper_id, support_count, paper_count, quality_score, best_score, embedding_text, cluster_id, cluster_key[], cluster_member_assertion_ids[], cluster_member_count, cluster_member_paper_ids[], cluster_member_pmids[]` | **`native_graph_chains[]` item**:`{chain_id:"G1", chain_source:"neo4j_native_path", hop_count:3, path_score:0.861, start:"SPL gene", end:"18 SPL genes in rice", bridge_entities[], hops[], score_breakdown{22}}`。 **hop**:`{hop_index, from_id, from_name, to_id, to_name, source, relation, target, source_canonical_id, target_canonical_id, source_type, target_type, relation_category, assertion_id, paper_id, title, pmid, pmcid, doi, species, evidence, support_count, paper_count, best_score, edge_score, score_breakdown, passive_relation, structural_direction, semantic_direction}`。 ### 4.2 `POST /api/v1/qa-v1-1-73/chat/stream` SSE 实测 帧格式:`event: ` + `data: ` 两行一组,空行分隔;期间有 `: keepalive` 注释帧(实测 2 次)。 **有序 stage 序列(data.stage,五阶段 UI 映射基准)**: 1. `understanding_started` — details `{}` 2. `entities_identified` — details `{entities:["SPL gene family"], question_type:"raw_question"}` 3. `related_search_started` — details `{}` 4. `concepts_found` — details `{concepts[], concept_count:250, connection_count:335, publication_count:109, candidate_count:328}` 5. `subquestion_retrieved` — details `{subquestion_id:"Q0", attempt:1, candidate_count:30, connection_count:305}` 6. `agent_review_started` — details `{attempt:1}` 7. `evidence_accepted` — details `{concepts[], concept_count, connection_count, publication_count, accepted_count:30}` 8. `answer_generation_started` — details `{}` 9. `completed` — details `{elapsed_seconds:38.357}` **终端帧**:`event: complete` + `data: <完整 JSON>`(与 search 响应同构,约 2.37MB;顶层键同 search 但 `citation_validation` 12 键、`sources` 仅 4 条、`timings` 10 键、`question_decomposition` 13 键、`subquestion_evidence_groups` 1 项、`agentic_controller_audit` 12 键、`agentic_review` 7 键)。**LLM 402 影响**:`answer` 为 fallback 文案 `"The retrieval pipeline completed. The answer model did not return usable text; the most relevant retrieved evidence facts are: - SPL gene family has domain SBP box [PMID: 33234605] ..."`(事实列表而非自然语言答案),`degraded_execution=true`,`runtime_recovery_audit` 4 条 LLM 失败记录。全流程耗时约 37–38s(不带 keepalive 间隙)。 **health**:`/api/v1/qa-v1-1-73/health` → `{"status":"ok","service":"qa_v1_1_73","version":"1.1.73-assertion-anchored"}`。 **info**:返回服务名、管道描述、config(alias_path/taxonomy_path/reranker 模型路径/knowledge_chain_defaults 等)。 其他路由:`/chat`(非流式)、`/search`。 --- ## 5. 环境与启动脚本 ### 5.1 `/home/xzq/5090/PlantAI-rag/scripts/` 清单(15 个) | 脚本 | 用途(据头部注释/内容) | |---|---| | `download_marker_models.sh` | 手动下载 marker-pdf 模型(解决自动下载中断) | | `organize_project.sh` | gene-family-mas-v2 项目文件整理(建目录结构) | | `process_all_pdfs.sh` | 批量处理 `gfpaper` 目录 PDF | | `process_by_inode_shell.sh` | 用 inode 处理乱码文件名 PDF → rag_index_v3 | | `process_failed_by_inode.sh` | 用 inode 重处理 failed_to_process 目录 → rag_index_v4 | | `run_v15_3_4_q1_5papers_smoke_20260604.sh` | V15.3.4 Q1 5 篇论文冒烟测试(gfpy312) | | `run_v15_3_4_q1_remaining_500_20260604.sh` | V15.3.4 Q1 剩余 500 篇批量(加载 .env.v15_deepseek) | | `run_v16_rerun6_20260625.sh` | V16 batch10 重跑 6(/data/gene-family-mas-v2) | | `start_dual_kb_qa_api_7902.sh` | 双 KB QA API 7902(/data/gene-family-mas-v2) | | `start_dual_kb_qa_api_8000.sh` | **历史名**;实际启动 `combined_qa_lightrag_keyword_server` 于 **7905**(V15+PC Qdrant 检索) | | `start_methodology_api_8000.sh` | **当前 8000 的启动脚本**(见 5.2) | | `start_mineru_api_50215_20260605.sh` | MinerU API 50215 | | `start_qa_v1_0_0_7908.sh` | QA v1.0.0 7908 | | `start_taxonomy_bge_unified_7907.sh` | taxonomy+BGE 统一服务 7907 | | `start-webui.sh` | WebUI(端口 8787,state 在 ~/.hermes/webui-mas-v2) | ### 5.2 三个上游服务 | 服务 | 端口 | 启动方式 | conda / 工作目录 | 重启安全性 | |---|---|---|---|---| | QA v1.1.73(graph QA) | 7920 | `python -m uvicorn scripts.qa_v1_1_73_server:app --app-dir /home/xzq/5090/PlanAI-cooperate/RAG/rag-qa-v1_1_73 --host 127.0.0.1 --port 7920`(PID 2586988,父进程 1 = 守护化;legacy 脚本在 `rag-qa-v1_1_73/docs/legacy_startup_scripts/`,其硬编码 URI 17687 已过时,**不能照抄**) | `gfpy312`;环境来自 `RAG/runtime/qa_v1_1_73.env` + 进程内联 env(`NEO4J_URI=bolt://127.0.0.1:18788`、`NEO4J_PASSWORD=`、`V15_QDRANT_URL=http://127.0.0.1:26333`、collection `plant_srt_direct_v1_bge_m3_20260702`) | 正在服务流量,**未验证重启安全性**;重启前需确认无长任务依赖(LLM 目前 402 已降级,重启不影响数据) | | Methodology API | 8000 | `/home/xzq/5090/PlantAI-rag/scripts/start_methodology_api_8000.sh`(脚本自带 health 检查 + 幂等启动,health 通过则直接退出) | `gfpy312`;工作目录 `/home/xzq/5090/PlantAI-rag`;日志 `runtime/methodology_api/methodology_api_8000.log` | 脚本幂等、支持 `METHODOLOGY_API_PORT`/`METHODOLOGY_BATCH_DIR` 覆盖;停止后重跑脚本即可。**当前别重启**(本探测依赖其持续在线) | | Protected RAG | 7900 | Docker 容器 `plantai-protected-rag-1`(镜像 `plantai-rag-protected:1.0.0`,compose:`hsj-workspace/encryption-test/server/protected_docker_packager/docker-compose.yml`),同一 compose 栈含 web/workers/redis/qdrant/neo4j 等 8+ 容器 | 容器内 `python -m uvicorn api.app:app`(2 workers),`NEO4J_URI=bolt://neo4j:7687`(compose 内部) | 容器健康检查通过;其 kg 路由数据为空(protected Neo4j 空库),**BFF 不应依赖** | ### 5.3 其他环境事实 - 端口 8090、5180:`ss -tln` 无监听 → **空闲可用**。 - `node -v` = v18.19.1,`npm -v` = 9.2.0;`npm ping` PONG 573ms → Playwright chromium 下载可行(约 150MB,未实际执行)。 - Qdrant 端口映射:QA 用 `qdrant-qa-v1-1-73-full` 26333;normalized 用 `qdrant-plant-srt-pc2025-v3-20260817-normalized` 27333;protected 用 `plantai-protected-qdrant-1` 16333。 - 全部 docker 容器(13 个)状态 Up,无异常退出。 --- ## 6. 遗留问题与风险 1. **QA LLM 余额不足(最重要风险)**:DeepSeek API 402 Insufficient Balance。所有 LLM 阶段(planner/agentic/review/answer)降级为 deterministic recovery。**chat/stream 目前无法产出自然语言答案**(只有证据列表 fallback),BFF 五阶段 UI 中"答案生成"阶段会看到降级行为。充值时注意:`QA_V1_LLM_BASE_URL=https://api.deepseek.com`,`QA_V1_LLM_MODEL=deepseek-v4-flash`、`QA_V1_FINAL_LLM_MODEL=deepseek-v4-flash`、`QA_V1_LLM_MODEL`(实际 env) = `deepseek-chat` 并存(进程 env 与 runtime env 文件略有差异,未确认哪行最终生效)。 2. **`entity_name_ftx` 全文索引不存在于任何实例**。若 BFF 必须全文检索,需要团队决策是否创建(会修改共享实例的 schema——本探测未创建任何东西)。 3. **normalized 实例名字检索慢**(name_norm 无索引,等值 6.81s):若团队将来切到 normalized(`Entity` 标签 631 万),需要先建索引。 4. **methodology `processing-status`/`progress`/`summary`/`run-log` 当前空数据**:原因是 `METHODOLOGY_BATCH_DIR` 指向不存在的 `methodology_batch_llm` 目录(默认值)。未确认哪个目录名才是"有数据"的正确批次目录(历史任务输出在 `data/evaluation/0505/methodology_batch_demo_paper_*`)。需要读有数据的目录必须重启 8000 并设 env——未执行。 5. **QA 7920 的正式启动脚本未找到**:只有 legacy 脚本且其中 NEO4J_URI(17687)与运行中进程(18788)矛盾。进程由谁、以何完整 env 启动,未确认。以 `/proc/2586988/environ` 实测为准。 6. **failed 任务(27 个)失败原因**:主要是 MinerU 二进制路径不存在(`/home/xia-lab/miniconda3/envs/minerupy311/bin/mineru`)。上传新 PDF 是否会再次失败取决于 MinerU 环境是否修复——**未测试实际上传**(按任务要求未执行)。 7. **7900 的 kg 路由源码不可读**(编译 .so),其 schema 以 OpenAPI + 实测为准;kg 数据为空的原因是 protected Neo4j 空库,后续若保护线灌库,kg 路由可能恢复。 8. **一次 search 约 92s**(88.8s 在 native_graph_chain_retrieval),stream 约 37s。BFF 需要长超时(>120s)和进度展示;未做并发压测。 9. **`SSH_CONNECTION` 显示会话来自 192.168.0.142 → 192.168.0.175**:远程机在 192.168.0.175(通过 Tailscale IP 100.109.52.26 可达)。BFF 若部署在远程机上,绑定 127.0.0.1 的端口只能本机访问——BFF 与本机服务同机部署即可;跨机需要另开隧道,未做。