프로덕션에 에이전트를 올리고 나면 반드시 마주치는 상황이 있습니다. 사용자가 "AI 답변이 이상해요"라고 신고하는데, 왜 틀렸는지 알 방법이 없는 겁니다. RAG가 잘못된 청크를 가져온 건지, 프롬프트 템플릿이 문제인지, 툴 호출이 실패한 건지 — 로그만 봐서는 모릅니다. LLM Observability가 필요한 이유가 바로 여기 있고, 2026년 기준 가장 많이 쓰이는 두 선택지가 LangSmith와 Langfuse입니다.
핵심 요약
두 플랫폼이 해결하는 문제는 같습니다. LLM 애플리케이션에서 각 단계를 트레이싱해서 어디서 무슨 일이 일어났는지 볼 수 있게 해주는 것입니다. RAG 파이프라인이라면 리트리버가 어떤 청크를 가져왔는지, 임베딩 단계에서 얼마나 걸렸는지, 최종 LLM 호출에서 어떤 프롬프트가 들어갔는지 전부 추적할 수 있습니다.
차이는 철학에서 나옵니다. LangSmith는 LangChain 팀이 만든 상용 SaaS로, LangChain과 LangGraph를 쓰면 환경변수 하나로 트레이싱이 자동 설정됩니다. Langfuse는 MIT 오픈소스로 자체 호스팅이 가능하고, OpenTelemetry 기반이라 어떤 프레임워크든 연동됩니다. 2026년 1월 ClickHouse에 인수됐지만 오픈소스 유지가 공식 확인됐습니다.
결정 기준을 단순하게 정리하면 이렇습니다. LangChain이나 LangGraph 올인 환경이면 LangSmith가 맞고, 멀티 프레임워크 환경이거나 코드와 프롬프트를 외부로 보내기 꺼려지거나 비용이 중요하면 Langfuse가 맞습니다.
비용 차이는 스케일에서 확연합니다. 월 100만 트레이스 기준으로 LangSmith Cloud는 약 $2,500 이상인 반면, Langfuse Cloud는 약 $919, 자체 호스팅 Langfuse는 인프라 비용만 약 $150입니다. 5인 팀 기준 LangSmith Plus는 좌석당 과금이라 월 $195부터 시작하고, Langfuse는 사용자 수와 무관하게 유닛 단위로 과금합니다.
실전 1: LangSmith 연동
LangChain을 쓰고 있다면 LangSmith 연동은 환경변수 두 개로 끝납니다. 별도 코드 추가 없이 기존 LangChain 코드가 자동으로 트레이싱됩니다. LangGraph까지 쓴다면 LangGraph Studio에서 그래프 실행을 시각적으로 따라갈 수 있습니다.
LangSmith를 시작하려면 smith.langchain.com에서 계정을 만들고 API 키를 받으면 됩니다. 무료 플랜에서 월 5,000 트레이스까지 사용할 수 있습니다.
import os
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
# LangSmith 활성화 — 이 두 줄이 전부
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_API_KEY"] = "ls__your_api_key"
os.environ["LANGCHAIN_PROJECT"] = "my-rag-agent" # 프로젝트 이름
# 기존 LangChain 코드 그대로 — 자동 트레이싱됨
llm = ChatOpenAI(model="gpt-4o")
prompt = ChatPromptTemplate.from_template("다음 질문에 답해줘: {question}")
chain = prompt | llm | StrOutputParser()
# 이 호출이 자동으로 LangSmith에 트레이싱됨
result = chain.invoke({"question": "LLM Observability가 뭐야?"})
print(result)
LangSmith의 핵심 강점은 @traceable 데코레이터입니다. LangChain을 안 써도 커스텀 함수를 트레이싱할 수 있고, 트레이스 UI에서 함수별로 입출력과 지연 시간을 나란히 볼 수 있습니다.
from langsmith import traceable
@traceable(name="retrieve_documents")
def retrieve(query: str) -> list[str]:
"""이 함수가 LangSmith에서 별도 스팬으로 추적됨"""
# 벡터 DB 검색 로직
return ["관련 문서 1", "관련 문서 2"]
@traceable(name="generate_answer")
def generate(question: str, docs: list[str]) -> str:
context = "\n".join(docs)
response = llm.invoke(f"Context: {context}\nQuestion: {question}")
return response.content
@traceable(name="rag_pipeline")
def rag(question: str) -> str:
"""전체 파이프라인이 하나의 트레이스로 묶임"""
docs = retrieve(question)
return generate(question, docs)
answer = rag("프로덕션 에이전트 모니터링 방법은?")
LangSmith 대시보드에서 rag_pipeline 트레이스를 열면 retrieve_documents → generate_answer 순서로 계층적으로 펼쳐지고, 각 단계의 입출력과 토큰 비용이 보입니다.
실전 2: Langfuse 연동
Langfuse는 세 가지 방법으로 시작할 수 있습니다. Langfuse Cloud 무료 플랜(월 50K 유닛), Docker로 자체 호스팅, 그리고 OpenTelemetry 방식입니다. 민감한 코드베이스라면 자체 호스팅을 권장합니다.
Cloud를 쓴다면 cloud.langfuse.com에서 프로젝트를 만들고 Public Key와 Secret Key를 받습니다. 자체 호스팅은 아래 Docker Compose로 30분이면 됩니다.
# 자체 호스팅 (Docker Compose)
git clone https://github.com/langfuse/langfuse.git
cd langfuse
cp .env.example .env
# .env에서 DATABASE_URL, NEXTAUTH_SECRET, SALT 설정
docker compose up -d
# http://localhost:3000 에서 접속
Python SDK로 연동하는 기본 방법입니다. LangChain을 쓰면 LangSmith처럼 자동 트레이싱이 되고, 다른 프레임워크는 수동으로 스팬을 추가합니다.
from langfuse import Langfuse
from langfuse.decorators import observe, langfuse_context
import os
# Langfuse 초기화
langfuse = Langfuse(
public_key=os.getenv("LANGFUSE_PUBLIC_KEY"),
secret_key=os.getenv("LANGFUSE_SECRET_KEY"),
host="https://cloud.langfuse.com" # 자체 호스팅이면 http://localhost:3000
)
# @observe 데코레이터로 함수 트레이싱
@observe()
def retrieve_docs(query: str) -> list[str]:
# 벡터 DB 검색
results = ["문서1", "문서2", "문서3"]
# 검색 메타데이터를 스팬에 추가
langfuse_context.update_current_observation(
metadata={"query": query, "results_count": len(results)}
)
return results
@observe()
def call_llm(prompt: str) -> str:
from openai import OpenAI
client = OpenAI()
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": prompt}]
)
output = response.choices[0].message.content
# 토큰 사용량 직접 기록
langfuse_context.update_current_observation(
usage={
"input": response.usage.prompt_tokens,
"output": response.usage.completion_tokens
}
)
return output
@observe(name="rag_pipeline")
def rag_pipeline(question: str) -> str:
docs = retrieve_docs(question)
context = "\n".join(docs)
prompt = f"다음 정보를 참고해서 질문에 답해줘:\n{context}\n\n질문: {question}"
return call_llm(prompt)
# 실행 — 자동으로 Langfuse에 트레이스 전송
result = rag_pipeline("LangSmith와 Langfuse 차이는?")
langfuse.flush() # 비동기 전송 완료 보장
실전 3: LangChain 연동 — LangSmith vs Langfuse 나란히
둘 다 LangChain 자동 트레이싱을 지원합니다. LangSmith는 환경변수 두 줄, Langfuse는 CallbackHandler 한 줄을 체인에 붙입니다.
# LangSmith — 환경변수만 설정하면 자동
import os
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_API_KEY"] = "ls__..."
os.environ["LANGCHAIN_PROJECT"] = "production-agent"
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
chain = ChatPromptTemplate.from_template("{input}") | ChatOpenAI()
chain.invoke({"input": "테스트"}) # 자동 트레이싱
# ─────────────────────────────────────────────────
# Langfuse — CallbackHandler를 체인에 주입
from langfuse.callback import CallbackHandler
langfuse_handler = CallbackHandler(
public_key="pk-lf-...",
secret_key="sk-lf-...",
host="https://cloud.langfuse.com"
)
chain = ChatPromptTemplate.from_template("{input}") | ChatOpenAI()
chain.invoke(
{"input": "테스트"},
config={"callbacks": [langfuse_handler]} # 핸들러 주입
)
LangSmith는 코드 변경이 없다는 점이 확실한 장점입니다. Langfuse는 한 줄이 추가되지만, 그 대신 LangChain 없이도 동일한 방식으로 어떤 프레임워크든 연동됩니다.
실전 4: 평가(Eval) 기능 비교
트레이싱만큼 중요한 게 출력 품질 평가입니다. 에이전트가 "맞는 답"을 내고 있는지 자동으로 점수를 매기는 기능으로, 두 플랫폼 모두 LLM-as-a-Judge 방식을 지원합니다.
LangSmith는 Evaluator가 더 완성도 높고, 데이터셋을 만들어 회귀 테스트를 돌리는 워크플로우가 잘 정리돼 있습니다. Langfuse는 스코어링 primitives를 제공하지만 평가 파이프라인은 직접 조립해야 합니다.
# LangSmith — 빌트인 Evaluator
from langsmith.evaluation import evaluate, LangChainStringEvaluator
evaluator = LangChainStringEvaluator("criteria", config={
"criteria": "helpfulness"
})
results = evaluate(
rag_pipeline,
data="my-test-dataset", # LangSmith에 미리 만들어둔 데이터셋
evaluators=[evaluator],
experiment_prefix="v1.2-prompt-change"
)
# ─────────────────────────────────────────────────
# Langfuse — 커스텀 스코어 직접 기록
from langfuse import Langfuse
langfuse = Langfuse()
# 트레이스 실행 후 스코어 붙이기
trace = langfuse.trace(name="eval-run")
span = trace.span(name="generation")
span.end(output=result)
# LLM-as-a-Judge로 점수 계산 후 기록
quality_score = judge_output_quality(result) # 커스텀 함수
langfuse.score(
trace_id=trace.id,
name="quality",
value=quality_score,
comment="LLM-as-a-Judge 결과"
)
어떤 팀이 무엇을 써야 하나
두 플랫폼을 정리하면 이렇습니다. LangSmith는 LangChain·LangGraph 올인 팀에게 최선입니다. 설정이 거의 없고, Prompt Hub와 LangGraph Studio 통합이 실제로 편하며, 평가 워크플로우가 가장 완성도 높습니다. 단점은 자체 호스팅이 엔터프라이즈 계약이 필요하고, 좌석당 과금이라 팀 규모가 커질수록 비용이 빠르게 올라갑니다.
Langfuse는 LangChain을 안 쓰거나 여러 프레임워크를 섞어 쓰는 팀에게 맞습니다. 오픈소스 자체 호스팅으로 프롬프트와 출력을 외부로 보내지 않을 수 있고, 스케일에서 비용 차이가 결정적입니다. 단점은 평가 파이프라인을 직접 구성해야 하고, LangSmith만큼 완성된 UI를 기대하면 실망할 수 있습니다.
둘 다 아닌 세 번째 선택지도 있습니다. Arize Phoenix는 오픈소스에 RAG 평가에 강하고, Braintrust는 CI/CD 파이프라인에 품질 게이트를 붙이는 데 특화됐습니다. LLM Observability 생태계 자체가 빠르게 성숙하고 있어서 선택지는 늘어나는 중입니다.
마무리
LLM Observability는 이제 선택이 아닙니다. 에이전트를 프로덕션에 올리는 순간, "왜 틀렸냐"는 질문을 받게 되고, 트레이스 없이는 그 질문에 답할 방법이 없습니다. LangSmith와 Langfuse 중 뭘 쓸지 고민하는 시간보다, 지금 당장 둘 중 하나를 연동하는 게 낫습니다. LangChain을 이미 쓰고 있으면 LangSmith 무료 플랜으로 시작하고, 그 외라면 Langfuse 자체 호스팅으로 시작하는 게 현실적입니다. 트레이스를 한 번이라도 열어보고 나면 없이는 못 돌아갑니다.
'AI Agent' 카테고리의 다른 글
| LangGraph로 프로덕션 AI 에이전트 만들기 실전 튜토리얼 (0) | 2026.06.23 |
|---|---|
| smolagents 완전 가이드 — 1,000줄 Python으로 에이전트 만드는 법 (0) | 2026.06.15 |
| "계획 먼저, 실행 나중" — Deep Research + Antigravity로 Plan-and-Execute 에이전트 만들기 (0) | 2026.06.12 |
| n8n AI 에이전트 워크플로우 실전 — 코드 없이 에이전트 만드는 법 (0) | 2026.06.10 |
| AI 에이전트 거버넌스 — Workday·OWASP·NIST가 그리는 안전한 에이전트 기준 (0) | 2026.06.05 |