
AI 에이전트를 구축하는 것은 복잡하게 들릴 수 있습니다. 처음부터 모든 것을 직접 만들려고 하면 실제로 복잡할 수 있습니다. 하지만 핵심 패턴은 간단합니다. 언어 모델에 도구 접근 권한을 부여하고, 어떤 도구를 언제 사용할지 스스로 결정하게 한 다음, 목표에 도달할 때까지 반복하는 것입니다.
이 가이드는 AI 에이전트를 아키텍처부터 작동하는 코드까지 단계별로 구축하는 방법을 설명합니다. 이 가이드를 마치면 웹 검색, 이미지 생성, 결과 전달까지 모두 하나의 CLI로 수행하는 기능적인 에이전트를 갖추게 됩니다.
AI 에이전트란 무엇인가?
코드를 작성하기 전에 우리가 무엇을 구축하고 있는지 정의해 봅시다.
AI 에이전트는 목표를 받아들이고, 일련의 행동을 계획하며, 도구를 사용해 그 행동을 실행하고, 결과를 관찰한 후 적응하는 시스템입니다. 단일 프롬프트에 응답하는 챗봇과 달리, 에이전트는 수십 번의 도구 호출을 거치면서 목표를 향해 자율적으로 작업합니다.
챗봇: "이 기사를 요약해 줘." → 요약 반환. AI 에이전트: "이 주제를 조사하고, 최고의 출처를 찾고, 보고서를 작성한 후 게시해 줘." → 계획 수립, 검색, 읽기, 작성, 게시.
에이전트의 힘은 도구에서 비롯됩니다. 도구가 없으면 에이전트는 긴 프롬프트를 가진 언어 모델에 불과합니다. 도구가 있으면 세상과 상호작용할 수 있습니다.
AI 에이전트의 아키텍처
모든 에이전트는 동일한 기본 루프를 따릅니다:
┌─────────────────────────────────────────┐
│ 에이전트 루프 │
│ │
│ 1. 목표 수신 │
│ 2. 생각: 다음에 무엇을 해야 할까? │
│ 3. 행동: 도구를 선택하고 호출 │
│ 4. 관찰: 결과는 무엇이었나? │
│ 5. 판단: 목표에 도달했는가? │
│ → 아니오? 2단계로 돌아간다. │
│ → 예? 결과를 반환한다. │
└─────────────────────────────────────────┘
이를 ReAct 패턴(추론 + 행동)이라고 합니다. LangChain, CrewAI, AutoGen, OpenAI Agents SDK 등 모든 에이전트 프레임워크는 이 루프의 어떤 버전을 구현합니다.
필요한 세 가지 구성 요소:
- 언어 모델 — 추론 엔진 (Claude, GPT-4o, Gemini)
- 도구 세트 — 에이전트가 할 수 있는 일 (검색, 크롤링, 생성, 저장, 게시)
- 오케스트레이터 — 다음에 어떤 도구를 호출할지 결정하는 루프
1단계: 도구 선택하기
도구는 에이전트가 달성할 수 있는 것을 정의합니다. "내 에이전트가 실제로 무엇을 해야 하는가?"라는 질문으로 시작하세요.
일반적인 에이전트 도구:
| 기능 | 중요한 이유 |
|---|---|
| 웹 검색 | 리서치, 사실 확인, 경쟁 분석 |
| 웹 크롤링 | 특정 페이지의 심층 읽기, 데이터 추출 |
| 이미지 생성 | 비주얼, 다이어그램, 에셋 생성 |
| 파일 저장 | 영구 출력, 공유, 에셋 관리 |
| 웹 게시 | 완성된 작업을 라이브 페이지로 게시 |
| 코드 실행 | 스크립트 실행, 데이터 처리, 자동화 |
대부분의 초보자가 저지르는 실수: 에이전트에 너무 적은 도구만 제공한 다음, 왜 아무것도 달성하지 못하는지 의아해합니다. 검색 전용 에이전트는 링크만 반환할 수 있습니다. 검색 + 크롤링 + 저장 + 게시 에이전트는 완성된 결과물을 만들어냅니다.
도구를 프로비저닝하는 가장 간단한 방법: 검색, 크롤링, 이미지 생성, 저장, 게시를 하나의 인터페이스로 통합한 능력 레이어를 사용하는 것입니다. 다섯 개의 별도 API를 설정하고 다섯 개의 자격 증명을 관리하는 대신, 하나의 인증 흐름으로 하나의 CLI를 호출합니다. 이렇게 하면 에이전트 루프가 단순하게 유지되고 토큰 오버헤드가 낮아집니다.
2단계: 에이전트의 시스템 프롬프트 정의하기
시스템 프롬프트는 에이전트의 "작동 매뉴얼"입니다. 모델에게 자신이 무엇이고, 어떤 도구를 가지고 있으며, 어떻게 사용해야 하는지 알려줍니다.
좋은 시스템 프롬프트는 네 가지 부분으로 구성됩니다:
- 정체성: 에이전트가 무엇인지
- 목표: 무엇을 달성해야 하는지
- 도구: 무엇을 사용할 수 있고 언제 사용해야 하는지
- 제약 사항: 하지 말아야 할 것
예시:
당신은 리서치 에이전트입니다. 주어진 주제를 철저히 조사하고
포괄적인 보고서를 작성하는 것이 목표입니다.
다음 도구에 접근할 수 있습니다:
- search: 웹에서 정보를 찾습니다. 광범위한 리서치에 사용하세요.
- crawl: 특정 웹 페이지를 전체 읽기 합니다. 유망한 출처를
찾은 후에 사용하세요.
- drive upload: 보고서와 에셋을 영구 저장합니다.
- page deploy: 최종 보고서를 웹 페이지로 게시합니다.
워크플로우:
1. 환경을 이해하기 위해 광범위한 검색 쿼리로 시작하세요.
2. 가장 권위 있는 출처를 식별하고 크롤링하세요.
3. 조사 결과를 구조화된 보고서로 종합하세요.
4. 안전한 보관을 위해 보고서를 Drive에 업로드하세요.
5. 보고서를 게시된 페이지로 배포하세요.
제약 사항:
- 항상 출처를 인용하세요.
- 한 출처가 다른 출처와 모순되면 추가 조사하세요.
- 절대 정보를 날조하지 마세요.
3단계: 에이전트 루프 구현하기
다음은 Python으로 작성된 최소한의 에이전트 루프입니다. 이 패턴은 프로덕션에 바로 사용할 수 있습니다 — 생각, 행동, 관찰, 반복:
import subprocess
import json
def call_tool(tool_name, **params):
"""도구를 실행하고 결과를 반환합니다."""
if tool_name == "search":
result = subprocess.run(
["anycap", "search", "--prompt", params["query"]],
capture_output=True, text=True
)
return json.loads(result.stdout)
elif tool_name == "crawl":
result = subprocess.run(
["anycap", "crawl", params["url"]],
capture_output=True, text=True
)
return result.stdout
elif tool_name == "drive_upload":
subprocess.run(
["anycap", "drive", "upload", params["file"]],
capture_output=True
)
return {"status": "uploaded", "file": params["file"]}
elif tool_name == "page_deploy":
result = subprocess.run(
["anycap", "page", "deploy", params["file"]],
capture_output=True, text=True
)
return json.loads(result.stdout)
# 에이전트 루프
def agent_loop(goal, tools, max_steps=20):
memory = [{"role": "system", "content": SYSTEM_PROMPT}]
memory.append({"role": "user", "content": goal})
for step in range(max_steps):
response = llm_call(memory, tools)
if response.get("done"):
return response["result"]
tool_name = response["tool"]
tool_params = response["params"]
result = call_tool(tool_name, **tool_params)
memory.append({"role": "assistant", "content": str(response)})
memory.append({"role": "tool", "content": str(result)})
return "에이전트가 목표를 완료하지 않고 최대 단계에 도달했습니다."
4단계: 실패 처리하기
에이전트는 실패합니다. 중요한 것은 어떻게 처리하느냐입니다. 처음부터 다음과 같은 안전 장치를 구축하세요:
타임아웃 보호
에이전트가 무한정 반복하지 않도록 하세요. 최대 단계 수와 시간 제한을 설정하세요. 에이전트가 둘 중 하나를 초과하면, 조용히 충돌하는 대신 지금까지 얻은 결과를 반환해야 합니다.
도구 실패 복구
도구 호출이 실패했을 때 — URL에 접근할 수 없거나, API가 오류를 반환할 때 — 에이전트는 오류 메시지를 받고 다음에 무엇을 할지 결정해야 합니다. 에이전트에게 오류를 숨기지 마세요. 무언가 작동하지 않았을 때 알아야 합니다.
try:
result = call_tool(tool_name, **tool_params)
except Exception as e:
result = {"error": str(e), "suggestion": "대체 접근 방식을 시도하세요"}
비용 인식
모든 검색, 모든 크롤링, 모든 이미지 생성에는 크레딧이 소모됩니다. 에이전트에 예산을 부여하고 비용을 인식하게 하세요. 간단한 질문에 답하기 위해 100번의 검색을 소모하는 에이전트는 잘못 설계된 것입니다.
5단계: 데모와 프로덕션의 차이
데모 에이전트와 유용한 에이전트의 차이는 실제 도구 접근에 있습니다. 데모 에이전트는 텍스트를 반환합니다. 유용한 에이전트는 게시된 보고서, 생성된 이미지, 배포된 웹 페이지를 반환합니다.
프로덕션 에이전트에는 다섯 가지 능력이 필요합니다: 웹 검색, 특정 페이지 읽기, 비주얼 생성, 출력 영구 저장, 완성된 작업 게시. 에이전트의 코드는 단순하게 유지됩니다 — 필요한 도구를 호출하기만 하면 됩니다. API 통합, 인증, 오류 처리의 복잡성은 런타임에 존재하며, 에이전트 루프에는 없습니다.
에이전트 구축 시 흔한 실수
실수 1: 종료 조건 없음
명확한 "완료" 신호가 없는 에이전트는 영원히 반복합니다. 성공을 명시적으로 정의하세요: 특정 출력(보고서, 배포된 페이지)을 생성했거나 목표에 도달할 수 없음을 확인했을 때 에이전트는 완료됩니다.
실수 2: 너무 적은 도구
"검색 전용" 에이전트는 과장된 검색 엔진에 불과합니다. 에이전트에 전체 파이프라인을 제공하세요: 찾기 → 읽기 → 생성 → 저장 → 전달.
실수 3: 도구 결과 무시하기
에이전트가 때때로 도구를 호출하고 결과를 무시한 채, 결과가 어떨 것이라고 가정한 내용을 바탕으로 진행합니다. 모든 도구 결과를 다음 결정에 반드시 통합하도록 강제하세요.
실수 4: 루프의 과도한 엔지니어링
대부분의 사용 사례에서 맞춤형 오케스트레이션 프레임워크는 필요하지 않습니다. 좋은 시스템 프롬프트와 유능한 도구를 갖춘 단순한 ReAct 루프가 80%의 작업에서 복잡한 멀티 에이전트 설정보다 뛰어납니다.
튜토리얼에서 프로덕션으로
여기서 구축한 에이전트는 시작점입니다. 프로덕션 준비를 위해:
- 로깅 추가: 디버깅을 위해 모든 도구 호출, 결과, 에이전트의 추론을 기록하세요.
- 휴먼 인 더 루프 추가: 게시, 이메일 전송과 같은 중요한 작업에는 사람의 승인이 필요하게 하세요.
- 모니터링 추가: 성공률, 작업당 평균 단계 수, 도구 호출 분포를 추적하여 병목 현상을 파악하세요.
- 시스템 프롬프트 반복 개선: 프롬프트는 에이전트의 두뇌입니다. 실제 사용 패턴을 기반으로 조정하세요.
AI 에이전트를 구축하는 것은 복잡한 아키텍처에 관한 것이 아닙니다. 추론 엔진에 적절한 도구와 명확한 목표를 제공하는 것입니다. 단순하게 시작하세요: 하나의 모델, 3-5개의 도구, 기본 루프. 단순한 버전이 한계에 도달할 때만 복잡성을 추가하세요.