Files
iov_ana/reporter.py

111 lines
3.2 KiB
Python
Raw Normal View History

"""
报告生成器
将分析计划 + 探索结果 + 洞察综合为一份可读报告
"""
import json
from typing import Any
import openai
from config import LLM_CONFIG
from explorer import ExplorationStep
from insights import Insight
REPORT_PROMPT = """你是一个数据分析报告撰写专家。基于以下信息撰写报告。
## 用户问题
{question}
## 分析计划
{plan}
## 探索过程
{exploration}
## 主动洞察
{insights_text}
## 撰写要求
1. **开头**一句话总结核心结论先给答案
2. **核心发现**按重要性排列每个发现带具体数字
3. **深入洞察**异常趋势关联从洞察中提取
4. **建议**基于数据的行动建议
5. **审计**末尾附上所有执行的 SQL
使用 Markdown中文撰写
语气专业但不枯燥像一个聪明的分析师在做简报"""
class ReportGenerator:
"""报告生成器"""
def __init__(self):
self.client = openai.OpenAI(
api_key=LLM_CONFIG["api_key"],
base_url=LLM_CONFIG["base_url"],
)
self.model = LLM_CONFIG["model"]
def generate(
self,
question: str,
plan: dict,
steps: list[ExplorationStep],
insights: list[Insight],
) -> str:
"""生成分析报告"""
# 构建探索过程文本
exploration = self._build_exploration(steps)
# 构建洞察文本
insights_text = self._build_insights(insights)
prompt = REPORT_PROMPT.format(
question=question,
plan=json.dumps(plan, ensure_ascii=False, indent=2),
exploration=exploration,
insights_text=insights_text,
)
response = self.client.chat.completions.create(
model=self.model,
messages=[
{"role": "system", "content": "你是专业的数据分析师,撰写清晰、有洞察力的分析报告。"},
{"role": "user", "content": prompt},
],
temperature=0.3,
max_tokens=4096,
)
return response.choices[0].message.content
def _build_exploration(self, steps: list[ExplorationStep]) -> str:
parts = []
for step in steps:
if step.action == "done":
parts.append(f"### 探索结束\n{step.reasoning}")
continue
if step.success:
parts.append(
f"### 第 {step.round_num} 轮:{step.purpose}\n"
f"思考: {step.reasoning}\n"
f"SQL: `{step.sql}`\n"
f"结果 ({step.row_count} 行):\n"
f"列: {step.columns}\n"
f"数据: {json.dumps(step.rows, ensure_ascii=False)}"
)
else:
parts.append(
f"### 第 {step.round_num} 轮:{step.purpose}\n"
f"SQL: `{step.sql}`\n"
f"执行失败: {step.error}"
)
return "\n\n".join(parts) if parts else "无探索步骤"
def _build_insights(self, insights: list[Insight]) -> str:
if not insights:
return "未检测到异常。"
return "\n".join(str(i) for i in insights)