시리즈: AI 에이전트 직접 만들어보기 | 3편 / 5편
안녕하세요! 드디어 실습 편이에요! 🎉
오늘은 에이전트를 3개 직접 만들어볼 거예요.
| 에이전트 | 난이도 | 결과물 | |
|---|---|---|---|
| 1번 | 계산기 에이전트 | ⭐ 쉬움 | 수식 계산 결과 출력 |
| 2번 | 리서치 에이전트 | ⭐⭐ 보통 | 조사 결과 파일 저장 |
| 3번 | 번역 에이전트 | ⭐⭐ 보통 | 번역 결과 파일 저장 |
같은 구조를 세 번 반복하면서 패턴을 익히는 방식이에요. 한 줄 한 줄 따라오시면 반드시 동작해요! 💪
시작 전 딱 2가지만 준비해요
① Google Colab 열기
- colab.research.google.com 접속
- Google 계정으로 로그인
- “새 노트북” 클릭 → 빈 노트북이 열려요
② API 키 저장
Claude를 쓰려면 API 키가 필요해요.
API 키 발급:
- console.anthropic.com 접속 → 회원가입
- 왼쪽 메뉴 “API Keys” → “Create Key” 클릭
- 생성된 키 복사 (딱 한 번만 보여줘요!)
Colab에 안전하게 저장:
- Colab 왼쪽 사이드바 🔑 자물쇠 아이콘 클릭
- “새 보안 비밀 추가” → 이름:
ANTHROPIC_API_KEY, 값: 복사한 키 - “노트북 액세스” 토글 켜기 ✅
이걸로 준비 완료예요! 이제 셀을 하나씩 실행해볼게요.
💡 셀 실행 방법: 셀 왼쪽 ▶ 버튼 클릭 또는
Shift + Enter

공통 준비 셀 (세 에이전트 모두 사용해요)
셀 1 — 패키지 설치
새 노트북을 열면 빈 셀이 하나 있어요. 아래를 입력하고 실행하세요.
!pip install anthropic -q
print("✅ 설치 완료!")
✅ 설치 완료! 가 뜨면 성공이에요.
셀 2 — API 키 연결
import anthropic
import json
from google.colab import userdata
# Colab Secrets에서 API 키 불러오기
client = anthropic.Anthropic(api_key=userdata.get('ANTHROPIC_API_KEY'))
print("✅ Claude 연결 완료!")
오류 없이 ✅ Claude 연결 완료! 가 뜨면 준비됐어요.
에이전트 1번: 계산기 에이전트 ⭐
수식을 주면 계산해서 알려주는 에이전트예요. 도구가 하나뿐이라 구조를 이해하기 가장 쉬워요!
나 : "지구 둘레는 약 40,075km야. 시속 900km 비행기로
지구를 한 바퀴 돌면 몇 시간 걸려?"
에이전트 : ① calculate 도구 사용 → 40075 ÷ 900 계산
② 결과 확인 → 약 44.5시간
③ 답변: "약 44시간 33분 걸려요!"
셀 3 — 계산 도구 만들기
# ① 도구 함수 — 실제로 계산하는 코드예요
def calculate(expression: str) -> str:
"""수식을 계산합니다."""
try:
result = eval(expression)
return f"{expression} = {result}"
except Exception as e:
return f"계산 오류: {e}"
# ② Claude에게 도구 목록 알려주기
TOOLS_CALC = [
{
"name": "calculate",
"description": "수학 계산을 합니다. 숫자 계산이 필요할 때 사용하세요.",
"input_schema": {
"type": "object",
"properties": {
"expression": {
"type": "string",
"description": "계산할 수식. 예: '40075 / 900'"
}
},
"required": ["expression"]
}
}
]
print("✅ 계산기 도구 준비 완료!")
셀 4 — 계산기 에이전트 함수
def run_calculator_agent(question: str):
"""계산기 에이전트를 실행해요."""
print(f"\n{'='*45}")
print(f"❓ 질문: {question}")
print(f"{'='*45}\n")
messages = [{"role": "user", "content": question}]
step = 1
while True:
print(f"🤔 [Step {step}] 생각 중...")
response = client.messages.create(
model="claude-opus-4-6",
max_tokens=1024,
tools=TOOLS_CALC,
messages=messages
)
# 도구를 쓰고 싶다고 한 경우
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":
print(f"🔢 계산 실행: {block.input['expression']}")
result = calculate(block.input["expression"])
print(f" 결과: {result}\n")
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": result
})
messages.append({"role": "user", "content": tool_results})
# 완료한 경우
elif response.stop_reason == "end_turn":
print(f"{'='*45}")
print("✅ 완료!")
print(f"{'='*45}\n")
for block in response.content:
if hasattr(block, "text"):
print(f"💬 답변: {block.text}")
break
step += 1
print("✅ 계산기 에이전트 준비 완료!")
셀 5 — 계산기 에이전트 실행!
run_calculator_agent(
"지구 둘레는 약 40,075km야. "
"시속 900km 비행기로 지구를 한 바퀴 돌면 몇 시간 걸려?"
)
이런 출력이 나오면 성공이에요! 🎉
=============================================
❓ 질문: 지구 둘레는 약 40,075km야. 시속 900km 비행기로...
=============================================
🤔 [Step 1] 생각 중...
🔢 계산 실행: 40075 / 900
결과: 40075 / 900 = 44.527...
🤔 [Step 2] 생각 중...
=============================================
✅ 완료!
=============================================
💬 답변: 시속 900km 비행기로 지구를 한 바퀴 돌면
약 44시간 32분이 걸려요!
다른 질문으로 바꿔보세요!
# 이것도 실행해보세요 😊
run_calculator_agent("1억 원을 연 이자율 3.5%로 10년 예금하면 얼마가 될까?")

에이전트 2번: 리서치 에이전트 ⭐⭐
주제를 주면 조사해서 파일로 저장해주는 에이전트예요. 도구가 2개로 늘어나지만, 구조는 1번과 완전히 똑같아요!
나 : "파이썬 asyncio에 대해 조사해서 파일로 저장해줘"
에이전트 : ① search_web 도구 사용 → "파이썬 asyncio" 검색
② 검색 결과 분석
③ save_to_file 도구 사용 → asyncio_report.txt 저장
④ 답변: "저장 완료했어요!"
셀 6 — 리서치 도구 2개 만들기
# ① 웹 검색 도구
def search_web(query: str) -> str:
"""웹에서 정보를 검색합니다."""
print(f" 🔍 검색 중: '{query}'")
# 학습용 예시 데이터예요 (실제 서비스에선 검색 API를 연동해요)
mock_data = {
"asyncio": """
- asyncio: 파이썬 3.4+ 내장 비동기 라이브러리
- async/await 키워드로 비동기 코드 작성
- 코루틴(coroutine)으로 동시 처리 가능
- I/O 작업(네트워크, 파일)에서 성능 향상 효과적
- FastAPI, aiohttp 등 유명 라이브러리가 asyncio 기반
""",
"AI 에이전트": """
- LLM 기반의 자율 실행 시스템
- ReAct 패턴: 생각 → 행동 → 관찰 반복
- Claude, GPT, Gemini 등 다양한 LLM 활용 가능
- 실무 도입 사례: 고객 서비스, 코드 리뷰, 데이터 분석
""",
"파이썬": """
- 1991년 귀도 반 로섬이 만든 프로그래밍 언어
- 간결한 문법, 방대한 라이브러리 생태계
- AI/ML, 웹 개발, 데이터 분석에 널리 사용
- 초보자 입문 언어로 전 세계적으로 인기
"""
}
for key, value in mock_data.items():
if key in query:
return value.strip()
return f"'{query}' 검색 완료. 관련 정보를 찾았어요."
# ② 파일 저장 도구
def save_to_file(filename: str, content: str) -> str:
"""내용을 파일로 저장합니다."""
print(f" 💾 저장 중: '{filename}'")
filepath = f"/content/{filename}"
with open(filepath, "w", encoding="utf-8") as f:
f.write(content)
return f"✅ '/content/{filename}' 저장 완료!"
# ③ Claude에게 도구 2개 알려주기
TOOLS_RESEARCH = [
{
"name": "search_web",
"description": "웹에서 정보를 검색합니다. 특정 주제를 조사할 때 사용하세요.",
"input_schema": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "검색할 키워드"}
},
"required": ["query"]
}
},
{
"name": "save_to_file",
"description": "내용을 파일로 저장합니다. 결과물을 파일로 남길 때 사용하세요.",
"input_schema": {
"type": "object",
"properties": {
"filename": {"type": "string", "description": "파일 이름 (예: report.txt)"},
"content": {"type": "string", "description": "저장할 내용"}
},
"required": ["filename", "content"]
}
}
]
def execute_research_tool(name: str, inputs: dict) -> str:
"""도구 이름에 맞는 함수를 실행해요."""
if name == "search_web":
return search_web(inputs["query"])
elif name == "save_to_file":
return save_to_file(inputs["filename"], inputs["content"])
return f"알 수 없는 도구: {name}"
print("✅ 리서치 도구 2개 준비 완료!")
셀 7 — 리서치 에이전트 함수
1번 계산기 에이전트와 구조가 완전히 똑같아요! 달라진 건 도구 목록(TOOLS_RESEARCH)과 도구 실행 함수(execute_research_tool)뿐이에요.
def run_research_agent(task: str, max_steps: int = 10):
"""리서치 에이전트를 실행해요."""
print(f"\n{'='*45}")
print(f"📋 작업: {task}")
print(f"{'='*45}\n")
messages = [{"role": "user", "content": task}]
step = 1
while step <= max_steps: # 무한 루프 방지!
print(f"🤔 [Step {step}] 생각 중...")
response = client.messages.create(
model="claude-opus-4-6",
max_tokens=2048,
system="search_web를 한 번만 사용해서 정보를 수집하고, 바로 save_to_file로 저장하세요.",
tools=TOOLS_RESEARCH, # ← 여기만 달라요!
messages=messages
)
# 도구를 쓰고 싶다고 한 경우
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":
print(f"🛠️ 도구 사용: {block.name}")
result = execute_research_tool(block.name, block.input)
print(f" → {result[:60]}{'...' if len(result) > 60 else ''}\n")
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": result
})
messages.append({"role": "user", "content": tool_results})
# 완료한 경우
elif response.stop_reason == "end_turn":
print(f"{'='*45}")
print("✅ 완료!")
print(f"{'='*45}\n")
for block in response.content:
if hasattr(block, "text"):
print(f"💬 결과: {block.text}")
break
step += 1
else:
print(f"⚠️ 최대 스텝({max_steps})에 도달해서 종료했어요.")
print("✅ 리서치 에이전트 준비 완료!")
셀 8 — 리서치 에이전트 실행!
run_research_agent(
"파이썬 asyncio에 대해 조사하고, "
"핵심 내용을 정리해서 'asyncio_report.txt' 파일로 저장해줘."
)
이런 출력이 나오면 성공이에요! 🎉
=============================================
📋 작업: 파이썬 asyncio에 대해 조사하고...
=============================================
🤔 [Step 1] 생각 중...
🛠️ 도구 사용: search_web
🔍 검색 중: 'asyncio'
→ - asyncio: 파이썬 3.4+ 내장 비동기 라이브러리...
🤔 [Step 2] 생각 중...
🛠️ 도구 사용: save_to_file
💾 저장 중: 'asyncio_report.txt'
→ ✅ '/content/asyncio_report.txt' 저장 완료!
🤔 [Step 3] 생각 중...
=============================================
✅ 완료!
=============================================
💬 결과: asyncio에 대한 조사를 완료했어요!
핵심 내용을 정리해서 'asyncio_report.txt'에 저장했습니다.

Colab 왼쪽 📁 폴더 아이콘 → /content/asyncio_report.txt 파일이 생겼어요! 📄

다른 주제로 바꿔보세요!
run_research_agent("AI 에이전트 트렌드를 조사해서 'ai_agent.txt'로 저장해줘.")

에이전트 3번: 번역 에이전트 ⭐⭐
영어 문장을 주면 한국어로 번역하고 파일로 저장해주는 에이전트예요. 포인트는 2번 에이전트에서 만든 save_to_file 도구를 그대로 재사용한다는 거예요!
나 : "아래 영어 문장을 한국어로 번역해서 파일로 저장해줘.
'Artificial intelligence is transforming the way we work.'"
에이전트 : ① translate 도구 사용 → 한국어로 번역
② save_to_file 도구 사용 → translation.txt 저장
③ 답변: "번역 완료, 저장했어요!"
셀 9 — 번역 도구 만들기 + 기존 도구 재사용
# ① 새 도구: 번역 함수
def translate(text: str, target_language: str) -> str:
"""텍스트를 지정한 언어로 번역합니다."""
print(f" 🌐 번역 중 → {target_language}")
# 학습용 예시 데이터예요
# 실제 서비스에선 DeepL API, Google Translate API 등을 연동해요
mock_translations = {
"Artificial intelligence is transforming the way we work.":
"인공지능은 우리가 일하는 방식을 변화시키고 있습니다.",
"The future belongs to those who learn more skills and combine them in creative ways.":
"미래는 더 많은 기술을 배우고 창의적인 방식으로 결합하는 사람들의 것입니다.",
"Small steps every day lead to big results over time.":
"매일 작은 발걸음이 시간이 지나면 큰 결과로 이어집니다.",
}
if text in mock_translations:
result = mock_translations[text]
else:
result = f"[{target_language} 번역] {text}"
return f"원문: {text}\n번역: {result}"
# ② Claude에게 도구 2개 알려주기
# translate (새 도구) + save_to_file (2번 에이전트에서 재사용!)
TOOLS_TRANSLATE = [
{
"name": "translate",
"description": "텍스트를 지정한 언어로 번역합니다.",
"input_schema": {
"type": "object",
"properties": {
"text": {
"type": "string",
"description": "번역할 원문 텍스트"
},
"target_language": {
"type": "string",
"description": "번역 목표 언어 (예: '한국어', '영어', '일본어')"
}
},
"required": ["text", "target_language"]
}
},
{
"name": "save_to_file",
"description": "내용을 파일로 저장합니다. 결과물을 파일로 남길 때 사용하세요.",
"input_schema": {
"type": "object",
"properties": {
"filename": {"type": "string", "description": "파일 이름"},
"content": {"type": "string", "description": "저장할 내용"}
},
"required": ["filename", "content"]
}
}
]
def execute_translate_tool(name: str, inputs: dict) -> str:
"""도구 이름에 맞는 함수를 실행해요."""
if name == "translate":
return translate(inputs["text"], inputs["target_language"])
elif name == "save_to_file":
return save_to_file(inputs["filename"], inputs["content"]) # 기존 함수 재사용!
return f"알 수 없는 도구: {name}"
print("✅ 번역 도구 준비 완료! (save_to_file은 2번에서 재사용)")
셀 10 — 번역 에이전트 함수
1, 2번과 구조가 또 똑같아요! 이제 패턴이 보이시죠? 😊
def run_translate_agent(task: str, max_steps: int = 10):
"""번역 에이전트를 실행해요."""
print(f"\n{'='*45}")
print(f"🌐 번역 작업: {task[:50]}...")
print(f"{'='*45}\n")
messages = [{"role": "user", "content": task}]
step = 1
while step <= max_steps: # 무한 루프 방지!
print(f"🤔 [Step {step}] 생각 중...")
response = client.messages.create(
model="claude-opus-4-6",
max_tokens=2048,
tools=TOOLS_TRANSLATE, # ← 여기만 달라요!
messages=messages
)
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":
print(f"🛠️ 도구 사용: {block.name}")
result = execute_translate_tool(block.name, block.input)
print(f" → {result[:60]}{'...' if len(result) > 60 else ''}\n")
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": result
})
messages.append({"role": "user", "content": tool_results})
elif response.stop_reason == "end_turn":
print(f"{'='*45}")
print("✅ 완료!")
print(f"{'='*45}\n")
for block in response.content:
if hasattr(block, "text"):
print(f"💬 결과: {block.text}")
break
step += 1
else:
print(f"⚠️ 최대 스텝({max_steps})에 도달해서 종료했어요.")
print("✅ 번역 에이전트 준비 완료!")
셀 11 — 번역 에이전트 실행!
run_translate_agent(
"아래 영어 문장을 한국어로 번역하고, "
"'translation.txt' 파일로 저장해줘.\n\n"
"Artificial intelligence is transforming the way we work."
)
이런 출력이 나오면 성공이에요! 🎉
=============================================
🌐 번역 작업: 아래 영어 문장을 한국어로 번역하고...
=============================================
🤔 [Step 1] 생각 중...
🛠️ 도구 사용: translate
🌐 번역 중 → 한국어
→ 원문: Artificial intelligence is...
🤔 [Step 2] 생각 중...
🛠️ 도구 사용: save_to_file
💾 저장 중: 'translation.txt'
→ ✅ '/content/translation.txt' 저장 완료!
🤔 [Step 3] 생각 중...
=============================================
✅ 완료!
=============================================
💬 결과: 번역을 완료했어요!
결과를 'translation.txt'에 저장했습니다.
다른 문장으로 바꿔보세요!
run_translate_agent(
"'Small steps every day lead to big results over time.' 을 "
"한국어로 번역해서 'quote_kr.txt'로 저장해줘."
)

세 에이전트를 비교해봐요
이제 세 에이전트를 만들어봤어요. 구조를 나란히 놓고 보면:
에이전트 1 에이전트 2 에이전트 3
──────────── ──────────────── ────────────────────
셀 3: 도구 정의 셀 6: 도구 정의 셀 9: 도구 정의
calculate search_web translate
save_to_file save_to_file ← 재사용!
셀 4: 함수 정의 셀 7: 함수 정의 셀 10: 함수 정의
셀 5: 실행! 셀 8: 실행! 셀 11: 실행!
완전히 같은 패턴이에요! 🎯
세 가지 핵심을 이해하셨으면 돼요:
- 도구(함수)를 만든다 → 에이전트가 쓸 손발
- 도구 목록을 Claude에게 알려준다 →
TOOLS리스트 - while 루프로 완료될 때까지 반복한다 → 에이전트의 심장
이 패턴만 알면 어떤 에이전트든 만들 수 있어요. 이메일 작성 에이전트, 일정 관리 에이전트, 코드 리뷰 에이전트… 모두 이 패턴 그대로예요!
핵심 포인트 4가지
① while 루프가 에이전트의 심장이에요
while True:
response = client.messages.create(...)
if response.stop_reason == "tool_use": # 도구 써야겠다 → 실행 후 계속
...
elif response.stop_reason == "end_turn": # 다 됐다 → 종료!
break
이 루프가 없으면 에이전트가 아니라 그냥 챗봇이에요.
② 도구 설명(description)을 잘 써야 해요
# 나쁜 예 ❌ — Claude가 언제 써야 할지 모름
"description": "계산 도구"
# 좋은 예 ✅ — Claude가 정확히 알 수 있음
"description": "수학 계산을 합니다. 숫자 계산이 필요할 때 사용하세요."
Claude는 description을 읽고 도구를 선택해요.
③ 무한 루프를 막으려면 max_steps를 쓰세요
while True는 에이전트가 end_turn을 반환해야만 종료돼요. 그런데 도구 결과가 기대와 다르면 AI가 계속 재시도하다 멈추지 않을 수 있어요.
# ❌ 위험 — 조건에 따라 영원히 돌 수 있어요
while True:
...
# ✅ 안전 — 최대 10번만 실행하고 멈춰요
while step <= max_steps:
...
else:
print(f"⚠️ 최대 스텝({max_steps})에 도달해서 종료했어요.")
system 프롬프트로 “한 번만 검색해”라고 지시해도, 예상치 못한 상황에서 Claude가 루프를 길게 가져갈 수 있어요. max_steps는 그런 경우를 막는 코드 레벨 안전망이에요. 둘은 역할이 달라서 함께 쓰는 게 좋아요.
실제 에이전트를 만들 때도 반드시 넣어두세요.
④ API 키는 Colab Secrets로만!
# ❌ 절대 이렇게 하지 마세요
client = anthropic.Anthropic(api_key="sk-ant-실제키...")
# ✅ 항상 이렇게 하세요
client = anthropic.Anthropic(api_key=userdata.get('ANTHROPIC_API_KEY'))
다른 AI 모델로도 만들 수 있어요!
지금까지 Claude로 만들었는데, OpenAI / Gemini도 구조는 같아요.
| 항목 | Claude (Anthropic) | ChatGPT (OpenAI) | Gemini (Google) |
|---|---|---|---|
| 패키지 설치 | !pip install anthropic | !pip install openai | !pip install google-generativeai |
| Colab Secret | ANTHROPIC_API_KEY | OPENAI_API_KEY | GEMINI_API_KEY |
| 모델 이름 | claude-opus-4-6 | gpt-4o | gemini-1.5-pro |
| 도구 종료 감지 | stop_reason == "tool_use" | msg.tool_calls | function_call.name |
OpenAI 버전으로 바꾸면:
# 셀 1: 패키지만 바꾸면 돼요
!pip install openai -q
# 셀 2: 클라이언트만 바꾸면 돼요
from openai import OpenAI
client = OpenAI(api_key=userdata.get('OPENAI_API_KEY'))
# 셀 4/7: 에이전트 루프 부분만 OpenAI 방식으로 변경
def run_agent_openai(question: str):
messages = [{"role": "user", "content": question}]
while True:
response = client.chat.completions.create(
model="gpt-4o",
tools=TOOLS_CALC, # 도구 정의는 그대로 재사용!
messages=messages
)
msg = response.choices[0].message
if msg.tool_calls: # ← 여기만 다름
messages.append(msg)
for tc in msg.tool_calls:
result = calculate(json.loads(tc.function.arguments)["expression"])
messages.append({"role": "tool", "tool_call_id": tc.id, "content": result})
else:
print(msg.content)
break
💡 구조(while 루프)는 Claude와 완전히 동일해요.
하나를 이해하면 다른 AI도 금방 적용할 수 있어요! 😊
정리해볼까요?
오늘 만든 세 에이전트의 공통 흐름:
요청 입력
↓
AI가 생각 → "어떤 도구를 써야 하지?"
↓
도구 실행 → 결과를 AI에게 전달
↓
AI가 다시 생각 → "더 할 일이 있나?"
↓
완료 → 최종 답변!
이 구조(ReAct 패턴)를 세 번 반복하면서 느끼셨나요? 도구만 바꾸면 어떤 에이전트든 만들 수 있어요. 🚀
다음 편 예고
에이전트 3개를 만들어봤는데, 복잡한 작업은 에이전트 하나로는 여전히 한계가 있어요.
다음 편에서는 여러 에이전트가 팀처럼 협력하는 멀티 에이전트 구조를 알아볼 거예요!
관리자 에이전트가 일을 나눠서 전문 에이전트들에게 맡기는 방식이에요. 오늘 배운 구조가 그대로 응용되니까 어렵지 않을 거예요! 🤩
| 편 | 제목 | 상태 |
|---|---|---|
| 1편 | AI 에이전트란 무엇인가요? | ✅ 완료 |
| 2편 | MCP란 무엇인가요? 도구를 에이전트에 연결하는 방법 | ✅ 완료 |
| 3편 | 나만의 에이전트 첫 번째 만들기 (Colab 실습) | ✅ 현재 글 |
| 4편 | 멀티 에이전트 설계 패턴 | 👉 다음 편 |
| 5편 | 실무에 AI 에이전트 도입하기 | 예정 |