Skip to main content

langchain-framework

Guidance for building LLM-powered agents with LangChain, LangGraph, or Deep Agents. Use when building agents with any of these frameworks, implementing tool-calling agents, stateful graph workflows, or multi-step orchestration. Read this skill before writing any LangChain/LangGraph agent code.

Source facts

Repository
NVIDIA-NeMo/nemo-platform
Last source activity
September 18, 2026 at 21:34
Detected SKILL.md language
English
Stars
79
Forks
24

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
15 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
langchain-framework
description
Guidance for building LLM-powered agents with LangChain, LangGraph, or Deep Agents. Use when building agents with any of these frameworks, implementing tool-calling agents, stateful graph workflows, or multi-step orchestration. Read this skill before writing any LangChain/LangGraph agent code.
compatibility
Python ≥ 3.10, uv for install, API keys in .env. langchain >= 1.0,<2.0; langgraph >= 1.0,<2.0; langsmith >= 0.3.0; deepagents latest.
allowed-tools
Read
metadata
{"author":"NeMo Helix Team <nemo-helix@nvidia.com>"}
<!-- SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. --> <!-- SPDX-License-Identifier: Apache-2.0 --> # Building Agents with LangChain / LangGraph > NVIDIA-authored guidance summarizing the public LangChain, LangGraph, and Deep Agents > documentation (<https://docs.langchain.com>), which is published by LangChain, Inc. under the > MIT license. API names and short usage examples are drawn from those docs; the framework > selection guidance, comparisons, and structure are original. LangChain, LangGraph, and Deep Agents are **layered** frameworks — each builds on the one below: ``` ┌─────────────────────────────────────────┐ │ Deep Agents │ ← batteries included: planning, memory, files ├─────────────────────────────────────────┤ │ LangGraph │ ← orchestration: graphs, loops, state ├─────────────────────────────────────────┤ │ LangChain │ ← foundation: models, tools, chains └─────────────────────────────────────────┘ ``` ## Pick Your Framework | Question | Yes → | No → | |----------|-------|------| | Need sub-task planning, file management, persistent memory, or on-demand skills? | **Deep Agents** | ↓ | | Need loops, branching, human-in-the-loop, or custom state? | **LangGraph** | ↓ | | Single-purpose agent with fixed tools? (+ middleware for HITL, retry, PII, etc.) | **LangChain** (`create_agent`) | ↓ | | Pure model call or chain with no agent loop? | **LangChain** (LCEL) | — | ## Installation ```bash uv add langchain langchain-core langsmith # Orchestration — only add if you use langgraph.* imports directly or Deep Agents: uv add langgraph # StateGraph, checkpointers, etc. uv add deepagents # Deep Agents (includes LangGraph) # Model provider — pick yours: uv add langchain-anthropic # Claude (direct) — installed in this environment uv add langchain-openai # GPT or any OpenAI-compatible endpoint — NOT pre-installed; add explicitly ``` > **Note:** `langchain-openai` is **not installed by default** in this environment. Code examples below that use `ChatOpenAI` require `uv add langchain-openai` first. All code examples work with `langchain-anthropic` out of the box. Set your API key in `.env`: ```bash ANTHROPIC_API_KEY=<your-key> # if using langchain-anthropic directly # or, for any OpenAI-compatible endpoint (e.g. a custom inference server): OPENAI_API_KEY=<your-key> LANGSMITH_API_KEY=<your-key> # optional, for tracing ``` ## Hello World ### LangChain — LCEL chain (pure model call, no agent loop) ```python from langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser from pydantic import BaseModel import os # Option A: Anthropic directly (langchain-anthropic installed by default) from langchain_anthropic import ChatAnthropic model = ChatAnthropic(model="claude-sonnet-4-5") # Option B: OpenAI-compatible endpoint — requires: uv add langchain-openai from langchain_openai import ChatOpenAI model = ChatOpenAI( model="<model-name>", base_url="<your-endpoint-url>", api_key=os.environ["YOUR_API_KEY"], ) # Option 1: plain text output chain = ChatPromptTemplate.from_messages([ ("system", "You are a helpful assistant."), ("human", "{input}"), ]) | model | StrOutputParser() print(chain.invoke({"input": "Say hello"})) # Option 2: structured output class Reply(BaseModel): message: str structured_chain = ChatPromptTemplate.from_messages([ ("system", "You are a helpful assistant."), ("human", "{input}"), ]) | model.with_structured_output(Reply) print(structured_chain.invoke({"input": "Say hello"})) ``` ### LangChain — `create_agent` (single-purpose agent with fixed tools) ```python from langchain.agents import create_agent from langchain_core.tools import tool from datetime import date @tool def get_current_date() -> str: """Get today's date.""" return date.today().isoformat() agent = create_agent( model="anthropic:claude-sonnet-4-5", # or a model instance (see above) tools=[get_current_date], system_prompt="You are a helpful assistant.", ) result = agent.invoke({"messages": [{"role": "user", "content": "What is today's date?"}]}) print(result["messages"][-1].content) ``` **Middleware** — `create_agent` supports a `middleware` list for cross-cutting concerns: | Middleware | Purpose | |---|---| | `HumanInTheLoopMiddleware` | Pause for human approval before tool calls | | `TodoListMiddleware` | Track sub-tasks with a built-in todo list | | `ModelRetryMiddleware` | Retry on model errors | | `ToolRetryMiddleware` | Retry on tool call errors | | `ModelCallLimitMiddleware` | Cap total LLM calls per run | | `SummarizationMiddleware` | Auto-compress context when it grows too long | | `PIIMiddleware` | Strip PII from model inputs/outputs | ```python from langchain.agents import create_agent from langchain.agents.middleware import HumanInTheLoopMiddleware, TodoListMiddleware agent = create_agent( model="anthropic:claude-sonnet-4-5", tools=[...], middleware=[HumanInTheLoopMiddleware(), TodoListMiddleware()], ) ``` **Per-invocation typed config (`context_schema`)** — pass typed context (user IDs, flags) to nodes without global state: ```python from langchain.agents import create_agent from pydantic import BaseModel class UserContext(BaseModel): user_id: str locale: str = "en" agent = create_agent( model="anthropic:claude-sonnet-4-5", tools=[...], context_schema=UserContext, ) result = agent.invoke( {"messages": [...]}, config={"configurable": {"context": UserContext(user_id="u123")}} ) ``` See `references/langchain-middleware.md` for full middleware reference. ### LangGraph — `StateGraph` (custom state, loops, branching) ```python from langgraph.graph import StateGraph, START, END from langchain_core.tools import tool from typing import Annotated from typing_extensions import TypedDict from langgraph.graph.message import add_messages from datetime import date import os # Requires: uv add langchain-openai (or swap for ChatAnthropic) from langchain_openai import ChatOpenAI model = ChatOpenAI( model="<model-name>", base_url="<your-endpoint-url>", api_key=os.environ["YOUR_API_KEY"], ) @tool def get_current_date() -> str: """Get today's date.""" return date.today().isoformat() class State(TypedDict): messages: Annotated[list, add_messages] model_with_tools = model.bind_tools([get_current_date]) def call_model(state: State) -> State: return {"messages": [model_with_tools.invoke(state["messages"])]} graph = StateGraph(State) graph.add_node("agent", call_model) graph.add_edge(START, "agent") graph.add_edge("agent", END) agent = graph.compile() result = agent.invoke({"messages": [{"role": "user", "content": "What is today's date?"}]}) print(result["messages"][-1].content) ``` ### Deep Agents — `create_deep_agent` (planning, files, memory, subagents) ```python from deepagents import create_deep_agent from langchain_core.tools import tool from langgraph.checkpoint.memory import MemorySaver from datetime import date @tool def get_current_date() -> str: """Get today's date.""" return date.today().isoformat() agent = create_deep_agent( model="anthropic:claude-sonnet-4-5", tools=[get_current_date], system_prompt="You are a helpful assistant.", checkpointer=MemorySaver(), # required for deep agents ) # thread_id is always required for deep agents config = {"configurable": {"thread_id": "session-1"}} result = agent.invoke({"messages": [{"role": "user", "content": "What is today's date?"}]}, config=config) print(result["messages"][-1].content) ``` ## Core Concepts ### Tools Tools are Python functions decorated with `@tool`. The docstring is the LLM's description of when and how to call the tool. Pass tools to `create_agent`, `create_deep_agent`, or bind them to a LangGraph model with `bind_tools`. ```python from langchain_core.tools import tool @tool def search_files(pattern: str) -> list[str]: """Search for files matching the given glob pattern.""" import glob return glob.glob(pattern, recursive=True) agent = create_agent(model="anthropic:claude-sonnet-4-5", tools=[search_files]) ``` For stateful or resource-sharing tools, use class-based tools or `StructuredTool` for complex input schemas. --- ### System Prompt Pass `system_prompt=` to `create_agent` or `create_deep_agent` to set the agent's role and constraints: ```python agent = create_agent( model="anthropic:claude-sonnet-4-5", tools=[...], system_prompt="You are a precise code reviewer. Always cite line numbers.", ) ``` For LCEL chains, set the system message in `ChatPromptTemplate`: ```python chain = ChatPromptTemplate.from_messages([ ("system", "You are a precise code reviewer. Always cite line numbers."), ("human", "{input}"), ]) | model | StrOutputParser() ``` For LangGraph, inject a `SystemMessage` at the start of the state or inside a node. --- ### Agent Types Choose based on workflow complexity: | Question | Answer | |---|---| | Need planning, memory, file management, or on-demand skills? | `create_deep_agent` | | Need custom state, loops, branching, or human-in-the-loop? | `StateGraph` (LangGraph) | | Single-purpose agent with fixed tools? | `create_agent` | | Pure model call or chain? | LCEL (`ChatPromptTemplate | model | parser`) | ```python # create_agent — fixed tools, middleware support agent = create_agent(model="anthropic:claude-sonnet-4-5", tools=[...]) # StateGraph — custom state and control flow graph = StateGraph(State) graph.add_node("agent", call_model) agent = graph.compile() # create_deep_agent — planning, memory, subagents, skills agent = create_deep_agent(model="...", tools=[...], checkpointer=MemorySaver()) ``` --- ### Structured Output When a method needs to return a specific format, use `.with_structured_output()` rather than describing the format in the system prompt. Structured output is enforced by the model API — it is more reliable than prompt instructions and gives downstream code a typed, predictable value. ```python from pydantic import BaseModel class Analysis(BaseModel): sentiment: str confidence: float topics: list[str] structured_chain = ChatPromptTemplate.from_messages([ ("system", "Analyze the text."), ("human", "{input}"), ]) | model.with_structured_output(Analysis) result = structured_chain.invoke({"input": "Great product!"}) print(result.sentiment) # validated Analysis instance ``` Bind the schema in `__init__` so every call on that model instance returns the typed output: ```python class MyAgent: def __init__(self): self.llm = ChatNVIDIA(model="meta/llama-3.1-70b-instruct").with_structured_output(MySchema) ``` --- ### Dynamic Prompts Use template variables in `ChatPromptTemplate` to inject runtime values: ```python chain = ChatPromptTemplate.from_messages([ ("system", "You are a {role}. Focus on {domain}."), ("human", "{input}"), ]) | model | StrOutputParser() result = chain.invoke({"role": "code reviewer", "domain": "security", "input": "..."}) ``` For `create_agent`, pass per-invocation typed config via `context_schema`: ```python class RunContext(BaseModel): language: str = "Python" strict_mode: bool = False agent = create_agent(model="...", tools=[...], context_schema=RunContext) result = agent.invoke({...}, config={"configurable": {"context": RunContext(language="Go")}}) ``` --- ### Skills Deep Agents supports skills — callable modules the agent can invoke on demand: ```python from deepagents import create_deep_agent, Skill
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub