claude-code-sdk
npx skills add https://github.com/miles990/claude-software-skills --skill claude-code-sdk
Agent 安装分布
Skill 文档
Claude Code SDK Integration
Overview
Claude Code SDK (claude-code-sdk) æ¯ Anthropic 宿¹æä¾ç Python å¥ä»¶ï¼ç¨æ¼å¨æç¨ç¨å¼ä¸æ´å Claude AI Agent åè½ã宿¯æ´ OAuth èªèï¼éé claude loginï¼å API Key èªèï¼è®éç¼è
å¯ä»¥å©ç¨ Claude Max/Pro è¨é±æ API è¨è²»æ¹æ¡ãéå SDK æ¯å»ºç« AI-powered æç¨ç¨å¼çééµå·¥å
·ï¼ç¹å¥é©åéè¦ç¨å¼ç¢¼çæãæªæ¡æä½ãæå¤è¼ªå°è©±çå ´æ¯ã
Key Concepts
èªèæ¹å¼
Description: Claude Code SDK æ¯æ´å ©ç¨®èªèæ¹å¼ Key Features:
- OAuth èªè: 使ç¨
claude loginå¾åå²å¨~/.claude/çæè - API Key èªè: éé
ANTHROPIC_API_KEYç°å¢è®æ¸
Use Cases:
- OAuthï¼å人éç¼ãæ Max/Pro è¨é±çç¨æ¶
- API Keyï¼çç¢ç°å¢ãéè¦è¨éè¨è²»çæå
SDK æ ¸å¿ API
Description: query() 彿¸æ¯ä¸»è¦çé忥ä»é¢
Key Features:
- é忥è¿ä»£å¨åå³è¨æ¯
- æ¯æ´ streaming å宿´åæ
- å¯é ç½®å·¥å ·æ¬éåå·è¡éå¶
Use Cases: ç¨å¼ç¢¼çæãæªæ¡æä½ãç ç©¶ä»»åãå¯è®åæ
å·¥å ·é¡å (ToolType)
Description: SDK æ¯æ´å¤ç¨®å §å»ºå·¥å · Key Features:
READ,WRITE,EDIT– æªæ¡æä½BASH– çµç«¯å½ä»¤å·è¡GLOB,GREP– æªæ¡æå°WEB_FETCH– ç¶²é æå
Best Practices
- ééèªè檢æ¥
- åææ¯æ´ OAuth å API Key
- åªå ä½¿ç¨ OAuthï¼å è²»ä½¿ç¨ Max/Pro é é¡ï¼
- API Key ä½çºå¾åæ¹æ¡
def check_auth_status() -> dict:
status = {
'api_key_set': bool(os.environ.get('ANTHROPIC_API_KEY')),
'oauth_logged_in': False,
}
# æª¢æ¥ OAuth ç»å
¥çæ
claude_dir = os.path.expanduser('~/.claude')
if os.path.exists(claude_dir):
auth_files = ['credentials.json', 'settings.json', '.credentials.json']
for auth_file in auth_files:
if os.path.exists(os.path.join(claude_dir, auth_file)):
status['oauth_logged_in'] = True
break
# åªéè¦å
¶ä¸ä¸ç¨®èªè
status['auth_available'] = status['api_key_set'] or status['oauth_logged_in']
return status
- å¢å Buffer Size
- é è¨ buffer 太å°ï¼èç大ååææåºé¯
- 建è°å¢å å° 50MB
try:
from claude_code_sdk._internal.transport import subprocess_cli
subprocess_cli._MAX_BUFFER_SIZE = 50 * 1024 * 1024 # 50MB
except Exception as e:
print(f"Failed to patch SDK buffer size: {e}")
- ä½¿ç¨ Singleton Pattern
- é¿å éè¤åå§å
- å ±äº«çæ åé ç½®
_claude_service: Optional['ClaudeCodeService'] = None
def get_claude_code() -> 'ClaudeCodeService':
global _claude_service
if _claude_service is None:
_claude_service = ClaudeCodeService()
return _claude_service
- é è¨é
置模å¼
- ä¾æä½¿ç¨å ´æ¯éå¶å·¥å ·æ¬é
- éä½é¢¨éªï¼æåå®å ¨æ§
@dataclass
class AgentConfig:
allowed_tools: List[str]
max_turns: int = 30
cwd: Optional[str] = None
@classmethod
def coding(cls) -> 'AgentConfig':
"""éç¼æ¨¡å¼ï¼å®æ´æ¬é"""
return cls(
allowed_tools=['Read', 'Write', 'Edit', 'Bash', 'Glob', 'Grep'],
max_turns=50
)
@classmethod
def research(cls) -> 'AgentConfig':
"""ç 究模å¼ï¼å¯ä¸ç¶²"""
return cls(
allowed_tools=['Read', 'Glob', 'Grep', 'WebFetch'],
max_turns=20
)
@classmethod
def readonly(cls) -> 'AgentConfig':
"""å¯è®æ¨¡å¼ï¼æå®å
¨"""
return cls(
allowed_tools=['Read', 'Glob', 'Grep'],
max_turns=10
)
Common Pitfalls
Pitfall 1: ç´æ¥å¨å端å¼å« SDK
- Problem: claude-code-sdk æ¯ Python å¥ä»¶ï¼ç¡æ³å¨ç覽å¨ä¸éè¡
- Solution: å¿ é 建ç«å¾ç«¯ API æå
- Example:
# â é¯èª¤ï¼å試å¨å端使ç¨
# JavaScript ç¡æ³ç´æ¥ä½¿ç¨ Python SDK
# â
æ£ç¢ºï¼å»ºç« FastAPI å¾ç«¯
from fastapi import FastAPI
from claude_code_sdk import query
app = FastAPI()
@app.post("/api/generate")
async def generate(prompt: str):
result = []
async for msg in query(prompt=prompt):
result.append(msg)
return {"result": result}
Pitfall 2: å¿è¨èçé忥
- Problem: SDK æ¯é忥çï¼å¿è¨ await æå°è´é¯èª¤
- Solution: ä½¿ç¨ async/await æ asyncio
# â é¯èª¤
def run_sync():
for msg in query(prompt="Hello"): # TypeError
print(msg)
# â
æ£ç¢º
async def run_async():
async for msg in query(prompt="Hello"):
print(msg)
Pitfall 3: æ··æ· Claude API å Claude Code SDK
- Problem:
- Claude API (
anthropicå¥ä»¶) – ç´æ¥ HTTP APIï¼éè¦ API Key - Claude Code SDK (
claude-code-sdk) – Agent åè½ï¼æ¯æ´ OAuth
- Claude API (
- Solution: æ ¹æéæ±é¸ææ£ç¢ºçå¥ä»¶
| ç¹æ§ | Claude API | Claude Code SDK |
|---|---|---|
| èªè | API Key only | OAuth + API Key |
| åè½ | ç´å°è©± | Agent (æªæ¡/çµç«¯æä½) |
| è¨è²» | API ç¨éè¨è²» | Max/Pro è¨é±å¯ç¨ |
| å¥ä»¶ | anthropic |
claude-code-sdk |
Patterns & Anti-Patterns
Patterns (Do This)
宿´çæåå°è£:
from dataclasses import dataclass, field
from typing import AsyncIterator, Optional, List, Dict, Any
from claude_code_sdk import query, ClaudeCodeOptions, AssistantMessage, TextBlock
@dataclass
class ClaudeCodeService:
"""Claude Code æåå°è£"""
async def run(self, prompt: str, config: Optional[AgentConfig] = None) -> Dict[str, Any]:
"""å·è¡ä¸¦æ¶é宿´çµæ"""
options = ClaudeCodeOptions(
allowed_tools=config.allowed_tools if config else None,
max_turns=config.max_turns if config else 30,
cwd=config.cwd
)
result_texts = []
tool_calls = []
async for message in query(prompt=prompt, options=options):
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, TextBlock):
result_texts.append(block.text)
return {
'status': 'success',
'result': '\n'.join(result_texts),
'tool_calls': tool_calls
}
async def stream(self, prompt: str, config: Optional[AgentConfig] = None) -> AsyncIterator[dict]:
"""串æµå·è¡ï¼å³æåå³"""
options = ClaudeCodeOptions(
allowed_tools=config.allowed_tools if config else None,
max_turns=config.max_turns if config else 30
)
async for message in query(prompt=prompt, options=options):
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, TextBlock):
yield {'type': 'text', 'content': block.text}
FastAPI 串æµç«¯é»:
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
import json
app = FastAPI()
@app.post("/api/agent/stream")
async def agent_stream(prompt: str):
async def event_generator():
service = ClaudeCodeService()
async for msg in service.stream(prompt):
yield f"data: {json.dumps(msg)}\n\n"
yield "data: [DONE]\n\n"
return StreamingResponse(
event_generator(),
media_type="text/event-stream"
)
Anti-Patterns (Avoid This)
# â ä¸è¦å¨æ¯æ¬¡è«æ±é½å»ºç«æ°æå
@app.post("/api/generate")
async def bad_generate(prompt: str):
service = ClaudeCodeService() # æ¯æ¬¡é½æ°å»º
return await service.run(prompt)
# â ä¸è¦å¿½ç¥é¯èª¤èç
async def bad_run(prompt: str):
async for msg in query(prompt=prompt): # å¯è½æåºç°å¸¸
print(msg)
# â ä¸è¦çµ¦äºé夿¬é
config = AgentConfig(
allowed_tools=['Read', 'Write', 'Edit', 'Bash', 'WebFetch'], # å
¨é
max_turns=100 # 太å¤
)
Tools & Resources
| Tool | Purpose | Link |
|---|---|---|
| claude-code-sdk | 宿¹ Python SDK | pip install claude-code-sdk |
| Claude Code CLI | å½ä»¤åå·¥å · | npm install -g @anthropic-ai/claude-code |
| FastAPI | å¾ç«¯æ¡æ¶ | fastapi.tiangolo.com |
Decision Guide
Use Claude Code SDK when:
- éè¦ Agent åè½ï¼æªæ¡æä½ãçµç«¯å½ä»¤ï¼
- æ³ä½¿ç¨ Max/Pro è¨é±èé API è¨è²»
- 建ç«éè¦å¤è¼ªäºåç AI æç¨
- éè¦ä¸²æµå³æåæ
Consider alternatives when:
- åªéè¦ç°¡å®å°è©± â 使ç¨
anthropicå¥ä»¶ - ç´å端æç¨ â 使ç¨
anthropic+anthropic-dangerous-direct-browser-access - ä¸éè¦ Agent åè½ â ä½¿ç¨æ¨æº Claude API
Examples
Example 1: 宿´å¾ç«¯æå
Context: 建ç«ä¸åå¯ä»¥å©ç¨ Claude Max è¨é±çå¾ç«¯ API
Implementation:
# backend/main.py
import os
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import StreamingResponse
from pydantic import BaseModel
import json
from claude_code_sdk import query, ClaudeCodeOptions, AssistantMessage, TextBlock
app = FastAPI()
# CORS è¨å®
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_methods=["*"],
allow_headers=["*"],
)
class GenerateRequest(BaseModel):
prompt: str
max_turns: int = 30
def check_auth():
"""檢æ¥èªèçæ
"""
api_key = bool(os.environ.get('ANTHROPIC_API_KEY'))
oauth = os.path.exists(os.path.expanduser('~/.claude/credentials.json'))
return api_key or oauth
@app.get("/api/health")
async def health():
return {
"status": "ok",
"auth_available": check_auth()
}
@app.post("/api/generate")
async def generate(request: GenerateRequest):
if not check_auth():
raise HTTPException(401, "è«å
å·è¡ claude login æè¨ç½® ANTHROPIC_API_KEY")
options = ClaudeCodeOptions(max_turns=request.max_turns)
results = []
async for message in query(prompt=request.prompt, options=options):
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, TextBlock):
results.append(block.text)
return {"result": "\n".join(results)}
@app.post("/api/stream")
async def stream(request: GenerateRequest):
if not check_auth():
raise HTTPException(401, "æªèªè")
async def event_generator():
options = ClaudeCodeOptions(max_turns=request.max_turns)
async for message in query(prompt=request.prompt, options=options):
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, TextBlock):
yield f"data: {json.dumps({'text': block.text})}\n\n"
yield "data: [DONE]\n\n"
return StreamingResponse(event_generator(), media_type="text/event-stream")
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
requirements.txt:
fastapi>=0.100.0
uvicorn>=0.23.0
claude-code-sdk>=0.1.0
python-dotenv>=1.0.0
Explanation: éåå¾ç«¯æèªå檢測 OAuth æ API Key èªèï¼æ¯æ´ä¸è¬è«æ±å串æµåæã
Example 2: å端æ´å
Context: å端å¼å«å¾ç«¯ API
Implementation:
// ä¸è¬è«æ±
async function generate(prompt) {
const response = await fetch('http://localhost:8000/api/generate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ prompt })
});
const data = await response.json();
return data.result;
}
// 串æµè«æ±
async function streamGenerate(prompt, onChunk) {
const response = await fetch('http://localhost:8000/api/stream', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ prompt })
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
const lines = chunk.split('\n');
for (const line of lines) {
if (line.startsWith('data: ') && line !== 'data: [DONE]') {
const data = JSON.parse(line.slice(6));
onChunk(data.text);
}
}
}
}
Example 3: Docker é¨ç½²
Context: 容å¨åé¨ç½²å å« Claude Code CLI
Implementation:
# Dockerfile
FROM python:3.11-slim
# å®è£ Node.js (Claude Code CLI éè¦)
RUN apt-get update && apt-get install -y curl && \
curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && \
apt-get install -y nodejs && \
rm -rf /var/lib/apt/lists/*
# å®è£ Claude Code CLI
RUN npm install -g @anthropic-ai/claude-code
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
# docker-compose.yml
version: '3.8'
services:
backend:
build: .
ports:
- "8000:8000"
environment:
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
volumes:
- ~/.claude:/root/.claude:ro # æè¼ OAuth æè
Related Skills
- [[api-design]] – è¨è¨ REST API 端é»
- [[backend]] – Python/FastAPI å¾ç«¯éç¼
- [[devops-cicd]] – Docker é¨ç½²å CI/CD
- [[security-practices]] – API èªèåå®å ¨