Agent 无限 while True 停不下来?让走 TaoToken 的 Codex 查 max_steps

📅 发布时间:2026/9/16 16:36:44
Agent 无限 while True 停不下来?让走 TaoToken 的 Codex 查 max_steps
1.while True无限循环先看run_agent()里到底少了什么很多读者在读完 Agent 原理四第十六节后都会照着代码自己抄一份run_agent()然后顺手把for step in range(max_steps)改成while True觉得这样“更像 Agent”。结果模型一直回tool_callmessages越拼越长Token 跟水龙头忘关一样哗哗地烧最后要么被 API 供应商限流要么被信用卡账单提醒戳醒。这类报错现场通常长这样RuntimeError: agent exceeded max_steps10或者是根本没有报错进程一直在跑日志里全是新一轮tool_call。问题往往不是模型“变笨了”而是你的循环没有终点。要查清楚这件事建议先打开 TaoToken 创建一把 API Key把 Base URL 填成https://taotoken.net/api再把报错现场和messages原样贴给走 TaoToken 的 Codex让它帮你检查run_agent()里的max_steps与response[type]判断逻辑。1.1 一个典型的“闷头循环”代码长什么样假设你从原文第十六节摘出来的run_agent()被改成了这样def run_agent(messages, tools): while True: response llm(messagesmessages, toolstools) if response[type] final: return response[content] # 这里漏掉了对 response[type] ! tool_call 的判断 messages.append(response) result execute_tool(response) observation build_observation(response, result) messages.append(observation)表面上看response[type] final已经给了出口。但问题在于模型误以为任务没完成或者你的工具结果不够明确它就会一直返回tool_call。而且你没有校验response[type]的其它值也没有max_steps兜底循环就会一直转下去。1.2 为什么messages会变成无底洞每一轮循环你都会往messages里追加一条 assistant 的tool_call和一条 tool 的 Observation。十轮之后messages里多了二十条记录二十轮之后就是四十条。模型的输入越来越长Token 消耗呈线性甚至超线性增长。更麻烦的是很多模型在长上下文中会“迷失”反复选择同一个工具。所以在排查时不要把责任全推给模型。你贴给 Codex 的代码里有没有max_steps上限有没有对response[type]的未知值做raise这两点正是原文第十六节反复强调的 Runtime 控制职责。2. 排查前准备报错信息、源码、最近几轮 messages我们要让 Codex 看懂现场就得给它足够的上下文。光贴一句RuntimeError: agent exceeded max_steps10不够还要把run_agent()的完整源码、以及触发循环的那几轮messages一起贴过去。2.1 打开 TaoToken 官网创建 Key在准备材料这一步先打开 TaoToken 注册并创建 API Key。这个 Key 是用来让 Codex 走 TaoToken 通道请求模型的不是给run_agent()用的。创建好以后把 Key 复制成YOUR_API_KEY稍后配置 Codex 时会用到。2.2 给 Codex 的输入模板你可以这样组织要贴给 Codex 的文字这是 run_agent() 的源码粘贴源码 它在第 N 轮抛出了 RuntimeError: agent exceeded max_steps10。 这是触发循环的最后几轮 messages 粘贴 messages 片段 请帮我检查 1. max_steps 为什么会被触发 2. response[type] 的判断逻辑有没有漏洞 3. 为什么模型一直没有返回 final注意不要贴太多无关日志否则模型容易被嘈杂信息带偏。只要源码、报错、最近三轮到五轮的messages就够了。TaoToken 只承载 Codex 的模型请求不替 Runtime 做 stop guard所以你在提问时还得把控制逻辑的责任留给代码本身。3. 把 Codex 指到 TaoToken配置~/.codex/config.tomlCodex 本身是一个命令行编程工具默认走 OpenAI 的通道。要让它走 TaoToken只需要在~/.codex/config.toml里定义一个自定义 provider。3.1 配置示例Base URL 不要加/v1# ~/.codex/config.toml model YOUR_MODEL_ID # 以 TaoToken 模型广场为准 model_provider taotoken [model_providers.taotoken] name TaoToken base_url https://taotoken.net/api api_key_env_var TAOTOKEN_API_KEY这里base_url直接填https://taotoken.net/api不要画蛇添足加上/v1。model字段的取值要去 TaoToken 的模型广场看当时的模型列表别硬编一个名字。3.2 设置环境变量在终端里导出 Keyexport TAOTOKEN_API_KEYYOUR_API_KEY注意这个环境变量名要和config.toml里的api_key_env_var对应。如果你把 Key 写死在配置文件里也可以但更推荐用环境变量避免不小心把 Key 提交到 Git。4. 让 Codex 检查max_steps与response[type]当 Codex 走通 TaoToken 后你直接在 Codex 里发上面那段排障模板。它通常能快速定位到两个问题一是response[type]没有处理“既不是final也不是tool_call”的情况二是max_steps虽然设了上限但循环内部的判断顺序导致提前跳出或永不跳出。4.1 Codex 的常用建议把“结束条件”放到最前面Codex 多半会建议你把final判断放在循环开头for step in range(max_steps): response llm(messagesmessages, toolstools) if response[type] final: return response[content] if response[type] ! tool_call: raise ValueError(funknown response type: {response[type]}) messages.append(response) result execute_tool(response) observation build_observation(response, result) messages.append(observation)这样一来只要模型返回final函数立刻返回遇到未知类型直接抛出异常不会继续往messages里堆垃圾。4.2 Codex 的第二个重点Runtime 必须拥有“强制停止”能力就算你用了while True也必须在循环体内维护一个计数器step 0 while True: if step max_steps: raise RuntimeError(fagent exceeded max_steps{max_steps}) step 1 response llm(messagesmessages, toolstools) # ... 后面一样模型可以决定“什么时候想结束”但 Runtime 必须决定“什么时候必须结束”。TaoToken 在这里只是模型请求的通道它不会帮你中断循环所以 stop guard 只能写在你的代码里。Codex 看到你的代码后会明确指出来while True里没有step自增也没检查step max_steps这才是循环停不下来的直接原因。5. 修复后的run_agent()把“继续”和“结束”分开看经过 Codex 检查你大概率会把代码改成下面这种结构用for循环代替裸while True把response[type]的判断写全并且把max_steps作为硬性边界。5.1 修改后的代码示例def run_agent(messages, tools, max_steps10): for step in range(max_steps): response llm(messagesmessages, toolstools) if response[type] final: return response[content] if response[type] ! tool_call: raise ValueError(finvalid model response: {response[type]}) messages.append(response) try: result execute_tool(response) observation build_observation( tool_callresponse, statussuccess, contentstr(result), ) except Exception as exc: observation build_observation( tool_callresponse, statuserror, contentstr(exc), ) messages.append(observation) raise RuntimeError(fagent exceeded max_steps{max_steps})这段代码把“模型认为完成”和“Runtime 强制停止”分成了两个完全独立的条件。模型可以在任意一轮返回final这是它的决定Runtime 则在for step in range(max_steps)的限制下保证最多只跑十轮。即使模型发疯一样连续返回tool_call十轮之后也会被强制打断。5.2 为什么messages.append()的顺序不能乱循环里messages.append(response)要在execute_tool()之前这代表“Action 发生过”。然后messages.append(observation)在工具执行之后代表“Action 的结果”。如果你把顺序调换模型会看到一条没有起因的 Observation容易误解当前状态进而在错误的上下文上继续决策。Codex 在检查这类代码时通常也会提醒你不要只追着while True看要看messages是否成对出现 assistant tool call 和 tool result。这比单纯加一个max_steps更重要因为max_steps只能止血成对的消息才能让模型在有限步骤内走出循环。6. 验证跑一遍同一个任务观察 Round 数代码改完以后不要直接扔进生产环境。先拿最小的任务试一遍比如37 × 58 等于多少然后看日志里的 Round 数。6.1 确认模型在第二轮返回final正常情况下第一轮模型请求调用calculator第二轮看到tool结果后返回final。日志里应该只出现 Round 1 和 Round 2 然后打印 Final Answer。如果 Round 数超过了max_steps说明response[type]的判断逻辑还是有问题或者模型根本没有看到足够清晰的 Observation。这时候把最新一轮的messages再贴回给 Codex让它检查是不是build_observation的参数传错了。6.2 在 TaoToken 控制台对一下这次调用验证通过后回到 TaoToken 控制台看调用记录确认刚才这次 Codex 请求确实被记上了账。如果没记账说明config.toml里的 provider 没生效或者模型 ID 填错了。这一步很有价值你能直观看到一个短任务消耗了多少 Token也能知道无限循环烧钱有多快。以后写长任务时你会更愿意保留max_steps而不是赌模型“最后一定能停下来”。7. 排障Codex 接不上 TaoToken先查这几处如果 Codex 报 401、404或者模型 ID 不存在的错误别急着找客服先对照检查。现象可能原因修复方式401 UnauthorizedTAOTOKEN_API_KEY没设置或设置错误确认环境变量名和config.toml一致Key 从 TaoToken 控制台复制404 Not FoundBase URL 多了/v1改成https://taotoken.net/api末尾不要加/v1Model Not Foundmodel字段写错了去 TaoToken 模型广场复制一个准确的模型 ID404 是新手最容易踩的坑。TaoToken 的 Base URL 设计就是https://taotoken.net/api不是https://taotoken.net/api/v1。所有工具接入时都用这个地址包括 Codex 和 Claude Code。官网链接和 Base URL 不同官网是给你注册、看用量、创建 Key 用的Base URL 是填进工具里用的。这两个千万别混。如果 Codex 能正常收到模型响应但发现自己还是在无限循环那就要回到代码层面。TaoToken 只承载模型请求不替 Runtime 做 stop guard。你的run_agent()必须自己检查max_steps和response[type]不然换哪个通道都一样。改完以后建议把今天这个修复过程记到自己的笔记里。下次再遇到 Agent 循环你就有排查套路了先看报错再贴messages让 Codex 帮你查max_steps和结束条件。如果遇到了新的问题也可以试着在 TaoToken 模型对话 里验证一下模型行为或者在 Coding Plan 里看看自己的调用量够不够支撑下一轮调试。真正需要长期跑 Agent 任务时去 创建 Key 再配一轮 Claude Code也是一样的流程。