What is ChatOpenAI?
ChatOpenAI is the LangChain wrapper around OpenAI's chat completions API. It is the most-used chat model in the ecosystem and the default reference implementation that newer providers (Anthropic, Google, Mistral) try to stay compatible with. The class accepts a list of BaseMessage objects (HumanMessage, SystemMessage, AIMessage, ToolMessage) and returns an AIMessage containing the model response, token usage, and any tool calls the model decided to make.
Under the hood it speaks the /v1/chat/completions endpoint and supports every modern OpenAI feature: streaming via server-sent events, structured output through JSON mode and response_format, tool calling, vision inputs on the gpt-4o family, and reasoning tokens on the o-series models. Token counts come back on response_metadata.token_usage so you can wire up cost tracking without a callback. The same instance exposes invoke, ainvoke, stream, astream, and batch so you rarely need to think about sync vs async.
The class moved from langchain.chat_models to its own langchain-openai package in the 0.1 split and the legacy import path was dropped in 0.2. Configure the API key with the OPENAI_API_KEY env var, or pass api_key directly for multi-tenant apps. For Azure OpenAI deployments use the sibling AzureChatOpenAI class — same surface, different auth and endpoint.
When to Use
You need OpenAI's chat models for production reasoning, tool calling, or multimodal input. Use ChatOpenAI as the default starting point when prototyping any LangChain agent or chain — every example in the docs assumes it, and you can swap providers later through the common Runnable interface.
Use Cases
- • Building AI chatbots and assistants
- • Question-answering and RAG pipelines
- • Code generation and refactoring
- • Tool-calling agents
- • Structured data extraction with JSON mode
- • Vision understanding on gpt-4o
- • Long-form reasoning with o1 / o3
Key Features
- ✓ Multiple models (GPT-4o, GPT-4.1, o1, o3, GPT-3.5-turbo)
- ✓ Token usage on response_metadata
- ✓ Streaming via stream / astream
- ✓ Tool calling with bind_tools
- ✓ Structured output via with_structured_output
- ✓ Vision inputs on gpt-4o family
- ✓ Azure variant via AzureChatOpenAI
When NOT to Use
For non-OpenAI models or local inference (use ChatOllama, ChatHuggingFace). Skip if data residency rules prevent sending prompts to OpenAI — use AzureChatOpenAI in your tenant region or a self-hosted model instead. For latency-critical embedding lookups, don't call a chat model — use OpenAIEmbeddings.
Notes
Streaming returns AIMessageChunk, not strings
model.stream() yields AIMessageChunk objects. The text lives on .content but chunks may also carry tool_call_chunks during function calling. If you concatenate chunks for a final message, use chunk1 + chunk2 (the class implements __add__) rather than string concatenation — that way tool calls and usage metadata survive the merge.
Token usage is on response_metadata, not the chunks
When streaming, usage normally arrives on the final empty chunk. To get it reliably, pass stream_usage=True (added in langchain-openai 0.1.9) or read response_metadata.token_usage on the merged AIMessage. The legacy get_openai_callback context manager still works but is being phased out — prefer the usage_metadata field on the response.
Rate limits and retries
ChatOpenAI retries on 429 and 5xx by default (max_retries=2). Bump max_retries and set a sensible timeout for production. For high-throughput pipelines use the .batch() method, which parallelises requests under a single RateLimitError-aware semaphore instead of spawning your own threads.
Tool calling vs. legacy functions
OpenAI deprecated the functions / function_call API in favour of tools / tool_choice. bind_tools() targets the new API; the older bind_functions() still exists for compatibility but emits a DeprecationWarning. Always prefer bind_tools — it returns AIMessage.tool_calls in a normalised shape that works across OpenAI, Anthropic, and Google providers.
gpt-4o vs o-series reasoning models
o1 and o3 are reasoning models — they ignore temperature, system messages are treated as developer messages, and they bill for hidden reasoning tokens that you cannot see but pay for. Do not pass streaming=True with o1-preview; it is not supported. For everyday chat, multimodal input, and tool use, stick with gpt-4o or gpt-4.1.
Import
from langchain_openai import ChatOpenAI
Initialization Parameters
| Parameter | Type | Default | Purpose |
|---|---|---|---|
| model | str | gpt-3.5-turbo | Model name (e.g., 'gpt-4o', 'gpt-4.1', 'o3-mini') |
| temperature | float | 0.7 | Sampling temperature. 0 for deterministic, 1+ for creative. Ignored on o-series. |
| max_tokens | int | None | None | Cap on completion tokens. None lets the model use the full context window. |
| max_retries | int | 2 | Automatic retries on 429 / 5xx errors before raising. |
| api_key | str | None | None | OpenAI API key. Falls back to OPENAI_API_KEY env var if omitted. |
Code Examples
Basic invocation
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
model = ChatOpenAI(model='gpt-4o', temperature=0)
result = model.invoke([HumanMessage(content='Hi')])
print(result.content)
Streaming tokens
from langchain_openai import ChatOpenAI
model = ChatOpenAI(model='gpt-4o', streaming=True)
for chunk in model.stream('Explain transformers in one paragraph'):
print(chunk.content, end='', flush=True)
Tool calling with Pydantic schema
from langchain_openai import ChatOpenAI
from pydantic import BaseModel, Field
class Weather(BaseModel):
city: str = Field(description='City name')
unit: str = Field(description='celsius or fahrenheit')
model = ChatOpenAI(model='gpt-4o').bind_tools([Weather])
result = model.invoke('What is the weather in Paris in C?')
print(result.tool_calls)
Retries and timeouts for production
from langchain_openai import ChatOpenAI
from openai import RateLimitError
model = ChatOpenAI(
model='gpt-4o',
max_retries=4,
timeout=30,
).with_retry(retry_if_exception_type=(RateLimitError,))
result = model.invoke('Summarise: ' + long_text)
Common Mistakes
❌ model.invoke('hello') # String not wrapped
✅ model.invoke([HumanMessage(content='hello')])
❌ from langchain.chat_models import ChatOpenAI # Legacy path, removed in 0.2
✅ from langchain_openai import ChatOpenAI
❌ ChatOpenAI(model_name='gpt-4o') # Old kwarg, silently ignored in newer versions
✅ ChatOpenAI(model='gpt-4o', temperature=0)
Alternative Models
| Model | When to Use |
|---|---|
| ChatAnthropic | For Claude models with better reasoning |
Related LangChain References
Browse the full LangChain API reference index to explore more classes, methods, and decorators, or start with the LangChain introduction tutorial for end-to-end context on building with ChatOpenAI and the wider framework.
ChatOpenAI FAQ
What is ChatOpenAI in LangChain?
Interact with OpenAI's chat models (GPT-4o, GPT-4.1, o-series, GPT-3.5-turbo) from LangChain. ChatOpenAI is the LangChain wrapper around OpenAI's chat completions API. It is the most-used chat model in the ecosystem and the default reference implementation that newer providers (Anthropic, Google, Mistral) try to stay compatible with. The class accepts a list of BaseMessage objects (HumanMessage, SystemMessage, AIMessage, ToolMessage) and returns an AIMessage containing the model response, token usage, and any tool calls the model decided to make. Under the hood it sp…
Which package provides ChatOpenAI?
DevShelfHub documents ChatOpenAI from the langchain-openai package. Pin your installed LangChain version and match imports to the snippet on this page.
When should I use ChatOpenAI?
You need OpenAI's chat models for production reasoning, tool calling, or multimodal input. Use ChatOpenAI as the default starting point when prototyping any LangChain agent or chain — every example in the docs assumes it, and you can swap providers later through the common Runnable interface.
When should I avoid using ChatOpenAI?
For non-OpenAI models or local inference (use ChatOllama, ChatHuggingFace). Skip if data residency rules prevent sending prompts to OpenAI — use AzureChatOpenAI in your tenant region or a self-hosted model instead. For latency-critical embedding lookups, don't call a chat model — use OpenAIEmbeddings.
How do I import ChatOpenAI in Python?
from langchain_openai import ChatOpenAI
Where can I explore more LangChain API reference pages?
Open the LangChain API reference index on DevShelfHub to browse classes, methods, and decorators, each with runnable examples, parameters, common mistakes, and cross-links.