Agent Infra:从 Harness 运行时到生产环境基础设施

本文是「Agent 基础与工程」系列专栏的第 9 篇。专栏总览参见:《Agent 基础认知与工程架构全景》。

在本地编写一个 while True 的 Agent 循环通常只需要几十行代码:组装提示词、发起模型调用、解析工具、执行并打印输出。然而,当把这一套逻辑部署至企业生产环境时,系统会直接暴露在真实世界的分布式挑战之下:

  • 运行中途工作节点(Worker Pod)发生 OOM 重启,未跑完的任务状态全部丢失;
  • 模型 API 遭遇供应商网络抖动或 429 限流,任务直接崩溃引发级联失败;
  • 含有写副作用的工具(如扣费、更新数据库)在重试过程中被触发多次,导致数据不一致;
  • 模型生成的 Shell 命令逃逸出预期目录,破坏宿主文件系统。

解决这些问题不再属于模型算法或提示词工程的范畴,而是依赖承载运行时的底层基础设施(Agent Infrastructure)。


职责分层:Loop、Harness 与 Infra

将 Agent 系统稳定推向生产,必须明确划分三个截然不同的系统层次:

各层的职责边界与关注点对比如下:

层次 核心职责 输入与输出 典型技术栈
Agent Loop(执行内核) 推进模型决策与工具派发的单步状态转移 输入本轮消息,输出文本或工具调用声明 原生 Python 循环、LangGraph 节点
Harness(运行时外壳) 管理上下文装配、参数 Schema 校验、权限拦截与错误重试 维护局部内存轨迹与因果配对,控制步数预算 Pydantic、自研 Agent Harness
Agent Infra(生产底座) 提供集群任务持久化、节点自愈、分布式链路追踪、沙箱隔离与多租户审计 保证长生命周期任务高可用,防范资源耗尽与安全穿透 Kubernetes、Temporal、PostgreSQL、OTel、Firecracker

外部依赖治理:大模型 API 的生产管控

大模型 API 具备典型的弱网络、高延迟、波动大的特征。必须将其作为具有强故障倾向的外部服务来治理。

1. 超时控制四层矩阵

简单的 HTTP Client 超时设置(如 timeout=60s)无法应对流式长文本输出。必须拆分为四级超时防护:

  • TCP Connect Timeout:限制建立底层 TCP/TLS 连接的时间(建议 );
  • TTFT(Time-To-First-Token)Timeout:请求发出到服务端吐出第一个 SSE 数据包的时限(针对深度思考模型可放宽至 );
  • Inter-Token Timeout:相邻两个 SSE Chunk 之间的传输间断上限(若超过 无任何字符推送,判定为中间网络僵死,主动断开);
  • Global Task Deadline:由外层调度器赋予当前任务全局硬性时限(如最多运行 10 分钟),随请求向下传递,防止死循环无限消耗费用。

2. 抖动重试与退避策略(Jittered Backoff)

面对模型厂商的 HTTP 429(Rate Limit)与 5xx 服务端错误,严禁使用固定间隔重试,必须采用带随机抖动的指数退避(Exponential Backoff with Full Jitter):

加入随机抖动能打散并发请求高峰,避免成百上千个 Agent Worker 在同一时刻重试引发雪崩。


状态持久化与断点续跑(Checkpointing)

在执行需要数十分钟的长程任务时,计算节点宕机是常态。生产级 Infra 必须支持步进检查点(Step-level Checkpoint)。

检查点持久化机制

每当一轮工具调用完成、返回结果被写入轨迹之后,Harness 必须先将此时的 AgentState 序列化并存入持久化存储(如 PostgreSQL),再发起下一轮模型请求:

幂等执行台账(Idempotency Ledger)

断点恢复中最危险的隐患是副作用工具的重复执行。
例如任务包含三个步骤:

  1. 扣减账户资金;
  2. 生成结算报表;
  3. 发送确认邮件。

若步骤 1 执行完毕后系统崩溃,重启恢复时若重新回放全部历史,可能导致资金被扣减两次。

工程解法:在 Harness 内部维护幂等执行台账。任何带副作用的工具在执行前,必须先在数据库中插入一条 PENDING 记录并生成确定性的幂等键(Idempotency Key):

重启恢复检测到该 Key 状态为 COMPLETED 时,直接跳过物理执行,返回台账中记录的历史输出。


执行环境隔离:沙箱(Sandbox)架构

当 Agent 具备执行 Python 脚本、Bash 终端命令或安装依赖包的能力时,必须构建严格的代码沙箱,杜绝逃逸到宿主操作系统。

常见沙箱隔离级别对比

技术方案 启动耗时 隔离级别 资源开销 适用场景
进程级受限(chroot / seccomp) 弱(共享内核,易逃逸) 极低 纯只读命令、受限计算
标准容器(Docker / OCI) 中等(共享宿主内核) 低 常规本地开发工具、非多租户企业内网
微虚拟机(MicroVM / Firecracker) 强(独立硬件级虚拟化内核) 较低 面向公网用户的任意代码执行(生产标配)
沙箱容器(gVisor / Kata Containers) 强(拦截系统调用 / 独立内核) 中等 K8s 原生集成的多租户执行 Pod

在网络层面,沙箱默认应配置禁止访问私网元数据服务(如 169.254.169.254)与内部内网 IP 段,仅允许经过白名单审核的外部网络出口。


生产级 Harness 持久化检查点实现

以下通过原生 Python 展示一个具备持久化检查点与崩溃恢复能力的 Harness 骨架:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import json
import sqlite3
import time
from typing import Dict, Any, List
from pydantic import BaseModel

class Checkpoint(BaseModel):
task_id: str
step: int
state: Dict[str, Any]
messages: List[Dict[str, Any]]
updated_at: float

class ProductionHarnessStore:
def __init__(self, db_path: str = "agent_state.db"):
self.conn = sqlite3.connect(db_path)
self._init_db()

def _init_db(self):
with self.conn:
self.conn.execute("""
CREATE TABLE IF NOT EXISTS checkpoints (
task_id TEXT PRIMARY KEY,
step INTEGER,
payload TEXT,
updated_at REAL
)
""")

def save_checkpoint(self, checkpoint: Checkpoint):
with self.conn:
self.conn.execute("""
INSERT OR REPLACE INTO checkpoints (task_id, step, payload, updated_at)
VALUES (?, ?, ?, ?)
""", (
checkpoint.task_id,
checkpoint.step,
checkpoint.model_dump_json(),
time.time()
))

def load_checkpoint(self, task_id: str) -> Checkpoint | None:
cursor = self.conn.cursor()
cursor.execute("SELECT payload FROM checkpoints WHERE task_id = ?", (task_id,))
row = cursor.fetchone()
if row:
return Checkpoint.model_validate_json(row[0])
return None

def run_resumable_task(task_id: str, initial_goal: str, store: ProductionHarnessStore):
# 尝试恢复已有的断点
checkpoint = store.load_checkpoint(task_id)

if checkpoint:
print(f"[恢复任务 {task_id}] 从第 {checkpoint.step} 步恢复...")
current_step = checkpoint.step
state = checkpoint.state
messages = checkpoint.messages
else:
print(f"[新建任务 {task_id}] 初始化状态机...")
current_step = 0
state = {"goal": initial_goal, "status": "IN_PROGRESS", "completed_work": []}
messages = [{"role": "user", "content": initial_goal}]

max_steps = 5
while current_step < max_steps:
current_step += 1
print(f"\n--- 执行第 {current_step} 步 ---")

# 模拟模型调用与工具操作
time.sleep(0.5)
step_result = f"完成阶段子任务 {current_step}"

# 更新状态
state["completed_work"].append(step_result)
messages.append({"role": "assistant", "content": step_result})

# 保存持久化检查点(在发生崩溃前落盘)
store.save_checkpoint(Checkpoint(
task_id=task_id,
step=current_step,
state=state,
messages=messages,
updated_at=time.time()
))
print(f"[持久化] 第 {current_step} 步检查点保存成功")

if current_step >= 3:
# 达成业务目标提前终止
state["status"] = "SUCCESS"
print("[任务完成] 全部业务指标达标。")
break

生产就绪检查表(Production Readiness Checklist)

在将 Agent 服务上线提供外部 SLA 前,需逐项验收以下基础设施指标:

  1. 状态持久化:计算节点被随手 kill -9 后,重启 Worker 能否在 5 秒内精准拉起上下文断点继续执行?
  2. 死循环熔断:单任务设置了硬性 Token 预算、工具调用上限与总超时时间,一旦超限立即阻断并告警?
  3. 调用全链路追踪:从收到用户输入到最终产出,每一次模型调用的 Request ID、Prompt Tokens、Completion Tokens 及工具执行耗时是否全部注入 OpenTelemetry Trace?
  4. 安全沙箱:运行代码的进程是否彻底剥离了宿主机 root 权限、隔离了物理文件系统并屏蔽了内网元数据接口?
  5. 幂等性保障:外部网络异常重试时,是否对扣减库存、转账等敏感动作通过 Idempotency Key 做了强拦截?

系列导航与参考