08 报告总结——把多节点执行结果组装成可读结论
2026/3/30大约 3 分钟
上一章我们完成了 Python 沙箱执行,链路已经具备“查数 + 二次计算 + 分析解释”的能力。
本章进入收官:把所有执行中间产物压缩成一份可直接给业务方阅读的报告输出。

🎯 本文目标
- 对查询与分析结果进行结构化汇总。
- 生成面向业务方可直接阅读的高质量报告。
- 打通
REPORT_GENERATION节点与前端 markdown 展示闭环。 - 让最终输出具备可追溯性(计划、SQL、结果、分析结论可回放)。
1. 报告节点在编排中的位置
报告节点是执行链路的最后一环,典型路径如下:
PLANNER
-> HUMAN_FEEDBACK
-> PLAN_EXECUTION
-> SQL/PYTHON ...
-> PLAN_EXECUTION
-> REPORT_GENERATION
-> END在图配置中,PLAN_EXECUTION 的条件边会把 REPORT_GENERATION 作为可跳转目标:
.addConditionalEdges(
DataAgentSpec.Graph.Node.PLAN_EXECUTION, edge_async(PlanExecutorEdge()),
mapOf(
DataAgentSpec.Graph.Node.SQL_GENERATION to DataAgentSpec.Graph.Node.SQL_GENERATION,
DataAgentSpec.Graph.Node.PYTHON_GENERATION to DataAgentSpec.Graph.Node.PYTHON_GENERATION,
DataAgentSpec.Graph.Node.REPORT_GENERATION to DataAgentSpec.Graph.Node.REPORT_GENERATION,
END to END,
)
)
.addEdge(DataAgentSpec.Graph.Node.REPORT_GENERATION, END)对应状态键:
const val REPORT_RESULT = "REPORT_GENERATOR_NODE_OUTPUT"2. ReportGeneratorNode 的输入与输出
报告节点不会重新查库,它只消费前面所有节点沉淀好的状态:
- 用户需求:
REWRITE_QUERY - 执行计划:
PLANNER_NODE_OUTPUT - 执行产物:
PLAN_EXECUTE_NODE_OUTPUT - 总结建议:
summaryAndRecommendations(来自当前 report 步骤参数)
核心逻辑:
override fun apply(state: OverAllState): Map<String, Any> {
val rewriteQuery = state.value(DataAgentSpec.Graph.StateKey.Recall.REWRITE_QUERY, "")
val plan = Plan.getPlan(state)
val result = state.value<Map<String, String>>(DataAgentSpec.Graph.StateKey.Planning.EXECUTION_OUTPUT).orElseThrow()
val summaryAndRecommendations = Plan.getCurrentStep(state).toolParameters.summaryAndRecommendations!!
return mapOf(
DataAgentSpec.Graph.StateKey.Execution.REPORT_RESULT to generateReport(
rewriteQuery,
plan,
result,
summaryAndRecommendations
)
)
}关键点
REPORT_RESULT 当前是一个流式 Flux<ChatResponse>,这意味着报告内容可以边生成边返回给前端,而不是整段阻塞等待。
3. 报告 Prompt 是怎么拼起来的
ReportGeneratorNode 做了两层拼装:
buildUserRequirementsAndPlan
- 组装原始需求
- 组装思考过程(thought process)
- 组装步骤与工具说明
buildAnalysisStepsAndData
- 遍历
step_n执行结果 - 自动关联步骤描述、工具名、SQL
- 追加
step_n_analysis的 Python 分析文本
这样模型在写报告时不是“空口胡说”,而是基于真实执行证据。
渲染模板入口:
val reportPrompt: String = promptManager.reportGeneratorPlainPromptTemplate
.render(
mapOf(
"user_requirements_and_plan" to userRequirementsAndPlan,
"analysis_steps_and_data" to analysisStepsAndData,
"summary_and_recommendations" to summaryAndRecommendations,
"json_example" to cleanJsonExample,
"optimization_section" to ""
)
)4. 可追溯报告的实现细节
为了保证“结论可追溯”,报告拼装时做了这几件事:
- 对每个
step_n尝试解析出步骤索引并回连计划步骤。 - 把对应
toolToUse、instruction、sqlQuery都写进上下文。 - 显式过滤
_analysis键,避免重复写入执行结果区。 - 再单独追加
step_n_analysis作为解释层内容。
效果是:报告里的每条结论都能追溯到某一步执行数据,而不是只给最终一句话答案。
5. 前端展示:Report 节点卡片 + Markdown 预览
在前端我们为 REPORT_GENERATION 增加了专用卡片,并接入 markdown 渲染组件:
- 组件映射:
[DATA_AGENT_GRAPH_NODE.REPORT_GENERATION]: markRaw(ReportGenerationNodeCard)- 展示策略:
- 若
REPORT_RESULT是字符串,按 markdown 渲染。 - 若是对象,JSON 格式化兜底展示。
- 流式
content也按 markdown 渲染。
- 若
这样业务方看到的是“可读报告”,不是裸 JSON。
6. 常见问题与优化建议
6.1 为什么报告内容有时不完整
通常是前序步骤没有把 EXECUTION_OUTPUT 写全。
建议排查每个执行节点是否都写入了 step_n 或 step_n_analysis。
6.2 如何让报告更“业务化”
可以在 summaryAndRecommendations 放入领域模板,例如:
- 风险等级
- 关键发现
- 建议动作
- 预计收益
这样模型更容易输出管理层可读格式。
6.3 报告节点为什么用流式
长报告若一次性返回,前端会等待很久。
流式可显著提升交互体验,用户能即时看到内容增长。
7. 小结
到这里,SQL Agent 从“能查询”进化为“能交付结果”:
- 前面节点负责取数、计算、分析。
- 报告节点负责归纳、组织、表达。
- 前端负责把结构化产物转成可读的业务文档。
这也是一个可落地数据分析 Agent 的完整闭环:
可执行、可解释、可交付、可追溯。
