设计哲学
Awaken 围绕三条准则构建。每一条都是硬边界,不是建议。三条合起来产生其它智能体框架普遍缺失的四项性质。
准则 1 —— 代码管工具,配置管提示词
Section titled “准则 1 —— 代码管工具,配置管提示词”工具是 Rust 产物:类型化输入 schema、可选的状态写入、可选的延迟加载钩子。工具需要编译期检查,改动很少。
提示词、工具描述、Reminder、权限规则、Skill 目录是内容。它们不断变化,需要快反馈循环。
两类严格分开。
| 层 | 落在 | 重载触发 |
|---|---|---|
| Tool、Plugin、Schema | Rust 代码 | 构建并部署 |
| Agent 系统提示、工具描述 | 通过配置 API 写入 AgentSpec | 下一次 run |
| 权限规则(allow/deny/ask) | 插件配置 | 下一次 run |
| Reminder 规则(工具模式 → 消息) | 插件配置 | 下一次 run |
| Skill 包(磁盘 YAML) | 文件系统 | PeriodicRefresher(显式调用 start_periodic_refresh(interval) 开启) |
| MCP server 工具 | 远端 MCP server | tools/list_changed 通知(自动) |
自动重载由 runtime 自己做。需要显式开启的(Skill)在 bootstrap 里调一次 start_periodic_refresh 即可 —— 你仍然不写 watcher 代码。
智能体工作的内循环 —— 改 prompt → 看效果 —— 由”一次 CI run”变成”一次 config API 往返”。
准则 2 —— 一个配置面,一个管理控制台
Section titled “准则 2 —— 一个配置面,一个管理控制台”/v1/config/* 是托管 runtime 配置的唯一修改 API。Agent、模型、model pool、Provider、MCP server、Skill 和插件策略 section 全部经它暴露。
管理控制台是这个 API 的一个消费者,CI 流水线是另一个。runtime 读的是控制台写的同一个源。
没有独立”运维 UI”子项目,没有生产里和运行配置漂移的影子 YAML,没有跟着跑的带外缓存。
准则 3 —— Runtime 就是平台
Section titled “准则 3 —— Runtime 就是平台”Runtime 提供一等模块来承载:
- 每个 phase、每次工具调用、每次 LLM 调用的 OpenTelemetry GenAI traces。
- 管理控制台可查询的持久化 trace store(需要接入 trace store 并开启 trace routes)。
- 自带 fixture 回放、打分、baseline 对比的 Eval 框架。
- Permission gate + mailbox 实现的 HITL 挂起 / 恢复。
它们接入 runtime 与 server 的模块表面,而不是独立 sidecar。Day-one 项目使用和更大部署相同的执行、配置、权限与重放表面;需要存储后端的能力由部署显式开启。
派生的四项性质
Section titled “派生的四项性质”快照隔离 + 确定性重放
Section titled “快照隔离 + 确定性重放”每个 phase 读取不可变 Snapshot,emit 类型化 MutationBatch。commit 原子应用 batch,即使工具并行运行也是。
两个推论:
- 并行工具不会污染状态。 每个类型化 state key 声明
MergeStrategy(Exclusive、Commutative)。合并在编译期校验。 - 任何 snapshot 都是时间机器。 历史 run 从保存的状态逐字节重放 —— 调试事故、回归、用昨天的流量跑 Eval,全部无需重付 LLM 成本。
常见替代是加锁的可变共享状态(或强制串行)。两个插件碰到同一字段的那一刻,两种方案都悄无声息地坏。
一套后端,多种协议适配器
Section titled “一套后端,多种协议适配器”同一个 runtime 暴露为多种 wire format:
- AI SDK v6(Vercel
useChat()) - AG-UI(CopilotKit:chat + 生成式 UI + HITL)
- A2A(智能体对智能体调用)
- MCP HTTP(JSON-RPC client)
- ACP stdio(Agent Client Protocol host)
Runtime emit 一条 AgentEvent 流;协议适配器编码到对应线协议。换客户端不动 agent 代码;同时承接多种协议不会让 runtime 翻倍。
常见替代是”挑一种协议,在每个客户端建适配器”。这把 agent 代码绑死在你下个季度可能后悔的前端选择上。
权限裁决是 runtime primitive
Section titled “权限裁决是 runtime primitive”权限不是 UI prompt 也不是 middleware hook。它运行在类型化 ToolGate phase 中(awaken-runtime-contract/src/model/phase.rs 的 Phase enum 变体),位于”决定调用工具”和”执行工具”之间 —— runtime 在任何工具执行前都会进入这个 phase。
awaken-ext-permission 对每次调用匹配规则:
Allow—— 放行。Deny—— 短路,返回结构化错误。Ask—— 通过 mailbox 挂起 run、持久化问题、回应后恢复(Web UI、Slack bot、CLI 任选)。
规则把工具名上的 glob/regex 与参数上的 JSON-path 表达式组合起来。规则落在配置里(准则 1 —— 在线调)。
常见替代是”工具抛异常 + 前端弹框”。这把 HITL 锁死在某一种前端,丢掉长生命周期 run 需要的挂起 / 恢复语义。
生成式 UI 是流式 primitive
Section titled “生成式 UI 是流式 primitive”Agent 在同一条 AgentEvent 流上 emit 声明式 UI(A2UI 组件、JSON Render 树、OpenUI Lang 文档)。协议适配器转发到前端;前端无需为每个工具写胶水。
UI surface 是一等状态 —— 有 ID、更新合并、子树和其它工具输出一样能通过 trace store 调试。
常见替代是”工具返回 JSON,前端按形状写 React”。这把 UI 迭代绑死在前端发布周期上,只要涉及 UI 就破坏’在线调’循环。
- 架构 —— 三层 runtime 结构
- Run 生命周期与 Phases —— 九个阶段
- 状态与快照模型 —— 合并策略详解
- HITL 与 Mailbox —— 挂起 / 恢复语义
- 设计取舍 —— 我们考虑过的替代方案