{"id":"langchain","kind":"sdk","name":"LangChain","slug":"langchain","description":"Framework for building LLM applications with chains, agents, and tools.","vendor":"LangChain","languages":["python","typescript","javascript","nodejs"],"categories":["ai"],"homepage":"https://www.langchain.com","docsUrl":"https://js.langchain.com/docs","githubUrl":"https://github.com/langchain-ai","packages":[{"registry":"pypi","name":"langchain","url":"https://pypi.org/project/langchain/"},{"registry":"npm","name":"langchain","url":"https://www.npmjs.com/package/langchain"}],"tags":["agents","rag","llm"],"skills":[{"name":"langchain-fundamentals","url":"https://skills.sh/langchain-ai/langchain-skills/langchain-fundamentals","install":"npx skills add langchain-ai/langchain-skills --skill langchain-fundamentals","sdk":"langchain","key":"langchain/langchain-fundamentals","description":"Create LangChain agents with create_agent, define tools, and use middleware for human-in-the-loop and error handling.","hasContent":true,"content":"---\nname: langchain-fundamentals\ndescription: Create LangChain agents with create_agent, define tools, and use middleware for human-in-the-loop and error handling.\n---\n\n<oneliner>\nBuild 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.\n</oneliner>\n\n<create_agent>\n## Creating Agents with create_agent\n\n`create_agent()` is the recommended way to build agents. It handles the agent loop, tool execution, and state management.\n\n### Agent Configuration Options\n\n| Parameter | Purpose | Example |\n|-----------|---------|---------|\n| `model` | LLM to use | `\"anthropic:claude-sonnet-4-5\"` or model instance |\n| `tools` | List of tools | `[search, calculator]` |\n| `system_prompt` / `systemPrompt` | Agent instructions | `\"You are a helpful assistant\"` |\n| `checkpointer` | State persistence | `MemorySaver()` |\n| `middleware` | Processing hooks | `[HumanInTheLoopMiddleware]` (Python) / `[humanInTheLoopMiddleware({...})]` (TypeScript) |\n</create_agent>\n\n<ex-basic-agent>\n<python>\n\n```python\nfrom langchain.agents import create_agent\nfrom langchain_core.tools import tool\n\n@tool\ndef get_weather(location: str) -> str:\n    \"\"\"Get current weather for a location.\n\n    Args:\n        location: City name\n    \"\"\"\n    return f\"Weather in {location}: Sunny, 72F\"\n\nagent = create_agent(\n    model=\"anthropic:claude-sonnet-4-5\",\n    tools=[get_weather],\n    system_prompt=\"You are a helpful assistant.\"\n)\n\nresult = agent.invoke({\n    \"messages\": [{\"role\": \"user\", \"content\": \"What's the weather in Paris?\"}]\n})\nprint(result[\"messages\"][-1].content)\n```\n</python>\n<typescript>\n\n```typescript\nimport { createAgent } from \"langchain\";\nimport { tool } from \"@langchain/core/tools\";\nimport { z } from \"zod\";\n\nconst getWeather = tool(\n  async ({ location }) => `Weather in ${location}: Sunny, 72F`,\n  {\n    name: \"get_weather\",\n    description: \"Get current weather for a location.\",\n    schema: z.object({ location: z.string().describe(\"City name\") }),\n  }\n);\n\nconst agent = createAgent({\n  model: \"anthropic:claude-sonnet-4-5\",\n  tools: [getWeather],\n  systemPrompt: \"You are a helpful assistant.\",\n});\n\nconst result = await agent.invoke({\n  messages: [{ role: \"user\", content: \"What's the weather in Paris?\" }],\n});\nconsole.log(result.messages[result.messages.length - 1].content);\n```\n</typescript>\n</ex-basic-agent>\n\n<ex-agent-with-persistence>\n<python>\nAdd MemorySaver checkpointer to maintain conversation state across invocations.\n\n```python\nfrom langchain.agents import create_agent\nfrom langgraph.checkpoint.memory import MemorySaver\n\ncheckpointer = MemorySaver()\n\nagent = create_agent(\n    model=\"anthropic:claude-sonnet-4-5\",\n    tools=[search],\n    checkpointer=checkpointer,\n)\n\nconfig = {\"configurable\": {\"thread_id\": \"user-123\"}}\nagent.invoke({\"messages\": [{\"role\": \"user\", \"content\": \"My name is Alice\"}]}, config=config)\nresult = agent.invoke({\"messages\": [{\"role\": \"user\", \"content\": \"What's my name?\"}]}, config=config)\n# Agent remembers: \"Your name is Alice\"\n```\n</python>\n<typescript>\nAdd MemorySaver checkpointer to maintain conversation state across invocations.\n\n```typescript\nimport { createAgent } from \"langchain\";\nimport { MemorySaver } from \"@langchain/langgraph\";\n\nconst checkpointer = new MemorySaver();\n\nconst agent = createAgent({\n  model: \"anthropic:claude-sonnet-4-5\",\n  tools: [search],\n  checkpointer,\n});\n\nconst config = { configurable: { thread_id: \"user-123\" } };\nawait agent.invoke({ messages: [{ role: \"user\", content: \"My name is Alice\" }] }, config);\nconst result = await agent.invoke({ messages: [{ role: \"user\", content: \"What's my name?\" }] }, config);\n// Agent remembers: \"Your name is Alice\"\n```\n</typescript>\n</ex-agent-with-persistence>\n\n<tools>\n## Defining Tools\n\nTools are functions that agents can call. Use the `@tool` decorator (Python) or `tool()` function (TypeScript).\n</tools>\n\n<ex-basic-tool>\n<python>\n\n```python\nfrom langchain_core.tools import tool\n\n@tool\ndef add(a: float, b: float) -> float:\n    \"\"\"Add two numbers.\n\n    Args:\n        a: First number\n        b: Second number\n    \"\"\"\n    return a + b\n```\n</python>\n<typescript>\n\n```typescript\nimport { tool } from \"@langchain/core/tools\";\nimport { z } from \"zod\";\n\nconst add = tool(\n  async ({ a, b }) => a + b,\n  {\n    name: \"add\",\n    description: \"Add two numbers.\",\n    schema: z.object({\n      a: z.number().describe(\"First number\"),\n      b: z.number().describe(\"Second number\"),\n    }),\n  }\n);\n```\n</typescript>\n</ex-basic-tool>\n\n<middleware>\n## Middleware for Agent Control\n\nMiddleware 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.\n\nKey imports:\n\n```python\nfrom langchain.agents.middleware import HumanInTheLoopMiddleware, wrap_tool_call\n```\n\n```typescript\nimport { humanInTheLoopMiddleware, createMiddleware } from \"langchain\";\n```\n\nKey patterns:\n- **HITL**: `middleware=[HumanInTheLoopMiddleware(interrupt_on={\"dangerous_tool\": True})]` — requires `checkpointer` + `thread_id`\n- **Resume after interrupt**: `agent.invoke(Command(resume={\"decisions\": [{\"type\": \"approve\"}]}), config=config)`\n- **Custom middleware**: `@wrap_tool_call` decorator (Python) or `createMiddleware({ wrapToolCall: ... })` (TypeScript)\n</middleware>\n\n<structured_output>\n## Structured Output\n\nGet typed, validated responses from agents using `response_format` or `with_structured_output()`.\n\n<python>\n\n```python\nfrom langchain.agents import create_agent\nfrom pydantic import BaseModel, Field\n\nclass ContactInfo(BaseModel):\n    name: str\n    email: str\n    phone: str = Field(description=\"Phone number with area code\")\n\n# Option 1: Agent with structured output\nagent = create_agent(model=\"gpt-4.1\", tools=[search], response_format=ContactInfo)\nresult = agent.invoke({\"messages\": [{\"role\": \"user\", \"content\": \"Find contact for John\"}]})\nprint(result[\"structured_response\"])  # ContactInfo(name='John', ...)\n\n# Option 2: Model-level structured output (no agent needed)\nfrom langchain_openai import ChatOpenAI\nmodel = ChatOpenAI(model=\"gpt-4.1\")\nstructured_model = model.with_structured_output(ContactInfo)\nresponse = structured_model.invoke(\"Extract: John, john@example.com, 555-1234\")\n# ContactInfo(name='John', email='john@example.com', phone='555-1234')\n```\n</python>\n<typescript>\n\n```typescript\nimport { ChatOpenAI } from \"@langchain/openai\";\nimport { z } from \"zod\";\n\nconst ContactInfo = z.object({\n  name: z.string(),\n  email: z.string().email(),\n  phone: z.string().describe(\"Phone number with area code\"),\n});\n\n// Model-level structured output\nconst model = new ChatOpenAI({ model: \"gpt-4.1\" });\nconst structuredModel = model.withStructuredOutput(ContactInfo);\nconst response = await structuredModel.invoke(\"Extract: John, john@example.com, 555-1234\");\n// { name: 'John', email: 'john@example.com', phone: '555-1234' }\n```\n</typescript>\n</structured_output>\n\n<model_config>\n## Model Configuration\n\n`create_agent` accepts model strings (`\"anthropic:claude-sonnet-4-5\"`, `\"openai:gpt-4.1\"`) or model instances for custom settings:\n\n```python\nfrom langchain_anthropic import ChatAnthropic\nagent = create_agent(model=ChatAnthropic(model=\"claude-sonnet-4-5\", temperature=0), tools=[...])\n```\n</model_config>\n\n\n<fix-missing-tool-description>\n<python>\nClear descriptions help the agent know when to use each tool.\n\n```python\n# WRONG: Vague or missing description\n@tool\ndef bad_tool(input: str) -> str:\n    \"\"\"Does stuff.\"\"\"\n    return \"result\"\n\n# CORRECT: Clear, specific description with Args\n@tool\ndef search(query: str) -> str:\n    \"\"\"Search the web for current information about a topic.\n\n    Use this when you need recent data or facts.\n\n    Args:\n        query: The search query (2-10 words recommended)\n    \"\"\"\n    return web_search(query)\n```\n</python>\n<typescript>\nClear descriptions help the agent know when to use each tool.\n\n```typescript\n// WRONG: Vague description\nconst badTool = tool(async ({ input }) => \"result\", {\n  name: \"bad_tool\",\n  description: \"Does stuff.\", // Too vague!\n  schema: z.object({ input: z.string() }),\n});\n\n// CORRECT: Clear, specific description\nconst search = tool(async ({ query }) => webSearch(query), {\n  name: \"search\",\n  description: \"Search the web for current information about a topic. Use this when you need recent data or facts.\",\n  schema: z.object({\n    query: z.string().describe(\"The search query (2-10 words recommended)\"),\n  }),\n});\n```\n</typescript>\n</fix-missing-tool-description>\n\n<fix-no-checkpointer>\n<python>\nAdd checkpointer and thread_id for conversation memory across invocations.\n\n```python\n# WRONG: No persistence - agent forgets between calls\nagent = create_agent(model=\"anthropic:claude-sonnet-4-5\", tools=[search])\nagent.invoke({\"messages\": [{\"role\": \"user\", \"content\": \"I'm Bob\"}]})\nagent.invoke({\"messages\": [{\"role\": \"user\", \"content\": \"What's my name?\"}]})\n# Agent doesn't remember!\n\n# CORRECT: Add checkpointer and thread_id\nfrom langgraph.checkpoint.memory import MemorySaver\n\nagent = create_agent(\n    model=\"anthropic:claude-sonnet-4-5\",\n    tools=[search],\n    checkpointer=MemorySaver(),\n)\nconfig = {\"configurable\": {\"thread_id\": \"session-1\"}}\nagent.invoke({\"messages\": [{\"role\": \"user\", \"content\": \"I'm Bob\"}]}, config=config)\nagent.invoke({\"messages\": [{\"role\": \"user\", \"content\": \"What's my name?\"}]}, config=config)\n# Agent remembers: \"Your name is Bob\"\n```\n</python>\n<typescript>\nAdd checkpointer and thread_id for conversation memory across invocations.\n\n```typescript\n// WRONG: No persistence\nconst agent = createAgent({ model: \"anthropic:claude-sonnet-4-5\", tools: [search] });\nawait agent.invoke({ messages: [{ role: \"user\", content: \"I'm Bob\" }] });\nawait agent.invoke({ messages: [{ role: \"user\", content: \"What's my name?\" }] });\n// Agent doesn't remember!\n\n// CORRECT: Add checkpointer and thread_id\nimport { MemorySaver } from \"@langchain/langgraph\";\n\nconst agent = createAgent({\n  model: \"anthropic:claude-sonnet-4-5\",\n  tools: [search],\n  checkpointer: new MemorySaver(),\n});\nconst config = { configurable: { thread_id: \"session-1\" } };\nawait agent.invoke({ messages: [{ role: \"user\", content: \"I'm Bob\" }] }, config);\nawait agent.invoke({ messages: [{ role: \"user\", content: \"What's my name?\" }] }, config);\n// Agent remembers: \"Your name is Bob\"\n```\n</typescript>\n</fix-no-checkpointer>\n\n<fix-infinite-loop>\n<python>\nSet recursion_limit in the invoke config to prevent runaway agent loops.\n\n```python\n# WRONG: No iteration limit - could loop forever\nresult = agent.invoke({\"messages\": [(\"user\", \"Do research\")]})\n\n# CORRECT: Set recursion_limit in config\nresult = agent.invoke(\n    {\"messages\": [(\"user\", \"Do research\")]},\n    config={\"recursion_limit\": 10},  # Stop after 10 steps\n)\n```\n</python>\n<typescript>\nSet recursionLimit in the invoke config to prevent runaway agent loops.\n\n```typescript\n// WRONG: No iteration limit\nconst result = await agent.invoke({ messages: [[\"user\", \"Do research\"]] });\n\n// CORRECT: Set recursionLimit in config\nconst result = await agent.invoke(\n  { messages: [[\"user\", \"Do research\"]] },\n  { recursionLimit: 10 }, // Stop after 10 steps\n);\n```\n</typescript>\n</fix-infinite-loop>\n\n<fix-accessing-result-wrong>\n<python>\nAccess the messages array from the result, not result.content directly.\n\n```python\n# WRONG: Trying to access result.content directly\nresult = agent.invoke({\"messages\": [{\"role\": \"user\", \"content\": \"Hello\"}]})\nprint(result.content)  # AttributeError!\n\n# CORRECT: Access messages from result dict\nresult = agent.invoke({\"messages\": [{\"role\": \"user\", \"content\": \"Hello\"}]})\nprint(result[\"messages\"][-1].content)  # Last message content\n```\n</python>\n<typescript>\nAccess the messages array from the result, not result.content directly.\n\n```typescript\n// WRONG: Trying to access result.content directly\nconst result = await agent.invoke({ messages: [{ role: \"user\", content: \"Hello\" }] });\nconsole.log(result.content); // undefined!\n\n// CORRECT: Access messages from result object\nconst result = await agent.invoke({ messages: [{ role: \"user\", content: \"Hello\" }] });\nconsole.log(result.messages[result.messages.length - 1].content); // Last message content\n```\n</typescript>\n</fix-accessing-result-wrong>\n","contentSource":"skills.sh/api/download/langchain-ai/langchain-skills/langchain-fundamentals","contentFetchedAt":"2026-07-27T08:59:35.245Z"}],"featured":true,"official":true,"generatedAt":"2026-07-27T09:02:29.956Z"}