Em aplicações novas com LangChain, use ChatOpenRouter. Mantenha ChatOpenAI com https://openrouter.ai/api/v1 em projetos antigos que não podem ser atualizados e use https://openrouter.ai/api apenas no caminho do Anthropic Agent SDK.
Resposta rápida: prefira a integração nativa em projetos novos com LangChain
O OpenRouter fornece o endpoint dos modelos e a camada de roteamento; o LangChain oferece as abstrações de modelos de chat, chains e agentes. Hoje, a combinação nativa é langchain-openrouter com ChatOpenRouter em Python, ou @langchain/openrouter com ChatOpenRouter em JavaScript e TypeScript.
| Sua situação | Caminho recomendado | Principal motivo |
|---|---|---|
| Aplicação nova em Python com LangChain | langchain-openrouter + ChatOpenRouter | Expõe os controles de roteamento do provedor, metadados, raciocínio, ferramentas e saída estruturada |
| Aplicação nova em JS/TS com LangChain | @langchain/openrouter + ChatOpenRouter | Mantém as interfaces nativas de mensagens, streaming e ferramentas do LangChain |
| Aplicação antiga existente com LangChain | ChatOpenAI + base_url="https://openrouter.ai/api/v1" | É a menor mudança para manter a compatibilidade |
Aplicação existente usando init_chat_model | LangChain v1 com langchain-openrouter | Habilita o caminho de despacho com model_provider="openrouter" |
| Aplicação com Claude/Anthropic Agent SDK | ANTHROPIC_BASE_URL="https://openrouter.ai/api" | O Agent SDK usa a rota compatível com Anthropic |
| Aplicação Next.js usando Vercel AI SDK | @openrouter/ai-sdk-provider + createOpenRouter() | Usa as abstrações streamText() e de ferramentas do AI SDK |
O anúncio do pacote oficial do LangChain afirma que o pacote nativo preserva comportamentos específicos do OpenRouter que um wrapper genérico de ChatOpenAI pode perder, como conteúdo de raciocínio, saída estruturada, metadados de roteamento e identidade de tracing. Se esses campos não forem importantes para o projeto, uma configuração de compatibilidade já existente não precisa ser reescrita imediatamente.
Comece pelo mapa de endpoints, não pelo nome do framework
Diferentes SDKs acrescentam caminhos de requisição distintos à URL base. A rota compatível com OpenAI é https://openrouter.ai/api/v1; o guia do OpenRouter para o OpenAI SDK usa esse valor. Já o guia do Anthropic Agent SDK define ANTHROPIC_BASE_URL como https://openrouter.ai/api.
| Cliente ou SDK | URL base a configurar | Família típica de requisições |
|---|---|---|
| OpenAI Python/JS SDK | https://openrouter.ai/api/v1 | OpenAI Chat Completions |
LangChain legado ChatOpenAI | https://openrouter.ai/api/v1 | Chamadas de chat compatíveis com OpenAI |
LangChain ChatOpenRouter | Normalmente, nenhuma URL base personalizada | Integração nativa com OpenRouter |
| Provedor OpenRouter do Vercel AI SDK | Normalmente, nenhuma URL base personalizada | O pacote do provedor gerencia o endpoint |
| Anthropic Agent SDK | https://openrouter.ai/api | Chamadas do Agent SDK compatíveis com Anthropic |
Não coloque /chat/completions na URL base de um SDK, a menos que ele peça explicitamente um endpoint completo. Se o erro mostrar um caminho duplicado, como /v1/v1, verifique como o SDK combina a URL base com o caminho do endpoint.
Para um cliente legado do LangChain compatível com OpenAI, o formato mínimo funcional é:
import os
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
model="openai/gpt-4o",
api_key=os.environ["OPENROUTER_API_KEY"],
base_url="https://openrouter.ai/api/v1",
)
response = llm.invoke("Explain provider routing in one sentence.")
print(response.content)
Use uma chave de API do OpenRouter, não uma chave da OpenAI. O Quickstart do OpenRouter especifica autenticação com token Bearer. HTTP-Referer e X-OpenRouter-Title são cabeçalhos opcionais para atribuição da aplicação, não substitutos de Authorization.
LangChain + OpenRouter: configuração atual
Python: langchain-openrouter
Instale a integração e mantenha a chave fora do arquivo-fonte:
pip install -U langchain-openrouter
export OPENROUTER_API_KEY="sk-or-..."
Depois, instancie o modelo de chat nativo. A integração do LangChain para Python documenta model, temperature, max_tokens e max_retries neste formato:
from langchain_openrouter import ChatOpenRouter
model = ChatOpenRouter(
model="anthropic/claude-sonnet-4.5",
temperature=0,
max_tokens=1024,
max_retries=2,
)
response = model.invoke([
("system", "You are a concise technical assistant."),
("human", "What does OpenRouter add to a LangChain application?"),
])
print(response.content)
Os nomes dos modelos no OpenRouter geralmente seguem o formato provider/model, como anthropic/claude-sonnet-4.5, openai/gpt-4o ou deepseek/deepseek-r1. Consulte a API de Modelos do OpenRouter antes de colocar a aplicação em produção, porque IDs de modelos, aliases, variantes, disponibilidade e parâmetros compatíveis podem mudar.
JavaScript e TypeScript: @langchain/openrouter
Instale a integração e o LangChain core:
npm install @langchain/openrouter @langchain/core
O construtor baseado em objeto da integração JavaScript do LangChain deixa a configuração explícita e facilita a comparação com o exemplo em Python:
import { ChatOpenRouter } from "@langchain/openrouter";
const model = new ChatOpenRouter({
model: "anthropic/claude-sonnet-4.5",
temperature: 0,
maxTokens: 1024,
});
const response = await model.invoke([
{ role: "system", content: "You are a concise technical assistant." },
{ role: "user", content: "Explain the provider/model format." },
]);
console.log(response.content);
Em Python, o parâmetro é max_tokens; no exemplo de JavaScript, ele aparece como maxTokens. As duas integrações leem OPENROUTER_API_KEY por padrão. Se um modelo aparece no catálogo, mas falha no código, confira o slug exato, o sufixo da variante e os parâmetros aceitos pela requisição.
init_chat_model e a armadilha das versões
Um erro comum é:
ValueError: Unsupported model_provider='openrouter'.
Uma discussão de troubleshooting no fórum do LangChain atribui esse caso ao uso de uma instalação do LangChain anterior à v1 com uma documentação voltada à v1. A recomendação é atualizar o framework e o pacote do provedor juntos:
pip install -U "langchain>=1" langchain-openrouter
Depois, use o inicializador genérico:
import os
from langchain.chat_models import init_chat_model
os.environ["OPENROUTER_API_KEY"] = "sk-or-..."
model = init_chat_model(
"anthropic/claude-sonnet-4.5",
model_provider="openrouter",
)
print(model.invoke("Say hello in one sentence.").content)
Se o projeto não puder migrar para o LangChain v1, instale langchain-openrouter e construa diretamente um ChatOpenRouter. Assim, você contorna o registro genérico de provedores e deixa a dependência do OpenRouter explícita.
Migre de ChatOpenAI para ChatOpenRouter
A alteração no código é pequena, mas a fronteira de integração muda de um adaptador genérico da OpenAI para uma classe específica do provedor:
# Antes: solução compatível com OpenAI
from langchain_openai import ChatOpenAI
model = ChatOpenAI(
model="anthropic/claude-sonnet-4.5",
base_url="https://openrouter.ai/api/v1",
api_key=os.environ["OPENROUTER_API_KEY"],
)
# Depois: integração nativa com OpenRouter
from langchain_openrouter import ChatOpenRouter
model = ChatOpenRouter(model="anthropic/claude-sonnet-4.5")
Primeiro, mantenha os mesmos prompts e pontos de chamada das chains. Só adicione roteamento de provedores, raciocínio, saída estruturada ou tratamento de metadados depois que a chamada nativa básica estiver funcionando.
Streaming, callbacks, ferramentas e saída estruturada no LangChain
model.stream() produz fragmentos de mensagem para um consumo simples de texto. Já stream_events(..., version="v3") expõe eventos do ciclo de vida mais adequados para logs baseados em callbacks, estado da interface e tracing; as duas interfaces estão documentadas na integração do LangChain para Python.
model = ChatOpenRouter(model="openai/gpt-4o")
for event in model.stream_events(
"Explain why OpenRouter has provider fallbacks.",
version="v3",
):
if event["event"] == "on_chat_model_stream":
chunk = event["data"]["chunk"]
print(chunk.text, end="", flush=True)
Use um callback quando a aplicação precisar de notificações de início, token, conclusão ou erro. Use stream() quando ela precisar apenas dos fragmentos do modelo. Leia o uso e os metadados da resposta concluída ou do resultado agregado do stream, como mostra a documentação da integração, em vez de buscá-los em um fragmento inicial qualquer.
Chamadas de ferramentas e roteamento de provedores
O OpenRouter documenta um fluxo normalizado de chamadas de ferramentas: o modelo propõe uma chamada, a aplicação a executa e envia o resultado de volta ao modelo. ChatOpenRouter.bind_tools() aceita ferramentas do LangChain, funções Python, classes Pydantic e schemas em dicionários.
from pydantic import BaseModel, Field
class GetWeather(BaseModel):
"""Get current weather for a city."""
location: str = Field(
description="City and state, for example San Francisco, CA"
)
model_with_tools = model.bind_tools(
[GetWeather],
strict=True,
)
result = model_with_tools.invoke("What is the weather in San Francisco?")
print(result.tool_calls)
A primeira chamada retorna apenas as chamadas de ferramentas propostas pelo modelo. Em um ciclo manual completo, crie uma ToolMessage para cada chamada antes de pedir ao modelo a resposta final:
from langchain_core.messages import HumanMessage, ToolMessage
from langchain_core.tools import tool
@tool
def get_weather(location: str) -> str:
"""Get the current weather in a location."""
return f"Sunny in {location}."
model_with_tools = model.bind_tools([get_weather])
messages = [HumanMessage("What is the weather in San Francisco?")]
ai_msg = model_with_tools.invoke(messages)
messages.append(ai_msg)
for call in ai_msg.tool_calls:
tool_output = get_weather.invoke(call["args"])
messages.append(
ToolMessage(
content=tool_output,
tool_call_id=call["id"],
)
)
final_msg = model_with_tools.invoke(messages)
print(final_msg.content)
O roteamento de provedores deve ser definido na configuração específica do OpenRouter, descrita na integração do LangChain e no guia de seleção de provedores do OpenRouter:
routed_model = ChatOpenRouter(
model="anthropic/claude-sonnet-4.5",
openrouter_provider={
"order": ["Anthropic", "Google"],
"allow_fallbacks": True,
"require_parameters": True,
"data_collection": "deny",
},
)
order define a preferência. only restringe os provedores elegíveis, enquanto ignore exclui provedores. allow_fallbacks=True pode enviar uma requisição para além da ordem preferencial. require_parameters=True impede que a requisição seja encaminhada a provedores que não aceitem todos os parâmetros do payload. Essas configurações equilibram disponibilidade e controle sobre o provedor.
Em clientes antigos baseados em ChatOpenAI, os campos específicos do OpenRouter talvez precisem ser enviados por extra_body ou model_kwargs, dependendo da versão do cliente. Um usuário perguntou em uma discussão sobre LangChain/OpenRouter no Reddit:
“Wondering, doesn't openrouter support the openai API spec such that the openai client works?” — u/tuxedo0.
O pacote dedicado torna explícita a fronteira de integração com o OpenRouter, sem exigir que um wrapper genérico da OpenAI exponha todos os campos específicos de cada provedor.
Saída estruturada: confira o endpoint, não apenas o nome do modelo
A integração nativa oferece saída tipada por meio de with_structured_output(). A documentação do LangChain para Python mostra o método nativo com JSON Schema:
from pydantic import BaseModel, Field
class Movie(BaseModel):
title: str
year: int
director: str
rating: float = Field(description="Rating from 0 to 10")
structured_model = ChatOpenRouter(
model="openai/gpt-5.5",
).with_structured_output(
Movie,
method="json_schema",
strict=True,
)
movie = structured_model.invoke("Give details about the movie Inception.")
print(movie)
A integração também documenta function_calling; strict não é compatível com json_mode. O comportamento da saída estruturada do OpenRouter pode variar de acordo com o endpoint que atende à requisição, portanto o nome do modelo, sozinho, não é garantia. O guia de saída estruturada do OpenRouter explica por que verificações de capacidade do provedor, require_parameters e validação no cliente são importantes.
Vercel AI SDK + OpenRouter
Em uma aplicação Next.js ou TypeScript que usa o AI SDK da Vercel, instale o provedor do OpenRouter:
npm install @openrouter/ai-sdk-provider ai zod
Este exemplo compacto cobre streaming de texto e uma ferramenta local com Zod. O guia do OpenRouter para o Vercel AI SDK usa o mesmo padrão com createOpenRouter() e openrouter("provider/model").
import { createOpenRouter } from "@openrouter/ai-sdk-provider";
import { isStepCount, streamText, tool } from "ai";
import { z } from "zod";
const openrouter = createOpenRouter({
apiKey: process.env.OPENROUTER_API_KEY,
});
const result = streamText({
model: openrouter("openai/gpt-4o"),
tools: {
getWeather: tool({
description: "Get the current weather in a location",
inputSchema: z.object({
location: z.string().describe("City and state"),
}),
execute: async ({ location }) => ({
location,
temperature: 18,
unit: "celsius",
}),
}),
},
stopWhen: isStepCount(3),
prompt: "What is the weather in San Francisco?",
});
for await (const textPart of result.textStream) {
process.stdout.write(textPart);
}
textStream expõe os deltas de texto. Use fullStream quando a aplicação precisar de raciocínio, chamadas de ferramentas, resultados de ferramentas, limites entre etapas ou eventos de conclusão; a referência de streamText() do AI SDK documenta essas interfaces de resultado. O executor de clima acima é um mock, não uma chamada a uma API real.
Uma issue pública do provedor OpenRouter relatou buffering percebido em um fluxo de chamadas de ferramentas com vários fragmentos usando @openrouter/ai-sdk-provider 2.2.3, AI SDK 6.0.81, Node.js 24 e openai/gpt-5.2. O relato descreveu a ausência do evento tool-input-end. Trate isso como um problema específico de versão, não como um comportamento universal. Se o problema se reproduzir, a issue relata esta solução alternativa:
import { createOpenAI } from "@ai-sdk/openai";
const openrouter = createOpenAI({
apiKey: process.env.OPENROUTER_API_KEY,
baseURL: "https://openrouter.ai/api/v1",
});
const model = openrouter.chat("openai/gpt-5.2");
Instale @ai-sdk/openai separadamente e fixe as versões testadas. Essa solução muda o adaptador do provedor, então confirme quais opções específicas do OpenRouter continuam disponíveis.
Anthropic Agent SDK + OpenRouter
O Anthropic Agent SDK representa uma fronteira de integração separada. O guia oficial do Agent SDK do OpenRouter informa que o SDK usa o Claude Code como runtime e aceita esta configuração de ambiente:
export ANTHROPIC_BASE_URL="https://openrouter.ai/api"
export ANTHROPIC_AUTH_TOKEN="$OPENROUTER_API_KEY"
export ANTHROPIC_API_KEY=""
Deixar ANTHROPIC_API_KEY vazio é intencional. A chave do OpenRouter deve ficar em ANTHROPIC_AUTH_TOKEN, e o caminho /api não deve ser trocado pelo caminho compatível com OpenAI, /api/v1, nessa configuração do Agent SDK.
O formato em TypeScript mostrado no guia é:
npm install @anthropic-ai/claude-agent-sdk
import { query } from "@anthropic-ai/claude-agent-sdk";
for await (const message of query({
prompt: "Find and explain the bug in auth.py.",
options: {
allowedTools: ["Read"],
},
})) {
if (message.type === "assistant") {
console.log(message.message.content);
}
}
O OpenRouter fornece o endpoint do modelo; o Agent SDK mantém o loop do agente e o runtime das ferramentas. Teste ferramentas, streaming, comportamento de contexto e opções específicas do modelo na rota exata que será usada em produção, porque a paridade automática com os recursos nativos da Anthropic não é garantida.
401, 404 e o clássico “funciona no curl, mas não no SDK”
Identifique a camada que está falhando antes de trocar de modelo. Autenticação, montagem da URL, busca do modelo, filtros de provedor e validação de parâmetros exigem correções diferentes.
| Sintoma | Camada provável | Primeira verificação |
|---|---|---|
401 Missing Authentication header | Cabeçalho ou carregamento do ambiente | Confirme Authorization: Bearer ...; teste /api/v1/key |
401 Unauthorized com uma chave presente | Chave incorreta, revogada ou vazia | Confirme se o processo enxerga OPENROUTER_API_KEY; use uma chave do OpenRouter |
404 com caminho malformado | Montagem da URL base | Clientes compatíveis com OpenAI usam /api/v1; o Agent SDK usa /api; procure por /v1 duplicado |
404 Invalid model ou model_not_found | Identificador do modelo | Consulte /api/v1/models e use o id retornado ou um alias documentado |
404 No allowed providers are available | Filtros de provedores ou disponibilidade do endpoint | Inspecione only, ignore, max_price, require_parameters e as configurações de política de dados |
400 para top_k, min_p, ferramentas ou JSON Schema | Incompatibilidade de capacidades | Confira supported_parameters; exija provedores compatíveis durante o roteamento |
curl funciona, mas o código do framework falha | Caminho do SDK, capitalização, serialização ou cabeçalhos descartados | Compare a URL final, o cabeçalho de autenticação, o ID do modelo e o corpo JSON |
O OpenRouter documenta GET /api/v1/key como uma verificação autenticada da chave de API. Execute esse teste antes de investigar o LangChain:
curl -sS https://openrouter.ai/api/v1/key \
-H "Authorization: Bearer $OPENROUTER_API_KEY"
Em seguida, confirme a descoberta de modelos:
curl -sS https://openrouter.ai/api/v1/models \
-H "Authorization: Bearer $OPENROUTER_API_KEY"
A API de Modelos permite filtrar modelos compatíveis com ferramentas antes de adicioná-las:
curl -sS \
"https://openrouter.ai/api/v1/models?supported_parameters=tools" \
-H "Authorization: Bearer $OPENROUTER_API_KEY"
Um 404 também pode significar que o modelo existe, mas nenhum provedor elegível restou depois da aplicação dos filtros da requisição. Para inspecionar as decisões de roteamento, habilite o cabeçalho opcional X-OpenRouter-Metadata: enabled; a documentação de Router Metadata descreve o objeto openrouter_metadata resultante e seu comportamento em caso de erro.
Durante o desenvolvimento, compare a requisição gerada depois de ocultar a chave: URL base, caminho final, presença de Authorization, ID exato do modelo e campos específicos do provedor no corpo. Para uma investigação específica de autenticação, consulte o guia da AIReiter para erros de chave de API inválida e problemas 401/403.
Checklist de migração para produção
- Alinhe as gerações dos pacotes. Mantenha versões compatíveis de
langchain,langchain-coreelangchain-openrouterou@langchain/openrouter, em vez de copiar versões de um tutorial antigo. - Resolva os IDs canônicos dos modelos. Use
/api/v1/modelsou o catálogo de modelos do OpenRouter; trate aliases como uma mudança de comportamento intencional. - Defina a fronteira do fallback. O fallback de provedor melhora a disponibilidade. O fallback de modelo pode alterar qualidade, latência, capacidades e custo. Registre o
modelfinal retornado pelo OpenRouter. - Exija as capacidades quando elas forem importantes. Use filtros de capacidade do provedor em requisições com ferramentas e saída estruturada; não trate suporte a ferramentas como prova de compatibilidade com JSON Schema estrito.
- Valide as saídas da aplicação. Pydantic, Zod ou outro validador deve conferir os argumentos das ferramentas e as respostas estruturadas antes que o código seguinte aja sobre elas.
- Registre metadados úteis. Preserve ID da requisição, modelo, uso, motivo de conclusão e informações sobre o provedor que atendeu à requisição, quando a política de privacidade permitir. A integração do LangChain também documenta
session_idpara agrupar requisições etracepara metadados por requisição. - Teste os dois modos de streaming. Uma chamada sem streaming bem-sucedida não prova que os fragmentos de chamadas de ferramentas ou o streaming da interface funcionarão corretamente.
- Exercite as restrições de provedores. Se usar
only,ignore, filtros de coleta de dados ou um teto de preço, teste o caminho de erro sem provedores elegíveis. - Mantenha as credenciais no servidor. Armazene
OPENROUTER_API_KEYno ambiente do servidor ou em um gerenciador de segredos, nunca em um bundle do navegador ou em um arquivo.envversionado.
A sequência mais confiável é: valide a chave, confirme o ID do modelo, faça uma chamada simples de texto e só então adicione roteamento, ferramentas, saída estruturada e streaming em múltiplas etapas.