运行时总体架构
这一章解释 backend/ 里“谁负责什么”,以及一次运行到底由哪些对象拼出来。
1. 启动时会装配哪些核心组件
build_application(应用装配入口)在启动时会把下面这些组件接起来:
| 代码对象 | 当前职责 |
|---|---|
AppConfig(进程级配置) | 读取 HTTP 监听地址、存储根目录、包目录、运行时配置、集群模式、默认命名空间、默认服务账号、挂载白名单、Job TTL |
FileBackedStore(文件型状态存储) | 维护 state.json、uploads/、workspaces/,保存 session、artifact、mount grant、run |
PackageCatalog(Agent 包目录索引) | 把 backend/packages/* 加载成内存里的 LoadedPackage(已加载 Agent 包) |
RuntimeProfileCatalog(运行时模板目录索引) | 把 backend/config/runtime_profiles.yaml 加载成内存里的 RuntimeProfile |
K3sOrchestrator(K3s 编排器) | 渲染和可选提交 ConfigMap、Secret、Job,并观察 K8s 状态 |
ApplicationService(应用服务层) | 串起 API、状态存储、工作区准备、K8s 提交、状态刷新、多轮会话同步 |
Router(HTTP 路由) | 对外暴露 /api/v1/* 接口 |
这意味着当前后端是一个“单进程控制面 + K3s 执行面”的结构:
- API 请求先进入
Router(HTTP 路由) Router调ApplicationService(应用服务层)ApplicationService同时依赖本地持久化状态和K3sOrchestrator(K3s 编排器)- 真正执行
agentcore的单元是被后端提交出去的 K3sJob
2. 当前系统里最重要的几个对象
2.1 SessionRecord(逻辑会话记录)
SessionRecord 表示“同一用户的一段逻辑会话”。核心字段包括:
user_iddefault_packagestatushistorylatest_run_idclosed_at
它的职责是保存多轮对话时间线,容器实例由后续的 run 单独创建。
2.2 ArtifactRecord(上传文件记录)
ArtifactRecord 表示用户上传到 backend 的文件元数据。文件本体会先落到 uploads/,后续在创建 run 时复制进当前 run 的工作区。
2.3 MountGrantRecord(宿主机挂载授权记录)
MountGrantRecord 表示“允许某个用户把某个 backend 所在主机目录挂进容器”。它是显式授权对象,包含:
host_pathmount_pathaccess_mode
2.4 RunRecord(一次运行记录)
RunRecord 描述一次真实运行,包含:
- 所属会话
session_id - 使用的包
package_name - 使用的运行时模板
runtime_profile - 工作区模式
workspace_mode - 输入文件
artifact_ids - 可选挂载授权
mount_grant_id - provider 环境变量键名
provider_env_keys - 工作区根目录
workspace_root - 运行状态
status - K8s 资源引用
resources - 渲染结果
rendered
当前物理隔离单元就是 RunRecord。
2.5 RuntimeProfile(运行时配置模板)
RuntimeProfile 决定一次 run 的基础运行时底座,主要包括:
- 基础镜像
image - 容器入口
executable - 安装策略
installStrategy - 执行模式
executionMode - 默认模型和默认 Base URL
- namespace、service account
- CPU、内存、临时存储的 requests / limits
从运行时设计上看,RuntimeProfile 表达的是“怎样启动一个 agentcore 容器”,并不绑定实现语言。
2.6 AgentPackageManifest(Agent 包清单)
AgentPackageManifest 定义 agent package 本身的业务层意图,主要包括:
runtimeentrypolicyassets
当前包目录示例位于:
backend/packages/codex-reviewer/backend/packages/claude-code-builder/
这些目录名是样例包名,架构层仍统一按 agent package 理解。
3. agentcore 和 agent package 当前怎样组合
3.1 agentcore 在当前代码里对应什么
如果把 agentcore 理解为“真正提供执行底座的运行时”,那在当前代码里它主要对应三部分:
RuntimeProfile(运行时配置模板)- 运行时镜像
image - 容器入口
executable
它们以共享模板的方式存在。
3.2 agent package 在当前代码里对应什么
如果把 agent package 理解为“开发者提供的提示词、工具声明、环境事实和策略”,那它对应:
agent.yamlprompt/system.mdbuild_in_tools.yamlenv/env_facts.yaml- 其它包内文本文件
这些文件在运行时由后端加载成 LoadedPackage(已加载 Agent 包),再通过 ConfigMap 注入 Pod 内的 /opt/agent/package。
3.3 两者的绑定时机
LaunchPlan(一次运行的不可变启动计划)是 agentcore 和 agent package 真正结合的地方。它同时持有:
packageruntime_profileworkspace_modeprovider_envmount_grantworkspace_host_pathnamespaceservice_account
随后 K3sOrchestrator 会把这个 LaunchPlan 渲染成三类资源:
ConfigMapSecretJob
3.4 当前组合模式的结论
结论很明确:
- 共享的是
RuntimeProfile和基础镜像 - 独立的是每次运行的 Pod、工作区、
ConfigMap、Secret - 一次 run 会把“共享运行时模板 + 当前
agent package+ 当前工作区 + 当前 provider 凭据”拼成一个独立运行单元
4. 当前隔离模型与连续性模型
4.1 逻辑隔离按 session
SessionRecord 保存:
- 历史消息
- 默认包
- 会话状态
- 最近一次 run
它定义的是“同一段对话时间线”。
4.2 物理隔离按 run
每次 create_run(创建运行)都会创建:
- 一个独立工作区目录
- 一个独立
ConfigMap - 一个可选独立
Secret - 一个独立 K3s
Job - 一个独立 Pod
这意味着当前模型是:
- 逻辑连续性按
session - 物理执行隔离按
run
4.3 会话连续性今天靠什么保持
当前代码里的连续性主要来自三块持久化数据:
SessionRecord.history(会话消息历史)ArtifactRecord(上传文件记录)和uploads/下的原始文件RunRecord(运行记录)和workspaces/<run-id>/out/下的结果文件
ApplicationService::sync_session_conversation_history(同步会话历史)会在新 run 开始前刷新该 session 下旧 run 的状态;ApplicationService::sync_run_assistant_message(同步助手回答)会把已完成 run 的 final-answer.md 回填进 SessionRecord.history。这样同一 session 的下一轮可以拿到前一轮回答。
4.4 agentcore 的 checkpoint 连续性应该怎样接入
从通用运行时架构看,agentcore 的 checkpoint 连续性应该依赖持久化挂载路径,典型模式是:
- 为每个
session分配一个持久化状态目录 - 在同一
session的每次 run 中都把这个目录挂到固定路径 - 由
agentcore在该目录内保存 checkpoint、状态数据库、工具缓存和恢复索引 - 由 backend 保存
session_id -> checkpoint_root的索引
当前代码已经具备:
- run 级工作区持久化
- session / run 元数据持久化
- reopen 同一
session
当前代码还没有显式的:
checkpoint_root字段- session 级持久化状态卷
- resume API
这部分会在“当前实现边界”章节里继续说明。
5. K8s Rust 调用在当前架构中的位置
这一节专门把代码和功能对应起来。
5.1 backend/src/k8s/mod.rs 负责真正访问集群
K3sOrchestrator::new(K3s 编排器初始化)通过 Client::try_default() 创建 kube 客户端,并调用:
ensure_namespace:确保 namespace 存在ensure_service_account:确保 service account 存在且关闭自动挂载 token
K3sOrchestrator::submit_run(提交运行)负责:
- 调
job_builder::build_bundle在内存里构造ConfigMap、Secret、Job - 在
apply模式下调用Api<ConfigMap>::create - 调用
Api<Secret>::create - 调用
Api<Job>::create
K3sOrchestrator::inspect_run_status(检查运行状态)负责:
Api<Job>::get_opt读取 Job 状态Api<Pod>::list读取同一 Job 对应 Pod 的状态- 把 Job / Pod 观察结果映射成
RunStatus
K3sOrchestrator::cluster_status(读取集群状态)负责:
Api<Node>::list读取节点- 汇总可调度节点数、taint、磁盘压力和阻塞原因
K3sOrchestrator::cancel_run(取消运行)负责:
Api<Job>::deleteApi<ConfigMap>::deleteApi<Secret>::delete
5.2 backend/src/k8s/job_builder.rs 负责把计划渲染成资源
job_builder::build_bundle(构建运行资源包)会:
- 构建承载 package 文件的
ConfigMap - 构建承载 provider 凭据的
Secret - 构建真正执行 run 的
Job
build_job(构建 Job)会把下面这些设置落到资源定义里:
/workspace工作区挂载/opt/agent/package包目录挂载- 可选的用户授权挂载
allowPrivilegeEscalation: falsecapabilities.drop = ["ALL"]runAsNonRoot = truefsGroup = 1000seccompProfile = RuntimeDefaultttl_seconds_after_finished
5.3 backend/src/service.rs 负责把业务对象和 K8s 编排串起来
ApplicationService::create_run(创建运行)是控制流入口,它会:
- 校验 session
- 解析 package
- 解析
RuntimeProfile - 合并 provider 配置
- 校验输入文件和挂载
- 做集群预检
- 同步历史回答
- 追加本轮用户消息
- 创建工作区
- 写
run-context.json - 组装
LaunchPlan - 调
K3sOrchestrator::submit_run - 持久化
RunRecord
6. 当前样例 runtime profile 如何理解
runtime_profiles.yaml 里当前有多组样例 profile。它们在代码里沿用了历史命名,例如:
codex-standardclaude-code-standardcodex-cli-standardclaude-code-cli-standard
这些名字只代表当前仓库里已有的样例配置。架构层需要关注的是下面这些字段:
imageexecutableinstallStrategyexecutionModerequestslimits
因此如果后续接入新的 Rust agentcore、Python agentcore 或其它容器入口,后端运行时模型本身不需要变化,变化点主要是:
- 基础镜像
- 容器入口
- checkpoint 目录约定
- 执行模式适配器
7. backend 与 agentcore 的责任边界
当前更合理的责任边界是:
agentcore负责自己的执行逻辑、checkpoint、工作目录状态、工具调用和恢复逻辑agent package负责提示词、工具声明、环境事实和策略- backend 负责保存
session、run、上传文件、工作区目录、K8s 资源引用、结果文件索引以及 reopen/resume 入口
这条边界与 agentcore 的实现语言无关。