Agent 工程:Manage Agent & Agent Runtime 设计
我们 H1 在做一个企业级 Agent 平台,暂且叫它 xbot:多租户、对接 IM 渠道、支持 Skill / MCP / Plugin 扩展,用户在群里或私聊里丢一句话,后面就得跑起一整套模型推理加工具执行的闭环。最近我在做它的 Agent Runtime 设计,也就是自研的执行内核——把原先散在各处的 Agent 循环、上下文治理、审批拦截、沙箱调度全部收敛成一个独立的运行时。
现在各种开源 Agent 框架,从最简单的单循环 ReAct 脚本,到基于图编排的重量级工作流引擎。但一旦把这些框架扔进真实生产环境,面对多租户隔离、高风险工具审批、长周期会话中断恢复、上下文溢出以及不可信代码执行等要求时,大部分原型级设计都会瞬间崩溃。
构建企业级 Agent 平台的核心分水岭在于:平台是控制面与事实源(Control Plane / Source of Truth),而 Native Runtime 是纯粹的执行内核与数据面(Execution Kernel / Data Plane)。Native Runtime 绝不是把平台业务逻辑做一份缩水版复制,而是对平台执行语义进行底层的内核化表达。
这篇文章是我这段时间调研加设计的技术总结。但原设计太多,篇幅很长。此文与 Opus5 一起总结。
一、Native Runtime 的定位与边界划分
在设计执行引擎之前,首先必须解决最根本的职责划分问题。很多团队在早期迭代时,容易把业务逻辑、会话管理和底层模型调用揉在一个进程里,导致后续重构代价极其高昂。
+-----------------------------------------------------------------+
| xbot Platform Control Plane |
| (User Auth / Workspace / Platform Session / Long-term ACL) |
+--------------------------------+--------------------------------+
| HTTP / SSE / WebSocket
v
+-----------------------------------------------------------------+
| Native Agent Runtime (Data Plane) |
| (Run Lifecycle / Agent Loop / Safe Points / Checkpoint Store) |
+--------------------------------+--------------------------------+
| gRPC / Internal RPC
v
+-----------------------------------------------------------------+
| Compute Plane (Sandbox Substrate) |
| (MicroVM / Filesystem / Shell / Process / Network Isolation) |
+-----------------------------------------------------------------+
1.1 控制面与数据面的解耦逻辑
传统业务后台通常采用典型的三层架构,但在 Agent 体系中,执行过程具有高度的动态性与非确定性。模型可能随时发起未知参数的工具调用,可能在推理到一半时被外部用户强制打断,也可能因为网络抖动导致事件流中断。
为了保证系统可维护性,必须在架构上明确确立:xbot 平台拥有业务实体与会话(Platform Session),而 Native Runtime 仅拥有执行实例(Run)。
平台侧负责用户登录、鉴权、计费、团队空间划分以及长期权限账本的持久化。而 Native Runtime 作为一个轻量但高度健壮的执行内核,只负责接收一个具体的运行任务(RunRequest),并在一个封闭、确定的生命周期内推进状态机、调用模型、分发工具、记录事件,并在发生异常时安全退出。这种解耦保证了 Runtime 自身是无状态可横向扩容的,或者其状态严格局限在当前 Run 的持久化快照中。
1.2 执行循环置于沙箱外部的设计抉择
在 Agent 执行架构的选型中,业界主要存在两大派系:Agent Loop Inside Sandbox 与 Agent Loop Outside Sandbox。
第一种方案是将 Agent 主循环、LLM API 客户端、工具路由以及工作空间全部打包塞进沙箱容器里。这种模式在本地 CLI 工具(如单机 Coding Agent)中非常常见,因为它给模型的感觉就像是"直接给了一台电脑",所有环境上下文和文件操作都在同一个操作系统命名空间内,调用延迟极低。
但在多租户的企业级平台中,Agent Loop Inside Sandbox 存在致命的安全缺陷与治理黑洞。首先,沙箱内部属于不可信计算环境,用户编写的代码或模型生成的 Shell 命令随时可以在沙箱内执行。如果把模型 API Key、平台系统凭证以及鉴权 Token 直接以环境变量形式注入到沙箱内部,恶意用户只需一行简单的打印命令就能将核心密钥全量窃取。其次,沙箱内的进程一旦崩溃或被 OOM 杀死,控制面将彻底丢失当前 Run 的执行轨迹与内存状态,导致故障恢复和重放审计几乎不可能。
因此,本架构坚定采用 Agent Loop Outside Sandbox(执行循环置于沙箱外部) 的架构模式。
[User / App]
↓
[Trusted Runtime / Control Plane (Outside)]
├── Agent Loop Engine & Safe Points
├── Model API Calling & Secret Store
├── Run State / Checkpoint / EventLog
└── Approval & Policy Enforcement
↓ (Action Protocol / RPC)
[Untrusted Sandbox / Compute Plane (Inside)]
├── Ephemeral Workspace & Filesystem
├── Restricted Shell & Tool Execution
└── Build / Test / Code Runner
外部的 Runtime Harness 作为可信控制面,统一持有核心密钥、审批策略、审计日志以及执行状态机;内部的 Sandbox Session 仅作为不可信算力平面,只暴露受限的底层执行接口。两者之间通过明确的操作协议进行跨边界调用,从根源上杜绝凭证泄露风险,并实现沙箱提供商的可插拔替换。
1.3 核心所有权原则:Runtime Owns Run, Not Session
在领域模型设计上,必须确立最核心的设计铁律:Native Runtime owns Run, not Session。
平台层面的 Platform Session 承载了产品形态下的完整对话上下文、多轮 Run 的前后关联、用户偏好以及跨执行周期的授权记录。如果把 Session 概念强行塞进 Native Runtime,会导致 Runtime 被各种前端展示需求和产品特定逻辑深度污染,无法作为通用执行底座。
在 Native Runtime 中,核心实体仅包含一次独立的执行单元——Run。一个 Run 可以在元数据中携带一个可选的 platformSessionId 用于弱关联引用。如果携带了该 ID,Runtime 便具备读取平台历史上下文、继承会话级权限以及支持追问的能力;如果未携带,该 Run 依然能作为完全独立的单次任务平稳运行。这种设计杜绝了 Runtime 与平台侧产生双写一致性问题,保证了底层执行内核的极简与纯粹。
二、主流 Agent Runtime 架构横向剖析
为了设计出工业级 Runtime 架构,我们需要先深度解剖几个最具代表性的项目,吸收其工程精华,避开其架构暗坑。
2.1 DeepAgents 的中间件链与增量持久化
DeepAgents 是基于 LangGraph 体系构建的代表性 Agent Harness。它的核心思想在于避免在底层手写裸露的死循环,而是把 Agent 的核心驱动力交由状态图编译器管理,将所有扩展能力抽象为中间件链(Middleware Stack)。
在 DeepAgents 中,系统状态流转基于增量通道机制,每次状态转移只记录增量差值(Delta),大幅降低了持久化 Checkpoint 时的内存开销与 IO 压力。其所有关键能力,包括文件系统拦截、子代理派发、上下文总结、参数修剪以及人工介入(HITL),全部通过包装模型调用或工具调用的中间件介入。
在上下文压缩方面,DeepAgents 提供了出色的解题思路:压缩不是直接破坏性地修改原始历史记录,而是在模型请求前由总结中间件介入,计算当前 Token 水位,并在触发阈值时将历史消息转储到存储后端,仅在当下视图中投影为"摘要消息 + 截断点之后的尾部消息"。这一机制对 Native Runtime 极具借鉴意义,即保证底层事实账本的不可变性,仅对模型可见的上下文视图做动态投影。
但 DeepAgents 的设计取向也有明显局限:它深度依赖 LangGraph 体系,缺乏统一的旁路控制面协议,对于外部强行下发的转向(Steer)、取消(Cancel)等异步指令,缺乏标准化的控制流通道。
2.2 Pi 的双层循环与旁路输入队列
Pi(coding-agent)在单机交互式执行引擎的设计上展现了极高的工程成熟度。它最值得称道的是清晰的双层循环架构(Double-Loop Architecture)与精确的安全点(Safe Point)控制。
+---------------------------------------------------------------+
| Pi Outer Loop |
| - Check Follow-up Queue |
| - Handle Session Level Events / UI Sync |
+-------------------------------+-------------------------------+
|
v
+---------------------------------------------------------------+
| Pi Inner Loop |
| - Stream LLM Response |
| - Execute Tools (Sequential / Parallel) |
| - Safe Point (prepareNextTurn): Poll Steering Queue |
| - Check shouldStopAfterTurn |
+---------------------------------------------------------------+
Pi 的内层循环专注单轮交互中的模型流式请求、工具执行以及工具结果回填。在每一轮模型交互交接的节点,Pi 设立了明确的 prepareNextTurn 安全点。当用户在模型流式输出或工具执行期间输入了新的纠偏指令时,系统不会粗暴地打断当前底层网络连接,而是将指令存入转向队列,并在安全点优雅地注入到下一轮请求的上下文内。
Pi 的外层循环则只在内层循环彻底没有工具调用、即将停机时才去拉取追问队列(Follow-up Queue)。这种内外交织的分层机制,完美解决了"外部输入在何时介入才不会破坏工具执行一致性"这一难题。
在上下文压缩上,Pi 引入了压缩条目树的概念,将压缩视为向会话树追加一个节点,使完整的原始 JSONL 历史保持只读,仅在构建模型上下文时动态提取摘要与保留区间。
2.3 YA SDK 与 YA Claw 的协调器分层与总线机制
YA 体系(YA SDK + YA Claw)展示了 SDK 执行循环与平台级运行时协调器(Runtime Coordinator)的分层典范。
在该架构中,底层 SDK 仅基于迭代器节点(如模型请求节点与工具调用节点)推进微观执行,并向上层抛出标准化的生命周期事件与 Token 采样数据。而外层的 Claw 协调器则管理宏观的 Run 生命周期状态机,负责状态认领、事件分发、人工审批中断以及终态提交。
YA 体系的核心亮点在于其基于消息总线(MessageBus)的旁路注入链路。外部发起的 HTTP 转向请求或后台子任务的返回结果,会被统一写入总线,随后由 SDK 内置的过滤器在下一次模型请求前完成消费与组装。此外,当工具执行需要人工介入时,系统会抛出延迟审批异常并持久化交互状态,协调器在收到审批结果后携带结构化的延迟工具结果继续唤醒循环。这种"内层推进循环、外层控制生命周期"的架构,为服务化提供了极佳范式。
2.4 Hermes Agent 的工程韧性与防御性设计
Hermes Agent 在工程防御性与执行韧性方面做得最为扎实。在真实场景中,大语言模型经常会返回格式错误的 JSON 参数、虚构不存在的工具名称,或是陷入死循环。
Hermes 在底层循环外围构建了厚重的工程防护:
- Turn Prologue 机制:在每次执行前进行会话绑定、日志上下文注入、迭代预算重置、防护栏规则校验以及前置上下文压缩评估;
- Provider-Safe 消息净化:在将消息推给特定模型供应商前,严格清洗内部保留字段与临时调试标记,防止供应商接口报错;
- 工具调用自动修复与去重:对模型生成的畸形工具调用进行语法层面的纠错与参数类型对齐;
- 双重预算熔断:通过单次最大轮数与执行预算双重计数器,强制阻断 Agent 的无限自我调用。
更重要的是,Hermes 在处理上下文压缩时会自动触发会话轮转(Session Rotation),将旧的物理会话封存并开辟带有父子关系的子会话;同时在审批流上支持"仅本次允许"、"当前会话全部允许"以及"全局允许"的分级授权策略。这些工程细节是构建高可用 Runtime 必不可少的组件。
2.5 Agno 的轻量控制面与服务化设计
Agno 走的是极简且高度服务化的路线。它把执行引擎清晰划分为两层:外层 Agent 负责运行编排与依赖管理,内层 Model 负责驱动具体的 ReAct 循环。
Agno 对 Native Runtime 最具参考价值的部分在于其完备的异步控制面 API 与协作式取消机制:
- 协作式取消管理:全局 Cancellation Manager 追踪每个 Run 的取消意图,在循环各关键阶段插入状态校验,一旦检测到取消标记便平滑中止并写回终态;
- 显式暂停工具执行:当工具标记了需要人工确认时,模型层不会崩溃报错,而是直接产出带有暂停标记的执行对象,由 Agent 层将其固化为数据库中的审批记录;
- 继续与重放分离:Agno 严格区分了业务层面的继续推进(Continue)与网络传输层面的事件流重放(Resume),通过全局索引游标实现断线后无损补发事件。
以下是各方案的核心架构维度对比:
| 架构维度 | DeepAgents | Pi (coding-agent) | YA / Claw | Hermes Agent | Agno | xbot Native Runtime 目标 |
|---|---|---|---|---|---|---|
| 循环抽象 | LangGraph 状态图 | 双层交互式循环 | 协调器 + 节点迭代 | Prologue + 单循环 | 编排器 + 模型循环 | RunController + AgentLoopEngine |
| 旁路控制 | 仅 HITL 中断 | Steer / Follow-up 队列 | MessageBus 异步注入 | 信号量 + 工具结果注入 | 协作式取消 + 状态重入 | 标准 RuntimeCommand + 安全点调度 |
| 上下文压缩 | 预执行剔除 + 摘要 | 树状 Entry 投影 | 历史重写 + 摘要过滤 | 会话轮转 + 结构化总结 | 单工具结果截断 | Run-scoped CompactionArtifact |
| 事件持久化 | Checkpoint 状态 | 本地 JSONL 树 | 紧凑事件流 | 关系型数据库存储 | 数据库 + SSE 缓冲区 | 单调递增 Run Event Log |
| 沙箱隔离 | 接口层抽象 | 本地执行优先 | 外部执行器桥接 | 容器绑定 | 进程/容器执行 | MicroVM 级别单沙箱串行排队 |
三、Native Runtime 核心架构与分层设计
基于上述调研与架构原则,xbot Native Runtime 采用分层解耦的系统架构。整个系统在代码工程与依赖方向上进行了严格的单向约束。
+---------------------------------------------------------------+
| xbot-agent-protocol |
| (Run / RuntimeEvent / RuntimeCommand / RuntimeItem / Enums) |
+-------------------------------+-------------------------------+
^ ^ ^
| | |
+--------------+---+ +-------+-------+ +---+---------------+
| xbot-agent-sdk | | xbot-worker | |xbot-agent-runtime |
| (Client Facade) | |(Platform Host)| | (Execution Core) |
+------------------+ +---------------+ +-------------------+
3.1 协议、内核与客户端的依赖拓扑
在依赖拓扑中,必须确保底层协议的绝对独立与稳定:
xbot-agent-protocol:跨进程、跨模块共享的公共契约包,使用纯粹的语言原生结构体定义。严禁引入任何业务数据库、HTTP 路由、Agent Loop 逻辑或具体沙箱适配代码。它定义了系统通用语言,包括RuntimeEvent、RuntimeCommand、RuntimeItem、CapabilitySnapshot等核心协议。xbot-agent-runtime:系统的核心服务进程与执行内核,依赖协议包。对外暴露标准的 RESTful / SSE / WebSocket 接口,对内完整拥有 Run 生命周期控制、事件日志事实源、执行循环引擎、能力解析系统以及计算沙箱调度。xbot-agent-sdk:面向业务开发码农的轻量客户端封装。SDK 绝对不拥有 Agent Loop,也不在客户端本地管理工具注册表或中间件。它仅仅是 Runtime API 的轻量门面,负责发起 Run、拉取事件流、提交审批与发送旁路控制指令。xbot-worker:平台侧的任务调度节点,负责将外部 IM 渠道的输入转化为 Run 调度,并消费 Runtime 吐出的事件流。
3.2 控制面 Run Controller 模块职责
在 xbot-agent-runtime 内部,控制面由 RunController 统领,主要职责包括:
- 请求准入与幂等控制:通过
CommandInbox与IdempotencyStore接收外部下发的控制指令,基于业务唯一键防止重复下发; - 状态事实追踪:维护 Run 的权威生命周期状态机,通过
EventAppender向底层存储追加单调递增的事件事实; - 能力快照固化:在任务真正由排队转入执行时,触发
CapabilityResolver固化当前 Run 允许使用的全部模型配置、工具列表、技能版本与安全策略; - 资源并发锁定:通过
RunLockManager基于沙箱路由键申请分布式锁,保证同一沙箱环境内的任务严格有序执行。
3.3 执行内核 Agent Loop Engine 与安全点机制
执行内核 AgentLoopEngine 运行在 RunController 的管控之下。它不再直接处理复杂的 HTTP 请求解析或分布式锁竞争,而是专注在一个受控的单次迭代中推动状态演进:
RunController.start(run)
│
├── 1. Append runtime.run.started
├── 2. Freeze CapabilitySnapshot
└── 3. Launch AgentLoopEngine.execute(run)
│
▼
┌─────────────────────────────────────────────────────────┐
│ Pipeline Stage Execution │
│ │
│ [ContextStage] ──> [SafePoint: before_model_request] │
│ │ │
│ [ModelStage] <──────────────────┘ │
│ │ │
│ └──> [SafePoint: after_model_response] │
│ │ │
│ [ToolPlanning] <──────┘ │
│ │ │
│ └──> [SafePoint: before_tool_execution] │
│ │ │
│ [ToolExecution]<──────┘ │
│ │ │
│ └──> [SafePoint: after_tool_result] │
│ │ │
│ [Compact / Checkpoint]< │
│ │ │
│ └──> [SafePoint: before_run_terminal] │
└─────────────────────────────────────────────────────────┘
该引擎的核心由流水线(Pipeline)与阶段(Stage)构成。在整个生命周期中,引擎通过 SafePointRunner 暴露标准拦截点。所有来自外部的非破坏性指令(如纠偏指令、人工审批通过信号),都必须排队等待流水线推进到特定安全点时才被检出并生效。这彻底杜绝了多线程并发改写 LLM 请求上下文,或在工具执行一半时强行切断底层连接引发的脏状态。
3.4 能力解析层与快照固化机制
在复杂的企业应用中,用户可能在 Agent 执行期间动态修改全局配置(例如上传了新的 Skill 文件、更新了 MCP 服务的认证 Token、或修改了提示词)。如果正在执行的任务动态读取这些变化,会导致同一个 Run 在前半程和后半程的行为模式完全不一致,使故障回溯变得极其困难。
因此,Runtime 内部设立了独立的能力管理矩阵:
ToolRegistry:维护当前系统可用的全部工具元数据与调用函数句柄;SkillStore:维护不可变的知识包、操作模板、资产文件与自动化脚本;McpManager:管理跨进程的 MCP 服务连接、工具协议转换与认证头注入;PluginManager:负责本地或远端扩展插件的生命周期与隔离;HookBus:在生命周期各阶段挂载审计、监控、脱敏等切面逻辑;ProviderManager:统一抽象底层的大模型网关、向量数据库、记忆引擎与持久化介质。
当 Run 状态从 queued 跃迁为 running 的瞬间,CapabilityResolver 会强制为当前 Run 生成一份不可变的 CapabilitySnapshot 并持久化。当前 Run 在后续整个执行过程中,只能且必须读取该快照中的能力定义。如果执行期间发生任何配置变更,只会影响后续新建的 Run,绝不污染当前正在执行的实例。
3.5 副作用计算层与微虚拟机沙箱抽象
任何涉及实际代码运行、Shell 指令下发、文件写入或编译构建的操作,都被严格定义为"带副作用的计算任务"。
副作用计算层完全收敛在 ComputeProvider 抽象接口之后。Runtime 内部支持对接轻量级容器编排,以及基于 MicroVM 技术的专业沙箱集群。
在沙箱文件系统内部,规划了严格的目录层级:
/skills/{skill_version_id}/:以只读模式挂载的平台级通用技能资产,防止被恶意脚本篡改;/sessions/{session_id}/context/:存放当前会话共享的历史上下文文件;/sessions/{session_id}/runs/{run_id}/input/:只读的当前 Run 初始输入数据与附件;/sessions/{session_id}/runs/{run_id}/output/:当前 Run 产出的最终文件与交付物;/sessions/{session_id}/runs/{run_id}/tmp/:执行期间的临时缓存空间,Run 结束后可随策略清理。
这种严密的目录划分,既保证了多轮执行之间的资产复用,又实现了单次执行在文件层面的物理隔离。
四、Run 生命周期与确定性状态机
一个高可靠的 Runtime 系统,其核心必然建立在一个简洁、完备且数学上严格封闭的状态机之上。
4.1 规范化 Run 状态集与流转约束
为了避免状态爆炸和逻辑歧义,xbot Native Runtime 严格收敛了核心状态集,仅保留 7 种标准状态,杜绝引入模糊的中间状态。
┌──────────────┐
│ created │
└──────┬───────┘
│ enqueue
v
┌──────────────┐
┌─────────────>│ queued ├──────────────┐
│ └──────┬───────┘ │
│ │ acquire lock & start │
│ v │
│ ┌──────────────┐ │
│ resume │ running │ │
├─────────────>│ ├──────────┐ │
│ └──────┬───────┘ │ │
│ │ need approval / │ │ cancel /
│ │ wait input │ │ timeout
│ v │ │
│ ┌──────────────┐ │ │
└──────────────┤ paused │ │ │
└──────┬───────┘ │ │
│ │ │
│ terminal event │ │
v v v
┌─────────────────────────────┐
│ Terminal States │
│ [completed/failed/cancelled/│
│ expired] │
└─────────────────────────────┘
状态流转的合法路径与前置条件如下:
| 源状态 | 目标状态 | 触发事件 / 条件 | 行为说明 |
| :-------- | :---------- | :---------------------- | :------------------------------------------------ |
| created | queued | runtime.run.accepted | 任务通过准入校验,写入持久化账本,进入排队队列 |
| queued | running | runtime.run.started | 成功获取沙箱锁,固化能力快照,拉起 Agent 循环 |
| queued | cancelled | CancelRun 指令到达 | 任务在排队阶段被主动取消,直接释放队列槽位 |
| running | paused | runtime.run.paused | 检测到高危动作触发审批,或模型主动发起追问等待输入 |
| paused | running | runtime.run.resumed | 收到审批通过指令或用户澄清回复,校验通过后唤醒循环 |
| paused | cancelled | CancelRun 指令到达 | 处于等待状态的任务被取消,清理待决审批并流转至终态 |
| paused | expired | 等待超时 (TTL Exceeded) | 超过平台允许的最大暂停等待时长,系统强制回收资源 |
| running | completed | runtime.run.completed | 模型输出终态结果且无未决任务,释放所有持有的锁 |
| running | failed | runtime.run.failed | 发生不可恢复的底层系统异常、网络崩溃或预算耗尽 |
| running | cancelled | CancelRun 成功应用 | 在安全点检测到取消意图,平滑中断正在执行的操作 |
值得特别注意的是:本架构坚决不引入 interrupted、compacting、approving 作为顶层状态。中断本质上是带有明确取消原因(CancellationReason)的 cancelled 终态;压缩是执行流水线内部的一个普通事件;而审批则是具体的 RuntimeItem 处于挂起态,Run 自身表现为标准的 paused(awaiting_approval)。
4.2 暂停态的多维诱因与恢复路径
当 Run 进入 paused 状态时,必须强制附带结构化的 pauseReason 枚举与上下文数据。常见暂停诱因包括:
awaiting_approval:底层工具调用触发了平台安全拦截规则,创建了待审批项,等待用户通过管理界面授权;awaiting_user_input:模型在推理过程中发现前置信息不足,主动调用提问工具等待用户补充澄清事实;awaiting_external_tool_result:触发了跨系统的异步长周期任务(如发起一次耗时十分钟的集群编译),释放计算资源等待回调;awaiting_checkpoint_restore:系统遭遇节点故障重启,从持久化快照中恢复了内存状态机,等待重新绑定物理沙箱。
无论何种诱因,处于 paused 的 Run 在内存中都可以被安全挂起,甚至从当前 Worker 节点的内存中卸载。一旦外部触发恢复指令,协调器重新从数据库加载 Checkpoint 并完成上下文拼装后,便能无缝回到 running 状态。
4.3 终态不可变性与取消动作的幂等处理
终态(completed、failed、cancelled、expired)在数学上具有不可逆性。一旦一个 Run 写入了终态事件,任何后续到达的外部控制指令均不得再改变其状态。
针对分布式环境中常见的重复请求与乱序到达问题,系统对 CancelRun 实现了严格的幂等控制:
- 如果目标 Run 处于
queued、running或paused状态,Controller 接受该取消请求,设置取消标记,并在下一个执行安全点将其跃迁为cancelled终态,向外发出runtime.run.cancelled事件; - 如果目标 Run 已处于终态(例如在用户点击取消的前一秒,任务刚刚执行完毕变成了
completed),Controller 会记录一条结果为no_effect的审计日志,但严禁重新抛出取消事件或反向修改既有终态结果。
五、Safe Point 驱动的 Agent Loop 执行引擎
在解释执行引擎如何处理复杂的上下文与工具调用前,先讲一个简单的道理。Run Event Log 好比银行的流水总账,Context Projector 则是取款机上打印给客户看的临时对账单。系统绝不通过涂改总账来删减历史,而是根据流水按需生成特定时刻的视图投影。
理解了这一点,就能明白为什么模型看到的提示词绝不能在内存里随意被破坏性修改。
5.1 五大核心安全点的判定与拦截逻辑
为了让复杂的异步指令能够精准、安全地对执行流产生影响,AgentLoopEngine 在流水线中锚定了五个关键的安全点(Safe Points)。
┌────────────────────────┐
│ before_model_request │
└───────────┬────────────┘
│ (Model Generation)
v
┌────────────────────────┐
│ after_model_response │
└───────────┬────────────┘
│ (Parse Tool Calls)
v
┌────────────────────────┐
│ before_tool_execution │
└───────────┬────────────┘
│ (Side-effect Execution)
v
┌────────────────────────┐
│ after_tool_result │
└───────────┬────────────┘
│ (Check Compaction / Loop)
v
┌────────────────────────┐
│ before_run_terminal │
└────────────────────────┘
每个安全点承载着不可替代的防御与分发职责。
第一,before_model_request(模型请求发出前):检查是否有挂起的取消指令,防止无效消耗昂贵的模型 Token;检出用户在运行期间下发的转向指令(Steer),将其拼装进本轮提示词;评估当前上下文总 Token 量,若逼近窗口上限则前置触发压缩算法;最后调用 ContextProjector 为当前选定的模型重新生成符合其格式规范的消息数组。
第二,after_model_response(模型返回结果后):将模型原始输出、思考链摘要(Reasoning Summary)结构化为 RuntimeItem;对模型返回的 tool_calls 进行静态校验与语法修复;若模型未发起工具调用且完成了文本输出,或发起了澄清提问,在此处引导状态机走向终态或暂停态。
第三,before_tool_execution(工具实际下发前):基于当前 Run 的能力快照校验该工具是否在授权白名单内;判断工具入参是否命中高危策略,若命中则构建审批项并将 Run 置为暂停;工具往往会产生不可逆的外部物理副作用(如写库、删文件),因此在下发执行前的最后一毫秒必须再次校验取消标记;最后为本次工具执行向沙箱底座申请计算资源与工作目录租约。
第四,after_tool_result(工具执行完成回填后):将工具的标准输出、错误输出、文件变更 Diff 写入 Run Event Log;若工具返回了数千行日志或超大 JSON 数据,立刻标记大结果卸载(Offload)或通知下一轮循环强制压缩。
第五,before_run_terminal(进入终态收尾前):检查命令收件箱中是否还有尚未消费的核心指令,确保指令不被静默丢失;向 RunLockManager 归还当前持有的沙箱分布式锁,发出终态事件。
5.2 上下文投影器 Context Projector 的无损重建
在传统的粗糙实现中,很多系统会直接在一个全局的 messages 数组里不断追加或弹出消息。这种做法在遇到大模型上下文溢出、断线重放或多模型混合路由时,会导致数据结构彻底混乱。
ContextProjector 彻底颠覆了这种破坏性修改模式,遵循纯函数式投影原则:
ContextProjector.build(RunState) -> ProviderSafeMessages[]
├── Inputs:
│ ├── Run Event Log (Immutable Truth)
│ ├── Latest CompactionArtifact (Summary + Cutoff Pointer)
│ ├── Platform Session History (Optional Read-only)
│ └── Effective Permission Grants & Steering Inputs
└── Transformations:
├── 1. Discard Raw Events before Compaction Cutoff
├── 2. Inject Compaction Summary as System / Context Anchor
├── 3. Project Kept Event Log to Standard Messages
├── 4. Append Live Steering / Clarification Inputs
└── 5. Convert to Provider-Specific Wire Schema
通过这一设计,不论底层发生过多少次上下文压缩、参数修剪或审批注入,底层的事件事实源永远保持纯净与完整。任何时候需要回溯历史,系统都可以从 Sequence 0 开始完整重放整个 Agent 的思考轨迹。
5.3 模型请求与工具调用的确定性管线
在整个迭代流水线中,工具调用的执行遵循严格的确定性约束。当模型单次返回多个并行工具调用请求(Multi Tool Calls)时,Runtime 支持按照配置采用受控并发或拓扑串行执行。
每个工具执行的所有输入参数、执行耗时、退出码以及返回载荷,都会被封装为独立的 RuntimeItem。如果工具执行失败,错误信息会作为标准的工具错误响应回填给模型,引导模型在下一轮循环中尝试自我纠错或调整策略,而不是让整个 Runtime 崩溃退出。
六、旁路控制 Runtime Command 与用户意图分流
在真实交互场景中,用户绝不是坐在屏幕前傻傻等待 Agent 一步步跑完。用户可能中途打断,可能在 Agent 跑偏时插话纠偏,也可能在任务彻底结束后继续追问。将这些完全不同的用户意图统一抽象为"普通的消息追加",是导致系统失控的元凶。
6.1 外部意图到确定性事实的转换链路
本架构确立了意图(Command)与事实(Event)的严格边界:
[External World (User/UI/Worker)]
│
│ Submits RuntimeCommand (External Intent)
▼
[RunController / CommandInbox]
│
├── 1. Schema & Security Validation
├── 2. Idempotency Check (idempotencyKey)
├── 3. Match Target Run State
│
├─── If Rejected ───> Emit runtime.command.rejected
└─── If Accepted ───> Emit runtime.command.accepted
│
▼ (Buffered in RunState)
[AgentLoopEngine @ SafePoint]
│
├── Apply Command Actions
▼
Emit runtime.command.applied
Emit Corresponding RuntimeEvents
外部系统只能向 Runtime 发送 RuntimeCommand。Command 仅仅表达了一种诉求,它可能被接受,也可能因为状态不符被拒绝,或者因为目标已达而产生 no_effect。只有当 Command 在特定安全点被真正处理后,才会转化为不可篡改的 RuntimeEvent 写入事实账本。
标准的 RuntimeCommand 信封结构定义如下:
{
"commandId": "cmd_01J8XK9B2C3D4E5F6G7H8J9K0L",
"idempotencyKey": "idem_a1b2c3d4e5f6",
"runId": "run_01J8XK8A1B2C3D4E5F6G7H8J9K",
"platformSessionId": "sess_01J8XK7Z0A1B2C3D4E5F6G7H8J",
"type": "AppendUserInput",
"actor": {
"type": "user",
"id": "usr_9f3c21a8"
},
"issuedAt": 1782806400000,
"payload": {
"intent": "steer",
"content": "先不要修改代码,先帮我读一下 README 里的规范"
}
}
6.2 转向、追问与澄清的三重意图路由
针对用户在交互界面输入的自然语言,Runtime 提供 AppendUserInput 指令,并强制要求上层显式声明其交互意图(Intent)。
| 意图分类 (Intent) | 适用 Run 状态 | 生效时机 | 运行时底层行为 |
| :----------------------------- | :--------------------------------- | :----------------------------------- | :----------------------------------------------------------- |
| steer (运行纠偏) | 仅限 running | 下一个 before_model_request 安全点 | 不切断当前正在执行的底层物理操作,将纠偏指令作为高优先级输入注入下一轮模型上下文,引导模型改变后续计划 |
| follow_up (会话追问) | 仅限终态 | 立即触发新 Run 创建 | 坚决不重新激活已进入终态的历史 Run。依据关联的 platformSessionId,在平台会话树下创建全新的 Next Run,继承历史上下文与权限 |
| clarification (澄清回复) | 仅限 paused(awaiting_user_input) | 校验后立即唤醒 Run | 将用户输入的答案作为提问工具的返回结果回填,解除暂停状态,将 Run 重新置为 running |
User Sends Message
│
┌──────────────┴──────────────┐
│ What is the current status? │
└──────────────┬──────────────┘
│
┌───────────────────────┼───────────────────────┐
│ │ │
v (status == running) v (status == paused) v (status == terminal)
+───────────────────+ +───────────────────+ +───────────────────+
| Intent = steer | |Intent=clarification| | Intent = follow_up|
+─────────┬─────────+ +─────────┬─────────+ +─────────┬─────────+
│ │ │
v v v
Inject to Next Turn Fulfill Prompt Question Create Brand New Run
at Safe Point and Resume Loop Engine in Same Platform Session
这种精确的意图划分,彻底解决了"用户发了一句话,系统不知道是该打断当前任务、还是该回答提问、还是该另起炉灶"的经典混乱局面。
6.3 幂等控制与命令处理状态流转
为了应对弱网环境下的前端重试,IdempotencyStore 会对每一个携带 idempotencyKey 的 Command 进行生命周期管理。Command 在系统内部的处理状态分为五种:
accepted:指令已通过校验并存入缓冲收件箱,等待流水线推进到安全点应用;rejected:指令被拒绝,例如试图对一个已处于终态的 Run 发送steer指令;duplicate:检测到完全一致的idempotencyKey且前序请求已处理完毕,直接返回前序处理结果的快照;no_effect:指令语义合法,但在当前执行上下文中无需产生实质变化(例如对已经cancelled的 Run 再次发送CancelRun);applied:指令在特定安全点被成功消费,对 Run 内部状态机、上下文投影或工具链产生了确定性修改。
七、事件溯源事实账本与运行时工作单元
在分布式系统中,状态丢失与事件乱序是高并发场景下的常态。Native Runtime 采用事件溯源(Event Sourced)架构作为底层事实的唯一基石。
7.1 Run Event Log 的单调递增与重放机制
在 Native Runtime 内部,Run Event Log 是唯一的 Source of Truth。内存中的 RunState、前端看到的实时流式打字机效果、以及多端协议视图,全都是由 Run Event Log 经由特定投影器计算出来的衍生视图(Projections)。
+---------------------------------------------------------------+
| Canonical Run Event Log |
| [Seq 1: accepted] ──> [Seq 2: started] ──> [Seq 3: item...] |
| │ │ │ |
+---------┼─────────────────────┼────────────────────┼----------+
│ │ │
v (Projection) v (Projection) v (Projection)
+-------------------+ +--------------------+ +------------------+
| xbot Web Stream | | Worker Task View | | External IDE View|
+-------------------+ +--------------------+ +------------------+
为了确保事件的严格全序,每个属于特定 Run 的事件都必须拥有一个在该 Run 维度内单调递增且连续无空洞的序列号(event_seq)。
事件的标准信封设计如下:
{
"eventId": "evt_01J8XK9M8N7P6Q5R4S3T2U1V0W",
"runId": "run_01J8XK8A1B2C3D4E5F6G7H8J9K",
"seq": 42,
"schemaVersion": "v1",
"type": "runtime.item.completed",
"occurredAt": 1782806405120,
"emittedAt": 1782806405125,
"platformSessionId": "sess_01J8XK7Z0A1B2C3D4E5F6G7H8J",
"itemId": "itm_tool_exec_001",
"commandId": "cmd_01J8XK9B2C3D4E5F6G7H8J9K0L",
"payload": {
"itemType": "command_execution",
"exitCode": 0,
"stdout": "task finished.\n",
"durationMs": 1450
}
}
当客户端(如 Web 前端或 Worker 节点)因网络抖动与 Runtime 断开连接后,重连时只需在请求中附带其本地记录的 last_seen_seq=41。Runtime 即可直接检索所有 seq > 41 的事件并顺序重放。这种纯粹的追加式重放机制,完全不需要上层业务做复杂的状态同步与对齐。
7.2 RuntimeItem 的提升准则与边界收敛
在 Runtime 执行期间,内部会发生无数细微的函数调用与数据转换。如果把每一个内部细节都作为事件向外广播,不仅会导致存储爆炸,还会让前端 UI 充斥无意义的噪音。
因此,系统提出了严格的 RuntimeItem 提升准则。只有满足下列条件之一的工作单元,才有资格被提升为一个独立的 RuntimeItem:需要在用户交互界面上作为独立卡片或进度节点渲染;该动作具备潜在风险需要暂停索取授权;定义了清晰的幂等边界允许单点重试;对外部世界产生了可观测的修改;在触发上下文压缩或生成 Checkpoint 时需要作为不可分割的语义块保留。
Runtime Internal Operations
│
┌──────────────────┴──────────────────┐
│ Meets RuntimeItem Promotion Criteria?│
└──────────────────┬──────────────────┘
│
┌──────────────┴──────────────┐
│ YES │ NO
v v
+──────────────────+ +──────────────────+
| RuntimeItem | | Internal Trace |
| (User/Audit/UI) | | (OTel / Metrics) |
+──────────────────+ +──────────────────+
| - assistant_msg | | - prompt_builder |
| - command_exec | | - token_counter |
| - file_change | | - schema_repair |
| - mcp_tool_call | | - retry_wrapper |
+──────────────────+ +──────────────────+
典型的 RuntimeItem 类型包括:user_message、assistant_message、reasoning(仅限脱敏后的阶段性摘要)、plan、command_execution、file_change、mcp_tool_call 以及 context_compaction。
反之,像提示词拼接、Token 计数、底层重试封装、参数合法性校验以及参数容错修复等底层动作,坚决不得提升为 RuntimeItem,它们只允许作为链路追踪的 Span 或内部 Debug 日志记录。
7.3 客户端多视图投影与断线续传
由于 xbot-agent-protocol 规范化了标准事件族,上层不同的产品形态可以根据自身需求构建轻量级投影适配器(Projection Adapter)。
例如,IM 界面需要将大模型的思考流与文本片段合并为平铺的会话气泡;开发工具形态需要将代码修改投影为带有行号 Diff 的文件变更树;而后台自动化 Worker 则仅关注状态跃迁事件。所有产品形态都建立在完全一致的底层事件事实之上,底层内核永远不需要为特定客户端定制私有接口。
八、上下文压缩与大载荷卸载机制
长周期 Agent 面临的最严峻挑战之一就是上下文窗口极限与推理成本的指数级上升。一个优秀的 Runtime 必须具备自主的上下文治理能力。
8.1 运行级压缩产物 CompactionArtifact
传统的上下文压缩往往采用就地替换的方式,直接把历史消息抹掉,替换为一段文字。这种做法会导致历史审计链条彻底断裂,一旦模型在后续执行中发现摘要丢失了关键细节,系统没有任何手段回查原始事实。
xbot Native Runtime 提出了 Run-scoped CompactionArtifact(运行级压缩产物) 的设计:
{
"artifactId": "cmp_01J8XK9Z8A7B6C5D4E3F2G1H0J",
"runId": "run_01J8XK8A1B2C3D4E5F6G7H8J9K",
"cutoffEventSeq": 128,
"triggerReason": "before_model_request_threshold",
"sourceRange": { "fromSeq": 1, "toSeq": 128 },
"summary": {
"userGoal": "重构订单服务的超时重试模块并补充集成测试",
"executedDecisions": [
"移除了已废弃的同步重试实现",
"引入了基于指数退避算法的重试中间件"
],
"modifiedFiles": ["service/retry.go", "service/retry_test.go"],
"pendingTasks": ["修复集成测试中的超时竞争条件"]
},
"retainedItemIds": ["itm_user_init_001", "itm_tool_test_fail_042"],
"tokenStats": { "beforeTokens": 112000, "afterTokens": 18500 }
}
压缩产物是一个独立的结构化事实对象,记录了被压缩的截止事件序号(cutoffEventSeq)、结构化的业务决策摘要、必须保留的核心实体引用以及压缩前后的 Token 统计数据。
8.2 触发策略与摘要加尾部的投影算法
压缩算法绝不由大模型自由发挥,而是由 Runtime 的策略评估器根据确定性规则触发:
before_model_request_threshold:在模型请求前进行前置评估,当预估 Token 占用超过模型物理窗口的既定水位(可配置)时主动触发;context_overflow_recovery:当模型供应商接口明确抛出上下文溢出错误时,捕获该异常并触发后置应急压缩,随后自动重试;post_tool_result_threshold:当某个工具执行产出了巨大输出,使总上下文急剧膨胀时立即触发;manual_compact:收到外部下发的RequestCompaction控制指令时触发。
在生成摘要时,系统提取结构化的核心要素(用户终极目标、已达成的关键决策、发生修改的文件清单、当前未决疑问)。在下一次调用 ContextProjector 构建模型输入时,投影器会依据最新的 CompactionArtifact,丢弃 cutoffEventSeq 之前的所有细碎工具调用过程,仅将结构化摘要与截断点之后的活跃事件拼接成新的上下文。原始事实完好无损地保存在数据库中,模型看到的则是高度浓缩的高价值上下文。
8.3 工具大结果的异步落盘与引用索引
除了会话层面的压缩,单个工具调用输出过大(例如读取了一个巨大的日志文件,或搜索接口返回了数百条原始 JSON)也是冲垮上下文的主要原因。
针对此类场景,系统设计了大载荷卸载(Context Offload)机制:
+---------------------------------------------------------------+
| Tool Execution Output |
| (Size > Threshold) |
+-------------------------------+-------------------------------+
│
v
+---------------------------------------------------------------+
| Storage Substrate Engine |
| - Offload Full Raw Content to Object Storage / Sandbox Disk |
| - Generate Content Summary / Head-Tail Truncation |
| - Issue Storage Ref URI |
+-------------------------------+-------------------------------+
│
v
+---------------------------------------------------------------+
| Model Context Projection |
| "Output truncated. Content preview: ... |
| Use tool 'read_file_part' with the given ref to read more" |
+---------------------------------------------------------------+
当工具输出体积超过预设阈值时,ToolRunner 会自动拦截原始输出并将其上传至对象存储或沙箱内部的持久化文件。随后回填给模型上下文的仅包含:一段高度浓缩的头尾预览内容、一个指向外部存储的引用指针,以及一段明确的系统提示(告知模型如需查看特定段落可调用专用分页工具读取)。这既保证了大数据的物理完整性,又避免了单次工具调用瞬间打爆模型上下文的灾难。
九、人机协同审批与跨会话权限继承
在涉及企业资产的实际生产场景中,绝对不能对大语言模型的自主行为抱有盲目信任。对于可能引发灾难性后果的操作,必须建立坚固的人机协同(Human-in-the-Loop)防护网。
9.1 基于 RuntimeItem 的细粒度审批模型
在很多初级设计中,审批往往被设计为"将整个 Run 暂停并等待同意"。这种设计在语义上存在严重缺陷:用户根本不知道自己批准的究竟是哪一个动作,系统也无法对授权范围进行精确审计。
在 xbot Native Runtime 中,审批的主体被严格绑定到具体的 RuntimeItem 实例之上:
[Agent Loop Engine]
│
▼ @ before_tool_execution
[Risk Policy Evaluator] ──(Risky Action Detected)──┐
│ │
│ ▼
│ Create RuntimeItem(I42)
│ ItemStatus = awaiting_approval
│ │
│ ▼
│ Emit runtime.item.awaiting_approval
│ Set RunStatus = paused(awaiting_approval)
│ │
│ <── SubmitApprovalDecision(I42, allow) ──┘
│
├── 1. Verify Item Binding & Permissions
├── 2. Emit runtime.approval.decision_submitted
├── 3. Set ItemStatus = approval_resolved
├── 4. Set RunStatus = running
└── 5. Dispatch ToolRunner to Compute Sandbox
Run 之所以暂停,仅仅是因为其内部某个编号为 I42 的危险工具执行项正处于 awaiting_approval 状态。用户的审批决定(通过 SubmitApprovalDecision 指令下发)精确作用于该 Item。这使得审计日志中能够无比清晰地追溯:在哪个时间点、哪位操作员针对哪一个具体参数的指令发放了授权。
9.2 权限作用域与平台侧权限账本协作
为了避免频繁弹出审批窗口打扰用户,系统设计了多级授权作用域(Permission Grant Scope):
item(单次有效):授权仅对当前这一个具体的RuntimeItem有效,Agent 后续若再次发起相同命令依然需要重新审批;run(单次 Run 有效):在当前 Run 的生命周期内,后续所有命中相同签名规则的工具调用均可直接复用该授权;platform_session(平台会话级有效):授权在整个平台会话的生命周期内持续有效,后续发起的多次 Run 均可直接继承。
这里再次体现了架构分层的精妙之处:Native Runtime 自身绝不持有跨 Run 的长期会话级权限账本。
+---------------------------------------------------------------+
| xbot Platform / Worker |
| (Owns Permission Ledger Store & TTL) |
+-------------------------------+-------------------------------+
▲ Write platform_session grant │ Read EffectiveGrants
│ v at Run Started
+---------------------------------------------------------------+
| Native Agent Runtime |
| (Enforces Grants within Current Run Execution) |
+---------------------------------------------------------------+
当用户勾选了"在当前会话中始终允许"并提交审批时,Native Runtime 在当前 Run 中应用该授权的同时,会发出 runtime.permission_grant.applied 事件,并将该授权事实通知给平台侧的权限账本服务。当该会话在未来发起全新的 Next Run 时,平台会在任务初始化时读取有效授权列表,并通过 CapabilitySnapshot 重新注入到新的 Run 中。Runtime 仅负责执行期间的授权核验,长期状态的管理权完全保留在平台控制面手中。
9.3 策略静默阻断与用户显式拒绝的处理差异
在安全控制路径上,必须明确区分三类完全不同的阻断行为。
第一是 Policy Deny(策略静默阻断):命中企业最高级别的硬性安全红线(例如试图递归删除根目录或读取系统凭证文件)。此类动作无需也不得打扰用户发起审批,Runtime 的策略引擎会直接在底层将其拦截,并生成一个类型为 blocked_by_policy 的错误结果回填给 Agent Loop,告知模型该路径被系统策略绝对封死,迫使模型寻找替代方案。
第二是 HITL Reject(用户主动拒绝):系统弹出了审批窗口,但用户认为该操作不合理并点击拒绝。拒绝决策会被封装为一个合法的动作执行结果回传给模型。模型会得知"用户明确拒绝了此项操作",并据此向用户解释限制或重新规划任务路径。
第三是 Tool Execution Error(工具执行异常):操作通过了审批但由于脚本语法错误或依赖缺失导致执行失败。这属于计算层面的普通异常,走标准错误重试流。
十、沙箱隔离、并发控制与依赖治理
对于包含代码生成与自主执行能力的 Agent 平台而言,计算环境的隔离与多任务并发冲突是决定系统能否上线的最后一道技术大关。
10.1 多维沙箱路由键与租户资源隔离
为了让用户的计算环境既能安全隔离,又能在合理范围内实现资源复用,系统设计了确定性的沙箱路由键(SandboxKey),由租户标识、工作空间标识、Agent 标识与沙箱归属者标识四个维度共同组成。
在私聊场景下,沙箱归属者精确映射到具体的用户 ID,保证每个码农拥有完全属于自己的独立开发沙箱;而在多人协作的群聊场景下,沙箱归属者可以映射为群组 ID,使群内所有成员在当前 Agent 下共享同一个协作工作空间。
10.2 单沙箱串行排队与并发锁竞争策略
如果同一个沙箱环境内允许多个 Run 完全并发执行,会引发极其严重的环境竞争灾难:两个任务可能同时修改同一个源码文件、同时执行包安装命令导致包管理器锁死、或者互相覆盖临时的上下文缓存。
因此,xbot Native Runtime 确立了铁律般的并发控制模型:同一个 SandboxKey 内部,单时间窗口内仅允许一个活跃 Run 占用沙箱执行,其余任务进入队列严格串行排队;不同的 SandboxKey 之间则完全允许并行执行。
Sandbox A (Key: tenantA_wsA_agentA_ownerA)
├── Run 1: [ RUNNING ] (Holds Sandbox Distributed Lock)
├── Run 2: [ QUEUED ] (Waiting for Run 1 Terminal / Yield)
└── Run 3: [ QUEUED ] (Waiting in FIFO Queue)
Sandbox B (Key: tenantA_wsA_agentA_ownerB)
└── Run 4: [ RUNNING ] (Concurrent Execution with Sandbox A)
Runtime 基于分布式锁管理器实现租约与排队机制。当 Run 1 结束并写入终态事件后,系统会主动释放分布式锁,调度器随即唤醒排在队首的 Run 2,重新完成能力快照绑定并拉起执行流水线。
10.3 技能资产物化与只读环境挂载
在企业平台中,Skill(技能包)通常包含大量说明文档、规范指南、自动化脚本以及预置资产。为了兼顾执行性能与安全性,系统采用按需物化与只读挂载机制。
Skill 在被平台发布时会生成唯一的不可变版本哈希。沙箱底座在拉起时,会将该版本的 Skill 资产包解压并以只读权限挂载至专用目录下。Agent 在执行 Skill 脚本时产生的所有临时数据与产出物,被强制重定向写入当前 Run 专属的输出目录或临时目录。
对于运行依赖,沙箱基础镜像预置了主流运行时环境。对于特定任务所需的额外依赖,系统支持在沙箱初始化阶段通过动态创建轻量级虚拟环境进行隔离安装,配合沙箱的休眠与快照恢复技术,将单次冷启动延迟压缩到可接受范围内。
十一、架构复盘 & 思考
行文至此,整套 Native Agent Runtime 的架构与设计细节已经全景式地展现在各位码农面前了。
在文章最后,作为一名常年在一线摸爬滚打的技术博主,我想抛开具体的接口定义与代码实现,和各位股东分享 4 点我个人对 Agent Runtime 演进方向的最核心理解:
11.1 事件溯源是解耦复杂 Agent 状态机的唯一正道
很多团队在早期做 Agent 时,习惯性地把整个会话维护成一个巨大的内存 JSON 对象,所有状态都在其上做原地覆盖与就地修改。这种做法在面对真实生产环境中的网络闪断重连、人工挂起数小时后再审批、以及多端异步展示时,会导致代码充斥着打补丁式的防御逻辑。
把每一次思考、每一个工具调用、每一次外部打断都看作一条不可篡改的单调递增事件,将当前状态与模型上下文视为事件在特定时间切片下的投影视图。这一架构思想不仅让断线重放变得轻而易举,更为系统提供了企业级系统最看重的绝对可审计性与确定性。
11.2 执行内核必须坚持所有权纯粹性
"Runtime owns Run, not Session" 是这套系统最精妙的架构决策。在过去的架构重构中,我见过太多把组织结构、会话历史、计费逻辑一股脑塞进底层执行引擎的失败案例,其最终结果必然是底层引擎彻底丧失通用性,上层业务重构步履维艰。
Runtime 就应当像操作系统的内核一样:调度算力、管理内存(上下文)、分发系统调用(工具)、执行安全策略并如实返回退出状态。让 Runtime 保持无产品状态的纯粹性,平台控制面才能在上层演进出千变万化的产品形态。
11.3 旁路控制必须依赖确定性安全点
一个能够被称为工业级的系统,其核心特征之一就是对异步控制信号的确定性收敛能力。不能因为用户在前端点了一下取消,底层的协程就抛出一个未捕获的异常导致连接直接断开,留下孤儿进程在沙箱里疯狂消耗算力;更不能在模型流式吐字的过程中随意篡改其提示词。
确立清晰的五大安全点,让所有的取消、转向、审批与压缩都在可控的生命周期交接点优雅生效,这是让 Agent 系统彻底告别"玩具原型",真正步入高可用基础设施的关键门槛。
11.4 算力沙箱的物理边界是安全不可逾越的生命线
永远不要把安全寄托在大模型的"自觉"之上。提示词注入(Prompt Injection)在当下的技术背景下几乎无法做到数学意义上的绝对防御。
将可信的执行控制与不可信的计算环境彻底物理隔离,核心密钥与审批权限寸步不离外部可信域,沙箱内部仅保留最小权限的执行接口。这种基于最坏安全假设构建的深层防御架构,才是企业级 Agent 平台能够抵御恶意利用、赢得客户信任的真正底气所在。
Comments