LangChain

`ChatOpenAI` 에 우리 엔드포인트를 준다

LangChain 에는 우리 전용 통합이 없지만 필요하지도 않습니다. ChatOpenAI 에 base URL 과 키만 넘기면 됩니다. OpenAI 호환 규격을 그대로 따르기 때문입니다.

항목
Base URLhttps://openrouter.myip.co.kr/api/v1
환경 변수MYIP_API_KEY
예제 모델google/gemma-4-26b-a4b, lgai/exaone-4.0-32b

Python

bash
pip install langchain langchain-openai
export MYIP_API_KEY="sk-mo-v1-..."
python
import os
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

llm = ChatOpenAI(
    model="google/gemma-4-26b-a4b",
    base_url="https://openrouter.myip.co.kr/api/v1",
    api_key=os.environ["MYIP_API_KEY"],
    temperature=0.7,
    default_headers={
        "HTTP-Referer": "https://example.com",
        "X-Title": "My LangChain App",
    },
)

prompt = ChatPromptTemplate.from_messages([
    ("system", "당신은 간결하게 답하는 도우미입니다."),
    ("human", "{question}"),
])

chain = prompt | llm | StrOutputParser()
print(chain.invoke({"question": "한국의 수도는?"}))

JavaScript / TypeScript

bash
npm install @langchain/openai @langchain/core
export MYIP_API_KEY="sk-mo-v1-..."
typescript
import { ChatOpenAI } from '@langchain/openai';
import { ChatPromptTemplate } from '@langchain/core/prompts';
import { StringOutputParser } from '@langchain/core/output_parsers';

const llm = new ChatOpenAI({
  model: 'google/gemma-4-26b-a4b',
  apiKey: process.env.MYIP_API_KEY,
  temperature: 0.7,
  configuration: {
    baseURL: 'https://openrouter.myip.co.kr/api/v1',
    defaultHeaders: {
      'HTTP-Referer': 'https://example.com',
      'X-Title': 'My LangChain App',
    },
  },
});

const prompt = ChatPromptTemplate.fromMessages([
  ['system', '당신은 간결하게 답하는 도우미입니다.'],
  ['human', '{question}'],
]);

const chain = prompt.pipe(llm).pipe(new StringOutputParser());
console.log(await chain.invoke({ question: '한국의 수도는?' }));

스트리밍

python
for chunk in llm.stream("짧은 시를 하나 써 줘"):
    print(chunk.content, end="", flush=True)
typescript
const stream = await llm.stream('짧은 시를 하나 써 줘');
for await (const chunk of stream) {
  process.stdout.write(String(chunk.content));
}

stream_options.include_usage 는 우리가 항상 붙여 보내므로 직접 켤 필요가 없습니다. 다만 LangChain 이 마지막 usage 청크를 집계 결과에 합쳐 주려면 다음처럼 스트림 usage 수집을 켜는 편이 좋습니다.

python
llm = ChatOpenAI(
    model="lgai/exaone-4.0-32b",
    base_url="https://openrouter.myip.co.kr/api/v1",
    api_key=os.environ["MYIP_API_KEY"],
    stream_usage=True,
)

비용과 generation id 읽기

LangChain 은 응답 헤더를 감춰 두므로, 비용은 응답 메타데이터의 generation id 로 조회하는 편이 확실합니다.

python
msg = llm.invoke("안녕")

print(msg.usage_metadata)             # 토큰 수
gen_id = msg.response_metadata.get("id")   # 'gen-...'
python
import requests

def cost_krw(generation_id: str) -> float:
    res = requests.get(
        "https://openrouter.myip.co.kr/api/v1/generation",
        params={"id": generation_id},
        headers={"Authorization": f"Bearer {os.environ['MYIP_API_KEY']}"},
        timeout=10,
    )
    return res.json()["data"]["total_cost"]   # 원 단위

print(cost_krw(gen_id), "원")

정산이 비동기로 끝나므로 스트리밍 직후에는 조회가 이를 수 있습니다. 잠깐 기다렸다 다시 부르세요. 금액은 전부 원(KRW) 입니다.

툴 콜링

python
from langchain_core.tools import tool

@tool
def get_weather(city: str) -> str:
    """도시의 현재 날씨를 조회한다."""
    return f"{city}: 맑음, 21도"

agent_llm = llm.bind_tools([get_weather])
msg = agent_llm.invoke("서울 날씨 알려줘")
print(msg.tool_calls)

모델이 툴 콜링을 지원해야 합니다. GET /api/v1/models 응답의 supported_parameterstools 가 들어 있는지 확인하세요. 툴 콜링 참고.

쓸 수 없는 것

  • OpenAIEmbeddings — 임베딩 엔드포인트가 없습니다. 404 not_supported 가 돌아옵니다.
  • 이미지·음성 관련 LangChain 통합 — 해당 엔드포인트가 없습니다.

RAG 파이프라인을 구성한다면 임베딩만 다른 곳(로컬 임베딩 모델 등)에서 만들고, 생성 단계만 우리 게이트웨이로 보내면 됩니다. 목록은 지원하지 않는 엔드포인트 에 있습니다.

관련 문서

마지막 수정 2026. 9. 5.