""" DiscoveryAgent V1 - CellVoyager风格的科学发现Agent 功能: 1. 分析执行结果,识别异常/新模式 2. 生成科学假设 3. 设计验证实验 4. 迭代优化分析计划 基于CellVoyager论文的REPLAN机制 """ from typing import Dict, List, Optional, Any from dataclasses import dataclass, field, asdict, is_dataclass from enum import Enum import json import asyncio from .base import AgentMessage, AgentState, BaseAgent from gfa_core.mas.llm import LLMManager from gfa_core.mas.dual_kb_qa import query_dual_kb_qa class DiscoveryType(Enum): """发现类型""" ANOMALY = "anomaly" # 异常检测 PATTERN = "pattern" # 新模式 CORRELATION = "correlation" # 相关性 HYPOTHESIS = "hypothesis" # 新假设 @dataclass class AnomalyDetection: """异常检测结果""" detected: bool description: str severity: str # low, medium, high affected_genes: List[str] = field(default_factory=list) expected_value: Any = None actual_value: Any = None @dataclass class GeneratedHypothesis: """生成的假设""" hypothesis: str rationale: str confidence: float testable: bool suggested_experiments: List[str] = field(default_factory=list) required_data: List[str] = field(default_factory=list) @dataclass class DiscoveryResult: """发现结果""" discovery_type: DiscoveryType description: str confidence: float hypothesis: Optional[GeneratedHypothesis] = None anomalies: List[AnomalyDetection] = field(default_factory=list) updated_plan: Optional[Dict] = None should_continue: bool = False class DiscoveryAgent(BaseAgent): """ 科学发现Agent - CellVoyager风格 核心流程: 1. INSPECT - 检查结果 2. ANALYZE - 分析异常/模式 3. HYPOTHESIZE - 生成假设 4. DESIGN - 设计验证 5. REPLAN - 更新计划 """ name = "discovery" role = "Scientific Discovery Assistant" def __init__(self, llm_manager: LLMManager): super().__init__(llm_manager) self.discovery_history: List[DiscoveryResult] = [] self.max_iterations = 3 async def execute(self, state: AgentState, message: AgentMessage) -> AgentState: """ 执行发现流程(科研模式:存储解读结果,支持按需生成深度报告) Args: state: 当前状态,包含执行结果 message: 消息,可能包含特定发现指令 - mode: "quick" (快速模式,只存储结果) "deep" (深度模式,立即生成解读) "generate_report" (生成综合报告) Returns: 更新后的状态,包含发现结果 """ mode = message.payload.get("mode", "quick") # 默认快速模式 print(f"[DiscoveryAgent] 开始科学发现流程 (模式: {mode})...") # 特殊模式:生成综合深度报告 if mode == "generate_report": return await self._generate_comprehensive_report(state, message) # 1. 获取当前结果(支持多种数据格式) execution_results = self._normalize_execution_results(state) current_plan = state.results.get("plan", state.results.get("task_plan", {})) past_discoveries = state.results.get("discoveries", []) # 提取基因家族名称 gene_family = self._extract_gene_family_from_state(state) print(f"[DiscoveryAgent] 分析基因家族: {gene_family}") # 2. 检查异常(使用RAG获取文献基准) anomalies = await self._detect_anomalies(execution_results, gene_family) print(f"[DiscoveryAgent] 检测到 {len(anomalies)} 个异常") # 3. 分析模式 patterns = await self._analyze_patterns(execution_results) print(f"[DiscoveryAgent] 识别到 {len(patterns)} 个模式") # 4. 生成假设(只要有可用执行摘要即调用 LLM,避免「无异常就无话」) hypothesis = None if execution_results: hypothesis = await self._generate_hypothesis( anomalies, patterns, execution_results ) if hypothesis: print(f"[DiscoveryAgent] 生成假设: {hypothesis.hypothesis[:80]}...") # 5. 决定是否继续迭代 should_continue = self._should_continue_iteration( anomalies, patterns, hypothesis, len(past_discoveries) ) # 6. 更新计划(如需要) updated_plan = None if should_continue and hypothesis: updated_plan = await self._update_plan(current_plan, hypothesis) print(f"[DiscoveryAgent] 更新分析计划") # 7. 构建发现结果 discovery_result = DiscoveryResult( discovery_type=self._determine_discovery_type(anomalies, patterns), description=self._build_description(anomalies, patterns, hypothesis), confidence=hypothesis.confidence if hypothesis else 0.5, hypothesis=hypothesis, anomalies=anomalies, updated_plan=updated_plan, should_continue=should_continue ) # 8. 构建完整发现结果(包含原始数据,供后续深度解读使用) discovery_data = { "type": discovery_result.discovery_type.value, "description": discovery_result.description, "confidence": discovery_result.confidence, "hypothesis": { "text": hypothesis.hypothesis if hypothesis else None, "rationale": hypothesis.rationale if hypothesis else None, "confidence": hypothesis.confidence if hypothesis else None, "suggested_experiments": hypothesis.suggested_experiments if hypothesis else [] }, "anomalies": [ { "description": a.description, "severity": a.severity, "affected_genes": a.affected_genes } for a in anomalies ], "should_continue": should_continue, # 新增:存储原始数据,供深度解读使用 "raw_data": { "execution_results": execution_results, "patterns": [p for p in patterns], "analysis_timestamp": self._get_timestamp() } } # 深度模式:立即生成详细解读 if mode == "deep": deep_interpretation = await self._generate_deep_interpretation(discovery_data) discovery_data["deep_interpretation"] = deep_interpretation print(f"[DiscoveryAgent] 已生成深度解读") state.results["discovery_result"] = discovery_data stage_hint = message.payload.get("stage") or "" if not stage_hint: pr = message.payload.get("parse_result") or state.results.get("parsed_report") or {} if isinstance(pr, dict): stage_hint = pr.get("stage", "unknown") history_entry = {**discovery_data, "stage": stage_hint} self.discovery_history.append(discovery_result) past_discoveries.append(history_entry) state.results["discoveries"] = past_discoveries # 添加消息 state.messages.append({ "role": "discovery", "content": discovery_result.description, "metadata": { "confidence": discovery_result.confidence, "should_continue": should_continue } }) print(f"[DiscoveryAgent] 发现流程完成,置信度: {discovery_result.confidence:.2f}") return state def _normalize_execution_results(self, state: AgentState) -> Dict: """ 标准化执行结果格式 支持多种输入格式: 1. Dict格式: {"identify": {...}, "phylogeny": {...}} 2. List格式: [{"stage": "identify", ...}, {"stage": "phylogeny", ...}] 3. 从parsed_report提取 """ results = {} # 尝试从execution_results获取(可能是list或dict) execution_results = state.results.get("execution_results", {}) if isinstance(execution_results, dict): results = execution_results elif isinstance(execution_results, list): # 转换为dict格式 for item in execution_results: if isinstance(item, dict): stage = item.get("stage", "unknown") results[stage] = item # 尝试从parsed_report获取更详细的数据 parsed_report = state.results.get("parsed_report", {}) if parsed_report: stage = parsed_report.get("stage", "unknown") if stage not in results: results[stage] = {} # 合并parsed数据 results[stage].update({ "metrics": parsed_report.get("metrics", {}), "parsed_data": parsed_report.get("parsed_data", {}), "status": parsed_report.get("status", "unknown") }) # 尝试从单个execution_result获取(最新执行结果) execution_result = state.results.get("execution_result", {}) if execution_result: manifest = execution_result.get("manifest", {}) stage = manifest.get("stage", "unknown") if stage not in results: results[stage] = {} results[stage].update({ "metrics": manifest.get("metrics", {}), "status": execution_result.get("status", "unknown"), "manifest": manifest }) return results def _bucket_metrics(self, bucket: Any) -> Dict[str, Any]: if not isinstance(bucket, dict): return {} m = bucket.get("metrics") if isinstance(m, dict) and m: return m manifest = bucket.get("manifest") or {} if isinstance(manifest, dict): mm = manifest.get("metrics") if isinstance(mm, dict): return mm return {} def _discovery_record_as_dict(self, discovery: Any) -> Dict[str, Any]: """兼容历史中的 DiscoveryResult dataclass 与 dict。""" if isinstance(discovery, dict): return discovery if isinstance(discovery, DiscoveryResult): hyp = discovery.hypothesis hyp_dict = {} if hyp is not None: hyp_dict = { "text": hyp.hypothesis, "rationale": hyp.rationale, "confidence": hyp.confidence, "suggested_experiments": hyp.suggested_experiments or [], } return { "type": discovery.discovery_type.value, "description": discovery.description, "confidence": discovery.confidence, "should_continue": discovery.should_continue, "stage": getattr(discovery, "stage", None), "hypothesis": hyp_dict, "anomalies": [ asdict(a) if is_dataclass(a) else a for a in (discovery.anomalies or []) ], } return {"description": str(discovery), "type": "unknown"} async def _detect_anomalies(self, results: Dict, gene_family: str = "SPL") -> List[AnomalyDetection]: """ 检测异常 检查执行结果中的异常情况: - 基因数量异常(过多/过少)- 基于RAG文献数据 - 表达模式异常 - 进化关系异常 """ anomalies = [] # 检查鉴定结果 - 支持多种数据路径 identify_data = results.get("identify", {}) # 尝试多种路径获取基因数量 gene_count = 0 if "parsed_data" in identify_data: gene_count = identify_data["parsed_data"].get("gene_count", 0) if gene_count == 0 and "metrics" in identify_data: gene_count = identify_data["metrics"].get("final_members", 0) if gene_count == 0 and "manifest" in identify_data: gene_count = identify_data["manifest"].get("metrics", {}).get("final_members", 0) # 基因数量异常检测 - 使用RAG获取文献基准 if gene_count > 0: # 查询RAG获取该基因家族的典型规模 expected_range = await self._get_gene_family_size_from_rag(gene_family) min_expected = expected_range.get("min", 5) max_expected = expected_range.get("max", 200) median_expected = expected_range.get("median", (min_expected + max_expected) // 2) # 动态阈值:低于最小值50%或高于最大值200%视为异常 # 例如:文献报道10-30个,低于5个或高于60个视为异常 lower_threshold = max(3, int(min_expected * 0.5)) # 至少低于3个才触发 upper_threshold = int(max_expected * 2.0) if gene_count < lower_threshold: anomalies.append(AnomalyDetection( detected=True, description=f"鉴定到的基因数量过少 ({gene_count}个),远低于文献报道的{min_expected}-{max_expected}个", severity="high", affected_genes=[], expected_value=f"{min_expected}-{max_expected} (中位数: {median_expected})", actual_value=gene_count )) elif gene_count > upper_threshold: anomalies.append(AnomalyDetection( detected=True, description=f"鉴定到的基因数量过多 ({gene_count}个),远高于文献报道的{min_expected}-{max_expected}个", severity="medium", affected_genes=[], expected_value=f"{min_expected}-{max_expected} (中位数: {median_expected})", actual_value=gene_count )) # 检查表达分析结果 if "expression" in results: expr_data = results["expression"] # 检测异常表达模式 # TODO: 实现具体检测逻辑 return anomalies async def _get_gene_family_size_from_rag(self, gene_family: str) -> Dict: """ 从RAG查询基因家族的典型规模 查询几个模式物种的数据,返回统计范围 """ try: import aiohttp import os api_url = os.environ.get("LEGACY_RAG_API_URL", "").rstrip("/") if api_url: async with aiohttp.ClientSession() as session: async with session.get( f"{api_url}/api/v1/rag/family/baseline", params={"family": gene_family} ) as response: if response.status == 200: data = await response.json() baseline = data.get("baseline") or {} if baseline.get("count", 0) and baseline.get("min") is not None and baseline.get("max") is not None: return { "min": int(baseline.get("min")), "max": int(baseline.get("max")), "median": baseline.get("median"), "count": int(baseline.get("count") or 0), "by_species": baseline.get("by_species") or [], "source": "rag_family_baseline" } # 查询RAG获取基因家族规模信息 query = f"{gene_family} gene family member count size Arabidopsis rice" data = await asyncio.to_thread(query_dual_kb_qa, query, top_k=5, use_llm=False) sources = data.get("sources", []) # 从文献中提取基因数量 sizes = [] for source in sources: content = str(source.get("content") or source.get("evidence") or "") # 尝试提取数字(如 "16 members", "about 20 genes") import re # 匹配模式:数字 + members/genes/family matches = re.findall(r'(\d+)\s+(?:members?|genes?|family)', content, re.IGNORECASE) for match in matches: try: size = int(match) if 1 <= size <= 1000: # 合理范围 sizes.append(size) except: pass if sizes: sizes.sort() return { "min": min(sizes), "max": max(sizes), "median": sizes[len(sizes)//2], "count": len(sizes), "source": "dual_kb_qa" } except Exception as e: print(f"[Discovery] RAG查询失败: {e}") # 回退到默认阈值(更严格的默认值) return {"min": 10, "max": 100, "median": 30, "source": "default"} def _extract_gene_family_from_state(self, state: AgentState) -> str: """从状态中提取基因家族名称""" # 尝试从多个来源提取 intent = state.results.get("results", {}).get("intent", {}) or state.results.get("intent", {}) if intent and "gene_family" in intent: return intent["gene_family"] # 从user_input提取 user_input = state.results.get("user_input", {}) if user_input and "gene_family" in user_input: return user_input["gene_family"] # 从prefix提取(如 "Ft.SPL" -> "SPL") prefix = state.results.get("prefix", "") if prefix and "." in prefix: return prefix.split(".")[-1] return "SPL" # 默认 async def _analyze_patterns(self, results: Dict) -> List[Dict]: """ 基于 manifest 常见 metrics 做轻量模式提炼(给假设生成结构化抓手)。 """ patterns: List[Dict] = [] id_b = results.get("identify") or {} mid = self._bucket_metrics(id_b) gcount = mid.get("final_members") or id_b.get("parsed_data", {}).get("gene_count") if gcount: patterns.append({ "type": "gene_family_size_observed", "label": "鉴定规模", "detail": f"当前鉴定成员数(final_members/gene_count)={gcount}", }) de_b = results.get("rnaseq_de") or {} mde = self._bucket_metrics(de_b) if mde.get("de_genes_total") is not None: tot = int(mde.get("de_genes_total") or 0) fam = mde.get("family_analysis") or {} dfg = fam.get("de_family_genes") tfg = fam.get("total_family_genes") patterns.append({ "type": "rnaseq_de_overview", "label": "差异表达规模", "detail": ( f"全局 DE 基因 {tot}(上/下={mde.get('de_genes_up')}/{mde.get('de_genes_down')});" f"家族内 DE {dfg}/{tfg}" ), }) if tot >= 80 and dfg == 0: patterns.append({ "type": "global_de_decoupled_from_family", "label": "家族与全局差异脱节", "detail": "全局大量差异基因但家族层面计数为 0,提示胁迫响应可能主要在非家族基因或其它家族", }) for st in ("rnaseq_kegg_enrich", "rnaseq_go_enrich"): eb = results.get(st) or {} me = self._bucket_metrics(eb) kp = me.get("kegg_enriched_pathways") gt = me.get("go_enriched_terms") if kp is not None or gt is not None: patterns.append({ "type": "enrichment_yield", "label": f"{st} 产出", "detail": f"KEGG pathways={kp}, GO terms={gt}, DE_input={me.get('de_genes_input')}", }) phy_b = results.get("phylogeny") or {} mp = self._bucket_metrics(phy_b) if mp.get("tips") or mp.get("taxa_count"): patterns.append({ "type": "phylogeny_resolution", "label": "系统发育规模", "detail": f"tips/taxa≈{mp.get('tips') or mp.get('taxa_count')}", }) return patterns async def _generate_hypothesis( self, anomalies: List[AnomalyDetection], patterns: List[Dict], results: Dict ) -> GeneratedHypothesis: """ 基于异常和模式生成科学假设 使用LLM生成可验证的假设 """ # 构建上下文 context = { "anomalies": [ {"description": a.description, "severity": a.severity} for a in anomalies ], "patterns": patterns, "results_summary": self._summarize_results(results) } prompt = f"""基于以下基因家族分析结果(可包含空的 anomalies/patterns),生成科学假设。 若未发现异常,请根据定量指标提出可检验的下一步科学问题,避免泛泛而谈。 分析结果摘要: {json.dumps(context, ensure_ascii=False, indent=2)} 请生成: 1. 一个具体的、可验证的科学假设 2. 假设的生物学依据 3. 建议的验证实验 4. 需要的额外数据 5. 置信度评估 (0.0-1.0) 以JSON格式返回: {{ "hypothesis": "假设描述", "rationale": "依据", "confidence": 0.8, "testable": true, "suggested_experiments": ["实验1", "实验2"], "required_data": ["数据1", "数据2"] }}""" try: response = await self._acall_llm(prompt, temperature=0.7) content = response.content # 解析JSON if "```json" in content: content = content.split("```json")[1].split("```")[0] elif "```" in content: content = content.split("```")[1].split("```")[0] data = json.loads(content.strip()) return GeneratedHypothesis( hypothesis=data.get("hypothesis", "无法生成假设"), rationale=data.get("rationale", ""), confidence=data.get("confidence", 0.5), testable=data.get("testable", False), suggested_experiments=data.get("suggested_experiments", []), required_data=data.get("required_data", []) ) except Exception as e: print(f"[DiscoveryAgent] 生成假设失败: {e}") return GeneratedHypothesis( hypothesis="基于当前结果无法生成明确假设", rationale="数据不足或分析结果不明确", confidence=0.3, testable=False ) def _should_continue_iteration( self, anomalies: List[AnomalyDetection], patterns: List[Dict], hypothesis: Optional[GeneratedHypothesis], iteration_count: int ) -> bool: """ 决定是否继续迭代 条件: 1. 检测到重要异常(high或medium严重性) 2. 生成了高置信度假设 3. 未达到最大迭代次数 """ if iteration_count >= self.max_iterations: return False # 有高严重性异常(必须修复) high_severity = any(a.severity == "high" for a in anomalies) # 有中等严重性异常且没有高置信度假设时也需要迭代 medium_severity = any(a.severity == "medium" for a in anomalies) # 有高置信度假设 high_confidence = hypothesis and hypothesis.confidence > 0.7 # 有值得关注的异常模式(非normal模式) significant_patterns = any( p.get("type") not in ["normal_gene_family_size"] for p in patterns ) return high_severity or (medium_severity and not high_confidence) or significant_patterns async def _update_plan( self, current_plan: Dict, hypothesis: GeneratedHypothesis, learning_agent=None # 传入Learning Agent获取参数建议 ) -> Dict: """ 基于假设更新分析计划 根据异常类型和假设,返回可执行的分析阶段 返回格式必须与 PlanningAgentV2 一致: { "stages": [{"id": "identify", "params": {...}}, ...], "job_id": "...", "prefix": "...", "workspace": "..." } """ import copy # 获取当前计划的元信息 job_id = current_plan.get("job_id", "") prefix = current_plan.get("prefix", "") workspace = current_plan.get("workspace", "") # 根据异常/假设确定需要重新执行的阶段 # 这里是示例逻辑,实际应根据 hypothesis.content 分析 stages_to_add = [] # 如果假设涉及参数调整,重新执行相关阶段 if hypothesis and hypothesis.confidence > 0.7: # 解析假设中提到的建议 suggested = hypothesis.suggested_experiments if hypothesis.suggested_experiments else [] # 根据建议映射到可执行的 stage_id # 例如: "调整鉴定参数" -> 重新执行 identify # 例如: "增加motif数量" -> 重新执行 motif stage_mapping = { "鉴定": "identify", "进化树": "phylogeny", "motif": "motif", "结构域": "domain", "基因结构": "structure", "启动子": "promoter", "种间共线性": "interspecies_synteny", "物种间共线性": "interspecies_synteny", "跨物种共线性": "interspecies_synteny", "种内共线性": "synteny", "共线性": "synteny", "表达": "expression", } for suggestion in suggested: for keyword, stage_id in stage_mapping.items(): if keyword in suggestion: stages_to_add.append({ "id": stage_id, "reason": f"基于假设: {hypothesis.hypothesis[:50]}", "params_adjustment": self._extract_param_adjustment(suggestion) }) break # 如果没有特定阶段,默认重新执行 identify(参数调整) if not stages_to_add and hypothesis: stages_to_add.append({ "id": "identify", "reason": f"基于异常检测重新鉴定", "params_adjustment": {"evalue": "放宽到 0.01"} }) # 构建新计划 updated_plan = { "stages": stages_to_add, "job_id": job_id, "prefix": prefix, "workspace": workspace, "triggered_by_hypothesis": hypothesis.hypothesis if hypothesis else "", "iteration_reason": "DiscoveryAgent 建议重新分析" } return updated_plan def _extract_param_adjustment(self, suggestion: str) -> Dict: """从建议中提取参数调整""" adjustments = {} # 简单的关键词匹配 if "放宽" in suggestion or "增加" in suggestion: adjustments["mode"] = "relaxed" if "严格" in suggestion or "减少" in suggestion: adjustments["mode"] = "strict" return adjustments def _determine_discovery_type( self, anomalies: List[AnomalyDetection], patterns: List[Dict] ) -> DiscoveryType: """确定发现类型""" if anomalies: return DiscoveryType.ANOMALY elif patterns: return DiscoveryType.PATTERN else: return DiscoveryType.HYPOTHESIS def _build_description( self, anomalies: List[AnomalyDetection], patterns: List[Dict], hypothesis: Optional[GeneratedHypothesis] ) -> str: """构建发现描述""" parts = [] if anomalies: parts.append(f"检测到{len(anomalies)}个异常:") for a in anomalies: parts.append(f" - {a.description} (严重性: {a.severity})") if patterns: parts.append(f"\n数据模式 ({len(patterns)}):") for p in patterns: lab = p.get("label") or p.get("type") parts.append(f" - [{lab}] {p.get('detail', '')}") if hypothesis: parts.append(f"\n生成假设: {hypothesis.hypothesis}") parts.append(f"置信度: {hypothesis.confidence:.2f}") elif not anomalies and not patterns: parts.append("当前未发现显著异常或结构化模式;建议查看下游 manifest 是否齐全。") return "\n".join(parts) def _summarize_results(self, results: Dict) -> Dict: """汇总各阶段关键 metrics,供假设生成使用""" summary: Dict[str, Any] = {} if "identify" in results: mid = self._bucket_metrics(results["identify"]) summary["identify"] = { "final_members": mid.get("final_members"), } if "phylogeny" in results: summary["phylogeny"] = self._bucket_metrics(results["phylogeny"]) if "rnaseq_de" in results: summary["rnaseq_de"] = self._bucket_metrics(results["rnaseq_de"]) for k in ("rnaseq_quant", "rnaseq_align", "annotation"): if k in results: summary[k] = self._bucket_metrics(results[k]) for k in ("rnaseq_go_enrich", "rnaseq_kegg_enrich"): if k in results: summary[k] = self._bucket_metrics(results[k]) return summary async def _generate_deep_interpretation(self, discovery_data: Dict) -> Dict: """生成深度解读(科研模式)""" stage = discovery_data.get("type", "unknown") hypothesis = discovery_data.get("hypothesis", {}) anomalies = discovery_data.get("anomalies", []) raw_compact = json.dumps( discovery_data.get("raw_data") or {}, ensure_ascii=False, indent=2, ) if len(raw_compact) > 3200: raw_compact = raw_compact[:3200] + "\n…(截断)" prompt = f"""你是一个基因家族分析专家。请基于以下发现结果,生成详细的科学解读。 发现类型: {stage} 假设: {hypothesis.get('text', '无')} 假设依据: {hypothesis.get('rationale', '无')} 异常检测: {len(anomalies)} 个异常 原始上下文摘录(patterns + execution_results 摘要): {raw_compact} 请生成以下内容的详细解读(JSON格式): {{ "biological_significance": "该发现的生物学意义(2-3句)", "mechanism_hypothesis": "可能的分子机制假设", "functional_implications": "对基因功能的影响", "evolutionary_insights": "进化层面的启示", "experimental_suggestions": ["建议的验证实验1", "建议的验证实验2"], "literature_context": "与已知研究的关联" }} 只返回JSON,不要其他内容。""" try: response = await self._acall_llm(prompt, temperature=0.7) content = response.content if hasattr(response, 'content') else str(response) # 提取JSON if "```json" in content: content = content.split("```json")[1].split("```")[0] elif "```" in content: content = content.split("```")[1].split("```")[0] interpretation = json.loads(content.strip()) return interpretation except Exception as e: print(f"[DiscoveryAgent] 深度解读生成失败: {e}") return { "biological_significance": "需要进一步分析", "mechanism_hypothesis": "暂不明确", "error": str(e) } async def _generate_comprehensive_report(self, state: AgentState, message: AgentMessage) -> AgentState: """生成综合深度报告(所有阶段完成后调用,或按需调用)""" print(f"[DiscoveryAgent] 生成综合深度报告...") raw_discoveries = state.results.get("discoveries", []) all_discoveries = [self._discovery_record_as_dict(d) for d in raw_discoveries] execution_results = state.results.get("execution_results", {}) # 获取当前阶段(如果是按需解读,只解读到当前阶段) current_stage = message.payload.get("current_stage", None) # 过滤发现结果:如果只解读到某个阶段 if current_stage: filtered_discoveries = [] for discovery in all_discoveries: filtered_discoveries.append(discovery) # 如果找到当前阶段,停止添加 if discovery.get("stage") == current_stage: break all_discoveries = filtered_discoveries print(f"[DiscoveryAgent] 生成阶段性报告,包含 {len(all_discoveries)} 个阶段") # 构建综合报告 report_sections = [] stage_names = [] for i, discovery in enumerate(all_discoveries, 1): stage = discovery.get("stage") or discovery.get("type", f"阶段{i}") stage_names.append(stage) description = discovery.get("description", "") section = f"## 阶段 {i}: {stage}\n\n{description}\n" # 如果有深度解读,加入报告 if "deep_interpretation" in discovery: interp = discovery["deep_interpretation"] section += f"\n### 科学解读\n" section += f"- **生物学意义**: {interp.get('biological_significance', 'N/A')}\n" section += f"- **机制假设**: {interp.get('mechanism_hypothesis', 'N/A')}\n" section += f"- **功能影响**: {interp.get('functional_implications', 'N/A')}\n" report_sections.append(section) # 生成阶段性综合结论(强调阶段间的关联) conclusion_prompt = f"""你是一个基因家族分析专家。请基于以下各阶段的分析结果,生成阶段性综合结论。 已完成的阶段: {' → '.join(stage_names)} 各阶段结果: {chr(10).join([f"阶段 {i+1} ({d.get('stage', d.get('type', 'unknown'))}): {d.get('description', '')[:200]}" for i, d in enumerate(all_discoveries)])} 请重点分析: 1. 各阶段结果的内在关联(如:鉴定到的基因数如何影响进化树构建) 2. 阶段性科学发现(基于目前已完成的工作) 3. 下一步分析的建议(基于当前结果) 4. 潜在的生物学意义 请用中文生成专业、详细的解读。""" try: conclusion_response = await self._acall_llm(conclusion_prompt, temperature=0.7) conclusion = conclusion_response.content if hasattr(conclusion_response, 'content') else str(conclusion_response) except Exception as e: conclusion = f"综合结论生成失败: {e}" # 组装完整报告 report_title = f"阶段性综合深度报告({' → '.join(stage_names)})" if len(stage_names) < 5 else "基因家族分析综合深度报告" comprehensive_report = f"""# 🔬 {report_title} **分析流程**: {' → '.join(stage_names)} **报告类型**: {'阶段性综合解读' if current_stage else '完整分析报告'} --- {chr(10).join(report_sections)} ## 📊 阶段性综合结论 {conclusion} --- *报告生成时间: {self._get_timestamp()}* """ # 更新状态 state.results["comprehensive_report"] = comprehensive_report state.results["discovery_result"] = { "report_generated": True, "sections_count": len(report_sections), "stages_included": stage_names, "mode": "comprehensive", "is_partial": current_stage is not None # 标记是否为阶段性报告 } state.messages.append({ "role": "discovery", "content": f"📊 阶段性综合报告已生成(包含 {len(stage_names)} 个阶段)" if current_stage else "📊 完整综合报告已生成", "metadata": { "report_length": len(comprehensive_report), "stages": stage_names } }) print(f"[DiscoveryAgent] 综合报告已生成,包含 {len(stage_names)} 个阶段,长度: {len(comprehensive_report)} 字符") return state def _get_timestamp(self) -> str: """获取当前时间戳""" from datetime import datetime return datetime.now().isoformat() # 便捷函数 def create_discovery_agent(llm_manager: LLMManager) -> DiscoveryAgent: """创建DiscoveryAgent实例""" return DiscoveryAgent(llm_manager)