실행 프로그램과 확장

최종 업데이트

Langfuse로 로컬 에이전트의 지연 구간 찾기

응답 한 번에 걸린 시간을 모델·검색·도구 단계로 나누면 느린 구간을 고르기 쉬워요.

Langfuse는 애플리케이션이 명시적으로 전송한 추적 이벤트를 받아 관찰 화면에 보여 줘요. 로컬 인스턴스와 Python SDK v4를 쓰면 API1 주소를 그 인스턴스로 지정하고 @observe로 함수 호출을 기록할 수 있어요. Langfuse를 설치했다고 임의의 Ollama 요청이 자동으로 기록되지는 않아요. 계측한 입력·출력에 개인정보나 문서 내용이 포함될 수 있으므로 기록할 필드를 직접 고르고 민감한 값을 마스킹해요.

로컬 에이전트가 답하는 동안 모델 호출, 파일 읽기, 도구 실행 중 어디에서 오래 기다리는지 알고 싶을 때 Langfuse를 써요. Python SDK로 각 단계의 추적 이벤트를 보내면 화면에서 시작·종료 시각과 소요 시간을 볼 수 있어요. 아래 예제는 로컬 Ollama 요청과 합성 파일 읽기를 기록하고, 입력·출력 본문은 남기지 않아요.

실행 조건과 핵심 내용
  • 전체 trace 시간에는 큐 대기, 도구, 모델 준비와 출력 시간이 함께 들어갈 수 있어요.
  • Python SDK v4에서는 @observe와 get_client()를 사용하고 이전 trace() API 예제를 새 계측에 섞지 않아요.
  • Langfuse 입력·출력에 민감한 정보가 들어가지 않도록 계측 경계를 직접 정해요.

전체 응답 시간을 처리 단계로 나눠요

에이전트가 느리다고 해서 모델 토큰2 생성이 항상 원인은 아니에요. 검색, 파일 읽기, 도구 대기, 재시도, 응답 출력이 차례로 이어질 수 있어요. Langfuse trace에 각 단계를 기록하면 같은 테스트 입력에서 어느 구간이 길어졌는지 확인할 수 있어요.

문서·표·메일 아이콘에서 화살표가 노트북 앞 로봇으로 이어지는 작업대
각 단계 시간을 나눠 기록하면 요청 전체의 지연 원인을 찾기 쉬워요.

로컬 인스턴스를 띄우고 SDK 계측 환경을 준비해요

저장소 루트의 docker-compose.yml에서 # CHANGEME 표시가 붙은 값을 모두 바꿔요. 웹 서비스의 ports는 127.0.0.1:3000:3000으로 제한하고 NEXTAUTH_URL도 http://localhost:3000으로 맞춰요. docker compose up -d와 docker compose ps를 실행해 포트가 127.0.0.1:3000->3000/tcp인지 확인해요.

docker compose logs -f langfuse-web에 Ready가 나타나면 브라우저에서 http://localhost:3000을 열어요. 가입 화면에서 첫 사용자를 만들고, 프로젝트의 Settings → API Keys에서 공개·비밀 키를 발급해요.

Langfuse Compose 저장소 준비
git clone https://github.com/langfuse/langfuse.git langfuse-local
cd langfuse-local
# 저장소 루트 docker-compose.yml에서 # CHANGEME 값을 바꾸고 NEXTAUTH_URL을 맞춰요.
저장소를 준비한 뒤 다음 포트 매핑을 UI 서비스에 적용해요.
UI 서비스의 로컬 전용 포트 매핑
ports:
  - "127.0.0.1:3000:3000"
Compose에서 3000번 포트를 공개하는 UI 서비스의 기존 ports 항목을 이 값으로 바꿔요.
Langfuse 시작과 포트 확인
docker compose up -d
docker compose ps
docker compose logs -f langfuse-web
PORTS 열에 127.0.0.1:3000->3000/tcp가 보일 때 브라우저에서 http://localhost:3000을 열어요.
작은 로봇 장치가 브라우저·달력·메시지 화면과 연결된 책상
로컬 UI와 계측 SDK가 같은 인스턴스를 향하도록 API 주소를 맞춰요.

SDK v4로 모델 호출과 도구 단계를 기록해요

Python 환경에 langfuse와 requests를 설치해요. 프로젝트 API 키와 LANGFUSE_BASE_URL=http://localhost:3000, ollama list에서 확인한 모델 ID를 환경 변수로 지정해요. @observe가 요청의 부모 span을 만들고 get_client()가 Ollama generation과 파일 읽기 tool observation을 그 아래에 기록해요. 입력·출력 본문은 수집하지 않고 상태와 문자 수만 metadata로 남겨요.

SDK와 환경 변수 준비
python -m venv .venv
source .venv/bin/activate
python -m pip install -U langfuse requests
export LANGFUSE_PUBLIC_KEY='pk-lf-project-key'
export LANGFUSE_SECRET_KEY='sk-lf-project-secret'
export LANGFUSE_BASE_URL='http://localhost:3000'
export OLLAMA_MODEL='YOUR_INSTALLED_MODEL_ID'
키는 프로젝트 설정에서 복사하고 모델 ID는 ollama list에 표시된 이름으로 바꿔요.

환경 변수를 준비한 뒤 아래 코드를 run_trace.py로 저장해요. 예제는 고정된 문장으로 Ollama를 한 번 호출하고 합성 텍스트 파일 하나를 읽어요. 추적 화면에는 두 작업의 소요 시간과 상태만 남겨요.

run_trace.py: Ollama와 합성 파일 읽기 계측
import os
from pathlib import Path
import requests
from langfuse import get_client, observe, propagate_attributes

MODEL = os.environ['OLLAMA_MODEL']
langfuse = get_client()

@observe(name='local-agent-request', as_type='span', capture_input=False, capture_output=False)
def run_trace():
    with propagate_attributes(trace_name='local-agent-toy', session_id='toy-session-1'):
        with langfuse.start_as_current_observation(as_type='generation', name='ollama-chat', model=MODEL) as generation:
            response = requests.post('http://127.0.0.1:11434/api/chat', json={'model': MODEL, 'stream': False, 'messages': [{'role': 'user', 'content': 'Reply with exactly: local trace test'}]}, timeout=120)
            response.raise_for_status()
            generation.update(metadata={'http_status': response.status_code})
        with langfuse.start_as_current_observation(as_type='tool', name='read-toy-file') as tool:
            text = Path('fixture.txt').read_text(encoding='utf-8')
            tool.update(metadata={'file': 'fixture.txt', 'characters': len(text)})
        print('Ollama status:', response.status_code, '| fixture characters:', len(text))

run_trace()
langfuse.flush()
이 코드 블록을 run_trace.py로 저장해요. fixture.txt에는 합성 문장만 넣고, 프롬프트·응답 본문 대신 모델명·HTTP 상태·파일 문자 수만 기록해요.
합성 파일을 만들고 trace 실행
printf '%s\n' 'Synthetic fixture for a local tracing example.' > fixture.txt && python run_trace.py
정상이라면 HTTP 상태 200과 파일 문자 수가 출력되고 Langfuse에 local-agent-toy trace가 생겨요.

민감하지 않은 고정 입력으로 trace를 읽어요

Trace 목록에 local-agent-toy가 보이면 열어 parent span 아래의 ollama-chat generation과 read-toy-file tool, 각 지연 시간과 기록한 메타데이터를 확인해요.

첫 오류가 401/403이면 공개·비밀 키가 같은 프로젝트에서 복사됐는지, API 주소가 http://localhost:3000인지 확인해요. 연결 오류면 서버 상태와 docker compose ps의 PORTS 값을 먼저 봐요. Ollama 오류면 curl http://127.0.0.1:11434/api/tags로 로컬 API 응답을 확인해요.

이 요청의 합성 프롬프트3와 파일만 보내며 문서 본문과 모델 응답은 추적에 입력·출력으로 넣지 않아요.

색 블록이 든 열린 수납장과 쓰레기통, 책상 위에 정렬된 블록과 체크리스트 노트
한 trace의 단계별 시간을 비교해 모델과 도구 대기를 구분해요.

용어 각주

  1. API — 프로그램의 기능을 다른 코드에서 호출하기 위한 약속된 인터페이스입니다.

    본문으로 돌아가기
  2. 토큰 — 모델이 입력이나 출력을 나누어 처리하는 단위입니다.

    본문으로 돌아가기
  3. 프롬프트 — 모델에 보내는 입력문입니다. 생성 모델에서는 만들 결과를 설명하는 문장이 되어 출력의 구성과 내용을 크게 좌우합니다.

    본문으로 돌아가기

자주 묻는 질문

이 글에서 가장 먼저 확인할 것은 무엇인가요?
Langfuse는 애플리케이션이 명시적으로 전송한 추적 이벤트를 받아 관찰 화면에 보여 줘요. 로컬 인스턴스와 Python SDK v4를 쓰면 API 주소를 그 인스턴스로 지정하고 `@observe`로 함수 호출을 기록할 수 있어요. Langfuse를 설치했다고 임의의 Ollama 요청이 자동으로 기록되지는 않아요. 계측한 입력·출력에 개인정보나 문서 내용이 포함될 수 있으므로 기록할 필드를 직접 고르고 민감한 값을 마스킹해요.