diff --git a/docs/docs/agents/human-in-the-loop.md b/docs/docs/agents/human-in-the-loop.md index 9ac148e55..9598b29cc 100644 --- a/docs/docs/agents/human-in-the-loop.md +++ b/docs/docs/agents/human-in-the-loop.md @@ -11,7 +11,13 @@ hide: # Human-in-the-loop +:::python To review, edit and approve tool calls in an agent you can use LangGraph's built-in [Human-In-the-Loop (HIL)](../concepts/human_in_the_loop.md) features, specifically the [`interrupt()`][langgraph.types.interrupt] primitive. +::: + +:::js +To review, edit and approve tool calls in an agent you can use LangGraph's built-in [human-in-the-loop](../concepts/human_in_the_loop.md) features, specifically the [`interrupt()`](/langgraphjs/reference/functions/langgraph.interrupt-1.html) primitive. +::: LangGraph allows you to pause execution **indefinitely** — for minutes, hours, or even days—until human input is received. @@ -27,6 +33,8 @@ A human can review and edit the output from the agent before proceeding. This is +:::python + ## Review tool calls To add a human approval step to a tool: @@ -34,6 +42,7 @@ To add a human approval step to a tool: 1. Use `interrupt()` in the tool to pause execution. 2. Resume with a `Command(resume=...)` to continue based on human input. + ```python from langgraph.checkpoint.memory import InMemorySaver from langgraph.types import interrupt @@ -233,6 +242,110 @@ for chunk in agent.stream( print("\n") ``` +::: + +:::js + +## Review tool calls + +To add a human approval step to a tool: + +1. Use `interrupt()` in the tool to pause execution. +2. Resume with a `Command({ resume: ... })` to continue based on human input. + +```ts +import { MemorySaver } from "@langchain/langgraph-checkpoint"; +import { interrupt } from "@langchain/langgraph"; +import { createReactAgent } from "@langchain/langgraph/prebuilt"; +import { initChatModel } from "langchain/chat_models/universal"; +import { tool } from "@langchain/core/tools"; +import { z } from "zod"; + +// An example of a sensitive tool that requires human review / approval +const bookHotel = tool( + async (input: { hotelName: string; }) => { + let hotelName = input.hotelName; + // highlight-next-line + const response = interrupt( // (1)! + `Trying to call \`book_hotel\` with args {'hotel_name': ${hotelName}}. ` + + `Please approve or suggest edits.` + ) + if (response.type === "accept") { + // proceed to execute the tool logic + } else if (response.type === "edit") { + hotelName = response.args["hotel_name"] + } else { + throw new Error(`Unknown response type: ${response.type}`) + } + return `Successfully booked a stay at ${hotelName}.`; + }, + { + name: "bookHotel", + schema: z.object({ + hotelName: z.string().describe("Hotel to book"), + }), + description: "Book a hotel.", + } +); + +// highlight-next-line +const checkpointer = new MemorySaver(); // (2)! + +const llm = await initChatModel("anthropic:claude-3-7-sonnet-latest"); +const agent = createReactAgent({ + llm, + tools: [bookHotel], + // highlight-next-line + checkpointer // (3)! +}); +``` + +1. The [`interrupt` function](/langgraphjs/reference/functions/langgraph.interrupt-1.html) pauses the agent graph at a specific node. In this case, we call `interrupt()` at the beginning of the tool function, which pauses the graph at the node that executes the tool. The information inside `interrupt()` (e.g., tool calls) can be presented to a human, and the graph can be resumed with the user input (tool call approval, edit or feedback). +2. The `InMemorySaver` is used to store the agent state at every step in the tool calling loop. This enables [short-term memory](./memory.md#short-term-memory) and [human-in-the-loop](./human-in-the-loop.md) capabilities. In this example, we use `InMemorySaver` to store the agent state in memory. In a production application, the agent state will be stored in a database. +3. Initialize the agent with the `checkpointer`. + +Run the agent with the `stream()` method, passing the `config` object to specify the thread ID. This allows the agent to resume the same conversation on future invocations. + +```ts +const config = { + configurable: { + // highlight-next-line + "thread_id": "1" + } +} + +for await (const chunk of await agent.stream( + { messages: "book a stay at McKittrick hotel" }, + // highlight-next-line + config +)) { + console.log(chunk); + console.log("\n"); +}; +``` + +> You should see that the agent runs until it reaches the `interrupt()` call, at which point it pauses and waits for human input. + +Resume the agent with a `Command({ resume: ... })` to continue based on human input. + +```ts +import { Command } from "@langchain/langgraph"; + +for await (const chunk of await agent.stream( + new Command({ resume: { type: "accept" } }), // (1)! + // new Command({ resume: { type: "edit", args: { "hotel_name": "McKittrick Hotel" } } }), + // highlight-next-line + config +)) { + console.log(chunk); + console.log("\n"); +}; +``` + +1. The [`interrupt` function](/langgraphjs/reference/functions/langgraph.interrupt-1.html) is used in conjunction with the [`Command`](/langgraphjs/reference/classes/langgraph.Command.html) object to resume the graph with a value provided by the human. + +::: + ## Additional resources * [Human-in-the-loop in LangGraph](../concepts/human_in_the_loop.md) diff --git a/docs/docs/agents/mcp.md b/docs/docs/agents/mcp.md index 919f5a967..964f6ed29 100644 --- a/docs/docs/agents/mcp.md +++ b/docs/docs/agents/mcp.md @@ -13,6 +13,8 @@ hide:  +:::python + Install the `langchain-mcp-adapters` library to use MCP tools in LangGraph: ```bash @@ -58,6 +60,57 @@ weather_response = await agent.ainvoke( {"messages": [{"role": "user", "content": "what is the weather in nyc?"}]} ) ``` +::: + +:::js +Install the `@langchain/mcp-adapters` library to use MCP tools in LangGraph: +```bash +npm install @langchain/mcp-adapters +``` + +## Use MCP tools + +The `@langchain/mcp-adapters` package enables agents to use tools defined across one or more MCP servers. + +```ts +// highlight-next-line +import { MultiServerMCPClient } from "@langchain/mcp-adapters"; +import { initChatModel } from "langchain/chat_models/universal"; +import { createReactAgent } from "@langchain/langgraph/prebuilt"; + +// highlight-next-line +const client = new MultiServerMCPClient({ + mcpServers: { + "math": { + command: "python", + // Replace with absolute path to your math_server.py file + args: ["/path/to/math_server.py"], + transport: "stdio", + }, + "weather": { + // Ensure your start your weather server on port 8000 + url: "http://localhost:8000/sse", + transport: "sse", + } + } +}) + +const llm = await initChatModel("anthropic:claude-3-7-sonnet-latest"); +const agent = createReactAgent({ + llm, + // highlight-next-line + tools: await client.getTools() +}); + +const mathResponse = await agent.invoke( + { messages: [ { role: "user", content: "what's (3 + 5) x 12?" } ] } +); +const weatherResponse = await agent.invoke( + { messages: [ { role: "user", content: "what is the weather in nyc?" } ] } +); +await client.close(); +``` +::: ## Custom MCP servers diff --git a/docs/docs/agents/overview.md b/docs/docs/agents/overview.md index b8ffb6cf2..f180001a0 100644 --- a/docs/docs/agents/overview.md +++ b/docs/docs/agents/overview.md @@ -40,6 +40,8 @@ LangGraph comes with a set of prebuilt components that implement common agent be Using LangGraph for agent development allows you to focus on your application's logic and behavior, instead of building and maintaining the supporting infrastructure for state, memory, and human feedback. + +:::python ## Package ecosystem The high-level components are organized into several packages, each with a specific focus. @@ -189,3 +191,159 @@ function initializeWidget() { window.addEventListener("DOMContentLoaded", initializeWidget); document$.subscribe(initializeWidget); + +::: + +:::js + +## Package ecosystem + +The high-level components are organized into several packages, each with a specific focus. + +| Package | Description | Installation | +| ------------------------ | --------------------------------------------------------------------------- | -------------------------------------------------- | +| `langgraph` | Prebuilt components to [**create agents**](./agents.md) | `npm install @langchain/langgraph @langchain/core` | +| `langgraph-supervisor` | Tools for building [**supervisor**](./multi-agent.md#supervisor) agents | `npm install @langchain/langgraph-supervisor` | +| `langgraph-swarm` | Tools for building a [**swarm**](./multi-agent.md#swarm) multi-agent system | `npm install @langchain/langgraph-swarm` | +| `langchain-mcp-adapters` | Interfaces to [**MCP servers**](./mcp.md) for tool and resource integration | `npm install @langchain/mcp-adapters` | +| `agentevals` | Utilities to [**evaluate agent performance**](./evals.md) | `npm install agentevals` | + +## Visualize an agent graph + +Use the following tool to visualize the graph generated by [`createReactAgent`](/langgraphjs/reference/functions/langgraph_prebuilt.createReactAgent.html) and to view an outline of the corresponding code. It allows you to explore the infrastructure of the agent as defined by the presence of: + +- [`tools`](./tools.md): A list of tools (functions, APIs, or other callable objects) that the agent can use to perform tasks. +- `preModelHook`: A function that is called before the model is invoked. It can be used to condense messages or perform other preprocessing tasks. +- `postModelHook`: A function that is called after the model is invoked. It can be used to implement guardrails, human-in-the-loop flows, or other postprocessing tasks. +- [`responseFormat`](./agents.md#structured-output): A data structure used to constrain the type of the final output (via Zod schemas). + +
+