LangChain
Use ChatOpenAI from langchain-openai against Melious — chains, agents, RAG, tool calling, all unchanged
LangChain is a Python and JavaScript framework for composing LLM applications: chains, agents, tool calling, retrieval, and structured outputs, all behind uniform interfaces. Providers are modular — first-party packages wrap OpenAI, Anthropic, and a long tail of others, each accepting a base-URL override. For OpenAI-shape endpoints like Melious, langchain-openai is the right entry point: it's maintained by the LangChain team, updated the day OpenAI ships something new, and works unchanged against us. Point ChatOpenAI at our base URL and you inherit that pace.
Setup
Install
pip install langchain langchain-openai langchain-community duckduckgo-searchlangchain-community and duckduckgo-search are only needed for the agent example below. Drop them if you're not building an agent.
npm install langchain @langchain/openai @langchain/coreExport your key
export MELIOUS_API_KEY=sk-mel-<YOUR_API_KEY>Create an LLM
import os
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
base_url="https://api.melious.ai/v1",
api_key=os.environ["MELIOUS_API_KEY"],
model="glm-5.1",
)
response = llm.invoke("Name three Hanseatic cities.")
print(response.content)import { ChatOpenAI } from '@langchain/openai';
const llm = new ChatOpenAI({
configuration: { baseURL: 'https://api.melious.ai/v1' },
apiKey: process.env.MELIOUS_API_KEY,
model: 'glm-5.1',
});
const response = await llm.invoke('Name three Hanseatic cities.');
console.log(response.content);LangChain treats the instance as any other ChatOpenAI — runnables, chains, with_structured_output, bind_tools, streaming all work.
Build a tool-calling agent
from langchain.agents import AgentExecutor, create_tool_calling_agent
from langchain_core.prompts import ChatPromptTemplate
from langchain_community.tools import DuckDuckGoSearchRun
tools = [DuckDuckGoSearchRun()]
prompt = ChatPromptTemplate.from_messages([
("system", "You are a careful researcher."),
("human", "{input}"),
("placeholder", "{agent_scratchpad}"),
])
agent = create_tool_calling_agent(llm, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools, max_iterations=6)
result = executor.invoke({
"input": "What's the historical capital of the Hanseatic League?"
})
print(result["output"])Tool calls flow through Melious' OpenAI-compatible tool_calls schema, so LangChain's agent loop behaves the same as against OpenAI — including parallel_tool_calls and streaming tool events.
LangChain 1.0 idiom. Fresh projects should use from langchain.agents import create_agent — built on LangGraph, with a flexible middleware system. The older create_tool_calling_agent + AgentExecutor API still works and is fine for a single example, but create_agent is the long-term-supported path. The earlier langgraph.prebuilt.create_react_agent import is deprecated; the prebuilt moved into langchain.agents and was renamed to create_agent in v1.
Structured outputs
from pydantic import BaseModel, Field
class City(BaseModel):
name: str
league: str = Field(description="The trading league the city belonged to")
class Cities(BaseModel):
cities: list[City]
structured_llm = llm.with_structured_output(Cities)
result = structured_llm.invoke("List three Hanseatic cities.")
print(result.cities)with_structured_output(Schema) defaults to tool-calling under the hood — it binds the schema as a forced function call and parses the result. Pass method="json_mode" if you need raw JSON-mode instead. Stronger models hit schemas more reliably; glm-5.1 is a safe default. Browse melious.ai/hub/models for alternatives.
Streaming
for chunk in llm.stream("Summarize GDPR in two sentences."):
print(chunk.content, end="", flush=True)Works against every chat model we run.
Embeddings and RAG
from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import FAISS
embeddings = OpenAIEmbeddings(
base_url="https://api.melious.ai/v1",
api_key=os.environ["MELIOUS_API_KEY"],
model="bge-m3",
check_embedding_ctx_length=False,
)
docs = [...] # your Document list
vectorstore = FAISS.from_documents(docs, embeddings)check_embedding_ctx_length=False is important — LangChain's default uses tiktoken to estimate input length, but our embedding models use their own tokenizers. Turning the check off bypasses the mismatch; we enforce context length server-side anyway.
Fallbacks
LangChain's .with_fallbacks() chains instances:
primary = ChatOpenAI(base_url="https://api.melious.ai/v1", model="glm-5.1")
secondary = ChatOpenAI(base_url="https://api.melious.ai/v1", model="<FALLBACK_MODEL_ID>")
chain = primary.with_fallbacks([secondary])
chain.invoke("Hello.")If the primary call errors, LangChain transparently retries against the secondary. Useful for chaining a stronger model behind a faster one, or hedging against provider outages.
What's different
langchain-communityproviders are unnecessary. Some third-party LangChain providers try to replicate OpenAI compatibility and lag behind. Usinglangchain-openaiwith a base URL override is faster and more reliable.- Callbacks still fire.
StreamingStdOutCallbackHandler, custom callbacks, and LangSmith tracing work normally. - Extra response fields (
environment_impact,billing_cost) aren't in LangChain's typed response objects. Pull them fromresponse.response_metadataif you need them.
When it breaks
InvalidRequestError: unknown model— model ID typo.GET /v1/modelsfor the canonical list.- Tokens-per-minute rate limit hit early — big chains accumulate. Switch to streaming; it reduces peak concurrent tokens. See Rate limits.
- Agent goes in circles — the model is too weak for the tool set. Upgrade to
glm-5.1or another strong tool-calling model from melious.ai/hub/models.
Errors and retry patterns: Errors.