docs: 更新协议文档和设计文档
This commit is contained in:
@@ -1,316 +1,306 @@
|
||||
# 自动化记忆任务设计方案(v2)
|
||||
# 自动化记忆与 Agent 重构设计(v3)
|
||||
|
||||
## 1. 背景与目标
|
||||
## 1. 目标
|
||||
|
||||
本方案用于重构自动化记忆能力,目标是:
|
||||
本次重构目标是把现有“router + worker”双阶段执行,收敛为更直接、可控、低 token 成本的执行链路。
|
||||
|
||||
- 保持单一运行时框架,不并行维护第二套执行系统;
|
||||
- 在运行时中新增一层抽象,使 `router` 与 `executor` 的启用策略可配置;
|
||||
- 将记忆处理职责从通用 worker 中剥离为独立 `memory agent` 角色;
|
||||
- 保留审计能力与用户可见性隔离(自动输入可审计、默认对用户隐藏);
|
||||
- 维持与现有 `/api/v1/agent`、SSE、history 协议的兼容演进路径。
|
||||
明确目标:
|
||||
|
||||
该版本是架构重构设计文档,重点解决职责边界与扩展性问题。
|
||||
1. 去除 `router agent`,由 `worker` 直接处理用户消息;
|
||||
2. `worker` 模型从 `deepseek-chat` 切换为 `qwen3.5-30b-a3b`;
|
||||
3. 关闭 `worker` 思考模式(thinking/reasoning off);
|
||||
4. 上下文策略从“今天+昨天”改为“向前回溯直到累计 20 条用户消息”;
|
||||
5. 引入专用 `memory agent`,负责记忆提取,模型为 `qwen3.5-flash`;
|
||||
6. 保持 `/api/v1/agent`、SSE、history 兼容演进,不引入第二运行时。
|
||||
|
||||
## 2. 设计原则
|
||||
## 2. 非目标
|
||||
|
||||
1. **单框架,多角色**
|
||||
- 仍复用同一套 runtime、队列、持久化、SSE 通道;
|
||||
- 不再让 worker 承担所有领域职责。
|
||||
1. 不新增独立部署的执行系统;
|
||||
2. 不引入复杂 DSL 编排;
|
||||
3. 不在本阶段改造前端交互形态;
|
||||
4. 不做跨域业务逻辑重写(仅围绕 agent 执行链路和 memory 提取职责)。
|
||||
|
||||
2. **配置驱动执行拓扑**
|
||||
- 运行路径由配置决定:是否经过 router、最终由哪个 executor 执行;
|
||||
- 执行拓扑可被审计并可回放。
|
||||
## 3. 总体架构
|
||||
|
||||
3. **记忆职责显式化**
|
||||
- 记忆提取、写入、遗忘由 `memory agent` 执行;
|
||||
- worker 继续承担通用对话/工具编排场景。
|
||||
|
||||
4. **默认安全最小权限**
|
||||
- 工具集必须是 `declared_tools ∩ allowlist`;
|
||||
- memory executor 默认仅开放记忆域工具。
|
||||
|
||||
5. **协议先行**
|
||||
- 任何对运行协议和数据结构的变更,先更新 `docs/protocols/` 再落地代码。
|
||||
|
||||
## 3. 范围与非目标
|
||||
|
||||
### 3.1 范围
|
||||
|
||||
- `automation_jobs` 引入执行拓扑配置,支持是否启用 router 与 executor 选择;
|
||||
- 运行时新增抽象层:`Execution Profile`;
|
||||
- 支持 executor 类型:`worker`、`memory`;
|
||||
- 自动任务默认使用 memory executor;
|
||||
- 消息可见性和审计策略保持增强。
|
||||
|
||||
### 3.2 非目标
|
||||
|
||||
- 不引入复杂 DSL 编排语言;
|
||||
- 不开放无限制策略字段;
|
||||
- 不新增独立部署形态的第二运行时;
|
||||
- 不在本阶段改造前端交互形态(仅保证协议兼容)。
|
||||
|
||||
## 4. 核心决策
|
||||
|
||||
1. **新增抽象层:Execution Profile(关键)**
|
||||
- 在 scheduler/orchestrator 与具体 agent 之间新增执行配置层;
|
||||
- 该层决定是否调用 router、调用哪个 executor、可用工具策略。
|
||||
|
||||
2. **executor 职责分离**
|
||||
- `worker executor`:通用任务、复杂工具编排、常规聊天;
|
||||
- `memory executor`:记忆提取、记忆写入、记忆遗忘、记忆总结。
|
||||
|
||||
3. **router 可配置启用**
|
||||
- 自动记忆任务默认 `enable_router=false`,减少不必要决策成本;
|
||||
- 普通 chat 默认 `enable_router=true`。
|
||||
|
||||
4. **拓扑合法性约束**
|
||||
- 必须保证至少有一个 executor;
|
||||
- 禁止出现 `enable_router=false` 且 `executor` 为空;
|
||||
- executor 仅允许枚举值:`worker | memory`。
|
||||
|
||||
5. **保持事件/审计统一出口**
|
||||
- 无论 executor 类型,SSE 与消息持久化走同一通道;
|
||||
- 仅扩展阶段字段枚举,不拆协议体系。
|
||||
|
||||
## 5. 目标架构
|
||||
|
||||
## 5.1 运行链路(重构后)
|
||||
### 3.1 重构后链路
|
||||
|
||||
```text
|
||||
scheduler/api trigger
|
||||
-> execution profile resolver
|
||||
-> (optional) router step
|
||||
-> executor step (worker | memory)
|
||||
-> persistence + redis stream
|
||||
-> history/sse consumers
|
||||
API/Scheduler Trigger
|
||||
-> Context Window Resolver (last 20 user messages)
|
||||
-> Executor Dispatch
|
||||
-> Worker Executor (qwen3.5-30b-a3b, thinking off)
|
||||
-> Memory Executor (qwen3.5-flash, thinking off)
|
||||
-> Tool Authorization
|
||||
-> Persistence + Redis Stream
|
||||
-> SSE/History Consumers
|
||||
```
|
||||
|
||||
与旧链路相比,变化点是新增 `execution profile resolver` 和 `memory executor`。
|
||||
### 3.2 核心变化
|
||||
|
||||
## 5.2 Execution Profile 抽象
|
||||
1. 删除 router 阶段,缩短调用链路与阶段状态;
|
||||
2. 把“意图识别”内聚到 worker 提示词与执行策略;
|
||||
3. 把“记忆提取”从通用 worker 中剥离为独立 memory executor;
|
||||
4. 上下文装配改为固定规模策略,降低输入 token 波动。
|
||||
|
||||
建议抽象(运行时内部模型):
|
||||
## 4. 执行角色与职责边界
|
||||
|
||||
### 4.1 Worker Executor(主对话执行器)
|
||||
|
||||
- 模型:`qwen3.5-30b-a3b`
|
||||
- 配置:`thinking=off`
|
||||
- 职责:
|
||||
- 处理用户请求;
|
||||
- 在单次推理中完成意图判断、工具决策、结果回复;
|
||||
- 遵守工具白名单与安全约束。
|
||||
|
||||
### 4.2 Memory Executor(记忆提取执行器)
|
||||
|
||||
- 模型:`qwen3.5-flash`
|
||||
- 配置:`thinking=off`
|
||||
- 职责:
|
||||
- 从对话中提取稳定记忆候选;
|
||||
- 产出结构化记忆写入/遗忘建议;
|
||||
- 不承担通用对话和复杂工具编排。
|
||||
|
||||
### 4.3 工具权限边界
|
||||
|
||||
统一规则:
|
||||
|
||||
`effective_tools = declared_tools ∩ profile_allowlist ∩ system_allowlist`
|
||||
|
||||
- worker 默认可调用通用工具子集;
|
||||
- memory 默认仅允许 `memory_write`、`memory_forget`;
|
||||
- 拒绝调用必须落审计(原因、工具名、请求上下文摘要)。
|
||||
|
||||
## 5. 上下文窗口策略(替代 today_yesterday)
|
||||
|
||||
### 5.1 策略定义
|
||||
|
||||
窗口规则:从当前待处理消息向前回溯,直到累计到 20 条 `role=user` 消息。
|
||||
|
||||
细则:
|
||||
|
||||
1. 计数对象仅为 `role=user`;
|
||||
2. 为保持语义连续,窗口中保留相关 assistant/tool/system 消息;
|
||||
3. 若历史不足 20 条用户消息,返回全部可用历史;
|
||||
4. 当前用户消息默认计入 20 条统计。
|
||||
|
||||
### 5.2 伪代码
|
||||
|
||||
```text
|
||||
collect_context(messages, current_message_id, n=20):
|
||||
included = []
|
||||
user_count = 0
|
||||
|
||||
for msg in reverse(messages up to current_message_id):
|
||||
included.append(msg)
|
||||
if msg.role == "user":
|
||||
user_count += 1
|
||||
if user_count >= n:
|
||||
break
|
||||
|
||||
return reverse(included)
|
||||
```
|
||||
|
||||
### 5.3 预期收益
|
||||
|
||||
1. 输入 token 成本更稳定,不再受日期边界放大;
|
||||
2. router 去除后仍可控住 worker 输入规模;
|
||||
3. 在高频会话下显著降低上下文冗余。
|
||||
|
||||
## 6. 去除 Router 后的意图识别设计
|
||||
|
||||
去掉 router 后,必须在 worker 内完成“识别 + 决策 + 执行”。本节给出可落地方案。
|
||||
|
||||
### 6.1 方案 A:复用 RouterAgentOutput 语义到 Worker Prompt
|
||||
|
||||
做法:把原 router 的标签、判定规则、优先级放进 worker system prompt,让 worker先做内部意图归类,再进入执行。
|
||||
|
||||
优点:
|
||||
|
||||
1. 迁移风险低,行为连续性强;
|
||||
2. 便于快速下线 router;
|
||||
3. 对现有回归样本复用程度高。
|
||||
|
||||
不足:
|
||||
|
||||
1. 提示词偏长;
|
||||
2. 分类与执行耦合,调试颗粒度较粗。
|
||||
|
||||
### 6.2 方案 B:重写 Worker-Native 轻量意图识别提示词
|
||||
|
||||
做法:定义最小标签集(示例:`chat | tool_call | memory_write | memory_forget | reject`)和明确优先级规则,直接服务 worker 执行。
|
||||
|
||||
优点:
|
||||
|
||||
1. prompt 更短,token 更省;
|
||||
2. 更匹配“20 条用户消息窗口”策略;
|
||||
3. 长期维护成本更低。
|
||||
|
||||
不足:
|
||||
|
||||
1. 需要重建回归集与阈值;
|
||||
2. 初期存在行为漂移风险。
|
||||
|
||||
### 6.3 推荐路线:A -> B 两阶段
|
||||
|
||||
1. 第一阶段(稳定迁移):先落地方案 A,确保 router 去除后行为不突变;
|
||||
2. 第二阶段(成本优化):基于线上样本收敛到方案 B,压缩提示词和标签集。
|
||||
|
||||
该路线兼顾了“短期稳定”和“中期降本”。
|
||||
|
||||
## 7. 数据模型与配置约定
|
||||
|
||||
### 7.1 Execution Profile(精简版)
|
||||
|
||||
建议收敛为:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "chat_default",
|
||||
"executor": "worker",
|
||||
"model": {
|
||||
"name": "qwen3.5-30b-a3b",
|
||||
"thinking": "off"
|
||||
},
|
||||
"history_policy": {
|
||||
"mode": "last_n_user_messages",
|
||||
"n": 20,
|
||||
"include_current_user_message": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
memory profile 示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "automation_memory_default",
|
||||
"enable_router": false,
|
||||
"executor": "memory",
|
||||
"model": {
|
||||
"name": "qwen3.5-flash",
|
||||
"thinking": "off"
|
||||
},
|
||||
"history_policy": {
|
||||
"mode": "last_n_user_messages",
|
||||
"n": 20,
|
||||
"include_current_user_message": true
|
||||
},
|
||||
"tool_policy": {
|
||||
"mode": "intersection",
|
||||
"allowlist": ["memory_write", "memory_forget"]
|
||||
},
|
||||
"history_policy": {
|
||||
"window": "today_yesterday"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
说明:
|
||||
### 7.2 兼容字段策略
|
||||
|
||||
- `enable_router`:是否执行 router 决策步骤;
|
||||
- `executor`:最终执行角色;
|
||||
- `tool_policy`:工具授权策略,默认交集模式;
|
||||
- `history_policy`:上下文窗口策略(保持最小化,不扩展过多字段)。
|
||||
- 历史 `enable_router` 字段保留读取兼容,写入路径不再依赖;
|
||||
- 新任务默认不再产出 router 配置;
|
||||
- 执行路径仅依据 `executor` 与 profile 配置。
|
||||
|
||||
## 5.3 默认 Profile 建议
|
||||
### 7.3 Metadata 扩展建议
|
||||
|
||||
- `chat_default`
|
||||
- `enable_router=true`
|
||||
- `executor=worker`
|
||||
建议标准字段:
|
||||
|
||||
- `automation_memory_default`
|
||||
- `enable_router=false`
|
||||
- `executor=memory`
|
||||
|
||||
## 6. 数据模型设计
|
||||
|
||||
## 6.1 `automation_jobs` 调整
|
||||
|
||||
保留现有调度相关字段:
|
||||
|
||||
- `id`, `owner_id`, `title`, `schedule_type`, `run_at`, `next_run_at`, `timezone`, `last_run_at`, `status`
|
||||
|
||||
新增/调整字段:
|
||||
|
||||
- `config JSONB NOT NULL`:任务输入与工具声明;
|
||||
- `execution_profile JSONB NOT NULL`:运行拓扑配置(MVP 可先内联,后续可抽到 profile registry)。
|
||||
|
||||
建议结构:
|
||||
|
||||
```json
|
||||
{
|
||||
"config": {
|
||||
"prompt": "提取最近对话中的稳定记忆并写入",
|
||||
"tools": ["memory_write", "memory_forget"]
|
||||
},
|
||||
"execution_profile": {
|
||||
"enable_router": false,
|
||||
"executor": "memory"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 6.2 Schema 约束
|
||||
|
||||
- `config.prompt`:必填非空,建议长度 `<= 2000`;
|
||||
- `config.tools`:必填数组,元素为已注册工具名;
|
||||
- `execution_profile.enable_router`:必填布尔;
|
||||
- `execution_profile.executor`:必填枚举 `worker|memory`;
|
||||
- `extra=forbid`,拒绝未知字段;
|
||||
- 执行前二次校验:`declared_tools ∩ runtime_allowlist`。
|
||||
|
||||
## 6.3 `messages.metadata` 扩展
|
||||
|
||||
建议标准化字段:
|
||||
|
||||
- `hidden_from_user: bool`
|
||||
- `origin: "chat" | "automation"`
|
||||
- `executor: "worker" | "memory"`
|
||||
- `execution_profile_name: string`
|
||||
- `hidden_from_user: boolean`
|
||||
|
||||
用途:
|
||||
用于用户可见性隔离与全链路审计。
|
||||
|
||||
- 用户视图过滤自动输入;
|
||||
- 审计可按 executor/profile 追踪行为;
|
||||
- 支持后续灰度比较(同任务不同 profile)。
|
||||
## 8. 协议影响与文档更新
|
||||
|
||||
## 7. 运行时行为约束
|
||||
|
||||
## 7.1 自动任务
|
||||
|
||||
- 会话类型:`session_type=automation`;
|
||||
- 自动输入消息:`role=user` + `hidden_from_user=true`;
|
||||
- 默认 profile:`automation_memory_default`;
|
||||
- executor:`memory`。
|
||||
|
||||
## 7.2 普通对话
|
||||
|
||||
- 会话类型:`session_type=chat`;
|
||||
- 默认 profile:`chat_default`;
|
||||
- executor:`worker`。
|
||||
|
||||
## 7.3 工具授权
|
||||
|
||||
- 输入工具集合来自 `config.tools`;
|
||||
- 实际可调用集合来自 `config.tools ∩ profile_allowlist ∩ system_allowlist`;
|
||||
- 对被拒绝工具记录审计日志与拒绝原因。
|
||||
|
||||
## 8. 调度器设计
|
||||
|
||||
## 8.1 扫描与触发
|
||||
|
||||
- 扫描条件:
|
||||
- `status='active'`
|
||||
- `next_run_at <= now_utc`
|
||||
- 命中后投递执行命令,命令中携带 `execution_profile` 快照。
|
||||
|
||||
## 8.2 幂等与并发
|
||||
|
||||
- 幂等键:`job_id + scheduled_slot`;
|
||||
- 通过原子更新或行级锁抢占,防止重复执行;
|
||||
- 失败重试并保留错误上下文。
|
||||
|
||||
## 8.3 时区策略
|
||||
|
||||
- 调度语义按用户本地时区(例如每日 10:00);
|
||||
- 存储执行点统一使用 UTC `next_run_at`;
|
||||
- 调度器仅按 UTC 扫描,避免多时区计算分散。
|
||||
|
||||
## 9. 协议影响与兼容策略
|
||||
|
||||
本阶段是设计重构,协议建议如下:
|
||||
按照“协议先行”原则,先更新 `docs/protocols/`:
|
||||
|
||||
1. `docs/protocols/agent/sse-events.md`
|
||||
- `STEP_STARTED/STEP_FINISHED.stepName` 从 `router|worker` 扩展为 `router|worker|memory`;
|
||||
- 当 `enable_router=false` 时,不产出 router step 事件。
|
||||
- step 枚举从 `router|worker|memory` 收敛为 `worker|memory`;
|
||||
- 对旧客户端声明:`router` 事件可能不再出现。
|
||||
|
||||
2. `docs/protocols/agent/run-agent-input.md`
|
||||
- 增补运行上下文说明:内部执行可由 profile 决定 executor;
|
||||
- 对外 API 入参保持兼容,不强制前端传 executor。
|
||||
- 增加 `history_policy.mode=last_n_user_messages` 语义与边界规则。
|
||||
|
||||
3. `docs/protocols/agent/api-endpoints.md`
|
||||
- 增补说明:`/runs` 的运行阶段由后端 profile 决定,历史与 SSE 保持统一消费方式。
|
||||
- 说明执行阶段由后端 profile 决定;
|
||||
- 不要求前端显式传入 router 或 executor 控制参数。
|
||||
|
||||
兼容要求:
|
||||
## 9. 迁移计划
|
||||
|
||||
- 老客户端仍可消费现有事件;
|
||||
- 仅新增枚举值,不删除既有字段;
|
||||
- 如客户端未识别 `memory`,按未知阶段容错处理。
|
||||
### 阶段 1:协议与配置就绪
|
||||
|
||||
## 10. 默认任务创建
|
||||
1. 完成协议文档更新;
|
||||
2. 增加 profile 新字段和兼容读取逻辑;
|
||||
3. 新建任务默认 profile 切到 worker/memory 双执行器模型。
|
||||
|
||||
用户创建后自动创建 daily 记忆任务:
|
||||
### 阶段 2:执行链路切换
|
||||
|
||||
- `schedule_type='daily'`
|
||||
- 本地时区目标时间 `10:00`
|
||||
- `timezone` 优先用户设置,缺省 `Asia/Shanghai`
|
||||
- `config.prompt` 使用内置记忆提取模板
|
||||
- `config.tools=["memory_write","memory_forget"]`
|
||||
- `execution_profile={"enable_router":false,"executor":"memory"}`
|
||||
1. 下线 router 运行路径;
|
||||
2. worker 切换 `qwen3.5-30b-a3b` + thinking off;
|
||||
3. 上下文装配切为“20 条用户消息策略”。
|
||||
|
||||
## 11. 安全与审计
|
||||
### 阶段 3:memory agent 接管记忆提取
|
||||
|
||||
安全约束:
|
||||
1. memory executor 切换 `qwen3.5-flash`;
|
||||
2. 自动记忆任务全量走 memory executor;
|
||||
3. 对比提取质量与成本,完成灰度放量。
|
||||
|
||||
- 禁止越权工具调用;
|
||||
- memory 读写必须强制 owner 作用域;
|
||||
- 日志不输出敏感内容与完整私密上下文。
|
||||
### 阶段 4:优化与收敛
|
||||
|
||||
审计能力:
|
||||
1. worker 意图识别从方案 A 迭代到方案 B;
|
||||
2. 清理 router 相关遗留代码和配置分支;
|
||||
3. 固化观测指标与报警阈值。
|
||||
|
||||
- 自动输入、工具调用、输出全链路可追踪;
|
||||
- 可按 `origin/executor/execution_profile_name` 回放。
|
||||
## 10. 测试与验收
|
||||
|
||||
## 12. 迁移与发布步骤
|
||||
### 10.1 单元测试
|
||||
|
||||
1. 更新 `docs/protocols`(先协议);
|
||||
2. 新增 `execution_profile` schema 与运行时模型;
|
||||
3. 数据迁移:历史任务写入默认 profile;
|
||||
4. 运行时接入 profile resolver;
|
||||
5. 引入 `memory executor` 并接管自动记忆任务;
|
||||
6. 灰度:先新建任务使用 memory executor,再迁移存量任务;
|
||||
7. 稳定后收敛旧逻辑分支。
|
||||
1. `last_n_user_messages` 窗口截取逻辑;
|
||||
2. 工具交集授权逻辑;
|
||||
3. profile 解析与兼容字段读取;
|
||||
4. memory 输出结构校验。
|
||||
|
||||
## 13. 测试与验收
|
||||
### 10.2 集成测试
|
||||
|
||||
## 13.1 单元测试
|
||||
1. 无 router 情况下 worker 正常执行;
|
||||
2. SSE/history 在 `worker|memory` 阶段下可稳定消费;
|
||||
3. 自动记忆任务完整链路可执行;
|
||||
4. hidden 消息对用户不可见但审计可见。
|
||||
|
||||
- profile schema 校验(非法枚举、空 executor、未知字段);
|
||||
- 工具授权交集逻辑;
|
||||
- `next_run_at` 跨时区计算;
|
||||
- 隐藏消息过滤与审计字段落库。
|
||||
### 10.3 验收指标
|
||||
|
||||
## 13.2 集成测试
|
||||
P0:
|
||||
|
||||
- 自动任务触发后进入 memory executor;
|
||||
- `enable_router=false` 时无 router step 事件;
|
||||
- SSE `stepName=memory` 可被稳定消费;
|
||||
- 自动输入审计可见、用户历史不可见。
|
||||
1. router 下线后核心对话流程零阻断;
|
||||
2. 平均输入 token 相比 today_yesterday 明显下降;
|
||||
3. 工具调用越权率为 0。
|
||||
|
||||
## 13.3 验收标准
|
||||
P1:
|
||||
|
||||
- 每日 10:00(用户本地时区)稳定执行;
|
||||
- memory 任务不经过 router 亦可稳定完成;
|
||||
- 工具权限边界有效;
|
||||
- 审计链路完整;
|
||||
- 对现有 chat 流程零回归。
|
||||
1. memory 提取质量不低于现网基线;
|
||||
2. 延迟与成本达到预期区间;
|
||||
3. 协议兼容无前端回归。
|
||||
|
||||
## 14. 实施顺序建议
|
||||
## 11. 风险与回滚
|
||||
|
||||
1. 协议文档更新(`docs/protocols/agent/*`);
|
||||
2. `automation_jobs` 数据结构改造与迁移;
|
||||
3. profile resolver 与 executor 抽象接入;
|
||||
4. memory executor 接入与工具边界验证;
|
||||
5. 调度器联调与默认任务创建;
|
||||
6. 端到端压测与灰度发布。
|
||||
主要风险:
|
||||
|
||||
1. worker 内聚识别导致误判率短期上升;
|
||||
2. 20 条用户消息窗口在极端长任务中可能信息不足;
|
||||
3. memory 轻量模型在复杂语义下提取质量波动。
|
||||
|
||||
回滚策略:
|
||||
|
||||
1. 保留 profile 级灰度开关,支持按租户/任务类型回切旧模型;
|
||||
2. 上下文策略支持临时扩容(20 -> 25)作为应急参数;
|
||||
3. memory agent 保留质量兜底阈值,低置信度结果不落库。
|
||||
|
||||
---
|
||||
|
||||
本版(v2)将“抽象 Agent 运行”落到可执行的配置模型,核心是:
|
||||
本版文档确立了清晰的一次性架构方向:
|
||||
|
||||
- 新增一层 `Execution Profile`;
|
||||
- 将 `router` 和 `executor` 拓扑配置化;
|
||||
- 使用独立 `memory executor` 承载记忆职责;
|
||||
- 在不引入第二运行时的前提下完成大规模重构演进。
|
||||
- router 从执行链路中移除;
|
||||
- worker 直连用户消息并承担意图识别;
|
||||
- memory 由专用 agent 执行;
|
||||
- 上下文按 20 条用户消息定长回溯,控制 token 成本;
|
||||
- 在兼容现有协议消费方式的前提下完成演进。
|
||||
|
||||
@@ -79,6 +79,11 @@ Base URL: `/api/v1/agent`
|
||||
- usage 审计与成本回退策略见 `docs/protocols/agent/sse-events.md`(5) Usage 审计协议)
|
||||
- 空闲时会发送 keep-alive 注释行 `: keep-alive`
|
||||
|
||||
当前阶段执行说明:
|
||||
|
||||
- 公开事件阶段为 `worker` / `memory`。
|
||||
- `router` 已从运行链路移除,不再作为阶段事件对外发送。
|
||||
|
||||
### 错误码
|
||||
|
||||
- `401` 未认证
|
||||
|
||||
@@ -185,7 +185,7 @@ interface Context {
|
||||
|
||||
---
|
||||
|
||||
## forwardedProps.client_time Schema
|
||||
## forwardedProps Schema(当前仅支持 client_time)
|
||||
|
||||
`RunAgentInput.forwardedProps` 支持透传客户端时间上下文。日历相关能力必须使用以下结构:
|
||||
|
||||
@@ -213,6 +213,7 @@ interface ForwardedProps {
|
||||
- `device_timezone` 必须是有效 IANA 时区。
|
||||
- `client_now_iso` 必须是 RFC3339 且包含时区偏移。
|
||||
- `client_epoch_ms` 必须是整数毫秒时间戳。
|
||||
- `forwardedProps` 当前仅允许 `client_time`,额外字段会触发 `422 invalid RunAgentInput.forwardedProps`。
|
||||
- 业务代码不得使用服务器本地时区作为事件语义时区。
|
||||
|
||||
### 说明
|
||||
@@ -434,7 +435,7 @@ interface HistoryMessageAssistant {
|
||||
seq: number;
|
||||
role: "assistant";
|
||||
content: string;
|
||||
ui_schema: UiSchemaRenderer | null; // 由 worker_agent_output.ui_hints 编译
|
||||
ui_schema: UiSchemaRenderer | null; // 由 agent_output.ui_hints 编译
|
||||
timestamp: string;
|
||||
}
|
||||
|
||||
@@ -519,4 +520,5 @@ interface UiSchemaRenderer {
|
||||
- `tools` 是前端工具通道字段;当前后端运行时不基于该字段构造后端工具 prompt
|
||||
- `RunAgentInput` 同时接受 camelCase 与 snake_case 别名输入(推荐统一使用 camelCase)
|
||||
- 日历能力依赖 `forwardedProps.client_time` 透传设备时间上下文;缺失时回退用户 profile 时区
|
||||
- `forwardedProps` 不支持业务私有控制字段(例如 `system_agent_mode`)
|
||||
- tool 消息在存储层用于运行时上下文续接,不在 `/history` 对外返回
|
||||
|
||||
@@ -84,7 +84,7 @@ data: <json>
|
||||
"type": "STEP_STARTED",
|
||||
"threadId": "...",
|
||||
"runId": "...",
|
||||
"stepName": "router" | "worker"
|
||||
"stepName": "worker" | "memory"
|
||||
}
|
||||
```
|
||||
|
||||
@@ -95,7 +95,7 @@ data: <json>
|
||||
"type": "STEP_FINISHED",
|
||||
"threadId": "...",
|
||||
"runId": "...",
|
||||
"stepName": "router" | "worker"
|
||||
"stepName": "worker" | "memory"
|
||||
}
|
||||
```
|
||||
|
||||
@@ -197,6 +197,11 @@ data: <json>
|
||||
|
||||
`inputTokens`、`outputTokens`、`cost`、`latencyMs`、`model` 属于后端内部统计字段,不在 SSE 对外协议中暴露。
|
||||
|
||||
当前实现补充说明:
|
||||
|
||||
- `TEXT_MESSAGE_END` 在 wire payload 中会包含 `totalTokens`、`cachedPromptTokens`、`promptCacheHitTokens`、`promptCacheMissTokens`、`reasoningTokens`、`costSource`、`usageComplete` 等 usage 摘要字段,供前端观测面板使用。
|
||||
- 这些字段来自后端 usage 归一化层,属于 AG-UI 事件数据的一部分,不改变 `TEXT_MESSAGE_END` 主结构。
|
||||
|
||||
---
|
||||
|
||||
## 5) Usage 审计协议(后端内部)
|
||||
|
||||
@@ -139,7 +139,19 @@ tool 结果不再走 UI 编译链路:`TOOL_CALL_RESULT` 提供 `tool_call_args
|
||||
3. 执行 GoRouter 跳转(建议 `context.go(...)`)。
|
||||
- `path` 必须是已落地页面路由,且应是已实参化路径(如 `/todo/123`,而非 `/todo/:id`)。
|
||||
|
||||
### 7.3 约束建议
|
||||
### 7.3 路由表达粒度(Route-First 约束)
|
||||
|
||||
- 关键业务动作(创建、编辑、分享、处理邀请等)应优先设计为可深链页面路由,而不是仅存在于临时弹层。
|
||||
- 若 UI 采用 sheet 风格展示,也应由页面路由承载状态,再以页面内 surface 呈现 sheet 视觉。
|
||||
- `todo.edit` 必须落地为独立子页面(`/todo/{id}/edit`),不应通过详情页内弹窗承载编辑主流程。
|
||||
- 推荐后端优先使用以下 route_id 生成导航(示例):
|
||||
- `calendar.event_create` -> `/calendar/events/new`
|
||||
- `calendar.event_edit` -> `/calendar/events/{id}/edit`
|
||||
- `calendar.event_share` -> `/calendar/events/{id}/share`
|
||||
- `todo.create` -> `/todo/new`
|
||||
- `todo.edit` -> `/todo/{id}/edit`
|
||||
|
||||
### 7.4 约束建议
|
||||
|
||||
- 为了让前端只保留一种解析逻辑,推荐强约束:
|
||||
- `path` 只接受内部路由;
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
# UI Schema File Split Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** 将 `apps/lib/core/schemas/ui_schema.dart` 从超大单文件拆分为同库的多个 `part` 文件,在不改变协议行为的前提下提升可维护性。
|
||||
|
||||
**Architecture:** 保留 `ui_schema.dart` 作为唯一对外入口和 single source of truth;通过 `part` 把 enums、common types、actions、nodes、document、builder 按职责拆分到 `core/schemas/ui_schema/` 子目录。所有类型名、JSON 字段、默认值与工厂方法逻辑保持完全一致,避免协议漂移。
|
||||
|
||||
**Tech Stack:** Dart library/part、Flutter analyze、Flutter test
|
||||
|
||||
---
|
||||
|
||||
### Task 1: 建立拆分骨架并保留外部接口
|
||||
|
||||
**Files:**
|
||||
- Modify: `apps/lib/core/schemas/ui_schema.dart`
|
||||
- Create: `apps/lib/core/schemas/ui_schema/enums.dart`
|
||||
- Create: `apps/lib/core/schemas/ui_schema/common_types.dart`
|
||||
- Create: `apps/lib/core/schemas/ui_schema/actions.dart`
|
||||
- Create: `apps/lib/core/schemas/ui_schema/nodes.dart`
|
||||
- Create: `apps/lib/core/schemas/ui_schema/document.dart`
|
||||
- Create: `apps/lib/core/schemas/ui_schema/builders.dart`
|
||||
|
||||
- [ ] **Step 1: 在主文件添加 `part` 声明并保留文件头注释**
|
||||
- [ ] **Step 1.1: 所有子文件统一使用 `part of '../ui_schema.dart';`,避免子目录相对路径错误**
|
||||
- [ ] **Step 2: 将 enum 定义迁移到 `enums.dart`,语义不变**
|
||||
- [ ] **Step 3: 将基础 DTO 迁移到 `common_types.dart`,语义不变**
|
||||
- [ ] **Step 4: 将 Action 协议与解析逻辑迁移到 `actions.dart`,语义不变**
|
||||
- [ ] **Step 5: 将 UiNode 与各 node 实现迁移到 `nodes.dart`,语义不变**
|
||||
- [ ] **Step 6: 将文档配置/文档模型迁移到 `document.dart`,语义不变**
|
||||
- [ ] **Step 7: 将 `buildSuccessDocument`/`buildErrorDocument` 迁移到 `builders.dart`**
|
||||
|
||||
### Task 2: 进行协议稳定性验证
|
||||
|
||||
**Files:**
|
||||
- Create: `apps/test/core/schemas/ui_schema_test.dart`
|
||||
- Test: `apps/test/features/chat/ui_schema_renderer_test.dart`
|
||||
- Test: `apps/test/features/chat/ui_schema_navigation_test.dart`
|
||||
- Test: `apps/test/features/chat/ag_ui_event_test.dart`
|
||||
|
||||
- [ ] **Step 1: 新增 `ui_schema.dart` 直连回归测试**
|
||||
- 覆盖 enum fallback、`actionSpecFromJson` 分支、`UiNode.fromJson` 分支、Document/builder 默认值、round-trip 稳定性。
|
||||
- [ ] **Step 2: 在 `apps/` 目录运行 analyze,确认 `part` 结构无编译错误**
|
||||
- Run (`apps/`): `flutter analyze`
|
||||
- [ ] **Step 3: 在 `apps/` 目录运行 UI Schema 渲染与导航相关测试**
|
||||
- Run: `flutter test test/features/chat/ui_schema_renderer_test.dart`
|
||||
- Run: `flutter test test/features/chat/ui_schema_navigation_test.dart`
|
||||
- [ ] **Step 4: 在 `apps/` 目录运行 AG-UI 事件模型回归测试**
|
||||
- Run: `flutter test test/features/chat/ag_ui_event_test.dart`
|
||||
- [ ] **Step 5: 在 `apps/` 目录运行新增 schema 回归测试**
|
||||
- Run: `flutter test test/core/schemas/ui_schema_test.dart`
|
||||
|
||||
### Task 3: 完成收尾与风险核对
|
||||
|
||||
**Files:**
|
||||
- Modify: `apps/lib/core/schemas/ui_schema.dart`
|
||||
- Modify: `apps/lib/core/schemas/ui_schema/*.dart`
|
||||
|
||||
- [ ] **Step 1: 检查 public API 未变化(类型名/函数名不变)**
|
||||
- [ ] **Step 2: 检查 JSON 键、默认值、fallback 分支未变化**
|
||||
- [ ] **Step 3: 确认 `ui_schema.dart` 行数显著下降并保留 single source 入口定位**
|
||||
Reference in New Issue
Block a user