−25%

Windows 연간 결제, 10월 31일까지. 요금제 보기

EQVPS
시작하기

Langfuse용 VPS: AI 에이전트가 무엇을 했는지 확인

Langfuse를 직접 호스팅해 무인 에이전트의 모든 LLM 호출과 도구 실행 단계를 추적하세요. 검증된 Docker Compose, 실제 RAM 수치, 알맞은 요금제.

새벽 3시에 아무도 보지 않는 동안 일하는 에이전트의 가치는, 나중에 그것이 무엇을 했는지 재구성할 수 있는 능력만큼입니다. "밤새 토큰으로 38 $를 태웠다"는 나쁜 아침입니다. "검색 도구가 빈 페이지를 돌려줬고 플래너가 400번 재시도해서 38 $를 태웠다"는 점심 전에 고칠 수 있는 버그입니다. 두 번째 문장을 쓰려면 트레이스가 있어야 합니다.

Langfuse는 모든 LLM 호출, 프롬프트, 도구 실행 단계, 토큰 수, 지연 시간을 클릭해서 따라갈 수 있는 트리로 기록합니다. 직접 호스팅하면 고객 데이터, API 출력, 가끔은 잘못 섞여 든 비밀값까지 담긴 프롬프트와 응답이 남의 대시보드가 아닌 내가 관리하는 서버에 남습니다.

운영 비용

Langfuse v4는 작은 바이너리 하나가 아니라 6개의 컨테이너입니다. 웹 앱, 백그라운드 worker, Postgres, 이벤트용 ClickHouse, Redis, 파일용 MinIO입니다. 테스트 서버에 설치해 보니 빈 프로젝트에서 약 3.5 GB RAM을 쓰고 있었습니다. 커지는 쪽은 ClickHouse로, 보내는 span이 모두 그곳에 쌓입니다.

부하요금제
에이전트 몇 개, 몇 주 치 트레이스Medium-IP: 6 vCPU, 6 GB, 45 GB (월 $20)
에이전트 무리, 몇 달 치 기록Pro 요금제, RAM 32 GB부터 — 문의

더 작은 요금제에도 설치는 되지만, ClickHouse와 worker가 동시에 메모리를 원하는 순간부터 버거워합니다. 저라면 6 GB 아래로는 내려가지 않겠습니다.

에이전트는 어디에 있나요? 다른 머신에서 실행된다면 전용 IPv4가 있는 요금제를 고르세요. 에이전트에는 HTTPS 엔드포인트가 필요한데, NAT 요금제에서는 나가는 주소가 내 것이 아니고 외부에서는 SSH 포트만 접속됩니다. 에이전트가 바로 이 서버에서 실행된다면 Langfuse를 인터넷에 노출할 필요가 전혀 없습니다. 시험용이라면 NAT Medium(월 $12)으로 충분합니다. 위치는 독일과 핀란드 두 곳이며, 사용 가능 여부는 주문할 때 표시됩니다. 내가 아니라 에이전트에 가까운 곳을 고르세요. 서버 요금은 암호화폐로 결제하며 KYC는 없습니다.

설치

새로 만든 Ubuntu 24.04 또는 Debian 12 서버에서 root로 진행합니다. 먼저 Docker:

curl -fsSL https://get.docker.com | sh

다음은 Langfuse입니다. compose 파일의 기본값 대신 실제 비밀값을 씁니다:

git clone --depth 1 https://github.com/langfuse/langfuse.git
cd langfuse

PG=$(openssl rand -hex 16); MINIO=$(openssl rand -hex 16)
cat > .env <<EOF
NEXTAUTH_URL=https://langfuse.example.com
NEXTAUTH_SECRET=$(openssl rand -hex 32)
SALT=$(openssl rand -hex 32)
ENCRYPTION_KEY=$(openssl rand -hex 32)
POSTGRES_PASSWORD=$PG
DATABASE_URL=postgresql://postgres:$PG@postgres:5432/postgres
CLICKHOUSE_PASSWORD=$(openssl rand -hex 16)
MINIO_ROOT_PASSWORD=$MINIO
LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY=$MINIO
LANGFUSE_S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY=$MINIO
LANGFUSE_S3_BATCH_EXPORT_SECRET_ACCESS_KEY=$MINIO
REDIS_AUTH=$(openssl rand -hex 16)
TELEMETRY_ENABLED=false
EOF
chmod 600 .env

이 중 두 비밀번호는 짝이 있습니다. Postgres 비밀번호는 DATABASE_URL 안에도 들어가고, MinIO 비밀번호는 S3_..._SECRET_ACCESS_KEY 세 줄과 같아야 합니다. 그래서 각각을 하나의 변수에서 가져옵니다.

이제 함정입니다. compose 파일은 웹 앱을 3000번, MinIO를 9090번 포트로 모든 인터페이스에 공개하고, Docker가 공개한 포트는 ufw를 우회합니다. 둘 다 localhost에 묶어 리버스 프록시만 입구로 남기세요:

sed -i 's/- 3000:3000/- 127.0.0.1:3000:3000/; s/- 9090:9000/- 127.0.0.1:9090:9000/' docker-compose.yml
docker compose up -d
curl -s http://127.0.0.1:3000/api/public/health

마지막 명령은 {"status":"OK", ...}를 출력해야 합니다. 첫 실행 때 데이터베이스 마이그레이션이 돌아가며, 저희 테스트에서는 컨테이너가 뜬 지 약 15초 뒤에 헬스 체크가 통과했습니다.

앞단에 HTTPS

langfuse.example.com을 서버 IP로 지정한 다음:

apt install -y caddy
cat > /etc/caddy/Caddyfile <<'EOF'
langfuse.example.com {
    reverse_proxy 127.0.0.1:3000
}
EOF
systemctl reload caddy
ufw allow 22/tcp && ufw allow 80/tcp && ufw allow 443/tcp && ufw enable

인증서는 Caddy가 알아서 받습니다. 사이트를 열고 계정을 만든 뒤(첫 조직이 됩니다) 프로젝트를 추가하고, 그 공개 키와 비밀 키를 복사하세요.

그다음 문을 닫아 두세요. Langfuse는 AUTH_DISABLE_SIGNUP을 이해하지만 기본 compose 파일은 이를 web 컨테이너에 넘기지 않으므로 langfuse-web 아래에 한 줄이 더 필요합니다:

sed -i 's|^      NEXTAUTH_SECRET: \(.*\)$|      NEXTAUTH_SECRET: \1\n      AUTH_DISABLE_SIGNUP: ${AUTH_DISABLE_SIGNUP:-false}|' docker-compose.yml
echo "AUTH_DISABLE_SIGNUP=true" >> .env
docker compose up -d

이제부터 가입 시도에는 «Sign up is disabled»가 돌아갑니다. 동료는 프로젝트 안에서 추가하세요.

에이전트에서 트레이스 보내기

Python SDK는 함수를 감싸고, 중첩된 호출은 중첩된 span이 됩니다:

python3 -m venv venv && . venv/bin/activate
pip install langfuse
export LANGFUSE_PUBLIC_KEY=pk-lf-...
export LANGFUSE_SECRET_KEY=sk-lf-...
export LANGFUSE_BASE_URL=https://langfuse.example.com
from langfuse import get_client, observe

langfuse = get_client()  # LANGFUSE_* 변수를 읽음

@observe(name="fetch-prices")
def fetch_prices(pair: str) -> dict:
    return {"pair": pair, "bid": 64210.5}

@observe(name="nightly-agent-run")
def run() -> str:
    data = fetch_prices("BTC/USDT")
    return f"done: {data['pair']}"

print(run())
langfuse.flush()  # 짧은 스크립트는 백그라운드 전송이 끝나기 전에 종료됨

LANGFUSE_BASE_URL을 건너뛰지 마세요. 이 변수가 없으면 SDK는 조용히 모든 것을 Langfuse 클라우드로 보내고, 그곳에는 내 키가 없으니 빈 대시보드만 보게 됩니다.

터미널에서 span이 도착했는지 확인하려면:

curl -s -u "$LANGFUSE_PUBLIC_KEY:$LANGFUSE_SECRET_KEY" \
  "$LANGFUSE_BASE_URL/api/public/v2/observations?limit=5"

v4에서는 예전 엔드포인트 /api/public/traces가 events-only 모드에 관한 오류로 응답합니다. 예상된 동작이며 설치가 잘못된 것이 아닙니다. 실제 에이전트에서도 LLM 호출과 각 도구를 같은 방식으로 감쌉니다. 또 Langfuse에는 널리 쓰이는 LLM SDK와 에이전트 프레임워크용 통합이 있어서, 곳곳에 데코레이터를 붙이는 대신 import 한 줄만 바꾸면 되는 경우가 많습니다.

지켜볼 것

  • 디스크. ClickHouse와 MinIO는 보낸 모든 것을 보관합니다. 공간이 어디에 쓰였는지는 docker system df -v로 볼 수 있습니다. 긴 프롬프트와 응답을 트레이스하면 Medium-IP의 45 GB는 몇 년이 아니라 몇 주 만에 찹니다. 한 달에 한 번 확인하고, 부족해지면 400 GB 이상의 Pro 요금제를 문의하세요.
  • 업데이트. compose 파일은 메이저 버전(:4)을 고정합니다. docker compose pull && docker compose up -d로 그 안의 수정 사항을 받습니다. 메이저 버전을 바꾸기 전에는 changelog를 읽으세요. 트레이스 엔드포인트가 사라진 것도 바로 v4였습니다.
  • 백업. 중요한 것은 Docker 볼륨에 있습니다. Postgres에는 사용자, 프로젝트, 키가, ClickHouse와 MinIO에는 트레이스 자체가 있습니다. 일정에 따라 서버 밖으로 복사하세요.

월 $20의 가치가 있을까요? 에이전트가 토큰에 그보다 많이 쓴다면(무인 에이전트는 대부분 그렇습니다), 토큰이 어디로 갔는지 아는 것은 루프가 처음 폭주하는 날 바로 본전을 뽑습니다. 하루 한 번 도는 작은 에이전트에는 이 중 어느 것도 필요 없습니다. 로그 파일과 토큰 카운터면 충분합니다.

관련 글

배포할 준비가 되셨나요? 암호화폐로 결제, KYC 없음 — 약 1분 만에 온라인.

지금 배포 →

FAQ

직접 호스팅한 Langfuse에는 RAM이 얼마나 필요한가요?

저희 테스트 서버에서 Langfuse v4는 web, worker, Postgres, ClickHouse, Redis, MinIO의 6개 컨테이너로 실행됐고, 빈 프로젝트 기준 약 3.5 GB RAM을 사용했습니다. ClickHouse는 보내는 span마다 커집니다. 에이전트 몇 개라면 Medium-IP(RAM 6 GB, 디스크 45 GB)로 여유 있게 돌아가고, 몇 달 치 기록을 가진 에이전트 무리 전체에는 Pro 요금제가 필요하며 이는 문의 시 제공됩니다.

Langfuse에 전용 IP 주소가 필요한가요?

에이전트가 다른 곳에서 실행되며 인터넷으로 트레이스를 보낼 때만 필요합니다. 에이전트에는 HTTPS 엔드포인트가 있어야 하는데, NAT 요금제는 외부에서 SSH 포트만 받습니다. 에이전트가 같은 서버에 있다면 Langfuse는 localhost에 두고 대시보드는 SSH 터널로 열면 됩니다. 이 경우 NAT Medium 요금제로 충분합니다.

코드는 실행되는데 대시보드가 비어 있습니다. 왜 그런가요?

거의 항상 LANGFUSE_BASE_URL이 빠져 있습니다. 이 변수가 없으면 SDK가 모든 데이터를 Langfuse 자체 클라우드로 보내는데, 직접 호스팅한 키는 그곳에 없으므로 내 서버에는 아무것도 도착하지 않습니다. 변수에 내 주소를 넣으세요.

/api/public/traces 엔드포인트가 오류를 반환합니다. 설치가 잘못됐나요?

아닙니다. Langfuse v4는 events-only 모드로 동작하며, 이 모드에서는 해당 엔드포인트가 꺼져 있습니다. 데이터는 /api/public/v2/observations로 읽으세요. 저희도 이 호출로 테스트 span이 도착했는지 확인했습니다.

낯선 사람이 내 인스턴스에 가입하지 못하게 하려면?

Langfuse는 AUTH_DISABLE_SIGNUP을 읽지만, 기본 docker-compose.yml은 이 변수를 web 컨테이너에 전달하지 않아서 .env에만 적어서는 효과가 없습니다. langfuse-web의 environment에 한 줄을 추가하고(명령은 아래에 있습니다), 내 계정을 만든 뒤 true로 바꾸면 이후 가입 시도에는 «Sign up is disabled»가 반환됩니다.

댓글

아직 댓글이 없습니다. 첫 번째가 되세요.

댓글 남기기

댓글은 표시되기 전에 검토됩니다.