先做了个聊天做 PPT 的 GUI,真正火的是它脚底下那台引擎

发布于 · 2,997 字 · 约 7 分钟#Github 解读#Agent 基建原文链接
先做了个聊天做 PPT 的 GUI,真正火的是它脚底下那台引擎 封面图
  • iOfficeAI 开源 OfficeCLI,简化 Office 文档操作
  • OfficeCLI 提供分层 API,简化 agent 操作文档
  • OfficeCLI 支持自纠闭环,提升 agent 工作效率
  • OfficeCLI 注重零依赖和常驻模式,降低使用成本
  • OfficeCLI 提供多种分发方式,方便集成和使用

你让 Claude 帮你做一份季度汇报的 PPT。

它熟练地抄起 python-pptx,写五十行代码,运行,成功,文件生成。你打开一看,标题溢出屏幕,两个文本框叠在一起,图表配色糊成一团。你把截图喂回去,它道歉,改,再生成,再错。

问题不在模型笨,问题在于它全程盲操。pptx 本质是一包 XML,模型能读 DOM,但读不出「这行字会不会压到下一行」。python-pptx 给了它手,没给它眼睛。

今年 3 月,做桌面应用 AionUi 的团队 iOfficeAI 把自家 GUI 产品底下的文档引擎拆了出来,单独开源成 OfficeCLI。一个 C# 写的单二进制,号称不装 Office、不带运行时依赖,让 agent 直接读、写、渲染 Word、Excel、PowerPoint 三件套。半年时间,30772 个 star,2096 个 fork,版本号已经刷到 v1.0.151。

有意思的就在这个顺序。一家挂着「AI on UI」招牌的 GUI 公司,真正出圈的杀手锏是个命令行工具。

它不是库,是一层翻译

先看它给 agent 的第一份见面礼,一段普通的命令。

officecli add deck.pptx / --type slide --prop title="Q4 Report"
officecli add deck.pptx '/slide[1]' --type shape \
  --prop text="Revenue grew 25%" --prop x=2cm --prop y=5cm
officecli get deck.pptx '/slide[1]/shape[1]' --json

对比 python-pptx 那五十行,这不是语法糖的区别,是两种世界观的区别。python-pptx 是给程序员设计的 API,你要理解 presentation、slide_layout、shape 的对象树,还要懂 EMU 单位换算。OfficeCLI 把这套东西翻译成了 agent 的母语,每个元素有个稳定路径 /slide[1]/shape[2],改什么就去哪,1 起始索引,不用碰 XML 命名空间。

这个翻译是分三层的。L1 是 view,给文档拍语义快照,outline、text、issues 各种视角,agent 侦察用。L2 是 DOM 层,get、set、add、remove、move、swap,按路径精准操作。L3 是 raw 和 raw-set,直接 XPath 改 XML,当 L2 的属性覆盖不到时兜底。设计哲学写在明面上,从只读开始,需要时升级,尽量别掉进原始 XML。

整个工具从入口到引擎的分层长这样。

OfficeCLI 系统架构
OfficeCLI 系统架构

自上而下五层,agent 从 CLI、MCP、SDK 任意一条路进来,都汇进同一套命令层,往下穿过常驻会话和三套格式处理器,最后落到引擎与输出。

你想想看 agent 以前怎么处理报错。库抛一个异常栈,模型硬着头皮猜。这里的报错长这样。

{
  "error": "Slide 50 not found (total: 8)",
  "code": "not_found",
  "suggestion": "Valid Slide index range: 1-8"
}

错了就告诉你合法区间在哪,属性名打错了返回最接近的正确拼写。九种错误码,not_found、invalid_value、unsupported_property,每种都带建议。自愈不是靠模型聪明,是靠工具把纠错信息递到嘴边。

坦白讲,这套设计单拎哪一条都不新鲜,路径寻址像 CSS 选择器,结构化错误像编译器诊断。妙处在组合,一个盲操的 agent 拿到它,第一次拥有了「改一下、看一眼、再改」的工作方式,README 里管这叫 render → look → fix 闭环。

让 Agent 看见自己写的字

闭环的另一半是渲染。这是整个项目最重的活,一个从零写的 HTML 渲染引擎,直接在仓库里吃掉一层目录,src/officecli/Core/Rendering/ 加上图表的 ChartSvgRenderer.cs,形状、趋势线、误差线、瀑布图、公式从 OMML 转 LaTeX 再走 KaTeX、3D 模型走 Three.js,全塞在一个二进制里。

三种消费方式。view html 输出自包含的 HTML 文件,资产全部内联,浏览器直接开。view screenshot 逐页出 PNG,给多模态模型看。watch 起一个本地服务,每条 set 命令落下去浏览器自动刷新,Excel 的 watch 还支持直接在预览里改单元格、拖图表。

串起来就是一条完整的自纠回路。

render → look → fix 闭环
render → look → fix 闭环

盲写、渲染、截图、看图、判定,不合格就带着 suggestion 回改,改完重新渲染,直到能交付。

但这里得停下说一句,零依赖这个宣称是有星号的。

我翻了 src/officecli/Core/HtmlScreenshot.cs,文件头注释写得明明白白,截图是 shell-out 到机器上已有的浏览器,按 playwright CLI、Chrome、Edge、Chromium、Firefox 的顺序找,注释原话是 No embedded browser engine,为了让二进制保持小体积。也就是说 view html 确实零依赖,view screenshot 在一个没装浏览器的裸 Docker 镜像里会静默失败。README 里那句渲染能力内置于二进制、CI 和无显示服务器都能跑,对 HTML 成立,对 PNG 得自己补一个 Chrome。代码里还有个细节,--virtual-time-budget=15000 配 --timeout=20000,前者等 mermaid 这类异步 JS 画完,后者是墙钟兜底,注释标着这是 issue #181 的教训,虚拟时间救不了卡死的资源加载。

一条命令一个进程太贵,于是有了常驻

CLI 给 agent 用的老毛病是进程开销。改一个字段 fork 一次进程,打开几十 MB 的文档,解析,改,序列化,退出,下一条命令再来一遍。

OfficeCLI 的解法是常驻模式,而且做得很激进。SKILL.md 里写了,每条命令第一次访问文件时会自动拉起一个 resident 进程,闲置 60 秒自杀,显式 open 则升级到 12 分钟。命令和常驻进程之间走命名管道,src/officecli/ResidentServer.cs 开头就是 System.IO.Pipes。

这个文件值得单独说,因为我很少在一个 CLI 工具里见到这么重的并发注释。它用两个独立的 CancellationTokenSource 管关闭时序,为的是维持一条不变量,ping 响应就等价于文件还被持有。主循环先停,ping 应答器等 handler 释放完文件才停,保证客户端看到活 ping 时去抢文件必然得到可重试的 busy 而不是脏读。闲置超时以 tick 形式存储做原子读写,因为 TimeSpan 是多字段结构体没法 volatile。还有 dirty 标记,改过的文档闲置 2 到 10 秒自适应刷盘,间隔按实测保存开销缩放。

对使用者的体感就一句话,agent 连续改五十个元素,只有第一次付解析成本。代价是文件可见性变了,README 单独划了个警告框,officecli 自己的读永远看到最新编辑,但 python-docx 或 Word 要读这个文件之前,得先 save 或 close 把管道里的状态刷到磁盘。

省 token 是第一生产力

再往上一层看,这个工具在认真算 agent 的经济学账。

merge 命令做模板填充,agent 花大力气设计好一份布局,之后生产代码拿 JSON 数据填 {{key}} 占位符,一千份报告一千次填充,零 token。它防的是那种「每份报告都让 agent 从头生成」的失败模式,十份产出十种不一致的排版,钱还烧了。

dump 是反向操作,把任何现成的 docx、pptx、xlsx 整份或任意子树序列化成可重放的 batch JSON,batch 再重放出来。用户递给 agent 一份「照着这个感觉做」的样例,agent 读的是结构化规格而不是原始 OOXML,改一改就能复制出一百个变体。学人写的文档,这件事从「读天书」变成了「读图纸」。

Excel 这边还内置了一个公式引擎,FormulaEvaluator.Functions.cs 一个文件 12 万字节,350 多个函数,写入 =SUM(A1:A2) 的瞬间就求值,动态数组、金融函数、回归检验都在内,不用开 Excel 回算。透视表也是原生 OOXML 级别的支持,一条命令从源区域建出来,聚合、日期分组、计算字段直接落盘。

分发即产品

这项目最「AI 时代」的部分,可能不是功能,是分发。

装好二进制跑一句 officecli install,它探测机器上的 Claude Code、Cursor、Windsurf、Copilot,把 skill 文件直接塞进各家配置目录。README 的入门方式更野,让用户往 agent 对话框里粘一行 curl -fsSL https://officecli.ai/SKILL.md,agent 读到内容就自己装好了一切。仓库里还有个 skills/ 目录,装着 morph-ppt 这种带完整风格库的子技能,brutalist、chromatic-aberration 每种风格一个参考 pptx 加说明文档,按需 load_skill 加载。

MCP 的接法也说明了很多。它没有为 MCP 重设计一套工具面,服务器只暴露一个参数,command 字符串,原样透传给 CLI。SKILL.md 里特意强调这一点。协议是壳,CLI 才是本体,一套命令同时服务 shell、SDK、MCP 三条通道。

还有个容易被略过的细节。README 文件末尾埋着两段 HTML 注释,一段 yaml-frontmatter 风格的元数据,一段 LLM/agent discovery metadata,写明 canonical 定位、能力清单、竞品名单、安装命令。人类读者永远看不见这两段,它们是写给爬虫和 agent 看的。给 AI 的 SEO 已经卷到源码注释层了,我一直觉得这是个值得记一笔的信号。

一个人加一个 Claude

轮到泼冷水了。

先看人。贡献者列表第一名 goworm,6017 次提交,第二名 55 次。差了一百多倍,bus factor 等于 1。这个人自我介绍就一句,The Builder Of OfficeCLI。更有意思的是贡献者名单里有个叫 claude 的账号,挂着 14 次提交。一个人带着 AI,两周刷五个版本,半年 151 个 release,这个产能本身是 AI 协作开发的活样本,但反过来看,火车的每一节车厢都拴在同一个人身上。

再看它引以为傲的自愈闭环,validate 自己就有盲区。issue #243 报了一个狠的,remove 掉一张 sheet 后,definedNames 里留下悬空的 localSheetId,文件直接打不开,而 validate 照样通过。类似的还有 #401,create 出来的工作簿缺 xl/styles.xml,Excel 能凑合打开,严格的 OPC 解析器直接报错。也就是说「校验通过」和「文件没坏」之间,目前还不能画等号,交付前最好再用别的工具开一遍。

第三个,渲染保真度还在追赶。#341 记录着 view html 不保留部分绘图、文本和公式属性。结合前面截图依赖外部浏览器那一条,你大概能拼出真实图景,骨架已经很完整,边角还在磨。文档同步也追不上代码,#399 吐槽 wiki 跟二进制不一致,move 和 swap 的帮助有缺口,一周两版的节奏下文档永远在追。

话术层面就更明显了。README 开篇那句 world's first and the best,first 无从考证,best 是典型营销。对比表里 LibreOffice 一列几乎打满叉,只在 Headless HTML/PNG 一格给了个 Partial,其实 LibreOffice headless 转换文档是能干的,只是没有 JSON 输出和路径寻址。看表格的时候记得自己打个折。

带走什么

和同类摆在一起看,位置就清楚了。python-docx、openpyxl、python-pptx 是好库,但它们是 Python API,给程序员的,渲染能力为零。LibreOffice headless 能转换能渲染,但没有结构化输出,agent 解析不了它的 stdout。Pandoc 管格式转换,不管 OOXML 级别的编辑。OfficeCLI 真正吃到的是一块空白,第一个把「Office 文档操作」整体重写成 agent 原语的工具,后面必然会跟上来一批。

如果说这篇文章只带走一个东西,我希望是这条判断。给 agent 造工具,不是给现有工具加个 AI 接口,而是把领域的复杂度翻译成 agent 能自查自纠的原语。这个翻译有五件套,稳定寻址让每次操作有明确的对象,结构化输出让结果可解析,错误带建议让失败可自愈,渲染回看让输出可验证,模板复用让成本可摊薄。OfficeCLI 每一条都踩中了,star 曲线就是答卷。你在自己领域做 agent 工具时,拿这五条挨个对照,缺哪条,哪条就是下一个 OfficeCLI 的机会。

选型上,agent 生成或修改 Office 文档、CI 和容器里无 Office 环境、模板批量填充,这些场景现在就可以上。渲染保真要求极高的场合先观望,交付重要文件前记得跨工具验一遍。还有,别指望一个 bus factor 为 1 的项目给你稳定性承诺,锁版本,慢慢升。

评论互动

© 2026 王若风的技术博客 · Powered by Astro