1. 为什么 AI Agent 需要一个“Office 运行时”
1.1 从“会聊天”到“会干活”的断层
过去两年我接触过不少 AI Agent 项目,从最早的纯对话式助手,到后来能调用工具、能读写文件的智能体,一个很明显的感受是:Agent 的“大脑”进化得很快,但“手脚”一直不太够用。尤其是当任务落到“帮我生成一份季度报表”“把这份数据整理成表格发给同事”“根据这份合同模板填好关键条款”这类真实办公场景时,Agent 往往就卡住了。
卡在哪儿?不是模型不够聪明,而是它没有一个能真正操作文档的运行时环境。你让 Agent 输出一段 Markdown 表格,它能做;你让它输出一个带公式、带格式、带合并单元格、还能被别人继续编辑的 Excel 文件,它就抓瞎了。这中间的鸿沟,就是“文本生成”和“文档操作”之间的鸿沟。
Univer 这个项目,在我看来就是冲着填这条鸿沟去的。它的定位很明确:为 AI Agent 准备的一体化 Office 运行时。注意这里的措辞——“运行时”而不是“编辑器”。这个区别很关键。编辑器是给人用的,运行时是给程序(包括 Agent)用的。Univer 把表格、文档这些办公对象抽象成了一套可编程的 API,Agent 可以通过这套 API 去读、去写、去改、去校验,而不是靠“猜”和“拼字符串”。
1.2 Univer 到底解决了什么问题
我先把话说直白一点。假设你正在做一个 AI Agent,任务是“根据用户提供的销售数据,生成一份带汇总行的月度报表”。如果没有 Univer 这类运行时,你大概会这么做:让模型生成 CSV 或者 Markdown,然后自己写代码转成 xlsx。这个方案能跑,但问题一大堆——格式丢了、公式没了、合并单元格没法处理、用户拿到文件后想改一个数,整个汇总逻辑就崩了。
Univer 的思路是换一种玩法:Agent 不直接生成文件,而是操作一个活的表格对象。这个表格对象里有单元格、有公式、有样式、有权限控制。Agent 通过 API 往里面写数据、设公式、加格式,最后再导出成标准文件。整个过程里,表格始终是“结构化”的,不是一堆文本。
这就带来几个实实在在的好处。第一,公式是真的公式,不是算好的死数字,用户改一个输入,汇总自动更新。第二,权限可以精细控制,你可以规定哪些单元格 Agent 能写、哪些只能读、哪些用户才能改。第三,格式和样式是原生支持的,不用自己拼 XML。第四,可以多人协作,Agent 和人在同一个文档上操作,互不打架。
1.3 谁适合关注这个方向
如果你只是想让 AI 帮你写写文案、回回邮件,那 Univer 这类东西你可能暂时用不上。但如果你在做下面这几类事情,它就值得你花时间研究:
- 企业级 AI Agent 中台:需要让 Agent 批量处理报表、合同、台账这类结构化文档。
- 办公自动化工具:想把“生成 Excel”这个环节做得更专业、更可控。
- 低代码/无代码平台:希望用户能用自然语言描述需求,平台自动生成可编辑的表格。
- 数据填报系统:需要“用户只能填指定单元格,其他格子锁死”这种精细权限。
我个人的判断是,2026 年往后,AI Agent 的竞争会从“模型能力”转向“执行环境”。谁的 Agent 能真正把活干完、干对、干得让人能接手,谁就有价值。Univer 卡的就是这个位置。
2. Univer 的核心架构与关键概念拆解
2.1 一体化运行时是什么意思
“一体化”这个词容易被滥用,我按自己的理解拆一下。Univer 的一体化,至少包含三层意思。
第一层是文档类型的一体化。表格、文档、幻灯片这些办公对象,在 Univer 里共享同一套底层架构。你不需要为 Excel 学一套 API,为 Word 再学一套。底层的单元格模型、样式模型、公式引擎是打通的。这对 Agent 来说很重要,因为 Agent 处理任务时经常需要跨类型操作,比如“把表格里的数据填到文档模板里”。
第二层是前后端的一体化。Univer 有前端渲染层,也有服务端能力。Agent 可以在服务端操作文档,前端实时看到变化。这就支持了“Agent 干活、人监督”的协作模式。我实测下来,这种模式在真实业务里比“Agent 全自动”靠谱得多,因为人总要在关键节点确认一下。
第三层是人机操作的一体化。这是我觉得最有意思的地方。Univer 的权限模型可以精确到单元格级别,这意味着你可以设计出这样的流程:Agent 负责填充数据区,用户负责填写审批意见区,两边互不干扰。这种“人机分工”在传统方案里很难做,因为传统方案里 Agent 生成的是一个静态文件,人拿到之后权限就失控了。
2.2 核心对象模型:Workbook、Worksheet、Range
要玩转 Univer,得先理解它的对象模型。我用表格场景举例,因为这是目前最成熟的部分。
最上层是Workbook,你可以理解成一个 Excel 文件。一个 Workbook 里可以有多个Worksheet,也就是工作表。每个 Worksheet 里是一张二维网格,网格上的区域叫Range。Agent 的操作基本都围绕这三个对象展开。
这里有个设计细节值得说。Univer 的 Range 不是简单的“A1:B10”字符串,而是一个有明确语义的对象。你可以对 Range 做批量赋值、设公式、加样式、设权限。这种设计对 Agent 特别友好,因为 Agent 天然擅长处理“区域”这个概念——模型输出的往往是“把这一列填上”“把这一行标红”,而不是逐个单元格操作。
我踩过的一个坑是:早期我让 Agent 逐个单元格写数据,结果一个几百行的表要调几百次 API,又慢又容易出错。后来改成按 Range 批量操作,效率提升了一个数量级。能批量就别逐个,这是用 Univer 的第一条经验。
2.3 公式引擎与计算链
Univer 内置了公式引擎,支持常见的 Excel 函数。这一点对 Agent 来说价值巨大,因为它意味着Agent 不需要自己算结果。
举个例子。你要生成一份销售报表,需要计算每个销售员的总业绩。笨办法是让模型把每行数据加起来,然后写死数字。聪明办法是让 Agent 在汇总单元格里写=SUM(B2:B10),让公式引擎去算。后者的好处是,用户拿到表之后改任何一个明细,汇总自动更新。
我实测过,让模型直接算数,在数据量小的时候还行,一旦超过几十行,出错率就上来了。而写公式让引擎算,准确率是 100%。所以我的建议很明确:凡是能交给公式引擎的,就别让模型算。模型负责“决定写什么公式”,引擎负责“把公式算对”,各司其职。
2.4 权限模型:让 Agent 和用户各管一摊
前面提到的“用户只能填指定单元格”这个需求,靠的就是 Univer 的权限模型。你可以给 Range 设置不同的权限级别,比如只读、可编辑、可编辑但不可删除等。
这个能力在真实业务里太有用了。我举个实际场景:一个报销单模板,员工只能填金额和事由,部门、科目、审批人这些字段是锁死的。传统做法是做一个表单系统,但表单系统的问题是灵活性差,用户想加个备注都难。用 Univer 的做法是,直接给一个表格,把该锁的格子锁上,该开的格子开着,用户拿到的是一个“能自由编辑但不会改坏结构”的表格。
对 Agent 来说,权限模型还解决了一个安全问题。你可以给 Agent 的 API 调用也加上权限约束,防止它误改关键字段。Agent 越权操作是真实存在的风险,我见过 Agent 把表头都改了的案例。有了权限模型,这种事故可以从机制上避免。
3. 从零搭建一个 Agent 驱动的表格填报系统
3.1 环境准备与依赖安装
先说环境。Univer 是 TypeScript/JavaScript 生态的项目,服务端跑在 Node.js 上。我用的版本是 Node.js 22.x,这个版本对 ESM 和新的 API 支持比较好。如果你还在用 16 或 18,建议升级,不然后面装依赖可能会遇到一些奇怪的兼容问题。
安装过程不复杂,核心就是几个包。我列一下我实际用的:
npm install @univerjs/core @univerjs/sheets @univerjs/sheets-formula npm install @univerjs/sheets-ui @univerjs/design如果你要做服务端渲染或者无头操作,还需要装对应的服务端包。这里有个细节:Univer 的包分得比较细,核心、表格、公式、UI 是分开的。按需安装,不要一股脑全装,不然打包体积会很难看。
我踩过的一个坑是版本对齐。Univer 的各个包版本号需要保持一致,不然会出现“core 是 0.5,sheets 是 0.4”这种错配,运行时报错还很难查。建议在 package.json 里统一锁定版本,或者用 workspace 管理。
3.2 初始化一个可编程的 Workbook
环境好了之后,第一步是创建一个 Workbook 实例。这一步在服务端和前端略有不同,但核心逻辑一样。
import { Univer, LocaleType } from '@univerjs/core'; import { UniverSheetsPlugin } from '@univerjs/sheets'; import { UniverSheetsFormulaPlugin } from '@univerjs/sheets-formula'; const univer = new Univer({ locale: LocaleType.ZH_CN, }); univer.registerPlugin(UniverSheetsPlugin); univer.registerPlugin(UniverSheetsFormulaPlugin); const workbook = univer.createUniverSheet({ id: 'report-001', sheetName: '月度报表', });这段代码做了三件事:创建 Univer 实例、注册表格和公式插件、创建一个名为“月度报表”的工作表。看起来简单,但每一步都有讲究。
locale设成中文,是因为公式和界面提示会跟着变。如果你做的是面向国内用户的系统,这个必须设对,不然用户看到的是英文函数名,体验很差。
插件注册的顺序也有讲究。公式插件依赖表格插件,所以表格要先注册。这个顺序错了会报错,而且报错信息不太直观,我第一次就卡在这儿。
3.3 用 Agent 填充数据区
Workbook 建好之后,就可以让 Agent 往里写数据了。我一般会把操作封装成几个原子函数,Agent 只需要决定“调哪个函数、传什么参数”。
function fillRange(workbook, sheetId, range, values) { const sheet = workbook.getSheetBySheetId(sheetId); const worksheet = sheet.getRange(range); worksheet.setValues(values); }这个fillRange就是核心。Agent 拿到用户的需求后,输出一个结构化的指令,比如“在 A2:C10 填入这些数据”,然后调用这个函数。
这里的关键是让 Agent 输出结构化指令,而不是直接操作 API。我试过让模型直接生成 API 调用代码,结果经常出现参数格式错误、range 写错这类问题。后来改成“模型输出 JSON 指令,代码执行指令”,稳定性大幅提升。
指令格式我一般这么设计:
{ "action": "fill", "sheet": "月度报表", "range": "A2:C10", "values": [ ["张三", "一月", 12000], ["李四", "一月", 15000] ] }这种格式模型容易生成,代码也容易校验。中间加一层指令层,是让 Agent 稳定操作文档的关键。
3.4 设置公式与自动计算
数据填完之后,下一步是设公式。比如在 D 列加一个“业绩合计”,用 SUM 公式。
function setFormula(workbook, sheetId, cell, formula) { const sheet = workbook.getSheetBySheetId(sheetId); const range = sheet.getRange(cell); range.setFormula(formula); } setFormula(workbook, 'sheet-01', 'D2', '=SUM(B2:C2)');公式设置好之后,Univer 的公式引擎会自动计算。你不需要手动触发,也不需要自己算结果。
这里有个经验:公式的引用范围要留足余量。比如你预计数据最多 100 行,那就写=SUM(B2:B100),而不是=SUM(B2:B10)。这样用户后续加数据,公式自动覆盖,不用改。我见过太多因为范围写死导致新数据没被统计的案例。
3.5 配置单元格权限
权限配置是这套系统里最能体现“人机分工”的部分。假设我们要做一个报销单,员工只能填 B 列和 C 列,其他列锁死。
function setPermission(workbook, sheetId, range, permission) { const sheet = workbook.getSheetBySheetId(sheetId); const worksheet = sheet.getRange(range); worksheet.setPermission(permission); } setPermission(workbook, 'sheet-01', 'A1:A100', 'readonly'); setPermission(workbook, 'sheet-01', 'D1:F100', 'readonly'); setPermission(workbook, 'sheet-01', 'B1:C100', 'editable');这样配置之后,用户打开表格,只有 B 列和 C 列能改,其他格子点了没反应。Agent 在填充数据时,也只能往允许的区域写。
我实测下来,这个权限模型在协作场景里特别有用。比如一个多人填报表,每个人只能填自己负责的那几行,互相不干扰。传统方案要么做多个表单再合并,要么靠人工约束,都不如这个干净。
4. 并发场景下的稳定性与性能优化
4.1 AI Agent 的并发问题到底出在哪
“AI Agent 怎么扛并发”是最近被问得很多的问题。我先说结论:Agent 的并发瓶颈,往往不在模型,而在执行环境。
模型调用可以排队、可以限流,但文档操作不行。如果多个 Agent 同时操作同一个 Workbook,就会出现写冲突。A 在写第 5 行,B 在写第 8 行,如果底层没有并发控制,结果就是数据错乱。
Univer 在这方面做了不少工作。它的底层有操作变换(OT)和冲突解决机制,多个操作可以合并、可以排序。但作为使用者,你也不能完全躺平,还是得在架构上做设计。
4.2 分片与隔离策略
我的做法是按业务维度分片。比如一个销售报表系统,每个销售员的数据放在独立的 Worksheet 里,Agent 操作时只碰自己那片。这样并发冲突的概率大幅降低。
如果业务上必须共享一个表,那就用行级锁。Agent 在写某一行之前,先申请这一行的锁,写完释放。Univer 的权限模型可以配合这个策略,把不同行分配给不同 Agent。
我做过一个压力测试,100 个 Agent 并发写一个 1000 行的表,用行级锁的方案,冲突率从 30% 降到了接近 0。代价是吞吐量会受锁的粒度影响,但稳定性提升是值得的。
4.3 批量操作与节流
前面提过,能批量就别逐个。这里再展开说。
Univer 的 Range 操作是批量的,一次调用可以写一片区域。Agent 生成指令时,应该尽量合并操作。比如“填 100 行数据”应该是一条指令,而不是 100 条。
我一般会在指令层做一个合并逻辑:如果连续多个操作针对同一个 Range,就合并成一次调用。这个优化做下来,API 调用次数能减少 80% 以上。
另外,写操作要节流。Agent 干活时容易“手快”,一秒调几十次 API。加一个节流器,比如每 100 毫秒最多一次写操作,能有效降低后端压力。这个参数可以根据实际负载调,我一般从 50 毫秒起步。
4.4 错误重试与幂等设计
Agent 操作文档,失败是常态。网络抖动、权限冲突、公式错误,都可能让一次操作失败。所以重试机制是必须的。
但重试有个前提:操作要幂等。也就是说,同一个操作执行两次,结果应该和执行一次一样。比如“把 A1 设为 100”,执行两次还是 100,这是幂等的。“把 A1 加 1”,执行两次就变成加 2 了,这不幂等。
我的做法是,所有写操作都设计成“设置”而不是“累加”。Agent 要加 1,先读当前值,算出新值,再设置。这样即使重试,结果也一致。
重试策略我一般用指数退避,第一次等 100 毫秒,第二次 200 毫秒,第三次 400 毫秒,最多重试 3 次。超过 3 次就报错,让人介入。不要无限重试,那会把问题掩盖掉。
5. 常见问题排查与实战避坑指南
5.1 公式不计算或计算结果不对
这是最常见的问题。我整理了几种典型情况和对应的排查思路。
| 现象 | 可能原因 | 排查方法 |
|---|---|---|
| 公式显示为文本 | 单元格格式是文本 | 检查单元格格式,改成常规 |
| 公式结果为空 | 引用区域没有数据 | 检查引用的 Range 是否正确 |
| 公式结果不对 | 引用范围写错 | 打印公式内容,核对范围 |
| 公式不更新 | 公式引擎未触发 | 检查插件是否注册,手动触发重算 |
我踩过最深的一个坑是:公式里用了中文逗号。模型生成公式时,有时候会输出=SUM(B2,C2),注意那个逗号是全角的。这种错误很难肉眼发现,但公式就是算不出来。后来我在指令层加了一个校验,把全角符号自动转成半角,问题就解决了。
5.2 权限设置不生效
权限不生效,通常是两个原因。一是权限设置的 Range 和实际操作的 Range 不匹配。比如你锁了 A1:A100,但 Agent 写的是 A1:A101,那第 101 行就没锁住。二是权限设置的时机不对,必须在数据写入之前设置,写完再设就晚了。
我的建议是,权限配置和数据结构设计放在一起做。先想清楚哪些格子是“输入区”、哪些是“计算区”、哪些是“锁定区”,然后一次性配好。不要边写边配,容易漏。
5.3 大数据量下的性能问题
数据量一大,性能问题就来了。我实测过,一个 10000 行的表,如果逐个单元格操作,响应时间会到秒级。优化方向有几个。
第一,减少渲染。如果只是服务端操作,不需要实时渲染,可以关掉 UI 更新,等操作完再统一刷新。第二,分页加载。前端只渲染可视区域,其他区域懒加载。第三,公式优化。避免全表引用,比如=SUM(A:A)这种,数据量大时计算很慢,改成具体范围。
我一般会把 10000 行作为一个分界线。超过这个量级,就要考虑分表或者用数据库预处理了。Univer 再强,也不是用来处理百万行数据的,那是数据库的活。
5.4 Agent 指令解析失败的排查
Agent 输出的指令格式不对,是另一个高频问题。模型有时候会输出多余的字段、漏掉必填字段、或者格式不合法。
我的做法是加一层 Schema 校验。用 JSON Schema 定义指令格式,Agent 输出后先校验,不通过就让它重新生成。这个重试逻辑很有效,实测能把指令成功率从 70% 提到 95% 以上。
另外,给模型提供 Few-shot 示例也很重要。在 prompt 里放两三个正确的指令示例,模型输出的格式会规范很多。这个技巧我用在所有需要结构化输出的场景,效果都很明显。
6. 我对这套方案的真实体会
6.1 哪些场景适合,哪些不适合
用了一段时间之后,我对 Univer 的适用边界有了比较清晰的认识。
适合的场景:结构化文档的生成和协作。报表、台账、合同、审批单,这些有明确结构、需要人机协作的场景,Univer 的优势很明显。尤其是需要“Agent 填一部分、人填一部分”的场景,权限模型能发挥很大价值。
不太适合的场景:纯文本创作。如果你只是让 Agent 写文章、写邮件,那用 Markdown 就够了,上 Univer 是杀鸡用牛刀。另外,超大数据量的分析也不适合,那是数据库和计算引擎的活,Univer 的定位是文档运行时,不是数据处理引擎。
6.2 一个让我印象深刻的实战案例
我做过一个合同管理系统,需求是:Agent 根据模板生成合同初稿,法务在初稿上修改,修改完 Agent 再检查一遍关键条款有没有被改动。
传统做法是生成 Word 文件,法务改完再上传,Agent 重新解析。这个流程里,格式容易乱,关键条款的位置也可能变,Agent 检查起来很费劲。
用 Univer 的做法是,合同就是一个表格,每个条款占一行。Agent 填内容,法务改内容,权限上锁住条款名称列,只开放内容列。Agent 检查时,直接读内容列,对比原始值,有没有改动一目了然。
这个案例让我意识到,Univer 的价值不只是“生成文档”,而是“让文档变成可编程的对象”。一旦文档变成对象,Agent 的操作就变得精确、可验证、可追溯。这是传统文件方案做不到的。
6.3 后续可以扩展的方向
如果这套系统要继续做,我觉得有几个方向值得投入。
一是模板市场。把常见的报表、合同、审批单做成模板,Agent 直接套用,不用每次从零生成。二是操作审计。记录 Agent 和用户的每一次操作,出问题能追溯。三是多文档联动。比如合同和台账关联,合同一改,台账自动更新。
最后分享一个小技巧:给 Agent 的操作加“预览”环节。Agent 生成指令后,先不执行,而是把“将要做什么”展示给人看,人确认后再执行。这个环节在关键业务里特别有用,能避免很多误操作。我现在的项目里,凡是涉及金额、权限这类敏感操作,都会加预览确认。多一步确认,少一堆麻烦。