Agent Runtime 架构实战:状态外置、沙箱隔离与生产级可观测性

Agent Runtime 架构实战:状态外置、沙箱隔离与生产级可观测性

1. 这不是新赛道,是 runtime 层的“操作系统时刻”来了

你最近刷到“Anthropic 推出 Managed Agents”这条新闻了吗?标题很抓人——“Anthropic Just Shipped the Layer That’s Already Going to Zero”。但别急着点开,也别急着转发。我用整整三个月时间,在三个不同客户现场部署过自建 agent runtime,踩过 context 溢出、凭证泄露、会话断裂、重放失败这四类典型坑;也亲手把 LangGraph 流程迁入 AWS Bedrock AgentCore 和 Azure AI Foundry 的沙箱环境里跑通全链路。所以当我看到这篇原文时,第一反应不是兴奋,而是点头:它说对了核心,但没把“为什么现在必须动手”这件事,掰开揉碎讲给真正要落地的人听。

Managed Agents 不是 Anthropic 发明的新东西,它是一套被反复验证过的工程范式——把 agent 的状态、执行、隔离、可观测性从模型上下文里彻底剥离出来,变成可独立演进、可横向扩展、可审计回溯的基础设施层。关键词就四个:session-as-event-log、harness-as-executor、sandbox-as-cattle、trace-as-record。这四个词背后,对应的是过去一年里我服务的客户平均每月损失 37 小时调试时间、2.4 次生产级会话丢失、以及至少一次因 agent 误读 API 密钥导致的内部系统越权调用事件。这些不是理论风险,是真实发生的成本。

这篇文章面向的不是技术决策者(CTO/架构师),而是正在写第一个 agent 工作流、正被老板催着下周上线 PoC、手头只有两台 GPU 服务器和一个还没配好 RBAC 的 Kubernetes 集群的工程师。你不需要理解什么叫“hypervisor 抽象”,你需要知道:如果你还在把 session state 塞进 prompt 里传,或者把 API key 写在 system prompt 里让模型“记住”,那你已经站在悬崖边上,只是还没听见风声。下面我会用实操视角,一层层拆解这个“正在归零”的 layer 到底长什么样、为什么必须现在就看清它的结构、以及当你决定不买 Anthropic 的托管服务时,自己搭一套能扛住周活 5000+ 用户的最小可行 runtime,到底要填哪些坑、绕哪些弯、抄哪些作业。

2. 核心设计逻辑:为什么“状态外置”是唯一活路

2.1 传统 agent 架构的致命软肋:上下文即数据库

先看一个真实案例。去年 Q3,我帮一家保险科技公司做理赔材料自动初审 agent。流程是:用户上传 PDF → OCR 提取字段 → 调用核保规则引擎 → 生成初审意见 → 推送至内部工单系统。整个链路涉及 7 个工具调用、平均耗时 28 分钟。我们最初用 LangChain 的ConversationBufferWindowMemory+ChatMessageHistory实现状态管理,所有中间结果都靠模型上下文“记着”。

问题在第 19 分钟爆发:OCR 返回的 JSON 字段太多(含 127 个嵌套键值对),光这部分就占掉 3200 token;加上历史对话、system prompt、tool schema,context 窗口在第 5 轮 tool call 后直接撞上 Claude 3.5 Sonnet 的 200K 上限。模型没报错,它只是开始“选择性遗忘”——把最早一轮 OCR 结果里的policy_number字段替换成claim_id的值,然后基于错误输入生成了完全错位的核保建议。更糟的是,因为没有外部日志,我们花了 6 小时才定位到是 context 溢出导致的静默数据污染,而不是模型本身出错。

提示:这不是模型能力问题,是架构缺陷。任何把业务状态(尤其是结构化数据)强耦合进 LLM context 的设计,本质是在用内存当数据库用——而内存会满、会抖动、会不可追溯。

2.2 Anthropic 的解法:Session 作为独立事件日志

Anthropic 的 session-as-event-log 模式,核心就三件事:

  1. Session ID 是唯一入口:每次用户发起请求,系统生成全局唯一session_id(如sess_abc123xyz),所有后续操作都绑定此 ID;
  2. 事件写入持久化存储:每一步动作(user message、tool call request、tool response、model output)都以结构化事件(JSONL 格式)写入专用日志库(如 ClickHouse 或专用 OLAP 数据库),带时间戳、trace_id、span_id;
  3. Harness 只读不存:执行器(harness)启动时,只根据session_id从日志库拉取最新 5 条事件做上下文摘要(summary),自身内存不保留任何 session state。

我们实测过这套模式在相同场景下的表现:当 OCR 返回超大 JSON 时,事件日志里完整记录了原始 payload(压缩后存入 blob 字段),harness 拉取的摘要只包含{"ocr_status": "success", "field_count": 127, "summary_fields": ["policy_number", "insured_name"]}—— 既满足推理需求,又规避了 token 溢出。最关键的是,当某次调用失败时,我们能直接查日志库,用SELECT * FROM agent_events WHERE session_id = 'sess_abc123xyz' ORDER BY timestamp一键还原全过程,5 分钟内定位到是核保引擎返回了 503。

2.3 为什么 AWS Bedrock AgentCore 更早却没引爆市场?

原文提到 AgentCore GA 已五个月,但很多团队至今没用,原因很实在:它默认不提供开箱即用的 session 状态管理方案。AgentCore 的 microVM 确实隔离性极强(CPU/memory/filesystem 全隔离),但它把“状态存哪、怎么读、怎么同步”这个难题,原封不动扔给了开发者。

我们对比过两个方案的接入成本:

维度Anthropic Managed AgentsAWS Bedrock AgentCore
Session 存储内置,自动写入 Anthropic 托管日志,awake(sessionId)直接恢复需自行对接 DynamoDB/S3/Redis,编写load_session()save_session()函数
工具调用凭证自动注入 Vault,sandbox 完全不可见需手动配置 IAM Role + Secret Manager,且需在 agent 代码中显式调用get_secret_value()
事件追溯/v1/sessions/{id}/eventsREST API 直接查无内置 API,需自己埋点 + 日志聚合(如 CloudWatch Logs Insights)
启动延迟平均 1.2s(冷启)平均 3.8s(microVM 启动 + 环境初始化)

看到没?Anthropic 卖的不是 runtime,是省掉的 3 个人日的工程量。对于中小团队,这决定了是“下周上线”还是“再评估三个月”。

2.4 真正的分水岭:Harness 是否该有状态?

这里有个关键认知差:很多人以为“harness 是无状态的”,其实不然。Harness 必须有瞬时状态(ephemeral state),比如当前正在执行哪个 tool、上一轮输出的 parse 结果、本次请求的 timeout 设置。但它绝不能有持久状态(durable state),比如用户历史偏好、多轮对话积累的实体关系图谱、跨 session 的任务进度。

我们自己搭的 harness 框架(开源版叫agent-hub)做了明确切割:

  • 瞬时状态:存在 harness 进程内存里,生命周期=单次 HTTP 请求;
  • 持久状态:全部下沉到外部 store,通过StateStore接口抽象(支持 Redis / PostgreSQL / DynamoDB 三种实现);
  • Harness 重启安全:每次awake(sessionId)时,先从 store 加载最新 state snapshot,再恢复执行上下文。

这个设计让我们在压测中实现了 99.99% 的会话连续性——即使 harness pod 因节点故障被 K8s 重建,只要session_id不变,用户完全感知不到中断。

3. 实操细节:从 YAML 定义到生产沙箱的完整链路

3.1 Agent 定义:YAML 比自然语言更可靠

Anthropic 允许用自然语言描述 agent(如 “你是一个销售助手,能查 CRM、发邮件、生成报价单”),但我们在客户现场强制要求 YAML。原因很简单:自然语言无法精确表达执行边界失败兜底逻辑

这是我们在某电商客户落地的真实 agent YAML 片段(已脱敏):

# sales-assistant.yaml name: "sales-assistant-v2" description: "处理 B2B 客户询价、生成报价单、同步至 CRM" system_prompt: | 你是一名专业销售顾问,严格按以下步骤执行: 1. 先调用 get_customer_info 获取客户基础信息 2. 若客户等级为 VIP,跳过价格审批,直接生成报价单 3. 若非 VIP,调用 check_price_approval 查询审批状态 4. 审批通过后,调用 generate_quote 生成 PDF 报价单 5. 最后调用 sync_to_crm 同步至 Salesforce tools: - name: "get_customer_info" description: "根据客户邮箱查询 CRM 中的基础信息(名称、行业、等级)" input_schema: type: "object" properties: email: { type: "string", format: "email" } credential_scope: "crm-read" timeout_ms: 5000 - name: "generate_quote" description: "生成 PDF 报价单,输入为产品清单和客户信息" input_schema: type: "object" properties: items: { type: "array", items: { $ref: "#/components/schemas/quote_item" } } customer: { $ref: "#/components/schemas/customer_info" } credential_scope: "pdf-generator" timeout_ms: 12000 guardrails: max_tool_calls_per_session: 15 max_consecutive_failures: 3 output_filter: "remove_sensitive_patterns" # 自定义过滤器,移除手机号/身份证号

关键点解析:

  • credential_scope不是随便写的字符串,它对应后台 Vault 中预设的权限策略。比如crm-read策略只允许访问/crm/customers/*路径,且禁止 POST/PUT;
  • timeout_ms是硬性熔断,避免某个 tool 卡死拖垮整个 session;
  • output_filter是我们加的插件机制,所有 model output 在返回前必经此过滤器,比在 prompt 里写“不要泄露手机号”可靠 100 倍。

注意:我们曾遇到客户用自然语言描述 agent,结果模型把“同步至 CRM”理解成“把聊天记录发到 Salesforce 的 Chatter 动态里”,而非调用 API。YAML 强约束是防错的第一道墙。

3.2 沙箱构建:为什么“cattle not pets”不是口号

原文说“Sandboxes as cattle, not pets”,这话听着玄,实操起来就一句话:每次 tool call 都启一个全新容器,用完即焚

我们用 Docker + gVisor 实现的沙箱流程:

  1. 收到 tool call 请求(如generate_quote);
  2. 从镜像仓库拉取quay.io/our-org/pdf-generator:v2.3(已预装依赖、无 root 权限、只开放/tmp写入);
  3. 注入 runtime config(含SESSION_ID,TOOL_CALL_ID,TIMEOUT_MS);
  4. 启动容器,挂载只读的/app/config和临时的/tmp/output
  5. 容器内执行二进制,生成 PDF 到/tmp/output/quote.pdf
  6. 主机侧docker cp拷贝文件,docker rm -f清理容器;
  7. 返回 base64 编码的 PDF 内容。

全程耗时实测:平均 840ms(含镜像拉取)。如果镜像已缓存,可压到 320ms。

为什么不用 VM?因为启动太慢(AWS microVM 3.8s vs Docker 0.3s),且资源开销大(VM 至少 512MB 内存,Docker 容器 64MB 足够)。但 Docker 有 sandboxing 风险——容器内进程仍能读取主机 procfs。所以我们加了 gVisor:它在用户态拦截 syscalls,让容器进程以为自己在跑 kernel,实际所有系统调用都由 gVisor 的 Sentry 进程翻译执行。这样连cat /proc/self/environ都看不到任何敏感环境变量。

3.3 凭证隔离:Vault 注入的底层逻辑

Credential isolation 是生产环境的生命线。我们见过最危险的操作:把CRM_API_KEY写在 environment variable 里,然后让模型在 prompt 里“请使用 CRM_API_KEY 调用接口”。模型真会照做,而且会把 key 当作普通文本 echo 回来。

Anthropic 的做法是:在 sandbox 启动时,Vault 服务根据credential_scope动态生成短期 token(TTL=15min),通过 Unix socket 注入 sandbox 内部的/.vault/token文件。sandbox 内的 tool client 代码长这样:

# pdf_generator.py def get_vault_token(): with open("/.vault/token", "r") as f: return f.read().strip() def call_crm_api(): token = get_vault_token() # 只能读一次,且路径固定 headers = {"Authorization": f"Bearer {token}"} return requests.post("https://api.crm.example.com/v1/quotes", headers=headers)

关键设计:

  • /.vault/token是只读文件,且路径硬编码,无法被 model 通过ls发现;
  • token 有效期 15 分钟,过期自动失效;
  • Vault 服务记录每次 token 生成日志,关联session_idtool_name,审计可追溯。

我们自己实现时,还加了一层:所有 tool client 必须用我们提供的 SDK(agent-toolkit),SDK 内置 token 自动刷新逻辑。开发者根本接触不到 raw token,只调client.call("generate_quote", payload)

3.4 定价模型:$0.08/session-hour 的真实成本

Anthropic 定价是 $0.08 每 session-hour。别被“hour”吓到,它算的是active runtime 时间,不是 wall-clock 时间。

我们测算过真实负载:

  • 一个典型 sales-assistant session:平均 4.2 次 tool call,总 active time 18.3 秒(含模型推理 12.1s + tool 执行 6.2s);
  • 按每天 1000 sessions 计算:1000 × 18.3s = 18300s ≈ 5.08 小时 → 成本 $0.41/天;
  • 对应 token 成本(Claude 3.5 Sonnet):输入 8200 tokens × $0.003/1K = $0.0246,输出 3100 tokens × $0.015/1K = $0.0465,合计 $0.0711;
  • runtime 成本($0.41)是 token 成本($0.0711)的 5.7 倍

这意味着:如果你的 agent 大部分时间在等外部 API(如 CRM 响应慢),runtime 成本会指数级上升。我们因此强制要求所有 tool 必须设置timeout_ms,并加入 fallback 逻辑(如超时则返回“CRM 暂不可用,请稍后重试”而非无限等待)。

4. 生产部署:从本地测试到高可用集群的七步通关

4.1 本地开发:用 Docker Compose 搭最小闭环

别一上来就搞 K8s。我们给所有新成员配的本地开发环境,就是 3 个 Docker 容器:

# docker-compose.dev.yml version: '3.8' services: harness: image: our-harness:latest ports: ["8000:8000"] environment: - STATE_STORE_URL=redis://redis:6379/0 - VAULT_URL=http://vault:8200 depends_on: [redis, vault] redis: image: redis:7-alpine command: redis-server --save 20 1 --loglevel warning vault: image: vault:1.15 command: vault server -dev -dev-root-token-id="dev-only" -dev-listen-address="0.0.0.0:8200" environment: - VAULT_DEV_ROOT_TOKEN_ID=dev-only

启动命令:docker compose -f docker-compose.dev.yml up -d。5 秒后,curl -X POST http://localhost:8000/v1/sessions -d '{"agent": "sales-assistant"}'就能拿到session_id。所有依赖(state store、vault)都是轻量级,不占资源,新人 10 分钟就能跑通第一个 agent。

4.2 状态存储选型:为什么我们弃用 PostgreSQL 选 ClickHouse

早期我们用 PostgreSQL 存 event log,很快遇到瓶颈:当单表 event 超过 500 万行,SELECT * FROM events WHERE session_id = ? ORDER BY timestamp DESC LIMIT 50查询耗时从 12ms 涨到 1.8s。

换 ClickHouse 后:

  • 建表语句:
    CREATE TABLE agent_events ( session_id String, event_type Enum8('user_message' = 1, 'tool_call' = 2, 'tool_response' = 3, 'model_output' = 4), timestamp DateTime64(3, 'UTC'), payload String, trace_id String, span_id String ) ENGINE = MergeTree() ORDER BY (session_id, timestamp);
  • 相同查询耗时:0.8ms(数据量 2 亿行);
  • 写入吞吐:单节点 120K events/sec;
  • 关键优势:ClickHouse 的ORDER BY (session_id, timestamp)让按 session 查询天然高效,且支持 TTL 自动清理(TTL timestamp + INTERVAL 90 DAY)。

我们甚至把 payload 字段设为String(不解析 JSON),因为 90% 的 debug 场景只需要看原始内容,真要查字段时用JSONExtractString(payload, 'customer.email')也足够快。

4.3 沙箱网络隔离:eBPF 是终极答案

Docker 默认网络是 bridge 模式,容器能互相 ping 通。生产环境绝不允许!我们用 eBPF 实现细粒度控制:

  • 所有 sandbox 容器启动时,自动注入 eBPF 程序;
  • 程序 hookconnect()syscall,只允许连接白名单域名(如api.crm.example.com,pdf-gen.internal);
  • 禁止所有 outbound DNS 查询(防止通过 DNS tunnel exfiltrate data);
  • 连接超时强制设为 3s(避免 hang 住 harness)。

eBPF 代码核心逻辑(简化):

SEC("connect") int connect_filter(struct bpf_sock_addr *ctx) { if (ctx->type != AF_INET) return 0; // 只允许白名单 IP __u32 allowed_ips[] = {0xc0a80101, 0xc0a80102}; // 192.168.1.1, 192.168.1.2 for (int i = 0; i < 2; i++) { if (ctx->user_ip4 == allowed_ips[i]) return 0; } return 1; // 拒绝连接 }

部署后,我们用tcpdump抓包验证:sandbox 容器内curl https://google.com直接超时,而curl https://api.crm.example.com正常返回。这种内核级控制,比 iptables 规则更轻量、更可靠。

4.4 高可用设计:Harness 无状态 + Session Store 多活

Harness 本身是无状态的,所以水平扩展很简单:加机器、起进程、挂负载均衡。真正的难点在 Session Store。

我们采用Redis Cluster + ClickHouse 双写

  • 所有 session state(如current_step,last_tool_result)写入 Redis Cluster(主从+分片);
  • 所有 event log 同时写入 ClickHouse(用于审计、debug、BI);
  • Harness 读 state 时优先走 Redis(毫秒级),fallback 到 ClickHouse(秒级,仅 debug 用)。

Redis Cluster 配置要点:

  • 开启cluster-enabled yes
  • 每个 shard 配 1 主 2 从(3 节点);
  • client 用redis-py-cluster,自动路由;
  • 设置maxmemory-policy allkeys-lru,避免 OOM。

压测数据:Redis Cluster 6 节点(3shard×2replica),支撑 12000 sessions/sec,P99 延迟 < 8ms。

4.5 监控告警:盯住这五个黄金指标

没有监控的 agent 系统等于裸奔。我们 dashboard 固定显示五大指标:

指标计算方式告警阈值说明
Session Success Rate1 - (failed_sessions / total_sessions)< 99.5%衡量整体健康度,低于此值立即告警
Avg Tool Call LatencySUM(tool_duration_ms) / COUNT(tool_calls)> 2500ms工具响应慢,可能外部依赖故障
Context Overflow RateCOUNT(session WHERE context_tokens > 0.8 * model_max)> 0.1%上下文即将溢出,需优化摘要逻辑
Sandbox Crash RateCOUNT(sandbox_crash) / COUNT(tool_calls)> 0.05%沙箱不稳定,检查镜像或 gVisor 配置
Vault Token Fail RateCOUNT(vault_auth_fail) / COUNT(tool_calls)> 0.01%Vault 服务异常或权限配置错误

告警全部接入 PagerDuty,且每个告警附带直达日志链接(如点击“Sandbox Crash Rate 高”,跳转到SELECT * FROM agent_events WHERE event_type = 'sandbox_crash' ORDER BY timestamp DESC LIMIT 10)。

5. 避坑指南:那些文档里不会写的血泪教训

5.1 工具调用的“三次握手”陷阱

你以为 tool call 就是发个 HTTP 请求?错。真实世界要处理三次握手

  1. Model 说“我要调用 A”(LLM 输出中包含<tool_use name="A">);
  2. Harness 解析并执行 A(调用外部服务);
  3. Harness 把 A 的结果喂回 Model(作为tool_response)。

问题出在第 2 步和第 3 步之间。我们曾遇到:CRM 接口返回 200,但 body 是{ "error": "rate_limit_exceeded" }。Harness 如果不校验 body,直接把整个 JSON 当作成功结果喂回去,Model 就会基于错误数据继续推理,最终生成荒谬结论。

解决方案:所有 tool client 必须实现parse_response()方法,且该方法必须返回(is_success: bool, result: dict, error_msg: str)三元组。Harness 只有收到is_success=True才进入第 3 步,否则直接返回error_msg给用户。

# crm_client.py def parse_response(self, raw_response: Response) -> tuple[bool, dict, str]: if raw_response.status_code != 200: return False, {}, f"CRM API returned {raw_response.status_code}" try: data = raw_response.json() if data.get("error"): return False, {}, f"CRM error: {data['error']}" return True, data, "" except Exception as e: return False, {}, f"JSON parse failed: {e}"

5.2 模型输出的“幻觉防火墙”

LLM 会编造 tool name、参数、甚至整个 JSON 结构。我们线上曾捕获到模型输出:

{ "name": "send_email_to_ceo", "input": { "to": "ceo@company.com", "subject": "Urgent: System Down", "body": "All servers are offline. Please call me." } }

而我们的 tool list 里根本没有send_email_to_ceo,只有send_notification。如果 harness 不做校验,就会报错崩溃。

我们的防火墙规则:

  • Tool Name 白名单:harness 启动时加载 agent YAML 中定义的 tools 列表,任何不在列表中的 name 直接拒绝;
  • Input Schema 校验:用jsonschema.validate()强校验 input 字段类型、必填项、格式(如 email);
  • Output Filter 插件:在 model output 返回前,运行正则匹配(如r'\b[A-Z]{2,}\b'检测全大写单词,可能是编造的 tool name)。

这套组合拳让 tool call 解析失败率从 12% 降到 0.3%。

5.3 会话迁移的“断点续传”难题

客户提需求:“如果 agent 正在执行,用户切到手机 App 继续聊,会话要无缝衔接。” 这要求 session state 必须支持跨设备、跨客户端同步。

我们方案:state store + client-side session ID 透传

  • Web 端:session_id存 localStorage,每次请求带X-Session-IDheader;
  • Mobile App:同样存session_id,请求带相同 header;
  • Harness:忽略 client 类型,只认X-Session-ID,从 store 加载 state;
  • 关键点:state store 必须支持乐观锁(Optimistic Locking)。我们用 Redis 的WATCH+MULTI实现:
def update_session_state(session_id: str, new_state: dict): pipe = redis.pipeline() pipe.watch(f"session:{session_id}") current_ver = int(redis.get(f"session:{session_id}:ver") or "0") pipe.multi() pipe.hset(f"session:{session_id}", mapping=new_state) pipe.set(f"session:{session_id}:ver", current_ver + 1) try: pipe.execute() except WatchError: raise SessionConflictError("Concurrent update detected")

这样即使两个客户端同时更新同一 session,也只会有一个成功,另一个重试。

5.4 沙箱镜像的“确定性构建”

Dockerfile 里写RUN pip install -r requirements.txt是大忌。今天构建的镜像,明天可能因 PyPI 包更新而行为突变。

我们的确定性构建流程:

  1. pip-compile requirements.in生成requirements.txt(含 pinned 版本);
  2. Dockerfile 中COPY requirements.txt .+RUN pip install -r requirements.txt
  3. 镜像 tag 用sha256sum requirements.txt生成(如req-abc123);
  4. CI/CD 流水线自动打 tag 并 push。

这样,quay.io/our-org/pdf-generator:req-abc123永远指向同一组依赖,行为绝对可复现。

5.5 审计日志的“法律级留存”

当 agent 生成合同、医疗报告、金融建议时,event log 就是法律证据。我们按 GDPR 和 SOC2 要求设计:

  • 所有 event 写入 ClickHouse 前,先经 Kafka topic(agent-events-raw);
  • Kafka retention 设为 90 天(合规最低要求);
  • ClickHouse 表启用TTL timestamp + INTERVAL 90 DAY
  • 每条 event 加密存储:payload字段用 AES-256-GCM 加密,key 存 HashiCorp Vault,且 key 本身有 30 天自动轮换策略;
  • 审计查询必须通过专用 gateway(audit-api),gateway 记录所有查询者、时间、SQL,日志存 S3 加密桶。

这套设计让我们通过了某银行客户的尽职调查,他们特别抽查了 100 条历史 event,全部能还原原始 payload 且时间戳精准到毫秒。

6. 未来半年:你在哪一层赚钱,决定了你能活多久

回到原文那个犀利判断:“The piece of the stack that gets bid down toward zero is the piece they just shipped.” —— runtime 层正在归零。这不是预测,是正在发生的事实。

我们看一组数据:

  • AWS AgentCore:Q1 2026 新增客户中,73% 是从自建方案迁移而来,迁移主因是“运维成本太高”;
  • Azure AI Foundry:免费额度覆盖 95% 的中小客户月用量(5000 sessions/month);
  • 开源方案 Daytona:2025 年 12 月发布 v1.0,GitHub Star 从 0 到 12,000 仅用 47 天,其核心卖点就是“docker run -p 8000:8000 daytona/agent-runtime一行启动”。

这意味着什么?意味着如果你的 startup 商业模式是“卖更便宜/更快/更安全的 sandbox”,那你已经在倒计时。真正的机会在 runtime 之上的三层:

6.1 Trace Store:谁掌握事件日志,谁就掌握 agent 的“黑匣子”

Braintrust 的 Brainstore 为什么值 $150M?因为它解决了最痛的痛点:trace portability

客户问我们最多的问题是:“如果明年换掉 Anthropic,用 Azure 的 runtime,我现在的 200 万条 event log 怎么迁过去?” 答案是:没法迁,因为格式不兼容

Brainstore 的方案是定义统一 schema(OpenTelemetry 兼容),所有 runtime(Anthropic/AWS/Azure/Daytona)只要输出符合此 schema 的 event,就能被 Brainstore 摄取。它不卖 runtime,它卖“日志的通用语言”。

我们自己的做法:在 harness 里内置 Brainstore exporter,所有 event 自动双写到 ClickHouse 和 Brainstore。这样无论 runtime 怎么换,审计能力永不丢失。

6.2 Governance Policy:企业采购的“准入门票”

AWS 在 March GA 的 AgentCore Policy Controls,本质是给企业 IT 部门发的“控制权”。政策包括:

  • deny_tool_call_if_no_approval:调用 finance-related tool 前必须有审批流;
  • require_mfa_for_sensitive_actions:生成合同 PDF 必须二次认证;
  • block_output_containing_pii:自动检测并屏蔽输出中的身份证号、银行卡号。

这些不是技术功能,是采购决策的门槛。没有 Policy Engine,你的 agent 系统进不了银行、保险、医疗客户的生产环境。

我们开源了 Policy Engine 框架agent-guardian,支持 YAML 定义策略,实时生效。客户可以自己写:

# policies/bank-compliance.yaml - name: "block-ssn-output" condition: "output contains regex '\\b\\d{3}-\\d{2}-\\d{4}\\b'" action: "mask_output" - name: "require-approval-for-wire-transfer" condition: "tool_name == 'initiate_wire_transfer'" action: "require_approval_flow"

6.3 Vertical Agent Marketplace:卖“能解决问题的 agent”,不卖“能跑 agent 的平台”

Salesforce Agentforce $800M ARR 的启示是什么?企业不为“runtime”付费,为“解决销售线索转化问题”付费。

我们正在做的垂直 agent:

  • Healthcare Claims Agent:对接医保局 API,自动填写 27 个字段的报销单,准确率 99.2%(经三甲医院实测);
  • Sales Dev Agent:从 LinkedIn 抓取目标客户信息,生成个性化 cold email,打开率 41%(行业平均 22%);
  • Security Pentest Agent:调用 Burp Suite API + Nmap,生成漏洞报告,附修复建议。

每个 agent 都打包成独立 SaaS 产品,按 seat/year 收费。runtime?我们用 AWS AgentCore,成本摊到每个 seat 不到 $0.5/月。

这才是钱流向的地方。当你还在争论“我的 sandbox 启动比 Anthropic 快 120ms”时,别人已经靠 Healthcare Claims Agent 拿下 37 家三甲医院的 PO。

最后说句实在的:Anthropic 的 Managed Agents 是一剂良药,治的是“不想碰 infra”的症状。但它不是解药。真正的解药,是你得清醒地知道——runtime 层的战争已经结束,胜者是云厂商和开源社区;而下一城,在 trace、policy、vertical 的高地上,正等着你插旗。