问题背景在一次AI回答采集项目中需要每周生成一份报告汇总模型响应时间、回答长度、评分等指标。手动从数据库导出数据、用Excel做图表、再排版每次耗时约2小时且容易遗漏指标或格式不一致。因此需要一套自动化报告生成系统能够从数据库读取数据、聚合指标、生成图表并输出HTML报告。环境说明Python 3.9Jinja2 模板引擎Matplotlib 用于图表生成Pandas 用于数据聚合数据存储在PostgreSQL中以下为通用实现思路具体表结构和字段请根据实际项目调整整体流程报告生成分为四个阶段数据读取从数据库查询原始采集记录。指标聚合按报告周期日/周/月计算平均响应时间、回答长度、评分等。模板渲染使用Jinja2将聚合结果和图表嵌入HTML模板。输出归档生成HTML文件并保存。选择先聚合再渲染的原因是聚合后的数据量小模板渲染更快不同周期如日、周对聚合的影响主要体现在SQL的GROUP BY粒度上周报需要按周聚合日报按天。报告模板设计使用Jinja2模板引擎将报告结构抽象为模板支持动态插入图表、表格和文本。模板分为三部分头部报告标题、时间范围、生成时间主体指标卡片、趋势图、对比表格尾部备注、数据来源说明示例模板片段report_template.html!DOCTYPEhtmlhtmlheadtitle{{ title }}/title/headbodyh1{{ title }}/h1p时间范围{{ start_date }} ~ {{ end_date }}/pp生成时间{{ generated_at }}/ph2核心指标/h2divclasscards{% for metric in metrics %}divclasscardh3{{ metric.name }}/h3p{{ metric.value }}/p/div{% endfor %}/divh2趋势图/h2imgsrc{{ trend_chart_path }}alt趋势图h2详细数据/h2tabletrth日期/thth指标A/thth指标B/th/tr{% for row in detail_rows %}trtd{{ row.date }}/tdtd{{ row.metric_a }}/tdtd{{ row.metric_b }}/td/tr{% endfor %}/table/body/html数据聚合从数据库查询原始数据使用Pandas进行聚合。以下代码为示例实际使用时需替换数据库连接信息和表名。importpandasaspdfromsqlalchemyimportcreate_enginedefaggregate_data(start_date,end_date):# 请替换为实际数据库连接信息enginecreate_engine(postgresql://your_user:your_passwordyour_host/your_db)queryf SELECT DATE(created_at) as date, AVG(response_time_ms) as avg_response_time, AVG(LENGTH(answer_text)) as avg_answer_length, AVG(score) as avg_score FROM ai_responses WHERE created_at {start_date} AND created_at {end_date} GROUP BY DATE(created_at) ORDER BY date dfpd.read_sql(query,engine)returndf可视化图表生成使用Matplotlib生成趋势图保存为图片嵌入报告。注意Matplotlib默认字体不支持中文需指定中文字体。importmatplotlib.pyplotaspltdefgenerate_trend_chart(df,metric_col,output_path):plt.figure(figsize(10,4))plt.plot(df[date],df[metric_col],markero)plt.title(f{metric_col}趋势)plt.xlabel(日期)plt.ylabel(metric_col)plt.grid(True)plt.tight_layout()plt.savefig(output_path)plt.close()报告生成主流程fromjinja2importEnvironment,FileSystemLoaderimportdatetimedefgenerate_report(start_date,end_date):# 1. 聚合数据dfaggregate_data(start_date,end_date)# 2. 计算核心指标metrics[{name:平均响应时间(ms),value:round(df[avg_response_time].mean(),2)},{name:平均回答长度(字符),value:round(df[avg_answer_length].mean(),2)},{name:平均评分,value:round(df[avg_score].mean(),2)},]# 3. 生成趋势图chart_path/tmp/trend.pnggenerate_trend_chart(df,avg_response_time,chart_path)# 4. 渲染模板envEnvironment(loaderFileSystemLoader(templates))templateenv.get_template(report_template.html)html_contenttemplate.render(titleAI回答采集周报,start_datestart_date,end_dateend_date,generated_atdatetime.datetime.now().strftime(%Y-%m-%d %H:%M),metricsmetrics,trend_chart_pathchart_path,detail_rowsdf.to_dict(records))# 5. 输出HTML文件output_pathfreport_{start_date}_{end_date}.htmlwithopen(output_path,w)asf:f.write(html_content)returnoutput_path支持自定义指标通过配置文件定义指标名称、SQL聚合表达式和单位系统动态加载。# metrics_config.yamlmetrics:-name:平均响应时间sql:AVG(response_time_ms)unit:ms-name:最大响应时间sql:MAX(response_time_ms)unit:ms-name:回答接受率sql:SUM(CASE WHEN accepted1 THEN 1 ELSE 0 END) * 1.0 / COUNT(*)unit:%代码中读取配置并动态生成SQL和图表。验证结果正常情况下运行脚本后会生成一个HTML文件打开可看到报告标题和时间范围核心指标卡片数值正确趋势图折线图显示日期和指标值数据表格与数据库查询结果一致常见问题与避坑图表中文乱码Matplotlib默认字体不支持中文需指定中文字体如plt.rcParams[font.sans-serif] [SimHei]。模板路径问题Jinja2的FileSystemLoader需要正确设置模板目录建议使用绝对路径或项目相对路径。大数据量性能如果数据量过大聚合查询可能慢可考虑预聚合表或使用数据库物化视图。图表保存路径生成图表时确保输出目录存在否则保存失败。总结本文提供了一个基于Python的AI回答采集报告自动生成方案核心思路是用Pandas聚合数据用Matplotlib生成图表用Jinja2渲染HTML模板。方案支持通过YAML配置文件自定义指标易于扩展。当前限制仅输出HTML格式如需PDF可借助wkhtmltopdf或WeasyPrint转换。适用于需要定期输出采集评估结果的场景但具体数据库表结构和字段需根据实际项目调整。