왜 우리는 프로덕션에서 LangChain을 원시 Anthropic SDK로 교체했는가
Source: Dev.to

증상
LangChain의 추상화는 우리가 정상 경로 데모를 넘어섰을 때부터 누수되기 시작했습니다. 세 가지 문제가 계속 우리를 괴롭혔습니다:
지옥 같은 스택 트레이스. 단일 AgentExecutor.invoke() 호출이 우리 코드에 도달하기까지 LangChain 내부를 14개의 프레임을 가로질렀습니다. 형식이 잘못된 툴 호출을 디버깅하는 것은 고고학을 하는 듯했습니다.
버전 변동. 모든 사소한 업데이트마다 우리가 의존하던 것이 이름이 바뀌거나, 위치가 이동하거나, 폐기되었습니다. 우리의 CI는 초록색을 유지하기 위해 6개월 동안 특정 LangChain SHA에 고정되었습니다.
추상화된 관측성. 내부 클래스를 몽키패치하지 않으면 토큰 사용량, 캐시 적중률, 툴별 지연 시간을 깔끔하게 추적할 수 없었습니다.
한편, Anthropic의 네이티브 SDK는 점점 더 좋아지고 있었습니다. 네이티브 툴 호출, 프롬프트 캐싱, 확장된 사고, 스트리밍 — 모두 일류 기능이며 문서화되어 있었습니다.
리팩터링
우리가 LangChain을 사용하던 로직은 복잡하지 않았습니다:
- 템플릿에서 시스템 프롬프트를 구축한다
- 도구 목록과 함께 Claude를 호출한다
- 도구 호출을 내부 핸들러로 라우팅한다
- 결과를 반환한다
우리는 약 800줄에 달하던 LangChain 코드를 다음과 같이 교체했습니다:
from anthropic import Anthropic
client = Anthropic()
def run_agent(user_input: str, tools: list[dict], tool_handlers: dict):
messages = [{"role": "user", "content": user_input}]
while True:
response = client.messages.create(
model="claude-opus-4-7",
max_tokens=4096,
tools=tools,
messages=messages,
system=SYSTEM_PROMPT,
)
if response.stop_reason == "end_turn":
return response.content[0].text
# Handle tool use
tool_calls = [b for b in response.content if b.type == "tool_use"]
messages.append({"role": "assistant", "content": response.content})
tool_results = []
for call in tool_calls:
result = tool_handlers[call.name](**call.input)
tool_results.append({
"type": "tool_result",
"tool_use_id": call.id,
"content": str(result),
})
messages.append({"role": "user", "content": tool_results})
그게 전부입니다. AgentExecutor도 없고, Callback도 없으며, ConversationBufferMemory도 없습니다. 모델과 우리의 코드만 있습니다.
메트릭
Vettio의 인터뷰‑봇 서비스에서 기존 경로와 새로운 경로를 2주 동안 병행 테스트했습니다. 결과:
- p50 지연 시간: 2.1 s → 1.4 s (‑33%)
- p95 지연 시간: 4.8 s → 3.2 s (‑33%)
- 오류율: 0.9 % → 0.2 %
- 오류 시 스택 트레이스 깊이: 14 → 4 프레임
- 통합 코드 라인 수: 812 → 187
지연 시간 감소는 주로 도구 사용 불일치 시 LangChain의 암묵적인 재시도‑재시도‑재시도 동작을 제거했기 때문입니다. 직접 SDK 호출을 사용하면, 잘못된 도구 스키마가 조용히 세 번 재시도하는 대신 크게 오류를 발생시킵니다.
LangChain이 아직도 의미가 있을 때
이 글은 “LangChain을 절대 사용하지 말라”는 전면적인 금지 글이 아닙니다. 다음과 같은 경우에 여전히 유리합니다:
- 다중 제공자 추상화. 안정적인 인터페이스 뒤에서 Claude, GPT‑4, Gemini을 자유롭게 전환하고 싶을 때.
- LangGraph 워크플로 그래프 기반 에이전트 토폴로지를 처음부터 직접 구축하지 않고도 사용하고 싶을 때.
- LangSmith 가시성을 직접 다시 만들고 싶지 않을 때.
이미 한 제공자에 전념하고(우리는 Claude에 전적으로 몰두함) 프롬프트, 도구 스키마, 가시성을 완전히 제어하고자 하는 팀이라면—2026년 현재 네이티브 SDK가 적합한 도구입니다.
교훈
Abstractions pay for themselves when the underlying APIs are bad. Anthropic’s API isn’t bad. It’s clean, well‑documented, and stable. The abstraction tax was real; the abstraction benefit had quietly evaporated.
If you’re still on LangChain in a production Claude app, benchmark a direct‑SDK rewrite of your hot path. You might be surprised.