我们追踪到近期关于 Claude Code 质量问题的报告,发现其根源在于三项独立的变更。以下是具体情况以及我们正在采取的改进措施。
过去一个月里,我们一直在调查部分用户反映 Claude 回复质量下降的报告。经追踪,这些报告源于三项独立的变更,分别影响了 Claude Code、Claude Agent SDK 和 Claude Cowork。API 未受影响。
截至 4 月 20 日(v2.1.116),这三个问题均已得到解决。
在这篇文章中,我们将说明调查结果、已修复的内容,以及我们将采取哪些不同的做法,以确保类似问题再次发生的可能性大大降低。
我们非常严肃地对待关于性能下降的报告。我们从未有意降低模型性能,并且能够立即确认我们的 API 和推理层未受影响。
经过调查,我们发现了三个不同的问题:
- 3 月 4 日,我们更改了 Claude Code 的默认推理努力程度,从高改为中,以减少部分用户在高模式下遇到的极长延迟——这种延迟足以让用户界面看起来像卡住了一样。这是一个错误的权衡。在用户反馈他们更倾向于默认使用更高的智能水平,并在处理简单任务时选择较低的努力程度后,我们于 4 月 7 日撤销了这一更改。该问题影响了 Sonnet 4.6 和 Opus 4.6。
- 3 月 26 日,我们发布了一项更改,以清除空闲超过一小时的会话中 Claude 的旧思考内容,从而减少用户恢复这些会话时的延迟。一个错误导致该操作在会话的后续每一轮对话中持续发生,而本应只执行一次,这使得 Claude 显得健忘且重复。我们于 4 月 10 日修复了此问题。该问题影响了 Sonnet 4.6 和 Opus 4.6。
- 4 月 16 日,我们添加了一条系统提示指令以减少冗长回复。该指令与其他提示词变更相结合,损害了编码质量,并于 4 月 20 日被撤销。该问题影响了 Sonnet 4.6、Opus 4.6 和 Opus 4.7。
由于每项变更在不同时间表上影响了不同的流量切片,其综合效果表现为广泛且不一致的性能下降。虽然我们在 3 月初就开始调查相关报告,但起初很难将其与用户反馈中的正常波动区分开来,而且我们内部的用法和评估最初也未能复现所识别出的问题。
这不应是用户对 Claude Code 应有的体验。自 4 月 23 日起,我们将重置所有订阅用户的使用限制。
Claude Code 默认推理强度的变更
当我们在 2 月份于 Claude Code 中发布 Opus 4.6 时,我们将默认推理强度设置为高。
不久之后,我们收到用户反馈,称 Claude Opus 4.6 在高强度模式下偶尔会思考过久,导致用户界面看似卡顿,并为这些用户带来了不成比例的延迟和 token 消耗。
通常,模型思考时间越长,输出效果越好。推理强度是 Claude Code 让用户设定这种权衡的方式——更多思考 vs 更低延迟和更少触及使用限制。在我们为模型校准推理强度时,会考虑这种权衡,以便在测试时计算曲线上选取能给予用户最佳选项范围的点。在产品层面,我们随后选择该曲线上的某个点作为默认值,并将该值作为推理强度参数发送给 Messages API;然后通过 `/effort` 提供其他选项。
在我们的内部评估和测试中,中等强度在大多数任务上实现了略低的智能水平,但延迟显著降低。它也没有出现偶尔因思考而产生极长尾延迟的问题,并且有助于最大化用户的使用限制。因此,我们推出了一项变更,将中等强度设为默认值,并通过产品内对话框解释了理由。
推出后不久,用户开始报告称 Claude Code 感觉变笨了。我们推出了多个设计迭代,以使当前的推理强度设置更加清晰,从而提醒用户可以更改默认值(启动时的通知、内联推理强度选择器,以及恢复超强思考模式),但大多数用户仍保留了中等强度的默认设置。
在听取了更多客户的反馈后,我们于 4 月 7 日撤销了这一决定。现在,所有用户在 Opus 4.7 上默认使用极高推理强度,在所有其他模型上默认使用高推理强度。
一项导致先前推理内容丢失的缓存优化
当 Claude 对某个任务进行推理时,该推理过程通常会保留在对话历史中,这样在后续的每一轮交互中,Claude 都能看到自己当初为何做出那些编辑和工具调用。
3 月 26 日,我们发布了一项本意是对该功能进行效率优化的更新。我们使用提示词缓存来降低用户连续 API 调用的成本并提升速度。当 Claude 发起 API 请求时,会将输入 token 写入缓存;在一段时间不活动后,该提示词会被从缓存中清除,为其他提示词腾出空间。缓存利用率是我们精心管理的一项指标(更多详情请参见我们的方法)。
该设计本应很简单:如果某个会话空闲超过一小时,我们可以通过清除旧的思考片段来降低用户恢复该会话的成本。由于该请求无论如何都会发生缓存未命中,我们可以从请求中修剪掉不必要的消息,以减少发送到 API 的未缓存 token 数量。之后我们再恢复发送完整的推理历史。为此,我们使用了 `clear_thinking_20251015` API 头部以及 `keep:1` 参数。
该实现存在一个缺陷。它并非只清除一次思考历史,而是在该会话的后续每一轮交互中都进行清除。一旦某个会话超过了空闲阈值,该进程后续的每一次请求都会告诉 API 只保留最近的一个推理块,并丢弃之前的所有内容。这个问题会不断累积:如果你在 Claude 正在执行工具调用时发送了一条后续消息,这会在有缺陷的标志下开启新的一轮,导致即使是当前轮次的推理也会被丢弃。Claude 会继续执行,但会越来越不记得自己当初为何选择做正在做的事。这便表现为用户所报告的健忘、重复以及奇怪的工具选择。
由于这会持续从后续请求中丢弃思考块,这些请求同样会导致缓存未命中。我们认为,这正是导致另有用户报告使用额度消耗速度超出预期的原因。
两个互不相关的实验最初让我们难以复现该问题:一个是仅限服务端内部、与消息队列相关的实验;另一个是我们对思考展示方式所做的正交改动,这一改动在大多数 CLI 会话中抑制了该 bug,导致我们在测试外部构建版本时也未能发现它。
这个 bug 出现在 Claude Code 的上下文管理、Anthropic API 以及扩展思考功能的交叉点上。它所引入的改动通过了多次人工和自动化代码审查,以及单元测试、端到端测试、自动化验证和内部试用。再加上该问题仅出现在一个边缘情况(过期会话)中,且复现难度大,我们花了一周多时间才找到并确认根本原因。
作为调查的一部分,我们使用 Opus 4.7 对有问题的拉取请求进行了代码审查回溯测试。在提供了获取完整上下文所需的代码仓库后,Opus 4.7 发现了该 bug,而 Opus 4.6 则没有。为防止此类问题再次发生,我们现在正在为代码审查增加对更多代码仓库作为上下文的支持。
我们于 4 月 10 日在 v2.1.101 版本中修复了此 bug。
为降低冗长程度而修改的系统提示词
我们最新的模型 Claude Opus 4.7 与其前代相比有一个显著的行为特点:正如我们在发布时提到的,它倾向于生成非常冗长的回答。这使得它在处理难题时更聪明,但同时也产生了更多的输出 token。
在发布 Opus 4.7 的几周前,我们就开始调整 Claude Code 以做准备。每个模型的行为都略有不同,我们会在每次发布前花时间为该模型优化其适配框架和产品。
我们拥有多种降低冗长程度的工具:模型训练、提示词优化,以及改进产品中的思考展示体验。最终我们使用了所有这些方法,但系统提示词中的一项新增内容对 Claude Code 的智能表现产生了超乎寻常的影响:
“长度限制:工具调用之间的文本保持在 25 词以内。最终回复保持在 100 词以内,除非任务需要更多细节。”
经过数周的内部测试,并且在我们运行的一系列评估中没有出现回归问题后,我们对这一改动充满信心,并于 4 月 16 日随 Opus 4.7 一同发布。
作为此次调查的一部分,我们使用更广泛的评估集进行了更多消融实验(从系统提示词中移除各行,以理解每行的影响)。其中一项评估显示,Opus 4.6 和 4.7 均下降了 3%。我们立即在 4 月 20 日的发布中回退了该提示词。
未来方向
我们将采取多项不同措施来避免这些问题:确保更多内部员工使用与公开版本完全一致的 Claude Code 构建版本(而非我们用于测试新功能的版本);同时改进我们内部使用的代码审查工具,并将改进后的版本交付给客户。
我们还将对系统提示词变更实施更严格的控制。对于 Claude Code 的每次系统提示词变更,我们都会运行一套覆盖各模型的广泛评估,持续进行消融实验以理解每行的影响,并且已构建新工具来使提示词变更更易于审查和审计。此外,我们已在 CLAUDE.md 中添加指引,确保针对特定模型的变更仅作用于该目标模型。对于任何可能影响智能水平的变更,我们将设置观察期、更广泛的评估套件以及逐步推出机制,以便更早发现问题。
我们最近在 X 平台创建了 @ClaudeDevs 账号,以便有空间深入解释产品决策及其背后的推理过程。我们将在 GitHub 的集中讨论帖中同步发布同样的更新。
最后,我们要感谢我们的用户:正是那些使用 /feedback 命令向我们反馈问题的人(或在网上发布具体可复现示例的人),最终帮助我们识别并修复了这些问题。今天,我们将重置所有订阅用户的使用限制。
我们无比感激您的反馈与耐心。
We traced recent reports of Claude Code quality issues to three separate changes. Here's what happened and what we're changing.
Over the past month, we’ve been looking into reports that Claude’s responses have worsened for some users. We’ve traced these reports to three separate changes that affected Claude Code, the Claude Agent SDK, and Claude Cowork. The API was not impacted.
All three issues have now been resolved as of April 20 (v2.1.116).
In this post, we explain what we found, what we fixed, and what we’ll do differently to ensure similar issues are much less likely to happen again.
We take reports about degradation very seriously. We never intentionally degrade our models, and we were able to immediately confirm that our API and inference layer were unaffected.
After investigation, we identified three different issues:
- On March 4, we changed Claude Code's default reasoning effort from
hightomediumto reduce the very long latency—enough to make the UI appear frozen—some users were seeing inhighmode. This was the wrong tradeoff. We reverted this change on April 7 after users told us they'd prefer to default to higher intelligence and opt into lower effort for simple tasks. This impacted Sonnet 4.6 and Opus 4.6. - On March 26, we shipped a change to clear Claude's older thinking from sessions that had been idle for over an hour, to reduce latency when users resumed those sessions. A bug caused this to keep happening every turn for the rest of the session instead of just once, which made Claude seem forgetful and repetitive. We fixed it on April 10. This affected Sonnet 4.6 and Opus 4.6.
- On April 16, we added a system prompt instruction to reduce verbosity. In combination with other prompt changes, it hurt coding quality and was reverted on April 20. This impacted Sonnet 4.6, Opus 4.6, and Opus 4.7.
Because each change affected a different slice of traffic on a different schedule, the aggregate effect looked like broad, inconsistent degradation. While we began investigating reports in early March, they were challenging to distinguish from normal variation in user feedback at first, and neither our internal usage nor evals initially reproduced the issues identified.
This isn’t the experience users should expect from Claude Code. As of April 23, we’re resetting usage limits for all subscribers.
A change to Claude Code's default reasoning effort
When we released Opus 4.6 in Claude Code in February, we set the default reasoning effort to high.
Soon after, we received user feedback that Claude Opus 4.6 in high effort mode would occasionally think for too long, causing the UI to appear frozen and leading to disproportionate latency and token usage for those users.
In general, the longer the model thinks, the better the output. Effort levels are how Claude Code lets users set that tradeoff—more thinking versus lower latency and fewer usage limit hits. As we calibrate effort levels for our models, we take this tradeoff into account in order to pick points along the test-time-compute curve that give people the best range of options. In the product layer, we then choose which point along this curve we set as our default, and that is the value we send to the Messages API as the effort parameter; we then make the other options available via /effort.
In our internal evals and testing, medium effort achieved slightly lower intelligence with significantly less latency for the majority of tasks. It also didn’t suffer from the same issues with occasional very long tail latencies for thinking, and it helped maximize users’ usage limits. As a result, we rolled out a change making medium the default effort, and explained the rationale via in-product dialog.
Soon after rolling out, users began reporting that Claude Code felt less intelligent. We shipped a number of design iterations to make the current effort setting clearer in order to alert people they could change the default (notices on startup, an inline effort selector, and bringing back ultrathink), but most users retained the medium effort default.
After hearing feedback from more customers, we reversed this decision on April 7. All users now default to xhigh effort for Opus 4.7, and high effort for all other models.
A caching optimization that dropped prior reasoning
When Claude reasons through a task, that reasoning is normally kept in the conversation history so that on every subsequent turn, Claude can see why it made the edits and tool calls it did.
On March 26, we shipped what was meant to be an efficiency improvement to this feature. We use prompt caching to make back-to-back API calls cheaper and faster for users. Claude writes the input tokens to the cache when it makes an API request, then after a period of inactivity the prompt is evicted from cache, making room for other prompts. Cache utilization is something we manage carefully (more on our approach).
The design should have been simple: if a session has been idle for more than an hour, we could reduce users’ cost of resuming that session by clearing old thinking sections. Since the request would be a cache miss anyway, we could prune unnecessary messages from the request to reduce the number of uncached tokens sent to the API. We’d then resume sending full reasoning history. To do this we used the clear_thinking_20251015 API header along with keep:1.
The implementation had a bug. Instead of clearing thinking history once, it cleared it on every turn for the rest of the session. After a session crossed the idle threshold once, each request for the rest of that process told the API to keep only the most recent block of reasoning and discard everything before it. This compounded: if you sent a follow-up message while Claude was in the middle of a tool use, that started a new turn under the broken flag, so even the reasoning from the current turn was dropped. Claude would continue executing, but increasingly without memory of why it had chosen to do what it was doing. This surfaced as the forgetfulness, repetition, and odd tool choices people reported.
Because this would continuously drop thinking blocks from subsequent requests, those requests also resulted in cache misses. We believe this is what drove the separate reports of usage limits draining faster than expected.
Two unrelated experiments made it challenging for us to reproduce the issue at first: an internal-only server-side experiment related to message queuing; and an orthogonal change in how we display thinking suppressed this bug in most CLI sessions, so we didn’t catch it even when testing external builds.
This bug was at the intersection of Claude Code’s context management, the Anthropic API, and extended thinking. The changes it introduced made it past multiple human and automated code reviews, as well as unit tests, end-to-end tests, automated verification, and dogfooding. Combined with this only happening in a corner case (stale sessions) and the difficulty of reproducing the issue, it took us over a week to discover and confirm the root cause.
As part of the investigation, we back-tested Code Review against the offending pull requests using Opus 4.7. When provided the code repositories necessary to gather complete context, Opus 4.7 found the bug, while Opus 4.6 didn't. To prevent this from happening again, we are now landing support for additional repositories as context for code reviews.
We fixed this bug on April 10 in v2.1.101.
A system prompt change to reduce verbosity
Our latest model, Claude Opus 4.7, has a notable behavioral quirk relative to its predecessor: as we wrote about at launch, it tends to be quite verbose. This makes it smarter on hard problems, but it also produces more output tokens.
A few weeks before we released Opus 4.7, we started tuning Claude Code in preparation. Each model behaves slightly differently, and we spend time before each release optimizing the harness and product for it.
We have a number of tools to reduce verbosity: model training, prompting, and improving thinking UX in the product. Ultimately we used all of these, but one addition to the system prompt caused an outsized effect on intelligence in Claude Code:
“Length limits: keep text between tool calls to ≤25 words. Keep final responses to ≤100 words unless the task requires more detail.”
After multiple weeks of internal testing and no regressions in the set of evaluations we ran, we felt confident about the change and shipped it alongside Opus 4.7 on April 16.
As part of this investigation, we ran more ablations (removing lines from the system prompt to understand the impact of each line) using a broader set of evaluations. One of these evaluations showed a 3% drop for both Opus 4.6 and 4.7. We immediately reverted the prompt as part of the April 20 release.
Going forward
We are going to do several things differently to avoid these issues: we’ll ensure that a larger share of internal staff use the exact public build of Claude Code (as opposed to the version we use to test new features); and we'll make improvements to our Code Review tool that we use internally, and ship this improved version to customers.
We’re also adding tighter controls on system prompt changes. We will run a broad suite of per-model evals for every system prompt change to Claude Code, continuing ablations to understand the impact of each line, and we have built new tooling to make prompt changes easier to review and audit. We've additionally added guidance to our CLAUDE.md to ensure model-specific changes are gated to the specific model they're targeting. For any change that could trade off against intelligence, we'll add soak periods, a broader eval suite, and gradual rollouts so we catch issues earlier.
We recently created @ClaudeDevs on X to give us the room to explain product decisions and the reasoning behind them in depth. We'll share the same updates in centralized threads on GitHub.
Finally, we’d like to thank our users: the people who used the /feedback command to share their issues with us (or who posted specific, reproducible examples online) are the ones who ultimately allowed us to identify and fix these problems. Today we are resetting usage limits for all subscribers.
We’re immensely grateful for your feedback and for your patience.