AWS 기술 블로그

티오더의 Amazon Bedrock을 활용한 MCP 기반 운영 플랫폼 개발기

티오더는 ‘테이블 오더’ 서비스를 시작으로, F&B 시장의 새로운 패러다임을 만들어나가고 있는 기업입니다. 누적 25만 대 이상의 태블릿 설치 대수와 매월 2,500만 명 이상의 사용자를 보유하며 태블릿 메뉴판 시장에서 업계를 선도해 나가고 있습니다.

다양한 사용자의 데이터를 수집 및 가공하여 F&B 시장에 꼭 필요한 정보를 추출하고, 가공한 데이터를 다시 매장의 사장님께 제공함으로써 서로 상생해나가는 선순환 구조를 확립하였습니다. 또한, 단순한 태블릿 메뉴판의 기능을 넘어서 새로운 고객 경험 제공과 광고 매체로써 무궁무진한 활용 능력을 인정받으며 국내를 넘어 해외에서도 만나볼 수 있는 글로벌 기업으로 폭발적인 성장을 이루어 나가고 있습니다.

MCP(Model Context Protocol) 개념 소개

MCP의 정의와 작동 원리

MCP(Model Context Protocol)는 애플리케이션이 LLM(Large Language Model)에 컨텍스트를 제공하는 방법을 표준화하는 개방형 프로토콜입니다. Anthropic사에서 제정한 이 프로토콜은 AI 모델과 외부 도구 간의 상호작용을 체계화하여, 복잡한 AI 애플리케이션에서 컨텍스트를 일관되고 효율적으로 관리할 수 있게 해줍니다.

MCP는 JSON-RPC 2.0을 기반으로 하는 클라이언트-서버 아키텍처를 채택하고 있습니다. 이 구조를 통해 AI 모델은 표준화된 방식으로 외부 도구를 호출하고, 결과를 받아 처리할 수 있습니다. LLM의 성능과 정확성을 높이기 위해서는 적절한 컨텍스트 제공이 필수적이며, MCP는 이러한 컨텍스트 관리를 체계적으로 지원합니다.

LLM과 도구 간 상호작용 메커니즘

MCP는 AI 에이전트가 외부 도구와 데이터 소스에 접근할 수 있는 표준화된 인터페이스를 제공합니다. 이 메커니즘을 통해 LLM은

  1. 사용자 요청을 이해하고 필요한 도구를 식별합니다.
  2. 표준화된 형식으로 도구 호출 요청을 생성합니다.
  3. 호스트 애플리케이션은 이 요청을 해석하여 실제 도구를 실행합니다.
  4. 도구 실행 결과는 다시 LLM에게 전달되어 최종 응답 생성에 활용됩니다.

이러한 상호작용 구조는 LLM이 자율적으로 다양한 도구와 데이터 소스를 활용하며 복잡한 작업을 수행할 수 있게 합니다. 호스트 애플리케이션은 MCP를 통해 LLM과 도구 사이의 중개자 역할을 수행하며, 이 과정에서 도구의 실행 결과를 적절히 포맷팅하여 LLM에게 제공합니다.

기존 AI 통합 방식과의 차이점

MCP 도입 이전에는 각 호스트 종류마다 해당 인터페이스에 맞춘 개별적인 구현이 필요했습니다. 예를 들어, Claude Desktop이나 Amazon Q Developer CLI와 같은 각각의 클라이언트를 위해 별도의 코드를 작성해야 했으며, 이는 코드 중복과 관리 복잡성을 초래했습니다. MCP의 가장 큰 차별점은 다음과 같습니다.

  1. 표준화된 인터페이스: 하나의 MCP 서버를 다양한 호스트/클라이언트에서 공통으로 이용할 수 있습니다. Claude Desktop, Amazon Q CLI 등 여러 클라이언트가 동일한 MCP 인터페이스를 통해 연결됩니다.
  2. 코드 재사용성 향상: 자체 개발 부담이 크게 줄고, 한 번 개발한 도구를 여러 AI 애플리케이션에서 재사용할 수 있습니다.
  3. 확장성: 새로운 도구나 데이터 소스를 추가할 때, 기존 인프라를 크게 변경하지 않고도 MCP 프로토콜을 통해 쉽게 통합할 수 있습니다.
  4. 일관된 컨텍스트 관리: 다양한 소스에서 수집된 정보를 일관된 방식으로 LLM에 제공함으로써, 모델의 응답 품질과 정확성을 향상시킵니다.

MCP는 AI 애플리케이션 개발의 복잡성을 줄이고, 다양한 도구와 데이터 소스를 효율적으로 통합할 수 있는 프레임워크를 제공함으로써, 보다 강력하고 유연한 AI 시스템 구축을 가능하게 합니다.

솔루션 개요

티오더는 운영 효율성과 시스템 가시성을 극대화하기 위해 Amazon Bedrock, Amazon MemoryDB, LangChain, 그리고 자체 구축한 MCP 기반 플랫폼을 도입하였습니다. 본 플랫폼은 자연어 인터페이스와 자동화된 이벤트 분석 기능을 통해 운영팀의 업무를 지능화하며, 빠른 장애 대응과 인사이트 확보를 가능하게 합니다. 아래는 MCP 기반 플랫폼을 도입했을 때 기대하는 점과 목표입니다.

  • 자연어 기반 도구 호출로 운영자의 접근성 향상
  • 실시간 이벤트 자동 요약 및 분석
  • 대화 맥락 및 검색 데이터의 효율적 유지와 처리
  • 시스템 장애에 대한 자동 감지 및 요약 피드백
  • 내부 도구와 운영 포털의 통합을 통한 일원화된 인터페이스 제공

솔루션 소개

아키텍처 다이어그램

티오더는 전사 시스템의 옵저빌리티를 향상시키기 위해 Amazon Bedrock과 MCP를 적극 도입하여, 다양한 도구와 유연하게 통합 가능한 AI 기반 플랫폼을 구축하였습니다. 이 플랫폼은 사용자 요청에 맞춰 정보를 직관적으로 제공하거나, 시스템 이벤트를 실시간 분석해 장애 상황을 자동으로 요약함으로써 운영 효율성을 높이는 데 기여하고 있습니다.

플랫폼의 모든 구성 요소는 Amazon EKS 기반으로 구축되어 있으며, 확장성과 안정성을 동시에 확보하고 있습니다. 백엔드 벡터 데이터베이스로는 Amazon MemoryDB를 채택하여, LLM 기반의 빠르고 정확한 문맥 검색 및 유사도 기반 질의 응답이 가능하도록 구성하였습니다.

Amazon Bedrock을 통한 AI 서비스 운영 측면에서는 기본 생성 모델로 Anthropic Claude Sonnet 3.7을 활용하고 있으며, 시스템 요약 및 장애 인사이트 제공과 같은 목적에는 Amazon Titan Text 및 Amazon Nova Micro 모델을 병행하여 사용하고 있습니다. 이를 통해 티오더는 모델별 역할을 명확히 구분하여 효율적인 리소스 사용과 정밀한 AI 응답 품질을 달성하고 있습니다.

시스템 프롬프트

### 🚫 절대 규칙
- **절대 허구의 정보를 만들어내지 마세요.**
- 컨텍스트 또는 도구 결과로 정확한 응답이 불가능하면, **정확히 찾을 수 없거나 실패했음을 명시**하세요. 추측 금지.
- **도구 입력 시 파라미터 값은 반드시 최종 계산된 값을 사용하세요.** 예를 들어, 시간 계산이 필요하면 `"1745110238 - 3600"`과 같은 문자열 수식이 아니라, 실제 계산된 숫자 값(예: `1745106638`)을 전달해야 합니다. 특히 `from`, `to`, `limit`, `pageSize` 등의 숫자 타입 파라미터에 유의하세요.
 
---
 
당신은 Bedrock MCP API 백엔드에서 실행되는 AI 어시스턴트입니다. 사용자의 요청을 처리하기 위해 제공된 컨텍스트와 여러 백엔드 도구를 활용합니다.
 
### [사용 가능 도구 목록]
{tool_names}
 
### [제공된 컨텍스트]
{retrieved_documents}
 
---
 
### 🛠 도구 사용 및 응답 지침
 
1.  **컨텍스트 우선:** 사용자의 질문에 컨텍스트(`retrieved_documents`)만으로 충분히 답변할 수 있다면, 컨텍스트 정보만을 사용하여 직접 답변하세요.
2.  **도구 사용 시점:** 컨텍스트가 부족하거나, 사용자가 명시적으로 '검색', '생성', '전송' 등의 **활동을 요청**할 경우, 가장 적합한 도구를 사용하세요.
3.  **정확한 입력:** 도구 입력 파라미터는 사용자 질문과 컨텍스트에서 정확히 추출하세요. 스키마에 정의된 파라미터 이름과 일치해야 합니다. **숫자 파라미터는 반드시 계산된 숫자 값으로 전달하세요.** (위의 절대 규칙 참조)
4.  **결과 평가:** 도구 실행 결과(`Observation`)를 받은 후, 컨텍스트와 결과를 종합하여 사용자 질문에 완전히 답할 수 있는지 평가하세요.
5.  **충분하면 즉시 응답:** 정보가 충분하면, **즉시** 검증된 사실만을 바탕으로 최종 한국어 답변(`Final Answer`)을 제공하세요. 더 이상 생각하거나 도구를 호출하지 마세요.
6.  **실패 처리:** 도구 실패, 오류, 결과 없음 등이 발생하면, **반드시** 최종 답변에 그 사실을 명확히 포함하세요 (예: "get_user_info 도구 실행 중 오류가 발생했습니다.", "요청하신 ID 123의 문서를 찾을 수 없습니다."). 재시도는 신중하게 (최대 1회).
7.  **제한:** 최대 9단계(Thought/Action), 도구 호출 최대 8회.
8.  **지시한 채널이외에 메시지 발송 절대 금지**
 
---
 
**실행 형식:**
Thought: [판단 및 계획]
Action: (도구 사용 시)
```json
{{
  "action": "tool_name",
  "action_input": {{ "param": "value" }} /* 숫자 파라미터는 계산된 값 사용 */
}}
```
Observation: [도구 결과 또는 N/A]
... (반복)
Final Answer: [최종 한국어 답변 또는 실패 명시]
 
---
 
이전 대화 내용:
{chat_history}
 
{agent_scratchpad}

티오더의 옵저빌리티 플랫폼은 두 가지 주요 아키텍처 흐름으로 구성되어 있습니다.

첫 번째는 일반 사용자의 자연어 입력을 기반으로 MCP 도구를 호출하는 방식입니다. 사용자는 복잡한 시스템 명령어를 몰라도, 자연어로 질문하거나 요청하는 것만으로 다양한 내부 도구와 연동할 수 있습니다. 이를 통해 운영팀은 직관적인 인터페이스로 빠르게 분석과 조치를 수행할 수 있습니다.

두 번째는 Amazon SNS-SQS-Subscribe 구조를 활용한 실시간 알람 분석입니다. 시스템 전반에서 발생하는 이벤트와 경고는 Amazon SNS를 통해 전송되고, Amazon SQS를 통해 안정적으로 큐잉된 후 MCP로 전달됩니다. 전달된 메시지는 요약 모델을 통해 자동 분석되어, 장애의 원인과 핵심 정보를 요약한 형태로 운영팀에 제공됩니다.

플랫폼의 중심에는 확장 가능한 MCP 서버가 존재하며, 다양한 툴과 시스템을 손쉽게 통합할 수 있도록 설계되어 있습니다. 실제로 티오더는 기존에 사용하던 내부 백오피스 시스템들까지도 MCP를 통해 통합하여, 단일 인터페이스에서 모든 운영 작업이 가능하도록 구성하였습니다.

사용 패턴 예시 1: Slack → ChatUI 기반의 흐름

위 그림의 보이는 Slack 메시지 확인 요청은 이후 다단계 자동화 프로세스의 트리거로 활용됩니다. 플랫폼에서는 이 알림을 기반으로 다음과 같은 순차 작업이 실행됩니다:

  • Slack 메시지 감지
  • Datadog 모니터링 데이터 분석 (최근 로그 / 트레이스 조회)
  • 요약 결과 영향도 자동 생성
  • Confluence 페이지 자동 발행 (장애 리포트 초안)
  • Jira 티켓 자동 생성 (긴급 장애 대응 태스크)
  • Slack 재알림 (요약 + 티켓 링크 포함)

이러한 흐름은 단일 Slack 알림을 운영 지식 기반 자동화 프로세스의 시작점으로 변환시키며, 인적 개입 없이도 분석 및 기록, 대응까지 이어지는 전사적 대응 체계를 가능하게 합니다.

사용 패턴 예시 2: 프롬프트 기반 알림 자동화 흐름

두 번째 패턴 예시는 Slack 메시지는 단순 경고에 그치지 않고, 이후 다단계 자동화 프로세스의 트리거로 활용됩니다. 플랫폼에서는 이 알림을 기반으로 다음과 같은 순차 작업이 실행됩니다:

  • Slack 메시지 감지
  • Datadog 모니터링 데이터 분석 (최근 로그 / 트레이스 조회)
  • 요약 결과 영향도 자동 생성
  • Confluence 페이지 자동 발행 (장애 리포트 초안)
  • Jira 티켓 자동 생성 (긴급 장애 대응 태스크)
  • Slack 재알림 (요약 + 티켓 링크 포함)

이러한 흐름은 단일 Slack 알림을 운영 지식 기반 자동화 프로세스의 시작점으로 변환시키며, 인적 개입 없이도 분석 및 기록, 대응까지 이어지는 전사적 대응 체계를 가능하게 합니다.

sqs message 
---
🔍 [시스템 작업 지시]
다음 메시지를 분석하여 **Datadog + Slack 기반 요약 응답**을 생성하세요.
 
요청 작업:
1. 위 Slack 메시지는 SQS를 통해 전달받은 Datadog/CloudWatch Alert 알림입니다. 관련 내용을 요약하세요.
2. Alert가 발생한 **타임스탬프 기준 전후 10분**의 로그를 Datadog에서 수집하고 분석하세요.
   - 📘 로그: `Error` 레벨만 조회
   - 📈 트레이스: `Error` 상태만 조회
3. 로그와 트레이스 데이터를 바탕으로 **장애 원인** 및 **핵심 증상**을 요약하세요.
4. Slack의 포맷에 맞춰 최대한 **간단하고 읽기 쉬운 형태**로 요약하세요.
   - 마크다운 형식 사용 (예: `•`, `🔧`, `✅`, `❌`)
5. 요약 메시지는 **슬랙 C123456789 채널의 해당 쓰레드에 리플**로 등록합니다.
6. 이슈가 해결된 상태라면 ✅ 체크 이모지를, 아직 해결되지 않았다면 ❌ X 이모지를 자동 추가합니다.

구성요소

UI requirements.txt

python-dotenv>=1.0.0
tiktoken>=0.7.0 # Keep for potential token counting features
nest_asyncio # Keep for potential async usage in Streamlit
requests # Needed to call the API backend
langchain-core # Added - Needed for message types (HumanMessage, AIMessage, etc.)
langchain
streamlit>=1.31.0
aiohttp>=3.8.5
API requirements.txt
# Common Dependencies
boto3>=1.28.0
botocore>=1.31.0
python-dotenv>=1.0.0
langchain
langchain-mcp-adapters
langchain-community
langchain-aws 
langchain-redis
redis
transformers
tiktoken>=0.7.0 
nest_asyncio
requests
fastapi
uvicorn[standard]

핵심코드

1. 요약특화 LLM을 통한 대화 맥락 유지

긴 대화 세션에서도 정확한 문맥을 유지하기 위해 요약 전용 LLM(summarizer_llm)을 활용한 구조를 도입하였습니다. 이 구조는 LangChain의 ConversationSummaryBufferMemory를 기반으로 설계되었으며, 세션별로 대화 이력을 효율적으로 관리할 수 있도록 구성되어 있습니다.

대화가 지속되며 설정된 토큰 수(MEMORY_MAX_TOKENS)를 초과하면, 해당 세션의 메모리는 자동으로 summarizer_llm을 호출하여 기존 내용을 요약하고 저장합니다. 이 과정을 통해 메모리 사용을 최적화하는 동시에, 에이전트는 이전 대화 흐름을 유지한 채 응답을 생성할 수 있습니다.

서버 구동 시에는 FastAPI의 lifespan 함수 내에서 summarizer_llm이 초기화됩니다. 구성 파일(bedrock_config)에 명시된 big_model_id가 존재할 경우, 해당 모델을 Amazon Bedrock을 통해 초기화하며, 설정되지 않았거나 초기화에 실패할 경우에는 기본 LLM 인스턴스를 fallback으로 사용합니다.

app.state.summarizer_llm = ChatBedrockConverse(model=big_model_id) # 명시적 모델 사용

이렇게 초기화된 요약 LLM은 이후 /chat 또는 /chat/stream API 요청 처리 시 각 세션의 메모리 객체에 전달되며, 다음과 같은 방식으로 적용됩니다.

session_memories[session_id] = ConversationSummaryBufferMemory(
    llm=summarizer_llm,
    ...
)

요약 모델의 도입은 단순한 대화 기록 유지에 그치지 않고, 시스템 전반의 응답 품질과 일관성을 향상시키는 중요한 구성 요소로 작용하고 있습니다. 이를 통해 티오더는 사용자와 시스템 간의 상호작용을 더욱 자연스럽고 맥락 있는 경험으로 확장해 나가고 있습니다.

2. 서버 시작 시 요약모델 초기화

lifespan 함수 내에서 big_model_id가 설정되어 있으면 summarizer_llm을 별도로 초기화합니다.

# src/server/main.py
@asynccontextmanager
async def lifespan(app: FastAPI):
    ...
    llm = ChatBedrockConverse(...)  # 기본 모델
    app.state.llm = llm
 
    # 요약 전용 모델 초기화
    big_model_id = bedrock_config.get("big_model_id")
    if big_model_id:
        summarizer_llm = ChatBedrockConverse(model=big_model_id, ...)
        app.state.summarizer_llm = summarizer_llm
    else:
        app.state.summarizer_llm = llm
    ...

2. 대화 기록 요약 (ConversationSummaryBufferMemory 활용)

긴 세션의 대화를 유지하기 위해 ConversationSummaryBufferMemory를 사용하고, 이 때 summarizer_llm을 전달합니다.

# src/server/main.py
session_memories[session_id] = ConversationSummaryBufferMemory(
    llm=summarizer_llm,
    max_token_limit=MEMORY_MAX_TOKENS,
    ...

플랫폼 진화 과정과 그 속의 도전 과제들

티오더의 AI 기반 운영 플랫폼은 수많은 시행착오를 거치며 현재의 구조로 정제되었습니다. 초기에는 단순히 Amazon Bedrock의 Converse API를 사용하여 MCP 도구를 호출하는 형태로 출발하였습니다. 이때의 프론트엔드는 React 기반으로 구성되었으나, 모델 전환, 파라미터 수정, 툴 상태 확인 등 고급 기능이 미비한 제한적인 구조였습니다. 이를 개선하기 위해 숙련된 Frontend 개발자가 아니더라도 쉽게 기능 개발이 가능한 Streamlit 기반 인터페이스를 도입하여, 사용자는 손쉽게 모델을 전환하고, 툴 로드 여부를 확인하거나, 캐시를 삭제하는 등의 기능을 개발할 수 있게 되었습니다.

하지만 시스템이 복잡해지고 대화 맥락이나 조직 정보를 장기적으로 유지하려는 필요성이 대두되면서, 구조화된 정보 저장소의 필요성이 명확해졌고, 결국 벡터 DB를 도입하게 되었습니다. 초기에는 Redis 파드를직접 구성하여 임시 벡터 DB로 활용하였으나, Pod 재시작 시 데이터 유실 문제가 반복적으로 발생하였고, 이를 해결하기 위해 Amazon MemoryDB로 전환하였습니다. 이 과정에서 langchain-aws 라이브러리를 활용하여 Bedrock 및 벡터 DB와의 통합을 구현했습니다.

그러나 새로운 문제는 예상치 못한 형태로 등장했습니다. 모델이 툴을 호출할 때, 정의된 도구 스키마를 무시하고 잘못된 파라미터를 전달하는 문제가 반복되었고, 이는 종종 ValidationError로 이어졌습니다. 이 문제를 해결하기 위해 langchain-mcp-adapters를 도입하였으나, Streamlit의 동기적 실행 구조와 MCP의 비동기 이벤트 흐름 간 충돌이 발생하면서 제대로 동작하지 않았습니다.

결국 프론트엔드와 백엔드를 완전 분리한 구조로 전환하였고, 이 구조는 도구 호출 시 스키마 불일치 문제를 완전히 해소했습니다. 이와 함께 Amazon SQS 기반 Subscriber 구성을 통해, 특정 이벤트가 발생할 경우 자동으로 MCP 서버로 요청을 전송하여 도구를 호출하는 이벤트 기반 자동화까지 완성할 수 있었습니다. 이 일련의 여정은 단순한 인터페이스 개선을 넘어, 안정성, 확장성, 자동화 가능성을 모두 확보한 플랫폼으로의 도약이었습니다.

정태환

정태환

티오더 R&D 그룹의 DevOps 엔지니어이자 팀장으로서 티오더 R&D그룹 소속되어 티오더 플랫폼의 안정적인 서비스를 제공하기위해 아키텍팅의 전반을 담당하고 있습니다.

남태형

남태형

티오더 R&D 그룹의 DBRE로 데이터 모델 설계, DB 플랫폼 자동화 개발, 티오더 데이터베이스의 서비스 안정성과 신뢰성 향상을 위해 운영 및 개선 업무를 수행하고 있습니다. 최근에는 GenAI를 활용해 자연어를 통한 SQL 플랜 분석 및 성능 개선 인사이트 제공을 위한 도구를 개발하고 있습니다.

김선경

김선경

티오더 R&D 그룹의 DevOps 엔지니어로서 인프라 설계부터 운영까지 전담하며 서비스 안정성과 개발팀 생산성을 극대화하고 있습니다. 최근에는 GenAI를 도입해 자연어 기반 시스템 모니터링 도구를 개발하며 차세대 DevOps 환경을 구축하고 있습니다.

최아름

최아름

티오더 R&D 그룹의 DevOps 엔지니어로서, 티오더 플랫폼의 서비스 안정성과 신뢰성 향상을 위해 운영 및 개선 업무를 수행하고 있습니다. 최근에는 GenAI를 활용해 서비스 모니터링 및 인사이트 제공을 위한 도구를 개발하였습니다.

박중균

박중균

티오더 R&D 그룹의 DevOps 엔지니어로서 티오더 플랫폼의 서비스에 대한 배포 파이프라인 제공과 개발자의 생산성 향상을 위한 노력하고 있습니다.

Jungseob Shin

Jungseob Shin

신정섭 Solutions Architect는 다양한 분야의 Backend 서버 개발 경험을 바탕으로 Startup 고객이 비즈니스 목표를 달성하도록 AWS 서비스의 효율적인 사용을 위한 아키텍처 설계 가이드와 기술을 지원하는 역할을 수행하고 있습니다. 컨테이너와 서버리스 기술에 관심이 많습니다.

이준우

이준우

이준우 어카운트 매니저는 스타트업 고객들이 직면하는 문제를 함께 고민하고 가장 효율적으로 해결할 수 있도록, 적합한 AWS 서비스 및 적용을 도와주는 다양한 프로그램 활용을 통해 기술 및 비즈니스 모두 지원드리고 있습니다.