ARTICLE DETAIL

资讯详情

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

AI Agent框架探秘:拆解 OpenHands(8)--- CodeActAgent 的代码执行链路与 TaoToken 接入实践

AI Agent框架探秘:拆解 OpenHands(8)--- CodeActAgent 的代码执行链路与 TaoToken 接入实践 1. 从一次失败的 CodeActAgent 执行说起如果你正在本地跑 OpenHands大概率遇到过这种场景任务描述写得很清楚CodeActAgent 也顺利解析出了execute_bash或execute_ipython_cell动作但执行结果迟迟回不来日志里反复出现local proxy failed或者401 Unauthorized。这不是 Agent 逻辑写错了而是模型 endpoint 和鉴权通道没有打通。CodeActAgent 是 OpenHands 里把“自然语言指令”翻译成“可执行代码”的核心模块。它的工作链路可以粗略拆成四段接收用户消息 → 组装上下文与工具描述 → 调用 LLM 生成 Action → 在沙盒里执行代码并把 Observation 回传给下一轮。任何一段的模型通道出问题整条链路就会卡住。这篇内容面向已经在本地部署 OpenHands、想让 CodeActAgent 稳定跑起来的开发者。我会先拆解 CodeActAgent 的代码执行链路然后重点讲怎么把模型 endpoint 和auth.json改到 TaoToken 统一 Key/API 通道最后给一次端到端验证动作确认 Agent 能正常发起代码执行并返回结果。适合谁手里有 OpenHands 源码、想统一管理多个模型 Key、不想在每个项目里重复配环境变量的人。2. CodeActAgent 代码执行链路拆解与模型通道定位CodeActAgent 的核心设计理念是“把动作空间统一到代码执行”。它不像传统 Agent 那样为每个工具定义独立的 JSON schema 调用而是让模型直接生成 Python 或 bash 代码交给沙盒解释器执行。理解这条链路才能知道模型通道该改哪里。2.1 从 step() 到 Action 的决策流程CodeActAgent 的step()方法是整条链路的起点。它接收当前State先检查pending_actions队列里有没有待执行动作如果没有就调用condenser.condensed_history(state)压缩历史事件再用_get_messages()把压缩后的事件转成 LLM 能理解的消息列表。关键点在这里params[tools] check_tools(self.tools, self.llm.config)会把当前启用的工具描述塞进请求体然后response self.llm.completion(**params)发起模型调用。这个self.llm就是模型通道的入口它的 endpoint、api_key、model 三个参数决定了请求发往哪里。response_to_actions(response)把模型返回的内容解析成具体 Action比如CmdRunAction(commandls -la)或IPythonRunCellAction(codeimport pandas)。这些 Action 被 append 到pending_actions然后逐个 popleft 返回给控制器执行。2.2 工具集与沙盒插件的依赖顺序CodeActAgent 的sandbox_plugins定义了两个必须按顺序初始化的插件sandbox_plugins: list[PluginRequirement] [ AgentSkillsRequirement(), # 提供 Python 工具函数 JupyterRequirement(), # 提供 IPython 执行环境 ]AgentSkillsRequirement必须在JupyterRequirement之前因为它提供了大量 Python 函数Jupyter 环境需要依赖这些函数才能正常工作。这个顺序如果搞反沙盒启动时会报ModuleNotFoundError。工具集通过_get_tools()动态组装受AgentConfig控制配置项对应工具作用enable_cmdcreate_cmd_run_tool执行 bash 命令enable_thinkThinkTool记录推理过程enable_finishFinishTool结束任务enable_jupyterIPythonTool执行 Python 代码enable_editorcreate_str_replace_editor_tool编辑文件enable_browsingBrowserTool浏览器交互非 Windows2.3 模型通道在链路中的位置整条链路里模型通道出现在self.llm.completion(**params)这一行。self.llm来自self.llm_registry.get_router(self.config)而LLMRegistry的配置最终来源于 OpenHands 的config.toml和auth.json。也就是说要让 CodeActAgent 正常发起代码执行必须保证三件事同时成立config.toml里的base_url指向可用的模型服务、auth.json里的 api_key 有效、model字段与目标服务支持的模型 ID 一致。任何一项不对completion()就会抛异常Agent 的代码执行链路直接断在第一步。3. 把 OpenHands 模型通道改到 TaoToken 的可复制配置这一节给可直接复制的配置片段。OpenHands 的模型配置分散在两个文件~/.openhands/config.toml管 endpoint 和 model~/.openhands/auth.json管鉴权。两个都要改缺一不可。3.1 config.toml 的 endpoint 与 model 配置打开~/.openhands/config.toml找到[llm]段改成下面这样[llm] # 模型服务地址指向 TaoToken 的 API 通道 base_url https://taotoken.net/api # 模型 ID按你实际使用的模型填写 model claude-sonnet-4-20250514 # 请求超时CodeActAgent 执行长任务时建议调大 timeout 300 # 最大输出 token max_output_tokens 8192 # 温度代码生成任务建议低一些 temperature 0.1base_url这里填https://taotoken.net/api不要带 UTM 参数保持干净。model字段必须和目标服务支持的模型 ID 完全一致大小写敏感。3.2 auth.json 的 Key 配置~/.openhands/auth.json管鉴权格式如下{ api_key: sk-你的TaoToken密钥 }如果你用的是 OpenHands 的 Codex 模式auth.json可能还包含openai_api_key字段。统一改成 TaoToken 的 Key 即可{ api_key: sk-你的TaoToken密钥, openai_api_key: sk-你的TaoToken密钥 }Key 的获取入口在 TaoToken 控制台的 API Keys 页面创建后复制完整字符串。注意不要提交到 Gitauth.json应该在.gitignore里。3.3 三件套对照表配置改完后用这张表自查一遍配置项文件值说明Base URLconfig.tomlhttps://taotoken.net/api不带 UTMAPI Keyauth.jsonsk-...从控制台复制Model IDconfig.toml如claude-sonnet-4-20250514大小写敏感三件套必须同时正确。我试过只改base_url忘了改auth.json结果 Agent 一直报 401排查了半小时才发现 Key 还是旧的。3.4 环境变量方式的备选配置如果你不想改文件也可以用环境变量覆盖export LLM_BASE_URLhttps://taotoken.net/api export LLM_API_KEYsk-你的TaoToken密钥 export LLM_MODELclaude-sonnet-4-20250514环境变量的优先级高于config.toml适合临时切换模型做对比测试。但长期使用还是建议写进配置文件避免每次开终端都要 export。4. 端到端验证确认 CodeActAgent 能发起代码执行并返回结果配置改完后需要一次完整的端到端验证确认从指令解析到代码执行、结果回传的整条链路都通。下面给一个最小验证动作。4.1 启动 OpenHands 并观察初始化日志在终端启动 OpenHandscd /path/to/OpenHands python -m openhands.core.main启动后观察日志重点看这几行INFO: LLM config loaded: base_urlhttps://taotoken.net/api, modelclaude-sonnet-4-20250514 INFO: CodeActAgent initialized with plugins: AgentSkillsRequirement, JupyterRequirement INFO: Sandbox started successfully如果base_url显示的不是你配置的地址说明config.toml没被正确加载检查文件路径和 TOML 语法。4.2 发一个触发代码执行的任务在 OpenHands 的交互界面里输入一个明确需要代码执行的任务在当前目录创建一个 test_codeact.py 文件写入一个计算斐波那契数列前10项的函数然后运行它并打印结果。这个任务会触发 CodeActAgent 的多个 Actioncreate_str_replace_editor_tool写文件、IPythonTool或create_cmd_run_tool执行代码、FinishTool结束任务。4.3 检查执行结果与 Observation 回传正常情况下你会看到类似这样的输出Action: create_str_replace_editor_tool path: test_codeact.py command: create file_text: def fib(n): ... Observation: File created successfully Action: IPythonRunCellAction code: exec(open(test_codeact.py).read()); print(fib(10)) Observation: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34] Action: AgentFinishAction message: 任务完成斐波那契数列前10项已计算并打印。看到Observation里有实际执行结果说明模型通道、代码执行、结果回传三段都通了。如果卡在Action之后没有Observation问题多半在沙盒执行环境而不是模型通道。4.4 用 curl 单独验证模型通道如果 Agent 链路有问题可以先用 curl 单独验证模型通道是否可用curl -X POST https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer sk-你的TaoToken密钥 \ -H Content-Type: application/json \ -d { model: claude-sonnet-4-20250514, messages: [{role: user, content: print hello}], max_tokens: 100 }返回 200 且有choices字段说明通道本身没问题问题在 OpenHands 的配置加载或沙盒环境。5. 本篇常见报错排查配置过程中最容易踩的坑集中在鉴权、代理、响应解析和 OAuth 四类。下面按真实报错逐条排查。5.1 401 Unauthorized报错原文openai.AuthenticationError: Error code: 401 - {error: {message: Invalid API key}}排查顺序先确认auth.json里的api_key是否完整复制有没有多余空格或换行再确认config.toml里的base_url是否指向https://taotoken.net/api最后用 curl 单独测 Key 是否有效。如果 curl 能通但 OpenHands 报 401说明 OpenHands 读的不是你改的那个auth.json检查OPENHANDS_CONFIG_DIR环境变量指向的目录。5.2 local proxy failed报错原文ConnectionError: local proxy failed to connect to upstream这个报错通常出现在base_url配置了本地代理地址但代理没启动的情况。检查config.toml里的base_url是否误填了http://localhost:xxxx。正确做法是直接填https://taotoken.net/api不需要本地代理层。5.3 reading choices 相关解析错误报错原文KeyError: choices或者IndexError: list index out of range这说明模型返回的响应体里没有choices字段。常见原因有两个一是model字段填了目标服务不支持的模型 ID服务返回了错误信息而不是正常响应二是请求被中间层拦截返回了 HTML 错误页。用 curl 发同样的请求看原始响应体就能定位。5.4 OAuth 相关报错报错原文OAuth token expired or invalid如果你用的是 Codex 模式auth.json里可能残留了旧的 OAuth token。把auth.json清空只保留api_key和openai_api_key两个字段重新填入 TaoToken 的 Key。OAuth 流程和 API Key 鉴权是两套机制不要混用。5.5 沙盒启动失败导致 Observation 缺失报错原文RuntimeError: Sandbox failed to start: JupyterRequirement initialization failed检查sandbox_plugins的顺序AgentSkillsRequirement必须在JupyterRequirement之前。如果顺序对了还报错检查 Docker 是否正常运行OpenHands 的沙盒依赖 Docker 容器。6. 统一模型通道后的 CodeActAgent 使用建议把模型通道统一到 TaoToken 之后CodeActAgent 的调试成本会明显下降。以前每个项目要配一套 Key现在一个 Key 走通所有模型切换模型只改config.toml里的model字段。几个实用建议第一config.toml里的timeout建议设到 300 秒以上CodeActAgent 执行复杂任务时单次 LLM 调用可能超过默认的 60 秒。第二temperature设低一些代码生成任务不需要创造性0.1 左右比较稳。第三如果要做长期编码任务或 Agent 编排可以了解 Coding Plan 的额度方案比按次调用更划算。验证模型本身的能力时可以直接在模型对话页面测试目标模型对代码生成任务的响应质量确认模型 ID 和实际能力匹配后再写进config.toml。接入文档里有完整的 endpoint 和参数说明遇到配置问题可以先查文档。最后一步把改好的config.toml和auth.json备份一份下次换机器直接复制省去重新排查 401 的时间。
返回列表