Cherry Studio v2 移除 Agent 最大回合数限制(max_turns)的破坏性变更指南
【免费下载链接】cherry-studio🍒 Cherry Studio 是一款支持多个 LLM 提供商的桌面客户端项目地址: https://gitcode.com/CherryHQ/cherry-studio
本指南基于仓库内 breaking-change 记录 2026-06-18-agent-edit-drops-max-turns.md,结合源码解读
max_turns配置的退役机制与替代方案。读者读完可以明确:v2 中 per-agent 回合上限为何被移除、旧数据如何被安全保留、以及仍需要硬性上限时如何通过CLAUDE_CODE_MAX_TURNS环境变量恢复。
变更概述:per-agentmax_turns配置正式退役
自 PR #16187 起,Cherry Studio v2 正式废弃(retire)了 per-agent 的max_turns配置项。该变更属于data-migration(数据迁移)类别的破坏性变更,影响所有曾在 v1 或早期 v2 构建中设置过回合上限的 Agent。
具体来说,这次变更同时落在两个层面:
- 编辑层:v2 的 Agent 编辑对话框中从未展示过
max_turns字段,因此用户没有入口去查看、修改或恢复该上限。 - 运行时层:运行时不再读取
max_turns配置。Agent 现在会持续运行,直到满足以下任一终止条件才结束:- 任务自行完成(finishes);
- 被用户主动中断(interrupted);
- 命中了并非由该配置主导的外部限制——例如上下文压缩(context compaction)或 Provider 层错误。
与此同时,内置的Cherry Assistant与Cherry Support两个 Agent 也不再附带任何回合数上限。
对既有用户的实际影响
如果你的 Agent 此前设置过max_turns(例如从 v1 迁移而来,或通过早期构建配置的),升级到 v2 后行为变化如下:
- 以往运行到第 N 个请求/响应轮次后会以"reached maximum number of turns"(达到最大轮次)结束的长周期自主任务,现在不会再在该轮次被强制终止,而会继续执行。
- v2 UI 中不存在任何字段可以查看或恢复这个旧上限——这一点与"编辑层从不展示该字段"的设计一致。
简言之:旧配置的约束效果静默消失,且无 UI 回退路径。这不是 bug,而是有意的设计变更。
用户需要做什么:默认无需任何操作
本次变更无需用户手动干预——升级后自动生效("automatic")。如果你仍然希望为一个 Agent 施加硬性的回合数上限,唯一官方保留的途径是:
在 Agent 的**高级设置(advanced settings)**中,将
CLAUDE_CODE_MAX_TURNS设置为环境变量。
从源码看,这一机制有明确的承载点:Agent 配置 Schema 中保留了env_vars字段(z.record(z.string(), z.string())),用于向 Agent 运行时注入任意环境变量(见 src/shared/data/api/schemas/agents.ts)。CLAUDE_CODE_MAX_TURNS正是通过该机制传入底层 CLI 运行时的——它由 Claude Code 运行时原生消费,属于"由 Agent 自己掌控"的上限,而非 Cherry Studio 应用层施加的限制,因此不受本次移除影响。
为什么旧数据"留而不读":.loose()模式与配置 JSON Blob
对发布与数据团队最关键的实现细节在于:旧max_turns值不会被删除,只是不再被读取。
Agent 的配置对象以 JSON blob 形式存储在数据库中,其解析 Schema 使用了.loose()(即 zod 的 passthrough)模式。源码中的注释明确了这一设计意图:
.loose()(passthrough) is intentional: the configuration object is stored as a JSON blob and may contain keys written by older or newer versions of the app. Unknown fields must survive a round-trip through parse() so they are not silently dropped on the next save.
也就是说(见 src/shared/data/api/schemas/agents.ts):
AgentConfigurationSchema通过.loose()允许未知键存在;- 存储的
max_turns作为未知扩展字段,在每次 parse 往返(round-trip)中原样保留,不会被静默丢弃; - 但由于 Schema 中已不再定义
max_turns这一已知键,没有任何运行时路径会读取它——它只是安静地留在 JSON blob 里。
这一设计与配套的读取端净化函数sanitizeAgentConfiguration相辅相成(见 src/shared/data/api/schemas/agents.ts):当配置中出现类型错误的已知键时,只剔除出错的顶层键、保留良构字段与未知扩展;未知的max_turns永远不会触发剔除逻辑。因此可以推断:即便未来某次写回配置,旧max_turns值也大概率继续留在 blob 中,形成一种"冗余但无害"的数据保留状态。
结论:旧数据安全、可追溯(便于未来迁移或审计),但不再具有任何行为语义。
内置 Agent 的变化:Cherry Assistant 与 Cherry Support
本次变更同步移除了内置 Agent 的回合上限。仓库中以BUILTIN_AGENT_ROLE常量定义了两种受保护的内置角色(见 src/shared/ai/builtinAgent.ts):
assistant—— Cherry Assistant;support—— Cherry Support(固定 ID 为cherry-support)。
二者的身份/人格由 BuiltinAgentProvisioner.ts 在启动时加载并初始化持久化目录(persona/memory 文件),角色与能力由configuration.builtin_role字段驱动(可参考 ensureBuiltinAgent.test.ts 等测试对内置 Agent 配置的断言)。本次变更意味着:这些内置 Agent 不再被任何 turn cap 约束,其运行终止条件与普通 Agent 保持一致(完成、中断、上下文压缩或 Provider 错误)。
源码证据:运行时仍识别"回合错误",但已与应用层配置解耦
需要澄清一个容易混淆的点:运行时层面依然存在与回合相关的终止信号,但这与 per-agent 的max_turns配置无关。
在 Claude Code 流式适配器中,mapClaudeCodeFinishReason仍然映射了error_max_turns这一 finish reason,并将其归类为unified: 'length'(见 src/main/ai/runtime/claudeCode/streamAdapter.ts):
case 'error_max_turns': return { unified: 'length', raw }这说明:如果底层 Claude Code 运行时(例如通过CLAUDE_CODE_MAX_TURNS环境变量)自身触发了回合数错误,Cherry Studio 仍能正确解析并向上层报告。区别在于——该上限由 CLI 运行时自己施加,而不是由 Cherry Studio 的应用层配置施加。本次废弃的只是后者,前者(运行时自带能力)完整保留,这正是"仍想要硬性上限就设环境变量"方案的底层依据。
不要混淆:OpenCode 的maxTurns配置键仍然存在
仓库中还存在另一处maxTurns,但它属于OpenCode CLI 自身的配置键,与本次废弃的 per-agentmax_turns是两回事:
- managedKeys.ts 中,
OPEN_CODE_MANAGED_TOP_LEVEL_KEYS = ['autoCompact', 'maxTurns', 'permission'],即应用会托管(managed)OpenCode 的maxTurns顶层配置; - 相关清理测试 clear.test.ts 中也能看到
maxTurns: 30的示例值。
同时,UI 测试确认了废弃方向的完整性:CliConfigFields.test.tsx 断言 OpenCode 高级设置面板不再渲染max_turns_hint提示文案(expect(screen.queryByText('code.adv.opencode.max_turns_hint')).not.toBeInTheDocument()),与"编辑层不展示该字段"的变更陈述互相印证。
因此:maxTurns这个名字在 OpenCode CLI 配置语境下依然有效,但它控制的是 OpenCode 运行时行为;不要再把它与已被废弃的 per-agentmax_turns应用层配置混为一谈。
给发布经理与维护者的备注
记录在案的关键信息(供 release notes 与后续维护参考):
- 数据安全:已存储的
max_turns值保留在配置 JSON blob 中,.loose()Schema 保证未知扩展字段不被清除;它们只是永远不会被再次读取。 - 行为来源:该行为与
feat/chat-page分支保持一致,最初由提交5383513090 feat(agent): enhance agent configuration with permission mode and soul mode options引入;如需修改,应同步回上游对应分支,而非仅在当前仓库内打补丁。 - 迁移类别:本变更归类为
data-migration(数据迁移类)破坏性变更,与 v2-refactor-temp/docs/breaking-changes 目录下其他同类别记录(如 Agent 会话主工作区、Agent 配置扁平化等变更)属于同一追踪体系,升级测试与回滚预案应一并纳入该类别评审。
常见问题速查
| 问题 | 答案 |
|---|---|
升级后旧max_turns会自动删除吗? | 不会。它保留在配置 JSON blob 中,只是不再被读取。 |
| v2 UI 能恢复旧上限吗? | 不能。编辑对话框从未展示该字段,也没有查看入口。 |
| 任务会无限运行吗? | 不会真正无限。任务会在完成、被中断、上下文压缩或 Provider 错误时终止。 |
| 想要硬性上限怎么办? | 在 Agent 高级设置中将CLAUDE_CODE_MAX_TURNS设为环境变量(通过配置中的env_vars注入运行时)。 |
OpenCode 的maxTurns也废弃了吗? | 没有。那是 OpenCode CLI 自身的托管配置键,仍然有效,与 per-agent 配置是两套机制。 |
总结
Cherry Studio v2 对 Agent 回合数策略做了一个方向性的简化:回合数不再由应用层配置主导,而是交给任务自然结束条件与底层运行时能力。对普通用户而言这是一次零操作升级;对依赖硬性回合上限的高级用户,CLAUDE_CODE_MAX_TURNS环境变量提供了明确且被官方文档化的替代路径;对维护者而言,.loose()Schema 保证旧数据可追溯、不丢失,为未来的数据迁移保留了充分的回旋空间。
【免费下载链接】cherry-studio🍒 Cherry Studio 是一款支持多个 LLM 提供商的桌面客户端项目地址: https://gitcode.com/CherryHQ/cherry-studio
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考