Files
iov_ana/output/consolidator.py
openclaw e8f8e2f1ba feat: 四层架构全面增强
安全与稳定性:
- 移除硬编码 API Key,改用 .env + 环境变量
- LLM 调用统一重试机制(指数退避,3 次重试,处理 429/5xx/超时)
- 中文字体检测增强(CJK 关键词兜底 + 无字体时英文 fallback)
- 缺失 API Key 给出友好提示而非崩溃

分析能力提升:
- 异常检测新增 z-score 检测(标准差>2 标记异常)
- 新增变异系数 CV 检测(数据波动性)
- 新增零值/缺失检测
- 上下文管理器升级为关键词语义匹配(替代简单取最近 2 条)

用户体验:
- 报告自动保存为 Markdown(reports/ 目录)
- 新增 export 命令导出查询结果为 CSV
- 新增 reports 命令查看已保存报告
- CLI 支持 readline 命令历史(方向键翻阅)
- CSV 导入工具重写:自动列名映射、容错处理、dry-run 模式
- 新增 .env.example 配置模板
2026-03-31 14:39:17 +08:00

84 lines
3.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
报告整合器 —— 将多次分析结果合并为一份完整报告
"""
import json
from core.config import LLM_CONFIG
from core.utils import get_llm_client, llm_chat
from layers.context import AnalysisSession
CONSOLIDATE_PROMPT = """你是一个高级数据分析总监。下面是你的团队针对同一份数据做的多次分析,请整合为一份完整的综合报告。
## 核心问题
{question}
## 各次分析结果
{sections}
## 可用图表
{charts_text}
## 整合要求
1. **执行摘要**3-5 句话概括全局结论
2. **核心发现**:从所有分析中提炼最重要的发现,去重,按重要性排列
3. **交叉洞察**:不同维度之间的关联
4. **图表引用**:用 `![标题](路径)` 嵌入相关段落
5. **风险与建议**:按优先级排列
6. **数据附录**:关键统计数字
中文,专业简报风格。先结论后细节。"""
class ReportConsolidator:
"""报告整合器"""
def __init__(self):
self.client, self.model = get_llm_client(LLM_CONFIG)
def consolidate(self, sessions: list[AnalysisSession], question: str = "",
charts: list[dict] | None = None) -> str:
if not sessions:
return "(无分析数据可整合)"
if not question:
question = sessions[0].question
sections = self._build_sections(sessions)
charts_text = "\n".join(f"{i}. {c['title']}: {c['path']}" for i, c in enumerate(charts or [], 1)) or "无图表。"
try:
return llm_chat(
self.client, self.model,
messages=[
{"role": "system", "content": "你是高级数据分析总监,整合多维度分析结果。"},
{"role": "user", "content": CONSOLIDATE_PROMPT.format(question=question, sections=sections, charts_text=charts_text)},
],
temperature=0.3, max_tokens=4096,
)
except Exception as e:
print(f" ⚠️ LLM 整合失败: {e},使用拼接模式")
return self._fallback_concat(sessions, charts)
def _build_sections(self, sessions: list[AnalysisSession]) -> str:
parts = []
for i, session in enumerate(sessions, 1):
section = f"### 分析 {i}: {session.question}\n"
section += f"类型: {session.plan.get('analysis_type', '未知')}\n\n"
for step in session.steps:
if not step.success or not step.rows or step.action == "done":
continue
section += f"- {step.purpose} ({step.row_count} 行)\n"
section += f" 数据: {json.dumps(step.rows[:8], ensure_ascii=False)}\n\n"
if session.insights:
section += "#### 洞察\n" + "\n".join(f"- {i}" for i in session.insights) + "\n"
parts.append(section)
return "\n---\n".join(parts)
def _fallback_concat(self, sessions: list[AnalysisSession], charts: list[dict] | None) -> str:
parts = ["# 综合分析报告\n"]
for i, s in enumerate(sessions, 1):
parts.append(f"## 第 {i} 部分: {s.question}\n{s.report}\n")
if charts:
parts.append("\n## 可视化\n" + "\n".join(f"![{c['title']}]({c['path']})" for c in charts))
return "\n".join(parts)