1. 为什么单次工具调用能跑通长任务却总崩很多人第一次写 Agent都会经历同一个阶段单轮问答没问题工具调用也能正确触发参数传递、结果解析全都正常。于是很自然地得出一个结论——Agent 的核心就是工具调用只要模型能识别该调哪个工具、把参数传对、把结果读回来任务就能自动完成。这个判断在 demo 阶段几乎不会出错因为 demo 的任务通常只有一两轮。可一旦把任务拉长到十几轮甚至几十轮问题就集中爆发了中途莫名终止、同一个工具被重复调用、上下文越堆越乱导致逻辑跑偏、偶尔接口直接报错卡死。你回头查代码发现工具函数本身没毛病模型也没报错但任务就是跑不完。我后来把 Claude Code 的query.ts和QueryEngine.ts翻了一遍才意识到之前的方向偏了。工具调用只是 Agent 的“肢体动作”是表层能力真正决定它能不能稳定跑长任务的是一套轮次继续逻辑和状态保持机制。换句话说难点从来不是“怎么调用工具”而是“工具执行完之后下一轮到底该怎么继续”。而这一切的配置骨架最终都落在settings.json上。它不是一个简单的偏好文件而是 Agent 持续运行的运行时契约哪些状态跨轮保留、上下文什么时候压缩、工具怎么调度、终止条件怎么判定都能在这里找到对应的开关。这篇就从settings.json的骨架切入把工具调用之外的运行循环和状态保持机制拆开讲并给出可以直接复制、在本地复现长时运行的配置片段。2. 前置准备TaoToken 接入与运行环境在动手改settings.json之前先把模型接入这一层理顺。Claude Code 这类工具的运行循环依赖稳定的模型接口接口不稳定再好的主循环也会被网络抖动打断排查起来还容易误判成配置问题。我这边用的是 TaoToken 的接口来做模型调用它的 API 地址是https://taotoken.net/api兼容常见的 Anthropic 风格调用方式接入 Claude Code 时不需要额外改造请求结构。官网入口在https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content注册后在控制台生成 API Key 即可。拿到 Key 之后建议先单独验证一次接口连通性再往 Claude Code 里配。这样出问题时能快速区分是“接口不通”还是“配置写错”。验证命令如下curl https://taotoken.net/api/v1/messages \ -H x-api-key: $TAOTOKEN_API_KEY \ -H anthropic-version: 2023-06-01 \ -H content-type: application/json \ -d { model: claude-sonnet-4-20250514, max_tokens: 128, messages: [{role: user, content: ping}] }返回里能看到content字段和正常的stop_reason说明接口这一层没问题。如果这里就报 401 或 404先别急着改settings.json去控制台确认 Key 是否有效、模型名是否拼错。API Key 的生成入口在https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite接入文档在https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite遇到字段含义不清楚的时候对着文档查比猜快得多。环境层面Claude Code 需要 Node 环境建议 Node 18 以上。确认版本node -v npm -v然后设置环境变量把 Key 注入到运行环境里避免写死在配置文件中export TAOTOKEN_API_KEYsk-你的key export ANTHROPIC_BASE_URLhttps://taotoken.net/api这两步做完模型接入层就通了。接下来才是重点——settings.json的骨架。3. settings.json 配置骨架让 Agent 持续运行的关键字段settings.json在 Claude Code 里承担的角色类似一个运行时的调度清单。它决定了会话状态怎么存、上下文什么时候压缩、工具怎么排队、循环什么时候该继续、什么时候该停。很多人只把它当成权限白名单来用其实它管的东西远不止这些。下面这份骨架是我实测下来比较稳的一版字段做了精简保留了和持续运行最相关的部分。你可以直接复制再按自己的场景微调{ model: claude-sonnet-4-20250514, maxTokens: 8192, maxTurns: 40, context: { maxContextTokens: 180000, compactThreshold: 0.75, keepRecentMessages: 12, enableAutoCompact: true }, tools: { executionMode: streaming, maxConcurrentSafeTools: 4, serialTools: [Bash, Edit, Write], syntheticResultOnError: true }, loop: { continueOnNoToolUse: true, detectToolUseFromStream: true, relyOnStopReason: false, maxConsecutiveNoProgress: 3 }, state: { persistSession: true, sessionLogPath: ./.claude/session.log, snapshotPerTurn: true }, permissions: { allow: [Read, Glob, Grep], ask: [Bash, Edit, Write] } }这份配置里和“持续运行”直接相关的字段可以分成四组来理解。第一组是context管上下文生命周期。maxContextTokens是硬上限compactThreshold是触发压缩的水位线0.75 意味着用到 75% 就开始折叠历史消息。keepRecentMessages保证最近 12 条消息不被压缩掉避免模型丢掉当前任务的现场。enableAutoCompact打开后超限不会直接报错而是先压缩再重试。第二组是tools管工具调度。executionMode设为streaming后不需要等模型完整输出解析到完整工具指令就能提前入队。serialTools里列的是有状态、不能并发的工具Bash、Edit、Write 必须串行否则会出现文件写冲突。syntheticResultOnError打开后工具执行失败会生成兜底结果主循环不会因为单个工具报错而中断。第三组是loop管轮次继续逻辑。relyOnStopReason设为false是关键——不要只信stop_reason字段改成从流式输出里实时检测tool_use块。continueOnNoToolUse打开后即使本轮没有工具调用也不直接判定任务结束而是继续校验是否真的完成。maxConsecutiveNoProgress是防死循环的保险连续 3 轮没有实质进展就强制收口。第四组是state管状态保持。persistSession和snapshotPerTurn配合每一轮结束都生成状态快照会话可以恢复。sessionLogPath指向日志文件排查长任务中断时非常有用。把这四组字段串起来看你会发现settings.json其实是在描述一套“交通规则”上下文什么时候该让路、工具什么时候能并行、循环什么时候该继续、状态什么时候该落盘。工具调用只是这套规则里的一个动作真正让 Agent 跑得久的是规则本身。4. 验证请求复现一次长时运行并观察循环行为配置写好后别急着上复杂任务先用一个能触发多轮工具调用的场景验证循环是否按预期工作。我一般用一个“遍历目录 读取文件 汇总”的任务来测因为它天然需要多轮迭代且工具调用密集。先建一个测试目录放几个文件mkdir -p ./agent-test/src for i in 1 2 3 4 5; do echo export const value$i $i; ./agent-test/src/mod$i.ts done然后启动 Claude Code让它执行一个需要多轮的任务claude 读取 ./agent-test/src 下所有 ts 文件逐个统计每个文件的行数最后汇总总行数并把结果写入 ./agent-test/summary.txt这个任务会触发 Glob 找文件、Read 逐个读取、Write 写结果至少需要 6 到 8 轮。运行过程中重点观察三件事。第一看上下文有没有被压缩。任务跑到中段时如果compactThreshold生效你会在日志里看到类似context compacted的记录但任务不会中断模型仍然能接上之前的进度。这说明enableAutoCompact和keepRecentMessages在起作用。第二看工具是不是按串行规则排队。Read 可以并行但 Write 必须等前面的 Read 都完成。如果配置正确你不会看到 Write 和 Read 同时操作同一个文件的情况。第三看循环有没有在“无工具调用”时误判结束。有时候模型会先输出一段分析文字再决定调工具。如果relyOnStopReason还是true这种中间态很容易被误判成任务完成。改成流式检测后循环会继续等工具指令出现。任务跑完后检查结果文件cat ./agent-test/summary.txt正常输出应该包含 5 个文件的行数明细和总行数。如果文件存在且内容完整说明多轮循环、状态保持、工具调度都跑通了。如果中途断了去看./.claude/session.log里面会记录每一轮的继续原因和终止判定比盲猜快很多。想更直观地看模型在长任务里的表现也可以直接在模型对话里跑一段多轮指令观察它怎么承接上下文https://taotoken.net/model-chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel_chatutm_campaignrewrite。如果是要长期跑编码类 Agent 任务Coding Plan 会更合适https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite。5. 本篇常见错排查配置和验证过程中有几个坑出现的频率特别高基本每次帮人排查都会遇到。第一个坑是maxTurns设得太小。默认值如果只有 10长任务跑到一半就被强制终止表现是“任务没做完就停了”但日志里没有任何报错。把maxTurns调到 40 以上或者根据任务复杂度动态设置。注意它和maxConsecutiveNoProgress是两回事前者是总轮次上限后者是连续无进展的容忍度。第二个坑是serialTools漏配。只写了Bash却忘了Edit和Write结果两个写操作并行执行后写的覆盖先写的文件内容错乱。表现是“结果文件内容不对但没报错”。把有副作用的工具全部列进serialTools。第三个坑是relyOnStopReason没关。这个字段默认行为在不同版本里可能不一样如果还是依赖stop_reason判定流式输出截断时会出现“模型明明输出了工具调用系统却判定任务结束”。表现是“工具没执行但循环停了”。显式设为false强制走流式检测。第四个坑是compactThreshold设得太高。比如设成 0.95上下文几乎撑满才压缩压缩过程本身可能超时或失败。表现是“任务跑到后半段突然卡死”。建议 0.7 到 0.8 之间留出压缩操作的余量。第五个坑是sessionLogPath指向的目录不存在。日志写不进去排查时没有任何线索。启动前先确保目录存在mkdir -p ./.claude第六个坑是环境变量没生效。ANTHROPIC_BASE_URL如果拼错或没 export请求会打到默认地址表现是 401 或连接超时。用echo $ANTHROPIC_BASE_URL确认一下再启动。这几个坑有个共同点它们都不会让程序直接崩溃而是让 Agent 在长任务里“悄悄跑偏”。这也是为什么持续运行比工具调用更难——工具调用错了会报错循环逻辑错了往往无声无息。6. 把配置当成运行时契约而不是偏好文件回到最开始那个问题为什么单次工具调用能跑通长任务却总崩。答案不在工具函数里而在settings.json描述的这套运行时契约里。上下文怎么压缩、工具怎么排队、循环怎么继续、状态怎么落盘这些才是决定 Agent 能不能跑完长任务的关键。我现在的习惯是每接一个新场景先改settings.json再写业务逻辑。配置对了主循环就稳主循环稳了工具调用才有意义。反过来工具写得再漂亮循环逻辑一乱任务照样断。如果你也在调 Claude Code 的长任务建议从这份骨架开始先把context、tools、loop、state四组字段跑通再逐步加复杂度。接入文档在https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewriteAPI Key 在https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite遇到字段含义不确定的时候对着查比反复试错省时间。
