Claude Messages API 是无状态的。每个请求必须包含完整的对话历史——所有之前的用户消息、助手响应和工具交互。如果你只发最新的消息,Claude 对之前的上下文一无所知。对话从头开始。
没有 session ID,没有 conversation ID,没有服务端状态,没有自动的上下文保留。
常见故障
一个聊天机器人在第 1 和第 2 轮运行完美。到第 3 轮,Claude 的回复好像没有对话发生过一样:“我没有任何搜索结果可以分析”——尽管第 2 轮的工具调用成功返回了有效数据。
开发者在第 3 轮的请求中只发了新的用户消息。第 2 轮的 tool_result 没有包含。Claude 确实不知道搜索发生过。
每个请求里必须有什么
完整的消息序列:
- 所有用户消息
- 所有助手响应(包括 tool_use 块)
- 所有 tool_result 消息
- 当前新的用户消息
缺任何一段——尤其是 tool_result 消息——对话就断了。助手的 tool_use 请求和对应的 tool_result 必须同时存在,Claude 才知道工具返回了什么。
数据
| 历史管理方式 | 客户满意度 | 上下文丢失投诉 |
|---|---|---|
| 每个请求发完整历史 | 95% | 2% |
| 间歇性截断历史 | 52% | 41% |
一个序列化 bug 间歇性地从数组中丢消息,造成了 43 个百分点的满意度差距。同样的模型、同样的 prompt、同样的话题——唯一的变量是完整历史有没有包含。
跨会话连续性
客户离开聊天,几小时后回来期望上下文还在。API 在请求之间什么都不记得——更别提会话之间了。
解决方案:把完整的消息数组存在数据库里,以客户/对话 ID 为键。客户回来时,加载完整历史并包含在下一个请求中。Claude 看到的是一段无缝对话。
管理超长对话
对于 50 轮以上的对话,每个请求都发完整历史成本太高。自适应策略:
- 普通对话(≤20 轮): 每个请求发完整历史
- 长对话(50+ 轮): 使用 Case Facts 块(保留关键值)加最近的消息。Case Facts 保持核心上下文同时裁剪旧的叙述轮次。
这就是 K5.1.1(结构化 case facts)的连接点:在摘要中保持精度的持久化机制同时也是无状态 API 中长对话的紧凑表示。
不存在的东西
- Conversation ID 参数 — 没有这个功能。API 没有引用先前请求的机制。
- 服务端会话状态 — 服务端不存储对话。每个请求是独立的。
- 自动上下文保留 — 不是 24 小时,不是任何时长。零服务端持久化。
- 缓存引用 token — API 无法从外部缓存中检索状态。
- 服务端状态的轮次限制 — 不存在服务端状态,也就不存在限制。
调试间歇性上下文丢失
如果有些轮次保持了上下文而有些丢了,问题在客户端的历史管理。第一步诊断:记录每个请求发送的完整 messages 数组。对比正常轮次和异常轮次。异常的那些会有不完整或被截断的历史——很可能是竞态条件或序列化 bug。
System prompt 指令弥补不了缺失的历史。如果之前的消息不在请求里,任何指令都无法让 Claude 引用它没有的信息。
一句话总结: Claude API 是无状态的——每个请求都需要完整的消息历史(所有轮次、所有工具结果),因为服务端什么都不记,一个丢弃历史的序列化 bug 会造成 43 个百分点的满意度崩塌。