Unify natural target resolution and message contracts, add deterministic IM event listening, streamline cold-start skills, and cover the flows with schema gates and end-to-end tests.
1547 lines
60 KiB
Markdown
1547 lines
60 KiB
Markdown
# Multi IM 优化完整执行方案
|
||
|
||
> 状态:方案已实施并完成端到端验证
|
||
>
|
||
> 日期:2026-08-03
|
||
>
|
||
> 适用范围:DWS Multi Skill 的 IM 发送、读取、搜索、群创建、回复、资源下载与个人 IM 事件监听
|
||
>
|
||
> 实现分支:`codex/multi-im-optimization`(基于最新 `origin/main`)
|
||
>
|
||
> Token 口径:`tiktoken 0.12.0`、`o200k_base`
|
||
|
||
## 0. 执行摘要
|
||
|
||
本方案的核心不是继续增加 Shortcut,也不是盲目追求 Skill 更短,而是提高每个控制 Token 对正确选路、正确执行、安全和结果判断的贡献,并把仍需 Agent 手工完成的名称解析、分页、富化、资源处理和事件映射下沉到 CLI。
|
||
|
||
目标路径统一为:
|
||
|
||
```text
|
||
激活 dingtalk-chat
|
||
→ 从有限 Golden Route 中选择最小充分的意图入口
|
||
→ CLI 内部完成自然目标解析、参数校验、分页、富化和执行
|
||
→ 返回稳定、可证明完整性的任务级 DTO
|
||
```
|
||
|
||
优化顺序冻结为:
|
||
|
||
```text
|
||
PR 1:Skill 路由收敛与 shared 冷启动解耦
|
||
→ PR 2:统一 Resolver 与发送执行内核
|
||
→ PR 3:读取、搜索、消息 DTO 与资源闭环
|
||
→ PR 4:扩展建群与回复闭环
|
||
→ PR 5:IM 事件高阶入口
|
||
→ 后续:依赖下层的新能力
|
||
```
|
||
|
||
其中 PR 1 收益最大、风险最低:不需要新增后端能力,就能消除 Skill 仍在推荐的旧多步链路。PR 2 是功能层 Token 价值密度和模型轮次收益最大的改造。
|
||
|
||
### 0.1 实施结果
|
||
|
||
截至 2026-08-03,本方案的 PR 1~PR 5 已在同一实现分支完成:
|
||
|
||
| 阶段 | 已实现结果 |
|
||
|---|---|
|
||
| PR 1 | Chat 根 Skill 改为 Golden Route;最小运行契约由单一 authored source 注入 Chat/Shared;正常单产品任务不再要求完整读取 Shared;卡片、Bot、复杂转发与运维细节按需加载 |
|
||
| PR 2 | 新增共享 typed target resolver、结构化 candidates 错误和批量全量预检;`+dm`、`+send-to-group` 与 `+messages-send` 复用发送执行内核;高级 user 发送支持 `--user-query/--chat-query` |
|
||
| PR 3 | `+chat-messages` 支持 `--chat-query/--user-query`,`+search-msg` 支持批量 `--chat-query/--sender-query`;list/search/mget/thread 共享 `MessageViewV1` 投影和 `im.message-list.v1` 完整性契约;资源失败并入任务级 ledger |
|
||
| PR 4 | `+chat-create --member-query` 在读取当前用户和创建群前完成全部成员解析;`+messages-reply` 返回 `im.message-reply.v1` 后续上下文并保证 dry-run 不触达写 transport |
|
||
| PR 5 | 新增 `event +listen-im`,把 kind/events/自然目标确定性编译为 EventKey 集合,并复用既有订阅、bus、ready、NDJSON、回滚和清理生命周期;Event 根 Skill 收敛为 Golden Route |
|
||
|
||
Schema 暴露同步完成:`+chat-create`、`+messages-reply` 和 `event +listen-im` 已进入 reviewed CommandRegistry、selection 与 metadata;生成 Catalog 由源输入重新生成,没有手改输出快照。
|
||
|
||
### 0.2 验证结果
|
||
|
||
截至 2026-08-03,最终工作树通过以下验证:
|
||
|
||
| 验证层 | 命令 / 结果 |
|
||
|---|---|
|
||
| 构建 | `go build -o /tmp/dws-multi-im-codex-build ./cmd` 通过 |
|
||
| 全仓测试 | `DWS_PACKAGE_VERSION=0.0.0-test go test ./...` 通过;90 个包、13,545 个测试/子测试通过事件,命令退出码为 0 |
|
||
| 真实 CLI 子进程 E2E | `go test ./test/mock_mcp -run '^TestMultiIME2E_NaturalTargetsCompletenessAndWriteBoundaries$' -count=1 -v` 通过 9 个场景 |
|
||
| E2E 覆盖 | 自然用户解析后恰好一次写;文件真实 PUT→commit→发送;用户歧义零写;资源通过受信任 HTTPS 实际原子落盘;第二页失败保留结果并 `complete=false`;Event 自然群 dry-run 零订阅;自然群完整读取;建群 dry-run 零创建;回复 continuation context |
|
||
| Event lifecycle E2E | facade 直通真实 lifecycle,覆盖多订阅 ready、正常退出全部清理、第二项创建失败回滚第一项且不启动 consumer |
|
||
| 真实钉钉组织 smoke | 当前 OAuth 身份创建仅含自己的临时测试群,真实发送后 delivery=`SUCCESS`,再由 `+chat-messages` 读回同一消息且 `complete=true`;`event +listen-im` 创建两个真实订阅并输出 ready,bounded 退出后两类订阅均为空;最后成功解散临时群 |
|
||
| Schema 生成漂移 | `go generate ./internal/cli`、`check-generated-drift.sh` 通过;两次独立生成一致 |
|
||
| Schema 合同 | `check-schema-catalog.sh` 通过:26 个产品、848 个工具;Runtime confirmation truth 为 137 个 gated 工具 |
|
||
| Agent 示例 | `make test-schema-agent-examples` 通过:1,045 个示例,其中 24 个走真实 dry-run |
|
||
| Skill 冷启动门禁 | `check-skill-context-budget.sh` 通过:Chat 根 Skill 8,346 bytes,最小 Runtime 契约 1,531 bytes;`check-skill-commands.sh` 校验 1,003 条可执行路径 |
|
||
| 精确 Token | 使用冻结的 `tiktoken 0.12.0 / o200k_base`:Chat 根 Skill 2,217;最小 Runtime 契约 380;Event 根 Skill 2,041;完整 Shared 1,493(正常单产品任务不冷加载) |
|
||
| 变更卫生 | `git diff --check` 通过 |
|
||
|
||
这里的 E2E 是隔离认证目录下启动真实 `app.Execute()` 子进程,经过真实 Cobra 解析和 HTTP JSON-RPC transport 访问本地 mock MCP;它验证 CLI 进程边界、调用顺序、输出 DTO 和写副作用,但不会向真实钉钉组织发送消息或创建群。
|
||
|
||
真实组织 smoke 与本地 E2E 分开执行:只创建带时间戳且仅含当前用户的临时群,不邀请其他用户;消息、读取、事件 ready/清理验证完成后立即解散。文档不记录真实 conversation/message/subscription ID 或凭证。
|
||
|
||
### 0.3 固定场景执行证据
|
||
|
||
| 场景 | 业务 CLI | 内部关键调用 | 结果护栏 |
|
||
|---|---:|---|---|
|
||
| 已知/自然用户发送 | 1 | resolve → send×1 | 成功只写一次 |
|
||
| 多人同名发送 | 1 | resolve | 写副作用 0,返回 candidates |
|
||
| 群名文件发送 | 1 | resolve → init → HTTP PUT → commit → send | 上传字节一致,最终只发送一次 |
|
||
| 跨会话分页搜索 | 1 | search page 1 → page 2 failure | 保留首屏,`complete=false`、failure ledger |
|
||
| 群名读取并下载 | 1 | resolve → list → resource URL → HTTPS download | 受信任域、相对路径、原子落盘、`complete=true` |
|
||
| 姓名建群 dry-run | 1 | resolve all → current profile | create 副作用 0 |
|
||
| 群事件监听 dry-run | 1 | resolve → compile EventKeys | subscription 副作用 0 |
|
||
| 群事件真实 lifecycle | 1 | create×2 → ready → bounded exit → delete×2 | 正常清理;第二项失败时回滚第一项 |
|
||
| 引用回复 | 1 | send×1 | 返回 continuation context |
|
||
|
||
上述场景均不需要泛化 `schema`/`help` 查询,证明 Golden Route 已把用户可见业务命令收敛为 1。模型轮次属于外部 Agent host 指标;仓库内以 reviewed selection fixture 和命令级 E2E 作为可复现门禁,Ark live-model 评测仍按仓库约定保持显式 opt-in,不作为普通 CI 或本轮合并前置条件。
|
||
|
||
本方案同时冻结以下约束:
|
||
|
||
1. 不通过删减安全事实、确认门禁或结果完整性换取 Token。
|
||
2. 不为已有能力重复新增同义 Shortcut。
|
||
3. 不做未版本化的公开输出 DTO 破坏性变更。
|
||
4. 不机械修改 `schema_command_registry.json`;只有稳定 identity、主路径或 alias 真正变化时才评审修改。
|
||
5. 不手改生成的 Schema Catalog 或 Agent metadata。
|
||
6. Token 预算是防膨胀护栏,不是要求删除所有上下文;能显著降低误路由、误写或 false success 的内容应保留。
|
||
7. Golden Route 负责公开意图分流;“统一”只发生在内部 Resolver、执行内核、DTO 和错误契约层,不强行收敛成一个万能公开命令。
|
||
|
||
---
|
||
|
||
## 1. 背景与当前事实
|
||
|
||
> 本章 1.1~1.4 冻结的是实施前基线;其中“当前”均指从 `origin/main` 切出实现分支时的状态,不代表完成后的工作树。完成态和验证证据以 0.1、0.2 为准。
|
||
|
||
### 1.1 当前冷启动成本
|
||
|
||
三套 IM Skill 根加载体量如下:
|
||
|
||
| 体系 | 根加载文件 | 行数 | Tokens |
|
||
|---|---|---:|---:|
|
||
| Mono | `mono/SKILL.md` | 319 | 8,914 |
|
||
| Multi | `dingtalk-chat` + `dws-shared` | 229 | 4,922 |
|
||
| lark-cli | `lark-im` + `lark-shared` | 460 | 8,449 |
|
||
|
||
Multi 的总量已经低于 Mono 和 lark-cli,但这不代表当前加载结构合理。Multi 的 4,922 Tokens 中仍有重复路由、旧 SOP 和无条件 shared 串行读取;lark-cli 的 8,449 Tokens 也不应成为 Multi 的目标预算。应吸收的是 lark-im 已验证的任务闭环、结果契约和渐进披露方式,而不是复制其根文件篇幅。
|
||
|
||
当前 Multi Chat 根加载由两个文件组成:
|
||
|
||
| 文件 | 行数 | Tokens | 说明 |
|
||
|---|---:|---:|---|
|
||
| `skills/multi/dingtalk-chat/SKILL.md` | 139 | 3,402 | IM 路由、意图表和旧 SOP |
|
||
| `skills/multi/dws-shared/SKILL.md` | 90 | 1,520 | 全局执行、安全、路由和错误契约 |
|
||
| 合计 | 229 | 4,922 | 当前正常 IM 强制冷启动 |
|
||
|
||
其中 `dingtalk-chat` 的“标准 SOP”约 1,551 Tokens,是当前产品根 Skill 最大单块;它与前面的 Shortcut 优先路由、意图表存在重复甚至冲突。
|
||
|
||
### 1.2 当前 Runtime 已具备的高频能力
|
||
|
||
| 能力 | 当前入口 | 已有行为 |
|
||
|---|---|---|
|
||
| 按姓名发单聊 | `chat +dm` | 姓名搜索、唯一性判断、使用 `openDingTalkId` 发送 |
|
||
| 按群名发消息 | `chat +send-to-group` | 群名搜索、精确匹配优先、歧义拒绝 |
|
||
| 统一发送 | `chat +messages-send` | user/bot/webhook、文本/Markdown、user 文件上传、幂等、@约束 |
|
||
| 指定会话读消息 | `chat +chat-messages` | 群/单聊统一浏览语义、默认最近时间、稳定消息投影、可选资源下载 |
|
||
| 跨会话搜索 | `chat +search-msg` | 多维过滤、默认近 7 天、翻页、mget 富化、失败 ledger |
|
||
| 批量取消息 | `chat +messages-mget` | 批量详情、reaction、资源引用和可选下载 |
|
||
| 单资源下载 | `chat +messages-resource-download` | 安全相对路径、默认不覆盖、原子落盘 |
|
||
| 引用回复 | `chat +messages-reply` | 自动读取原发送者、可选幂等键 |
|
||
| 置顶会话 | `chat +conversation-list-top` | group/direct 规范化、保留 unresolved 项 |
|
||
| 创建群聊 | `chat +chat-create` | 当前用户入群并设为群主、基础群类型和话题模式 |
|
||
| 事件监听 | `event consume` | 多 EventKey、NDJSON、ready marker、状态与清理 |
|
||
|
||
因此,当前首要问题不是 CLI 缺少高频入口,而是 Skill 仍指导 Agent 绕开这些入口。
|
||
|
||
### 1.3 当前 Skill 与 Runtime 的主要冲突
|
||
|
||
| 用户意图 | Skill 旧路线 | 已有最短路线 | 直接代价 |
|
||
|---|---|---|---|
|
||
| 给姓名发消息 | `aisearch person` → 原子 `message send` | `chat +dm` | 多一次业务命令和模型继续轮次 |
|
||
| 给群名发消息 | `chat search` → `+messages-send` | `chat +send-to-group` | 多一次业务命令和 ID 搬运 |
|
||
| 已知目标发送文件 | 独立上传 → 提取 mediaId → 发送 | `chat +messages-send --file ...` | 多次调用、旧链路漂移 |
|
||
| 读最近聊天记录 | 旧 SOP 强制 `--time` | `chat +chat-messages` 可自动取当前时间边界 | Agent 需要额外构造参数 |
|
||
| Webhook 发送 | 原子 `send-by-webhook` | `chat +messages-send --as webhook` | 身份入口分叉 |
|
||
| 群消息下载 | 读消息 → 手工识别资源 → 单独下载 | `+chat-messages --download-resources` | Agent 手工 join,失败语义不统一 |
|
||
|
||
### 1.4 当前实现仍有的真实缺口
|
||
|
||
1. `+dm` 与 `+send-to-group` 已完成名称解析,但仍各自直接调用发送接口,没有完全复用 `+messages-send` 的统一内容、幂等、AI 标记和输出逻辑。
|
||
2. 当前 person/group resolver 能拒绝零命中和多命中,但错误主要是人类可读字符串,尚未形成稳定结构化 candidates 契约。
|
||
3. `+chat-messages`、`+search-msg`、`+chat-create` 和事件监听仍要求调用者先提供 ID。
|
||
4. `+chat-create` 与 `+messages-reply` 已存在;后续任务是扩展闭环,而不是再次创建同义命令。
|
||
5. 不同消息读取入口的核心字段已较接近,但尚未冻结兼容的公共 Message DTO 和完整性字段。
|
||
6. `dws-shared` 既是共享入口又被产品 Skill 当作每次必须完整读取的文本依赖,导致清晰单产品任务仍多一个串行读取阶段。
|
||
|
||
### 1.5 从 lark-im 吸收什么
|
||
|
||
吸收原则是“迁移设计能力,不迁移平台假设”。
|
||
|
||
| lark-im 中值得吸收的设计 | DWS 当前基础 | Multi 的落点 | 阶段 |
|
||
|---|---|---|---|
|
||
| 根 Skill 以用户意图选择任务级入口 | 已有多个高阶 Shortcut,但旧 SOP 仍优先 | Golden Route 成为唯一默认路由 | PR 1 |
|
||
| 已知 leaf 直接执行,参数和安全由 leaf/Runtime 提供 | Schema/Runtime 已能交付参数和 confirmation | 根 Skill 删除整张参数、身份和 Scope 表 | PR 1 |
|
||
| 认证、权限和错误恢复按失败类型加载 | shared 当前无条件读取 | 最小公共契约内嵌,完整 shared 按需 | PR 1 |
|
||
| 自然姓名/群名解析进入 CLI | `+dm`、`+send-to-group` 已有局部实现 | 统一 typed Resolver,扩展到 send/read/search/create/event | PR 2~5 |
|
||
| 歧义返回 candidates,禁止默认第一个 | 当前能拒绝歧义,但主要是错误字符串 | 稳定 resolution envelope 和退出语义 | PR 2 |
|
||
| 发送入口统一承载身份、文件和幂等 | `+messages-send` 已具备主要能力 | 让 `+dm`、`+send-to-group` 复用同一执行器 | PR 2 |
|
||
| 读取命令直接保留 reaction、引用和资源语义 | Multi 已有投影、mget 和下载基础 | 统一 MessageView、完整性和 failure ledger | PR 3 |
|
||
| 搜索、富化、分页是一个任务闭环 | `+search-msg` 已具备大部分链路 | 增加自然 sender/chat 目标和稳定 DTO | PR 3 |
|
||
| 建群先完成全部成员解析再写入 | `+chat-create` 目前只接受 IDs | `--member-query` 全量预检 | PR 4 |
|
||
| 普通引用回复与 Thread 回复语义分离 | `+messages-reply` 已存在 | 先补引用回复闭环,Thread 等真实 writer | PR 4/后续 |
|
||
| 事件入口按用户语义映射底层 EventKey | 已有 `event consume` 控制面 | `+listen-im` 作为确定性 facade | PR 5 |
|
||
|
||
以下内容不得直接从 lark-im 照搬:
|
||
|
||
1. Lark 的 `open_id`、`chat_id`、资源 key、消息字段和事件名;DWS 必须保留自己的稳定 identity 和下层接口事实。
|
||
2. 群 description、初始 Bot、visibility、owner/manager、Thread writer 等尚未确认的能力。
|
||
3. Bot/Webhook 与 user 完全等价的富媒体能力假设。
|
||
4. 把嵌套 sender/resources 或 `items` 顶层结构无版本替换到当前公开 DTO。
|
||
5. lark-im 的完整根文件体量、全量命令表或平台特有 SOP。
|
||
6. 依赖 Agent 手工调用 contact/chat search 再搬运 ID 的多步流程;应吸收结果语义,但把确定性步骤下沉到 CLI。
|
||
|
||
最终对齐目标不是命令名相同,而是同一类高频意图在两套 CLI 中都具备:短路由、唯一解析、完整结果、可恢复错误和可证明的安全边界。
|
||
|
||
---
|
||
|
||
## 2. 目标、指标与非目标
|
||
|
||
### 2.1 北极星目标
|
||
|
||
高频 IM 请求应满足:
|
||
|
||
```text
|
||
一个明确用户意图
|
||
→ 一个最小充分的 Golden Shortcut
|
||
→ 最多一个用户可见业务 CLI 命令
|
||
→ 无 Agent 手工搬运 ID、分页或拼接资源结果
|
||
```
|
||
|
||
优化优先级固定为:
|
||
|
||
```text
|
||
任务正确完成
|
||
→ 安全且无错误副作用
|
||
→ 结果完整、可继续使用
|
||
→ 首次选路正确、少返工
|
||
→ 在满足以上条件后减少无效控制 Token 和模型轮次
|
||
```
|
||
|
||
不能因为根 Skill 变短,却导致更多 Schema/Help 查询、更多纠错轮次或更高 false success;这种变化属于 Token 搬家,不属于优化。
|
||
|
||
### 2.2 价值与效率目标
|
||
|
||
主指标优先于体量指标:
|
||
|
||
| 类型 | 指标 | 目标 |
|
||
|---|---|---|
|
||
| 任务价值 | 首次路由正确率 | 不低于基线,并逐 PR 提升 |
|
||
| 任务价值 | 任务成功率、完整结果率 | 不低于基线 |
|
||
| 安全价值 | 多候选误写、false success | 0 |
|
||
| Token 价值 | 已加载根 Skill 内容均能映射到路由、安全、结果判断或错误恢复场景 | 100% 可解释 |
|
||
| Token 价值 | 因 Skill 缺失而追加的 Schema/Help/纠错 Token | 不高于基线 |
|
||
| 执行效率 | 用户可见业务 CLI 和模型继续轮次 | 在质量护栏内下降 |
|
||
|
||
体量和轮次作为次级量化目标:
|
||
|
||
按每轮固定 20K 基础输入计算:
|
||
|
||
| 指标 | 当前 | 最终目标 |
|
||
|---|---:|---:|
|
||
| 核心场景平均模型轮次 | 4.67 | ≤3.7 |
|
||
| 平均累计输入 | 111.7K | ≤90K |
|
||
| 平均常驻上下文 | 25.7K | 23~24.5K |
|
||
| 已知目标发送 | 4 轮 | 3 轮 |
|
||
| 唯一姓名发送 | 6 轮 | 3~4 轮 |
|
||
| 群名读取并下载 | 5 轮 | 3~4 轮 |
|
||
| IM 事件监听 | 5 轮 | 3~4 轮 |
|
||
|
||
业务消息正文、文件内容和最终用户回答不计入控制 Token。
|
||
|
||
### 2.3 Skill 预算
|
||
|
||
| 内容 | 目标预算 |
|
||
|---|---:|
|
||
| `dingtalk-chat/SKILL.md` | ≤2.5K Tokens |
|
||
| 正常单产品 IM 强制 shared | 0 |
|
||
| 内嵌最小全局契约 | 300~500 Tokens |
|
||
| 单个任务 reference | ≤1.5K Tokens |
|
||
| 高频任务 reference | 默认不读取 |
|
||
|
||
Token 使用 `o200k_base` 计量;CI 同时保留稳定字节预算,防止 tokenizer 环境差异让硬门禁失效。这些预算是评审触发线:超过预算必须解释新增内容防止了什么失败;低于预算也不能作为内容充分的证明。
|
||
|
||
根 Skill 中每个保留区块至少要承担一种明确作用:
|
||
|
||
- 选择正确任务入口;
|
||
- 阻止高代价误操作;
|
||
- 解释 Runtime 输出中无法从 Schema 推导的关键语义;
|
||
- 把已知失败精确路由到按需 reference。
|
||
|
||
不承担上述作用的内容迁出;承担作用但表达重复的内容合并;能够由 leaf Schema/Runtime 稳定交付的内容不再复制。
|
||
|
||
### 2.4 质量与安全护栏
|
||
|
||
效率优化必须同时满足:
|
||
|
||
- 高频场景任务成功率不低于优化前基线;
|
||
- 多候选写操作副作用为 0;
|
||
- 所有写操作继续遵循最终 Runtime/Schema 的 confirmation truth;
|
||
- 读取、搜索和下载不得把部分结果标记为完整成功;
|
||
- `--dry-run` 与真实执行使用同一目标解析链;
|
||
- 不泄露 token、appSecret、webhook token 或内部原始错误载荷;
|
||
- 不发生跨 profile、跨组织 ID 串用;
|
||
- 不通过隐藏命令、未公开 Shortcut 或猜测接口绕过能力边界。
|
||
|
||
### 2.5 非目标
|
||
|
||
本轮不做:
|
||
|
||
1. 删除旧原子命令或已发布 Shortcut。
|
||
2. 为了命名统一机械重写 CommandRegistry identity 或主路径。
|
||
3. 把完整 Shortcut Catalog、原子 API 清单或 Scope 表重新放入根 Skill。
|
||
4. 在没有下层能力的情况下承诺 Bot 富媒体、Thread 写入、群 description、初始机器人或断点续传。
|
||
5. 无版本地把现有 `sender` 字段从字符串改成对象,或把 `messages` 顶层数组改名为 `items`。
|
||
6. 同时重构所有 DWS Multi Skill;本方案先验证 IM 路径。
|
||
|
||
---
|
||
|
||
## 3. 目标架构
|
||
|
||
### 3.1 四层职责
|
||
|
||
| 层 | 负责 | 不负责 |
|
||
|---|---|---|
|
||
| 产品根 Skill | 触发边界、Golden Route、最小不可推导语义 | 全量命令、完整参数表、旧 SOP |
|
||
| 最小全局契约 | CLI 使用、安全底线、ID 不猜测、写后验证 | 产品路由大全、认证手册、错误码大全 |
|
||
| Task reference | 低频复杂流程、卡片、复杂转发、Bot 管理、事件运维 | 高频命令选择 |
|
||
| Runtime + leaf Schema/Help | 参数、约束、身份矩阵、确认、接口与执行 | 自然语言产品路由教程 |
|
||
|
||
### 3.2 目标加载路径
|
||
|
||
清晰单产品任务:
|
||
|
||
```text
|
||
dingtalk-chat 根 Skill(含最小全局契约)
|
||
→ 一个 Golden Shortcut
|
||
→ 完成
|
||
```
|
||
|
||
低频复杂任务:
|
||
|
||
```text
|
||
dingtalk-chat 根 Skill
|
||
→ 精确 task reference
|
||
→ 已知 leaf
|
||
→ 仅在参数/安全不确定时查询 leaf Schema
|
||
→ 仅在 Cobra flag 不确定时查询 leaf Help
|
||
```
|
||
|
||
异常路径:
|
||
|
||
```text
|
||
认证/权限/profile/未知错误
|
||
→ 按错误类型读取 dws-shared 对应 reference
|
||
→ 修复或停止
|
||
```
|
||
|
||
### 3.3 Golden Route
|
||
|
||
根 Skill 的核心只保留以下高频路线:
|
||
|
||
| 意图 | 唯一推荐入口 | 说明 |
|
||
|---|---|---|
|
||
| 按姓名发文本/Markdown | `chat +dm` | PR 2 后内部委托统一发送器 |
|
||
| 按群名发文本/Markdown | `chat +send-to-group` | PR 2 后内部委托统一发送器 |
|
||
| 已知目标、文件、Bot、Webhook | `chat +messages-send` | 身份和内容矩阵由 Runtime 校验 |
|
||
| 指定会话读取 | `chat +chat-messages` | 最近消息无需强制 `--time` |
|
||
| 跨会话搜索 | `chat +search-msg` | 支持多维过滤、翻页、富化 |
|
||
| 读取并下载附件 | 查询命令加 `--download-resources` | 不另起手工下载循环 |
|
||
| 查看置顶会话 | `chat +conversation-list-top` | group/direct/unresolved 契约 |
|
||
| 监听 IM 事件 | 切换 `dingtalk-event` | PR 5 后优先 `event +listen-im` |
|
||
|
||
以下能力作为次级直接入口保留,但不扩大成完整命令表:
|
||
|
||
| 意图 | 入口 |
|
||
|---|---|
|
||
| 已知消息 ID 批量读取 | `chat +messages-mget` |
|
||
| 已知资源引用单独下载 | `chat +messages-resource-download` |
|
||
| 引用回复 | `chat +messages-reply` |
|
||
| 创建基础群 | `chat +chat-create` |
|
||
|
||
### 3.4 降级顺序
|
||
|
||
```text
|
||
Golden Shortcut
|
||
→ 精确 task reference 中的专用 Shortcut
|
||
→ 已知原子 leaf
|
||
→ leaf Schema / leaf Help
|
||
→ 最后才使用低频发现接口
|
||
```
|
||
|
||
已知意图禁止调用:
|
||
|
||
- 产品级 Schema;
|
||
- `schema --all`;
|
||
- 完整 `shortcut list --service chat`;
|
||
- 父级 Help 代替 leaf Help;
|
||
- 旧原子 SOP 作为默认路线。
|
||
|
||
### 3.5 Golden Route 与内部统一的边界
|
||
|
||
Golden Route 和内部统一解决的是不同层次的问题:
|
||
|
||
```text
|
||
用户意图层:按任务分流,入口少而明确
|
||
+dm / +send-to-group / +messages-send
|
||
+chat-messages / +search-msg / +messages-mget
|
||
↓
|
||
Runtime 内部层:复用同一 Resolver、执行内核、投影和错误契约
|
||
```
|
||
|
||
公开层不建设一个同时承担发送、读取、搜索、下载和事件的万能命令。内部层也不允许每个 Shortcut 各自复制名称解析、分页、消息投影或错误处理。
|
||
|
||
选择公开入口时采用“最小充分能力”原则,而不是“argv 最短”或“功能最多”原则:
|
||
|
||
| 意图 | 公开入口 | 选择理由 |
|
||
|---|---|---|
|
||
| 给姓名发简单文本/Markdown | `+dm` | 语义窄,参数空间小,误选身份概率低 |
|
||
| 给群名发简单文本/Markdown | `+send-to-group` | 群目标明确,不暴露无关身份矩阵 |
|
||
| 文件、Bot、Webhook、复杂 @、已知 ID 或高级发送控制 | `+messages-send` | 需要统一发送的完整能力矩阵 |
|
||
| 浏览一个指定会话的消息 | `+chat-messages` | 以会话和时间窗口为中心 |
|
||
| 跨会话或按多维条件检索 | `+search-msg` | 以查询条件、分页和富化为中心 |
|
||
| 已知一组消息 ID 获取详情 | `+messages-mget` | 精确读取,不应伪装成搜索 |
|
||
|
||
因此,`+messages-send --user-query/--chat-query` 可以支持“自然目标 + 高级发送能力”,但不会取代简单文本场景的 `+dm` 和 `+send-to-group`。三个入口共享内部发送内核,不共享同一份公开参数复杂度。
|
||
|
||
---
|
||
|
||
## 4. Skill 与 shared 设计
|
||
|
||
### 4.1 `dingtalk-chat` 目标结构
|
||
|
||
建议根文件固定为:
|
||
|
||
```text
|
||
Frontmatter / 触发边界
|
||
→ 最小 DWS 执行契约
|
||
→ Golden Route
|
||
→ 三条关键结果语义
|
||
→ 低频 reference 导航
|
||
→ 最短错误分流
|
||
```
|
||
|
||
只保留三类无法完全由 leaf Schema 表达的结果语义:
|
||
|
||
1. `openTaskId` 是发送任务 ID,不是回复/撤回使用的消息 ID。
|
||
2. 消息读取默认保留 reaction、`updateTime`、引用、转发和 `resourceRefs`;`--no-reactions` 可关闭 reaction 输出。
|
||
3. Favorite、消息 Pin、消息 Top、会话 Top 是不同对象层级,不能互换。
|
||
|
||
不在根 Skill 重复完整身份矩阵;只说明如何选择 `+messages-send`。具体 target/content/credential 互斥关系以 leaf Schema 与 Runtime 为唯一事实源。
|
||
|
||
### 4.2 必须删除或迁移的内容
|
||
|
||
- 七条旧原子 SOP 的命令细节;
|
||
- 人名先查 ID 的手工流程;
|
||
- 群名先查会话 ID 的手工流程;
|
||
- 文件先上传再提取 mediaId 的旧默认流程;
|
||
- 聊天记录强制 `--time`;
|
||
- Webhook 默认原子发送路线;
|
||
- 完整 Shortcut 表;
|
||
- 完整 flags、互斥和 required 说明;
|
||
- 卡片 payload、复杂转发、Bot 管理和事件运维细节。
|
||
|
||
### 4.3 shared 冷启动解耦
|
||
|
||
正常 IM 请求不再强制完整读取 `dws-shared/SKILL.md`。但不能简单删除 `MUST read` 而丢失全局安全契约。
|
||
|
||
冻结的交付方式为:
|
||
|
||
1. 新建一份单一来源的最小公共契约,例如:
|
||
`skills/multi/dws-shared/references/runtime-contract.md`。
|
||
2. 由生成器把该区块同步到 `dingtalk-chat/SKILL.md` 的受控 marker 中。
|
||
3. `dws-shared/SKILL.md` 继续作为泛称 DWS、跨产品、认证/profile/错误路由入口,但不再是清晰 IM 任务的强制文本依赖。
|
||
4. 策略门禁校验源文件与内嵌区块一致,禁止人工漂移。
|
||
|
||
最小契约只包括:
|
||
|
||
- 只通过 `dws` 操作;
|
||
- 结构化读取使用 JSON;
|
||
- 不猜命令、flag、ID 或字段;
|
||
- 后续 ID 来自真实返回;
|
||
- 不输出凭据;
|
||
- 高影响操作遵循 Runtime confirmation;
|
||
- 写后按任务契约验证;
|
||
- 未知命令只查精确 leaf Help。
|
||
|
||
### 4.4 shared 按需入口
|
||
|
||
仅在以下条件加载 shared 或其 reference:
|
||
|
||
| 条件 | 内容 |
|
||
|---|---|
|
||
| 登录态或权限失败 | `global-reference.md` / 对应错误章节 |
|
||
| profile 或组织不明确 | `dingtalk-profile` 与 shared profile 规则 |
|
||
| confirmation 错误 | Runtime confirmation 处理协议 |
|
||
| 未知 CLI/业务错误 | `error-codes.md` 对应章节 |
|
||
| 跨产品流程 | `workflow-routing.md` |
|
||
| 泛称 DWS、产品不明 | `routing.md` |
|
||
|
||
### 4.5 Task reference 策略
|
||
|
||
根 Skill 不加载下列低频内容:
|
||
|
||
- 流式卡片生命周期;
|
||
- 合并转发、话题转发和复杂引用;
|
||
- Bot 搜索、入群、管理员和撤回;
|
||
- Favorite/Pin/Top 的完整原子命令;
|
||
- 事件 ready、cooldown、terminal hold、status/stop 运维;
|
||
- 兼容媒体链路和异常恢复。
|
||
|
||
只有现有 reference 超过单任务预算且无法精确定位时才继续拆文件,避免为了“细粒度”制造大量无路由价值的小文档。
|
||
|
||
---
|
||
|
||
## 5. 统一 Resolver 契约
|
||
|
||
### 5.1 目标
|
||
|
||
所有自然目标解析必须复用同一套内部组件:
|
||
|
||
```text
|
||
ResolveUser(profile, query, requiredIdentity)
|
||
ResolveChat(profile, query)
|
||
ResolveBot(profile, query)
|
||
ResolveUsers(profile, queries, requiredIdentity)
|
||
```
|
||
|
||
Resolver 只做确定性解析,不执行最终写操作。
|
||
|
||
### 5.2 类型化结果
|
||
|
||
建议内部结构:
|
||
|
||
```json
|
||
{
|
||
"status": "resolved",
|
||
"entityType": "user",
|
||
"query": "张三",
|
||
"matchType": "exact",
|
||
"selected": {
|
||
"id": "userId-or-openDingTalkId",
|
||
"userId": "...",
|
||
"openDingTalkId": "...",
|
||
"name": "张三",
|
||
"organization": "..."
|
||
},
|
||
"candidates": [],
|
||
"profile": "corpId:userId"
|
||
}
|
||
```
|
||
|
||
状态固定为:
|
||
|
||
- `resolved`
|
||
- `ambiguous`
|
||
- `not_found`
|
||
- `forbidden`
|
||
- `upstream_failure`
|
||
|
||
### 5.3 匹配规则
|
||
|
||
1. 去除首尾空白,按产品允许的大小写规则比较。
|
||
2. 按稳定 ID 去重,禁止同一对象的重复行制造假歧义。
|
||
3. 用户解析按稳定 ID 去重后必须只有一个可用候选;即使其中一个显示名 exact,也不能隐藏同名或外部联系人候选。
|
||
4. 群聊解析仅有一个 exact match 时优先 exact;多个 exact match 仍为 `ambiguous`。
|
||
5. 群聊没有 exact 时,只有一个可用候选才允许 resolved。
|
||
6. 多候选禁止默认第一项、最近使用项或第一组织项。
|
||
7. 下游需要 `openDingTalkId` 时,不得选择只有 userId 且无法转换的候选;反之亦然。
|
||
8. 已提供稳定 ID 时直接使用,不触发名称搜索。
|
||
|
||
### 5.4 结构化错误
|
||
|
||
零命中和多命中应返回非零退出码和机器可读细节:
|
||
|
||
```json
|
||
{
|
||
"ok": false,
|
||
"error": {
|
||
"type": "resolution",
|
||
"subtype": "ambiguous",
|
||
"entityType": "chat",
|
||
"query": "项目群",
|
||
"candidates": [
|
||
{
|
||
"name": "项目群",
|
||
"openConversationId": "..."
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
禁止只把候选拼进不可解析的错误字符串。面向人的 `message` 可以保留,但不是唯一数据面。
|
||
|
||
### 5.5 Profile 与组织一致性
|
||
|
||
- 解析和最终执行必须使用同一个 `--profile`。
|
||
- Resolver 输出记录 profile identity,执行器在写入前校验一致。
|
||
- 不缓存或跨调用复用其它 profile 下的 userId/openDingTalkId/openConversationId。
|
||
- 多组织名称搜索遵循现有 profile 选择规则;没有明确默认账号时先停止并要求用户选择。
|
||
|
||
### 5.6 批量解析
|
||
|
||
`ResolveUsers` 采用全量预检:
|
||
|
||
```text
|
||
解析所有查询
|
||
→ 收集 resolved / ambiguous / not_found
|
||
→ 任意一项未 resolved,则整体停止
|
||
→ 全部 resolved 后才进入写操作
|
||
```
|
||
|
||
创建群等不可接受半完成的操作禁止“成功一个先写一个”。
|
||
|
||
### 5.7 Dry-run 一致性
|
||
|
||
`--dry-run` 必须:
|
||
|
||
1. 运行与真实执行相同的只读 Resolver;
|
||
2. 运行相同的 target/content/identity 校验;
|
||
3. 输出最终 resolved target 和将调用的下层动作;
|
||
4. 在第一个写调用前停止;
|
||
5. 不因 dry-run 使用另一套模糊匹配逻辑。
|
||
|
||
现有 `CallMCPData` 的 dry-run 只读通道继续作为基础;新增 resolver 所使用的下层工具必须进入明确的只读分类,不能用名称猜测绕过写保护。
|
||
|
||
---
|
||
|
||
## 6. 分层发送路由与统一执行内核
|
||
|
||
### 6.1 自然目标参数
|
||
|
||
扩展 `chat +messages-send`:
|
||
|
||
```bash
|
||
--user-query
|
||
--chat-query
|
||
```
|
||
|
||
示例:
|
||
|
||
```bash
|
||
dws chat +messages-send \
|
||
--as user \
|
||
--user-query "张三" \
|
||
--text "请查收"
|
||
|
||
dws chat +messages-send \
|
||
--as user \
|
||
--chat-query "项目群" \
|
||
--file ./report.pdf \
|
||
--idempotency-key <key>
|
||
```
|
||
|
||
目标严格且只能选择一个:
|
||
|
||
```text
|
||
--chat-id / --group
|
||
--chat-query
|
||
--user
|
||
--user-query
|
||
--open-dingtalk-id
|
||
```
|
||
|
||
Bot 和 Webhook 不自动继承 user 的自然目标或文件能力;是否支持由现有身份矩阵和真实下层能力决定。
|
||
|
||
这些自然目标参数服务于“自然目标 + 文件/复杂 @/幂等等高级发送”场景,不把 `+messages-send` 提升为所有发送意图的唯一公开入口。简单姓名文本继续走 `+dm`,简单群名文本继续走 `+send-to-group`。
|
||
|
||
### 6.2 统一内部发送器
|
||
|
||
将当前发送路径收敛为一个内部执行器:
|
||
|
||
```text
|
||
resolve target(如需要)
|
||
→ validate identity/content/target
|
||
→ normalize @ placeholders
|
||
→ resolve/upload file(如需要)
|
||
→ attach idempotency / AI tag
|
||
→ dispatch lower transport
|
||
→ normalize delivery result
|
||
```
|
||
|
||
`+dm` 和 `+send-to-group` 保留稳定 CLI path,但不再各自维护发送实现:
|
||
|
||
```text
|
||
+dm
|
||
→ ResolveUser
|
||
→ unified send executor
|
||
|
||
+send-to-group
|
||
→ ResolveChat
|
||
→ unified send executor
|
||
```
|
||
|
||
这里的“统一”指 transport 前的校验、内容构造、幂等、AI tag、执行和结果归一化,不要求三个公开命令接受完全相同的 flags。
|
||
|
||
### 6.3 内容与身份边界
|
||
|
||
- user:文本、Markdown、已有 mediaId 图片、安全相对路径文件/音频/视频;
|
||
- bot:仅发布真实下层支持的文本/Markdown;
|
||
- webhook:目标由 token 所属群决定,只发布真实支持的文本/Markdown;
|
||
- 不把 user 文件能力伪装为 bot/webhook 等价能力;
|
||
- 不在 Skill 复制完整矩阵,由 leaf Schema/Runtime 交付。
|
||
|
||
### 6.4 幂等与重试
|
||
|
||
- 已提供 idempotency key 时原样透传;
|
||
- Agent 或 facade 重试必须复用原 key;
|
||
- 未提供时不得宣称具备跨进程幂等;
|
||
- 解析成功但发送结果未知时,返回明确 delivery/unknown 状态,不自动换目标重发;
|
||
- 不因错误 envelope 误判成功而重复发送。
|
||
|
||
### 6.5 Dry-run 输出
|
||
|
||
```json
|
||
{
|
||
"identity": "user",
|
||
"resolvedTarget": {
|
||
"type": "chat",
|
||
"name": "项目群",
|
||
"openConversationId": "..."
|
||
},
|
||
"contentType": "file",
|
||
"file": "./report.pdf",
|
||
"idempotencyKey": "...",
|
||
"willSend": false
|
||
}
|
||
```
|
||
|
||
### 6.6 兼容策略
|
||
|
||
- 保留 `+dm`、`+send-to-group`、旧 ID flags 和原子命令;
|
||
- 不为统一发送新建第二个 canonical Shortcut;
|
||
- 新增 flags 属于现有 Cobra leaf 的兼容扩展,不修改稳定 command identity;
|
||
- 只有主路径或 alias 真正调整时才评审 CommandRegistry;
|
||
- Skill 始终按最小充分意图选路;PR 2 完成后也不把简单文本意图统一改为 `+messages-send`。
|
||
|
||
---
|
||
|
||
## 7. 读取、搜索与资源闭环
|
||
|
||
读取侧不新增一个万能 `+messages-read`。`+chat-messages`、`+search-msg` 和 `+messages-mget` 的任务语义不同,继续作为三个公开入口;它们只在内部共享自然目标 Resolver、分页基元、`MessageViewV1` 投影、资源处理和完整性契约。
|
||
|
||
### 7.1 扩展 `+chat-messages`
|
||
|
||
新增:
|
||
|
||
```bash
|
||
--chat-query
|
||
--user-query
|
||
```
|
||
|
||
示例:
|
||
|
||
```bash
|
||
dws chat +chat-messages \
|
||
--chat-query "项目群" \
|
||
--download-resources
|
||
```
|
||
|
||
内部路径:
|
||
|
||
```text
|
||
解析 chat/user
|
||
→ 获取消息
|
||
→ 投影 sender/text/time/identity
|
||
→ 保留 reaction/引用/转发/resourceRefs
|
||
→ 计算分页完整性
|
||
→ 可选安全下载
|
||
→ 输出稳定 DTO
|
||
```
|
||
|
||
省略 `--time` 继续默认以当前时间为边界向前读取;Skill 不再强制 Agent 构造时间。
|
||
|
||
### 7.2 扩展 `+search-msg`
|
||
|
||
新增:
|
||
|
||
```bash
|
||
--sender-query
|
||
--chat-query
|
||
```
|
||
|
||
其中 `--sender-query` 应支持重复或列表输入,先解析全部发送者,再执行一次搜索;任何名称歧义都在搜索前停止。
|
||
|
||
继续保留:
|
||
|
||
- 时间范围和默认近 7 天;
|
||
- 多会话、多发送人;
|
||
- @我/@对象;
|
||
- 消息类型和机器人来源;
|
||
- `--page-all` 与页数上限;
|
||
- mget 批量富化;
|
||
- `--no-enrich`、`--no-reactions`;
|
||
- partial failure ledger;
|
||
- `--download-resources`。
|
||
|
||
### 7.3 Message DTO 兼容策略
|
||
|
||
目标是让 list/search/mget/thread reply 共享一个内部 `MessageViewV1` 构造器,但不得无版本破坏现有公开输出。
|
||
|
||
第一阶段保留已有字段类型和顶层名称:
|
||
|
||
```json
|
||
{
|
||
"contractVersion": "im.message-list.v1",
|
||
"messages": [
|
||
{
|
||
"messageId": "...",
|
||
"conversationId": "...",
|
||
"threadId": "...",
|
||
"sender": "张三",
|
||
"senderId": "...",
|
||
"senderType": "user",
|
||
"messageType": "text",
|
||
"text": "...",
|
||
"createTime": "...",
|
||
"updateTime": "...",
|
||
"reactions": {},
|
||
"quotedMessage": {},
|
||
"forwarded": [],
|
||
"resourceRefs": []
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
兼容规则:
|
||
|
||
1. `sender` 暂时保持现有标量类型,不直接替换为对象。
|
||
2. 新的 `senderId`、`senderType` 采用增量字段。
|
||
3. `resourceRefs` 保留现有名称;如需新 `resources` 结构,必须增量发布或引入显式 DTO 版本。
|
||
4. 顶层 `messages` 不无版本改名为 `items`。
|
||
5. 原字段删除或类型变化必须走独立兼容性评审。
|
||
|
||
如果未来确需嵌套 sender/resources 对象,使用显式 `v2` projection 或新主版本,而不是静默切换。
|
||
|
||
### 7.4 完整性字段
|
||
|
||
所有分页读取和搜索逐步统一为:
|
||
|
||
```json
|
||
{
|
||
"messages": [],
|
||
"complete": true,
|
||
"hasMore": false,
|
||
"nextCursor": "",
|
||
"pagesFetched": 1,
|
||
"enrichedCount": 0,
|
||
"failedCount": 0,
|
||
"failures": []
|
||
}
|
||
```
|
||
|
||
规则:
|
||
|
||
- `hasMore=true` 且未继续翻页时,`complete=false`;
|
||
- 下层缺失可靠分页字段时,不能证明完整,`complete=false`;
|
||
- 达到 page limit 且仍有后续页,`complete=false`;
|
||
- mget 富化部分失败,保留已有消息并记录 failures;
|
||
- 单资源下载失败不丢弃消息;
|
||
- 不捕获错误后动态降级为虚假的完整成功。
|
||
|
||
### 7.5 资源下载契约
|
||
|
||
- 路径必须是工作目录内安全相对路径;
|
||
- 默认不覆盖;
|
||
- 显式 `--overwrite` 才允许覆盖;
|
||
- 临时文件完成后原子 rename;
|
||
- 按稳定资源 key 去重;
|
||
- 单资源失败隔离;
|
||
- 返回每项 `messageId`、resource key/type、local path、size/error;
|
||
- 下载保持 `read/not_required`,不得制造无意义的 `--yes`;
|
||
- 资源引用中的子消息 ID 优先使用子消息自己的 `messageId`。
|
||
|
||
---
|
||
|
||
## 8. 建群与回复闭环
|
||
|
||
### 8.1 扩展现有 `+chat-create`
|
||
|
||
`+chat-create` 已存在,本阶段增加自然成员解析,而不是创建同义命令。
|
||
|
||
目标示例:
|
||
|
||
```bash
|
||
dws chat +chat-create \
|
||
--name "项目群" \
|
||
--member-query "张三,李四" \
|
||
--type INTERNAL
|
||
```
|
||
|
||
保留现有:
|
||
|
||
- `--users`;
|
||
- `--type INTERNAL|EXTERNAL|NORMAL`;
|
||
- `--thread`;
|
||
- 当前用户自动加入并设为群主;
|
||
- `openCid` 规范化为 `openConversationId`。
|
||
|
||
新增:
|
||
|
||
- `--member-query`;
|
||
- 批量解析预检;
|
||
- dry-run 成员清单与最终下层参数;
|
||
- 重复 ID 去重;
|
||
- 结构化 ambiguity/not-found 错误。
|
||
|
||
以下能力只有下层真实支持并完成 Schema/Runtime 评审后才能加入:
|
||
|
||
- 群 description;
|
||
- 初始机器人;
|
||
- 指定其他 owner;
|
||
- public/private 或其它 Lark 专属语义;
|
||
- 服务端幂等键。
|
||
|
||
不得通过群名预搜索把“禁止同名群”伪装成幂等,因为业务上可能合法存在同名群。
|
||
|
||
### 8.2 扩展现有 `+messages-reply`
|
||
|
||
当前入口已能根据原消息补全发送者;本阶段目标是补齐后续可执行上下文:
|
||
|
||
```bash
|
||
dws chat +messages-reply \
|
||
--message-id <id> \
|
||
--conversation-id <id> \
|
||
--text "收到"
|
||
```
|
||
|
||
期望结果包含:
|
||
|
||
- 新消息 ID(下层可提供时);
|
||
- conversation ID;
|
||
- thread ID(适用时);
|
||
- delivery 状态;
|
||
- idempotency key;
|
||
- 原消息解析结果或来源。
|
||
|
||
`--reply-in-thread` 只有在确认真实 Thread writer 下层能力后才发布。普通引用回复和 Thread 回复必须是两个明确模式,不能用同一个 flag 猜测下层行为。
|
||
|
||
### 8.3 写操作安全
|
||
|
||
- 目标解析、原消息读取和参数校验全部先于写调用;
|
||
- 多候选或缺失原消息时不产生副作用;
|
||
- confirmation 由最终 Runtime gate 与 Schema 决定,不根据 `risk` 文案机械推导;
|
||
- dry-run 必须在写调用前停止;
|
||
- 部分成功时返回已创建对象和恢复上下文,禁止统一报成“完全失败”。
|
||
|
||
---
|
||
|
||
## 9. IM 事件高阶入口
|
||
|
||
### 9.1 定位
|
||
|
||
新增一个高层 facade:
|
||
|
||
```bash
|
||
dws event +listen-im --kind at-me
|
||
dws event +listen-im --kind sender --user-query "张三"
|
||
dws event +listen-im --kind group --chat-query "项目群"
|
||
dws event +listen-im \
|
||
--events message,reaction,recall \
|
||
--chat-query "项目群"
|
||
```
|
||
|
||
它不是新事件系统,而是现有 `event consume` 的确定性编译层。
|
||
|
||
### 9.2 建议参数
|
||
|
||
```text
|
||
--kind at-me|sender|group|all-direct|all-group
|
||
--events message,reaction,read,recall
|
||
--user / --open-dingtalk-id / --user-query
|
||
--chat-id / --chat-query
|
||
--max-events
|
||
--timeout
|
||
--profile
|
||
```
|
||
|
||
`kind`、target 和 events 的组合由 Runtime 校验;不兼容组合在创建订阅前失败。
|
||
|
||
### 9.3 确定性映射
|
||
|
||
示例:
|
||
|
||
| 用户语义 | EventKey |
|
||
|---|---|
|
||
| @我消息 | `user_im_message_receive_at` |
|
||
| 指定人的单聊消息 | `user_im_message_receive_o2o` |
|
||
| 指定人发给我的所有消息 | `user_im_message_receive_user` |
|
||
| 指定群消息 | `user_im_message_receive_group` |
|
||
| 指定群 reaction | `user_im_message_reaction_group` |
|
||
| 指定群撤回 | `user_im_message_recall_group` |
|
||
| 指定单聊已读 | `user_im_message_read_o2o` |
|
||
|
||
映射表由代码和测试维护,根 Skill 只保留高频用户语义,不展开全部 EventKey。
|
||
|
||
### 9.4 执行与生命周期
|
||
|
||
内部必须复用现有 event 控制面:
|
||
|
||
- 多个兼容事件合并为一次命令、一个消费进程;
|
||
- 自动启用 `--flatten -f ndjson`;
|
||
- stdout 只输出事件 NDJSON;
|
||
- stderr 输出 subscription/ready/status/error;
|
||
- 等待真实 ready marker,不用 `sleep` 猜测;
|
||
- 部分订阅创建失败时回滚已创建订阅;
|
||
- stdin、SIGINT、SIGTERM 和 timeout 触发有序清理;
|
||
- 尊重 `in_flight`、`cooldown`、`terminal_hold`;
|
||
- `--profile` 在目标解析、订阅、status 和 stop 全程一致;
|
||
- bounded 结束不泄漏订阅。
|
||
|
||
由于这是持续输出命令,不应简单套用只在结束时 `rt.Output` 一次的普通 Shortcut 模板。优先设计为复用 `event consume` 内部 runner 的 composite facade,避免通过 shell 启动第二个 `dws`。
|
||
|
||
### 9.5 `dingtalk-event` Skill 精简
|
||
|
||
根 Skill只保留:
|
||
|
||
- 监听对象选择;
|
||
- `+listen-im` 高频示例;
|
||
- 有界/无界监听;
|
||
- 何时进入运维 reference;
|
||
- chat 写操作与 event 监听的边界。
|
||
|
||
全部 EventKey 表、ready 细节、重试状态和 status/stop 运维迁入按需 reference。
|
||
|
||
---
|
||
|
||
## 10. 分阶段实施计划
|
||
|
||
### PR 1:Skill 路由收敛与 shared 解耦
|
||
|
||
#### 范围
|
||
|
||
只修改 Skill、reference、生成器和策略门禁;不改变 CLI 行为、公开参数或业务接口。
|
||
|
||
#### 工作项
|
||
|
||
1. 将 `dingtalk-chat` 重写为 Golden Route。
|
||
2. 删除旧原子 SOP 和旧文件上传路线。
|
||
3. 修正 `--time`、Webhook、资源下载说明。
|
||
4. 移除正常 IM 对完整 `dws-shared` 的强制读取。
|
||
5. 建立最小公共契约单一来源和受控注入区块。
|
||
6. 将卡片、复杂转发、Bot 管理、事件运维迁入精确 reference。
|
||
7. 增加禁止旧路线回流的静态策略。
|
||
|
||
#### 验收
|
||
|
||
- 已知 ID 发送:读产品 Skill → 执行一个业务命令;
|
||
- 姓名发送直接选择 `+dm`;
|
||
- 群名发送直接选择 `+send-to-group`;
|
||
- 最近聊天记录不强制 `--time`;
|
||
- Webhook 默认选择 `+messages-send --as webhook`;
|
||
- 文件不再推荐独立 mediaId 上传链;
|
||
- 同一意图只有一个主入口;
|
||
- 根 Skill ≤2.5K Tokens;
|
||
- 正常 IM 强制 shared 为 0;
|
||
- 所有示例通过真实 Cobra 路径和 flag 校验。
|
||
|
||
#### 回滚边界
|
||
|
||
PR 仅改变 Agent 路由文本,可独立回滚,不影响 CLI 兼容性。
|
||
|
||
### PR 2:统一 Resolver 与发送执行内核
|
||
|
||
#### 范围
|
||
|
||
- 内部 typed resolver;
|
||
- 结构化 resolution error;
|
||
- `+messages-send --user-query/--chat-query`;
|
||
- `+dm`、`+send-to-group` 委托统一发送内核;
|
||
- dry-run parity;
|
||
- Schema/Help/selection metadata 同步。
|
||
|
||
#### 验收
|
||
|
||
- 唯一姓名发送只执行一个用户可见业务命令;
|
||
- 群名发送只执行一个用户可见业务命令;
|
||
- 群名发送文件可由 `+messages-send --chat-query --file` 一步完成;
|
||
- 多候选副作用为 0,并返回结构化 candidates;
|
||
- 已知 ID 不触发 resolver;
|
||
- dry-run 与真实执行选择同一目标;
|
||
- `+dm`、`+send-to-group` 经统一发送内核产生等价的下层发送结果;
|
||
- AI tag、幂等和内容验证不因入口不同而漂移。
|
||
- 简单姓名/群名文本仍分别选择 `+dm`、`+send-to-group`,不会因为内部统一而暴露完整身份参数矩阵。
|
||
|
||
#### 兼容性
|
||
|
||
只增加可选 flags 和内部复用;保留已有命令与参数。
|
||
|
||
### PR 3:读取、搜索、DTO 与资源闭环
|
||
|
||
#### 范围
|
||
|
||
- `+chat-messages --chat-query/--user-query`;
|
||
- `+search-msg --sender-query/--chat-query`;
|
||
- 公共 `MessageViewV1` 投影;
|
||
- 完整性字段;
|
||
- 资源下载 ledger 统一;
|
||
- 兼容性 fixture。
|
||
|
||
#### 验收
|
||
|
||
- 群名读取并下载资源只需要一个业务命令;
|
||
- 跨群搜索某人消息只需要一个业务命令;
|
||
- 单资源失败不影响其它消息;
|
||
- 翻页和富化结束后能证明 `complete=true`;
|
||
- list/search/mget/thread 的核心字段一致;
|
||
- Agent 不再手工 join sender/chat/resource;
|
||
- 现有公开 DTO 字段类型和顶层名称保持兼容。
|
||
|
||
### PR 4:扩展建群与回复闭环
|
||
|
||
#### 范围
|
||
|
||
- 扩展现有 `+chat-create --member-query`;
|
||
- 批量解析全量预检;
|
||
- dry-run 成员计划;
|
||
- 扩展 `+messages-reply` 输出上下文;
|
||
- Thread writer 若下层仍缺失则只保留需求,不虚假发布。
|
||
|
||
#### 验收
|
||
|
||
- 使用姓名创建群不需 Agent 手工查 ID;
|
||
- 任一成员歧义时不创建群;
|
||
- 当前用户仍在成员列表并作为群主;
|
||
- 回复结果可继续用于查询、撤回和资源操作;
|
||
- 普通引用回复与 Thread 回复不混淆;
|
||
- 不承诺下层不存在的 description/bot/visibility 能力。
|
||
|
||
### PR 5:IM 事件高阶入口
|
||
|
||
#### 范围
|
||
|
||
- `event +listen-im`;
|
||
- kind/events 到 EventKey 的映射;
|
||
- user/chat natural resolution;
|
||
- 多事件合并;
|
||
- ready、bounded、取消、回滚和清理;
|
||
- `dingtalk-event` 根 Skill 精简。
|
||
|
||
#### 验收
|
||
|
||
- 已知监听意图不调用 `event list`;
|
||
- 不需要字段推断时不调用 `event schema`;
|
||
- 多兼容事件使用一个命令和一个进程;
|
||
- 等待 ready marker,不使用 sleep;
|
||
- 正常、超时、取消和部分失败均不泄漏订阅;
|
||
- 控制模型轮次 ≤4;
|
||
- stdout/stderr 契约保持稳定。
|
||
|
||
---
|
||
|
||
## 11. 后续依赖下层的能力(明确非本轮遗留)
|
||
|
||
以下项目依赖尚未存在或未确认的下层能力,不阻塞前五个 PR,也不属于本轮完成定义:
|
||
|
||
| 优先级 | 能力 | 当前处理 |
|
||
|---|---|---|
|
||
| P1 | Thread 回复 writer | 未确认前不发布 `--reply-in-thread` |
|
||
| P1 | 异步 delivery status / `--wait` | 先保留 `openTaskId` 和明确未知状态 |
|
||
| P1 | 图片、文件、音视频统一资源元数据 | PR 3 先规范当前可识别资源 |
|
||
| P2 | Bot 富媒体发送 | 不把 user 能力映射给 bot |
|
||
| P2 | 大文件分片、Range、断点续传 | 保持当前安全下载边界 |
|
||
| P2 | 卡片按钮回调与完整生命周期 | 独立 card/event reference |
|
||
| P3 | Moderation、owner/manager/visibility | 仅发布真实 DWS 下层子集 |
|
||
| P3 | 事件触发发送幂等关联 | 待 delivery/event correlation 下层支持 |
|
||
|
||
---
|
||
|
||
## 12. 评测设计
|
||
|
||
### 12.1 固定回归场景
|
||
|
||
1. 已知 ID 发文本;
|
||
2. 唯一姓名发文本;
|
||
3. 多人同名发消息;
|
||
4. 群名发文件;
|
||
5. 跨群搜索某人最近消息;
|
||
6. 群名读取历史并下载资源;
|
||
7. 使用姓名创建群;
|
||
8. 监听某群消息和 reaction。
|
||
|
||
### 12.2 每场景记录
|
||
|
||
```text
|
||
task_success
|
||
routing_correct
|
||
first_pass_success
|
||
model_calls
|
||
skill_files_loaded
|
||
reference_files_loaded
|
||
schema_calls
|
||
help_calls
|
||
business_cli_calls
|
||
internal_read_calls
|
||
internal_write_calls
|
||
resident_control_tokens
|
||
cumulative_input_tokens
|
||
ambiguous_target_behavior
|
||
side_effect_count
|
||
complete
|
||
false_success
|
||
correction_rounds
|
||
```
|
||
|
||
### 12.3 指标定义
|
||
|
||
- `model_calls`:初始决策及每次工具结果后的模型继续调用;
|
||
- `business_cli_calls`:Agent 显式执行的用户可见 `dws` 业务命令;Shortcut 内部 MCP 调用不另算模型轮次;
|
||
- `resident_control_tokens`:本任务进入上下文的 Skill、shared、reference、Schema 和 Help 去重总量;
|
||
- `cumulative_input_tokens`:每轮模型输入中固定基础上下文与已驻留控制文本的累计暴露;
|
||
- `first_pass_success`:首次选定入口和参数后,无需改走其它命令或补查泛化 Schema/Help 即完成任务;
|
||
- `correction_rounds`:因路由、参数、身份或结果解释不足产生的额外模型继续轮次;
|
||
- `false_success`:结果不完整、写入未知或部分失败却被报告为完整成功;
|
||
- `side_effect_count`:测试期望之外的创建、发送、更新、订阅或删除次数。
|
||
|
||
Token 价值通过场景证据评审,而不是仅计算“越少越好”:根 Skill 每个区块必须标注它支持的评测场景或阻止的失败;删除区块后若 Schema/Help fallback、纠错轮次或失败率上升,即使冷启动 Token 下降也不能合入。
|
||
|
||
### 12.4 分阶段预期路径
|
||
|
||
| 场景 | PR 1 后 | 最终目标 |
|
||
|---|---|---|
|
||
| 已知 ID 发文本 | `+messages-send` | 1 个业务命令,3 轮 |
|
||
| 唯一姓名发文本 | `+dm` | 1 个业务命令,3~4 轮 |
|
||
| 多人同名发送 | `+dm` 无写入失败 | 结构化 candidates,副作用 0 |
|
||
| 群名发文件 | 仍可能需 ID | `+messages-send --chat-query --file` 一步 |
|
||
| 跨群搜某人 | 仍可能需先解析 | `+search-msg --sender-query` 一步 |
|
||
| 群名读并下载 | 仍可能需先解析 | `+chat-messages --chat-query --download-resources` 一步 |
|
||
| 姓名建群 | 仍需 IDs | `+chat-create --member-query` 一步 |
|
||
| 群事件监听 | 切 `dingtalk-event` | `event +listen-im --chat-query` 一步 |
|
||
|
||
### 12.5 硬门禁
|
||
|
||
- 任务成功率、首次路由正确率和完整结果率不得低于基线;
|
||
- 冷启动 Token 下降但 Schema/Help fallback 或纠错轮次上升,不算通过;
|
||
- 高频已知意图 `schema_calls=0`;
|
||
- 高频已知意图 `help_calls=0`;
|
||
- 唯一姓名/群名最终只执行一个业务 CLI 命令;
|
||
- 多候选写操作 `side_effect_count=0`;
|
||
- 不允许完整 Shortcut Catalog 进入上下文;
|
||
- 不允许根 Skill 恢复旧原子 SOP;
|
||
- 不允许正常 Chat 强制读取完整 shared;
|
||
- 不允许 partial result 标记 `complete=true`;
|
||
- 不允许生成文件被手工编辑。
|
||
|
||
---
|
||
|
||
## 13. 测试与 CI 门禁
|
||
|
||
### 13.1 Skill 静态门禁
|
||
|
||
扩展 `check-skill-context-budget.sh` 或增加专用检查:
|
||
|
||
1. `dingtalk-chat` 字节与 Token 预算;
|
||
2. Golden Route 精确命令集合;
|
||
3. 同一意图不得出现两个“优先/必须”入口;
|
||
4. 禁止旧模式文本回流,例如:
|
||
- 发消息必须先 `aisearch person`;
|
||
- 文件必须先 `dt_media_upload`;
|
||
- `+chat-messages` 必须传 `--time`;
|
||
- Webhook 默认走原子命令;
|
||
5. 禁止 Chat 完整 Shortcut 表重新展开;
|
||
6. 最小公共契约生成区块必须与源一致;
|
||
7. 所有示例通过真实 Cobra path/flag/constraint 校验。
|
||
|
||
### 13.2 Resolver 单元测试
|
||
|
||
至少覆盖:
|
||
|
||
- 零命中;
|
||
- 单一模糊候选;
|
||
- 单一 exact;
|
||
- 多个 exact;
|
||
- 重复 ID 去重;
|
||
- 外部联系人只有 openDingTalkId;
|
||
- 下游要求 userId/openDingTalkId 的差异;
|
||
- 群 exact 优先和同名群歧义;
|
||
- profile 不一致;
|
||
- upstream error;
|
||
- dry-run 与真实解析相同;
|
||
- 已知 ID 不调用搜索。
|
||
|
||
### 13.3 Shortcut 行为测试
|
||
|
||
- `+dm`、`+send-to-group`、`+messages-send` 使用同一发送器;
|
||
- user/bot/webhook 目标矩阵;
|
||
- 文件路径与内容类型;
|
||
- idempotency 和 AI tag;
|
||
- 解析失败前无写调用;
|
||
- send/read/search/create 的 dry-run 计划;
|
||
- Message DTO fixture 和向后兼容;
|
||
- 分页、富化、资源 partial failure;
|
||
- 群创建全量预检;
|
||
- 回复结果的后续上下文。
|
||
|
||
### 13.4 Event 测试
|
||
|
||
- kind/events/target 映射;
|
||
- 多事件去重和顺序;
|
||
- ready marker;
|
||
- 部分订阅失败回滚;
|
||
- timeout/SIGINT/SIGTERM 清理;
|
||
- dry-run 不创建订阅;
|
||
- profile 一致;
|
||
- stdout 只包含 NDJSON;
|
||
- bounded 结束无泄漏。
|
||
|
||
### 13.5 Schema 与生成门禁
|
||
|
||
每个改变 Cobra flags、Runtime Schema 或 Agent selection 的 PR 必须:
|
||
|
||
```bash
|
||
go generate ./internal/cli
|
||
./scripts/policy/check-generated-drift.sh
|
||
./scripts/policy/check-schema-catalog.sh
|
||
./scripts/policy/check-runtime-confirmation-truth.sh
|
||
make skill-command-integrity skill-context-budget
|
||
DWS_PACKAGE_VERSION=0.0.0-test go test ./...
|
||
```
|
||
|
||
并重点运行:
|
||
|
||
```bash
|
||
go test ./internal/shortcut/... -count=1
|
||
go test ./internal/app -run 'Test(Chat|Event|Schema|ManualAgentExample)' -count=1
|
||
make test-schema-agent-examples
|
||
```
|
||
|
||
示例中不得存储 `--yes`;所有公开示例必须通过真实 `BoundCommand` 的路径、flag、required 和跨参数约束。
|
||
|
||
### 13.6 Live 验证
|
||
|
||
在具备隔离测试账号和明确授权时运行:
|
||
|
||
- 唯一/歧义姓名;
|
||
- 同名群;
|
||
- user 文本与文件;
|
||
- bot/webhook 文本;
|
||
- 消息分页和下载;
|
||
- 事件多订阅和清理。
|
||
|
||
Live 报告必须脱敏,不保存 token、webhook token、原始私人消息或下载内容。
|
||
|
||
---
|
||
|
||
## 14. 生成与单一来源
|
||
|
||
### 14.1 Command identity
|
||
|
||
- 已有 `+dm`、`+send-to-group`、`+messages-send`、`+chat-messages`、`+search-msg`、`+chat-create`、`+messages-reply` 保持 identity 和主路径;
|
||
- 新增可选 flag 不机械改写 CommandRegistry;
|
||
- `event +listen-im` 是新公开 leaf,需要评审 registry identity、主路径、selection 和 metadata;
|
||
- alias 只有存在真实兼容需求时才加入。
|
||
|
||
### 14.2 参数与安全来源
|
||
|
||
- Cobra tree:命令存在性与接受的 flags;
|
||
- Runtime constraints:互斥、至少一个、条件组合;
|
||
- metadata:接口、安全、runtime gate 和必要参数 overlay;
|
||
- selection:Agent 选择语义;
|
||
- Skill:Golden Route,不重复参数真相。
|
||
|
||
### 14.3 输出 DTO 来源
|
||
|
||
消息投影应有单一内部 builder 和共享 fixture。list/search/mget/thread 不各自维护字段别名、reaction、quoted、forwarded 和 resource 解析逻辑。
|
||
|
||
### 14.4 生成文件
|
||
|
||
只能修改源输入和生成器,再运行生成:
|
||
|
||
- 不手改 `schema_catalog/`;
|
||
- 不手改 `schema_agent_metadata/`;
|
||
- 不以旧 Catalog 为生成输入;
|
||
- 生成前后必须通过 byte guard 和 drift check。
|
||
|
||
---
|
||
|
||
## 15. 风险与缓解
|
||
|
||
| 风险 | 表现 | 缓解 |
|
||
|---|---|---|
|
||
| Skill 过度精简 | 低频能力找不到 | 精确 reference + 最后回退发现,不恢复全量 Catalog |
|
||
| 移除 shared 后安全丢失 | 产品 Skill 缺全局底线 | 单一来源最小契约生成注入 + hash/marker 门禁 |
|
||
| Resolver 误选人/群 | 发错对象 | exact/unique 规则、结构化 candidates、写前停止 |
|
||
| 批量解析半完成 | 建出成员不完整的群 | 全量预检,全成功后单次写入 |
|
||
| dry-run 与真实执行漂移 | 预览目标不同 | 同一 resolver、同一校验、只在写调用前分叉 |
|
||
| DTO 统一导致兼容破坏 | 脚本解析失败 | 共享内部模型、增量字段、显式版本、禁止改字段类型 |
|
||
| facade 继续膨胀 | 又出现大量同义入口 | 只扩展五个主入口,保留兼容 wrapper,不再横向新增 |
|
||
| 虚假对齐 Lark | 广告下层不支持能力 | `availability/interface_reason` 如实发布,能力进入后续清单 |
|
||
| 事件订阅泄漏 | 进程结束后仍订阅 | ready/rollback/cancel/timeout/cleanup 全路径测试 |
|
||
| 跨 profile ID 串用 | 错组织操作 | Resolver 结果携带 profile,执行前一致性校验 |
|
||
| 输出富化过度 | 延迟和业务数据 Token 增长 | 保留 `--no-enrich`、`--no-reactions`、下载 opt-in |
|
||
| 安全从 Skill 下沉后漂移 | confirmation 不一致 | Runtime gate truth + final embedded Schema 语义测试 |
|
||
|
||
---
|
||
|
||
## 16. 冻结决策与待确认项
|
||
|
||
### 16.1 已冻结
|
||
|
||
1. PR 顺序为 Skill → Resolver/Send → Read/Search → Create/Reply → Event。
|
||
2. 正常 IM 不再完整读取 shared。
|
||
3. 最小公共契约采用单一来源生成注入,不人工复制。
|
||
4. `+dm`、`+send-to-group` 保留兼容,但内部复用统一发送器。
|
||
5. 自然目标 canonical flag 使用 `--user-query`、`--chat-query`、`--sender-query`、`--member-query`。
|
||
6. 多候选永不默认第一项。
|
||
7. dry-run 运行真实只读解析。
|
||
8. `+chat-create`、`+messages-reply` 是扩展项,不重复新增。
|
||
9. 消息 DTO 只做兼容性增量;嵌套对象需要显式新版本。
|
||
10. `event +listen-im` 复用现有事件控制面,不另建订阅系统。
|
||
11. Token 预算是防膨胀护栏,北极星是任务价值、正确性、安全和完整性。
|
||
12. Golden Route 保留多个最小充分意图入口;发送和读取只在内部执行内核与数据契约层统一。
|
||
13. 简单姓名文本走 `+dm`,简单群名文本走 `+send-to-group`;高级发送才选择 `+messages-send`。
|
||
|
||
### 16.2 实施前仍需确认
|
||
|
||
| 项目 | 需要确认的事实 |
|
||
|---|---|
|
||
| Thread writer | 下层是否能稳定返回新消息 ID、thread ID 和 delivery 状态 |
|
||
| 群创建幂等 | 下层是否支持服务端幂等键;否则不宣称幂等 |
|
||
| 群 description/初始 Bot | DWS 下层是否真实支持,不照搬 Lark 参数 |
|
||
| sender DTO v2 | 是否有消费者需要嵌套对象,是否值得显式版本 |
|
||
| event bounded 模式 | `--max-events`、`--timeout` 的退出码和 cleanup 语义 |
|
||
| Resolution envelope | 是否扩展通用 `apperrors`,供其它产品复用 |
|
||
| Token CI | 使用固定 tokenizer 依赖还是字节硬门禁 + Token 报告双轨 |
|
||
|
||
未确认项不得阻塞 PR 1,也不得在 Skill 中提前广告。
|
||
|
||
---
|
||
|
||
## 17. PR 评审清单
|
||
|
||
### 路由
|
||
|
||
- [ ] 高频意图只有一个主入口;
|
||
- [ ] 已知意图不需要产品 Schema、Catalog 或 Help;
|
||
- [ ] 原子命令只作为明确降级;
|
||
- [ ] Skill 没有广告当前下层不可用能力。
|
||
|
||
### Resolver
|
||
|
||
- [ ] 已知 ID 跳过解析;
|
||
- [ ] exact、unique、ambiguous、not_found 行为有测试;
|
||
- [ ] candidates 结构化且不泄露敏感信息;
|
||
- [ ] profile 全链路一致;
|
||
- [ ] dry-run 与真实执行同解析结果。
|
||
|
||
### 安全
|
||
|
||
- [ ] 多候选写操作副作用为 0;
|
||
- [ ] confirmation 与最终 Runtime gate/Schema 一致;
|
||
- [ ] 文件路径、覆盖和原子落盘规则未放宽;
|
||
- [ ] partial success 不被报告为完整成功;
|
||
- [ ] 事件异常退出完成清理。
|
||
|
||
### 兼容性
|
||
|
||
- [ ] 未删除旧 CLI path/flag;
|
||
- [ ] 未机械改写 CommandRegistry;
|
||
- [ ] 未改变现有 DTO 字段类型;
|
||
- [ ] 新字段为增量或显式版本;
|
||
- [ ] alias 有真实兼容理由。
|
||
|
||
### 生成与验证
|
||
|
||
- [ ] 修改了正确的 authored source;
|
||
- [ ] 未手改 Catalog/Agent metadata;
|
||
- [ ] generation、drift、Schema policy 通过;
|
||
- [ ] Skill 命令完整性和 context budget 通过;
|
||
- [ ] 单元、dry-run、fixture、事件清理测试通过;
|
||
- [ ] 评测表记录了模型轮次和控制 Token 变化。
|
||
|
||
---
|
||
|
||
## 18. 最终验收标准
|
||
|
||
全部五个 PR 完成后,必须同时达到:
|
||
|
||
1. 八个固定高频场景的任务成功率、首次路由正确率和完整结果率不低于基线。
|
||
2. 多候选写操作副作用和 false success 为 0。
|
||
3. 每个根 Skill 区块都能映射到路由、安全、结果判断或错误恢复证据。
|
||
4. 八个固定高频场景平均模型轮次 ≤3.7。
|
||
5. 平均累计输入 ≤90K。
|
||
6. 平均常驻上下文 23~24.5K。
|
||
7. 高频已知意图 Schema/Help 调用为 0。
|
||
8. 自然姓名/群名场景只执行一个用户可见业务命令。
|
||
9. 群名读取并下载可一命令完成。
|
||
10. 姓名建群可一命令完成,任一歧义时不创建。
|
||
11. 多事件监听使用一个 facade 和一个消费进程。
|
||
12. 读取/搜索 partial failure 不产生 false success。
|
||
13. 消息 DTO 保持兼容并共享同一内部投影实现。
|
||
14. Safety、confirmation、Schema、Help 和真实 Runtime 无漂移。
|
||
|
||
如果效率指标达到但任务成功率、安全或完整性退化,则该阶段不算通过。
|
||
|
||
---
|
||
|
||
## 附录 A:目标根 Skill 骨架
|
||
|
||
```markdown
|
||
# 钉钉群聊 / 消息 Skill
|
||
|
||
## 最小执行契约
|
||
|
||
<!-- 由共享源生成;约 300~500 Tokens -->
|
||
|
||
## Golden Route
|
||
|
||
| 用户意图 | 唯一入口 |
|
||
|---|---|
|
||
| 按姓名发文本 | `dws chat +dm ...` |
|
||
| 按群名发文本 | `dws chat +send-to-group ...` |
|
||
| 已知目标/文件/Bot/Webhook | `dws chat +messages-send ...` |
|
||
| 读指定会话 | `dws chat +chat-messages ...` |
|
||
| 跨会话搜索 | `dws chat +search-msg ...` |
|
||
| 读并下载资源 | 查询命令加 `--download-resources` |
|
||
| 查看置顶会话 | `dws chat +conversation-list-top` |
|
||
| 监听事件 | 切 `dingtalk-event` |
|
||
|
||
## 关键结果语义
|
||
|
||
- openTaskId 不是消息 ID。
|
||
- reaction/updateTime/resourceRefs 默认随稳定投影返回。
|
||
- Favorite/Pin/Message Top/Conversation Top 不可混用。
|
||
|
||
## 低频能力
|
||
|
||
- 卡片、复杂转发、Bot 管理、事件运维按需读取精确 reference。
|
||
- 已知 leaf 直接执行;仅在参数/安全不确定时读取 leaf Schema。
|
||
|
||
## 错误分流
|
||
|
||
- resolution candidates:交给用户消歧,不猜。
|
||
- auth/profile/confirmation:读取对应 shared reference。
|
||
- unknown command/flag:精确 leaf Help,最多修正一次。
|
||
```
|
||
|
||
## 附录 B:评测记录模板
|
||
|
||
```markdown
|
||
| 场景 | 成功 | 主入口 | 模型轮次 | Skill | Ref | Schema | Help | 业务 CLI | 常驻 Tokens | 累计输入 | 副作用 | complete | false success |
|
||
|---|---|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|---|---|
|
||
| 已知 ID 发文本 | | | | | | | | | | | | | |
|
||
| 唯一姓名发文本 | | | | | | | | | | | | | |
|
||
| 多人同名发送 | | | | | | | | | | | | | |
|
||
| 群名发文件 | | | | | | | | | | | | | |
|
||
| 跨群搜某人 | | | | | | | | | | | | | |
|
||
| 群名读并下载 | | | | | | | | | | | | | |
|
||
| 姓名创建群 | | | | | | | | | | | | | |
|
||
| 群消息+reaction 监听 | | | | | | | | | | | | | |
|
||
```
|
||
|
||
## 附录 C:实施总路线
|
||
|
||
```text
|
||
先修 Skill,使 Agent 使用现有最小充分路由
|
||
→ 再统一 Resolver,消除名称到 ID 的 Agent 手工步骤
|
||
→ 再统一发送内核,以及读取/搜索共享的投影和完整性契约
|
||
→ 扩展现有建群与回复入口
|
||
→ 最后封装长连接事件入口
|
||
→ 下层能力成熟后再补 Thread、Bot 富媒体和大文件能力
|
||
```
|
||
|
||
最终判断标准不是 Shortcut 数量,而是:用户的高频 IM 意图是否能由一个稳定入口完成,Agent 是否不再承担本可由 CLI 确定性完成的工作。
|