夜雨聆风学习资料网

ARTICLE · 1203329

拆解一个 3254 行的 Excel Skill:手把手写一份 Agent 愿意调用的技能包

拆解一个 3254 行的 Excel Skill:手把手写一份 Agent 愿意调用的技能包

全文约 6500 字,适合收藏后对照实操。

让 Agent 写一个带公式的表格,它常常直接给你一堆算好的数字;让它改一份存量工作簿,它可能顺手把原有公式覆盖掉;你提醒它检查公式,它看到退出码是 0 就回复完成,而文件里还躺着十几个 #NAME?。

这些问题多半不出在模型能力上。模型会写 Python,也会调 openpyxl,缺的是一份写给 Agent 看的作业规范:什么任务用什么方法,做到什么程度算合格,哪些坑不能踩。

我最近把一份真实的 xlsx skill 从头到尾读了一遍:60 个文件,3254 行脚本,39 个 XSD 模式文件。下面按它的目录结构逐层拆开,讲清楚每部分在解决什么问题,最后给出一套可以照着做的七步流程。

一、先看清这个 Skill 的定位

1.1 它覆盖什么

这份技能包管的是 Excel 文件的整个生命周期:创建带公式和格式的工作簿、做图表和数据透视、读取和清洗数据、批量改单元格、条件格式和数据验证。

它自己在描述里写得很直接:交付 Excel 类成果时使用。

这句话其实划定了它的位置。它不是一本 Excel 教程,而是交付前的检查关口。它默认调用它的 Agent 已经会写代码,真正补上的是验收标准。

1.2 用一张路由表消灭选择困难

技能开头没有铺垫概念,直接给了一张任务和方法对照表:

任务
方法
创建或编辑(含公式、格式)
openpyxl
批量数据导入导出
pandas
(read_excel / to_excel)
快速查看某个工作表
markitdown file.xlsx
读取模型(公式和值都要)
两次 load_workbook

Agent 扫一眼就知道该用哪个库,不用在 openpyxl、pandas 和 markitdown 之间反复试。

1.3 把「不适用」也写明白

成熟一点的技能都会写清禁区。这份 skill 有三处:

  • markitdown
     的输出不带单元格坐标,所以不能拿它的结果去规划编辑;
  • 工作簿有跨文件链接时,重算会丢链接,脚本会直接拒绝执行;
  • LibreOffice 只实现了一部分 Excel 函数,XLOOKUP、FILTER 这类新函数加什么前缀都算不出来,文档里提前列进了黑名单。

边界写清楚,Agent 才不会在禁区里反复试错。

二、60 个文件,每层只做一件事

先看目录:

xlsx/├── SKILL.md              # 技能主文档:Agent 的入口 SOP├── README.md             # 写给人类读者的简介├── LICENSE.txt           # 授权声明├── _icon.png             # 市场展示图标├── _meta.json            # 市场展示元数据├── _skillhub_meta.json   # 安装态元数据├── references/│   └── zh-CN.md          # 中文完整指南(含交付前自查清单)├── schemas/              # 39 个 OOXML XSD,校验器的事实来源└── scripts/              # 11 个 Python 脚本,约 3254 行    ├── recalc.py         # LibreOffice 公式重算 + 错误扫描    ├── soffice.py        # 沙箱环境适配层    ├── validate.py       # OOXML XSD 校验 CLI 入口    ├── validators_base.py      # 校验器基类    ├── validators_docx.py      # Word 校验子类    ├── validators_pptx.py      # PPT 校验子类    ├── validators_redlining.py # 修订痕迹校验    ├── validators.py     # 门面:统一再导出    ├── helpers.py        # zip 安全解压、重打包等公共函数    └── pptx_chart.py 等  # 检测型小工具,只报告不修复

2.1 谁写给谁看

层
文件
读者
职责
改错的后果
元数据层
SKILL.md
 frontmatter
运行时路由系统
决定技能何时被触发、如何展示
触发失灵,技能「失踪」
主文档层
SKILL.md
 正文
Agent
判断用什么方法、做到什么标准
Agent 行为跑偏
参考文档层
references/zh-CN.md
Agent(中文输入时)
完整中文 SOP 和自查清单
中文场景质量下降
脚本层
scripts/*.py
Agent 通过 CLI 调用
确定性执行:重算、校验、解压
能力锚点失效
参考资料层
schemas/*.xsd
校验器脚本
提供校验判据
校验器失去依据
配置层
_meta.json
、_skillhub_meta.json
市场与安装系统
展示信息和安装态
展示错乱、重复安装

2.2 三层分离

这份包的设计可以概括成三层:

  • 文档负责判断:什么时候用什么方法,红线在哪,哪些坑踩过;
  • 脚本负责执行:公式重算、XSD 校验、zip 安全解压这类模型不擅长又必须确定的事,交给代码;
  • 参考资料负责事实:XSD 这类「法条」单独存放,文档只引用。

判断、执行、存档分开,改一层不会牵动另外两层。

三、每一层该怎么写

3.1 SKILL.md 是写给 Agent 的作业指导书

frontmatter:技能的身份证

---name: xlsxdisplay_name: "Excel 表格处理"description: >-  全面处理 .xlsx/.xlsm 表格:创建带公式与格式的表格……触发词:Excel 表格、xlsx、做个表……category: documentversion: "1.0.0"author: "zxh"user-invocable: trueruntime: generictags: ["Excel", "xlsx", "表格", "公式", "charts", "pivot table"]dependencies: []---

有几处要注意:

  • name
     是唯一标识,不能和市场上的其他技能重名;
  • description
     直接决定路由能不能命中,所以要同时写清「做什么」和「什么时候用」,这份技能把触发词嵌进了描述里;
  • user-invocable
     决定用户能不能手动 @ 调用;
  • dependencies
     要如实写,否则用户装完才发现缺东西。

正文顺序:路由表、红线、操作手册、陷阱、领域规范、依赖

这个顺序是按 Agent 的阅读路径排的:先选工具,再知道及格线,然后查具体做法,最后避开已知的坑。需要从头读到尾才能用的文档,等于在浪费上下文。

指令要可执行

反面例子是「注意公式的正确性」,这种话 Agent 没法执行。

正面的写法是这样:

写公式,不要写死结果。用 sheet['B10'] = '=SUM(B2:B9)',而不是把 Python 算好的合计值填进去。工作簿必须在输入变化时能重新计算。

正面句式、正反例、一句原因,三样都有。再看一条带原因的禁令:

不要使用 XLOOKUP、XMATCH、SORT、FILTER、UNIQUE、SEQUENCE。运行时使用的 LibreOffice 无法对这些函数求值;而且它们是溢出数组函数,openpyxl 写出的文件没有溢出元数据,只有区域左上角有值,重算脚本还会把这种截断结果判定为零错误。

只写禁令不写原因,Agent 下次换条路照样会踩。

异常情况要写成明文条款

这份 skill 把三类异常写成了明确规则,而不是留给 Agent 临场判断:

  • 拒绝执行,同时给出口:检测到跨文件链接的缓存值会丢失时,重算脚本停止运行,并在错误信息里给出两条路,保存前从原文件复制这些单元格的值,或者传 --force 自己承担损失;
  • 退出码的含义:公式有错时退出码仍然是 0,只有根本没执行重算才返回非零。文档里特意强调,不能把「正常退出」当成「工作簿干净」;
  • 通过不等于正确:recalc 只能证明公式可以求值,不能证明它算得对。范围差一格、引用错一行,都会得到一份没有报错但数字错误的表。

异常处理的文档写法,核心就是把「工具在什么情况下会骗你」提前讲清楚。

3.2 脚本是能力的确定性地基

脚本部分有三个约定。

输入约定

python scripts/recalc.py output.xlsx [timeout_seconds]   # 默认 30

位置参数加可选参数,--force 这类开关单独识别;路径相对于技能目录;不带参数时打印用法并退出。Agent 试错的成本很低。

输出约定

{  "status": "success",  "total_formulas": 42,  "total_errors": 0,  "error_summary": {}}

这份 JSON 契约有几个细节:

  • status
     只有 success 和 errors_found 两个值,Agent 不需要猜;
  • 失败时返回带 error 键、没有 status 键的 JSON,并且只有这种情况才以非零退出码结束,于是「没跑成」和「跑完但有错」在协议层就能区分;
  • 每类错误最多列 100 个单元格,同时用 locations_truncated 说明省略了多少,并提醒以 total_errors 为准,不要看列表长度;
  • 每条错误都附带下一步动作,比如延长超时、从原文件复制单元格值。

依赖和异常

依赖分成三档:预装的(openpyxl、pandas、markitdown)不要先跑 pip install;缺失时才装;环境相关的做适配,比如 soffice.py 会探测沙箱是否禁用了 AF_UNIX socket,需要时现场编译一个 LD_PRELOAD shim,Linux 用 timeout、macOS 用 gtimeout。

异常处理铺了四层:输入层(文件不存在、不可写、soffice 缺失)、执行层(超时、返回码 124、文件修改时间和体积没变说明 LibreOffice 没有真正重写)、数据层(openpyxl 加载失败)、安全层(defusedxml 防 XML 攻击、safe_extract 防 zip 路径逃逸、拒绝符号链接条目)。

检测和修复分开

包里有一个只检测不修复的脚本,注释写得很坦白:

Detection only: for either fault more than one repair is valid, and only the author knows which was meant.

能自动修的小问题才提供 --auto-repair;「哪个修复才对」取决于业务意图的,只报告。脚本越是想替用户做决定,越容易帮倒忙。

3.3 参考资料层:把法条和流程分开

schemas/ 下 39 个 XSD 文件(约 1MB)是 OOXML 的官方模式定义,校验器靠它们判断文档是否合法。三个设计点:

  • 映射表驱动:SCHEMA_MAPPINGS 把目录名(word/ppt/xl)映射到具体的 XSD 文件,加新文档类型只改映射,不改逻辑;
  • 噪声白名单:把已知无害的报错过滤掉,避免每次校验都淹没在噪声里;
  • 不内嵌:文档只引用文件名,不复制 XSD 内容,改模式文件时不需要同步改文档。

3.4 元数据:展示和安装分开

_meta.json 管市场展示(emoji、主题色 #217346、标签、支持语言),_skillhub_meta.json 管安装态(安装时间、skillId、图标地址和本地路径)。

这两类信息混在一起是常见事故:改展示信息导致路由失效,或者手改安装态导致重复安装。分开存放,每类读者只面对自己需要的信息。

四、从零写一个 Skill:七步

Step 1 枚举场景:列出技能要覆盖的任务矩阵(创建、编辑、读取、校验等),每项标注「模型自己做」还是「必须脚本做」。

Step 2 设计路由表:把任务矩阵压缩成「任务到方法」对照表,放在文档最前面。

Step 3 定红线:写清每个交付物的硬性要求。这份技能列了 6 条:专业字体、零公式错误、公式不能硬编码、严格遵循用户规格、假设可溯源、编辑存量文件时不能改动既有公式。

Step 4 把高频易错操作脚本化:约定好 CLI 入口、JSON 输出契约和失败语义。最小骨架:

def main():    if not args:        print("Usage: python recalc.py <excel_file> [timeout_seconds] [--force]")        sys.exit(1)    result = do_work(...)    print(json.dumps(result, indent=2))    # 区分「执行失败」和「执行完成但结果有问题」    sys.exit(1 if "error" in result else 0)

Step 5 沉淀 Gotchas:用「现象、原因、对策」三段式记录踩过的坑。例如读模型要加载两次:data_only=True 给值但丢公式,默认模式给公式但没有值。

Step 6 补领域规范:通用方法之外,把行业惯例写死。这份技能的财务模型规范连颜色都定了:蓝色是硬编码输入,黑色是公式,绿色是跨表链接,红色是跨文件链接,黄色填充是待填假设。

Step 7 双语分层和自查清单:中文输入先读 references/zh-CN.md,文档末尾放一份交付前自查清单,让 Agent 逐项确认。

五、几条建议和六个坑

5.1 五条建议

  1. 先写文档,再写脚本。文档没写明白,脚本再好也会被用错地方。
  2. 脚本只做模型做不好的事:重算、schema 校验、安全解压。写文案这种事不值得脚本化。
  3. 每个脚本给一份稳定的 JSON 契约。字段固定、语义明确、失败可区分,Agent 才敢放心调用。
  4. 错误信息要能指导下一步。不要只说「出错了」,要说「文件不可写,重算会原地重写文件,请检查权限」。
  5. 踩过的坑要写进文档。不写,下一个会话的 Agent 还会再踩一遍。

5.2 六个坑

  1. frontmatter 分隔符被转义:这份包里的 SKILL.md 开头是 \--- 而不是标准的 ---,导出或打包环节做了转义,按 YAML 解析会直接失败。自建技能后要用原始格式验证一次。
  2. 导入方式和目录结构不一致:pptx_chart.py 用了 from . import part_text 这种相对导入,但 scripts/ 下没有 __init__.py,单独导入会报 ImportError。平铺目录就用平铺导入,要做成包就补上 __init__.py。
  3. 夹带系统垃圾文件:zip 里有 __MACOSX/ 和 .DS_Store。发布前用 unzip -l 看一眼。
  4. 迷信退出码:errors_found 的退出码是 0。结论要从输出协议里读。
  5. 文档和内容漂移:包叫 xlsx,里面却有大量 Word/PPT 校验脚本。要么在文档里讲清定位,要么拆开。
  6. 只写 happy path:文件不存在、超时、不可写、跨文件链接,这份技能都写了。生产环境里出问题的往往就是这些边界。

结语

这份 skill 给我印象最深的,是它把经验拆成了三种可以传递的东西:文档里的判断、脚本里的断言、契约里的字段。

一个老工程师知道公式不能写死,知道退出码 0 不代表文件干净,知道改存量文件前要先找到输入单元格。这些知识留在人脑子里,换个 Agent 就要重新教一遍;写进 skill,才算是真正沉淀下来。

如果手头有反复做、每次都容易出错的活,不妨从一份 SKILL.md 开始,把它写下来。


# 话题标签

#AI技能#Agent#Skill编写#效率工具#人工智能#自动化#程序员#提示词工程

相关学习资料