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에서 아직 구현되지 않아, 툴의description과input_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-rubyGem:chat.completions엔드포인트를 사용하여 OpenAI, LM Studio, Ollama 등 다양한 LLM 백엔드와 호환성을 유지합니다. -
보안: API 키와 같은 민감 정보는 레포지토리 외부에 안전하게 보관하고,
.env파일을 통해 로드하는 것이 좋습니다. -
유연한 설정:
config/ai_services.yml파일을 통해base_url과models를 환경에 따라 쉽게 전환할 수 있도록 구성합니다. -
툴 메타데이터 변환: MCP 서버의 툴 정의를 OpenAI의 함수 툴 형식으로 변환하는 ‘마법 클래스’가 필요합니다.
-
response_format: 툴 사용 시에는response_format을nil로 설정해야 합니다. 구조화된 응답과 툴은 동시에 사용할 수 없습니다.
8. 대화 흐름(Orchestration) 및 컨텍스트 관리
-
루프: 메시지 전송, 요청된 툴 실행, 결과 피드백, 그리고 컨텍스트 창 제한을 위한 이력 요약/정리 과정을 반복하는 루프를 구성합니다.
-
툴 호출 응답: LLM이 툴 호출을 요청하면, 해당 툴을 실행한 후 그 결과를 다시 LLM에 메시지 형태로 전달해야 합니다.
-
컨텍스트 전략: 메시지 요약, 비핵심 대화 제거, 대용량 툴 출력 요약, 문서 청킹, 롤링 윈도우 유지 등을 통해 컨텍스트 폭주를 방지합니다.
9. 개발 생존 키트 및 팁
-
버전 고정: Gem, 서버 빌드, 모델 이름 등을 고정하여 재현 가능한 환경을 만듭니다.
-
기능 감지:
prompt_cache_key와 같은 추가 필드를 보내기 전에 작은 요청으로 지원 여부를 확인합니다. -
로깅: 원본 HTTP 요청/응답을 로깅하여 문제 해결에 활용합니다 (민감 정보는 마스킹).
-
디버거 및
curl: 실제 디버거를 사용하고,curl스크립트를 준비하여 SDK의 동작과 실제 통신 내용을 비교합니다. -
폴백 및 백엔드 전환: 툴 호출 실패 시 일반 응답으로 폴백하고, 동작 불일치 시 다른 LLM 백엔드(OpenAI, LM Studio, Ollama)로 전환하여 테스트합니다.