LangChain · Python + JS
LangChain + Leanroute
LangChain's ChatOpenAI and OpenAIEmbeddings accept a base_url override. Point that at Leanroute and every LangChain workflow you have — chains, agents, RAG pipelines, streaming — keeps working, but you can now route across every provider we support instead of just OpenAI.
1. Get a gateway key
From /dashboard/keys create a key labeled "langchain". Copy the gw_live_* value — it's shown only once.
2. Python: chat
pip install langchain-openai if you don't already have it. Then:
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
model="anthropic/claude-sonnet-4-6", # or openai/gpt-4o, deepseek/deepseek-v4-flash, etc.
api_key="gw_live_YOUR_KEY",
base_url="https://api.leanroute.dev/v1",
)
print(llm.invoke("Explain retrieval-augmented generation in one sentence.").content)The model string uses our canonical provider/model form. Full list at /dashboard/models.
3. Python: streaming
for chunk in llm.stream("Write a haiku about caching."):
print(chunk.content, end="", flush=True)Server-sent events are forwarded from the upstream provider chunk-by-chunk with no intermediate buffering — your first token latency matches going direct.
4. Python: embeddings
from langchain_openai import OpenAIEmbeddings
embed = OpenAIEmbeddings(
model="openai/text-embedding-3-small",
api_key="gw_live_YOUR_KEY",
base_url="https://api.leanroute.dev/v1",
)
vec = embed.embed_query("what is prompt caching?")
print(len(vec)) # 1536Use the same key. Any LangChain vector-store integration (Chroma, Pinecone, pgvector, Weaviate, etc.) accepts an embedding_function argument — pass this embed and your entire indexing + query flow now runs through Leanroute.
5. JavaScript / TypeScript
npm install @langchain/openai. The JS package uses configuration.baseURL (nested) instead of the flat base_url Python uses.
import { ChatOpenAI } from "@langchain/openai";
const llm = new ChatOpenAI({
model: "anthropic/claude-sonnet-4-6",
apiKey: "gw_live_YOUR_KEY",
configuration: {
baseURL: "https://api.leanroute.dev/v1",
},
});
const res = await llm.invoke("Explain retrieval-augmented generation in one sentence.");
console.log(res.content);6. Agents + tool calling
LangChain agents (React, tool-calling, structured-output) work end-to-end because Leanroute forwards the tools and tool_calls fields to the upstream unchanged. Any model that supports tool calling upstream supports it via us — every flagship SKU today does.
from langchain.agents import create_react_agent, AgentExecutor
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
@tool
def get_weather(city: str) -> str:
"""Return the current temperature for a city."""
return f"{city}: 22°C"
llm = ChatOpenAI(
model="anthropic/claude-sonnet-4-6",
api_key="gw_live_YOUR_KEY",
base_url="https://api.leanroute.dev/v1",
)
# Tool calling works because Leanroute proxies function_call / tool_calls
# transparently. Model must support tools (all flagship models do).
agent = create_react_agent(llm, tools=[get_weather])
executor = AgentExecutor(agent=agent, tools=[get_weather], verbose=True)
print(executor.invoke({"input": "What's the weather in Singapore?"}))Optional: cross-provider fallback
Enable the cross-provider failover toggle in /dashboard/settings and any 5xx from your chosen provider (e.g. Anthropic 529 overload) will retry on the cheapest same-tier alternative. Your LangChain code doesn't change; the retry is transparent from the SDK's perspective. Response header x-gateway-routing tells you which provider actually served the request.
Troubleshooting
- 401 unauthenticated: the key was rotated or revoked. Issue a new one at /dashboard/keys.
- 400 unknown_model: the model name doesn't match our canonical list. The provider prefix is required (use
anthropic/claude-sonnet-4-6, notclaude-sonnet-4-6). - Tool calls not firing: confirm the model supports tools upstream (all flagship models do; some cheap_fast SKUs like
glm/glm-4.7-flashxdo not). Check the model page at /models for tool-calling support. - Async streaming hangs: if you're using
astream()ensure your outer loop is inside anasync def. Sync streaming works from anywhere.