☰
Univer + AI Agent:把办公文档变成可编程的智能执行环境
2026/9/29 18:12:55 网站建设 项目流程

写这篇文章之前,我先说一个最近的感触。身边好几个做 AI 应用的朋友,去年还在头疼"怎么让大模型把结果塞进 Excel",今年不约而同开始聊一个东西:Univer。它不是又一个在线表格,而是把文档、表格、幻灯片整个摊开,变成一个可以供 AI Agent 直接调用的 SDK。这个定位很有意思,等于把传统办公软件从"给人用的界面"变成了"给程序用的执行环境"。这篇文章我会从实际集成的角度,把 Univer 在 AI Agent 场景里到底能干什么、怎么接、会踩哪些坑,尽量一次讲透。

1. 先想明白:AI Agent 到底需要办公 SDK 提供什么

1.1 Agent 和文档应用的关系不是"套壳",而是"执行环境"

很多人做 AI + 办公的第一步,是试着让大模型输出一段 CSV,再靠前端去解析渲染成表格。这确实能做,但做出来的东西本质上是"一次性数据快照"。你今天让 Agent 生成一张经营分析表,明天想让它在这张表上追加一列,它做不到——因为它根本没有保住这张表的对象模型,没有单元格地址,没有公式依赖,没有历史命令。

Univer 解决的是这个更深层的问题。它把文档内容建模成可编程、可寻址、可变的内存对象,Agent 拿到的不只是一堆呈现出来的像素,而是整棵可操作的文档树。你可以通过 SDK 命令直接说:"把 A 列的格式改成百分比""在 B2 插入一个 SUM 公式""删除第 3 行"。每一次操作都能被记录,回放,撤销。这才是 Agent 能真正"上手干活"的基础。

从工程视角看,Univer 更像一个带文档能力的运行时,而不是一个"套壳表格"。Agent 是大脑,Univer 是双手。

1.2 为什么不用现成的 Excel 库或 Google Sheets API / Luckysheet

有人会问,Excel 有 COM 接口,Google Sheets 有 API,不是一样能让程序操作表格吗?区别在三个层面。

一是形态。Excel 的自动化接口面向桌面进程,Google Sheets API 面向云服务,它们默认的工作方式是一问一答的请求响应。而 Univer 本身是前端 SDK,天然嵌入你的应用进程,你可以把渲染、计算、数据状态、命令管线都放在同一个运行环境里,Agent 调用无网络往返,无协议转换。

二是可控性。Univer 的命令系统是完备的,任何一次修改都是一条命令,命令可以被拦截、校验、审批。这对 Agent 场景是致命的——你总不希望大模型一句话就直接把企业核心报表改崩了。有了命令层,你可以在 AI 操作之前加一道"人工确认",也可以限制 Agent 只能操作某一个 sheet 范围。

三是协议开放度。Univer 不但用 JSON 数据结构来描述工作簿,还提供了一套可插拔的插件机制。你可以写一个插件,专门给 Agent 暴露"只读模式""公式审计""单元格锁定"这些能力。这类东西在 Excel VBA 里不是做不到,而是做起来极其痛苦,维护成本极高。

1.3 最适合 Agent 的到底是什么形态

做 AI 办公有个误区,总想着"让 Agent 直接输出一个完整文档"。真正常见的落地形态其实是任务驱动 + 局部修改 + 多轮确认。

举个例子,你的 Agent 对用户说:"我帮你在新增的 Sheet 里生成了 6 月销售明细,需要我再按区域汇总一版吗?"这个过程中,Agent 做的是:

  • 创建工作表
  • 写入表头和原始数据
  • 计算区域汇总
  • 添加条件格式

每一步都是局部操作,每一次都依赖工作簿当前的状态。Univer 天然适合这种模式,因为它的所有 API 都是围绕"当前文档对象"设计的。你在任何时刻拿去读,拿到的都是最新状态;你在任何时刻命令它写,写入的都是连续上下文里的一部分。

2. Univer 的架构画像:四个可能被 AI Agent 直接利用的能力层

2.1 文档引擎层:把 Spreadsheet、Doc、Slide 统一建模

Univer 的核心不是某个具体产品,而是基于 TypeScript 的文档引擎。它统一抽象了电子表格、富文本文档和演示文稿三种文档模型,底层共享一套渲染引擎和命令架构。

这个统一建模对 AI Agent 很关键。因为你不需要为"表格场景"写一套工具、为"文档场景"再写一套工具。Agent 的工具集里只需要挂一个univer对象,通过参数区分操作类型。

import { Univer, UniverInstanceType } from '@univerjs/core'; // 获取当前活动的工作簿实例 const workbook = univer.getCurrentUnitForType<ISheetData>(UniverInstanceType.UNIVER_SHEET);

三种文档类型在底层共享协变逻辑,意味着一个文档里可以同时有表格、富文本段落、内嵌图表,Agent 可以在同一个上下文里对它们一起操作。比如说"把第一页标题改成红色,顺手把底下表格里低于 100 的数据标黄",这类混合操作在 Univer 里就是一次事务。

2.2 命令系统:Agent 操作文档的"确定性出入口"

AI Agent 最大的风险不是"不会干活",而是"干出来的活不可预期"。Univer 的命令系统天然提供了这个护栏。

所有修改文档的动作,在 Univer 中都通过 Command 完成。命令可以有前置校验,可以记录到历史栈,可以触发多端同步。这意味着:

  1. Agent 的操作可以被完整审计,每一条命令对应一个明确的行为描述;
  2. Agent 的操作可以被回滚,只要命令在历史栈内,用户永远能撤销;
  3. Agent 的操作可以被限制,你在命令注册层做白名单,它就只有白名单内的"自由"。

这是很多国产表格件完全没有想过的设计。它做插件时总是想着怎么渲染得好、怎么缓存快,很少把"外部智能体操作文档"当成一等公民。Univer 不是这样,它把命令当作基础设施,Agent 集成反而顺理成章。

2.3 公式引擎与自定义函数:复杂计算直接内置

办公文档的场景,除了数据的录入和展示,还有大量计算。Agent 如果只会写字符串/数字,干不了真正的财务分析活。Univer 内置了一套完整的公式引擎,支持常见的 Excel 公式,并且允许注册自定义函数。

这对 Agent 来说意味着两件事。

第一,Agent 不必自己实现计算逻辑。它可以把 SUMIFS、VLOOKUP、XLOOKUP 这些公式直接写进单元格,计算交给公式引擎完成。你甚至可以让 Agent 组合公式,比如"对 B 列匹配到的所有记录求和,结果放在 C10"。

第二,自定义函数机制给 Agent 扩展了一个外部世界。你可以注册一个自定义函数AI_QUERY(prompt, range),让用户在常规公式里也能调用大模型。这样 Agent 的能力是作为公式的一部分存在,而不是游离在文档之外。

import { FunctionType } from '@univerjs/sheets-formula'; export const aiQueryFunction = { name: 'AI_QUERY', type: FunctionType.STATIC, minParams: 2, maxParams: 3, calculate: (promptText, rangeText, mode?) => { return callLLM(`${promptText},请基于数据:${getRangeData(rangeText)} 给出回答,模式:${mode ?? '摘要'}`); } };

2.4 渲染层与 UI 容器:Agent 的"工作台界面"从哪来

如果你只把 Univer 当成数据操作 SDK,那就低估它了。它还有一层非常强的渲染能力,包括 Canvas 渲染器、DOM 渲染器,以及一套 UI 容器机制。

在实际产品里,我们往往需要给用户呈现一个"Agent 正在编辑表格"的可视界面。Univer 可以以多种方式嵌入你的应用:独立挂载整个工作簿,或者只挂载一个特定的表格区域,甚至把编辑区域嵌进你自己的弹窗里。

更关键的是,Univer 支持多实例运行。同一个页面里可以同时存在多个工作簿实例,一个负责用户主操作,一个负责 Agent 的"草稿区",Agent 改完草稿之后,再通过命令把结果合并进主文档。这种"人机隔离"的设计在协作场景里非常实用。

3. 从 0 到 1 搭建一个"AI 数据分析助手"的最小闭环

3.1 项目目标与选型思路

我建议第一次接触 Univer + AI Agent 的朋友,不要一上来追求全面。先做一个最小闭环:用户上传一个 CSV,Agent 读取后生成一份带公式和条件格式的分析表格。

选型上我用了:

  • 前端框架:React + Vite,方便快速验证 UI;
  • 后端:Node.js + Express,提供一个简单的 LLM 转发接口;
  • 大模型:OpenAI 兼容接口,方便替换;
  • 集成方式:前端直接引入 Univer SDK,Agent 通过工具注册调用。

为什么选前端集成而不是后端渲染?因为 Univer 的完整能力(撤销、实时协作、UI 交互)都依赖前端运行时。后端接入主要用于处理模型请求和复杂计算,文档本体留在前端。

3.2 环境准备:不太麻烦的初始化

Univer 的安装逻辑和大多数前端 SDK 类似,核心包拆得很细。这里我给一份实测可行的初始化清单。

npm install @univerjs/core @univerjs/sheets @univerjs/sheets-formula @univerjs/sheets-ui @univerjs/ui @univerjs/preset-sheets

需要注意,Univer 的版本迭代比较快,安装时最好固定一个大版本,避免小版本之间 API 不兼容。我在实测时见过一次@univerjs/core锁在一个旧版本,而@univerjs/sheets-ui拉到了新版,导致整个表格渲染后命令注册异常。这种问题排查起来非常恶心,强烈建议用package-lock.json锁定。

初始化一个最简工作簿大约是下面的样子:

import { Univer } from '@univerjs/core'; import { UniverSheetsPlugin } from '@univerjs/sheets'; import { UniverSheetsFormulaPlugin } from '@univerjs/sheets-formula'; import { UniverSheetsUIPlugin } from '@univerjs/sheets-ui'; import { UniverUIPlugin } from '@univerjs/ui'; const univer = new Univer(); univer.registerPlugin(UniverSheetsPlugin); univer.registerPlugin(UniverSheetsFormulaPlugin); univer.registerPlugin(UniverUIPlugin, { container: 'app' }); univer.registerPlugin(UniverSheetsUIPlugin);

这个初始化模板可以套用到后续所有项目里。有几个注意点:container必须是一个真实存在的 DOM 节点,不能是空字符串或者 undefined,否则渲染层会静默失败,表格区域一片空白,控制台却没有任何报错,这是新手最容易撞上的坑。

3.3 给 Agent 注册"表格工具集"

Agent 要操作表格,不能靠提示词让它"想象"表格长什么样,必须给它一组真实的工具。我将工具设计为三类:

  1. 读取类:读取单元格值、读取范围数据、读取公式;
  2. 写入类:写入单元格、批量填充、插入行/列;
  3. 结构类:新建工作表、重命名、设置列宽、添加条件格式。

在 Agent 的工具协议里,每个工具都需要定义入参和返回值的 schema。拿读取范围为例:

const readRangeTool = { name: 'univer.readRange', description: '读取当前工作表中指定区域的数据,返回二维数组', parameters: { type: 'object', properties: { range: { type: 'string', description: '例如 A1:C10' } }, required: ['range'] } };

工具调用的执行层,直接映射到 Univer 的 API。这里有一个设计细节值得多说两句:不要让 Agent 直接操作 workbook 对象,而是通过你自己定义的 service 做封装。理由很简单,以后想加权限控制、加审计日志、加 Mock 数据,只需要在 service 层改,不需要满项目去找工具函数。

读取范围的实际代码:

function readRange(range: string) { const workbook = univer.getCurrentUnitForType(UniverInstanceType.UNIVER_SHEET); const worksheet = workbook.getActiveSheet(); return worksheet.getRange(range).getValue(); }

3.4 让 Agent 生成公式:不只是填文本

写公式是这个最小闭环里最出效果的部分。你可以让模型直接生成=SUM(B2:B9)这样的公式文本,然后作为单元格的值写入。但如果公式有误,比如引用了不存在的单元格、括号不匹配,Univer 会在状态层报错,而 Agent 自己是感知不到的。

所以我的方案里增加了一个"公式验算"步骤:Agent 写入公式之后,系统读取该单元格的 computedValue,判断是否为#ERROR或#REF!。如果是,就把错误信息回传给大模型,让它自己修正。

function writeFormula(range: string, formula: string) { const workbook = univer.getCurrentUnitForType(UniverInstanceType.UNIVER_SHEET); const worksheet = workbook.getActiveSheet(); worksheet.getRange(range).setFormula(formula); // 延迟一个微任务再读,确保公式引擎已重算 requestAnimationFrame(() => { const value = worksheet.getRange(range).getValue(); if (typeof value === 'string' && value.startsWith('#')) { return { ok: false, error: value }; } return { ok: true }; }); }

实测下来,把这种"验算反馈"做成闭环,Agent 的表格操作成功率能从 60% 提到 90% 以上。不能指望大模型一次写对公式,但只要反馈回路够快,它迭代得比你想象中好。

3.5 多轮对话中的状态保持问题

Agent 和用户对话是多轮的,这意味着模型需要知道"当前表格变成什么样了"。如果每次对话都重新描述整个表格,token 消耗会大得吓人,而且描述的信息密度还不高。

我的做法是提供一个snapshot工具。每轮对话末尾,系统把当前 sheet 的关键状态压缩成摘要:

  • 一共几个工作表,每个叫什么名字;
  • 每个工作表的行列数;
  • 当前激活的单元格和选区;
  • 最近 5 条修改记录。

把这个摘要拼进系统提示词,模型就能用很小开销地追踪表格演化。实践下来,一个 100 行 * 20 列的表格,压缩成摘要后大约只要 300 个 token,整个对话的上下文消耗可控。

4. 一个容易忽略的细节:命令回放与人机协同

4.1 为什么不能只做"结果同步"

很多人做 AI 表格的时候,会觉得既然 Univer 能直接读写字格,那我把 Agent 的修改结果同步到界面上不就行了?看起来简单,实际上会丢失一个非常重要的前提:用户可能正在界面上手动编辑。

想象一个场景:用户在 B2 单元格手动输入了一个值,Agent 的异步任务又在同时写 B2。如果你的 Agent 操作不经过命令系统,而是直接设置数据,那么用户的输入会被静默覆盖。这还不是最严重的,最严重的是撤销栈紊乱——用户 Ctrl+Z,不知道会回退到哪个操作。

Univer 的命令系统是把人机协同问题解决干净的关键。Agent 的修改被包装成 UNIVER_CMD 命令,进入统一的命令队列。这样:

  • 用户能感知到"Agent 刚才改了我这张表",因为界面上会有操作变化;
  • 用户能撤销 Agent 的操作,因为它在历史栈里有位置;
  • 并发冲突可以通过命令版本机制协调,避免直接数据覆盖。

4.2 命令回放在 Agent 日志里的价值

还有一个容易被忽视的点:命令是可序列化的。你可以把 Agent 执行过的每一条命令存进数据库,这不仅是一份审计日志,更是可复现的任务轨迹。

比如用户的诉求是"把这季度数据按地区透视一下",Agent 实际执行了 17 条命令:建表、填数据、写公式、调格式、加透视表。这 17 条命令记录下来,下次用户再提出几乎一样的诉求时,Agent 不一定非要重新调大模型,它可以参考过去成功的命令序列,做少量参数修改就直接回放。这是我实测效率提升最明显的地方,单轮任务耗时从 15 秒降到 2 秒以内。

4.3 人机可交互的"审批点"

在 AI Agent 修改重要表格的场景,比如财务报销表、采购订单,我强烈建议你加入审批点机制。Univer 提供了可拦截命令的方式,你在命令执行前判断"该命令是否由 Agent 发起",如果是,就暂停执行,弹窗让用户确认。

univer.getCommandService().beforeCommandExecuted((command) => { if (command.params?.origin === 'agent') { return { type: 'block', hookId: 'agent-confirm', payload: command }; } });

拦截后怎么恢复?拿到用户确认事件,再重新派发这条命令即可。效果上,就是用户在表格边上看到一个"AI 正在修改:设置 C2:C12 数据条格式",点允许后命令继续,点拒绝后命令丢弃。这套流程对建立用户信任非常有帮助。

5. 踩坑实录:我把 Univer 接进 Agent 项目后遇到的四个问题

5.1 全量重算导致的性能崩塌

第一个坑是性能。Agent 批量写入数据时,如果你循环调用 API 写单元格,比如一个 500 行数据要逐个 set,Univer 的公式引擎会每次变更后都做一次重算。在公式多的时候,界面会肉眼可见地卡顿,甚至出现输入延迟。

解决方式不是去优化循环,而是用批量命令。Univer 提供了setRangeValues这类 API,一次性更新一个大区域。同时我关闭了临时重算,等所有数据写完后手动触发一次全量刷新。

worksheet.getRange('A1:C500').setValues(bulkData); univer.getCurrentUnitForType(UniverInstanceType.UNIVER_SHEET)?.getActiveSheet().markDirty();

实测数据:500 行 * 5 列的写入,逐格 set 需要 8 秒左右,批量 set 加一次刷新,300 毫秒内完成。差距是数量级的。

5.2 公式错误时 Agent 并不知道,除非你主动去读

第二次大的麻烦,是模型生成的公式看着合理,实际执行错误。大模型写=VLOOKUP(A2, 表2!A:B, 2, FALSE)这种公式,你从文本上看不出来任何问题,但可能因为表名带空格、感叹号转义不对,Univer 就是不认。

我前面提到的"写入后复查 computedValue"就是在这个坑里总结出来的。没有这层验证,用户会看到一片错误提示,而 Agent 完全无感,体验极差。

5.3 多实例共享状态时的命名冲突

Univer 支持多实例,但每个实例的全局事件和命名空间是共享的。如果你在同一个页面里创建了两个工作簿实例,在第二个实例里写公式时注册的自定义函数,可能会因为命名冲突覆盖第一个实例的配置。

在实际产品里,我只保留一个主 Univer 实例,Agent 的草稿区改用独立的隐藏 DOM 区域挂载同一个实例的隐藏 sheet,而不是创建新实例。这样可以避开命名冲突,也让命令历史栈保持单一。

5.4 用户手动编辑和 Agent 异步写入的并发冲突

前面讲命令系统时说了思路,但实际代码实现还有细节。Univer 的命令是异步派发的,Agent 的一条写命令发出之后,如果用户马上手动改了同一单元格,就可能出现覆盖。

我的经验是:Agent 的写命令必须带上版本号,每次读取时拿到当前 sheet 的 version,写入时带上 version,如果 Univer 发现版本不匹配,就拒绝执行然后让 Agent 重新读取再重试。这套类似乐观锁的机制,虽然增加了一点复杂度,但换来了人机协同的确定性。

6. 边界与后续扩展:Univer 在 Agent 场景里还能做什么

6.1 从表格走向文档与演示文稿

如果你只把 Univer 用在电子表格上,视角就窄了。它的文档引擎内置了 Sheet、Doc、Slide 三种文档类型。也就是说,Agent 不只可以操作表格,还可以生成富文本报告、制作幻灯片。

这带来一个很自然的业务闭环:Agent 读表格 → 做分析 → 生成图文报告 → 再转成 PPT。整个过程在同一套 SDK 里完成,文档之间的数据引用也不需要走文件导入导出。

我当前在做的第二版产品,就是把"数据分析 + 报告生成 + PPT 演示"串成一条 Agent 工作流。实测下来,文档、表格、幻灯片之间互相引用单元格数据,比预想中顺滑很多,因为底层数据模型是一致的。

6.2 把 Univer 变成 Agent 的"可视化工具箱",而不只是表格控件

有一类更前卫的玩法,是把 Univer 当成 AI Agent 的通用可视化层。Agent 不只输出表格,还可以控制图表、数据透视表、甚至内嵌的交互面板。

想象一个数据运营助手,它读取完数据后交给 Univer 渲染成图表,然后直接在表格上叠加一个"洞察浮层",把大模型生成的结论逐条列在相关数据旁边。这种交互在消费者级产品里几乎见不到,但确实是 AI Agent 落地的最好形态——数据、分析、结论、操作,全部在一个容器里闭环。

6.3 最后提醒:SDK 是底座,但产品成败仍在 Agent 体验设计

我见过不少团队把集成 Univer 的任务当成"把表格渲染出来就完了"。实际上,渲染只是一层,体验才是护城河。你需要关注的是:

  • Agent 修改表格之后,用户怎么感知到"这里被 AI 动过了";
  • 用户如何信任 Agent 的修改,如何快速回退;
  • 在 Agent 执行多步操作时,怎么向用户实时同步进度;
  • 当 Agent 和用户同时编辑同一张表时,期待效果是什么。

这些问题,Univer 的命令体系只是给了你地基,具体怎么搭出体验,还是得靠产品与工程自己设计。单论"做 AI 原生办公应用",Univer 目前是我见过最顺手的底座。但我建议大家把它当成一个可编程的文档运行时来用,而不是当成在线表格的替代品。思路一旦换了,能做的事情就宽阔得多。

如果你现在正打算做 AI + 办公方向的工具,我的建议是先跑通一个最小闭环:用 Univer 搭一个可交互表格,接一个大模型,让 Agent 能读、能写、能加公式,然后在这个基础上慢慢加权限、加审批、加多模态。这套路看似朴素,但每一步踩实了,后面做多复杂的功能都不慌。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询