
1. 从 task.md 到自主循环Claude Code agent 系统要解决的真实问题很多人第一次听到「自主循环 agent」脑子里浮现的是那种能自己写代码、自己测试、自己提交的科幻画面。但落到工程里它其实是一个非常朴素的东西一个能反复读取任务文件、判断当前进度、执行下一步、把结果写回状态然后继续下一轮的循环体。Claude Code 本身是一个交互式编码助手它不会自己转圈所以我们要做的是给它套一层「任务队列 状态机 循环驱动」的外壳。我试过最省事的做法就是在项目根目录放一个task.md里面写清楚项目目标、当前阶段、待办清单。然后写一个脚本每次调用 Claude Code 时把task.md和progress.json一起喂进去让它输出「下一步动作」执行完再把结果写回。这样循环下去直到task.md里所有条目都被标记为 done。这套东西适合谁适合那些有明确阶段性目标、但步骤重复度高的项目比如批量重构、文档补全、测试用例生成、数据清洗流水线。它不适合开放式探索因为循环需要一个可判定的终止条件。核心检索词就是Claude Code 自主循环 agent 系统你要找的是「任务读取 自主执行 循环推进」这三件事怎么串起来。下面我会按「问题场景 → 前置准备 → 可复制配置 → 验证请求 → 常见报错 → 接入入口」的顺序讲每一步都给能直接跑的命令和文件内容。你不需要先理解全部原理照着搭一遍再回头调参数就行。2. TaoToken 前置给 Claude Code 一个稳定的模型入口Claude Code 默认走 Anthropic 官方通道但在国内网络环境下直接调用经常遇到连接超时、证书校验失败、或者额度受限的问题。我踩过的坑是本地明明能 ping 通但 Claude Code 启动后一直卡在Connecting to Anthropic API最后报local proxy failed。后来换成 TaoToken 的兼容入口把 Base URL 指过去问题就消失了。TaoToken 在这里的角色是「模型接入层」它提供与 Anthropic API 兼容的接口你只需要改 Base URL 和 API KeyClaude Code 的其余逻辑完全不用动。官网入口是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 根地址是 https://taotoken.net/api 注意这个不加 UTM 参数直接用于配置。你需要准备三样东西第一一个 TaoToken 账号登录后在控制台创建 API Key。控制台地址是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 进去后找「API Keys」页面点新建复制那串sk-开头的字符串。这个 Key 只显示一次丢了就重新建。第二确认你要用的模型 ID。Claude Code 场景下常用的是claude-sonnet-4-5这类标识具体以你账号里可用的模型列表为准。模型对话页面在 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 可以先在那里发一条消息确认模型可用。第三把 Claude Code 的配置指向 TaoToken。Claude Code 读取的是环境变量ANTHROPIC_BASE_URL和ANTHROPIC_API_KEY或者项目里的.claude/settings.json。我建议用环境变量因为循环脚本里要反复调用环境变量最稳。这里有个细节Claude Code 对 Base URL 的格式比较敏感末尾不要带/v1直接写https://taotoken.net/api就行。如果你写成https://taotoken.net/api/v1它会拼成/v1/v1/messages直接 404。这个坑我在第一次配置时踩了半小时。另外如果你用的是 Claude Code 的 coding plan 模式长期编码任务建议单独走 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 那个通道对长上下文和连续调用更友好。普通循环 agent 用标准 API 就够。3. 可复制配置settings.json 任务队列脚本 循环驱动这一节是核心我给三份可直接复制的文件。第一份是 Claude Code 的 settings 配置第二份是任务队列读取脚本第三份是循环驱动脚本。三份配合起来就是一个最小可用的自主循环 agent 系统。3.1 Claude Code settings.json 配置在项目根目录建.claude/settings.json内容如下{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_API_KEY: sk-你的TaoToken密钥, ANTHROPIC_MODEL: claude-sonnet-4-5 }, permissions: { allow: [ Read, Write, Edit, Bash(git status), Bash(git diff), Bash(python3 *) ], deny: [ Bash(rm -rf *), Bash(curl * | sh) ] } }这里ANTHROPIC_BASE_URL指向 TaoToken 的 API 根地址ANTHROPIC_API_KEY填你控制台生成的 KeyANTHROPIC_MODEL填模型 ID。permissions.allow里我放开了读写和 git 查看、python 执行但把rm -rf和管道执行远程脚本禁掉了——循环 agent 最怕的就是它自己把项目删了。如果你更习惯用环境变量而不是 settings.json可以在 shell 里 exportexport ANTHROPIC_BASE_URLhttps://taotoken.net/api export ANTHROPIC_API_KEYsk-你的TaoToken密钥 export ANTHROPIC_MODELclaude-sonnet-4-5两种方式选一种即可不要同时配否则 settings.json 会覆盖环境变量容易搞混。3.2 任务队列读取脚本 task_reader.py这个脚本负责读task.md和progress.json输出当前应该执行的任务。task.md用简单的 Markdown 清单格式# 项目目标 把 utils/ 目录下所有 Python 文件的类型注解补全。 ## 任务清单 - [ ] utils/string_helper.py 补全类型注解 - [ ] utils/date_helper.py 补全类型注解 - [ ] utils/file_helper.py 补全类型注解 - [ ] 运行 mypy 检查并修复报错task_reader.py内容import json import re from pathlib import Path TASK_FILE Path(task.md) PROGRESS_FILE Path(progress.json) def load_progress(): if PROGRESS_FILE.exists(): return json.loads(PROGRESS_FILE.read_text(encodingutf-8)) return {done: [], current: None, history: []} def parse_tasks(): text TASK_FILE.read_text(encodingutf-8) tasks [] for line in text.splitlines(): m re.match(r^- \[( |x)\] (.)$, line.strip()) if m: tasks.append({done: m.group(1) x, desc: m.group(2)}) return tasks def next_task(): progress load_progress() tasks parse_tasks() for t in tasks: if not t[done] and t[desc] not in progress[done]: return t[desc] return None if __name__ __main__: nxt next_task() if nxt: print(fNEXT_TASK: {nxt}) else: print(ALL_DONE)这个脚本的逻辑很直白解析task.md里的- [ ]和- [x]再对照progress.json里已完成的条目返回第一个未完成的任务。如果全部完成输出ALL_DONE循环就可以停了。3.3 循环驱动脚本 agent_loop.sh这个脚本是循环体每一轮做四件事读下一个任务、调用 Claude Code 执行、把结果写回 progress.json、判断是否终止。#!/usr/bin/env bash set -euo pipefail MAX_ROUNDS20 ROUND0 while [ $ROUND -lt $MAX_ROUNDS ]; do ROUND$((ROUND 1)) echo Round $ROUND NEXT$(python3 task_reader.py) echo $NEXT if [ $NEXT ALL_DONE ]; then echo 所有任务已完成退出循环。 break fi TASK_DESC${NEXT#NEXT_TASK: } claude -p 当前任务${TASK_DESC}。请读取 task.md 和 progress.json执行这一步完成后把结果写入 progress.json 的 done 数组并把 task.md 里对应条目改成 [x]。 \ --allowedTools Read,Write,Edit,Bash(git status),Bash(python3 *) \ --max-turns 10 python3 - PY import json from pathlib import Path p Path(progress.json) data json.loads(p.read_text(encodingutf-8)) if p.exists() else {done: [], history: []} data.setdefault(history, []).append({round: auto}) p.write_text(json.dumps(data, ensure_asciiFalse, indent2), encodingutf-8) PY done echo 循环结束共执行 $ROUND 轮。这里claude -p是 Claude Code 的非交互模式-p后面跟提示词--allowedTools限制它能用的工具--max-turns 10防止单轮跑飞。每轮结束后脚本会更新progress.json下一轮task_reader.py就会跳过已完成的任务。注意MAX_ROUNDS20是安全阀防止任务判定逻辑出 bug 导致死循环。实际项目里你可以调大但一定要有这个上限。4. 验证请求一次完整任务从入队到收尾配置写完了现在跑一次完整验证。我拿一个真实的小项目演示utils/目录下有三个 Python 文件需要补全类型注解。第一步确认 Claude Code 能连上 TaoToken。在项目根目录执行claude -p 回复 OK --max-turns 1如果返回OK说明 Base URL 和 Key 都对了。如果报401说明 Key 无效或没读到如果报local proxy failed说明 Base URL 格式不对检查是不是多写了/v1。第二步准备task.md和空的progress.jsoncat progress.json EOF { done: [], current: null, history: [] } EOF第三步跑循环脚本chmod x agent_loop.sh ./agent_loop.sh你会看到类似输出 Round 1 NEXT_TASK: utils/string_helper.py 补全类型注解 Claude Code 执行修改文件更新 progress.json Round 2 NEXT_TASK: utils/date_helper.py 补全类型注解 ... Round 4 NEXT_TASK: 运行 mypy 检查并修复报错 Round 5 ALL_DONE 所有任务已完成退出循环。第四步验证结果。检查task.md里所有条目是否都变成了- [x]progress.json的done数组是否包含四条记录utils/下的文件是否真的加上了类型注解。再跑一次mypy utils/确认没有报错。这一步的关键是循环的终止条件必须可验证。ALL_DONE不是靠模型说「我做完了」而是靠task_reader.py解析文件状态得出的。模型只负责执行单步状态判定交给脚本这样才不会出现「模型以为自己完成了但其实没做」的情况。如果你想让循环更智能可以在每轮结束后加一个校验步骤比如跑pytest或mypy把结果写进progress.json下一轮提示词里带上上次的报错。这样 agent 就能根据真实反馈调整而不是盲目推进。5. 本篇常见错排查401、local proxy failed、reading choices、OAuth循环 agent 跑不起来90% 的问题出在接入层。我把几个高频报错和对应解法列出来你对照着查。报错一401 UnauthorizedError: 401 {error:{type:authentication_error,message:invalid api key}}原因通常是 Key 没配对或者 settings.json 和环境变量冲突。检查顺序先echo $ANTHROPIC_API_KEY看环境变量里是不是空再看.claude/settings.json里的 Key 有没有多余空格最后去 TaoToken 控制台确认这个 Key 还在有效期内。如果 Key 是对的检查 Base URL 是不是写成了https://taotoken.net/api/末尾多了斜杠去掉斜杠再试。报错二local proxy failedError: connect ECONNREFUSED 127.0.0.1:8080 local proxy failed这个报错说明 Claude Code 在尝试走本地代理但代理没起来。常见原因是之前配过HTTP_PROXY或HTTPS_PROXY环境变量残留下来了。执行unset HTTP_PROXY HTTPS_PROXY http_proxy https_proxy清掉再重新跑。另外确认ANTHROPIC_BASE_URL是https://taotoken.net/api不要带端口号。报错三reading choices 相关错误Error: reading choices - undefined这个报错通常出现在你用 OpenAI 兼容格式去调 Anthropic 接口或者反过来。Claude Code 走的是 Anthropic Messages API 格式TaoToken 的/api根路径已经做了兼容但如果你在脚本里手动拼了/v1/chat/completions就会返回 OpenAI 格式的响应Claude Code 解析不了。检查你的调用路径确保是 Claude Code 自己发起的请求而不是你手写的 curl。报错四OAuth 相关提示OAuth token expired, please re-authenticateClaude Code 某些版本会尝试 OAuth 登录。如果你用的是 API Key 模式在 settings.json 里显式配了ANTHROPIC_API_KEY一般不会触发 OAuth。如果还是弹检查是不是装了多个 Claude Code 版本或者~/.claude/下有旧的凭据缓存。清掉~/.claude/auth.json再重启。报错五循环跑了一轮就停如果agent_loop.sh只跑了一轮就退出检查task_reader.py的输出。可能是progress.json格式不对load_progress()抛异常被set -e捕获了。手动执行python3 task_reader.py看报错。另一个可能是claude -p返回非零退出码set -e直接终止脚本。把set -e改成set e或者在claude命令后加|| true让循环继续。排查完这些你的循环 agent 基本就能稳定跑了。记住一个原则接入层的问题用最小请求验证逻辑层的问题用日志定位。不要一上来就怀疑模型先确认claude -p 回复 OK能通。6. 接入入口与长期编码建议如果你只是想让 Claude Code 能稳定调用模型走标准 API 通道就够了在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 生成 Key然后按第 3 节的 settings.json 配好 Base URL 和 Model ID。三件套齐了循环脚本就能跑。如果你打算把这种循环 agent 用在长期项目上比如持续几天的重构或文档补全建议走 coding plan 通道https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。那个通道对连续调用和长上下文更友好不容易在几十轮之后出现响应变慢。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 里面有各语言 SDK 的调用示例和错误码说明。遇到报错先翻文档比在群里问快。最后给一个实用技巧循环 agent 的提示词里一定要让它「先读 progress.json再决定做什么」。我见过太多循环跑飞的情况都是因为模型没看状态就动手结果重复执行同一个任务。把状态读取写进提示词的第一句能省掉大量调试时间。