Chuyển từ OpenAI Agents SDK sang Claude — Hướng dẫn migration chi tiết
Điểm nổi bật
Nhấn để đến mục tương ứng
- 1Xác định đúng vấn đề trước khi nghĩ tới giải pháp
- 2Khung tư duy nền tảng giúp ra quyết định nhất quán
- 3Áp dụng vào thực tế với quy trình 4 bước
- 4Tránh những sai lầm phổ biến khi triển khai

Hướng dẫn port từng primitive từ OpenAI Agents SDK sang Claude Agent SDK — tools, guardrails, sessions, observability.
Nếu bạn đang dùng OpenAI Agents SDK và muốn chuyển sang Claude Agent SDK, bài này mapping từng primitive giữa hai SDK qua ví dụ thực tế: expense approval agent.
Bài viết dựa trên Claude Cookbooks chính thức của Anthropic.
Bạn được gì sau migration?
Claude Agent SDK chạy trên cùng runtime với Claude Code — bạn thừa hưởng:
- Built-in tools:
Read,Edit,Bash,Grep - Layered permission system cho tool gating
- Automatic prompt caching
- Event stream cho progress streaming hoặc mid-run interception
Trade-off: tool definitions explicit hơn (declare schemas thay vì dựa vào type-hint introspection), nhưng ít boilerplate ở mọi chỗ khác.
Mapping tổng quan
| OpenAI Agents SDK | Claude Agent SDK |
|---|---|
Agent(name, instructions, tools) |
ClaudeAgentOptions + system prompt |
@function_tool |
@tool + create_sdk_mcp_server
|
@input_guardrail |
Plain function before loop (hoặc UserPromptSubmit hook) |
@output_guardrail |
Plain function on ResultMessage.result
|
Runner.run(agent, msg) |
ClaudeSDKClient context manager |
| Sessions (client-managed) | Reuse same ClaudeSDKClient
|
conversation_id (server) |
resume=session_id (disk-backed) |
| Built-in tracing dashboard | OTel-native (Grafana/Datadog/Honeycomb) |
handoffs=[...] |
AgentDefinition + Agent tool |
Primitive 1: @function_tool → @tool + MCP Server
OpenAI
from agents import function_tool
@function_tool
def check_policy(expense_type: str, amount: float) -> str:
"""Check if expense complies with company policy"""
if amount > 5000:
return "REQUIRES_APPROVAL: Over $5000 limit"
return "APPROVED: Within policy limits"
Claude
from claude_agent_sdk import tool, create_sdk_mcp_server
@tool(
name="check_policy",
description="Check if expense complies with company policy",
schema={
"type": "object",
"properties": {
"expense_type": {"type": "string"},
"amount": {"type": "number"}
},
"required": ["expense_type", "amount"]
}
)
async def check_policy(args):
if args["amount"] > 5000:
result = "REQUIRES_APPROVAL: Over $5000 limit"
else:
result = "APPROVED: Within policy limits"
return {"content": [{"type": "text", "text": result}]}
# Bundle vào MCP server
expense_server = create_sdk_mcp_server(
"expense", tools=[check_policy]
)
Key difference: Claude yêu cầu explicit JSON Schema thay vì derive từ type hints. Business logic bên trong không thay đổi.
Primitive 2: Agent() → ClaudeAgentOptions
OpenAI
from agents import Agent
agent = Agent(
name="expense_agent",
instructions="You are an expense approval agent...",
tools=[check_policy],
model="gpt-4o"
)
Claude
from claude_agent_sdk import ClaudeAgentOptions
expense_options = ClaudeAgentOptions(
model="claude-sonnet-4-6",
system_prompt="You are an expense approval agent...",
mcp_servers={"expense": expense_server},
allowed_tools=["mcp__expense__check_policy"]
)
Note về permissions: allowed_tools make tool available. Read-only custom tools chạy tự do. Write tools cần approval trừ khi set permission_mode="bypassPermissions".
Primitive 3: Guardrails
Input Guardrail — OpenAI vs Claude
OpenAI: @input_guardrail decorator, registered on Agent.
Claude: Plain function called before loop. Hoặc UserPromptSubmit hook.
# Claude: plain function approach
def validate_input(prompt: str) -> str | None:
if "$" not in prompt and "dollar" not in prompt.lower():
return "Please include dollar amount in your request"
return None # Valid
# Gọi trước khi start client
error = validate_input(user_prompt)
if error:
print(error)
return
# Proceed with agent
async with ClaudeSDKClient(options=expense_options) as client:
await client.query(user_prompt)
...
Output Guardrail
# Claude: check result after loop
async for msg in client.receive_response():
if hasattr(msg, 'result'):
if "REQUIRES_APPROVAL" in msg.result:
# Flag for human review
notify_manager(msg.result)
final_result = msg.result
Primitive 4: Runner.run() → ClaudeSDKClient
OpenAI
result = await Runner.run(agent, "Approve expense: $200 lunch")
print(result.final_output)
Claude
async with ClaudeSDKClient(options=expense_options) as client:
await client.query("Approve expense: $200 lunch")
async for msg in client.receive_response():
if hasattr(msg, 'result'):
print(msg.result)
Claude's event stream cho bạn thấy mọi thứ: tool calls, text blocks, final result — theo thứ tự real-time.
| Event Type | Contains |
|---|---|
| SystemMessage | Session init metadata |
| AssistantMessage | Text blocks hoặc tool-use blocks |
| UserMessage | Tool-result blocks |
| ResultMessage | .result, .usage, .total_cost_usd |
Primitive 5: Sessions
-
In-memory: Reuse same
ClaudeSDKClientinstance -
Disk-backed:
resume=session_idđể persist across restarts
# Session persists across restarts
async with ClaudeSDKClient(
options=expense_options,
resume="session-abc-123" # Disk-backed persistence
) as client:
await client.query("Follow up on yesterday's expense")
...
Observability: OTel-native
OpenAI có built-in tracing dashboard. Claude SDK export qua OpenTelemetry — plugs vào existing Grafana, Datadog, Honeycomb stack.
Migration Checklist
- Port
@function_tool→@tool+ explicit schemas - Replace
Agent()→ClaudeAgentOptions - Move guardrails ra khỏi decorators, thành plain functions
- Replace
Runner.run()→ClaudeSDKClientcontext manager - Port sessions → reuse client hoặc
resume= - Wire OTel export cho observability
- Test từng primitive independently trước khi integrate
Bước tiếp theo: Bắt đầu với Research Agent cho Agent SDK basics, hoặc Chief of Staff Agent cho advanced multi-agent patterns.
Bài viết liên quan
Bài viết có hữu ích không?
Bản quyền thuộc về tác giả. Vui lòng dẫn nguồn khi chia sẻ.










Bình luận (0)