Skip to main content
skill Claude Code CX Codex Cursor GitHub Copilot

langchain-fundamentals — Claude Code skill: install guide

Guides LangChain agent work with create_agent(), tools, and middleware. Use it when you need saved conversation state, approval flows, or error handling.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add langchain-ai/langchain-skills --skill langchain-fundamentals -a claude-code
Open on GitHub

What langchain-fundamentals does

This skill steers LangChain agent implementation toward create_agent(), which handles the agent loop, tool calls, and state management. It covers model selection, tool lists, system prompts, checkpointers, and middleware. Examples use Python and TypeScript.

Define callable tools with the @tool decorator in Python or tool() in TypeScript. MemorySaver can retain state between invocations when used with a thread_id. The skill also covers typed, validated responses through response_format and with_structured_output().

Middleware can intercept the agent loop for human approval, logging, and error handling. HumanInTheLoopMiddleware requires a checkpointer and thread_id, so those are mandatory for approval flows around dangerous tools. Custom hooks use @wrap_tool_call or createMiddleware.

What it helps with

  • build a LangChain agent with create_agent()
  • define a callable tool with @tool
  • keep conversation state across invocations
  • require approval for a dangerous tool call
  • return data matching a typed schema

Example prompts for the agent

  • Create a LangChain agent with `create_agent()`, a search tool, and a system prompt.
  • Add `MemorySaver` and a `thread_id` so the agent retains conversation state.
  • Set up `HumanInTheLoopMiddleware` to approve calls to a dangerous tool.

How to install langchain-fundamentals

1Skills CLI (Vercel)

npx skills add langchain-ai/langchain-skills --skill langchain-fundamentals -a claude-code

2Manually: put the files in place

~/.claude/skills/langchain-fundamentals/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/langchain-fundamentals/

From the same set14

The whole set →
deep-agents-memory langchain-ai A skill that maps where a Deep Agent keeps its files: thread state, a persistent store, or the real disk. Useful once the agent starts dropping context. Claude Code CX Codex Cursor +1 19,000installs langgraph-persistence langchain-ai A Claude Code skill for LangGraph persistence: wiring a checkpointer, keeping conversations apart by thread_id, and replaying older graph state. Claude Code CX Codex Cursor +1 18,000installs langgraph-fundamentals langchain-ai Skill for writing LangGraph code across platforms. Covers StateGraph, state schemas, nodes, edges, Command, Send, invoke, streaming, and error handling. Claude Code CX Codex Cursor +1 18,000installs langchain-rag langchain-ai Equips coding agents with reference RAG implementations in Python and TypeScript using LangChain loaders, splitters, and vector stores. Claude Code CX Codex Cursor +1 17,500installs langgraph-human-in-the-loop langchain-ai Skill for building LangGraph workflows that pause and wait for human input. Use it to show agent output, request approval, or validate user responses before continuing. Claude Code CX Codex Cursor +1 17,200installs langchain-middleware langchain-ai Adds middleware hooks for LangChain agents: pauses execution before dangerous tool calls, lets a human approve, edit or reject the action, intercepts calls for logging and retry logic. Claude Code CX Codex Cursor +1 16,200installs deep-agents-orchestration langchain-ai Guides setup of orchestration in Deep Agents: subagent delegation, todo planning, and human approval interrupts. Claude Code CX Codex Cursor +1 16,100installs langchain-dependencies langchain-ai Provides verified package versions and dependency rules for LangChain, LangGraph, and LangSmith. Helps set up clean Python or TypeScript projects without version conflicts. Claude Code CX Codex Cursor +1 16,000installs

Similar

hugging-science K-Dense-AI A skill to find and evaluate scientific datasets, models, and interactive demos via the Hugging Science catalog. Use it when you need an ML resource for biology, chemistry, genomics, materials science, climate, or physics. Claude Code CX Codex Cursor +1 1,800installs library-curator nexu-io Pulls images, logos and screenshots out of the OD Library and copies the file into your project, handing back a relative path you can drop into markup. Claude Code CX Codex Cursor +1 951installs debug-mantra thananon Sets a debugging sequence from reproducing a failure through testing hypotheses and recording experiments. Use it for errors, logs, and stack traces. Claude Code CX Codex Cursor +1 4,800installs atlassian-mcp https://github.com/Jeffallan Skill connects Jira and Confluence to Claude Code, Cursor, and other editors through MCP protocol. Query tasks with JQL, create tickets, search and edit wiki pages directly from your IDE. Claude Code CX Codex Cursor +1 4,400installs spec-miner https://github.com/Jeffallan A skill for reverse-engineering codebases. Extracts specifications from existing code, maps dependencies, and generates documentation for legacy and undocumented systems. Claude Code CX Codex Cursor +1 4,400installs hud Yeachan-Heo The hud skill configures a HUD display in Claude Code's statusline, showing git branch, context usage, running subagents, and other metrics. Track session state and keep tabs on complex work without losing context. Claude Code CX Codex Cursor +1 1,100installs setup-matt-pocock-skills Matt Pocock This skill configures a repository for Matt Pocock's engineering skills by setting its issue tracker, triage labels, and domain docs layout. Run it before using the other skills. Claude Code 1,052,851installs to-tickets Matt Pocock Turns a plan, spec, or conversation into small end-to-end tickets with explicit blockers. Use it to agree on the work breakdown before tickets go to a tracker. Claude Code 711,230installs

Questions about langchain-fundamentals

How do I install langchain-fundamentals in Claude Code?

Run npx skills add langchain-ai/langchain-skills --skill langchain-fundamentals -a claude-code, then run npx skills add langchain-ai/langchain-skills --skill langchain-fundamentals -a claude-code again. The skill file is placed at ~/.claude/skills/langchain-fundamentals/SKILL.md.

What does langchain-fundamentals do?

It provides patterns and examples for LangChain agents built with create_agent(), tools, and middleware. It covers state persistence, approval workflows, and structured output.

What is required for HumanInTheLoopMiddleware?

It requires a checkpointer and a thread_id. An interrupted agent call can then be resumed with an approval decision.

Source text

SKILL.md · MIT
---
name: langchain-fundamentals
description: Create LangChain agents with create_agent, define tools, and use middleware for human-in-the-loop and error handling.
---

<oneliner>
Build production agents using `create_agent()`, middleware patterns, and the `@tool` decorator / `tool()` function. When creating LangChain agents, you MUST use create_agent(), with middleware for custom flows. All other alternatives are outdated.
</oneliner>

<create_agent>
## Creating Agents with create_agent

`create_agent()` is the recommended way to build agents. It handles the agent loop, tool execution, and state management.

### Agent Configuration Options

| 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>

<ex-basic-agent>
<python>

```python
from langchain.agents import create_agent
from langchain_core.tools import tool

@tool
def get_weather(location: str) -> str:
    """Get current weather for a location.

    Args:
        location: City name
    """
    return f"Weather in {location}: Sunny, 72F"

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)
```
</python>
<typescript>

```typescript
import { createAgent } from "langchain";
import { tool } from "@langchain/core/tools";
import { z } from "zod";

const getWeather = tool(
  async ({ location }) => `Weather in ${location}: Sunny, 72F`,
  {
    name: "get_weather",
    description: "Get current weather for a location.",
    schema: z.object({ location: z.string().describe("City name") }),
  }
);

const agent = createAgent({
  model: "anthropic:claude-sonnet-4-5",
  tools: [getWeather],
});

const result = await agent.invoke({
  messages: [{ role: "user", content: "What's the weather in Paris?" }],
});
console.log(result.messages[result.messages.length - 1].content);
```
</typescript>
</ex-basic-agent>

<ex-agent-with-persistence>
<python>
Add MemorySaver checkpointer to maintain conversation state across invocations.

```python
from langchain.agents import create_agent
from langgraph.checkpoint.memory import MemorySaver

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)
# Agent remembers: "Your name is Alice"
```
</python>
<typescript>
Add MemorySaver checkpointer to maintain conversation state across invocations.

```typescript
import { createAgent } from "langchain";
import { MemorySaver } from "@langchain/langgraph";

const checkpointer = new MemorySaver();

const agent = createAgent({
  model: "anthropic:claude-sonnet-4-5",
  tools: [search],
  checkpointer,
});

const config = { configurable: { thread_id: "user-123" } };
await agent.invoke({ messages: [{ role: "user", content: "My name is Alice" }] }, config);
const result = await agent.invoke({ messages: [{ role: "user", content: "What's my name?" }] }, config);
// Agent remembers: "Your name is Alice"
```
</typescript>
</ex-agent-with-persistence>

<tools>
## Defining Tools

Tools are functions that agents can call. Use the `@tool` decorator (Python) or `tool()` function (TypeScript).
</tools>

<ex-basic-tool>
<python>

```python
from langchain_core.tools import tool

@tool
def add(a: float, b: float) -> float:
    """Add two numbers.

    Args:
        a: First number
        b: Second number
    """
    return a + b
```
</python>
<typescript>

```typescript
import { tool } from "@langchain/core/tools";
import { z } from "zod";

const add = tool(
  async ({ a, b }) => a + b,
  {
    name: "add",
    description: "Add two numbers.",
    schema: z.object({
      a: z.number().describe("First number"),
      b: z.number().describe("Second number"),
    }),
  }
);
```
</typescript>
</ex-basic-tool>

<middleware>
## Middleware for Agent Control

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:

```python
from langchain.agents.middleware import HumanInTheLoopMiddleware, wrap_tool_call
```

```typescript
import { humanInTheLoopMiddleware, createMiddleware } from "langchain";
```

Key patterns:
- **HITL**: `middleware=[HumanInTheLoopMiddleware(interrupt_on={"dangerous_tool": True})]` — requires `checkpointer` + `thread_id`
- **Resume after interrupt**: `agent.invoke(Command(resume={"decisions": [{"type": "approve"}]}), config=config)`
- **Custom middleware**: `@wrap_tool_call` decorator (Python) or `createMiddleware({ wrapToolCall: ... })` (TypeScript)
</middleware>

<structured_output>
## Structured Output

Get typed, validated responses from agents using `response_format` or `with_structured_output()`.

<python>

```python
from langchain.agents import create_agent
from pydantic import BaseModel, Field

class ContactInfo(BaseModel):
    name: str
    email: str
    phone: str = Field(description="Phone number with area code")

# Option 1: Agent with structured output
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', ...)

# Option 2: Model-level structured output (no agent needed)
from langchain_openai import ChatOpenAI
model = ChatOpenAI(model="gpt-4.1")
structured_model = model.with_structured_output(ContactInfo)
response = structured_model.invoke("Extract: John, [email protected], 555-1234")
# ContactInfo(name='John', email='[email protected]', phone='555-1234')
```
</python>
<typescript>

```typescript
import { ChatOpenAI } from "@langchain/openai";
import { z } from "zod";

const ContactInfo = z.object({
  name: z.string(),
  email: z.string().email(),
  phone: z.string().describe("Phone number with area code"),
});

// Model-level structured output
const model = new ChatOpenAI({ model: "gpt-4.1" });
const structuredModel = model.withStructuredOutput(ContactInfo);
const response = await structuredModel.invoke("Extract: John, [email protected], 555-1234");
// { name: 'John', email: '[email protected]', phone: '555-1234' }
```
</typescript>
</structured_output>

<model_config>
## Model Configuration

`create_agent` accepts model strings (`"anthropic:claude-sonnet-4-5"`, `"openai:gpt-4.1"`) or model instances for custom settings:

```python
from langchain_anthropic import ChatAnthropic
agent = create_agent(model=ChatAnthropic(model="claude-sonnet-4-5", temperature=0), tools=[...])
```
</model_config>


<fix-missing-tool-description>
<python>
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"

# CORRECT: Clear, specific description with Args
@tool
def search(query: str) -> str:
    """Search the web for current information about a topic.

    Use this when you need recent data or facts.

    Args:
        query: The search query (2-10 words recommended)
    """
    return web_search(query)
```
</python>
<typescript>
Clear descriptions help the agent know when to use each tool.

```typescript
// WRONG: Vague description
const badTool = tool(async ({ input }) => "result", {
  name: "bad_tool",
  description: "Does stuff.", // Too vague!
  schema: z.object({ input: z.string() }),
});

// CORRECT: Clear, specific description
const search = tool(async ({ query }) => webSearch(query), {
  name: "search",
  description: "Search the web for current information about a topic. Use this when you need recent data or facts.",
  schema: z.object({
    query: z.string().describe("The search query (2-10 words recommended)"),
  }),
});
```
</typescript>
</fix-missing-tool-description>

<fix-no-checkpointer>
<python>
Add checkpointer and thread_id for conversation memory across invocations.

```python
# WRONG: No persistence - agent forgets between calls
agent = create_agent(model="anthropic:claude-sonnet-4-5", tools=[search])
agent.invoke({"messages": [{"role": "user", "content": "I'm Bob"}]})
agent.invoke({"messages": [{"role": "user", "content": "What's my name?"}]})
# Agent doesn't remember!

# CORRECT: Add checkpointer and thread_id
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)
# Agent remembers: "Your name is Bob"
```
</python>
<typescript>
Add checkpointer and thread_id for conversation memory across invocations.

```typescript
// WRONG: No persistence
const agent = createAgent({ model: "anthropic:claude-sonnet-4-5", tools: [search] });
await agent.invoke({ messages: [{ role: "user", content: "I'm Bob" }] });
await agent.invoke({ messages: [{ role: "user", content: "What's my name?" }] });
// Agent doesn't remember!

// CORRECT: Add checkpointer and thread_id
import { MemorySaver } from "@langchain/langgraph";

const agent = createAgent({
  model: "anthropic:claude-sonnet-4-5",
  tools: [search],
  checkpointer: new MemorySaver(),
});
const config = { configurable: { thread_id: "session-1" } };
await agent.invoke({ messages: [{ role: "user", content: "I'm Bob" }] }, config);
await agent.invoke({ messages: [{ role: "user", content: "What's my name?" }] }, config);
// Agent remembers: "Your name is Bob"
```
</typescript>
</fix-no-checkpointer>

<fix-infinite-loop>
<python>
Set recursion_limit in the invoke config to prevent runaway agent loops.

```python
# WRONG: No iteration limit - could loop forever
result = agent.invoke({"messages": [("user", "Do research")]})

# CORRECT: Set recursion_limit in config
result = agent.invoke(
    {"messages": [("user", "Do research")]},
    config={"recursion_limit": 10},  # Stop after 10 steps
)
```
</python>
<typescript>
Set recursionLimit in the invoke config to prevent runaway agent loops.

```typescript
// WRONG: No iteration limit
const result = await agent.invoke({ messages: [["user", "Do research"]] });

// CORRECT: Set recursionLimit in config
const result = await agent.invoke(
  { messages: [["user", "Do research"]] },
  { recursionLimit: 10 }, // Stop after 10 steps
);
```
</typescript>
</fix-infinite-loop>

<fix-accessing-result-wrong>
<python>
Access the messages array from the result, not result.content directly.

```python
# WRONG: Trying to access result.content directly
result = agent.invoke({"messages": [{"role": "user", "content": "Hello"}]})
print(result.content)  # AttributeError!

# CORRECT: Access messages from result dict
result = agent.invoke({"messages": [{"role": "user", "content": "Hello"}]})
print(result["messages"][-1].content)  # Last message content
```
</python>
<typescript>
Access the messages array from the result, not result.content directly.

```typescript
// WRONG: Trying to access result.content directly
const result = await agent.invoke({ messages: [{ role: "user", content: "Hello" }] });
console.log(result.content); // undefined!

// CORRECT: Access messages from result object
const result = await agent.invoke({ messages: [{ role: "user", content: "Hello" }] });
console.log(result.messages[result.messages.length - 1].content); // Last message content
```
</typescript>
</fix-accessing-result-wrong>

© langchain-ai · MIT · langchain-ai/langchain-skills

See also

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor