系统架构总览
本章用一张图说清楚 K3s 运行时模块在整个系统中的位置,以及各个组件之间的关系。
1. 整体系统组成
整个智能体商店系统由四个主要部分组成:
graph TB
subgraph 用户侧["🖥️ 用户侧(macOS 本地)"]
User["用户"]
Helper["Helper(本地桥接服务)"]
UI["Web UI(浏览器界面)"]
end
subgraph 后端控制面["☁️ 后端控制面"]
API["HTTP API 路由层"]
Service["应用服务层<br/>ApplicationService"]
Store["状态存储<br/>FileBackedStore"]
DataGateway["数据访问网关<br/>统一查库/写库"]
PackageCatalog["Agent 包目录索引"]
ProfileCatalog["运行时配置索引"]
end
subgraph K3s运行时["⚙️ K3s 运行时模块"]
Orchestrator["K3s 编排器<br/>K3sOrchestrator"]
K3sAPI["Kubernetes API"]
end
subgraph 执行层["📦 容器执行层(K3s 集群)"]
DEP1["Deployment(长驻部署)"]
SVC1["Service(网络服务)"]
Pod1["Pod(容器组)"]
AgentCore["agentcore<br/>(智能体核心运行时)"]
end
User -->|"发送消息/上传文件"| UI
UI -->|"HTTP 请求"| Helper
Helper -->|"转发 API 请求"| API
API -->|"调用"| Service
Service -->|"读写状态"| Store
Service -->|"统一数据访问"| DataGateway
Service -->|"查询包"| PackageCatalog
Service -->|"查询配置"| ProfileCatalog
Service -->|"提交运行"| Orchestrator
Orchestrator -->|"创建资源"| K3sAPI
K3sAPI -->|"调度执行"| DEP1
DEP1 -->|"创建"| Pod1
SVC1 -->|"路由流量 :8081"| Pod1
Pod1 -->|"运行"| AgentCore
各组件职责一句话总结
| 组件 | 职责 |
|---|---|
| Helper(本地桥接服务) | 运行在用户 macOS 上,提供 Web UI,将用户操作转化为 API 请求发送到后端 |
| 后端控制面(Backend) | 接收请求、管理会话/文件/运行记录、组装启动计划、持久化所有状态,并统一负责数据库查询与写入 |
| K3s 编排器(K3sOrchestrator) | 将启动计划渲染成 Kubernetes 资源(Deployment + Service + ConfigMap + Secret),提交到集群,监控运行状态 |
| K3s 集群 | 真正调度和运行容器的底层系统 |
| agentcore(智能体核心运行时) | 容器内的执行程序,负责推理、工具调用、文件读写 |
2. 控制面统一数据访问
当前方案有一个必须先记住的原则:
所有数据库访问都由 Backend 负责,容器内的 Worker 不直接连接数据库。
这包括三类数据:
- 会话数据库:对话历史、RunRecord、SessionRuntimeState 等
- 检查点数据库:checkpoint、恢复快照、执行中间状态
- 业务数据库:PostgreSQL / MySQL / Redis / 向量库等外部数据源
对应关系如下:
graph LR
H["Helper / 用户请求"] --> B["Backend"]
W["Worker / agentcore"] -->|"协议请求"| B
B -->|"查询 / 写入"| DB1["会话数据库"]
B -->|"查询 / 写入"| DB2["检查点数据库"]
B -->|"查询 / 写入"| DB3["业务数据库"]
这样设计有四个直接好处:
- 安全更简单:数据库凭据只保留在 Backend,不进容器
- 协议更稳定:Worker 只需要理解“协议”,不需要关心数据库类型和地址
- 审计更集中:所有查库、写库都可以统一记录和限流
- 同步/异步更清晰:哪些操作必须等结果,哪些可以异步流式返回,都由 Backend 统一定义
3. 两层架构:控制面 + 执行面
当前系统采用**“单进程控制面 + K3s 执行面”**的架构:
graph LR
subgraph 控制面["控制面(Backend 进程)"]
direction TB
A1["接收 API 请求"]
A2["管理会话、文件和数据库访问"]
A3["组装 LaunchPlan(启动计划)"]
A4["持久化运行记录与检查点"]
end
subgraph 执行面["执行面(K3s 集群)"]
direction TB
B1["创建 ConfigMap / Secret / Deployment / Service"]
B2["调度 Pod 到节点"]
B3["拉取镜像、挂载目录"]
B4["启动 agentcore,通过协议与 Backend 通信"]
end
控制面 -->|"LaunchPlan"| 执行面
执行面 -->|"运行状态 / WebSocket 事件"| 控制面
关键理解:后端(Backend)不会直接创建容器。它只负责创建四种“声明式资源“——ConfigMap(配置映射)、Secret(密钥资源)、Deployment(部署)、Service(服务)。真正把这些声明变成运行中容器的,是 K3s 系统内部的控制器和节点代理程序。
同时,Backend 也不会把数据库直接暴露给容器。容器只拿到:
- 运行上下文文件(
run-context.json) - 必要的文件挂载
- 与 Backend 通信所需的协议地址
4. 同步 / 异步的总分工
从系统层面看,操作被分成三类:
| 操作 | 语义 | 例子 |
|---|---|---|
| 同步 | 发起方必须等待结果 | 创建会话、读取会话详情、Worker 请求 Backend 查库 |
| 异步 | 发出后继续执行,结果稍后返回 | 流式输出、状态变化、心跳、工具进度 |
| 混合 | 提交同步,执行异步 | 创建 Run、取消 Run、ask_user 等待用户回复 |
详细矩阵见:同步与异步语义
5. 代码模块分层
从代码角度看,K3s 相关的逻辑分成了两个独立的层:
graph TB
subgraph Backend应用层["Backend 应用层 (app crate)"]
SVC["service.rs<br/>应用服务层"]
K8S["k8s/mod.rs<br/>适配层"]
DOM["domain.rs<br/>领域类型"]
end
subgraph K3s运行时层["K3s 运行时 crate"]
LIB["lib.rs — 编排器门面"]
TYPES["types.rs — 输入输出类型"]
APPLY["apply.rs — 资源创建与清理"]
INSPECT["inspect.rs — 状态观察"]
WL_WK["workload_worker.rs — SessionWorker 渲染"]
VOL["volumes.rs — 卷布局"]
PKG["package_bundle.rs — ConfigMap/Secret 渲染"]
NAM["naming.rs — 资源命名"]
SB["service_bindings.rs — 外部服务绑定"]
end
SVC -->|"组装 LaunchPlan"| K8S
K8S -->|"转换成 crate 输入"| LIB
LIB --> APPLY
LIB --> INSPECT
LIB --> WL_WK
LIB --> VOL
LIB --> PKG
LIB --> NAM
WL_WK --> VOL
WL_WK --> PKG
WL_WK --> NAM
为什么要分成两层
这种分层设计带来三个明确的好处:
- 职责清晰:Backend 可以独立演进会话管理、权限校验等业务逻辑,不需要了解 Kubernetes API 的细节。
- 可替换执行层:如果未来需要把 K3s 替换成其他容器编排系统,只需要替换 K3s 运行时 crate,Backend 的代码基本不用改。
- 便于并行开发:不同开发者可以同时修改不同模块而不互相冲突。
6. 适配层的桥梁作用
Backend 和 K3s 运行时之间通过一个适配层(k8s/mod.rs)连接。适配层只做四件事:
| 序号 | 工作内容 | 方向 |
|---|---|---|
| 1 | 把 Backend 的进程配置(AppConfig)转换成编排器配置 | Backend → K3s |
| 2 | 把 Agent 包、运行时模板、挂载授权转换成 K3s crate 能理解的 DTO(数据传输对象) | Backend → K3s |
| 3 | 把 K3s crate 返回的渲染结果、集群状态、运行状态转换回 Backend 领域对象 | K3s → Backend |
| 4 | 把 K3s crate 的错误映射成 Backend 的 HTTP/API 错误 | K3s → Backend |
7. 一次运行涉及的 Kubernetes 资源
每次用户发起一个运行请求,K3s 编排器会创建以下四种资源:
graph TB
subgraph 一次Run的K8s资源["一次 Run(运行)对应的 K8s 资源"]
CM["ConfigMap<br/>📋 agent-pkg-<run-id><br/>存放 Agent 包的文本文件"]
SEC["Secret<br/>🔒 agent-env-<run-id><br/>存放 API 密钥等敏感信息"]
DEP["Deployment<br/>⚙️ agent-worker-<run-id><br/>定义长驻 Worker 容器"]
SVC["Service<br/>🌐 agent-worker-svc-<run-id><br/>暴露 8081 控制端口"]
POD["Pod<br/>📦 由 Deployment 自动创建<br/>运行 agentcore 的容器"]
end
CM -->|"挂载为文件目录"| POD
SEC -->|"注入为环境变量"| POD
DEP -->|"自动创建"| POD
SVC -->|"路由 :8081 流量"| POD
重要:Backend 只负责创建前四个(ConfigMap、Secret、Deployment、Service)。Pod(容器组)是由 Kubernetes 的 Deployment Controller(部署控制器)自动创建的,Backend 不直接操控 Pod。Deployment 通过 OwnerReference(所有者引用)级联管理所有关联资源——删除 Deployment 会自动清理 Service、ConfigMap 和 Secret。
8. 当前部署模型
当前系统采用本地部署 + 单节点 K3s 模式:
- 用户的本地机器就是宿主机——Backend 进程、K3s 集群、Helper 前端都运行在同一台机器上
- 用户通过本机浏览器访问 Helper 提供的 Web UI
- 所有工作区文件和会话状态存储在本机磁盘,容器通过 hostPath 直接读写
graph LR
subgraph LOCAL["用户的本地机器"]
H["Helper + Web UI<br/>(本地前端)"]
B["Backend 进程<br/>(本地后端)"]
K["K3s 集群<br/>(本地容器引擎)"]
D["本地磁盘<br/>uploads / workspaces / sessions"]
end
H -->|"localhost"| B
B -->|"Kubernetes API"| K
B -->|"读写文件"| D
K -->|"hostPath 挂载"| D
本地部署的优势:
- 零网络延迟:Helper → Backend → 容器全部通过 localhost 通信
- 文件无需传输:用户的本地文件可以直接通过 hostPath 挂载进容器
- 部署简单:用户只需安装一次,无需维护远程服务器
- 数据私密:所有数据留在用户本地机器,不经过网络
未来扩展:如果要支持远程部署或多节点集群,需要把文件存储从本地磁盘升级为共享存储(如 PVC 或网络文件系统),后续章节会详细分析这一点。
下一步
理解了整体架构后,请继续阅读 运行生命周期 了解一次运行从开始到结束的完整流程。