<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>阿里云 on 扎塔-Zata</title><link>https://www.zata.cc/tags/%E9%98%BF%E9%87%8C%E4%BA%91/</link><description>Recent content in 阿里云 on 扎塔-Zata</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><copyright>Example Person</copyright><lastBuildDate>Mon, 21 Sep 2026 23:43:31 +0800</lastBuildDate><atom:link href="https://www.zata.cc/tags/%E9%98%BF%E9%87%8C%E4%BA%91/index.xml" rel="self" type="application/rss+xml"/><item><title>E2B 迁到阿里云云沙箱：能跑通，但别急着上生产</title><link>https://www.zata.cc/p/e2b-%E8%BF%81%E5%88%B0%E9%98%BF%E9%87%8C%E4%BA%91%E4%BA%91%E6%B2%99%E7%AE%B1%E8%83%BD%E8%B7%91%E9%80%9A%E4%BD%86%E5%88%AB%E6%80%A5%E7%9D%80%E4%B8%8A%E7%94%9F%E4%BA%A7/</link><pubDate>Mon, 21 Sep 2026 19:00:00 +0800</pubDate><guid>https://www.zata.cc/p/e2b-%E8%BF%81%E5%88%B0%E9%98%BF%E9%87%8C%E4%BA%91%E4%BA%91%E6%B2%99%E7%AE%B1%E8%83%BD%E8%B7%91%E9%80%9A%E4%BD%86%E5%88%AB%E6%80%A5%E7%9D%80%E4%B8%8A%E7%94%9F%E4%BA%A7/</guid><description>&lt;img src="https://www.zata.cc/p/e2b-%E8%BF%81%E5%88%B0%E9%98%BF%E9%87%8C%E4%BA%91%E4%BA%91%E6%B2%99%E7%AE%B1%E8%83%BD%E8%B7%91%E9%80%9A%E4%BD%86%E5%88%AB%E6%80%A5%E7%9D%80%E4%B8%8A%E7%94%9F%E4%BA%A7/images/index/index.svg" alt="Featured image of post E2B 迁到阿里云云沙箱：能跑通，但别急着上生产" />&lt;p>写《Agent 沙箱选型指南》那篇时，我把 E2B 放在「要做 Code Interpreter 就优先试」那一档。文章发出去以后有人在评论里追问：国内有没有对应的方案，网络和合规能不能绕过去。&lt;/p>
&lt;p>当时我的回答挺敷衍的，大意是自托管虽然开源，但底下压着 Firecracker、快照、调度、对象存储和一整套控制面，不是周五下午 &lt;code>docker compose up&lt;/code> 一下就能收工的。&lt;/p>
&lt;p>后来才发现，阿里云函数计算（FC）已经把这件事做完了，而且做法相当取巧。&lt;/p>
&lt;p>&lt;strong>它没有另起一套 SDK，而是直接兼容了 E2B 的数据面协议。&lt;/strong>&lt;/p>
&lt;p>于是问题就变成了一个特别诱人的形式：已有 E2B 应用，能不能只改几个环境变量就接上去？&lt;/p>
&lt;p>我把一个跑在 E2B 上的小 Runtime 搬了一遍。结论是：&lt;strong>能跑通，而且真的就三个环境变量。但「跑通」和「能上生产」之间，隔着一页清单。&lt;/strong>&lt;/p>
&lt;p>这一页清单才是这篇想讲的东西。&lt;/p>
&lt;blockquote>
&lt;p>本文对应的官方文档共 38 页，逐页的对照表放在最后一节「文档地图」，你可以按需跳转。&lt;/p>
&lt;/blockquote>
&lt;h2 id="一先把它跑起来">一、先把它跑起来
&lt;/h2>&lt;p>对象是阿里云函数计算的&lt;strong>云沙箱（FC Agent Sandbox）&lt;/strong>——面向 AI Agent 和代码执行场景的云端隔离运行环境，按需创建，任务完成后释放。&lt;/p>
&lt;p>它的&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/product-overview-of-fc-agent-sandbox" target="_blank" rel="noopener"
>产品简介&lt;/a>写得挺克制：适合承载「不应该直接运行在业务服务进程内」的任务。举的例子是 AI 生成代码执行、数据分析、自动化脚本、依赖复杂的工具调用、临时 Web 服务。这句话其实已经划出了它的边界——&lt;strong>它不是一个通用计算平台，是一个给不可信代码用的执行槽。&lt;/strong>&lt;/p>
&lt;p>官方把可做的事分成五类：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>场景&lt;/th>
&lt;th>说明&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>运行 Agent 工具&lt;/td>
&lt;td>给 Agent 一个独立执行环境，运行命令、处理文件、调用工具链&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>构建代码解释器&lt;/td>
&lt;td>执行 Python / Shell 等代码，返回 stdout、stderr、文本结果或文件产物&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>处理临时数据任务&lt;/td>
&lt;td>上传数据文件，在 Sandbox 内清洗、转换、分析、生成报告&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>启动临时服务&lt;/td>
&lt;td>在 Sandbox 内起 HTTP 服务或开发服务器，通过端口访问地址调用&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>固化运行环境&lt;/td>
&lt;td>用模板预装依赖、运行时和工具链，减少每次任务的初始化成本&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="核心对象先认一遍">核心对象先认一遍
&lt;/h3>&lt;p>迁移之前值得先花十分钟把这几个对象对上号，因为后面所有的兼容性讨论都是围绕它们展开的：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>对象&lt;/th>
&lt;th>作用&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>Sandbox&lt;/strong>&lt;/td>
&lt;td>一次远端隔离执行环境。创建、用、销毁&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Template&lt;/strong>&lt;/td>
&lt;td>定义 Sandbox 启动时的运行环境（基础镜像、语言运行时、依赖、工具链）&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Commands&lt;/strong>&lt;/td>
&lt;td>在 Sandbox 中执行命令或进程&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Filesystem&lt;/strong>&lt;/td>
&lt;td>管理 Sandbox 内的文件&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Code Interpreter&lt;/strong>&lt;/td>
&lt;td>执行代码片段并在多次执行间保持上下文，常用模板 &lt;code>code-interpreter-v1&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Network&lt;/strong>&lt;/td>
&lt;td>访问 Sandbox 暴露的端口（&lt;code>getHost(port)&lt;/code>）&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Storage&lt;/strong>&lt;/td>
&lt;td>本地文件系统只服务当前任务；长期数据走 NAS / OSS&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>FC Extensions&lt;/strong>&lt;/td>
&lt;td>云上扩展：VPC、OSS 挂载、自定义域名、日志监控、Team 配额&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="先分清teamapi-key-和-ram-权限是三件事">先分清：Team、API Key 和 RAM 权限是三件事
&lt;/h3>&lt;p>这张表建议在看任何配置步骤之前先过一遍，因为它能省掉一段弯路：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>&lt;/th>
&lt;th>Team&lt;/th>
&lt;th>API Key&lt;/th>
&lt;th>RAM 权限策略&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>是什么&lt;/td>
&lt;td>资源隔离单元&lt;/td>
&lt;td>数据面凭据&lt;/td>
&lt;td>控制台 / OpenAPI 的操作授权&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>绑在谁身上&lt;/td>
&lt;td>账号下的资源组&lt;/td>
&lt;td>一个 Team&lt;/td>
&lt;td>RAM 用户 / 用户组 / Role&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>用在哪&lt;/td>
&lt;td>划分项目和环境&lt;/td>
&lt;td>E2B SDK、CLI、兼容 HTTP API&lt;/td>
&lt;td>控制台、OpenAPI&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>在哪里建&lt;/td>
&lt;td>控制台&lt;/td>
&lt;td>控制台&lt;/td>
&lt;td>RAM 控制台&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>Team 是「项目 × 环境」的边界&lt;/strong>，不是随便起的名字。Template、Sandbox、API Key、Volume 全都挂在 Team 下面，共用一个 Team 就等于这些资源互相全都可见，所以官方建议不同项目、测试和生产各用一个 Team，资源组则留给部门当边界。&lt;/p>
&lt;p>然后是这次真正卡住我的地方。&lt;/p>
&lt;p>&lt;strong>我一开始以为要跑通沙箱，得先把 RAM 权限配齐。&lt;/strong> 这个判断是错的——但我错得挺有迷惑性，因为它「看起来」更安全。官方在&lt;a class="link" href="https://help.aliyun.com/zh/agent-sandbox/getting-started/configure-ram-user-permissions" target="_blank" rel="noopener"
>配置 RAM 用户权限&lt;/a>里把两套鉴权分得很干脆：&lt;/p>
&lt;blockquote>
&lt;p>通过 E2B SDK、E2B CLI 或兼容 HTTP API 创建和访问 Sandbox 时，使用 API Key，不需要配置 RAM 权限。&lt;/p>
&lt;/blockquote>
&lt;p>再换个说法：&lt;strong>RAM 权限管控制台和 OpenAPI，API Key 管数据面。&lt;/strong> RAM 权限能让你在控制台管 Team、管 API Key、管 Volume；但你想创建一个 Sandbox 并往里跑代码，只认 API Key。文档的「常见误区」里专门点了这一条——&lt;strong>混淆 RAM 权限和 API Key&lt;/strong>。&lt;/p>
&lt;p>顺带一句，这份文档现在挂在 &lt;code>help.aliyun.com/zh/agent-sandbox/&lt;/code> 下（产品名从「云沙箱」往「智能体沙箱 Agent Sandbox」上靠了），旧链接仍然能打开，但搜的时候别只按老名字搜。&lt;/p>
&lt;p>&lt;strong>但如果你确实要用 OpenAPI 建模板，就会撞上我撞的那面墙。&lt;/strong>&lt;/p>
&lt;p>我在 RAM 控制台里翻权限策略，按 &lt;code>fcsandbox&lt;/code> 搜，什么都搜不到；换「服务」下拉列表一个个翻，也没有。第一反应是「是不是我的账号权限太小，看不见这一项」——不是。&lt;/p>
&lt;p>&lt;strong>原因很朴素：&lt;code>fcsandbox&lt;/code> 不在可视化编辑器的服务下拉列表里。&lt;/strong> 那个列表只收录注册过 RAM 元数据的服务，这个新产品没进去。而 RAM 创建策略时&lt;strong>并不校验 action 白名单&lt;/strong>——你写什么它就存什么。所以正路是根本不要走可视化编辑：&lt;/p>
&lt;ol>
&lt;li>RAM 控制台 → 权限策略 → 创建权限策略&lt;/li>
&lt;li>编辑方式选 &lt;strong>脚本编辑&lt;/strong>，不要选可视化编辑&lt;/li>
&lt;li>手写 JSON&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;Version&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;1&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;Statement&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;Effect&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Allow&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;Action&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;fcsandbox:*&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;Resource&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;*&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这一份是「管理账号下全部 Agent Sandbox 资源」，不含函数计算或其他云服务权限。想收紧到指定地域，&lt;code>Resource&lt;/code> 改成 &lt;code>acs:fcsandbox:&amp;lt;region&amp;gt;:&amp;lt;account-id&amp;gt;:*&lt;/code>。&lt;/p>
&lt;p>&lt;code>Action&lt;/code> 的命名规则是 &lt;code>fcsandbox:&amp;lt;接口名&amp;gt;&lt;/code>——你要找的「建模板、查模板、列模板、删模板」就是这四个字符串，&lt;strong>在控制台里是搜不到的，得直接写进策略&lt;/strong>：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;Action&amp;#34;&lt;/span>&lt;span class="err">:&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;fcsandbox:CreateTemplate&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;fcsandbox:GetTemplate&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;fcsandbox:ListTemplates&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;fcsandbox:DeleteTemplate&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>接口名去哪儿查？去 &lt;a class="link" href="https://api.aliyun.com/document/FCSandbox/2026-05-09/overview" target="_blank" rel="noopener"
>Agent Sandbox 的 OpenAPI 文档&lt;/a>找到业务要调的那个接口，页面上「授权信息」一节会直接告诉你对应的 action 名。&lt;strong>别猜名字&lt;/strong>——写错不会报错，只会在调用时静默变成 403。&lt;/p>
&lt;p>想收紧到单个 Team 的话：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;Resource&amp;#34;&lt;/span>&lt;span class="err">:&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;acs:fcsandbox:cn-beijing:&amp;lt;account-id&amp;gt;:teams/&amp;lt;team-id&amp;gt;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;acs:fcsandbox:cn-beijing:&amp;lt;account-id&amp;gt;:teams/&amp;lt;team-id&amp;gt;/*&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>两条 Resource 都要写，少一条会出那种「看得见但动不了」的怪状态&lt;/strong>（文档专门提醒了这一条）：&lt;code>teams/&amp;lt;team-id&amp;gt;&lt;/code> 是 Team 本身，&lt;code>teams/&amp;lt;team-id&amp;gt;/*&lt;/code> 才是它下面的 Template / Sandbox / API Key。只给前者，用户能看见 Team，但建模板、建 Key 全都失败。&lt;/p>
&lt;p>ARN 的完整形态是 &lt;code>acs:fcsandbox:&amp;lt;region&amp;gt;:&amp;lt;account-id&amp;gt;:&amp;lt;resource-path&amp;gt;&lt;/code>，层级比想象的深一层：&lt;strong>Sandbox 没有带自己 ID 的 ARN&lt;/strong>，它挂在 Template 下面，某个模板创建的沙箱是 &lt;code>teams/&amp;lt;team-id&amp;gt;/templates/&amp;lt;template-id&amp;gt;/*&lt;/code>。所以「只允许用某个模板」这种粒度是能做出来的。&lt;/p>
&lt;p>还有一条：&lt;strong>&lt;code>fcsandbox&lt;/code> 没有配套的系统策略，只能自定义。&lt;/strong> 如果你在「系统策略」里也搜不到，那是对的，不是漏配了什么。文档在「常见误区」里也点名了别图省事挂 &lt;code>AdministratorAccess&lt;/code>——那会把函数计算和其他云服务的权限一起给出去。&lt;/p>
&lt;p>所以回到开头：&lt;strong>先确认你走哪条路。&lt;/strong> 只是拿 SDK / CLI 跑沙箱，这一节可以整段跳过，去控制台建 Team 和 API Key 就行；要在 OpenAPI 侧管 Team、Template、API Key 或 Volume，才需要上面这段策略。两种都做的话，记住它俩是&lt;strong>平行的两套凭据&lt;/strong>，权限模型、轮换节奏和泄露影响面都不一样。&lt;/p>
&lt;h3 id="前置先把-api-key-建出来">前置：先把 API Key 建出来
&lt;/h3>&lt;p>这一步没有捷径，必须去控制台。按&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/create-api-key" target="_blank" rel="noopener"
>创建 API Key&lt;/a>的步骤，创建时有两个字段要填：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>描述&lt;/strong>：用来标识用途（开发环境 / 生产环境 / 某个应用 / 某个团队）。文档特别点了一句「不要只写 &lt;code>test&lt;/code> 或 &lt;code>default&lt;/code>」——因为后面要按描述筛 Key。&lt;/li>
&lt;li>&lt;strong>过期时间&lt;/strong>：可以选永不过期，也可以自定义。&lt;strong>生产环境建议设明确的过期时间并建立轮换机制。&lt;/strong>&lt;/li>
&lt;/ul>
&lt;p>创建完把完整 Key 复制出来存好。那句「不要写入代码仓库、镜像、模板、日志、截图、工单或前端页面」我不重复了，只说一个容易忽略的：&lt;strong>不要写进模板&lt;/strong>——模板是会被复用和分发的。&lt;/p>
&lt;p>Key 的管理操作有四个：编辑（改描述、改过期时间、启停）、&lt;strong>重置&lt;/strong>（生成新值，旧值立刻失效，用旧值的应用会认证失败）、删除（必须先禁用，建议禁用后观察一段时间再删）。&lt;/p>
&lt;h3 id="三个环境变量">三个环境变量
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">export&lt;/span> &lt;span class="nv">E2B_API_KEY&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;&amp;lt;your-api-key&amp;gt;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">export&lt;/span> &lt;span class="nv">E2B_API_URL&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;https://api.&amp;lt;region&amp;gt;.e2b.fc.aliyuncs.com&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">export&lt;/span> &lt;span class="nv">E2B_DOMAIN&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;&amp;lt;region&amp;gt;.e2b.fc.aliyuncs.com&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>关于这三个变量，有几件事值得单独说清楚（&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/e2b-sdk-integration-parameter-description" target="_blank" rel="noopener"
>接入参数说明&lt;/a>里有完整对应关系）：&lt;/p>
&lt;p>&lt;strong>第一，SDK 会自动读它们。&lt;/strong> 所以你会看到官方示例里有的显式传参、有的什么都不传——两种都对。显式传参的好处是排查时一眼能看到连的是哪个 endpoint，我在迁移阶段是坚持显式传的。&lt;/p>
&lt;p>&lt;strong>第二，&lt;code>E2B_API_URL&lt;/code> 和 &lt;code>E2B_DOMAIN&lt;/code> 必须显式配置。&lt;/strong> 官方 E2B 的示例代码通常不写这两个，因为默认就走 E2B 自己的服务。云沙箱是 FC 侧提供的&lt;strong>兼容端点&lt;/strong>，不配就是连到 E2B 官方去了——你的阿里云 Key 在那边自然认不出来。&lt;/p>
&lt;p>&lt;code>E2B_API_URL&lt;/code> 是 SDK 访问云沙箱 API 的地址，&lt;code>E2B_DOMAIN&lt;/code> 是 SDK 拼接沙箱服务访问地址时用的基础域名。两个都要给，因为控制链路和数据链路是分开的。&lt;/p>
&lt;p>&lt;strong>第三，地域必须四处一致。&lt;/strong> &lt;code>E2B_API_URL&lt;/code>、&lt;code>E2B_DOMAIN&lt;/code>、模板、Sandbox，任意一个不在同一账号或同一地域，现象都是「认证失败 / 模板不可见 / 创建失败 / 连接失败」。按&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/usage-constraints-of-fc-agent-sandbox" target="_blank" rel="noopener"
>使用约束&lt;/a>，当前支持这八个：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>地域&lt;/th>
&lt;th>region 值&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>华北 2（北京）&lt;/td>
&lt;td>&lt;code>cn-beijing&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>华东 2（上海）&lt;/td>
&lt;td>&lt;code>cn-shanghai&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>华东 1（杭州）&lt;/td>
&lt;td>&lt;code>cn-hangzhou&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>华南 1（深圳）&lt;/td>
&lt;td>&lt;code>cn-shenzhen&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>中国（香港）&lt;/td>
&lt;td>&lt;code>cn-hongkong&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>新加坡&lt;/td>
&lt;td>&lt;code>ap-southeast-1&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>美国（弗吉尼亚）&lt;/td>
&lt;td>&lt;code>us-east-1&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>美国（硅谷）&lt;/td>
&lt;td>&lt;code>us-west-1&lt;/code>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>第四，鉴权细节。&lt;/strong> 如果你不走 SDK、直接调数据面 HTTP 接口，API Key 是放在 &lt;code>X-API-KEY&lt;/code> 请求头里的。走 SDK 或 CLI 时，同一个 Key 传给 &lt;code>api_key&lt;/code> 参数或设成 &lt;code>E2B_API_KEY&lt;/code> 就行。&lt;/p>
&lt;h3 id="最小验证python">最小验证：Python
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">os&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">e2b_code_interpreter&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Sandbox&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">require_env&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&amp;gt;&lt;/span> &lt;span class="nb">str&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">value&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">environ&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">strip&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="ne">RuntimeError&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;缺少环境变量: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">value&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">sandbox&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kc">None&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">try&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sandbox&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Sandbox&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">create&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">template&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;code-interpreter-v1&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">api_key&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">require_env&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;E2B_API_KEY&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">api_url&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">require_env&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;E2B_API_URL&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">domain&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">require_env&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;E2B_DOMAIN&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">sandbox&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">commands&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">run&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;python3 -c &lt;/span>&lt;span class="se">\&amp;#34;&lt;/span>&lt;span class="s2">print(&amp;#39;hello from sandbox&amp;#39;)&lt;/span>&lt;span class="se">\&amp;#34;&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">stdout&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">strip&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">finally&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">sandbox&lt;/span> &lt;span class="ow">is&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="kc">None&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sandbox&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">kill&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="最小验证typescript">最小验证：TypeScript
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-typescript" data-lang="typescript">&lt;span class="line">&lt;span class="cl">&lt;span class="kr">import&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="nx">Sandbox&lt;/span> &lt;span class="p">}&lt;/span> &lt;span class="kr">from&lt;/span> &lt;span class="s2">&amp;#34;@e2b/code-interpreter&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">async&lt;/span> &lt;span class="kd">function&lt;/span> &lt;span class="nx">main() {&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">const&lt;/span> &lt;span class="nx">sandbox&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="nx">Sandbox&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">create&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;code-interpreter-v1&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">apiKey&lt;/span>: &lt;span class="kt">process.env.E2B_API_KEY&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">apiUrl&lt;/span>: &lt;span class="kt">process.env.E2B_API_URL&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">domain&lt;/span>: &lt;span class="kt">process.env.E2B_DOMAIN&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">timeoutMs&lt;/span>: &lt;span class="kt">300_000&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">const&lt;/span> &lt;span class="nx">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="nx">sandbox&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">commands&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">run&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;python3 -c \&amp;#34;print(&amp;#39;hello from sandbox&amp;#39;)\&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">result&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">stdout&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">trim&lt;/span>&lt;span class="p">());&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">finally&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">await&lt;/span> &lt;span class="nx">sandbox&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">kill&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">main&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>看到 &lt;code>hello from sandbox&lt;/code>，说明 SDK、API Key、Endpoint、域名和内置模板这五样东西全都通了。&lt;/p>
&lt;h3 id="版本会被钉住">版本会被钉住
&lt;/h3>&lt;p>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/using-the-cloud-sandbox-via-the-sdk" target="_blank" rel="noopener"
>通过 SDK 使用云沙箱&lt;/a>里明说了：&lt;strong>方法名和参数形态以你正在使用的 E2B SDK 版本为准。&lt;/strong> Python 和 TypeScript 的命名风格还不一样。所以「兼容」这两个字是有版本前提的。&lt;/p>
&lt;p>快速入门验证过的固定组合是：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>语言&lt;/th>
&lt;th>安装命令&lt;/th>
&lt;th>运行时要求&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Python&lt;/td>
&lt;td>&lt;code>pip install e2b==2.31.0 e2b-code-interpreter==2.8.1&lt;/code>&lt;/td>
&lt;td>Python 3.10+&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>TypeScript&lt;/td>
&lt;td>&lt;code>npm install e2b@^2.31.0 @e2b/code-interpreter@^2.6.1&lt;/code>&lt;/td>
&lt;td>Node.js 20.18.1+&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>别用 &lt;code>latest&lt;/code>。&lt;/strong> 生产项目应该把 lockfile 提交上去，升级依赖后重新跑一遍验证脚本。&lt;/p>
&lt;p>还有一个具体的差异必须记住：&lt;strong>Python 的参数是 snake_case，TypeScript 是 camelCase。&lt;/strong> Python 是 &lt;code>api_key&lt;/code> / &lt;code>api_url&lt;/code>，TypeScript 是 &lt;code>apiKey&lt;/code> / &lt;code>apiUrl&lt;/code>；Python 的 &lt;code>timeout&lt;/code> 单位通常是&lt;strong>秒&lt;/strong>，TypeScript 的 &lt;code>timeoutMs&lt;/code> 是&lt;strong>毫秒&lt;/strong>。排查时以当前语言 SDK 的类型定义为准，别把另一个语言的字段名复制过来——这种错不报错，只是悄悄用了默认值。&lt;/p>
&lt;p>顺带一句：&lt;code>E2B_ACCESS_TOKEN&lt;/code> 是 E2B 已经废弃的旧认证变量。新版本 CLI 和 SDK 统一用 &lt;code>E2B_API_KEY&lt;/code>。如果旧版 CLI 还在要求那个变量，先升级 CLI 再重试。&lt;/p>
&lt;h2 id="二这套兼容比我想的更深">二、这套兼容比我想的更深
&lt;/h2>&lt;p>一开始我以为所谓「兼容」就是照着 E2B 的接口抄了一遍，包一层自家 API。&lt;/p>
&lt;p>不是的。&lt;strong>它兼容的是 E2B 的数据面协议。&lt;/strong> 这句话的分量在于：只要协议对得上，第三方完全可以自己写 SDK。&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/e2b-sdk-integration-parameter-description" target="_blank" rel="noopener"
>接入参数说明&lt;/a>里写得很清楚：云沙箱数据面以兼容 E2B SDK / CLI 为主，&lt;strong>未提供独立的数据面 SDK&lt;/strong>；而 Team、API Key、Quota 这些&lt;strong>控制面资源&lt;/strong>可以走原生 OpenAPI、阿里云 SDK 或阿里云 CLI。&lt;/p>
&lt;p>阿里云函数计算团队就顺手把 Java 和 Go 的 SDK 写了——因为 E2B 官方只出 Python 和 TypeScript。见 &lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/e2b-sdk-java-and-go" target="_blank" rel="noopener"
>E2B SDK（Java 与 Go）&lt;/a>：&lt;/p>
&lt;ul>
&lt;li>Java：&lt;a class="link" href="https://github.com/aliyun-fc/e2b-java-sdk" target="_blank" rel="noopener"
>aliyun-fc/e2b-java-sdk&lt;/a>&lt;/li>
&lt;li>Go：&lt;a class="link" href="https://github.com/aliyun-fc/e2b-go-sdk" target="_blank" rel="noopener"
>aliyun-fc/e2b-go-sdk&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>两个都还处于「以源码形式提供」的阶段，接入方式有点原生态：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-xml" data-lang="xml">&lt;span class="line">&lt;span class="cl">&lt;span class="c">&amp;lt;!-- Java：2.1.0 还没发到 Maven Central，得先克隆并 mvn clean install 到本地仓库 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;dependency&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;groupId&amp;gt;&lt;/span>com.alibaba.serverless&lt;span class="nt">&amp;lt;/groupId&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;artifactId&amp;gt;&lt;/span>e2b-java-sdk&lt;span class="nt">&amp;lt;/artifactId&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;version&amp;gt;&lt;/span>2.1.0&lt;span class="nt">&amp;lt;/version&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;/dependency&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git clone https://github.com/aliyun-fc/e2b-java-sdk.git
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> e2b-java-sdk
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">mvn clean install -DskipTests
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Go：go.mod 里声明的还是旧模块路径 github.com/e2b-dev/e2b-go-sdk，&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 该路径已经取不到了，得用 replace 指到本地目录&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git clone https://github.com/aliyun-fc/e2b-go-sdk.git
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> myapp
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">go mod edit -replace&lt;span class="o">=&lt;/span>github.com/e2b-dev/e2b-go-sdk&lt;span class="o">=&lt;/span>../e2b-go-sdk
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Go 这边有个细节挺反直觉：&lt;strong>虽然有本地替换，import 路径仍然要写旧模块路径&lt;/strong>，才能和 SDK 当前 &lt;code>go.mod&lt;/code> 的声明对齐。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-go" data-lang="go">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nx">e2b&lt;/span> &lt;span class="s">&amp;#34;github.com/e2b-dev/e2b-go-sdk&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Java 版有个挺讨喜的设计：&lt;code>Sandbox&lt;/code> 实现了 &lt;code>AutoCloseable&lt;/code>，退出 &lt;code>try&lt;/code> 块就自动 &lt;code>kill()&lt;/code>。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-java" data-lang="java">&lt;span class="line">&lt;span class="cl">&lt;span class="n">ConnectionConfig&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">config&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">ConnectionConfig&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">builder&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">apiKey&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">getenv&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;E2B_API_KEY&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">apiUrl&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">getenv&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;E2B_API_URL&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">domain&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">getenv&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;E2B_DOMAIN&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">build&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">try&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Sandbox&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">sandbox&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Sandbox&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">create&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;code-interpreter-v1&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">config&lt;/span>&lt;span class="p">))&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">CommandResult&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">sandbox&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">getCommands&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="na">run&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="s">&amp;#34;python3 -c \&amp;#34;print(&amp;#39;hello from sandbox&amp;#39;)\&amp;#34;&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">out&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="na">getStdout&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="na">trim&lt;/span>&lt;span class="p">());&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Go 版则是 &lt;code>defer sandbox.Kill(...)&lt;/code>。两边都在用语言本身的机制替你兜住「忘记释放」这件事——这其实是一个挺重要的信号：&lt;strong>写这两个 SDK 的人知道，真正的生产事故里，「忘了 kill」比「调不通接口」更常见。&lt;/strong>&lt;/p>
&lt;p>但官方也提示了一句：&lt;strong>两个 SDK 实现的是 E2B 数据面协议，接口和默认值与 Python / TypeScript 并不完全一致。&lt;/strong> 协议兼容不等于 API 表面对齐，接入前还是得看各自仓库的版本说明。&lt;/p>
&lt;h2 id="三一页清单什么能用什么别用">三、一页清单：什么能用，什么别用
&lt;/h2>&lt;p>这是我建议在动手之前先读完的东西——&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/e2b-compatibility-explanation" target="_blank" rel="noopener"
>E2B 兼容说明&lt;/a>。它把能力分成四档，其中最有价值的不是「兼容」，而是后面三档。&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>能力模块&lt;/th>
&lt;th>状态&lt;/th>
&lt;th>关键说明&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Sandbox&lt;/td>
&lt;td>兼容&lt;/td>
&lt;td>创建、连接、查询、超时、终止、上传下载地址、端口访问；&lt;strong>暂停/恢复与 Snapshot 需白名单&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Commands&lt;/td>
&lt;td>兼容&lt;/td>
&lt;td>命令执行、进程管理、标准输入、PTY&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Filesystem&lt;/td>
&lt;td>部分兼容&lt;/td>
&lt;td>读写、目录管理、重命名、删除、存在性检查、目录监听；&lt;strong>不支持文件自定义元数据&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Code Interpreter&lt;/td>
&lt;td>兼容&lt;/td>
&lt;td>代码执行、上下文管理、流式输出、跨次执行状态保持；&lt;strong>不支持 Java 和 R&lt;/strong>；上下文管理&lt;strong>仅 Python SDK&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Template&lt;/td>
&lt;td>兼容&lt;/td>
&lt;td>模板 CRUD、构建、标签、别名&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>CLI&lt;/td>
&lt;td>部分兼容&lt;/td>
&lt;td>常用 Sandbox / Template 命令&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Metrics&lt;/td>
&lt;td>兼容&lt;/td>
&lt;td>CPU、内存可用；&lt;strong>磁盘/页缓存字段是占位值&lt;/strong>，按 1 分钟粒度&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Logs / Network Config Update&lt;/td>
&lt;td>&lt;strong>受限&lt;/strong>&lt;/td>
&lt;td>接口可调用，但返回结果或实际效果存在限制&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Snapshots&lt;/td>
&lt;td>兼容（需白名单）&lt;/td>
&lt;td>仅第二代运行时可用，默认保留 7 天&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Volume / Access Token&lt;/td>
&lt;td>&lt;strong>暂不兼容&lt;/strong>&lt;/td>
&lt;td>不建议作为接入路径；Team 请在控制台管理&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>方法级的完整清单在 &lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/e2b-sdk-compatible-api-list" target="_blank" rel="noopener"
>E2B SDK 兼容 API 清单&lt;/a>里。下面按模块展开，方便你对着自己的代码库勾一遍。&lt;/p>
&lt;h3 id="sandbox覆盖了完整生命周期">Sandbox：覆盖了完整生命周期
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">Sandbox.create() 创建
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Sandbox.connect(sandboxId) 连接已有 Sandbox（已暂停时自动恢复）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Sandbox.list() 列出 Sandbox
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Sandbox.getInfo(sandboxId) 查询指定 Sandbox 信息
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sandbox.getInfo() 查询当前 Sandbox 信息
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sandbox.isRunning() 判断是否运行中
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Sandbox.setTimeout(sandboxId, ms) 调整指定 Sandbox 超时
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sandbox.setTimeout(ms) 调整当前 Sandbox 超时
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sandbox.pause() 暂停（需白名单）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sandbox.kill() / Sandbox.kill(id) 终止
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sandbox.uploadUrl(path) 获取上传地址
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sandbox.downloadUrl(path) 获取下载地址
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sandbox.getHost(port) 获取端口访问地址
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>Sandbox.create()&lt;/code> 支持的常用参数（&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/create-a-sandbox" target="_blank" rel="noopener"
>创建沙箱&lt;/a>）：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>参数&lt;/th>
&lt;th>说明&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>template&lt;/code>&lt;/td>
&lt;td>模板名 / 模板 ID / Snapshot ID / 命名 Snapshot 全名&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>timeout&lt;/code> / &lt;code>timeoutMs&lt;/code>&lt;/td>
&lt;td>沙箱超时，Python 秒 / TS 毫秒&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>envs&lt;/code>&lt;/td>
&lt;td>写入沙箱运行环境的环境变量&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>metadata&lt;/code>&lt;/td>
&lt;td>写入沙箱&lt;strong>控制面&lt;/strong>的自定义元数据&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>secure&lt;/code>&lt;/td>
&lt;td>控制端点访问保护强度，见第四节&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>沙箱实例在生命周期内只有三个状态（&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/code-interpreter-v1-template" target="_blank" rel="noopener"
>code-interpreter-v1 模板&lt;/a>）：&lt;code>running&lt;/code>（就绪）、&lt;code>paused&lt;/code>（已暂停，可恢复）、&lt;code>terminated&lt;/code>（已终止）。&lt;/p>
&lt;p>&lt;strong>关于超时&lt;/strong>（&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/timeout" target="_blank" rel="noopener"
>超时&lt;/a>）：可以在创建时设，也可以创建后用 &lt;code>setTimeout()&lt;/code> 调。文档的提醒很短但很实在——设置过短任务会被提前回收，设置过长则增加资源占用和费用风险。以及老规矩：&lt;strong>超时不是释放。&lt;/strong> 任务做完就 &lt;code>kill()&lt;/code>，别指望超时回收，那个窗口期里资源一直在计费。&lt;/p>
&lt;h3 id="commands批处理走-run交互走-pty长任务走后台">Commands：批处理走 run，交互走 pty，长任务走后台
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">sandbox.commands.run() 启动进程并等待结果
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sandbox.commands.list() 列出运行中的进程
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sandbox.commands.connect() 连接到已有进程
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sandbox.commands.sendStdin() 发送标准输入
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sandbox.commands.kill() 终止进程
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>三类任务三种走法（&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/run-the-command" target="_blank" rel="noopener"
>运行命令&lt;/a> / &lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/backend-command" target="_blank" rel="noopener"
>后台命令&lt;/a> / &lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/pty" target="_blank" rel="noopener"
>PTY&lt;/a>）：&lt;/p>
&lt;p>&lt;strong>批处理&lt;/strong>用 &lt;code>commands.run()&lt;/code>，同步拿结果。这是我见过的 95% 场景。&lt;/p>
&lt;p>&lt;strong>后台进程&lt;/strong>加 &lt;code>background=True&lt;/code>，SDK 立刻返回进程对象，之后可以继续访问端口、连接进程或终止进程：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">try&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">process&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">sandbox&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">commands&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">run&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;python3 -m http.server 8000&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">background&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">timeout&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">10&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="mi">60&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">host&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">sandbox&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_host&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">8000&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;https://&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">host&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">running&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">sandbox&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">commands&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">list&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">running&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">process&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">kill&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">finally&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sandbox&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">kill&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这里有个&lt;strong>必须知道的默认值&lt;/strong>：&lt;strong>命令执行超时默认通常只有 60 秒。&lt;/strong> 后台进程不会因为 SDK 调用返回就自动结束，但&lt;strong>仍受命令超时约束&lt;/strong>。所以起个长跑服务而不显式设 &lt;code>timeout&lt;/code> / &lt;code>timeoutMs&lt;/code>，它会在 60 秒后被掐。&lt;/p>
&lt;p>另外文档的建议也值得照做：&lt;strong>需要持续读取输出的任务，用后台进程 + 连接进程，别用长超时的同步命令阻塞主流程。&lt;/strong>&lt;/p>
&lt;p>&lt;strong>交互式终端&lt;/strong>用独立的 &lt;code>sandbox.pty&lt;/code>：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">e2b&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">PtySize&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Sandbox&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">terminal&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">sandbox&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">pty&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">create&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">PtySize&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">rows&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">24&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cols&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">80&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">timeout&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">sandbox&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">pty&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">send_stdin&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">terminal&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">pid&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="sa">b&lt;/span>&lt;span class="s2">&amp;#34;python3 - &amp;lt;&amp;lt;&amp;#39;PY&amp;#39;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">import sys&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">print(sys.stdout.isatty())&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">PY&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">sandbox&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">pty&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">send_stdin&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">terminal&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">pid&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="sa">b&lt;/span>&lt;span class="s2">&amp;#34;exit&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">terminal&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">wait&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">on_pty&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="k">lambda&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">decode&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="n">end&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">exit_code&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>pty.create()&lt;/code> 开一个伪终端会话，TypeScript 用 &lt;code>sendInput()&lt;/code>、Python 用 &lt;code>send_stdin()&lt;/code>，&lt;code>terminal.wait()&lt;/code> 等退出。要断开后重连就保存 &lt;code>terminal.pid&lt;/code>，再用 &lt;code>sandbox.pty.connect(pid)&lt;/code>；窗口大小变了用 &lt;code>resize()&lt;/code>。&lt;/p>
&lt;p>PTY 的取舍文档列得很干脆：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>适合 PTY&lt;/th>
&lt;th>不适合 PTY&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>需要模拟真实终端行为的命令&lt;/td>
&lt;td>只需要稳定解析 stdout/stderr 的批处理&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>工具在非 TTY 环境下会关掉颜色/进度/交互&lt;/td>
&lt;td>需要严格区分 stdout 和 stderr 的任务&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>需要给交互式进程发标准输入&lt;/td>
&lt;td>大量结构化日志输出（PTY 会改格式，解析成本变高）&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>一句话：默认用 &lt;code>commands.run()&lt;/code>，只有命令明确依赖终端行为时才升到 PTY。&lt;/strong> 我见过有人为了「保险」全部走 PTY，结果输出里混进一堆 ANSI 控制字符，正则全废。&lt;/p>
&lt;h3 id="filesystem够用但不要当存储">Filesystem：够用，但不要当存储
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">sandbox.files.list() 列出目录内容
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sandbox.files.exists() 判断路径是否存在
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sandbox.files.getInfo() / get_info() 元信息
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sandbox.files.read() 读文件（默认文本，可读为 bytes / 流）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sandbox.files.write() 写文件（文本 / bytes / 流；TS 支持批量）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sandbox.files.makeDir() / make_dir() 创建目录
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sandbox.files.remove() 删除
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sandbox.files.rename() 移动或重命名
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sandbox.files.watchDir() / watch_dir() 目录监听
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>细节见&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/read-and-write-files" target="_blank" rel="noopener"
>读写文件&lt;/a>。几个实用行为值得记：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>&lt;code>write()&lt;/code> 会自动创建缺失的父目录&lt;/strong>，写入已存在文件时直接覆盖。所以 Python 那边写两个文件其实不用先 &lt;code>make_dir&lt;/code>——官方示例里先建目录只是习惯。&lt;/li>
&lt;li>&lt;strong>TypeScript 支持一次写入多个文件&lt;/strong>，适合把 Agent 生成的代码、测试文件、配置一起丢进去：&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-typescript" data-lang="typescript">&lt;span class="line">&lt;span class="cl">&lt;span class="k">await&lt;/span> &lt;span class="nx">sandbox&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">files&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">write&lt;/span>&lt;span class="p">([&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span> &lt;span class="nx">path&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;/tmp/project/main.py&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">data&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;print(&amp;#39;hello&amp;#39;)\n&amp;#34;&lt;/span> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span> &lt;span class="nx">path&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;/tmp/project/README.md&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">data&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;# Demo\n&amp;#34;&lt;/span> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">]);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>&lt;strong>二进制也支持&lt;/strong>：Python 写 &lt;code>bytes&lt;/code> 和文件对象，读的时候 &lt;code>format=&amp;quot;bytes&amp;quot;&lt;/code>；TypeScript 写 &lt;code>ArrayBuffer&lt;/code>、&lt;code>Blob&lt;/code>、&lt;code>ReadableStream&lt;/code>。&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>目录监听&lt;/strong>是个被低估的能力——等 Agent 输出文件、同步任务产物，比轮询 &lt;code>exists()&lt;/code> 优雅得多。只等单个文件时，可以退回 &lt;code>exists()&lt;/code> 做有限次数轮询。&lt;/p>
&lt;h3 id="code-interpreter核心能力齐全但减法不止一个">Code Interpreter：核心能力齐全，但减法不止一个
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">sandbox.runCode() / run_code()
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sandbox.createCodeContext() / create_code_context()
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sandbox.listCodeContexts() / list_code_contexts()
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sandbox.restartCodeContext() / restart_code_context()
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sandbox.removeCodeContext() / remove_code_context()
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>输出侧有 stdout、stderr、execution count、裸表达式结果，以及 &lt;code>execution.results&lt;/code> 富结果；流式场景下还有 stdout / stderr / 结果回调。&lt;strong>同一 Context 内变量和执行状态会保持&lt;/strong>——这也是 Code Interpreter 和「每次新起一个进程跑脚本」的本质区别。&lt;/p>
&lt;p>但&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/code-interpreter-v1-template" target="_blank" rel="noopener"
>code-interpreter-v1 模板&lt;/a>那页列出的减法比兼容说明里写的更多：&lt;/p>
&lt;p>&lt;strong>一是不支持 Java 和 R。&lt;/strong> &lt;code>language&lt;/code> 参数只认 Python、JavaScript、TypeScript、Bash；&lt;code>run_code&lt;/code> 的 &lt;code>language&lt;/code> 默认是 &lt;code>python&lt;/code>。&lt;/p>
&lt;p>&lt;strong>二是图表只有降级方案。&lt;/strong> 官方原话是「在 Sandbox 内生成图片文件后，通过 Filesystem 或下载 URL 取回」。没有「直接返回一个图片对象」那条路。如果你原来的实现依赖 SDK 直接吐出 png，这里要改。&lt;/p>
&lt;p>&lt;strong>三是上下文管理当前只有 Python SDK 能用。&lt;/strong> 这条我觉得是整页里最容易被忽略的：TypeScript 的 &lt;code>runCode&lt;/code> 能正常执行代码，但 &lt;code>createCodeContext&lt;/code> / &lt;code>listCodeContexts&lt;/code> / &lt;code>restartCodeContext&lt;/code> / &lt;code>removeCodeContext&lt;/code> &lt;strong>当前在本平台不可用&lt;/strong>，需要管理独立上下文只能换 Python SDK。做跨语言迁移的话，这一条会直接把方案卡住。&lt;/p>
&lt;p>&lt;strong>四是 &lt;code>logs.stdout&lt;/code> / &lt;code>logs.stderr&lt;/code> 是字符串列表&lt;/strong>，不是字符串。要 &lt;code>&amp;quot;&amp;quot;.join(...)&lt;/code>（Python）或 &lt;code>.join(&amp;quot;&amp;quot;)&lt;/code>（TypeScript）拼起来才是完整文本。&lt;/p>
&lt;p>&lt;code>run_code&lt;/code> 的主要参数和默认值：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>参数&lt;/th>
&lt;th>说明&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>code&lt;/code>&lt;/td>
&lt;td>要执行的代码&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>language&lt;/code>&lt;/td>
&lt;td>&lt;code>python&lt;/code> / &lt;code>javascript&lt;/code>，未指定默认 &lt;code>python&lt;/code>；&lt;strong>与 &lt;code>context&lt;/code> 互斥&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>context&lt;/code>&lt;/td>
&lt;td>指定在哪个代码上下文执行；&lt;strong>与 &lt;code>language&lt;/code> 互斥&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>timeout&lt;/code> / &lt;code>timeoutMs&lt;/code>&lt;/td>
&lt;td>执行超时，&lt;strong>Python 默认 300 秒，TypeScript 默认 60000 毫秒&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>envs&lt;/code>&lt;/td>
&lt;td>自定义环境变量&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>on_stdout&lt;/code> / &lt;code>onStdout&lt;/code> 等&lt;/td>
&lt;td>流式回调，逐行接收 stdout / stderr / 结果 / 错误&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>执行结果 &lt;code>Execution&lt;/code> 包含：&lt;code>logs&lt;/code>（stdout / stderr 列表）、&lt;code>results&lt;/code>（末表达式结果，含 &lt;code>text&lt;/code> 文本表示）、&lt;code>error&lt;/code>（执行异常）、执行计数（Python &lt;code>execution_count&lt;/code> / TS &lt;code>executionCount&lt;/code>）。&lt;/p>
&lt;p>上下文隔离的行为也很直观：默认上下文里 &lt;code>x = 42&lt;/code> 之后另一个 &lt;code>run_code(&amp;quot;print(x)&amp;quot;)&lt;/code> 能读到；但你 &lt;code>create_code_context()&lt;/code> 出来的独立上下文里定义的变量，默认上下文&lt;strong>读不到&lt;/strong>（会拿到 &lt;code>NameError&lt;/code>）；&lt;code>restart_code_context()&lt;/code> 之后变量被清空。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">ctx&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">sbx&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">create_code_context&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">language&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;python&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cwd&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;/home/user&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">sbx&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">run_code&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;y = 100&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">context&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">ctx&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">sbx&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">run_code&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;print(y)&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">context&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">ctx&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 100&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">sbx&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">run_code&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;print(y)&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># NameError：默认上下文看不到 ctx 的变量&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>create_code_context&lt;/code> 需要指定 &lt;code>language&lt;/code>，&lt;code>cwd&lt;/code> 默认 &lt;code>/home/user&lt;/code>。&lt;code>run_code&lt;/code> 的 &lt;code>context&lt;/code> 参数要传 &lt;code>Context&lt;/code> 对象；&lt;code>restart_code_context&lt;/code> / &lt;code>remove_code_context&lt;/code> 传对象或 ID 字符串都行。&lt;/p>
&lt;p>另外从构建模板的官方脚本里还能看到更细的返回值形态，注意这里&lt;strong>有两个超时参数&lt;/strong>：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">execution&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">sandbox&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">run_code&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;print(&amp;#39;hello&amp;#39;)&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">timeout&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">60&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">request_timeout&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">120&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">stdout&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">join&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">execution&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">logs&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">stdout&lt;/span> &lt;span class="ow">or&lt;/span> &lt;span class="p">[])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">stderr&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">join&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">execution&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">logs&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">stderr&lt;/span> &lt;span class="ow">or&lt;/span> &lt;span class="p">[])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">execution&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">error&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>timeout&lt;/code> 管代码执行，&lt;code>request_timeout&lt;/code> 管这次请求本身。&lt;strong>这两个别混。&lt;/strong> 后面讲 Snapshot 的时候会看到，混了会很贵。&lt;/p>
&lt;h3 id="template-与-cli">Template 与 CLI
&lt;/h3>&lt;p>模板侧支持 CRUD、构建、标签、别名。CLI 侧的兼容表（&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/using-the-cloud-sandbox-via-the-cli" target="_blank" rel="noopener"
>通过 CLI 使用云沙箱&lt;/a>）：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>命令&lt;/th>
&lt;th>状态&lt;/th>
&lt;th>说明&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>sandbox create &amp;lt;template&amp;gt;&lt;/code>&lt;/td>
&lt;td>支持&lt;/td>
&lt;td>创建沙箱并连接交互式终端，&lt;strong>退出终端后自动终止该沙箱&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>sandbox list&lt;/code>&lt;/td>
&lt;td>支持&lt;/td>
&lt;td>默认返回运行中的；可用 &lt;code>--state&lt;/code>、&lt;code>--metadata&lt;/code>、&lt;code>--limit&lt;/code>、&lt;code>--format&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>sandbox kill&lt;/code>&lt;/td>
&lt;td>支持&lt;/td>
&lt;td>按 ID 终止，也支持 &lt;code>--all&lt;/code> 批量终止&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>sandbox connect&lt;/code>&lt;/td>
&lt;td>支持&lt;/td>
&lt;td>连接已有沙箱；&lt;strong>退出终端不会自动终止&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>sandbox exec&lt;/code>&lt;/td>
&lt;td>支持&lt;/td>
&lt;td>在运行中的沙箱内执行命令，输出回到本地终端&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>sandbox metrics&lt;/code>&lt;/td>
&lt;td>支持&lt;/td>
&lt;td>CPU、内存，分钟级粒度&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>template list&lt;/code>&lt;/td>
&lt;td>云沙箱扩展&lt;/td>
&lt;td>E2B 官方 CLI 文档未单独说明该命令&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>&lt;code>create&lt;/code> 和 &lt;code>connect&lt;/code> 在退出终端时的行为是相反的&lt;/strong>，这一点特别容易咬人：&lt;code>e2b sandbox create&lt;/code> 退出就把沙箱杀了，&lt;code>e2b sandbox connect&lt;/code> 退出则留着。调试时用错一个，要么白等一遍启动，要么留下一堆僵尸沙箱在账单上。&lt;/p>
&lt;p>CLI 的安装与配置：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">brew install e2b &lt;span class="c1"># macOS&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">npm i -g @e2b/cli@2.20.0 &lt;span class="c1"># 或者用 npm&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">e2b --version &lt;span class="c1"># 装完先确认版本&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">export&lt;/span> &lt;span class="nv">E2B_API_KEY&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;&amp;lt;your-api-key&amp;gt;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">export&lt;/span> &lt;span class="nv">E2B_API_URL&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;https://api.&amp;lt;region&amp;gt;.e2b.fc.aliyuncs.com&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">export&lt;/span> &lt;span class="nv">E2B_DOMAIN&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;&amp;lt;region&amp;gt;.e2b.fc.aliyuncs.com&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">e2b sandbox list &lt;span class="c1"># 用一条只读命令验证配置&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">e2b template list &lt;span class="c1"># 看当前账号有哪些模板&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>CLI 不固定单一版本，官方建议用最新兼容版本。&lt;strong>如果命令行为和文档不一致，先跑 &lt;code>e2b --version&lt;/code> 和对应命令的 &lt;code>--help&lt;/code>&lt;/strong>，确认本机 CLI 的版本和参数形态，而不是先怀疑文档。&lt;/p>
&lt;h2 id="四五个会静默骗你的坑">四、五个会静默骗你的坑
&lt;/h2>&lt;p>这部分是我觉得最有信息量的。它们有的抛异常、有的不抛，但共同点是：&lt;strong>都不会告诉你「你要的功能其实没生效」。&lt;/strong>&lt;/p>
&lt;h3 id="坑一fileswrite-的-metadata-参数">坑一：&lt;code>files.write()&lt;/code> 的 &lt;code>metadata&lt;/code> 参数
&lt;/h3>&lt;p>云沙箱当前不支持文件自定义元数据。但 SDK 的方法签名&lt;strong>是接受 &lt;code>metadata&lt;/code> 的&lt;/strong>——Python SDK 会在请求发出去之前自己拦下来，报的错长这样（&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/custom-metadata" target="_blank" rel="noopener"
>自定义元数据&lt;/a>）：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">e2b.exceptions.TemplateException:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">File metadata requires envd 0.6.2 or later.
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>原因写得很清楚：Sandbox 当前上报 &lt;code>envd 0.5.2&lt;/code>，而文件自定义元数据需要 &lt;code>envd 0.6.2&lt;/code> 或以上。普通文件读写完全不受影响。&lt;/p>
&lt;p>那页文档还补了一句很关键的：&lt;strong>「升级 SDK 或仅修改 &lt;code>envd&lt;/code> 版本号声明无法绕过限制」&lt;/strong>——该能力需要运行环境完整支持元数据校验、键名小写化和扩展属性持久化。所以这不是一个「等版本」的问题，是后端还没实现。&lt;/p>
&lt;p>顺手澄清一个容易混的概念，这个混淆我自己也犯过：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>&lt;/th>
&lt;th>文件自定义元数据&lt;/th>
&lt;th>Sandbox &lt;code>metadata&lt;/code>&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>挂在哪&lt;/td>
&lt;td>单个文件上&lt;/td>
&lt;td>沙箱控制面&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>写入方式&lt;/td>
&lt;td>&lt;code>files.write(..., metadata=...)&lt;/code>&lt;/td>
&lt;td>&lt;code>Sandbox.create(..., metadata=...)&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>当前可用&lt;/td>
&lt;td>&lt;strong>否&lt;/strong>&lt;/td>
&lt;td>是&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>典型用途&lt;/td>
&lt;td>给文件打业务标签&lt;/td>
&lt;td>标记任务、用户、场景、版本，便于列表过滤和审计&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>控制面 &lt;code>metadata&lt;/code> 的用法是这样的（&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/metadata" target="_blank" rel="noopener"
>元数据&lt;/a>），创建时写、&lt;code>getInfo()&lt;/code> 读，也能用来过滤 &lt;code>Sandbox.list()&lt;/code>：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">sandbox&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Sandbox&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">create&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">template&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;code-interpreter-v1&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">metadata&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;task_id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;task-001&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;agent&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;code-reviewer&amp;#34;&lt;/span>&lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">info&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">sandbox&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_info&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">info&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">metadata&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>有个细节文档专门强调了：&lt;strong>元数据不会自动变成沙箱内的环境变量。&lt;/strong> 如果同一个字段既要管理面可见、又要沙箱内进程能读到，得同时写进 &lt;code>metadata&lt;/code> 和 &lt;code>envs&lt;/code>。&lt;/p>
&lt;p>元数据的取值建议用短字符串，只放可索引的关联 ID。大段上下文、用户隐私、凭证都不要塞进去。&lt;/p>
&lt;p>&lt;strong>那文件标签怎么做？&lt;/strong> 文档给了三条替代路径，我按推荐度排了一下：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>标签存业务库或对象存储&lt;/strong>，用「Sandbox ID + 文件路径」做关联键。这是最干净的。&lt;/li>
&lt;li>&lt;strong>同目录写一个 JSON 清单文件&lt;/strong>，记录文件路径和业务标签。需要跨 Sandbox 保留时，把文件和清单一起写进 NAS / OSS。&lt;/li>
&lt;li>&lt;strong>如果只是想标记 Sandbox 本身&lt;/strong>，直接用控制面 &lt;code>metadata&lt;/code>——但别把它当文件元数据用。&lt;/li>
&lt;/ol>
&lt;h3 id="坑二run_code-用错了-sdk">坑二：&lt;code>run_code&lt;/code> 用错了 SDK
&lt;/h3>&lt;p>这个坑卡了我一会儿。现象是：Sandbox 创建成功，&lt;code>commands.run()&lt;/code> 正常，但 &lt;code>run_code&lt;/code> 就是不行。&lt;/p>
&lt;p>原因是 SDK 装错了。&lt;strong>通用 &lt;code>e2b&lt;/code> SDK 只能使用文件、命令和进程这些基础能力&lt;/strong>——即使你指定了 &lt;code>code-interpreter-v1&lt;/code> 模板，也一样调不了 &lt;code>runCode&lt;/code> / &lt;code>run_code&lt;/code>。&lt;/p>
&lt;p>而这个坑有一半责任在&lt;strong>默认值&lt;/strong>上。官方模板文档列得很清楚：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>SDK&lt;/th>
&lt;th>&lt;code>template&lt;/code> 要不要传&lt;/th>
&lt;th>不传时的默认模板&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>e2b_code_interpreter&lt;/code>（Python）/ &lt;code>@e2b/code-interpreter&lt;/code>（TS）&lt;/td>
&lt;td>&lt;strong>不用传&lt;/strong>&lt;/td>
&lt;td>&lt;code>code-interpreter-v1&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>e2b&lt;/code>（通用）&lt;/td>
&lt;td>&lt;strong>必须传&lt;/strong>&lt;/td>
&lt;td>&lt;strong>&lt;code>base&lt;/code>&lt;/strong>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>通用 SDK 不传模板拿到的是 &lt;code>base&lt;/code>，而 &lt;code>base&lt;/code> 不提供 Code Interpreter 服务。&lt;/strong> 所以「我用通用 SDK + 不指定模板 + 调 run_code」和「我用通用 SDK + 指定 code-interpreter-v1 + 调 run_code」，失败原因其实不同：前者连模板都不对，后者模板对了但 SDK 不对。&lt;/p>
&lt;p>判断顺序也简单：先用内置 &lt;code>code-interpreter-v1&lt;/code> 模板跑通代码执行、命令执行、文件读写。内置模板正常而自定义模板不行，再去查自定义模板的 Code Interpreter 依赖、启动命令、监听端口和就绪条件。&lt;/p>
&lt;h3 id="坑三上传下载-url-需要-securefalse">坑三：上传下载 URL 需要 &lt;code>secure=false&lt;/code>
&lt;/h3>&lt;p>这个坑不报错，但它会让一个「看起来已经写好的」浏览器直传链路在最后一跳 403。见&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/upload-and-download-files" target="_blank" rel="noopener"
>上传和下载文件&lt;/a>。&lt;/p>
&lt;p>&lt;code>sandbox.downloadUrl(path)&lt;/code> 和 &lt;code>sandbox.uploadUrl(path)&lt;/code> 生成的是带签名的访问地址，适合浏览器直传、把结果文件交给未持有 SDK 鉴权信息的环境，或者交给后续系统处理。但文档里有一句加粗的注意：&lt;/p>
&lt;blockquote>
&lt;p>如果要使用 &lt;code>downloadUrl()&lt;/code> 和 &lt;code>uploadUrl()&lt;/code> 返回的 URL 上传下载文件，&lt;strong>确保在创建 Sandbox 时显式设置了 &lt;code>secure=false&lt;/code>&lt;/strong>。否则，通过 URL 上传下载文件仍需要请求方携带 &lt;code>X-Access-Token&lt;/code>。&lt;/p>
&lt;/blockquote>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">sandbox&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Sandbox&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">create&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">...&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">secure&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">False&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>而 &lt;code>secure=false&lt;/code> 的代价文档也写得很直白：&lt;strong>会降低 Sandbox 暴露端点的访问保护强度。&lt;/strong> 所以要配合「控制 Sandbox 生命周期、文件路径、数据敏感性」一起用。&lt;/p>
&lt;p>我自己的取舍是：如果只是后端之间传文件，宁可不省这一下，直接用 &lt;code>files.write()&lt;/code> / &lt;code>files.read()&lt;/code>。只有「浏览器直传」这种真的拿不到 SDK 凭证的场景，才开 &lt;code>secure=false&lt;/code>，并且把路径写死在业务侧、不让它由模型决定。&lt;/p>
&lt;p>选型标准文档给得也挺清楚，直接抄：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>场景&lt;/th>
&lt;th>用什么&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>小文件、文本、二进制、流式内容、Agent 生成代码&lt;/td>
&lt;td>&lt;code>files.write()&lt;/code> / &lt;code>files.read()&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>浏览器直传、下载结果文件、交给无 SDK 鉴权环境&lt;/td>
&lt;td>&lt;code>uploadUrl()&lt;/code> / &lt;code>downloadUrl()&lt;/code> + &lt;code>secure=false&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>目录遍历、重命名、删除&lt;/td>
&lt;td>Filesystem API&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>浏览器直传的接收端用 &lt;code>multipart/form-data&lt;/code>，字段名是 &lt;code>file&lt;/code>：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">requests&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">with&lt;/span> &lt;span class="nb">open&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;input.csv&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;rb&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">f&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">requests&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">post&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">upload_url&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">files&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;file&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">f&lt;/span>&lt;span class="p">})&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">raise_for_status&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>大文件上传后建议用 &lt;code>sandbox.files.exists()&lt;/code> 或命令确认文件可读&lt;/strong>——文档专门提了这句，说明「上传成功但文件不可读」是有过的。&lt;/p>
&lt;h3 id="坑四logs-和-network-config-update">坑四：Logs 和 Network Config Update
&lt;/h3>&lt;p>这两个是官方明确标记为「受限」的：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Sandbox Logs&lt;/strong>：当前返回空数组。&lt;/li>
&lt;li>&lt;strong>Network Config Update&lt;/strong>：当前返回成功，但&lt;strong>不进行实际的网络变更&lt;/strong>。&lt;/li>
&lt;/ul>
&lt;p>官方对它们的定位说得很坦诚——「用于保持 SDK 调用兼容」。所以它们可以留着，让老代码不至于跑挂；但&lt;strong>不能作为生产日志采集或网络治理的控制面依赖&lt;/strong>。接入参数说明那页也把它们列进了「不作为接入参数的能力」。&lt;/p>
&lt;p>第二个尤其阴。返回 &lt;code>success&lt;/code> 的操作什么都不做，这种设计在本地联调时完全看不出来，只有到线上要改网络策略、发现改了没生效的时候才会撞上。&lt;/p>
&lt;p>正路是：&lt;strong>日志走函数计算日志采集 + 日志服务，网络变更走云沙箱控制面&lt;/strong>（&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/monitoring-and-logging" target="_blank" rel="noopener"
>监控与日志&lt;/a>）。而且更进一步——「生产排查应依赖业务侧结构化日志、函数计算日志采集、云监控和日志服务中的数据」。&lt;/p>
&lt;p>配合这个结论，文档给了一段挺实用的日志约定：在业务侧记录 &lt;code>sandbox_created&lt;/code> / &lt;code>command_finished&lt;/code> 这类事件，字段带上 &lt;code>taskId&lt;/code>、&lt;code>sandboxId&lt;/code>、&lt;code>exitCode&lt;/code>、stdout / stderr 摘要，并且&lt;strong>业务系统要保存任务 ID 与 &lt;code>sandboxId&lt;/code> 的映射&lt;/strong>。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">json&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">dumps&lt;/span>&lt;span class="p">({&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;event&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;command_finished&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;taskId&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">task_id&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;sandboxId&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">sandbox&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">sandbox_id&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;exitCode&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">exit_code&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;stdout&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">stdout&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">strip&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;stderr&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">stderr&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">strip&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}))&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>如果希望沙箱内的程序日志也能被日志服务检索，就让程序直接输出结构化 JSON、并带上 &lt;code>sandboxId&lt;/code> 和任务 ID。两条日志流最后在日志服务里能按 &lt;code>taskId&lt;/code> 关联起来。&lt;/p>
&lt;p>&lt;strong>关于日志采集配置，文档提醒了三件事要先确认&lt;/strong>：配置入口（以云沙箱控制台 / 函数计算控制台 / 日志服务为准，控制台没展示入口就联系产品支持）、生效范围（对账号 / 地域 / 模板 / Sandbox / 会话生效，以及是否只影响新建的 Sandbox）、日志目标（Project、Logstore、索引字段、保存时间和费用策略）。第三项最容易被忽略——&lt;strong>日志费用是那种平时不痛、月底很痛的东西&lt;/strong>。&lt;/p>
&lt;h3 id="坑五metrics-的磁盘字段">坑五：Metrics 的磁盘字段
&lt;/h3>&lt;p>&lt;code>e2b sandbox metrics &amp;lt;sandbox-id&amp;gt;&lt;/code> 能看 CPU 和内存，但&lt;strong>磁盘 / 页缓存字段返回的是占位值&lt;/strong>，不能用来判断容量。数据按 1 分钟粒度返回。&lt;/p>
&lt;p>官方给的建议是：计费、告警、容量治理都要以函数计算控制台、云监控或日志服务里的正式数据为准。指标接口适合调试和看趋势，别拿去搭容量大盘——&lt;strong>1 分钟粒度配占位字段，做成大盘只会得到一条看起来很有道理、实际上是假的曲线。&lt;/strong>&lt;/p>
&lt;h2 id="五snapshot-和-pause白名单能力别写进架构">五、Snapshot 和 pause：白名单能力，别写进架构
&lt;/h2>&lt;h3 id="snapshot-比兼容两个字复杂得多">Snapshot 比「兼容」两个字复杂得多
&lt;/h3>&lt;p>我一开始是照「不兼容」处理的，后来翻&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/snapshots" target="_blank" rel="noopener"
>快照（邀测）&lt;/a>发现已经变了。&lt;strong>Snapshots 现在兼容，但要加白名单，而且仅限第二代运行时（&lt;code>micro-sandbox&lt;/code>）。&lt;/strong>&lt;/p>
&lt;p>它的心智模型很好理解：&lt;strong>保存运行中沙箱在某一时刻的文件系统与内存状态，之后用这份快照秒级启动一个同样状态的新沙箱，不必重新构建模板。&lt;/strong> 典型场景就是 Agent 任务断点续跑、环境预热、并行克隆探索。&lt;/p>
&lt;p>几个关键属性：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Snapshot 独立于源沙箱和源模板。&lt;/strong> 删除源沙箱或源模板不会删掉 Snapshot；删 Snapshot 也不会影响它们。创建成功后即使源模板被删，仍能用该 Snapshot 恢复沙箱。&lt;/li>
&lt;li>&lt;strong>默认保留 7 天&lt;/strong>，到期自动过期，过期后不出现在列表里、也不能用于创建沙箱。&lt;/li>
&lt;li>&lt;strong>留存独立于源沙箱生命周期&lt;/strong>——源沙箱终止或超时回收后，未过期的 Snapshot 仍可用。&lt;/li>
&lt;/ul>
&lt;p>API 表（注意 Python 和 TypeScript 的名字差异）：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>操作&lt;/th>
&lt;th>TypeScript&lt;/th>
&lt;th>Python&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>创建&lt;/td>
&lt;td>&lt;code>sandbox.createSnapshot({ name? })&lt;/code> / &lt;code>Sandbox.createSnapshot(sandboxId, { name? })&lt;/code>&lt;/td>
&lt;td>&lt;code>sandbox.create_snapshot(name=...)&lt;/code> / &lt;code>Sandbox.create_snapshot(sandbox_id, name=...)&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>列表&lt;/td>
&lt;td>&lt;code>Sandbox.listSnapshots({ sandboxId?, name?, limit?, nextToken? })&lt;/code>&lt;/td>
&lt;td>&lt;code>Sandbox.list_snapshots(sandbox_id=..., name=..., limit=..., next_token=...)&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>从快照建沙箱&lt;/td>
&lt;td>&lt;code>Sandbox.create(snapshotId | &amp;quot;&amp;lt;TeamName&amp;gt;/&amp;lt;短名&amp;gt;&amp;quot;)&lt;/code>&lt;/td>
&lt;td>&lt;code>Sandbox.create(template=snapshot_id | &amp;quot;&amp;lt;TeamName&amp;gt;/&amp;lt;短名&amp;gt;&amp;quot;)&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>删除&lt;/td>
&lt;td>&lt;code>Sandbox.deleteSnapshot(snapshotId | qualifiedName)&lt;/code>&lt;/td>
&lt;td>&lt;code>Sandbox.delete_snapshot(snapshot_id | qualified_name)&lt;/code>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>实例方法和静态方法语义相同——实例方法隐含当前沙箱，不用再传 ID；&lt;strong>列表和删除只提供静态方法&lt;/strong>。&lt;/p>
&lt;p>返回字段里有两个：&lt;code>snapshotId&lt;/code> / &lt;code>snapshot_id&lt;/code> 是 UUID，创建、删除、恢复时&lt;strong>优先用它&lt;/strong>；&lt;code>names&lt;/code> 是有名快照的全名列表，无名快照是空数组。&lt;strong>两者相互独立&lt;/strong>——全名只出现在 &lt;code>names&lt;/code> 字段和按名解析里，不替代 ID。&lt;/p>
&lt;p>&lt;strong>命名规则是这里最容易踩的地方。&lt;/strong> 全名格式是 &lt;code>&amp;lt;当前 Team 名&amp;gt;/&amp;lt;短名&amp;gt;:&amp;lt;tag&amp;gt;&lt;/code>：&lt;/p>
&lt;ul>
&lt;li>短名和 tag 的规则是 &lt;code>^[_a-zA-Z][-_a-zA-Z0-9]*$&lt;/code>，最长 64，必须以字母或下划线开头。&lt;/li>
&lt;li>Team 名前缀与 Team 展示名相同，最长 32，允许数字开头和空格、点、下划线、连字符（例如默认 Team 的数字名、&lt;code>My Team&lt;/code>）。&lt;/li>
&lt;li>段内不能含 &lt;code>/&lt;/code> 或 &lt;code>:&lt;/code>，所以「含且仅含一个 &lt;code>/&lt;/code> 的字符串」只可能是 Snapshot 全名，不会和模板名冲突。&lt;/li>
&lt;/ul>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>传入的 &lt;code>name&lt;/code>&lt;/th>
&lt;th>结果&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>省略 / 空&lt;/td>
&lt;td>无名，&lt;code>names = []&lt;/code>，只能通过 Snapshot ID 访问&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>deps-ready&lt;/code>&lt;/td>
&lt;td>&lt;code>&amp;lt;当前 Team 名&amp;gt;/deps-ready:default&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>deps-ready:v1&lt;/code>&lt;/td>
&lt;td>&lt;code>&amp;lt;当前 Team 名&amp;gt;/deps-ready:v1&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>demo-team/deps-ready&lt;/code>&lt;/td>
&lt;td>&lt;code>demo-team/deps-ready:default&lt;/code>（前缀必须等于当前 Team 名，大小写不敏感）&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>省略 tag 等价于 &lt;code>default&lt;/code>。同一 Team 内同一个 &lt;code>(短名, tag)&lt;/code> 同时只能存在一份可用 Snapshot，&lt;strong>名称冲突时创建失败，不覆盖已有快照&lt;/strong>，删除后名称立即释放。&lt;strong>Team 没有名字时只能创建无名 Snapshot&lt;/strong>。&lt;/p>
&lt;p>&lt;strong>然后是那个我觉得最实用的坑：请求超时。&lt;/strong>&lt;/p>
&lt;p>创建可能持续数分钟。文档明确建议 &lt;strong>SDK 请求超时不少于 300 秒&lt;/strong>（TypeScript &lt;code>requestTimeoutMs: 300_000&lt;/code>；Python &lt;code>request_timeout=300&lt;/code>）。并且特意点破了那个容易混的点：&lt;/p>
&lt;blockquote>
&lt;p>&lt;code>timeoutMs&lt;/code> / &lt;code>timeout&lt;/code> 控制的是沙箱生命周期，&lt;strong>不是 Snapshot 请求超时&lt;/strong>；默认请求超时通常为 60 秒，不加大时可能在创建完成前失败。&lt;/p>
&lt;/blockquote>
&lt;p>60 秒默认值 + 数分钟的实际耗时 = 一个会间歇性失败的接口。而更麻烦的是它失败之后的处理：&lt;/p>
&lt;blockquote>
&lt;p>创建超时：创建失败，但&lt;strong>服务端可能已建成 Snapshot&lt;/strong>。先增大超时。有名 Snapshot 按 &lt;code>name&lt;/code> 或全名列表确认后再决定是否重试；无名 Snapshot 的 &lt;code>name&lt;/code> 过滤无效，应先按源沙箱 &lt;code>sandboxId&lt;/code> 列表核对；&lt;strong>若已存在目标 Snapshot，直接使用其 ID，不要无条件重试。&lt;/strong>&lt;/p>
&lt;/blockquote>
&lt;p>「不要无条件重试」这六个字是整篇文档里我最想圈出来的一句。它意味着一个朴素的重试装饰器在这里会持续制造垃圾快照，而每一份都在算存储费。&lt;/p>
&lt;p>还有个更隐蔽的：&lt;strong>创建成功后立即调用列表接口，由于索引延迟，可能暂时看不到刚写入的记录。&lt;/strong> 但按 ID 或全名恢复、删除都不受影响，可以直接用创建接口返回的值——所以别用「列表里没有」来判断创建失败。&lt;/p>
&lt;p>失败条件我整理成表：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>条件&lt;/th>
&lt;th>结果&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>源沙箱不存在或不属于当前调用方&lt;/td>
&lt;td>创建失败&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>沙箱运行时不是 &lt;code>MicroVM&lt;/code>&lt;/td>
&lt;td>创建失败&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>名称非法，或全名前缀不是当前 Team 名&lt;/td>
&lt;td>创建失败&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Team 无名却传了 &lt;code>name&lt;/code>&lt;/td>
&lt;td>创建失败&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>同名同 tag 已存在&lt;/td>
&lt;td>创建失败，不覆盖&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>源沙箱已暂停 / 正在创建 Snapshot / 被其他操作占用&lt;/td>
&lt;td>创建失败&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>从 Snapshot 创建时覆盖环境变量、挂载或镜像&lt;/td>
&lt;td>创建失败&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Snapshot 仍被已恢复沙箱占用&lt;/td>
&lt;td>删除失败&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>按全名恢复或删除但 Snapshot 不存在&lt;/td>
&lt;td>失败，&lt;strong>不回退为模板&lt;/strong>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>创建过程中源沙箱的 &lt;code>state&lt;/code> 是 &lt;code>snapshotting&lt;/code>，此时&lt;strong>不能删除该沙箱&lt;/strong>；失败则是 &lt;code>snapshot_failed&lt;/code>，这个状态&lt;strong>默认不出现在沙箱列表里&lt;/strong>，得显式按状态过滤才看得到。这一点挺关键——排查「为什么快照没建出来」时，默认列表里是找不到线索的。失败后源沙箱仍可使用或删除。&lt;/p>
&lt;p>从 Snapshot 创建沙箱时，哪些参数能覆盖也有明确清单：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>允许覆盖&lt;/strong>：超时、空闲超时、&lt;code>secure&lt;/code>、&lt;code>allowInternetAccess&lt;/code>、用户 metadata、&lt;code>autoPause&lt;/code>、&lt;code>autoResume&lt;/code>、网络、自定义沙箱 ID。&lt;/li>
&lt;li>&lt;strong>不允许覆盖（传入即失败）&lt;/strong>：环境变量、卷 / 文件系统挂载、函数配置、构建 / 镜像、&lt;code>fc.&lt;/code> 前缀的系统 metadata。&lt;/li>
&lt;/ul>
&lt;p>以及一个 TS 特有的坑：&lt;strong>&lt;code>listSnapshots&lt;/code> / &lt;code>createSnapshot&lt;/code> / &lt;code>deleteSnapshot&lt;/code> 的静态调用要走环境变量配 &lt;code>E2B_API_URL&lt;/code>，不要传不被支持的 &lt;code>apiUrl&lt;/code> 字段。&lt;/strong>&lt;/p>
&lt;p>最后一条使用建议我觉得挺值得照做：&lt;strong>没用的 Snapshot 及时删，避免持续产生存储费用；能短时暂停就优先用暂停与恢复，不要动不动就快照。&lt;/strong> 7 天保留期是一个「会悄悄花钱」的默认值。&lt;/p>
&lt;h3 id="pause只为短期保留上下文">pause：只为短期保留上下文
&lt;/h3>&lt;p>&lt;code>sandbox.pause()&lt;/code> 同样需要白名单（&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/pause-and-resume" target="_blank" rel="noopener"
>暂停与恢复&lt;/a>）。它的语义是「在一段时间内保留状态，之后连同一个 Sandbox 继续用」。&lt;code>Sandbox.connect(sandboxId)&lt;/code> 连一个已暂停的沙箱时会自动恢复。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">sandbox&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">pause&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 之后&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">sandbox&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Sandbox&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">connect&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sandbox_id&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">api_key&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">environ&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;E2B_API_KEY&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">api_url&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">environ&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;E2B_API_URL&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">domain&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">environ&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;E2B_DOMAIN&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>文档里有三句提醒，我原样保留，因为它们都很容易忽略：&lt;/p>
&lt;ul>
&lt;li>恢复后要&lt;strong>重新确认长连接、进程状态和业务层状态&lt;/strong>是否符合预期。暂停期间那些东西的存活不能想当然。&lt;/li>
&lt;li>&lt;strong>暂停不等于终止。&lt;/strong> 任务完成后仍然要 &lt;code>kill()&lt;/code>。&lt;/li>
&lt;li>对需要短期保留上下文的任务才用暂停，不要拿它替代资源释放。&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>我的整体判断是：白名单能力不要写进架构。&lt;/strong> 白名单是账号级的开关，今天开了明天能关，把它当成设计前提，等于把系统的可用性挂在一个后台配置上。Snapshot 可以当作「运维手段」和「性能优化」，但不要把「断点续跑」做成唯一路径——至少留一条「重建环境」的兜底。&lt;/p>
&lt;h2 id="六模板三个档位和一个必须自己构建的">六、模板：三个档位，和一个必须自己构建的
&lt;/h2>&lt;p>模板是这次迁移里我改动最大的一块。内置模板不是「一堆可选镜像」，而是三个能力档位，而且&lt;strong>默认值会咬人&lt;/strong>。&lt;/p>
&lt;h3 id="内置模板清单">内置模板清单
&lt;/h3>&lt;p>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/built-in-templates" target="_blank" rel="noopener"
>内置模板&lt;/a>一共三个，另有若干需要自行构建：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>模板&lt;/th>
&lt;th>需要构建&lt;/th>
&lt;th>适用场景&lt;/th>
&lt;th>说明&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/base-template" target="_blank" rel="noopener"
>&lt;code>base&lt;/code>&lt;/a>&lt;/td>
&lt;td>否，开通即用&lt;/td>
&lt;td>基础命令、文件访问、SDK 连通性验证&lt;/td>
&lt;td>&lt;strong>不提供 Code Interpreter 服务&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/code-interpreter-v1-template" target="_blank" rel="noopener"
>&lt;code>code-interpreter-v1&lt;/code>&lt;/a>&lt;/td>
&lt;td>否，开通即用&lt;/td>
&lt;td>AI Agent 代码执行、数据分析、文件处理&lt;/td>
&lt;td>快速入门和代码解释器示例默认用它&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/browser-template" target="_blank" rel="noopener"
>&lt;code>browser&lt;/code>&lt;/a>&lt;/td>
&lt;td>&lt;strong>是&lt;/strong>&lt;/td>
&lt;td>浏览器自动化、截图、动态页面抓取&lt;/td>
&lt;td>要从官方 browser 镜像构建&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/all-in-one-template" target="_blank" rel="noopener"
>All-In-One&lt;/a>&lt;/td>
&lt;td>&lt;strong>是&lt;/strong>&lt;/td>
&lt;td>浏览器 + 代码执行协同&lt;/td>
&lt;td>要从官方 all-in-one 镜像构建&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>其他（Desktop、Claude Code、OpenClaw 等）&lt;/td>
&lt;td>&lt;strong>是&lt;/strong>&lt;/td>
&lt;td>桌面环境、编码 Agent&lt;/td>
&lt;td>从对应官方镜像自行构建&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;code>base&lt;/code> 和 &lt;code>code-interpreter-v1&lt;/code> 在账号开通云沙箱后自动就绪，直接用模板名创建沙箱即可。&lt;/p>
&lt;h3 id="三者的默认配置对比">三者的默认配置对比
&lt;/h3>&lt;p>这部分我建议直接抄进自己的容量规划里：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>配置项&lt;/th>
&lt;th>&lt;code>base&lt;/code>&lt;/th>
&lt;th>&lt;code>code-interpreter-v1&lt;/code>&lt;/th>
&lt;th>&lt;code>browser&lt;/code>&lt;/th>
&lt;th>All-In-One&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>CPU&lt;/td>
&lt;td>2 vCPU（最低要求）&lt;/td>
&lt;td>2 vCPU（最低要求）&lt;/td>
&lt;td>4 vCPU（推荐起始）&lt;/td>
&lt;td>4 vCPU（推荐规格）&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>内存&lt;/td>
&lt;td>2048 MB（最低要求）&lt;/td>
&lt;td>2048 MB（最低要求）&lt;/td>
&lt;td>8192 MB（推荐起始）&lt;/td>
&lt;td>8192 MB（推荐规格）&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>磁盘&lt;/td>
&lt;td>10240 MB&lt;/td>
&lt;td>10240 MB&lt;/td>
&lt;td>10240 MB&lt;/td>
&lt;td>10240 MB&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>端口&lt;/td>
&lt;td>无业务端口（只有 envd 基础服务）&lt;/td>
&lt;td>5000（沙箱服务监听）&lt;/td>
&lt;td>3000（browser 服务）&lt;/td>
&lt;td>3000（浏览器）+ 5000（代码/文件）&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Code Interpreter&lt;/td>
&lt;td>不支持&lt;/td>
&lt;td>支持 Python / JavaScript&lt;/td>
&lt;td>不支持&lt;/td>
&lt;td>支持&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;code>base&lt;/code> 的定位写得很清楚：提供最小化运行环境，内置 E2B envd 兼容基础服务，是 &lt;code>code-interpreter-v1&lt;/code>、&lt;code>browser&lt;/code>、All-In-One 三个模板的&lt;strong>共同能力基础&lt;/strong>。它不预装数据科学库，也不预置浏览器自动化服务。&lt;/p>
&lt;p>&lt;strong>回到坑二那句话&lt;/strong>——通用 &lt;code>e2b&lt;/code> SDK 不传 &lt;code>template&lt;/code> 时默认创建的就是 &lt;code>base&lt;/code> 沙箱。而 &lt;code>base&lt;/code> 的 TypeScript 写法还不太一样，没有模板时 options 是第一个参数：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-typescript" data-lang="typescript">&lt;span class="line">&lt;span class="cl">&lt;span class="kr">const&lt;/span> &lt;span class="nx">sbx&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="nx">Sandbox&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">create&lt;/span>&lt;span class="p">({&lt;/span> &lt;span class="nx">timeoutMs&lt;/span>: &lt;span class="kt">600_000&lt;/span> &lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="code-interpreter-的硬限制">Code Interpreter 的硬限制
&lt;/h3>&lt;p>&lt;code>code-interpreter-v1&lt;/code> 那页除了能力介绍，还给了一组迁移时一定会用到的数字：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>限制项&lt;/th>
&lt;th>约束&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>沙箱生命周期&lt;/td>
&lt;td>单个实例&lt;strong>最长 24 小时&lt;/strong>（&lt;code>timeout&lt;/code> 上限 &lt;strong>86400 秒&lt;/strong>）&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>空闲超时&lt;/td>
&lt;td>&lt;code>sandboxIdleTimeoutSeconds&lt;/code>，&lt;strong>有效下限 60 秒&lt;/strong>（低于 60 秒按 60 秒生效）&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>代码执行超时&lt;/td>
&lt;td>单次同步执行默认 &lt;strong>Python 300 秒 / TypeScript 60000 毫秒&lt;/strong>，可通过 &lt;code>timeout&lt;/code> / &lt;code>timeoutMs&lt;/code> 调整&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>语言支持&lt;/td>
&lt;td>Python、JavaScript（&lt;code>language&lt;/code> 默认 &lt;code>python&lt;/code>）&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>24 小时这个上限值得单独记住。&lt;/strong> 如果你的 Runtime 设计里有一个「常驻沙箱」的角色，它在这里是有天花板的。&lt;/p>
&lt;h3 id="code-interpreter-sandbox-的生产形态">Code Interpreter Sandbox 的生产形态
&lt;/h3>&lt;p>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/using-the-code-interpreter-sandbox" target="_blank" rel="noopener"
>使用 Code Interpreter Sandbox&lt;/a>那页其实在讲一件更重要的方法论：&lt;strong>交互式 &lt;code>run_code&lt;/code> 适合开发，固定脚本入口适合生产。&lt;/strong>&lt;/p>
&lt;p>它建议把分析任务拆成四步：&lt;/p>
&lt;ol>
&lt;li>写入输入数据和分析脚本。&lt;/li>
&lt;li>使用&lt;strong>固定入口&lt;/strong>执行脚本，例如 &lt;code>python3 analyze.py&lt;/code>。&lt;/li>
&lt;li>要求脚本输出 JSON 摘要，必要时生成文件产物。&lt;/li>
&lt;li>读取结果并销毁沙箱。&lt;/li>
&lt;/ol>
&lt;p>理由说得很直白：&lt;strong>固定脚本入口更容易做审计、超时和输出校验&lt;/strong>，因为脚本版本、输入目录、超时时间和输出格式都更容易固化。&lt;code>run_code&lt;/code> 更适合模型逐步生成和修正代码的交互式任务。&lt;/p>
&lt;p>它还顺手给了一份上线建议，我挑几条最实用的：&lt;/p>
&lt;ul>
&lt;li>输入文件要限制大小、类型和路径，避免一次任务占用过多内存或磁盘。&lt;/li>
&lt;li>&lt;strong>输出优先用 JSON 摘要&lt;/strong>，图表、表格、报告文件写 &lt;code>/tmp&lt;/code> 后再下载。&lt;/li>
&lt;li>对 &lt;code>stdout&lt;/code>、&lt;code>stderr&lt;/code>、退出码和结果文件做&lt;strong>统一封装&lt;/strong>，避免上层 Agent 直接解析非结构化日志。&lt;/li>
&lt;li>&lt;strong>对分析代码做版本化&lt;/strong>——「生产系统不要只保存模型生成的自然语言解释」，这句挺重的。&lt;/li>
&lt;li>常用依赖（pandas、openpyxl、绘图库、业务 SDK）放进模板。&lt;/li>
&lt;li>用户可见结果和排障日志分开处理，别把完整堆栈或敏感数据直接返回。&lt;/li>
&lt;/ul>
&lt;h3 id="browser-模板不是开通即用cdp-之外还要过鉴权">browser 模板：不是开通即用，CDP 之外还要过鉴权
&lt;/h3>&lt;p>&lt;code>browser&lt;/code> 模板提供云原生浏览器环境，通过&lt;strong>标准 Chrome DevTools Protocol（CDP）over WebSocket&lt;/strong> 远程控制，原生兼容 Puppeteer、Playwright。它内置 VNC 服务，可以实时看浏览器桌面。&lt;strong>但它的使用分两个阶段：先构建模板，再运行模板。&lt;/strong>&lt;/p>
&lt;p>&lt;strong>默认配置&lt;/strong>：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>配置项&lt;/th>
&lt;th>值&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>容器镜像&lt;/td>
&lt;td>&lt;code>fc-e2b-registry.cn-beijing.cr.aliyuncs.com/runtime/browser:v0.0.44&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>默认端口&lt;/td>
&lt;td>3000&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>CPU&lt;/td>
&lt;td>4 vCPU（推荐起始）&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>内存&lt;/td>
&lt;td>8192 MB（推荐起始）&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>磁盘&lt;/td>
&lt;td>10240 MB（建议 10 GB）&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>第一步：构建。&lt;/strong> 从官方镜像固化出一个带名称的模板：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">dotenv&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">load_dotenv&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">e2b&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Template&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">default_build_logger&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">load_dotenv&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">FROM_IMAGE&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;fc-e2b-registry.cn-beijing.cr.aliyuncs.com/runtime/browser:v0.0.44&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">build&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Template&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">build&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Template&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_image&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">FROM_IMAGE&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;my-browser-template&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpu_count&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">memory_mb&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">8192&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">on_build_logs&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">default_build_logger&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;template_id: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">build&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">template_id&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>第二步：运行。&lt;/strong> 创建沙箱后&lt;strong>先轮询 &lt;code>/health&lt;/code> 等 browser 服务就绪&lt;/strong>，再连 CDP：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">sbx&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Sandbox&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">create&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">template&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;my-browser-template&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">timeout&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">900&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">host&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">sbx&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_host&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">BROWSER_PORT&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># BROWSER_PORT = 3000&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">token&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">sbx&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_envd_access_token&lt;/span> &lt;span class="c1"># 公网网关要求 X-Access-Token，否则 403&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">headers&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;X-Access-Token&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">token&lt;/span>&lt;span class="p">}&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="n">token&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">wait_until_healthy&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">sbx&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">host&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">token&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">with&lt;/span> &lt;span class="n">sync_playwright&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">browser&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">p&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">chromium&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">connect_over_cdp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;wss://&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">host&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">/ws/automation&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">headers&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">headers&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>三个 WebSocket 端点，&lt;strong>全部需要在请求头带 &lt;code>X-Access-Token&lt;/code> 鉴权&lt;/strong>：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>端点&lt;/th>
&lt;th>路径&lt;/th>
&lt;th>用途&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>健康检查&lt;/td>
&lt;td>&lt;code>https://&amp;lt;sandbox-host&amp;gt;/health&lt;/code>&lt;/td>
&lt;td>判断 browser 服务是否启动完成&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>CDP 自动化&lt;/td>
&lt;td>&lt;code>wss://&amp;lt;sandbox-host&amp;gt;/ws/automation&lt;/code>&lt;/td>
&lt;td>浏览器自动化，兼容 Puppeteer 和 Playwright&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>VNC 实时流&lt;/td>
&lt;td>&lt;code>wss://&amp;lt;sandbox-host&amp;gt;/ws/livestream&lt;/code>&lt;/td>
&lt;td>实时查看浏览器桌面，可用 noVNC 客户端&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>这里的坑密度比前面几个模块高，我总结成四条：&lt;/strong>&lt;/p>
&lt;p>&lt;strong>① &lt;code>X-Access-Token&lt;/code> 的取法是非公开 API。&lt;/strong> Python 用 &lt;code>sbx._envd_access_token&lt;/code>（下划线前缀，说明是内部属性），TypeScript 用 &lt;code>sbx.envdAccessToken&lt;/code>。文档自己标注了「后续版本可能重命名或移除」。&lt;strong>这意味着这条链路在 SDK 升级时是有断裂风险的&lt;/strong>，值得在代码里加一层封装并写测试。&lt;/p>
&lt;p>&lt;strong>② noVNC 这种纯浏览器客户端连不上。&lt;/strong> 原因很实在：&lt;strong>浏览器 WebSocket API 不支持在握手时设置自定义请求头&lt;/strong>，所以带不了 &lt;code>X-Access-Token&lt;/code>，直连就是 403。要看画面得换支持自定义 header 的客户端（&lt;code>wscat&lt;/code>、Python &lt;code>websockets&lt;/code>）。&lt;strong>如果只是想看结果，用 CDP 连接后 &lt;code>page.screenshot()&lt;/code> 截图更省事&lt;/strong>——我觉得这是官方给的最务实的一句建议。&lt;/p>
&lt;p>&lt;strong>③ 改窗口尺寸要重新烤镜像，&lt;code>envs&lt;/code> 不管用。&lt;/strong> 浏览器窗口和虚拟屏幕由镜像里三个环境变量控制：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>环境变量&lt;/th>
&lt;th>作用&lt;/th>
&lt;th>默认值&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>RESOLUTION&lt;/code>&lt;/td>
&lt;td>Xvfb 虚拟屏幕分辨率（宽x高x色深）&lt;/td>
&lt;td>&lt;code>1680x1050x24&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>BROWSER_WINDOW_SIZE&lt;/code>&lt;/td>
&lt;td>Chrome 启动窗口大小（&lt;code>--window-size&lt;/code>）&lt;/td>
&lt;td>取 &lt;code>RESOLUTION&lt;/code> 的宽高&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>VNC_CLIP&lt;/code>&lt;/td>
&lt;td>VNC 实时流的画面裁剪区域&lt;/td>
&lt;td>与窗口大小一致&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>而 &lt;code>Sandbox.create&lt;/code> 的 &lt;code>envs&lt;/code> &lt;strong>只注入沙箱内的命令执行进程，不会影响浏览器栈&lt;/strong>。所以想改尺寸，得先用 Dockerfile 把环境变量烤进自定义镜像：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-dockerfile" data-lang="dockerfile">&lt;span class="line">&lt;span class="cl">&lt;span class="k">FROM&lt;/span>&lt;span class="s"> fc-e2b-registry.cn-beijing.cr.aliyuncs.com/runtime/browser:v0.0.44&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">ENV&lt;/span> &lt;span class="nv">RESOLUTION&lt;/span>&lt;span class="o">=&lt;/span>1920x1080x24
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">ENV&lt;/span> &lt;span class="nv">BROWSER_WINDOW_SIZE&lt;/span>&lt;span class="o">=&lt;/span>1920x1080
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">ENV&lt;/span> &lt;span class="nv">VNC_CLIP&lt;/span>&lt;span class="o">=&lt;/span>1920x1080
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>推送到镜像仓库后，再用 &lt;code>from_image&lt;/code> 构建模板。注意&lt;strong>窗口尺寸同时决定 VNC 实时流的画面范围&lt;/strong>，但页面内视口仍由 Playwright / Puppeteer 通过 CDP 自己设。&lt;/p>
&lt;p>&lt;strong>④ 探测 WebSocket 时会「假失败」。&lt;/strong> 在沙箱内用 curl 测 CDP 握手：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">curl -sS -m &lt;span class="m">4&lt;/span> -i &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> -H &lt;span class="s1">&amp;#39;Connection: Upgrade&amp;#39;&lt;/span> -H &lt;span class="s1">&amp;#39;Upgrade: websocket&amp;#39;&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> -H &lt;span class="s1">&amp;#39;Sec-WebSocket-Version: 13&amp;#39;&lt;/span> -H &lt;span class="s1">&amp;#39;Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==&amp;#39;&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> http://localhost:3000/ws/automation
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>收到 &lt;code>101 Switching Protocols&lt;/code> 之后，服务端会继续发 WebSocket 数据帧，&lt;strong>curl 会一直等到 &lt;code>-m 4&lt;/code> 超时并以退出码 28 结束&lt;/strong>。文档专门解释了这不代表握手失败——&lt;strong>判断依据是响应里有没有 &lt;code>101&lt;/code>，不是 curl 的退出码。&lt;/strong>&lt;/p>
&lt;h3 id="all-in-one浏览器--代码执行同一沙箱">All-In-One：浏览器 + 代码执行，同一沙箱
&lt;/h3>&lt;p>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/all-in-one-template" target="_blank" rel="noopener"
>All-In-One&lt;/a> 就是在 browser 的基础上叠加 Code Interpreter 服务。差异很简洁：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>对比项&lt;/th>
&lt;th>browser&lt;/th>
&lt;th>All-In-One&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>核心定位&lt;/td>
&lt;td>轻量浏览器自动化环境&lt;/td>
&lt;td>浏览器自动化 + 代码执行一体化&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Code Interpreter&lt;/td>
&lt;td>不支持&lt;/td>
&lt;td>支持 Python / JavaScript，含上下文保持&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>端口&lt;/td>
&lt;td>3000&lt;/td>
&lt;td>3000（浏览器）+ 5000（代码与文件）&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>默认镜像&lt;/td>
&lt;td>&lt;code>runtime/browser&lt;/code>&lt;/td>
&lt;td>&lt;code>runtime/all-in-one&lt;/code>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>默认镜像示例是新加坡地域：&lt;code>fc-e2b-registry.ap-southeast-1.cr.aliyuncs.com/runtime/all-in-one:v0.0.44&lt;/code>。&lt;strong>注意跨地域镜像构建会失败&lt;/strong>——镜像地址里的地域必须换成云沙箱接入地域。&lt;/p>
&lt;p>浏览器部分（建沙箱、等 &lt;code>/health&lt;/code>、CDP、截图）和 browser 模板完全一致，只是多了一段：&lt;strong>浏览器阶段产生的截图、HTML、下载文件，可以直接在同一沙箱里交给 Code Interpreter 处理。&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 承接 browser 流程中的同一个 sbx&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">execution&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">sbx&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">run_code&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;import json&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;print(json.dumps({&amp;#39;status&amp;#39;: &amp;#39;ok&amp;#39;, &amp;#39;source&amp;#39;: &amp;#39;all-in-one&amp;#39;}, ensure_ascii=False))&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">join&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">execution&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">logs&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">stdout&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>用 Code Interpreter 时，SDK 要换回 &lt;code>e2b_code_interpreter&lt;/code> / &lt;code>@e2b/code-interpreter&lt;/code>，沙箱由你自己的 All-In-One 模板创建。&lt;/p>
&lt;p>&lt;strong>选型标准文档给得很清楚，我直接抄&lt;/strong>（&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/use-browser-use-sandbox" target="_blank" rel="noopener"
>使用 Browser Use Sandbox&lt;/a> / &lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/using-aio-sandbox" target="_blank" rel="noopener"
>使用 AIO Sandbox&lt;/a>）：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>任务形态&lt;/th>
&lt;th>选择&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>只访问网页、点击、截图、下载、轻量提取&lt;/td>
&lt;td>&lt;strong>Browser Use Sandbox&lt;/strong>（browser 模板）&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>浏览器产物还要在同一会话里清洗、分析、生成报告&lt;/td>
&lt;td>&lt;strong>AIO Sandbox&lt;/strong>（All-In-One 模板）&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>只有代码执行&lt;/td>
&lt;td>&lt;strong>Code Interpreter Sandbox&lt;/strong>（code-interpreter-v1）&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>只要基础命令和文件&lt;/td>
&lt;td>&lt;strong>base&lt;/strong>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>AIO 那两页的「推荐流程」都是 8 步，结构很像，我合并一下：&lt;strong>构建业务模板 → 建沙箱并设足够超时 → &lt;code>get_host(3000)&lt;/code> 拿 host → 轮询 &lt;code>/health&lt;/code> → 连 CDP 执行操作 → 产物写入沙箱文件系统 → 交给 Code Interpreter 或命令继续处理 → 下载结果、销毁沙箱&lt;/strong>。&lt;/p>
&lt;p>中间有个细节值得抄：&lt;strong>用固定的任务目录&lt;/strong>，例如 &lt;code>/tmp/aio-task/&amp;lt;task-id&amp;gt;&lt;/code>，把截图、HTML、下载文件、脚本和结果文件放同一目录。另外官方明确提了**「浏览器阶段和代码阶段分别记录输入、输出、日志和错误」**——排查时先确认是页面操作失败，还是后续脚本处理失败，否则这两种错在同一个沙箱里长得一模一样。&lt;/p>
&lt;h3 id="browseruse-这类框架怎么接">BrowserUse 这类框架怎么接
&lt;/h3>&lt;p>这块是很多 Agent 框架落地的关键：&lt;strong>让 BrowserUse 连接沙箱暴露的 CDP 地址。&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">browser_session&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">BrowserSession&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cdp_url&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;wss://&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">host&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">/ws/automation&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">browser_profile&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">BrowserProfile&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">headless&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">False&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">keep_alive&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">headers&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;X-Access-Token&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">sandbox&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">_envd_access_token&lt;/span>&lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">agent&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Agent&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">task&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;访问 https://example.com，提取页面标题并总结首屏正文&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llm&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">ChatOpenAI&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="o">=...&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">api_key&lt;/span>&lt;span class="o">=...&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">base_url&lt;/span>&lt;span class="o">=...&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">browser_session&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">browser_session&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">use_vision&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>职责划分很清楚：&lt;strong>业务服务负责创建和销毁沙箱，BrowserUse 只连接这个沙箱中的浏览器会话。&lt;/strong> 用 Puppeteer Core 也一样，&lt;code>browserWSEndpoint&lt;/code> 填 &lt;code>wss://&amp;lt;host&amp;gt;/ws/automation&lt;/code>，headers 带 token。&lt;/p>
&lt;p>上线建议里有两条我特别认同，顺便呼应了前面沙箱选型那篇的老话题：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>页面内容可能包含 prompt injection。不要让 Agent 未经校验地执行网页中的指令。&lt;/strong>&lt;/li>
&lt;li>&lt;strong>登录态、Cookie、账号凭证和业务 Token 应按任务隔离，通过运行时注入，不写进模板。&lt;/strong>&lt;/li>
&lt;li>每个浏览器任务限制在明确的 URL 范围内，必要时加域名白名单；限制下载文件类型、单文件大小、总输出大小和任务生命周期。&lt;/li>
&lt;/ul>
&lt;h3 id="自定义模板从自己的镜像构建">自定义模板：从自己的镜像构建
&lt;/h3>&lt;p>内置模板满足不了时（业务依赖、系统库、运行时版本、企业标准化），才做自定义镜像模板。&lt;strong>生产模板还有几条纪律&lt;/strong>（&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/build-a-custom-image-template" target="_blank" rel="noopener"
>构建和管理模板&lt;/a>）：&lt;/p>
&lt;ul>
&lt;li>模板名称应唯一、可读，&lt;strong>便于灰度和回滚&lt;/strong>。&lt;/li>
&lt;li>基础镜像来自云沙箱可访问的镜像仓库。&lt;/li>
&lt;li>&lt;strong>镜像仓库、网络配置和云沙箱要在同一地域。&lt;/strong>&lt;/li>
&lt;li>构建依赖不宜过大，否则可能构建超时或失败。&lt;/li>
&lt;li>&lt;strong>生产环境不应覆盖正在使用的模板&lt;/strong>，建议新建模板、验证后再切换。&lt;/li>
&lt;/ul>
&lt;p>构建流程本身很短——定义模板、提交构建、拿 &lt;code>template_id&lt;/code> 建沙箱（&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/templates" target="_blank" rel="noopener"
>快速开始&lt;/a>）：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">build&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Template&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">build&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Template&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_image&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">environ&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;FROM_IMAGE&amp;#34;&lt;/span>&lt;span class="p">]),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;template-&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="nb">int&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">time&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">time&lt;/span>&lt;span class="p">())&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cpu_count&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">memory_mb&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">2048&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">on_build_logs&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">default_build_logger&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">sandbox&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Sandbox&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">create&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">template&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">build&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">template_id&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">timeout&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">900&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>如果你要用自己的 &lt;strong>ACR EE&lt;/strong> 镜像，前置条件比较硬：&lt;/p>
&lt;ul>
&lt;li>ACR EE 实例要和云沙箱在&lt;strong>同一 UID、同一地域&lt;/strong>（经济版不支持）。&lt;/li>
&lt;li>ACR EE 实例要&lt;strong>至少绑定一个 VPC&lt;/strong>，且该 VPC 下至少有一个 vSwitch 在函数计算支持的可用区。&lt;/li>
&lt;li>镜像仓库、VPC、vSwitch 与云沙箱同地域，且访问控制已放通。&lt;/li>
&lt;li>推送时用 VPC 内网地址，例如 &lt;code>test-registry-vpc.cn-beijing.cr.aliyuncs.com/runtime/python:3.12-v1&lt;/code>。&lt;/li>
&lt;li>&lt;strong>不要给不同内容的镜像推同一个 tag。&lt;/strong> 每个不同镜像都要有新且唯一的 tag（版本号、日期或 commit ID），模板引用那个具体 tag。&lt;/li>
&lt;/ul>
&lt;p>镜像本身也有一张要求表，违反任何一条都会让构建或运行失败：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>级别&lt;/th>
&lt;th>要求&lt;/th>
&lt;th>不满足的后果&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>必须&lt;/td>
&lt;td>架构为 &lt;code>linux/amd64&lt;/code>（多架构镜像的 manifest list 要包含 amd64）&lt;/td>
&lt;td>模板转换立即失败&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>必须&lt;/td>
&lt;td>不要开启镜像加速&lt;/td>
&lt;td>模板转换立即失败&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>必须&lt;/td>
&lt;td>&lt;code>/etc/passwd&lt;/code>、&lt;code>/etc/group&lt;/code> 是标准文件且可写&lt;/td>
&lt;td>gatewayd 无法初始化默认用户，容器启动失败&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>条件&lt;/td>
&lt;td>固定路径 &lt;code>/bin/bash&lt;/code> 存在（不能只是能从 PATH 解析到）&lt;/td>
&lt;td>&lt;code>commands.run&lt;/code> 和 PTY 失败&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>条件&lt;/td>
&lt;td>PATH 中有 &lt;code>python3&lt;/code> 或 &lt;code>python&lt;/code>&lt;/td>
&lt;td>Python &lt;code>run_code&lt;/code> 不可用&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>条件&lt;/td>
&lt;td>PATH 中有 &lt;code>node&lt;/code>&lt;/td>
&lt;td>JavaScript &lt;code>run_code&lt;/code> 不可用&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>按需&lt;/td>
&lt;td>&lt;code>git&lt;/code>、&lt;code>openssh-client&lt;/code>、CA 证书、构建工具链&lt;/td>
&lt;td>对应的 Git / SSH / HTTPS / 源码构建操作不可用&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>建议&lt;/td>
&lt;td>系统 PATH 至少包含 &lt;code>/usr/local/bin&lt;/code>、&lt;code>/usr/bin&lt;/code>、&lt;code>/bin&lt;/code>&lt;/td>
&lt;td>登录 shell 里可能缺常用命令&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;code>/bin/bash&lt;/code> 那一条我建议特别留意：它说的是&lt;strong>固定路径存在&lt;/strong>，不是 PATH 里能找到。很多精简基础镜像（busybox / distroless 派生）会把 bash 放在别处或者干脆没有。还有「不要开镜像加速」这条也挺反直觉——那是个平时看起来纯占便宜的开关。&lt;/p>
&lt;p>&lt;strong>模板的定位也说得很清楚&lt;/strong>：模板固化的是系统依赖、语言运行时、工具链和基础代码；&lt;strong>用户数据、临时文件和频繁变化的业务状态要在运行时写入&lt;/strong>；&lt;strong>密钥、Token 这类敏感凭证不要写进模板，创建沙箱时用环境变量注入&lt;/strong>。最后这句我在前面提过一次，这里再强调一遍，因为它是最容易被「顺手固化一下」的操作。&lt;/p>
&lt;h4 id="一次真的跑通从跨地域失败到新加坡模板可用">一次真的跑通：从跨地域失败到新加坡模板可用
&lt;/h4>&lt;p>上面的要求表看起来像文档摘录，直到我真的推了一次镜像，才发现它更适合当成一条&lt;strong>排错顺序&lt;/strong>。这次镜像里要固化的是 Node.js、openpyxl、pandas、NumPy 和 SciPy；最终跑通的路径不是「把 Dockerfile 写对」这么简单，而是连续解决了地域、账号、API Key、镜像 manifest 和登录 Shell 五层问题。&lt;/p>
&lt;p>先给结论：&lt;strong>自定义模板构建至少有五个必须同时对齐的坐标：Sandbox 地域、E2B Endpoint、E2B API Key 的归属地域、镜像仓库地域、镜像仓库所属账号。&lt;/strong> Dockerfile 只是第六个变量。&lt;/p>
&lt;h5 id="第一步永远用官方镜像建立基线">第一步永远用官方镜像建立基线
&lt;/h5>&lt;p>不要一上来就拿私有镜像测试。先用同地域官方镜像构建模板并创建 Sandbox：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-env" data-lang="env">&lt;span class="line">&lt;span class="cl">&lt;span class="nv">E2B_API_KEY&lt;/span>&lt;span class="o">=&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">E2B_API_URL&lt;/span>&lt;span class="o">=&lt;/span>https://api.&amp;lt;region&amp;gt;.e2b.fc.aliyuncs.com
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">E2B_DOMAIN&lt;/span>&lt;span class="o">=&lt;/span>&amp;lt;region&amp;gt;.e2b.fc.aliyuncs.com
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">OFFICIAL_IMAGE&lt;/span>&lt;span class="o">=&lt;/span>fc-e2b-registry.&amp;lt;region&amp;gt;.cr.aliyuncs.com/runtime/code-interpreter-v1:&amp;lt;published-tag&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这一步成功，才能证明 Team、API Key、Endpoint、Domain 和模板服务链路都正常。否则后面看到 &lt;code>401&lt;/code>、模板不可见或构建失败时，很容易把凭证问题误判成镜像问题。&lt;/p>
&lt;p>API Key 是地域级凭据。最安全的只读探测是查询 Sandbox 列表，而不是创建 Sandbox：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">httpx&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">httpx&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;https://api.ap-southeast-1.e2b.fc.aliyuncs.com/sandboxes&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">headers&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;X-API-KEY&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">api_key&lt;/span>&lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">timeout&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">15&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">status_code&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>我们这次就碰到过一种很有迷惑性的状态：Endpoint 和 Domain 已经换成新加坡，但 Key 仍然属于北京。结果是新加坡返回 &lt;code>401&lt;/code>，北京返回 &lt;code>200&lt;/code>。&lt;strong>Endpoint 改了，不代表 Key 跟着迁移；目标地域必须重新创建 Team/API Key。&lt;/strong>&lt;/p>
&lt;h5 id="地域不一致不是慢一点而是构建器根本不存在">地域不一致不是“慢一点”，而是构建器根本不存在
&lt;/h5>&lt;p>第一次自定义镜像放在河源 ACR，Sandbox 在北京。构建请求已经被接受，但注入 envd 时失败：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">envd inject failed
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">lookup &amp;lt;account&amp;gt;.cn-heyuan.fc.aliyuncs.com: no such host
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这不是 DNS 偶发故障。河源不是 FC 云沙箱支持地域，平台根据镜像仓库地域准备 Builder，最终指向了不存在的河源 FC 服务。后来把镜像和 Sandbox 一起迁到新加坡，这一层才消失。&lt;/p>
&lt;p>所以地域检查不要只看 Endpoint。完整矩阵应该是：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>对象&lt;/th>
&lt;th>必须检查的值&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>E2B API URL&lt;/td>
&lt;td>&lt;code>api.&amp;lt;region&amp;gt;.e2b.fc.aliyuncs.com&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>E2B Domain&lt;/td>
&lt;td>&lt;code>&amp;lt;region&amp;gt;.e2b.fc.aliyuncs.com&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>API Key&lt;/td>
&lt;td>在目标地域 Team 下创建&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>源镜像仓库&lt;/td>
&lt;td>与 Sandbox 同地域&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Template / Sandbox&lt;/td>
&lt;td>与前三者同地域&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>VPC / vSwitch / 安全组（ACR EE）&lt;/td>
&lt;td>与仓库和 Sandbox 同地域&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h5 id="账号一致可以从错误信息里反推">“账号一致”可以从错误信息里反推
&lt;/h5>&lt;p>镜像迁到新加坡后，第一次仍然失败：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">get personal ACR authorization token
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">AUTHENTICATION_FAILED
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">user jurisdiction error
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>当时地域、镜像地址、仓库用户名密码都没错。真正的问题是 &lt;strong>E2B API Key 所属账号与 ACR 仓库所属账号不一致&lt;/strong>。换成镜像仓库所在账号、同一新加坡 Team 下创建的 Key 后，构建日志依次变成：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">template build accepted
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">starting image conversion
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">registry resolved
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">builder prepared
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">image conversion completed
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">template function created
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这条日志序列很有用：&lt;code>registry resolved&lt;/code> 之前失败，先查仓库类型、账号归属和凭证；&lt;code>builder prepared&lt;/code> 之前失败，先查地域和 FC Builder；镜像转换完成但 Sandbox 起不来，再查镜像内部结构与运行依赖。&lt;/p>
&lt;p>官方文档把受支持的私有 ACR 主路径写成 &lt;strong>ACR 企业版、同 UID、同地域、绑定 VPC&lt;/strong>。这次实测中，同账号同地域的 ACR 个人版也通过 E2B &lt;code>Template.build()&lt;/code> 跑通了镜像转换和 Sandbox 创建，但这只能记作&lt;strong>当前实测行为，不应提升为生产承诺&lt;/strong>。生产仍然应按官方支持路径使用 ACR EE；否则平台调整授权或构建策略时，没有稳定性保证。&lt;/p>
&lt;h5 id="镜像要同时满足构建器和登录-shell">镜像要同时满足构建器和登录 Shell
&lt;/h5>&lt;p>最终镜像采用 Node 22 slim 作为基础，再安装 Python 3 虚拟环境和数据依赖。这样比在 Python 镜像里通过 Debian 安装 &lt;code>npm&lt;/code> 少拉数百个系统包。核心结构如下：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-dockerfile" data-lang="dockerfile">&lt;span class="line">&lt;span class="cl">&lt;span class="k">FROM&lt;/span>&lt;span class="s"> node:22-bookworm-slim&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">RUN&lt;/span> apt-get update &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> apt-get install -y --no-install-recommends &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> bash ca-certificates curl git openssh-client &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> python3 python3-pip python3-venv &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> rm -rf /var/lib/apt/lists/*&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">RUN&lt;/span> python3 -m venv /opt/venv&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">ENV&lt;/span> &lt;span class="nv">PATH&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;/opt/venv/bin:&lt;/span>&lt;span class="si">${&lt;/span>&lt;span class="nv">PATH&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">COPY&lt;/span> requirements-image.txt /tmp/requirements-image.txt&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">RUN&lt;/span> python -m pip install --no-cache-dir -r /tmp/requirements-image.txt&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这里又踩了一个只有运行时才出现的坑：Docker 构建阶段用 &lt;code>python&lt;/code> 导入依赖正常，但 Sandbox 的 &lt;code>bash -lc&lt;/code> 会重置 PATH，&lt;code>python3&lt;/code> 最后指向系统 Python，报 &lt;code>ModuleNotFoundError&lt;/code>。&lt;/p>
&lt;p>单纯把 &lt;code>/usr/local/bin/python3&lt;/code> 软链接到虚拟环境也不够。Python 会根据启动路径判断虚拟环境，跨目录软链接可能让它重新落回系统环境。最后用一个明确的包装器解决：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-dockerfile" data-lang="dockerfile">&lt;span class="line">&lt;span class="cl">&lt;span class="k">RUN&lt;/span> &lt;span class="nb">printf&lt;/span> &lt;span class="s1">&amp;#39;%s\n&amp;#39;&lt;/span> &lt;span class="s1">&amp;#39;#!/bin/sh&amp;#39;&lt;/span> &lt;span class="s1">&amp;#39;exec /opt/venv/bin/python3 &amp;#34;$@&amp;#34;&amp;#39;&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> &amp;gt; /usr/local/bin/python3 &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> chmod +x /usr/local/bin/python3&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Docker build 中能 import，不代表 Sandbox 登录 Shell 中也能 import。&lt;/strong> 验收必须用和 Sandbox 接近的命令：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">docker run --rm --platform linux/amd64 &amp;lt;image&amp;gt; bash -lc &lt;span class="s1">&amp;#39;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1">python3 -c &amp;#34;import openpyxl, pandas, numpy, scipy&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1">node --version
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1">test -w /etc/passwd
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1">test -w /etc/group
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1">&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h5 id="推送时关闭附加-manifest">推送时关闭附加 manifest
&lt;/h5>&lt;p>FC 模板排错文档明确建议使用单一 &lt;code>linux/amd64&lt;/code> 并关闭 provenance / SBOM。否则 Buildx 可能同时推送一个 &lt;code>unknown/unknown&lt;/code> 的 attestation manifest，模板构建器可能把它当成镜像平台异常。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">docker buildx build &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --platform linux/amd64 &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --provenance&lt;span class="o">=&lt;/span>&lt;span class="nb">false&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --sbom&lt;span class="o">=&lt;/span>&lt;span class="nb">false&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --tag &lt;span class="s2">&amp;#34;&amp;lt;registry&amp;gt;/&amp;lt;namespace&amp;gt;/&amp;lt;image&amp;gt;:&amp;lt;unique-tag&amp;gt;&amp;#34;&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --push &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> .
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这里的 &lt;code>&amp;lt;unique-tag&amp;gt;&lt;/code> 是纪律，不是装饰。不要把不同内容覆盖到已经被模板引用的 tag；使用日期、版本号或 commit ID，让镜像、模板和一次验证结果能够互相追溯。&lt;/p>
&lt;h5 id="最后的验收必须发生在云端-sandbox">最后的验收必须发生在云端 Sandbox
&lt;/h5>&lt;p>本地镜像测试只证明容器能跑，不能证明 envd 注入、模板函数和 Sandbox 生命周期正常。最终验收应当创建一次临时 Sandbox，实际导入依赖，然后在 &lt;code>finally&lt;/code> 中释放：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">sandbox&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Sandbox&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">create&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">template&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">template_id&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">timeout&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">300&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">try&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">sandbox&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">commands&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">run&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;python3 -c &lt;/span>&lt;span class="se">\&amp;#34;&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;import openpyxl, pandas, numpy, scipy; &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;print(openpyxl.__version__, pandas.__version__, &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;numpy.__version__, scipy.__version__)&lt;/span>&lt;span class="se">\&amp;#34;&lt;/span>&lt;span class="s2"> &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;amp;&amp;amp; node --version&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">exit_code&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="ne">RuntimeError&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">stderr&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">stdout&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">finally&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sandbox&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">kill&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这次云端最终验证通过的组合是 Python 3.11、Node.js 22、openpyxl 3.1.5、pandas 2.3.2、NumPy 2.3.3、SciPy 1.16.2。版本号不是推荐清单，只是一次可复现构建的证据；真正值得复用的是验收顺序：&lt;/p>
&lt;ol>
&lt;li>官方镜像验证控制链路；&lt;/li>
&lt;li>只读探测 API Key 地域；&lt;/li>
&lt;li>单平台、唯一 tag 推送自定义镜像；&lt;/li>
&lt;li>观察构建日志停在哪一阶段；&lt;/li>
&lt;li>在云端 Sandbox 里导入全部关键依赖；&lt;/li>
&lt;li>无论成功失败都释放临时 Sandbox。&lt;/li>
&lt;/ol>
&lt;p>这轮实测最后留下的判断是：&lt;strong>自定义模板最难排查的不是 Dockerfile，而是“地域 × 账号 × 凭据 × 仓库类型”共同决定的构建控制面。&lt;/strong> 先把这四个坐标钉死，再谈镜像内部依赖，排错会快很多。&lt;/p>
&lt;h3 id="模板的版本管理名称--标签">模板的版本管理：名称 + 标签
&lt;/h3>&lt;p>发布纪律这块，官方给的做法是&lt;strong>名称标识运行环境，标签标记某次构建的阶段或版本&lt;/strong>（&lt;code>prod&lt;/code>、&lt;code>staging&lt;/code>、&lt;code>v1&lt;/code>），用来做灰度和回滚（&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/template-name" target="_blank" rel="noopener"
>模板名称与版本&lt;/a>）。&lt;/p>
&lt;p>名称建议带上业务场景、语言或基础镜像、关键依赖版本和日期：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">agent-python313-20260704
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">code-review-node22-20260704
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">data-analysis-py313-v1
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>标签操作有三个：&lt;code>assignTags&lt;/code> 分配、&lt;code>getTags&lt;/code> 查询、&lt;code>removeTags&lt;/code> 移除。有两个坑值得记：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>不能删除 &lt;code>default&lt;/code> 标签&lt;/strong>（返回 400）。&lt;/li>
&lt;li>&lt;strong>Python 查询标签要用模板 ID&lt;/strong>，不是模板名；TypeScript 用模板名就行。分配和移除倒是都按模板名。&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">Template&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">assign_tags&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;agent-python313-20260704&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;staging&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;v1&amp;#34;&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">tags&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Template&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_tags&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;&amp;lt;template-id&amp;gt;&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># 注意这里是 ID&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>分配和移除标签都是幂等的，重复分配、删不存在的标签都不会报错。&lt;code>assignTags&lt;/code> 第一个参数用 &lt;code>name:tag&lt;/code> 格式指定从哪个构建打标签，不带 &lt;code>:tag&lt;/code> 时默认指向 &lt;code>default&lt;/code> 构建。&lt;/p>
&lt;h3 id="沙箱内的环境变量">沙箱内的环境变量
&lt;/h3>&lt;p>环境变量分两层，用途不同（&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/environment-variable" target="_blank" rel="noopener"
>环境变量&lt;/a>）：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>沙箱级 &lt;code>envs&lt;/code>&lt;/strong>：创建时传入，适合多次命令都会用到的配置。&lt;/li>
&lt;li>&lt;strong>命令级 &lt;code>envs&lt;/code>&lt;/strong>：&lt;code>commands.run()&lt;/code> 时传入，适合单次执行参数，会覆盖沙箱级。&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">sandbox&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Sandbox&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">create&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">...&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">envs&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;NODE_ENV&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;production&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;TASK_ID&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;task-001&amp;#34;&lt;/span>&lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">sandbox&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">commands&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">run&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;echo $TASK_ID&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">envs&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;TASK_ID&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;task-002&amp;#34;&lt;/span>&lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>官方建议是&lt;strong>环境变量只放非敏感开关、任务参数和工具配置&lt;/strong>，密钥和 Token 由业务侧控制访问范围。以及一条和 metadata 呼应的边界：&lt;strong>不要依赖环境变量保存业务状态&lt;/strong>，跨沙箱的持久状态写外部存储。&lt;/p>
&lt;h2 id="七fc-extensions云沙箱不是-e2b-的镜像">七、FC Extensions：云沙箱不是 E2B 的镜像
&lt;/h2>&lt;p>如果只是纯「E2B 兼容，换个 endpoint」，那云沙箱的价值就只是「国内有个能连上的 E2B」。但它其实还多了一层 E2B 原生接口里没有的东西：&lt;strong>FC Extensions（云上扩展）&lt;/strong>（&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/fc-extensions-overview" target="_blank" rel="noopener"
>概览&lt;/a>）。&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>扩展&lt;/th>
&lt;th>作用&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/vpc-network-configuration-1" target="_blank" rel="noopener"
>VPC 网络配置&lt;/a>&lt;/td>
&lt;td>让 Sandbox 访问 VPC 内的数据库、内网 API、镜像仓库或其他云资源&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/custom-domain-name" target="_blank" rel="noopener"
>自定义域名&lt;/a>&lt;/td>
&lt;td>用固定域名和自有证书访问云沙箱 API 及沙箱内服务&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/mount-oss-dynamically-1" target="_blank" rel="noopener"
>动态挂载 OSS&lt;/a>&lt;/td>
&lt;td>通过 metadata 把 OSS 路径挂进 Sandbox，按本地路径读写对象&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/monitoring-and-logging" target="_blank" rel="noopener"
>监控与日志&lt;/a>&lt;/td>
&lt;td>查看运行状态与资源指标，把 stdout / stderr 采集到日志服务&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/quota-management" target="_blank" rel="noopener"
>Team 配额管理&lt;/a>&lt;/td>
&lt;td>给指定 Team 设置 CPU 和内存配额&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/create-oss-volume" target="_blank" rel="noopener"
>OSS Volume&lt;/a> / &lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/create-an-agenticfs-volume" target="_blank" rel="noopener"
>AgenticFS Volume&lt;/a>&lt;/td>
&lt;td>保存可复用的挂载配置，创建沙箱时按名称挂载&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>它的接入方式有一个很重要的性质：&lt;strong>FC Extensions 不是 E2B SDK 的新方法，不需要改导入方式。&lt;/strong> 应用侧还是照常 &lt;code>Sandbox.create()&lt;/code>，VPC、OSS、日志、监控这些是在函数计算控制台或云沙箱控制面配好、然后生效的。&lt;/p>
&lt;p>而且它的实际机制比「控制台点一下」更有意思：&lt;strong>VPC 和 OSS 挂载都是通过 Sandbox 的保留 metadata 字段传进去的。&lt;/strong>&lt;/p>
&lt;h3 id="vpc-配置一个保留-metadata-字段">VPC 配置：一个保留 metadata 字段
&lt;/h3>&lt;p>云沙箱通过 &lt;code>fc.sandbox.network.vpc&lt;/code> 传 VPC 配置——把 &lt;code>vpcId&lt;/code>、&lt;code>securityGroupId&lt;/code>、&lt;code>vSwitchIds&lt;/code> 序列化成 &lt;strong>JSON 字符串&lt;/strong>：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;vpcId&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;vpc-xxxxxxxx&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;securityGroupId&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;sg-xxxxxxxx&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;vSwitchIds&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;vsw-xxxxxxxx&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">sandbox&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Sandbox&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">create&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">**&lt;/span>&lt;span class="n">conn_opts&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">metadata&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;fc.sandbox.network.vpc&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">json&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">dumps&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">vpc_config&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>字段&lt;/th>
&lt;th>必填&lt;/th>
&lt;th>说明&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>vpcId&lt;/code>&lt;/td>
&lt;td>是&lt;/td>
&lt;td>要接入的专有网络 ID&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>securityGroupId&lt;/code>&lt;/td>
&lt;td>是&lt;/td>
&lt;td>安全组 ID，用于控制&lt;strong>出方向&lt;/strong>访问范围&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>vSwitchIds&lt;/code>&lt;/td>
&lt;td>是&lt;/td>
&lt;td>vSwitch ID 列表，&lt;strong>建议配两个或更多&lt;/strong>，提高可用性并降低单网段 IP 不足的风险&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>前置条件比想象中多，漏一个就是「创建成功但连不上」：&lt;/p>
&lt;ul>
&lt;li>vSwitch 要在函数计算支持的可用区（同 VPC 内不同 vSwitch 默认可私网互通）。&lt;/li>
&lt;li>安全组要是&lt;strong>非云服务托管&lt;/strong>的，且&lt;strong>出方向规则&lt;/strong>允许访问目标资源的协议和端口。&lt;/li>
&lt;li>目标资源自己有白名单的（RDS 白名单、自建服务 ACL），要把 &lt;strong>vSwitch 网段&lt;/strong>加进去。&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>「网络可达不等于业务鉴权通过」&lt;/strong>——数据库账号、API Token、RAM Role 这些都还得单独配。这句话文档写得很明白，我觉得是这一节最有价值的一句。&lt;/p>
&lt;p>&lt;strong>验证方式&lt;/strong>也很实在，而且给了一个我觉得很聪明的判别实验：&lt;/p>
&lt;ol>
&lt;li>用 &lt;code>socket.create_connection((host, port), timeout=5)&lt;/code> 在沙箱内测 TCP 连通性，可以拿去测 NAS 2049、RDS 3306、Redis 6379 或内网 HTTP 端口。&lt;/li>
&lt;li>&lt;strong>先建一个不带 &lt;code>fc.sandbox.network.vpc&lt;/code> 的 Sandbox，确认同一个内网地址不可达；再建一个带 VPC metadata 的，确认可达。&lt;/strong> 这样才能证明是 VPC 配置生效，而不是网络本来就通。&lt;/li>
&lt;/ol>
&lt;p>常见问题那张表也能当排错清单用：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>现象&lt;/th>
&lt;th>可能原因&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>创建 Sandbox 失败&lt;/td>
&lt;td>资源 ID 不存在，或与沙箱不在同一地域 / 账号&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>创建成功但内网地址不可达&lt;/td>
&lt;td>安全组出方向未放行、目标资源白名单未含 vSwitch 网段、目标服务未监听&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>提示 vSwitch 可用区不支持&lt;/td>
&lt;td>vSwitch 不在函数计算当前地域支持的可用区内&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>偶发创建 / 连接失败&lt;/td>
&lt;td>vSwitch 网段可用 IP 不足，或只配了单个可用区&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>需要访问公网和 VPC&lt;/td>
&lt;td>&lt;strong>只配 VPC 不代表固定公网出口&lt;/strong>，公网能力以云沙箱和函数计算网络策略为准&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>还有个表述细节：&lt;strong>&lt;code>fc.sandbox.network.vpc&lt;/code> 的值必须是 JSON 字符串，不能直接传 Python dict 或 JavaScript object。&lt;/strong>&lt;/p>
&lt;h3 id="oss-挂载两个-metadata-字段">OSS 挂载：两个 metadata 字段
&lt;/h3>&lt;p>OSS 动态挂载要传两个字段（&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/mount-oss-dynamically-1" target="_blank" rel="noopener"
>动态挂载 OSS&lt;/a>）：&lt;/p>
&lt;ul>
&lt;li>&lt;code>fc.sandbox.storage.oss&lt;/code>：挂载配置，JSON 字符串。&lt;/li>
&lt;li>&lt;code>fc.sandbox.auth.role&lt;/code>：&lt;strong>用于访问 OSS 的 RAM Role ARN&lt;/strong>。&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">sandbox&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Sandbox&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">create&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">api_key&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">api_key&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">timeout&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">300&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">**&lt;/span>&lt;span class="n">conn_opts&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">metadata&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;fc.sandbox.storage.oss&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">json&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">dumps&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">oss_config&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;fc.sandbox.auth.role&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">role_arn&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>挂载点配置：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;mountPoints&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;bucketName&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;example-bucket&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;mountDir&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;/mnt/oss&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;bucketPath&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;/e2b-test&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;endpoint&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;https://oss-cn-hangzhou.aliyuncs.com&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;readOnly&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">false&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>字段&lt;/th>
&lt;th>必填&lt;/th>
&lt;th>说明&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>bucketName&lt;/code>&lt;/td>
&lt;td>是&lt;/td>
&lt;td>OSS Bucket 名称&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>mountDir&lt;/code>&lt;/td>
&lt;td>是&lt;/td>
&lt;td>Sandbox 内挂载目录，必须是绝对路径&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>endpoint&lt;/code>&lt;/td>
&lt;td>是&lt;/td>
&lt;td>OSS Endpoint，&lt;strong>应与 Bucket 所在地域匹配&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>bucketPath&lt;/code>&lt;/td>
&lt;td>否&lt;/td>
&lt;td>Bucket 内子目录，建议绝对路径；&lt;code>/&lt;/code> 或留空表示根目录&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>readOnly&lt;/code>&lt;/td>
&lt;td>否&lt;/td>
&lt;td>&lt;code>true&lt;/code> 时只能读挂载目录&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>几个容易踩的点：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>挂载必须同时配 &lt;code>fc.sandbox.auth.role&lt;/code>，否则沙箱拿不到 OSS 权限。&lt;/strong> 两者缺一不可。&lt;/li>
&lt;li>RAM Role 要授予函数计算服务&lt;strong>可扮演权限&lt;/strong>，并具备访问目标 Bucket 或子目录的 OSS 权限。&lt;/li>
&lt;li>&lt;code>mountDir&lt;/code> 推荐 &lt;code>/mnt/oss&lt;/code> 或 &lt;code>/home/user/oss&lt;/code>，&lt;strong>避免与模板内已有系统目录冲突&lt;/strong>。&lt;/li>
&lt;li>跨地域 &lt;code>endpoint&lt;/code> 会导致延迟升高或访问失败。&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>权限建议是这一页最值得抄的部分&lt;/strong>，因为它正好把之前沙箱选型那篇讲的「最小权限」落到了具体 policy 上：&lt;/p>
&lt;ul>
&lt;li>用 &lt;code>readOnly: true&lt;/code> 挂输入数据目录，避免任务误写或删除源数据。&lt;/li>
&lt;li>写入结果用独立前缀，例如 &lt;code>tenants/&amp;lt;tenant-id&amp;gt;/tasks/&amp;lt;task-id&amp;gt;/outputs/&lt;/code>。&lt;/li>
&lt;li>RAM Policy 只授权任务需要的对象前缀：只读任务给 &lt;code>oss:ListObjects&lt;/code> + &lt;code>oss:GetObject&lt;/code>；读写任务再按需加 &lt;code>oss:PutObject&lt;/code>、&lt;code>oss:DeleteObject&lt;/code>、&lt;code>oss:AbortMultipartUpload&lt;/code>、&lt;code>oss:ListParts&lt;/code>。&lt;/li>
&lt;li>&lt;strong>不要在代码、模板或 metadata 中写长期 AK/SK&lt;/strong>，访问 OSS 走 &lt;code>fc.sandbox.auth.role&lt;/code>。&lt;/li>
&lt;li>临时产物配 OSS 生命周期清理规则。&lt;/li>
&lt;/ul>
&lt;h3 id="自定义域名证书要求比想象中严格">自定义域名：证书要求比想象中严格
&lt;/h3>&lt;p>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/custom-domain-name" target="_blank" rel="noopener"
>自定义域名&lt;/a>解决的是「生产环境要固定域名 + 自有证书」。它把域名分成两条链路：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>用途&lt;/th>
&lt;th>示例&lt;/th>
&lt;th>说明&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>控制链路域名&lt;/td>
&lt;td>&lt;code>api.example.com&lt;/code>&lt;/td>
&lt;td>创建、查询、删除云沙箱等 API 请求&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>数据链路域名&lt;/td>
&lt;td>&lt;code>*.example.com&lt;/code>&lt;/td>
&lt;td>访问沙箱内指定端口的服务&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>对应到 SDK 参数就是 &lt;code>apiUrl&lt;/code> = &lt;code>https://api.example.com&lt;/code>、&lt;code>domain&lt;/code> = &lt;code>example.com&lt;/code>。之后 &lt;code>sandbox.getHost(8000)&lt;/code> 返回的就变成 &lt;code>8000-&amp;lt;sandbox-id&amp;gt;.example.com&lt;/code>，&lt;code>https://{port}-{sandboxId}.example.com&lt;/code> 这种形式。&lt;/p>
&lt;p>限制条件我列一下，因为这几条挺容易在配置阶段反复：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>必须选云沙箱所在地域&lt;/strong>，否则域名解析和证书校验可能不生效。&lt;/li>
&lt;li>&lt;strong>控制链路只支持 &lt;code>api.&lt;/code> 开头的单域名&lt;/strong>；数据链路是控制链路去掉 &lt;code>api.&lt;/code> 前缀后的泛域名。&lt;/li>
&lt;li>&lt;strong>必须 HTTPS。&lt;/strong>&lt;/li>
&lt;li>&lt;strong>证书必须覆盖数据链路泛域名&lt;/strong>（例如 &lt;code>*.example.com&lt;/code>）——只覆盖 &lt;code>api.example.com&lt;/code> 的单域名证书&lt;strong>不满足要求&lt;/strong>。&lt;/li>
&lt;li>&lt;strong>私钥必须是未加密的 RSA PEM 格式。&lt;/strong> 如果你的私钥是 PKCS#8 的 &lt;code>-----BEGIN PRIVATE KEY-----&lt;/code>，要先转换：&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">openssl rsa -in pkcs8.key -out pkcs1.key
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>&lt;strong>不支持中文域名。&lt;/strong>&lt;/li>
&lt;li>同一主账号默认最多绑 &lt;strong>5 个&lt;/strong>云沙箱自定义域名。&lt;/li>
&lt;li>自定义域名需要完成备案或接入备案，以控制台校验结果为准。&lt;/li>
&lt;/ul>
&lt;p>配置要动两个控制台：云沙箱控制台加域名拿 CNAME，再去云解析 DNS 配解析（控制链路主机记录 &lt;code>api&lt;/code>，数据链路主机记录 &lt;code>*&lt;/code>）。配完用 &lt;code>dig +short CNAME api.example.com&lt;/code> 和 &lt;code>dig +short CNAME test.example.com&lt;/code> 验证——&lt;strong>第二条是专门用来验证泛域名解析的&lt;/strong>，这个细节挺贴心。&lt;/p>
&lt;p>还有一个实用提醒：&lt;strong>&lt;code>sandbox.getHost(port)&lt;/code> 返回的是 host，访问时通常要自己拼 &lt;code>https://&lt;/code>。&lt;/strong>&lt;/p>
&lt;h3 id="team-配额管理注意鉴权通道不一样">Team 配额管理：注意鉴权通道不一样
&lt;/h3>&lt;p>这块的&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/quota-management" target="_blank" rel="noopener"
>文档&lt;/a>里有一条我认为最容易被忽略、也最容易配错的信息：&lt;/p>
&lt;blockquote>
&lt;p>Team 配额管理使用 &lt;strong>POP SDK 和阿里云 AK/SK，不使用云沙箱 API Key 鉴权&lt;/strong>。&lt;/p>
&lt;/blockquote>
&lt;p>也就是说，你的系统在这里会同时持有两套凭证：沙箱的 API Key 和阿里云的 AK/SK。&lt;strong>这两套东西的权限模型、轮换策略、泄露影响面都不一样&lt;/strong>，值得在密钥管理上分开对待。文档也重申了「云沙箱 API Key 仍通过函数计算控制台创建和管理」「不要把 AK/SK、API Key 写入代码仓库、镜像、模板、日志、截图、工单或前端页面」。&lt;/p>
&lt;p>前置条件里有一条挺关键：&lt;strong>「已在阿里云控制台联系客服完成加白」&lt;/strong>——所以 Team 配额同样是白名单能力。&lt;/p>
&lt;p>配额模型很简单，以 Team ID 作为 &lt;code>TagValue&lt;/code>，两个配额项：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>字段&lt;/th>
&lt;th>类型&lt;/th>
&lt;th>约束&lt;/th>
&lt;th>说明&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;code>TagValue&lt;/code>&lt;/td>
&lt;td>&lt;code>*string&lt;/code>&lt;/td>
&lt;td>匹配 &lt;code>[A-Za-z0-9_-]{1,64}&lt;/code>&lt;/td>
&lt;td>填 Team ID&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>CpuCores&lt;/code>&lt;/td>
&lt;td>&lt;code>*int32&lt;/code>&lt;/td>
&lt;td>≥ 0&lt;/td>
&lt;td>CPU 核数配额&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;code>MemoryGB&lt;/code>&lt;/td>
&lt;td>&lt;code>*int32&lt;/code>&lt;/td>
&lt;td>≥ 0&lt;/td>
&lt;td>内存 GB 配额&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>设为 &lt;code>0&lt;/code> 表示禁止该 Team 使用对应资源&lt;/strong>（不是「无限制」，别理解反）。&lt;code>UpdateQuota&lt;/code> 是&lt;strong>覆盖式更新&lt;/strong>，同一 &lt;code>TagValue&lt;/code> 多次调用后一次覆盖前一次。&lt;/p>
&lt;p>四个接口和对应的 RAM Action：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>操作&lt;/th>
&lt;th>Go 方法&lt;/th>
&lt;th>RAM Action&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>创建或更新配额&lt;/td>
&lt;td>&lt;code>UpdateQuota&lt;/code>&lt;/td>
&lt;td>&lt;code>fcsandbox:UpdateQuota&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>查询配额&lt;/td>
&lt;td>&lt;code>DescribeQuota&lt;/code>&lt;/td>
&lt;td>&lt;code>fcsandbox:DescribeQuota&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>列出配额&lt;/td>
&lt;td>&lt;code>ListQuota&lt;/code>&lt;/td>
&lt;td>&lt;code>fcsandbox:ListQuota&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>删除配额&lt;/td>
&lt;td>&lt;code>DeleteQuota&lt;/code>&lt;/td>
&lt;td>&lt;code>fcsandbox:DeleteQuota&lt;/code>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>服务的 RAM 授权码是 &lt;code>fcsandbox&lt;/code>。如果要按地域和账号收敛范围，把 &lt;code>Resource&lt;/code> 从 &lt;code>*&lt;/code> 改成 &lt;code>acs:fcsandbox:&amp;lt;region&amp;gt;:&amp;lt;account-id&amp;gt;:*&lt;/code>。&lt;/p>
&lt;p>这也是我和第一节那段绕了一圈的地方：&lt;strong>配额走的是 RAM 这条路，不是 API Key。&lt;/strong> 第一节里说过 &lt;code>fcsandbox&lt;/code> 不在可视化编辑器里、要用脚本编辑手写——所以真正的现象往往是「沙箱跑得好好的，一到配额接口就 401」，因为两条链路上的凭证压根不是同一套。&lt;/p>
&lt;p>用阿里云 POP Go SDK 的骨架：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-go" data-lang="go">&lt;span class="line">&lt;span class="cl">&lt;span class="nx">config&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="o">&amp;amp;&lt;/span>&lt;span class="nx">openapiutil&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">Config&lt;/span>&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">AccessKeyId&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nx">tea&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">String&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">os&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Getenv&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;ALIBABA_CLOUD_ACCESS_KEY_ID&amp;#34;&lt;/span>&lt;span class="p">)),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">AccessKeySecret&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nx">tea&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">String&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">os&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Getenv&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;ALIBABA_CLOUD_ACCESS_KEY_SECRET&amp;#34;&lt;/span>&lt;span class="p">)),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">SecurityToken&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nx">tea&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">String&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">os&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Getenv&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;ALIBABA_CLOUD_SECURITY_TOKEN&amp;#34;&lt;/span>&lt;span class="p">)),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">Endpoint&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nx">tea&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">String&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;fcsandbox.cn-beijing.aliyuncs.com&amp;#34;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">client&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">err&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nx">fcsandbox&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">NewClient&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">config&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">resp&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">err&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nx">client&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">UpdateQuota&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="nx">fcsandbox&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">UpdateQuotaRequest&lt;/span>&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">Body&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="o">&amp;amp;&lt;/span>&lt;span class="nx">fcsandbox&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">Quota&lt;/span>&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">TagValue&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nx">tea&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">String&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">teamID&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">CpuCores&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nx">tea&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Int32&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">32&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">MemoryGB&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nx">tea&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Int32&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">32&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>错误码表（也可以当排错用）：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>HTTP&lt;/th>
&lt;th>Code&lt;/th>
&lt;th>说明&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>400&lt;/td>
&lt;td>&lt;code>InvalidParameter&lt;/code>&lt;/td>
&lt;td>参数校验失败，缺少必填字段或格式不合法&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>401&lt;/td>
&lt;td>&lt;code>Unauthorized&lt;/code>&lt;/td>
&lt;td>凭证无效或未提供&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>403&lt;/td>
&lt;td>&lt;code>Forbidden&lt;/code>&lt;/td>
&lt;td>无权操作&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>404&lt;/td>
&lt;td>&lt;code>ResourceQuotaNotFound&lt;/code>&lt;/td>
&lt;td>查询的配额不存在&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>429&lt;/td>
&lt;td>&lt;code>LimitExceeded&lt;/code>&lt;/td>
&lt;td>超出配额限制&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>500&lt;/td>
&lt;td>&lt;code>InternalError&lt;/code>&lt;/td>
&lt;td>服务内部错误&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>删除配额后再查会返回 404，&lt;strong>但可能有短暂的最终一致性延迟&lt;/strong>，文档建议用有上限的轮询确认——「有上限」三个字是重点。&lt;/p>
&lt;p>使用建议里我最认同两条：&lt;strong>「不要让测试任务和生产任务共用同一个高配额 Team」&lt;/strong>，以及 &lt;strong>「配额只解决资源上限问题，不能替代业务侧限流、任务队列、超时控制和资源释放」&lt;/strong>。后者是在提醒你：配额是天花板，不是限流器；撞到天花板的失败模式和排队等待完全不一样。&lt;/p>
&lt;h3 id="日志采集要确认的三件事">日志采集要确认的三件事
&lt;/h3>&lt;p>前面坑四里说过，E2B 的 Logs 接口返回空数组是已知行为。正路是走&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/monitoring-and-logging" target="_blank" rel="noopener"
>监控与日志&lt;/a>。那一页有一句我觉得该抄进设计文档的话：&lt;/p>
&lt;blockquote>
&lt;p>应用侧可以记录 sandboxId、任务 ID 和命令结果，便于在云上监控或日志页面中定位问题。&lt;/p>
&lt;/blockquote>
&lt;p>它还把常见观测对象列成了清单，可以直接当埋点需求单用：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Sandbox 生命周期&lt;/strong>：创建、连接、暂停、恢复、终止。&lt;/li>
&lt;li>&lt;strong>命令执行结果&lt;/strong>：退出码、stdout、stderr、耗时。&lt;/li>
&lt;li>&lt;strong>资源使用&lt;/strong>：CPU、内存、磁盘和网络。&lt;/li>
&lt;li>&lt;strong>关联字段&lt;/strong>：&lt;code>sandboxId&lt;/code>、任务 ID、用户或租户标识、模板名称。&lt;/li>
&lt;li>&lt;strong>结构化日志&lt;/strong>：&lt;code>event&lt;/code>、&lt;code>taskId&lt;/code>、&lt;code>sandboxId&lt;/code>、&lt;code>exitCode&lt;/code>、stdout / stderr 摘要。&lt;/li>
&lt;/ul>
&lt;p>注意这里列了「资源使用：CPU、内存、磁盘和网络」——&lt;strong>但指标接口的磁盘字段是占位值&lt;/strong>，所以真实数据得从控制台或云监控拿。这两处放在一起看，能看出「观测对象」和「可获取的数据源」是两件事。&lt;/p>
&lt;h2 id="八迁不动的那部分怎么办">八、迁不动的那部分怎么办
&lt;/h2>&lt;p>几个决策，我按「原来怎么做 → 现在怎么做」列一下（&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/e2b-compatibility-and-migration" target="_blank" rel="noopener"
>E2B 兼容与迁移&lt;/a>）：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>原来（E2B 原生）&lt;/th>
&lt;th>现在（云沙箱）&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Volume 做持久化&lt;/td>
&lt;td>换 NAS / OSS；跨 Sandbox 的数据本来就不该放本地文件系统&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>SDK 管理 API Key&lt;/td>
&lt;td>函数计算控制台创建、查看、编辑、重置、禁用、删除&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Team 管理&lt;/td>
&lt;td>函数计算控制台（创建 Team 见&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/create-team" target="_blank" rel="noopener"
>创建 Team&lt;/a>，订阅计划见 &lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/team-and-subscription-plans" target="_blank" rel="noopener"
>Team 与订阅计划&lt;/a>）&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Snapshot 做状态分叉&lt;/td>
&lt;td>可以，但要白名单 + 第二代运行时，且注意命名与超时规则与官方不同&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>文件自定义元数据&lt;/td>
&lt;td>不支持；改用控制面 &lt;code>metadata&lt;/code>，或把标签写进业务库 / JSON 清单&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>依赖 E2B 的 Logs 接口&lt;/td>
&lt;td>换成函数计算日志采集 + 业务侧结构化日志&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>依赖 E2B 的网络配置更新接口&lt;/td>
&lt;td>换到云沙箱控制面&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>想要固定域名和自有证书&lt;/td>
&lt;td>用 FC Extensions 的&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/custom-domain-name" target="_blank" rel="noopener"
>自定义域名&lt;/a>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>沙箱要访问内网 RDS / Redis / NAS&lt;/td>
&lt;td>用 FC Extensions 的 &lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/vpc-network-configuration-1" target="_blank" rel="noopener"
>VPC 网络配置&lt;/a>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>E2B 托管 MCP Gateway / BYOC&lt;/td>
&lt;td>不在兼容路径里，需要单独设计&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>API Key 的隔离策略&lt;/strong>值得单独说一句：按应用、环境、团队或租户拆分 Key，不要多人多系统共用一个长期 Key；生产用自定义过期时间并定期轮换；&lt;strong>重置或删除前先确认业务侧已经切到新 Key&lt;/strong>——这条写在文档里，但我猜真出事的时候是「先重置，再发现有三个服务挂了」。&lt;/p>
&lt;p>还有一条和 E2B 一样的老常识，仍然要重复一遍：&lt;strong>Sandbox 的本地文件系统只适合当前任务内的临时文件。&lt;/strong> Sandbox 终止之后，这些文件不应该被当成持久数据依赖。临时输入、生成代码和中间结果建议写 &lt;code>/tmp&lt;/code> 或业务自定义工作目录。&lt;/p>
&lt;p>以及从沙箱选型那篇就一直在强调的点：处理用户上传路径时，要限制文件大小、文件类型和可写路径，别把未校验的路径直接传给 Filesystem API 或命令行。&lt;strong>这一点和用哪家沙箱无关&lt;/strong>——沙箱防的是代码逃逸，不防你的业务逻辑被 prompt injection 牵着走。浏览器模板那一页把这条说得更直接：&lt;strong>网页内容和下载文件都可能携带 prompt injection。&lt;/strong>&lt;/p>
&lt;h2 id="九上生产前必须确认的边界">九、上生产前必须确认的边界
&lt;/h2>&lt;p>这一节是&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/usage-constraints-of-fc-agent-sandbox" target="_blank" rel="noopener"
>使用约束&lt;/a>的整理。官方把话说得很直接：&lt;strong>快速入门只演示最小接入路径，实际业务接入前应先确认本文约束。&lt;/strong>&lt;/p>
&lt;h3 id="配额六类不能假设无限">配额：六类不能假设无限
&lt;/h3>&lt;ul>
&lt;li>单账号或单地域&lt;strong>并发 Sandbox 数&lt;/strong>&lt;/li>
&lt;li>单个 Sandbox 可用的 &lt;strong>CPU、内存和本地磁盘空间&lt;/strong>&lt;/li>
&lt;li>单个 Sandbox 可打开的&lt;strong>进程数、端口数、文件数&lt;/strong>&lt;/li>
&lt;li>单次任务的&lt;strong>输入、输出文件大小&lt;/strong>&lt;/li>
&lt;li>&lt;strong>模板构建&lt;/strong>的并发数、构建资源和构建时长&lt;/li>
&lt;li>&lt;strong>端口访问&lt;/strong>&lt;/li>
&lt;/ul>
&lt;p>超出默认配额时，Sandbox 创建、模板构建或任务执行都可能失败。需要更高配额要走控制台或阿里云支持渠道申请。&lt;strong>这条对做 To C 产品的人尤其重要&lt;/strong>——你的并发上限不是你代码写的并发数，是账号配额。&lt;/p>
&lt;h3 id="生命周期">生命周期
&lt;/h3>&lt;p>Sandbox 创建后会持续占用资源，直到被主动终止、超时回收，或进入支持的暂停状态。任务完成后 &lt;code>kill()&lt;/code>。&lt;/p>
&lt;p>三个和生命周期相关的数字放在一起记：&lt;strong>上限 24 小时（86400 秒）、空闲超时下限 60 秒、命令超时默认 60 秒。&lt;/strong> 超时参数单位差异再说一遍：&lt;strong>Python 通常用秒，TypeScript 用毫秒。&lt;/strong>&lt;/p>
&lt;h3 id="文件与存储">文件与存储
&lt;/h3>&lt;ul>
&lt;li>本地文件系统只服务当前 Sandbox 生命周期。&lt;/li>
&lt;li>跨 Sandbox 保留、共享或长期保存的数据写 NAS / OSS。&lt;/li>
&lt;li>处理用户上传时限制文件大小、类型和可写路径。&lt;/li>
&lt;/ul>
&lt;h2 id="十一份可执行的迁移顺序">十、一份可执行的迁移顺序
&lt;/h2>&lt;p>如果你手上有现成的 E2B 应用，我会建议按这个顺序推，每一步都有明确的验收点：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>开通、建 Team、建 Key。&lt;/strong> 确认目标地域支持云沙箱、账号已开通云沙箱功能，按「项目 × 环境」建 Team，再在 Team 下创建 API Key，描述写清楚用途。&lt;strong>这一步会同时决定你要不要那段 &lt;code>fcsandbox&lt;/code> 策略&lt;/strong>——只用 SDK 就不需要，要在 OpenAPI 侧管资源才要。&lt;/li>
&lt;li>&lt;strong>定地域、配环境变量、钉版本。&lt;/strong> 选出地域，配好三个环境变量，把 SDK 版本写进 requirements / package.json，别用 &lt;code>latest&lt;/code>。&lt;/li>
&lt;li>&lt;strong>跑最小验证，只验证四件事&lt;/strong>：创建 Sandbox、执行命令、读写文件、释放资源。文档原话是「不要一开始就迁移复杂模板、网络和存储逻辑」——这个顺序是对的，因为它把变量控制在最少。&lt;/li>
&lt;li>&lt;strong>想清楚用哪个模板，别让默认值替你做决定。&lt;/strong> 要 &lt;code>run_code&lt;/code> 就必须装 &lt;code>e2b-code-interpreter&lt;/code> / &lt;code>@e2b/code-interpreter&lt;/code>；用通用 &lt;code>e2b&lt;/code> SDK 时&lt;strong>必须显式传 &lt;code>template&lt;/code>&lt;/strong>，不传会落到 &lt;code>base&lt;/code>。&lt;/li>
&lt;li>&lt;strong>再迁自定义模板。&lt;/strong> 用官方镜像先跑通构建流程，再换自己的 ACR EE 镜像；构建前对着镜像要求表逐条核一遍，并确认镜像仓库、VPC 和沙箱同地域。&lt;/li>
&lt;li>&lt;strong>需要浏览器能力的话，这里才开始&lt;/strong>。browser / All-In-One 都要先构建模板，再注意 &lt;code>/health&lt;/code> 轮询、&lt;code>X-Access-Token&lt;/code>、窗口尺寸烤镜像这几件事。&lt;/li>
&lt;li>&lt;strong>迁移时同步做「能力减法」&lt;/strong>：把 Volume、Access Token、Team 管理、文件自定义元数据、E2B Logs 接口这些从代码里挑出来，换成 NAS / OSS、控制台、控制面 &lt;code>metadata&lt;/code> 和日志采集。&lt;/li>
&lt;li>&lt;strong>最后才是网络和可观测。&lt;/strong> VPC、OSS 挂载、自定义域名、日志采集、Team 配额，都属于 FC Extensions，走 metadata 或控制面配置，不占用迁移改造的窗口。&lt;/li>
&lt;li>&lt;strong>上线前补三样东西&lt;/strong>：显式的 &lt;code>kill()&lt;/code> 释放路径（&lt;code>try/finally&lt;/code>、&lt;code>defer&lt;/code> 或 &lt;code>AutoCloseable&lt;/code> 都行）、业务侧的 &lt;code>taskId ↔ sandboxId&lt;/code> 映射、以及结构化日志。&lt;/li>
&lt;/ol>
&lt;h2 id="十一排错对照表">十一、排错对照表
&lt;/h2>&lt;p>踩过一轮之后，我把「现象 → 先查什么」整理成了一张表，比按文档目录翻快：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>现象&lt;/th>
&lt;th>优先排查&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>认证失败 / 模板不可见&lt;/td>
&lt;td>三个环境变量是否配全、Key 是否被禁用或重置、账号与地域是否一致&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>创建失败、连接失败、模板找不到&lt;/td>
&lt;td>API URL、域名、模板、Sandbox &lt;strong>是否同地域&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>连接失败&lt;/td>
&lt;td>目标 Sandbox 是否已终止、超时回收，或不属于当前账号 / 地域&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Sandbox 创建成功但 &lt;code>run_code&lt;/code> 失败&lt;/td>
&lt;td>&lt;strong>SDK 是否装错&lt;/strong>；通用 &lt;code>e2b&lt;/code> SDK 不传模板会落到 &lt;code>base&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>内置模板正常、自定义模板 &lt;code>run_code&lt;/code> 失败&lt;/td>
&lt;td>自定义模板的 Code Interpreter 依赖、启动命令、监听端口、就绪条件&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>TypeScript 里上下文管理方法不可用&lt;/td>
&lt;td>该能力当前&lt;strong>仅 Python SDK&lt;/strong> 提供&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>写入报 &lt;code>File metadata requires envd 0.6.2 or later&lt;/code>&lt;/td>
&lt;td>用了文件自定义元数据，当前不支持；改用控制面 &lt;code>metadata&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>上传 / 下载 URL 403&lt;/td>
&lt;td>创建 Sandbox 时是否显式设了 &lt;code>secure=false&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>服务起来 60 秒后被杀&lt;/td>
&lt;td>命令超时默认 60 秒，后台进程要显式设 &lt;code>timeout&lt;/code> / &lt;code>timeoutMs&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>PTY 输出解析不了&lt;/td>
&lt;td>PTY 会改变输出格式；批处理应该用 &lt;code>commands.run()&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>浏览器端点 403&lt;/td>
&lt;td>请求头缺 &lt;code>X-Access-Token&lt;/code>（&lt;code>sbx._envd_access_token&lt;/code> / &lt;code>sbx.envdAccessToken&lt;/code>）&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>noVNC 连不上&lt;/td>
&lt;td>浏览器 WebSocket API 不能带自定义 header；改用支持 header 的客户端，或直接截图&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>CDP 探测返回退出码 28&lt;/td>
&lt;td>正常现象，看响应里有没有 &lt;code>101 Switching Protocols&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>改了浏览器窗口尺寸没生效&lt;/td>
&lt;td>&lt;code>envs&lt;/code> 不影响浏览器栈，要烤进镜像（&lt;code>RESOLUTION&lt;/code> 等）&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>browser / All-In-One 创建模板失败&lt;/td>
&lt;td>跨地域镜像构建会失败，镜像地址里的地域要换成沙箱地域&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>建了带 VPC 的沙箱但内网连不通&lt;/td>
&lt;td>安全组出方向、目标资源白名单里的 &lt;strong>vSwitch 网段&lt;/strong>、服务监听状态&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>挂载 OSS 后没有权限&lt;/td>
&lt;td>是否同时配了 &lt;code>fc.sandbox.auth.role&lt;/code>（RAM Role ARN）&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>自定义域名证书校验失败&lt;/td>
&lt;td>证书要覆盖&lt;strong>数据链路泛域名&lt;/strong>（&lt;code>*.example.com&lt;/code>），且私钥是未加密 RSA PEM&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>改了网络策略没生效&lt;/td>
&lt;td>Network Config Update 是受限能力，要去控制面改&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>抓不到沙箱日志&lt;/td>
&lt;td>E2B Logs 接口返回空数组是已知行为，走函数计算日志采集&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>容量 / 费用看着不对&lt;/td>
&lt;td>别用 Metrics 的磁盘字段（占位值），以控制台 / 云监控 / 日志服务为准&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>创建 Snapshot 超时&lt;/td>
&lt;td>&lt;code>request_timeout&lt;/code> 是否 ≥ 300；&lt;strong>先查是否已建成，不要无条件重试&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>沙箱列表里找不到失败的快照&lt;/td>
&lt;td>&lt;code>snapshot_failed&lt;/code> 状态默认不显示，要按状态过滤&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>刚建的 Snapshot 列表里看不到&lt;/td>
&lt;td>索引延迟；直接用创建返回的 &lt;code>snapshotId&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Team 配额调用报 401 / 403&lt;/td>
&lt;td>配额用 &lt;strong>AK/SK + &lt;code>fcsandbox&lt;/code> RAM 授权&lt;/strong>，不用沙箱 API Key&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>RAM 控制台搜不到 &lt;code>fcsandbox&lt;/code>&lt;/td>
&lt;td>该服务不在可视化编辑器的服务列表里，改用&lt;strong>脚本编辑&lt;/strong>手写 action&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>建策略后仍建不了模板 / API Key&lt;/td>
&lt;td>Team 级策略要同时给 &lt;code>teams/&amp;lt;id&amp;gt;&lt;/code> 和 &lt;code>teams/&amp;lt;id&amp;gt;/*&lt;/code>，只给前者会「看得见动不了」&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>沙箱能跑，但 OpenAPI 管不了 Team / API Key&lt;/td>
&lt;td>两套鉴权别混：SDK / CLI 用 API Key，控制台 / OpenAPI 用 RAM 策略 + AK/SK&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>模板构建失败&lt;/td>
&lt;td>先查镜像仓库、网络、账号权限，再查 SDK 参数&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>SDK 可用但 CLI 不可用&lt;/td>
&lt;td>CLI 版本、&lt;code>E2B_API_KEY&lt;/code>、&lt;code>E2B_API_URL&lt;/code>、&lt;code>E2B_DOMAIN&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>CLI 行为与文档不一致&lt;/td>
&lt;td>先 &lt;code>e2b --version&lt;/code> 和 &lt;code>&amp;lt;cmd&amp;gt; --help&lt;/code>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="十二文档地图">十二、文档地图
&lt;/h2>&lt;p>上面所有结论都来自官方文档。我把 38 页按分组列在这里，并标了每页在本文的对应位置——&lt;strong>标「—」的是我提了一句但没展开的，需要细节请直接点链接。&lt;/strong>&lt;/p>
&lt;p>&lt;strong>入门与接入&lt;/strong>&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>页面&lt;/th>
&lt;th>内容&lt;/th>
&lt;th>本文位置&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/product-overview-of-fc-agent-sandbox" target="_blank" rel="noopener"
>产品简介&lt;/a>&lt;/td>
&lt;td>定位、五类场景、八个核心对象、基本使用路径&lt;/td>
&lt;td>第一节&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/create-api-key" target="_blank" rel="noopener"
>创建 API Key&lt;/a>&lt;/td>
&lt;td>控制台创建步骤、过期时间、编辑/重置/删除、安全建议&lt;/td>
&lt;td>第一节&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/using-the-cloud-sandbox-via-the-sdk" target="_blank" rel="noopener"
>通过 SDK 使用云沙箱&lt;/a>&lt;/td>
&lt;td>Python / TypeScript 快速入门、版本要求&lt;/td>
&lt;td>第一节&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/using-the-cloud-sandbox-via-the-cli" target="_blank" rel="noopener"
>通过 CLI 使用云沙箱&lt;/a>&lt;/td>
&lt;td>CLI 安装、八步操作流程、各命令示例&lt;/td>
&lt;td>第三节&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/e2b-sdk-integration-parameter-description" target="_blank" rel="noopener"
>E2B SDK 接入参数说明&lt;/a>&lt;/td>
&lt;td>三个环境变量与 SDK 参数逐个对应、snake/camel 差异、不作为接入参数的能力&lt;/td>
&lt;td>第一、二节&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>兼容与迁移&lt;/strong>&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>页面&lt;/th>
&lt;th>内容&lt;/th>
&lt;th>本文位置&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/e2b-compatibility-explanation" target="_blank" rel="noopener"
>E2B 兼容说明&lt;/a>&lt;/td>
&lt;td>四档兼容状态、各模块完整方法清单、受限与暂不兼容能力&lt;/td>
&lt;td>第三节&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/e2b-sdk-compatible-api-list" target="_blank" rel="noopener"
>E2B SDK 兼容 API 清单&lt;/a>&lt;/td>
&lt;td>按对象罗列的兼容方法、使用建议&lt;/td>
&lt;td>第三节&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/e2b-compatibility-and-migration" target="_blank" rel="noopener"
>E2B 兼容与迁移&lt;/a>&lt;/td>
&lt;td>迁移四件事、地域一致性、常见问题&lt;/td>
&lt;td>第一、八节&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/e2b-sdk-java-and-go" target="_blank" rel="noopener"
>E2B SDK（Java 与 Go）&lt;/a>&lt;/td>
&lt;td>两个 SDK 的安装与快速入门、Maven / replace 注意事项&lt;/td>
&lt;td>第二节&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/usage-constraints-of-fc-agent-sandbox" target="_blank" rel="noopener"
>使用约束&lt;/a>&lt;/td>
&lt;td>地域、版本、鉴权、六类配额、生命周期、模板构建、文件存储&lt;/td>
&lt;td>第九节&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>Sandbox 功能&lt;/strong>&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>页面&lt;/th>
&lt;th>内容&lt;/th>
&lt;th>本文位置&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/create-a-sandbox" target="_blank" rel="noopener"
>创建沙箱&lt;/a>&lt;/td>
&lt;td>&lt;code>Sandbox.create&lt;/code> 参数（&lt;code>timeoutMs&lt;/code> / &lt;code>envs&lt;/code> / &lt;code>metadata&lt;/code>）、Python 与 TS 传参差异&lt;/td>
&lt;td>第三节&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/lifecycle" target="_blank" rel="noopener"
>生命周期&lt;/a>&lt;/td>
&lt;td>创建、连接、查询、终止、设置超时&lt;/td>
&lt;td>第三节&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/timeout" target="_blank" rel="noopener"
>超时&lt;/a>&lt;/td>
&lt;td>创建时配置、创建后调整、单位差异&lt;/td>
&lt;td>第三节&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/pause-and-resume" target="_blank" rel="noopener"
>暂停与恢复&lt;/a>&lt;/td>
&lt;td>白名单、&lt;code>pause()&lt;/code>、连接时自动恢复、使用建议&lt;/td>
&lt;td>第五节&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/environment-variable" target="_blank" rel="noopener"
>环境变量&lt;/a>&lt;/td>
&lt;td>沙箱级与命令级 &lt;code>envs&lt;/code>、覆盖规则&lt;/td>
&lt;td>第六节&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/metadata" target="_blank" rel="noopener"
>元数据&lt;/a>&lt;/td>
&lt;td>控制面 &lt;code>metadata&lt;/code> 写法、与环境变量的区别&lt;/td>
&lt;td>第四节&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/snapshots" target="_blank" rel="noopener"
>快照（邀测）&lt;/a>&lt;/td>
&lt;td>API 表、名称规则、保留 7 天、请求超时 300 秒、十种失败条件、参数覆盖清单&lt;/td>
&lt;td>第五节&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>Commands 与 Filesystem&lt;/strong>&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>页面&lt;/th>
&lt;th>内容&lt;/th>
&lt;th>本文位置&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/run-the-command" target="_blank" rel="noopener"
>运行命令&lt;/a>&lt;/td>
&lt;td>&lt;code>commands.*&lt;/code> 方法清单、与 PTY 的分工&lt;/td>
&lt;td>第三节&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/backend-command" target="_blank" rel="noopener"
>后台命令&lt;/a>&lt;/td>
&lt;td>&lt;code>background=True&lt;/code>、&lt;code>getHost&lt;/code>、进程连接与终止、命令超时默认 60 秒&lt;/td>
&lt;td>第三节&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/pty" target="_blank" rel="noopener"
>PTY&lt;/a>&lt;/td>
&lt;td>&lt;code>pty.create&lt;/code> / &lt;code>send_stdin&lt;/code> / &lt;code>wait&lt;/code> / &lt;code>resize&lt;/code> / &lt;code>connect&lt;/code>、何时该用 PTY&lt;/td>
&lt;td>第三节&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/read-and-write-files" target="_blank" rel="noopener"
>读写文件&lt;/a>&lt;/td>
&lt;td>方法清单、批量写入、二进制与流、目录监听&lt;/td>
&lt;td>第三节&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/upload-and-download-files" target="_blank" rel="noopener"
>上传和下载文件&lt;/a>&lt;/td>
&lt;td>&lt;code>uploadUrl&lt;/code> / &lt;code>downloadUrl&lt;/code>、&lt;strong>&lt;code>secure=false&lt;/code> 要求&lt;/strong>、选型建议&lt;/td>
&lt;td>第四节&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/custom-metadata" target="_blank" rel="noopener"
>自定义元数据&lt;/a>&lt;/td>
&lt;td>不支持文件自定义元数据、失败行为、三条替代方案&lt;/td>
&lt;td>第四节&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>Code Interpreter&lt;/strong>&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>页面&lt;/th>
&lt;th>内容&lt;/th>
&lt;th>本文位置&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/overview-1" target="_blank" rel="noopener"
>Code Interpreter 概览&lt;/a>&lt;/td>
&lt;td>Code Interpreter 能力总览&lt;/td>
&lt;td>第三节&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/using-the-code-interpreter-sandbox" target="_blank" rel="noopener"
>使用 Code Interpreter Sandbox&lt;/a>&lt;/td>
&lt;td>四步推荐流程、固定脚本入口优于 &lt;code>run_code&lt;/code>、六条上线建议&lt;/td>
&lt;td>第六节&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>模板&lt;/strong>&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>页面&lt;/th>
&lt;th>内容&lt;/th>
&lt;th>本文位置&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/built-in-templates" target="_blank" rel="noopener"
>内置模板&lt;/a>&lt;/td>
&lt;td>三个内置模板清单、哪些需要自行构建、如何查看&lt;/td>
&lt;td>第六节&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/base-template" target="_blank" rel="noopener"
>base 模板&lt;/a>&lt;/td>
&lt;td>功能特性、默认配置（2 vCPU / 2048 MB）、&lt;strong>不传 template 时的默认值&lt;/strong>&lt;/td>
&lt;td>第六节&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/code-interpreter-v1-template" target="_blank" rel="noopener"
>code-interpreter-v1 模板&lt;/a>&lt;/td>
&lt;td>默认端口 5000、24 小时上限、空闲超时下限、&lt;code>run_code&lt;/code> 参数与默认超时、上下文管理仅 Python&lt;/td>
&lt;td>第三、六节&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/browser-template" target="_blank" rel="noopener"
>browser 模板&lt;/a>&lt;/td>
&lt;td>镜像与规格、CDP / VNC 端点、&lt;code>X-Access-Token&lt;/code>、窗口尺寸烤镜像、构建与验证&lt;/td>
&lt;td>第六节&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/all-in-one-template" target="_blank" rel="noopener"
>All-In-One 模板&lt;/a>&lt;/td>
&lt;td>与 browser 的差异、3000 + 5000 双端口、跨地域构建会失败&lt;/td>
&lt;td>第六节&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/use-browser-use-sandbox" target="_blank" rel="noopener"
>使用 Browser Use Sandbox&lt;/a>&lt;/td>
&lt;td>八步推荐流程、Puppeteer 示例、BrowserUse 接入、六条上线建议&lt;/td>
&lt;td>第六节&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/using-aio-sandbox" target="_blank" rel="noopener"
>使用 AIO Sandbox&lt;/a>&lt;/td>
&lt;td>浏览器 + 代码执行协同流程、固定任务目录、接入建议&lt;/td>
&lt;td>第六节&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/templates" target="_blank" rel="noopener"
>快速开始（模板）&lt;/a>&lt;/td>
&lt;td>&lt;code>Template.build&lt;/code> 用法、从模板创建沙箱&lt;/td>
&lt;td>第六节&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/template-name" target="_blank" rel="noopener"
>模板名称与版本&lt;/a>&lt;/td>
&lt;td>命名建议、标签 &lt;code>assignTags&lt;/code> / &lt;code>getTags&lt;/code> / &lt;code>removeTags&lt;/code>、&lt;code>default&lt;/code> 不可删&lt;/td>
&lt;td>第六节&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/build-a-custom-image-template" target="_blank" rel="noopener"
>构建自定义镜像模板&lt;/a>&lt;/td>
&lt;td>ACR EE 前置条件、镜像要求表、官方镜像地址、构建脚本&lt;/td>
&lt;td>第六节&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>其他模板（Desktop / Claude Code / OpenClaw 等）&lt;/td>
&lt;td>需从对应官方镜像自行构建&lt;/td>
&lt;td>第六节（未展开）&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>FC Extensions&lt;/strong>&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>页面&lt;/th>
&lt;th>内容&lt;/th>
&lt;th>本文位置&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/fc-extensions-overview" target="_blank" rel="noopener"
>FC Extensions 概览&lt;/a>&lt;/td>
&lt;td>七项扩展、五步使用方式、注意事项&lt;/td>
&lt;td>第七节&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/vpc-network-configuration-1" target="_blank" rel="noopener"
>VPC 网络配置&lt;/a>&lt;/td>
&lt;td>&lt;code>fc.sandbox.network.vpc&lt;/code> metadata 格式、前置条件、连通性验证、常见问题&lt;/td>
&lt;td>第七节&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/mount-oss-dynamically-1" target="_blank" rel="noopener"
>动态挂载 OSS&lt;/a>&lt;/td>
&lt;td>&lt;code>fc.sandbox.storage.oss&lt;/code> + &lt;code>fc.sandbox.auth.role&lt;/code>、挂载字段、RAM Policy 建议&lt;/td>
&lt;td>第七节&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/custom-domain-name" target="_blank" rel="noopener"
>自定义域名&lt;/a>&lt;/td>
&lt;td>控制链路 / 数据链路域名、证书与私钥要求、DNS 配置、五步验证&lt;/td>
&lt;td>第七节&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/monitoring-and-logging" target="_blank" rel="noopener"
>监控与日志&lt;/a>&lt;/td>
&lt;td>配置入口与生效范围、结构化日志、常见观测对象&lt;/td>
&lt;td>第四、七节&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/quota-management" target="_blank" rel="noopener"
>Team 配额管理&lt;/a>&lt;/td>
&lt;td>POP SDK + AK/SK 鉴权、配额模型、四个接口、RAM 授权、错误码&lt;/td>
&lt;td>第七节&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/agent-sandbox/getting-started/configure-ram-user-permissions" target="_blank" rel="noopener"
>配置 RAM 用户权限&lt;/a>&lt;/td>
&lt;td>两套鉴权方式的边界、&lt;code>fcsandbox&lt;/code> action 与 ARN 格式、三种授权粒度、常见误区&lt;/td>
&lt;td>第一节&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/agent-sandbox/getting-started/create-team" target="_blank" rel="noopener"
>创建 Team&lt;/a>&lt;/td>
&lt;td>创建 Team、获取 Team ID、资源组与订阅计划&lt;/td>
&lt;td>第一节&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/team-and-subscription-plans" target="_blank" rel="noopener"
>Team 与订阅计划&lt;/a>&lt;/td>
&lt;td>Team 与订阅计划的关系&lt;/td>
&lt;td>—&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/create-oss-volume" target="_blank" rel="noopener"
>创建 OSS Volume&lt;/a>&lt;/td>
&lt;td>为 OSS Bucket 或子目录创建可复用挂载配置&lt;/td>
&lt;td>—&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;a class="link" href="https://help.aliyun.com/zh/functioncompute/create-an-agenticfs-volume" target="_blank" rel="noopener"
>创建 AgenticFS Volume&lt;/a>&lt;/td>
&lt;td>为 AgenticFS Access Point 创建可复用挂载配置&lt;/td>
&lt;td>—&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="总结">总结
&lt;/h2>&lt;p>几点收获：&lt;/p>
&lt;p>&lt;strong>1. 「协议兼容」比「接口兼容」值钱得多。&lt;/strong> 三个环境变量就能跑通，是因为它兼容的是数据面协议，而不是照着表抄了一遍方法名——这也是 Java / Go SDK 能被第三方写出来的前提。代价是你得把 SDK 版本钉住，因为协议对齐是跟着版本走的，而且 Python 与 TypeScript 的参数名和单位还不一样。&lt;/p>
&lt;p>&lt;strong>2. 兼容清单要当成契约读，重点看「受限」和「暂不兼容」那两档。&lt;/strong> 「能调用」不等于「有效果」。Logs 返回空数组、Network Config Update 返回成功但不生效，这两个如果只看方法名不看文档，最后会以「线上偶发空白」和「改了没反应」的形式还给你。&lt;/p>
&lt;p>&lt;strong>3. 默认值是这个系统里最需要审计的东西。&lt;/strong> 通用 SDK 不传模板落到 &lt;code>base&lt;/code>（没有 Code Interpreter）、命令超时默认 60 秒、Snapshot 请求超时默认 60 秒但它要跑好几分钟、Snapshot 默认保留 7 天、&lt;code>secure&lt;/code> 默认要求带 token——&lt;strong>这五个默认值凑在一起，就是一个「Demo 能跑、生产出事」的配置集合。&lt;/strong> 文档里专门写了「不要无条件重试」，这种提醒通常意味着它真的发生过。&lt;/p>
&lt;p>&lt;strong>4. 静默失败比报错更贵。&lt;/strong> 这次真正花时间的坑，基本都不抛异常。&lt;code>metadata&lt;/code> 那个算厚道的——至少在发请求前把你拦下来了；&lt;code>secure&lt;/code> 和 Network Config Update 连拦都不拦。判断一个兼容层成熟不成熟，可以看它有多少能力是「返回成功但什么都没做」。&lt;/p>
&lt;p>&lt;strong>5. 跨语言抄示例是新的高频错误源。&lt;/strong> &lt;code>timeout&lt;/code> 秒 vs &lt;code>timeoutMs&lt;/code> 毫秒、&lt;code>api_key&lt;/code> vs &lt;code>apiKey&lt;/code>、&lt;code>make_dir&lt;/code> vs &lt;code>makeDir&lt;/code>、&lt;code>get_tags&lt;/code> 要传模板 ID 而 TS 传模板名、TS 里模板是第一个位置参数&lt;strong>但没模板时 options 又跑到第一位&lt;/strong>——同一个功能两套写法，而 SDK 不会因为你传错字段名报错，只会用默认值继续跑。&lt;strong>这类错误的共同特征是不报错，所以只能靠纪律防。&lt;/strong>&lt;/p>
&lt;p>&lt;strong>6. 「兼容」两个字的颗粒度，比你想的细。&lt;/strong> 同一个 Code Interpreter，&lt;code>run_code&lt;/code> 在两种语言里都通，但上下文管理只有 Python 有；同一个 Snapshot，创建和恢复能用，命名和删除路径又和官方不同。&lt;strong>迁移检查表要按「方法 × 语言 × 平台」三维核对，不能按模块粗过。&lt;/strong>&lt;/p>
&lt;p>&lt;strong>7. 白名单能力不要写进架构。&lt;/strong> pause、Snapshot、Team 配额都要加白。能开不代表一直在，当成设计前提就是把可用性挂在别人的后台配置上。&lt;/p>
&lt;p>&lt;strong>8. 云沙箱的差异化在 E2B SDK 之外。&lt;/strong> 真正的增量是 FC Extensions——VPC、OSS、自定义域名、日志、配额。如果你的场景需要这些，那这套东西的价值远不止「国内能连上的 E2B」；如果不需要，它就成了架构里一块只属于这朵云的代码。&lt;/p>
&lt;p>&lt;strong>9. 同一朵云里并存两套鉴权，是新的认知负担。&lt;/strong> API Key 管数据面，RAM 权限策略管控制台和 OpenAPI，管配额还要再叠一层 AK/SK。它们报的错长得几乎一样（401 / 403），但该修的地方完全不同。&lt;strong>排查任何「没权限」之前，先确认自己走的是哪条链路&lt;/strong>——我这次的弯路，就是从「以为只有一套凭证」开始的。还有一个附带结论：&lt;code>fcsandbox&lt;/code> 这种新服务不在 RAM 可视化编辑器里，是正常现象，不是你的账号有问题。&lt;/p>
&lt;p>&lt;strong>10. 顺手再提醒一次地域。&lt;/strong> &lt;code>E2B_API_URL&lt;/code>、&lt;code>E2B_DOMAIN&lt;/code>、模板、Sandbox 必须同地域；镜像仓库、VPC、自定义域名也都要同地域。这条排在最前面，也最容易在第一次接入时踩到，因为它和「Key 填错了」的现象几乎一样——都是认证或创建失败，而人的第一反应通常是去查 Key。&lt;/p></description></item></channel></rss>