资讯动态

Univer:为AI Agent打造的办公文档运行时

发布时间:2026/10/27 8:00:13 来源:尧图企业网站定制
1. 当表格、文档、幻灯片变成 Agent 的办公桌第一次看到 Univer 这个项目的时候我的直觉是这不就是个开源版的在线表格吗毕竟市面上做协同表格、在线文档的项目一抓一大把多一个不多。但真正把它的架构文档翻了一遍、又动手跑了一个 demo 之后我意识到自己判断错了方向——Univer 真正想做的事情不是做一个给人用的 Office而是做一个给 AI Agent 用的 Office 运行时。这两个目标的差别比想象中大得多。给人用的 Office核心指标是交互体验单元格好不好点、公式栏响应快不快、协同光标跟不跟手。而给 Agent 用的 Office核心指标变成了另一套东西Agent 能不能用代码精确地读写一个单元格、能不能在无 UI 的环境里跑公式引擎、能不能把一次改表格的操作拆成可回滚的事务、能不能让多个 Agent 同时操作同一份文档而不打架。这就是Agent 办公运行时这个赛道的关键词。它要解决的不是人怎么用表格而是Agent 怎么把表格当成自己的工作内存。我之所以对这个方向感兴趣是因为过去一年里几乎每个做 Agent 的团队都会撞上同一堵墙Agent 能调 API、能写代码、能搜网页但一旦任务涉及处理一份表格生成一份带格式的报告维护一份持续更新的文档就立刻变得笨拙。要么让模型直接吐 Markdown格式全丢要么让模型生成一段 Python 去操作 openpyxl环境依赖重、样式难控、协同无从谈起。中间缺的正是一个专门为 Agent 设计的、结构化的办公文档运行时。Univer 恰好卡在这个位置上。它用 TypeScript 写了一套完整的表格、文档、幻灯片内核把公式引擎、协同、渲染、数据模型全部拆成可独立使用的模块然后通过一套 Facade API 暴露给上层。对 Agent 来说这意味着它不需要看表格而是可以直接操作表格的数据模型。这篇文章我会从几个角度把这件事讲透Univer 到底提供了什么能力、它的架构为什么适合 Agent、怎么把它接进一个 Agent 的工作流、以及我在实际折腾过程中踩到的那些坑。如果你正在做 Agent 应用尤其是那种需要处理结构化文档的 Agent这篇应该能帮你省下不少试错时间。2. Univer 到底给 Agent 提供了什么从 Facade API 说起2.1 为什么 Agent 需要的是 API 而不是 UI先说一个容易被忽略的前提。现在很多让 AI 操作 Office的方案本质上是让模型去模拟人的操作截图识别、点击坐标、模拟键盘输入。这条路在演示里很惊艳但落到生产环境问题一堆——分辨率一变就失灵、操作不可回滚、并发一上来就冲突、每一步都要等渲染。Agent 真正需要的不是能看见表格而是能理解并修改表格的结构。一份表格在数据层面是什么是若干个工作表Worksheet每个工作表里是一张稀疏的单元格矩阵每个单元格有值、公式、样式、格式、批注、数据验证等属性。Agent 要做的操作无非是读某个区域的值、写某个区域的值、插入删除行列、设置公式、应用样式、创建新工作表。这些操作如果都有对应的 APIAgent 就可以用代码精确表达意图而不需要猜界面。Univer 的 Facade API 就是干这个的。它把底层复杂的领域模型包装成一组语义清晰的方法比如拿到一个工作簿、拿到某个工作表、按 A1 记法读写区域、批量设置样式等等。2.2 Facade API 的分层设计Univer 的 API 大致可以分成几层理解这个分层对 Agent 开发很重要层级作用Agent 使用频率工作簿层创建/加载/保存整个工作簿高工作表层增删改工作表、获取范围高范围层按区域批量读写值、公式、样式极高单元格层单点精细操作中事件层监听变更、做响应式处理中对 Agent 来说范围层是主战场。因为 Agent 处理表格时绝大多数操作都是把这一片区域读出来把这一片区域写进去而不是一个格子一个格子地抠。范围层的批量 API 既减少了调用次数也让 Agent 生成的代码更简洁、更不容易出错。举个直观的例子。假设 Agent 要读取 A1 到 D10 的数据用范围 API 就是一次调用拿到一个二维数组如果只能按单元格读那就是 40 次调用。对 Agent 来说调用次数直接关系到 token 消耗和执行时间这个差别是数量级的。2.3 公式引擎Agent 的计算外包Univer 内置了公式引擎这一点对 Agent 特别有价值。为什么因为很多数据处理任务Agent 其实不需要自己算。举个例子Agent 拿到一份销售表要算每个区域的汇总。笨办法是 Agent 把数据读出来自己在代码里循环求和再写回去。聪明办法是 Agent 直接往汇总单元格写一个SUM(B2:B100)公式让 Univer 的公式引擎去算。后者的好处有三点第一Agent 不用把整片数据读进上下文省 token第二计算逻辑留在文档里人打开表格还能看到公式可追溯第三公式引擎是确定性的不会像模型那样算错数。提示让 Agent 优先写公式而不是自己算结果是提升表格类任务准确率的一个实用技巧。模型算算术容易出错但写公式很擅长。2.4 无头运行Agent 不需要浏览器这是 Univer 架构里我认为最关键的一点。Univer 的内核和渲染是分离的。渲染层依赖 Canvas/DOM但数据模型、公式引擎、命令系统这些核心逻辑理论上可以在没有浏览器 UI 的环境里跑。对 Agent 意味着什么意味着你可以在服务端跑一个 Univer 实例Agent 通过 API 操作它处理完再导出成文件。整个过程不需要打开任何界面不需要截图不需要模拟点击。这才是运行时这个词的真正含义——它是一个可以被程序驱动的办公文档引擎而不是一个需要人去点的应用。我在本地试过用 Node 环境加载 Univer 的核心包配合一个内存中的工作簿实例跑通创建表格 → 写入数据 → 设置公式 → 读取计算结果这条链路。整个过程没有任何 UI 参与纯数据操作速度非常快。3. 把 Univer 接进 Agent 工作流的三种姿势3.1 姿势一把 Univer 当成 Agent 的工具Tool最直接的接法是把 Univer 的操作封装成 Agent 可以调用的工具。比如定义这么几个工具read_range(sheet, range)读取指定区域的值write_range(sheet, range, values)写入二维数组set_formula(sheet, cell, formula)设置公式apply_style(sheet, range, style)应用样式create_sheet(name)新建工作表Agent 在推理时根据需要调用这些工具Univer 实例在后台维护文档状态。这种模式的好处是可控每个工具的参数都是结构化的Agent 不容易乱来而且每次操作都可以做校验和日志。这种模式适合任务边界比较清晰的场景比如把这份 CSV 整理成带汇总的报表。Agent 的每一步操作都能映射到一个明确的工具调用。3.2 姿势二让 Agent 直接生成 Univer 操作代码第二种接法更激进给 Agent 一份 Univer Facade API 的说明让它直接生成操作代码然后在沙箱里执行。这种模式灵活度最高Agent 可以组合出任意复杂的操作序列。但它的风险也明显Agent 可能生成错误的 API 调用、可能写出死循环、可能误删数据。所以这种模式必须配沙箱和权限控制。我一般会做几件事限制可用的 API 白名单、给执行加超时、操作前先做一次 dry-run 校验、关键操作要求二次确认。这种模式适合探索性任务比如帮我把这份表格里所有异常值标红并生成一份说明。任务路径不固定让 Agent 自由发挥更合适。3.3 姿势三Univer 作为多 Agent 的共享工作区第三种接法是我觉得最有想象空间的多个 Agent 共享同一个 Univer 文档实例把它当成协作的白板。比如一个数据分析任务可以拆成几个角色一个 Agent 负责数据清洗一个负责计算一个负责生成图表数据一个负责写结论。它们都操作同一份 Univer 文档通过文档的状态来传递中间结果。因为 Univer 本身支持协同有 OT/CRDT 那套东西多 Agent 并发操作在底层是有保障的。这种模式把 Univer 从工具升级成了环境。Agent 之间不再需要通过消息传递大量数据而是通过共享文档来协作这在大规模任务里能显著降低通信开销。接入姿势灵活度可控性适用场景工具封装低高边界清晰的结构化任务代码生成高低探索性、路径不固定的任务共享工作区中中多 Agent 协作的复杂任务3.4 三种姿势怎么选我的经验是先用工具封装跑通主流程再按需放开到代码生成。一上来就让 Agent 自由生成代码调试成本会高到让你怀疑人生。工具封装虽然笨但每一步都可观测、可回放出问题好定位。等主流程稳定了再针对那些确实需要灵活性的环节局部放开代码生成能力。至于共享工作区模式建议等单 Agent 流程完全跑顺之后再考虑。多 Agent 协作本身就会引入协调复杂度如果底层文档操作还不稳定两个问题叠在一起会非常难排查。4. 实操从零搭一个能读写表格的 Agent4.1 环境准备与依赖选择先说环境。Univer 是 TypeScript 项目核心包通过 npm 分发。做 Agent 集成我建议用 Node 环境而不是浏览器环境原因前面说过——Agent 不需要 UI。需要装的核心包大致是这几类Univer 的核心包提供数据模型和命令系统、公式引擎包如果需要公式能力、以及对应的预设包把常用能力打包好。具体包名会随版本变化装之前建议看一眼官方文档的当前版本说明。注意Univer 的包拆分比较细不同版本之间包名和 API 可能有调整。我踩过的坑是照着半年前的教程装包结果 API 对不上白折腾半天。养成先确认版本的习惯。4.2 创建一个无头工作簿实例核心思路是不挂载任何渲染层只初始化数据模型和命令系统。伪代码大概长这样import { createUniver } from univerjs/presets; const univer createUniver({ // 不传渲染相关的配置 // 只保留核心能力 }); const workbook univer.createUniverSheet({ // 初始数据 });关键点是不要引入渲染相关的插件。Univer 的插件化设计让你可以只挑需要的部分加载这在服务端环境里能省掉大量浏览器 API 的依赖。4.3 用 Facade API 做一次完整的读写拿到工作簿实例之后操作就顺了。假设我们要往第一个工作表写一批数据再设一个汇总公式const sheet workbook.getActiveSheet(); // 写入表头和数据 sheet.getRange(A1:C1).setValues([[区域, 销售额, 成本]]); sheet.getRange(A2:C5).setValues([ [华东, 12000, 8000], [华南, 9500, 6200], [华北, 11000, 7300], [西南, 7800, 5100], ]); // 用公式算汇总而不是自己算 sheet.getRange(B6).setFormula(SUM(B2:B5)); sheet.getRange(C6).setFormula(SUM(C2:C5));注意最后两行——我让 Univer 的公式引擎去算汇总而不是在代码里reduce。这就是前面说的计算外包。Agent 生成这段代码时只需要知道范围不需要知道具体数值出错概率大大降低。4.4 把操作封装成 Agent 工具有了上面的基础封装工具就是体力活了。以读取范围为例const tools { read_range: { description: 读取指定工作表的指定区域返回二维数组, parameters: { sheetName: string, range: string, // A1 记法如 A1:C10 }, execute: async ({ sheetName, range }) { const sheet workbook.getSheetByName(sheetName); return sheet.getRange(range).getValues(); }, }, // ... 其他工具 };这里有个细节值得说工具的 description 要写得足够清楚尤其是参数格式。Agent 判断该调哪个工具、怎么填参数全靠这段描述。我见过太多人把 description 写得含糊结果 Agent 老是调错工具或者传错参数然后怪模型笨。其实问题出在工具定义上。4.5 一次真实的任务链路把上面这些串起来一个完整的任务链路是这样的用户说帮我把这份销售数据整理一下加上区域汇总Agent 调用read_range读取原始数据Agent 判断需要新建一个整理后的工作表调用create_sheetAgent 调用write_range写入清洗后的数据Agent 调用set_formula写入汇总公式Agent 调用apply_style给表头加粗完成后导出文件整条链路里Agent 做的都是结构化的工具调用没有一步依赖 UI。这就是办公运行时的价值——它把办公文档的操作变成了 Agent 可以精确编排的原子动作。5. 踩坑记录那些文档里不会写的细节5.1 范围记法的边界问题第一个坑是范围记法。A1 记法看起来简单但边界情况不少。比如A1:A1和A1是不是一回事跨工作表的范围怎么写整列引用A:A在 API 里支不支持我的经验是在工具层做一次规范化。不管 Agent 传进来什么格式先统一转成标准的起始:结束形式再做校验。这样即使 Agent 偶尔传了不规范的范围也能被兜住而不是直接抛异常。5.2 公式计算的时机第二个坑是公式的计算时机。你写了一个公式不代表它立刻就算好了。Univer 的公式引擎有自己的计算调度可能是异步的、可能是懒计算的。如果你写完公式马上读结果很可能读到的是空值或者旧值。解决办法是监听计算完成事件或者在读取前主动触发一次计算。我在工具层加了一个waitForCalculation的封装写完公式后等计算完成再返回这样 Agent 拿到的结果才是准的。5.3 并发写入的冲突第三个坑是并发。如果多个 Agent 同时操作同一份文档或者一个 Agent 的多个工具调用并行执行就可能出现写冲突。比如两个操作同时改同一个单元格后写的覆盖先写的。Univer 本身有协同机制但那套机制是为多人实时编辑设计的用在 Agent 场景下需要额外注意。我的做法是在 Agent 这一层做串行化同一份文档的写操作排队执行。虽然牺牲了一点并发度但换来的是确定性值。5.4 大表格的内存与性能第四个坑是规模。小表格怎么玩都行一旦数据量上去问题就来了。把几万行数据一次性读进 Agent 的上下文token 直接爆炸一次性写入大量数据也可能触发性能问题。我的处理策略是分页 摘要。读取时按需分块不要一次全读写入时批量提交但每批控制在一定规模。另外对于 Agent 只需要知道大概的场景可以先读一个采样或者统计摘要而不是全量数据。坑点表现处理方式范围记法格式不统一导致报错工具层规范化 校验公式时机读到空值/旧值监听计算完成事件并发写入数据被覆盖Agent 层串行化大表格token 爆炸、性能下降分页读取 摘要5.5 错误信息的可读性最后一个坑也是我觉得最容易被忽视的错误信息要写给 Agent 看不是写给人看。传统的错误处理抛一个异常、打一行日志就完事了。但在 Agent 场景下错误信息是 Agent 自我修正的重要输入。如果错误信息是TypeError: Cannot read property x of undefinedAgent 根本不知道该怎么办。但如果错误信息是范围 A1:C10 超出了工作表边界当前工作表只有 5 行 3 列Agent 就能自己调整范围重试。所以我在工具层做了一层错误包装把底层异常翻译成 Agent 能理解的、带上下文和修复建议的信息。这个投入回报比非常高能显著减少 Agent 的无效重试。6. 为什么是 Univer而不是别的方案6.1 和让模型直接吐 Markdown比最简单的方案是让模型直接输出 Markdown 表格。这个方案上手最快但天花板也最低格式信息全丢、公式没法表达、大数据量下模型容易漏行、没法做增量修改。它适合一次性生成一份简单文档不适合持续维护一份结构化文档。Univer 的优势在于文档是有状态的。Agent 可以读一部分、改一部分、再读回来验证这种交互式的能力是 Markdown 方案给不了的。6.2 和生成 Python 操作 openpyxl比另一个常见方案是让 Agent 生成 Python 代码去操作 Excel 文件。这个方案能力很强但有几个硬伤环境依赖重要装 Python 和一堆库、样式控制繁琐、协同无从谈起、每次操作都要读写整个文件。Univer 是纯 TypeScript 的和 Agent 应用的技术栈天然一致不需要跨语言调用。而且它的数据模型是常驻内存的操作是增量的不需要每次读写整个文件。6.3 和用现成的在线表格 SaaS比还有人是接一个在线表格服务的 API。这个方案省事但受制于第三方API 能力有限、数据在别人那里、定制困难、成本随用量上涨。Univer 是开源的、可自部署的你可以完全掌控数据模型和操作能力。对 Agent 应用来说这种可控性很重要因为 Agent 的操作模式往往需要深度定制。6.4 选型的关键判断说到底选不选 Univer取决于你的 Agent 是不是需要持续、结构化地操作办公文档。如果只是偶尔生成一份简单文档Markdown 就够了。如果任务涉及复杂的表格计算、格式控制、多轮修改、多 Agent 协作那 Univer 这类运行时方案的价值就体现出来了。我的判断标准很简单如果这个任务人用 Excel 会怎么做如果人的操作是打开、看、改几个格子、存那 Agent 也需要一个能打开、看、改、存的运行时。Univer 就是这个运行时。7. 我对这条赛道的一点观察折腾 Univer 这段时间我越来越觉得Agent 办公运行时这个定位抓得很准。过去大家做 Agent注意力都在模型和编排上很少有人认真想过Agent 处理结构化文档时到底需要一个什么样的底层设施答案不是更好的模型而是更合适的运行时。模型再强让它去数一个一万行的表格也会出错但如果有一个运行时能帮它精确地读写、计算、校验模型只需要做它擅长的判断和决策整体效果就上来了。Univer 把表格、文档、幻灯片统一到一套数据模型和 API 之下这个抽象层次选得挺好。对 Agent 来说它不需要分别学三套操作方式而是用一套 Facade API 就能覆盖三种文档类型。这种一致性在构建通用 Agent 能力时能省很多事。当然这条路还很长。无头运行的成熟度、公式引擎在服务端的稳定性、多 Agent 协同的语义、大文档的性能这些都还有打磨空间。但方向是对的而且开源意味着这些问题会被社区一起解决。如果你也在做 Agent 应用尤其是那种需要处理表格和文档的我建议花点时间研究一下 Univer 的架构。哪怕最后不用它理解办公文档运行时这个抽象对你设计 Agent 的工具层也会很有启发。我自己最大的收获就是从让 Agent 操作界面的思路彻底转向了让 Agent 操作数据模型——这个转变让很多原本棘手的问题一下子变得简单了。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑