Agent SDK로 자동화 에이전트 만들기: 실전 가이드 (2026)
Claude Agent SDK는 Claude가 외부 도구(툴)를 직접 호출하며 멀티스텝 작업을 자율 실행하게 해준다. 단순 API 호출(질문→답변)과 달리, 에이전트는 검색 → 분석 → 결과 저장처럼 여러 단계를 스스로 결정하며 완료한다. 이 가이드는 첫 에이전트 작성부터 실제 자동화 워크플로우, 프로덕션 배포까지 전부 다룬다.
에이전트 vs 단순 API 호출
| 단순 API 호출 | 에이전트 | |
|---|---|---|
| 작동 방식 | 질문 → 응답 | 목표 → 계획 → 툴 실행 → 완료 |
| 스텝 수 | 1 | 여러 스텝 (자율 결정) |
| 툴 사용 | 없음 | 직접 함수/API 호출 |
| 적합한 작업 | 단순 Q&A, 텍스트 생성 | 데이터 수집, 분석, 자동화 |
에이전트가 필요한 경우: "웹을 검색해서 최신 정보 가져오기", "파일 읽고 분석 후 보고서 저장", "외부 API 여러 개를 조합해 작업 완료"
설치 및 기본 구조
pip install anthropic
Agent SDK는 별도 패키지가 아니라 anthropic SDK의 일부다. 핵심은 툴 정의와 툴 루프다.
가장 단순한 에이전트
import anthropic
import json
client = anthropic.Anthropic()
# 1. 툴 정의
tools = [
{
"name": "get_current_time",
"description": "현재 날짜와 시간을 반환합니다",
"input_schema": {
"type": "object",
"properties": {},
"required": []
}
}
]
# 2. 툴 실행 함수
def get_current_time() -> str:
from datetime import datetime
return datetime.now().strftime("%Y년 %m월 %d일 %H:%M:%S")
# 3. 에이전트 루프
def run_agent(user_message: str) -> str:
messages = [{"role": "user", "content": user_message}]
while True:
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=4096,
tools=tools,
messages=messages
)
# Claude가 작업 완료 → 최종 답변 반환
if response.stop_reason == "end_turn":
return response.content[-1].text
# Claude가 툴 사용 요청 → 실행 후 결과 전달
if response.stop_reason == "tool_use":
messages.append({"role": "assistant", "content": response.content})
tool_results = []
for block in response.content:
if block.type == "tool_use":
if block.name == "get_current_time":
result = get_current_time()
else:
result = f"Unknown tool: {block.name}"
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": result
})
messages.append({"role": "user", "content": tool_results})
print(run_agent("지금 몇 시야?"))
실전 에이전트 1: 뉴스 수집 + 요약 에이전트
웹에서 뉴스를 가져와 한국어로 요약하는 에이전트:
import anthropic
import requests
from bs4 import BeautifulSoup
client = anthropic.Anthropic()
tools = [
{
"name": "search_news",
"description": "주제에 관한 최신 뉴스를 검색합니다",
"input_schema": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "검색할 키워드"
},
"num_results": {
"type": "integer",
"description": "가져올 결과 수 (최대 5)",
"default": 3
}
},
"required": ["query"]
}
},
{
"name": "fetch_article",
"description": "URL에서 기사 본문을 가져옵니다",
"input_schema": {
"type": "object",
"properties": {
"url": {"type": "string", "description": "기사 URL"}
},
"required": ["url"]
}
},
{
"name": "save_summary",
"description": "요약 내용을 파일로 저장합니다",
"input_schema": {
"type": "object",
"properties": {
"filename": {"type": "string"},
"content": {"type": "string"}
},
"required": ["filename", "content"]
}
}
]
def search_news(query: str, num_results: int = 3) -> str:
# 실제 구현에서는 News API, Naver News API 등을 사용
# 예: Naver Search API (클라이언트 ID/시크릿 필요)
return json.dumps([
{"title": f"{query} 관련 뉴스 1", "url": "https://example.com/1"},
{"title": f"{query} 관련 뉴스 2", "url": "https://example.com/2"},
], ensure_ascii=False)
def fetch_article(url: str) -> str:
try:
response = requests.get(url, timeout=10)
soup = BeautifulSoup(response.text, "html.parser")
paragraphs = soup.find_all("p")
return " ".join(p.get_text() for p in paragraphs[:10])
except Exception as e:
return f"기사 가져오기 실패: {e}"
def save_summary(filename: str, content: str) -> str:
with open(filename, "w", encoding="utf-8") as f:
f.write(content)
return f"저장 완료: {filename}"
def execute_tool(name: str, input_data: dict) -> str:
dispatch = {
"search_news": lambda d: search_news(**d),
"fetch_article": lambda d: fetch_article(**d),
"save_summary": lambda d: save_summary(**d),
}
handler = dispatch.get(name)
return handler(input_data) if handler else f"알 수 없는 툴: {name}"
def news_agent(topic: str) -> str:
messages = [{
"role": "user",
"content": f"""'{topic}'에 관한 오늘의 주요 뉴스를 수집하고 한국어로 요약해줘.
1. 관련 뉴스 3개 검색
2. 각 기사 본문 확인
3. 전체 요약을 'news_summary.md' 파일로 저장
4. 핵심 내용 3가지 불릿으로 정리해서 알려줘"""
}]
while True:
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=4096,
tools=tools,
messages=messages
)
if response.stop_reason == "end_turn":
for block in response.content:
if hasattr(block, "text"):
return block.text
if response.stop_reason == "tool_use":
messages.append({"role": "assistant", "content": response.content})
tool_results = []
for block in response.content:
if block.type == "tool_use":
result = execute_tool(block.name, block.input)
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": result
})
messages.append({"role": "user", "content": tool_results})
result = news_agent("인공지능 규제")
print(result)
실전 에이전트 2: 코드 분석 에이전트
프로젝트 파일을 읽고 보안 이슈를 찾는 에이전트:
tools = [
{
"name": "read_file",
"description": "파일 내용을 읽습니다",
"input_schema": {
"type": "object",
"properties": {
"path": {"type": "string"}
},
"required": ["path"]
}
},
{
"name": "list_files",
"description": "디렉토리의 파일 목록을 반환합니다",
"input_schema": {
"type": "object",
"properties": {
"directory": {"type": "string"},
"extension": {"type": "string", "default": ""}
},
"required": ["directory"]
}
},
{
"name": "write_report",
"description": "분석 보고서를 저장합니다",
"input_schema": {
"type": "object",
"properties": {
"content": {"type": "string"},
"filename": {"type": "string", "default": "security_report.md"}
},
"required": ["content"]
}
}
]
def security_audit_agent(project_path: str) -> str:
messages = [{
"role": "user",
"content": f"""'{project_path}' 프로젝트 보안 감사:
1. Python/JS 파일 목록 확인
2. SQL injection, 하드코딩된 시크릿, 위험한 직렬화 패턴 검사
3. 이슈를 Critical/High/Medium/Low로 분류
4. 보고서를 security_report.md로 저장
5. 요약 알려줘"""
}]
# 에이전트 루프 실행 (위와 동일한 패턴)
...
멀티에이전트 패턴
복잡한 작업은 전문화된 서브에이전트로 분업:
def orchestrator_agent(task: str) -> str:
"""오케스트레이터: 작업을 분석하고 서브에이전트에게 위임"""
tools = [
{
"name": "delegate_to_researcher",
"description": "정보 수집이 필요한 작업을 리서치 에이전트에게 위임",
"input_schema": {
"type": "object",
"properties": {
"research_task": {"type": "string"}
},
"required": ["research_task"]
}
},
{
"name": "delegate_to_writer",
"description": "콘텐츠 작성 작업을 라이터 에이전트에게 위임",
"input_schema": {
"type": "object",
"properties": {
"writing_task": {"type": "string"},
"research_context": {"type": "string"}
},
"required": ["writing_task"]
}
}
]
def delegate_to_researcher(research_task: str) -> str:
response = client.messages.create(
model="claude-haiku-4-5", # 리서치엔 Haiku로 비용 절감
max_tokens=2048,
messages=[{"role": "user", "content": f"다음을 조사해줘: {research_task}"}]
)
return response.content[0].text
def delegate_to_writer(writing_task: str, research_context: str) -> str:
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=4096,
messages=[{
"role": "user",
"content": f"참고 자료:\n{research_context}\n\n작성 요청: {writing_task}"
}]
)
return response.content[0].text
dispatch = {
"delegate_to_researcher": lambda d: delegate_to_researcher(**d),
"delegate_to_writer": lambda d: delegate_to_writer(**d),
}
messages = [{"role": "user", "content": task}]
while True:
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=4096,
tools=tools,
messages=messages
)
if response.stop_reason == "end_turn":
return response.content[-1].text
if response.stop_reason == "tool_use":
messages.append({"role": "assistant", "content": response.content})
tool_results = []
for block in response.content:
if block.type == "tool_use":
handler = dispatch.get(block.name)
result = handler(block.input) if handler else f"Unknown: {block.name}"
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": result
})
messages.append({"role": "user", "content": tool_results})
에러 핸들링 및 안정성
재시도 로직
import time
from anthropic import APIStatusError
def robust_agent(task: str, max_retries: int = 3) -> str:
for attempt in range(max_retries):
try:
return run_agent(task)
except APIStatusError as e:
if e.status_code == 429: # 레이트 리밋
wait_time = 2 ** attempt # 지수 백오프: 1s, 2s, 4s
print(f"레이트 리밋. {wait_time}초 후 재시도...")
time.sleep(wait_time)
elif e.status_code == 529: # API 과부하
time.sleep(5)
else:
raise
raise RuntimeError(f"{max_retries}번 재시도 후 실패")
무한 루프 방지
def safe_agent(task: str, max_steps: int = 20) -> str:
messages = [{"role": "user", "content": task}]
step = 0
while step < max_steps:
step += 1
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=4096,
tools=tools,
messages=messages
)
if response.stop_reason == "end_turn":
return response.content[-1].text
# 툴 처리 로직...
return "최대 스텝 수 초과 — 작업 중단"
비용 최적화
서브에이전트 모델 선택
def select_model(task_complexity: str) -> str:
model_map = {
"simple": "claude-haiku-4-5", # 분류, 간단한 추출
"medium": "claude-sonnet-4-5", # 분석, 코드 생성
"complex": "claude-opus-4-7", # 복잡한 추론, 전략적 판단
}
return model_map.get(task_complexity, "claude-sonnet-4-5")
에이전트 비용 예시
| 작업 | 평균 스텝 수 | 비용 (Sonnet) |
|---|---|---|
| 뉴스 3개 요약 | 5-8 스텝 | ~$0.05-0.10 |
| 코드 파일 5개 분석 | 10-15 스텝 | ~$0.10-0.20 |
| 리포트 작성 (10페이지) | 15-25 스텝 | ~$0.20-0.50 |
Vercel Serverless 배포
에이전트를 API 엔드포인트로 배포:
// app/api/agent/route.ts
import Anthropic from "@anthropic-ai/sdk";
import { NextRequest } from "next/server";
export const maxDuration = 300; // 최대 5분 (Vercel Pro 필요)
export async function POST(req: NextRequest) {
const { task } = await req.json();
const client = new Anthropic();
const encoder = new TextEncoder();
const stream = new ReadableStream({
async start(controller) {
const sendUpdate = (message: string) => {
controller.enqueue(
encoder.encode(`data: ${JSON.stringify({ status: message })}\n\n`)
);
};
try {
const result = await runAgent(task, client, sendUpdate);
controller.enqueue(
encoder.encode(`data: ${JSON.stringify({ done: true, result })}\n\n`)
);
} finally {
controller.close();
}
}
});
return new Response(stream, {
headers: {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
}
});
}
자주 묻는 질문
Q: Agent SDK와 일반 API 호출의 비용 차이는? 에이전트는 여러 번 API를 호출하므로 비용이 더 든다. 단순 작업에 에이전트를 쓰면 비용 낭비다. 멀티스텝 자동화가 필요한 경우에만 사용하는 것이 맞다.
Q: 에이전트가 잘못된 툴을 실행하면 어떻게 하나요? 툴 실행 전 사용자 확인을 추가하거나, 위험한 툴(파일 삭제, 외부 API 호출 등)은 샌드박스 환경에서 실행하는 것을 권장한다.
Q: LangChain과 어떻게 다른가요? LangChain은 여러 LLM을 지원하는 추상화 레이어다. Claude Agent SDK는 Claude 특화로 더 단순하고 직접적이다. 프로젝트가 Claude 전용이라면 SDK 직접 사용이 낫다.
Q: 에이전트가 루프에 빠지는 경우는?
max_steps 제한과 명확한 완료 조건 정의로 방지한다. 에이전트 로그를 저장하면 디버깅에 도움이 된다.
관련 가이드
- Claude Agent SDK Quickstart (영어) — 영어 상세 가이드
- 멀티에이전트 시스템 구축 — 오케스트레이션 심화
- 에이전트 비용 관리 — 에이전트 비용 절감
더 깊게 배우기
Claude Agent SDK Cookbook — $49 — 프로덕션에서 검증된 40개 에이전트 패턴. 뉴스 수집, 코드 분석, 고객 지원, 데이터 파이프라인까지. Python + TypeScript 완전한 코드.
30일 환불 보장. 즉시 다운로드.