140 lines
4.9 KiB
Python
140 lines
4.9 KiB
Python
|
|
"""
|
|||
|
|
Agent 编排层 —— 调度四层架构完成分析
|
|||
|
|
|
|||
|
|
Layer 1: Planner 意图规划
|
|||
|
|
Layer 2: Explorer 自适应探索
|
|||
|
|
Layer 3: Insight 异常洞察
|
|||
|
|
Layer 4: Context 上下文记忆
|
|||
|
|
"""
|
|||
|
|
from typing import Optional
|
|||
|
|
|
|||
|
|
from config import DB_PATH, MAX_EXPLORATION_ROUNDS
|
|||
|
|
from schema_extractor import extract_schema, schema_to_text
|
|||
|
|
from sandbox_executor import SandboxExecutor
|
|||
|
|
from planner import Planner
|
|||
|
|
from explorer import Explorer
|
|||
|
|
from insights import InsightEngine, quick_detect
|
|||
|
|
from reporter import ReportGenerator
|
|||
|
|
from context import ContextManager
|
|||
|
|
|
|||
|
|
|
|||
|
|
class DataAnalysisAgent:
|
|||
|
|
"""
|
|||
|
|
数据分析 Agent
|
|||
|
|
|
|||
|
|
四层架构:
|
|||
|
|
1. Planner - 理解用户意图,生成分析计划
|
|||
|
|
2. Explorer - 基于计划多轮迭代探索
|
|||
|
|
3. Insights - 从结果中检测异常、输出主动洞察
|
|||
|
|
4. Context - 管理多轮对话上下文
|
|||
|
|
|
|||
|
|
Agent 负责编排这四层,从问题到报告。
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
def __init__(self, db_path: str):
|
|||
|
|
# 数据层
|
|||
|
|
self.db_path = db_path
|
|||
|
|
self.schema = extract_schema(db_path)
|
|||
|
|
self.schema_text = schema_to_text(self.schema)
|
|||
|
|
self.executor = SandboxExecutor(db_path)
|
|||
|
|
|
|||
|
|
# 四层组件
|
|||
|
|
self.planner = Planner()
|
|||
|
|
self.explorer = Explorer(self.executor)
|
|||
|
|
self.insight_engine = InsightEngine()
|
|||
|
|
self.reporter = ReportGenerator()
|
|||
|
|
self.context = ContextManager()
|
|||
|
|
|
|||
|
|
def analyze(self, question: str, max_rounds: Optional[int] = None) -> str:
|
|||
|
|
"""
|
|||
|
|
完整分析流程
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
question: 用户分析问题
|
|||
|
|
max_rounds: 最大探索轮数(默认用配置值)
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
格式化的分析报告
|
|||
|
|
"""
|
|||
|
|
max_rounds = max_rounds or MAX_EXPLORATION_ROUNDS
|
|||
|
|
|
|||
|
|
print(f"\n{'='*60}")
|
|||
|
|
print(f"📊 {question}")
|
|||
|
|
print(f"{'='*60}")
|
|||
|
|
|
|||
|
|
# ── Layer 0: 检查上下文 ──────────────────────────
|
|||
|
|
prev_context = self.context.get_context_for(question)
|
|||
|
|
if prev_context:
|
|||
|
|
print("📎 发现历史分析上下文,将结合之前的发现")
|
|||
|
|
|
|||
|
|
# ── Layer 1: 意图规划 ────────────────────────────
|
|||
|
|
print("\n🎯 [Layer 1] 意图规划...")
|
|||
|
|
plan = self.planner.plan(question, self.schema_text)
|
|||
|
|
|
|||
|
|
analysis_type = plan.get("analysis_type", "unknown")
|
|||
|
|
dimensions = plan.get("dimensions", [])
|
|||
|
|
rationale = plan.get("rationale", "")
|
|||
|
|
print(f" 类型: {analysis_type}")
|
|||
|
|
print(f" 维度: {', '.join(dimensions) if dimensions else '自动发现'}")
|
|||
|
|
print(f" 理由: {rationale[:80]}{'...' if len(rationale) > 80 else ''}")
|
|||
|
|
|
|||
|
|
# ── Layer 2: 自适应探索 ──────────────────────────
|
|||
|
|
print(f"\n🔍 [Layer 2] 自适应探索 (最多 {max_rounds} 轮)...")
|
|||
|
|
steps = self.explorer.explore(plan, self.schema_text, max_rounds=max_rounds)
|
|||
|
|
|
|||
|
|
successful = sum(1 for s in steps if s.success)
|
|||
|
|
print(f"\n 完成: {len(steps)} 轮, {successful} 条成功查询")
|
|||
|
|
|
|||
|
|
# ── Layer 3: 异常洞察 ────────────────────────────
|
|||
|
|
print("\n🔎 [Layer 3] 异常洞察...")
|
|||
|
|
|
|||
|
|
# 先做规则检测
|
|||
|
|
rule_alerts = quick_detect(steps)
|
|||
|
|
for alert in rule_alerts:
|
|||
|
|
print(f" {alert}")
|
|||
|
|
|
|||
|
|
# 再做 LLM 深度分析
|
|||
|
|
insights = self.insight_engine.analyze(steps, question)
|
|||
|
|
if insights:
|
|||
|
|
print(f" 发现 {len(insights)} 条洞察")
|
|||
|
|
for insight in insights:
|
|||
|
|
print(f" {insight}")
|
|||
|
|
else:
|
|||
|
|
print(" 未发现异常")
|
|||
|
|
|
|||
|
|
# ── 生成报告 ────────────────────────────────────
|
|||
|
|
print("\n📝 正在生成报告...")
|
|||
|
|
report = self.reporter.generate(question, plan, steps, insights)
|
|||
|
|
|
|||
|
|
# 追加主动洞察
|
|||
|
|
if insights:
|
|||
|
|
insight_text = self.insight_engine.format_insights(insights)
|
|||
|
|
report += f"\n\n---\n\n{insight_text}"
|
|||
|
|
|
|||
|
|
# ── Layer 4: 记录上下文 ──────────────────────────
|
|||
|
|
self.context.add_session(
|
|||
|
|
question=question,
|
|||
|
|
plan=plan,
|
|||
|
|
steps=steps,
|
|||
|
|
insights=insights,
|
|||
|
|
report=report,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
return report
|
|||
|
|
|
|||
|
|
def get_schema(self) -> str:
|
|||
|
|
"""获取 Schema 文本"""
|
|||
|
|
return self.schema_text
|
|||
|
|
|
|||
|
|
def get_history(self) -> str:
|
|||
|
|
"""获取分析历史摘要"""
|
|||
|
|
return self.context.get_history_summary()
|
|||
|
|
|
|||
|
|
def get_audit(self) -> str:
|
|||
|
|
"""获取执行审计日志"""
|
|||
|
|
return self.executor.get_execution_summary()
|
|||
|
|
|
|||
|
|
def clear_history(self):
|
|||
|
|
"""清空分析历史"""
|
|||
|
|
self.context.clear()
|