Ruby 및 Rails로 AI 에이전트 구축하기: 아무도 알려주지 않는 것들

Building an AI Agent with Ruby and Rails from Scratch — What No One Tells You | by Dieter S. | Code and Coffee | Aug, 2025 | Medium

작성자
jeff
발행일
2025년 08월 08일

핵심 요약

  • 1 AI 에이전트 구축은 툴 호출, 상태 관리, 엄격한 컨텍스트 제어가 필요한 복잡한 과정이며, 단순한 코드 리팩토링보다 훨씬 어렵습니다.
  • 2 MCP(Model Context Protocol) 서버는 툴과 리소스를 노출하는 핵심 인프라 역할을 하며, RAG(검색 증강 생성)는 임베딩, 검색, 청킹 등을 포함하는 별도의 데이터 처리 영역입니다.
  • 3 LLM 선택 시 툴 호출을 지원하는 모델을 사용하고, 컨텍스트 창 제한을 엄격히 준수하며, Ruby SDK의 잠재적 문제점을 인지하고 철저히 로깅 및 디버깅해야 합니다.

도입

본 문서는 Ruby on Rails를 활용하여 AI 에이전트를 구축하는 과정에서 직면할 수 있는 예상치 못한 난관과 실질적인 해결 방안을 제시합니다. 많은 개발자가 AI 워크플로우를 에이전트로 확장하는 것을 쉽게 생각하지만, 실제로는 툴 호출, 상태 관리, 컨텍스트 제어 등 복합적인 요소들이 요구됩니다. 이 글은 AI 에이전트 개발의 복잡성을 이해하고, 효과적인 개발 전략을 수립하는 데 필요한 핵심적인 통찰을 제공합니다.

AI 에이전트 구축은 단순한 워크플로우 자동화를 넘어섭니다. 주요 고려사항은 다음과 같습니다.

1. MCP(Model Context Protocol) 서버 활용

  • 역할: MCP 서버는 JSON-RPC를 기반으로 툴(함수)과 리소스(정적 데이터)를 LLM에 노출하는 역할을 합니다. 이는 curl 명령어로 쉽게 테스트할 수 있으며, LM Studio와 같은 로컬 LLM 환경과 연동성이 뛰어납니다.

  • 툴 vs. 리소스: 툴은 AI가 수행할 수 있는 ‘액션’을 의미하며, 리소스는 AI가 작업할 ‘정적 객체’를 의미합니다.

2. RAG(Retrieval-Augmented Generation)의 이해

  • 독립적인 영역: RAG는 MCP와는 별개로, 임베딩, 검색, 청킹 과정을 통해 LLM에 관련 정보를 제공하는 기술입니다. MCP는 리소스를 노출할 수 있지만, RAG 기능을 기본적으로 제공하지 않습니다.

  • 구성 요소: 임베딩(텍스트를 벡터로 변환), 검색(유사 벡터 탐색), 청킹(텍스트를 컨텍스트 창에 맞게 분할)이 핵심이며, Pinecone, Weaviate, pgvector 등 벡터 데이터베이스가 활용됩니다.

3. 컨텍스트 창(Context Window) 관리의 중요성

  • LLM의 한계: LLM은 제한된 컨텍스트 창을 가지므로, 대용량 데이터를 직접 입력하는 것은 불가능합니다. 예를 들어, PDF 파일을 base64 문자열로 전달하면 토큰 한도를 빠르게 초과합니다.

  • 데이터 전처리: LLM이 이해할 수 있도록 PDF에서 HTML이나 텍스트를 추출하고, 필요한 부분만 선별하여 제공하는 전략이 필수적입니다.

4. 올바른 LLM 선택

  • 툴 호출 지원: 모든 LLM이 툴 호출(Tool Calling) 기능을 지원하는 것은 아닙니다. 에이전트가 툴을 사용하려면 반드시 툴 호출을 지원하는 모델을 선택해야 합니다.

5. Ruby SDK 사용 시 유의사항

  • 오류 처리: json_rpc_handler 내부에서 발생하는 예외는 추적하기 어려우므로, 적극적인 로깅과 명시적인 예외 처리가 필요합니다.

  • server_context: 툴의 call 메서드에 자동으로 전달되는 해시로, user_id나 컨트롤러 객체와 같은 정보를 전달하는 데 유용합니다.

  • outputSchema: Ruby SDK에서 아직 구현되지 않아, 툴의 descriptioninput_schema를 통해 LLM이 툴 사용법을 명확히 인지하도록 문서화해야 합니다.

6. Rails 애플리케이션 구조화

  • 네임스페이스: AI::MCP::Server::Tools, AI::MCP::Server::Resources, AI::MCP::Server::Prompts와 같이 명확한 모듈 네임스페이스를 사용하여 코드를 체계적으로 관리합니다.

  • ActiveSupport::Inflector: MCP, AI와 같은 약어를 inflector에 추가하여 Zeitwerk 오토로딩이 원활하게 작동하도록 합니다.

7. LLM 클라이언트 설정 및 연동

  • openai-ruby Gem: chat.completions 엔드포인트를 사용하여 OpenAI, LM Studio, Ollama 등 다양한 LLM 백엔드와 호환성을 유지합니다.

  • 보안: API 키와 같은 민감 정보는 레포지토리 외부에 안전하게 보관하고, .env 파일을 통해 로드하는 것이 좋습니다.

  • 유연한 설정: config/ai_services.yml 파일을 통해 base_urlmodels를 환경에 따라 쉽게 전환할 수 있도록 구성합니다.

  • 툴 메타데이터 변환: MCP 서버의 툴 정의를 OpenAI의 함수 툴 형식으로 변환하는 ‘마법 클래스’가 필요합니다.

  • response_format: 툴 사용 시에는 response_formatnil로 설정해야 합니다. 구조화된 응답과 툴은 동시에 사용할 수 없습니다.

8. 대화 흐름(Orchestration) 및 컨텍스트 관리

  • 루프: 메시지 전송, 요청된 툴 실행, 결과 피드백, 그리고 컨텍스트 창 제한을 위한 이력 요약/정리 과정을 반복하는 루프를 구성합니다.

  • 툴 호출 응답: LLM이 툴 호출을 요청하면, 해당 툴을 실행한 후 그 결과를 다시 LLM에 메시지 형태로 전달해야 합니다.

  • 컨텍스트 전략: 메시지 요약, 비핵심 대화 제거, 대용량 툴 출력 요약, 문서 청킹, 롤링 윈도우 유지 등을 통해 컨텍스트 폭주를 방지합니다.

9. 개발 생존 키트 및 팁

  • 버전 고정: Gem, 서버 빌드, 모델 이름 등을 고정하여 재현 가능한 환경을 만듭니다.

  • 기능 감지: prompt_cache_key와 같은 추가 필드를 보내기 전에 작은 요청으로 지원 여부를 확인합니다.

  • 로깅: 원본 HTTP 요청/응답을 로깅하여 문제 해결에 활용합니다 (민감 정보는 마스킹).

  • 디버거 및 curl: 실제 디버거를 사용하고, curl 스크립트를 준비하여 SDK의 동작과 실제 통신 내용을 비교합니다.

  • 폴백 및 백엔드 전환: 툴 호출 실패 시 일반 응답으로 폴백하고, 동작 불일치 시 다른 LLM 백엔드(OpenAI, LM Studio, Ollama)로 전환하여 테스트합니다.

결론

Ruby on Rails로 AI 에이전트를 구축하는 것은 기술적 도전과제를 수반하지만, MCP 서버를 통한 툴 노출, RAG의 전략적 활용, 컨텍스트 창의 효율적 관리, 그리고 적절한 LLM 및 SDK 활용법을 이해한다면 성공적인 구현이 가능합니다. 특히, 동적으로 변화하는 AI API 환경에 대응하기 위해 유연한 설정과 철저한 디버깅, 그리고 견고한 오류 처리 메커니즘을 갖추는 것이 중요합니다. 이 글에서 제시된 실질적인 가이드라인과 '아무도 알려주지 않는' 팁들은 개발자들이 AI 에이전트 개발 과정에서 겪을 시행착오를 줄이고, 보다 안정적이고 효율적인 시스템을 구축하는 데 기여할 것입니다.

댓글 0

댓글 작성

0/1000
정중하고 건설적인 댓글을 작성해 주세요.

아직 댓글이 없습니다

첫 번째 댓글을 작성해보세요!