shazhou-wiki/research/officecli-tech.md

278 lines
15 KiB
Markdown

# OfficeCLI 技术方案分析
> 调研时间:2026 年 5 月 | 作者:沙洲工作室
>
> 基于源码阅读(v1.0.72),非黑盒测评
## 基本信息
| 项目 | 信息 |
|------|------|
| 仓库 | [iOfficeAI/OfficeCLI](https://github.com/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` — 将公式文本解析为 AST
- `FormulaEvaluator.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 继承泄漏。