""" Layer 4: 上下文管理器 管理多轮对话的分析上下文,让后续问题可以引用之前的发现。 """ import json import time from dataclasses import dataclass, field from typing import Any, Optional from explorer import ExplorationStep from insights import Insight @dataclass class AnalysisSession: """一次分析的完整记录""" question: str plan: dict steps: list[ExplorationStep] insights: list[Insight] report: str timestamp: float = field(default_factory=time.time) def summary(self) -> str: """生成本次分析的摘要(供后续对话引用)""" parts = [f"**问题**: {self.question}"] if self.plan: parts.append(f"**分析类型**: {self.plan.get('analysis_type', 'unknown')}") parts.append(f"**关注维度**: {', '.join(self.plan.get('dimensions', []))}") # 核心发现(从成功步骤中提取) key_findings = [] for step in self.steps: if step.success and step.rows: # 提取最突出的值 top_row = step.rows[0] if step.rows else {} finding = f"{step.purpose}: " finding += ", ".join( f"{k}={v}" for k, v in top_row.items() if k.lower() not in ("id",) ) key_findings.append(finding) if key_findings: parts.append("**核心发现**:") for f in key_findings[:5]: parts.append(f" - {f}") # 洞察 if self.insights: parts.append("**主动洞察**:") for insight in self.insights[:3]: parts.append(f" - {insight}") return "\n".join(parts) def to_reference_text(self) -> str: """生成供 LLM 使用的上下文文本""" return ( f"## 之前的分析\n\n" f"### 问题\n{self.question}\n\n" f"### 摘要\n{self.summary()}\n\n" f"### 详细发现\n" + "\n".join( f"- {step.purpose}: {step.row_count} 行结果" for step in self.steps if step.success ) ) class ContextManager: """上下文管理器:管理多轮对话的分析历史""" def __init__(self, max_history: int = 10): self.sessions: list[AnalysisSession] = [] self.max_history = max_history def add_session( self, question: str, plan: dict, steps: list[ExplorationStep], insights: list[Insight], report: str, ) -> AnalysisSession: """记录一次分析""" session = AnalysisSession( question=question, plan=plan, steps=steps, insights=insights, report=report, ) self.sessions.append(session) # 保持历史大小 if len(self.sessions) > self.max_history: self.sessions = self.sessions[-self.max_history:] return session def get_context_for(self, new_question: str) -> Optional[str]: """ 根据新问题,从历史中找到相关上下文。 简单实现:取最近的分析会话。 """ if not self.sessions: return None # 取最近 2 轮分析的摘要 recent = self.sessions[-2:] parts = [] for session in recent: parts.append(session.to_reference_text()) return "\n\n---\n\n".join(parts) def get_history_summary(self) -> str: """获取所有历史的摘要""" if not self.sessions: return "(无历史分析)" lines = [f"共 {len(self.sessions)} 次分析:"] for i, session in enumerate(self.sessions, 1): ts = time.strftime("%H:%M", time.localtime(session.timestamp)) lines.append(f" {i}. [{ts}] {session.question}") if session.insights: for insight in session.insights[:2]: lines.append(f" {insight}") return "\n".join(lines) def clear(self): """清空历史""" self.sessions.clear()