observe-llm

운영 환경을 고려한 Self-Correcting AI Agent와 완전한 관찰 가능성

1. 소개: 프로토타입을 넘어서

많은 AI 에이전트 프로젝트는 개념 증명(PoC) 단계에 머물러 있습니다. 핵심 기능은 보여주지만, 배포, 모니터링, 확장성이라는 중요한 측면을 간과하는 경우가 많습니다. `observe-llm`은 이 간극을 메우기 위해 만들어졌습니다. 단순한 스크립트를 넘어, 견고하고 운영 가능한(production-ready) AI 에이전트 시스템을 구축하는 방법을 보여주는 실용적인 오픈소스 예제입니다.

왜 Langfuse가 필수적인가?

단순한 LLM 체인은 디버깅하기 쉽지만, 순환적인 Self-Correcting 루프를 가진 에이전트는 '블랙박스'가 될 수 있습니다. Langfuse는 에이전트의 모든 생각과 행동에 대한 깊은 통찰력을 제공하여, 복잡한 AI 워크플로우의 관찰 가능성(observability)문제를 해결합니다.

  • 사용자별 비용 추적: `user_id`를 기준으로 각 API 호출의 비용을 정확하게 추적하여 사용자별 과금의 기반을 마련할 수 있습니다.
  • 성능 병목 분석: LLM 모델별, 에이전트의 각 노드(단계)별 평균 지연 시간(latency)과 토큰 사용량을 분석하여 어느 부분에서 시간이 오래 걸리는지, 어떤 모델이 비효율적인지 쉽게 파악할 수 있습니다.
  • 품질 평가: 프롬프트의 버전을 관리하고, 동일한 입력에 대해 다른 프롬프트나 모델 버전이 어떻게 다른 결과물을 내놓는지 A/B 테스트하며, 사용자 피드백을 수집하여 에이전트의 응답 품질을 정량적으로 평가할 수 있습니다.
  • 신속한 디버깅: 복잡한 에이전트의 실행 흐름 전체를 시각적인 트레이스로 한눈에 파악하여, 어느 단계에서 문제가 발생했는지 신속하게 디버깅할 수 있습니다.
observe-llm 소개 영상 썸네일
교육 목적의 설명 영상입니다. 클릭 시 플레이어가 로드됩니다.

2. 시스템 아키텍처: 전체적인 관점

에이전트 자체는 퍼즐의 한 조각에 불과합니다. 견고한 시스템은 지원 서비스의 전체 스택을 필요로 하며, 이 모든 것이 원활하게 조율되어야 합니다. 저희는 Docker Compose를 사용하여 이 생태계를 관리하며, 여기에는 다음이 포함됩니다:

graph TD subgraph User A[Browser] end subgraph Docker Network B(observe-llm Agent) -- HTTP Request --> A B -- Trace Data --> C(Langfuse Server) C -- Writes/Reads --> D(PostgreSQL) C -- Writes/Reads --> E(Clickhouse) C -- Uses --> F(Redis) C -- Uses --> G(Minio) end A -- Interacts --> B

그림 1: Docker Compose로 관리되는 전체 시스템 아키텍처

3. 코드 분석: Self-Correcting Loop

핵심 로직은 `run_agent.py`에 있습니다. LangGraph를 사용하여 인간이 글을 다듬는 과정을 모방한 순환적인 '비평 및 수정' 워크플로우를 가능하게 하는 상태 머신을 만듭니다.

graph TD Start --> Researcher Researcher --> Writer Writer --> Critique Critique -- REVISE --> Reviser Reviser --> Critique Critique -- APPROVE --> SetFinalOutput SetFinalOutput --> End

그림 2: LangGraph 에이전트의 워크플로우

상태 머신 (`AgentState`)

`AgentState` TypedDict는 에이전트의 생명선입니다. 그래프의 각 노드가 읽고 쓰는 공유 메모리 역할을 하여 워크플로우 전반에 걸쳐 원활한 정보 흐름을 보장합니다.

class AgentState(TypedDict):
    topic: str
    research_result: str
    draft: str
    critique: str
    # ... and other state variables

조건부 엣지의 역할

이 워크플로우의 핵심은 `Critique` 노드 이후의 분기입니다. `should_revise` 함수는 `critique`의 내용에 'REVISE'라는 키워드가 있는지 확인하여, 에이전트가 수정을 계속할지 아니면 작업을 완료할지를 동적으로 결정합니다. 이 조건부 라우팅이 바로 LangGraph의 강력함입니다.

def should_revise(state: AgentState) -> str:
    if "REVISE" in state["critique"]:
        return "reviser"  # Loop back to revise
    else:
        return "set_final_output" # Exit the loop

4. 개발에서 배포까지

이 프로젝트를 진정으로 운영 가능하게 만들기 위해 몇 가지 핵심적인 운영 전략이 구현되었습니다.

보안 및 구성

API 키와 같은 모든 민감 정보는 `.env` 파일을 통해 관리됩니다. `docker-compose.yml`은 이러한 변수를 참조하여 소스 코드에 비밀이 하드코딩되지 않도록 합니다. `.gitignore` 파일은 `.env` 파일이 버전 제어에 커밋되는 것을 방지합니다.

데이터 영속성

Langfuse 스택은 영구 데이터를 필요로 합니다. 임시 Docker 볼륨 대신, 시스템은 로컬 바인드 마운트로 구성됩니다. 모든 데이터는 로컬 머신의 `langfuse-data/` 디렉토리에 저장되어, 컨테이너 재시작 및 제거에도 추적 기록이 유지됩니다.

5. 향후 방향 및 고도화

`observe-llm`은 견고한 기반을 제공하지만, 확장할 수 있는 흥미로운 방법이 많이 있습니다:

  • 에이전트 도구 추가: `researcher` 노드에 웹 검색 API(예: Tavily)와 같은 도구를 제공하여 기능을 향상시킬 수 있습니다. 이를 통해 에이전트는 실시간 정보를 통합하고 더 강력한 팩트체크를 수행할 수 있습니다.
  • 인간 참여 루프(Human-in-the-Loop): Langfuse의 사용자 피드백 기능을 통합합니다. 에이전트가 수정 루프를 완료한 후, 최종 초안을 인간에게 제시하여 최종 '승인' 또는 '거절' 조치를 받게 하고, 이 피드백을 Langfuse에 기록하여 에이전트의 성능을 추가로 평가할 수 있습니다.
  • 자동화된 테스트 및 평가: Langfuse의 데이터셋 및 점수 기능을 사용하여 자동화된 평가 파이프라인을 만듭니다. 주제와 예상 요점의 데이터셋을 구축한 다음, 이 데이터셋에 대해 에이전트를 프로그래밍 방식으로 실행하여 시간 경과에 따른 정확성과 일관성을 점수화할 수 있습니다.