如何用 C# 构建 AI Agent 驱动的 Excel 报表工作流

AI Excel 报表自动化指把语言模型的判断力与真正的 Excel 处理库结合进 .NET 应用,让应用用自然语言指令完成电子表格的合并、归一化、分析与格式化,而不必逐列编写字段映射代码。Excel 报表真正的难点很少是画最后那张图,而是把一堆格式各异的源工作簿变成你真正能信任的数据。用 AI 智能体,你只需描述报表任务(”把这 20 份门店工作簿合并,并标记营收下降超过 30% 的门店”),拿回来的是格式正确的成品工作簿,而不是一段聊天回复。Spire.Agent.Office 同时提供这两半能力:语言理解负责判断,其下的确定性文档层保证输出的是真实、格式正确的 .xlsx(或 PDF)文件。

快速导航


1. Excel 报表自动化的真正瓶颈

以大多数”月度报表”需求背后的例行任务为例。运营团队管理着 20 家区域门店,月底每家门店都会发来一份销售工作簿。理论上这是一份报表,实际上却是 20 个恰好文件名相似的不同文件:

  • 列名对不上。 一家门店把营收叫做 Revenue,另一家叫 Sales Amount,第三家叫 Net Sales
  • 布局对不上。 一家把月份横着排,另一家竖着排,第三家在中间硬塞了一列备注。
  • 数据类型对不上。 日期被存成文本,数字被存成千分位,至少一家门店把标题行并进了表头。

所以在任何人能给管理层画图之前,分析员要先花一周时间打开文件、映射列、归一化日期、排查笔误,然后才开始找异常、拼报表。这些都不是”报表生成”的部分,全是数据准备。

要记住的核心观点是:Excel 报表真正的难点很少是画最后那张图,而是把不一致的源工作簿变成你真正能信任的数据。 图表库会很乐意画出错误的数据;团队真正缺的,是一条从原始收件箱文件到干净、可对比表格的可靠路径。而这条路径,正是 AI 智能体改变投入产出比的地方。


2. AI 智能体进入工作流后改变了什么

这个任务的自动化并不新鲜,只是通常很贵。对比一下两条工作流:

传统自动化

1
检查文件 → 映射列 → 归一化数据 → 写规则 → 生成工作簿

最后一步之前的每一步都是预先定义的:为每个已知表头写一份列映射、为每个已知格式写一个日期解析、为每条规则写一个阈值。一旦某家门店改了列名或业务规则变化,映射和规则就错了,人又得重新介入。

智能体自动化

1
描述报表任务 → 提供源工作簿 → 复核结果

智能体读取的是每份工作簿的含义,而不是固定位置,因此列映射和规则集不再需要预先穷举。它真正省掉的,正是最贵的那部分:预先定义一套下一个文件就会失效的 schema 和规则集的工作量。

Spire.Agent.Office 工作流:20 份异构门店工作簿进入智能体,产出合并表、异常清单与管理层报告

本文接下来把这条流水线完整走一遍,从原始工作簿到可打印的 PDF,用 20 家门店的场景作为贯穿始终的示例。第 3 到第 5 节解释智能体在每个阶段做了什么;第 6 节给出驱动这一切的完整 C# 代码。


3. 从异构工作簿到统一数据模型

这个问题在 Excel 里的独特之处在于:不同工作簿”看起来一样”,其实并不一样。 三张门店表可能都只有四列,却让你在没有人来解释的情况下根本无法合并:

门店 A 门店 B 门店 C
Revenue Sales Amount Net Sales
Month Reporting Period Date
Units Quantity Sold Qty

没有任何列索引能把它们一一对应起来,因为这种对应是语义层面的,不是位置层面的。RevenueSales AmountNet Sales 是同一个概念的三种叫法,只有真正读懂表头,才能把它们对齐。

智能体的合并步骤把这种语义对齐变成统一 schema:

1
门店 / 区域 / SKU / 销量 / 营收 / 月份

它读取每份源工作簿,把表头解析到目标模型上,对齐行和列,跳过重复的表头行和标题行,最后写出一张归一化表。开发者完全不用写 FindColumnByHeader("Revenue") 这类例程,指令里直接给出目标 schema,智能体自己从每份文件里找出映射关系。

这是投入产出比最高的一步,因为它当前最消耗分析员时间,也最容易在新增门店时出问题。要了解智能体对齐多份异构文件、算出合计并标出最低价的完整示例,参见多版本报价单自动对比教程


4. 把业务规则变成自然语言分析

数据一旦归到一处,报表就需要判断力,而判断力恰恰是硬编码规则会失效的地方。示例里用的是一条典型财务规则:

标记营收较上月下降超过 30%增长超过 50% 的行。

注意这句话里包含了多少信息,而每一部分写成代码都别扭:

  • 为什么是 30% 和 50%? 这是带上下文的业务阈值,季节性门店、新 SKU 或促销活动都会改变”异常”的含义。硬编码的 if (change < -0.30) 对所有门店一视同仁,遇到季节性就会误报。
  • 怎么改? 代码里要重新编译部署;指令里分析员改一句话就行:”下降超过 20%””只针对华东区域””只标记销量超过 100 的 SKU”。
  • 加一个维度? 想让规则按门店、按区域、按月分别生效?在指令里加一个分句即可,而不是加一层嵌套循环。
  • 解释结果? 智能体还能追加一列「原因」,为每个被标记的行写一句可能的成因说明,这是单纯的阈值比较永远给不出来的。

这一节引出的原则值得写清楚:

代码定义如何做*;指令定义*做什么。**

开发者不再编码规则,而是描述结果。规则保持可读、可被业务方修改,并且在新门店加入或阈值变化时不必改动代码。


5. 从分析结果到可交付的管理报表

找出异常只是报表的一半。结果最终要变成一份别人真正用得上的工作簿:分析员的电子表格不是交付物,管理汇总才是。

整条流水线这样收尾:

1
2
3
4
5
6
7
8
9
原始工作簿

合并数据

异常清单

管理汇总

PDF

最后一条指令拼出交付物:最前面放一张「汇总」工作表,带 KPI 块(总营收、最佳门店、最差门店、异常数量)、月度趋势表、按区域的营收柱状图,并按打印要求排版。把同一条指令指向 .pdf 路径,就能导出同样一份 PDF 用于分发,无需额外的渲染步骤。

要记住的是:分析与排版是两件不同的事,而智能体两件都做。 分析员的工作变成了复核标记清单并签字确认,而不是每月重新拼一份报告。


6. 用 C# 构建完整工作流

上面所有环节都由一条 C# 流水线驱动。配置一次智能体,然后按顺序执行三条指令:合并、分析、出报表。令牌、包与项目接线的完整搭建步骤见集成入门教程,这里聚焦工作流本身。

1
2
3
4
5
6
7
8
9
10
11
12
13
using System.IO;
using Spire.Xls;
using Spire.Agent.Office.AI;
using Spire.Agent.Office.Extensions;

AIOptions options = new AIOptions {
SpireToken = spireToken,
WorkDir = @"C:\retail-ops\output",
TimeoutMs = 300000
};

string[] storeFiles = Directory.GetFiles(@"C:\retail-ops\inbox", "*.xlsx");
Directory.CreateDirectory(@"C:\retail-ops\output");

1. 合并。 把 20 份收件箱文件作为附件传入,并给出目标 schema。第 3 节的归一化就发生在这里,由指令驱动,而不是任何列映射:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
using (Workbook consolidated = new Workbook())
{
AIResult result = consolidated.AI(options).ExecuteInstruction(
consolidated,
"读取收件箱里的每一份区域销售工作簿并合并到一张工作表。各门店的列名各不相同" +
"(例如有的叫 Sales、有的叫 Amount,有的叫 Month、有的叫 Period);将它们归一化为" +
"统一结构:门店、区域、SKU、销量、营收、月份。跳过重复的表头行,并把合并结果" +
"另存为工作簿。",
@"C:\retail-ops\output\consolidated.xlsx",
storeFiles);

if (result == null || !result.Success)
throw new InvalidOperationException($"合并失败: {result?.ErrorMessage}");
}

2. 分析。 加载合并文件,用中文把第 4 节的规则讲清楚。智能体新增一张「异常」工作表,并保持源数据不变:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
using (Workbook analysis = new Workbook())
{
analysis.LoadFromFile(@"C:\retail-ops\output\consolidated.xlsx");

AIResult result = analysis.AI(options).ExecuteInstruction(
analysis,
"新增一张「异常」工作表。将每家门店和每个 SKU 的营收与上月对比,标记营收下降" +
"超过 30% 或增长超过 50% 的行,下降行填红色、增长行填绿色,并加一列「原因」用" +
"一句话说明可能的原因。保持原始数据工作表不变。",
@"C:\retail-ops\output\analyzed.xlsx");

if (result == null || !result.Success)
throw new InvalidOperationException($"分析失败: {result?.ErrorMessage}");
}

「异常」工作表会落在源数据旁边,被标记的行、填充色和「原因」列都由指令应用:

输出示例:合并后的数据加上一张带标记行、填充色与「原因」列的异常工作表

3. 出报表。 按第 5 节拼出管理汇总并导出。savePath 单独决定输出格式,这里是 .xlsx,换成 .pdf 即可用于分发:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
using (Workbook report = new Workbook())
{
report.LoadFromFile(@"C:\retail-ops\output\analyzed.xlsx");

AIResult result = report.AI(options).ExecuteInstruction(
report,
"生成管理层报告。在最前面新增一张「汇总」工作表,包含 KPI 块(总营收、最佳门店、" +
"最差门店、异常数量)、月度趋势表,以及一张按区域的营收柱状图。按打印要求排版,并" +
"保存成品工作簿。",
@"C:\retail-ops\output\monthly-report.xlsx");

if (result == null || !result.Success)
throw new InvalidOperationException($"报表生成失败: {result?.ErrorMessage}");
}

「汇总」工作表落在工作簿最前面,随时可以打印或导出 PDF:

输出示例:成品管理层报告,带汇总页、趋势表与区域图表

关键 API 调用

  • Workbook.AI(options) – 为现有工作簿对象挂载 AI 文档处理器
  • ExecuteInstruction(doc, instruction, savePath, attachments) – 执行一个阶段并写出结果
  • AIResult.Success / AIResult.ErrorMessage – 校验每个阶段并暴露失败信息

不用智能体时,你会怎么写

作为对比,传统 SDK 完成同样三个阶段,需要按表头字符串逐列定位、把每条阈值硬编码、再逐个单元格设置填充色,并且每当门店改了列名或规则变化时都要重新调参:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
foreach (string file in storeFiles)
{
Workbook wb = new Workbook();
wb.LoadFromFile(file);
Worksheet sheet = wb.Worksheets[0];

// 一旦某家门店把列命名为 "Sales" 而不是 "Revenue",这里就失效。
int revenueCol = FindColumnByHeader(sheet, "Revenue");
int storeCol = FindColumnByHeader(sheet, "Store");

for (int r = sheet.LastRow; r >= 2; r--)
{
double current = double.Parse(sheet.Range[r, revenueCol].Text);
double prior = double.Parse(sheet.Range[r, revenueCol + 1].Text);
double change = (current - prior) / prior;

// 一个硬编码阈值;季节性门店会触发误报。
if (change < -0.30) sheet.Range[r, revenueCol].Style.Color = Color.Red;
}
// ...接着合并、汇总、生成图表 -- 逐店、逐月数百行代码。
}

前后对比:硬编码的列与阈值逻辑被一条自然语言指令取代

智能体不是让你不用写代码,而是让你不用写映射代码。区别在于逻辑放在哪里:放在列查找器和阈值里,还是放在业务方读得懂、改得动的句子里。


7. AI 的边界与应用逻辑从哪里开始

比一张”能做/不能做”清单更准确的视角是:智能体并不会取代确定性应用逻辑,它是在其上叠加的一层。

应用仍然负责所有与理解电子表格无关的部分:

  • 文件发现与访问 – 找到收件箱文件、检查权限、暂存文件
  • 工作流调度 – 报表何时运行、由什么触发、以什么顺序执行
  • 数据来源控制 – 哪些文件是合法输入、它们来自哪里
  • 错误处理与重试 – 文件缺失或某阶段失败时怎么办
  • 最终审批 – 由人复核被标记的异常后再签字
  • 外部对账 – 把报表与记录系统核对

智能体负责的是真正语义化的部分:

  • 理解 – 读懂每一列实际代表什么
  • 归一化 – 把异构 schema 对齐到一个模型
  • 解释 – 套用业务规则判断什么是异常
  • 转换 – 把原始数据变成汇总、图表和排版
  • 排版 – 拼出最终的工作簿或 PDF

这个视角比能力表更有用,因为它告诉你该把工程精力放在哪里。把确定性的管道留在代码里,那里可测试、可审计;把语义工作交给智能体。各司其职,各自发挥所长。


8. 给现有 .NET Excel 工作流加上 AI

最后值得说清楚的一点是:要走到这一步,你需要重建的东西少得惊人。如果你的应用已经用 Spire.Xls 处理 Excel,那你手里的文档模型就是集成点:

1
2
3
4
5
Workbook

Workbook.AI(options)

ExecuteInstruction(...)

你不需要引入新的文档层,也不需要另起一套文档处理服务。你只是在已经持有的 Workbook 对象上,加了一个自然语言执行层。 同一个曾经打开、合并、保存文件的对象,现在能接收一条指令并执行整个工作流,由确定性的 Excel 引擎保证输出是真实、格式正确的文件,合并单元格、数字格式和图表都原样保留。同样的 ExecuteInstruction 模式也延伸到 Word 与 PDF 文档,参见 AI 合同审查

这才是用 Excel 开发者听得懂的话讲出来的价值主张:不是”去接入一个 AI 平台”,而是”教会你已经在用的工作簿听懂指令”。当门店改了列名或财务改了标记规则,改的是一个句子,而不是重建整条文档流水线。


9. 常见问题

我需要把 Excel 数据发到云端吗?

不一定。Spire.Agent.Office 从你自己的应用运行,SDK 和文档处理都留在你的环境里,文件不会被上传到第三方服务做存储或转换。要分析内容,AI 需要相关数据,这些数据会被发给模型处理,这是任何 AI 工作流的固有步骤。如果你在本地网络部署自有模型,内容就完全不出内网;如果你通过托管模型 API(如 OpenAI 或 Azure OpenAI)接入,相关内容会按你的配置经网络传输给该提供商。

支持哪些 Excel 格式?

输入覆盖 XLSX、XLS 等常见工作簿文件,智能体直接以原生格式读取。输出可保存为 XLSX、XLS、CSV、PDF 或 HTML,成品报表可以直接进入归档或分发列表。

能替代我的财务或运营复核吗?

不能。智能体自动化的是读取、归一化、分析与排版,也就是分析员每月要花的那几个小时,但最终签字确认仍由复核人完成。把标记出的异常当作待核对的候选清单,而不是已经下好的结论。

这和把数据粘贴进 ChatGPT 有什么区别?

聊天模型能告诉你哪里看起来异常,却无法把答案放进带汇总页、条件格式和图表的样式化工作簿,也无法导出 PDF。AI Excel 智能体把语言模型的判断力与确定性 Excel 层结合,因此输出是团队能打开、能分发的真实、格式正确的文件。

能使用我自己的 AI 模型吗?

可以。Spire.Agent.Office 支持灵活的 AI 模型接入,兼容主流 AI 基础设施,包括托管模型 API 与私有化部署模型,你可以把智能体指向自己的端点。关于你的部署中支持哪些提供商,请联系你的客户团队:联系我们

准备好自动化你的 Excel 报表了吗?

合并、异常分析与报表生成是最快见效的场景:把智能体指向收件箱、描述报表需求,就能得到格式正确的工作簿或 PDF。跟随集成入门教程,在 .NET 中跑通你的第一个表格工作流。