Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

外部数据库访问

本章说明当前方案下“数据库访问”到底是怎么做的。

当前统一方案Backend(后端控制面)负责所有数据库查询和写入,容器内的 Worker / agentcore 不直接连接数据库。 Worker 只需要实现与 Backend 的协议通信。

这意味着:

  • Worker 不直接连接 PostgreSQL / MySQL / Redis / 向量数据库
  • Worker 不直接打开 checkpoint 数据库文件
  • Worker 不持有数据库地址、账号、密码
  • 所有数据库访问都由 Backend 统一代理、审计和裁剪

1. 为什么要这样设计

过去最容易出现的误解是:既然容器在本地机器上运行,那是不是可以让容器直接连数据库?

当前方案明确不这么做,原因有四个:

原因说明
安全数据库凭据只留在 Backend,容器内不暴露
简化容器Worker 只实现协议,不需要感知数据库类型、网络地址、驱动差异
审计一致所有查库、写库都在 Backend 一侧统一记录
演进容易将来数据库从本地迁到云端,Worker 协议无需改变

2. 整体模型:Backend 统一查库

graph TB
    subgraph USER_SIDE["用户侧"]
        H["Helper / Web UI"]
    end

    subgraph CONTROL["Backend 控制面"]
        API["API + WS 路由"]
        SVC["ApplicationService"]
        GATE["数据访问网关"]
    end

    subgraph EXEC["执行面"]
        W["Worker / agentcore"]
    end

    subgraph DATA["数据层"]
        DB1["会话数据库"]
        DB2["检查点数据库"]
        DB3["业务数据库"]
    end

    H --> API
    W -->|"协议请求"| API
    API --> SVC --> GATE
    GATE --> DB1
    GATE --> DB2
    GATE --> DB3

一句话概括就是:

Worker 只会说“我要什么数据 / 我要写什么状态”,真正的查库和写库由 Backend 完成。


3. 本地部署时为什么更适合 Backend 查库

当前系统是本地部署

  • 用户的本地机器 = Backend 所在宿主机
  • K3s 也在这台机器上运行

因此如果数据库也在本机,Backend 访问数据库最直接:

graph LR
    subgraph HOST["用户本地机器 / 宿主机"]
        B["Backend"]
        DB["本地数据库"]
        K["K3s"]
        W["Worker Pod"]
    end

    B -->|"localhost / 本机 socket / 本机地址"| DB
    W -->|"协议通信"| B

这样可以直接避免几个典型问题:

  1. Pod 内 localhost 不是宿主机 localhost
  2. 容器不需要知道宿主机 IP、Service、Endpoints 这些网络细节
  3. 容器里不需要再装数据库驱动和连接配置

所以在你们当前的架构里,“宿主机上的数据库怎么让容器访问”这个问题本身就被收敛掉了:不是容器去访问,而是 Backend 去访问。


4. Worker 与 Backend 的数据库协议

既然 Worker 不直接查库,那么就必须通过协议把“我要读什么 / 我要写什么”表达给 Backend。

推荐把协议操作分成四类:

协议操作用途语义
backend_query读取业务数据 / 会话数据 / 配置数据同步
backend_command写入业务状态或执行事务性操作同步
checkpoint_get拉取恢复所需的检查点同步
checkpoint_put上报新的检查点快照同步

4.1 backend_query(同步)

用于 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 的后续推理通常依赖这个结果,不能“先继续、稍后补回来”。

示例:

{
  "type": "backend_query",
  "id": "query-001",
  "timestamp": "2026-04-17T02:30:00Z",
  "payload": {
    "resource": "customer_profile",
    "operation": "get",
    "arguments": {
      "customerId": "cust-001"
    }
  }
}

响应:

{
  "type": "backend_query_result",
  "id": "query-001",
  "timestamp": "2026-04-17T02:30:00Z",
  "payload": {
    "ok": true,
    "data": {
      "customerId": "cust-001",
      "name": "Alice"
    }
  }
}

4.2 backend_command(同步)

用于 Worker 需要 Backend 执行有副作用的数据库操作,例如:

  • 创建一条记录
  • 更新某个状态
  • 记录审批结果
  • 触发一个事务性写入
sequenceDiagram
    participant W as Worker
    participant B as Backend
    participant DB as 数据库

    W->>B: backend_command
    B->>DB: 执行写入 / 事务
    DB-->>B: 返回提交结果
    B-->>W: backend_command_result

这类操作也应是同步语义,因为 Worker 需要明确知道写入是否成功,才能决定下一步。

4.3 checkpoint_get(同步)

Worker 启动后,如果需要恢复上一次状态,不直接读本地数据库文件,而是向 Backend 请求:

sequenceDiagram
    participant W as Worker
    participant B as Backend
    participant DB as 检查点数据库

    W->>B: checkpoint_get(session_id, run_id)
    B->>DB: 查询最新检查点
    DB-->>B: 返回 checkpoint snapshot
    B-->>W: checkpoint_get_result

这是同步语义,因为恢复流程没拿到 checkpoint 结果就不能继续。

4.4 checkpoint_put(同步)

Worker 在关键步骤结束后,把新的检查点快照通过协议发给 Backend:

sequenceDiagram
    participant W as Worker
    participant B as Backend
    participant DB as 检查点数据库

    W->>B: checkpoint_put
    B->>DB: 持久化 checkpoint
    DB-->>B: 写入成功
    B-->>W: checkpoint_put_ack

这同样建议定义成同步语义,因为只有拿到 ACK,Worker 才能认为“这份状态已经可恢复”。


5. 哪些操作是异步的

虽然数据库操作统一走同步语义,但并不是所有协议都同步。

以下仍然是异步事件

协议消息语义原因
stream_chunk异步高频流式输出,不能每个 token 都等确认
state_change异步状态通知型消息
tool_progress异步进度展示用,不阻塞主流程
error异步失败上报,Backend 收到后再统一处理
ask_user混合发送是异步,Worker 业务流程会暂停等待回复

所以整体规则可以简单记为:

查库 / 写库 / checkpoint 恢复与保存 = 同步语义
流式输出 / 状态变化 / 进度通知 = 异步语义


6. run-context.json 在这里扮演什么角色

run-context.json 仍然存在,但它的角色是:

  • 给 Worker 提供启动时的初始快照
  • 减少刚启动时第一批必须走协议请求的次数
  • 让 Worker 在还没发出第一条协议消息前,就能拿到基础上下文

它通常包含:

  • 当前会话摘要
  • 最近对话历史
  • 已授权的输入文件信息
  • 最近检查点的元数据摘要

但它不是数据库本身,也不是容器的长期状态源。

长期、权威的数据源仍然是 Backend 管理的数据库。


7. 本地数据库、远程数据库、云数据库有什么区别

在当前方案里,这三种数据库对 Worker 来说没有本质区别

区别只发生在 Backend 这一层:

数据库位置实际连接方Worker 是否感知地址差异
宿主机本地数据库Backend
局域网数据库Backend
云数据库 / 托管数据库Backend

这就是当前方案最大的架构收益之一:Worker 不需要因为数据库部署位置不同而改变协议。


8. 安全与治理收益

能力收益
凭据集中管理数据库用户名、密码、Token 都只保留在 Backend
权限收敛Worker 没有直接数据库访问权限
审计统一所有数据库操作都可以在 Backend 侧统一留痕
限流与缓存Backend 可统一做缓存、熔断、重试和速率控制
数据裁剪Backend 可以只返回 Worker 真正需要的字段

9. 技术可行性判断

方案可行性复杂度推荐度
Worker 直接连数据库可行但不推荐
Worker 直接读 checkpoint DB 文件可行但不推荐
Backend 统一查库 + Worker 协议请求强烈推荐

推荐 Backend 统一代理的原因不是“唯一能做”,而是它最符合你们当前的本地部署模型和协议化架构。


下一步

理解了数据库访问模型后,建议继续阅读: