ARTICLE DETAIL

资讯详情

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

AI Agent 框架探秘:拆解 OpenHands(7)--- Agent State 与 LLM 配置实战

AI Agent 框架探秘:拆解 OpenHands(7)--- Agent State 与 LLM 配置实战 1. 从一次“Agent 卡死”说起State 到底管什么如果你在本地跑过 OpenHands大概率遇到过这种场景任务跑到一半终端突然不动了日志停在某条AgentStateChangedObservation上重启之后整个会话从头再来。表面看是“卡死”本质是 Agent State 的流转和持久化没接上。OpenHands 里的 State 不是简单的变量集合它是 Agent 的“草稿板 记忆 控制面板”三合一当前迭代到第几步、预算还剩多少、历史事件从哪到哪、有没有委托子 Agent、上一次错误是什么全在里面。这一篇聚焦两件事一是把 State 的流转机制讲清楚让你知道step()拿到的 State 从哪来、Action执行完怎么回写二是给出可复制的config.toml骨架用 TaoToken 统一 Key 和 API 通道把 LLM 接进去最后演示一次 Agent 状态切换的验证动作。适合已经在本地部署 OpenHands、想搞明白“为什么我的 Agent 不恢复”的开发者。读完你能自己搭一个能跑、能暂停、能恢复的最小配置。2. 前置准备TaoToken 统一 Key 与 API 通道OpenHands 的 LLM 适配层基于 LiteLLM理论上支持上百种模型提供商但本地部署时最烦的是每个模型一套 Key、一套 base_url切换模型要改一堆环境变量。我的做法是用 TaoToken 做统一入口一个 Key 走所有模型base_url 固定OpenHands 侧只认一个custom_llm_provider配置。先拿 Key。打开 https://taotoken.net/api-keys 登录后创建一个 API Key复制出来形如sk-xxxx。这个 Key 后面会写进config.toml的api_key字段。注意别把它提交到 Git本地用环境变量注入更稳。TaoToken 的 API 地址是 https://taotoken.net/api 兼容 OpenAI 的 Chat Completions 协议所以 OpenHands 里把base_url指向它、custom_llm_provider设为openai就能通。模型名按 TaoToken 文档里的写法填比如claude-sonnet-4-5、gpt-5-codex这类。如果你还没决定用哪个模型可以先到 https://taotoken.net/models 看一眼可用列表再回来填配置。这一步的核心价值是State 恢复时LLM 实例要能被LLMRegistry重新创建而配置一致性靠的就是这份统一的LLMConfig。Key 和 base_url 固定恢复逻辑才不会因为配置漂移而失败。3. 可复制配置config.toml 骨架与 State 相关字段OpenHands 的配置分两层全局config.toml管 LLM 和运行时Agent 的 State 在会话运行时由StateTracker管理。下面这份骨架是我实测能跑通的最小配置重点标出和 State 流转相关的字段。[core] # 工作目录State 持久化文件会落在会话目录下 workspace_base ./workspace # 缓存目录pickle 序列化后的 state 文件走这里 cache_dir ./cache # 最大迭代次数对应 State.iteration_flag.max_value max_iterations 100 # 单任务预算上限对应 State.budget_flag max_budget_per_task 5.0 [llm] # 统一走 TaoToken 通道 model claude-sonnet-4-5 base_url https://taotoken.net/api api_key sk-你的TaoToken密钥 custom_llm_provider openai # 温度与输出上限影响 Agent 决策稳定性 temperature 0.2 max_output_tokens 8192 # 重试策略State 恢复时若 LLM 调用失败会按此重试 num_retries 3 retry_min_wait 2 retry_max_wait 30 retry_multiplier 2.0 # 开启日志方便排查 State 流转 log_completions true log_completions_folder ./logs/llm [agent] # 默认 Agent 类型CodeActAgent 是核心 default_agent CodeActAgent # 确认模式开启后每个 Action 执行前需人工确认 confirmation_mode false [sandbox] # 沙箱类型本地用 local 即可 type local # 超时时间影响 Observation 回写 State 的时机 timeout 120几个和 State 强相关的点单独说。max_iterations直接映射到State.iteration_flag.max_valueAgent 每走一步current_value加一到顶就停这是防止无限循环的第一道闸。max_budget_per_task对应budget_flagLLM 每次调用的成本累加进去超了就暂停。confirmation_mode打开后AgentState会在RUNNING和PAUSED之间切换这正是验证状态流转的好开关。配置写完后用环境变量覆盖 Key 更安全export TAOTOKEN_API_KEYsk-你的TaoToken密钥然后在config.toml里把api_key改成api_key ${TAOTOKEN_API_KEY}OpenHands 启动时会做变量替换。4. 验证请求跑一次 Agent 状态切换配置就绪后启动 OpenHands 并观察 State 的流转。先起服务python -m openhands.server默认监听 3000 端口。打开浏览器进 http://localhost:3000 新建一个会话输入一个简单任务比如“在当前目录创建一个 hello.py打印 hello openhands”。这时候重点看后端日志里AgentState的变化序列。正常情况下你会看到这样的流转AgentState.LOADING - AgentState.RUNNINGLOADING是 State 初始化阶段StateTracker从cache_dir里找有没有历史 state 文件没有就新建。RUNNING是AgentController._step()开始循环。每执行一个 Actionadd_history把事件追加到State.historystart_id和end_id跟着更新。想验证暂停和恢复把confirmation_mode改成true重启再跑一次任务。这次你会看到AgentState.RUNNING - AgentState.PAUSED - AgentState.RUNNINGPAUSED出现在 Action 执行前等待确认的时刻确认后回到RUNNING。这个切换背后是State.resume_state在记录“暂停前是什么状态”恢复时读它。如果你在PAUSED时直接杀掉进程重启后StateTracker会尝试从 pickle 文件恢复日志里能看到Saving state to session和后续的加载动作。用 curl 直接打一次 LLM 通道确认 TaoToken 侧通curl https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d { model: claude-sonnet-4-5, messages: [{role: user, content: reply with ok}], max_tokens: 16 }返回里choices[0].message.content有内容说明 Key 和通道没问题。这一步单独验证很有必要因为 OpenHands 的 LLM 封装层出错时日志会被重试逻辑盖住先确认底层通再排查上层。5. 本篇常见错排查错误一LLMNoResponseError: Response choices is less than 1这个在 Gemini 系模型上出现过根因是响应里choices为空。排查顺序先用上面的 curl 确认 TaoToken 侧返回正常再检查config.toml里model名是否和 TaoToken 文档一致写错模型名有时会返回空 choices最后看max_output_tokens是不是设得太小推理模型思考 token 占满后没有输出空间。错误二State 恢复后 Agent 从头开始日志里如果看到Failed to save state to session说明 pickle 序列化失败。常见原因是State里塞了不可序列化的对象比如某个自定义工具持有文件句柄。检查你的extra_data字段只放基本类型。另一个原因是cache_dir权限不对file_store.write静默失败确认目录可写。错误三Agent not stepping because state is ... (not RUNNING)这是AgentController._step()里的保护逻辑State 不是RUNNING就不走。如果你手动改了confirmation_mode但没重启或者前端还停在PAUSED就会一直卡。检查State.agent_state当前值确认前端确认按钮真的触发了状态切换。错误四迭代次数到了但任务没完成iteration_flag.current_value触顶后 Agent 会停但不会自动报“任务未完成”。把max_iterations调大或者拆任务。注意delegate_level大于 0 时子 Agent 的迭代计数是独立的父 Agent 的parent_iteration记录委托前的值排查时要看对层级。错误五TaoToken 返回 401Key 没注入成功。检查config.toml里是${TAOTOKEN_API_KEY}还是硬编码环境变量名别拼错。另外确认 Key 没有多余空格复制时容易带上换行。6. 把 State 和 LLM 配置接稳再谈 Agent 能力State 的流转机制决定了 Agent 能不能“记住自己在干嘛”LLM 配置决定了它“想得对不对”。这两块接稳之后CodeActAgent 的step()循环才有意义每次拿到的 State 是完整的输出的 Action 是基于正确上下文的Observation 回写后历史是连续的。我试过在confirmation_mode下反复暂停恢复十几次只要cache_dir和 Key 配置没动会话都能接上。如果你要长期跑编码类任务或者搭多 Agent 委托建议把配置固化成一份config.toml模板Key 走环境变量模型切换只改model一行。需要看当前可用模型和通道状态直接到 https://taotoken.net/models 和 https://taotoken.net/console 查。接入文档在 https://taotoken.net/doc 里面有 LiteLLM 兼容层的字段说明配custom_llm_provider时对着看能少踩坑。
返回列表