서버 아키텍처와 LLM 통합 구조
현재 서버는 DB, Redis, MQ, WebSocket 등의 주요 기능을 AppContext 기반으로 통합 관리하고, 서비스 로직에서는 이를 유틸리티 레이어를 통해 일관되게 호출하는 구조를 채택하고 있다.

웹소켓 테스트 등 시연화면에서 사용된 LLM 기능은 컨텍스트 외부에서 개별 함수로 처리되어 단순 일회성 호출로 구현되어 있었다.
특히 AI 서버의 요구사항 중 "알고리즘은 교체 가능해야한다"를 충족하기 위해서, LLM 기능을 기존 서버 아키텍처의 원칙(DI, IoC)에 따라 통합하고 모듈화하는 형태로 설계할 필요가 있었다.
또한 AI 개발자가 전체 서버 구조를 처음부터 끝까지 이해하지 않더라도 LLM 관련 모듈만 파악하면 즉시 작업에 투입될 수 있도록 인터페이스 형태로 구조를 명확히 분리하려 했다.
LLM 인터페이스 요구사항
LLM 인터페이스 설계 시 다음과 같은 요구사항을 기반으로 구조를 정의했다.
1. 모든 LLM 매니저는 공통 인터페이스를 따르며, 전역 컨텍스트에 등록되어야 한다.
2. 각 모듈의 구조만 파악하면 전체 흐름 이해 및 유지보수가 가능해야 한다.
3. LLM 호출 기능은 목적별로 모듈 단위로 분리할 수 있어야 한다.
LLM 기능 모듈화 전략

LLM 기능은 모델이나 알고리즘을 교체하더라도 서버 전체에 영향을 주지 않도록 의존성을 최소화하고, 기능별로 분리된 구조를 따르도록 설계했다.
디렉토리 구조
LLM 관련 코드는 service/ai 디렉토리 아래에 집중시켰다. AI 엔지니어는 해당 디렉토리만 파악하면 전체 서버 구조를 알지 못해도 필요한 AI 기능을 독립적으로 작업할 수 있도록 구성했다.
service/
┗ ai/
┣ llm_base_manager.py # 추상 Base 클래스
┣ llm_ops_manager.py # 코드 변환 등 ops용
┣ llm_analyze_manager.py # 감성 분석 등 분석용
┗ llm_default_manager.py # 기본 매니저
LLM 매니저 클래스
각 매니저는 모두 BaseLLMManager 라는 공통 추상 클래스를 상속받아 작성한다. 이 base manger는 init / process / destroy의 생명주기를 기본으로 하여 모든 LLM 기능이 동일한 흐름으로 초기화되고 실행되고 정리될 수 있도록 강제했다. 따라서 매니저마다 내부 process가 다르게 실행되더라도 외부에서는 항상 같은 방식으로 기능을 호출하고 사용할 수 있도록 일관성을 확보했다.
class BaseLLMManager:
def init() # 매니저 초기화
def destroy() # 리소스 정리
def get_chain() # 실행 체인 구성
def _get_model() # 실제 모델 로딩
@abstractmethod
def _get_prompt_template() # 프롬프트 템플릿 정의
@abstractmethod
def _log_stats() # 실행 결과 로그 기록
기본 틀은 모두 베이스 클래스에 담아두었기 때문에, 새로운 기능이 필요하면 자식 클래스에서 필요한 메서드만 선택적으로 작성하면 된다. 아래는 BaseLLMManager 를 상속받아 작성한 OpsLLMManager 클래스의 예제이다.
# 구체 LLM 매니저 1: 어드민 페이지 내 실험용
class OpsLLMManager(BaseLLMManager):
model_key = "default"
manager_key = "ops"
def _get_prompt_template()
def _get_pattern_prompt(js_code)
def _log_stats()
async def convert_pattern(js_code)
서비스 로직에서의 사용
LLM 매니저는 AppContext에 등록된 매니저를 통해 일관된 방식으로 호출한다.
LLM 매니저는 실제 서비스 로직에서는 아래처럼 불러와 사용할 수 있다.
# 예: scripts/some_scripts.py
async def handle_code_transform(ctx, js_code):
result = await ctx.manager.convert_pattern(js_code)
return result
임의로 작성된 자바스크립트 코드를 p5.js 템플릿 스타일로 변환하는 코드
테스트 단계에서 RAG(Retrieval-Augmented Generation)를 적용하려는 시도를 했었는데, 기존의 단순 LLM 호출 구조로는 벡터 검색, 문서 컨텍스트 구성 등 복합적인 처리가 어려울 것 같았다. 아직 LangChain이나 RAG 와 같은 기술에 대한 이해도가 부족해 본격적으로 고도화 작업을 하지 못하고 있는데, 추후 LLM 전담 개발자가 들어오면 논의후에 구조를 일부 재설계하는 가능성을 열어두고 있다.
'DevLog' 카테고리의 다른 글
| 프로젝트 관리 (2) | 2025.07.19 |
|---|---|
| procedural 방식의 패턴 생성(2) (1) | 2025.07.03 |
| LLM 정량평가하기(1) (0) | 2025.06.21 |
| procedural 방식의 패턴 생성(1) (1) | 2025.06.06 |
| [캡스톤] 서버 설계 (0) | 2025.05.17 |