同步与异步语义
本章专门说明 K3s Runtime 里每类操作到底是同步还是异步。这是理解整套交互协议的关键。
当前统一原则:Backend(后端控制面)负责所有数据库查询与持久化,Worker(容器内 agentcore)不直接连接数据库。 Worker 只通过协议向 Backend 发起请求或上报事件。
1. 三种语义先分清
| 类型 | 含义 | 典型特征 |
|---|---|---|
| 同步 | 发起方必须等待结果,才能继续后续逻辑 | 有明确请求和响应,超时会中断当前步骤 |
| 异步 | 发起方发出后即可继续,不阻塞当前主流程 | 结果稍后以事件、回调或状态更新返回 |
| 混合 | 提交动作本身同步,但实际执行过程异步 | API 立即返回 accepted,结果稍后到达 |
注意:这里说的“同步/异步”是业务语义,不是底层网络库是不是
async/await。即使底层使用 WebSocket 异步 I/O,也可以承载“语义上同步”的请求-响应。
2. 总体规则
graph TB
A["用户 / Helper 发起操作"] --> B{"操作是否必须等结果?"}
B -->|"是"| C["同步语义<br/>请求 → 等待响应"]
B -->|"否"| D["异步语义<br/>提交 → 继续执行"]
D --> E["后续通过事件返回进度 / 结果"]
C --> F["超时或失败立即影响当前步骤"]
3. Helper → Backend 操作矩阵
| 操作 | 语义 | 原因 |
|---|---|---|
健康检查 /health | 同步 | 需要立即知道服务是否可用 |
创建会话 /sessions | 同步 | 需要立即拿到 session_id |
获取会话 /sessions/{id} | 同步 | 读取型查询,返回即完成 |
上传附件 /artifacts/upload | 同步 | 需要先确认文件已被 Backend 接收 |
创建挂载授权 /mount-grants | 同步 | 需要先确认路径校验和授权结果 |
创建运行 /runs | 混合 | 请求提交同步返回 run_id,真正执行异步发生 |
查询运行 /runs/{id} | 同步 | 读取当前状态快照 |
取消运行 /runs/{id}/cancel | 混合 | 接收取消请求同步返回,Worker 实际停止异步完成 |
关闭会话 /sessions/{id}/close | 混合 | 归档动作同步完成,Worker 退出异步完成 |
重开会话 /sessions/{id}/reopen | 同步 | 状态切换立即生效 |
4. Backend → Worker 协议矩阵
| 协议消息 | 语义 | 说明 |
|---|---|---|
push_message | 异步 | Backend 把用户消息推给 Worker,执行结果稍后返回 |
cancel_task | 异步 | Backend 发出取消信号,不等待瞬时完成 |
ping | 异步 | 心跳探测,不改变业务流程 |
backend_query_result | 同步响应 | 用于回应 Worker 发起的同步查询 |
backend_command_result | 同步响应 | 用于回应 Worker 发起的同步写入/变更 |
checkpoint_get_result | 同步响应 | 返回恢复执行所需的检查点数据 |
checkpoint_put_ack | 同步响应 | 确认 Backend 已持久化检查点 |
5. Worker → Backend 协议矩阵
| 协议消息 | 语义 | 说明 |
|---|---|---|
state_change | 异步 | Worker 上报状态变化,Backend 记录即可 |
stream_chunk | 异步 | 高频流式片段,不阻塞 Worker 主流程 |
message_response | 异步 | 最终回复事件,由 Backend 接收后写入会话历史 |
ask_user | 混合 | 发送本身异步,但 Worker 会暂停,等待后续 user_reply |
tool_call / tool_progress | 异步 | 通知型事件,便于前端展示进度 |
error | 异步 | 失败事件,Backend 收到后再统一处理 |
backend_query | 同步 | Worker 请求 Backend 查询数据库,必须等结果再继续 |
backend_command | 同步 | Worker 请求 Backend 执行写操作,必须等确认 |
checkpoint_get | 同步 | Worker 恢复状态时请求历史检查点 |
checkpoint_put | 同步 | Worker 发送检查点并等待持久化 ACK,确保可恢复性 |
pong | 异步 | 心跳响应 |
6. 为什么“查库”必须是同步语义
当前方案下,业务数据库、会话数据库、检查点数据库都由 Backend 统一访问,因此 Worker 的“取数据”动作本质上是:
sequenceDiagram
participant W as Worker
participant B as Backend
participant DB as 数据库
W->>B: backend_query
B->>DB: 查询数据库
DB-->>B: 返回结果
B-->>W: backend_query_result
这类操作必须定义成同步语义,原因有三个:
- Worker 后续推理往往依赖查询结果,不能“先继续再补结果”。
- Backend 可以在同一次响应里附带权限校验、数据裁剪和审计结果。
- 超时、权限不足、数据不存在等错误必须立刻返回给 Worker,便于当前步骤决定重试、降级或询问用户。
7. 为什么“流式输出”必须是异步语义
stream_chunk、state_change、tool_progress 这类消息的目标是边执行边展示。如果把它们设计成同步语义,会导致:
- Worker 每输出一个 token 都要等待确认
- Backend 和前端很容易成为吞吐瓶颈
- 整个回复速度明显下降
因此这些消息统一采用异步事件语义:尽快发送、尽快渲染,必要时依靠 WebSocket 自身的 TCP 背压控制限速。
8. 需要特别注意的“混合语义”操作
| 操作 | 为什么是混合 |
|---|---|
| 创建运行 | API 层要立刻返回 run_id,但容器启动和执行要异步完成 |
| ask_user | 事件推送本身异步,但 Worker 的业务流程会暂停等待用户答复 |
| 取消运行 | 提交取消请求同步成功,不代表 Worker 已经立刻退出 |
| 关闭会话 | 会话状态可以立刻改成 closed,但 Deployment 回收还需要异步完成 |
9. 当前推荐约束
为了让协议清晰且稳定,推荐遵循以下约束:
- 所有数据库读写统一走 Backend,Worker 不直接持有数据库 DSN、账号和驱动配置。
- 所有需要“等结果才能继续”的协议消息都必须有明确响应消息,不能只靠超时猜测结果。
- 所有高频输出都采用异步事件,不要为每个 token 设计同步确认。
- 所有长任务都拆成“启动 + 进度 + 完成”三段式,不要让单次同步请求占住连接太久。
下一步
理解了同步/异步语义后,建议继续阅读: