# identify 阶段多智能体数据流转详解 ## 概述 本文档详细分析 identify 阶段从用户输入到最终输出的 10 个 Agent 数据流转,包括每个 Agent 的输入、输出、数据类型,以及错误处理机制。 --- ## 1. 用户输入 -> Router Agent ### 输入数据 ```json { "query": "鉴定Ft.SPL基因家族", "user_input": { "prefix": "Ft.SPL", "stage": "identify", "species_name": "Fagopyrum tataricum" }, "job_id": "job_xxx" } ``` ### Router Agent 处理 1. 调用 `RouterAgent.classify()` 判断模式: `analysis` 2. 如果是单 stage 模式(`user_input.stage` 存在),直接设置 intent: - `stages = ["identify"]` - `prefix = "Ft.SPL"` 3. 否则调用 `IntentAgentV2` 解析意图 ### 输出数据(设置到 state) ```python state["mode"] = "analysis" state["intent_result"] = { "mode": "analysis", "stages": ["identify"], "prefix": "Ft.SPL", "single_stage_mode": True, "job_id": "job_xxx", "workspace": "/path/to/workspace/job_xxx" } state["next_node"] = "learning_recommend" ``` --- ## 2. Router -> Learning Recommend Agent ### 输入数据(从 state 获取) ```python intent = state.get("intent_result", {}) target_stages = intent.get("stages", ["identify"]) # ["identify"] ``` ### Learning Recommend Agent 处理 - 查询历史执行记录,获取参数推荐 - 如果有高置信度历史记录,返回推荐参数 - 否则返回默认参数 ### 输出数据(设置到 state) ```python state["learning_recommendations"] = { "confidence": "high", # 或 "medium" / "low" "params": { "evalue": "1e-5", "coverage": 0.5 }, "message": "基于历史执行推荐参数" } ``` --- ## 3. Learning Recommend -> Planning Agent ### 输入数据(从 state 获取) ```python state["intent_result"] # 包含 stages, prefix 等 state["learning_recommendations"] # 参数推荐 state["completed_stages"] # 已完成的阶段(从 manifest 查询) ``` ### Planning Agent 处理 1. 重新查询 `completed_stages`(从文件系统 manifest) 2. 根据 intent 和 learning_recommendations 制定执行计划 3. 设置 stages_to_run = ["identify"](排除已完成的) ### 输出数据(设置到 state) ```python state["plan_result"] = { "stages": [ { "id": "identify", "name": "基因鉴定", "params": { "evalue": "1e-5", "coverage": 0.5 } } ], "prefix": "Ft.SPL", "workspace": "/path/to/workspace/job_xxx", "job_id": "job_xxx" } ``` --- ## 4. Planning -> PreFlight Agent ### 输入数据(从 state 获取) ```python plan = state.get("plan_result", {}) job_id = state.get("job_id", "") prefix = intent.get("prefix", "Ft.SPL") ``` ### PreFlight Agent 处理 1. 检查输入文件是否存在: - `input/{prefix}.pep.fa`(参考序列) - `input/{species_prefix}.pep.fa`(物种序列) 2. 检查契约文件是否存在 3. 检查环境配置 ### 输出数据(设置到 state) ```python state["preflight_result"] = { "valid": True, # 或 False "issues": [], # 如果 valid=False,列出问题 "checked_files": [ "input/Ft.SPL.pep.fa: EXISTS", "input/Ft.pep.fa: EXISTS" ] } ``` ### 错误处理 - 如果 `preflight_result.valid = False`: - 记录 `state["errors"]` - Planning Agent 可能重新规划(目前未实现) --- ## 5. PreFlight -> Execution Agent 【关键】 ### 输入数据(从 state 获取) ```python plan = state.get("plan_result", {}) # plan 包含: # - stages: [{"id": "identify", "params": {...}}] # - prefix: "Ft.SPL" # - workspace: "/path/to/workspace/job_xxx" # - job_id: "job_xxx" ``` ### Execution Agent 处理 1. 解析 plan,获取 `stages_to_run = ["identify"]` 2. 调用 `stage_registry.execute("identify", job_id, prefix, params)` 3. 执行 `python apps/cli/run_identify.py --prefix Ft.SPL --workspace ...` 4. 等待执行完成,读取 manifest ### 执行结果结构(关键) ```python result = { "status": "success", # 或 "error" "manifest": {...}, # manifest.json 内容 "manifest_path": "/path/to/manifest.json", "elapsed_sec": 45.2, "metrics": { "final_members": 15, "initial_candidates": 120 } } ``` ### 输出数据(设置到 state)【问题点】 ```python execution_results = [ { "stage": "identify", "result": { "status": "success", "manifest": {...}, "manifest_path": "...", "message": "✅ Identify completed successfully" } } ] state["execution_results"] = execution_results # LIST 类型 ``` ### **LangGraph State 传递问题** - `_execution_node` 设置 `state["execution_results"] = execution_results`(list) - LangGraph 调用 `return state` 返回给下一个节点 - **TypedDict 类型定义必须匹配**: `execution_results: list[dict[str, Any]]` - 如果类型不匹配,LangGraph 可能无法正确传递 --- ## 6. Execution -> ResultParser Agent ### 输入数据(从 state 获取) ```python execution_results = state.get("execution_results", []) # LIST ``` ### **Fallback 机制(关键)** 如果 `execution_results` 为空(LangGraph state 传递失败): ```python if not execution_results: # 从文件系统重新加载 manifest workspace = Path(f"/path/to/workspace/{job_id}/final") for manifest_file in workspace.glob(f"{prefix}.*.manifest.json"): manifest = json.load(manifest_file) execution_results.append({ "stage": manifest.get("stage"), "result": { "status": manifest.get("status", "success"), "manifest": manifest } }) ``` ### ResultParser Agent 处理 - 解析 execution_results,生成结构化报告 - 提取关键指标:final_members, initial_candidates 等 ### 输出数据(设置到 state) ```python state["parse_result"] = { "stage": "identify", "status": "success", "summary": "鉴定到 15 个 Ft.SPL 基因家族成员", "metrics": { "final_members": 15, "initial_candidates": 120 }, "files": [ "final/Ft.SPL.identify.pep.fa", "final/Ft.SPL.identify.manifest.json" ] } ``` --- ## 7. ResultParser -> Validator Agent 【关键决策点】 ### 输入数据(从 state 获取) ```python execution_results_list = state.get("execution_results", []) # LIST parse_result = state.get("parse_result", {}) ``` ### **Fallback 机制(再次确认)** 如果 `execution_results_list` 为空: ```python # 再次从 manifest 加载(双重保险) ``` ### Validator Agent 处理 1. 检查 `execution_result.status == "success"` 2. 检查输出文件是否存在 3. 检查数据合理性(final_members > 0) 4. 检查 manifest 完整性 ### 输出数据(设置到 state) ```python state["validation_result"] = { "overall_passed": True, # 或 False "stage": "identify", "score": 95.0, "errors": [], # 如果 overall_passed=False "warnings": [], # 可能有警告但不影响通过 "summary": "✅ 验证通过,所有检查项正常" } ``` --- ## 8. Validator -> Decision: _validate_decision ### 决策逻辑 ```python def _validate_decision(state: GraphState) -> str: validation = state.get("validation_result", {}) if validation.get("overall_passed", False): return "success" # -> Discovery Agent else: return "failure" # -> Diagnosis Agent ``` ### **关键问题根因** 如果 `validation_result` 为空 `{}`(LangGraph state 传递失败): - `validation.get("overall_passed", False)` 返回 `False` - 决策走 `"failure"` -> Diagnosis Agent - 触发错误诊断 -> retry --- ## 9. Validator(success) -> Discovery Agent ### 输入数据(从 state 获取) ```python execution_results = state.get("execution_results", []) parse_result = state.get("parse_result", {}) ``` ### Discovery Agent 处理 - 分析鉴定结果,生成科学发现报告 - 例如:发现新的 SPL 基因亚家族 ### 输出数据(设置到 state) ```python state["discovery_result"] = { "findings": ["发现 15 个 SPL 基因,分为 3 个亚家族"], "should_continue": False, # 是否继续迭代 "updated_plan": None # 如果继续迭代,新的计划 } ``` --- ## 10. Discovery -> Decision: _discovery_decision ### 决策逻辑 ```python def _discovery_decision(state: GraphState) -> str: discovery = state.get("discovery_result", {}) iteration_count = state.get("iteration_count", 0) max_iterations = state.get("max_iterations", 3) if iteration_count >= max_iterations: return "learning" if discovery.get("should_continue", False): return "replan" # -> Planning(循环迭代) else: return "learning" # -> Learning Agent ``` --- ## 11. Discovery -> Learning Agent ### 输入数据(从 state 获取) ```python execution_results = state.get("execution_results", []) discovery_result = state.get("discovery_result", {}) ``` ### Learning Agent 处理 - 记录本次执行的参数、结果 - 更新知识库 - 生成学习总结 ### 输出数据(设置到 state) ```python state["final_output"] = { "response": "鉴定完成,发现 15 个 SPL 基因", "artifacts": [ "final/Ft.SPL.identify.pep.fa", "final/Ft.SPL.identify.manifest.json" ], "metrics": {...} } state["status"] = "completed" ``` --- ## 错误处理路径 ### Validator 验证失败 -> Diagnosis Agent ### Diagnosis Agent 处理 ```python state["diagnosis_result"] = { "error_type": "missing_output_file", "suggested_fix": "检查输入文件路径", "retry_params": {...} } state["retry_count"] += 1 ``` ### Diagnosis -> Decision: _diagnosis_decision ```python if retry_count < max_retries: return "retry" # -> Execution Agent(重新执行) else: return "fail" # -> END(失败结束) ``` --- ## LangGraph State 传递问题详解 ### TypedDict 类型定义(state.py) ```python class GraphState(TypedDict): execution_results: list[dict[str, Any]] # LIST 类型(已修复) validation_result: dict[str, Any] # DICT 类型 ... ``` ### LangGraph 内部机制 LangGraph 使用 TypedDict 进行类型检查: 1. 节点函数返回 `state`(dict) 2. LangGraph 检查返回值是否符合 TypedDict 定义 3. 如果类型不匹配,可能导致: - 数据丢失(字段被忽略) - 类型转换错误 - 默认值覆盖 ### 已修复的问题 之前 `execution_results` 定义为 `dict[str, Any]`,但实际使用 `list[dict]`,导致: - `_execution_node` 设置 list - `_validator_node` 获取空 `{}` 或 `[]` - fallback 机制从 manifest 加载(但可能加载失败) - `_validate_decision` 判断 failure --- ## 数据流转图(简化版) ``` 用户输入 ↓ [Router] → state["intent_result"] = {stages, prefix, mode} ↓ [Learning Recommend] → state["learning_recommendations"] = {params} ↓ [Planning] → state["plan_result"] = {stages, prefix, workspace} ↓ [PreFlight] → state["preflight_result"] = {valid, issues} ↓ [Execution] → state["execution_results"] = [{stage, result}] ← 关键 ↓ [ResultParser] → state["parse_result"] = {summary, metrics} ← 有 fallback ↓ [Validator] → state["validation_result"] = {overall_passed} ← 有 fallback ↓ [_validate_decision] → "success" / "failure" ↓ [Discovery] (success) → state["discovery_result"] ↓ [Learning] → state["final_output"] ↓ END OR (failure): [Validator] → "failure" ↓ [Diagnosis] → state["diagnosis_result"] + retry_count++ ↓ [_diagnosis_decision] → "retry" (if retry < max) / "fail" (if max reached) ↓ [Execution] (retry) → 重新执行 ``` --- ## 关键数据类型总结 | 字段名 | 类型 | 设置节点 | 使用节点 | |--------|------|----------|----------| | `intent_result` | `dict[str, Any]` | Router | Planning | | `learning_recommendations` | `dict[str, Any]` | Learning Recommend | Planning | | `plan_result` | `dict[str, Any]` | Planning | PreFlight, Execution | | `preflight_result` | `dict[str, Any]` | PreFlight | (记录 errors) | | `execution_results` | `list[dict[str, Any]]` | Execution | ResultParser, Validator, Diagnosis | | `parse_result` | `dict[str, Any]` | ResultParser | Validator | | `validation_result` | `dict[str, Any]` | Validator | _validate_decision | | `diagnosis_result` | `dict[str, Any]` | Diagnosis | _diagnosis_decision | | `discovery_result` | `dict[str, Any]` | Discovery | _discovery_decision | --- ## 测试验证步骤 1. 启动 Celery 服务 2. 前端触发 identify 任务 3. 观察 Celery 日志: - `[Execution] DEBUG: state['execution_results'] set: 1 items` - `[Validator] ✅ 使用execution_results进行验证` - `[Validator] overall_passed: True` 4. 检查 `workspace/job_xxx/logs/` 只有 1 个日志文件 5. 前端显示 "执行成功"