15 KiB
OfficeCLI 技术方案分析
调研时间:2026 年 5 月 | 作者:沙洲工作室
基于源码阅读(v1.0.72),非黑盒测评
基本信息
| 项目 | 信息 |
|---|---|
| 仓库 | iOfficeAI/OfficeCLI |
| 语言 | C#(.NET 10) |
| 许可证 | Apache 2.0 |
| 代码量 | ~285 个源文件,约 137,800 行 C# |
| 外部依赖 | 仅 3 个 NuGet 包 |
| 支持格式 | Word (.docx)、Excel (.xlsx)、PowerPoint (.pptx) |
一、整体架构
分层结构
┌─────────────────────────────────────────────────────────┐
│ AI Agent / 用户终端 │
├────────────┬──────────────┬─────────────────────────────┤
│ CLI 命令 │ MCP Server │ Resident 管道(Named Pipe) │
│ (System. │ (JSON-RPC │ (常驻进程,内存持有文档, │
│ CommandLine│ over stdio) │ 近零延迟响应) │
│ 路由) │ │ │
├────────────┴──────────────┴─────────────────────────────┤
│ CommandBuilder │
│ (partial class,按功能拆分十余个文件) │
│ View / Set / Add / Get / Dump / Raw / Batch / │
│ Watch / Mark / Help / Import / Refresh / Check │
├─────────────────────────────────────────────────────────┤
│ DocumentHandlerFactory │
│ (按扩展名分发到对应 Handler) │
├──────────┬───────────────┬──────────────────────────────┤
│ WordHandler │ ExcelHandler │ PowerPointHandler │
│ (~25 partial│ (~20 partial │ (~30 partial files) │
│ files) │ files) │ │
│ 持有 │ 持有 │ 持有 │
│ Wordprocessing│Spreadsheet │ Presentation │
│ Document │ Document │ Document │
├──────────┴───────────────┴──────────────────────────────┤
│ Core 模块 │
│ ┌──────────┬──────────┬──────────┬──────────────────┐ │
│ │ Formula/ │ Chart/ │ Watch/ │ PivotTableHelper │ │
│ │ 公式解析 │ SVG渲染 │ 实时预览 │ 透视表引擎 │ │
│ │ + 求值 │ + ChartEx│ + SSE │ │ │
│ ├──────────┼──────────┼──────────┼──────────────────┤ │
│ │ ThemeColor│ FontMetrics│ Units │ HtmlPreview │ │
│ │ 主题色解析│ 字体度量 │ 单位转换│ HTML 预览 │ │
│ └──────────┴──────────┴──────────┴──────────────────┘ │
├─────────────────────────────────────────────────────────┤
│ DocumentFormat.OpenXML SDK 3.4.1 │
│ (微软开源 OpenXML SDK) │
└─────────────────────────────────────────────────────────┘
模块关系
入口层:Program.cs 是 top-level statements 入口。在进入 System.CommandLine 之前,先拦截处理一批"快捷命令"——mcp、install、skills、load_skill、config 等,这些不走标准 CLI 路由。
命令路由层:CommandBuilder 是一个 partial class,拆分到十几个文件(CommandBuilder.View.cs、CommandBuilder.Set.cs、CommandBuilder.Add.cs 等),通过 BuildRootCommand() 注册所有子命令。注册的命令包括:open/close、view、get、query、set、add、remove、move、swap、raw、rawSet、addPart、validate、batch、dump、import、create、merge、watch/unwatch、mark/unmark、goto、help 等。
Handler 层:DocumentHandlerFactory.Open() 根据文件扩展名分发到三个 Handler。每个 Handler 持有对应的 OpenXML Document 对象,用 partial class 按功能拆分为大量文件:
| Handler | partial 文件数 | 覆盖功能 |
|---|---|---|
| WordHandler | ~25 | View/Set/Add/Query/Navigation/HtmlPreview/FormFields/StyleList/I18n/ImageHelpers/Selector |
| ExcelHandler | ~20 | View/Set/Add/Query/Import/Slicer/HtmlPreview/CheckOverflow,带行索引缓存 |
| PowerPointHandler | ~30 | View/Set/Add/Query/Fill/Effects/Animations/Background/Theme/Comments/Hyperlinks/SvgPreview/Model3D |
Core 层:40+ 个辅助模块,包含多个自研引擎(公式、图表、透视表等),以及主题色解析、字体度量、单位转换、HTML 预览等基础能力。
统一接口:三个 Handler 都实现 IDocumentHandler 接口,这是整个项目的核心抽象。
二、API / CLI 抽象设计
三层操作架构
OfficeCLI 最核心的设计是将 Office 文档操作分为三个粒度层次:
L1:语义视图层(只读,理解文档)
| 命令 | 视图模式 | 用途 |
|---|---|---|
view --mode text |
纯文本 | 获取文档全部文字内容 |
view --mode annotated |
带编号标注 | 每个元素标上 [P1] [T2] 等编号,AI 通过编号定位 |
view --mode outline |
大纲 | 文档标题层级结构 |
view --mode stats |
统计 | 字数、段落数、表格数等 |
view --mode issues |
问题检测 | 格式问题、兼容性问题 |
view --mode html |
HTML 预览 | 可视化渲染 |
所有视图模式都有 JSON 变体(如 ViewAsStatsJson()),支持 --start/--end/--max-lines/--cols 分页参数。
annotated 视图是关键设计——它为文档中的每个元素生成唯一编号,AI Agent 在后续的编辑操作中可以直接引用编号进行精确定位,不需要用模糊的自然语言描述位置。
L2:DOM 操作层(读写,结构化编辑)
| 命令 | 功能 | 操作粒度 |
|---|---|---|
get <path> |
获取元素,返回 DocumentNode |
元素级,可指定深度 |
query <selector> |
CSS-like 选择器查询 | 类型/属性筛选 |
set <path> <props> |
修改元素属性 | 属性级(字体、颜色、对齐等) |
add <parent> <type> |
添加元素 | 支持 Index/After/Before 定位 |
remove <path> |
删除元素 | 元素级 |
move <src> <dst> |
移动元素 | 元素级 |
swap <a> <b> |
交换两个元素 | 元素级 |
DocumentNode 是跨文档类型的通用 DOM 节点抽象,包含:path(DOM 路径)、type(元素类型)、text(文本内容)、preview(预览)、style、format(属性字典)、children(子节点)。
L3:Raw XML 层(底层逃生舱)
| 命令 | 功能 |
|---|---|
raw <partPath> |
直接读取 OpenXML part 的原始 XML |
rawSet <partPath> <xpath> |
XPath 定位并修改 XML 节点 |
addPart |
创建新的 XML part(图表、页眉页脚等) |
validate |
OpenXML schema 合规性验证 |
这层的存在非常务实:Office 格式的 XML 规范极其庞大,L2 无法覆盖所有操作。当 AI Agent 遇到 L2 不支持的功能时,可以降级到 XML 层直接操作——相当于一个"逃生舱"。
AI Agent 交互设计
1. MCP Server
McpServer.cs 实现了 JSON-RPC 2.0 over stdio 的 MCP 协议。为了兼容 .NET 的 PublishTrimmed(会裁剪掉反射),手写 Utf8JsonWriter 序列化,不使用 JSON 反射。支持 tools/list 和 tools/call,内置后台升级检查。
McpInstaller 支持一键注册到主流 AI 编辑器的配置文件:Claude Code、Cursor、VS Code Copilot、LM Studio。
2. SKILL.md 技能系统
内置 SKILL.md 文件嵌入到二进制中,AI Agent 读取后自动学会使用方式。策略分层指导 AI 先用 L1 理解文档,再用 L2 编辑,必要时降级 L3。
skills/ 目录包含 12 个专项技能包:
| 技能 | 场景 |
|---|---|
| officecli-docx / xlsx / pptx | 三种格式的通用操作指南 |
| morph-ppt / morph-ppt-3d | PPT Morph 动画和 3D 效果 |
| officecli-academic-paper | 学术论文模板 |
| officecli-data-dashboard | 数据仪表板 |
| officecli-financial-model | 财务模型 |
| officecli-pitch-deck | 商业路演 PPT |
| officecli-word-form | Word 表单 |
通过 officecli skills install 安装到 Agent 环境。
3. Schema 驱动的帮助系统
schemas/help/ 目录按格式(docx/pptx/xlsx)存放 JSON Schema 文件,描述每种元素的属性、别名、示例。嵌入为 EmbeddedResource,运行时通过 SchemaHelpLoader 读取,SchemaHelpRenderer 渲染。支持按动词(add/set/get)过滤——AI 可以查询"我能给 slide 设置哪些属性"。
4. JSON 输出
全局 --json 选项,OutputFormatter.WrapEnvelopeText() 统一 JSON 信封格式。所有命令的输出都可以结构化,方便 AI 解析。
三、Office 文档引擎
底层依赖:OpenXML SDK
OfficeCLI 基于微软开源的 DocumentFormat.OpenXml 3.4.1 构建。这个 SDK 提供了 Office Open XML(OOXML)格式的底层读写能力——本质上是操作 .docx/.xlsx/.pptx 文件内部的 XML 结构。
OpenXML SDK 本身是低层级的——它只提供 XML 节点的创建和操作,不提供"添加一个格式化的表格"这样的高层 API。OfficeCLI 在此基础上自研了大量高层抽象。
自研引擎模块
1. 公式引擎(Core/Formula/)
自研 Excel 公式解析和求值器:
FormulaParser.cs— 将公式文本解析为 ASTFormulaEvaluator.cs+.Functions.cs+.Helpers.cs— 150+ 内置函数的求值- 支持 Numeric/String/Boolean/Error/Array 类型
- 15 位有效数字精度控制
ModernFunctionQualifier处理新版函数名
这意味着 OfficeCLI 可以在不打开 Excel 的情况下计算公式结果。
2. 图表引擎(Core/Chart/)
这是代码量最大的自研模块之一:
ChartSvgRenderer.cs(2,897 行)— 完整的 SVG 图表渲染器ChartSvgRenderer.CxExtract.cs— ChartEx 扩展图表支持(直方图、漏斗图、树状图、旭日图、箱线图)ChartHelper.cs+ Builder/Reader/Setter/Axis/Advanced — 图表 DOM 操作ChartExBuilder.cs— ChartEx 格式构建器ChartPresets.cs/ChartExResources.cs— 预设样式和嵌入的 XML 模板
可以在不安装 Office 的情况下渲染图表为 SVG。
3. 透视表引擎(Core/PivotTableHelper*)
6 个 partial 文件覆盖完整的透视表处理链:Parse → Cache → Definition → Render → Set → Readback。自行实现了透视表的缓存计算。
4. 主题色系统
ThemeColorResolver— 解析 Office 主题色(accent1-6 + shade/tint 变体)OfficeDefaultThemeColors— 内置默认主题- 这是正确渲染 Office 文档颜色的关键——Office 的颜色系统不是简单的 hex,而是基于主题的相对值
5. 其他自研模块
| 模块 | 功能 |
|---|---|
| FontMetricsReader / LocaleFontRegistry | 字体度量和区域字体映射 |
| WordTocBuilder | 目录自动构建 |
| WordNumFmtRenderer | Word 编号格式渲染 |
| ExcelStyleManager | Excel 样式管理 |
| HtmlPreviewHelper / HtmlScreenshot | HTML 预览和浏览器截图 |
| DrawingEffectsHelper | 绘图效果(阴影、发光等) |
| SvgImageHelper | SVG 图片处理 |
| EmuConverter / Units / SpacingConverter | EMU/pt/cm/inch 单位转换 |
| OleHelper + OpenMcdf | OLE 嵌入对象处理 |
| WordStrictAttributeSanitizer | Strict OpenXML 属性清理 |
| GenericXmlQuery | 通用 XML 查询 |
| TemplateMerger | 模板合并 |
| PathAliases | DOM 路径别名系统 |
兼容性考量
优势:
- 基于 OpenXML SDK,直接操作标准 OOXML 格式,与 Microsoft Office 原生兼容
- 支持 Strict OpenXML 和 Transitional OpenXML 两种变体
- 完整的 i18n 和 RTL(从右到左文字)支持
validate命令可验证文档是否符合 OpenXML schema
风险:
- OpenXML SDK 只是"能读写 XML",正确性取决于上层实现——Office 格式有大量未文档化的行为和边缘情况
- 不支持旧格式(.doc/.xls/.ppt),仅支持 OOXML 格式(.docx/.xlsx/.pptx)
- 图表渲染、公式求值等自研引擎可能与 Office 的实际行为有差异
- 没有自动化测试(13.8 万行代码零测试),格式兼容性靠人工验证
四、技术栈
| 组件 | 技术选择 | 说明 |
|---|---|---|
| 运行时 | .NET 10.0 | 最新版,启用 nullable + implicit usings |
| CLI 框架 | System.CommandLine 3.0.0-preview | 微软官方 CLI 库(仍是预览版) |
| 文档引擎 | DocumentFormat.OpenXml 3.4.1 | 微软开源 OpenXML SDK |
| OLE 支持 | OpenMcdf 3.1.3 | 开源 OLE 复合文档库 |
| IPC | Named Pipe | 驻留模式进程间通信 |
| MCP | 手写 JSON-RPC 2.0 | 不依赖 MCP 框架库 |
| 序列化 | Utf8JsonWriter + Source Generator | 兼容 PublishTrimmed,避免反射 |
| 构建 | dotnet publish | PublishSingleFile + SelfContained + PublishTrimmed |
| 实时预览 | 内嵌 HTTP 服务器 + SSE | Watch Mode |
| CI/CD | GitHub Actions | 8 个平台目标交叉编译 |
单二进制分发
通过 .NET 的三个发布选项组合实现:
PublishSingleFile— 打包为单文件SelfContained— 内嵌 .NET 运行时PublishTrimmed— 裁剪未使用的代码
Skills、Schemas、CSS/JS 资源全部作为 EmbeddedResource 嵌入程序集。build.sh 支持 8 个平台目标:macOS (ARM64/x64)、Linux (x64/ARM64/musl)、Windows (x64/ARM64)。macOS 构建包含 ad-hoc 代码签名。
驻留模式(Resident Mode)
问题:每次执行 CLI 命令都要启动 .NET 运行时 → 打开文件 → 解析 XML → 执行操作 → 保存文件。AI Agent 连续执行几十条命令时,这个开销不可接受。
解法:双管道架构的常驻进程:
- 主命令管道:接收和执行命令
- Ping 管道:独立的健康检查通道,用于验证进程是否存活
SemaphoreSlim单命令锁,串行化请求- 两种生命周期:自动启动模式(60 秒空闲退出),显式 open/close 模式(12 分钟空闲退出)
- 支持
__set-idle-timeout__RPC 动态调整超时 - 关键不变量:ping 响应 ⇔ handler 持有文件锁
流程:open → 启动子进程(__resident-serve__)→ 后续命令通过 pipe 转发 → close 发送关闭指令。Windows 上有特殊处理来避免 handle 继承泄漏。