ARTICLE · 1259577
迭代篇:八套插件 Skill 换底座——24,847 页 VBA、7,234 份 PIA 类型页、两道真机闸门,AI 写加载项不再靠猜
前面那篇 Excel 文档库篇,我留了一句话:AI 强不强,不在记忆,在文档。 那篇讲的是"实时操作"——AI 在你已经打开的表、文档、演示里动手。 这一篇讲另一半:写插件。 同一句
Range.Find,实时操作里是脚本,插件里是 C#;坑是同一批坑,只是换了语言、换了宿主、换了交付形态。 所以这一轮,我把八套插件 Skill 的底座掀了重铺:文档搬进来,真机装进去,闸门立起来。
一、先交代:这轮改的不是功能,是底子
先把八套名字摆出来,免得你对不上号:
- word-com-addin-builder:Word 传统 COM 加载项
- ppt-com-addin-builder:PowerPoint 传统 COM 加载项
- exceldna-addin-builder:Excel / WPS 的 XLL 插件
- outlook-com-addin-builder:Outlook 传统 COM 加载项
- excel-vba-addin-builder:Excel VBA / xlam 加载项
- word-vba-addin-builder:Word VBA 加载项
- powerpoint-vba-addin-builder:PPT VBA 加载项
- pbi-desktop-tool-builder:Power BI Desktop 外部工具
八套,横跨三条技术线:C# COM 加载项、VBA 宏、Power BI 外部工具。
为什么八套一起改?
因为它们大多共用同一套对象模型、同一批宿主差异、同一种验证难题。
分开改,等于把同一个坑,踩八遍。
这轮改了什么?
一句话:加的功能不算多,改的是"AI 凭什么写对"。
拆成三层:
1. 文档层:VBA 官方文档、PIA 官方互操作文档、OpenXML 官方文档,全部离线随包;
2. 语料层:把实时操作那边已经跑通的实测,翻成插件这边可以直接抄的 C# 配方;
3. 验证层:逻辑冒烟 + 全量部署冒烟 + 人工 UI,三道关,前两道全自动。
先看一张表:
说实话,这轮最累的不是写脚本,是承认一件事:以前的参考文档,不够 AI 用。
不是写得少,是写得太像"给人看的"。
人看文档,看到"调用 Find.Execute 做替换",就够了;剩下的他会自己试、自己调、自己问。
AI 不会。
它会把这句当成完整指令,直接写下去;参数顺序错了,它不知道;WPS 下不生效,它也不知道;等你发现,它已经交付了。
给 AI 的文档,不能只写"怎么做",还得写"哪里会错、错了怎么认、这个宿主行不行"。
这就是这轮要补的东西。
这轮的总账,先记在这儿:
- 24,847 页 VBA 官方文档,覆盖 Excel / Word / PowerPoint 三个宿主;
- 7,234 份 PIA 类型页,88,088 条成员口径,1,843 个枚举,17,933 个常量;
- OpenXML 全量 API 索引:4,314 个类型、33,945 条成员、63 篇官方 how-to;
- 89 条 C# 主干配方(Word 40 + PPT 22 + Excel 底座 27),另加 16 条 OpenXML 配方;Outlook 侧是 5 套蓝图各带 3 条 smoke,不重复计入;
- 两道自动关卡,把插件开发的反馈环从"分钟级"压到"秒级",实测提速 20–40 倍;
- 文件层批量处理,Word 快 约 1,700 倍,PPT 快 684 倍。
数字先放这儿,下面一条条讲清楚它们是怎么来的、能干什么、不能干什么。
从 6 月第一套 VBA Skill 到现在,四个多月;这八套不是一天长成的,是一轮一轮补出来的。
二、实时操作和写插件,本来就是同一套知识
先说一个我这两年越来越清楚的判断:
实时操作,是 AI 替你现在动手;写插件,是 AI 教软件以后自己动手。
看起来是两件事,其实是同一套知识的两种用法。
你想想,一个 Word 加载项在干什么?
- 它拿到当前的 Application、Document、Selection;
- 它调 Range.Find 做替换,调 Tables.Add 建表,调 Fields.Add 插域;
- 它把结果写回文档,再回读一遍确认。
这跟"实时操作"里的每一步,有区别吗?
没有。
同一句 Range.Find.Execute,在实时操作里是 pywin32 的一行调用,在插件里是 C# 的强类型签名;参数一样、枚举一样、WPS 的脾气也一样。
差别只在三处:
- 谁在动手:实时操作是 AI 现在动手,插件是软件以后自己动手;
- 什么形态:实时操作是脚本,插件是 DLL / XLL / xlam;
- 怎么验收:实时操作看眼前这份文件,插件要看"装到别人机器上还灵不灵"。
但知识本体,是同一套。
举个最小的例子。
你要在 Word 里,把全文的"旧公司名称"换成"新公司名称"。
实时操作里,是 pywin32 的一行:
doc.Content.Find.Execute("旧公司名称", False, False, False, False, False, True, 1, False, "新公司名称",2)
十一个参数,一个都不能省。你要是图省事写命名参数,它返回 True,但替换不生效——这是 pywin32 的封送坑。
到了 C# 插件里,同一个需求:
doc.Content.Find.Execute(
FindText:"旧公司名称", ReplaceWith: "新公司名称",Replace:WdReplace.wdReplaceAll);
命名参数可以用,可选参数由编译器封送;同一个坑,消失了。
但另一边,又长出新的:Range.Value 不能直接用、Range.Sort 的默认方向是错的、Style 得走 set_Style。
同一个需求,两种语言,两套坑。
所以"Office 自动化知识"不能只维护一份:语言变了,封送层变了,坑也跟着变。
问题就出在这儿。
过去这两份知识是分头长的:
- 实时操作那边,Word 有 128 个对象模型语料函数、Excel 有 416 个(om_* 模块),还有成体系的证据等级、双宿主实测;
- 插件这边,多数时候只有"模板 + 示例代码",参数靠记忆、行为靠猜、WPS 差异靠用户报错。
这就好比:同一个师傅,白天在客户现场干活,晚上回家教徒弟,却只给徒弟一本产品说明书。
说明书不是手艺。
所以这一轮,我把两条线并在了一起:把实时操作那边"跑通过的",变成插件这边"抄得到的"。
不是把 Python 代码翻成 C#,那太浅了。
是把"验证过的行为",翻成"可复用的判断"。
三、第一层:把"原典"搬进来
先说文档。
这一轮补了三座库:VBA、PIA、OpenXML。
VBA:24,847 页,先让 AI 学会"母语"
| 合计 | 24,847 | 1,379 | 1,211 | 13,295 |
你可能会问:写 C# 插件,为什么要塞 VBA 文档?
因为 VBA 文档是 Office 对象模型的"母语说明书"。
C# 的 PIA 是它的强类型投影:对象一样、层级一样、枚举值一样;差别只在类型系统和封送层。
很多行为,PIA 的 XML 里只有一句签名,VBA 文档里才有 Remarks、才有示例、才告诉你"这个参数在什么情况下会被忽略"。
而且,VBA 那三套 Skill 本身就要用。
查法做成了命令行,六种:
--id 完整 api id,如 Excel.Range.Merge
--object 对象名,如 Range / Shapes
--member 成员名,配合 --object
--enum 枚举名,如 XlDirection
--const 常量反查,如 xlUp
--kw 关键词搜标题与摘要
举个真例子。AI 要写 xlUp,以前是背 -4162;现在是查:
xlUp =-4162 (枚举 XlDirection;晚绑定直接写数值 -4162)
含义:Up.
枚举页:api/Excel.XlDirection.md
背的会错,查的不会。
文档里到底有什么?
不只是"一个 API 一页":
- 对象页:方法、属性、事件、返回值、Remarks;
- 枚举页:成员、数值、适用对象;
- 常量页:属于哪个枚举、值是多少;
- 语言参考:语句、函数、常量、VBIDE 模型;
- 概念篇:这个对象模型为什么这么设计。
连"语言参考"都有用。
AI 写 VBA,最容易犯的错不是不会调 API,是风格上的坏习惯:On Error Resume Next 一把梭、Select / Activate 满天飞、循环里反复读单元格。
这些,文档里都有正确写法;它不查,就会按训练数据里最常见的烂代码写。
文档不是给 AI 背书,是给它刹车。
常量更典型。Excel 有 4,272 个、Word 有 5,612 个、PPT 有 3,411 个;靠记忆,迟早写错一个数字,然后花半小时排查一个"看起来完全正确"的宏。
现在不用背了。
PIA:7,234 份类型页,强类型的官方口径
| 合计 | 7,234 | 88,088 | 1,843 | 17,933 |
PIA(Primary Interop Assembly,主互操作程序集)是写 C# 加载项的"强类型官方口径":C# 签名、ref object 可选参数怎么展开、接口/委托/枚举结构、DispId、枚举数值——全在本地。
六种查法:--id / --object / --member / --enum / --const / --kw。
查一个成员,长这样:
==P:Microsoft.Office.Interop.Word.Range.Style[property]
Range.Style
摘要:Returns or sets the style for the specified object.
C#: public objectStyle{ get; set;}
查一个常量:
wdAlertsAll =-1 (枚举 WdAlertLevel;C# 直接写数值 -1)
不过,有三条结构规则,不知道就会白查:
1. coclass 和接口分列:Application 是 coclass 视图,成员多半是空壳;真正的成员在 _Application、_Document 这类接口上。查 --object Application 得到 0 成员,不代表没有,去掉或加上下划线再查。
2. 事件在 *Events*_Event 接口:比如 ApplicationEvents4_Event,按事件名搜。
3. **可选参数是 ref object**:C# 里传 Type.Missing,或者用 dynamic;枚举常量用 --const 拿到数值后,可以直接写数字。
这三条不是 API 知识,是"查法知识"。
查法不对,AI 会得出"这个成员不存在"的错误结论,然后转身去编一个。
但我要提醒一句:文档不是圣经。
这轮实测,撞出三类"文档和编译器不一致"的情况,每一类都值得说。
第一类:文档写 Boolean,PIA 是 int。
VBA 文档里,PageSetup.DifferentFirstPageHeaderFooter 是 Boolean;到了 PIA,它是 int。你写 true,编译报 CS0029。
正确写法是 -1(开)/ 0(关)。
更阴的是 Borders.Enable:写 1,编译过、运行也过,但回读不等于 1;必须写 -1。
这就是"看起来对、跑起来错"的典型。
第二类:文档写 property,编译器让你用访问器。
Range.Style 在 PIA 的 XML 里,确实是一个属性;但你写 rng.Style = style,编译报 CS1545。
原因是它同时有 propput 和 propputref 两种形式,C# 只生成 set_Style(obj) / get_Style()。
听谁的?
听编译器的。然后回来,把这条写进语料。
第三类:文档有,代码没有。
Application.Ready,微软文档里明明白白写着;但在 COM 自动化里,IDispatch 和 PIA 双证据都读不到——它只存在于 VBA 宿主内。
所以判活不要用 Ready,用 Version。
这也是为什么,PBI 那边的 tom-docs 要做成"先反射本机 DLL,再抓文档页":查到的每个 API,本机一定存在;不存在于本机的,文档里也不给你。
一句话:文档告诉你"应该是什么",编译器告诉你"到底是什么",真机告诉你"现在能不能用"。三方对账,才算数。
OpenXML:文件层的另一把刀
COM 很强,但 COM 不是万能。
这轮给 Word 和 PPT 各补了一座 OpenXML 官方文档库:
- index.json 6.7 MB,4,314 个类型、33,945 条成员;
- 63 篇官方 how-to(PowerPoint 侧 60 篇);
- 六种查法:--type / --member / --enum / --const / --kw / --howto。
查一个类型:
[类型]DocumentFormat.OpenXml.Packaging.SlidePart
ns:DocumentFormat.OpenXml.Packaging
summary:Defines the SlidePart
成员 35 个(--type SlidePart --member <名> 查明细)
为什么要两把刀?
因为有些事,COM 根本做不到。
比如 PPT 的"节"(Section)。PIA 里没有强类型成员,dynamic 走 IDispatch 也抛 RuntimeBinderException——这是一个负能力,不是你不会写。
再比如批量性能。Word 里写 300 个段落:
- COM 逐段写:3,419 ms;
- OpenXML 一次性建包:2 ms。
约 1,700 倍。
PPT 侧同类场景,684 倍。
所以现在插件 Skill 的判断链是:当前窗口的交互走 COM,文件包的批量处理走 OpenXML,COM 够不到的地方才换路线。
不是"哪个高级用哪个",是"哪个合适用哪个"。
一条纪律:修错两次,先查库
文档库再大,不用也白搭。
所以八套 Skill 都写进了同一条纪律:
同一个问题,凭记忆修错两次,就停止盲试。
先查本地库;库里没有,再联网;联网还没有,再凭通用知识写,但写完必须实测。
这不是为了省 token。
是为了省"幻觉"。
模型最危险的地方,不是它不会,是它会一本正经地编。你让它猜第三次,它不会告诉你"我在猜",它只会给你一个更像答案的答案。
把"查"变成流程里的硬动作,它才没有机会编。
四、第二层:把"实测"搬过来
文档解决"查得到",但不解决"对不对"。
所以第二层,是把实时操作那边已经跑通的代码,翻成插件这边可以直接抄的配方。
一条配方,长什么样
不是一段示例代码,是四样东西:
1. 方法体:可以整段抄进加载项的 Logic 层;
2. 回读断言:写完怎么证明它真的生效;
3. 坑注:这条在什么宿主、什么版本、什么参数下会翻车;
4. 双宿主战绩:Office 过没过、WPS 过没过、差异属于哪一类。
配方文件的头部,会把来源和坑直接标出来,比如:
// recipe: Word.OpenXml.CreateDocRoundtrip
// source: 16 号「文件层负责离线处理」标准建文档模式
// pitfall: WordprocessingDocument.Create 后 Dispose 才落盘;
// InnerInnerText 不存在,用 InnerText
AI 看到这条,就不用"设计"怎么写;它只需要判断"这条合不合我的场景"。
合用,抄;不合用,改;改完,跑。
这就是"语料"和"示例"的区别:示例是给人看的,语料是给 AI 抄的。
配方里的回读,长这样:
// 写
range.Text=&quot;自动化改写成功&quot;;
// 读(独立回读,不复用写入时的 Range)
string text = doc.Content.Text;
lab.Assert(text.Contains(&quot;自动化改写成功&quot;),&quot;改写未生效&quot;);
注意那个"不复用":写之前拿到的 Range、Content.End,写之后未必还对。
后面你会看到,这轮全量冒烟模板自己就栽在这上面。
转写不是翻译:坑也会迁徙
这一轮最值钱的发现,不是"抄了多少条",是坑的迁徙图。
我们把 Word 实时操作那边的五个经典坑,逐条翻成 C# 重测,结果是:
两个消失,三个留下,另外还长出十几个新的。
Find.Execute | 不复现 |
OpenDataSource | 不复现Type.Missing)即可——但 WPS 宿主替换回读失败,属 B 类差异 |
Content.Text 偏移错位 | 保留 |
| 保留 | |
\r\x07 | 保留 |
新长出来的,更狠:
- Range.Value 是参数化属性,rng.Value 直接编译不过,一律用 Value2;
- ws.Cells[r, c] 索引器返回 object,必须 cast 到 Range;
- Range.Sort 的 PIA 缺省 Orientation 生成错误,省略就变成"按行排序",必须显式写 xlSortColumns;
- VBA 的 True 在 PIA 的 int 属性上一律写 -1;
- Range.Style 编译报 CS1545,改 set_Style;
- PowerPoint 不允许隐藏应用窗口,Visible = msoFalse 抛 0x80048240;
- 同名字段跨宿主三型:Font.Bold 在 Excel 是 bool、Word 是 int、PPT 是 MsoTriState。
你看出问题了吗?
如果只是把 Python 代码丢给 AI,说一句"翻成 C#",它会把那三个"留下的坑"原样带过去,再踩上这十几个新的——而且它不会告诉你,它只是"翻"了,没有"验"。
跨语言不是翻译,是重新验证。
这就是为什么,这轮不是"让 AI 翻译",是"让 AI 在真宿主里重跑一遍,再把结论写成配方"。
三条线的战绩:89 条配方
注意,差异不是"失败"。
我们把差异分成三类:
- A 类·能力缺失:宿主根本没有这个能力,比如 WPS 下 InsertCaption 报 E_FAIL;
- B 类·语义差异:能力有,行为不一样,比如 WPS 的 ListRows.Add() 之后计数不增长;
- C 类·静默失败:最危险的一类——不报错、不生效,比如 WPS 的 MailMerge.Execute,数据源打开了、执行也不报错,就是不替换。
A 类告诉你"换路线",B 类告诉你"加探针",C 类告诉你"别信它"。
这三类写进配方,AI 才知道:什么时候可以照抄,什么时候必须分宿主写,什么时候要先跑一次探针。
负能力:知道"做不到"更值钱
我越来越觉得,一份好的技术文档,不是告诉你"能做什么",是告诉你"什么做不到、为什么、该换哪条路"。
这轮我们专门收了一批"负能力":
- PPT 的节 API:PIA 无强类型成员,dynamic 也进不去——走 OpenXML,或注入 VBA 宏;
- WPS 演示的复制页:Duplicate 和 Copy+Paste 都静默无效,页数不变、也不报错——走重放构建或 OpenXML;
- **Word 的 Application.Ready**:COM 自动化不可见——用 Version 判活;
- Excel 的数据模型:程序化"播种"不可行——只对已有模型做读改,不负责从零造。
AI 最怕的,不是"不会",是"不知道自己不会"。
负能力写进文档,它才知道什么时候该刹车、该换道,而不是一头撞上去,撞完还告诉你"已完成"。
五、第三层:把"真机"装进开发环
文档有了,配方有了,还剩最后一个问题:写完怎么验?
这一轮最大的工程改动,就在这儿。
旧流程:改一行,等两分钟
以前的插件冒烟,是一条很长的链:
改代码 → build → 注册 COM → 重启 Word / Excel / PPT → 点 Ribbon → 看日志 → 关宿主 → 卸载。
一轮 1–2 分钟。
人一天能忍十轮;AI 呢?
它会在第三轮开始"猜"——因为试错太贵,它宁愿一次多改一点,也不愿意为了验证一个小函数重启一次 Office。
试错成本,决定试错密度;试错密度,决定交付质量。
这是我做这一轮底座升级最原始的动机。
新底座:台架先跑,路试后跑
我把实时操作那边的 excel-com-base 搬了过来,做成一个叫 CsLab 的实验室:
- net462 + Roslyn CSharpScript 宿主;
- 进程外附着或新建真实 Office 实例;
- 引用与加载项同一套 PIA;
- 每条配方独立跑、独立回读、证据落 JSONL。
于是冒烟变成两道关卡。
第一道·逻辑冒烟(秒级)
构建用户工程(不注册、不加载 XLL)
→ CsLab 引用用户 DLL
→ 跑 smoke_logic.csx
→ 独立回读断言
→ smoke-evidence/*.jsonl
不注册、不重启、不点按钮。改一次逻辑,跑一次。
这就是"非 UI 部分的接口测试":不开窗格、不走 Ribbon,直接把 Logic 层当接口调。
实测数据:
- 单条配方 68–1449 ms;
- 11 条种子配方,约 4 秒/宿主;
- 对比完整 build + 注册冒烟 1–2 分钟/轮,提速 20–40 倍;
- 写一条配方到拿到证据,不超过 30 秒。
而且它稳:
- 90 秒看门狗,防宿主挂死;
- 退出码 42(宿主硬退)自动换实例重试;
- Office 孤儿进程按 PID 差量清理,不误杀你正在用的窗口。
这套东西能成立,靠的是一条"可测性约定":
- Logic 层方法 public static;
- 宿主对象(Document / Range / Slide)强类型参数直收;
- 返回基元或字符串,不返回 COM 对象;
- 不碰 Ribbon(功能区)、CTP(自定义任务窗格)、日志单例、当前选区;
- 写操作由冒烟脚本独立回读,写入和读取分开。
哪些代码该进 Logic 层?
我的判断很简单:
- 能脱离 UI 单独描述的业务规则;
- 入参出参都是数据,或者宿主对象(Document / Range / Slide);
- 不依赖"当前选区""当前窗口""当前用户点了哪个按钮"。
反过来说:Ribbon 回调、CTP 显示隐藏、WebView2 导航、日志单例——这些留在 UI 层,不往 Logic 里塞。
不是为了测试好看,是为了让 AI 有个可验证的核心:
界面可以最后接,逻辑必须先跑通。
类型统一也实测过了:EmbedInteropTypes=true 的用户 DLL,可以被实验室直接强类型调用,不需要 dynamic;真要用 dynamic 兜底,工程必须显式引用 Microsoft.CSharp,否则报 CS0656。
第二道·全量部署冒烟(分钟级)
注册表安装 → 宿主加载 → COMAddIns.Connect → Automation 主链。
这一道验的是"装得上、连得上、调得动",交付前跑一次。
第三道·人工验收
Ribbon 长什么样、CTP 会不会被宿主抢焦点、WebView2 退出会不会白屏、窗口切换后任务窗格跟不跟手——这些只能人看。
最讽刺的一件事:冒烟脚本自己也会错
这轮端到端实测,抓到一个很讽刺的 bug:全量冒烟模板自己有问题。
原来的断言,用的是改写前捕获的 Content.End 去截范围。
替换文本比原文长的时候,尾字会被裁掉。
实测:7 个字的「自动化改写成功」,被裁成 6 个字,断言失败——但文档其实改对了。
修法很朴素:改写后重新取端点。
这条我写进了文档,因为它说明一件事:
测试也会骗你。
所以断言必须独立回读,不能用写之前的快照;回读坐标和目标坐标,必须逐个对照。
这也是我不太相信"AI 说自己测过了"的原因——测过,和测对,是两件事。
边界:台架不是路试
说清楚三条边界:
1. CsLab 只支持 netfx(net462 / net48)。net6+ 的 CLR 与它不互通,逻辑冒烟不可用,直接走第二道;
2. lab 不覆盖进程内行为:Ribbon 回调、CTP 生命周期、WebView2、COM 事件——这些只有真加载项能验;
3. 台架不替代路试:逻辑冒烟过了,只说明"这段逻辑对";装到别人机器上灵不灵,还得靠第二道和人工。
但话说回来:
台架不是路试,可没有台架,你只能靠路试撞运气。
两道关卡不是"更严",是"更快"。因为快,AI 才愿意多测;因为多测,交付才稳。
到这轮为止,插件开发的工作流,已经收敛成五步:
1. 问清:宿主、入口、UI、安装方式;
2. 查/选:查文档,选最接近的蓝图;
3. 抄/写:抄配方写 Logic,抄不到的才新写;
4. 逻辑冒烟:秒级,改一次跑一次;
5. 全量 + 人工:交付前跑一次,UI 自己看一眼。
这五步里,AI 能自己完成前四步;第五步的"看一眼",还是得你来。
六、同一套能力,三种吃法
八套 Skill,不是八套各干各的。
说是"换底座",其实换的不是同一个零件:C# 加载项换的是验证引擎,VBA 换的是文档与冒烟链路,PBI 换的是知识域。
但底层思路是同一条。
八套铺完,我回头看,发现它们其实是同一套实时操作能力的三种吃法。
C# 加载项:复用"验证底座"
ExcelDNA、Word、PPT、Outlook,四家 C# 加载项共用同一套 CsLab 底座。
ExcelDNA 这边有 11 套蓝图,我常跟人说:这不是模板库,是教材库。
UDF 六域样本、工作簿自动化、OpenXML 批量读写、报表模板、完整工作台、异步公式与命令、共享缓存、注册管线、配置状态、组织树集合、netfx 基线——每一套都对应一类高频场景。
选哪套,只决定你的项目骨架;写业务时,还得去别的蓝图里翻 helper、翻状态模型、翻异常处理。
Excel 底座那 27 条配方,是 CsLab 的母本语料;ExcelDNA 复用同一个实验室,项目内另有 3 条 smoke 用例随蓝图生成,开箱即跑。
ExcelDNA 这边,先翻一段旧账:轨道对齐。
之前有个很隐蔽的坑:runtime 里的 XLL 是 net6 宿主(二进制里带 hostfxr),但编译的是 net462 的 dll。表面上 UDF、IntelliSense、Ribbon 都正常,可 Excel 端一创建 CTP 就报 0x80004005,WPS 端反而成功。
同一份代码,两个宿主,两种命运。
后来用源码重编了 netfx 宿主,问题才收口;顺带确认:netfx 路线在 WPS 个人版免关沙箱。
这也是为什么,现在 ExcelDNA 默认推荐 net462,除非需求明确命中 .NET 6+ 专属能力。
Word COM 这轮的关键词是"文件层收口"。
OpenXML 方案从"路线说明"变成"实测可抄":9 条独立回读,CsLab 双宿主全绿;Logic/WordOpenXmlOps.cs 里带着"离线编辑会话 + 跨 run 正解 + 状态读写"。
七大坑也一并写进去了,包括"跨 run 替换"这个金坑、3.x 双程序集 CS0012、IdPartPair 在 3.x 没有 Uri、包部件遍历只返直接关系件、图遍历不去重会递归栈溢出静默死进程。
还有那个 1,700 倍:写 300 段,COM 3,419 ms,OpenXML 2 ms。
UI 侧也有它的老规矩:Word 是 SDI,任务窗格要按"活动窗口"维护,不能做成全局单例;CTP 外层保持 WinForms UserControl,里面用 ElementHost 承载 WPF——这套骨架,蓝图里已经搭好了。
PPT COM 这轮的关键词是"负能力正解"。
7 条 OpenXML 配方,把"COM 做不到"的三件事讲清楚了:复制页、节、落盘竞态。
- 复制页要三件事:克隆部件、挂关系、修 ID;
- 节在 extLst 的 p14 命名空间里;
- 落盘会撞 0x80070570,要 sleep + 重试 + 降级人工。
性能 684 倍。
另外,0x80048240 这条也值得记住:PowerPoint 不允许隐藏应用窗口,而 Excel 允许。跨宿主移植,连"窗口可见性"这种常识都要重测。
Outlook COM 这轮的关键词是"对象联动"。
Outlook 不是"一个文档",是五个对象世界:邮件、日程、联系人、任务、便签。
所以这套 Skill 给了五个工作台蓝图,每个都按对象联动设计:邮件生成跟进草稿、日程生成会后任务、联系人生成外联邮件、任务生成汇报邮件、便签转任务。
PIA 2,085 份类型页、22,295 条成员口径;Ribbon 要按 Explorer / Inspector 分流,右键菜单按对象挂到 ContextMenuMailItem 这类上下文菜单上。
逻辑冒烟这块,Outlook 只跑 Office 宿主——WPS 没有 Outlook 等价物;还有一个细节:单例 COM 刻意不 Quit,进程交给 PID 差量清理,避免误杀你正在用的 Outlook。
VBA:复用"操作链路"
VBA 三套,天生就是实时操作流。
它的冒烟不是 mock,是真的让 Excel / Word / PPT 把宏跑一遍:
- 编译探针:把模块和窗体导入 VBProject,插一个探针过程强制编译;
- 运行探针:Application.Run 真跑;
- 内容断言:回读单元格、段落、形状;
- 示例文件断言:连示例工作簿一起验。
Excel VBA 这轮还补了一套 chart-pivot-reporting-addin 蓝图:图表、透视表、字典聚合、CSV 导出。
实测 12/12:柱形图 ChartType=51 落在图表页、透视表行标签含品类与总计、字典聚合金额精确、CSV 以 UTF-16 落盘。
这三套 VBA Skill 的文档库,就是前面那 24,847 页:Excel 9,306、Word 9,503、PPT 6,038。
Word 和 PPT 各有六套蓝图,Excel 三套;蓝图不是"模板",是"教 AI 写正确 VBA 的样本"——先选一套当骨架,再按索引去别的蓝图里抄 helper、抄状态模型、抄异常处理。
比如 Word 那边,合同模板、会议纪要、内容控件、表格规范化、公文评审、窗体录入,各有一套;PPT 那边,汇报 deck、评审、版式、形状批量格式、窗体录入,也各有一套。
为什么不合并成一套"万能模板"?
因为 VBA 的坑,是按场景长的:合同要看条款编号和页脚,纪要要看标题层级和待办,内容控件要看占位符和锁定——你把这六个场景揉进一个模板,AI 反而不知道哪个写法对应哪个需求。
分开,是为了让它"照着这一类抄",而不是"从一大锅里舀"。
Power BI 外部工具:复用"知识域"
PBI 这套最特殊。
它不是 COM 加载项,是一个独立的 WPF 程序,靠 pbitool.json 注册到 Power BI 的"外部工具"功能区,再用 %server% / %database% 连回模型。
所以它复用的不是 CsLab,是整个 PBI 实时操作的知识域:
- 25 篇 references(18–42 号):活会话附加、TOM 对象模型、57 条体检规则、DAX 最佳实践、VertiPaq 性能、写回策略、PBIP-TMDL、DMV 目录、自动化三件套、BPA 覆盖图;
- 29 个实测 Python 脚本:live_core、om_tom_ops、adomd_query、batch_ops、trace_ops、model_health、fix_apply……
- 五座库:TOM 422 个类型、DAX 509 条、PQ 770 条、BPA 71 条官方规则、DMV 74 个 rowset;外加 SQLBI 的 488 个 DAX 函数版本矩阵。
为什么要这么重?
因为外部工具不是"一个按钮",是"一把手术刀"。
它要改的是别人的模型:加度量值、调格式、改关系、刷新区、跑 DAX、看执行计划。改错一步,用户可能一周后才发现数字不对。
所以这轮把实时操作里最硬的三件事也搬了过来:
- 事务批量原子写:defer + 单次 SaveChanges,失败 UndoLocalChanges,零残留;
- Trace 性能诊断:FE / SE 并集拆分、并行度、xmSQL、缓存命中,按官方口径读;
- ADOMD 查询防挂死:强制 CommandTimeout,不让一个查询把工具拖死。
还有两个小坑,也一并写进了主文档:
- 参数两侧有引号:Power BI 传过来的是 -server "localhost:52874" -database "9d4b2f0c-...",解析时必须 Trim('"');不 trim,连接串就多两个引号。
- 无参数启动 = 手动模式:用户直接双击 exe 时,不能报错退出,要给他一个"运行中的实例选择器"。
这些不是"高深技术",是"装到别人机器上第一天就会遇到的事"。
还有一份"官方 Modeling MCP 21 组工具兼容矩阵"——不是照抄,是逐项对照:它有什么、我们有什么、它在哪一步比我们省事、我们在哪一步比它更懂模型。
把别人的接口文档吃透,不是为了复刻,是为了知道哪条路该自己走。
一张总表
七、为什么 Flash 模型也能交付
东西齐了,我最想验证的一件事是:
如果模型根本不知道这些 API,它还能不能写出能用的插件?
答案是可以。
不是因为它突然变强了,是因为能力被外置了。
外置成三样东西:
1. 文档:不懂就查,本地就有,不用联网、不用碰运气;
2. 配方:查到就抄,抄的是别人跑通过的写法,不是它自己编的;
3. 闸门:抄完就跑,跑不过就改,改完再跑。
我拿一个最小需求走一遍。
你说:"给 PPT 加一个按钮,把选中的文本框字号统一改成 28。"
它会这么走:
1. 查:--object TextRange --member Font,确认 Font.Size 是 float,不是 int;再 --const msoTrue,确认三态枚举的值;
2. 抄:去 powerpoint-interop-recipes 里找"形状文本格式"那一条,把方法体抄进 Logic 层;
3. 跑:逻辑冒烟构造一个带窗口的演示、放一个文本框、调方法、回读 Font.Size;
4. 改:如果 WPS 下 TextRange.Replace 一类 API 有差异,配方里已经标了"先探针",它就不会硬上;
5. 交付:全量部署冒烟过一遍,你打开 PPT 点一下按钮。
整个过程,它不需要"记住"PPT 的对象模型;它只需要会查、会抄、会跑。
这三样在,Flash 模型和顶级模型的差别,就变成了:
- 查得快不快;
- 一次写对的概率高不高;
- 复杂需求下,架构判断准不准。
而不是"能不能交付"。
说白了:
顶级模型的上限更高,但交付的下限,应该由闸门来决定,而不是由模型的记忆来决定。
这也是我为什么坚持"本地语料",而不是"等模型更新":
- 模型会换代,语料不会;
- 今天用 Flash,明天用顶级,底座是同一套;
- 模型不知道的,语料知道;模型记错的,实测纠正。
但我也得说句实话:
闸门保证下限,不保证上限。
它能拦住"参数写错""宿主不支持""写完没生效",拦不住"这个功能一开始就不该这么做"。
业务判断、架构取舍、什么该自动化、什么该留给人——这些还是得你来。
工具能替你验错,不能替你负责。
八、边界与门槛:丑话说在前面
第一,还是 Windows 专属。
COM、PIA、VBA、Power BI 外部工具,都是 Windows 桌面体系的能力。Mac 上跑不了,这不是我不努力,是路线决定的。
第二,需要本机装 Office 或 WPS。
实时操作要真宿主,插件冒烟也要真宿主。CsLab 不会给你模拟一个"假 Word"。
第三,逻辑冒烟只支持 netfx。
net462 / net48 可以;net6+ 直接走全量部署冒烟。这不是偷懒,是 CLR 不互通。
第四,文档库第一次用要解压。
VBA、PIA、HandyControl、OpenXML 的文档大多打包成 zip 母本;首跑由 AI 自己执行 --extract,线程池并行解压,校验通过后自动删母本。删不掉就静默跳过,不影响检索。
第五,文档有版权,也有边界。
VBA 文档来自 MicrosoftDocs/VBA-Docs(CC BY 4.0);PIA 文档来自微软官方 PIA 参考库(MIT/CC);OpenXML 文档来自 OfficeDev/open-xml-docs(MIT)。原典保留署名、页面内容零修改,Skill 只做本地检索,不搬运文字。
第六,文档不是保证。
官方文档也会漏、会错、会过时。所以每条关键写法都要过实测;文档和实测冲突时,以实测为准,再回来更新文档。
第七,它不测 UI。
Ribbon 好不好看、CTP 会不会闪、WebView2 会不会白屏——这些只能人看。自动化能替你省掉 80% 的重复验证,省不掉最后那 20% 的眼睛。
第八,它不替你做业务判断。
工具做什么、给谁用、什么叫做"好用"——这些是你的决定。Skill 只负责把它做出来、验出来。
第九,版本会漂。
文档会更新,宿主会升级,今天的"已验证"可能明天就变成"待复测"。所以每套 Skill 都有 CHANGELOG 和证据文件;看到"verified",也请看它是哪一天、在哪个宿主上验的。
九、写在最后:把"手艺"变成"底座"
这轮做完,我最大的感受不是"又补了多少页文档"。
是:我以前太依赖"我记得"。
我记得 xlUp 是 -4162;我记得 Range.Style 要写 set_Style;我记得 WPS 的 ListObjects.Add 会忽略命名参数;我记得 PPT 不能隐藏窗口。
可这些"我记得",对 AI 有什么用?
它不在我脑子里。
它能用的,只有两样:手边的文档,和跑得动的真机。
所以这一轮,我做的事情,说到底就三句:
- 把"我知道",变成"它查得到";
- 把"我试过",变成"它能复现";
- 把"我相信",变成"它过得了"。
这才叫底座。
不是多了几个函数,不是多了几个按钮,是换了一种让 AI 写代码的方式:
不懂就查,查到就抄,抄完就跑,跑不过就改。
以前它靠猜,现在它靠证据。
手艺人的本事,从来不在手上,在标准里。
标准立住了,谁来干,都不会太差。
这套底座也不是终点。
新的宿主、新的文档、新的配方,都可以往里接;骨架不用改,闸门不用改,AI 换一代,也不用改。
这才是"底座"两个字的意思:不是今天能跑,是明天还能长。
叫上身边的人,一起来把 AI 编程玩转。
想体验全套免费 Skill?欢迎加好友进入免费社群,关注公众号,后台回复「Skill」,不要理会AI自动回复,等我发联系方式,加好友进群自助获取。















































































