2년 넘게 LangChain에서 OpenRouter에 연결하는 표준적인 방법은 한 줄짜리 편법이었습니다. ChatOpenAI가 OpenRouter의 base URL을 보게 해두고 넘어가는 방식이었죠. 이 방식은 퍼져 나갈 만큼은 잘 작동했지만, 동시에 추적 데이터를 조용히 망가뜨릴 만큼은 충분히 나빴습니다.
base_url 덮어쓰기가 텔레메트리를 왜곡한 이유
base_url 덮어쓰기는 요청을 OpenRouter로 보내기는 했지만, 누가 응답했는지에 대해서는 거짓말을 했습니다. ChatOpenAI(base_url='https://openrouter.ai/api/v1')라는 패턴은 OpenAI 클라이언트를 다른 게이트웨이에 재사용했기 때문에, 실제로 어떤 백엔드가 호출을 처리했는지와 상관없이 LangChain은 제공자를 OpenAI로 기록했습니다. LangChain의 자체 발표(GitHub Discussion #35672, 2026년 3월)는 추적에서 발생하는 두 가지 핵심 실패 모드를 "response-schema mismatches and misattributed provider identity"라고 짚었습니다 .
이 편법이 살아남은 이유는 쉬운 경로에서는 문제가 없었기 때문입니다. 일반 텍스트 완성은 정상적으로 오갔고, 그래서 많은 튜토리얼이 이 방식을 그대로 실었습니다. 하지만 OpenRouter에 특화된 모든 것에서는 조용히 깨졌습니다. reasoning content, session IDs, routing metadata가 누락되거나 망가졌는데, OpenAI 응답 스키마에는 애초에 이런 값을 담을 자리가 없었기 때문입니다 . 답변은 받았지만, 비용과 지연 시간, 요청이 어떤 모델로 라우팅됐는지 감사하는 데 필요한 필드는 받지 못한 셈입니다.
"[The dedicated package] solves this with a dedicated integration built on the official OpenRouter Python SDK," — LangChain 팀, 통합 발표 (source: GitHub Discussion #35672).
이 편법이 퍼진 더 깊은 이유는 공식적으로 권장할 만한 대안이 없었기 때문입니다. 이전의 유일한 시도였던 langchain-openrouter 0.0.1은 2024년 2월에 배포됐지만 오래된 패키지로 간주되어 yanked 처리됐습니다 . 실제 first-party 패키지는 2026년 3월 4일 0.1.0이 나오고서야 등장했습니다 . 일단 출시된 뒤에는 유지보수가 빠르게 진행됐습니다. 0.1.0 → 0.2.0 → 0.2.1 → 0.2.2 → 0.2.3 → 0.2.4까지, 네 달도 안 되어 여섯 번 릴리스됐고 0.2.4는 2026년 6월 23일에 배포됐습니다 . 이 릴리스 속도가 진짜 신호입니다. 이제 멀티 제공자 라우팅은 프레임워크가 유지보수하는 공식 표면이 되었고, base_url 편법은 공식적으로 낡은 방식이 됐습니다.
0.2.4 자세히 보기

2026년 6월 23일 릴리스는 재설계가 아니라 점진적 업데이트입니다. 하지만 그중 세 가지 변경은 에이전트 코드에 직접적인 영향을 줍니다. 가장 눈에 띄는 차이는 기반 openrouter Python SDK의 최소 버전을 >=0.9.2로 올리고, 이전 빌드에 들어 있던 파일 기반 우회 코드를 삭제한 것입니다 . 프로젝트에서 그 우회 코드를 명시적으로 고정하거나 vendoring했다면 제거해야 합니다. 그대로 두면 새 설치와 충돌할 수 있습니다.
기능적으로 가장 중요한 추가 사항은 이제 parallel_tool_calls가 bind_tools()에 노출된다는 점입니다 . 이전에는 이 값이 빠져 있었기 때문에, 한 턴에서 여러 도구 호출을 펼치는 에이전트 워크로드는 기반 모델이 병렬 처리를 지원하더라도 순차 실행으로 되돌아갔습니다. 멀티 도구 에이전트를 운영한다면, 이 플래그 하나가 왕복 한 번과 여러 번의 차이를 만듭니다.
이번 릴리스에는 도구 정의에서 cache_control passthrough에 대한 테스트 커버리지도 추가됐습니다 . 새로운 코드 경로가 생긴 것은 아닙니다. 도구 스키마에 대한 프롬프트 캐싱은 이미 존재했습니다. 다만 테스트가 없었기 때문에 동작이 취약했고, SDK 업그레이드 때 조용히 깨질 수 있었습니다. 여기서 핵심은 커버리지입니다. 큰 도구 스키마를 캐시해 지연 시간과 토큰 비용을 줄이는 에이전트에게, 테스트되지 않은 passthrough는 운영 리스크입니다.
0.2.4는 스트리밍을 다시 설계하기보다 안정화된 스트리밍 기반 위에 쌓인 릴리스입니다. 직전 버전인 0.2.3은 2026년 5월 1일에 fragmented reasoning_details chunks를 병합해 스트리밍을 수정했고, session_id와 trace 필드를 추가했습니다 . 그 기반이 마련된 상태에서 0.2.4는 스트림 처리 대신 도구 호출 충실도를 보강했습니다.
마지막 정리 항목은 모델 프로필 갱신입니다. 배포하기 전에 설정에 고정해 둔 모델 ID가 여전히 해석되는지 확인해야 합니다. OpenRouter는 버전이 없는 모델 별칭이 더 새로운 checkpoint 버전으로 조용히 이동할 수 있으며, 선택을 제한하거나 고정하지 않으면 변경된 요율로 계속 라우팅된다고 경고합니다. 그래서 명시적이고 버전이 붙은 모델 ID를 기본값으로 삼는 편이 더 안전합니다 .
OpenRouter가 백엔드를 고르는 방식: 가동률 × 저렴함
OpenRouter의 기본 라우팅은 가동률을 고려하되 비용 쪽으로 기울어져 있습니다. 무작위도 아니고, 무조건 가장 싼 곳만 고르는 것도 아닙니다. 여러 백엔드가 제공하는 모델의 경우, 먼저 최근 30초 동안 큰 장애가 있었던 제공자의 우선순위를 낮춘 뒤, 남은 후보 중 비용이 가장 낮은 쪽들을 가격의 역제곱으로 가중해 선택합니다 . 그 결과 트래픽은 저렴한 엔드포인트 쪽으로 기울어지면서도 분산됩니다. 그래서 특정 제공자의 지연 시간이 튀거나 rate limit 벽에 막혀도 모든 요청이 함께 멈추지는 않습니다.
이 가중치는 구체적입니다. OpenRouter의 예시는 이렇습니다. 백만 토큰당 1달러인 제공자는 3달러 제공자보다 첫 번째로 라우팅될 가능성이 약 9배 높습니다. 역제곱 가중치가 작은 가격 차이도 크게 벌리기 때문입니다. 반면 몇 초 전까지 실패하던 2달러 제공자는 가격만 보면 조건에 맞더라도 아예 건너뛸 수 있습니다 . 각 호출은 고정 순위가 아니라 확률로 결정됩니다. 그래서 트레이스에는 가장 싼 제공자가 응답했다고 가정하지 말고, 실제로 응답을 처리한 제공자를 반드시 기록해야 합니다.
이 복원력을 포기하고 결정성을 얻을 수도 있습니다. sort나 order 중 하나를 설정하면 로드 밸런싱 가중치가 비활성화됩니다. order는 명시한 제공자 순서에 고정하고, sort는 price, throughput, latency 중 하나의 축으로 강제 정렬합니다. OpenRouter는 가장 흔한 두 경우를 위한 축약형도 제공합니다. :floor 슬러그 접미사는 가격 기준 정렬과 같고, :nitro는 처리량 기준 정렬과 같습니다 . 결정성은 재현성에는 유용하지만, 기본 알고리즘이 무료로 제공하던 자동 장애 조치를 제거합니다.
| 제어 항목 | 효과 | 강제 여부 |
|---|---|---|
| 기본값(sort/order 없음) | 장애 제공자의 우선순위를 낮춘 뒤, 가격 역제곱 가중치 적용 | 확률적 |
sort / :floor / :nitro | 밸런싱 비활성화, 단일 축 기준의 결정적 정렬 | 결정적 |
preferred_max_latency / preferred_min_throughput | 롤링 백분위수로 선택 방향 조정 | 소프트(선호) |
max_price | 상한을 넘는 제공자 거부 | 하드(거부) |
지연 시간과 처리량 제어는 소프트 조건입니다. preferred_max_latency와 preferred_min_throughput은 5분 윈도우에서 측정한 롤링 p50/p75/p90/p99 백분위수를 사용해 선택 방향을 조정하지만, 조건을 만족하는 제공자를 선호할 뿐입니다. 조건에 맞는 곳이 없다고 요청을 하드 차단하지는 않습니다 . 라우팅 설정 중 max_price만 best-effort 선호가 아니라 요청을 outright 거부합니다. 실제 예산 가드레일을 코드로 박기 시작하면 바로 이 차이가 중요해집니다.
예산 가드레일: max_price, ZDR, 엄격한 거부

max_price는 선호가 아니라 하드 상한입니다. 프롬프트, 완성, 요청, 이미지 요율을 백만 토큰당 USD로 넘깁니다. 예를 들어 {prompt: 1, completion: 2}는 프롬프트를 $1/M, 완성을 $2/M으로 제한합니다. OpenRouter는 이 한도를 넘는 모든 백엔드를 거부합니다. 조건을 만족하는 제공자가 없으면 더 비싼 엔드포인트로 조용히 라우팅하는 대신 요청이 오류로 끝납니다 . 바로 그 실패 방식이 핵심입니다. 앞에서 다룬 선호형 필드(preferred_max_latency, preferred_min_throughput)는 우아하게 degrade되지만, max_price는 그렇지 않습니다. 재무팀이 강제하는 지출 상한에는 바로 이런 동작이 필요합니다.
| 필드 | 조건을 만족하는 백엔드가 없을 때 | 사용 사례 |
|---|---|---|
max_price | 요청 실패(엄격한 거부) | 하드 지출 상한 |
preferred_max_latency | 사용 가능한 최선으로 폴백 | 소프트 성능 편향 |
zdr / data_collection | 미준수 제공자를 피해 라우팅 | 데이터 레지던시 정책 |
only / ignore | 요청별 허용 목록 / 차단 목록 | 제공자 거버넌스 |
컴플라이언스 설정도 같은 방식으로 조합할 수 있습니다. data_collection과 zdr(Zero Data Retention)는 추론 데이터를 기록하거나 보관하는 백엔드를 피해 요청을 보내도록 합니다. 덕분에 GDPR, HIPAA, 계약상 데이터 레지던시 제약을 애플리케이션 코드가 아니라 라우팅 정책에 담을 수 있습니다 . only와 ignore 목록은 요청별 제공자 허용 목록과 차단 목록을 더합니다. 이들을 함께 쌓으면, 예를 들어 max_price에 zdr를 더하고 only 허용 목록까지 붙이면, 각 호출은 자체 정책 봉투를 갖게 됩니다. 비용 상한, 데이터 보관 규칙, 승인된 제공자 집합이 단 하나의 토큰이 생성되기 전에 모두 평가됩니다.
한 가지 주의할 점 때문에 max_price는 단순한 편의 기능을 넘어섭니다. OpenRouter는 모델 가격이 바뀌면 선택을 제한하지 않는 한 계속 라우팅하고 새 요율로 과금한다고 경고합니다. 그래서 max_price 상한도 없고 명시적 버전 모델 ID도 없는 요청은 제공자가 가격을 다시 매기거나 모델 버전이 앞으로 이동할 때 예상치 못한 비용을 조용히 만들 수 있습니다 . 구체적인 모델 ID를 고정하면 예상치 못한 버전 변경을 피할 수 있고, 여기에 max_price를 함께 쓰면 표시 가격이 아래에서 바뀌어도 청구액을 제한할 수 있습니다 . 모델 카탈로그를 변동 가능한 인프라로 취급해야 합니다. 그러면 이 두 필드는 선언만 한 예산과 게이트웨이가 실제로 강제하는 예산을 가르는 기준이 됩니다.
LiteLLM vs OpenRouter: 이제 둘 다 공식 지원 어댑터입니다
2026년 3월 기준, LangChain에는 유지보수되는 라우팅 어댑터가 두 개 포함되어 있습니다. 6개월 전만 해도 하나도 없었던 영역입니다. 팀은 langchain-openrouter와 함께, 원래 Akshay Dongare가 만든 커뮤니티 프로젝트였던 langchain-litellm을 langchain-ai 조직으로 편입했습니다. 그 결과 개발자는 예전 접착 코드에서 벗어날 수 있는 공식 지원 경로를 두 가지 갖게 됐습니다 . 구분은 명확합니다. OpenRouter는 호출해서 쓰는 호스팅 게이트웨이이고, LiteLLM은 직접 운영하는 프록시/라이브러리입니다.
빠른 답: 운영 부담 없이 관리형 멀티 백엔드 접근이 필요하다면 OpenRouter를 고르세요. 하나의 키로 70개 이상 제공업체의 400개 이상 모델을 쓰고, 종량제 5.5% 수수료를 냅니다. 온프레미스 배포, 팀별 또는 태그별 예산 귀속, 직접 통제하는 BYOK 컴플라이언스가 필요하다면 LiteLLM을 고르세요.
OpenRouter는 운영이 필요 없는 선택지입니다. 70개 이상 제공업체의 400개 이상 활성 모델을 앞단에서 제공하며, 토큰당 마크업 없이 제공업체 정가로 추론을 전달하고 대신 5.5% 종량제 플랫폼 수수료를 붙입니다 . 무료 티어에는 25개 이상 무료 모델과 하루 50회 요청이 포함되며, BYOK 종량제는 월 100만 회 무료 요청 이후 5% 수수료가 적용됩니다 . 라우팅 인프라는 직접 작성하지 않습니다. 대신 다른 누군가가 운영한다는 전제를 받아들이는 방식입니다.
LiteLLM은 그 장치를 자체 배포 환경 안으로 가져옵니다. LiteLLM 라우터 문서는 제공업체 간 로드 밸런싱, 쿨다운, 폴백, 재시도, Redis 기반 TPM/RPM 추적을 설명합니다 . 비용을 신경 쓰는 팀에서 LiteLLM이 앞서는 지점은 예산 관리입니다.
- 제공업체 예산 — OpenAI 하루 $100, Azure 하루 $100처럼 각 백엔드를 독립적으로 제한하고, 1d 또는 30d 같은 기간 단위로 Redis에서 추적합니다 .
- 태그 예산 —
product:chat-bot에 하루 $10처럼 워크로드별로 비용을 귀속하고, 예산을 초과한 제공업체는 건너뛰며, 모두 초과하면 오류를 냅니다 . - 가상 키 —
completion_cost()를 통해 키별, 사용자별, 팀별 지출을 USD로 추적하고,max_budget기본값과 상한을 둘 수 있습니다 .
결정 기준은 실제로 당신을 묶는 제약입니다. LangChain 팀은 채택 발표에서 "Multi-provider routing is no longer a bring-your-own-glue concern — the framework now ships maintained adapters for it,"라고 설명합니다 (source: LangChain Discussion #35672). 인프라 부담 없는 관리형 접근이 우선이면 OpenRouter를 선택하세요. 온프레미스 배포, 팀 또는 태그 단위의 세밀한 예산 귀속, BYOK 컴플라이언스 요건이 있다면 LiteLLM을 선택하세요.
교체 방법: base_url 대신 ChatOpenRouter 쓰기

base_url 우회 방식을 걷어내는 마이그레이션은 diff는 작지만 텔레메트리 개선 효과가 큽니다. pip install 'langchain-openrouter>=0.2.4'로 패키지를 설치하세요. Python >=3.10, <4.0이 필요하며 MIT 라이선스로 배포됩니다 . 생성자 표면은 의도적으로 ChatOpenAI와 가깝게 되어 있어, 대부분의 호출 지점은 한 줄만 바꾸면 됩니다.
# Before — the base_url override
llm = ChatOpenAI(
base_url="https://openrouter.ai/api/v1",
api_key=OR_KEY,
model="openai/gpt-4o",
)
# After — the first-party integration
llm = ChatOpenRouter(
model="openai/gpt-4o",
openrouter_api_key=OR_KEY,
)제공업체 라우팅은 model_kwargs 안에 묻어두는 대신 kwarg로 함께 전달합니다. 생성자에 openrouter_provider={...}를 넘기면 order, max_price, sort 선호도를 일급 필드로 설정할 수 있습니다 . 에이전트형 워크로드에서는 계속 bind_tools()를 쓰면 됩니다. 0.2.4 기준으로 parallel_tool_calls가 올바르게 전달되며, 도구 정의에는 이제 cache_control 패스스루도 포함됩니다 .
2026년 5월 1일, 조각난 reasoning_details를 병합하던 0.2.3 수정 이후 스트리밍은 별도 개입 없이 동작합니다. 따라서 그 버그를 덮기 위해 작성했던 커스텀 청크 재조립 로직은 삭제해도 됩니다 .
승인 테스트의 기준은 출력이 아니라 귀속 정보입니다. 업그레이드 후 LangSmith 트레이스를 열어, 실행 기록이 단순한 openai 식별자가 아니라 실제 호출을 처리한 OpenRouter 하위 제공업체, 예컨대 Anthropic, Google 또는 해당 엔드포인트를 기록하는지 확인하세요. 트레이스가 여전히 openai로 표시된다면 체인의 상류 어딘가에 남아 있는 ChatOpenAI+base_url 인스턴스가 아직 연결되어 있는 것이며, 전용 통합의 올바른 제공업체 식별이 적용되지 않은 상태입니다 .
프록시가 엔드포인트를 고를 때 생기는 텔레메트리 사각지대
langchain-openrouter 0.2.4의 올바른 제공자 표시 는 사용자가 요청한 OpenRouter 라우트를 기록합니다. 다만 실제로 호출을 실행한 하위 제공자가 항상 기록되는 것은 아닙니다. allow_fallbacks가 true이면 OpenRouter는 컨텍스트 길이 검증, 모더레이션 플래그, 속도 제한, 다운타임 같은 오류가 발생했을 때 우선순위에 따라 모델을 시도할 수 있으며, 최종적으로 사용된 모델 기준으로 과금합니다 . 트레이스에는 의도가 남지만, 실제 응답한 엔드포인트는 조용히 달라질 수 있습니다. 이것이 사각지대입니다. 라우팅은 프리미엄 모델을 과도하게 써서 생기는 낭비를 줄여 주지만, 텔레메트리를 직접 수집하지 않으면 어느 제공자가 답했는지 숨길 수 있습니다.
통합이 이미 노출하는 상관관계 필드로 이 간극을 줄이십시오. 이전 0.2.3 릴리스(2026년 5월 1일)는 조각난 reasoning_details에 대한 스트리밍 수정과 함께 session_id와 trace를 추가했습니다 . 이 필드들은 OpenRouter 자체 대시보드 안에서 요청을 연결해 주지만, 시스템 간 출처 표시는 이 값을 관측성 스택으로 명시적으로 전달해야만 작동합니다. 한쪽에는 LangSmith, 다른 한쪽에는 OpenRouter 기록을 두고, 공유 키로 조인해야 합니다.
병렬 도구 호출은 이제 0.2.4에서 의미적으로 올바르게 처리되며, bind_tools의 parallel_tool_calls를 통해 노출됩니다 . 에이전트 루프가 특정 백엔드 하나의 도구 호출 스키마를 전제로 하고 있지 않은지 확인하십시오. OpenRouter가 70개 이상의 제공자에 걸쳐 400개 이상의 모델을 제공한다고 밝히는 상황에서는 스키마 차이가 실제로 발생합니다. 특히 allow_fallbacks가 실행 중 보조 엔드포인트로 라우팅할 때 그 차이가 드러나기 쉽습니다.
오래 가는 결론은 분명합니다. 백엔드와 모델 카탈로그를 정적 의존성이 아니라 변동 가능한 인프라로 다루십시오. OpenRouter는 모델 가격이 바뀌면 선택지를 제한하거나 고정하지 않는 한 계속 라우팅하고 새 요금을 청구한다고 경고합니다 . 버전이 붙은 모델 ID는 동작을 고정하지만, 버전 없는 별칭은 그렇지 않습니다. 올바른 추적과 도구 의미를 위해 0.2.4를 도입한 다음, 엄격한 한도를 설정하고 실제 라우팅된 제공자를 감사하며 버전을 고정하십시오. 그렇지 않으면 프록시의 편의성이 곧 감사 공백이 됩니다.
자주 묻는 질문
ChatOpenAI(base_url=…)에서 ChatOpenRouter로 마이그레이션해야 하나요?
반드시 마이그레이션해야 하는 것은 아니지만 권장됩니다. base_url 재정의로 ChatOpenAI를 OpenRouter에 연결하면 응답 스키마 불일치로 버그가 생기고, 트레이스에서 제공자 정체성이 잘못 표시됩니다. LangChain은 전용 패키지를 발표하면서 이 문제를 March 8, 2026 GitHub Discussion #35672에서 문서화했습니다. ChatOpenRouter는 두 문제를 모두 해결하고, reasoning 콘텐츠를 네이티브로 처리하며, OpenRouter 메타데이터를 일급 필드로 노출합니다. 또한 우회 방식에서는 제공되지 않았던 parallel_tool_calls도 드러냅니다.
parallel_tool_calls는 에이전트 워크로드에서 무엇을 바꾸나요?
parallel_tool_calls를 사용하면 모델이 한 번의 턴에서 도구를 하나씩이 아니라 여러 개 호출할 수 있습니다. version 0.2.4, released June 23, 2026 이전에는 이 플래그가 ChatOpenRouter의 bind_tools()에 노출되지 않았기 때문에, 백엔드 모델이 병렬 처리를 지원하더라도 에이전트 루프는 순차 호출로 돌아갔습니다 (release notes). 여러 도구를 쓰는 에이전트에서는 왕복 횟수와 전체 지연 시간이 줄어듭니다.
max_price는 그냥 저렴한 모델을 고르는 것과 어떻게 다른가요?
max_price는 요청 시점에 적용되는 엄격한 상한입니다. 지정한 프롬프트, 완성, 요청, 이미지 요율을 넘는 제공자는 거부합니다. 예를 들어 프롬프트 ≤ $1/M, 완성 ≤ $2/M 토큰처럼 제한하고, 더 비싼 백엔드로 라우팅하는 대신 요청을 실패시킵니다 (provider routing). 저렴한 모델 ID를 수동으로 고르는 것만으로는 이런 보호가 없습니다. OpenRouter는 해당 모델의 가격이 바뀌면 선택지를 제한하거나 고정하지 않는 한 계속 라우팅하고 새 요금을 청구한다고 경고합니다 (pricing).
langchain-openrouter 0.2.4는 스트리밍을 지원하나요?
예. 스트리밍은 version 0.2.3 on May 1, 2026에서 조각난 reasoning_details 청크를 병합하는 방식으로 수정되었고, 0.2.4는 그 수정 위에 만들어졌습니다 (changelog). 이전 조각화 문제를 우회하려고 직접 청크 재조립 로직을 작성했다면, 업그레이드 전에 제거해 스트림을 중복 처리하지 않도록 하십시오.
멀티 백엔드 라우팅에서 OpenRouter와 LiteLLM은 어떻게 다른가요?
OpenRouter는 호스팅 게이트웨이입니다. 운영 부담이 없고, 400+ models across 70+ providers and a 5.5% pay-as-you-go fee를 제공합니다 (pricing). LiteLLM은 셀프 호스팅할 수 있으며, 온프레미스 비용 통제를 위해 키, 팀, 태그별 Redis 기반 예산 추적을 제공합니다 (LangChain releases). 둘 다 2026년 3월 같은 발표에서 공식 LangChain 어댑터가 되었으므로, 관리형의 단순함이 우선인지 셀프 호스팅 기반 비용 거버넌스가 우선인지에 따라 선택하면 됩니다.