npx skills add ...
npx skills add langchain-ai/skills-benchmarks --skill langchain-fundamentals
npx skills add langchain-ai/skills-benchmarks --skill langchain-fundamentals
Create LangChain agents with create_agent, define tools, and use middleware for human-in-the-loop and error handling.
<create_agent>
create_agent() is the recommended way to build agents. It handles the agent loop, tool execution, and state management.
| Parameter | Purpose | Example |
|---|---|---|
model | LLM to use | "anthropic:claude-sonnet-4-5" or model instance |
tools | List of tools | [search, calculator] |
system_prompt / systemPrompt | Agent instructions | "You are a helpful assistant" |
checkpointer | State persistence | MemorySaver() |
middleware | Processing hooks | [HumanInTheLoopMiddleware] (Python) / [humanInTheLoopMiddleware({...})] (TypeScript) |
| </create_agent> |
@tool def get_weather(location: str) -> str: """Get current weather for a location.
agent = create_agent( model="anthropic:claude-sonnet-4-5", tools=[get_weather], system_prompt="You are a helpful assistant." )
result = agent.invoke({ "messages": [{"role": "user", "content": "What's the weather in Paris?"}] }) print(result["messages"][-1].content)
checkpointer = MemorySaver()
agent = create_agent( model="anthropic:claude-sonnet-4-5", tools=[search], checkpointer=checkpointer, )
config = {"configurable": {"thread_id": "user-123"}} agent.invoke({"messages": [{"role": "user", "content": "My name is Alice"}]}, config=config) result = agent.invoke({"messages": [{"role": "user", "content": "What's my name?"}]}, config=config)
Tools are functions that agents can call. Use the @tool decorator (Python) or tool() function (TypeScript).
@tool def calculate(expression: str) -> str: """Evaluate a mathematical expression.
Middleware intercepts the agent loop to add human approval, error handling, logging, and more. A deep understanding of middleware is essential for production agents — use HumanInTheLoopMiddleware (Python) / humanInTheLoopMiddleware (TypeScript) for approval workflows, and @wrap_tool_call (Python) / createMiddleware (TypeScript) for custom hooks.
Key imports:
Key patterns:
middleware=[HumanInTheLoopMiddleware(interrupt_on={"dangerous_tool": True})] — requires checkpointer + thread_idagent.invoke(Command(resume={"decisions": [{"type": "approve"}]}), config=config)@wrap_tool_call decorator (Python) or createMiddleware({ wrapToolCall: ... }) (TypeScript)<structured_output>
Get typed, validated responses from agents using response_format or with_structured_output().
class ContactInfo(BaseModel): name: str email: str phone: str = Field(description="Phone number with area code")
agent = create_agent(model="gpt-4.1", tools=[search], response_format=ContactInfo) result = agent.invoke({"messages": [{"role": "user", "content": "Find contact for John"}]}) print(result["structured_response"]) # ContactInfo(name='John', ...)
from langchain_openai import ChatOpenAI model = ChatOpenAI(model="gpt-4.1") structured_model = model.with_structured_output(ContactInfo) response = structured_model.invoke("Extract: John, john@example.com, 555-1234")
<model_config>
create_agent accepts model strings ("anthropic:claude-sonnet-4-5", "openai:gpt-4.1") or model instances for custom settings:
</model_config>
Clear descriptions help the agent know when to use each tool. ```python # WRONG: Vague or missing description @tool def bad_tool(input: str) -> str: """Does stuff.""" return "result"@tool def search(query: str) -> str: """Search the web for current information about a topic.
from langgraph.checkpoint.memory import MemorySaver
agent = create_agent( model="anthropic:claude-sonnet-4-5", tools=[search], checkpointer=MemorySaver(), ) config = {"configurable": {"thread_id": "session-1"}} agent.invoke({"messages": [{"role": "user", "content": "I'm Bob"}]}, config=config) agent.invoke({"messages": [{"role": "user", "content": "What's my name?"}]}, config=config)
result = agent.invoke( {"messages": [("user", "Do research")]}, config={"recursion_limit": 10}, # Stop after 10 steps )
result = agent.invoke({"messages": [{"role": "user", "content": "Hello"}]}) print(result["messages"][-1].content) # Last message content
from langchain.agents.middleware import HumanInTheLoopMiddleware, wrap_tool_callimport { humanInTheLoopMiddleware, createMiddleware } from "langchain";from langchain_anthropic import ChatAnthropic
agent = create_agent(model=ChatAnthropic(model="claude-sonnet-4-5", temperature=0), tools=[...])