拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

AI Agent框架探秘:拆解 OpenHands Runtime 的沙箱执行链路与 TaoToken 接入

AI Agent框架探秘:拆解 OpenHands Runtime 的沙箱执行链路与 TaoToken 接入

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_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_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 到这个 server,server 执行完把结果返回。这个设计的好处是沙箱隔离——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_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_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_source=taotoken_aicg_blog_end&utm_campaign=rewrite&utm_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_KEY="sk-你的TaoTokenKey" export LLM_BASE_URL="https://taotoken.net/api" export LLM_MODEL="你的模型ID" # OpenHands 部分版本使用的变量名 export OPENHANDS_LLM_API_KEY="sk-你的TaoTokenKey" export OPENHANDS_LLM_BASE_URL="https://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填你的 Key,model填模型 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_KEY=sk-你的TaoTokenKey - LLM_BASE_URL=https://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_source=taotoken_aicg_blog_end&utm_campaign=rewrite&utm_content= 。模型对话的调试入口在 https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_campaign=rewrite&utm_content= ,接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_campaign=rewrite&utm_content= ,Key 管理还是 https://taotoken.net/console/api-keys 。这几个入口按需用,配置阶段主要盯 Key 和文档。

最后留一个实用习惯:每次改完 Runtime 或模型配置,先跑第 4 节那个最小任务,确认 hello.txt 能生成,再上真实任务。这个习惯能帮你把配置问题和任务逻辑问题分开,省掉大量来回试的时间。

返回列表