LangChain Output Strategies
LangChain provides three structured output strategies. Understanding their differences and how they work can help you make the best choice in different scenarios.
Overview of Three Strategies
| Strategy | Principle | Model Support | Response Speed |
|---|---|---|---|
| ToolStrategy | Disguises the Schema as a tool; the model "calls" this tool to output structured data | All models that support function calling | Slower (one extra tool call) |
| ProviderStrategy | Uses the model's native structured output capability (e.g., OpenAI's response_format) | Some models (GPT-4o+, Claude 3+, etc.) | Faster (direct output) |
| AutoStrategy | Automatically detects model capabilities and selects the best strategy | Automatic adaptation | Automatically selects the optimal |
ToolStrategy — Tool Calling Mode
ToolStrategy is the most compatible approach. It converts your Schema into a "fake tool," and the model outputs structured data by calling this tool.
Example
from langchain.agents import create_agent
from langchain.agents.structured_output import ToolStrategy
from langchain.chat_models import init_chat_model
from langchain.messages import HumanMessage
class WeatherReport(BaseModel):
"""Weather Report"""
city: str = Field(description="City name")
temperature: float = Field(description="Temperature (Celsius)")
condition: str = Field(description="Weather condition")
humidity: int = Field(description="Humidity percentage")
model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)
# Explicitly specify using ToolStrategy
agent = create_agent(
model=model,
response_format=ToolStrategy(schema=WeatherReport),
system_prompt="You are a weather assistant. Generate a structured weather report based on the user's description.",
)
result = agent.invoke({
"messages": [HumanMessage(content="Hangzhou is sunny today, 25 degrees, humidity 60%")]
})
report = result["structured_response"]
print(f"City: {report.city}")
print(f"Temperature: {report.temperature}°C")
print(f"Condition: {report.condition}")
print(f"Humidity: {report.humidity}%")
# View the execution process — you can see an extra tool call message
print(f"\n"Total messages: {len(result['messages'])}")
for msg in result["messages"]:
print(f" [{msg.type}]", end="")
if hasattr(msg, 'tool_calls') and msg.tool_calls:
print(f" Calls: {[tc['name'] for tc in msg.tool_calls]}")
elif msg.type == "tool":
print(f" {msg.content[:60]}")
else:
print(f" {str(msg.content)[:60]}")
Output:
City: 杭州 Temperature: 25.0°C Condition: 晴天 Humidity: 60% Total messages: 4 [human] 杭州今天晴天,温度25度,湿度60% [ai] 调用: ['WeatherReport'] [tool] Returning structured response: ... [ai]
You can see that ToolStrategy adds an extra tool calling step (calling a "fake tool" named WeatherReport) before producing the structured output.
handle_errors — Error Retry
ToolStrategy supports automatic retry when structured output fails:
Example
# handle_errors=True: when the output format is wrong, feed the error message back to the model to retry
strategy_with_retry = ToolStrategy(
schema=WeatherReport,
handle_errors=True, # Default is False
)
# handle_errors can also be a custom error message template
strategy_custom_error = ToolStrategy(
schema=WeatherReport,
handle_errors="The format is incorrect. Please correct it according to {error} and output again.",
)
ProviderStrategy — Native Structured Output
ProviderStrategy uses the model provider's native capabilities (such as OpenAI's response_format parameter). Not all models support it.
Example
from langchain.agents import create_agent
from langchain.agents.structured_output import ProviderStrategy
from langchain.chat_models import init_chat_model
from langchain.messages import HumanMessage
class CourseInfo(BaseModel):
"""Course Information"""
name: str = Field(description="Course name")
level: str = Field(description="Difficulty: Beginner/Intermediate/Advanced")
price: str = Field(description="Price information")
model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)
# Explicitly specify ProviderStrategy
agent = create_agent(
model=model,
response_format=ProviderStrategy(schema=CourseInfo),
system_prompt="You are the course assistant for EXAMPLE.",
)
result = agent.invoke({
"messages": [HumanMessage(content="The Python 3 basics tutorial is a free beginner-level course")]
})
course = result["structured_response"]
print(f"Course: {course.name}")
print(f"Difficulty: {course.level}")
print(f"Price: {course.price}")
print(f"\n"Number of messages: {len(result['messages'])}") # Fewer than ToolStrategy
Output:
Course: Python3 基础教程 Difficulty: 入门 Price: 免费 Message count: 2
Compared with ToolStrategy, ProviderStrategy has fewer messages (2 vs 4) because it does not require an extra tool calling step.
ProviderStrategy is currently mainly supported by OpenAI's GPT-4o and above, and Claude 3 and above. If the model does not support it, LangChain will automatically fall back to ToolStrategy. You can check whether the model supports it via model.profile.
AutoStrategy — Automatic Selection
This is the most recommended approach. Pass in a Pydantic model (instead of a strategy object), and LangChain will automatically select the best strategy:
Example
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model
from langchain.messages import HumanMessage
class Analysis(BaseModel):
"""Analysis Result"""
summary: str = Field(description="One-sentence summary")
score: int = Field(description="Score 1~10")
pros: list[str] = Field(description="List of pros")
cons: list[str] = Field(description="List of cons")
# Directly pass in a Pydantic model — LangChain automatically selects the strategy
model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)
agent = create_agent(
model=model,
response_format=Analysis, # Directly pass the model; the strategy is selected automatically
system_prompt="You are a course evaluation expert. Evaluate the course described by the user.",
)
result = agent.invoke({
"messages": [HumanMessage(
content="EXAMPLE's Python course: comprehensive and systematic content,"
"rich in examples, and completely free. However, video tutorials are limited,"
"and advanced content coverage is insufficient."
)]
})
analysis = result["structured_response"]
print(f"Summary: {analysis.summary}")
print(f"Score: {analysis.score}/10")
print(f"Pros: {', '.join(analysis.pros)}")
print(f"Cons: {', '.join(analysis.cons)}")
Output:
Summary: Example Python 课程内容系统且免费,但缺乏视频教学和高级内容 Rating: 7/10 Pros: 内容系统全面, 实例丰富, 完全免费 Cons: 视频教程较少, 高级内容覆盖不够
Guide to Choosing Among Three Strategies
| Scenario | Recommended Strategy | Reason |
|---|---|---|
| Not sure whether the model supports native output | AutoStrategy (directly pass Pydantic) | Automatically selects the best strategy |
| Need to be compatible with various models | ToolStrategy | Works with all models that support function calling |
| Pursuing maximum performance | ProviderStrategy | Skips the tool calling step, faster |
| Need error retry | ToolStrategy(handle_errors=True) | Only ToolStrategy supports handle_errors |
Other ExtensionsIn most cases, directly passing a Pydantic model (i.e., using AutoStrategy) is sufficient. Only when you need error retry or explicit control over strategy behavior do you need to explicitly specify ToolStrategy or ProviderStrategy.