본문 바로가기
LLM/Architecture

Agent Observability (Langfuse, LangSmith)

by AteN 2026. 4. 15.

에이전트 관측성 완전 정리, Langfuse와 LangSmith

요약

  • 에이전트는 한 요청에 여러 도구를 여러 턴에 걸쳐 자율로 부릅니다. 최종 응답만 로깅하면 실패해도 어느 스텝에서 왜 깨졌는지 재현할 수 없습니다.
  • 로깅과 관측은 다릅니다. 로깅은 줄글 텍스트를 시간순으로 흘려보내는 것이고, 관측은 스팬의 위계와 속성과 상관키를 구조로 남기는 것입니다.
  • 두 대표 도구가 데이터를 다르게 쪼갭니다. Langfuse는 observation / trace / session 3층, LangSmith는 run / trace / threadtrajectory라는 뷰를 하나 더 둡니다.
  • 결정적 차이는 성능이 아니라 철학입니다. Langfuse는 OpenTelemetry 기반 오픈소스로 self-host가 1급이고, LangSmith는 LangChain과 LangGraph에 가장 깊게 붙습니다.
  • 둘 다 비동기 배치 전송을 씁니다. 그래서 짧게 살고 죽는 프로세스에서는 명시적으로 flush를 불러야 데이터가 안 날아갑니다.
  • 관측에도 비용이 붙습니다. 프롬프트 본문 전량 로깅은 저장과 프라이버시와 지연을 부릅니다. 계측은 "무엇을 캡처할지 설계하는 일"입니다.

1장. 왜 일반 로깅으로는 안 되나

1.1 에이전트는 멀티스텝 블랙박스다

일반 API 호출
   요청 하나 → 응답 하나
   로그도 한 줄이면 된다

에이전트
   계획을 세우고
   도구를 고르고
   실행하고
   관찰하고
   다시 계획한다

   이걸 자율로 여러 턴 돈다

1.2 그래서 질문이 어려워진다

답이 틀렸다
   계획이 틀렸나
   도구 선정이 틀렸나
   도구는 맞는데 인자가 틀렸나
   실행은 됐는데 최종 종합이 틀렸나

느리다
   어느 LLM 호출이 병목인가
   아니면 어느 도구가 오래 걸리나

비싸다
   어느 스텝이 토큰을 가장 많이 태우나

최종 응답만 로깅해서는 이 중 무엇도 답할 수 없습니다.

1.3 로깅과 관측의 차이

로깅
   줄글 텍스트를 시간순으로 흘려보낸다
   "어느 LLM 호출이 이 도구 실패를 유발했나"를
   기계적으로 이을 수 없다

관측
   스팬의 위계(트리) + 속성 + 상관키를 구조로 남긴다
   그 연결을 구조로 만든다

2장. 공통 뼈대

2.1 세 층

두 도구의 이름은 다르지만 개념 층은 같습니다.

가장 작은 단위   한 작업 구간. LLM 호출 하나, 도구 실행 하나
중간 단위        한 요청의 처리 전체
가장 큰 단위     여러 턴을 묶은 대화 세션

2.2 두 성질이 이 구조를 쓸모 있게 만든다

상관(correlation)

한 요청 안 모든 기록이 같은 id 를 달아야
흩어진 기록이 하나의 이야기로 이어진다

   라우터와 계획 LLM 과 도구 실행이 서로 다른 id 로 찍히면
   한 요청이 여러 개의 고아 조각으로 쪼개진다

중첩(nesting)

기록은 부모와 자식으로 겹쳐 트리를 이룬다
이 트리가 곧 "무슨 일이 있었나"의 지도다

2.3 무엇을 남기나

계획과 라우팅 결정   결정 결과, 근거
LLM 호출            모델명, 역할, 입출력 토큰, 지연, 종료 이유
도구 선정           도구 이름, 인자
도구 실행           도구 이름, 상태, 에러 코드, 산출물
검색                질의, 히트 수, 청크
종합                최종 답변, 성공 여부

3장. Langfuse의 데이터 모델

3.1 세 개념

공식 문서 기준으로 Langfuse는 데이터를 observation, trace, session 세 개념으로 조직합니다.

Observation
   애플리케이션의 개별 스텝
   LLM 호출, 도구 호출, 검색 스텝 등

   중첩할 수 있어 애플리케이션 구조를 반영한다
   generation 이나 event 같은 LLM 특화 타입도 지원한다

Trace
   단일 요청이나 작업
   예: 사용자 질문에서 최종 응답까지의 챗봇 상호작용 한 번

   같은 trace_id 를 공유하는 모든 observation 의 논리적 묶음

Session
   같은 사용자 상호작용에 속하는 trace 들을 묶는다
   흔한 예가 챗 인터페이스의 스레드
Session
   ├─ Trace
   │    ├─ Observation
   │    ├─ Observation
   │    └─ Observation
   ├─ Trace
   │    ├─ Observation
   │    └─ Observation
   └─ Trace
        └─ Observation

3.2 저장 구조가 특이하다

여기가 Langfuse의 설계 결정 중 흥미로운 부분입니다.

trace 수준 속성 (user_id, session_id, tags, metadata) 은
그 trace 안의 모든 observation 에 얹힌다
   SDK 가 자동으로 전파한다

개념적으로 Langfuse 는 observation 테이블 하나를 두고
각 행이 observation 수준 데이터에
trace 수준 속성의 복사본을 함께 담는다

왜 이렇게 하나. 공식 문서가 이유를 밝힙니다.

쿼리와 집계를 빠르게 유지하기 위해서다

   조인 없이 한 테이블에서
   "이 사용자의 모든 LLM 호출 지연" 같은 질의가 바로 된다
   저장 중복을 감수하고 조회 성능을 택한 것

3.3 속성으로 자르기

Environments   production, staging, development 등 배포 맥락 분리
Tags           기능이나 API 엔드포인트나 워크플로별 분류
User           어느 최종 사용자가 이 trace 를 일으켰나
Metadata       임의의 키-값
Releases       애플리케이션 버전과 컴포넌트 변경 추적

Environments가 실무에서 특히 유용합니다. 스테이징 트래픽이 프로덕션 지표를 오염시키는 걸 막습니다.


4장. LangSmith의 데이터 모델

4.1 네 개념

LangSmith는 run, trace, thread에 더해 trajectory라는 뷰를 둡니다.

Run
   에이전트가 수행한 단일 작업 단위
   모델 호출, 프롬프트 포매팅, 문서 검색 등

   공식 문서가 직접 말한다
   "OpenTelemetry 에 익숙하다면 run 을 span 으로 생각하면 된다"

Trace
   단일 작업에 대한 run 들의 모음
   고유한 trace ID 로 묶인다

Thread
   단일 멀티턴 세션을 나타내는 trace 의 시퀀스
   한 turn 은 사용자 메시지와 그에 대한 에이전트의 모든 행동
   각 turn 이 자기 trace 로 기록된다
   thread_id 메타데이터 키로 묶는다

Trajectory
   에이전트가 처음부터 끝까지 걸어간 경로를
   평평하고 순서 있는 메시지 목록으로 보여준다

4.2 trajectory가 무엇인가

LangSmith에만 있는 개념이라 따로 볼 만합니다.

thread 는 세션의 trace 들을 묶고 중첩 구조를 유지한다
trajectory 는 세션 전체를 평평하게 편다

   thread 안 trace 들에 대한 projection 이다
   세션에서 주고받은 human, AI, tool 메시지를 담되
   각각 한 번씩, 처음 나타난 순서로, run 중첩을 제거한 형태

4.3 셋을 언제 쓰나

공식 문서의 비교입니다.

  Trace Thread Trajectory
형태 run의 트리 trace의 시퀀스 평평하고 순서 있는 메시지 목록
담는 것 모든 run과 전체 입출력 연결된 모든 trace의 모든 run 모든 메시지, 중복 제거됨
언제 한 작업이 왜 실패했거나 느렸는지 디버깅할 때 여러 턴에 걸친 행동을 타이밍과 중첩까지 볼 때 실행 세부 없이 무엇이 오갔는지 읽을 때

세 번째가 실무에서 의외로 자주 필요합니다. "이 대화에서 뭐가 오갔지"를 볼 때 run 트리는 오히려 방해가 됩니다.

4.4 알아둘 제약

각 trace 는 최대 25,000 run 으로 제한된다
한도에 닿으면 그 trace 에 추가로 보내는 run 을 거부한다

긴 에이전트 루프에서 걸릴 수 있는 실제 상한입니다.


5장. 두 도구의 개념 대응

5.1 대응표

Langfuse              LangSmith             OpenTelemetry
────────────────────────────────────────────────────────
Observation           Run                   Span
Trace                 Trace                 Trace
Session               Thread                (없음)
(없음)                Trajectory            (없음)

이 표만 봐도 두 제품의 성격이 갈립니다.

5.2 Langfuse는 OTel에 붙어 있다

Langfuse 는 OpenTelemetry 위에 지어졌다

   공식 문서의 표현
   "Langfuse 전용 SDK 만 써야 하는 게 아니다
    트레이스를 여러 목적지로 동시에 보낼 수 있다
    예를 들어 LLM 관측은 Langfuse 로
    인프라 모니터링은 Datadog 으로"

   호환성을 높이고 벤더 락인을 줄이는 게 명시적 목표다

수집 경로도 넓습니다.

Python 과 JS 네이티브 SDK
100개 이상의 라이브러리와 프레임워크 통합
OpenTelemetry 직접
LiteLLM 같은 LLM 게이트웨이 경유

5.3 LangSmith는 LangChain 생태계에 붙어 있다

LangChain 과 LangGraph 를 쓰면 계측이 사실상 자동이다
   노드 단위 state diff
   전체 에이전트 그래프
   "새 모델로 replay"

   대신 프레임워크 종속이 생긴다

5.4 그래서 선택 기준

LangChain 이나 LangGraph 로 짰다
   └──► LangSmith 가 압도적으로 편하다
        계측 코드를 거의 안 쓴다

프레임워크가 제각각이거나 직접 짠 루프다
   └──► Langfuse 가 유리하다
        OTel 표준이라 무엇이든 받는다

self-host 가 요구사항이다
   └──► Langfuse
        오픈소스이고 self-host 가 1급이다

이미 Datadog 같은 APM 이 있다
   └──► Langfuse
        같은 트레이스를 양쪽으로 보낼 수 있다

6장. 트레이스 한 벌 읽기

6.1 예시

리서치 에이전트가 "이번 주 서울 날씨를 요약해줘"를 처리하는 한 턴입니다. 계획을 세우고, 날씨 도구를 부르는데 첫 시도가 timeout으로 실패하고, 재시도로 성공한 뒤 결과를 종합합니다.

Trace t-9f2a12   "이번 주 서울 날씨 요약해줘"
                 model=gpt-4o   전체 10.1s   status=ok (재시도로 복구)
  │
  ├─ 계획 LLM 호출
  │     종료 이유=tool_calls   in=856  out=98   2.1s
  │     get_weather(city="서울", range="이번주") 호출 결정
  │
  ├─ 도구 실행 get_weather
  │     status=error   error=timeout (5s 초과)   5.0s
  │     첫 시도 실패
  │
  ├─ 도구 실행 get_weather
  │     status=ok   result={7일치 예보}   1.2s
  │     재시도 성공
  │
  └─ 종합 LLM 호출
        종료 이유=stop   in=1200  out=180   1.8s

6.2 여기서 바로 나오는 답

어디서 깨졌나
   두 번째 기록이 status=error 에 timeout
   계획과 모델은 멀쩡했고 도구 실행 단계가 원인
   재시도로 복구돼 턴 전체는 성공

왜 느렸나
   전체 10.1초 중 실패한 도구 호출이 5초
   병목은 LLM 이 아니라 도구 timeout

얼마 들었나
   입력 856 과 1200, 출력 98 과 180
   모델 단가를 곱하면 이 케이스의 비용이 나온다

6.3 상관키가 없으면

다섯 기록이 서로 다른 id 로 찍혔다면
대시보드에서 무관한 다섯 기록으로 흩어진다

   "timeout 이 어느 요청의 어느 스텝이었는지"를
   영영 이을 수 없다

6.4 status를 정하는 규약

턴 전체의 status 는
그 안의 기록들 중 최악값으로 정하는 게 흔한 규약이다

   하나라도 실패면 턴을 실패로 본다
   위 예에서는 재시도가 성공했으니 ok

   심각도는 보통 ok < warn < timeout < error 순

7장. 수집 방식과 함정

7.1 비동기 배치 전송

두 도구 모두 같은 방식이고, 여기서 실무 사고가 납니다.

Langfuse 공식 문서

   애플리케이션을 느리게 하지 않으려고
   트레이스를 생성 즉시 동기로 보내지 않는다
   로컬에 배치로 모았다가 백그라운드로 보낸다

7.2 짧게 사는 프로세스의 함정

긴 수명 애플리케이션 (웹 서버, API)
   백그라운드 exporter 가 계속 돌며
   배치를 flush 할 시간이 충분하다
   문제없다

짧게 사는 애플리케이션 (시작 → 실행 → 종료)
   큐에 안 보낸 트레이스가 남은 채로
   프로세스가 종료될 위험이 있다

   └──► 종료 전에 명시적으로 flush() 를 불러야 한다

배치 작업이나 CLI 도구나 서버리스 함수에서 "트레이스가 일부만 보인다"의 대표 원인입니다. 에러가 안 나고 조용히 사라집니다.

7.3 단일 수집 경로로 모으기

계측 배선이 한 곳으로 모이지 않으면 수집이 샌다

   예: 스트리밍 응답처럼 직접 emit 지점이 없는 경로가
       게이트웨이 콜백에만 의존하고 있으면
       │
       └──► 누군가 게이트웨이를 우회하는 순간 수집이 0 이 된다
             그런데 대시보드는 "트래픽이 없다"로 보여서
             알아채기 어렵다

8장. 무엇을 캡처할지 설계하기

8.1 본문 캡처의 세 모드

본문 생략              메타데이터만. 가장 안전하고 싸다
전량 저장              디버깅은 최고, 프라이버시와 저장 비용이 문제
외부 저장 후 참조만     기록에는 URL 만. 접근 통제를 따로 건다

OpenTelemetry의 GenAI 규약에서도 프롬프트 본문은 기본 미기록이고 명시적 opt-in입니다. 두 상용 도구도 마스킹이나 필터링 옵션을 제공합니다.

8.2 오버헤드 관리

로그 writer 를 논블로킹으로 둔다   턴 지연 영향 최소화
크기나 일자 기준 회전을 건다        파일 폭주 방지
이벤트는 문자열이 아니라 필드로     나중에 파싱 없이 조회

8.3 실패 이벤트에 분류 키를 함께

error_code   tool.bad_request     기계가 집계할 분류 키
error        "city 파라미터 누락"  사람이 읽을 메시지

   분류 키가 있으면 실패 분석이 자동으로 단계 x 유형으로 묶인다
   메시지만 있으면 매번 사람이 읽어야 한다

9장. 관측이 평가로 이어지는 이유

9.1 트레이스는 평가의 입력이다

프로덕션 트레이스에서 좋은 케이스를 골라 골든셋을 키운다
트레이스별로 점수를 붙여 회귀를 CI 로 막는다

   기록이 단계별로 있으니 단계별 채점도 가능하다
라우팅이 맞았나        계획 기록의 결정 결과를 채점
도구 선정이 맞았나      도구 이름과 정답 도구를 비교
인자가 맞았나          인자를 채점
실행 산출물이 맞았나    결과를 채점
최종 답변 품질은       종합 기록의 출력을 채점

   최종 답만 보면 이 다섯을 구분할 수 없다

두 도구 모두 이 연결을 제품 기능으로 갖고 있습니다. Langfuse는 평가 플랫폼과 데이터셋을, LangSmith는 데이터셋과 실험 비교를 관측과 같은 계정 안에서 제공합니다.

9.2 트레이스는 실패 진단의 지도다

status != ok 인 기록을
어느 단계에서 x 무슨 유형으로 군집하면

   "도구 timeout 이 특정 모델과 특정 도구에 몰려 있다"처럼
   실패 모드가 통계로 드러난다

9.3 정리

관측 없이는 평가가 없고
평가 없이는 개선의 방향을 알 수 없다

10장. 도구 선택과 자체 구현

10.1 세 도구 비교

  Langfuse LangSmith Arize Phoenix
성격 OTel 네이티브 오픈소스 LangChain 팀 제품 ML 모니터링 혈통 오픈소스
데이터 모델 observation / trace / session run / trace / thread / trajectory OTel 기반
강점 어떤 프레임워크든 받는다. self-host 1급 LangChain과 LangGraph에 가장 깊다 eval과 drift 탐지가 탄탄
대가 프레임워크별 깊이는 얕은 편 프레임워크 종속, 좌석과 트레이스량 과금 완전 오픈소스

10.2 고르는 다섯 축

① 프레임워크 종속      LangChain 이면 LangSmith, 무관하면 Langfuse
② 배포 모델           클라우드 SaaS 냐 self-host 냐
③ 평가 엄밀성         eval 과 drift 를 얼마나 다루나
④ 데이터 주권         트레이스가 어디에 저장되나
⑤ 과금 모델          좌석, 트레이스량, 보관 기간

10.3 자체 구현이 합리적인 경우

항상 SaaS를 붙이는 게 답은 아닙니다. 관측 도구가 주는 핵심 이득은 셋으로 압축됩니다.

① 비용과 토큰과 지연 집계   모델별 케이스별로 얼마, 몇 초, 몇 토큰
② run 영속화              평가 실행을 저장해 A/B 와 회귀를 비교
③ dataset 스냅샷과 버전    재현성 확보, 실행 간 상태 오염 방지

셋 다 표준적인 패턴입니다. 가격표 조인, run 테이블, 스냅샷입니다. 다음 경우에는 OTel 표준의 이득만 네이티브로 채택하고 위 셋을 자체 구현하는 게 합리적일 수 있습니다.

LangChain 을 쓰지 않는 커스텀 루프
오프라인이나 온프렘이 필수
이미 자체 대시보드를 가진 경우

반대로 빠른 시작과 풍부한 UI가 필요하면 SaaS가 낫습니다. 판단의 축은 "이득 3종 대 이미 가진 것의 중복도"입니다.


11장. 정리

11.1 자주 하는 오해

응답만 로깅하면 된다. 에이전트의 실패 원인은 대개 중간 도구 호출과 인자와 관찰에 있습니다.

관측이 곧 로깅이다. 로깅은 텍스트, 관측은 구조화된 트레이스입니다. 결정적 차이는 상관키와 중첩입니다.

관측에는 비용이 안 든다. 전량 로깅은 저장과 프라이버시와 지연을 유발합니다.

두 도구가 같은 걸 부른다. Langfuse의 observation과 LangSmith의 run은 대응되지만, session과 thread는 미묘하게 다르고 trajectory는 대응이 없습니다. 마이그레이션할 때 걸립니다.

11.2 핵심 셋

① 에이전트는 멀티스텝 블랙박스라
   최종 응답만 로깅하면 어디서 왜 깨졌는지 알 수 없다

② Langfuse 는 OTel 기반 오픈소스로 무엇이든 받고 self-host 가 1급
   LangSmith 는 LangChain 생태계에 가장 깊게 붙는다
   성능이 아니라 철학이 갈린다

③ 트레이스는 평가의 입력이자 실패 진단의 지도다
   관측 없이는 개선의 방향을 알 수 없다

11.3 용어 정리

용어 한 줄 뜻
관측성 시스템 내부 상태를 외부 출력으로 파악하는 능력
Observation (Langfuse) 애플리케이션의 개별 스텝. LLM 호출이나 도구 호출
Run (LangSmith) 에이전트가 수행한 단일 작업 단위. OTel의 span에 대응
Trace 한 요청 처리 전체. 같은 id로 묶인 기록들의 트리
Session (Langfuse) / Thread (LangSmith) 여러 턴을 묶는 상위 단위
Trajectory (LangSmith) 세션 전체를 평평한 메시지 목록으로 편 뷰
상관키 흩어진 기록을 하나로 묶는 id
중첩 기록이 부모와 자식으로 겹쳐 트리를 이루는 것
비동기 배치 전송 트레이스를 모았다 백그라운드로 보내는 방식
flush 버퍼에 남은 트레이스를 즉시 강제 전송하는 것
Environments production과 staging 등 배포 맥락을 분리하는 속성
골든셋 평가 기준이 되는 검증된 케이스 모음

11.4 참고자료

'LLM > Architecture' 카테고리의 다른 글

GQA와 MQA  (0) 2024.10.07

댓글