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 模式,核心就三件事:
- Session ID 是唯一入口:每次用户发起请求,系统生成全局唯一
session_id(如sess_abc123xyz),所有后续操作都绑定此 ID; - 事件写入持久化存储:每一步动作(user message、tool call request、tool response、model output)都以结构化事件(JSONL 格式)写入专用日志库(如 ClickHouse 或专用 OLAP 数据库),带时间戳、trace_id、span_id;
- 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 Agents | AWS 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 实现的沙箱流程:
- 收到 tool call 请求(如
generate_quote); - 从镜像仓库拉取
quay.io/our-org/pdf-generator:v2.3(已预装依赖、无 root 权限、只开放/tmp写入); - 注入 runtime config(含
SESSION_ID,TOOL_CALL_ID,TIMEOUT_MS); - 启动容器,挂载只读的
/app/config和临时的/tmp/output; - 容器内执行二进制,生成 PDF 到
/tmp/output/quote.pdf; - 主机侧
docker cp拷贝文件,docker rm -f清理容器; - 返回 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_id和tool_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 程序;
- 程序 hook
connect()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 Rate | 1 - (failed_sessions / total_sessions) | < 99.5% | 衡量整体健康度,低于此值立即告警 |
| Avg Tool Call Latency | SUM(tool_duration_ms) / COUNT(tool_calls) | > 2500ms | 工具响应慢,可能外部依赖故障 |
| Context Overflow Rate | COUNT(session WHERE context_tokens > 0.8 * model_max) | > 0.1% | 上下文即将溢出,需优化摘要逻辑 |
| Sandbox Crash Rate | COUNT(sandbox_crash) / COUNT(tool_calls) | > 0.05% | 沙箱不稳定,检查镜像或 gVisor 配置 |
| Vault Token Fail Rate | COUNT(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 请求?错。真实世界要处理三次握手:
- Model 说“我要调用 A”(LLM 输出中包含
<tool_use name="A">); - Harness 解析并执行 A(调用外部服务);
- 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 包更新而行为突变。
我们的确定性构建流程:
pip-compile requirements.in生成requirements.txt(含 pinned 版本);- Dockerfile 中
COPY requirements.txt .+RUN pip install -r requirements.txt; - 镜像 tag 用
sha256sum requirements.txt生成(如req-abc123); - 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 的高地上,正等着你插旗。