[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6C52VHAPKBC6RGPJX2HDQ17":3,"skill-same:01M6C52VHAPKBC6RGPJX2HDQ17":53},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":27,"linkOnly":28,"markdownContent":29,"markdownBody":30,"frontMatter":31,"refName":32,"commitSha":33,"skillDirectory":34,"forksCount":14,"repositoryHtmlUrl":35,"repositoryHomepageUrl":6,"ownerHtmlUrl":36,"ownerBlogUrl":37,"ownerDescription":6,"updatedAt":38,"install":39,"resources":52},"01M6C52VHAPKBC6RGPJX2HDQ17","langchain-fundamentals",null,"Create LangChain agents with create_agent, define tools, and use middleware for human-in-the-loop and error handling.","CoralShades\u002Facm-ai","CoralShades","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F220297585?v=4","01M6C5211QSJHZ8HXSDDWCR507","Coral Shades AI Agency","01M6C52161FNQDRQ0FRR8DAA9D",0,"MIT","https:\u002F\u002Fgithub.com\u002FCoralShades\u002Facm-ai\u002Fblob\u002Fmain\u002F.agent\u002Fskills\u002Flangchain-fundamentals\u002FSKILL.md",[],[19,20,21,22,23,24,25,26],"langchain","langchain fundamentals","create","error handling","Tools","human-in-the-loop","loop","use","2026-11-10 10:12:30",false,"---\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\u003Coneliner>\nBuild production agents using `create_agent()`, middleware patterns, and the `@tool` decorator \u002F `tool()` function. When creating LangChain agents, you MUST use create_agent(), with middleware for custom flows. All other alternatives are outdated.\n\u003C\u002Foneliner>\n\n\u003Ccreate_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` \u002F `systemPrompt` | Agent instructions | `\"You are a helpful assistant\"` |\n| `checkpointer` | State persistence | `MemorySaver()` |\n| `middleware` | Processing hooks | `[HumanInTheLoopMiddleware]` (Python) \u002F `[humanInTheLoopMiddleware({...})]` (TypeScript) |\n\u003C\u002Fcreate_agent>\n\n\u003Cex-basic-agent>\n\u003Cpython>\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\u003C\u002Fpython>\n\u003Ctypescript>\n```typescript\nimport { createAgent } from \"langchain\";\nimport { tool } from \"@langchain\u002Fcore\u002Ftools\";\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\u003C\u002Ftypescript>\n\u003C\u002Fex-basic-agent>\n\n\u003Cex-agent-with-persistence>\n\u003Cpython>\nAdd MemorySaver checkpointer to maintain conversation state across invocations.\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\u003C\u002Fpython>\n\u003Ctypescript>\nAdd MemorySaver checkpointer to maintain conversation state across invocations.\n```typescript\nimport { createAgent } from \"langchain\";\nimport { MemorySaver } from \"@langchain\u002Flanggraph\";\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\u002F\u002F Agent remembers: \"Your name is Alice\"\n```\n\u003C\u002Ftypescript>\n\u003C\u002Fex-agent-with-persistence>\n\n\u003Ctools>\n## Defining Tools\n\nTools are functions that agents can call. Use the `@tool` decorator (Python) or `tool()` function (TypeScript).\n\u003C\u002Ftools>\n\n\u003Cex-basic-tool>\n\u003Cpython>\n```python\nfrom langchain_core.tools import tool\n\n@tool\ndef calculate(expression: str) -> str:\n    \"\"\"Evaluate a mathematical expression.\n\n    Args:\n        expression: Math expression like \"2 + 2\" or \"10 * 5\"\n    \"\"\"\n    return str(eval(expression))\n```\n\u003C\u002Fpython>\n\u003Ctypescript>\n```typescript\nimport { tool } from \"@langchain\u002Fcore\u002Ftools\";\nimport { z } from \"zod\";\n\nconst calculate = tool(\n  async ({ expression }) => String(eval(expression)),\n  {\n    name: \"calculate\",\n    description: \"Evaluate a mathematical expression.\",\n    schema: z.object({\n      expression: z.string().describe(\"Math expression like '2 + 2' or '10 * 5'\"),\n    }),\n  }\n);\n```\n\u003C\u002Ftypescript>\n\u003C\u002Fex-basic-tool>\n\n\u003Cmiddleware>\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) \u002F `humanInTheLoopMiddleware` (TypeScript) for approval workflows, and `@wrap_tool_call` (Python) \u002F `createMiddleware` (TypeScript) for custom hooks.\n\nKey imports:\n```python\nfrom langchain.agents.middleware import HumanInTheLoopMiddleware, wrap_tool_call\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\u003C\u002Fmiddleware>\n\n\u003Cstructured_output>\n## Structured Output\n\nGet typed, validated responses from agents using `response_format` or `with_structured_output()`.\n\n\u003Cpython>\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\u003C\u002Fpython>\n\u003Ctypescript>\n```typescript\nimport { ChatOpenAI } from \"@langchain\u002Fopenai\";\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\u002F\u002F 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\u002F\u002F { name: 'John', email: 'john@example.com', phone: '555-1234' }\n```\n\u003C\u002Ftypescript>\n\u003C\u002Fstructured_output>\n\n\u003Cmodel_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\u003C\u002Fmodel_config>\n\n\n\u003Cfix-missing-tool-description>\n\u003Cpython>\nClear descriptions help the agent know when to use each tool.\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\u003C\u002Fpython>\n\u003Ctypescript>\nClear descriptions help the agent know when to use each tool.\n```typescript\n\u002F\u002F WRONG: Vague description\nconst badTool = tool(async ({ input }) => \"result\", {\n  name: \"bad_tool\",\n  description: \"Does stuff.\", \u002F\u002F Too vague!\n  schema: z.object({ input: z.string() }),\n});\n\n\u002F\u002F 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\u003C\u002Ftypescript>\n\u003C\u002Ffix-missing-tool-description>\n\n\u003Cfix-no-checkpointer>\n\u003Cpython>\nAdd checkpointer and thread_id for conversation memory across invocations.\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\u003C\u002Fpython>\n\u003Ctypescript>\nAdd checkpointer and thread_id for conversation memory across invocations.\n```typescript\n\u002F\u002F 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\u002F\u002F Agent doesn't remember!\n\n\u002F\u002F CORRECT: Add checkpointer and thread_id\nimport { MemorySaver } from \"@langchain\u002Flanggraph\";\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\u002F\u002F Agent remembers: \"Your name is Bob\"\n```\n\u003C\u002Ftypescript>\n\u003C\u002Ffix-no-checkpointer>\n\n\u003Cfix-infinite-loop>\n\u003Cpython>\nSet recursion_limit in the invoke config to prevent runaway agent loops.\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\u003C\u002Fpython>\n\u003Ctypescript>\nSet recursionLimit in the invoke config to prevent runaway agent loops.\n```typescript\n\u002F\u002F WRONG: No iteration limit\nconst result = await agent.invoke({ messages: [[\"user\", \"Do research\"]] });\n\n\u002F\u002F CORRECT: Set recursionLimit in config\nconst result = await agent.invoke(\n  { messages: [[\"user\", \"Do research\"]] },\n  { recursionLimit: 10 }, \u002F\u002F Stop after 10 steps\n);\n```\n\u003C\u002Ftypescript>\n\u003C\u002Ffix-infinite-loop>\n\n\u003Cfix-accessing-result-wrong>\n\u003Cpython>\nAccess the messages array from the result, not result.content directly.\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\u003C\u002Fpython>\n\u003Ctypescript>\nAccess the messages array from the result, not result.content directly.\n```typescript\n\u002F\u002F WRONG: Trying to access result.content directly\nconst result = await agent.invoke({ messages: [{ role: \"user\", content: \"Hello\" }] });\nconsole.log(result.content); \u002F\u002F undefined!\n\n\u002F\u002F 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); \u002F\u002F Last message content\n```\n\u003C\u002Ftypescript>\n\u003C\u002Ffix-accessing-result-wrong>\n","\u003Coneliner>\nBuild production agents using `create_agent()`, middleware patterns, and the `@tool` decorator \u002F `tool()` function. When creating LangChain agents, you MUST use create_agent(), with middleware for custom flows. All other alternatives are outdated.\n\u003C\u002Foneliner>\n\n\u003Ccreate_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` \u002F `systemPrompt` | Agent instructions | `\"You are a helpful assistant\"` |\n| `checkpointer` | State persistence | `MemorySaver()` |\n| `middleware` | Processing hooks | `[HumanInTheLoopMiddleware]` (Python) \u002F `[humanInTheLoopMiddleware({...})]` (TypeScript) |\n\u003C\u002Fcreate_agent>\n\n\u003Cex-basic-agent>\n\u003Cpython>\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\u003C\u002Fpython>\n\u003Ctypescript>\n```typescript\nimport { createAgent } from \"langchain\";\nimport { tool } from \"@langchain\u002Fcore\u002Ftools\";\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\u003C\u002Ftypescript>\n\u003C\u002Fex-basic-agent>\n\n\u003Cex-agent-with-persistence>\n\u003Cpython>\nAdd MemorySaver checkpointer to maintain conversation state across invocations.\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\u003C\u002Fpython>\n\u003Ctypescript>\nAdd MemorySaver checkpointer to maintain conversation state across invocations.\n```typescript\nimport { createAgent } from \"langchain\";\nimport { MemorySaver } from \"@langchain\u002Flanggraph\";\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\u002F\u002F Agent remembers: \"Your name is Alice\"\n```\n\u003C\u002Ftypescript>\n\u003C\u002Fex-agent-with-persistence>\n\n\u003Ctools>\n## Defining Tools\n\nTools are functions that agents can call. Use the `@tool` decorator (Python) or `tool()` function (TypeScript).\n\u003C\u002Ftools>\n\n\u003Cex-basic-tool>\n\u003Cpython>\n```python\nfrom langchain_core.tools import tool\n\n@tool\ndef calculate(expression: str) -> str:\n    \"\"\"Evaluate a mathematical expression.\n\n    Args:\n        expression: Math expression like \"2 + 2\" or \"10 * 5\"\n    \"\"\"\n    return str(eval(expression))\n```\n\u003C\u002Fpython>\n\u003Ctypescript>\n```typescript\nimport { tool } from \"@langchain\u002Fcore\u002Ftools\";\nimport { z } from \"zod\";\n\nconst calculate = tool(\n  async ({ expression }) => String(eval(expression)),\n  {\n    name: \"calculate\",\n    description: \"Evaluate a mathematical expression.\",\n    schema: z.object({\n      expression: z.string().describe(\"Math expression like '2 + 2' or '10 * 5'\"),\n    }),\n  }\n);\n```\n\u003C\u002Ftypescript>\n\u003C\u002Fex-basic-tool>\n\n\u003Cmiddleware>\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) \u002F `humanInTheLoopMiddleware` (TypeScript) for approval workflows, and `@wrap_tool_call` (Python) \u002F `createMiddleware` (TypeScript) for custom hooks.\n\nKey imports:\n```python\nfrom langchain.agents.middleware import HumanInTheLoopMiddleware, wrap_tool_call\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\u003C\u002Fmiddleware>\n\n\u003Cstructured_output>\n## Structured Output\n\nGet typed, validated responses from agents using `response_format` or `with_structured_output()`.\n\n\u003Cpython>\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\u003C\u002Fpython>\n\u003Ctypescript>\n```typescript\nimport { ChatOpenAI } from \"@langchain\u002Fopenai\";\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\u002F\u002F 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\u002F\u002F { name: 'John', email: 'john@example.com', phone: '555-1234' }\n```\n\u003C\u002Ftypescript>\n\u003C\u002Fstructured_output>\n\n\u003Cmodel_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\u003C\u002Fmodel_config>\n\n\n\u003Cfix-missing-tool-description>\n\u003Cpython>\nClear descriptions help the agent know when to use each tool.\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\u003C\u002Fpython>\n\u003Ctypescript>\nClear descriptions help the agent know when to use each tool.\n```typescript\n\u002F\u002F WRONG: Vague description\nconst badTool = tool(async ({ input }) => \"result\", {\n  name: \"bad_tool\",\n  description: \"Does stuff.\", \u002F\u002F Too vague!\n  schema: z.object({ input: z.string() }),\n});\n\n\u002F\u002F 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\u003C\u002Ftypescript>\n\u003C\u002Ffix-missing-tool-description>\n\n\u003Cfix-no-checkpointer>\n\u003Cpython>\nAdd checkpointer and thread_id for conversation memory across invocations.\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\u003C\u002Fpython>\n\u003Ctypescript>\nAdd checkpointer and thread_id for conversation memory across invocations.\n```typescript\n\u002F\u002F 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\u002F\u002F Agent doesn't remember!\n\n\u002F\u002F CORRECT: Add checkpointer and thread_id\nimport { MemorySaver } from \"@langchain\u002Flanggraph\";\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\u002F\u002F Agent remembers: \"Your name is Bob\"\n```\n\u003C\u002Ftypescript>\n\u003C\u002Ffix-no-checkpointer>\n\n\u003Cfix-infinite-loop>\n\u003Cpython>\nSet recursion_limit in the invoke config to prevent runaway agent loops.\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\u003C\u002Fpython>\n\u003Ctypescript>\nSet recursionLimit in the invoke config to prevent runaway agent loops.\n```typescript\n\u002F\u002F WRONG: No iteration limit\nconst result = await agent.invoke({ messages: [[\"user\", \"Do research\"]] });\n\n\u002F\u002F CORRECT: Set recursionLimit in config\nconst result = await agent.invoke(\n  { messages: [[\"user\", \"Do research\"]] },\n  { recursionLimit: 10 }, \u002F\u002F Stop after 10 steps\n);\n```\n\u003C\u002Ftypescript>\n\u003C\u002Ffix-infinite-loop>\n\n\u003Cfix-accessing-result-wrong>\n\u003Cpython>\nAccess the messages array from the result, not result.content directly.\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\u003C\u002Fpython>\n\u003Ctypescript>\nAccess the messages array from the result, not result.content directly.\n```typescript\n\u002F\u002F WRONG: Trying to access result.content directly\nconst result = await agent.invoke({ messages: [{ role: \"user\", content: \"Hello\" }] });\nconsole.log(result.content); \u002F\u002F undefined!\n\n\u002F\u002F 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); \u002F\u002F Last message content\n```\n\u003C\u002Ftypescript>\n\u003C\u002Ffix-accessing-result-wrong>\n",{"name":5,"description":7},"main","1ca81b0a7de199942400f965edd4d7544077ac5d",".agent\u002Fskills\u002Flangchain-fundamentals","https:\u002F\u002Fgithub.com\u002FCoralShades\u002Facm-ai","https:\u002F\u002Fgithub.com\u002FCoralShades","coralshades.com.au","2026-04-18 00:45:07",{"source":8,"skillName":5,"commands":40,"prompt":50,"zipAvailable":51},[41,44,47],{"tool":42,"command":43},"npx","npx skills add CoralShades\u002Facm-ai --skill langchain-fundamentals",{"tool":45,"command":46},"bunx","bunx skills add CoralShades\u002Facm-ai --skill langchain-fundamentals",{"tool":48,"command":49},"pnpm","pnpm dlx skills add CoralShades\u002Facm-ai --skill langchain-fundamentals","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FCoralShades\u002Facm-ai\u002Fblob\u002Fmain\u002F.agent\u002Fskills\u002Flangchain-fundamentals\u002FSKILL.md",true,[],[54,77,90,106,125,135],{"skillNo":55,"name":56,"nameZh":6,"description":57,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":58,"categories":59,"keywords":65,"publishedAt":27},"01M6C63HKXA890HHV47WBAX0TB","uncodixfy","Prevents generic AI\u002FCodex UI patterns when generating frontend code. Use this skill whenever generating HTML, CSS, React, Vue, Svelte, or any frontend UI code to enforce clean, human-designed aesthetics inspired by Linear, Raycast, Stripe, and GitHub instead of typical AI-generated UI.","https:\u002F\u002Fgithub.com\u002FCoralShades\u002Facm-ai\u002Fblob\u002Fmain\u002F.qwen\u002Fskills\u002Funcodixfy\u002FSKILL.md",[60],{"categoryNo":61,"categoryName":62,"taxonomyType":63,"taxonomyTypeDesc":64},"01JBSEEDCAT000000000000009","前端开发","SCENARIO","使用场景",[56,66,67,68,69,70,71,72,73,74,75,26,76],"github","frontend","css","codex","react","code","linear","ui","vue","generated","html",{"skillNo":78,"name":79,"nameZh":6,"description":80,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":81,"licenseFileUrl":6,"sourceHtmlUrl":82,"categories":83,"keywords":84,"publishedAt":27},"01M6C63FJ2GEBBGZ5XSMV40KXB","runpodctl","Runpod CLI to manage your GPU workloads.","Apache-2.0","https:\u002F\u002Fgithub.com\u002FCoralShades\u002Facm-ai\u002Fblob\u002Fmain\u002F.qwen\u002Fskills\u002Frunpodctl\u002FSKILL.md",[],[79,85,86,87,88,89],"macos","cli","linux","gpu","Bash",{"skillNo":91,"name":92,"nameZh":6,"description":93,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":94,"categories":95,"keywords":96,"publishedAt":27},"01M6C63DPAV46TFVQ01SFYPJ7X","langgraph-persistence","INVOKE THIS SKILL when your LangGraph needs to persist state, remember conversations, travel through history, or configure subgraph checkpointer scoping. Covers checkpointers, thread_id, time travel, Store, and subgraph persistence modes.","https:\u002F\u002Fgithub.com\u002FCoralShades\u002Facm-ai\u002Fblob\u002Fmain\u002F.qwen\u002Fskills\u002Flanggraph-persistence\u002FSKILL.md",[],[97,98,99,100,101,102,103,104,105],"langgraph persistence","langgraph","persistence","travel","history","scoping","remember","state","configure",{"skillNo":107,"name":108,"nameZh":6,"description":109,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":110,"categories":111,"keywords":117,"publishedAt":27},"01M6C63BNS9CQEBTB8RNSSBFPA","langgraph-human-in-the-loop","INVOKE THIS SKILL when implementing human-in-the-loop patterns, pausing for approval, or handling errors in LangGraph. Covers interrupt(), Command(resume=...), approval\u002Fvalidation workflows, and the 4-tier error handling strategy.","https:\u002F\u002Fgithub.com\u002FCoralShades\u002Facm-ai\u002Fblob\u002Fmain\u002F.qwen\u002Fskills\u002Flanggraph-human-in-the-loop\u002FSKILL.md",[112],{"categoryNo":113,"categoryName":114,"taxonomyType":115,"taxonomyTypeDesc":116},"01JBSEEDCAT000000000000038","人力资源","PROFESSION","适用职业",[118,25,98,119,22,120,24,121,122,123,124],"langgraph human in the loop","workflows","validation","command","strategy","approval","resume",{"skillNo":126,"name":127,"nameZh":6,"description":128,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":129,"categories":130,"keywords":131,"publishedAt":27},"01M6C639GVYZFX3NFPV5FBDR4F","langgraph-fundamentals","INVOKE THIS SKILL when writing ANY LangGraph code. Covers StateGraph, state schemas, nodes, edges, Command, Send, invoke, streaming, and error handling.","https:\u002F\u002Fgithub.com\u002FCoralShades\u002Facm-ai\u002Fblob\u002Fmain\u002F.qwen\u002Fskills\u002Flanggraph-fundamentals\u002FSKILL.md",[],[132,98,22,104,133,134,121,71],"langgraph fundamentals","streaming","writing",{"skillNo":136,"name":137,"nameZh":6,"description":138,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":139,"categories":140,"keywords":141,"publishedAt":27},"01M6C6375N34YX2GZ3SD3R7XR2","langchain-rag","INVOKE THIS SKILL when building ANY retrieval-augmented generation (RAG) system. Covers document loaders, RecursiveCharacterTextSplitter, embeddings (OpenAI), and vector stores (Chroma, FAISS, Pinecone).","https:\u002F\u002Fgithub.com\u002FCoralShades\u002Facm-ai\u002Fblob\u002Fmain\u002F.qwen\u002Fskills\u002Flangchain-rag\u002FSKILL.md",[],[142,143,19,144,145,146,147,148,149,150],"rag","langchain rag","embeddings","vector","openai","chroma","faiss","vector stores","system"]