引言
传统 BI 的分析逻辑是「预定义的」——开发者提前写好查询模板、计算公式、图表配置,用户触发后系统按既定路径执行。这种模式的优点是确定性高,缺点是灵活性低——任何不在预设范围内的分析需求都要提给开发团队排期。
Agentic BI 的愿景是「自主分析的智能体」——用户只需提出分析意图,Agent 自己决定查什么数据、怎么计算、用什么图表、如何解读。这要求 Agent 具备多步推理能力:不是一步到位给出答案,而是边思考边行动、根据中间结果调整后续步骤。
ReAct(Reasoning + Acting)框架是实现这种多步推理的经典范式。衡石 Agentic BI 在工程化落地 ReAct 框架的过程中,积累了大量实践经验。本文将深入解析 ReAct 在 BI 场景的技术实现。
一、ReAct 框架核心原理
1.1 思考与行动的交替
ReAct 的名字来自两个词的组合:Reasoning(推理)和 Acting(行动)。它的核心思想是:让 LLM 在「思考」和「行动」之间交替进行,形成一个 Thought-Action-Observation 循环。
一个完整的 ReAct 循环:
Thought(思考):LLM 分析当前状态,决定下一步该做什么。如「用户想知道销售额下降的原因,我需要先查询最近 3 个月的销售数据看趋势。」
Action(行动):基于思考结果,调用一个工具执行操作。如调用query_metric工具查询最近 3 个月销售额。
Observation(观察):工具返回结果,LLM 观察结果并进入下一轮思考。如「销售额确实在 2 月下降了 15%,我需要进一步查询按产品线的分解数据,定位是哪个产品线导致的下降。」
这个循环持续进行,直到 LLM 认为已经获得了足够的信息来回答用户的问题,输出最终答案。
1.2 ReAct vs 其他推理范式
vs Chain-of-Thought(CoT):CoT 让 LLM 做纯文本推理链,不调用外部工具。适用于数学推理等不需要外部数据的场景。BI 分析必须查数据,CoT 不适用。
vs Plan-and-Execute:先一次性生成完整计划,再逐步执行。问题是一旦中间步骤返回意外结果,整个计划作废。ReAct 的优势是每步都可以根据实际结果调整方向。
vs Tree-of-Thoughts(ToT):在每个决策点生成多个分支,做树搜索。效果好但计算成本高,BI 场景的实时性要求使其不太适用。
ReAct 在 BI 场景的适配性最好:既有推理能力(分析中间结果),又有行动能力(调用工具查询数据),且每步成本可控。
二、衡石 Agentic BI 的 ReAct 实现
2.1 Prompt 模板设计
ReAct 框架的核心是 Prompt 模板——它指导 LLM 如何在思考、行动、观察之间切换。衡石的 Prompt 模板包含以下结构:
系统指令:定义 Agent 的角色和能力边界。「你是一个 BI 分析 Agent。你可以调用以下工具来回答用户的数据分析问题。每次只执行一个工具调用,等待结果返回后再决定下一步。」
工具描述:列出所有可用工具的名称、描述、参数 Schema。LLM 在 Action 步骤中从这里选择工具。
历史交互记录:之前的 Thought-Action-Observation 序列。这让 LLM 知道「我已经做了什么、得到了什么结果」。
当前问题:用户的原始分析需求。
输出格式约束:要求 LLM 按固定格式输出——先输出 Thought 段落,再输出 Action 调用。系统解析 Action 后执行工具,把结果以 Observation 格式追加到 Prompt 中,触发下一轮推理。
2.2 思考链的质量控制
ReAct 的效果高度依赖 Thought 的质量。如果 LLM 的思考是浅层的(「我要查数据」),行动就会是盲目的(随机调用工具)。衡石通过三个手段提升思考质量:
思考引导:在系统指令中增加思考引导规则——「在每次 Thought 中,请明确以下三点:1)当前已知什么信息;2)还缺什么信息;3)下一步应该做什么来获取缺失信息。」这种结构化引导避免了浅层思考。
反思机制:每 3 步 ReAct 循环后,插入一个反思步骤——LLM 回顾前三步的行动和结果,评估是否偏离了原始目标。如果偏离,做方向修正。
终止判断:LLM 在每次 Thought 中需要判断「我是否已经有足够的信息来回答用户问题了?」如果判断为是,输出 Final Answer;如果判断为否,继续 Action。为防止无限循环,系统设置最大步数上限(默认 10 步)。
2.3 行动选择的约束与引导
LLM 在 Action 步骤中选择调用的工具。为了提高选择准确率,衡石增加了以下约束:
工具白名单:根据当前分析阶段限制可选工具。如在「数据查询」阶段,只允许调用查询类工具;在「结果可视化」阶段,才允许调用图表类工具。这种分阶段约束减少了工具误选。
参数引导:LLM 生成工具参数时,系统在参数 Schema 中嵌入「参数获取提示」。如时间参数的提示为「如果用户说『上个月』,请输出标准日期范围格式 YYYY-MM-DD」,引导 LLM 生成规范参数。
历史去重:如果 LLM 在之前的步骤中已经调用过相同工具+相同参数,系统在 Prompt 中提示「你已经调用过这个查询,结果如下」,避免重复调用。
三、典型场景的 ReAct 执行轨迹
3.1 场景:销售异常归因分析
用户问题:「2 月份销售额为什么突然下降了?」
第 1 轮:
Thought:用户想知道 2 月销售额下降的原因。我需要先确认下降的事实和幅度,查询最近 6 个月的销售额趋势。
Action:调用
query_metric,参数:指标=销售额,时间范围=近6个月,粒度=月Observation:返回 6 个月销售额数据,2 月确实环比下降 18%,同比下降 12%。
第 2 轮:
Thought:下降事实已确认。接下来需要定位下降来源——是哪个产品线、哪个区域、哪个客户群体导致的下降。我先按产品线分解。
Action:调用
aggregate_metric,参数:指标=销售额,维度=产品线,时间范围=1月vs2月Observation:返回各产品线 1-2 月销售额对比。发现产品线 C 下降了 42%,其他产品线波动不大。
第 3 轮:
Thought:产品线 C 是主要下降来源。进一步分析产品线 C 的下降是区域性的还是全局性的,以及是否与特定客户相关。
Action:调用
aggregate_metric,参数:指标=销售额,维度=区域+客户,过滤条件=产品线C,时间范围=1月vs2月Observation:返回产品线 C 各区域各客户的销售变化。发现华南区的大客户 A 从 350 万降到 50 万。
第 4 轮:
Thought:核心原因是华南区大客户 A 在产品线 C 上的采购大幅减少。我需要查询这个客户的近期订单状态,看是否有异常。
Action:调用
query_dataset,参数:数据集=订单明细,过滤条件=客户A, 产品线C, 近3个月Observation:返回大客户 A 近 3 个月订单明细。发现 2 月有一笔大单状态为「已取消」。
第 5 轮(终止):
Thought:已经找到根本原因——2 月销售额下降 18% 的主要原因是华南区大客户 A 在产品线 C 上取消了一笔大单(约 300 万)。我有足够信息回答用户了。
Final Answer:2 月销售额环比下降 18%,同比下降 12%。主要原因是华南区大客户 A 在产品线 C 上取消了一笔约 300 万的大单(2 月 15 日取消)。排除该因素后,其他业务线销售额基本持平。建议关注大客户 A 的订单取消原因(可能涉及合同到期、竞品替换或服务问题)。
3.2 轨迹分析
这个案例展示了 ReAct 的三个核心特征:
渐进式深入:从确认事实 → 定位来源 → 细化到客户 → 查明订单状态,每步都比上一步更深入。
数据驱动决策:每一步的行动都基于上一步的观察结果。如果第 2 步发现不是产品线问题,第 3 步就会转向其他方向。
自主终止:Agent 在第 5 步判断已经找到根因,自主决定输出最终答案,不需要外部干预。
四、ReAct 的工程化挑战与解决方案
4.1 Token 消耗控制
ReAct 的多轮循环意味着 Prompt 会越来越长——每轮的 Thought-Action-Observation 都追加到 Prompt 中。10 轮循环后,Prompt 可能超过 10000 Token,推理成本急剧上升。
衡石的解决方案:
上下文压缩:每 5 轮做一次上下文压缩——LLM 总结前 5 轮的关键发现,替换原始的详细记录。压缩后的摘要只有 200-300 Token,大幅减少后续轮次的 Prompt 长度。
观察结果裁剪:工具返回的 Observation 如果是大数据表,只保留关键聚合数字,不把全量明细放入 Prompt。如「返回 1200 行数据,关键发现:产品线 C 下降 42%」替代 1200 行原始数据。
早停机制:如果 LLM 连续 3 轮没有获得新信息(Observation 与已有信息重复),系统强制终止循环,输出当前最佳答案。
4.2 错误恢复
工具调用可能失败——查询超时、参数错误、数据不存在。ReAct 框架需要优雅处理这些错误:
自动重试:工具执行失败时,系统自动重试 1 次。如果重试仍失败,把错误信息以 Observation 格式返回给 LLM。
错误信息友好化:原始错误信息(如SQLSyntaxErrorException: ORA-00904: invalid identifier)对 LLM 来说难以理解。系统把错误转换为自然语言描述(如「查询失败:字段名不正确,请检查字段名是否拼写正确」),帮助 LLM 做修正。
降级策略:如果某个工具连续失败 3 次,系统建议 LLM 换一个工具或换一种查询方式。如execute_sql失败后,建议改用query_dataset(基于数据集的安全查询)。
4.3 推理路径的可解释性
Agentic BI 的用户需要知道「Agent 是怎么得出这个结论的」——不能只给答案,还要给推理路径。
衡石的做法是保留完整的 ReAct 轨迹日志,并以可读格式呈现给用户:
每一步的 Thought 以「Agent 思考」卡片展示
每一步的 Action 以「执行操作」卡片展示,包含工具名和参数
每一步的 Observation 以「获得结果」卡片展示,包含关键数据摘要
最终答案以「分析结论」卡片展示
用户可以展开查看任意步骤的详细信息,验证 Agent 的推理逻辑是否合理。这种透明性是建立用户信任的关键——用户不会相信一个「黑盒给出的答案」。
4.4 并行推理
某些分析场景中,Agent 需要同时探索多个方向。如「分析销售额下降原因」时,可能需要同时查产品线维度、区域维度、客户维度。
串行 ReAct 一次只能查一个维度,效率较低。衡石支持并行 ReAct:
Agent 在 Thought 阶段判断「当前需要同时查询多个独立维度」
系统并行发起多个 Action 调用
所有 Action 返回后,Agent 在统一的 Observation 中合并分析
并行推理把 3 次串行查询的 3 倍延迟压缩为 1 倍,显著提升了用户体验。
五、ReAct 的效果评估
5.1 评估维度
ReAct Agent 的效果需要从多个维度评估:
任务完成率:Agent 最终是否给出了正确且可用的答案。在衡石内部测试集上,ReAct Agent 的任务完成率为 87%,显著高于单轮 Function Calling 的 72%。
推理步数:完成任务所需的平均 ReAct 循环次数。衡石的数据是平均 4.2 步,其中简单查询 2-3 步,复杂归因分析 6-8 步。
工具调用准确率:每步选择的工具和参数是否正确。内部测试集上为 93.5%,错误主要发生在多工具选择场景。
Token 消耗:完成任务消耗的平均 Token 数。通过上下文压缩和观察结果裁剪,衡石把平均 Token 消耗控制在 8000 以内。
5.2 与非 ReAct 模式的对比
在「销售异常归因」类复杂分析任务上:
指标 | 单轮 Function Calling | ReAct Agent |
任务完成率 | 72% | 87% |
答案深度 | 给出表层原因 | 给出根因链 |
平均延迟 | 2.1s | 6.5s |
Token 消耗 | 2K | 8K |
关键发现:ReAct 用 3 倍的延迟和 4 倍的 Token 换取了 15 个百分点的完成率提升和显著更深的分析深度。对于「需要准确答案」的 BI 场景,这个交换是值得的。
六、总结
ReAct 框架是 Agentic BI 的技术基石。它让 BI Agent 从「一问一答的查询器」进化为「边思考边行动的分析师」。
衡石 Agentic BI 的 ReAct 工程化实践,三个核心设计:
结构化思考引导:通过 Prompt 模板引导 LLM 做结构化思考,避免浅层推理
上下文压缩与早停:控制多轮循环的 Token 消耗,避免成本失控
推理路径透明化:完整展示 Thought-Action-Observation 轨迹,建立用户信任
当一个 BI 系统不仅能给出答案,还能展示「它是怎么想出来的」,它就从「智能工具」跨入了「可信分析伙伴」的领域。