Subagent stopped after 30 turns without final answer?TaoToken 这样改 learn-claude-code 通道 📅 发布时间:2026/9/18 18:22:40 👁 浏览次数: Subagent stopped after 30 turns without final answerTaoToken 这样改 learn-claude-code 通道用 TaoToken 排障 learn-claude-code 的 s06 子代理时常见报错是Subagent stopped after 30 turns without final answer.。先别急着改 30 轮上限先把模型通道接到https://taotoken.net/apiKey 到 TaoToken 官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 创建。这个提示既可能来自子代理确实跑满 30 轮且没有文本结论也可能来自模型通道没接对导致子代理一直拿不到正常 assistant 文本。排障顺序应该是确认client.messages.create的 Base URL、Key、模型 ID跑最小请求验证再回到spawn_subagent看extract_text的倒序回看逻辑。TaoToken 只保证模型请求到达不改变代码里的 30 轮上限也不改写摘要兜底。一、原问题与场景s06 的 spawn_subagent 为什么会返回兜底句learn-claude-code 到 s06 这一节核心变化是父代理的 tools 里多了一个task工具。父代理不需要把所有探索都塞进同一个上下文而是可以把一部分工作交给子代理子代理在全新的messages[]里独立执行最后只把摘要文本带回父代理。父代理拿到的是结论不是子代理完整的上下文历史这样主对话可以保持相对干净。对应到代码父代理的agent_loop在每轮拿到模型响应后如果response.stop_reason tool_use就会遍历response.content里的 tool_use 块找到对应 handler 并执行。task工具注册的 handler 就是spawn_subagent。父代理把block.input传进去spawn_subagent返回一个字符串父代理再把字符串包进tool_result追加回自己的messages。子代理内部则是一个独立的循环。它用新的 messages 开始最多跑 30 轮。每一轮同样调用client.messages.create参数里带model、system、messages、tools、max_tokens。如果模型返回的stop_reason不是tool_use循环就提前结束如果一直是tool_use循环会一直跑到for _ in range(30)用尽。30 轮结束后代码要做一件事从子代理自己的消息历史里提取最终文本。关键逻辑大致是这样result extract_text(messages[-1][content]) if not result: for msg in reversed(messages): if msg[role] assistant: result extract_text(msg[content]) if result: break if not result: result Subagent stopped after 30 turns without final answer.这段逻辑本身没有请求网络它只是从已有消息里找文本。最后一条消息很可能是tool_result里面装的是工具执行结果不是 assistant 文本所以extract_text(messages[-1][content])可能返回空字符串。接着代码从后往前找最近的 assistant 消息希望捞到一句文本结论。如果所有 assistant 消息里都没有非空文本比如子代理一直在调用工具、从未输出text块那么最终就会返回硬编码的兜底句。所以这个报错的第一层含义是子代理没有在历史里留下可提取的 assistant 文本。它可能是 30 轮真的跑满了也可能是模型通道没有正常返回 assistant 文本。实际复现时很多人看到这句话就去检查extract_text但更前面的原因可能是client.messages.create没有访问到正确的 Base URL或者 Key、模型 ID 有问题。TaoToken 在这个场景里的作用是把模型请求通道接对而不是把 30 轮上限改掉。二、TaoToken 前置learn-claude-code 的模型通道先接对learn-claude-code 是独立项目它通常直接使用 Anthropic SDK代码里会初始化一个client然后在父代理和子代理里共用client.messages.create。因此你要改的不是某一句提示词而是这个client实际访问的地址和认证信息。第一步到 TaoToken 官网创建 Key。地址是https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content创建后拿到YOUR_API_KEY。不要把 Key 写进公开仓库也不要把 Key 拼进前端代码。本地排障时可以先用环境变量确认通了再考虑项目内的配置方式。第二步把 API Base URL 设为https://taotoken.net/api注意这里不要带 UTM 参数也不要写成官网首页。SDK 会在 Base URL 后面拼接对应路径例如/v1/messages。如果你把 Base URL 写成https://taotoken.net/或者把带 UTM 的官网地址填进去请求可能到不了正确接口。第三步确认模型 ID。learn-claude-code 代码里通常有一个MODEL变量父代理和子代理都可能引用它。这个MODEL必须换成 TaoToken 通道可用的模型 ID不能想当然地沿用原来的原生模型名。模型 ID 可以从接入文档或模型对话页面确认不要靠猜。第四步如果你外层使用的是 Claude Code那么它读取的是settings.json里的env配置。你需要关注ANTHROPIC_BASE_URL、ANTHROPIC_AUTH_TOKEN或ANTHROPIC_API_KEY、ANTHROPIC_MODEL这几项。但如果你的报错来自 learn-claude-code 这个独立 Python 项目改 Claude Code 的settings.json不会自动影响它因为 Python 脚本读的是自己的环境变量和代码初始化参数。第五步可选 CLI 方式。如果你使用 TaoToken 的 CLI 来启动相关客户端可以这样安装和执行npm i -g taotoken/taotoken taotoken cc -k YOUR_API_KEY -u https://taotoken.net/api -m MODEL_ID这里的YOUR_API_KEY换成你创建的 KeyMODEL_ID换成确认可用的模型 ID。三、可复制配置把 client.messages.create 指到 TaoToken先给一个环境变量版本。你可以在终端里临时设置也可以在项目启动脚本里设置export ANTHROPIC_BASE_URLhttps://taotoken.net/api export ANTHROPIC_API_KEYYOUR_API_KEY export ANTHROPIC_MODELMODEL_ID然后检查 learn-claude-code 里 client 的初始化方式。如果它使用默认构造函数Anthropic SDK 会读取ANTHROPIC_BASE_URL和ANTHROPIC_API_KEY。但为了排障清晰建议显式写出来import os from anthropic import Anthropic client Anthropic( api_keyos.environ.get(ANTHROPIC_API_KEY, YOUR_API_KEY), base_urlos.environ.get(ANTHROPIC_BASE_URL, https://taotoken.net/api), ) MODEL os.environ.get(ANTHROPIC_MODEL, MODEL_ID)父代理的agent_loop和子代理的spawn_subagent都应该使用同一个client和同一个MODEL。如果项目里为了方便复制在子代理函数里又新建了一次 client那就要把子代理里的 Base URL 和 Key 也改掉。否则会出现父代理能通、子代理不通最后子代理返回兜底句的情况。检查关键调用response client.messages.create( modelMODEL, systemSUB_SYSTEM, messagesmessages, toolsSUB_TOOLS, max_tokens8000, )这里要确认model不是被硬编码成了别的值system只是子代理提示词不负责网络转发。tools和messages如果格式有问题模型可能返回错误或者一直调用工具不输出文本。通道配置正常之后再看 30 轮和extract_text才有意义。如果你外层使用 Claude Codesettings.json可以这样写{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_AUTH_TOKEN: YOUR_API_KEY, ANTHROPIC_MODEL: MODEL_ID } }如果某个项目读取的是ANTHROPIC_API_KEY就把ANTHROPIC_AUTH_TOKEN换成ANTHROPIC_API_KEY不要同时保留两个冲突的旧值。改完 JSON 后重启终端或客户端确保环境变量重新加载。四、验证请求与成功结果先确认 API 能通再跑子代理在改完 learn-claude-code 后不要直接跑复杂任务。先用最小请求验证 TaoToken 通道。curl 版本curl https://taotoken.net/api/v1/messages \ -H x-api-key: YOUR_API_KEY \ -H anthropic-version: 2023-06-01 \ -H content-type: application/json \ -d { model: MODEL_ID, max_tokens: 64, messages: [ {role: user, content: 只回复 ok} ] }成功时你应该看到 HTTP 200返回 JSON 里有content数组里面包含type为text的块文本内容类似ok。如果返回 401 或 403先检查 Key 是否复制完整是否从 TaoToken 官网创建。如果返回 404检查 Base URL 和路径是否写错。如果返回 400重点看模型 ID 和请求体字段。Python 版本python - PY from anthropic import Anthropic c Anthropic( api_keyYOUR_API_KEY, base_urlhttps://taotoken.net/api, ) r c.messages.create( modelMODEL_ID, max_tokens32, messages[{role: user, content: ping}], ) print(r.content) PY如果这个最小脚本能打印出文本块说明模型通道已经通了。此时再运行 learn-claude-code 的 s06python s06.py观察终端输出父代理调用task后出现[Subagent spawned]。子代理每轮如果有工具调用会出现[sub] tool_name: ...之类的日志。子代理结束后出现[Subagent done]。父代理收到的tool_result里应该是子代理摘要而不是Subagent stopped after 30 turns without final answer.。如果你只想先在网页上确认模型 ID 是否可用可以打开模型对话页面测试。注意模型对话能回复不等于你的 learn-claude-code 代码已经读到了正确环境变量。代码里还要确认base_url和model实际传入了client.messages.create。五、本篇常见错排查Subagent stopped、extract_text 与 settings.json1. Base URL 写成了官网首页或带 UTM 的地址错误示例是https://taotoken.net/、https://taotoken.net/?utm_source...或者漏掉/api。正确值是https://taotoken.net/apiAPI 地址不需要加 UTM。SDK 会自己拼接/v1/messages等路径。2. Key 没有从正确入口创建或复制不完整Key 应该是YOUR_API_KEY对应的实际值。建议到 API Keys 页面重新确认不要用旧项目里的其他 Key 混用。复制时注意前后空格和换行。3. 模型 ID 不对MODEL如果还是原来的原生模型名TaoToken 通道可能无法识别。先通过接入文档或模型对话确认可用模型 ID。不要把MODEL_ID原样留在生产代码里。4. Claude Code 的 settings.json 没生效如果你改的是 Claude Code检查 JSON 是否合法env层级是否正确改完后是否重启。ANTHROPIC_BASE_URL必须是https://taotoken.net/api。认证字段按客户端读取习惯使用ANTHROPIC_AUTH_TOKEN或ANTHROPIC_API_KEY不要同时留着两个不同来源的值。5. learn-claude-code 不读取 Claude Code 的 settings.json这是最容易混淆的一点。learn-claude-code 是一个 Python 项目它有自己初始化 Anthropic client 的方式。你只改 Claude Code 的settings.json不会改变这个 Python 脚本里的client。要在脚本里设置环境变量或者直接改Anthropic(base_url..., api_key...)。6. 子代理一直只调用工具不输出 assistant 文本如果通道已经正常但spawn_subagent仍然返回兜底句就去看extract_text。最后一条消息如果是tool_result提取不到文本代码会倒序找 assistant 消息。如果所有 assistant 消息都只有tool_use没有text块那么兜底句就是代码预期行为。你可以把SUB_SYSTEM调整得更明确要求子代理在结束时用文本给出结论但不要把这归因到 TaoToken 通道。7. 把 30 轮上限和 API 超时混在一起for _ in range(30)是代码安全上限和 HTTP 请求超时不是一回事。TaoToken 不改变这个上限。如果子代理任务确实需要更多轮应该拆分任务或修改代码逻辑而不是只改 Base URL。8. 日志不足无法判断请求是否成功在client.messages.create前后加日志只打印base_url、model、stop_reason和异常类型不要打印完整 Key。这样你能看出是请求没通还是请求通了但模型一直返回tool_use。9. 环境变量被旧值覆盖运行前检查env | grep ANTHROPIC如果系统里已经有旧的ANTHROPIC_BASE_URL、ANTHROPIC_API_KEY、ANTHROPIC_MODEL代码可能读取到旧值。临时排障时可以在启动脚本里显式覆盖。10. 本机网络、DNS、证书链或公司代理影响请求如果 curl 和 Python 都超时先检查本机是否能正常访问https://taotoken.net/api再检查 DNS、证书链和公司代理设置。排障时不要依赖不合规网络手段先把基础网络和配置确认清楚。六、语义一致 CTA排障接入走 API Keys 与接入文档如果你正在按 learn-claude-code s06 排Subagent stopped after 30 turns without final answer.建议按这个顺序处理先到 API Keys 创建并确认 Key。再对照 接入文档 把ANTHROPIC_BASE_URL设为https://taotoken.net/api确认认证字段和模型 ID。用 curl 或最小 Python 脚本验证请求能通。回到spawn_subagent检查extract_text的倒序回看逻辑确认子代理是否真的产出过 assistant 文本。如果你只是想验证模型名和通道是否可用可以先用 模型对话。如果你后续要长期跑子代理、编码 Agent 或更完整的 Coding 工作流可以再看 Coding Plan。TaoToken 负责把模型请求接稳30 轮上限和extract_text兜底仍由 learn-claude-code 代码决定。