AI Agent 运行时架构:从 Context 陷阱到事件日志驱动的稳定执行
1. 这不是新赛道,是 runtime 层的“操作系统时刻”来了
你有没有试过让一个 AI 代理连续工作四十分钟?不是闲聊,而是真正在查资料、调 API、写代码、改文档——一环扣一环地推进一个复杂任务。我去年就带着团队跑过这样一个销售线索深度分析 Agent:它要从 CRM 拉客户数据,交叉比对公开财报和新闻,生成定制化 pitch deck,再自动发邮件并追踪打开率。前 35 分钟一切丝滑,第 38 分钟,它突然开始胡说八道:把某家公司的 CEO 名字替换成虚构人物,把刚调用过的财务 API 返回值当成新查询条件反复重试,最后卡死在一封根本没生成完的邮件草稿里。我们翻遍日志,发现 context 窗口早被撑爆了——模型把最开始拉到的客户名单全挤掉了,只记得中间三步的碎片信息,于是它开始“合理编造”。更糟的是,整个 session 没有外部快照,没有事件回放,没有可审计的 trace。我们只能重来,而重来意味着重新支付 token 费用、重新等待 API 延迟、重新触发所有人工审批节点。那一次失败,直接吃掉了我们当周 17% 的推理预算。
Anthropic 在 4 月 8 日发布的Claude Managed Agents,表面看是一次常规功能更新,但内核解决的正是这个“安静却昂贵”的崩溃问题。它把 agent 的“记忆”从模型 context 这个脆弱、易溢出、不可靠的临时缓存里,彻底搬到了一个独立、持久、可查询的事件日志系统中。Session 不再是模型上下文里一段随时可能被覆盖的文本流,而是一个结构化的、带时间戳、带状态标记、带工具调用完整 payload 的 durable log。Harness(执行器)本身是无状态的,它只负责按需拉起沙箱、传入当前 step 的输入、拿到输出、再把结果写回 log。哪怕 harness 进程崩了,只要 sessionId 还在,就能awake(sessionId)继续执行——就像操作系统进程崩溃后,你双击图标还能继续编辑未保存的文档一样自然。
这背后不是炫技,而是对 LLM 应用工程本质的一次正本清源。关键词Towards AI - Medium所代表的这波技术观察者群体,早已看透:当模型能力趋同(Claude 4、GPT-5、Gemini 2.5 在多数任务上差距已缩至 5% 以内),真正的战场就下沉到了 runtime 层——那个决定“你的智能体能不能活过 30 分钟”、“能不能在出错时精准定位到哪一步调用了错误的凭证”、“能不能让法务部一键导出过去三个月所有客户数据访问记录”的底层基础设施。Managed Agents 的发布,不是 Anthropic 在开辟新大陆,而是它终于交出了一份符合生产级标准的“操作系统内核”。它不承诺让你的 agent 更聪明,但它保证,当你的 agent 聪明起来之后,不会因为 infrastructure 的短板而原地爆炸。这才是为什么 Notion、Rakuten、Sentry 这些真实业务场景里的重量级玩家,第一时间就把它接入了核心工作流——他们要的从来不是“又一个能聊天的模型”,而是一个能让智能体像数据库连接池一样稳定、像 Kafka topic 一样可追溯、像 Kubernetes pod 一样可调度的运行时环境。
2. 核心设计拆解:为什么是“Session-as-Event-Log”,而不是“Context-as-Database”
2.1 旧范式之殇:把数据库建在内存里
在 Managed Agents 出现之前,绝大多数自研 agent 系统都遵循一个隐含假设:模型的 context window 就是 agent 的唯一状态存储。开发者会把历史对话、工具返回结果、用户偏好、甚至临时变量,一股脑塞进 system prompt 和 message history 里。这种做法在 demo 阶段很迷人——几行代码就能跑通一个“能订咖啡的 agent”。但一旦进入真实业务,它立刻暴露出三大结构性缺陷:
容量天花板不可逾越:Claude 3.5 Sonnet 的 context 是 200K tokens,听起来很大。但实际使用中,一个包含 5 个 API schema 定义、3 次工具调用返回的 JSON、2 页 PDF 提取文本的 session,轻松就吃掉 80K+。剩下 120K 要留给模型思考、生成、纠错。当任务链超过 12 步,context 就开始“滚动丢弃”——不是优雅截断,而是随机抹掉最早几条消息。我见过最离谱的案例:一个法律合同审查 agent,在第 18 步时把最关键的“甲方违约责任条款”原文给挤没了,模型只能凭模糊印象生成风险提示,结果漏掉了 300 万美元的赔偿上限。
状态不可审计、不可回放:所有状态都混在文本流里,没有 schema,没有版本,没有索引。你想查“昨天下午 3 点,agent 是不是调用了 Stripe API 查询了客户 A 的订阅状态?”答案是:不可能。你只能翻原始日志文件,手动 grep,然后祈祷格式没被模型自己改乱。更致命的是,当 agent 因为 context 溢出开始 hallucinate,你无法区分这是模型逻辑错误,还是状态丢失导致的连锁反应。调试成本呈指数级上升。
安全边界形同虚设:为了“方便”,很多团队会把数据库密码、API key 直接拼进 system prompt,或者作为 environment variable 注入沙箱。模型在生成 tool call 参数时,如果 prompt 工程没做好隔离,它完全可能把
{"api_key": "sk_live_..."}当成普通字符串输出,甚至写进日志。去年某金融科技公司就因此泄露了生产环境 Redis 密钥——根源就是 agent 的 credential management 完全依赖于 prompt 中的“不要泄露”指令,而非架构级隔离。
提示:如果你的 agent 系统目前还把 state 存在 context 里,请立刻停止新增功能开发。这不是优化问题,是架构债务。每多写一行业务逻辑,都在给未来的线上事故埋一颗雷。
2.2 新范式基石:三层解耦的稳定抽象
Anthropic 的 Managed Agents 并非凭空造轮子,而是将过去两年社区实践中验证有效的模式,提炼为一套清晰、稳定、可组合的抽象层。其核心是三个关键组件的严格解耦:
Session(会话)作为事件日志(Event Log):这是整个架构的“真相源”(Source of Truth)。每个 session 对应一个唯一的
sessionId,其生命周期独立于任何计算资源。所有 agent 的行为——用户输入、模型决策、工具调用请求与响应、guardrail 触发、错误堆栈——都被序列化为结构化事件(JSON Schema 定义),按时间顺序追加到该 session 的 log stream 中。这个 log 是持久化、可分页查询、可导出、可设置 TTL 的。它不存储原始二进制数据(如图片),但存储所有元数据和文本摘要,确保审计合规性。Harness(执行器)作为无状态函数:Harness 是纯粹的“搬运工”。它不持有任何 session 数据,只接收
awake(sessionId, nextStep)请求,根据 session log 中的最新状态,决定下一步该调用哪个 tool、传什么参数。它通过execute(name, input) → string接口与沙箱通信,这个接口设计得极其克制——只接受字符串输入,只返回字符串输出,强制所有复杂类型(如 JSON、二进制)必须经过明确的序列化/反序列化。这意味着 harness 可以被任意语言重写(Go、Rust、Python),只要实现这个简单契约即可。它的崩溃不会丢失状态,因为 state 全在 log 里;它的升级无需迁移数据,因为 log schema 是向前兼容的。Sandbox(沙箱)作为一次性 cattle:沙箱是真正执行 tool call 的容器。Managed Agents 采用“按需创建、用完即焚”策略。每次
execute()调用,系统都会拉起一个全新的、隔离的 Linux container(基于 Firecracker microVM),注入本次调用所需的最小权限凭证(从 Vault 动态获取,绝不暴露给 agent 本身),执行代码,捕获 stdout/stderr,然后立即销毁。沙箱之间零共享,零状态残留。这直接解决了 credential 泄露风险——即使模型在 prompt 里疯狂要求“把我的 AWS key 打印出来”,沙箱里根本没有这个环境变量,它只有一份临时的、作用域精确到单次调用的 IAM role credentials。
这三层解耦,复刻了 1990 年代操作系统虚拟化硬件的经典路径:Session Log 如同虚拟内存管理单元(MMU),将物理内存(context window)的碎片化、易失性,抽象为统一、连续、可寻址的逻辑地址空间;Harness 如同 CPU 指令调度器,只关心“下一条指令是什么”,不关心指令数据存在哪块物理内存;Sandbox 如同 I/O 设备驱动,将千差万别的硬件(各种 API、数据库、文件系统)封装成标准化的read/write/execute接口。这种抽象的价值,在于它让上层应用(你的 agent 逻辑)可以无视底层变化——今天用 Claude,明天换 GPT-5,只要 harness 能解析它们的输出格式,session log 的结构就不需要动。
3. 实操落地:从 YAML 定义到生产级部署的完整链路
3.1 定义你的第一个 Managed Agent:YAML 即代码
Managed Agents 最大的生产力提升,来自于它把 agent 的“灵魂”——系统行为、工具集成、安全策略——全部声明化(Declarative)。你不再需要写一堆 Python 脚本来 orchestrate 模型调用、工具路由、错误重试。一切始于一个 YAML 文件。以下是一个为销售团队设计的“客户健康度分析 Agent”的精简版定义(已脱敏):
# sales-health-agent.yaml name: "sales-health-analyzer" description: "Analyzes customer health score by combining CRM data, usage metrics, and support ticket sentiment" system_prompt: | You are a senior sales operations analyst at Acme Corp. Your goal is to assess the health of a customer account and recommend next steps. Use ONLY the tools provided. Never fabricate data. tools: - name: "get_crm_account" description: "Fetches core account data (revenue, contract status, renewal date) from Salesforce" input_schema: type: "object" properties: account_id: type: "string" description: "The unique ID of the Salesforce account" # Credentials for this tool are managed by Anthropic's Vault # No env vars or secrets appear in this YAML - name: "get_usage_metrics" description: "Retrieves product usage statistics (DAU, feature adoption rate) from internal analytics DB" input_schema: type: "object" properties: account_id: type: "string" - name: "analyze_support_sentiment" description: "Analyzes the sentiment of recent support tickets for an account" input_schema: type: "object" properties: account_id: type: "string" days_back: type: "integer" default: 30 guardrails: - type: "pii_redaction" config: fields: ["email", "phone", "address"] mode: "mask" # Replaces with *** - type: "output_validation" config: required_fields: ["health_score", "risk_level", "next_step_recommendation"] schema: type: "object" properties: health_score: type: "number" minimum: 0 maximum: 100 risk_level: type: "string" enum: ["low", "medium", "high", "critical"] next_step_recommendation: type: "string" # Optional: Define fallback behavior if a tool fails fallback_strategy: type: "retry_with_context" max_retries: 2 backoff_seconds: [1, 5]这个 YAML 文件定义了 agent 的全部“契约”:
- What it does(系统提示)
- What it can do(工具列表及输入规范)
- What it must not do(PII 脱敏、输出结构校验)
- How it recovers(工具失败重试策略)
注意:
get_crm_account工具的 credentials 完全不在 YAML 里出现。Anthropic 的后台 Vault 会根据 tool name 自动绑定预配置的、最小权限的 Salesforce 连接器。你在 YAML 里看到的只是一个“能力声明”,而非“密钥注入”。
部署只需一行 CLI 命令(假设你已配置好 Anthropic CLI):
anthropic agents deploy --file sales-health-agent.yaml --environment production系统返回一个唯一的agentId(如agnt-8a3f2b1c...),这就是你后续所有调用的入口。
3.2 启动 Session:从“一次调用”到“持续协作”
启动一个 session,就是开启一段有始有终的智能协作。它不是简单的POST /chat,而是一个状态机的初始化:
# 创建新 session,传入初始用户输入 curl -X POST https://api.anthropic.com/v1/agents/sessions \ -H "x-api-key: $ANTHROPIC_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "agent_id": "agnt-8a3f2b1c...", "user_input": "Analyze health for account ID ACME-2026-001", "metadata": { "source": "salesforce_webhook", "triggered_by": "user_id_12345" } }' # 返回 { "session_id": "sess-9e4d7c2a...", "status": "running" }此时,Managed Agents 后台会:
- 创建一个空的、持久化的 session log stream;
- 启动一个 harness 实例;
- harness 读取 session log(当前只有初始输入),调用
get_crm_account工具; - 系统拉起一个 sandbox,注入 Salesforce 凭证,执行查询;
- 将查询结果(JSON)作为新事件写入 session log;
- harness 读取新事件,决定下一步调用
get_usage_metrics...
整个过程对开发者透明。你只需要关心 session ID。你可以随时用这个 ID 查询当前状态:
# 查询 session 状态和最新事件 curl "https://api.anthropic.com/v1/agents/sessions/sess-9e4d7c2a...?include_events=true&limit=10" # 返回包含所有事件的 JSON,包括 timestamp、event_type、tool_name、input、output、error 等字段实操心得:在生产环境中,我强烈建议你为每个 session 设置
metadata。我们曾用{"pipeline_id": "sales-q4-review"}标记所有季度回顾相关的 session,这样在排查问题时,可以用metadata.pipeline_id = 'sales-q4-review'一键过滤出整条业务线的所有 agent 行为,效率提升十倍。别小看这个字段,它是你未来做 BI 分析的黄金索引。
3.3 生产级运维:监控、告警与成本控制
Managed Agents 的定价模型是$0.08 per session-hour of active runtime,外加标准 Claude token 费用。这里的“active runtime”指 harness 进程实际在 CPU 上执行的时间(毫秒级计费),不包括沙箱启动、网络延迟、工具 API 等待时间。这比按 token 或按请求计费更公平,但也更需要精细化的运维。
我们团队建立了一套最小可行监控体系:
- Session Duration Dashboard:跟踪每个 agent 的平均 session 时长、P95 时长、超时(> 8 小时)率。我们发现,当 P95 时长突破 120 秒,往往意味着某个工具(如慢查询的数据库)成为瓶颈,需要优化。
- Tool Call Success Rate:按 tool name 统计成功率。
get_crm_account成功率低于 99.5%,立刻触发告警——这通常意味着 Salesforce 连接器配置错误或配额耗尽。 - Guardrail Trigger Rate:监控 PII 脱敏、输出校验等 guardrail 的触发频率。如果
output_validation触发率突然飙升,说明 agent 的系统提示或工具 schema 可能需要调整,否则大量 session 会卡在无效输出上。 - Cost Allocation Tagging:利用
metadata字段打标。例如,所有来自 Slack 的请求都带{"channel": "sales-team", "initiator": "slack_user_abc"}。月底导出账单时,可以精确计算出“销售团队”本月在 agent 上花了多少钱,为 ROI 分析提供硬数据。
注意:
$0.08/session-hour看似便宜,但一个长流程 agent(如生成完整报告)可能消耗 3-5 小时 runtime。我们曾因忘记设置max_session_duration(默认无限制),导致一个 debug session 运行了 36 小时,账单直接跳涨 $2.88。现在所有生产 agent 都强制设置max_session_duration: 3600(1 小时),超时自动终止并返回友好错误。
4. 竞争格局与生存法则:为什么 runtime 层注定走向“零价化”
4.1 不是 Anthropic 在开创,而是在防御
媒体标题总爱说“Anthropic 开辟新赛道”,但现实残酷得多:AWS Bedrock AgentCore 在 2025 年底就已 GA(General Availability),比 Managed Agents 早了整整五个月。到 2026 年 3 月,AgentCore SDK 下载量已超 200 万次。它同样提供 microVM 沙箱、8 小时 session、框架无关(LangGraph/CrewAI 全支持)、以及与 AWS IAM 深度集成的凭证管理。Google Vertex AI Agent Builder、Microsoft Azure AI Foundry 也早已发布功能对等的托管 runtime。
这意味着什么?意味着 Anthropic 的 Managed Agents,从诞生第一天起,就不是一个“从 0 到 1”的创新产品,而是一个“从 1 到 N”的防御性产品。它的核心商业逻辑,不是“卖 runtime”,而是“锁住 Claude 的 token 消费”。想象一下:一个企业客户,原本用 LangChain + 自建 Kubernetes 集群跑 Claude agent,现在 AWS 告诉他:“用 AgentCore,免费托管 runtime,token 价格打 9 折,且所有日志自动流入 CloudWatch 和 OpenSearch。” 这个客户会怎么选?他很可能把 runtime 迁到 AWS,但继续用 Claude——直到某天,AWS 宣布“Bedrock Claude Pro”版本上线,性能更强、价格更低。
这就是 Anthropic 必须回答的问题:如果我不提供 Managed Agents,我的 token 客户会不会轻易地把 agent runtime 搬到 AWS/Google/Microsoft 上,然后在那个 runtime 里,无缝切换成 GPT-5 或 Gemini?答案几乎是肯定的。所以 Managed Agents 的本质,是一张“Claude 专属 runtime 会员卡”,目的是让客户在享受便利的同时,更深地绑定在 Anthropic 的生态里。
4.2 历史的镜像:VMware 的兴衰启示录
Anthropic 的工程师博客里,反复强调“OS 类比”——session、harness、sandbox 如同虚拟内存、CPU 调度、设备驱动。这个类比非常精准,但博客刻意回避了一个关键事实:历史上,所有成功的“虚拟化层”最终都走向了 commoditization(商品化)。
VMware 在 1999 年推出 ESX,一度是 x86 虚拟化的代名词,售价高达数万美元/主机。它构建了巨大的商业帝国。但历史的车轮滚滚向前:
- 2003 年,开源 Xen 项目发布;
- 2007 年,KVM(Kernel-based Virtual Machine)被合并进 Linux 内核,成为免费、高性能的替代方案;
- 2010 年代,AWS/GCP/Azure 将虚拟化作为云服务的“默认基座”,不再单独收费;
- 到 2020 年代初,企业新部署中,开源 hypervisor 占比已达 70%。VMware 依然活着,但增长停滞,价值重心早已上移到 vRealize(配置管理)、Tanzu(Kubernetes 平台)等更高层。
Managed Agents 正站在同样的岔路口。它的“hypervisor”角色,正被三股力量快速侵蚀:
- Hyperscaler 的“免费捆绑”:AWS 不需要把 AgentCore 卖得比 Anthropic 便宜,它只需要让它“足够好、足够快、足够安全”,并将其深度集成到现有云账单中。客户采购时,不会为“runtime”单独立项,它只是“我买 AWS 的一部分”。
- 开源压力的加速形成:Daytona(2025 年初转型 AI infra,2400 万美元 A 轮)、Kubernetes SIG 的官方 agent-sandbox 项目、ByteDance 的 deer-flow(59,000+ GitHub stars),都在提供 sub-90ms 沙箱启动、可自定义 harness、开放 log schema 的方案。它们不追求“比 Anthropic 更好”,只追求“足够好,且免费、可控、可审计”。
- 垂直场景的“绕过”:Salesforce 的 Agentforce 不是 runtime,而是预装了 CRM、Service Cloud、Marketing Cloud 集成的“开箱即用 agent 套件”。客户买的是“销售线索自动跟进”,不是“一个能跑 agent 的服务器”。它天然绕过了通用 runtime 层。
我个人在实际操作中的体会是:当你在 2026 年评估一个 agent infra 初创公司时,问的第一个问题不该是“你们的 sandbox 启动速度多少毫秒?”,而应该是“如果 AWS 明年宣布 AgentCore 免费,且性能提升 20%,你们的核心壁垒还剩什么?”。如果答案还是“我们的 runtime 更快/更稳”,那它大概率是下一个 VMware 2008——能活,但难有爆发性增长。
4.3 价值上移:钱流向哪里?Trace、Governance、Vertical Marketplace
当 runtime 层不可避免地滑向“零价化”,价值必然向上迁移。目前,三条清晰的价值高地已经浮现:
4.3.1 Trace Store:谁拥有“agent 行为的真相”
Runtime 可以免费,但“agent 到底干了什么”这个记录,无法免费。一个金融风控 agent 调用了多少次征信 API?一个医疗诊断 agent 查阅了哪些文献?这些 trace 不是日志,而是法律意义上的证据链。Braintrust(150M 美元估值)、Arize(131M 美元融资)、LangSmith(LangChain 生态默认)正在争夺这个“系统记录权”。
它们的竞争焦点,不是 dashboard 多漂亮,而是trace portability。你能把一个在 Anthropic Managed Agents 上跑的 session log,无缝导入 Arize 进行分析吗?你能把 AWS AgentCore 的 trace,一键迁移到 Brainstore 做合规审计吗?目前都不能。这是一个尚未解决的“SQL 标准”问题。谁先定义并推广 open trace schema(如 OpenTelemetry for Agents),谁就掌握了通往上层应用的钥匙。
4.3.2 Governance & Policy:企业的“agent 宪法”
当 agent 开始修改生产数据库、签署电子合同、处理 PII 数据,企业法务和安全部门坐不住了。他们需要回答:
- 这个 agent 被允许做什么?(Policy:只能读取,不能写入)
- 谁批准了这个权限?(Approval Workflow:CTO 审批)
- 如何证明它确实遵守了?(Audit Trail:每一次 tool call 都有签名和 timestamp)
AWS AgentCore 在 2026 年 3 月 GA 的 Policy Controls,就是这个需求的直接回应。OWASP Agentic Top 10 的发布,则标志着行业共识正在形成。这是一个全新的 SaaS 类别:Agentic Governance Platform。它不运行 agent,它监管 agent。它的客户不是开发者,而是 CISO 和合规官。
4.3.3 Vertical Agent Marketplace:为“具体工作”付费
Salesforce Agentforce 在 2026 年 Q4 达到 8 亿美元 ARR,同比增长 169%。这不是因为它的 runtime 多先进,而是因为它卖的是“销售开发代表(SDR)的数字分身”。客户付钱,是因为这个 agent 能识别高意向线索、自动发送个性化 LinkedIn 消息、预约 demo,并且效果可量化(线索转化率提升 X%)。
价值正在从“我能跑 agent”转向“我能帮你完成 XX 工作”。开源社区已经涌现出大量垂直 agent:
virattt/ai-hedge-fund:为对冲基金构建的实时市场情绪分析与交易信号生成 agent;vxcontrol/pentagi:红队使用的自动化渗透测试 agent,能自主发现漏洞、编写 exploit、生成报告;TradingAgents:面向散户的、合规的股票/加密货币交易辅助 agent。
这些 agent 的成功,不依赖于底层 runtime 的品牌,而依赖于它对垂直领域知识的深度编码、对工作流的精准理解、以及与现有 SaaS(如 Bloomberg Terminal、Jira)的无缝集成。它们才是未来十年价值创造的主战场。
5. 常见问题与实战排坑指南
5.1 “Session 为什么卡在 ‘waiting_for_tool’ 状态?”
现象:调用awake(sessionId)后,session 状态长时间停留在waiting_for_tool,get_session_events返回的最新事件是{"event_type": "tool_call_requested", "tool_name": "get_crm_account", ...},但后续没有tool_call_completed事件。
排查思路:
- 检查工具配置:登录 Anthropic 控制台,进入该 agent 的
Tools页面,确认get_crm_account的状态是Enabled,且其关联的 Salesforce 连接器Status为Healthy。我们曾因连接器的 OAuth token 过期,导致所有调用静默失败。 - 检查沙箱网络:在
Tools配置中,点击Test Connection。如果失败,查看错误详情——常见原因是沙箱的 outbound network policy 未放行 Salesforce 的域名(acme.my.salesforce.com)。 - 检查输入参数:
tool_call_requested事件中的input字段是否符合 schema?例如,account_id是否为字符串?我们遇到过前端传入数字12345,而 schema 要求字符串"12345",导致沙箱内代码解析失败,但错误被静默吞掉。
实操心得:在 agent YAML 的
tools定义中,务必为每个input_schema添加examples字段。这不仅帮助前端开发,更能触发 Anthropic 的输入预校验——如果输入不符合 examples,harness 会在调用沙箱前就返回invalid_input错误,避免无谓的沙箱启动开销。
5.2 “Guardrail 触发了,但 agent 没有按预期 fallback”
现象:设置了output_validationguardrail,当 agent 输出缺少next_step_recommendation字段时,期望它重试或返回错误,但实际 session 却进入了failed状态,且没有重试日志。
原因与解决:
- Guardrail 的
mode选择错误:output_validation默认mode: "fail",即直接终止 session。若要重试,必须显式设置mode: "retry",并在fallback_strategy中定义重试逻辑。 - Fallback 策略未覆盖该 guardrail:
fallback_strategy是全局的,但某些 guardrail(如pii_redaction)有自己的on_failure配置。请仔细阅读文档,确认你配置的 fallback 是针对output_validation的。
修正后的 YAML 片段:
guardrails: - type: "output_validation" config: required_fields: ["health_score", "risk_level", "next_step_recommendation"] # ... schema ... mode: "retry" # 关键!改为 retry 模式 fallback_strategy: type: "retry_with_context" max_retries: 2 backoff_seconds: [1, 5] # 此策略将应用于所有 mode="retry" 的 guardrail5.3 “如何调试沙箱内代码?日志看不到任何输出”
现象:在get_usage_metrics工具的沙箱代码中,写了console.log("Fetching metrics for:", accountId),但在get_session_events返回的tool_call_completed事件中,stdout字段为空。
原因:Managed Agents 的沙箱默认只捕获stdout和stderr的最终输出,不捕获运行时的console.log。它期望沙箱程序是一个“函数式”程序:接收 stdin(JSON 输入),处理,然后将结果 JSON 写入 stdout。
正确调试方式:
- 在沙箱代码中,将调试信息写入 stderr(而非 stdout),因为 stderr 的内容会被完整捕获并存入 event 的
stderr字段。 - 确保最终输出是合法 JSON:沙箱的
stdout必须是单行、合法的 JSON 字符串。任何额外的console.log输出到 stdout 都会导致解析失败,整个调用失败。
沙箱代码(Node.js 示例):
// 正确:调试信息走 stderr,结果走 stdout const input = JSON.parse(await readStdin()); console.error("DEBUG: Received input", input); // 这行会出现在 event.stderr 中 const result = await fetchMetrics(input.account_id); console.error("DEBUG: Fetched result", result); // 这行也会出现在 event.stderr 中 process.stdout.write(JSON.stringify(result)); // 这行是最终输出,必须是纯 JSON5.4 “Session 运行了 10 小时,但 billing 显示只有 0.5 小时?”
现象:一个 session 的created_at和ended_at时间差为 10 小时,但账单上session_hours只有 0.5。
解释:这完全正常,且是 Managed Agents 的核心优势。session_hours计费的是 harness 进程实际在 CPU 上执行的时间(active compute time),不包括:
- 沙箱启动/销毁时间(约 100-200ms);
- 网络 I/O 等待时间(如调用外部 API 的 2 秒延迟);
- Harness 空闲等待时间(如等待用户输入、等待异步 webhook 回调)。
一个典型的分析型 agent,大部分时间花在等待 API 响应上,真正占用 CPU 的时间(模型推理、JSON 解析、逻辑判断)可能只有总时长的 5%。所以 10 小时 session 只收 0.5 小时费用,恰恰说明它高效地利用了资源,没有为“等待”付费。
最后再分享一个小技巧:如果你的 agent 需要处理大量异步任务(如并发调用 10 个 API),不要在单个 harness 中用
Promise.all。这会让 harness 长时间阻塞在等待上,增加session_hours。更好的做法是,让 harness 每次只发起 1-2 个并发调用,然后sleep等待,再唤醒继续。这样session_hours会显著降低,而总 wall-clock time 几乎不变。
