LangChain Python
ChatOpenAI from langchain-openai. For Claude through the Messages API use LangChain Python (ChatAnthropic); for Gemini, LangChain Google GenAI.
Connect
py
def chat_model(model, **overrides):
from langchain_openai import ChatOpenAI
settings = {
"base_url": os.environ["PLUGBOARD_BASE_URL"], # ends in /v1
"api_key": os.environ["PLUGBOARD_KEY"],
"model": model,
"use_responses_api": False, # Chat Completions. Left unset, a gpt-5.6 id can switch to /v1/responses
**NO_RETRIES,
}
if model == "fast":
settings["max_tokens"] = 1024 # fast is a reasoning model: leave room for the answer after its thinking
settings.update(overrides)
return ChatOpenAI(**settings)Set use_responses_api=False to stay on Chat Completions: otherwise some model ids (gpt-5.6...) switch the client to the Responses API.
Chat
py
message = client(model).invoke("Reply with exactly: pong")Tool calls
py
@tool
def get_weather(city: str) -> str:
"""Current weather for a city."""
return TOOL_RESULTpy
llm = client(model).bind_tools([get_weather])
first = llm.invoke(messages)
call = first.tool_calls[0] # {"name", "args", "id"}; the id goes back on the ToolMessage
messages += [first, ToolMessage(content=get_weather.invoke(call["args"]), tool_call_id=call["id"])]
second = llm.invoke(messages)Structured output
llm.with_structured_output(Meal, method="json_schema") and method="function_calling" both work. Avoid method="json_mode": it sends no schema, so the model guesses the keys.
Responses API
ChatOpenAI(use_responses_api=True, ...) sends the same calls to /v1/responses:
py
def responses_model(model, **overrides):
"""The same client on the Responses API (`/v1/responses`). Set explicitly: LangChain also switches on its own for gpt-5.6 ids."""
return chat_model(model, use_responses_api=True, **overrides)On that route LangChain exposes no finish_reason; read response_metadata["status"] instead.
Limits
- LangChain has no model-list call. Use the wrapped client:
llm.root_client.models.list(). - Errors are the
openaipackage's:AuthenticationError(401),NotFoundError(404).