主题
定义态、运行态与支撑服务
一句话:把“能做什么”和“怎么跑”拆成物理隔离的两层,再用一组无状态支撑服务连接,是平台能安全演进的前提;代价是多一层网络跳转和一套跨层契约。
为什么需要
平台早期最常见的错误,是把编排界面、Skill 定义和 Agent 执行放在同一个服务里。演示时很方便:点一下“运行”,同一个进程直接调模型、读文件、执行代码。上线后问题集中爆发:
- 定义态的配置错误会直接拖垮执行进程,改一个提示词要重启整个平台;执行环境又需要 GPU、网络隔离和临时文件系统,和 Web 服务的资源模型完全不同,混在一起无法独立扩缩容。
- 审计说不清一次执行用了哪个版本的 Skill、哪份知识、哪个工具,因为定义和执行共享内存,版本在运行中被覆盖;执行代码的进程还同时持有配置库和管理接口的凭证,安全边界失效。
根因是把“元信息”和“执行”当成同一类负载。它们的变更频率、资源模型、信任边界和故障影响都不同,必须拆开。
核心机制
三层分离
看这张图只抓三件事。第一,中间一列是唯一的执行主链:会话管理 → 任务分发 → 队列 → Pod,实线带标签的就是这条链上的动作;第二,右下六个支撑服务全由 Pod 调用,Pod 自己不留状态,所以它随时可以被杀掉重建;第三,所有跨到定义态的线都是虚线且方向只有一个——运行态读定义,定义态永远不碰运行态。
定义态只写元信息,不执行任何代码;运行态只读配置、不修改定义;支撑服务被运行态调用,自身无状态。三层的依赖是单向的:定义态可以独立发布,运行态可以独立扩缩容,支撑服务可以独立升级。反过来,如果运行态能回写定义态,一次故障就可能污染配置;如果支撑服务持有会话状态,Pod 回收后会话就断了。三层的依赖是单向的:定义态可以独立发布,运行态可以独立扩缩容,支撑服务可以独立升级。反过来,如果运行态能回写定义态,一次故障就可能污染配置;如果支撑服务持有会话状态,Pod 回收后会话就断了。
定义态:四个 Hub 各自管什么
| 组件 | 管什么 | 不该管什么 |
|---|---|---|
| Skill Hub | SKILL.md、版本、审核、依赖声明 | 不执行 Skill,不持有工具凭证 |
| MCP Hub | Server 注册、健康检查、工具目录 | 不代理调用,不做业务鉴权 |
| 编排界面 | 图定义、节点参数、发布版本 | 不保存运行中间结果 |
| 知识库管理 | 摄入、分块、索引、权限标记 | 不直接向模型注入内容 |
| 模型路由配置 | 路由规则、限流、降级链 | 不承载具体请求 |
定义态的核心产物是可版本化的配置:工作流 JSON、SKILL.md、MCP 注册信息、知识索引和路由规则。它们应该像代码一样评审、diff、回滚,而不是在数据库里被随手改掉。
运行态:五个服务与一条任务链
| 服务 | 职责 | 关键设计 |
|---|---|---|
| 会话管理 | 会话创建、粘性路由、上下文装载 | 会话与 Pod 解耦,Pod 回收不丢会话 |
| 任务分发 | 依赖检查、任务分配、结果回收 | 按任务类型选池,按依赖解锁下游 |
| Pod 池管理 | 冷 / 暖 / 热池、回收、扩容 | 池化复用,不按用户独占 |
| 任务队列 | 优先级、重试、死信 | 至少一次投递 + 幂等消费 |
| 自动扩缩 | 按队列深度与 GPU 指标扩容 | 预热副本,避免冷启动打穿 SLA |
运行态不保存业务定义,只保存“这次执行到哪了”。所有中间结果写入支撑服务,Pod 可以随时被杀掉重建。
一次任务的九个步骤
- 用户消息经网关鉴权、限流后进入会话管理。
- 会话管理查找活跃会话;没有则创建
session_id并分配管理 Pod。 - 任务分发从池中取 Pod,优先热池,其次冷池;池满则排队并触发扩容。
- 管理 Pod 拉取工作流、会话历史和用户上下文,组装本轮输入。
- 模型输出任务分解:子任务、依赖、执行类型。
- 分发器按类型分配执行 Pod,依赖未满足的任务留在队列。
- 执行 Pod 加载 Skill、连接 MCP、读取上下文,按步骤执行并做输出校验。
- 每个子任务完成后写回结果,解锁下游;全部分完成后管理 Pod 聚合。
- 结果推送给用户,Pod 进入空闲,超时后回收;会话记忆保留在支撑服务。
这条链路里,任何一个 Pod 都是可替换的:管理 Pod 挂了,会话从支撑服务恢复;执行 Pod 挂了,任务按检查点重试。真正不能丢的是 session_id、任务状态和已提交的结果,它们必须在 Pod 之外。
故障域与隔离
| 故障 | 影响范围 | 隔离手段 |
|---|---|---|
| 执行 / 管理 Pod 崩溃 | 单个子任务或会话 | 检查点重试 + 幂等键;会话粘性重建 + 历史回放 |
| 模型网关 / 向量库不可用 | 调用该模型的会话、依赖检索的 Skill | 熔断降级;无检索时标注置信度 |
| 定义态发布错误 | 新版本会话 | 版本固定 + 灰度 + 快速回滚 |
| 审计写入失败 | 合规风险,不影响执行 | 本地缓冲 + 告警 + 拒绝高风险操作 |
隔离的设计原则是:故障不能跨层传播。定义态的错误不应该让运行态整体不可用;运行态的过载不应该拖慢定义态的发布。
实战场景
场景一:一行提示词直接打进全量在线会话
现象:一名开发者在编排界面把客服 Skill 的提示词“微调一行”,没走审核直接保存;运行态当时每次执行都实时拉定义库,改动在几分钟内命中全部在途会话。此后两小时客服任务成功率从 96% 跌到 78%,31 个会话中断转人工、投诉二十余单(损失数字为经验值,需校准)。复盘会第一个问题就答不上来:“线上正在跑的到底是哪个版本?”
排查:按一次任务的九个步骤逐层排:网关鉴权正常、会话管理正常、任务分发正常;查到执行 Pod 加载 Skill 这一步,Skill Loader 每次取的是“最新版”,请求里没有版本参数。审计环节跟着暴露——执行记录关联不到任何 Skill 版本,因为定义与执行共享内存,版本在运行中被覆盖。根因两条:会话启动时没有固定 Skill、知识库与模型路由版本;定义态的“保存”直接等于生效,两层之间缺少“发布才生效”的契约。
对症:版本固定加发布流水线。会话创建时把本次要用的版本写进会话上下文,运行期间不变;界面保存不等于生效,改动必须走草稿 → 审核 → 灰度 → 全量:
yaml
session_runtime:
pinned_versions:
skill: skill-cs@1.4.1 # 会话创建时固定,每次执行随结果落审计
knowledge: kb-cs@2026.09
routing: rt-default@3
rollout:
canary_percent: 10 # 经验值,需校准
auto_rollback_on: [error_rate>5%]复盘:故障域表把“定义态发布错误”的影响范围定为“新版本会话”,而不是“全部在线会话”——圈住这个范围的手段就是版本固定加灰度,缺一样,表就只是纸。发布顺序同样按契约执行:先发布支撑服务,再发布运行态,最后切定义态版本;回滚按相反顺序。
场景二:运行态回写定义库,谁都能改提示词
现象:一个月内,同一个 Skill 的提示词被 4 个人改过 9 次,没人说得清哪次改动对应哪段线上行为;月底更严重的一次:执行 Pod 故障重试,补偿逻辑把半截工作流 JSON 回写进定义库,污染了 3 个已发布编排,平台组周末抢修(频次与影响为经验值,需校准)。起因是平台早期把编排界面、Skill 定义和执行放在同一个服务、同一个数据库里,“方便”了两头,失信了中间。
排查:第一个问题查变更通道——界面和数据库都能直达同一个对象,绕库那条路没有审核记录;审计说不清用了哪个版本,正是定义与执行共享内存的后果。第二个问题查信任边界——执行代码的进程同时持有配置库和管理接口的凭证,“运行态只读配置”只写在文档里,网络策略没挡写连接。两条都指向依赖方向失守:运行态能回写定义态,一次故障就污染了配置。
对症:凭证与通道各收一道,主体权限一张表收敛:
| 主体 | 对定义库的权限 | 变更通道 |
|---|---|---|
| 业务开发者 | 无直连权限 | 编排界面提交,走草稿 → 审核 → 灰度 → 全量 |
| 定义态服务 | 读写 | 只经版本化定义态 API,禁止共享表 |
| 运行态与执行 Pod | 只读 | 回写请求在网关直接拒绝,落审计并告警 |
yaml
data_plane:
definition_access:
mode: read_only
write_back: reject_and_audit # 运行态回写定义态即配置污染复盘:三层分离的验收不看目录结构,看三条:Pod 被杀后会话还在不在;定义态发布是否影响在跑的会话;一次执行能否按 trace 还原用了哪个版本。任何一条答不上,就不是“已经拆了”,只是“代码分开放了”。
场景三:接入第三个业务方,才发现支撑服务欠了三本账
现象:第三个业务方(强合规场景)的接入冻结了一个月:对方安全评审直接退回,因为接入清单上的三条硬要求——凭证不长期持有、每次执行可按 trace 还原、成本按租户归集——平台一条都答不利索;上游排队的另外三个团队跟着一起等(时长为经验值,需校准)。前两个业务方靠“各自配一下”跑了大半年,没人觉得这三条是缺口。
排查:按“定义态管元信息、运行态管执行、支撑服务被运行态调用且自身无状态”逐层核对:定义态四个 Hub 齐了,运行态五个服务能跑任务,缺项全部集中在支撑服务层——它长期被当成“以后再说”。MCP Proxy 缺位,鉴权逻辑每个工具适配各写一遍,凭证只能沉在各仓库配置文件里;LLM Gateway 只做了转发没做计量,成本归集没有数据源;审计与追踪没做成独立服务,执行 Pod 顺手写本地日志,冷热回收把日志连同证据一起回收掉了。
对症:支撑服务清单按欠账补齐,每项的无状态约束随接口一起定:
| 支撑服务 | 补什么 | 关键约束 |
|---|---|---|
| MCP Proxy | 统一鉴权、限流、短期凭证 | 自身不持会话状态,Pod 回收不断调用链 |
| LLM Gateway | 路由、熔断、计量、按租户归集 | 计量随 trace 上报,不落执行 Pod 本地 |
| 审计与追踪 | 追加式审计:输入摘要、工具调用、权限判定、输出校验、终止原因 | 写失败走本地缓冲 + 告警 + 拒绝高风险操作,不阻塞执行主链路 |
复盘:支撑服务的账,总在第三个接入方到来那天结算。无状态不是架构洁癖——会话粘性、检查点重试、Pod 池冷热回收,全部以记忆、结果、审计外置在这些服务里为前提;支撑服务缺一层,运行态的“Pod 可以随时杀掉重建”就只是口号。
最小上手
先做一条最小链路,不要求多 Agent:网关 → 会话服务 → 单个执行 Pod → Skill Loader → LLM Gateway → 审计。用一份 SKILL.md 和一个只读工具跑通“输入 → 执行 → 结果 → 审计”四段。验收看四件事:Pod 重启后会话还在;Skill 改版本后旧会话仍按旧版本执行;工具超时能返回可读错误;每次执行能按 trace 查到用了哪份配置。
生产动作
- 契约先行:定义态与运行态只通过版本化 API 通信,禁止共享表;会话启动时固定 Skill、知识库和模型路由版本,运行中不跟随定义态变化。
- 只读配置:运行态对定义态只有读权限;执行环境不持有配置库写凭证。
- 超时与预算:每层调用都设超时,跨层传递剩余预算,避免下游无限重试;trace 贯穿网关、会话、Pod、工具和模型调用。
- 发布顺序:先发布支撑服务,再发布运行态,最后切定义态版本;回滚按相反顺序。
边界
- 三层分离会增加延迟:多一次网络跳转和序列化,极低延迟场景要评估是否值得;小团队低并发时可以同进程,等出现独立扩缩容需求再拆。
- 物理隔离不等于安全,无状态也不等于无瓶颈:同一集群仍共享网络与内核,强隔离要独立节点池;连接池、限流和向量库容量仍要独立规划。
- 定义态不是越集中越好:所有团队共用一个发布通道会形成瓶颈,需要按业务域划分命名空间与审批流。
讲清楚
平台的可演进性来自三层分离:定义态只保存可版本化的元信息,运行态只负责执行和状态推进,支撑服务提供无状态的加载、代理、记忆与审计。分离的收益是独立发布、独立扩缩容和清晰的故障域;代价是跨层契约、额外延迟和更复杂的排障。判断拆分是否做对,可以看三条:Pod 被杀后会话是否还在,定义态发布是否影响正在运行的会话,一次执行能否按 trace 还原用了哪个版本。三条都成立,三层才算真正分开。
适用:2026 年企业级 Agent 平台运行态设计 | 初稿 2026-10