나의 .NET 여행 AI 라이브러리를 OpenAI, Anthropic, Ollama, Azure와 연동되도록 만들었습니다. 단 하나가 아니라요.
요약
.NET 기반의 여행 AI 라이브러리인 TravelAI.Core를 다양한 AI 프로바이더와 연동할 수 있도록 리팩토링했습니다. Azure에 국한되었던 기존 구조를 OpenAI, Anthropic, Ollama 및 Mock 프로바이더를 지원하는 추상화 구조로 개선했습니다.
핵심 포인트
- ILlmProvider 인터페이스를 통한 다양한 LLM 프로바이더 추상화 구현
- Azure 없이도 개발 가능한 Mock 프로바이더 도입으로 개발 편의성 증대
- Ollama 어댑터 구현을 통해 로컬 LLM 환경 지원
- 인터페이스 유지 및 백엔드 교체 방식의 유연한 아키텍처 설계
제가 처음 TravelAI.Core를 출시했을 때는 Azure OpenAI와 Azure AI Search에서만 작동했습니다. 단 하나의 일정(itinerary)을 생성하기 위해서도 Azure 구독, 배포된 GPT-4o 모델, 구성된 AI Search 인덱스, 그리고 이 모든 것을 연결하기 위한 인내심이 필요했습니다.
다운로드 속도는 느렸습니다. 돌이켜보면 놀라운 일도 아닙니다.
대부분의 개발자는 Azure 자격 증명(credentials)을 가지고 있지 않습니다. 그들은 클라우드 제공업체에 전념하기 전에 무언가를 먼저 시도해보고 싶어 합니다. 저는 기본적으로 사람들이 이 라이브러리가 유용한지 확인하기도 전에 상당한 설정 작업을 수행하도록 요구하고 있었던 셈입니다.
그래서 저는 프로바이더(provider) 계층을 다시 구축했습니다.
변경된 사항
핵심 인터페이스(interface)는 정확히 동일하게 유지되었습니다. IItineraryGenerationService, IDestinationSearchService, IPriceAnomalyDetector는 외부에서 보기에 모두 동일합니다. 변경된 점은 백엔드를 연결하는 방식입니다.
v1.0.0에서는 Azure 자격 증명이 포함된 설정 섹션이 필요했습니다. v2.0.0에서는 프로바이더를 선택합니다:
builder.Services.AddTravelAI(options => options.UseMock());
builder.Services.AddTravelAI(options => options.UseOpenAI("sk-..."));
builder.Services.AddTravelAI(options => options.UseAnthropic("sk-ant-..."));
...
Mock 프로바이더는 제가 가장 만족하는 부분입니다. 자격 증명이 전혀 필요 없고, 오프라인에서 작동하며, 활동, 비용, 시간이 포함된 현실적인 3일간의 로마 여행 일정을 반환합니다. 인터넷이 없는 기차 안에서도 전체 통합 흐름(integration flow)을 빌드하고 테스트할 수 있습니다.
추상화(abstraction) 작동 방식
단일 ILlmProvider 인터페이스가 존재합니다:
public interface ILlmProvider
{
Task<string> GenerateAsync(
...
각 프로바이더가 이를 구현합니다. 이제 ItineraryGenerationService는 AzureOpenAIClient 대신 ILlmProvider를 받습니다. Anthropic 어댑터(adapter)는 Anthropic.SDK를 사용하고, Ollama 어댑터는 /api/chat로 직접 HTTP 호출을 수행하며, Mock은 단순히 하드코딩된 JSON 문자열을 반환합니다.
목적지 검색(destination search) 측에도 Mock이 있습니다. MockDestinationSearchService는 엄선된 5개의 목적지를 대상으로 메모리 내에서 키워드 점수 산정(keyword scoring)을 수행합니다. Azure AI Search를 사용할지 아니면 다른 것을 사용할지 결정하는 동안 개발을 진행하기에 충분합니다.
Ollama 어댑터
Ollama의 API는 간단하지만, 스트리밍 응답(streaming responses)을 처리해야 하며 모델 버전에 따라 JSON 형식이 약간씩 다릅니다. 저는 어댑터를 상태 비저장(stateless)으로 유지하기 위해 비스트리밍(non-streaming) 요청 방식을 선택했으며, 이는 일정 생성(itinerary generation) 작업에 충분히 잘 작동합니다.
var response = await _http.PostAsJsonAsync("/api/chat", new
{
model = _model,
...
특별한 기교는 없습니다. 그냥 잘 작동합니다.
라이브러리가 하는 일
등록이 완료되면 다음 네 가지 기능을 수행합니다:
일정 생성(Itinerary generation)은 여행자 프로필과 목적지를 입력받아 활동 및 예상 비용이 포함된 구조화된 일별 계획을 반환합니다. 가격 이상 탐지(Price anomaly detection)는 과거 기준치(historical baselines)와 항공 옵션을 비교 분석하여 특이 사항을 표시합니다. 목적지 검색(Destination search)은 "해변이 있고 현지 음식이 있으며 너무 관광객 위주가 아닌 따뜻한 곳"과 같은 자연어 질의(natural language queries)를 이해합니다. 예약 자동화(Booking automation)는 재시도 로직(retry logic)과 실패 시 롤백(rollback) 기능을 갖춘 엔드 투 엔드(end-to-end) 흐름을 실행합니다.
전체 시스템은 Azure Kubernetes Service에 배포됩니다. GitHub Actions 파이프라인은 linux/arm64용으로 빌드하고, GHCR로 푸시하며, 수동 승인 게이트(manual approval gate)를 통해 배포됩니다. arm64 부분을 파악하는 데 시간이 좀 걸렸습니다.
시작하기
dotnet add package TravelAI.Core
UseMock()으로 시작하세요. 필요한 기능이 충족된다면 실제 제공자(provider)로 전환하면 됩니다. 나머지 코드는 변경할 필요가 없습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기