46 KiB
Lark IM 与 DWS Multi IM Skill 设计对比
状态:设计评审
日期:2026-08-03
DWS Git 基线:分支
codex/multi-im-optimization,HEAD017258e5b49517e3787a3d373f90953c128eaf58(feat(im): optimize Multi IM golden routes)工作区口径:评审时除本文档为未跟踪文件外,DWS 业务代码、Skills、references 和 scripts 均与上述 HEAD 一致;因此“当前实现”指该提交,不指远端默认分支。
对比基线:当前工作区中的 DWS Multi IM 实现,以及本机安装的
lark-im、lark-shared、lark-contact、lark-eventSkills评审范围:Skill 根入口、shared 契约、目标解析、发送/读取/搜索、群聊、 消息资源、卡片、事件、Schema 元数据、task references 与配套脚本
实施后说明:本文是对上述提交的历史基线审计,其中“当前问题”、旧脚本路径和 文件数统计不代表优化后工作树。实施结果与完成口径见 DWS Multi IM 优化方案。被退役脚本的链接作为历史证据保留, 不应再被当作可执行入口。
1. 执行摘要
当前 DWS Multi IM 的主链设计比 lark-im 更适合 Agent 执行:
- 根 Skill 更小,只保留 Golden Route、不可推导的结果语义和按需导航;
- 人名、群名解析已经下沉到共享 typed resolver;
- 发送、读取、搜索、建群和事件 facade 能复用同一套消歧规则;
- 消息查询具有
complete、hasMore、failures和资源下载 ledger,能够证明 结果是否完整; event +listen-im能把自然目标和事件意图确定性编译为多个 EventKey,并复用 一个 consume 生命周期;- 参数、安全、selection 与 interface 事实由 reviewed Schema 输入和 Runtime 交付, 不需要在根 Skill 复制完整参数表。
但当前实现只完成了“根 Skill 收敛”,还没有完成“整条文档链收敛”。进入第二层
reference 后,部分文档仍会把 Agent 带回手工查 ID、原子发送、原子建群和原子回复;
这些路径不仅增加步骤,还可能从带 typed_yes 门禁的 Golden Shortcut 切换到
confirmation=not_required 的原子 leaf。Shared 故障文档和三个遗留 Python 脚本也
存在同样的代际漂移。
总体判断:
主链架构:DWS 更优
文档一致性:Lark 更优
任务闭环:DWS 高频路径更优,Lark 富媒体/Thread/Card 更完整
当前主要风险:DWS 子 reference 与脚本仍形成第二套执行语义
2. 对比方法与口径
本评审以实际文件和当前 CLI 合同为依据,不按命令名称做表面对齐。
事实优先级:
当前 Cobra/Runtime
→ DWS leaf Schema 与 reviewed metadata/selection
→ 产品根 Skill
→ 精确 task reference
→ 全量原子参考与遗留脚本
Lark 侧重点读取:
~/.agents/skills/lark-im/SKILL.md~/.agents/skills/lark-shared/SKILL.md~/.agents/skills/lark-contact/SKILL.md~/.agents/skills/lark-event/SKILL.md~/.agents/skills/lark-im/references/~/.agents/skills/lark-event/references/lark-event-im.md
DWS 侧重点读取:
dingtalk-chat/SKILL.mddws-shared/SKILL.mddingtalk-event/SKILL.mddingtalk-contact/SKILL.mddingtalk-aisearch/SKILL.mddingtalk-chat/references/event-im.mdtargetresolverevent +listen-imchatSchema registry/metadata/selection
2.1 当前文件体量
| 内容 | Lark | DWS Multi |
|---|---|---|
| IM 根 Skill | 249 行 / 21,524 bytes | 103 行 / 8,346 bytes |
| 正常 IM 强制 shared | 211 行 / 10,908 bytes | 0;最小契约内嵌 |
| IM references | 58 个 Markdown,5,336 行 | 9 个 Markdown,1,467 行 |
| IM scripts | 无 | 3 个 Python,565 行 |
| Event 根 Skill | 156 行 / 10,848 bytes | 100 行 / 7,521 bytes |
这组数字不能单独证明设计质量,但能够说明两套系统的基本取向:
Lark:操作手册 + 显式 API/Scope Catalog
DWS:意图编译器 + Runtime/Schema 合同
3. 根 Skill 逐段映射
3.1 Frontmatter 与产品边界
lark-im/SKILL.md L1–13:
- 声明 Skill 版本、CLI bin 和
cliHelp; - 将消息、群聊、文件、Reaction、卡片、Feed、Flag 和短信/电话加急都归入 IM;
- 强制先完整读取
lark-shared。
- 声明 DWS 最低版本、产品分类和 CLI bin;
- 明确把紧急 DING/短信/电话切到
dingtalk-misc,邮件切到dingtalk-mail; - 不要求正常单产品任务完整读取
dws-shared。
判断:DWS 的产品边界更清楚;Lark 的 IM 边界更宽,但因此根文件承担更多平台概念。
3.2 对象模型
lark-im/SKILL.md L15–34 在根文件定义:
- Message;
- Chat;
- Thread;
- Reaction;
- Flag;
- Feed Shortcut;
- Feed Group;
- Chat → Message/Member → Thread/Reaction/Resource 的对象关系。
DWS 根 Skill 没有完整对象树,只在
dingtalk-chat/SKILL.md L71–78
保留无法从普通 leaf 参数推导的关键区别:
openTaskId不是消息 ID;- 子消息使用自己的
messageId; - Favorite、消息 Pin、消息 Top、会话 Top 不是同一对象。
判断:Lark 更适合首次理解平台;DWS 更节省根上下文,但对象语义分散到多个 reference 和 Runtime DTO。
3.3 Shared 与身份
lark-im/SKILL.md L38–42 和 lark-shared/SKILL.md L48–87 显式解释:
--as user使用 UAT;--as bot使用 TAT;- app scope、用户授权、群成员关系和租户边界共同决定是否成功;
- bot 缺 Scope 与 user 缺 Scope 的恢复路径不同。
DWS 通过
runtime-contract.md
强调:
- 解析、读取和写入使用同一 profile;
- 不跨组织复用
userId、openDingTalkId、openConversationId; - 是否确认以最终 Runtime gate 和 Schema 为准。
具体 user/bot/webhook 能力矩阵不在根 Skill 展开,而由 +messages-send 的 leaf
Schema 与 Runtime 校验。
判断:DWS 的 typed 交付更可维护,Lark 的身份故障解释更直接。
3.4 消息富化与资源
lark-im/SKILL.md L44–59 把下列事实直接放在根 Skill:
- sender name 由服务端返回,不额外查询 contact;
- 四个消息读取 Shortcut 默认附加 reactions 和编辑后的
update_time; - 三个读取 Shortcut 支持
--download-resources; - 资源按
(message_id, file_key)去重、并发下载、单项失败隔离。
DWS 在
dingtalk-chat/SKILL.md L71–77
只保留任务级结果语义:
- list/search/mget 共享稳定消息投影;
- 检查
complete、hasMore、failures; - 下载失败进入 ledger,不丢弃已取得消息;
- 路径必须位于工作目录内,默认不覆盖,完成后原子落盘。
内部由 chatmsg 维护
im.message-list.v1、reaction、updateTime、resourceRefs 和分页完整性。
判断:DWS 更强调“能否证明完整”;Lark 更强调字段来源、批量并发和缺字段语义。
3.5 卡片、音频与跨产品内容
lark-im/SKILL.md L61–75 在根文件声明:
- Interactive Card 发送前必须读取专用建卡 workflow;
- 卡片 callback 走
card.action.trigger; - Opus 才能作为语音消息;
- Lark Doc 内容应以
im-markdown读取后再用 Markdown 发送。
DWS 根 Skill只将流式卡片路由到 +messages-send-card,并把参数交给精确 leaf
Schema。当前 DWS 卡片是创建/流式更新模型,不等同于 Lark 任意 Interactive Card
JSON,也没有同等的 callback Skill 闭环。
判断:DWS 的根设计更紧凑;Lark 的卡片设计和回调闭环更完整。该差异属于真实平台 能力差异,不应通过复制参数伪装对齐。
3.6 Shortcut 发现
lark-im/SKILL.md L100–126 在根文件逐项列出 22 个高阶 Shortcut。
dingtalk-chat/SKILL.md L28–60
只说明当前有 97 个公开 Shortcut,并暴露:
- 8 条 Golden Route;
- 6 条次级直接入口;
- 完整 Catalog 仅作最后发现回退。
判断:
- 高频首次选路:DWS 更好;
- 低频能力人工浏览:Lark 更直接;
- DWS 必须保证精确 references 与 Golden Route 一致,否则隐藏全量 Catalog 后将缺少 可靠的第二层导航。
3.7 原生 API 与 Scope
lark-im/SKILL.md L128–249 继续列出原生 API 资源和完整 Scope 表;调用原生 API 前
要求先查询 Schema。
DWS 根 Skill不放原子 API 和 Scope 表,只在最后降级到
chat.md,并把参数、selection、安全和
interface 事实交给 reviewed Schema 输入。
判断:DWS 更符合单一事实源和防漂移目标;Lark 更方便人工排障,但静态权限表与参数表 的维护成本更高。
4. 相关 Skill 与子产品设计
4.1 Shared 冷启动
Lark 的每个 IM task reference 都重复声明必须先读 lark-shared。优点是身份、授权、
JSON envelope 和高风险 exit-10 协议随处可见;代价是高频任务反复加载同一大段文本。
DWS 把 11 行最小契约作为 authored source,通过
gen_skill_shortcut_sections.py L193–210
注入 Chat 与 Shared。正常 IM 只读产品根 Skill,认证、权限、profile 和未知错误才进入
Shared reference。
这是 DWS 相对 Lark 最明确的架构改进之一。
当前边界问题:生成器只注入 Chat 和 Shared,但
dws-shared/SKILL.md L14
泛称“产品根 Skill 已内嵌最小执行契约”。Contact、AI Search 仍强制完整读取 Shared,
Event 则没有注入该 marker。这一描述应收窄为真实覆盖范围,或将注入机制推广到其它
明确需要独立冷启动的产品根。
4.2 Contact、AI Search 与目标解析
Lark 的姓名发送仍是两条业务命令:
lark-contact +search-user
→ Agent 选择 open_id
→ lark-im +messages-send
群名读取同样先 +chat-search 再调用消息读取。
DWS 将确定性目标解析下沉到
targetresolver:
ResolveUser;ResolveChat;ResolveUsers;ResolveChats;- 稳定 ID 去重;
- exact/unique 匹配;
ambiguous/not_found结构化 candidates;- 批量全量预检。
它被 +dm、+send-to-group、+messages-send、+chat-messages、+search-msg、
+chat-create 和 event +listen-im 复用。
判断:DWS 在高频 IM 目标解析上明显优于 Lark。Contact/AI Search 仍应保留给人员详情、 组织关系和独立搜索意图,但不应重新成为普通发消息的强制前置步骤。
4.3 Event
Lark Event 是跨产品通用控制面:
- 根 Skill 负责 list/schema/consume、ready、stdin、退出码和 jq;
- IM reference 维护 12 个 EventKey;
- 一个 consume 进程只接受一个 EventKey;
- 多事件由多个进程完成。
DWS Event 是个人 IM 专用产品,并增加
event +listen-im:
kind + events + target
→ typed resolver
→ 确定 EventKey 集合
→ 一次 event consume 生命周期
DWS 能在一个进程中复用单 bus、多 consumer、ready marker、NDJSON、回滚和退出清理。
判断:
- 高频个人 IM 监听:DWS 更适合 Agent;
- 跨产品事件和任意 payload/jq 探索:Lark 更通用;
- DWS 不应复制 Lark 的“一 EventKey 一进程”限制。
4.4 子文件粒度
Lark 采用“一个高阶 Shortcut 一个 reference”的细粒度模式,并为卡片拆出 schema、 style、组件和 callback workflow。优点是加载后任务边界清晰,缺点是文件总数和总体积较大。
DWS 采用较少、较宽的子产品 reference:
01-messaging.md:任务级组合;chat-message.md:消息、搜索、卡片、Reaction、Pin/Top/Favorite;chat-group.md:群与成员;chat-bot.md:Bot 与 Webhook;chat-conversation.md:会话状态;chat.md:全量原子降级。
这种粒度本身合理,但每个宽 reference 必须先重申自己负责的 Golden Shortcut,再把原子 命令放入明确的降级区。当前部分文件仍以原子命令作为正文主路径,导致加载 reference 后 发生路由反转。
4.5 子产品依赖闭包
这里的“相关子产品”按真实导航边定义:根 Skill、reference 或 Runtime 会把任务交给它, 而不是仅仅因为它也属于协作套件。
flowchart LR
U["用户 IM 意图"]
subgraph L["Lark"]
LI["lark-im:消息与群聊主产品"]
LS["lark-shared:强制冷启动"]
LC["lark-contact:姓名/邮箱 → open_id"]
LE["lark-event:实时事件"]
LD["lark-doc:文档正文 → im-markdown"]
CARD["lark-im/card:卡片编译子树"]
LI --> LS
LC --> LI
LE --> LI
LD --> LI
LI --> CARD
end
subgraph D["DWS Multi"]
DC["dingtalk-chat:消息与群聊主产品"]
DS["dws-shared:安装必带、故障按需读取"]
DP["dingtalk-profile:profile/组织选择"]
DA["dingtalk-aisearch:人员语义搜索"]
DT["dingtalk-contact:人员详情/精确手机号"]
DE["dingtalk-event:个人 IM 事件"]
DM["dingtalk-misc:DING/短信/电话"]
DX["drive/todo/calendar/mail:跨产品终点"]
DC -. "认证/权限/未知错误" .-> DS
DS --> DP
DA --> DT
DA -. "普通自然目标由 typed resolver 旁路" .-> DC
DT -. "资料查询后交接" .-> DC
DE --> DC
DC --> DM
DC --> DX
end
U --> LI
U --> DC
Lark 子产品逐项
| 子产品/子树 | 进入条件 | 合同所有者 | 与 IM 的关系 |
|---|---|---|---|
lark-im |
消息、群、资源、reaction、flag、feed、urgent、card | IM 根 Skill + 精确 Shortcut reference + CLI | 主产品 |
lark-shared |
所有 IM/Event 操作前 | 认证、user/bot、scope、JSON envelope、exit 10 | 强制前置;每个 IM task reference 再次提醒 |
lark-contact |
姓名/邮箱目标、已知 ID 补资料 | +search-user / +get-user |
普通按姓名发消息仍需 contact → im 两步 |
lark-event |
实时消息、reaction、群变化、card callback | 通用 event consume 生命周期 |
IM 只是 12 个 EventKey 中的一个 topic;一 key 一进程 |
lark-doc |
把文档正文作为消息发送 | --doc-format im-markdown |
内容生产者;IM 保持原文并以 Markdown 发送 |
lark-im/references/card |
发送 interactive 卡片 |
card schema、style、component、resource | 不是独立产品,但拥有独立编译/校验工作流 |
lark-openapi-explorer |
Contact 不覆盖的部门树/组织架构 | 原生 OpenAPI 探索 | 仅由 Contact 边界引出,不属于普通 IM 链 |
Lark 没有独立 profile 子产品。身份切换集中在 lark-shared 的 --as user|bot;紧急
应用内/短信/电话能力留在 lark-im,没有像 DWS 一样拆到 sibling Skill。
DWS Multi 子产品逐项
| 子产品 | 进入条件 | 合同所有者 | IM 链中的地位 |
|---|---|---|---|
dingtalk-chat |
消息、群聊、资源、Bot/Webhook、会话状态 | Golden Route + Runtime Shortcut + leaf Schema | 主产品 |
dws-shared |
安装时始终附带;认证/权限/profile/confirmation/未知错误时读取 | 最小 Runtime 契约与故障导航 | 正常路径不冷启动,故障路径按需 |
dingtalk-profile |
多账号、多组织、切换 profile | profile/组织选择规则 | 由 shared 引出;保障解析、读取、写入同 profile |
dingtalk-aisearch |
姓名、工号、职责、上下级、部门语义搜索 | 人员语义候选 | 普通 DM/群目标已由 Chat typed resolver 内化,不再是强制前置 |
dingtalk-contact |
已知 ID 补详情、完整手机号、部门/角色 | 精确通讯录事实 | 作为资料查询/低层 ID 补全 sibling |
dingtalk-event |
监听消息、reaction、已读、撤回、群生命周期 | +listen-im 与 event consume |
个人 IM 实时入口;回复交回 Chat |
dingtalk-misc |
DING、短信、电话、班级群 | Misc 内部的 Ding 等 reference | Chat 明确排除,产品边界比 Lark 更窄 |
dingtalk-mail |
用户目标是邮件 | Mail Skill | Chat 边界排除 |
dingtalk-drive |
查询群钉盘/群文件 | Drive Skill | 先由 Chat 取 spaceId,再交给 Drive |
dingtalk-todo |
消息转待办 | Todo Skill | Chat 读取真实消息上下文后交接 |
dingtalk-calendar |
消息转日程 | Calendar Skill | Chat 读取时间、地点、参会人后交接 |
不应把 dingtalk-dev 计入日常 IM 数据链。它管理应用、机器人配置或开发控制面;当前
Chat 根 Skill 和精确 task references 没有把普通消息任务路由到它。
4.6 Multi 安装与发布边界
DWS Multi 不只是仓库里的文档目录,它有独立交付边界:
skills/embed.goL23–29 将mono与multi整棵目录嵌入 二进制,包含 references 和 scripts;skill_setup.goL77–95 将 multi 标记为EXPERIMENTAL/Preview,支持按子 Skill 安装;skill_setup.goL139–156 即使用户只选 Chat,也会 强制附带dws-shared;- 安装采用 additive 语义,不删除未列出的已安装 sibling Skill;
- Release 的
dws-skills.zip同时携带根部兼容 mono、显式mono/和完整multi/。
这带来一个重要设计结论:Multi reference/script 是真实发布产物,不能按“开发辅助文件”
处理。但当前 Agent Schema 生成的 Markdown evidence 入口仍主要是 skills/mono/;Multi
文档并不会因为 Schema 生成成功就自动证明自己与 Runtime 一致。这正是第二层漂移需要
独立 policy gate 的原因。
5. References 逐文件对比
5.1 Lark IM references 全量清单
Lark IM 共 58 个 Markdown reference:顶层 26 个,Card 子树 32 个。根 Skill 直接链接 全部 21 个 Shortcut task reference,并另外链接 enrichment、reaction、feed 原子合同和 card workflow。它的基本单元是“一个任务/一个 Shortcut/一个精确合同”。
| 顶层 reference | 行数 | 职责 | DWS 对应/差异 |
|---|---|---|---|
lark-im-card-action-reply.md |
175 | card.action.trigger 监听、解析、回卡 |
DWS 无等价 callback Skill 闭环 |
lark-im-chat-create.md |
162 | 建群、身份、owner、成员、输出 | +chat-create + chat-group.md;DWS 自然成员解析更强 |
lark-im-chat-identity.md |
55 | 群主、user/bot 操作者判断 | DWS 分散在 profile、Schema identity 和 Runtime |
lark-im-chat-list.md |
166 | 当前身份加入的会话、排序、分页、mute | DWS 会话/群列表 Shortcut 与 chat-conversation.md |
lark-im-chat-members-list.md |
83 | users/bots 分桶与截断语义 | DWS group members;无同等独立 truncation reference |
lark-im-chat-messages-list.md |
157 | 单会话消息、thread 展开、资源、分页 | DWS +chat-messages;更强调 complete/failures ledger |
lark-im-chat-search.md |
142 | 按关键词/成员搜群、mute、分页 | DWS +chat-search 或目标 resolver |
lark-im-chat-update.md |
84 | 群名/描述更新与身份边界 | DWS group rename/settings;没有统一精确 task reference |
lark-im-feed-group-list-item.md |
68 | 列出标签内 feed cards | DWS category list-conversations,平台语义不完全相同 |
lark-im-feed-group-list.md |
65 | 列出 feed groups | DWS category list |
lark-im-feed-group-query-item.md |
44 | 按 ID 查标签成员 | DWS category batch/list-by-conv,仅近似映射 |
lark-im-feed-groups.md |
452 | Feed Group 原子 API、枚举、规则、scope | DWS chat-conversation.md 的 category 族;不应字段级复制 |
lark-im-feed-shortcut-create.md |
97 | 会话 Feed 置顶、批量结果 ledger | DWS conversation set-top,缺少同粒度 task reference |
lark-im-feed-shortcut-list.md |
103 | Feed 置顶列表与 detail enrichment | DWS +conversation-list-top |
lark-im-feed-shortcut-remove.md |
48 | 取消 Feed 置顶与幂等语义 | DWS set-top off |
lark-im-flag-cancel.md |
67 | message/feed 两层 flag 的 best-effort cancel | DWS Favorite/Top 对象不同,不应机械对应 |
lark-im-flag-create.md |
67 | 创建 message/feed flag 与合法组合 | DWS Favorite/消息 Top 仅部分近似 |
lark-im-flag-list.md |
101 | flag 排序、分页上限、thread enrichment | DWS list-favorites 等分散能力 |
lark-im-message-enrichment.md |
54 | reaction、更新时间、thread、资源富化合同 | DWS 根结果语义 + chatmsg Runtime;不是独立 reference |
lark-im-messages-mget.md |
99 | 最多 50 条批量消息详情 | DWS +messages-mget |
lark-im-messages-reply.md |
277 | 安全、内容格式、媒体、thread reply、返回值 | DWS +messages-reply 当前只覆盖较窄文本引用回复 |
lark-im-messages-resources-download.md |
94 | 资源 key、8 MB 分块、扩展名检测 | DWS +messages-resource-download;本地安全/ledger 更强 |
lark-im-messages-search.md |
234 | 搜索、自动二步富化、分页、报告生成 | DWS +search-msg;typed target 与完整性更强 |
lark-im-messages-send.md |
279 | user/bot 发送、内容格式、媒体、mention、返回值 | DWS +messages-send;平台能力矩阵不同 |
lark-im-reactions.md |
299 | reaction CRUD/batch、完整 emoji enum | DWS reaction/文字表情分散在 chat-message + emoji 表 |
lark-im-threads-messages-list.md |
115 | thread ID 来源、分页、资源 | DWS +thread-replies,当前主要是 reader |
Card 的 32 个子文件不是普通“补充说明”,而是一个内嵌小型子产品:
| 层 | 文件数 | 文件 | 设计职责 |
|---|---|---|---|
| 工作流 | 1 | lark-im-card-create.md |
强制生成/校验/发送流程;禁止手写卡片 payload |
| Schema | 1 | card-2.0-schema.md |
卡片 2.0 可用组件及嵌套关系 |
| Style | 1 | lark-im-card-style.md |
版式、层级、间距、视觉规范 |
| Components | 27 | button、chart、checker、collapsible_panel、column_set、date_picker、div、form、header、hr、img、img_combination、input、interactive_container、markdown、multi_select_person、multi_select_static、overflow、person、person_list、picker_datetime、picker_time、recycling_container、select_img、select_person、select_static、table |
每组件合法字段、枚举、嵌套和示例 |
| Resources | 2 | colors.md、icons.md |
受控视觉枚举 |
DWS 当前只有流式卡片发送/更新命令和 chat-message.md 中约 10 行说明,没有对应的卡片
Schema/组件/风格/callback 子树。因此卡片差异不是“少写几篇 reference”,而是缺少一个
可独立审计的卡片编译层。
5.2 DWS Chat references 全量清单
| reference | 行数 | 当前角色 | 主要问题 | 建议归宿 |
|---|---|---|---|---|
01-messaging.md |
76 | Golden Route 不能单步覆盖时的任务编排 | 与根路由总体一致 | 保留为任务级主 reference |
chat-emoji-list.md |
209 | 199 个默认表情枚举 | 静态大表;易随平台漂移 | 若 Runtime 可查询则生成,否则加来源/更新时间门禁 |
intent-guide.md |
51 | 低频意图与对象层级消歧 | 与根路由一致 | 保留,继续限制为低频加载 |
lite-recipes.md |
5 | recipe 导航壳 | 只重定向到 01-messaging,价值很低 |
合并或删除,减少无效跳转 |
chat.md |
363 | 原子能力总索引与回退 | 前 20 行说 Shortcut 优先,后续大量意图表又把原子命令设为默认 | 降级为纯 Catalog/原子 fallback,不再承担任务选路 |
chat-message.md |
269 | 消息、搜索、卡片、reaction、资源 | L23 起重新以原子 send 为主;reply 也回退原子路径 | 先列对应 Shortcut,再隔离原子特殊字段区 |
chat-group.md |
215 | 群、成员、公告、设置、身份 | L32 起以原子建群为主,L186 再次手工搜人 | +chat-create 为默认;管理原子命令保留 |
chat-bot.md |
139 | Bot/Webhook、机器人进群/撤回 | L11 与根 +messages-send --as bot/webhook 直接冲突 |
统一发送走 Shortcut;专属管理能力保留 |
chat-conversation.md |
140 | 会话状态、Top、mute、category | 仍手工 aisearch → conversation-info,部分能力缺 Shortcut 首选说明 |
按对象层级列高阶入口;原子管理作为细节 |
DWS 的优点是只有 9 个 Chat reference,Agent 不必在 58 个文件中发现入口;缺点是每个 文件跨度过宽,任务级路由、原子 Catalog、参数表、工作流和错误处理常在同一文件内混合。 Lark 的精细拆分值得吸收,但不必照搬“一 Shortcut 一文件”到所有 97 个 Shortcut。
5.3 相关子产品 references
| 子产品 | reference/script 规模 | IM 实际读取点 | 评审结论 |
|---|---|---|---|
dws-shared |
12 个 reference:runtime-contract、routing、workflow-routing、global-reference、error-codes、capability-limits、channel-login、url-patterns、intent-guide 和 3 个 common recipe/convention 文件 |
正常 Chat 不预读;错误、跨产品或 URL 不明时精确进入 | 分层正确,但 global-reference/error-codes 已有 Runtime 漂移 |
dingtalk-event |
1 个 event-im.md,399 行 |
群生命周期、精确 EventKey、Filter、订阅运维/排障 | 单文件过宽;高频已回根,建议再拆 lifecycle/filter/ops |
dingtalk-contact |
5 个 reference + 1 个 contact_dept_members.py |
人员资料、完整手机号、部门/角色;不是普通 DM 必经 | 根 Skill 仍重、仍优先脚本;与 Chat 新 resolver 代际不同 |
dingtalk-aisearch |
3 个 reference,无脚本 | 语义找人、跨源检索 | 对独立搜索正确;不应回流为 Chat 普通自然目标前置 |
dingtalk-profile |
规则集中在根 Skill | 多组织/profile 消歧 | 应由 shared/Runtime 统一,不应复制到每个 Chat reference |
Lark 相关 sibling 的规模更小:lark-contact 只有 2 个 task reference,lark-event 的 IM
部分只有 1 个 86 行 reference;但它把较多通用生命周期合同放在各自根 Skill。DWS 则把
Event 的大量运维细节放入一个 399 行 IM 文件,两侧“文件数”不能脱离根文件体量比较。
5.4 Reference 加载链结论
理想链路应满足:
根 Skill 选意图
→ 一个精确 task reference 补充不可推导语义
→ leaf Schema 提供参数/安全/interface 真相
→ Runtime 执行
当前 Lark 基本符合这个形状,但根和 shared 更重;当前 DWS 根已经符合,第二层却常变成:
根 Skill 选 Golden Shortcut
→ 宽 reference 重新选原子命令
→ 复制静态 flags/返回结构
→ 绕开原 Shortcut 的 resolver、DTO 或 confirmation gate
所以 DWS 的整改重点不是增加 reference 数量,而是让每个 reference 只拥有一种职责: 任务选路、平台语义、原子 fallback 或静态枚举,不能四者混合。
6. Scripts 逐文件对比
6.1 Lark IM scripts
lark-im、lark-contact、lark-event 当前均没有产品内 scripts/。这不是能力缺失:
- 自动分页、thread 展开、reaction 富化、资源下载、目标搜索等编排在 CLI Shortcut 内;
- 卡片生成通过 reference 驱动的 workflow 完成;
- Event 的长连接生命周期由
event consume承担; - 因而不存在“脚本自行解析 CLI JSON、再调用第二套原子命令”的旁路。
6.2 DWS Chat 产品 scripts
Multi Chat 的 3 个 Python 会随 skills/multi 一起嵌入二进制和发布包,即使根 Skill 与
references 没有导航到它们。它们不是未交付的草稿,而是“已交付但不可发现”的旁路。
| script | 行数 | 做什么 | 逐行级问题 | 建议 |
|---|---|---|---|---|
bot_broadcast.py |
112 | 对多个会话逐个调用机器人发送 | L92–99 直接调用原子 send-by-bot;仅以进程码/是否有 JSON 判断成功;无 profile、confirmation、幂等键、逐项 unknown ledger |
若真实需要批量能力,应下沉为 typed Runtime Shortcut;否则删除 |
chat_export_messages.py |
230 | 搜群、翻页、导出 JSON | L88 默认 groups[0];自行兼容多种旧 envelope;固定 +08:00;直接写任意输出路径;没有 complete/failures/resource 合同 |
已被 +chat-messages --chat-query 和任务结果合同覆盖,应删除或只做稳定 DTO 导出器 |
chat_history_with_user.py |
223 | 搜人、翻页、导出单聊 | L57 明示返回首项,L80 users[0];还调用已不推荐的 contact user search;同样自行猜 envelope、固定时区和直接写文件 |
已被 +chat-messages --user-query 覆盖,应删除 |
还有一层副本漂移:同名脚本同时存在于 skills/mono/scripts/ 和
skills/multi/dingtalk-chat/scripts/。bot_broadcast.py 当前字节一致;另外两个已经不同,
Multi 副本新增 nextCursor 与错误兼容,而 Mono 副本未同步。没有单一 authored source 或
生成门禁时,即使保留脚本,也会形成 mono/multi 两套行为。
6.3 DWS 仓库级相关 scripts
这些 scripts 不随单个 Chat Skill 作为操作 recipe 使用,但决定 Shortcut、Skill 文档、 测试证据和发布质量。应与产品脚本分开评审。
| script | 行数 | 角色 | 是否覆盖 Multi 第二层 |
|---|---|---|---|
gen_skill_shortcut_sections.py |
253 | 从公开 Catalog 生成 Shortcut 区块,并把最小 Runtime contract 注入 Chat/Shared | 只改根 Skill 生成块,不改 Chat references/scripts |
check-skill-context-budget.sh |
109 | Chat/Event 根字节预算、必备 Golden Route、旧路由禁词 | 不扫描 references/scripts |
check-skill-commands.sh |
16 | 构建并运行 Skill 命令静态检查器 | 检查命令可解析,不证明首选路由/安全门禁一致 |
gen_shortcut_public_catalog.py |
255 | 生成公开 Shortcut Catalog 和 Go 投影 | Runtime Catalog 层,不审文档加载链 |
gen_shortcut_test_matrix.go |
316 | 通过真实 Cobra 树与 fake caller 装配全部 Shortcut | 证明命令装配,不审原子 reference 旁路 |
gen_shortcut_comparison.py |
580 | 聚合 Shortcut 对比和测试 HTML | 报告生成,不是 policy gate |
gen_shortcut_backend_mcp_issues.py |
237 | 汇总下层 MCP 对接问题 | Runtime 后端审计 |
gen_shortcut_error_review.py |
449 | 将测试失败映射到修复位置 | 测试报告辅助 |
record_real_shortcut_run.py |
135 | 记录真实 Shortcut 运行结果 | 单次证据采集 |
shortcut_real_result.py |
480 | 统一解析真实运行的成功/失败事实 | 审计公共库,不供产品脚本复用 |
run_shortcut_real_write_matrix.py |
455 | 真实写 Shortcut 矩阵 | 跨产品写审计 |
run_chat_shortcut_live_audit.py |
1,162 | Chat 只读 Shortcut 真实链路审计 | Runtime 很深,但不扫描文档 |
run_chat_shortcut_live_write_audit.py |
865 | Chat 真实写入/清理审计 | Runtime 很深,但不扫描产品 scripts |
run_chat_shortcut_write_dry_run_audit.py |
1,101 | Chat 写 Shortcut dry-run 合同审计 | 证明 Shortcut 预览,不证明 reference 会选择它 |
因此当前 DWS 已有大量 Runtime/Shortcut 审计资产,真正缺的是很薄的一层“发布内容一致性” 检查,而不是再增加一个大型 live audit:
- 枚举 Multi 根 Skill 的所有 reference 边;
- 抽取 reference 和产品 script 中出现的 CLI path;
- 与 reviewed selection、Runtime confirmation 和 Golden Route 对照;
- 拒绝
users[0]/groups[0]、旧 envelope、未声明原子 fallback; - 检查 mono/multi 同名脚本是否来自单一源或明确允许差异。
7. 能力对比
| 场景 | 更强的一方 | 说明 |
|---|---|---|
| 按姓名/群名直接发送 | DWS | 一条业务命令完成解析、消歧和发送 |
| 自然目标读取、搜索和建群 | DWS | 共享 resolver、批量预检、结构化歧义 |
| 分页完整性与 partial result | DWS | complete/hasMore/failures 任务级合同 |
| 统一发送身份 | DWS | 一个 +messages-send 承载 user/bot/webhook 的真实子集 |
| Thread 自动展开 | Lark | list/mget 默认扩展 replies;DWS 使用单独读取入口 |
| 回复能力 | Lark | 支持 user/bot、媒体和 thread reply;DWS 当前只做用户纯文本引用回复 |
| 卡片创建与 callback | Lark | 建卡 workflow、Schema、自检和 card.action.trigger 完整 |
| 资源下载细节 | Lark | 8 MB 分块、扩展名检测和身份 Scope 描述更完整 |
| 下载安全与完整性 ledger | DWS | 相对路径、默认不覆盖、原子落盘、失败并入任务完整性 |
| 多事件 Agent 监听 | DWS | 多 EventKey、自然目标、单进程统一生命周期 |
| 通用跨产品事件 | Lark | 同一 Event Skill 覆盖 IM/Approval/Task/VC 等 |
| Scope/身份人工排障 | Lark | 根 Skill 与 shared 更显式 |
| 参数和安全防漂移 | DWS | reviewed registry + metadata + selection + generated Catalog |
| Feed/会话分类 | 不可直接比较 | 平台对象不同,不能只按名称映射 |
| 紧急短信/电话 | 产品边界不同 | Lark 放在 IM;DWS 放在 dingtalk-misc |
8. 当前设计漂移
8.1 高优先级:子 reference 把 Golden Shortcut 降级为原子写路径
根 Skill 已冻结以下入口:
建群 → +chat-create
引用回复 → +messages-reply
高级/Bot/Webhook 发送 → +messages-send
但子 reference 仍保留相反的默认路线:
chat-group.mdL32–49 以chat group create为建群主入口;L186–192 又要求先手工执行aisearch person。chat-message.mdL23–68 以原子chat message send为发送主入口;L146–153 以原子message reply为引用回复。chat-bot.mdL11–15 强制所有 Bot 发送使用原子send-by-bot;L75–86 继续推荐原子 Webhook。event-im.mdL308–312 自动回复仍调用原子chat message send,与 Event 根 Skill 的+messages-send不一致。
这不是单纯的命令风格差异。当前 reviewed metadata 中:
+chat-create、+messages-reply、+messages-send为confirmation=user_required、runtime_gate=typed_yes;- 原子
chat message send和chat message reply为confirmation=not_required; - 当前 leaf Schema 同样显示原子 group create、bot send、webhook send 为
not_required。
因此,加载低频 reference 可能让同一个用户意图切换到更弱的安全门禁,同时失去 typed resolver、dry-run parity、稳定输出 DTO 或 continuation context。
8.2 高优先级:策略门禁只检查根 Skill
check-skill-context-budget.sh
当前检查:
- 根 Skill 字节预算;
- Golden Route 必备字符串;
- 根 Skill 中的旧
aisearch、Webhook、媒体上传和 shared 冷启动模式; - 根 Skill 是否重新展开完整 Shortcut 表。
它不扫描:
dingtalk-chat/references/**;dingtalk-event/references/**;dingtalk-chat/scripts/**;- reference 中的高阶入口与原子入口 confirmation 差异。
所以当前门禁可以通过,但无法证明整条 Skill 加载链一致。
8.3 高优先级:遗留 Python 脚本违反 typed resolver 原则
当前 Chat Skill 目录仍包含:
其中:
chat_history_with_user.py搜人后直接选择users[0];chat_export_messages.py搜群后直接选择groups[0];bot_broadcast.py逐群调用原子send-by-bot,不复用统一发送合同;- 三者均未被当前 Multi Chat 根 Skill 或 references 导航引用。
这些脚本形成孤立的第二套解析、分页、发送和错误处理系统,且直接违反“多候选禁止选择 第一项”的最小运行契约。
8.4 中优先级:Shared 故障文档已落后于 Runtime
global-reference.md 仍声明:
--format默认 table;- JSON 成功统一为
{"success":true,"body":...}; - 存在旧的全局 token 参数描述。
当前 CLI leaf Help 默认 JSON,Shortcut 又会输出各自的版本化 DTO。
error-codes.md L65–70
仍声称 Chat text 是位置参数而不是 flag;当前 Runtime Help 明确推荐 --text。
正常 IM 不加载这些文件是正确的,但一旦发生认证或执行错误,Agent 恰好会被路由到这些 过期信息,因此故障路径的一致性仍然重要。
8.5 中优先级:Shared 注入范围与文案不一致
dws-shared 声称产品根 Skill 已从同一来源内嵌最小契约,但生成器当前只更新 Chat 与
Shared。Contact、AI Search 继续强制读取 Shared;Event 没有受控注入 marker。
两种方案都可以成立,但必须选择一种明确合同:
- 文案收窄为“Chat 等已迁移产品根已内嵌”;或
- 将 marker 与生成门禁推广到全部需要独立冷启动的产品根。
8.6 低优先级:Event 根仍保留较多运维细节
当前 Event 根 Skill 已由 254 行缩至 100 行,但仍包含:
- 16 个兼容 EventKey;
- ready marker 细节;
0/2/1重试预算;- 本地订阅保护文件路径和权限。
这些内容本身正确,但与“根只保留高频入口,完整 EventKey/ready/retry 运维进入按需 reference”的目标仍有距离。可以根据真实误用率决定是否继续迁移,不应仅为缩短而删除 关键长连接安全信息。
9. 建议目标结构
9.1 保留 DWS 当前根设计
不要把 Lark 的完整 API、Scope 和 Shortcut 表复制回 DWS 根 Skill。目标结构继续保持:
Frontmatter / 产品边界
→ 最小 Runtime 契约
→ Golden Route
→ 不可推导的结果语义
→ 精确 task reference 导航
→ 最短错误分流
9.2 吸收 Lark 的精确 reference 原则
每个 reference 开头都应先声明本文件负责的高阶入口:
默认入口
→ 关键结果与安全语义
→ 平台限制
→ 只有需要原始响应/特殊下层能力时才进入原子降级
原子命令不应与 Golden Shortcut 并列为两个默认答案。
9.3 收敛子文件
建议按以下规则重写:
| 文件 | 默认高阶入口 | 原子命令保留条件 |
|---|---|---|
chat-message.md |
+messages-reply、+messages-forward*、+messages-send-card、+flag-* |
高阶入口未暴露的特殊字段或原始响应 |
chat-group.md |
+chat-create、群成员/设置对应 Shortcut |
无自然目标支持或 Shortcut 不覆盖的管理能力 |
chat-bot.md |
+messages-send --as bot/webhook |
多群广播、机器人撤回、入群等专属能力 |
chat-conversation.md |
+conversation-list-top 与对应 Shortcut |
低频分类/状态原子能力 |
event-im.md |
+listen-im、回复使用 chat +messages-send |
群生命周期、显式 EventKey、Filter DSL、订阅运维 |
9.4 处理遗留脚本
三种可选策略按推荐顺序排列:
- 已由 Golden Shortcut 完全覆盖的脚本从 Multi 发布包删除;
- 仍有价值的脚本改为调用 Golden Shortcut,并解析其稳定 DTO;
- 只有 Runtime 暂时无法承载的批量流程才保留脚本,同时增加 typed candidates、 profile、confirmation、partial failure ledger 和测试。
禁止继续维护“脚本自己搜第一个候选、自己拼原子写命令”的模式。
9.5 增加跨文件门禁
在现有预算检查之外增加:
- 扫描全部
dingtalk-chat/**和dingtalk-event/**,禁止已废弃默认路线回流; - 对每个 reference 中出现的写命令,验证它是否为该意图的 reviewed 首选入口;
- 若 reference 从 gated Shortcut 降级到 ungated 原子 leaf,必须有精确的、可审核的
fallback_reason; - 禁止脚本使用
results[0]、users[0]、groups[0]作为自然目标默认选择; - 校验根 Skill 导航的每个 reference 不会再次推荐与根相反的路径;
- 校验 shared 输出、全局 flags 和错误 envelope 与当前 Cobra/Runtime 一致。
10. 不应照搬的 Lark 设计
以下设计只可作为能力启发,不应直接迁移:
open_id、chat_id、message_id、资源 key 与 EventKey 名称;- user/bot 完全对称的富媒体假设;
- 群 description、initial bot、visibility、指定 owner;
- Thread writer;
- Interactive Card 1.0/2.0 JSON 和 callback 结构;
- Lark Feed Group 与 DingTalk 会话分类的字段映射;
- 完整根文件、静态 Scope 表和全量 API Catalog;
- 每个 task reference 强制重新读取整个 shared;
- 多 EventKey 必须多进程的实现限制。
DWS 应继续遵守“迁移任务能力,不迁移平台假设”。
11. 建议实施顺序
第一阶段:修正文档安全漂移
- 修正
chat-group.md、chat-message.md、chat-bot.md、event-im.md的默认入口; - 原子写命令降级必须说明原因和门禁差异;
- 修复 shared 的输出、flags、Chat 错误说明。
第二阶段:清理旁路
- 删除或重写三个孤立 Python 脚本;
- 增加禁止首候选和原子写回流的策略检查;
- 把 references 纳入同一生成/漂移审计。
第三阶段:继续能力闭环
在下层真实支持后再评审:
- Thread writer;
- Bot 富媒体;
- 卡片 callback;
- 分块/断点资源下载;
- 更丰富的群创建参数。
这些能力未落地前继续通过 avoid_when、availability 和 interface_reason 明确限制。
12. 验证记录
本次评审执行了:
./scripts/policy/check-skill-context-budget.sh
go test ./internal/shortcut/targetresolver -count=1
go test ./internal/shortcut/chat ./internal/shortcut/smart ./internal/app \
-run 'Test.*(ListenIM|NaturalTarget|MultiSkill|MessageView|MessagesSend|MessagesReply|ChatCreate)' \
-count=1
go test ./internal/app -run '^(TestEventListenIM|Test.*ListenIM.*)$' -count=1
结果:
- Chat 根 Skill 8,346 bytes,低于 10,000 bytes 门禁;
- 最小 Runtime 契约 1,531 bytes,低于 3,000 bytes 门禁;
- 根 Skill 未重新展开 Shortcut 表;
- target resolver、Chat/Smart 相关测试与 Event listen-im 测试通过。
这些结果证明根路由、Runtime 主链和预算门禁已经成立,但现有门禁尚未覆盖本评审识别的 子 reference、shared 故障文档和遗留脚本漂移。
13. 最终结论
DWS Multi IM 已经从“Agent 手工编排多个原子命令”升级为“产品 Skill 选择任务入口、
CLI 完成确定性执行”的架构。相较 lark-im,它在高频目标解析、任务级完整性、Schema
单一来源和多事件监听上更先进;相较 Lark 的不足主要不是根设计,而是第二层内容尚未
完全迁移到新架构。
最有价值的下一步不是继续缩短根 Skill,也不是增加更多同义 Shortcut,而是消除所有 子文件和脚本中的第二套执行语义,使任意合法加载路径最终都收敛到相同的 Golden Route、 Runtime gate、typed resolver 和结果合同。