任务停止时机对比
任务停止时机对比
1. 这份文档回答什么问题
这份文档聚焦一个非常实际的问题:
当用户发来一条完整需求时,Claude Code 和 Opencode 会在什么时候判断“当前应该停下来”,以及什么时候会继续自动推进。
这不是在问“能不能完成任务”,而是在问:
- 一次用户请求会自动推进到什么程度
- 系统靠什么判断该结束
- 什么时候必须等用户下一条提示词
2. 先给结论
2.1 Claude Code
Claude Code 更像:
尽量自己多跑几轮,直到系统级裁决认为该停。
它不会简单按“一轮模型输出结束”就停,而是会继续检查:
- 还有没有
tool_use - 是否需要恢复重试
- stop hook 是否阻止结束
- token budget 是否要求继续
- 是否触发中断、报错或上限
2.2 Opencode
Opencode 更像:
按一轮一轮推进;这轮如果没有明确继续理由,就停下来等下一条用户消息。
它的停止判定更集中在:
- 本轮是否被阻塞
- 是否出错
- 是否需要压缩
- 模型是否自然完成
3. Claude Code:任务什么时候停
3.1 最基础的停点
Claude Code 的主循环核心在:
claude-code-rev/src/query.ts
最原始的继续判断来自:
needsFollowUp
只要 assistant 流式输出里出现了 tool_use,就会把:
needsFollowUp = true
这意味着:
- 本轮不能停
- 后面必须先执行工具,再决定是否进入下一轮
反过来,如果这一轮结束时:
needsFollowUp === false
它才进入“可能结束”的分支。
3.2 但“没有 tool_use”也不代表马上停
即便模型没有继续调工具,Claude Code 也还会继续检查:
- prompt-too-long 恢复
- media-size 恢复
- max_output_tokens 恢复
- stop hooks
- token budget continuation
也就是说:
模型觉得自己答完了,不等于系统认可这轮该结束。
3.3 常见停止原因
Claude Code 常见的停点包括:
completedstop_hook_preventedprompt_too_longaborted_streamingaborted_toolsmax_turns
这些停止原因说明,Claude Code 的结束时机是由一整套状态机共同裁决的,而不是由单个“完成标志”决定。
4. Claude Code:面对完整需求文档时会怎样
如果用户发来一份完整需求文档,Claude Code 的典型行为不是“只做一轮”,而是:
- 读取需求
- 调工具搜上下文
- 可能修改代码
- 再次调工具验证
- 若还需要,再继续下一轮
所以它有可能在一条用户消息下自动推进很多轮。
但它不会无限推进,因为以下场景都会让它停住:
4.1 当前子任务已经闭环
比如:
- 没有新的
tool_use - 没有恢复路径要继续
- stop hook 不阻止
- budget 也没要求续跑
这时它就结束这次用户请求。
4.2 遇到必须由用户裁决的点
比如:
- 权限不足
- 方案有歧义
- 需要用户决定方向
- hook 或规则要求人工确认
这时它就会停住,等待用户下一条消息。
4.3 被系统边界拦下
比如:
- token 不够
- 上下文过长
- max turns
- 用户主动中断
这时也会停止。
5. Opencode:任务什么时候停
5.1 内层判定只有三种结果
Opencode 的主循环核心拆成两层:
packages/opencode/src/session/processor.tspackages/opencode/src/session/prompt.ts
其中 processor.ts 在处理完一轮流之后,只返回三种结果:
continuecompactstop
这是理解 Opencode 停止时机的关键。
5.2 stop 的典型条件
processor.ts 最终会在这些情况下返回 stop:
- 本轮被阻塞
- assistant message 进入错误状态
其中“被阻塞”常见来源是:
- 权限拒绝
- 问题请求被拒绝
这类情况意味着:
当前自动推进已经无法继续,必须停下来。
5.3 compact 的条件
如果本轮发现上下文溢出,需要压缩,就返回:
compact
外层 loop 会先跑 compaction,再继续,而不是直接结束。
5.4 默认继续条件
如果:
- 没被阻塞
- 没出错
- 不需要压缩
那么 processor 就返回:
continue
6. Opencode:真正结束的时机
外层 prompt.ts 会拿到 processor.process(...) 的结果,然后决定:
stop:直接 breakcompact:先压缩,再继续continue:进入下一轮
但它还有一个很关键的上层语义:
如果模型这一轮自然完成了,并且没有明确的继续理由,Opencode 会更倾向于停下来。
也就是说,Opencode 更像是:
- 一轮做一段
- 能继续就继续
- 没明确继续理由就停
7. Opencode:面对完整需求文档时会怎样
如果用户发来一份完整需求文档,Opencode 通常也可能自动跑多轮,但整体风格比 Claude Code 更保守:
- 做完当前这轮能闭环的内容
- 如果还有工具调用或 compaction 需要,就继续
- 如果模型自然停了、没有工具、没有继续条件,就停住
所以它并不是“永远做完整个需求”,而是:
做到当前 session loop 认为合理的停点,然后等用户下一句。
8. 两者最本质的差异
8.1 Claude Code
Claude Code 的结束时机更像:
系统级状态机裁决。
它会综合:
- tool follow-up
- 恢复路径
- hook
- budget
- 中断
- 上限
因此它更容易在一条用户消息下自动跑很多轮。
8.2 Opencode
Opencode 的结束时机更像:
流处理结果 + 外层 loop 的简单控制。
它的判断没有 Claude Code 那么集中和厚重,停止点更接近:
- 本轮是否自然完成
- 是否被阻塞
- 是否出错
- 是否需要压缩
因此它更容易在“做完当前可闭环部分”后停下。
9. 一句话总结
如果把两者压成一句话:
- Claude Code:会尽量自己把一次用户请求往后推进,直到系统确认该停。
- Opencode:会按轮推进任务,没明确继续理由时更容易停下来等用户下一句。
所以面对一份完整需求文档,两者都不等于“必然一次做完全部”,只是 Claude Code 更激进,Opencode 更保守。