본문 바로가기
최신 AI

MCP, LangGraph 및 FastAPI로 스마트 웹 AI 에이전트 구축하기

by 구라100단 2026. 1. 23.

인공지능(AI)은 단일 프롬프트에 응답하는 거대 모델에서, 사용자 목표를 해결하기 위해 추론하고 행동하며 협력하는 자율 구성 요소(에이전트)가 있는 에이전트 중심 시스템으로 빠르게 이동하고 있다. 이 데모 프로젝트에서는 Model Context Protocol(MCP), FastAPI 및 기타 최신 Python 도구를 사용하여 이러한 차세대 프런티어를 탐구한다.

이 글에서는 Agents MCP 데모 프로젝트의 이유(Why), 대상(What), 방법(How)을 설명하고, 자신만의 에이전트 기반 애플리케이션을 구축할 수 있는 접근 가능한 경로를 제시한다. 이 프로젝트는 단순한 코드가 아니라 실제 에이전트 애플리케이션을 구축할 수 있는 교육용 발판이다.

왜 에이전트 기반 AI가 중요한가?

전통적인 LLM(대규모 언어 모델) 사용은 종종 단발성 상호작용(질문하고 답변받기)을 중심으로 이루어진다. 하지만 실제 자동화에는 그 이상의 것이 필요하다.

  • 상태 유지 세션(Stateful sessions): 단계별로 컨텍스트가 유지됨
  • 모듈식 로직(Modular logic): 시스템의 다른 부분이 특정 작업에 전문화됨
  • 상호운용성(Interoperability): 외부 도구(API, 워크플로우, 데이터베이스)와 연동
  • 재사용성(Reusability): 향후 요청을 위한 워크플로우 재사용

에이전트 아키텍처는 다음과 같은 기능을 수행할 수 있는 자율 구성 요소를 연결하여 이러한 요구를 충족하려고 노력한다.

  • 사용자 의도 추론
  • 도구 호출
  • 다단계 작업 조율
  • 메모리 또는 상태 지속

이 데모 프로젝트는 FastAPI, LangGraph, Model Context Protocol(MCP)과 같은 핵심 구성 요소를 결합하여 확장 가능한 프로덕션 수준의 AI 에이전트 플랫폼을 보여준다.

Agents MCP 데모 프로젝트란 무엇인가?

핵심적으로 이 저장소는 다음과 같은 기능을 수행하는 웹 액세스 가능 에이전트 애플리케이션을 구축하는 방법을 보여준다.

✔ API를 통해 사용자 쿼리 수신 ✔ 에이전트 오케스트레이션 계층으로 라우팅 ✔ MCP를 사용하여 외부 도구 및 모델 제공자 활용 ✔ 로컬 실행 또는 컨테이너화 가능

주요 기능:

  • FastAPI: 고성능 비동기 웹 서비스 제공
  • LangGraph: 에이전트 오케스트레이션 및 상태 유지 대화 관리
  • Model Context Protocol(MCP): 도구 및 모델 통합
  • 멀티 LLM 지원: OpenAI, Anthropic/Claude
  • Docker & Compose: 쉬운 배포 지원
  • Python 3.12+: 구조화된 로깅 및 강력한 타입 안전성

이 스택은 개발자에게 일회성 Q&A 봇이 아닌 실제 로봇 팀원처럼 느껴지는 AI 에이전트를 구축할 수 있는 유연한 기반을 제공한다.

빠른 설정 (로컬 & Docker)

프로젝트 시작은 간단하다.

1. 전제 조건

  • Python 3.12 이상
  • OpenAI 또는 Anthropic API 키
  • Docker & Docker Compose (선택 사항이지만 권장됨)

2. 설치 및 구성

# 가상 환경 생성
python -m venv .venv
source .venv/bin/activate

# 의존성 설치
pip install -e ".[dev]"

# 환경 변수 복사
cp .env.example .env

# .env 파일에 API 키 업데이트

로컬에서 애플리케이션 실행:

make dev
# 또는
uvicorn app.main:app --reload

실행 후 다음 주소에서 API 문서/Swagger를 확인할 수 있다:
http://localhost:8000/docs

 

여기서 docs/swagger 또는 CURL을 통해 요청을 테스트할 수 있다. 예:

curl -X POST http://localhost:8000/api/v1/agent/invoke \
  -H "Content-Type: application/json" \
  -d '{"query": "What is 25 * 4?", "session_id": "test"}'

이 간단한 API 호출은 서버가 자연어를 받아들이고 에이전트가 추론할 수 있는 세션으로 라우팅하는 방법을 보여준다.

아키텍처 개요

높은 수준에서 Agents MCP 데모는 API 관심사, 에이전트 오케스트레이션, 도구 실행을 분리하는 깔끔한 계층형 아키텍처를 따른다.

클라이언트 → FastAPI → LangGraph 에이전트 → 도구(MCP 준비됨) → LLM 제공자

이 구조는 시스템을 모듈화하고 테스트하기 쉽게 유지하며 새로운 도구 나 모델로 쉽게 확장할 수 있게 한다. 코드베이스의 구체적인 예제와 함께 각 계층을 살펴보자.

 

1. FastAPI - 에이전트 진입점

FastAPI는 에이전트의 공개 진입점 역할을 하며 다음을 담당한다.

  • HTTP 엔드포인트 노출
  • 요청/응답 직렬화 처리
  • 헬스 체크 및 API 문서 제공

app/main.py에서:

app = FastAPI(
    title="AI Agent API",
    version="0.1.0",
)

@app.get("/health")
async def health_check():
    return {
        "status": "healthy",
        "environment": settings.ENVIRONMENT,
    }

에이전트는 단일 호출 엔드포인트를 통해 노출된다.

# POST /api/v1/agent/invoke (사용법은 README 참조)

이 계층은 의도적으로 얇게 유지되며 추론 로직이나 도구 실행을 포함하지 않는다. 대신 요청을 에이전트 오케스트레이션 계층으로 전달한다.

2. 에이전트 서비스 계층 - API와 오케스트레이션의 연결

FastAPI와 LangGraph 사이의 서비스 경계는 이 데모에서 의도적으로 최소화되었다. FastAPI는 에이전트 오케스트레이션 함수를 직접 호출하여 데모를 쉽게 따라갈 수 있게 하면서도 깔끔한 분리를 유지한다.

app/agents/graph.py에서:

async def invoke_agent(query: str, session_id: str | None = None):
    logger.info("invoking_agent", query=query)
    agent = get_agent()
    initial_state = {
        "messages": [HumanMessage(content=query)]
    }
    result = await agent.ainvoke(initial_state)

이 함수는 서비스 계층 역할을 하며 다음을 조정한다.

  • 세션 초기화
  • 에이전트 실행
  • 최종 응답 포맷팅

3. LangGraph - 에이전트 오케스트레이션 및 상태

에이전트 아키텍처의 핵심은 create_agent_graph() 함수로, 에이전트가 어떻게 추론하고 언제 도구를 호출하며 단계 간에 상태가 어떻게 흐르는지 정의한다. 블랙박스 에이전트 추상화를 사용하는 대신, LangGraph의 StateGraph를 사용하여 에이전트를 명시적으로 구축한다.

app/agents/graph.py에서:

def create_agent_graph():
    llm = get_llm()
    tools = get_tools()
    llm_with_tools = llm.bind_tools(tools)
    
    workflow = StateGraph(AgentState)

    async def call_model(state: AgentState) -> dict:
        logger.info("calling_model")
        response = await llm_with_tools.ainvoke(state["messages"])
        return {"messages": [response]}

    workflow.add_node("agent", call_model)
    workflow.add_node("tools", ToolNode(tools))

    workflow.add_edge(START, "agent")

    def should_continue(state: AgentState) -> str:
        last_message = state["messages"][-1]
        if hasattr(last_message, "tool_calls") and last_message.tool_calls:
            return "tools"
        return END

    workflow.add_conditional_edges("agent", should_continue, ["tools", END])
    workflow.add_edge("tools", "agent")

    return workflow.compile()

그래프는 app/agents/state.py에 정의된 타입화된 상태 객체 위에서 작동한다.

class AgentState(TypedDict):
    messages: Annotated[list[BaseMessage], add_messages]

이 상태는 노드 간에 전달되며 에이전트가 추론하고 도구와 상호 작용함에 따라 메시지를 자동으로 누적한다.

create_agent_graph() 내에서 두 개의 핵심 노드가 등록된다.

  • LLM 추론 노드
  • 도구 실행 노드

LangGraph의 조건부 엣지(edge)는 에이전트 루프를 제어하며, 명시적인 추론 → 행동 → 관찰 → 추론 주기를 생성한다. 여기서 에이전트는 도구를 호출할지 아니면 최종 답변으로 종료할지 결정한다. 마지막으로 그래프는 실행 가능한 에이전트로 컴파일된다.

이 접근 방식은 에이전트의 동작을 투명하고 디버깅 가능하며 확장하기 쉽게 만든다. 이는 나중 계층에서 MCP 기반 도구를 도입할 때 특히 중요해진다.

4. 에이전트 노드 - 추론 + 도구 사용

에이전트는 고전적인 ReAct 스타일 루프를 따른다.

  1. LLM이 현재 메시지에 대해 추론한다.
  2. 도구가 필요한 경우 LangGraph는 실행을 도구 노드로 라우팅한다.
  3. 도구 결과가 상태에 다시 추가된다.
  4. 에이전트는 완료될 때까지 계속한다.

도구 실행은 LangGraph의 ToolNode를 통해 처리된다.

from langgraph.prebuilt import ToolNode
from app.agents.tools import get_tools

tools = get_tools()
tool_node = ToolNode(tools)

최종 응답은 마지막 AI 메시지에서 추출된다.

final_message = result["messages"][-1]
response = {
    "response": final_message.content,
    "message_count": len(result["messages"]),
    "session_id": session_id,
}

이러한 깔끔한 분리는 추론, 상태, 실행을 명확하게 정의된 상태로 유지한다.

5. MCP - Model Context Protocol 통합

이 데모는 로컬 도구와 함께 제공되지만 MCP를 지원하도록 설계되었다. 도구는 LangChain의 @tool 데코레이터를 사용하여 선언적으로 정의되며, 이는 MCP의 스키마 우선 접근 방식을 반영한다.

app/agents/tools.py에서:

@tool
def calculator(expression: str) -> str:
    """수식 평가"""
    return str(eval(expression))

@tool
def get_current_time() -> str:
    """ISO 형식으로 현재 시간 가져오기"""
    return datetime.now().isoformat()

모든 도구는 중앙에서 등록된다.

def get_tools() -> List:
    return [calculator, get_current_time]

이 레지스트리 패턴을 사용하면 다음 작업이 매우 쉬워진다.

  • 로컬 도구를 MCP 도구 서버로 교체
  • 런타임에 동적으로 도구 로드
  • 에이전트 로직 변경 없이 새로운 기능 노출

6. LLM 제공자 추상화

LLM 선택은 전용 서비스를 통해 처리되므로 에이전트는 제공자에 구애받지 않는다.

app/services/llm.py에서:

def get_llm():
    if settings.LLM_PROVIDER == "openai":
        return ChatOpenAI(
            model=settings.DEFAULT_LLM_MODEL,
            temperature=settings.DEFAULT_TEMPERATURE,
        )
    elif settings.LLM_PROVIDER == "anthropic":
        return ChatAnthropic(
            model=settings.DEFAULT_LLM_MODEL,
            temperature=settings.DEFAULT_TEMPERATURE,
        )

이 추상화 덕분에 제공자를 전환하거나 추가 모델 지원을 쉽게 확장할 수 있다.

요청 수명 주기: API 호출에서 에이전트 응답까지

요청이 들어오면 실제로 어떤 일이 발생하는가?

  1. API가 사용자 쿼리를 수신한다 (예: "회의 일정 잡고 메모 준비해줘").
  2. FastAPI가 이를 세션으로 라우팅한다.
  3. LangGraph가 에이전트 로직을 조율하며, 잠재적으로 작업을 하위 작업으로 나눈다.
  4. 에이전트가 하나 이상의 외부 도구 또는 MCP 서버를 호출한다.
  5. 응답과 작업이 집계된다.
  6. 에이전트가 최종 구조나 답변으로 응답한다.

이는 실제 자율 AI 시스템이 복잡한 요청을 처리하는 방식(계획, 행동, 관찰, 반응)을 반영한다.

MCP가 데모를 향상시키는 방법

Model Context Protocol은 모델과 도구 간의 상호 작용을 표준화하기 때문에 특히 강력하다.

일반적인 LLM 설정에서는 다음과 같이 직접 호출할 수 있다.

openai.ChatCompletion.create(...)

하지만 MCP를 사용하면 에이전트는 다음을 사용하여 여러 도구 제공자에게 위임할 수 있다.

  • 구조화된 도구 호출
  • 텍스트가 아닌 데이터로 반환되는 관찰
  • 추론에 연결된 외부 함수 실행

이로 인해 에이전트는 더욱 신뢰할 수 있고 조합 가능해진다.

테스트 및 개발

프로젝트에는 다음을 확인하기 위한 기본 테스트 모음이 tests/ 아래에 포함되어 있다.

  • API 라우트가 예상대로 응답하는지
  • 에이전트 세션이 올바르게 동작하는지
  • 엣지 케이스 입력이 처리되는지

다음 명령어로 실행할 수 있다.

make test
# 또는
pytest

좋은 테스트 커버리지는 기능을 확장할 때 에이전트 로직을 자신 있게 발전시키는 데 도움이 된다.

배포 고려 사항

이 프로젝트는 기본적으로 컨테이너화를 지원한다. 이는 FastAPI 서비스, 구성된 모의 의존성, MCP를 통해 연결된 선택적 도구를 구동한다.

YAML
# docker-compose.yml
services:
  api:
    build: .
    ports:
      - "8000:8000"
    env_file:
      - .env

이는 다음을 보장한다.

  • 일관된 런타임 동작
  • 쉬운 클라우드 배포
  • 인프라와 로직 간의 깔끔한 분리

다음으로 실행한다. docker-compose up --build

그런 다음 Cloud Run, ECS, Kubernetes 등 모든 컨테이너 환경에 배포할 수 있다.

마무리

Agents MCP 데모 프로젝트는 최신 AI 에이전트의 세계로 도약하기 위한 귀중한 발판이다. 견고한 API, 지능형 오케스트레이션, 상호 운용 가능한 프로토콜을 결합하여 단일 질문 응답을 넘어서는 시스템을 구축하는 방법을 보여준다.

이 프로젝트는 지능적으로 생각하고 행동하며 협업하는 애플리케이션을 구축하는 데 있어 실습 기반을 제공한다.

더 깊이 들어가기 위한 몇 가지 미래 아이디어:

  • 사용자 정의 도구를 구축하고 MCP를 통해 노출하기
  • 멀티 홉(multi-hop) 추론을 위해 여러 에이전트 연결하기
  • 세션에 인간 피드백 통합하기
  • 에이전트 워크플로우에 관찰 가능성(observability) 및 원격 측정 추가하기

이러한 모든 업그레이드는 데모에서 프로덕션 등급의 AI 에이전트 시스템으로 나아가는 데 도움이 된다.