文档索引
在此处获取完整文档索引:https://code.claude.com/docs/llms.txt 使用此文件发现所有可用页面,然后再进一步探索。
使用会话
会话如何持久化智能体对话历史,以及何时使用 continue、resume 和 fork 返回到之前的运行。
会话是 SDK 在你的智能体工作期间累积的对话历史。它包含你的提示、智能体进行的每次工具调用、每个工具结果和每次响应。SDK 自动将其写入磁盘,以便你稍后可以返回。
返回到会话意味着智能体拥有之前的完整上下文:它已经读取的文件、已经执行的分析、已经做出的决定。你可以提出后续问题、从中断中恢复或分支去尝试不同的方法。
会话持久化的是对话,而非文件系统。要快照和恢复智能体所做的文件更改,请使用文件检查点。
本指南涵盖如何为你的应用选择正确的方法、自动跟踪会话的 SDK 接口、如何捕获会话 ID 并手动使用 resume 和 fork,以及跨主机恢复会话的注意事项。
选择方法
你需要多少会话处理取决于你的应用程序形态。当你发送应该共享上下文的多个提示时,会话管理才会起作用。在单个 query() 调用中,智能体已经根据需要进行多轮交互,权限提示和 AskUserQuestion 在循环内处理(它们不会结束调用)。
| 你在构建什么 | 使用什么 |
|---|---|
| 一次性任务:单个提示,无后续 | 无需额外操作。一个 query() 调用即可处理。 |
| 单个进程中的多轮对话 | ClaudeSDKClient(Python)或 continue: true(TypeScript)。SDK 自动为你跟踪会话,无需处理 ID。 |
| 进程重启后从上次中断的地方继续 | continue_conversation=True(Python)/ continue: true(TypeScript)。恢复目录中最近的会话,无需 ID。 |
| 恢复特定的过去会话(非最近的) | 捕获会话 ID 并传递给 resume。 |
| 尝试替代方案而不丢失原始会话 | 分叉会话。 |
| 无状态任务,不想将任何内容写入磁盘(仅 TypeScript) | 设置 persistSession: false。会话仅在调用期间存在于内存中。Python 始终持久化到磁盘。 |
Continue、Resume 和 Fork
Continue、resume 和 fork 是你在 query() 上设置的选项字段(Python 中的 ClaudeAgentOptions,TypeScript 中的 Options)。
Continue 和 resume 都会拾取现有会话并向其添加内容。区别在于它们如何找到该会话:
- Continue 查找当前目录中最近的会话。你无需跟踪任何东西。当你的应用一次运行一个对话时效果很好。
- Resume 接受特定的会话 ID。你需要跟踪 ID。当你有多个会话(例如多用户应用中每个用户一个会话)或想返回到非最近的会话时需要使用。
Fork 不同:它创建一个以原始会话历史副本开始的新会话。原始会话保持不变。使用 fork 在保持返回选项的同时尝试不同的方向。
自动会话管理
两个 SDK 都提供了在调用之间跟踪会话状态的接口,因此你无需手动传递 ID。在单个进程内的多轮对话中使用这些。
Python:ClaudeSDKClient
ClaudeSDKClient 内部处理会话 ID。每次调用 client.query() 自动继续同一会话。调用 client.receive_response() 迭代当前查询的消息。客户端通常用作异步上下文管理器。
此示例对同一个 client 运行两个查询。第一个要求智能体分析模块;第二个要求重构该模块。因为两个调用都通过同一个客户端实例,第二个查询拥有第一个查询的完整上下文,无需显式 resume 或会话 ID:
import asyncio
from claude_agent_sdk import (
ClaudeSDKClient,
ClaudeAgentOptions,
AssistantMessage,
ResultMessage,
TextBlock,
)
def print_response(message):
"""Print only the human-readable parts of a message."""
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, TextBlock):
print(block.text)
elif isinstance(message, ResultMessage):
cost = (
f"${message.total_cost_usd:.4f}"
if message.total_cost_usd is not None
else "N/A"
)
print(f"[done: {message.subtype}, cost: {cost}]")
async def main():
options = ClaudeAgentOptions(
allowed_tools=["Read", "Edit", "Glob", "Grep"],
)
async with ClaudeSDKClient(options=options) as client:
# First query: client captures the session ID internally
await client.query("Analyze the auth module")
async for message in client.receive_response():
print_response(message)
# Second query: automatically continues the same session
await client.query("Now refactor it to use JWT")
async for message in client.receive_response():
print_response(message)
asyncio.run(main())
有关何时使用 ClaudeSDKClient 与独立 query() 函数的详情,请参阅 Python SDK 参考。
TypeScript:continue: true
TypeScript SDK 没有像 Python 的 ClaudeSDKClient 那样的会话持有客户端对象。相反,在每个后续的 query() 调用中传递 continue: true,SDK 会拾取当前目录中最近的会话。无需 ID 跟踪。
此示例进行两个独立的 query() 调用。第一个创建新会话;第二个设置 continue: true,告诉 SDK 查找并恢复磁盘上最近的会话。智能体拥有第一个调用的完整上下文:
import { query } from "@anthropic-ai/claude-agent-sdk";
// First query: creates a new session
for await (const message of query({
prompt: "Analyze the auth module",
options: { allowedTools: ["Read", "Glob", "Grep"] }
})) {
if (message.type === "result" && message.subtype === "success") {
console.log(message.result);
}
}
// Second query: continue: true resumes the most recent session
for await (const message of query({
prompt: "Now refactor it to use JWT",
options: {
continue: true,
allowedTools: ["Read", "Edit", "Write", "Glob", "Grep"]
}
})) {
if (message.type === "result" && message.subtype === "success") {
console.log(message.result);
}
}
实验性的 V2 会话 API 提供了带有 send / stream 模式的 createSession(),已在 TypeScript Agent SDK 0.3.142 中移除。请改用 query() 函数和本页描述的会话选项。
在 query() 中使用会话选项
捕获会话 ID
Resume 和 fork 需要会话 ID。从结果消息的 session_id 字段读取(Python 中的 ResultMessage,TypeScript 中的 SDKResultMessage),该字段在每个结果上都存在,无论成功还是错误。在 TypeScript 中,ID 也可以更早地作为 init SystemMessage 的直接字段获得;在 Python 中,它嵌套在 SystemMessage.data 内。
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
async def main():
session_id = None
async for message in query(
prompt="Analyze the auth module and suggest improvements",
options=ClaudeAgentOptions(
allowed_tools=["Read", "Glob", "Grep"],
),
):
if isinstance(message, ResultMessage):
session_id = message.session_id
if message.subtype == "success":
print(message.result)
print(f"Session ID: {session_id}")
return session_id
session_id = asyncio.run(main())
import { query } from "@anthropic-ai/claude-agent-sdk";
let sessionId: string | undefined;
for await (const message of query({
prompt: "Analyze the auth module and suggest improvements",
options: { allowedTools: ["Read", "Glob", "Grep"] }
})) {
if (message.type === "result") {
sessionId = message.session_id;
if (message.subtype === "success") {
console.log(message.result);
}
}
}
console.log(`Session ID: ${sessionId}`);
通过 ID 恢复
将会话 ID 传递给 resume 以返回到该特定会话。智能体从上次中断的地方恢复完整上下文。恢复的常见原因:
- 跟进已完成的任务。 智能体已经分析了某些内容;现在你想让它在不重新读取文件的情况下对该分析采取行动。
- 从限制中恢复。 第一次运行以
error_max_turns或error_max_budget_usd结束(参见处理结果);使用更高的限制恢复。 - 重启进程。 你在关闭前捕获了 ID,想恢复对话。
此示例使用后续提示恢复捕获会话 ID 中的会话。因为你是恢复,智能体已经将之前的分析包含在上下文中:
# Earlier session analyzed the code; now build on that analysis
async for message in query(
prompt="Now implement the refactoring you suggested",
options=ClaudeAgentOptions(
resume=session_id,
allowed_tools=["Read", "Edit", "Write", "Glob", "Grep"],
),
):
if isinstance(message, ResultMessage) and message.subtype == "success":
print(message.result)
// Earlier session analyzed the code; now build on that analysis
for await (const message of query({
prompt: "Now implement the refactoring you suggested",
options: {
resume: sessionId,
allowedTools: ["Read", "Edit", "Write", "Glob", "Grep"]
}
})) {
if (message.type === "result" && message.subtype === "success") {
console.log(message.result);
}
}
如果 resume 调用返回新会话而非预期的历史记录,最常见的原因是 cwd 不匹配。会话存储在 ~/.claude/projects/<encoded-cwd>/*.jsonl 下,其中 <encoded-cwd> 是绝对工作目录,每个非字母数字字符被替换为 -(因此 /Users/me/proj 变为 -Users-me-proj)。如果你的 resume 调用从不同的目录运行,SDK 会在错误的位置查找。会话文件也需要存在于当前机器上。
要在机器之间或在无服务器环境中恢复会话,请使用 SessionStore 适配器将记录镜像到共享存储。
分叉以探索替代方案
分叉创建一个以原始会话历史副本开始但从该点分叉的新会话。分叉获得自己的会话 ID;原始会话的 ID 和历史保持不变。你最终得到两个独立的会话,可以分别恢复。
分叉分支的是对话历史,而非文件系统。如果分叉的智能体编辑了文件,这些更改是真实的,在同一目录中工作的任何会话都可以看到。要分支和恢复文件更改,请使用文件检查点。
此示例基于捕获会话 ID:你已经在 session_id 中分析了认证模块,想探索 OAuth2 而不丢失以 JWT 为中心的线程。第一个代码块分叉会话并捕获分叉的 ID(forked_id);第二个代码块恢复原始 session_id 以继续 JWT 路径。你现在有两个指向两个独立历史的会话 ID:
# Fork: branch from session_id into a new session
forked_id = None
async for message in query(
prompt="Instead of JWT, implement OAuth2 for the auth module",
options=ClaudeAgentOptions(
resume=session_id,
fork_session=True,
),
):
if isinstance(message, ResultMessage):
forked_id = message.session_id # The fork's ID, distinct from session_id
if message.subtype == "success":
print(message.result)
print(f"Forked session: {forked_id}")
# Original session is untouched; resuming it continues the JWT thread
async for message in query(
prompt="Continue with the JWT approach",
options=ClaudeAgentOptions(resume=session_id),
):
if isinstance(message, ResultMessage) and message.subtype == "success":
print(message.result)
// Fork: branch from sessionId into a new session
let forkedId: string | undefined;
for await (const message of query({
prompt: "Instead of JWT, implement OAuth2 for the auth module",
options: {
resume: sessionId,
forkSession: true
}
})) {
if (message.type === "system" && message.subtype === "init") {
forkedId = message.session_id; // The fork's ID, distinct from sessionId
}
if (message.type === "result" && message.subtype === "success") {
console.log(message.result);
}
}
console.log(`Forked session: ${forkedId}`);
// Original session is untouched; resuming it continues the JWT thread
for await (const message of query({
prompt: "Continue with the JWT approach",
options: { resume: sessionId }
})) {
if (message.type === "result" && message.subtype === "success") {
console.log(message.result);
}
}
跨主机恢复
会话文件本地存储在创建它们的机器上。要在不同的主机(CI 工作器、临时容器、无服务器)上恢复会话,你有两个选择:
- 移动会话文件。 从第一次运行持久化
~/.claude/projects/<encoded-cwd>/<session-id>.jsonl,并在调用resume之前将其恢复到新主机上的相同路径。cwd必须匹配。 - 不依赖会话恢复。 将你需要的结果(分析输出、决策、文件差异)作为应用状态捕获,并将它们传入新会话的提示中。这通常比来回传送记录文件更可靠。
两个 SDK 都提供了枚举磁盘上会话和读取消息的函数:TypeScript 中的 listSessions() 和 getSessionMessages(),Python 中的 list_sessions() 和 get_session_messages()。使用它们来构建自定义会话选择器、清理逻辑或记录查看器。
两个 SDK 还提供了查找和修改单个会话的函数:Python 中的 get_session_info()、rename_session() 和 tag_session(),TypeScript 中的 getSessionInfo()、renameSession() 和 tagSession()。使用它们按标签组织会话或为其添加人类可读的标题。
相关资源
- 智能体循环如何工作:了解会话内的轮次、消息和上下文累积
- 文件检查点:跨会话跟踪和恢复文件更改
- Python
ClaudeAgentOptions:Python 的完整会话选项参考 - TypeScript
Options:TypeScript 的完整会话选项参考