Skip to main content
代理将语言模型与工具结合起来,创建能够推理任务、决定使用哪些工具并迭代解决方案的系统。 create_agent 提供了一个生产就绪的代理实现。 一个 LLM 代理在循环中运行工具以实现目标。 代理运行直到满足停止条件——即模型发出最终输出或达到迭代限制。
create_agent 使用 LangGraph 构建了一个基于的代理运行时。图由节点(步骤)和边(连接)组成,定义了代理如何处理信息。代理通过此图移动,执行诸如模型节点(调用模型)、工具节点(执行工具)或中间件的节点。了解更多关于 Graph API 的信息。

核心组件

模型

模型是代理的推理引擎。它可以以多种方式指定,支持静态和动态模型选择。

静态模型

静态模型在创建代理时配置一次,执行过程中保持不变。这是最常见的直接方法。 要从一个 初始化一个静态模型:
from langchain.agents import create_agent

agent = create_agent("openai:gpt-5", tools=tools)
模型标识符字符串支持自动推断(例如,"gpt-5" 会被推断为 "openai:gpt-5")。参见 参考 以查看完整的模型标识符字符串映射表。
对于模型配置的更多控制,直接使用提供者包初始化模型实例。在这个例子中,我们使用 ChatOpenAI。参见 Chat models 以查看其他可用的聊天模型类。
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI

model = ChatOpenAI(
    model="gpt-5",
    temperature=0.1,
    max_tokens=1000,
    timeout=30
    # ... (other params)
)
agent = create_agent(model, tools=tools)
模型实例给你完全的配置控制。使用它们时,你需要设置特定的 参数temperature, max_tokens, timeouts, base_url, 和其他提供者特定的设置。参见 参考 以查看可用的参数和方法。

动态模型

动态模型在 基于当前 和上下文进行选择。这使得复杂的路由逻辑和成本优化成为可能。 要使用动态模型,创建中间件使用 @wrap_model_call 装饰器,该装饰器在请求中修改模型:
from langchain_openai import ChatOpenAI
from langchain.agents import create_agent
from langchain.agents.middleware import wrap_model_call, ModelRequest, ModelResponse


basic_model = ChatOpenAI(model="gpt-4.1-mini")
advanced_model = ChatOpenAI(model="gpt-4.1")

@wrap_model_call
def dynamic_model_selection(request: ModelRequest, handler) -> ModelResponse:
    """Choose model based on conversation complexity."""
    message_count = len(request.state["messages"])

    if message_count > 10:
        # Use an advanced model for longer conversations
        model = advanced_model
    else:
        model = basic_model

    return handler(request.override(model=model))

agent = create_agent(
    model=basic_model,  # Default model
    tools=tools,
    middleware=[dynamic_model_selection]
)
Pre-bound models (models with bind_tools already called) are not supported when using structured output. If you need dynamic model selection with structured output, ensure the models passed to the middleware are not pre-bound.
For model configuration details, see Models. For dynamic model selection patterns, see Dynamic model in middleware.

工具

工具给代理提供了采取行动的能力。代理超越了简单的模型工具绑定,通过促进:
  • 多个工具调用的序列(由单个提示触发)
  • 适当时候的并行工具调用
  • 基于先前结果的动态工具选择
  • 工具重试逻辑和错误处理
  • 工具调用之间的状态持久性
更多信息,请参见 Tools

静态工具

静态工具在创建代理时定义,执行过程中保持不变。这是最常见的直接方法。 要定义一个带有静态工具的代理,将工具列表传递给代理。
工具可以指定为普通的 Python 函数或 工具装饰器 可以用于自定义工具名、描述、参数模式和其他属性。
from langchain.tools import tool
from langchain.agents import create_agent


@tool
def search(query: str) -> str:
    """Search for information."""
    return f"Results for: {query}"

@tool
def get_weather(location: str) -> str:
    """Get weather information for a location."""
    return f"Weather in {location}: Sunny, 72°F"

agent = create_agent(model, tools=[search, get_weather])
如果提供了一个空的工具列表,代理将由一个单一的 LLM 节点组成,没有工具调用能力。

动态工具

与动态工具,代理在运行时修改可用工具的集合,而不是在一开始就定义。不是每个工具都适合每个情况。太多工具可能会使模型过载(超出上下文)并增加错误;太少则限制了能力。动态工具选择使代理能够根据认证状态、用户权限、功能标志或对话阶段来适应可用工具集。 有两种方法,取决于工具是否在运行时已知:
当所有可能的工具在代理创建时都已知,你可以预注册它们,并基于状态、权限或上下文动态过滤哪些工具暴露给模型。
只有在达到某些对话里程碑后才启用高级工具:
from langchain.agents import create_agent
from langchain.agents.middleware import wrap_model_call, ModelRequest, ModelResponse
from typing import Callable

@wrap_model_call
def state_based_tools(
    request: ModelRequest,
    handler: Callable[[ModelRequest], ModelResponse]
) -> ModelResponse:
    """Filter tools based on conversation State."""
    # Read from State: check if user has authenticated
    state = request.state
    is_authenticated = state.get("authenticated", False)
    message_count = len(state["messages"])

    # Only enable sensitive tools after authentication
    if not is_authenticated:
        tools = [t for t in request.tools if t.name.startswith("public_")]
        request = request.override(tools=tools)
    elif message_count < 5:
        # Limit tools early in conversation
        tools = [t for t in request.tools if t.name != "advanced_search"]
        request = request.override(tools=tools)

    return handler(request)

agent = create_agent(
    model="gpt-4.1",
    tools=[public_search, private_search, advanced_search],
    middleware=[state_based_tools]
)
This approach is best when:
  • All possible tools are known at compile/startup time
  • You want to filter based on permissions, feature flags, or conversation state
  • Tools are static but their availability is dynamic
See Dynamically selecting tools for more examples.
To learn more about tools, see Tools.

Tool error handling

To customize how tool errors are handled, use the @wrap_tool_call decorator to create middleware:
from langchain.agents import create_agent
from langchain.agents.middleware import wrap_tool_call
from langchain.messages import ToolMessage


@wrap_tool_call
def handle_tool_errors(request, handler):
    """Handle tool execution errors with custom messages."""
    try:
        return handler(request)
    except Exception as e:
        # Return a custom error message to the model
        return ToolMessage(
            content=f"Tool error: Please check your input and try again. ({str(e)})",
            tool_call_id=request.tool_call["id"]
        )

agent = create_agent(
    model="gpt-4.1",
    tools=[search, get_weather],
    middleware=[handle_tool_errors]
)
The agent will return a ToolMessage with the custom error message when a tool fails:
[
    ...
    ToolMessage(
        content="Tool error: Please check your input and try again. (division by zero)",
        tool_call_id="..."
    ),
    ...
]

Tool use in the ReAct loop

Agents follow the ReAct (“Reasoning + Acting”) pattern, alternating between brief reasoning steps with targeted tool calls and feeding the resulting observations into subsequent decisions until they can deliver a final answer.
Prompt: Identify the current most popular wireless headphones and verify availability.
================================ Human Message =================================

Find the most popular wireless headphones right now and check if they're in stock
  • Reasoning: “Popularity is time-sensitive, I need to use the provided search tool.”
  • Acting: Call search_products("wireless headphones")
================================== Ai Message ==================================
Tool Calls:
  search_products (call_abc123)
 Call ID: call_abc123
  Args:
    query: wireless headphones
================================= Tool Message =================================

Found 5 products matching "wireless headphones". Top 5 results: WH-1000XM5, ...
  • Reasoning: “I need to confirm availability for the top-ranked item before answering.”
  • Acting: Call check_inventory("WH-1000XM5")
================================== Ai Message ==================================
Tool Calls:
  check_inventory (call_def456)
 Call ID: call_def456
  Args:
    product_id: WH-1000XM5
================================= Tool Message =================================

Product WH-1000XM5: 10 units in stock
  • Reasoning: “I have the most popular model and its stock status. I can now answer the user’s question.”
  • Acting: Produce final answer
================================== Ai Message ==================================

I found wireless headphones (model WH-1000XM5) with 10 units in stock...

System prompt

You can shape how your agent approaches tasks by providing a prompt. The system_prompt parameter can be provided as a string:
agent = create_agent(
    model,
    tools,
    system_prompt="You are a helpful assistant. Be concise and accurate."
)
When no system_prompt is provided, the agent will infer its task from the messages directly. The system_prompt parameter accepts either a str or a SystemMessage. Using a SystemMessage gives you more control over the prompt structure, which is useful for provider-specific features like Anthropic’s prompt caching:
from langchain.agents import create_agent
from langchain.messages import SystemMessage, HumanMessage

literary_agent = create_agent(
    model="anthropic:claude-sonnet-4-5",
    system_prompt=SystemMessage(
        content=[
            {
                "type": "text",
                "text": "You are an AI assistant tasked with analyzing literary works.",
            },
            {
                "type": "text",
                "text": "<the entire contents of 'Pride and Prejudice'>",
                "cache_control": {"type": "ephemeral"}
            }
        ]
    )
)

result = literary_agent.invoke(
    {"messages": [HumanMessage("Analyze the major themes in 'Pride and Prejudice'.")]}
)
The cache_control field with {"type": "ephemeral"} tells Anthropic to cache that content block, reducing latency and costs for repeated requests that use the same system prompt.

Dynamic system prompt

For more advanced use cases where you need to modify the system prompt based on runtime context or agent state, you can use middleware. The @dynamic_prompt decorator creates middleware that generates system prompts based on the model request:
from typing import TypedDict

from langchain.agents import create_agent
from langchain.agents.middleware import dynamic_prompt, ModelRequest


class Context(TypedDict):
    user_role: str

@dynamic_prompt
def user_role_prompt(request: ModelRequest) -> str:
    """Generate system prompt based on user role."""
    user_role = request.runtime.context.get("user_role", "user")
    base_prompt = "You are a helpful assistant."

    if user_role == "expert":
        return f"{base_prompt} Provide detailed technical responses."
    elif user_role == "beginner":
        return f"{base_prompt} Explain concepts simply and avoid jargon."

    return base_prompt

agent = create_agent(
    model="gpt-4.1",
    tools=[web_search],
    middleware=[user_role_prompt],
    context_schema=Context
)

# The system prompt will be set dynamically based on context
result = agent.invoke(
    {"messages": [{"role": "user", "content": "Explain machine learning"}]},
    context={"user_role": "expert"}
)
For more details on message types and formatting, see Messages. For comprehensive middleware documentation, see Middleware.

Name

Set an optional name for the agent. This is used as the node identifier when adding the agent as a subgraph in multi-agent systems:
agent = create_agent(
    model,
    tools,
    name="research_assistant"
)
Prefer snake_case for agent names (e.g., research_assistant instead of Research Assistant). Some model providers reject names containing spaces or special characters with errors. Using alphanumeric characters, underscores, and hyphens only ensures compatibility across all providers. The same applies to tool names.

Invocation

You can invoke an agent by passing an update to its State. All agents include a sequence of messages in their state; to invoke the agent, pass a new message:
result = agent.invoke(
    {"messages": [{"role": "user", "content": "What's the weather in San Francisco?"}]}
)
For streaming steps and / or tokens from the agent, refer to the streaming guide. Otherwise, the agent follows the LangGraph Graph API and supports all associated methods, such as stream and invoke.
Use LangSmith to trace, debug, and evaluate your agents.

Advanced concepts

Structured output

In some situations, you may want the agent to return an output in a specific format. LangChain provides strategies for structured output via the response_format parameter.

ToolStrategy

ToolStrategy uses artificial tool calling to generate structured output. This works with any model that supports tool calling. ToolStrategy should be used when provider-native structured output (via ProviderStrategy) is not available or reliable.
from pydantic import BaseModel
from langchain.agents import create_agent
from langchain.agents.structured_output import ToolStrategy


class ContactInfo(BaseModel):
    name: str
    email: str
    phone: str

agent = create_agent(
    model="gpt-4.1-mini",
    tools=[search_tool],
    response_format=ToolStrategy(ContactInfo)
)

result = agent.invoke({
    "messages": [{"role": "user", "content": "Extract contact info from: John Doe, john@example.com, (555) 123-4567"}]
})

result["structured_response"]
# ContactInfo(name='John Doe', email='john@example.com', phone='(555) 123-4567')

ProviderStrategy

ProviderStrategy uses the model provider’s native structured output generation. This is more reliable but only works with providers that support native structured output:
from langchain.agents.structured_output import ProviderStrategy

agent = create_agent(
    model="gpt-4.1",
    response_format=ProviderStrategy(ContactInfo)
)
As of langchain 1.0, simply passing a schema (e.g., response_format=ContactInfo) will default to ProviderStrategy if the model supports native structured output. It will fall back to ToolStrategy otherwise.
To learn about structured output, see Structured output.

Memory

Agents maintain conversation history automatically through the message state. You can also configure the agent to use a custom state schema to remember additional information during the conversation. Information stored in the state can be thought of as the short-term memory of the agent: Custom state schemas must extend AgentState as a TypedDict. There are two ways to define custom state:
  1. Via middleware (preferred)
  2. Via state_schema on create_agent

Defining state via middleware

Use middleware to define custom state when your custom state needs to be accessed by specific middleware hooks and tools attached to said middleware.
from langchain.agents import AgentState
from langchain.agents.middleware import AgentMiddleware
from typing import Any


class CustomState(AgentState):
    user_preferences: dict

class CustomMiddleware(AgentMiddleware):
    state_schema = CustomState
    tools = [tool1, tool2]

    def before_model(self, state: CustomState, runtime) -> dict[str, Any] | None:
        ...

agent = create_agent(
    model,
    tools=tools,
    middleware=[CustomMiddleware()]
)

# The agent can now track additional state beyond messages
result = agent.invoke({
    "messages": [{"role": "user", "content": "I prefer technical explanations"}],
    "user_preferences": {"style": "technical", "verbosity": "detailed"},
})

Defining state via state_schema

Use the state_schema parameter as a shortcut to define custom state that is only used in tools.
from langchain.agents import AgentState


class CustomState(AgentState):
    user_preferences: dict

agent = create_agent(
    model,
    tools=[tool1, tool2],
    state_schema=CustomState
)
# The agent can now track additional state beyond messages
result = agent.invoke({
    "messages": [{"role": "user", "content": "I prefer technical explanations"}],
    "user_preferences": {"style": "technical", "verbosity": "detailed"},
})
As of langchain 1.0, custom state schemas must be TypedDict types. Pydantic models and dataclasses are no longer supported. See the v1 migration guide for more details.
Defining custom state via middleware is preferred over defining it via state_schema on create_agent because it allows you to keep state extensions conceptually scoped to the relevant middleware and tools.state_schema is still supported for backwards compatibility on create_agent.
To learn more about memory, see Memory. For information on implementing long-term memory that persists across sessions, see Long-term memory.

Streaming

We’ve seen how the agent can be called with invoke to get a final response. If the agent executes multiple steps, this may take a while. To show intermediate progress, we can stream back messages as they occur.
from langchain.messages import AIMessage, HumanMessage

for chunk in agent.stream({
    "messages": [{"role": "user", "content": "Search for AI news and summarize the findings"}]
}, stream_mode="values"):
    # Each chunk contains the full state at that point
    latest_message = chunk["messages"][-1]
    if latest_message.content:
        if isinstance(latest_message, HumanMessage):
            print(f"User: {latest_message.content}")
        elif isinstance(latest_message, AIMessage):
            print(f"Agent: {latest_message.content}")
    elif latest_message.tool_calls:
        print(f"Calling tools: {[tc['name'] for tc in latest_message.tool_calls]}")
For more details on streaming, see Streaming.

Middleware

Middleware provides powerful extensibility for customizing agent behavior at different stages of execution. You can use middleware to:
  • Process state before the model is called (e.g., message trimming, context injection)
  • Modify or validate the model’s response (e.g., guardrails, content filtering)
  • Handle tool execution errors with custom logic
  • Implement dynamic model selection based on state or context
  • Add custom logging, monitoring, or analytics
Middleware integrates seamlessly into the agent’s execution, allowing you to intercept and modify data flow at key points without changing the core agent logic.
For comprehensive middleware documentation including decorators like @before_model, @after_model, and @wrap_tool_call, see Middleware.