Một session là lịch sử hội thoại SDK tích luỹ trong khi agent của bạn làm việc. Nó chứa prompt của bạn, mọi lời gọi tool agent thực hiện, mọi kết quả tool, và mọi phản hồi. SDK tự động ghi nó xuống đĩa để bạn quay lại sau.
Quay lại một session nghĩa là agent có đầy đủ context từ trước: file nó đã đọc, phân tích nó đã thực hiện, quyết định nó đã đưa ra. Bạn có thể hỏi tiếp một câu, khôi phục sau gián đoạn, hoặc rẽ nhánh để thử cách tiếp cận khác.
Hướng dẫn này bao gồm cách chọn cách tiếp cận phù hợp cho ứng dụng của bạn, các interface SDK tự động theo dõi session, cách lấy session ID và dùng resume và fork thủ công, và những điều cần biết khi resume session xuyên host.
Chọn cách tiếp cận
Phần tiêu đề “Chọn cách tiếp cận”Bạn cần xử lý session nhiều hay ít tuỳ vào hình dạng ứng dụng của bạn. Quản lý session phát huy tác dụng khi bạn gửi nhiều prompt cần chia sẻ context. Trong một lời gọi query() duy nhất, agent đã tự thực hiện bao nhiêu turn nó cần, và permission prompt cùng AskUserQuestion được xử lý trong vòng lặp (chúng không kết thúc lời gọi).
| Bạn đang xây gì | Dùng gì |
|---|---|
| Tác vụ một lần: một prompt, không có follow-up | Không cần gì thêm. Một lời gọi query() là đủ. |
| Chat nhiều lượt trong một process | ClaudeSDKClient (Python) hoặc continue: true (TypeScript). SDK tự theo dõi session cho bạn, không cần xử lý ID. |
| Tiếp tục từ nơi bạn dừng lại sau khi process restart | continue_conversation=True (Python) / continue: true (TypeScript). Resume session gần nhất trong thư mục, không cần ID. |
| Resume một session cụ thể trong quá khứ (không phải gần nhất) | Lấy session ID và truyền vào resume. |
| Thử một cách tiếp cận khác mà không mất bản gốc | Fork session. |
| Tác vụ stateless, không muốn ghi gì xuống đĩa (chỉ TypeScript) | Đặt persistSession: false. Session chỉ tồn tại trong bộ nhớ trong lúc lời gọi diễn ra. Python luôn ghi xuống đĩa. |
Continue, resume, và fork
Phần tiêu đề “Continue, resume, và fork”Continue, resume, và fork là các trường option bạn đặt trên query() (ClaudeAgentOptions trong Python, Options trong TypeScript).
Continue và resume đều lấy một session có sẵn và thêm vào nó. Khác biệt là cách chúng tìm session đó:
- Continue tìm session gần nhất trong thư mục hiện tại. Bạn không cần theo dõi gì. Phù hợp khi ứng dụng của bạn chạy một hội thoại tại một thời điểm.
- Resume nhận một session ID cụ thể. Bạn theo dõi ID. Cần thiết khi bạn có nhiều session (ví dụ, một cho mỗi người dùng trong ứng dụng multi-user) hoặc muốn quay lại một session không phải gần nhất.
Fork thì khác: nó tạo một session mới bắt đầu với bản copy lịch sử của bản gốc. Bản gốc giữ nguyên không đổi. Dùng fork để thử một hướng khác trong khi vẫn giữ được lựa chọn quay lại.
Quản lý session tự động
Phần tiêu đề “Quản lý session tự động”Cả hai SDK đều cung cấp một interface tự theo dõi trạng thái session qua các lời gọi, nên bạn không cần tự truyền ID. Dùng chúng cho hội thoại nhiều lượt trong một process.
Python: ClaudeSDKClient
Phần tiêu đề “Python: ClaudeSDKClient”ClaudeSDKClient tự xử lý session ID nội bộ. Mỗi lời gọi client.query() tự động tiếp tục cùng session. Gọi client.receive_response() để lặp qua message cho query hiện tại. Dùng client như một async context manager để việc thiết lập và dọn dẹp kết nối được xử lý cho bạn, hoặc gọi connect() và disconnect() thủ công.
Ví dụ này chạy hai query trên cùng client. Query đầu yêu cầu agent phân tích một module; query thứ hai yêu cầu nó refactor module đó. Vì cả hai lời gọi đi qua cùng một instance client, query thứ hai có đầy đủ context từ query đầu mà không cần resume hay session ID tường minh nào:
import asynciofrom claude_agent_sdk import ( ClaudeSDKClient, ClaudeAgentOptions, AssistantMessage, ResultMessage, TextBlock,)
def print_response(message): """In chỉ phần dễ đọc của một 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: # Query đầu: client lưu session ID nội bộ await client.query("Analyze the auth module") async for message in client.receive_response(): print_response(message)
# Query thứ hai: tự động tiếp tục cùng session await client.query("Now refactor it to use JWT") async for message in client.receive_response(): print_response(message)
asyncio.run(main())Mỗi query in ra phản hồi text của agent theo sau bởi một dòng trạng thái từ result message, ví dụ [done: success, cost: $0.0042].
TypeScript: continue: true
Phần tiêu đề “TypeScript: continue: true”TypeScript SDK không có một client object giữ session như ClaudeSDKClient của Python. Thay vào đó, truyền continue: true trên mỗi lời gọi query() tiếp theo và SDK sẽ tìm session gần nhất trong thư mục hiện tại. Không cần theo dõi ID.
Ví dụ này thực hiện hai lời gọi query() riêng biệt. Lời gọi đầu tạo một session mới; lời gọi thứ hai đặt continue: true, báo cho SDK tìm và resume session gần nhất trên đĩa. Agent có đầy đủ context từ lời gọi đầu:
import { query } from "@anthropic-ai/claude-agent-sdk";
// Query đầu: tạo một session mớitry { 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); } }} catch (error) { // Một lời gọi query() single-shot throw lỗi sau khi yield result lỗi, // nên query tiếp theo bên dưới vẫn chạy. console.error(`Session ended with an error: ${error}`);}
// Query thứ hai: continue: true resume session gần nhấtfor 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); }}Dùng session option với query()
Phần tiêu đề “Dùng session option với query()”Lấy session ID
Phần tiêu đề “Lấy session ID”Resume và fork cần một session ID. Đọc nó từ trường session_id trên result message (ResultMessage trong Python, SDKResultMessage trong TypeScript), luôn có mặt trên mọi result bất kể thành công hay lỗi. Trong TypeScript, ID cũng khả dụng sớm hơn như một trường trực tiếp trên SystemMessage init; trong Python nó nằm lồng trong SystemMessage.data.
import asynciofrom claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
async def main(): session_id = None
try: 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) except Exception as error: # Một lời gọi query() single-shot raise lỗi sau khi yield result lỗi. Nếu # lỗi đến từ result lỗi, vòng lặp trên đã lưu session_id rồi; # lỗi process không yield result message nào, nên session_id vẫn None. print(f"Session ended with an error: {error}")
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;
try { 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); } } }} catch (error) { // Một lời gọi query() single-shot throw lỗi sau khi yield result lỗi. Nếu // lỗi đến từ result lỗi, vòng lặp trên đã lưu sessionId rồi; // lỗi process không yield result message nào, nên sessionId vẫn undefined. console.error(`Session ended with an error: ${error}`);}
console.log(`Session ID: ${sessionId}`);Khi query hoàn tất, script in ra phản hồi của agent theo sau bởi một dòng như Session ID: 5b3f2c1a-8d4e-4f6b-9a7c-2e1d0f9b8a6c. Ở các phần tiếp theo, bạn truyền ID này vào resume.
Resume theo ID
Phần tiêu đề “Resume theo ID”Truyền một session ID vào resume để quay lại session đó. Agent tiếp tục với đầy đủ context từ nơi session dừng lại. Lý do phổ biến để resume:
- Follow up một tác vụ đã hoàn tất. Agent đã phân tích thứ gì đó; giờ bạn muốn nó hành động dựa trên phân tích đó mà không cần đọc lại file.
- Khôi phục sau khi chạm giới hạn. Lần chạy đầu kết thúc bằng
error_max_turnshoặcerror_max_budget_usd; resume với giới hạn cao hơn. Trong một lời gọiquery()single-shot, SDK raise lỗi sau khi yield result đó, nên bắt lỗi trước khi resume. - Restart process của bạn. Bạn đã lưu ID trước khi shutdown và muốn khôi phục hội thoại.
Ví dụ này resume session từ Lấy session ID với một prompt follow-up. Vì bạn đang resume, agent đã có phân tích trước đó trong context:
import asynciofrom claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
session_id = "..." # ID bạn đã lưu ở ví dụ trước
async def main(): # Session trước đã phân tích code; giờ dựa trên phân tích đó 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)
asyncio.run(main())import { query } from "@anthropic-ai/claude-agent-sdk";
const sessionId = "..."; // ID bạn đã lưu ở ví dụ trước
// Session trước đã phân tích code; giờ dựa trên phân tích đó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); }}Bạn sẽ thấy một phản hồi xây dựng dựa trên phân tích trước đó thay vì bắt đầu lại từ đầu. Điều đó xác nhận agent đã resume session với context trước đó còn nguyên vẹn.
Để resume session xuyên máy hoặc trong môi trường serverless, mirror transcript vào shared storage bằng một adapter SessionStore.
Fork để khám phá phương án khác
Phần tiêu đề “Fork để khám phá phương án khác”Fork tạo một session mới bắt đầu với bản copy lịch sử của bản gốc nhưng rẽ nhánh từ điểm đó. Bản fork có session ID riêng; ID và lịch sử của bản gốc giữ nguyên không đổi. Bạn sẽ có hai session độc lập, mỗi cái có thể resume riêng.
Ví dụ này dựa trên Lấy session ID: bạn đã phân tích một module auth trong session_id và muốn khám phá OAuth2 mà không mất luồng tập trung vào JWT. Khối đầu fork session và lưu ID của bản fork (forked_id); khối thứ hai resume session_id gốc để tiếp tục hướng JWT. Giờ bạn có hai session ID trỏ tới hai lịch sử riêng biệt:
import asynciofrom claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
session_id = "..." # ID bạn đã lưu ở ví dụ trước
async def main(): # Fork: rẽ nhánh từ session_id thành một session mới forked_id = None try: async for message in query( prompt="Instead of JWT, outline how OAuth2 would work for the auth module", options=ClaudeAgentOptions( resume=session_id, fork_session=True, max_turns=5, ), ): if isinstance(message, ResultMessage): forked_id = message.session_id # ID của bản fork, khác session_id if message.subtype == "success": print(message.result) except Exception as error: # Một lời gọi query() single-shot raise lỗi sau khi yield result lỗi. Nếu # lỗi đến từ result lỗi, forked_id đã được lưu bởi vòng lặp trên; # lỗi process không yield result message nào cả. print(f"Session ended with an error: {error}")
print(f"Forked session: {forked_id}")
# Session gốc không bị đụng tới; resume nó tiếp tục luồng JWT try: 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) except Exception as error: # Một lời gọi query() single-shot raise lỗi sau khi yield result lỗi. print(f"Session ended with an error: {error}")
asyncio.run(main())import { query } from "@anthropic-ai/claude-agent-sdk";
const sessionId = "..."; // ID bạn đã lưu ở ví dụ trước
// Fork: rẽ nhánh từ sessionId thành một session mớilet forkedId: string | undefined;
try { for await (const message of query({ prompt: "Instead of JWT, outline how OAuth2 would work for the auth module", options: { resume: sessionId, forkSession: true, maxTurns: 5 } })) { if (message.type === "system" && message.subtype === "init") { forkedId = message.session_id; // ID của bản fork, khác sessionId } if (message.type === "result" && message.subtype === "success") { console.log(message.result); } }} catch (error) { // Một lời gọi query() single-shot throw lỗi sau khi yield result lỗi. Nếu // lỗi đến từ result lỗi, forkedId đã được lưu bởi vòng lặp trên; // lỗi process không yield result message nào cả. console.error(`Session ended with an error: ${error}`);}
console.log(`Forked session: ${forkedId}`);
// Session gốc không bị đụng tới; resume nó tiếp tục luồng JWTtry { 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); } }} catch (error) { // Một lời gọi query() single-shot throw lỗi sau khi yield result lỗi. console.error(`Session ended with an error: ${error}`);}Bạn sẽ thấy forkedId khác với session ID gốc. Resume session gốc vẫn tiếp tục luồng JWT, xác nhận fork không làm thay đổi lịch sử gốc.
Resume xuyên host
Phần tiêu đề “Resume xuyên host”File session gắn với máy đã tạo ra nó. Để resume một session trên host khác (CI worker, container ephemeral, serverless), bạn có hai lựa chọn:
- Di chuyển file session. Lưu
~/.claude/projects/<encoded-cwd>/<session-id>.jsonltừ lần chạy đầu và khôi phục nó vào cùng đường dẫn trên host mới trước khi gọiresume.cwdphải khớp. - Không dựa vào resume session. Lưu kết quả bạn cần (output phân tích, quyết định, file diff) làm trạng thái ứng dụng và đưa chúng vào prompt của một session mới. Cách này thường bền vững hơn là gửi transcript file đi.
Cả hai SDK đều expose hàm để liệt kê session trên đĩa và đọc message của chúng: listSessions() và getSessionMessages() trong TypeScript, list_sessions() và get_session_messages() trong Python. Dùng chúng để xây session picker tuỳ biến, logic dọn dẹp, hoặc transcript viewer.
Cả hai SDK cũng expose hàm để tra cứu và thay đổi từng session riêng lẻ: get_session_info(), rename_session(), và tag_session() trong Python, và getSessionInfo(), renameSession(), và tagSession() trong TypeScript. Dùng chúng để tổ chức session theo tag hay đặt tiêu đề dễ đọc.
Tài nguyên liên quan
Phần tiêu đề “Tài nguyên liên quan”- Agent loop hoạt động thế nào: Hiểu turn, message, và tích luỹ context trong một session
- File checkpointing: Snapshot và revert thay đổi file agent đã làm trong một session
- Python
ClaudeAgentOptions: Tham khảo đầy đủ option session cho Python - TypeScript
Options: Tham khảo đầy đủ option session cho TypeScript
lượt xem