
1. OpenHands Runtime 沙箱执行链路到底在跑什么OpenHands Runtime 是 OpenHands 这个 AI Agent 框架里真正“动手干活”的那一层。你可以把它理解成一个被 Agent 大脑遥控的隔离工作间Agent 负责思考下一步做什么Runtime 负责在沙箱里把这一步真正执行出来——跑 shell 命令、读写文件、启动浏览器、执行 Python 脚本然后把结果回传给 Agent。它解决的问题很具体让大模型生成的行动指令在一个可控、可回收、可观测的环境里落地而不是直接在你本机乱跑。它适合谁如果你正在做 AI Agent 相关的开发尤其是想让 Agent 完成“改代码、跑测试、装依赖、看日志”这类真实工程任务那 Runtime 就是你必须搞懂的一环。很多人第一次接触 OpenHands 时注意力都在 Agent 的 prompt 和工具定义上结果任务一下发就卡住日志里全是模型调用失败或者沙箱起不来。我实测下来链路里最容易出问题的两个点一个是沙箱容器本身另一个就是模型调用入口——也就是 Runtime 怎么拿到模型 API。这篇就沿着“任务下发 → Runtime 接收 → 沙箱执行 → 模型调用 → 结果回传”这条链路拆。重点放在两件事一是 Runtime 的沙箱执行机制到底怎么运转二是怎么用 TaoToken 的统一 Key/API 通道给 Agent 配好模型调用入口。TaoToken 在这里的角色是提供一个统一的模型接入层你不需要在 Runtime 里分别维护多家模型的地址和密钥一个 Base URL 加一个 Key 就能把模型调用收敛到一处。官网入口是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 地址是 https://taotoken.net/api 后面配置里会反复用到。先把链路讲清楚。OpenHands 的整体结构大致分三层前端/会话层负责接收用户任务Agent 层负责推理和决策Runtime 层负责执行。当你在界面里输入一个任务比如“把这个仓库的单元测试跑通”会话层会把任务交给 Agent Controller。Controller 调用模型模型返回一个 action比如run_command参数是pytest -q。这个 action 不会直接在你机器上执行而是被序列化后发给 Runtime。Runtime 收到后在自己的沙箱环境里执行捕获 stdout、stderr、退出码再打包成 observation 回传给 Controller。Controller 把 observation 拼进下一轮上下文继续调用模型循环直到任务完成或达到步数上限。这里的关键是 Runtime 和 Agent 是解耦的。Runtime 可以跑在本地 Docker 里也可以跑在远程容器里Agent 只通过一个约定的接口和它通信。OpenHands 默认用 Docker 起一个 runtime 容器容器里预装了 Python、Node、常用命令行工具还有一个 action execution server 监听请求。Agent 发过来的每个 action 都走 HTTP 到这个 serverserver 执行完把结果返回。这个设计的好处是沙箱隔离——Agent 再怎么乱来破坏范围也限制在容器内同时可观测——每个 action 和 observation 都有日志。那模型调用在哪一环在 Agent Controller 里。Controller 每次要决策时会向配置好的 LLM 发请求。这个请求的 Base URL、API Key、模型名就是我们要配的东西。如果你用 TaoToken 作为统一入口Controller 的 LLM 配置里 Base URL 指向 TaoToken 的 API 地址Key 用 TaoToken 生成的 Key模型名填你实际要用的模型 ID。这样 Runtime 沙箱执行和模型调用就串起来了沙箱负责“做”模型负责“想”TaoToken 负责把“想”这一步的通道统一。理解这条链路之后排障就有方向了。任务卡住先看是模型调用失败Controller 层还是沙箱执行失败Runtime 层。前者看 API 返回和 Key 配置后者看容器日志和 action server 状态。下面先把 TaoToken 的前置准备做掉再进配置。2. TaoToken 前置准备统一 Key 与 API 通道在给 OpenHands Runtime 配模型入口之前得先把 TaoToken 这边的凭证准备好。这一步不复杂但顺序别搞反先拿 Key再确认 Base URL最后才是往 Runtime 的环境变量里填。TaoToken 的定位是一个统一的模型调用通道你在这边生成一个 Key就能通过同一个 Base URL 访问背后配置好的模型不用在 OpenHands 里为每个模型单独维护一套地址和密钥。对 Agent 这种会频繁调用模型的场景来说收敛入口能省掉很多配置漂移的麻烦。先访问官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 进入控制台。如果你还没有账号先完成注册登录。登录后找到 API Keys 管理页面路径是 https://taotoken.net/console/api-keys 。在这个页面你可以创建新的 API Key。创建时一般会让你起个名字方便后面区分用途比如叫openhands-runtime。创建完成后Key 只会完整显示一次复制下来存到安全的地方后面配置环境变量要用。如果没存下来就只能重新生成一个。这里有个细节要注意Key 是敏感凭证不要直接硬编码到代码仓库里也不要在日志里打印完整 Key。OpenHands 的配置支持通过环境变量注入所以我们后面会用环境变量的方式传而不是写死在配置文件里。这样即使配置文件被分享出去Key 也不会泄露。拿到 Key 之后确认 API 的 Base URL。TaoToken 的 API 地址是 https://taotoken.net/api 注意这个地址不带任何查询参数就是纯 Base URL。在 OpenHands 的 LLM 配置里通常需要填的是完整的 chat completions 端点或者填 Base URL 让框架自己拼。不同版本的 OpenHands 配置字段名可能略有差异但核心就三个Base URL、API Key、Model ID。这三个我们后面会在配置片段里写全。模型 ID 怎么确定这取决于你在 TaoToken 这边开通或配置了哪些模型。在控制台里一般能看到可用模型列表或者在你的套餐/配置里能看到模型标识。OpenHands 调用时用的模型名要和你实际要用的模型 ID 对上。比如你要用某个 Claude 系列模型就填对应的模型 ID要用某个 GPT 系列就填那个。填错模型 ID 的典型表现是 API 返回模型不存在或者 404这个在排障章节会细说。还有一个前置项是确认你的调用额度或套餐状态正常。如果 Key 创建了但账户没有可用额度调用会返回 401 或 403 之类的鉴权/权限错误。这个不是配置问题是账户状态问题提前确认能省掉后面排查时间。如果你打算长期跑 Agent 任务尤其是那种会连续多轮调用模型的编码类任务可以关注一下 Coding Plan 相关的入口 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_campaignrewriteutm_content 。Agent 任务的特点是调用密集、上下文长跑一个稍复杂的任务可能几十上百次模型调用提前把额度规划好比跑到一半断掉要省心。前置准备做完你手上应该有三样东西一个 TaoToken API Key、Base URLhttps://taotoken.net/api、以及你要用的 Model ID。下面进入 OpenHands Runtime 的实际配置。3. 可复制配置Runtime 环境变量与 Base URL 片段这一节是整篇最需要动手的部分。OpenHands 的模型配置入口在不同版本里位置不太一样但核心都是让 Agent Controller 知道去哪调模型。我们分几种常见配置方式来写你按自己用的版本选对应的那份。所有片段里的 Key 都用占位符你替换成自己从 https://taotoken.net/console/api-keys 拿到的真实 Key。先说环境变量方式这是最通用也最推荐的做法因为不涉及改代码也不容易把 Key 提交进仓库。OpenHands 的 runtime 和 controller 通常读取一组 LLM 相关的环境变量。你可以在启动 OpenHands 之前在 shell 里 export或者写进.env文件。下面是一份可复制的环境变量片段# TaoToken 统一模型调用入口 export LLM_API_KEYsk-你的TaoTokenKey export LLM_BASE_URLhttps://taotoken.net/api export LLM_MODEL你的模型ID # OpenHands 部分版本使用的变量名 export OPENHANDS_LLM_API_KEYsk-你的TaoTokenKey export OPENHANDS_LLM_BASE_URLhttps://taotoken.net/api export OPENHANDS_LLM_MODEL你的模型ID注意这里我把两套变量名都列出来了因为 OpenHands 不同版本读取的变量名有差异。你先按你版本对应的文档确认或者两套都设上重复设置不会冲突框架会读它认识的那个。Key 一定要替换成真实的Base URL 保持https://taotoken.net/api不要加多余路径。如果你用的是config.toml这类配置文件方式OpenHands 的 LLM 配置段大概长这样[llm] model 你的模型ID api_key sk-你的TaoTokenKey base_url https://taotoken.net/api这份 TOML 片段里三个字段和上面环境变量一一对应。base_url填 TaoToken 的 API 地址api_key填你的 Keymodel填模型 ID。如果你的 OpenHands 版本用的是settings.json或者类似的 JSON 配置结构类似{ llm: { model: 你的模型ID, api_key: sk-你的TaoTokenKey, base_url: https://taotoken.net/api } }JSON 这份适合直接贴进 settings 文件。路径和字段名以你本地 OpenHands 的实际配置文件为准不要照搬字段名到不匹配的版本上否则框架读不到。判断字段名对不对的方法很简单改完启动看日志里有没有打印出你配置的 base_url 和 model如果打印的是默认值说明字段名没对上。还有一种情况是你用 Docker 起 OpenHands runtime这时候环境变量要通过docker run的-e参数传进去或者在docker-compose.yml的environment段里写。docker-compose 片段如下services: openhands: image: openhands/runtime:latest environment: - LLM_API_KEYsk-你的TaoTokenKey - LLM_BASE_URLhttps://taotoken.net/api - LLM_MODEL你的模型ID这份 compose 片段的关键是 environment 列表每个变量一行。如果你同时用 runtime 容器和 controller确保两个容器都能读到这些变量或者至少 controller 能读到因为模型调用发生在 controller 侧。配置写完先别急着跑复杂任务。用一个最小的验证请求确认通道是通的再进沙箱执行。下一节给验证方法。4. 验证请求从一次实际任务看执行日志与调用返回配置改完最稳妥的验证方式是先单独测模型通道再跑一个最小 Agent 任务看整条链路。分两步走出问题好定位。第一步绕过 OpenHands直接用 curl 测 TaoToken 的 chat completions 端点。这一步能确认 Key、Base URL、模型 ID 三者都对。命令如下curl -s https://taotoken.net/api/v1/chat/completions \ -H Content-Type: application/json \ -H Authorization: Bearer sk-你的TaoTokenKey \ -d { model: 你的模型ID, messages: [ {role: user, content: 只回复两个字通了} ] }如果返回的 JSON 里有choices数组且message.content是类似“通了”的内容说明模型通道没问题。如果返回 401是 Key 问题返回 404 或模型不存在是模型 ID 或路径问题返回超时是网络或 Base URL 问题。这一步过了再进 OpenHands。第二步启动 OpenHands跑一个最小任务。任务内容可以简单到“在当前目录创建一个 hello.txt写入 hello runtime”。这个任务会触发至少一次模型调用决定用什么命令和至少一次沙箱执行真正创建文件。启动后观察日志重点看两处一是 controller 侧有没有打印模型请求的 base_url 和 model确认读到了你的配置二是 runtime 侧有没有打印 action 执行记录比如执行的命令和返回码。一次成功的执行日志大概会呈现这样的顺序controller 收到任务 → 调用模型 → 模型返回 action比如write_file或run_command→ action 发给 runtime → runtime 在沙箱执行 → 返回 observation → controller 把 observation 拼回上下文 → 再次调用模型 → 模型判断任务完成 → 结束。你在日志里能看到模型调用的耗时、action 的类型、沙箱命令的输出。如果任务完成检查沙箱工作目录里是不是真的出现了 hello.txt内容是不是对的。文件真的生成了说明从模型调用到沙箱执行的整条链路都通了。这里有个观察点模型调用和沙箱执行是交替的不是先全部想完再全部做完。Agent 是走一步看一步每执行一个 action 就把结果喂回模型再决定下一步。所以日志里模型调用会出现多次这是正常的。如果你看到模型只调用了一次就结束可能是任务太简单也可能是 Agent 提前判定完成可以换个稍复杂的任务再验证。验证通过后你就有了一个可用的 OpenHands TaoToken 组合。后面跑真实任务时如果出现异常按下一节的对照表排查。5. 常见报错排查401、local proxy failed、reading choices、OAuth链路跑起来之后报错基本集中在几个固定位置。这一节按真实报错对照着排每个都给出定位方法和处理方向。401 Unauthorized。这个最直接鉴权没过。可能原因有三个Key 填错或过期、Key 前面多了空格或少了Bearer前缀、账户没有可用额度。先检查环境变量里的 Key 是不是完整复制有没有把引号也带进去。然后用第 4 节的 curl 单独测一次如果 curl 也 401就是 Key 或账户问题去 https://taotoken.net/console/api-keys 重新确认 Key 状态。如果 curl 通了但 OpenHands 里 401说明 OpenHands 读到的 Key 不是你设的那个检查变量名是否匹配、有没有被其他配置覆盖。local proxy failed。这个报错通常出现在 runtime 容器和 controller 通信的阶段不是模型调用本身。含义是本地代理或转发失败常见于容器网络配置问题。排查方向确认 runtime 容器在运行、端口映射正确、controller 配置的 runtime 地址能通。如果你在容器里跑检查容器是否在同一网络或者 host 地址有没有写错。这个错和 TaoToken 无关是沙箱通信层的问题别往模型配置上找。reading choices 相关报错。典型形式是解析响应时读不到choices字段比如KeyError: choices或reading choices of undefined。这说明模型返回的 JSON 结构和你框架预期的不一致。可能原因Base URL 填错导致请求打到了非预期端点、模型 ID 不存在导致返回了错误结构、或者响应被中间层改写了。先用 curl 确认返回结构里有choices再检查 OpenHands 里的 base_url 是不是https://taotoken.net/api有没有多写或少写路径段。如果 curl 返回正常但框架报这个错检查框架版本对响应格式的解析逻辑必要时看框架日志里打印的原始响应。OAuth 相关报错。如果你在 OpenHands 里看到 OAuth 或 token 刷新类的错误通常是因为框架尝试用某种 OAuth 流程获取凭证而你的配置是 API Key 模式。检查配置里有没有误开 OAuth 相关选项或者环境变量里有没有残留的 OAuth 配置。把鉴权方式明确设为 API Key清掉无关的 OAuth 变量。这类错误和 Key 本身无关是鉴权模式选错了。排查时有个通用原则先在 OpenHands 外面用 curl 验证模型通道通道通了再进框架排查。这样能把“模型调用问题”和“框架配置问题”分开。另外日志里打印的 base_url 和 model 一定要核对很多问题就是配置没被读到框架用了默认值。6. 把模型入口收敛到一处Agent 任务才跑得稳OpenHands Runtime 的沙箱执行链路本身不复杂复杂的是链路上每个环节的配置要对齐。任务下发、模型决策、沙箱执行、结果回传任何一环的地址或凭证错了表现都是任务卡住但原因可能完全不同。把模型调用入口收敛到 TaoToken 这一层好处是配置面变小了Base URL 固定、Key 统一、模型 ID 集中管理排查时只需要确认这三个值。如果你后面要跑更重的编码类 Agent 任务或者想把 OpenHands 接到持续集成流程里建议把 Coding Plan 的额度提前规划好入口在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_campaignrewriteutm_content 。模型对话的调试入口在 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_campaignrewriteutm_content 接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_campaignrewriteutm_content Key 管理还是 https://taotoken.net/console/api-keys 。这几个入口按需用配置阶段主要盯 Key 和文档。最后留一个实用习惯每次改完 Runtime 或模型配置先跑第 4 节那个最小任务确认 hello.txt 能生成再上真实任务。这个习惯能帮你把配置问题和任务逻辑问题分开省掉大量来回试的时间。