Ekko Studio docx Skill 源码级解析:Word 修订(Tracked Changes)与批注(Comments)的 WordprocessingML 处理
AI 应用人工智能AI Agent本地部署前端后端工作流自动化【免费下载链接】ekko-studioEkko Studio is a local-first AI workspace for multi-agent chat, coding, and visual workflows, available on desktop and the web.项目地址https://gitcode.com/gh_mirrors/he/ekko-studio点击查看免费下载本篇技术指南聚焦 Ekko Studio 仓库中packages/ekko-agent/skills/docx这一文档处理 Skill 的核心难点——Word 修订追踪w:ins/w:del与批注Comments的底层 WordprocessingML 处理。文章以 revisions-and-comments.md 为骨架结合 docx_revisions.py 与 docx_comments.py 的源码实现帮助读者理解修订接受/拒绝的决议语义、批注的三件套XML 结构以及如何在日常自动化流程中安全地使用这些命令。读完本文你将能读懂任意 .docx 中的修订与批注 XML并能用命令行完成列出、接受、拒绝、增删批注等全部操作。一、docx Skill 中修订与批注的定位Ekko Studio 的 docx Skill 是一套围绕 python-docx 与 lxml 构建的 Word 文档处理工具集其入口与总览见 SKILL.md。其中与本文主题直接相关的两个脚本是docx_revisions.py检查并决议修订追踪w:ins/w:deldocx_comments.py列出、添加、删除批注。这两个脚本被定位为深层参考deep reference日常使用只需按 SKILL.md 的操作流程走只有需要推理原始 WordprocessingML、扩展脚本或调试异常文档时才需要进入 revisions-and-comments.md 这一层。SKILL.md 还给出了明确的安全约定除非用户明确要求绝不丢弃批注或修订accept-all/reject-all与批量删除批注均属于破坏性变换操作前必须确认范围。脚本运行环境仅需两个 Python 依赖见 SKILL.md 的 Core dependency 段python3 -m pip install python-docx lxml所有脚本均以python3 脚本路径 ...方式调用例如python3 packages/ekko-agent/skills/docx/scripts/docx_read.py input.docx --json python3 packages/ekko-agent/skills/docx/scripts/docx_validate.py output.docx二、修订追踪的 XML 结构w:ins/w:delWord 将运行级run-level修订记录为段落w:p内部的包装元素wrapper element命名空间为http://schemas.openxmlformats.org/wordprocessingml/2006/mainrevisions-and-comments.md 给出的典型结构如下w:p w:rw:tBase /w:t/w:r w:ins w:id1 w:authorEditor w:date2026-01-02T03:04:05Z w:rw:tinserted text/w:t/w:r /w:ins w:del w:id2 w:authorEditor w:date2026-01-02T03:04:05Z w:rw:delTextdeleted text/w:delText/w:r /w:del /w:p两个关键事实决定了脚本的全部行为被删除的文本存放在w:delText而非w:t中。正因为如此普通的纯文本提取如 python-docx 的paragraph.text天然呈现接受修订后的视图——插入可见、删除隐藏。这可以从 docx_read.py 的 docstring 中得到印证Body text is the accepted/as-is text (python-docx ignores deleted-in-revision text and shows inserted text)。决议resolve语义是确定性的见下表修订类型动作处理方式w:ins接受accept解包unwrap把子 runs 上移到父级移除包装元素w:ins拒绝reject移除包装元素及其全部内容w:del接受accept移除包装元素及其全部内容w:del拒绝reject把每个w:delText重命名为w:t然后解包上述解包逻辑在 docx_revisions.py 中有直接实现_unwrap找到父元素中当前元素的位置把其子节点逐个插入到原位置并移除包装器_apply则按上表分支执行——拒绝删除时对delText改名再解包从而实现恢复被删文本。三、docx_revisions.py五个子命令与调用链docx_revisions.py 提供五个子命令对应argparsesubparsers子命令说明额外参数list以 JSON 列出全部修订id、author、date、type、text无accept-all接受全部插入与删除-o/--outputreject-all拒绝全部插入与删除-o/--outputaccept按w:id接受单个修订--id必填reject按w:id拒绝单个修订--id必填所有命令的通用参数是输入path-o/--output省略时原地覆盖输入文件源码中out args.output or args.path因此生产环境建议总是显式传-o。典型用法摘自脚本 docstringpython3 docx_revisions.py list report.docx python3 docx_revisions.py accept-all report.docx -o accepted.docx python3 docx_revisions.py reject report.docx --id 3 -o out.docx输出为结构化 JSON例如list返回{ok: true, revisions: [...]}accept/reject返回{ok: true, output: ..., resolved: n, action: accept|reject}。当按--id决议但找不到该 id 时返回{ok: false, error: no revision with id ...}并以退出码 1 结束见 docx_revisions.py。覆盖范围正文、表格、页眉页脚脚本遍历的是body 根 每个页眉/页脚部件根核心是root.iter(Wins, Wdel)它按文档顺序递归查找任意深度的元素。提供这套遍历的是公共模块 docx_common.py 中的iter_part_roots它依次产出 body 根以及每个 section 的 header / footer / first_page_header / first_page_footer / even_page_header / even_page_footer 的 XML 根用id(part._element)去重避免同源部件重复处理。因此正文段落、表格单元格含嵌套表格、页眉、页脚、文本框中的修订都能被发现和决议修订可以出现在任何允许块级内容block content的位置。关于w:id的注意事项w:id的值在每个修订元素上是唯一的但一次逻辑上的编辑会话可能产生多个元素。因此accept/reject --id精确作用于携带该 id 的一个或多个元素——源码resolve()中rev_id is None or el.get(q(id)) rev_id正是这种按 id 精确匹配的语义。四、脚本不处理的修订类型与检测手段revisions-and-comments.md 明确列出了脚本不做决议、仅检测的修订类型段落标记修订paragraph-mark revisions即w:pPr上的w:rPr/w:ins表格行插入/删除w:trPr/w:ins格式变更记录w:rPrChange、w:pPrChange移动修订w:moveFrom/w:moveTo。其中移动修订在常见编辑器中较为罕见文档建议如果文档中存在移动修订直接用 Word 本身处理不要猜测。这些类型的检测由 docx_read.py 的--revisions参数完成其detect_revisions()实现方式非常轻量直接以 zipfile 打开 .docx扫描word/下所有 XML 部件的原始字节匹配w:ins、w:del、w:rPrChange以及word/comments部件是否存在见 docx_read.py返回has_tracked_changes、comments等布尔标记。建议任何编辑操作前先运行它做是否有修订/批注的摸底。五、批注的三件套XML 结构批注由三个相互协作的部分组成见 revisions-and-comments.md 的 Comments 一节word/comments.xml部件——每个批注一个w:comment元素携带w:id、w:author、w:initials、w:date及正文段落。它通过关系类型.../comments与 document.xml 关联内容类型为application/vnd...wordprocessingml.commentsxml同时需要在[Content_Types].xml中登记 override——python-docx 的 part 机制在部件注册时会自动补上。故事story中的范围标记——锚定文本之前放置w:commentRangeStart w:idN之后放置w:commentRangeEnd w:idN。引用 run——一个包含w:commentReference w:idN的w:r紧跟范围结束标记之后它把批注气泡与位置绑定。三者的位置关系可示意为w:p w:rw:tQ3 /w:t/w:r w:commentRangeStart w:id0/ w:rw:trevenue/w:t/w:r w:commentRangeEnd w:id0/ w:rw:commentReference w:id0//w:r /w:p六、docx_comments.pylist / add / delete 的实现细节docx_comments.py 提供三个子命令子命令说明关键参数list按批注输出 JSONid、author、initials、date、text、anchored_textpathadd在--target文本首次出现处锚定新批注--target、--text必填--author默认Hermes、--initials、--xmldelete按--id删除批注及其全部范围标记--id必填listXML 层的锚定文本重建list/delete始终工作在 XML 层因此能处理任何生产者生成的文档。anchored_text的重建算法见 docx_comments.py是遍历每个部件根同样复用iter_part_roots保证按文档顺序维护一个活跃 id 集合——遇到commentRangeStart加入 id遇到commentRangeEnd移除 id期间遇到的所有w:t文本都追加到该 id 的文本缓冲中。这保证跨 run、甚至跨段落锚定的文本都能被正确拼接。add先切分 run 再锚定add的第一步是把目标文本隔离成完整的 run。find_anchor_runs在全文正文表格页眉页脚经 docx_common.py 的iter_all_paragraphs中查找--target的首次出现若匹配起点或终点落在某个 run 中间_split_run会在边界处把 run 一分为二——切分时会深拷贝w:rPrright deepcopy(run_el)因此格式粗体、斜体、颜色等得以保留并且新w:t会设置xml:spacepreserve防止前后空格丢失。随后按环境二选一python-docx 1.2使用原生document.add_comment(runs, ...)API由 python-docx 自己创建 comments 部件、范围标记和引用 run见add_comment_native旧版本或显式--xml脚本自行构建word/comments.xml——通过 OPC 层创建Partpack URI 为/word/comments.xml内容类型为 commentsxml用part.relate_to(part, RT.COMMENTS)注册关系再手工插入范围标记与引用 run见add_comment_xml。为让编辑结果能写回保存代码还给 part 动态换上了自定义 blob 属性每次保存时重新序列化 live 的 XML 树。新批注的 id 由_next_id计算取 comments 部件中现存全部数字 id 的max 1避免冲突。delete同时清理四类痕迹删除批注会移除w:comment元素以及该 id 的全部三种标记commentRangeStart、commentRangeEnd、commentReference其中引用 run 标记还会连带删除其外层w:r见 docx_comments.py。被锚定的文档正文文本不受影响——这一点在测试中也被明确断言删除后docx_read.py --text仍能读到完整句子。commentsExtended.xml 的边界现代 Word 还会写出commentsExtended.xml用于记录回复threading与已解决resolved状态。脚本既不读取也不产出该部件回复和 resolved 标记在此不可见由本 Skill 添加的批注都是顶层top-level批注。这是使用前必须知晓的能力边界。七、实战组合完整操作流程结合 SKILL.md 的工作流一个典型的修订批注自动化场景如下# 1. 摸底是否有修订/批注 python3 docx_read.py report.docx --revisions # 2. 查看全部修订 python3 docx_revisions.py list report.docx # 3. 拒绝某条错误的插入按 id python3 docx_revisions.py reject report.docx --id 3 -o step1.docx # 4. 接受其余全部修订 python3 docx_revisions.py accept-all step1.docx -o step2.docx # 5. 在关键段落添加批注 python3 docx_comments.py add step2.docx --target Q3 revenue \ --text Needs a source --author Reviewer --initials R -o step3.docx # 6. 查看批注含锚定文本 python3 docx_comments.py list step3.docx # 7. 结构校验后交付 python3 docx_validate.py step3.docx其中第 7 步 docx_validate.py 做的是健康检查而非完整 XSD 校验验证 zip 可读、必需部件存在、所有关系可解析悬空引用报错、r:id/r:embed引用有效、嵌入图片非空且魔数正确、文档引用的样式 id 在 styles.xml 中存在并尝试用 python-docx 打开。任何 error 级问题都会使退出码为 1。八、测试套件如何背书这些语义这些行为并非仅靠文档描述端到端测试 test_docx_skill.py 直接以子进程方式运行脚本并断言结果TestRevisions构造同时含正文与表格单元格修订的文档_add_ins/_add_del直接向w:p注入w:ins/w:del验证list输出 4 条记录、accept-all后正文变为Base ADDED且表格变为Cell CELLADD、reject-all后为Base REMOVED/Cell CELLGONE、按--id单条决议只影响目标 id、未知 id 返回退出码 1。TestComments验证add→list→delete全链路——anchored_text精确等于目标文本、文档正文不受影响、--xml强制走回退路径后文件仍可被 python-docx 正常打开、目标文本不存在时报错退出。测试还固定了LC_ALLC与PYTHONIOENCODINGutf-8证明脚本在无本地化环境下的非 ASCII 文本处理是稳定的。这些测试文件位于 packages/ekko-agent/skills/docx/tests是阅读本文后继续深挖底层行为的最佳入口。九、总结与安全边界修订决议是纯 XML 层的确定性操作接受插入解包拒绝插入移除接受删除移除拒绝删除delText改名w:t后解包。批注由 comments 部件、范围标记、引用 run 三件套构成list/delete通用兼容任何生产者add会先切分 run 保留格式再选择原生 API 或 XML 回退路径。边界段落标记修订、表格行修订、格式变更、移动修订只检测不决议commentsExtended.xml的回复与 resolved 状态不可见。安全删除批注或批量决议修订属于破坏性操作应遵循 SKILL.md 的约定——先docx_read.py --revisions摸底、保留可恢复的原始副本、默认输出到新文件、操作后运行docx_validate.py校验并在布局敏感的文档上用 LibreOffice 渲染核对。对于需要对接 Word 协作工作流的 Agent 与自动化管线理解本文的 WordprocessingML 细节是避免修订丢失批注错位文件损坏等问题的前提。赞分享AI 应用人工智能AI Agent本地部署前端后端工作流自动化【免费下载链接】ekko-studioEkko Studio is a local-first AI workspace for multi-agent chat, coding, and visual workflows, available on desktop and the web.项目地址https://gitcode.com/gh_mirrors/he/ekko-studio点击查看免费下载相关推荐pandoc 批注处理实战深入解析 Word 修订与评论的 --track-changes 机制pandoc 批注处理实战深入解析 Word 修订与评论的 track changes 机制 导读 本文以 pandoc 仓库中的命令测试用例 test/co文档开发工具CLIpandoc 转换带 Word 修订标记的 docx 时如何设置 --track-changespandoc 转换带 Word 修订标记的 docx 时如何设置 track changes 如果你用 pandoc 转换由 Word 生成的 .docx 文文档开发工具CLIdocx 修订追踪Track Changes完整指南用 InsertedTextRun、DeletedTextRun 与 revision 属性生成带修订标记的 Word 文档docx 修订追踪Track Changes完整指南用 InsertedTextRun、DeletedTextRun 与 revision 属性生成带修订文档创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

Java Swing 黄金矿工小游戏:抓钩状态机与碰撞检测实战

Java Swing 黄金矿工小游戏:抓钩状态机与碰撞检测实战

简介:这是一份基于Java实现的黄金矿工小游戏完整源码包,面向Java初学者、课程设计学生以及想通过经典小游戏练手的开发者,帮助读者理解Swing图形界面、游戏循环、碰撞检测与资源加载等核心机制。压缩包共30个文件,约141KB&#xf…

2026/9/24 22:02:05 阅读更多 →
体育馆场地预约系统开发实战:微信小程序+Django+Flask架构解析

体育馆场地预约系统开发实战:微信小程序+Django+Flask架构解析

体育馆场地预约平台开发手记:从电话排队到小程序一键订场做体育馆场地预约系统,最早是因为一个朋友在高校体育部上班,天天被电话轰炸:羽毛球场地有没有?今晚七点的场子被人占了能不能调?隔壁单位想包场怎么…

2026/9/24 22:02:05 阅读更多 →
GPT-Live-1+Agora构建AI会议助手实战指南

GPT-Live-1+Agora构建AI会议助手实战指南

1. 这不是“又一个AI聊天框”,而是一个能真正坐在会议室里干活的数字同事GPT‑Live‑1 Agora 实战教程:做一个能参会、操作看板的 AI 助手——这个标题里藏着三个被多数人忽略的关键动作:“能参会”、“操作看板”、“实战教程”。它不讲大模…

2026/9/24 22:02:05 阅读更多 →

最新新闻

Agent Skills:让AI Agent从“有工具”到“会干活”的实战指南

Agent Skills:让AI Agent从“有工具”到“会干活”的实战指南

如果你也在折腾AI Agent,一定遇到过这种场景:模型能力很强,工具也接了一堆,可它一遇到稍微复杂的情况就掉链子,要么压根不知道该调什么,要么调了却用不对参数。我前段时间接手一个内部自动化项目&#xff0…

2026/9/24 22:38:36 阅读更多 →
Java面试真题集锦:从HashMap到JVM与并发编程的体系化备战指南

Java面试真题集锦:从HashMap到JVM与并发编程的体系化备战指南

每年到了二三月份和九十月,牛客网上就像赶大集一样热闹,各种Java面经满天飞,有人刷题刷到凌晨三点,有人拿着 offer 在帖子里报喜。我从几年前开始招人,这几年陆陆续续面过了两三百个候选人,也帮朋友改过不少…

2026/9/24 22:38:36 阅读更多 →
AI安全审计技能化:从提示词到可复用Skill的完整实践指南

AI安全审计技能化:从提示词到可复用Skill的完整实践指南

直接说结论:把安全审计这种“高重复、强规则、容错率低”的活儿交给AI,最好的落地方式不是现写一次性提示词,而是把它固化成一套可复用的技能包,也就是现在社区里常说的Skill。我最近做完的这个security-audit-skill,就…

2026/9/24 22:38:36 阅读更多 →
网络热词“cua”解码:从拟声词到弹幕文化的流行密码

网络热词“cua”解码:从拟声词到弹幕文化的流行密码

刷短视频的时候,一条猫从镜头前飞窜过去,弹幕里齐刷刷飘过一串“cua”;群里聊到某个东西刚上架就售罄,有人跟一句“cua一下没了”;就连朋友发消息秒撤回,也有人吐槽“cua,啥也没看着”。你要是最…

2026/9/24 22:38:36 阅读更多 →
Java面试高频真题备战:考点拆解与答题框架

Java面试高频真题备战:考点拆解与答题框架

不少人在后台问我,牛客网上那些Java面试真题到底该怎么刷才有效,是不是把答案背下来就稳了。说实话,我面试过不少候选人,也在牛客网刷过很多题,见过太多“背得很熟但一追问就露馅”的情况。这篇内容我打算把自己反复研…

2026/9/24 22:38:36 阅读更多 →
EMC测试中30MHz分界线:传导发射与辐射发射的物理奥秘与整改实战

EMC测试中30MHz分界线:传导发射与辐射发射的物理奥秘与整改实战

做EMC测试的老哥估计都问过这个问题:传导发射(CE)测得好好的,一测到30MHz,标准就喊停;换到辐射发射(RE),嘿,又从30MHz开始测。两个频段无缝衔接,跟…

2026/9/24 22:37:35 阅读更多 →

日新闻

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为…

2026/9/24 0:00:19 阅读更多 →
单细胞注释实战:基于Scanpy的标记基因与参考映射流程解析

单细胞注释实战:基于Scanpy的标记基因与参考映射流程解析

简介:一份基于单细胞RNA测序数据的细胞类型注释算法研究Python毕业设计源码,针对计算机相关专业正在做毕设或需要项目实战的学习者,可用于课程设计与期末大作业。项目代码完整、经导师指导评审通过,可直接运行,覆盖数据…

2026/9/24 0:00:19 阅读更多 →
C#源生成器实战:用增量生成器替代反射,告别AOT崩溃

C#源生成器实战:用增量生成器替代反射,告别AOT崩溃

第一次在项目里被反射卡住,是在一个老旧的WinForms模块里:几十个类依赖PropertyChanged通知,运行时反射读属性、发通知,每次启动慢半拍不说,一上.NET Native/AOT裁剪模式几乎全面崩盘。后来我把这段逻辑全部改成C#源生…

2026/9/24 0:00:19 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/24 14:34:13 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/24 9:10:42 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/24 14:33:56 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/24 12:50:34 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/24 14:33:48 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/24 12:49:17 阅读更多 →