流式输出与多轮对话
- 逐 token 流式返回响应,让用户立即看到输出
- 理解为什么这个 API 是无状态的,以及如何自行携带对话历史
- 通过重新发送完整的此前交互内容来继续多轮对话
- 避免让长对话撑爆上下文窗口并推高成本
在 API 上构建类聊天体验,归根结底要面对两个现实:要流式输出,让用户立即看到结果;要自行管理历史,因为 API 是无状态的。掌握这两点,你的聊天体验就会既快速又能记住一切。
流式输出
不使用流式输出时,用户要等待整段回复。使用流式输出时,token 会随生成而陆续到达——感知速度要快得多。
- 使用 SDK 的流式辅助方法,而不是手动解析原始事件——它会替你管理事件的生命周期。
- Python
- TypeScript
with client.messages.stream(
model="claude-sonnet-5", max_tokens=1024,
messages=[{"role": "user", "content": "Explain RAG in two sentences."}],
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)
const stream = client.messages.stream({
model: "claude-sonnet-5", max_tokens: 1024,
messages: [{ role: "user", content: "Explain RAG in two sentences." }],
});
for await (const event of stream) {
if (event.type === "content_block_delta") process.stdout.write(event.delta.text ?? "");
}
多轮对话:历史由你保管
API 在两次调用之间没有记忆(原因)。要继续一段对话,每次都要把此前的全部交互内容重新发送回去。
Guided walkthrough1 of 4
- 在 messages 列表中发送第一条用户消息。
- 从结果中读取 assistant 的响应文本。
- 把 assistant 的回复和下一条用户消息都加入同一个 messages 列表。
- 再次发送完整的 messages 列表——Claude 正是这样“记住”整段交互的。
messages = [{"role": "user", "content": "Hi, I'm planning a trip."}]
# ... get assistant reply, then append both turns:
messages.append({"role": "assistant", "content": assistant_text})
messages.append({"role": "user", "content": "Make it 3 days."})
# send the full `messages` list again
长对话会填满窗口
随着历史增长,它会蚕食上下文窗口,成本也随之上升。以下是控制它的几种策略:
- 总结/压缩较早的对话轮次,浓缩为一段简短的回顾并继续向前携带。
- 裁剪掉不相关的较早轮次。
- 与 提示词缓存 搭配,避免为稳定前缀重复付费。
- 每次调用都会重新发送整段历史——长对话成本更高,如果你从不压缩或裁剪,最终可能超出上下文窗口。
- 流式返回 token 以获得快速的感知速度;SDK 辅助方法会处理事件生命周期。
- API 是无状态的——它在两次调用之间没有记忆。
- 通过追加每一轮并重新发送完整的 messages 列表来继续对话。
- 通过压缩、裁剪和缓存来控制长对话的成本与体量。