
이 글에서 다룰 주제
주요 단어 · Langfuse · Ollama · Trace · Span · Generation · Docker Compose
LLM이 답을 돌려줬다는 사실만으로는 애플리케이션의 동작을 충분히 설명하기 어렵다. 어떤 프롬프트가 전달됐는지, 응답에 얼마나 걸렸는지, 여러 단계 중 어디서 문제가 생겼는지를 함께 남겨야 한다.
이번 공부는 외부 유료 LLM API 없이 시작한다. Ollama가 로컬 모델을 실행하고, Python 앱이 그 모델을 호출하며, Langfuse는 그 실행을 관측한다. 첫 글의 목표는 대규모 서비스를 만드는 것이 아니라, 이후 프롬프트 비교와 평가를 반복할 수 있는 작은 실습 환경을 준비하는 것이다.
이전에 정리한 AIOps 에이전트 운영과 Langfuse에서 운영 관점을 살펴봤다면, 이번 글에서는 직접 데이터를 남기는 출발점을 만든다.
Langfuse는 LLM 애플리케이션의 실행, 입력·출력, 모델 호출 등의 관측 데이터를 수집하고 조회하는 도구다. 이 실습에서 답변을 생성하는 모델 서버 역할은 Ollama가 맡는다.
Ollama는 로컬 모델을 내려받아 실행하고 API로 호출할 수 있게 하는 도구다. 이번 모델은
qwen3:8b이며, Python은 Ollama의 OpenAI 호환 API를 호출한다.
Langfuse를 설치했다고 Python 앱의 모든 호출이 저절로 기록되지는 않는다. 앱 코드에 SDK를 붙여 어떤 실행을 기록할지 정해야 한다. 예제는 LLM 호출 전후를 직접 감싸는 방식으로 작성했다. 자동 계측보다 코드가 조금 길지만, 부모 실행과 모델 호출이 어떻게 연결되는지 처음 공부할 때 확인하기 쉽다.
이 글에서 먼저 익힐 용어는 세 가지다.
| 용어 | 뜻 | 이번 예제 |
|---|---|---|
| Trace | 하나의 요청에 속하는 실행 전체 | 질문 하나를 처리한 실행 |
| Span | 실행 안의 일반 작업 구간 | local-ollama-study |
| Generation | 모델 호출을 표현하는 관측 구간 | ollama-chat |
Generation에는 일반 작업 정보에 더해 모델명과 토큰 사용량 같은 LLM 관련 정보를 기록한다. 이번 trace는 루트 span 하나와 그 아래 generation 하나로 시작한다. 개념과 API는 Langfuse 계측 문서를 기준으로 확인했다.

전체 구성도. 파란 화살표는 LLM·UI 요청, 초록 화살표는 관측 데이터 전송이다. 보라색 선은 Web/Worker가 사용하는 공통 저장소의 연결 의존성이며, 저장소 사이의 전달 순서를 뜻하지 않는다.
Langfuse는 web 컨테이너 하나로 끝나지 않는다. 이번 구성은 web, worker, PostgreSQL, ClickHouse, Redis, MinIO의 여섯 서비스를 사용한다.
| 구성요소 | 이 실습의 역할 |
|---|---|
| Langfuse web | 브라우저 UI, API, SDK 데이터 수신 |
| Langfuse worker | 들어온 이벤트의 비동기 처리 |
| PostgreSQL | 사용자·조직·프로젝트 등 트랜잭션 데이터 |
| ClickHouse | trace와 observation 등 분석용 관측 데이터 |
| Redis | 작업 큐와 캐시 |
| MinIO | S3 호환 저장소. 수집 원본 이벤트와 미디어 저장 |
수집 API는 원본 이벤트를 객체 저장소에 두고 처리를 큐에 넣는다. worker가 비동기로 처리한 뒤 관측 데이터를 ClickHouse에 저장하므로, SDK 호출이 끝나는 순간과 UI에서 검색되는 순간 사이에는 차이가 날 수 있다. 저장소별 역할과 이 흐름은 공식 아키텍처 설명에 근거한다.
Apple Silicon에서 Ollama는 Metal을 통한 GPU 가속을 지원한다. 이번에는 이 경로를 사용하도록 Ollama를 macOS에 직접 설치하고, Langfuse 쪽 서비스만 Docker로 실행했다. Python도 호스트에서 실행하므로 모델 주소는 http://127.0.0.1:11434/v1이다. Ollama 하드웨어 지원
여기서 localhost는 호출하는 프로세스가 실행 중인 환경을 가리킨다. 지금 Python 코드를 컨테이너로 옮긴다면 같은 127.0.0.1 주소는 호스트의 Ollama가 아니라 그 컨테이너 자신을 가리키므로 주소 설정을 다시 해야 한다.
2026년 10월 4일에 준비한 환경은 다음과 같다.
| 항목 | 사용 환경 |
|---|---|
| 호스트 | macOS 26.6.2 · Apple M5 Pro · 메모리 64GB |
| Docker Engine / Compose | 29.7.2 / 5.4.0 |
| Docker에 할당된 메모리 | 약 7.75GiB |
| Langfuse web / worker | 4.50.0 |
| Ollama | Homebrew 패키지 0.35.1_1 |
| Python | 3.14.8 |
| Python 주요 패키지 | langfuse 4.16.0 · openai 3.24.0 · httpx 0.28.1 · python-dotenv 1.2.4 |
| 모델 | qwen3:8b |
서버와 SDK의 버전은 서로 다른 제품 버전이다. 둘 다 이름에 Langfuse가 들어간다고 같은 숫자를 맞추는 것은 아니다. 이번 앱은 서버 v4의 observation 조회 API를 사용한다. 버전 업그레이드 시에는 호환성 문서를 함께 확인한다.
qwen3:8b의 모델 페이지는 다운로드 크기 약 5.2GB와 Q4_K_M 양자화를 표시한다. 이 숫자는 실행에 필요한 전체 메모리 크기가 아니다. 모델 가중치 외에 컨텍스트와 실행 버퍼 등도 메모리를 사용한다. Ollama 모델 정보
Docker 메모리 제한은 이번 단일 요청 실습을 위한 설정이다. 운영 환경의 권장 사양이나 처리량을 검증한 결과로 해석하면 안 된다. Compose 환경 자체도 고가용성과 백업을 갖춘 운영 구성이 아니다. 공식 Compose 설치 문서
기존 Homebrew 환경에 Ollama를 설치하고 macOS 서비스로 실행했다.
brew install ollama
brew services start ollama
ollama --version
curl http://127.0.0.1:11434/api/version
ollama pull qwen3:8b
ollama list
첫 다운로드에는 인터넷 연결과 모델 파일을 저장할 공간이 필요하다. 내려받은 모델의 로컬 추론과 모델 다운로드는 서로 다른 작업이다.
이번 실습은 로컬 추론에 집중하기 위해 Ollama 설정 파일 ~/.ollama/server.json에 아래 값을 적용했다. 이미 다른 설정이 있다면 파일 전체를 덮어쓰지 않고 이 항목을 합쳐야 한다. 이번에는 첫 서비스 시작 전에 설정했다. 실행 중인 서비스의 설정을 바꿨다면 brew services restart ollama로 다시 시작한다.
{
"disable_ollama_cloud": true
}
모델이 로딩된 동안 ollama ps를 실행하면 메모리에 올라온 모델과 처리 장치를 확인할 수 있다. 공식 문서에서 100% GPU는 모델이 전부 GPU 메모리에 올라온 상태를 뜻한다. 이번 실행의 ollama ps에서도 100% GPU가 표시됐다. 출력의 모델 메모리 크기는 8.8GB, 컨텍스트 설정은 40,960토큰이었다. 이는 실제로 질문에 40,960토큰을 사용했다는 뜻은 아니다. Ollama FAQ
공식 저장소의 Compose 파일을 출발점으로 사용했다. 실습 파일은 docs/langfuse-study-2026-10-04/lab에 모았다.
lab/
├── compose.yaml
├── upstream-compose.yaml
├── init_env.py
├── .env # 비밀값, 공개하지 않음
├── .venv/
└── app/
├── requirements.txt
├── config.py
├── trace_smoke.py
└── verify_trace.py
주요 변경은 브라우저 주소, 비밀값, 저장소 노출 범위다.
| 설정 | 이번 값과 이유 |
|---|---|
| web 포트 | 127.0.0.1:3300:3000. 호스트 3300에서 컨테이너 3000으로 연결 |
NEXTAUTH_URL | http://localhost:3300. 실제 브라우저 접속 주소와 일치 |
| MinIO 호스트 포트 | 127.0.0.1:9190:9000. 브라우저 미디어 경로에 사용 |
| 내부 MinIO 주소 | http://minio:9000. Docker 서비스 이름으로 접근 |
| DB·Redis·worker 포트 | 호스트에 따로 공개하지 않음 |
CLICKHOUSE_CLUSTER_ENABLED | false. 단일 ClickHouse 컨테이너 사용 |
| 서버 익명 사용 통계 | TELEMETRY_ENABLED=false |
| 영속 데이터 | Compose의 named volume에 보관 |
TELEMETRY_ENABLED=false는 Langfuse 서버의 사용 통계 설정이다. 학습 앱에서 보내는 trace 계측을 끄는 의미로 사용한 것이 아니다.
포트를 바꿀 때 ports만 바꾸면 브라우저 주소와 인증·미디어 URL이 어긋날 수 있다. NEXTAUTH_URL과 미디어 업로드 URL도 함께 맞춰야 한다. 공식 포트 변경 안내
init_env.py는 DB 비밀번호, 암호화 키, API 키, 로컬 사용자 비밀번호를 무작위로 생성해 .env에 저장한다. 파일 권한은 소유자만 읽고 쓸 수 있는 600으로 설정했다. 실제 키와 비밀번호는 글과 스크린샷에 싣지 않는다.
초기 조직은 Local Study, 프로젝트는 Langfuse Local Lab이다. LANGFUSE_INIT_* 환경변수를 이용해 처음 시작할 때 사용자·조직·프로젝트를 만든다. 이는 이 실습이 생성한 계정이며, Langfuse가 제공하는 공통 기본 관리자 비밀번호가 아니다. Headless initialization
다음은 이번에 생성한 로컬 실습 자료를 사용하는 명령이다. 저장소 루트에서 LAB_DIR를 정한 뒤 해당 프로젝트와 Compose 파일을 명시해 실행한다.
LAB_DIR="$PWD/docs/langfuse-study-2026-10-04/lab"
cd "$LAB_DIR"
/opt/homebrew/bin/python3.14 init_env.py
docker compose -p langfuse-study -f "$LAB_DIR/compose.yaml" up -d
docker compose -p langfuse-study -f "$LAB_DIR/compose.yaml" ps
컨테이너가 시작됐다는 사실과 서비스가 준비됐다는 사실은 다르다. 첫 실행에는 DB migration과 초기화가 필요하다. ps에서 의존 저장소의 상태를 확인하고, 문제가 생기면 해당 서비스 로그를 읽는다.
docker compose -p langfuse-study -f "$LAB_DIR/compose.yaml" \
logs --tail=100 langfuse-web langfuse-worker
curl http://localhost:3300/api/public/health
브라우저의 접속 주소는 http://localhost:3300이다. DB 비밀번호나 SDK secret key를 로그인 비밀번호로 넣지 않고, 생성된 로컬 사용자 계정을 사용한다.
앞의 init_env.py, app/trace_smoke.py 등은 이번에 만든 로컬 실습 자료다. 내 작업 폴더가 없는 독자는 별도의 새 폴더에서 공식 파일로 시작할 수 있다. 아래 경로는 같은 버전의 공식 Compose를 가져오는 시작 절차이며, 이번 실측은 앞에서 설명한 수정본에서 수행했다.
mkdir langfuse-reader-lab
cd langfuse-reader-lab
curl -fL \
https://raw.githubusercontent.com/langfuse/langfuse/v4.50.0/docker-compose.yml \
-o compose.yaml
공식 파일에서 # CHANGEME로 표시된 비밀값을 바꾸고 다음 항목을 맞춘다. 임의의 예제 비밀번호를 그대로 사용하는 대신 openssl rand -hex 32 등으로 각 값을 생성한다. 같은 저장소에 연결하는 항목에는 동일한 비밀번호를 넣어야 한다.
| 공식 파일의 위치 | 변경할 값 |
|---|---|
| web / worker의 이미지 | 각각 docker.langfuse.com/langfuse/langfuse:4.50.0, docker.langfuse.com/langfuse/langfuse-worker:4.50.0 |
web의 ports | 127.0.0.1:3300:3000 |
worker 공통 NEXTAUTH_URL | http://localhost:3300 |
MinIO의 ports | 127.0.0.1:9190:9000 |
| web의 미디어 외부 endpoint | http://localhost:9190 |
| worker의 미디어 endpoint | 내부 주소 http://minio:9000 유지 |
| MinIO·S3 비밀번호 | MINIO_ROOT_PASSWORD와 모든 *_SECRET_ACCESS_KEY에 같은 값 |
| PostgreSQL 비밀번호 | POSTGRES_PASSWORD와 DATABASE_URL에 같은 값 |
| ClickHouse 비밀번호 | 서버와 web/worker의 CLICKHOUSE_PASSWORD에 같은 값 |
| Redis 비밀번호 | Redis 명령의 --requirepass와 web/worker REDIS_AUTH에 같은 값 |
| Langfuse 암호화·세션 | SALT, NEXTAUTH_SECRET은 각각 생성, ENCRYPTION_KEY는 32바이트의 64자리 hex |
이 표는 .env만으로 모든 변경이 적용된다는 뜻이 아니다. 이미지와 ports, web의 미디어 endpoint처럼 파일에 적힌 위치를 직접 수정하는 항목도 있다. Compose 설정이 유효한지 확인한 뒤 실행한다.
docker compose -p langfuse-reader-lab -f compose.yaml config --quiet
docker compose -p langfuse-reader-lab -f compose.yaml pull
docker compose -p langfuse-reader-lab -f compose.yaml up -d
docker compose -p langfuse-reader-lab -f compose.yaml ps
처음 접속하면 사용자·조직·프로젝트를 만들고 프로젝트의 API 키를 발급한다. 그 키를 Python 예제용 .env의 LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY에 넣는다. 뒤의 짧은 Python 예제를 first_trace.py로 저장하면 직접 만든 app/ 폴더 없이도 같은 계측 구조를 확인할 수 있다.
공식 Compose의 의존 이미지 일부는 범위 태그를 쓴다. 재현할 버전을 정확히 보존하려면 내려받은 이미지의 digest도 기록·고정해야 한다. 실제 로컬 구성은 여섯 이미지 모두 내려받은 arm64 digest로 고정했고, 이미지 식별자를 lab/images.lock.json에 보관했다. 범위 태그 redis:7이나 latest만 기록한 상태와 구분한다.

빨간 윤곽은 현재 설명하는 계측 영역이다. 모델 요청은 위쪽 Python→Ollama 경로로 나가고, 그 호출을 설명하는 관측 데이터는 아래쪽 Langfuse web으로 전송된다.
별도 가상환경에 고정한 패키지를 설치한다. 아래 명령은 앞에서 준비한 lab 폴더 기준이다. 이 Mac의 기본 python3는 3.9였으므로 이번 실습에서는 Homebrew Python 3.14 경로를 명시했다. 다른 환경에서는 Python 3.10 이상의 실행 경로로 바꾼다.
/opt/homebrew/bin/python3.14 -m venv .venv
.venv/bin/python -m pip install -r app/requirements.txt
.venv/bin/python app/trace_smoke.py
.venv/bin/python app/verify_trace.py
trace_smoke.py는 다음 질문을 로컬 모델에 전달한다.
Langfuse에서 trace, span, generation의 차이를 한국어로 각각 한 문장씩 설명해줘.
OpenAI라는 Python 클라이언트 이름을 사용하지만, 이번 base_url은 Ollama의 로컬 주소다. 클라이언트 이름과 실제 요청 목적지를 구분해야 한다. api_key="ollama"는 OpenAI 호환 클라이언트에 넣는 더미 문자열이며, 유료 OpenAI API 키를 발급할 필요가 없다. Ollama OpenAI 호환 API
전체 스크립트에서 핵심은 모델 호출을 generation으로 감싼 부분이다. 아래는 별도 파일 first_trace.py로 저장해 실행할 수 있는 짧은 예제다. 현재 폴더의 .env에 LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY를 준비한다. 키는 프로젝트 설정에서 발급하며, 이 글의 로컬 프로젝트에는 초기화 때 생성한 키가 들어 있다.
import os
from dotenv import load_dotenv
from langfuse import Langfuse
from openai import OpenAI
load_dotenv(".env")
langfuse = Langfuse(
public_key=os.environ["LANGFUSE_PUBLIC_KEY"],
secret_key=os.environ["LANGFUSE_SECRET_KEY"],
base_url="http://localhost:3300",
)
assert langfuse.auth_check(), "Langfuse 연결과 프로젝트 키를 확인하세요"
prompt = "Langfuse의 trace, span, generation을 각각 한 문장으로 설명해줘."
messages = [{"role": "user", "content": prompt}]
ollama = OpenAI(
base_url="http://127.0.0.1:11434/v1",
api_key="ollama",
)
with langfuse.start_as_current_observation(
as_type="span",
name="local-ollama-study",
input={"question": prompt},
) as root:
trace_id = langfuse.get_current_trace_id()
with langfuse.start_as_current_observation(
as_type="generation",
name="ollama-chat",
model="qwen3:8b",
input=messages,
) as generation:
response = ollama.chat.completions.create(
model="qwen3:8b",
messages=messages,
temperature=0.2,
max_tokens=512,
reasoning_effort="none",
)
answer = response.choices[0].message.content
generation.update(
output=answer,
usage_details={
"input": response.usage.prompt_tokens,
"output": response.usage.completion_tokens,
"total": response.usage.total_tokens,
},
)
root.update(output={"answer": answer})
langfuse.flush()
print(answer)
print(langfuse.get_trace_url(trace_id=trace_id))
langfuse.shutdown()
ollama.close()
짧은 예제만 실행할 때는 다음처럼 의존성을 설치하고 실행한다. 이 예제는 API 재조회 검증을 포함하지 않으므로 출력된 trace 주소에서도 저장 결과를 확인한다.
/opt/homebrew/bin/python3.14 -m venv .venv
.venv/bin/python -m pip install \
langfuse==4.16.0 openai==3.24.0 python-dotenv==1.2.4 httpx==0.28.1
.venv/bin/python first_trace.py
with 블록의 중첩으로 부모 span 아래에 generation을 만든다. Ollama가 반환한 토큰 수를 기록하고, 짧게 실행되는 스크립트가 끝나기 전에 flush()로 쌓인 관측 데이터를 전송한다.
reasoning_effort="none"은 이번 Ollama 예제에서 thinking을 끄고 작은 최종 답변을 받기 위한 설정이다. 모델·제공자마다 지원 범위가 다르므로 모든 OpenAI 호환 서버에 그대로 적용되는 공통 옵션으로 생각하면 안 된다.
모델 답변이 출력되는 것만으로 Langfuse 연동이 완료됐다고 판단하지 않는다. 아래 세 단계를 따로 확인한다.
verify_trace.py는 /api/public/v2/observations를 조회한다. 루트 span과 generation의 ID, 같은 trace에 속하는지, 부모 관계, 실제 입력과 출력, 모델명, 토큰 수, 종료 시각을 비교한다. 비동기 처리 때문에 잠시 조회되지 않을 수 있어 제한된 시간 동안 다시 조회한다. flush()가 끝났다는 사실만으로 서버 저장을 확인했다고 표현하지 않는다.
2026년 10월 4일 23:02 KST에 실제 호출과 저장 재조회를 확인했다. 실행 기록 lab/evidence/trace-smoke.json에서 API 키를 제외한 주요 결과는 다음과 같다.
{
"status": "verified",
"model": "qwen3:8b",
"usage": {
"input": 69,
"output": 67,
"total": 136
},
"request_seconds": 4.382,
"verification": {
"all_passed": true,
"observation_count": 2
}
}
루트 span과 generation 두 건이 조회됐고, 앞서 설명한 12개 검증 항목이 모두 통과했다. request_seconds는 Python에서 모델 요청 전후를 측정한 시간이다. 모델 로딩·요청 처리 등의 영향을 받을 수 있으므로 한 번의 4.382초를 일반적인 성능 수치로 제시하지 않는다. 이 수치는 본문의 짧은 예제가 아니라 system 메시지와 검증 처리를 포함한 app/trace_smoke.py의 실제 실행 결과다.
실제 화면에서 읽기
Tracing에서 첫 실행을 열면 local-ollama-study 아래에 ollama-chat이 보인다. 아래 화면은 로컬 Langfuse에서 직접 캡처한 trace 상단과 트리 영역이다. 합계 136토큰과 약 4.38초가 표시된다.

실제 UI 부분 캡처. Tree에서 ollama-chat을 선택하면 모델 호출 상세로 이동한다.
ollama-chat의 Preview에는 System·User·Assistant가 나뉘어 표시된다. 상단의 qwen3:8b와 136 tokens를 확인하고, 질문과 원본 응답이 스크립트 출력과 같은지 비교한다.

실제 UI 부분 캡처. 데이터나 응답을 고쳐 그린 화면이 아니다. 이 응답의 부정확한 정의는 아래 문단에서 교정한다.
본문의 짧은 first_trace.py도 별도로 실행해 두 번째 trace의 저장과 UI 목록 표시를 확인했다. 위 수치와 캡처는 검증 스크립트로 확인한 첫 실행을 기준으로 한다. 설치를 마친 뒤에는 컨테이너 6개와 Ollama 서비스를 실행한 상태로 두어 바로 다음 실습을 이어갈 수 있게 했다.
여기서 답변 내용도 읽어 볼 필요가 있다. 로컬 모델이 실제로 반환한 답변은 다음과 같았다. 아래 인용은 모델 출력 원문이며, 올바른 정의로 인용한 것이 아니다.
Trace: 작업의 전체 흐름을 나타내는 고유한 식별자입니다.
Span: Trace 내에서 특정 작업 단위를 나타내는 세부적인 기록입니다.
Generation: 모델이 생성한 출력 결과를 나타내는 데이터입니다.
Trace는 식별자 그 자체라기보다 하나의 요청에 속하는 실행을 묶는 단위이고, trace ID는 그 실행을 식별하는 값이다. Generation 역시 출력 데이터만 가리키는 것이 아니라 모델 호출을 나타내는 관측 기록이며 입력·출력·모델·사용량 등을 함께 담는다.
따라서 이번 검증이 확인한 것은 실제 모델 호출의 내용과 구조가 Langfuse에 정확히 저장됐다는 것이다. 답변의 사실 정확성까지 자동으로 보장한 결과는 아니다. 오히려 불완전한 답변을 입력·모델·설정과 함께 다시 볼 수 있게 되었으므로, 이후 데이터셋과 평가를 공부할 구체적인 출발점이 생겼다.
로컬 모델에는 외부 API의 토큰당 청구가 없더라도 전력·하드웨어 비용이 있다. 그래서 예제는 비용을 임의로 0으로 기록하지 않는다. UI에 비용이 비어 있다고 해서 관측 전체가 실패한 것도 아니다.
공부를 멈출 때는 서비스를 중지하고 데이터를 남긴다. 새 터미널에서는 먼저 LAB_DIR를 실제 실습 폴더의 절대경로로 지정한다.
# 앞에서 정한 LAB_DIR 사용
docker compose -p langfuse-study -f "$LAB_DIR/compose.yaml" stop
brew services stop ollama
다음 공부를 시작할 때는 아래 순서로 실행한다.
brew services start ollama
docker compose -p langfuse-study -f "$LAB_DIR/compose.yaml" up -d
cd "$LAB_DIR"
.venv/bin/python app/trace_smoke.py \
--prompt 'LLM 관측성은 왜 필요할까?'
.venv/bin/python app/verify_trace.py
docker compose -p langfuse-study -f "$LAB_DIR/compose.yaml" down은 이 실습의 컨테이너와 네트워크를 정리하지만 named volume은 기본적으로 남긴다. down -v는 저장 데이터도 지우므로, 학습 기록을 유지할 때는 사용하지 않는다. 모델 파일도 서비스 중지와 별개로 남는다. Compose 종료 안내
환경을 준비한 뒤에는 같은 로컬 앱을 확장하면서 다음 순서로 공부할 예정이다.
| 편 | 핵심 질문 | 직접 해볼 일 |
|---|---|---|
| 1. 설치와 첫 기록 | 모델 호출이 실제로 기록되는가? | 로컬 추론·SDK 전송·저장 조회 |
| 2. Trace 읽기 | 한 요청의 어느 단계가 느렸는가? | 여러 span, 오류, session 비교 |
| 3. 프롬프트 관리 | 어떤 프롬프트를 사용했는가? | 프롬프트 버전과 실행 연결 |
| 4. 데이터셋과 평가 | 변경한 답변이 더 나아졌는가? | 작은 데이터셋·점수·실험 비교 |
| 5. 운영 관점 | 지속적으로 무엇을 관리해야 하는가? | 민감 정보, 보존, 백업, 용량 확인 |
첫 연습은 질문을 바꿔 두 번 실행한 뒤, trace 전체 시간과 generation 시간, 입력·출력 토큰이 각각 무엇을 설명하는지 비교하는 것이다. 아직 모델 성능 순위를 매기기보다 기록의 의미와 관측 범위를 이해하는 데 집중한다.
공식 문서 확인일: 2026년 10월 4일. 실행 환경의 버전은 위 표를 기준으로 한다. 문서의 변경과 재설치 시 선택되는 버전은 별도로 확인해야 한다.
구조도는 이 실습 구성에 맞춰 직접 제작했다. Langfuse·Docker·Python·ClickHouse·MinIO 로고는 각 공식 배포 자산을 제품 식별에 사용했고, 다른 제품의 후원·인증을 의미하지 않는다. PostgreSQL·Redis·Ollama는 일반 역할 기호와 이름으로 표시했다. MinIO is a trademark of the MinIO Corporation. Python 및 Python 로고는 Python Software Foundation의 상표다.