feat(wechat): add Intent Transaction Layer with unified task schema

Introduce Draft → Confirm → Commit flow for WeChat schedule intents behind
feature flags, plus h5_tasks dual-write/read aggregation and rollout scripts
so reminders and automations get explicit user confirmation before persisting.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
john
2026-08-24 15:59:17 +08:00
parent b93c92a3e2
commit d58dc2a251
45 changed files with 4972 additions and 30 deletions
+296
View File
@@ -0,0 +1,296 @@
# Intent Transaction Layer — 意图事务层设计
> **状态:** 架构草案(2026-08-24
> **受众:** Memind / TKMind 智趣 — 面向普通用户的 Agent 平台
> **与现有文档关系:** 本文件是 [schedule-reminder-design.md](./schedule-reminder-design.md) 的演进方向;不替代当前已上线的 `h5_schedule_*` / `h5_scheduled_tasks` 实现,而是定义下一阶段的统一模型与 Commit Gate。
## 1. 核心判断
三层/四层 **路由准确率**(规则 + Preflight)可达 **99%+**,但这只解决:
```text
用户一句话 → 分类 → 写入
```
生产级 Agent 平台必须覆盖完整 **意图生命周期**
```text
用户输入 → 理解 → Draft → 确认 → Commit → Worker 执行 → 查询 / 修改 / 删除 → Event Log
```
**任何具有副作用的 Agent 行为,都不应直接 Commit**,包括但不限于:
- 创建提醒 / 定时任务
- 发送消息 / 邮件
- 调用外部接口
- 创建或发布页面
因此第 4 层不应称为「互动确认」,而应升级为 **Intent Transaction Layer(意图事务层)**
---
## 2. 内部分层命名(用户语义 vs 技术实现)
| 内部 Layer | 用户感知 | 到点后系统行为 | 当前 Memind 落点 |
|------------|----------|----------------|------------------|
| **Layer 0: Query Guard** | 「只是问问」 | 只回答,零副作用 | `parseScheduleIntent``query_schedule`;需扩展 query _guard |
| **Layer 1: Personal Memory** | 「帮我记着 / 到点叫我」 | **通知用户** | `h5_schedule_items` + `h5_schedule_reminders`Preflight `create_timed_reminder` |
| **Layer 2: Scheduled Action** | 「到点替我做」 | **系统执行动作并交付** | `h5_scheduled_tasks` + `scheduled-task-worker` |
| **Layer 3: Agent Workflow** | 「多步骤复杂任务」 | Agent 编排 + 工具链 | Goose session + MCP toolsFinish 后可能有页面/消息 |
**本质区别不是「有没有时间」,而是到点以后:**
- Personal Memory → 微信/站内 **通知**
- Scheduled Action → **调用能力链**(搜索 → 生成 → 发送)
示例:
| 用户说法 | Layer | 08:00 发生什么 |
|----------|-------|------------------|
| 每天 8 点提醒我跑步 | L1 Personal Memory | 推送通知 |
| 每天 8 点帮我生成跑步报告 | L2 Scheduled Action | 拉数据 → 分析 → 生成页 → 推送链接 |
---
## 3. 意图事务层(ITL)流程
```text
User Message
Intent Classifier
┌──────────────┴──────────────┐
▼ ▼
Query Guard Action Router
(Layer 0) (L1 / L2 / L3)
│ │
▼ ▼
Answer Only Draft Object
(no DB write) │
Confirmation Layer
(Agent Action Card)
┌────────────┼────────────┐
▼ ▼ ▼
Confirm Modify Cancel
│ │ │
▼ └→ 新 Draft ─┘
Commit
Worker / Agent
Event Log
```
### Draft 状态
- 所有 Layer 1–3 的创建请求,**默认先写 Draft**(或内存 + `source_message_id` 关联,MVP 可用 `status=draft` 行)。
- 微信侧:Passive Reply / 客服消息展示 **Agent Action Card**;用户回复「确认」或点按钮后再 Commit。
- 现有 `guardScheduleConfirmationReply`**反伪确认**ITL 是 **正向前置 Gate**,二者互补。
### Event Log
建议字段:`intent_id`, `user_id`, `action`, `from_status`, `to_status`, `source_message_id`, `committed_at`, `worker_run_id`, `error`
可与现有 `h5_schedule_delivery_log`、scheduled task `last_result_json` 逐步合并。
---
## 4. Action Level(风险分级)
每个 Draft 附带 metadata
```json
{
"intent": "schedule",
"layer": 1,
"action_level": 1,
"risk": "low",
"side_effects": ["notify_wechat"]
}
```
| Level | 含义 | 示例 | Confirm 策略 |
|-------|------|------|----------------|
| **0** | 纯查询 | 「有没有我的新闻任务?」 | 禁止创建;只读 |
| **1** | 低风险 | 「提醒我下午买咖啡」 | 简卡片,单次 Confirm |
| **2** | 中风险 | 「每天 7 点发日报」 | 完整 Action Card + 周期说明 |
| **3** | 高风险 | 「每天自动给客户发报价」 | Confirm + 权限 / 白名单 / 人工开关 |
Layer 2 周期性 Scheduled Action 默认 **Level 2**;涉及外发第三方默认 **Level 3**
---
## 5. 统一 Agent Action Card(所有 Layer 复用)
```text
🤖 我准备执行:
任务:每天 08:00 生成 AI 新闻日报
动作:
1. 搜索最新 AI 新闻
2. 总结 10 条重点
3. 生成页面并发送给你
开始时间:明天 08:00Asia/Shanghai
频率:每天自动执行
风险:中(重复执行)
[确认执行] [修改] [取消]
```
Layer 1 简版:
```text
🤖 我准备设置提醒:
📌 项目计划例会
🕐 今天 14:30Asia/Shanghai
[确认] [改时间] [取消]
```
**实现锚点:** `wechat-mp.mjs` 在 Preflight 返回前不 `finishWechatMpMessage`;Draft 存 DB 后推卡片;下一条消息走 `confirm_intent` 解析器 Commit。
---
## 6. 统一 Task SchemaP0.5 — 停止模型分裂)
当前三套存储:
| 用途 | 表 |
|------|-----|
| 待办/日程/提醒 | `h5_schedule_items`, `h5_schedule_reminders` |
| 定时自动化 | `h5_scheduled_tasks` |
| Agent 多步 | 无一等公民(落在 session + 偶发 scheduled_task |
**目标:** 单一 `h5_tasks`(名称可调整),类型区分行为,而非分表。
```sql
-- 演进目标(草案,非 MVP 迁移脚本)
CREATE TABLE h5_tasks (
id CHAR(36) PRIMARY KEY,
user_id CHAR(36) NOT NULL,
type ENUM('reminder','todo','digest','automation','workflow') NOT NULL,
title VARCHAR(255) NOT NULL,
spec JSON NOT NULL, -- 执行说明 / taskSpec / 步骤摘要
trigger JSON NOT NULL, -- { kind, time, repeat, timezone, condition? }
action JSON NOT NULL, -- { kind: notify|agent_run|webhook, payload }
action_level TINYINT NOT NULL DEFAULT 1,
notify_channel ENUM('wechat','web','both','none') DEFAULT 'both',
status ENUM('draft','confirmed','active','locked','paused','completed','failed','cancelled') NOT NULL,
next_run_at BIGINT NULL,
last_run_at BIGINT NULL,
source_channel VARCHAR(32),
source_message_id VARCHAR(128),
source_text TEXT,
event_log_tail JSON,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL
);
```
**映射:**
- 提醒 → `type=reminder`, `action.kind=notify`
- 待办 → `type=todo`, `action.kind=none`(可无 trigger
- Digest → `type=digest`, `trigger.repeat=daily`
- 唐用户 8:00 天气 / 5:30 新闻 → `type=automation`, `action.kind=agent_run`
- 复杂 Agent → `type=workflow`
**迁移策略(渐进,不要求 Big Bang):**
1. **Phase A** 新建 `h5_intent_drafts` + Confirm Gate;现有表不变,Commit 时仍写旧表。
2. **Phase B** 读路径聚合 `listTasks(userId)` 统一展示;写路径双写。
3. **Phase C** 迁移脚本 + 废弃 `h5_scheduled_tasks` 直连创建。
---
## 7. 对抗测试(Adversarial Routing
分类器必须覆盖 **故意模糊** 话术。纳入 `scripts/simulate-schedule-capability-routing.mjs`
| 输入 | 期望 Layer | 说明 |
|------|------------|------|
| 明天提醒我自动生成日报 | L2 或 Clarify | 「提醒」+「生成」歧义 → 必须 Clarify,禁止静默 |
| 帮我每天看看有没有新的招聘信息 | L2 | 「看看」但含每天 → Scheduled Action(监控+推送) |
| 设置任务,余额低于 100 提醒我 | L1 + Condition | 非 cron;未来 Event Trigger |
| 查一下是否有执行的新闻任务 | L0 | Query Guard,禁止 create_todo |
| 每天 8 点提醒我跑步 | L1 recurrence | 循环提醒,非 L2 |
| 每天 8 点帮我生成跑步报告 | L2 | 明确执行链 |
**规则:** 对抗样本命中 **Clarify** 视为通过,命中错误 Layer Commit 视为失败。
---
## 8. 未来:Event Trigger(超出 Schedule
```text
Event Trigger → Condition → Action
```
示例:余额 < 100 → 微信提醒;股价跌破 → 通知;新邮件 → 摘要。
**不要塞进 cron schedule 表**;在统一 Task Schema 的 `trigger.kind` 扩展:
```json
{ "kind": "condition", "watch": "balance", "op": "lt", "value": 10000 }
```
MVP 已有雏形:`create_balance_low_alert` + digest subscription。应归入 Layer 1/2 的 **Condition Task** 子类,而非新的第四套表。
---
## 9. 与 Goose + Memind 的插入点
| 组件 | 插入方式 |
|------|----------|
| **Intent Router** | 已有:`wechat-mp.mjs` → scheduled-task / schedule handlers → Agent prompt |
| **Draft** | 新增:`intent-draft-service.mjs`;微信 preflight 改 `createDraft` 而非 `createItem` |
| **Confirm Gate** | 微信下一条消息优先匹配 `confirm|取消|改` + `draft_id` |
| **Commit** | 现有 `schedule-service` / `scheduled-task-service` 作为 Commit 后端 |
| **Worker** | 不变:`schedule-reminder-worker`, `scheduled-task-worker` |
| **Agent** | Layer 3 仍走 Goose SSEITL 约束:**工具成功 + 用户 Confirm 后才可宣称「已设置」** |
**不需要改 SSE 主链路**ITL 在微信 inbound 与 MCP write 工具之间加一层。
---
## 10. 修订后的优先级
| 优先级 | 项 | 说明 |
|--------|-----|------|
| **P0** | Intent Transaction LayerDraft + Confirm + Commit | 所有副作用走 Gate |
| **P0** | Agent Action Card 统一组件 | L1 简版 + L2/L3 完整版 |
| **P0** | Query GuardLayer 0 | 「查一下/有没有/是否」禁止 create |
| **P0.5** | 统一 Task Schema 草案 + 双写计划 | 停止 reminder/schedule/automation 三分裂 |
| **P1** | 相对时间 / 循环提醒 / 偏移提醒 | 规则或 Agent 填槽 |
| **P1** | Action Level 2/3 策略 | 周期任务默认 L2;外发 L3 |
| **P2** | Event Trigger 模型 | condition task |
| **P2** | 对抗测试 CI 门禁 | `simulate-schedule-capability-routing.mjs --adversarial` |
---
## 11. 与当前工程状态的对齐(2026-08-24)
**已有:**
- Layer 1 Preflight`create_timed_reminder`(待发版)
- Layer 2`h5_scheduled_tasks` + worker + 去重修复(含 `locked`
- 反伪确认:`schedule-guard.mjs`
- 压测:`scripts/simulate-schedule-capability-routing.mjs`
**缺口(与你指出的完全一致):**
- 无 Draft / Confirm 状态机
- 无统一 Task 模型
- Query 与 Create 未 hard 分离
- 无 Action Level
- 对抗样本未进 CI
**结论:** 路由工程可用;体验与可靠性由 **ITL + 统一 Task + Confirm Gate** 决定。下一迭代应少堆规则、多建事务层。