Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8aa7c46d81 |
@@ -1,6 +1,6 @@
|
||||
name: "\U0001F41B Bug Report"
|
||||
description: Report a bug in LangGraph. To report a security issue, please instead use the security option below. For questions, please use the GitHub Discussions.
|
||||
labels: [pending,bug]
|
||||
labels: ["02 Bug Report"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
blank_issues_enabled: true
|
||||
blank_issues_enabled: false
|
||||
version: 2.1
|
||||
contact_links:
|
||||
- name: 🤔 Question or Problem
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
name: Documentation
|
||||
description: Report an issue related to the LangGraph documentation.
|
||||
title: "DOC: <Please write a comprehensive title after the 'DOC: ' prefix>"
|
||||
labels: [documentation]
|
||||
labels: [03 - Documentation]
|
||||
|
||||
body:
|
||||
- type: textarea
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
# Please see the documentation for all configuration options:
|
||||
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||
# and
|
||||
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
@@ -49,7 +49,7 @@ jobs:
|
||||
|
||||
- name: Get .mypy_cache to speed up mypy
|
||||
if: steps.changed-files.outputs.all
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v3
|
||||
env:
|
||||
SEGMENT_DOWNLOAD_TIMEOUT_MIN: "2"
|
||||
with:
|
||||
@@ -75,7 +75,7 @@ jobs:
|
||||
|
||||
- name: Get .mypy_cache_test to speed up mypy
|
||||
if: steps.changed-files.outputs.all
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v3
|
||||
env:
|
||||
SEGMENT_DOWNLOAD_TIMEOUT_MIN: "2"
|
||||
with:
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
name: test
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version:
|
||||
- "3.11"
|
||||
- "3.12"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: libs/scheduler-kafka
|
||||
name: "test #${{ matrix.python-version }}"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: astral-sh/setup-uv@v6
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
enable-cache: true
|
||||
cache-suffix: "test-scheduler-kafka"
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
if: ${{ !github.event.pull_request.head.repo.fork }}
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_RO_TOKEN }}
|
||||
|
||||
- name: Install dependencies
|
||||
shell: bash
|
||||
run: uv sync --frozen --group dev
|
||||
|
||||
- name: Run tests
|
||||
shell: bash
|
||||
run: make test
|
||||
|
||||
- name: Ensure the tests did not create any additional files
|
||||
shell: bash
|
||||
run: |
|
||||
set -eu
|
||||
|
||||
STATUS="$(git status)"
|
||||
echo "$STATUS"
|
||||
|
||||
# grep will exit non-zero if the target message isn't found,
|
||||
# and `set -e` above will cause the step to fail.
|
||||
echo "$STATUS" | grep 'nothing to commit, working tree clean'
|
||||
@@ -35,6 +35,7 @@ jobs:
|
||||
- 'libs/checkpoint/**'
|
||||
- 'libs/checkpoint-sqlite/**'
|
||||
- 'libs/checkpoint-postgres/**'
|
||||
- 'libs/scheduler-kafka/**'
|
||||
- 'libs/prebuilt/**'
|
||||
sdk-js:
|
||||
- 'libs/sdk-js/**'
|
||||
@@ -52,7 +53,7 @@ jobs:
|
||||
"libs/checkpoint",
|
||||
"libs/checkpoint-sqlite",
|
||||
"libs/checkpoint-postgres",
|
||||
|
||||
"libs/scheduler-kafka",
|
||||
"libs/prebuilt",
|
||||
]
|
||||
if: needs.changes.outputs.python == 'true'
|
||||
@@ -88,6 +89,14 @@ jobs:
|
||||
uses: ./.github/workflows/_test_langgraph.yml
|
||||
secrets: inherit
|
||||
|
||||
# NOTE: we're testing scheduler-kafka separately because it requires a different matrix
|
||||
test-scheduler-kafka:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.python == 'true'
|
||||
name: "cd libs/scheduler-kafka"
|
||||
uses: ./.github/workflows/_test_scheduler_kafka.yml
|
||||
secrets: inherit
|
||||
|
||||
check-sdk-methods:
|
||||
needs: changes
|
||||
if: needs.changes.outputs.python == 'true'
|
||||
@@ -157,9 +166,9 @@ jobs:
|
||||
run:
|
||||
working-directory: ${{ matrix.working-directory }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup Node.js (LTS)
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: "20"
|
||||
cache: "yarn"
|
||||
@@ -183,9 +192,9 @@ jobs:
|
||||
run:
|
||||
working-directory: ${{ matrix.working-directory }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup Node.js (LTS)
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: "20"
|
||||
cache: "yarn"
|
||||
@@ -203,6 +212,7 @@ jobs:
|
||||
lint-js,
|
||||
test,
|
||||
test-langgraph,
|
||||
test-scheduler-kafka,
|
||||
check-sdk-methods,
|
||||
check-schema,
|
||||
integration-test,
|
||||
|
||||
@@ -4,11 +4,9 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- v0
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- v0
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
@@ -84,9 +82,9 @@ jobs:
|
||||
run: make llms-text
|
||||
- name: Build site
|
||||
run: |
|
||||
# If this is v0 branch, then we want to download stats. we do this
|
||||
# If this is main branch, then we want to download stats. we do this
|
||||
# with the env variable DOWNLOAD_STATS=true
|
||||
if [ "${{ github.ref }}" == "refs/heads/v0" ]; then
|
||||
if [ "${{ github.ref }}" == "refs/heads/main" ]; then
|
||||
DOWNLOAD_STATS=true make build-docs
|
||||
else
|
||||
make build-docs
|
||||
@@ -146,8 +144,8 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Configure GitHub Pages
|
||||
if: github.ref == 'refs/heads/v0'
|
||||
uses: actions/configure-pages@v5
|
||||
if: github.ref == 'refs/heads/main'
|
||||
uses: actions/configure-pages@v4
|
||||
|
||||
- name: Upload Pages Artifact
|
||||
# if: github.ref == 'refs/heads/main'
|
||||
@@ -156,6 +154,6 @@ jobs:
|
||||
path: ./docs/site/
|
||||
|
||||
- name: Deploy to GitHub Pages
|
||||
if: github.ref == 'refs/heads/v0'
|
||||
if: github.ref == 'refs/heads/main'
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v4
|
||||
|
||||
@@ -22,7 +22,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
# JS Build
|
||||
- name: Use Node.js
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: "20"
|
||||
cache: "yarn"
|
||||
|
||||
@@ -181,4 +181,3 @@ Chinook.db
|
||||
.vercel
|
||||
.turbo
|
||||
.editorconfig
|
||||
.scratch
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
# AGENTS Instructions
|
||||
|
||||
This repository is a monorepo. Each library lives in a subdirectory under `libs/`.
|
||||
|
||||
When you modify code in any library, run the following commands in that library's directory before creating a pull request:
|
||||
|
||||
- `make format` – run code formatters
|
||||
- `make lint` – run the linter
|
||||
- `make test` – execute the test suite
|
||||
|
||||
To run a particular test file or to pass additional pytest options you can specify the `TEST` variable:
|
||||
|
||||
```
|
||||
TEST=path/to/test.py make test
|
||||
```
|
||||
|
||||
Other pytest arguments can also be supplied inside the `TEST` variable.
|
||||
|
||||
## Libraries
|
||||
|
||||
The repository contains several Python and JavaScript/TypeScript libraries.
|
||||
Below is a high-level overview:
|
||||
|
||||
- **checkpoint** – base interfaces for LangGraph checkpointers.
|
||||
- **checkpoint-postgres** – Postgres implementation of the checkpoint saver.
|
||||
- **checkpoint-sqlite** – SQLite implementation of the checkpoint saver.
|
||||
- **cli** – official command-line interface for LangGraph.
|
||||
- **langgraph** – core framework for building stateful, multi-actor agents.
|
||||
- **prebuilt** – high-level APIs for creating and running agents and tools.
|
||||
- **sdk-js** – JS/TS SDK for interacting with the LangGraph REST API.
|
||||
- **sdk-py** – Python SDK for the LangGraph Platform API.
|
||||
|
||||
### Dependency map
|
||||
|
||||
The diagram below lists downstream libraries for each production dependency as
|
||||
declared in that library's `pyproject.toml` (or `package.json`).
|
||||
|
||||
```text
|
||||
checkpoint
|
||||
├── checkpoint-postgres
|
||||
├── checkpoint-sqlite
|
||||
├── prebuilt
|
||||
└── langgraph
|
||||
|
||||
prebuilt
|
||||
└── langgraph
|
||||
|
||||
sdk-py
|
||||
├── langgraph
|
||||
└── cli
|
||||
|
||||
sdk-js (standalone)
|
||||
```
|
||||
|
||||
Changes to a library may impact all of its dependents shown above.
|
||||
@@ -109,7 +109,7 @@ Here are some high-level tips on writing a good how-to guide:
|
||||
LangGraph's conceptual guides fall under the **Explanation** quadrant of Diataxis. They should cover LangChain terms and concepts
|
||||
in a more abstract way than how-to guides or tutorials, and should be geared towards curious users interested in
|
||||
gaining a deeper understanding of the framework. Try to avoid excessively large code examples. The goal here is to
|
||||
impart perspective to the user rather than to finish a practical project. These guides should cover **why** things work the way they do.
|
||||
impart perspective to the user rather than to finish a practical project. These guides should cover **why** things work they way they do.
|
||||
|
||||
|
||||
To quote the Diataxis website:
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
# Define the directories containing projects
|
||||
LIBS_DIRS := $(wildcard libs/*)
|
||||
|
||||
# Default target
|
||||
.PHONY: all
|
||||
all: lint format lock test
|
||||
|
||||
# Install dependencies for all projects
|
||||
.PHONY: install
|
||||
install:
|
||||
@echo "Creating virtual environment..."
|
||||
@uv venv
|
||||
@for dir in $(LIBS_DIRS); do \
|
||||
if [ -f $$dir/pyproject.toml ]; then \
|
||||
echo "Installing dependencies for $$dir"; \
|
||||
uv pip install -e $$dir; \
|
||||
fi; \
|
||||
done
|
||||
|
||||
# Lint all projects
|
||||
.PHONY: lint
|
||||
lint:
|
||||
@for dir in $(LIBS_DIRS); do \
|
||||
if [ -f $$dir/Makefile ]; then \
|
||||
echo "Running lint in $$dir"; \
|
||||
$(MAKE) -C $$dir lint; \
|
||||
fi; \
|
||||
done
|
||||
|
||||
# Format all projects
|
||||
.PHONY: format
|
||||
format:
|
||||
@for dir in $(LIBS_DIRS); do \
|
||||
if [ -f $$dir/Makefile ]; then \
|
||||
echo "Running format in $$dir"; \
|
||||
$(MAKE) -C $$dir format; \
|
||||
fi; \
|
||||
done
|
||||
|
||||
# Lock all projects
|
||||
.PHONY: lock
|
||||
lock:
|
||||
@for dir in $(LIBS_DIRS); do \
|
||||
if [ -f $$dir/Makefile ]; then \
|
||||
echo "Running lock in $$dir"; \
|
||||
(cd $$dir && uv lock); \
|
||||
fi; \
|
||||
done
|
||||
|
||||
# Test all projects
|
||||
.PHONY: test
|
||||
test:
|
||||
@for dir in $(LIBS_DIRS); do \
|
||||
if [ -f $$dir/Makefile ]; then \
|
||||
echo "Running test in $$dir"; \
|
||||
$(MAKE) -C $$dir test; \
|
||||
fi; \
|
||||
done
|
||||
@@ -12,6 +12,7 @@
|
||||
[](https://pepy.tech/project/langgraph)
|
||||
[](https://github.com/langchain-ai/langgraph/issues)
|
||||
[](https://langchain-ai.github.io/langgraph/)
|
||||
[](https://gitmcp.io/langchain-ai/langgraph)
|
||||
|
||||
Trusted by companies shaping the future of agents – including Klarna, Replit, Elastic, and more – LangGraph is a low-level orchestration framework for building, managing, and deploying long-running, stateful agents.
|
||||
|
||||
@@ -73,7 +74,7 @@ While LangGraph can be used standalone, it also integrates seamlessly with any L
|
||||
|
||||
- [Guides](https://langchain-ai.github.io/langgraph/how-tos/): Quick, actionable code snippets for topics such as streaming, adding memory & persistence, and design patterns (e.g. branching, subgraphs, etc.).
|
||||
- [Reference](https://langchain-ai.github.io/langgraph/reference/graphs/): Detailed reference on core classes, methods, how to use the graph and checkpointing APIs, and higher-level prebuilt components.
|
||||
- [Examples](https://langchain-ai.github.io/langgraph/tutorials/overview/): Guided examples on getting started with LangGraph.
|
||||
- [Examples](https://langchain-ai.github.io/langgraph/tutorials/): Guided examples on getting started with LangGraph.
|
||||
- [LangChain Academy](https://academy.langchain.com/courses/intro-to-langgraph): Learn the basics of LangGraph in our free, structured course.
|
||||
- [Templates](https://langchain-ai.github.io/langgraph/concepts/template_applications/): Pre-built reference apps for common agentic workflows (e.g. ReAct agent, memory, retrieval etc.) that can be cloned and adapted.
|
||||
- [Case studies](https://www.langchain.com/built-with-langgraph): Hear how industry leaders use LangGraph to ship AI applications at scale.
|
||||
|
||||
@@ -1,154 +1,157 @@
|
||||
"""Translate Python markdown to TypeScript and/or consolidate Python-JS markdown into a single document."""
|
||||
"""Add typescript translation to a given markdown file."""
|
||||
|
||||
import argparse
|
||||
import re
|
||||
|
||||
import requests
|
||||
from langchain_anthropic import ChatAnthropic
|
||||
|
||||
# Load reference TypeScript snippets
|
||||
URL = "https://gist.githubusercontent.com/eyurtsev/e7486731415463a9bc5b4682358859c8/raw/b5a5fda9c7e3387cfcb781f25082814d43675d50/gistfile1.txt"
|
||||
response = requests.get(URL)
|
||||
response.raise_for_status()
|
||||
reference_snippets = response.text
|
||||
|
||||
# Initialize model
|
||||
model = ChatAnthropic(model="claude-sonnet-4-0", max_tokens=64_000)
|
||||
|
||||
TRANSLATION_PROMPT = (
|
||||
"You are a helpful assistant that translates Python-based technical "
|
||||
"documentation written in Markdown to equivalent TypeScript-based documentation. "
|
||||
"The input is a Markdown file written in mkdocs format. It contains "
|
||||
"Python code snippets embedded in prose. "
|
||||
"Your task is to rewrite the content by translating the Python code to "
|
||||
"idiomatic TypeScript, using the provided TypeScript reference snippets "
|
||||
"to ensure accurate and consistent usage (e.g., correct imports, function "
|
||||
"names, and patterns). "
|
||||
"Remove the original Python code and replace it with the corresponding "
|
||||
"TypeScript version. "
|
||||
"Do not alter the surrounding prose unless a change is necessary to "
|
||||
"reflect differences between Python and TypeScript. "
|
||||
"Preserve the structure and formatting of the original Markdown document. "
|
||||
"Do not make stylistic or structural changes unless they directly support "
|
||||
"the translation. "
|
||||
"Use the reference TypeScript snippets as guidance whenever possible to "
|
||||
"maintain alignment with existing conventions.\n\n"
|
||||
f"Here are the reference TypeScript snippets:\n\n{reference_snippets}\n\n"
|
||||
)
|
||||
|
||||
CONSOLIDATION_PROMPT = (
|
||||
"You are a helpful assistant that consolidates parallel Python and JavaScript (TypeScript) technical documentation "
|
||||
"written in Markdown into a single unified Markdown document. "
|
||||
"The input consists of two documents: the first is for Python users, and the second is for JavaScript/TypeScript users. "
|
||||
"Your task is to merge these into one Markdown file using language-specific fenced blocks to separate the content where needed. "
|
||||
"Use the following syntax to distinguish content for each language:\n\n"
|
||||
":::python\n"
|
||||
"# Python-specific content\n"
|
||||
":::\n\n"
|
||||
":::js\n"
|
||||
"# JavaScript/TypeScript-specific content\n"
|
||||
":::\n\n"
|
||||
"Follow these consolidation rules:\n"
|
||||
"- When content (prose or code) is the same or nearly identical in both versions, include it only once—outside of any fenced block.\n"
|
||||
"- When content differs between the Python and JS versions, wrap each version in its corresponding fenced block.\n"
|
||||
"- Prefer **paragraph-level separation** of language-specific content. Do not combine Python and JS snippets or terminology in the same sentence or paragraph using conditional phrases.\n"
|
||||
" For example, avoid inline constructs like:\n"
|
||||
" `The :::python add_messages ::: :::js reducer ::: function...`\n"
|
||||
" Instead, write two distinct paragraphs:\n\n"
|
||||
" :::python\n"
|
||||
" The `add_messages` function in our `State` will append the LLM's response messages to whatever messages are already in the state.\n"
|
||||
" ::: \n\n"
|
||||
" :::js\n"
|
||||
" The `reducer` function in our `StateAnnotation` will append the LLM's response messages to whatever messages are already in the state.\n"
|
||||
" :::\n\n"
|
||||
"- Preserve the overall structure, ordering, and formatting of the original Markdown documents.\n"
|
||||
"- Do not rephrase or unify content unless it is logically and semantically identical.\n"
|
||||
"- Use the fenced blocks for both prose and code as needed, and ensure output is clean, readable Markdown suitable for tools that parse these directives.\n"
|
||||
"Your goal is to produce a cleanly merged documentation file that serves both Python and JavaScript users without redundancy, while maximizing clarity and separation of language-specific details."
|
||||
)
|
||||
model = ChatAnthropic(model="claude-3-5-sonnet-latest")
|
||||
|
||||
|
||||
def translate_python_to_ts(markdown_content: str) -> str:
|
||||
response = model.invoke(
|
||||
def _get_tqdm():
|
||||
try:
|
||||
from tqdm import tqdm
|
||||
except ImportError:
|
||||
# If not available return a simple identity function
|
||||
def tqdm(iterable, *args, **kwargs):
|
||||
return iterable
|
||||
|
||||
return tqdm
|
||||
|
||||
|
||||
_tqdm = _get_tqdm()
|
||||
|
||||
opening_pattern = re.compile(r"^\s*```python(?:\s+.*)?\s*$")
|
||||
closing_pattern = re.compile(r"^\s*```\s*$")
|
||||
|
||||
|
||||
def extract_python_snippets(markdown: str) -> list[str]:
|
||||
"""
|
||||
Extract all python code blocks (including their fence lines) from the markdown content.
|
||||
A python block is defined as any block that starts with a line containing an opening fence
|
||||
with '```python' (optionally with extra parameters) and ends with a closing fence '```'.
|
||||
"""
|
||||
snippets = []
|
||||
inside_block = False
|
||||
current_snippet = []
|
||||
|
||||
for line in markdown.splitlines(keepends=True):
|
||||
if not inside_block:
|
||||
if opening_pattern.match(line):
|
||||
inside_block = True
|
||||
current_snippet = [line]
|
||||
else:
|
||||
current_snippet.append(line)
|
||||
if closing_pattern.match(line):
|
||||
inside_block = False
|
||||
snippets.append("".join(current_snippet))
|
||||
current_snippet = []
|
||||
return snippets
|
||||
|
||||
|
||||
def translate_snippet(python_snippet: str) -> str:
|
||||
"""Translate a python code block into a TypeScript code block using Langchain.
|
||||
The response is expected to be a properly fenced TypeScript code block (i.e.
|
||||
starting with ```typescript and ending with ```).
|
||||
"""
|
||||
ai_message = model.invoke(
|
||||
[
|
||||
{
|
||||
"role": "system",
|
||||
"content": TRANSLATION_PROMPT,
|
||||
"cache_control": {"type": "ephemeral"},
|
||||
"content": (
|
||||
f"You have access to the following up-to-date example TypeScript code "
|
||||
f"snippets that show examples of building with langgraph "
|
||||
f"and langchain:\n\n{reference_snippets}\n\n"
|
||||
"Use this context to translate the following Python code to equivalent "
|
||||
"TypeScript. Ensure that your output is a valid fenced TypeScript "
|
||||
"code block (i.e. starts with ```typescript and ends with ```)."
|
||||
),
|
||||
},
|
||||
{"role": "user", "content": markdown_content},
|
||||
]
|
||||
)
|
||||
return response.content
|
||||
|
||||
|
||||
def consolidate_python_and_ts(combined_content: str) -> str:
|
||||
response = model.invoke(
|
||||
[
|
||||
{
|
||||
"role": "system",
|
||||
"content": CONSOLIDATION_PROMPT,
|
||||
"cache_control": {"type": "ephemeral"},
|
||||
"role": "user",
|
||||
"content": f"Translate this Python snippet to TypeScript:\n\n{python_snippet}",
|
||||
},
|
||||
{"role": "user", "content": combined_content},
|
||||
]
|
||||
)
|
||||
return response.content
|
||||
|
||||
# Use a regular expression to search for a TypeScript code block in the response.
|
||||
pattern = r"```typescript\s*(.*?)\s*```"
|
||||
match = re.search(pattern, ai_message.content, re.DOTALL)
|
||||
if match:
|
||||
# Reconstruct the code block with proper fences.
|
||||
typescript_code = match.group(1).strip()
|
||||
return f"```typescript\n{typescript_code}\n```"
|
||||
else:
|
||||
raise ValueError("No TypeScript code block found in the model's response.")
|
||||
|
||||
|
||||
def main(file_path: str, translate_only: bool, consolidate_only: bool) -> None:
|
||||
with open(file_path, "r", encoding="utf-8") as f:
|
||||
def insert_translations_into_markdown(
|
||||
markdown: str, typescript_snippets: list[str]
|
||||
) -> str:
|
||||
"""Walks through the original markdown content and, after each
|
||||
Python snippet block, inserts the corresponding translated TypeScript snippet.
|
||||
It assumes that the ordering of the Python snippets
|
||||
(from extract_python_snippets) matches the order they appear in the markdown.
|
||||
"""
|
||||
output_lines = []
|
||||
lines = markdown.splitlines(keepends=True)
|
||||
inside_block = False
|
||||
snippet_index = 0
|
||||
|
||||
for line in lines:
|
||||
output_lines.append(line)
|
||||
if not inside_block and opening_pattern.match(line):
|
||||
# We've encountered the start of a python code block.
|
||||
inside_block = True
|
||||
elif inside_block:
|
||||
if closing_pattern.match(line):
|
||||
# End of a python snippet block.
|
||||
inside_block = False
|
||||
if snippet_index < len(typescript_snippets):
|
||||
# Insert an extra newline for clarity, then the translated TypeScript snippet.
|
||||
output_lines.append("\n")
|
||||
output_lines.append(typescript_snippets[snippet_index])
|
||||
output_lines.append("\n")
|
||||
snippet_index += 1
|
||||
return "".join(output_lines)
|
||||
|
||||
|
||||
def main(file_path: str) -> None:
|
||||
# Read the markdown file.
|
||||
with open(file_path, "r") as f:
|
||||
markdown_content = f.read()
|
||||
|
||||
if translate_only:
|
||||
translated = translate_python_to_ts(markdown_content)
|
||||
output_path = file_path.replace(".md", ".translated.md")
|
||||
with open(output_path, "w", encoding="utf-8") as f:
|
||||
f.write(translated)
|
||||
print(f"Translated JS/TS version written to: {output_path}")
|
||||
# 1. Extract all Python snippets.
|
||||
python_snippets = extract_python_snippets(markdown_content)[:1]
|
||||
|
||||
elif consolidate_only:
|
||||
consolidated = consolidate_python_and_ts(markdown_content)
|
||||
with open(file_path, "w", encoding="utf-8") as f:
|
||||
f.write(consolidated)
|
||||
print(f"Consolidated content written to: {file_path}")
|
||||
# 2. Translate each Python snippet to TypeScript.
|
||||
typescript_snippets = []
|
||||
# Replace with .batch() for faster translation
|
||||
for python_snippet in _tqdm(python_snippets):
|
||||
ts_snippet = translate_snippet(python_snippet)
|
||||
typescript_snippets.append(ts_snippet)
|
||||
|
||||
else:
|
||||
# Default behavior: translate first, then consolidate both
|
||||
translated = translate_python_to_ts(markdown_content)
|
||||
combined = f"{markdown_content.strip()}\n\n\n{translated.strip()}"
|
||||
consolidated = consolidate_python_and_ts(combined)
|
||||
with open(file_path, "w", encoding="utf-8") as f:
|
||||
f.write(consolidated)
|
||||
print(f"Translated and consolidated content written to: {file_path}")
|
||||
# 3. Insert the TypeScript translations after their respective Python snippets.
|
||||
updated_markdown = insert_translations_into_markdown(
|
||||
markdown_content, typescript_snippets
|
||||
)
|
||||
|
||||
# Overwrite the original markdown file with the updated content.
|
||||
with open(file_path, "w") as f:
|
||||
f.write(updated_markdown)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(
|
||||
description=(
|
||||
"Translate Python markdown to TypeScript and/or consolidate "
|
||||
"Python-JS markdown into one file."
|
||||
)
|
||||
description="Translate Python snippets in a markdown file to TypeScript and insert them after each Python snippet."
|
||||
)
|
||||
parser.add_argument("file_path", type=str, help="Path to the markdown file.")
|
||||
parser.add_argument(
|
||||
"--translate-only",
|
||||
action="store_true",
|
||||
help="Only generate the JS translation.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--consolidate-only",
|
||||
action="store_true",
|
||||
help="Only consolidate pre-paired Python and JS content.",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.translate_only and args.consolidate_only:
|
||||
raise ValueError(
|
||||
"Cannot use both --translate-only and --consolidate-only at the same time."
|
||||
)
|
||||
|
||||
main(
|
||||
args.file_path,
|
||||
translate_only=args.translate_only,
|
||||
consolidate_only=args.consolidate_only,
|
||||
)
|
||||
main(args.file_path)
|
||||
|
||||
@@ -1,72 +1,22 @@
|
||||
"""Experimental script to generate consolidated llms text from the docs."""
|
||||
|
||||
import asyncio
|
||||
import glob
|
||||
import os
|
||||
import re
|
||||
from typing import TypedDict, List, Optional
|
||||
from typing import TypedDict, List
|
||||
|
||||
import yaml
|
||||
from langchain.chat_models import init_chat_model
|
||||
from langchain_core.rate_limiters import InMemoryRateLimiter
|
||||
from mkdocs.structure.files import File
|
||||
from mkdocs.structure.pages import Page
|
||||
from pydantic import BaseModel, Field
|
||||
from yaml import SafeLoader
|
||||
|
||||
from _scripts.notebook_hooks import (
|
||||
_on_page_markdown_with_config,
|
||||
_apply_conditional_rendering,
|
||||
)
|
||||
from _scripts.notebook_hooks import _on_page_markdown_with_config
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
# Get source directory (parent of HERE / docs)
|
||||
SOURCE_DIR = os.path.abspath(os.path.join(os.path.dirname(HERE), "docs"))
|
||||
|
||||
|
||||
async def convert_ipynb_to_md(file_path: str) -> Optional[str]:
|
||||
"""Process a file (markdown or notebook) to markdown format.
|
||||
|
||||
Args:
|
||||
file_path: Path to the file to process
|
||||
|
||||
Returns:
|
||||
Processed markdown content if successful, None otherwise
|
||||
"""
|
||||
rel_path = os.path.relpath(file_path, SOURCE_DIR)
|
||||
|
||||
# Create File and Page objects to match mkdocs structure
|
||||
file_obj = File(
|
||||
path=rel_path, src_dir=SOURCE_DIR, dest_dir="", use_directory_urls=True
|
||||
)
|
||||
page = Page(
|
||||
title="",
|
||||
file=file_obj,
|
||||
config={},
|
||||
)
|
||||
|
||||
try:
|
||||
# Read raw content
|
||||
with open(file_path, "r", encoding="utf-8") as f:
|
||||
content = f.read()
|
||||
|
||||
# Convert to markdown without logic to resolve API references
|
||||
processed_content = _on_page_markdown_with_config(
|
||||
content, page, add_api_references=False, remove_base64_images=True
|
||||
)
|
||||
# Remove self-closing img tags <img ... />
|
||||
processed_content = re.sub(r"<img[^>]*/>", "", processed_content)
|
||||
# Remove img tags with content <img ...>...</img>
|
||||
processed_content = re.sub(
|
||||
r"<img[^>]*>.*?</img>", "", processed_content, flags=re.DOTALL
|
||||
)
|
||||
return processed_content
|
||||
except Exception as e:
|
||||
print(f"Error processing file {file_path}: {e}")
|
||||
return None
|
||||
|
||||
|
||||
async def generate_full_llms_text(output_file: str) -> None:
|
||||
def generate_full_llms_text(output_file: str) -> str:
|
||||
"""Generate a consolidated text file from markdown/notebook files for LLM training.
|
||||
|
||||
Args:
|
||||
@@ -74,9 +24,11 @@ async def generate_full_llms_text(output_file: str) -> None:
|
||||
"""
|
||||
# Collect all markdown and notebook files
|
||||
all_files = glob.glob(os.path.join(SOURCE_DIR, "how-tos/*.md"), recursive=True)
|
||||
|
||||
all_files.extend(
|
||||
glob.glob(os.path.join(SOURCE_DIR, "how-tos/*.ipynb"), recursive=True)
|
||||
)
|
||||
# Add all concepts
|
||||
all_files.extend(
|
||||
glob.glob(os.path.join(SOURCE_DIR, "concepts/*.md"), recursive=True)
|
||||
)
|
||||
@@ -86,14 +38,30 @@ async def generate_full_llms_text(output_file: str) -> None:
|
||||
|
||||
all_content = []
|
||||
|
||||
# Process files concurrently
|
||||
tasks = [convert_ipynb_to_md(file_path) for file_path in all_files]
|
||||
results = await asyncio.gather(*tasks)
|
||||
# Process each file
|
||||
for file_path in all_files:
|
||||
print(f"Processing {file_path}")
|
||||
rel_path = os.path.relpath(file_path, SOURCE_DIR)
|
||||
|
||||
# Combine results with file paths
|
||||
for file_path, processed_content in zip(all_files, results):
|
||||
# Create File and Page objects to match mkdocs structure
|
||||
file_obj = File(
|
||||
path=rel_path, src_dir=SOURCE_DIR, dest_dir="", use_directory_urls=True
|
||||
)
|
||||
page = Page(
|
||||
title="",
|
||||
file=file_obj,
|
||||
config={},
|
||||
)
|
||||
|
||||
# Read raw content
|
||||
with open(file_path, "r", encoding="utf-8") as f:
|
||||
content = f.read()
|
||||
|
||||
# Convert to markdown without logic to resolve API references
|
||||
processed_content = _on_page_markdown_with_config(
|
||||
content, page, add_api_references=False, remove_base64_images=True
|
||||
)
|
||||
if processed_content:
|
||||
rel_path = os.path.relpath(file_path, SOURCE_DIR)
|
||||
# Add file name
|
||||
all_content.append(f"---\n{rel_path}\n---")
|
||||
# Add content
|
||||
@@ -118,7 +86,6 @@ class NavItem(TypedDict):
|
||||
title: str
|
||||
url: str
|
||||
hierarchy: tuple[str, ...]
|
||||
description: str
|
||||
|
||||
|
||||
def _flatten_nav(
|
||||
@@ -131,14 +98,7 @@ def _flatten_nav(
|
||||
new_path = path + (title,)
|
||||
if isinstance(node, str):
|
||||
# Leaf page
|
||||
flat.append(
|
||||
{
|
||||
"title": title,
|
||||
"url": node,
|
||||
"hierarchy": new_path,
|
||||
"description": "",
|
||||
}
|
||||
)
|
||||
flat.append({"title": title, "url": node, "hierarchy": new_path})
|
||||
elif isinstance(node, list):
|
||||
# Dive in, carrying along the updated path
|
||||
flat.extend(_flatten_nav(node, new_path))
|
||||
@@ -149,84 +109,14 @@ def _flatten_nav(
|
||||
elif isinstance(item, str):
|
||||
# Bare string entry → use itself as title, and as URL
|
||||
new_path = path + (item,)
|
||||
flat.append(
|
||||
{"title": item, "url": item, "hierarchy": new_path, "description": ""}
|
||||
)
|
||||
flat.append({"title": item, "url": item, "hierarchy": new_path})
|
||||
else:
|
||||
raise TypeError(f"Unexpected item type {type(item)} in nav")
|
||||
return flat
|
||||
|
||||
|
||||
class PageInfo(BaseModel):
|
||||
title: str = Field(description="The title of the page")
|
||||
description: str = Field(
|
||||
description="A short description of the page no longer than 3 sentences "
|
||||
"explaining the kind of content that can be found in the page."
|
||||
)
|
||||
|
||||
|
||||
async def process_nav_items(nav_items: list[NavItem]) -> list[NavItem]:
|
||||
"""Open the contents of each nav item and come up with a better title and description."""
|
||||
rate_limiter = InMemoryRateLimiter(requests_per_second=10)
|
||||
model = init_chat_model("gpt-4o-mini", temperature=0.0, rate_limiter=rate_limiter)
|
||||
model = model.with_structured_output(PageInfo)
|
||||
|
||||
async def process_single_item(item: NavItem) -> NavItem:
|
||||
path = item["url"]
|
||||
file_path = os.path.join(SOURCE_DIR, path)
|
||||
|
||||
# Process the file content (handles both markdown and notebooks)
|
||||
if path.endswith(".ipynb"):
|
||||
content = await convert_ipynb_to_md(file_path)
|
||||
else:
|
||||
with open(file_path, "r", encoding="utf-8") as f:
|
||||
content = f.read()
|
||||
|
||||
if not content:
|
||||
return item
|
||||
|
||||
# Generate a better title and description
|
||||
response = await model.ainvoke(
|
||||
[
|
||||
{
|
||||
"role": "system",
|
||||
"content": "You are a technical documentation writer. "
|
||||
"You are given a markdown page of documentation. "
|
||||
"Please come up with an appropriate title and "
|
||||
"description for the page. The description should "
|
||||
"be a short summary of the page content that is "
|
||||
"no longer than 3 sentences.",
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "The markdown page is as follows:\n\n" + content,
|
||||
},
|
||||
]
|
||||
)
|
||||
return {
|
||||
"title": response.title,
|
||||
"url": item["url"],
|
||||
"hierarchy": item["hierarchy"],
|
||||
"description": response.description,
|
||||
}
|
||||
|
||||
# Remove any items that start with http:// or https:// looking only for
|
||||
# local file at this stages.
|
||||
nav_items = [
|
||||
item
|
||||
for item in nav_items
|
||||
if not item["url"].startswith(("http://", "https://"))
|
||||
]
|
||||
# Process items in parallel
|
||||
tasks = [process_single_item(item) for item in nav_items]
|
||||
new_nav_items = await asyncio.gather(*tasks)
|
||||
return new_nav_items
|
||||
|
||||
|
||||
async def generate_nav_links_text(
|
||||
output_file: str, *, replace_links: bool = False
|
||||
) -> None:
|
||||
"""Generate llms.txt from mkdocs.yaml."""
|
||||
def generate_nav_links_text(output_file: str, *, replace_links: bool = False) -> None:
|
||||
"""Generate a text file containing navigation structure and links from mkdocs.yaml."""
|
||||
# Get path to mkdocs.yaml relative to this script
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
mkdocs_path = os.path.join(os.path.dirname(script_dir), "mkdocs.yml")
|
||||
@@ -239,15 +129,15 @@ async def generate_nav_links_text(
|
||||
nav = config.get("nav", [])
|
||||
flattened = _flatten_nav(nav)
|
||||
|
||||
processed_nav = await process_nav_items(flattened)
|
||||
|
||||
with open(output_file, "w") as f:
|
||||
current_section = None
|
||||
for item in processed_nav:
|
||||
for item in flattened:
|
||||
# Get the top-level section (first item in hierarchy)
|
||||
section = item["hierarchy"][0]
|
||||
|
||||
if section not in {"Guides", "Examples", "Resources"}:
|
||||
if section not in {
|
||||
"Guides", "Examples", "Resources"
|
||||
}:
|
||||
continue
|
||||
|
||||
# If we're starting a new section, add a heading
|
||||
@@ -255,7 +145,15 @@ async def generate_nav_links_text(
|
||||
f.write(f"\n# {section}\n\n")
|
||||
current_section = section
|
||||
|
||||
title = item["title"]
|
||||
# Add the item as a bullet point with title and link
|
||||
# Include full hierarchy path in title, separated by " > "
|
||||
hierarchy_path = " > ".join(item["hierarchy"][1:])
|
||||
title = (
|
||||
f"{item['title']} ({hierarchy_path})"
|
||||
if hierarchy_path
|
||||
else item["title"]
|
||||
)
|
||||
|
||||
# Process URL based on replace_links flag
|
||||
url = item["url"]
|
||||
if replace_links:
|
||||
@@ -265,7 +163,7 @@ async def generate_nav_links_text(
|
||||
url = url.rstrip("/") + "/"
|
||||
url = f"https://langchain-ai.github.io/langgraph/{url}"
|
||||
|
||||
f.write(f"- [{title}]({url}): {item['description']}\n")
|
||||
f.write(f"- [{title}]({url})\n")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
@@ -290,10 +188,6 @@ if __name__ == "__main__":
|
||||
|
||||
args = parser.parse_args()
|
||||
if args.link_only:
|
||||
coro = generate_nav_links_text(
|
||||
args.output_file, replace_links=args.replace_links
|
||||
)
|
||||
generate_nav_links_text(args.output_file, replace_links=args.replace_links)
|
||||
else:
|
||||
coro = generate_full_llms_text(args.output_file)
|
||||
|
||||
asyncio.run(coro)
|
||||
generate_full_llms_text(args.output_file)
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
JS_LINK_MAP = {
|
||||
"langgraph.types.interrupt": "https://langchain-ai.github.io/langgraphjs/reference/functions/langgraph.interrupt-2.html",
|
||||
"create_react_agent": "https://langchain-ai.github.io/langgraphjs/reference/functions/langgraph_prebuilt.createReactAgent.html",
|
||||
"langgraph.types.Command": "https://langchain-ai.github.io/langgraphjs/reference/classes/langgraph.Command.html",
|
||||
|
||||
}
|
||||
@@ -1,22 +1,14 @@
|
||||
"""mkdocs hooks for adding custom logic to documentation pipeline.
|
||||
|
||||
Lifecycle events: https://www.mkdocs.org/dev-guide/plugins/#events
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import posixpath
|
||||
import re
|
||||
from typing import Any, Dict
|
||||
|
||||
from bs4 import BeautifulSoup
|
||||
from mkdocs.config.defaults import MkDocsConfig
|
||||
from mkdocs.structure.files import Files, File
|
||||
from mkdocs.structure.pages import Page
|
||||
|
||||
from _scripts.generate_api_reference_links import update_markdown_with_imports
|
||||
from _scripts.notebook_convert import convert_notebook
|
||||
from _scripts.link_map import JS_LINK_MAP
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logging.basicConfig()
|
||||
@@ -79,7 +71,7 @@ REDIRECT_MAP = {
|
||||
"cloud/faq/studio.md": "concepts/langgraph_studio.md#studio-faqs",
|
||||
"cloud/how-tos/human_in_the_loop_edit_state.md": "cloud/how-tos/add-human-in-the-loop.md",
|
||||
"cloud/how-tos/human_in_the_loop_user_input.md": "cloud/how-tos/add-human-in-the-loop.md",
|
||||
"concepts/platform_architecture.md": "concepts/langgraph_cloud#architecture",
|
||||
"concepts/platform_architecture.md": "langgraph/concepts/langgraph_cloud#architecture",
|
||||
# cloud streaming redirects
|
||||
"cloud/how-tos/stream_values.md": "cloud/how-tos/streaming.md#stream-graph-state",
|
||||
"cloud/how-tos/stream_updates.md": "cloud/how-tos/streaming.md#stream-graph-state",
|
||||
@@ -109,7 +101,8 @@ REDIRECT_MAP = {
|
||||
"how-tos/deploy-self-hosted.md": "cloud/deployment/self_hosted_data_plane.md",
|
||||
"concepts/self_hosted.md": "concepts/langgraph_self_hosted_data_plane.md",
|
||||
# assistant redirects
|
||||
"cloud/how-tos/assistant_versioning.md": "cloud/how-tos/configuration_cloud.md",
|
||||
"cloud/how-tos/assistant_versioning.md": "cloud/how-tos/configuration_cloud.md"
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -159,62 +152,6 @@ def _add_path_to_code_blocks(markdown: str, page: Page) -> str:
|
||||
return code_block_pattern.sub(replace_code_block_header, markdown)
|
||||
|
||||
|
||||
def _resolve_cross_references(md_text: str, link_map: dict[str, str]) -> str:
|
||||
"""Replace [title][identifier] with [title](url) using language-specific link_map.
|
||||
|
||||
Args:
|
||||
md_text: The markdown text to process.
|
||||
link_map: mapping of identifier to URL.
|
||||
|
||||
Returns:
|
||||
The processed markdown text with cross-references resolved.
|
||||
"""
|
||||
# Pattern to match [title][identifier]
|
||||
pattern = re.compile(r"\[([^\]]+)\]\[([^\]]+)\]")
|
||||
|
||||
def replace_reference(match: re.Match) -> str:
|
||||
"""Replace the matched reference with the corresponding URL."""
|
||||
title, identifier = match.group(1), match.group(2)
|
||||
url = link_map.get(identifier)
|
||||
|
||||
if url:
|
||||
return f"[{title}]({url})"
|
||||
else:
|
||||
# Leave it unchanged if not found
|
||||
return match.group(0)
|
||||
|
||||
return pattern.sub(replace_reference, md_text)
|
||||
|
||||
|
||||
def _apply_conditional_rendering(md_text: str, target_language: str) -> str:
|
||||
if target_language not in {"python", "js"}:
|
||||
raise ValueError("target_language must be 'python' or 'js'")
|
||||
|
||||
pattern = re.compile(
|
||||
r"(?P<indent>[ \t]*):::(?P<language>\w+)\s*\n"
|
||||
r"(?P<content>((?:.*\n)*?))" # Capture the content inside the block
|
||||
r"(?P=indent):::" # Match closing with the same indentation
|
||||
)
|
||||
|
||||
def replace_conditional_blocks(match: re.Match) -> str:
|
||||
"""Keep active conditionals."""
|
||||
language = match.group("language")
|
||||
content = match.group("content")
|
||||
|
||||
if language not in {"python", "js"}:
|
||||
# If the language is not supported, return the original block
|
||||
return match.group(0)
|
||||
|
||||
if language == target_language:
|
||||
return content
|
||||
|
||||
# If the language does not match, return an empty string
|
||||
return ""
|
||||
|
||||
processed = pattern.sub(replace_conditional_blocks, md_text)
|
||||
return processed
|
||||
|
||||
|
||||
def _highlight_code_blocks(markdown: str) -> str:
|
||||
"""Find code blocks with highlight comments and add hl_lines attribute.
|
||||
|
||||
@@ -314,20 +251,6 @@ def _on_page_markdown_with_config(
|
||||
# Apply highlight comments to code blocks
|
||||
markdown = _highlight_code_blocks(markdown)
|
||||
|
||||
# Apply conditional rendering for code blocks
|
||||
target_language = kwargs.get("target_language", "js")
|
||||
markdown = _apply_conditional_rendering(markdown, target_language)
|
||||
if target_language == "js":
|
||||
markdown = _resolve_cross_references(markdown, JS_LINK_MAP)
|
||||
elif target_language == "python":
|
||||
# Via a dedicated plugin
|
||||
pass
|
||||
else:
|
||||
raise ValueError(
|
||||
f"Unsupported target language: {target_language}. "
|
||||
"Supported languages are 'python' and 'js'."
|
||||
)
|
||||
|
||||
# Add file path as an attribute to code blocks that are executable.
|
||||
# This file path is used to associate fixtures with the executable code
|
||||
# which can be used in CI to test the docs without making network requests.
|
||||
@@ -369,7 +292,7 @@ Redirecting...
|
||||
"""
|
||||
|
||||
|
||||
def _write_html(site_dir, old_path, new_path):
|
||||
def write_html(site_dir, old_path, new_path):
|
||||
"""Write an HTML file in the site_dir with a meta redirect to the new page"""
|
||||
# Determine all relevant paths
|
||||
old_path_abs = os.path.join(site_dir, old_path)
|
||||
@@ -385,52 +308,6 @@ def _write_html(site_dir, old_path, new_path):
|
||||
f.write(content)
|
||||
|
||||
|
||||
def _inject_gtm(html: str) -> str:
|
||||
"""Inject Google Tag Manager code into the HTML.
|
||||
|
||||
Code to inject Google Tag Manager noscript tag immediately after <body>.
|
||||
|
||||
This is done via hooks rather than via a template because the MkDocs material
|
||||
theme does not seem to allow placing the code immediately after the <body> tag
|
||||
without modifying the template files directly.
|
||||
|
||||
Args:
|
||||
html: The HTML content to modify.
|
||||
|
||||
Returns:
|
||||
The modified HTML content with GTM code injected.
|
||||
"""
|
||||
# Code was copied from Google Tag Manager setup instructions.
|
||||
gtm_code = """
|
||||
<!-- Google Tag Manager (noscript) -->
|
||||
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-T35S4S46"
|
||||
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
|
||||
<!-- End Google Tag Manager (noscript) -->
|
||||
"""
|
||||
soup = BeautifulSoup(html, "html.parser")
|
||||
body = soup.body
|
||||
if body:
|
||||
# Insert the GTM code as raw HTML at the top of <body>
|
||||
body.insert(0, BeautifulSoup(gtm_code, "html.parser"))
|
||||
return str(soup)
|
||||
else:
|
||||
return html # fallback if no <body> found
|
||||
|
||||
|
||||
def on_post_page(output: str, page: Page, config: MkDocsConfig) -> str:
|
||||
"""Inject Google Tag Manager noscript tag immediately after <body>.
|
||||
|
||||
Args:
|
||||
output: The HTML output of the page.
|
||||
page: The page instance.
|
||||
config: The MkDocs configuration object.
|
||||
|
||||
Returns:
|
||||
modified HTML output with GTM code injected.
|
||||
"""
|
||||
return _inject_gtm(output)
|
||||
|
||||
|
||||
# Create HTML files for redirects after site dir has been built
|
||||
def on_post_build(config):
|
||||
use_directory_urls = config.get("use_directory_urls")
|
||||
@@ -447,4 +324,4 @@ def on_post_build(config):
|
||||
+ hash
|
||||
+ suffix
|
||||
)
|
||||
_write_html(config["site_dir"], old_html_path, new_html_path)
|
||||
write_html(config["site_dir"], old_html_path, new_html_path)
|
||||
|
||||
@@ -11,13 +11,11 @@ hide:
|
||||
|
||||
This guide shows you how to set up and use LangGraph's **prebuilt**, **reusable** components, which are designed to help you construct agentic systems quickly and reliably.
|
||||
|
||||
:::python
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before you start this tutorial, ensure you have the following:
|
||||
|
||||
- An [Anthropic](https://console.anthropic.com/settings/keys) API key
|
||||
- An [Anthropic](https://console.anthropic.com/settings/admin-keys) API key
|
||||
|
||||
## 1. Install dependencies
|
||||
|
||||
@@ -230,244 +228,3 @@ response["structured_response"]
|
||||
- [Deploy your agent locally](../tutorials/langgraph-platform/local-server.md)
|
||||
- [Learn more about prebuilt agents](../agents/overview.md)
|
||||
- [LangGraph Platform quickstart](../cloud/quick_start.md)
|
||||
|
||||
:::
|
||||
|
||||
:::js
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before you start this tutorial, ensure you have the following:
|
||||
|
||||
- An [Anthropic](https://console.anthropic.com/settings/keys) API key
|
||||
|
||||
## 1. Install dependencies
|
||||
|
||||
If you haven't already, install LangGraph and LangChain:
|
||||
|
||||
```
|
||||
npm install langchain @langchain/langgraph @langchain/anthropic
|
||||
```
|
||||
|
||||
## 2. Create an agent
|
||||
|
||||
Use [`createReactAgent`][create_react_agent] to instantiate an agent:
|
||||
|
||||
```ts
|
||||
import { createReactAgent } from "@langchain/langgraph/prebuilt";
|
||||
import { initChatModel } from "langchain/chat_models/universal";
|
||||
import { tool } from "@langchain/core/tools";
|
||||
import { z } from "zod";
|
||||
|
||||
const getWeather = tool( // (1)!
|
||||
async (input: { city: string }) => {
|
||||
return `It's always sunny in ${input.city}!`;
|
||||
},
|
||||
{
|
||||
name: "getWeather",
|
||||
schema: z.object({
|
||||
city: z.string().describe("The city to get the weather for"),
|
||||
}),
|
||||
description: "Get weather for a given city.",
|
||||
}
|
||||
);
|
||||
|
||||
const llm = await initChatModel("anthropic:claude-3-7-sonnet-latest"); // (2)!
|
||||
const agent = createReactAgent({
|
||||
llm,
|
||||
tools: [getWeather], // (3)!
|
||||
prompt: "You are a helpful assistant", // (4)!
|
||||
});
|
||||
|
||||
// Run the agent
|
||||
await agent.invoke({
|
||||
messages: [{ role: "user", content: "what is the weather in sf" }],
|
||||
});
|
||||
```
|
||||
|
||||
1. Define a tool for the agent to use. For more advanced tool usage and customization, check the [tools](./tools.md) page.
|
||||
2. Provide a language model for the agent to use. To learn more about configuring language models for the agents, check the [models](./models.md) page.
|
||||
3. Provide a list of tools for the model to use.
|
||||
4. Provide a system prompt (instructions) to the language model used by the agent.
|
||||
|
||||
## 3. Configure an LLM
|
||||
|
||||
Use [`initChatModel`](https://api.js.langchain.com/functions/langchain.chat_models_universal.initChatModel.html) to configure an LLM with specific parameters, such as temperature:
|
||||
|
||||
```ts
|
||||
import { createReactAgent } from "@langchain/langgraph/prebuilt";
|
||||
import { initChatModel } from "langchain/chat_models/universal";
|
||||
|
||||
// highlight-next-line
|
||||
const llm = await initChatModel("anthropic:claude-3-7-sonnet-latest", {
|
||||
// highlight-next-line
|
||||
temperature: 0,
|
||||
});
|
||||
|
||||
const agent = createReactAgent({
|
||||
// highlight-next-line
|
||||
llm,
|
||||
tools: [getWeather],
|
||||
});
|
||||
```
|
||||
|
||||
See the [models](./models.md) page for more information on how to configure LLMs.
|
||||
|
||||
## 4. Add a custom prompt
|
||||
|
||||
Prompts instruct the LLM how to behave. They can be:
|
||||
|
||||
- **Static**: A string is interpreted as a **system message**
|
||||
- **Dynamic**: a list of messages generated at **runtime** based on input or configuration
|
||||
|
||||
=== "Static prompt"
|
||||
|
||||
Define a fixed prompt string or list of messages.
|
||||
|
||||
```ts
|
||||
import { createReactAgent } from "@langchain/langgraph/prebuilt";
|
||||
import { initChatModel } from "langchain/chat_models/universal";
|
||||
|
||||
const llm = await initChatModel("anthropic:claude-3-7-sonnet-latest");
|
||||
const agent = createReactAgent({
|
||||
llm,
|
||||
tools: [getWeather],
|
||||
// A static prompt that never changes
|
||||
// highlight-next-line
|
||||
prompt: "Never answer questions about the weather.",
|
||||
});
|
||||
|
||||
await agent.invoke({
|
||||
messages: "what is the weather in sf",
|
||||
});
|
||||
```
|
||||
|
||||
=== "Dynamic prompt"
|
||||
|
||||
Define a function that returns a message list based on the agent's state and configuration:
|
||||
|
||||
```ts
|
||||
import { BaseMessageLike } from "@langchain/core/messages";
|
||||
import { RunnableConfig } from "@langchain/core/runnables";
|
||||
import { initChatModel } from "langchain/chat_models/universal";
|
||||
import { MessagesAnnotation } from "@langchain/langgraph";
|
||||
import { createReactAgent } from "@langchain/langgraph/prebuilt";
|
||||
|
||||
const prompt = (
|
||||
state: typeof MessagesAnnotation.State,
|
||||
config: RunnableConfig
|
||||
): BaseMessageLike[] => { // (1)!
|
||||
const userName = config.configurable?.userName;
|
||||
const systemMsg = `You are a helpful assistant. Address the user as ${userName}.`;
|
||||
return [{ role: "system", content: systemMsg }, ...state.messages];
|
||||
};
|
||||
|
||||
const llm = await initChatModel("anthropic:claude-3-7-sonnet-latest");
|
||||
const agent = createReactAgent({
|
||||
llm,
|
||||
tools: [getWeather],
|
||||
// highlight-next-line
|
||||
prompt,
|
||||
});
|
||||
|
||||
await agent.invoke(
|
||||
{ messages: [{ role: "user", content: "what is the weather in sf" }] },
|
||||
// highlight-next-line
|
||||
{ configurable: { userName: "John Smith" } }
|
||||
);
|
||||
```
|
||||
|
||||
1. Dynamic prompts allow including non-message [context](./context.md) when constructing an input to the LLM, such as:
|
||||
|
||||
- Information passed at runtime, like a `userId` or API credentials (using `config`).
|
||||
- Internal agent state updated during a multi-step reasoning process (using `state`).
|
||||
|
||||
Dynamic prompts can be defined as functions that take `state` and `config` and return a list of messages to send to the LLM.
|
||||
|
||||
For more information, see [Context](./context.md).
|
||||
|
||||
## 5. Add memory
|
||||
|
||||
To allow multi-turn conversations with an agent, you need to enable [persistence](../concepts/persistence.md) by providing a `checkpointer` when creating an agent. At runtime you need to provide a config containing `thread_id` — a unique identifier for the conversation (session):
|
||||
|
||||
```ts
|
||||
import { createReactAgent } from "@langchain/langgraph/prebuilt";
|
||||
import { MemorySaver } from "@langchain/langgraph-checkpoint";
|
||||
import { initChatModel } from "langchain/chat_models/universal";
|
||||
|
||||
// highlight-next-line
|
||||
const checkpointer = new MemorySaver();
|
||||
|
||||
const llm = await initChatModel("anthropic:claude-3-7-sonnet-latest");
|
||||
const agent = createReactAgent({
|
||||
llm,
|
||||
tools: [getWeather],
|
||||
// highlight-next-line
|
||||
checkpointer, // (1)!
|
||||
});
|
||||
|
||||
// Run the agent
|
||||
// highlight-next-line
|
||||
const config = { configurable: { thread_id: "1" } };
|
||||
const sfResponse = await agent.invoke(
|
||||
{ messages: [{ role: "user", content: "what is the weather in sf" }] },
|
||||
config // (2)!
|
||||
);
|
||||
const nyResponse = await agent.invoke(
|
||||
{ messages: [{ role: "user", content: "what about new york?" }] },
|
||||
config
|
||||
);
|
||||
```
|
||||
|
||||
1. `checkpointer` allows the agent to store its 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.
|
||||
2. Pass configuration with `thread_id` to be able to resume the same conversation on future agent invocations.
|
||||
|
||||
When you enable the checkpointer, it stores agent state at every step in the provided checkpointer database (or in memory, if using `InMemorySaver`).
|
||||
|
||||
Note that in the above example, when the agent is invoked the second time with the same `thread_id`, the original message history from the first conversation is automatically included, together with the new user input.
|
||||
|
||||
For more information, see [Memory](./memory.md).
|
||||
|
||||
## 6. Configure structured output
|
||||
|
||||
To produce structured responses conforming to a schema, use the `responseFormat` parameter. The schema can be defined with a `zod` schema. The result will be accessible via the `structuredResponse` field.
|
||||
|
||||
```ts
|
||||
import { z } from "zod";
|
||||
import { createReactAgent } from "@langchain/langgraph/prebuilt";
|
||||
import { initChatModel } from "langchain/chat_models/universal";
|
||||
|
||||
const WeatherResponse = z.object({
|
||||
conditions: z.string(),
|
||||
});
|
||||
|
||||
const llm = await initChatModel("anthropic:claude-3-7-sonnet-latest");
|
||||
const agent = createReactAgent({
|
||||
llm,
|
||||
tools: [getWeather],
|
||||
// highlight-next-line
|
||||
responseFormat: WeatherResponse, // (1)!
|
||||
});
|
||||
|
||||
const response = await agent.invoke({
|
||||
messages: [{ role: "user", content: "what is the weather in sf" }],
|
||||
});
|
||||
// highlight-next-line
|
||||
response.structuredResponse;
|
||||
```
|
||||
|
||||
1. When `responseFormat` is provided, a separate step is added at the end of the agent loop: agent message history is passed to an LLM with structured output to generate a structured response.
|
||||
|
||||
To provide a system prompt to this LLM, use an object `{ prompt, schema }`, e.g., `responseFormat: { prompt, schema: WeatherResponse }`.
|
||||
|
||||
!!! Note "LLM post-processing"
|
||||
|
||||
Structured output requires an additional call to the LLM to format the response according to the schema.
|
||||
|
||||
## Next steps
|
||||
|
||||
- [Deploy your agent locally](../tutorials/langgraph-platform/local-server.md)
|
||||
- [Learn more about prebuilt agents](../agents/overview.md)
|
||||
- [LangGraph Platform quickstart](../cloud/quick_start.md)
|
||||
|
||||
:::
|
||||
|
Before Width: | Height: | Size: 9.3 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 16 KiB |
@@ -43,8 +43,6 @@ when you have values that don't change mid-run.
|
||||
Specify configuration using a key called **"configurable"** which is reserved
|
||||
for this purpose:
|
||||
|
||||
|
||||
:::python
|
||||
```python
|
||||
agent.invoke(
|
||||
{"messages": [{"role": "user", "content": "hi!"}]},
|
||||
@@ -52,23 +50,11 @@ agent.invoke(
|
||||
config={"configurable": {"user_id": "user_123"}}
|
||||
)
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```ts
|
||||
await agent.invoke(
|
||||
{ messages: "hi!" },
|
||||
// highlight-next-line
|
||||
{ configurable: { userId: "user_123" } }
|
||||
)
|
||||
```
|
||||
:::
|
||||
|
||||
### State (mutable context)
|
||||
|
||||
State acts as short-term memory during a run. It holds dynamic data that can evolve during execution, such as values derived from tools or LLM outputs.
|
||||
|
||||
:::python
|
||||
```python
|
||||
class CustomState(AgentState):
|
||||
# highlight-next-line
|
||||
@@ -85,29 +71,6 @@ agent.invoke({
|
||||
"user_name": "Jane"
|
||||
})
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```ts
|
||||
const CustomState = Annotation.Root({
|
||||
...MessagesAnnotation.spec,
|
||||
userName: Annotation<string>,
|
||||
});
|
||||
|
||||
const agent = createReactAgent({
|
||||
// Other agent parameters...
|
||||
// highlight-next-line
|
||||
stateSchema: CustomState,
|
||||
})
|
||||
|
||||
await agent.invoke(
|
||||
// highlight-next-line
|
||||
{ messages: "hi!", userName: "Jane" }
|
||||
)
|
||||
```
|
||||
:::
|
||||
|
||||
|
||||
|
||||
!!! tip "Turning on memory"
|
||||
|
||||
@@ -130,8 +93,6 @@ Common use cases:
|
||||
- Role or goal customization
|
||||
- Conditional behavior (e.g., user is admin)
|
||||
|
||||
:::python
|
||||
|
||||
=== "Using config"
|
||||
|
||||
```python
|
||||
@@ -201,90 +162,8 @@ Common use cases:
|
||||
})
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
:::js
|
||||
=== "Using config"
|
||||
|
||||
```ts
|
||||
import { BaseMessageLike } from "@langchain/core/messages";
|
||||
import { RunnableConfig } from "@langchain/core/runnables";
|
||||
import { initChatModel } from "langchain/chat_models/universal";
|
||||
import { MessagesAnnotation } from "@langchain/langgraph";
|
||||
import { createReactAgent } from "@langchain/langgraph/prebuilt";
|
||||
|
||||
const prompt = (
|
||||
state: typeof MessagesAnnotation.State,
|
||||
// highlight-next-line
|
||||
config: RunnableConfig
|
||||
): BaseMessageLike[] => {
|
||||
// highlight-next-line
|
||||
const userName = config.configurable?.userName;
|
||||
const systemMsg = `You are a helpful assistant. Address the user as ${userName}.`;
|
||||
return [{ role: "system", content: systemMsg }, ...state.messages];
|
||||
};
|
||||
|
||||
const llm = await initChatModel("anthropic:claude-3-7-sonnet-latest");
|
||||
const agent = createReactAgent({
|
||||
llm,
|
||||
tools: [getWeather],
|
||||
// highlight-next-line
|
||||
prompt
|
||||
});
|
||||
|
||||
await agent.invoke(
|
||||
{ messages: "hi!" },
|
||||
// highlight-next-line
|
||||
{ configurable: { userName: "John Smith" } }
|
||||
);
|
||||
```
|
||||
|
||||
=== "Using state"
|
||||
|
||||
```ts
|
||||
import { BaseMessageLike } from "@langchain/core/messages";
|
||||
import { RunnableConfig } from "@langchain/core/runnables";
|
||||
import { initChatModel } from "langchain/chat_models/universal";
|
||||
import { Annotation, MessagesAnnotation } from "@langchain/langgraph";
|
||||
import { createReactAgent } from "@langchain/langgraph/prebuilt";
|
||||
|
||||
const CustomState = Annotation.Root({
|
||||
...MessagesAnnotation.spec,
|
||||
// highlight-next-line
|
||||
userName: Annotation<string>,
|
||||
});
|
||||
|
||||
const prompt = (
|
||||
// highlight-next-line
|
||||
state: typeof CustomState.State,
|
||||
): BaseMessageLike[] => {
|
||||
// highlight-next-line
|
||||
const userName = state.userName;
|
||||
const systemMsg = `You are a helpful assistant. Address the user as ${userName}.`;
|
||||
return [{ role: "system", content: systemMsg }, ...state.messages];
|
||||
};
|
||||
|
||||
const llm = await initChatModel("anthropic:claude-3-7-sonnet-latest");
|
||||
const agent = createReactAgent({
|
||||
llm,
|
||||
tools: [getWeather],
|
||||
// highlight-next-line
|
||||
prompt,
|
||||
// highlight-next-line
|
||||
stateSchema: CustomState,
|
||||
});
|
||||
|
||||
await agent.invoke(
|
||||
// highlight-next-line
|
||||
{ messages: "hi!", userName: "John Smith" },
|
||||
);
|
||||
```
|
||||
:::
|
||||
|
||||
|
||||
## Accessing Context in Tools { #tools }
|
||||
|
||||
:::python
|
||||
Tools can access context through special parameter **annotations**.
|
||||
|
||||
* Use `RunnableConfig` for config access
|
||||
@@ -351,167 +230,7 @@ Tools can access context through special parameter **annotations**.
|
||||
"user_id": "user_123"
|
||||
})
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
Tools can access context through:
|
||||
|
||||
* Use `RunnableConfig` for config access
|
||||
* Use `getCurrentTaskInput()` for agent state
|
||||
|
||||
=== "Using config"
|
||||
|
||||
```ts
|
||||
import { RunnableConfig } from "@langchain/core/runnables";
|
||||
import { initChatModel } from "langchain/chat_models/universal";
|
||||
import { createReactAgent } from "@langchain/langgraph/prebuilt";
|
||||
import { tool } from "@langchain/core/tools";
|
||||
import { z } from "zod";
|
||||
|
||||
const getUserInfo = tool(
|
||||
async (input: Record<string, any>, config: RunnableConfig) => {
|
||||
// highlight-next-line
|
||||
const userId = config.configurable?.userId;
|
||||
return userId === "user_123" ? "User is John Smith" : "Unknown user";
|
||||
},
|
||||
{
|
||||
name: "get_user_info",
|
||||
description: "Look up user info.",
|
||||
schema: z.object({}),
|
||||
}
|
||||
);
|
||||
|
||||
const llm = await initChatModel("anthropic:claude-3-7-sonnet-latest");
|
||||
const agent = createReactAgent({
|
||||
llm,
|
||||
tools: [getUserInfo],
|
||||
});
|
||||
|
||||
await agent.invoke(
|
||||
{ messages: "look up user information" },
|
||||
// highlight-next-line
|
||||
{ configurable: { userId: "user_123" } }
|
||||
);
|
||||
```
|
||||
|
||||
=== "Using state"
|
||||
|
||||
```ts
|
||||
import { initChatModel } from "langchain/chat_models/universal";
|
||||
import { createReactAgent } from "@langchain/langgraph/prebuilt";
|
||||
import { Annotation, MessagesAnnotation, getCurrentTaskInput } from "@langchain/langgraph";
|
||||
import { tool } from "@langchain/core/tools";
|
||||
import { z } from "zod";
|
||||
|
||||
const CustomState = Annotation.Root({
|
||||
...MessagesAnnotation.spec,
|
||||
// highlight-next-line
|
||||
userId: Annotation<string>(),
|
||||
});
|
||||
|
||||
const getUserInfo = tool(
|
||||
async (
|
||||
input: Record<string, any>,
|
||||
) => {
|
||||
// highlight-next-line
|
||||
const state = getCurrentTaskInput() as typeof CustomState.State;
|
||||
// highlight-next-line
|
||||
const userId = state.userId;
|
||||
return userId === "user_123" ? "User is John Smith" : "Unknown user";
|
||||
},
|
||||
{
|
||||
name: "get_user_info",
|
||||
description: "Look up user info.",
|
||||
schema: z.object({})
|
||||
}
|
||||
);
|
||||
|
||||
const llm = await initChatModel("anthropic:claude-3-7-sonnet-latest");
|
||||
const agent = createReactAgent({
|
||||
llm,
|
||||
tools: [getUserInfo],
|
||||
// highlight-next-line
|
||||
stateSchema: CustomState,
|
||||
});
|
||||
|
||||
await agent.invoke(
|
||||
// highlight-next-line
|
||||
{ messages: "look up user information", userId: "user_123" }
|
||||
);
|
||||
```
|
||||
:::
|
||||
|
||||
### Update Context from Tools
|
||||
|
||||
:::python
|
||||
Tools can update agent's context (state and long-term memory) during execution. This is useful for persisting intermediate results or making information accessible to subsequent tools or prompts. See [Memory](./memory.md#read-short-term) guide for more information.
|
||||
:::
|
||||
|
||||
:::js
|
||||
Tools can modify the agent's state during execution. This is useful for persisting intermediate results or making information accessible to subsequent tools or prompts.
|
||||
|
||||
```ts
|
||||
import { Annotation, MessagesAnnotation, LangGraphRunnableConfig, Command } from "@langchain/langgraph";
|
||||
import { tool } from "@langchain/core/tools";
|
||||
import { z } from "zod";
|
||||
import { ToolMessage } from "@langchain/core/messages";
|
||||
import { initChatModel } from "langchain/chat_models/universal";
|
||||
import { createReactAgent } from "@langchain/langgraph/prebuilt";
|
||||
|
||||
const CustomState = Annotation.Root({
|
||||
...MessagesAnnotation.spec,
|
||||
// highlight-next-line
|
||||
userName: Annotation<string>(), // Will be updated by the tool
|
||||
});
|
||||
|
||||
const getUserInfo = tool(
|
||||
async (
|
||||
_input: Record<string, never>,
|
||||
config: LangGraphRunnableConfig
|
||||
): Promise<Command> => {
|
||||
const userId = config.configurable?.userId;
|
||||
if (!userId) {
|
||||
throw new Error("Please provide a user id in config.configurable");
|
||||
}
|
||||
|
||||
const toolCallId = config.toolCall?.id;
|
||||
|
||||
const name = userId === "user_123" ? "John Smith" : "Unknown user";
|
||||
// Return command to update state
|
||||
return new Command({
|
||||
update: {
|
||||
// highlight-next-line
|
||||
userName: name,
|
||||
// Update the message history
|
||||
// highlight-next-line
|
||||
messages: [
|
||||
new ToolMessage({
|
||||
content: "Successfully looked up user information",
|
||||
tool_call_id: toolCallId,
|
||||
}),
|
||||
],
|
||||
},
|
||||
});
|
||||
},
|
||||
{
|
||||
name: "get_user_info",
|
||||
description: "Look up user information.",
|
||||
schema: z.object({}),
|
||||
}
|
||||
);
|
||||
|
||||
const llm = await initChatModel("anthropic:claude-3-7-sonnet-latest");
|
||||
const agent = createReactAgent({
|
||||
llm,
|
||||
tools: [getUserInfo],
|
||||
// highlight-next-line
|
||||
stateSchema: CustomState,
|
||||
});
|
||||
|
||||
await agent.invoke(
|
||||
{ messages: "look up user information" },
|
||||
// highlight-next-line
|
||||
{ configurable: { userId: "user_123" } }
|
||||
);
|
||||
```
|
||||
:::
|
||||
Tools can update agent's context (state and long-term memory) during execution. This is useful for persisting intermediate results or making information accessible to subsequent tools or prompts. See [Memory](./memory.md#read-short-term) guide for more information.
|
||||
@@ -27,8 +27,6 @@ A human can review and edit the output from the agent before proceeding. This is
|
||||
</figure>
|
||||
|
||||
|
||||
:::python
|
||||
|
||||
## Review tool calls
|
||||
|
||||
To add a human approval step to a tool:
|
||||
@@ -36,7 +34,6 @@ 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
|
||||
@@ -236,110 +233,6 @@ 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][langgraph.types.interrupt] 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][langgraph.types.interrupt] is used in conjunction with the [`Command`][langgraph.types.Command] 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)
|
||||
|
||||
@@ -13,8 +13,6 @@ hide:
|
||||
|
||||

|
||||
|
||||
:::python
|
||||
|
||||
Install the `langchain-mcp-adapters` library to use MCP tools in LangGraph:
|
||||
|
||||
```bash
|
||||
@@ -40,7 +38,7 @@ client = MultiServerMCPClient(
|
||||
"transport": "stdio",
|
||||
},
|
||||
"weather": {
|
||||
# Ensure you start your weather server on port 8000
|
||||
# Ensure your start your weather server on port 8000
|
||||
"url": "http://localhost:8000/mcp",
|
||||
"transport": "streamable_http",
|
||||
}
|
||||
@@ -60,57 +58,6 @@ 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
|
||||
|
||||
|
||||
@@ -82,13 +82,13 @@ ny_response = agent.invoke(
|
||||
```
|
||||
|
||||
1. The `InMemorySaver` is a checkpointer that stores the agent's state in memory. In a production setting, you would typically use a database or other persistent storage. Please review the [checkpointer documentation](../reference/checkpoints.md) for more options. If you're deploying with **LangGraph Platform**, the platform will provide a production-ready checkpointer for you.
|
||||
2. The `checkpointer` is passed to the agent. This enables the agent to persist its state across invocations.
|
||||
2. The `checkpointer` is passed to the agent. This enables the agent to persist its state across invocations. Please note that
|
||||
3. A unique `thread_id` is provided in the config. This ID is used to identify the conversation session. The value is controlled by the user and can be any string.
|
||||
4. The agent will continue the conversation using the same `thread_id`. This will allow the agent to infer that the user is asking specifically about the **weather** in New York.
|
||||
|
||||
When the agent is invoked the second time with the same `thread_id`, the original message history from the first conversation is automatically included, allowing the agent to infer that the user is asking specifically about the **weather** in New York.
|
||||
|
||||
!!! Note "LangGraph Platform provides a production-ready checkpointer"
|
||||
!!! Note "LangGraph Platform providers a production-ready checkpointer"
|
||||
|
||||
If you're using [LangGraph Platform](./deployment.md), during deployment your checkpointer will be automatically configured to use a production-ready database.
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ hide:
|
||||
|
||||
# Multi-agent
|
||||
|
||||
A single agent might struggle if it needs to specialize in multiple domains or manage many tools. To tackle this, you can break your agent into smaller, independent agents and compose them into a [multi-agent system](../concepts/multi_agent.md).
|
||||
A single agent might struggle if it needs to specialize in multiple domains or manage many tools. To tackle this, you can break your agent into smaller, independent agents and composing them into a [multi-agent system](../concepts/multi_agent.md).
|
||||
|
||||
In multi-agent systems, agents need to communicate between each other. They do so via [handoffs](#handoffs) — a primitive that describes which agent to hand control to and the payload to send to that agent.
|
||||
|
||||
|
||||
@@ -40,8 +40,6 @@ 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.
|
||||
@@ -55,297 +53,3 @@ The high-level components are organized into several packages, each with a speci
|
||||
| `langmem` | Agent memory management: [**short-term and long-term**](./memory.md) | `pip install -U langmem` |
|
||||
| `agentevals` | Utilities to [**evaluate agent performance**](./evals.md) | `pip install -U agentevals` |
|
||||
|
||||
## Visualize an agent graph
|
||||
|
||||
Use the following tool to visualize the graph generated by
|
||||
[`create_react_agent`][langgraph.prebuilt.chat_agent_executor.create_react_agent]
|
||||
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`](../agents/tools.md): A list of tools (functions, APIs, or other callable objects) that the agent can use to perform tasks.
|
||||
* [`pre_model_hook`](../how-tos/create-react-agent-manage-message-history.ipynb): A function that is called before the model is invoked. It can be used to condense messages or perform other preprocessing tasks.
|
||||
* `post_model_hook`: 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.
|
||||
* [`response_format`](../agents/agents.md#6-configure-structured-output): A data structure used to constrain the type of the final output, e.g., a `pydantic` `BaseModel`.
|
||||
|
||||
<div class="agent-layout">
|
||||
<div class="agent-graph-features-container">
|
||||
<div class="agent-graph-features">
|
||||
<h3 class="agent-section-title">Features</h3>
|
||||
<label><input type="checkbox" id="tools" checked> <code>tools</code></label>
|
||||
<label><input type="checkbox" id="pre_model_hook"> <code>pre_model_hook</code></label>
|
||||
<label><input type="checkbox" id="post_model_hook"> <code>post_model_hook</code></label>
|
||||
<label><input type="checkbox" id="response_format"> <code>response_format</code></label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="agent-graph-container">
|
||||
<h3 class="agent-section-title">Graph</h3>
|
||||
<img id="agent-graph-img" src="../assets/react_agent_graphs/0001.svg" alt="graph image" style="max-width: 100%;"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
The following code snippet shows how to create the above agent (and underlying graph) with
|
||||
[`create_react_agent`][langgraph.prebuilt.chat_agent_executor.create_react_agent]:
|
||||
|
||||
<div class="language-python">
|
||||
<pre><code id="agent-code" class="language-python"></code></pre>
|
||||
</div>
|
||||
|
||||
|
||||
<script>
|
||||
function getCheckedValue(id) {
|
||||
return document.getElementById(id).checked ? "1" : "0";
|
||||
}
|
||||
|
||||
function getKey() {
|
||||
return [
|
||||
getCheckedValue("response_format"),
|
||||
getCheckedValue("post_model_hook"),
|
||||
getCheckedValue("pre_model_hook"),
|
||||
getCheckedValue("tools")
|
||||
].join("");
|
||||
}
|
||||
|
||||
function generateCodeSnippet({ tools, pre, post, response }) {
|
||||
const lines = [
|
||||
"from langgraph.prebuilt import create_react_agent",
|
||||
"from langchain_openai import ChatOpenAI"
|
||||
];
|
||||
|
||||
if (response) lines.push("from pydantic import BaseModel");
|
||||
|
||||
lines.push("", 'model = ChatOpenAI("o4-mini")', "");
|
||||
|
||||
if (tools) {
|
||||
lines.push(
|
||||
"def tool() -> None:",
|
||||
' """Testing tool."""',
|
||||
" ...",
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
if (pre) {
|
||||
lines.push(
|
||||
"def pre_model_hook() -> None:",
|
||||
' """Pre-model hook."""',
|
||||
" ...",
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
if (post) {
|
||||
lines.push(
|
||||
"def post_model_hook() -> None:",
|
||||
' """Post-model hook."""',
|
||||
" ...",
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
if (response) {
|
||||
lines.push(
|
||||
"class ResponseFormat(BaseModel):",
|
||||
' """Response format for the agent."""',
|
||||
" result: str",
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
lines.push("agent = create_react_agent(");
|
||||
lines.push(" model,");
|
||||
|
||||
if (tools) lines.push(" tools=[tool],");
|
||||
if (pre) lines.push(" pre_model_hook=pre_model_hook,");
|
||||
if (post) lines.push(" post_model_hook=post_model_hook,");
|
||||
if (response) lines.push(" response_format=ResponseFormat,");
|
||||
|
||||
lines.push(")", "", "agent.get_graph().draw_mermaid_png()");
|
||||
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
async function render() {
|
||||
const key = getKey();
|
||||
document.getElementById("agent-graph-img").src = `../assets/react_agent_graphs/${key}.svg`;
|
||||
|
||||
const state = {
|
||||
tools: document.getElementById("tools").checked,
|
||||
pre: document.getElementById("pre_model_hook").checked,
|
||||
post: document.getElementById("post_model_hook").checked,
|
||||
response: document.getElementById("response_format").checked
|
||||
};
|
||||
|
||||
document.getElementById("agent-code").textContent = generateCodeSnippet(state);
|
||||
}
|
||||
|
||||
function initializeWidget() {
|
||||
render(); // no need for `await` here
|
||||
document.querySelectorAll(".agent-graph-features input").forEach((input) => {
|
||||
input.addEventListener("change", render);
|
||||
});
|
||||
}
|
||||
|
||||
// Init for both full reload and SPA nav (used by MkDocs Material)
|
||||
window.addEventListener("DOMContentLoaded", initializeWidget);
|
||||
document$.subscribe(initializeWidget);
|
||||
</script>
|
||||
|
||||
:::
|
||||
|
||||
:::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`][create_react_agent] 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#6-configure-structured-output): A data structure used to constrain the type of the final output (via Zod schemas).
|
||||
|
||||
<div class="agent-layout">
|
||||
<div class="agent-graph-features-container">
|
||||
<div class="agent-graph-features">
|
||||
<h3 class="agent-section-title">Features</h3>
|
||||
<label><input type="checkbox" id="tools" checked> <code>tools</code></label>
|
||||
<label><input type="checkbox" id="preModelHook"> <code>preModelHook</code></label>
|
||||
<label><input type="checkbox" id="postModelHook"> <code>postModelHook</code></label>
|
||||
<label><input type="checkbox" id="responseFormat"> <code>responseFormat</code></label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="agent-graph-container">
|
||||
<h3 class="agent-section-title">Graph</h3>
|
||||
<img id="agent-graph-img" src="../assets/react_agent_graphs/0001.svg" alt="graph image" style="max-width: 100%;"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
The following code snippet shows how to create the above agent (and underlying graph) with [`createReactAgent`][create_react_agent]:
|
||||
|
||||
```typescript
|
||||
|
||||
<div class="language-typescript">
|
||||
<pre><code id="agent-code" class="language-typescript"></code></pre>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function getCheckedValue(id) {
|
||||
return document.getElementById(id).checked ? "1" : "0";
|
||||
}
|
||||
|
||||
function getKey() {
|
||||
return [
|
||||
getCheckedValue("responseFormat"),
|
||||
getCheckedValue("postModelHook"),
|
||||
getCheckedValue("preModelHook"),
|
||||
getCheckedValue("tools")
|
||||
].join("");
|
||||
}
|
||||
|
||||
function dedent(strings, ...values) {
|
||||
const str = String.raw({ raw: strings }, ...values)
|
||||
const [space] = str.split("\n").filter(Boolean).at(0).match(/^(\s*)/)
|
||||
const spaceLen = space.length
|
||||
return str.split("\n").map(line => line.slice(spaceLen)).join("\n").trim()
|
||||
}
|
||||
|
||||
Object.assign(dedent, {
|
||||
offset: (size) => (strings, ...values) => {
|
||||
return dedent(strings, ...values).split("\n").map(line => " ".repeat(size) + line).join("\n")
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
function generateCodeSnippet({ tools, pre, post, response }) {
|
||||
const lines = []
|
||||
|
||||
lines.push(dedent`
|
||||
import { createReactAgent } from "@langchain/langgraph/prebuilt";
|
||||
import { ChatOpenAI } from "@langchain/openai";
|
||||
`)
|
||||
|
||||
if (tools) lines.push(`import { tool } from "@langchain/core/tools";`);
|
||||
if (response || tools) lines.push(`import { z } from "zod";`);
|
||||
|
||||
lines.push("", dedent`
|
||||
const agent = createReactAgent({
|
||||
llm: new ChatOpenAI({ model: "o4-mini" }),
|
||||
`)
|
||||
|
||||
if (tools) {
|
||||
lines.push(dedent.offset(2)`
|
||||
tools: [
|
||||
tool(() => "Sample tool output", {
|
||||
name: "sampleTool",
|
||||
schema: z.object({}),
|
||||
}),
|
||||
],
|
||||
`)
|
||||
}
|
||||
|
||||
if (pre) {
|
||||
lines.push(dedent.offset(2)`
|
||||
preModelHook: (state) => ({ llmInputMessages: state.messages }),
|
||||
`)
|
||||
}
|
||||
|
||||
if (post) {
|
||||
lines.push(dedent.offset(2)`
|
||||
postModelHook: (state) => state,
|
||||
`)
|
||||
}
|
||||
|
||||
if (response) {
|
||||
lines.push(dedent.offset(2)`
|
||||
responseFormat: z.object({ result: z.string() }),
|
||||
`)
|
||||
}
|
||||
|
||||
lines.push(`});`);
|
||||
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
function render() {
|
||||
const key = getKey();
|
||||
document.getElementById("agent-graph-img").src = `../assets/react_agent_graphs/${key}.svg`;
|
||||
|
||||
const state = {
|
||||
tools: document.getElementById("tools").checked,
|
||||
pre: document.getElementById("preModelHook").checked,
|
||||
post: document.getElementById("postModelHook").checked,
|
||||
response: document.getElementById("responseFormat").checked
|
||||
};
|
||||
|
||||
document.getElementById("agent-code").textContent = generateCodeSnippet(state);
|
||||
}
|
||||
|
||||
function initializeWidget() {
|
||||
render(); // no need for `await` here
|
||||
document.querySelectorAll(".agent-graph-features input").forEach((input) => {
|
||||
input.addEventListener("change", render);
|
||||
});
|
||||
}
|
||||
|
||||
// Init for both full reload and SPA nav (used by MkDocs Material)
|
||||
window.addEventListener("DOMContentLoaded", initializeWidget);
|
||||
document$.subscribe(initializeWidget);
|
||||
</script>
|
||||
|
||||
:::
|
||||
@@ -280,21 +280,7 @@ LangGraph allows access to short-term and long-term memory from tools. See [Memo
|
||||
|
||||
## Prebuilt tools
|
||||
|
||||
You can use prebuilt tools from model providers by passing a dictionary with tool specs to the `tools` parameter of `create_react_agent`. For example, to use the `web_search_preview` tool from OpenAI:
|
||||
|
||||
```python
|
||||
from langgraph.prebuilt import create_react_agent
|
||||
|
||||
agent = create_react_agent(
|
||||
model="openai:gpt-4o-mini",
|
||||
tools=[{"type": "web_search_preview"}]
|
||||
)
|
||||
response = agent.invoke(
|
||||
{"messages": ["What was a positive news story from today?"]}
|
||||
)
|
||||
```
|
||||
|
||||
Additionally, LangChain supports a wide range of prebuilt tool integrations for interacting with APIs, databases, file systems, web data, and more. These tools extend the functionality of agents and enable rapid development.
|
||||
LangChain supports a wide range of prebuilt tool integrations for interacting with APIs, databases, file systems, web data, and more. These tools extend the functionality of agents and enable rapid development.
|
||||
|
||||
You can browse the full list of available integrations in the [LangChain integrations directory](https://python.langchain.com/docs/integrations/tools/).
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@ Then, navigate to [Agent Chat UI](https://agentchat.vercel.app), or clone the re
|
||||
|
||||
UI has out-of-box support for rendering tool calls, and tool result messages. To customize what messages are shown, see the [Hiding Messages in the Chat](https://github.com/langchain-ai/agent-chat-ui?tab=readme-ov-file#hiding-messages-in-the-chat) section in the Agent Chat UI documentation.
|
||||
|
||||
:::python
|
||||
## Add human-in-the-loop
|
||||
|
||||
Agent Chat UI has full support for [human-in-the-loop](../concepts/human_in_the_loop.md) workflows. To try it out, replace the agent code in `src/agent/graph.py` (from the [deployment](./deployment.md) guide) with this [agent implementation](./human-in-the-loop.md#using-with-agent-inbox):
|
||||
@@ -33,7 +32,6 @@ Agent Chat UI has full support for [human-in-the-loop](../concepts/human_in_the_
|
||||
!!! Important
|
||||
|
||||
Agent Chat UI works best if your LangGraph agent interrupts using the [`HumanInterrupt` schema][langgraph.prebuilt.interrupt.HumanInterrupt]. If you do not use that schema, the Agent Chat UI will be able to render the input passed to the `interrupt` function, but it will not have full support for resuming your graph.
|
||||
:::
|
||||
|
||||
## Generative UI
|
||||
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"0000": "graph TD;\n\t__start__ --> agent;\n\tagent --> __end__;",
|
||||
"0001": "graph TD;\n\t__start__ --> agent;\n\tagent -.-> __end__;\n\tagent -.-> tools;\n\ttools --> agent;",
|
||||
"0010": "graph TD;\n\t__start__ --> pre_model_hook;\n\tpre_model_hook --> agent;\n\tagent --> __end__;",
|
||||
"0011": "graph TD;\n\t__start__ --> pre_model_hook;\n\tagent -.-> __end__;\n\tagent -.-> tools;\n\tpre_model_hook --> agent;\n\ttools --> pre_model_hook;",
|
||||
"0100": "graph TD;\n\t__start__ --> agent;\n\tagent --> post_model_hook;\n\tpost_model_hook --> __end__;",
|
||||
"0101": "graph TD;\n\t__start__ --> agent;\n\tagent --> post_model_hook;\n\tpost_model_hook -.-> __end__;\n\tpost_model_hook -.-> agent;\n\tpost_model_hook -.-> tools;\n\ttools --> agent;",
|
||||
"0110": "graph TD;\n\t__start__ --> pre_model_hook;\n\tagent --> post_model_hook;\n\tpre_model_hook --> agent;\n\tpost_model_hook --> __end__;",
|
||||
"0111": "graph TD;\n\t__start__ --> pre_model_hook;\n\tagent --> post_model_hook;\n\tpost_model_hook -.-> __end__;\n\tpost_model_hook -.-> pre_model_hook;\n\tpost_model_hook -.-> tools;\n\tpre_model_hook --> agent;\n\ttools --> pre_model_hook;",
|
||||
"1000": "graph TD;\n\t__start__ --> agent;\n\tagent --> generate_structured_response;\n\tgenerate_structured_response --> __end__;",
|
||||
"1001": "graph TD;\n\t__start__ --> agent;\n\tagent -.-> generate_structured_response;\n\tagent -.-> tools;\n\ttools --> agent;\n\tgenerate_structured_response --> __end__;",
|
||||
"1010": "graph TD;\n\t__start__ --> pre_model_hook;\n\tagent --> generate_structured_response;\n\tpre_model_hook --> agent;\n\tgenerate_structured_response --> __end__;",
|
||||
"1011": "graph TD;\n\t__start__ --> pre_model_hook;\n\tagent -.-> generate_structured_response;\n\tagent -.-> tools;\n\tpre_model_hook --> agent;\n\ttools --> pre_model_hook;\n\tgenerate_structured_response --> __end__;",
|
||||
"1100": "graph TD;\n\t__start__ --> agent;\n\tagent --> post_model_hook;\n\tpost_model_hook --> generate_structured_response;\n\tgenerate_structured_response --> __end__;",
|
||||
"1101": "graph TD;\n\t__start__ --> agent;\n\tagent --> post_model_hook;\n\tpost_model_hook -.-> agent;\n\tpost_model_hook -.-> generate_structured_response;\n\tpost_model_hook -.-> tools;\n\ttools --> agent;\n\tgenerate_structured_response --> __end__;",
|
||||
"1110": "graph TD;\n\t__start__ --> pre_model_hook;\n\tagent --> post_model_hook;\n\tpost_model_hook --> generate_structured_response;\n\tpre_model_hook --> agent;\n\tgenerate_structured_response --> __end__;",
|
||||
"1111": "graph TD;\n\t__start__ --> pre_model_hook;\n\tagent --> post_model_hook;\n\tpost_model_hook -.-> generate_structured_response;\n\tpost_model_hook -.-> pre_model_hook;\n\tpost_model_hook -.-> tools;\n\tpre_model_hook --> agent;\n\ttools --> pre_model_hook;\n\tgenerate_structured_response --> __end__;"
|
||||
}
|
||||
|
||||
@@ -16,4 +16,4 @@ Users can add an array of additional lines to add to the Dockerfile following th
|
||||
}
|
||||
```
|
||||
|
||||
This would install the system packages required to use Pillow if we were working with `jpeg` or `png` image formats.
|
||||
This would install the system packages required to use Pillow if we were working with `jpeq` or `png` image formats.
|
||||
@@ -20,7 +20,7 @@ my-app/
|
||||
|-- openai_agent.py # code for your graph
|
||||
```
|
||||
|
||||
where the graph is defined in `openai_agent.py`.
|
||||
where the graph is defined in `openai_agent.py`.
|
||||
|
||||
### No rebuild
|
||||
|
||||
@@ -28,11 +28,11 @@ In the standard LangGraph API configuration, the server uses the compiled graph
|
||||
|
||||
```python
|
||||
from langchain_openai import ChatOpenAI
|
||||
from langgraph.graph import END, START, StateGraph, MessagesState
|
||||
from langgraph.graph import END, START, MessageGraph
|
||||
|
||||
model = ChatOpenAI(temperature=0)
|
||||
|
||||
graph_workflow = StateGraph(MessagesState)
|
||||
graph_workflow = MessageGraph()
|
||||
|
||||
graph_workflow.add_node("agent", model)
|
||||
graph_workflow.add_edge("agent", END)
|
||||
@@ -61,7 +61,7 @@ To make your graph rebuild on each new run with custom configuration, you need t
|
||||
from typing import Annotated
|
||||
from typing_extensions import TypedDict
|
||||
from langchain_openai import ChatOpenAI
|
||||
from langgraph.graph import END, START
|
||||
from langgraph.graph import END, START, MessageGraph
|
||||
from langgraph.graph.state import StateGraph
|
||||
from langgraph.graph.message import add_messages
|
||||
from langgraph.prebuilt import ToolNode
|
||||
@@ -144,4 +144,4 @@ Finally, you need to specify the path to your graph-making function (`make_graph
|
||||
}
|
||||
```
|
||||
|
||||
See more info on LangGraph API configuration file [here](../reference/cli.md#configuration-file)
|
||||
See more info on LangGraph API configuration file [here](../reference/cli.md#configuration-file)
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
Before deploying, review the [conceptual guide for the Self-Hosted Control Plane](../../concepts/langgraph_self_hosted_control_plane.md) deployment option.
|
||||
|
||||
!!! info "Important"
|
||||
The Self-Hosted Control Plane deployment option is currently in beta stage and requires an [Enterprise](../../concepts/plans.md) plan.
|
||||
!!! important "Beta"
|
||||
The Self-Hosted Control Plane deployment option is currently in beta stage.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
@@ -30,17 +30,18 @@ Before deploying, review the [conceptual guide for the Self-Hosted Control Plane
|
||||
1. `LangGraphPlatform CRD`: A CRD for LangGraph Platform deployments. This contains the spec for managing an instance of a LangGraph platform deployment.
|
||||
1. `operator`: This operator handles changes to your LangGraph Platform CRDs.
|
||||
1. `host-backend`: This is the [control plane](../../concepts/langgraph_control_plane.md).
|
||||
1. Two additional images will be used by the chart. Use the images that are specified in the latest release.
|
||||
1. Two additional images will be used by the chart.
|
||||
|
||||
hostBackendImage:
|
||||
repository: "docker.io/langchain/hosted-langserve-backend"
|
||||
pullPolicy: IfNotPresent
|
||||
tag: "0.9.80"
|
||||
operatorImage:
|
||||
repository: "docker.io/langchain/langgraph-operator"
|
||||
pullPolicy: IfNotPresent
|
||||
tag: "aa9dff4"
|
||||
|
||||
1. In your config file for langsmith (usually `langsmith_config.yaml`, enable the `langgraphPlatform` option. Note that you must also have a valid ingress setup:
|
||||
|
||||
1. In your `values.yaml` file, enable the `langgraphPlatform` option. Note that you must also have a valid ingress setup:
|
||||
config:
|
||||
langgraphPlatform:
|
||||
enabled: true
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
Before deploying, review the [conceptual guide for the Self-Hosted Data Plane](../../concepts/langgraph_self_hosted_data_plane.md) deployment option.
|
||||
|
||||
!!! info "Important"
|
||||
The Self-Hosted Data Plane deployment option is currently in beta stage and requires an [Enterprise](../../concepts/plans.md) plan.
|
||||
!!! important "Beta"
|
||||
The Self-Hosted Data Plane deployment option is currently in beta stage.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ my-app/
|
||||
|
||||
## Define Graphs
|
||||
|
||||
Implement your graphs! Graphs can be defined in a single file or multiple files. Make note of the variable names of each [CompiledStateGraph][langgraph.graph.state.CompiledStateGraph] to be included in the LangGraph application. The variable names will be used later when creating the [LangGraph configuration file](../reference/cli.md#configuration-file).
|
||||
Implement your graphs! Graphs can be defined in a single file or multiple files. Make note of the variable names of each [CompiledGraph][langgraph.graph.graph.CompiledGraph] to be included in the LangGraph application. The variable names will be used later when creating the [LangGraph configuration file](../reference/cli.md#configuration-file).
|
||||
|
||||
Example `agent.py` file, which shows how to import from other modules you define (code for the modules is not shown here, please see [this repository](https://github.com/langchain-ai/langgraph-example) to see their implementation):
|
||||
|
||||
@@ -129,6 +129,9 @@ workflow.add_edge("action", "agent")
|
||||
graph = workflow.compile()
|
||||
```
|
||||
|
||||
!!! warning "Assign `CompiledGraph` to Variable"
|
||||
The build process for LangGraph Platform requires that the `CompiledGraph` object be assigned to a variable at the top-level of a Python module (alternatively, you can provide [a function that creates a graph](./graph_rebuild.md)).
|
||||
|
||||
Example file directory:
|
||||
|
||||
```bash
|
||||
|
||||
@@ -155,6 +155,10 @@ const workflow = new StateGraph(MessagesAnnotation)
|
||||
export const graph = workflow.compile();
|
||||
```
|
||||
|
||||
!!! info "Assign `CompiledGraph` to Variable"
|
||||
|
||||
The build process for LangGraph Platform requires that the `CompiledGraph` object be assigned to a variable at the top-level of a JavaScript module (alternatively, you can provide [a function that creates a graph](./graph_rebuild.md)).
|
||||
|
||||
Example file directory:
|
||||
|
||||
```bash
|
||||
|
||||
@@ -108,7 +108,7 @@ my-app/
|
||||
|
||||
## Define Graphs
|
||||
|
||||
Implement your graphs! Graphs can be defined in a single file or multiple files. Make note of the variable names of each [CompiledStateGraph][langgraph.graph.state.CompiledStateGraph] to be included in the LangGraph application. The variable names will be used later when creating the [LangGraph configuration file](../reference/cli.md#configuration-file).
|
||||
Implement your graphs! Graphs can be defined in a single file or multiple files. Make note of the variable names of each [CompiledGraph][langgraph.graph.graph.CompiledGraph] to be included in the LangGraph application. The variable names will be used later when creating the [LangGraph configuration file](../reference/cli.md#configuration-file).
|
||||
|
||||
Example `agent.py` file, which shows how to import from other modules you define (code for the modules is not shown here, please see [this repository](https://github.com/langchain-ai/langgraph-example-pyproject) to see their implementation):
|
||||
|
||||
@@ -142,6 +142,9 @@ workflow.add_edge("action", "agent")
|
||||
graph = workflow.compile()
|
||||
```
|
||||
|
||||
!!! warning "Assign `CompiledGraph` to Variable"
|
||||
The build process for LangGraph Platform requires that the `CompiledGraph` object be assigned to a variable at the top-level of a Python module.
|
||||
|
||||
Example file directory:
|
||||
|
||||
```bash
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
!!! info "Prerequisites"
|
||||
|
||||
- [Assistants Overview](../../../concepts/assistants.md)
|
||||
- [Assistants Overview](../../concepts/assistants.md)
|
||||
|
||||
LangGraph Studio lets you view, edit, and update your assistants, and allows you to run your graph using these assistant configurations.
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
How to integrate LangGraph into your React application# How to integrate LangGraph into your React application
|
||||
# How to integrate LangGraph into your React application
|
||||
|
||||
!!! info "Prerequisites"
|
||||
!!! info "Prerequisites"
|
||||
|
||||
- [LangGraph Platform](../../concepts/langgraph_platform.md)
|
||||
- [LangGraph Platform](../../concepts/langgraph_platform.md)
|
||||
- [LangGraph Server](../../concepts/langgraph_server.md)
|
||||
|
||||
The `useStream()` React hook provides a seamless way to integrate LangGraph into your React applications. It handles all the complexities of streaming, state management, and branching logic, letting you focus on building great chat experiences.
|
||||
@@ -113,115 +113,6 @@ export default function App() {
|
||||
}
|
||||
```
|
||||
|
||||
### Resume a stream after page refresh
|
||||
|
||||
The `useStream()` hook can automatically resume an ongoing run upon mounting by setting `reconnectOnMount: true`. This is useful for continuing a stream after a page refresh, ensuring no messages and events generated during the downtime are lost.
|
||||
|
||||
```tsx
|
||||
const thread = useStream<{ messages: Message[] }>({
|
||||
apiUrl: "http://localhost:2024",
|
||||
assistantId: "agent",
|
||||
reconnectOnMount: true,
|
||||
});
|
||||
```
|
||||
|
||||
By default the ID of the created run is stored in `window.sessionStorage`, which can be swapped by passing a custom storage in `reconnectOnMount` instead. The storage is used to persist the in-flight run ID for a thread (under `lg:stream:${threadId}` key).
|
||||
|
||||
```tsx
|
||||
const thread = useStream<{ messages: Message[] }>({
|
||||
apiUrl: "http://localhost:2024",
|
||||
assistantId: "agent",
|
||||
reconnectOnMount: () => window.localStorage,
|
||||
});
|
||||
```
|
||||
|
||||
You can also manually manage the resuming process by using the run callbacks to persist the run metadata and the `joinStream` function to resume the stream. Make sure to pass `streamResumable: true` when creating the run; otherwise some events might be lost.
|
||||
|
||||
````tsx
|
||||
import type { Message } from "@langchain/langgraph-sdk";
|
||||
import { useStream } from "@langchain/langgraph-sdk/react";
|
||||
import { useCallback, useState, useEffect, useRef } from "react";
|
||||
|
||||
export default function App() {
|
||||
const [threadId, onThreadId] = useSearchParam("threadId");
|
||||
|
||||
const thread = useStream<{ messages: Message[] }>({
|
||||
apiUrl: "http://localhost:2024",
|
||||
assistantId: "agent",
|
||||
|
||||
threadId,
|
||||
onThreadId,
|
||||
|
||||
onCreated: (run) => {
|
||||
window.sessionStorage.setItem(`resume:${run.thread_id}`, run.run_id);
|
||||
},
|
||||
onFinish: (_, run) => {
|
||||
window.sessionStorage.removeItem(`resume:${run?.thread_id}`);
|
||||
},
|
||||
});
|
||||
|
||||
// Ensure that we only join the stream once per thread.
|
||||
const joinedThreadId = useRef<string | null>(null);
|
||||
useEffect(() => {
|
||||
if (!threadId) return;
|
||||
|
||||
const resume = window.sessionStorage.getItem(`resume:${threadId}`);
|
||||
if (resume && joinedThreadId.current !== threadId) {
|
||||
thread.joinStream(resume);
|
||||
joinedThreadId.current = threadId;
|
||||
}
|
||||
}, [threadId]);
|
||||
|
||||
return (
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
const form = e.target as HTMLFormElement;
|
||||
const message = new FormData(form).get("message") as string;
|
||||
thread.submit(
|
||||
{ messages: [{ type: "human", content: message }] },
|
||||
{ streamResumable: true }
|
||||
);
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
{thread.messages.map((message) => (
|
||||
<div key={message.id}>{message.content as string}</div>
|
||||
))}
|
||||
</div>
|
||||
<input type="text" name="message" />
|
||||
<button type="submit">Send</button>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
// Utility method to retrieve and persist data in URL as search param
|
||||
function useSearchParam(key: string) {
|
||||
const [value, setValue] = useState<string | null>(() => {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
return params.get(key) ?? null;
|
||||
});
|
||||
|
||||
const update = useCallback(
|
||||
(value: string | null) => {
|
||||
setValue(value);
|
||||
|
||||
const url = new URL(window.location.href);
|
||||
if (value == null) {
|
||||
url.searchParams.delete(key);
|
||||
} else {
|
||||
url.searchParams.set(key, value);
|
||||
}
|
||||
|
||||
window.history.pushState({}, "", url.toString());
|
||||
},
|
||||
[key]
|
||||
);
|
||||
|
||||
return [value, update] as const;
|
||||
}
|
||||
```
|
||||
|
||||
### Thread Management
|
||||
|
||||
Keep track of conversations with built-in thread management. You can access the current thread ID and get notified when new threads are created:
|
||||
@@ -236,7 +127,7 @@ const thread = useStream<{ messages: Message[] }>({
|
||||
threadId: threadId,
|
||||
onThreadId: setThreadId,
|
||||
});
|
||||
````
|
||||
```
|
||||
|
||||
We recommend storing the `threadId` in your URL's query parameters to let users resume conversations after page refreshes.
|
||||
|
||||
|
||||
@@ -3818,14 +3818,6 @@
|
||||
"title": "Filter",
|
||||
"description": "Optional dictionary of key-value pairs to filter results."
|
||||
},
|
||||
"query": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
],
|
||||
"title": "Query",
|
||||
"description": "Query string for semantic/vector search."
|
||||
},
|
||||
"limit": {
|
||||
"type": "integer",
|
||||
"default": 10,
|
||||
|
||||
@@ -40,10 +40,9 @@ The LangGraph CLI requires a JSON configuration file that follows this [schema](
|
||||
| Key | Description |
|
||||
| ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| <span style="white-space: nowrap;">`dependencies`</span> | **Required**. Array of dependencies for LangGraph Platform API server. Dependencies can be one of the following: <ul><li>A single period (`"."`), which will look for local Python packages.</li><li>The directory path where `pyproject.toml`, `setup.py` or `requirements.txt` is located.</br></br>For example, if `requirements.txt` is located in the root of the project directory, specify `"./"`. If it's located in a subdirectory called `local_package`, specify `"./local_package"`. Do not specify the string `"requirements.txt"` itself.</li><li>A Python package name.</li></ul> |
|
||||
| <span style="white-space: nowrap;">`graphs`</span> | **Required**. Mapping from graph ID to path where the compiled graph or a function that makes a graph is defined. Example: <ul><li>`./your_package/your_file.py:variable`, where `variable` is an instance of `langgraph.graph.state.CompiledStateGraph`</li><li>`./your_package/your_file.py:make_graph`, where `make_graph` is a function that takes a config dictionary (`langchain_core.runnables.RunnableConfig`) and returns an instance of `langgraph.graph.state.StateGraph` or `langgraph.graph.state.CompiledStateGraph`. See [how to rebuild a graph at runtime](../../cloud/deployment/graph_rebuild.md) for more details.</li></ul> |
|
||||
| <span style="white-space: nowrap;">`graphs`</span> | **Required**. Mapping from graph ID to path where the compiled graph or a function that makes a graph is defined. Example: <ul><li>`./your_package/your_file.py:variable`, where `variable` is an instance of `langgraph.graph.state.CompiledStateGraph`</li><li>`./your_package/your_file.py:make_graph`, where `make_graph` is a function that takes a config dictionary (`langchain_core.runnables.RunnableConfig`) and creates an instance of `langgraph.graph.state.StateGraph` / `langgraph.graph.state.CompiledStateGraph`.</li></ul> |
|
||||
| <span style="white-space: nowrap;">`auth`</span> | _(Added in v0.0.11)_ Auth configuration containing the path to your authentication handler. Example: `./your_package/auth.py:auth`, where `auth` is an instance of `langgraph_sdk.Auth`. See [authentication guide](../../concepts/auth.md) for details. |
|
||||
| <span style="white-space: nowrap;">`base_image`</span> | Optional. Base image to use for the LangGraph API server. Defaults to `langchain/langgraph-api` or `langchain/langgraphjs-api`. Use this to pin your builds to a particular version of the langgraph API, such as `"langchain/langgraph-server:0.2"`. See https://hub.docker.com/r/langchain/langgraph-server/tags for more details. (added in `langgraph-cli==0.2.8`) |
|
||||
| <span style="white-space: nowrap;">`image_distro`</span> | Optional. Linux distribution for the base image. Must be either `"debian"` or `"wolfi"`. If omitted, defaults to `"debian"`. Available in `langgraph-cli>=0.2.11`.|
|
||||
| <span style="white-space: nowrap;">`env`</span> | Path to `.env` file or a mapping from environment variable to its value. |
|
||||
| <span style="white-space: nowrap;">`store`</span> | Configuration for adding semantic search and/or time-to-live (TTL) to the BaseStore. Contains the following fields: <ul><li>`index` (optional): Configuration for semantic search indexing with fields `embed`, `dims`, and optional `fields`.</li><li>`ttl` (optional): Configuration for item expiration. An object with optional fields: `refresh_on_read` (boolean, defaults to `true`), `default_ttl` (float, lifespan in **minutes**, defaults to no expiration), and `sweep_interval_minutes` (integer, how often to check for expired items, defaults to no sweeping).</li></ul> |
|
||||
| <span style="white-space: nowrap;">`ui`</span> | Optional. Named definitions of UI components emitted by the agent, each pointing to a JS/TS file. (added in `langgraph-cli==0.1.84`) |
|
||||
@@ -58,7 +57,7 @@ The LangGraph CLI requires a JSON configuration file that follows this [schema](
|
||||
|
||||
| Key | Description |
|
||||
| ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| <span style="white-space: nowrap;">`graphs`</span> | **Required**. Mapping from graph ID to path where the compiled graph or a function that makes a graph is defined. Example: <ul><li>`./src/graph.ts:variable`, where `variable` is an instance of `CompiledStateGraph`</li><li>`./src/graph.ts:makeGraph`, where `makeGraph` is a function that takes a config dictionary (`LangGraphRunnableConfig`) and returns an instance of `StateGraph` or `CompiledStateGraph`. See [how to rebuild a graph at runtime](../../cloud/deployment/graph_rebuild.md) for more details.</li></ul> |
|
||||
| <span style="white-space: nowrap;">`graphs`</span> | **Required**. Mapping from graph ID to path where the compiled graph or a function that makes a graph is defined. Example: <ul><li>`./src/graph.ts:variable`, where `variable` is an instance of `CompiledStateGraph`</li><li>`./src/graph.ts:makeGraph`, where `makeGraph` is a function that takes a config dictionary (`LangGraphRunnableConfig`) and creates an instance of `StateGraph` / `CompiledStateGraph`.</li></ul> |
|
||||
| <span style="white-space: nowrap;">`env`</span> | Path to `.env` file or a mapping from environment variable to its value. |
|
||||
| <span style="white-space: nowrap;">`store`</span> | Configuration for adding semantic search and/or time-to-live (TTL) to the BaseStore. Contains the following fields: <ul><li>`index` (optional): Configuration for semantic search indexing with fields `embed`, `dims`, and optional `fields`.</li><li>`ttl` (optional): Configuration for item expiration. An object with optional fields: `refresh_on_read` (boolean, defaults to `true`), `default_ttl` (float, lifespan in **minutes**, defaults to no expiration), and `sweep_interval_minutes` (integer, how often to check for expired items, defaults to no sweeping).</li></ul> |
|
||||
| <span style="white-space: nowrap;">`node_version`</span> | Specify `node_version: 20` to use LangGraph.js. |
|
||||
@@ -80,20 +79,6 @@ The LangGraph CLI requires a JSON configuration file that follows this [schema](
|
||||
}
|
||||
```
|
||||
|
||||
#### Using Wolfi Base Images
|
||||
|
||||
You can specify the Linux distribution for your base image using the `image_distro` field. Valid options are `debian` or `wolfi`. Wolfi is the recommended option as it provides smaller and more secure images. This is available in `langgraph-cli>=0.2.11`.
|
||||
|
||||
```json
|
||||
{
|
||||
"dependencies": ["."],
|
||||
"graphs": {
|
||||
"chat": "./chat/graph.py:graph"
|
||||
},
|
||||
"image_distro": "wolfi"
|
||||
}
|
||||
```
|
||||
|
||||
#### Adding semantic search to the store
|
||||
|
||||
All deployments come with a DB-backed BaseStore. Adding an "index" configuration to your `langgraph.json` will enable [semantic search](../deployment/semantic_search.md) within the BaseStore of your deployment.
|
||||
|
||||
@@ -123,12 +123,3 @@ Defaults to `''`.
|
||||
Set `REDIS_CLUSTER` to `True` to enable Redis Cluster mode. When enabled, the system will connect to Redis using cluster mode. This is useful when connecting to a Redis Cluster deployment.
|
||||
|
||||
Defaults to `False`.
|
||||
|
||||
## `MOUNT_PREFIX`
|
||||
|
||||
!!! info "Only Allowed in Self-Hosted Deployments"
|
||||
The `MOUNT_PREFIX` environment variable is only allowed in Self-Hosted Deployment models, LangGraph Platform SaaS will not allow this environment variable.
|
||||
|
||||
Set `MOUNT_PREFIX` to serve the LangGraph Server under a specific path prefix. This is useful for deployments where the server is behind a reverse proxy or load balancer that requires a specific path prefix.
|
||||
|
||||
For example, if the server is to be served under `https://example.com/langgraph`, set `MOUNT_PREFIX` to `/langgraph`.
|
||||
|
||||
@@ -32,7 +32,7 @@ Below are examples of directory structures for Python and JavaScript application
|
||||
│ ├── utils # utilities for your graph
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── tools.py # tools for your graph
|
||||
│ │ ├── nodes.py # node functions for your graph
|
||||
│ │ ├── nodes.py # node functions for you graph
|
||||
│ │ └── state.py # state definition of your graph
|
||||
│ ├── __init__.py
|
||||
│ └── agent.py # code for constructing your graph
|
||||
|
||||
@@ -26,4 +26,4 @@ Once you've created an assistant, subsequent edits to that assistant will create
|
||||
|
||||
## Learn more
|
||||
|
||||
* The LangGraph Cloud API provides several endpoints for creating and managing assistants and their versions. See the [API reference](../cloud/reference/api/api_ref.html#tag/assistants) for more details.
|
||||
* The LangGraph Cloud API provides several endpoints for creating and managing assistants their versions. See the [API reference](../cloud/reference/api/api_ref.html#tag/assistants) for more details.
|
||||
@@ -198,7 +198,7 @@ async def add_owner(
|
||||
You can register handlers for specific resources and actions by chaining the resource and action names together with the [`@auth.on`](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.Auth.on) decorator.
|
||||
When a request is made, the most specific handler that matches that resource and action is called. Below is an example of how to register handlers for specific resources and actions. For the following setup:
|
||||
|
||||
1. Authenticated users are able to create threads, read threads, and create runs on threads
|
||||
1. Authenticated users are able to create threads, read thread, create runs on threads
|
||||
2. Only users with the "assistants:create" permission are allowed to create new assistants
|
||||
3. All other endpoints (e.g., e.g., delete assistant, crons, store) are disabled for all users.
|
||||
|
||||
|
||||
@@ -40,8 +40,8 @@ For more information, please see:
|
||||
|
||||
## Self-Hosted Data Plane
|
||||
|
||||
!!! info "Important"
|
||||
The Self-Hosted Data Plane deployment option is currently in beta stage and requires an [Enterprise](../concepts/plans.md) plan.
|
||||
!!! important "Beta"
|
||||
The Self-Hosted Data Plane deployment option is currently in beta stage.
|
||||
|
||||
The [Self-Hosted Data Plane](./langgraph_self_hosted_data_plane.md) deployment option is a "hybrid" model for deployment where we manage the [control plane](./langgraph_control_plane.md) in our cloud and you manage the [data plane](./langgraph_data_plane.md) in your cloud. This option provides a way to securely manage your data plane infrastructure, while offloading control plane management to us.
|
||||
|
||||
@@ -56,10 +56,10 @@ For more information, please see:
|
||||
|
||||
## Self-Hosted Control Plane
|
||||
|
||||
!!! info "Important"
|
||||
The Self-Hosted Control Plane deployment option is currently in beta stage and requires an [Enterprise](../concepts/plans.md) plan.
|
||||
!!! important "Beta"
|
||||
The Self-Hosted Control Plane deployment option is currently in beta stage.
|
||||
|
||||
The [Self-Hosted Control Plane](./langgraph_self_hosted_control_plane.md) deployment option is a fully self-hosted model for deployment where you manage the [control plane](./langgraph_control_plane.md) and [data plane](./langgraph_data_plane.md) in your cloud. This option gives you full control and responsibility of the control plane and data plane infrastructure.
|
||||
The [Self-Hosted Control Plane](./langgraph_self_hosted_control_plane.md) deployment option is a fully self-hosted model for deployment where you manage the [control plane](./langgraph_control_plane.md) and [data plane](./langgraph_data_plane.md) in your cloud. This option give you full control and responsibility of the control plane and data plane infrastructure.
|
||||
|
||||
Build a Docker image using the [LangGraph CLI](./langgraph_cli.md) and deploy your LangGraph Server from the [control plane UI](./langgraph_control_plane.md#control-plane-ui).
|
||||
|
||||
|
||||
@@ -59,8 +59,8 @@ Yes! You can use LangGraph with any LLMs. The main reason we use LLMs that suppo
|
||||
|
||||
Yes! LangGraph is totally ambivalent to what LLMs are used under the hood. The main reason we use closed LLMs in most of the tutorials is that they seamlessly support tool calling, while OSS LLMs often don't. But tool calling is not necessary (see [this section](#does-langgraph-work-with-llms-that-dont-support-tool-calling)) so you can totally use LangGraph with OSS LLMs.
|
||||
|
||||
## Can I use LangGraph Studio without logging in to LangSmith
|
||||
## Can I use LangGraph Studio without logging to LangSmith
|
||||
|
||||
Yes! You can use the [development version of LangGraph Server](../tutorials/langgraph-platform/local-server.md) to run the backend locally.
|
||||
This will connect to the studio frontend hosted as part of LangSmith.
|
||||
If you set an environment variable of `LANGSMITH_TRACING=false`, then no traces will be sent to LangSmith.
|
||||
If you set an environment variable of `LANGSMITH_TRACING=false` then no traces will be sent to LangSmith.
|
||||
@@ -186,7 +186,7 @@ When declaring an `entrypoint`, you can request access to additional parameters
|
||||
|
||||
| Parameter | Description |
|
||||
|--------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| **previous** | Access the state associated with the previous `checkpoint` for the given thread. See [short-term-memory](#short-term-memory). |
|
||||
| **previous** | Access the the state associated with the previous `checkpoint` for the given thread. See [short-term-memory](#short-term-memory). |
|
||||
| **store** | An instance of [BaseStore][langgraph.store.base.BaseStore]. Useful for [long-term memory](../how-tos/use-functional-api.md#long-term-memory). |
|
||||
| **writer** | Use to access the StreamWriter when working with Async Python < 3.11. See [streaming with functional API for details](../how-tos/use-functional-api.md#streaming). |
|
||||
| **config** | For accessing run time configuration. See [RunnableConfig](https://python.langchain.com/docs/concepts/runnables/#runnableconfig) for information. |
|
||||
|
||||
@@ -47,22 +47,17 @@ This section describes various features of the control plane.
|
||||
|
||||
For simplicity, the control plane offers two deployment types with different resource allocations: `Development` and `Production`.
|
||||
|
||||
| **Deployment Type** | **CPU/Memory** | **Scaling** | **Database** |
|
||||
|---------------------|-----------------|---------------------|----------------------------------------------------------------------------------|
|
||||
| Development | 1 CPU, 1 GB RAM | Up to 1 container | 10 GB disk, no backups |
|
||||
| Production | 2 CPU, 2 GB RAM | Up to 10 containers | Autoscaling disk, automatic backups, highly available (multi-zone configuration) |
|
||||
| **Deployment Type** | **CPU** | **Memory** | **Scaling** |
|
||||
|---------------------|---------|------------|---------------------|
|
||||
| Development | 1 CPU | 1 GB | Up to 1 container |
|
||||
| Production | 2 CPU | 2 GB | Up to 10 containers |
|
||||
|
||||
CPU and memory resources are per container.
|
||||
|
||||
!!! warning "Immutable Deployment Type"
|
||||
|
||||
Once a deployment is created, the deployment type cannot be changed.
|
||||
|
||||
!!! info "Resource Customization"
|
||||
!!! info "For [Cloud SaaS](../concepts/langgraph_cloud.md)"
|
||||
For `Production` type deployments, resources can be manually increased on a case-by-case basis depending on use case and capacity constraints. Contact support@langchain.dev to request an increase in resources.
|
||||
|
||||
For `Development` types deployments, database disk size can be manually increased on a case-by-case basis depending on use case and capacity constraints. For most use cases, [TTLs](../how-tos/ttl/configure_ttl.md) should be configured to manage disk usage. Contact support@langchain.dev to request an increase in resources.
|
||||
|
||||
!!! info
|
||||
Resources for [Self-Hosted Data Plane](../concepts/langgraph_self_hosted_data_plane.md) and [Self-Hosted Control Plane](../concepts/langgraph_self_hosted_control_plane.md) deployments can be fully customized.
|
||||
|
||||
### Database Provisioning
|
||||
|
||||
@@ -9,7 +9,7 @@ The term "data plane" is used broadly to refer to [LangGraph Servers](./langgrap
|
||||
|
||||
## Server Infrastructure
|
||||
|
||||
In addition to the [LangGraph Server](./langgraph_server.md) itself, the following infrastructure components for each server are also included in the broad definition of "data plane":
|
||||
In addition to the [LangGraph Server](./langgraph_server.md) itself, the following infrastructure for each server are also included in the broad definition of "data plane":
|
||||
|
||||
- Postgres
|
||||
- Redis
|
||||
@@ -44,7 +44,7 @@ All runs in a LangGraph Server are executed by a pool of background workers that
|
||||
|
||||
### Ephemeral metadata
|
||||
|
||||
Runs in a LangGraph Server may be retried for specific failures (currently only for transient Postgres errors encountered during the run). In order to limit the number of retries (currently limited to 3 attempts per run) we record the attempt number in a Redis string when it is picked up. This contains no run-specific info other than its ID, and expires after a short delay.
|
||||
Runs in a LangGraph Server may be retried for specific failures (currently only for transient Postgres errors encountered during the run). In order to limit the number of retries (currently limited to 3 attempts per run) we record the attempt number in a Redis string when is picked up. This contains no run-specific info other than its ID, and expires after a short delay.
|
||||
|
||||
## Data Plane Features
|
||||
|
||||
@@ -62,7 +62,7 @@ For CPU utilization, the autoscaler targets 75% utilization. This means the auto
|
||||
|
||||
For number of pending runs, the autoscaler targets 10 pending runs. For example, if the current number of containers is 1, but the number of pending runs in 20, the autoscaler will scale up the deployment to 2 containers (20 pending runs / 2 containers = 10 pending runs per container).
|
||||
|
||||
Each metric is computed independently and the autoscaler will determine the scaling action based on the metric that results in the largest number of containers.
|
||||
Each metric is computed independently and the autoscaler will determine the scaling action based on the metric that results in the most number of containers.
|
||||
|
||||
Scale down actions are delayed for 30 minutes before any action is taken. In other words, if the autoscaler decides to scale down a deployment, it will first wait for 30 minutes before scaling down. After 30 minutes, the metrics are recomputed and the deployment will scale down if the recomputed metrics result in a lower number of containers than the current number. Otherwise, the deployment remains scaled up. This "cool down" period ensures that deployments do not scale up and down too frequently.
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ Develop, deploy, scale, and manage agents with **LangGraph Platform** — the pu
|
||||
|
||||
!!! tip "Get started with LangGraph Platform"
|
||||
|
||||
Check out the [LangGraph Platform quickstart](../tutorials/langgraph-platform/local-server.md) for instructions on how to use LangGraph Platform to run a LangGraph application locally.
|
||||
Check out the [LangGraph Platform quickstart](../tutorials/langgraph-platform/local-server.md) for instructions on how to use LangGraph Platform run a LangGraph application locally.
|
||||
|
||||
## Why use LangGraph Platform?
|
||||
|
||||
@@ -33,4 +33,4 @@ LangGraph Platform makes it easy to get your agent running in production — wh
|
||||
|
||||
- **[LangGraph Studio](./langgraph_studio.md)**: Enables visualization, interaction, and debugging of agentic systems that implement the LangGraph Server API protocol. Studio also integrates with LangSmith to enable tracing, evaluation, and prompt engineering.
|
||||
|
||||
- **[Deployment](./deployment_options.md)**: There are four ways to deploy on LangGraph Platform: [Cloud SaaS](../concepts/langgraph_cloud.md), [Self-Hosted Data Plane](../concepts/langgraph_self_hosted_data_plane.md), [Self-Hosted Control Plane](../concepts/langgraph_self_hosted_control_plane.md), and [Standalone Container](../concepts/langgraph_standalone_container.md).
|
||||
- **[Deployment](./deployment_options.md)**: There are four ways to deploy on LangGraph Platform: [Cloud Saas](../concepts/langgraph_cloud.md), [Self-Hosted Data Plane](../concepts/langgraph_self_hosted_data_plane.md), [Self-Hosted Control Plane](../concepts/langgraph_self_hosted_control_plane.md), and [Standalone Container](../concepts/langgraph_standalone_container.md).
|
||||
@@ -2,19 +2,17 @@
|
||||
|
||||
There are two versions of the self-hosted deployment: [Self-Hosted Data Plane](./deployment_options.md#self-hosted-data-plane) and [Self-Hosted Control Plane](./deployment_options.md#self-hosted-control-plane).
|
||||
|
||||
!!! info "Important"
|
||||
The Self-Hosted Control Plane deployment option is currently in beta stage and requires an [Enterprise](../../concepts/plans.md) plan.
|
||||
!!! important "Beta"
|
||||
The Self-Hosted Control Plane deployment option is currently in beta stage.
|
||||
|
||||
## Requirements
|
||||
|
||||
- You use `langgraph-cli` and/or [LangGraph Studio](./langgraph_studio.md) app to test graph locally.
|
||||
- You use `langgraph build` command to build image.
|
||||
- You have a Self-Hosted LangSmith instance deployed.
|
||||
- You are using Ingress for your LangSmith instance. All agents will be deployed as Kubernetes services behind this ingress.
|
||||
|
||||
## Self-Hosted Control Plane
|
||||
|
||||
The [Self-Hosted Control Plane](./langgraph_self_hosted_control_plane.md) deployment option is a fully self-hosted model for deployment where you manage the [control plane](./langgraph_control_plane.md) and [data plane](./langgraph_data_plane.md) in your cloud. This option gives you full control and responsibility of the control plane and data plane infrastructure.
|
||||
The [Self-Hosted Control Plane](./langgraph_self_hosted_control_plane.md) deployment option is a fully self-hosted model for deployment where you manage the [control plane](./langgraph_control_plane.md) and [data plane](./langgraph_data_plane.md) in your cloud. This option give you full control and responsibility of the control plane and data plane infrastructure.
|
||||
|
||||
| | [Control plane](../concepts/langgraph_control_plane.md) | [Data plane](../concepts/langgraph_data_plane.md) |
|
||||
|-------------------|-------------------|------------|
|
||||
@@ -31,4 +29,4 @@ The [Self-Hosted Control Plane](./langgraph_self_hosted_control_plane.md) deploy
|
||||
- **Kubernetes**: The Self-Hosted Control Plane deployment option supports deploying control plane and data plane infrastructure to any Kubernetes cluster.
|
||||
|
||||
!!! tip
|
||||
If you would like to enable this on your LangSmith instance, please follow the [Self-Hosted Control Plane deployment guide](../cloud/deployment/self_hosted_control_plane.md).
|
||||
If you would like to deploy to Kubernetes, you can use this [Helm chart](https://github.com/langchain-ai/helm/blob/main/charts/langgraph-cloud/README.md).
|
||||
@@ -7,8 +7,8 @@ search:
|
||||
|
||||
There are two versions of the self-hosted deployment: [Self-Hosted Data Plane](./deployment_options.md#self-hosted-data-plane) and [Self-Hosted Control Plane](./deployment_options.md#self-hosted-control-plane).
|
||||
|
||||
!!! info "Important"
|
||||
The Self-Hosted Data Plane deployment option is currently in beta stage and requires an [Enterprise](../../concepts/plans.md) plan.
|
||||
!!! important "Beta"
|
||||
The Self-Hosted Data Plane deployment option is currently in beta stage.
|
||||
|
||||
## Requirements
|
||||
|
||||
@@ -37,4 +37,4 @@ For information on how to deploy a [LangGraph Server](../concepts/langgraph_serv
|
||||
- **Amazon ECS**: Coming soon!
|
||||
|
||||
!!! tip
|
||||
If you would like to deploy to Kubernetes, you can follow the [Self-Hosted Data Plane deployment guide](../cloud/deployment/self_hosted_data_plane.md).
|
||||
If you would like to deploy to Kubernetes, you can use this [Helm chart](https://github.com/langchain-ai/helm/blob/main/charts/langgraph-cloud/README.md).
|
||||
@@ -26,7 +26,7 @@ Feature Differences:
|
||||
|-------|------------|------------|
|
||||
| [Cron Jobs](../cloud/concepts/cron_jobs.md) |❌|✅|
|
||||
| [Custom Authentication](../concepts/auth.md) |❌|✅|
|
||||
| [Deployment options](../concepts/deployment_options.md) | Standalone container | Cloud SaaS, Self-Hosted Data Plane, Self-Hosted Control Plane, Standalone container
|
||||
| [Deployment options](../concepts/deployment_options.md) | Standalone container | Cloud Saas, Self-Hosted Data Plane, Self-Hosted Control Plane, Standalone container
|
||||
|
||||
## Application structure
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ Key features of LangGraph Studio:
|
||||
|
||||
- Visualize your graph architecture
|
||||
- [Run and interact with your agent](../cloud/how-tos/invoke_studio.md)
|
||||
- [Manage assistants](../cloud/how-tos/studio/manage_assistants.md)
|
||||
- [Manage assistants](../cloud/how-tos/studio/manage_assistants.md.md)
|
||||
- [Manage threads](../cloud/how-tos/threads_studio.md)
|
||||
- [Iterate on prompts](../cloud/how-tos/iterate_graph_studio.md)
|
||||
- Manage [long term memory](memory.md)
|
||||
@@ -33,7 +33,7 @@ Studio supports two modes:
|
||||
|
||||
### Graph mode
|
||||
|
||||
Graph mode exposes the full feature-set of Studio and is useful when you would like as many details about the execution of your agent, including the nodes traversed, intermediate states, and LangSmith integrations (such as adding to datasets and playground).
|
||||
Graph mode exposes the full feature-set of Studio and is useful when you would like as many details about the execution of your agent, including the nodes traversed, intermediate states, and LangSmith integrations (such as adding to datasets an playground).
|
||||
|
||||
### Chat mode
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ def node_3(state: PrivateState) -> OutputState:
|
||||
# Read from PrivateState, write to OutputState
|
||||
return {"graph_output": state["bar"] + " Lance"}
|
||||
|
||||
builder = StateGraph(OverallState,input_schema=InputState,output_schema=OutputState)
|
||||
builder = StateGraph(OverallState,input=InputState,output=OutputState)
|
||||
builder.add_node("node_1", node_1)
|
||||
builder.add_node("node_2", node_2)
|
||||
builder.add_node("node_3", node_3)
|
||||
@@ -105,9 +105,9 @@ graph.invoke({"user_input":"My"})
|
||||
|
||||
There are two subtle and important points to note here:
|
||||
|
||||
1. We pass `state: InputState` as the input schema to `node_1`. But, we write out to `foo`, a channel in `OverallState`. How can we write out to a state channel that is not included in the input schema? This is because a node _can write to any state channel in the graph state._ The graph state is the union of the state channels defined at initialization, which includes `OverallState` and the filters `InputState` and `OutputState`.
|
||||
1. We pass `state: InputState` as the input schema to `node_1`. But, we write out to `foo`, a channel in `OverallState`. How can we write out to a state channel that is not included in the input schema? This is because a node _can write to any state channel in the graph state._ The graph state is the union of of the state channels defined at initialization, which includes `OverallState` and the filters `InputState` and `OutputState`.
|
||||
|
||||
2. We initialize the graph with `StateGraph(OverallState,input_schema=InputState,output_schema=OutputState)`. So, how can we write to `PrivateState` in `node_2`? How does the graph gain access to this schema if it was not passed in the `StateGraph` initialization? We can do this because _nodes can also declare additional state channels_ as long as the state schema definition exists. In this case, the `PrivateState` schema is defined, so we can add `bar` as a new state channel in the graph and write to it.
|
||||
2. We initialize the graph with `StateGraph(OverallState,input=InputState,output=OutputState)`. So, how can we write to `PrivateState` in `node_2`? How does the graph gain access to this schema if it was not passed in the `StateGraph` initialization? We can do this because _nodes can also declare additional state channels_ as long as the state schema definition exists. In this case, the `PrivateState` schema is defined, so we can add `bar` as a new state channel in the graph and write to it.
|
||||
|
||||
### Reducers
|
||||
|
||||
@@ -167,7 +167,7 @@ In addition to keeping track of message IDs, the `add_messages` function will al
|
||||
{"messages": [{"type": "human", "content": "message"}]}
|
||||
```
|
||||
|
||||
Since the state updates are always deserialized into LangChain `Messages` when using `add_messages`, you should use dot notation to access message attributes, like `state["messages"][-1].content`. Below is an example of a graph that uses `add_messages` as its reducer function.
|
||||
Since the state updates are always deserialized into LangChain `Messages` when using `add_messages`, you should use dot notation to access message attributes, like `state["messages"][-1].content`. Below is an example of a graph that uses `add_messages` as it's reducer function.
|
||||
|
||||
```python
|
||||
from langchain_core.messages import AnyMessage
|
||||
@@ -197,25 +197,19 @@ In LangGraph, nodes are typically python functions (sync or async) where the **f
|
||||
Similar to `NetworkX`, you add these nodes to a graph using the [add_node][langgraph.graph.StateGraph.add_node] method:
|
||||
|
||||
```python
|
||||
from typing_extensions import TypedDict
|
||||
|
||||
from langchain_core.runnables import RunnableConfig
|
||||
from langgraph.graph import StateGraph
|
||||
|
||||
class State(TypedDict):
|
||||
input: str
|
||||
results: str
|
||||
|
||||
builder = StateGraph(State)
|
||||
builder = StateGraph(dict)
|
||||
|
||||
|
||||
def my_node(state: State, config: RunnableConfig):
|
||||
def my_node(state: dict, config: RunnableConfig):
|
||||
print("In node: ", config["configurable"]["user_id"])
|
||||
return {"results": f"Hello, {state['input']}!"}
|
||||
|
||||
|
||||
# The second argument is optional
|
||||
def my_other_node(state: State):
|
||||
def my_other_node(state: dict):
|
||||
return state
|
||||
|
||||
|
||||
|
||||
@@ -383,7 +383,7 @@ def update_memory(state: MessagesState, config: RunnableConfig, *, store: BaseSt
|
||||
|
||||
```
|
||||
|
||||
As we showed above, we can also access the store in any node and use the `store.search` method to get memories. Recall the memories are returned as a list of objects that can be converted to a dictionary.
|
||||
As we showed above, we can also access the store in any node and use the `store.search` method to get memories. Recall the the memories are returned as a list of objects that can be converted to a dictionary.
|
||||
|
||||
```python
|
||||
memories[-1].dict()
|
||||
@@ -470,51 +470,9 @@ If the checkpointer is used with asynchronous graph execution (i.e. executing th
|
||||
|
||||
### Serializer
|
||||
|
||||
When checkpointers save the graph state, they need to serialize the channel values in the state. This is done using serializer objects.
|
||||
When checkpointers save the graph state, they need to serialize the channel values in the state. This is done using serializer objects.
|
||||
`langgraph_checkpoint` defines [protocol][langgraph.checkpoint.serde.base.SerializerProtocol] for implementing serializers provides a default implementation ([JsonPlusSerializer][langgraph.checkpoint.serde.jsonplus.JsonPlusSerializer]) that handles a wide variety of types, including LangChain and LangGraph primitives, datetimes, enums and more.
|
||||
|
||||
#### Serialization with `pickle`
|
||||
|
||||
The default serializer, [`JsonPlusSerializer`][langgraph.checkpoint.serde.jsonplus.JsonPlusSerializer], uses ormsgpack and JSON under the hood, which is not suitable for all types of objects.
|
||||
|
||||
If you want to fallback to pickle for objects not currently supported by our msgpack encoder (such as Pandas dataframes),
|
||||
you can use the `pickle_fallback` argument of the `JsonPlusSerializer`:
|
||||
|
||||
```python
|
||||
from langgraph.checkpoint.memory import MemorySaver
|
||||
from langgraph.checkpoint.serde.jsonplus import JsonPlusSerializer
|
||||
|
||||
# ... Define the graph ...
|
||||
graph.compile(
|
||||
checkpointer=MemorySaver(serde=JsonPlusSerializer(pickle_fallback=True))
|
||||
)
|
||||
```
|
||||
|
||||
#### Encryption
|
||||
|
||||
Checkpointers can optionally encrypt all persisted state. To enable this, pass an instance of [`EncryptedSerializer`][langgraph.checkpoint.serde.encrypted.EncryptedSerializer] to the `serde` argument of any `BaseCheckpointSaver` implementation. The easiest way to create an encrypted serializer is via [`from_pycryptodome_aes`][langgraph.checkpoint.serde.encrypted.EncryptedSerializer.from_pycryptodome_aes], which reads the AES key from the `LANGGRAPH_AES_KEY` environment variable (or accepts a `key` argument):
|
||||
|
||||
```python
|
||||
import sqlite3
|
||||
|
||||
from langgraph.checkpoint.serde.encrypted import EncryptedSerializer
|
||||
from langgraph.checkpoint.sqlite import SqliteSaver
|
||||
|
||||
serde = EncryptedSerializer.from_pycryptodome_aes() # reads LANGGRAPH_AES_KEY
|
||||
checkpointer = SqliteSaver(sqlite3.connect("checkpoint.db"), serde=serde)
|
||||
```
|
||||
|
||||
```python
|
||||
from langgraph.checkpoint.serde.encrypted import EncryptedSerializer
|
||||
from langgraph.checkpoint.postgres import PostgresSaver
|
||||
|
||||
serde = EncryptedSerializer.from_pycryptodome_aes()
|
||||
checkpointer = PostgresSaver.from_conn_string("postgresql://...", serde=serde)
|
||||
checkpointer.setup()
|
||||
```
|
||||
|
||||
When running on LangGraph Platform, encryption is automatically enabled whenever `LANGGRAPH_AES_KEY` is present, so you only need to provide the environment variable. Other encryption schemes can be used by implementing [`CipherProtocol`][langgraph.checkpoint.serde.base.CipherProtocol] and supplying it to `EncryptedSerializer`.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### Human-in-the-loop
|
||||
|
||||
@@ -25,7 +25,7 @@ Each step consists of three phases:
|
||||
|
||||
Repeat until no **actors** are selected for execution, or a maximum number of steps is reached.
|
||||
|
||||
## Actors
|
||||
## Actors
|
||||
|
||||
An **actor** is a `PregelNode`. It subscribes to channels, reads data from them, and writes data to them. It can be thought of as an **actor** in the Pregel algorithm. `PregelNodes` implement LangChain's Runnable interface.
|
||||
|
||||
@@ -39,7 +39,7 @@ Channels are used to communicate between actors (PregelNodes). Each channel has
|
||||
|
||||
## Examples
|
||||
|
||||
While most users will interact with Pregel through the [StateGraph][langgraph.graph.StateGraph] API or
|
||||
While most users will interact with Pregel through the [StateGraph][langgraph.graph.StateGraph] API or
|
||||
the [entrypoint][langgraph.func.entrypoint] decorator, it is possible to interact with Pregel directly.
|
||||
|
||||
Below are a few different examples to give you a sense of the Pregel API.
|
||||
@@ -49,12 +49,12 @@ Below are a few different examples to give you a sense of the Pregel API.
|
||||
```python
|
||||
|
||||
from langgraph.channels import EphemeralValue
|
||||
from langgraph.pregel import Pregel, NodeBuilder
|
||||
from langgraph.pregel import Pregel, Channel
|
||||
|
||||
node1 = (
|
||||
NodeBuilder().subscribe_only("a")
|
||||
.do(lambda x: x + x)
|
||||
.write_to("b")
|
||||
Channel.subscribe_to("a")
|
||||
| (lambda x: x + x)
|
||||
| Channel.write_to("b")
|
||||
)
|
||||
|
||||
app = Pregel(
|
||||
@@ -78,18 +78,18 @@ Below are a few different examples to give you a sense of the Pregel API.
|
||||
|
||||
```python
|
||||
from langgraph.channels import LastValue, EphemeralValue
|
||||
from langgraph.pregel import Pregel, NodeBuilder
|
||||
from langgraph.pregel import Pregel, Channel
|
||||
|
||||
node1 = (
|
||||
NodeBuilder().subscribe_only("a")
|
||||
.do(lambda x: x + x)
|
||||
.write_to("b")
|
||||
Channel.subscribe_to("a")
|
||||
| (lambda x: x + x)
|
||||
| Channel.write_to("b")
|
||||
)
|
||||
|
||||
node2 = (
|
||||
NodeBuilder().subscribe_only("b")
|
||||
.do(lambda x: x + x)
|
||||
.write_to("c")
|
||||
Channel.subscribe_to("b")
|
||||
| (lambda x: x + x)
|
||||
| Channel.write_to("c")
|
||||
)
|
||||
|
||||
|
||||
@@ -115,18 +115,23 @@ Below are a few different examples to give you a sense of the Pregel API.
|
||||
|
||||
```python
|
||||
from langgraph.channels import EphemeralValue, Topic
|
||||
from langgraph.pregel import Pregel, NodeBuilder
|
||||
from langgraph.pregel import Pregel, Channel
|
||||
|
||||
node1 = (
|
||||
NodeBuilder().subscribe_only("a")
|
||||
.do(lambda x: x + x)
|
||||
.write_to("b", "c")
|
||||
Channel.subscribe_to("a")
|
||||
| (lambda x: x + x)
|
||||
| {
|
||||
"b": Channel.write_to("b"),
|
||||
"c": Channel.write_to("c")
|
||||
}
|
||||
)
|
||||
|
||||
node2 = (
|
||||
NodeBuilder().subscribe_to("b")
|
||||
.do(lambda x: x["b"] + x["b"])
|
||||
.write_to("c")
|
||||
Channel.subscribe_to("b")
|
||||
| (lambda x: x + x)
|
||||
| {
|
||||
"c": Channel.write_to("c"),
|
||||
}
|
||||
)
|
||||
|
||||
app = Pregel(
|
||||
@@ -153,19 +158,24 @@ Below are a few different examples to give you a sense of the Pregel API.
|
||||
|
||||
```python
|
||||
from langgraph.channels import EphemeralValue, BinaryOperatorAggregate
|
||||
from langgraph.pregel import Pregel, NodeBuilder
|
||||
from langgraph.pregel import Pregel, Channel
|
||||
|
||||
|
||||
node1 = (
|
||||
NodeBuilder().subscribe_only("a")
|
||||
.do(lambda x: x + x)
|
||||
.write_to("b", "c")
|
||||
Channel.subscribe_to("a")
|
||||
| (lambda x: x + x)
|
||||
| {
|
||||
"b": Channel.write_to("b"),
|
||||
"c": Channel.write_to("c")
|
||||
}
|
||||
)
|
||||
|
||||
node2 = (
|
||||
NodeBuilder().subscribe_only("b")
|
||||
.do(lambda x: x + x)
|
||||
.write_to("c")
|
||||
Channel.subscribe_to("b")
|
||||
| (lambda x: x + x)
|
||||
| {
|
||||
"c": Channel.write_to("c"),
|
||||
}
|
||||
)
|
||||
|
||||
def reducer(current, update):
|
||||
@@ -187,7 +197,8 @@ Below are a few different examples to give you a sense of the Pregel API.
|
||||
|
||||
app.invoke({"a": "foo"})
|
||||
```
|
||||
|
||||
|
||||
|
||||
=== "Cycle"
|
||||
|
||||
This example demonstrates how to introduce a cycle in the graph, by having
|
||||
@@ -196,12 +207,12 @@ Below are a few different examples to give you a sense of the Pregel API.
|
||||
|
||||
```python
|
||||
from langgraph.channels import EphemeralValue
|
||||
from langgraph.pregel import Pregel, NodeBuilder, ChannelWriteEntry
|
||||
from langgraph.pregel import Pregel, Channel, ChannelWrite, ChannelWriteEntry
|
||||
|
||||
example_node = (
|
||||
NodeBuilder().subscribe_only("value")
|
||||
.do(lambda x: x + x if len(x) < 10 else None)
|
||||
.write_to(ChannelWriteEntry("value", skip_none=True))
|
||||
Channel.subscribe_to("value")
|
||||
| (lambda x: x + x if len(x) < 10 else None)
|
||||
| ChannelWrite(writes=[ChannelWriteEntry(channel="value", skip_none=True)])
|
||||
)
|
||||
|
||||
app = Pregel(
|
||||
@@ -224,6 +235,7 @@ Below are a few different examples to give you a sense of the Pregel API.
|
||||
|
||||
LangGraph provides two high-level APIs for creating a Pregel application: the [StateGraph (Graph API)](./low_level.md) and the [Functional API](functional_api.md).
|
||||
|
||||
|
||||
=== "StateGraph (Graph API)"
|
||||
|
||||
The [StateGraph (Graph API)][langgraph.graph.StateGraph] is a higher-level abstraction that simplifies the creation of Pregel applications. It allows you to define a graph of nodes and edges. When you compile the graph, the StateGraph API automatically creates the Pregel application for you.
|
||||
@@ -254,7 +266,7 @@ LangGraph provides two high-level APIs for creating a Pregel application: the [S
|
||||
builder.add_node(score_essay)
|
||||
builder.add_edge(START, "write_essay")
|
||||
|
||||
# Compile the graph.
|
||||
# Compile the graph.
|
||||
# This will return a Pregel instance.
|
||||
graph = builder.compile()
|
||||
```
|
||||
@@ -267,7 +279,7 @@ LangGraph provides two high-level APIs for creating a Pregel application: the [S
|
||||
|
||||
You will see something like this:
|
||||
|
||||
```pycon
|
||||
```pycon
|
||||
{'__start__': <langgraph.pregel.read.PregelNode at 0x7d05e3ba1810>,
|
||||
'write_essay': <langgraph.pregel.read.PregelNode at 0x7d05e3ba14d0>,
|
||||
'score_essay': <langgraph.pregel.read.PregelNode at 0x7d05e3ba1710>}
|
||||
@@ -298,7 +310,7 @@ LangGraph provides two high-level APIs for creating a Pregel application: the [S
|
||||
=== "Functional API"
|
||||
|
||||
In the [Functional API](functional_api.md), you can use an [`entrypoint`][langgraph.func.entrypoint] to create
|
||||
a Pregel application. The `entrypoint` decorator allows you to define a function that takes input and returns output.
|
||||
a Pregel application. The `entrypoint` decorator allows you to define a function that takes input and returns output.
|
||||
|
||||
```python
|
||||
from typing import TypedDict, Optional
|
||||
@@ -327,8 +339,8 @@ LangGraph provides two high-level APIs for creating a Pregel application: the [S
|
||||
```
|
||||
|
||||
```pycon
|
||||
Nodes:
|
||||
Nodes:
|
||||
{'write_essay': <langgraph.pregel.read.PregelNode object at 0x7d05e2f9aad0>}
|
||||
Channels:
|
||||
Channels:
|
||||
{'__start__': <langgraph.channels.ephemeral_value.EphemeralValue object at 0x7d05e2c906c0>, '__end__': <langgraph.channels.last_value.LastValue object at 0x7d05e2c90c40>, '__previous__': <langgraph.channels.last_value.LastValue object at 0x7d05e1007280>}
|
||||
```
|
||||
|
||||
@@ -25,7 +25,7 @@ When a graceful shutdown request is received (SIGINT) an instance enters shutdow
|
||||
- gives any in-progress runs a limited number of seconds to finish (if not finished it will be put back in the queue)
|
||||
- stops the instance from picking up more runs from the queue
|
||||
|
||||
If a hard shutdown occurs due to a server crash or an infrastructure failure, any runs that were in progress will be picked up by an internal sweeper task that looks for in-progress runs that have breached their heartbeat window. The sweeper runs every 2 minutes and will put the runs back in the queue for another instance to pick them up.
|
||||
If a hard shutdown occurs due to a server crash or an infrastructure failure, any runs that were in progress will be picked up by a internal sweeper task that looks for in-progress runs that have breached their heartbeat window. The sweeper runs every 2 minutes and will put the runs back in the queue for another instance to pick them up.
|
||||
|
||||
## Postgres resilience
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ def answer_node(state: InputState):
|
||||
return {"answer": "bye", "question": state["question"]}
|
||||
|
||||
# Build the graph with explicit schemas
|
||||
builder = StateGraph(OverallState, input_schema=InputState, output_schema=OutputState)
|
||||
builder = StateGraph(OverallState, input=InputState, output=OutputState)
|
||||
builder.add_node(answer_node)
|
||||
builder.add_edge(START, "answer_node")
|
||||
builder.add_edge("answer_node", END)
|
||||
|
||||
@@ -59,9 +59,8 @@ The main question when adding subgraphs is how the parent graph and subgraph com
|
||||
response = model.invoke(state["subgraph_messages"])
|
||||
return {"subgraph_messages": response}
|
||||
|
||||
subgraph_builder = StateGraph(SubgraphMessagesState)
|
||||
subgraph_builder.add_node("call_model_from_subgraph", call_model)
|
||||
subgraph_builder.add_edge(START, "call_model_from_subgraph")
|
||||
subgraph_builder = StateGraph(State)
|
||||
subgraph_builder.add_node(call_model)
|
||||
...
|
||||
# highlight-next-line
|
||||
subgraph = subgraph_builder.compile()
|
||||
|
||||
@@ -74,7 +74,7 @@ In your `langgraph.json`, add the path to your auth file:
|
||||
|
||||
## 3. Connect from the client
|
||||
|
||||
Once you've set up authentication in your server, requests must include the required authorization information based on your chosen scheme.
|
||||
Once you've set up authentication in your server, requests must include the the required authorization information based on your chosen scheme.
|
||||
Assuming you are using JWT token authentication, you could access your deployments using any of the following methods:
|
||||
|
||||
=== "Python Client"
|
||||
|
||||
@@ -439,7 +439,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 6,
|
||||
"id": "6ec0eb77-874e-443e-8c73-93125b515106",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
@@ -478,7 +478,7 @@
|
||||
"\n",
|
||||
"\n",
|
||||
"# Build the graph with input and output schemas specified\n",
|
||||
"builder = StateGraph(OverallState, input_schema=InputState, output_schema=OutputState)\n",
|
||||
"builder = StateGraph(OverallState, input=InputState, output=OutputState)\n",
|
||||
"builder.add_node(answer_node) # Add the answer node\n",
|
||||
"builder.add_edge(START, \"answer_node\") # Define the starting edge\n",
|
||||
"builder.add_edge(\"answer_node\", END) # Define the ending edge\n",
|
||||
@@ -1198,7 +1198,7 @@
|
||||
"\n",
|
||||
"There are many use cases where you may wish for your node to have a custom retry policy, for example if you are calling an API, querying a database, or calling an LLM, etc. LangGraph lets you add retry policies to nodes.\n",
|
||||
"\n",
|
||||
"To configure a retry policy, pass the `retry_policy` parameter to the [add_node](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.state.StateGraph.add_node). The `retry_policy` parameter takes in a `RetryPolicy` named tuple object. Below we instantiate a `RetryPolicy` object with the default parameters and associate it with a node:\n",
|
||||
"To configure a retry policy, pass the `retry` parameter to the [add_node](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.state.StateGraph.add_node). The `retry` parameter takes in a `RetryPolicy` named tuple object. Below we instantiate a `RetryPolicy` object with the default parameters and associate it with a node:\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"from langgraph.pregel import RetryPolicy\n",
|
||||
@@ -1206,7 +1206,7 @@
|
||||
"builder.add_node(\n",
|
||||
" \"node_name\",\n",
|
||||
" node_function,\n",
|
||||
" retry_policy=RetryPolicy(),\n",
|
||||
" retry=RetryPolicy(),\n",
|
||||
")\n",
|
||||
"```"
|
||||
]
|
||||
@@ -1241,7 +1241,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 2,
|
||||
"id": "ad92598c-b688-42fa-aae0-9de36273d584",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
@@ -1276,9 +1276,9 @@
|
||||
"builder.add_node(\n",
|
||||
" \"query_database\",\n",
|
||||
" query_database,\n",
|
||||
" retry_policy=RetryPolicy(retry_on=sqlite3.OperationalError),\n",
|
||||
" retry=RetryPolicy(retry_on=sqlite3.OperationalError),\n",
|
||||
")\n",
|
||||
"builder.add_node(\"model\", call_model, retry_policy=RetryPolicy(max_attempts=5))\n",
|
||||
"builder.add_node(\"model\", call_model, retry=RetryPolicy(max_attempts=5))\n",
|
||||
"builder.add_edge(START, \"model\")\n",
|
||||
"builder.add_edge(\"model\", \"query_database\")\n",
|
||||
"builder.add_edge(\"query_database\", END)\n",
|
||||
@@ -2235,7 +2235,7 @@
|
||||
" if termination_condition(state):\n",
|
||||
" return END\n",
|
||||
" else:\n",
|
||||
" return \"b\"\n",
|
||||
" return \"a\"\n",
|
||||
"\n",
|
||||
"builder.add_edge(START, \"a\")\n",
|
||||
"builder.add_conditional_edges(\"a\", route)\n",
|
||||
@@ -2950,6 +2950,16 @@
|
||||
" When you send updates from a subgraph node to a parent graph node for a key that's shared by both parent and subgraph [state schemas](../../concepts/low_level#schema), you **must** define a [reducer](../../concepts/low_level#reducers) for the key you're updating in the parent graph state. See the example below."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "6be0aeb9-e138-4adc-a1df-5d743a8eb348",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"!!! important \"State updates with `Command.PARENT`\"\n",
|
||||
"\n",
|
||||
" When you send updates from a subgraph node to a parent graph node for a key that's shared by both parent and subgraph [state schemas](../../concepts/low_level#schema), you **must** define a [reducer](../../concepts/low_level#reducers) for the key you're updating in the parent graph state."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
@@ -3416,7 +3426,7 @@
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": ".venv",
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
@@ -3430,7 +3440,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.6"
|
||||
"version": "3.10.4"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
"\n",
|
||||
"\n",
|
||||
"1. **Run the graph** with initial inputs using `invoke` or `stream` APIs.\n",
|
||||
"2. **Identify a checkpoint in an existing thread**: Use the [`get_state_history()`][langgraph.graph.state.CompiledStateGraph.get_state_history] method to retrieve the execution history for a specific `thread_id` and locate the desired `checkpoint_id`. \n",
|
||||
"2. **Identify a checkpoint in an existing thread**: Use the [`get_state_history()`][langgraph.graph.graph.CompiledGraph.get_state_history] method to retrieve the execution history for a specific `thread_id` and locate the desired `checkpoint_id`. \n",
|
||||
" Alternatively, set a [breakpoint](../../../concepts/breakpoints/) before the node(s) where you want execution to pause. You can then find the most recent checkpoint recorded up to that breakpoint.\n",
|
||||
"3. **(Optional) modify the graph state**: Use the [`update_state`][langgraph.graph.state.CompiledStateGraph.update_state] method to modify the graph’s state at the checkpoint and resume execution from alternative state.\n",
|
||||
"3. **(Optional) modify the graph state**: Use the [`update_state`][langgraph.graph.graph.CompiledGraph.update_state] method to modify the graph’s state at the checkpoint and resume execution from alternative state.\n",
|
||||
"4. **Resume execution from the checkpoint**: Use the `invoke` or `stream` APIs with an input of `None` and a configuration containing the appropriate `thread_id` and `checkpoint_id`.\n",
|
||||
"\n",
|
||||
"## Example\n",
|
||||
|
||||
@@ -405,7 +405,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 46,
|
||||
"id": "1954a5f1-91e4-4b32-9be9-c8bc1cc43cb5",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
@@ -465,9 +465,7 @@
|
||||
"\n",
|
||||
"graph_builder = StateGraph(State)\n",
|
||||
"graph_builder.add_node(\"agent\", agent)\n",
|
||||
"graph_builder.add_node(\n",
|
||||
" \"select_tools\", select_tools, retry_policy=RetryPolicy(max_attempts=3)\n",
|
||||
")\n",
|
||||
"graph_builder.add_node(\"select_tools\", select_tools, retry=RetryPolicy(max_attempts=3))\n",
|
||||
"\n",
|
||||
"tool_node = ToolNode(tools=tools)\n",
|
||||
"graph_builder.add_node(\"tools\", tool_node)\n",
|
||||
|
||||
@@ -207,7 +207,7 @@
|
||||
"id": "213d661e-6ba4-42b9-bc7f-6c8c423e3419",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Let's now create our agents using the prebuilt [`create_react_agent`][langgraph.prebuilt.chat_agent_executor.create_react_agent] and our multi-agent workflow. Note that will be calling [`interrupt`][langgraph.types.interrupt] every time after we get the final response from each of the agents."
|
||||
"Let's now create our agents using the the prebuilt [`create_react_agent`][langgraph.prebuilt.chat_agent_executor.create_react_agent] and our multi-agent workflow. Note that will be calling [`interrupt`][langgraph.types.interrupt] every time after we get the final response from each of the agents."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -739,6 +739,7 @@
|
||||
" 'id': '1f029ca3-1f5b-6704-8004-820c16b69a5a',\n",
|
||||
" 'channel_versions': {'__start__': '00000000000000000000000000000005.0.5290678567601859', 'messages': '00000000000000000000000000000006.0.3205149138784782', 'branch:to:call_model': '00000000000000000000000000000006.0.14611156755133758'}, 'versions_seen': {'__input__': {}, '__start__': {'__start__': '00000000000000000000000000000004.0.5736472536395331'}, 'call_model': {'branch:to:call_model': '00000000000000000000000000000005.0.1410174088651449'}},\n",
|
||||
" 'channel_values': {'messages': [HumanMessage(content=\"hi! I'm bob\"), AIMessage(content='Hi Bob! How are you doing today?), HumanMessage(content=\"what's my name?\"), AIMessage(content='Your name is Bob.')]},\n",
|
||||
" 'pending_sends': []\n",
|
||||
" },\n",
|
||||
" metadata={\n",
|
||||
" 'source': 'loop',\n",
|
||||
@@ -855,7 +856,7 @@
|
||||
" 'id': '1f029ca3-1f5b-6704-8004-820c16b69a5a', \n",
|
||||
" 'channel_versions': {'__start__': '00000000000000000000000000000005.0.5290678567601859', 'messages': '00000000000000000000000000000006.0.3205149138784782', 'branch:to:call_model': '00000000000000000000000000000006.0.14611156755133758'}, \n",
|
||||
" 'versions_seen': {'__input__': {}, '__start__': {'__start__': '00000000000000000000000000000004.0.5736472536395331'}, 'call_model': {'branch:to:call_model': '00000000000000000000000000000005.0.1410174088651449'}},\n",
|
||||
" 'channel_values': {'messages': [HumanMessage(content=\"hi! I'm bob\"), AIMessage(content='Hi Bob! How are you doing today? Is there anything I can help you with?'), HumanMessage(content=\"what's my name?\"), AIMessage(content='Your name is Bob.')]},\n",
|
||||
" 'channel_values': {'messages': [HumanMessage(content=\"hi! I'm bob\"), AIMessage(content='Hi Bob! How are you doing today? Is there anything I can help you with?'), HumanMessage(content=\"what's my name?\"), AIMessage(content='Your name is Bob.')]}, 'pending_sends': []\n",
|
||||
" },\n",
|
||||
" metadata={'source': 'loop', 'writes': {'call_model': {'messages': AIMessage(content='Your name is Bob.')}}, 'step': 4, 'parents': {}, 'thread_id': '1'}, \n",
|
||||
" parent_config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1f029ca3-1790-6b0a-8003-baf965b6a38f'}}, \n",
|
||||
@@ -869,7 +870,8 @@
|
||||
" 'id': '1f029ca3-1790-6b0a-8003-baf965b6a38f', \n",
|
||||
" 'channel_versions': {'__start__': '00000000000000000000000000000005.0.5290678567601859', 'messages': '00000000000000000000000000000005.0.7935064215293443', 'branch:to:call_model': '00000000000000000000000000000005.0.1410174088651449'}, \n",
|
||||
" 'versions_seen': {'__input__': {}, '__start__': {'__start__': '00000000000000000000000000000004.0.5736472536395331'}, 'call_model': {'branch:to:call_model': '00000000000000000000000000000002.0.9300422176788571'}}, \n",
|
||||
" 'channel_values': {'messages': [HumanMessage(content=\"hi! I'm bob\"), AIMessage(content='Hi Bob! How are you doing today? Is there anything I can help you with?'), HumanMessage(content=\"what's my name?\")], 'branch:to:call_model': None}\n",
|
||||
" 'channel_values': {'messages': [HumanMessage(content=\"hi! I'm bob\"), AIMessage(content='Hi Bob! How are you doing today? Is there anything I can help you with?'), HumanMessage(content=\"what's my name?\")], 'branch:to:call_model': None}, \n",
|
||||
" 'pending_sends': []\n",
|
||||
" }, \n",
|
||||
" metadata={'source': 'loop', 'writes': None, 'step': 3, 'parents': {}, 'thread_id': '1'}, \n",
|
||||
" parent_config={...}, \n",
|
||||
@@ -883,7 +885,8 @@
|
||||
" 'id': '1f029ca3-1790-616e-8002-9e021694a0cd', \n",
|
||||
" 'channel_versions': {'__start__': '00000000000000000000000000000004.0.5736472536395331', 'messages': '00000000000000000000000000000003.0.7056767754077798', 'branch:to:call_model': '00000000000000000000000000000003.0.22059023329132854'}, \n",
|
||||
" 'versions_seen': {'__input__': {}, '__start__': {'__start__': '00000000000000000000000000000001.0.7040775356287469'}, 'call_model': {'branch:to:call_model': '00000000000000000000000000000002.0.9300422176788571'}}, \n",
|
||||
" 'channel_values': {'__start__': {'messages': [{'role': 'user', 'content': \"what's my name?\"}]}, 'messages': [HumanMessage(content=\"hi! I'm bob\"), AIMessage(content='Hi Bob! How are you doing today? Is there anything I can help you with?')]}\n",
|
||||
" 'channel_values': {'__start__': {'messages': [{'role': 'user', 'content': \"what's my name?\"}]}, 'messages': [HumanMessage(content=\"hi! I'm bob\"), AIMessage(content='Hi Bob! How are you doing today? Is there anything I can help you with?')]}, \n",
|
||||
" 'pending_sends': []\n",
|
||||
" }, \n",
|
||||
" metadata={'source': 'input', 'writes': {'__start__': {'messages': [{'role': 'user', 'content': \"what's my name?\"}]}}, 'step': 2, 'parents': {}, 'thread_id': '1'}, \n",
|
||||
" parent_config={...}, \n",
|
||||
@@ -897,7 +900,8 @@
|
||||
" 'id': '1f029ca3-178d-6f54-8001-d7b180db0c89', \n",
|
||||
" 'channel_versions': {'__start__': '00000000000000000000000000000002.0.18673090920108737', 'messages': '00000000000000000000000000000003.0.7056767754077798', 'branch:to:call_model': '00000000000000000000000000000003.0.22059023329132854'}, \n",
|
||||
" 'versions_seen': {'__input__': {}, '__start__': {'__start__': '00000000000000000000000000000001.0.7040775356287469'}, 'call_model': {'branch:to:call_model': '00000000000000000000000000000002.0.9300422176788571'}}, \n",
|
||||
" 'channel_values': {'messages': [HumanMessage(content=\"hi! I'm bob\"), AIMessage(content='Hi Bob! How are you doing today? Is there anything I can help you with?')]}\n",
|
||||
" 'channel_values': {'messages': [HumanMessage(content=\"hi! I'm bob\"), AIMessage(content='Hi Bob! How are you doing today? Is there anything I can help you with?')]}, \n",
|
||||
" 'pending_sends': []\n",
|
||||
" }, \n",
|
||||
" metadata={'source': 'loop', 'writes': {'call_model': {'messages': AIMessage(content='Hi Bob! How are you doing today? Is there anything I can help you with?')}}, 'step': 1, 'parents': {}, 'thread_id': '1'}, \n",
|
||||
" parent_config={...}, \n",
|
||||
@@ -911,7 +915,8 @@
|
||||
" 'id': '1f029ca3-0874-6612-8000-339f2abc83b1', \n",
|
||||
" 'channel_versions': {'__start__': '00000000000000000000000000000002.0.18673090920108737', 'messages': '00000000000000000000000000000002.0.30296526818059655', 'branch:to:call_model': '00000000000000000000000000000002.0.9300422176788571'}, \n",
|
||||
" 'versions_seen': {'__input__': {}, '__start__': {'__start__': '00000000000000000000000000000001.0.7040775356287469'}}, \n",
|
||||
" 'channel_values': {'messages': [HumanMessage(content=\"hi! I'm bob\")], 'branch:to:call_model': None}\n",
|
||||
" 'channel_values': {'messages': [HumanMessage(content=\"hi! I'm bob\")], 'branch:to:call_model': None}, \n",
|
||||
" 'pending_sends': []\n",
|
||||
" }, \n",
|
||||
" metadata={'source': 'loop', 'writes': None, 'step': 0, 'parents': {}, 'thread_id': '1'}, \n",
|
||||
" parent_config={...}, \n",
|
||||
@@ -925,7 +930,8 @@
|
||||
" 'id': '1f029ca3-0870-6ce2-bfff-1f3f14c3e565', \n",
|
||||
" 'channel_versions': {'__start__': '00000000000000000000000000000001.0.7040775356287469'}, \n",
|
||||
" 'versions_seen': {'__input__': {}}, \n",
|
||||
" 'channel_values': {'__start__': {'messages': [{'role': 'user', 'content': \"hi! I'm bob\"}]}}\n",
|
||||
" 'channel_values': {'__start__': {'messages': [{'role': 'user', 'content': \"hi! I'm bob\"}]}}, \n",
|
||||
" 'pending_sends': []\n",
|
||||
" }, \n",
|
||||
" metadata={'source': 'input', 'writes': {'__start__': {'messages': [{'role': 'user', 'content': \"hi! I'm bob\"}]}}, 'step': -1, 'parents': {}, 'thread_id': '1'}, \n",
|
||||
" parent_config=None, \n",
|
||||
@@ -1107,10 +1113,10 @@
|
||||
"source": [
|
||||
"### Use in production\n",
|
||||
"\n",
|
||||
"In production, you would want to use a store backed by a database:\n",
|
||||
"In production, you would want to use a checkpointer backed by a database:\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"from langgraph.store.postgres import PostgresStore\n",
|
||||
"from langgraph.checkpoint.postgres import PostgresSaver\n",
|
||||
"\n",
|
||||
"DB_URI = \"postgresql://postgres:postgres@localhost:5442/postgres?sslmode=disable\"\n",
|
||||
"# highlight-next-line\n",
|
||||
|
||||
@@ -321,7 +321,7 @@ attempts = 0
|
||||
# The default RetryPolicy is optimized for retrying specific network errors.
|
||||
retry_policy = RetryPolicy(retry_on=ValueError)
|
||||
|
||||
@task(retry_policy=retry_policy)
|
||||
@task(retry=retry_policy)
|
||||
def get_info():
|
||||
global attempts
|
||||
attempts += 1
|
||||
|
||||
@@ -1,149 +1,150 @@
|
||||
|
||||
# Guides
|
||||
|
||||
- [LangGraph Documentation](https://langchain-ai.github.io/langgraph/index/): This page provides an overview of the LangGraph project, including its logo and essential scripts for functionality within MkDocs. It also includes a reference to the README.md file for detailed information about the project. The content is designed to be user-friendly and visually appealing.
|
||||
- [LangGraph Quickstart Guide](https://langchain-ai.github.io/langgraph/agents/agents/): This quickstart guide provides step-by-step instructions for setting up and using LangGraph's prebuilt components to create agentic systems. It covers prerequisites, installation, agent creation, configuration of language models, and advanced features like memory and structured output. Ideal for developers looking to leverage LangGraph for building intelligent agents.
|
||||
- [Getting Started with LangGraph: Building AI Agents](https://langchain-ai.github.io/langgraph/concepts/why-langgraph/): This page provides an overview of LangGraph, a platform designed for developers to create adaptable AI agents. It highlights key features such as reliability, extensibility, and streaming support, and offers a series of tutorials to help users build a support chatbot with various capabilities. By following the tutorials, developers will learn to implement essential functionalities like conversation state management and human-in-the-loop controls.
|
||||
- [Building a Basic Chatbot with LangGraph](https://langchain-ai.github.io/langgraph/tutorials/get-started/1-build-basic-chatbot/): This tutorial guides you through the process of creating a basic chatbot using LangGraph. It covers prerequisites, installation of necessary packages, and step-by-step instructions to set up a state machine for the chatbot. By the end of the tutorial, you will have a functional chatbot that can engage in simple conversations.
|
||||
- [Integrating Web Search Tools into Your Chatbot](https://langchain-ai.github.io/langgraph/tutorials/get-started/2-add-tools/): This tutorial guides you through the process of enhancing your chatbot's capabilities by integrating a web search tool, specifically the Tavily Search Engine. It covers prerequisites, installation, configuration, and the implementation of the search tool within a LangGraph-based chatbot. By the end, you'll have a functional chatbot that can retrieve real-time information to answer user queries beyond its training data.
|
||||
- [Implementing Memory in Chatbots with LangGraph](https://langchain-ai.github.io/langgraph/tutorials/get-started/3-add-memory/): This page provides a comprehensive guide on how to add memory functionality to chatbots using LangGraph's persistent checkpointing feature. It details the steps to create a `MemorySaver` checkpointer, compile the graph, and interact with the chatbot to maintain context across multiple interactions. Additionally, it explains how to inspect the state of the chatbot and highlights the advantages of checkpointing over simple memory solutions.
|
||||
- [Implementing Human-in-the-Loop Controls in LangGraph](https://langchain-ai.github.io/langgraph/tutorials/get-started/4-human-in-the-loop/): This page provides a comprehensive guide on adding human-in-the-loop controls to LangGraph workflows, enabling agents to pause execution for human input. It details the use of the `interrupt` function to facilitate user feedback and outlines the steps to integrate a `human_assistance` tool into a chatbot. Additionally, the tutorial covers graph compilation, visualization, and resuming execution with human input.
|
||||
- [Customizing State in LangGraph for Enhanced Chatbot Functionality](https://langchain-ai.github.io/langgraph/tutorials/get-started/5-customize-state/): This tutorial guides you through the process of adding custom fields to the state in LangGraph, enabling complex behaviors in your chatbot without relying solely on message lists. You will learn how to implement human-in-the-loop controls to verify information before it is stored in the state. By the end of this tutorial, you will have a deeper understanding of state management and how to enhance your chatbot's capabilities.
|
||||
- [Implementing Time Travel in LangGraph Chatbots](https://langchain-ai.github.io/langgraph/tutorials/get-started/6-time-travel/): This page provides a comprehensive guide on utilizing the time travel functionality in LangGraph to enhance chatbot interactions. It covers how to rewind, add steps, and replay the state history of a chatbot, allowing users to explore different outcomes and fix mistakes. Additionally, it includes code snippets and practical examples to help developers implement these features effectively.
|
||||
- [LangGraph Deployment Options](https://langchain-ai.github.io/langgraph/tutorials/deployment/): This page outlines the various options available for deploying LangGraph applications, including local testing and different cloud-based solutions. It details free deployment methods such as Local and Standalone Container (Lite), as well as production options like Cloud SaaS and self-hosted solutions. Each deployment method is linked to further documentation for in-depth guidance.
|
||||
- [Agent Development with LangGraph](https://langchain-ai.github.io/langgraph/agents/overview/): This page provides an overview of agent development using LangGraph, highlighting its prebuilt components and capabilities for building agent-based applications. It explains the structure of an agent, key features such as memory integration and human-in-the-loop control, and outlines the package ecosystem available for developers. With LangGraph, users can focus on application logic while leveraging robust infrastructure for state management and feedback.
|
||||
- [Guide to Running Agents in LangGraph](https://langchain-ai.github.io/langgraph/agents/run_agents/): This page provides a comprehensive overview of how to execute agents in LangGraph, detailing both synchronous and asynchronous methods. It covers input and output formats, streaming capabilities, and how to manage execution limits to prevent infinite loops. Additionally, it includes code examples and links to further resources for deeper understanding.
|
||||
- [Streaming Data in LangGraph](https://langchain-ai.github.io/langgraph/agents/streaming/): This page provides an overview of streaming data types in LangGraph, including agent progress, LLM tokens, and custom updates. It includes code examples for both synchronous and asynchronous streaming methods. Additionally, it covers how to stream multiple modes and disable streaming when necessary.
|
||||
- [Configuring Chat Models for Agents](https://langchain-ai.github.io/langgraph/agents/models/): This page provides detailed instructions on how to configure various chat models for use with agents in LangChain. It covers model initialization, tool calling support, and how to specify models from different providers such as OpenAI, Anthropic, Azure, Google Gemini, and AWS Bedrock. Additionally, it includes information on disabling streaming, adding model fallbacks, and links to further resources.
|
||||
- [Using Tools in LangChain](https://langchain-ai.github.io/langgraph/agents/tools/): This page provides an overview of how to define, customize, and manage tools within the LangChain framework. It covers creating simple tools, handling tool errors, and utilizing prebuilt integrations for enhanced functionality. Additionally, it discusses advanced features such as memory management and controlling tool behavior during agent execution.
|
||||
- [Integrating MCP with LangGraph Agents](https://langchain-ai.github.io/langgraph/agents/mcp/): This page provides a comprehensive guide on how to integrate the Model Context Protocol (MCP) with LangGraph agents using the `langchain-mcp-adapters` library. It includes installation instructions, example code for using MCP tools, and guidance on creating custom MCP servers. Additional resources for further reading on MCP are also provided.
|
||||
- [Understanding Context in LangGraph Agents](https://langchain-ai.github.io/langgraph/agents/context/): This page provides an overview of how to supply context to agents in LangGraph, detailing the three primary types: Config, State, and Long-Term Memory. It explains how to use these context types to enhance agent behavior, customize prompts, and access context in tools. Additionally, it includes code examples for implementing context in various scenarios.
|
||||
- [Understanding Memory in LangGraph for Conversational Agents](https://langchain-ai.github.io/langgraph/agents/memory/): This documentation page provides an overview of the two types of memory supported by LangGraph: short-term and long-term memory. It explains how to implement these memory types in conversational agents, including code examples and best practices for managing message history. Additionally, it covers the use of persistent storage and tools for enhancing memory functionality.
|
||||
- [Implementing Human-in-the-Loop in LangGraph](https://langchain-ai.github.io/langgraph/agents/human-in-the-loop/): This documentation page provides a comprehensive guide on how to implement Human-in-the-Loop (HIL) features in LangGraph, allowing for human review and approval of tool calls in agents. It covers the use of the `interrupt()` function to pause execution for human input, along with practical examples and code snippets. Additionally, it explains how to create a wrapper to add HIL capabilities to any tool seamlessly.
|
||||
- [Building Multi-Agent Systems](https://langchain-ai.github.io/langgraph/agents/multi-agent/): This page provides an overview of multi-agent systems, detailing how to create and manage them using supervisor and swarm architectures. It includes practical examples of implementing a flight and hotel booking assistant using the LangGraph libraries. Additionally, the page explains the concept of handoffs between agents, allowing for seamless communication and task delegation.
|
||||
- [Evaluating Agent Performance with LangSmith](https://langchain-ai.github.io/langgraph/agents/evals/): This page provides a comprehensive guide on how to evaluate the performance of agents using the LangSmith evaluations framework. It includes instructions on defining evaluator functions, utilizing prebuilt evaluators from the AgentEvals package, and running evaluations with specific datasets. Additionally, it covers different evaluation techniques, including trajectory matching and using LLMs as judges.
|
||||
- [Deploying Your LangGraph Agent](https://langchain-ai.github.io/langgraph/agents/deployment/): This page provides a comprehensive guide on how to deploy a LangGraph agent, including setting up a LangGraph app for both local development and production. It covers essential features, installation steps, and configuration requirements, along with instructions for launching the local server and utilizing the LangGraph Studio Web UI for debugging. Additionally, it offers links to further resources for deployment options.
|
||||
- [Agent Chat UI Documentation](https://langchain-ai.github.io/langgraph/agents/ui/): This page provides comprehensive guidance on using the Agent Chat UI for interacting with LangGraph agents. It covers setup instructions, features like human-in-the-loop workflows, and the integration of generative UI components. Users can find links to relevant resources and tips for customizing their chat experience.
|
||||
- [Overview of Agent Architectures in LLM Applications](https://langchain-ai.github.io/langgraph/concepts/agentic_concepts/): This page provides a comprehensive overview of various agent architectures used in large language model (LLM) applications, highlighting their control flows and functionalities. It discusses key concepts such as routers, tool-calling agents, memory management, and planning, along with customization options for specific tasks. Additionally, it covers advanced features like human-in-the-loop, parallelization, subgraphs, and reflection mechanisms to enhance agent performance.
|
||||
- [Understanding Workflows and Agents in LangGraph](https://langchain-ai.github.io/langgraph/tutorials/workflows/): This documentation page provides an in-depth overview of workflows and agents within LangGraph, highlighting their differences and use cases. It covers various patterns for building agentic systems, including setup instructions, building blocks, and advanced concepts like prompt chaining, parallelization, and routing. Additionally, it offers practical examples and code snippets to help users implement these workflows effectively.
|
||||
- [Understanding LangGraph: Core Concepts and Components](https://langchain-ai.github.io/langgraph/concepts/low_level/): This documentation page provides an in-depth overview of the core concepts of LangGraph, focusing on how agent workflows are modeled as graphs. It covers essential components such as States, Nodes, and Edges, and explains how they interact to create complex workflows. Additionally, it discusses graph compilation, message handling, and configuration options to enhance the functionality of your graphs.
|
||||
- [LangGraph Runtime Overview](https://langchain-ai.github.io/langgraph/concepts/pregel/): This page provides a comprehensive overview of the LangGraph runtime, specifically focusing on the Pregel execution model. It details the structure and functionality of actors and channels within the Pregel framework, along with examples of how to implement applications. Additionally, it introduces high-level APIs for creating Pregel applications using StateGraph and Functional API.
|
||||
- [Using the LangGraph API: A Comprehensive Guide](https://langchain-ai.github.io/langgraph/how-tos/graph-api/): This documentation provides a detailed overview of how to utilize the LangGraph Graph API, covering essential concepts such as state management, node creation, and control flow. It includes practical examples for building sequences, branches, and loops, as well as advanced features like retry policies and async execution. Additionally, the guide offers insights into visualizing graphs and integrating with external tools.
|
||||
- [LangGraph Streaming System](https://langchain-ai.github.io/langgraph/concepts/streaming/): This page provides an overview of the streaming capabilities of LangGraph, enabling real-time updates for enhanced user experiences. It details the types of data that can be streamed, including workflow progress, LLM tokens, and custom updates. Additionally, it outlines various functionalities and modes available for streaming within the LangGraph framework.
|
||||
- [Streaming Outputs in LangGraph](https://langchain-ai.github.io/langgraph/how-tos/streaming/): This documentation page provides an overview of how to utilize the streaming capabilities of LangGraph, including synchronous and asynchronous streaming methods. It covers various stream modes, such as updates, values, and custom data, along with examples of how to implement them in your graphs. Additionally, it discusses the integration of Large Language Models (LLMs) and how to handle streaming outputs effectively.
|
||||
- [LangGraph Persistence and Checkpointing](https://langchain-ai.github.io/langgraph/concepts/persistence/): This page provides an in-depth overview of the persistence layer in LangGraph, focusing on the use of checkpointers to save graph states at each super-step. It covers key concepts such as threads, checkpoints, state retrieval, and memory management, along with practical examples and code snippets. Additionally, it discusses advanced features like time travel, fault tolerance, and the integration of memory stores for cross-thread information retention.
|
||||
- [Understanding Durable Execution in LangGraph](https://langchain-ai.github.io/langgraph/concepts/durable_execution/): This page provides an overview of durable execution, a technique that allows workflows to save their progress and resume from key points. It details the requirements for implementing durable execution in LangGraph, including the use of persistence and tasks to ensure deterministic and consistent replay. Additionally, it covers how to handle pausing, resuming, and recovering workflows effectively.
|
||||
- [Implementing Memory in LangGraph for AI Applications](https://langchain-ai.github.io/langgraph/how-tos/persistence/): This documentation page provides a comprehensive guide on adding persistence to AI applications using LangGraph. It covers both short-term and long-term memory implementations, including code examples for managing conversation context and user-specific data. Additionally, it discusses the use of various storage backends and semantic search capabilities for enhanced memory management.
|
||||
- [Understanding Memory in AI Agents](https://langchain-ai.github.io/langgraph/concepts/memory/): This documentation page provides an in-depth overview of memory types in AI agents, focusing on short-term and long-term memory. It explains how these memory types can be implemented and managed within applications using LangGraph, including techniques for handling conversation history and storing memories. Additionally, it discusses the importance of memory in enhancing user interactions and the various strategies for writing and updating memories.
|
||||
- [Memory Management in LangGraph for AI Applications](https://langchain-ai.github.io/langgraph/how-tos/memory/): This page provides an overview of memory management in LangGraph, focusing on short-term and long-term memory functionalities essential for conversational agents. It includes detailed instructions on how to implement memory strategies such as trimming, summarizing, and deleting messages to optimize conversation tracking without exceeding context limits. Code examples are provided to illustrate the implementation of these memory management techniques.
|
||||
- [Human-in-the-Loop Workflows in LangGraph](https://langchain-ai.github.io/langgraph/concepts/human_in_the_loop/): This page provides an overview of the human-in-the-loop (HIL) capabilities within LangGraph, highlighting how human intervention can enhance automated processes. It details key features such as persistent execution state and flexible integration points, along with typical use cases for validating outputs and providing context. Additionally, it outlines the implementation of HIL through specific functions and primitives.
|
||||
- [Implementing Human-in-the-Loop Workflows with Interrupts](https://langchain-ai.github.io/langgraph/how-tos/human_in_the_loop/add-human-in-the-loop/): This documentation page provides a comprehensive guide on using the `interrupt` function in LangGraph to facilitate human-in-the-loop workflows. It covers the implementation details, design patterns, and best practices for pausing graph execution to gather human input, as well as how to resume execution with that input. Additionally, it highlights common pitfalls and offers extended examples to illustrate various use cases.
|
||||
- [Understanding Breakpoints in LangGraph](https://langchain-ai.github.io/langgraph/concepts/breakpoints/): This page provides an overview of breakpoints in LangGraph, which allow users to pause graph execution at specific points for inspection. It explains how breakpoints utilize the persistence layer to save the graph state and how execution can be resumed after inspection. An illustrative example is included to demonstrate the concept visually.
|
||||
- [Using Breakpoints in Graph Execution](https://langchain-ai.github.io/langgraph/how-tos/human_in_the_loop/breakpoints/): This page provides a comprehensive guide on how to implement breakpoints in graph execution for debugging purposes. It covers the requirements for setting breakpoints, the difference between static and dynamic breakpoints, and includes code examples for both compile-time and run-time configurations. Additionally, it explains how to manage breakpoints in subgraphs.
|
||||
- [Time Travel Functionality in LangGraph](https://langchain-ai.github.io/langgraph/concepts/time-travel/): This page explains the time travel feature in LangGraph, which allows users to analyze and debug decision-making processes in non-deterministic systems. It outlines how to understand reasoning, debug mistakes, and explore alternative solutions by resuming execution from prior checkpoints. The functionality enables users to create new forks in the execution history for deeper insights.
|
||||
- [Using Time-Travel in LangGraph](https://langchain-ai.github.io/langgraph/how-tos/human_in_the_loop/time-travel/): This page provides a comprehensive guide on how to implement time-travel functionality in LangGraph. It outlines the steps to run a graph, identify checkpoints, modify graph states, and resume execution from specific checkpoints. Additionally, an example workflow is included to illustrate the process of generating and modifying jokes using LangGraph.
|
||||
- [Integrating Tools with AI Models](https://langchain-ai.github.io/langgraph/concepts/tools/): This page provides an overview of how AI models can interact with external systems using tool calling. It explains the concept of tools, their integration with chat models, and how to create or use prebuilt tools for various applications. Additionally, it highlights the importance of relevance in tool invocation and offers links to further resources and guides.
|
||||
- [Using Tools in LangChain](https://langchain-ai.github.io/langgraph/how-tos/tool-calling/): This documentation page provides a comprehensive guide on how to create and utilize tools within the LangChain framework. It covers defining simple and customized tools, managing tool arguments, accessing configuration and state, and integrating tools with chat models and agents. Additionally, it discusses error handling and strategies for managing a large number of tools.
|
||||
- [Understanding Subgraphs in LangGraph](https://langchain-ai.github.io/langgraph/concepts/subgraphs/): This page provides an overview of subgraphs in LangGraph, explaining their role as encapsulated nodes within larger graphs. It discusses the benefits of using subgraphs, such as facilitating multi-agent systems and enabling independent team work. Additionally, it outlines the communication methods between parent graphs and subgraphs, detailing scenarios involving shared and different state schemas.
|
||||
- [Using Subgraphs in LangGraph](https://langchain-ai.github.io/langgraph/how-tos/subgraph/): This guide provides an overview of how to effectively use subgraphs within LangGraph, including communication methods between parent graphs and subgraphs. It covers shared and different state schemas, setup instructions, and examples for implementing subgraphs in multi-agent systems. Additionally, it discusses persistence, state management, and streaming outputs from subgraphs.
|
||||
- [Understanding Multi-Agent Systems](https://langchain-ai.github.io/langgraph/concepts/multi_agent/): This page provides an in-depth overview of multi-agent systems, focusing on the architecture and benefits of using multiple independent agents to manage complex applications. It discusses various multi-agent architectures, including network, supervisor, and hierarchical models, as well as communication strategies and state management techniques for effective agent interaction.
|
||||
- [Building Multi-Agent Systems with LangGraph](https://langchain-ai.github.io/langgraph/how-tos/multi_agent/): This guide provides an overview of how to build multi-agent systems using LangGraph, focusing on the implementation of handoffs for agent communication. It covers the creation of independent agents, the use of handoffs to transfer control and data between agents, and examples of prebuilt multi-agent architectures. Additionally, it includes code snippets and best practices for managing agent interactions and state.
|
||||
- [Understanding the Functional API in LangGraph](https://langchain-ai.github.io/langgraph/concepts/functional_api/): This documentation page provides an overview of the Functional API in LangGraph, detailing its key features such as persistence, memory, and human-in-the-loop capabilities. It explains how to define workflows using the `@entrypoint` and `@task` decorators, along with examples and best practices for implementing workflows with state management and streaming. Additionally, it compares the Functional API with the Graph API, highlighting their differences and use cases.
|
||||
- [Functional API Documentation](https://langchain-ai.github.io/langgraph/how-tos/use-functional-api/): This page provides comprehensive guidance on using the Functional API, including creating workflows, handling parallel execution, and integrating with other APIs. It covers various features such as retry policies, caching, and human-in-the-loop workflows, along with practical examples. Additionally, it discusses memory management strategies for both short-term and long-term use cases.
|
||||
- [Overview of LangGraph Platform](https://langchain-ai.github.io/langgraph/concepts/langgraph_platform/): The LangGraph Platform is designed for developing, deploying, and managing long-running agent workflows with ease. This page outlines the platform's features, including streaming support, background runs, and memory management, which enhance the performance and reliability of agent applications. Additionally, it provides links to resources for getting started and deploying agents effectively.
|
||||
- [LangGraph Platform Quickstart Guide](https://langchain-ai.github.io/langgraph/tutorials/langgraph-platform/local-server/): This quickstart guide provides step-by-step instructions for running a LangGraph application locally. It covers prerequisites, installation of the LangGraph CLI, app creation, dependency installation, and launching the server. Additionally, it includes testing your application using the LangGraph Studio and API.
|
||||
- [LangGraph Platform Deployment Quickstart](https://langchain-ai.github.io/langgraph/cloud/quick_start/): This quickstart guide provides step-by-step instructions for deploying an application on the LangGraph Platform using GitHub. It covers prerequisites, repository creation, deployment procedures, and testing your application and API. Follow these steps to successfully set up and run your application in the LangGraph environment.
|
||||
- [Overview of LangGraph Platform Components](https://langchain-ai.github.io/langgraph/concepts/langgraph_components/): This page provides a comprehensive overview of the various components that make up the LangGraph Platform. It details the functionalities of each component, including the LangGraph Server, CLI, Studio, SDKs, and the control and data planes. Users can learn how these components work together to facilitate the development, deployment, and management of LangGraph applications.
|
||||
- [LangGraph Server Documentation](https://langchain-ai.github.io/langgraph/concepts/langgraph_server/): This page provides an overview of the LangGraph Server, an API designed for creating and managing agent-based applications. It details the server versions, application structure, deployment components, and the use of assistants, persistence, and task queues. Additionally, it includes links to further resources and guides for effective deployment and usage.
|
||||
- [LangGraph Application Structure Guide](https://langchain-ai.github.io/langgraph/concepts/application_structure/): This page provides an overview of the structure of a LangGraph application, detailing the essential components such as the configuration file, dependencies, graphs, and environment variables. It includes examples of directory structures for both Python and JavaScript applications, as well as guidance on how to specify the necessary information for deployment. Additionally, it covers key concepts related to the configuration file and the role of dependencies and environment variables in the application.
|
||||
- [Setting Up a LangGraph Application with requirements.txt](https://langchain-ai.github.io/langgraph/cloud/deployment/setup/): This guide provides step-by-step instructions for configuring a LangGraph application for deployment using a requirements.txt file to manage dependencies. It covers essential topics such as specifying dependencies, defining environment variables, and creating the LangGraph configuration file. Additionally, it includes examples and tips for alternative setup methods.
|
||||
- [Setting Up a LangGraph Application with pyproject.toml](https://langchain-ai.github.io/langgraph/cloud/deployment/setup_pyproject/): This guide provides step-by-step instructions for configuring a LangGraph application using the `pyproject.toml` file for dependency management. It covers the necessary components, including specifying dependencies, environment variables, and defining graphs, along with examples and best practices. Additionally, it offers tips for alternative setups and links to further resources for deployment.
|
||||
- [Setting Up a LangGraph.js Application](https://langchain-ai.github.io/langgraph/cloud/deployment/setup_javascript/): This guide provides step-by-step instructions for configuring a LangGraph.js application for deployment on the LangGraph Platform or for self-hosting. It covers essential topics such as specifying dependencies, environment variables, defining graphs, and creating the necessary configuration file. By following this walkthrough, users will learn how to structure their application and prepare it for deployment.
|
||||
- [Customizing Your Dockerfile in LangGraph](https://langchain-ai.github.io/langgraph/cloud/deployment/custom_docker/): This page provides a guide on how to customize your Dockerfile by adding additional commands through the `langgraph.json` configuration file. It explains how to specify the `dockerfile_lines` key to include necessary dependencies, such as installing system packages and Python libraries. An example is provided to illustrate the process of integrating the Pillow library for image processing.
|
||||
- [LangGraph CLI Documentation](https://langchain-ai.github.io/langgraph/concepts/langgraph_cli/): This page provides an overview of the LangGraph CLI, a command-line tool for building and running the LangGraph API server locally. It includes installation instructions, a list of core commands, and their descriptions to help users effectively utilize the CLI for development and deployment. For further details, users can refer to the LangGraph CLI Reference.
|
||||
- [LangGraph Studio Documentation](https://langchain-ai.github.io/langgraph/concepts/langgraph_studio/): This page provides an overview of LangGraph Studio, an IDE for visualizing, interacting with, and debugging agentic systems that utilize the LangGraph Server API. It outlines the prerequisites for using the studio, key features, and the two operational modes: Graph mode and Chat mode. Additionally, it includes links to further resources for getting started with LangGraph Studio.
|
||||
- [Getting Started with LangGraph Studio](https://langchain-ai.github.io/langgraph/cloud/how-tos/studio/quick_start/): This page provides a comprehensive guide on how to connect and use LangGraph Studio with both deployed applications on the LangGraph Platform and local development servers. It includes instructions for installation, running the server, accessing the Studio UI, and debugging options. Additionally, troubleshooting tips and next steps for further exploration of LangGraph Studio features are also provided.
|
||||
- [Running Applications: A Comprehensive Guide](https://langchain-ai.github.io/langgraph/cloud/how-tos/invoke_studio/): This page provides a detailed guide on how to submit a run to your application, covering both Graph and Chat modes. It includes instructions on specifying input, managing assistants, enabling streaming, and using breakpoints. Additionally, it offers tips for running applications from specific checkpoints in existing threads.
|
||||
- [Managing Assistants in LangGraph Studio](https://langchain-ai.github.io/langgraph/cloud/how-tos/studio/manage_assistants/): This page provides guidance on how to manage assistants within LangGraph Studio, including viewing, editing, and updating assistant configurations. It covers both Graph mode and Chat mode, detailing how to activate assistants and make changes to their settings. Users will learn how to navigate the interface to effectively manage their assistant configurations for graph runs.
|
||||
- [Managing Threads in Studio](https://langchain-ai.github.io/langgraph/cloud/how-tos/threads_studio/): This page provides a comprehensive guide on how to view and edit threads within the Studio application. It covers both Graph and Chat modes, detailing the steps to create new threads, view thread history, and edit thread states. Additionally, it includes links to related concepts for further learning.
|
||||
- [Modifying Prompts in LangGraph Studio](https://langchain-ai.github.io/langgraph/cloud/how-tos/iterate_graph_studio/): This page provides guidance on how to modify prompts within LangGraph Studio using two methods: direct node editing and the LangSmith Playground interface. It details the configuration options available for nodes, including `langgraph_nodes` and `langgraph_type`, along with examples for both Pydantic models and dataclasses. Additionally, it outlines the steps for editing prompts in the UI and utilizing the LangSmith Playground for testing LLM calls.
|
||||
- [Debugging LangSmith Traces in LangGraph Studio](https://langchain-ai.github.io/langgraph/cloud/how-tos/clone_traces_studio/): This guide provides step-by-step instructions for opening and debugging LangSmith traces in LangGraph Studio. It covers how to deploy threads and test local agents with remote traces, ensuring a seamless debugging experience. Additionally, it outlines the requirements for local agents and the process for cloning threads for local testing.
|
||||
- [How to Add Nodes to LangSmith Datasets](https://langchain-ai.github.io/langgraph/cloud/how-tos/datasets_studio/): This guide provides step-by-step instructions on how to add examples from nodes in the thread log to LangSmith datasets. It covers selecting threads, choosing nodes, and editing inputs/outputs before adding them to the dataset. Additionally, it includes links to further resources on evaluating intermediate steps.
|
||||
- [LangGraph SDK Documentation](https://langchain-ai.github.io/langgraph/concepts/sdk/): This page provides an overview of the LangGraph SDK, including installation instructions for both Python and JavaScript. It details the synchronous and asynchronous client options available for interacting with the LangGraph Server. Additionally, it offers links to further resources and references for the SDK.
|
||||
- [Integrating Semantic Search in LangGraph](https://langchain-ai.github.io/langgraph/cloud/deployment/semantic_search/): This guide provides step-by-step instructions on how to implement semantic search in your LangGraph deployment. It covers prerequisites, configuration of the store, and usage examples for searching memories and documents by semantic similarity. Additionally, it includes information on using custom embeddings and querying via the LangGraph SDK.
|
||||
- [Configuring Time-to-Live (TTL) in LangGraph Applications](https://langchain-ai.github.io/langgraph/how-tos/ttl/configure_ttl/): This guide provides detailed instructions on how to configure Time-to-Live (TTL) settings for checkpoints and store items in LangGraph applications. It covers the necessary configurations in the `langgraph.json` file, including strategies for managing data lifecycle and memory. Additionally, it explains how to combine TTL configurations and override them at runtime.
|
||||
- [LangGraph Authentication & Access Control Overview](https://langchain-ai.github.io/langgraph/concepts/auth/): This page provides a comprehensive guide to the authentication and authorization mechanisms within the LangGraph Platform. It explains the core concepts of authentication versus authorization, outlines default security models, and details the system architecture involved in user identity management. Additionally, it covers implementation examples for authentication and authorization handlers, along with common access patterns and supported resources.
|
||||
- [Custom Authentication Setup for LangGraph Platform](https://langchain-ai.github.io/langgraph/how-tos/auth/custom_auth/): This guide provides step-by-step instructions on how to implement custom authentication in your LangGraph Platform application. It covers the necessary prerequisites, implementation details, configuration updates, and client connection methods. The guide is applicable to both managed and Enterprise self-hosted deployments, but not to Lite self-hosted plans.
|
||||
- [Documenting API Authentication in OpenAPI for LangGraph](https://langchain-ai.github.io/langgraph/how-tos/auth/openapi_security/): This guide provides instructions on how to customize the security schema for your LangGraph Platform API documentation using OpenAPI. It covers default security schemes for both LangGraph Platform and self-hosted deployments, as well as how to implement custom authentication. Additionally, it includes examples for OAuth2 and API key authentication, along with testing procedures.
|
||||
- [Managing Assistants in LangGraph](https://langchain-ai.github.io/langgraph/concepts/assistants/): This page provides an overview of how to create and manage assistants within the LangGraph Platform, which allows for separate configuration of agents without altering the core graph logic. It covers the prerequisites, configuration options, and versioning of assistants, highlighting their role in optimizing agent performance for different tasks. Additionally, it includes links to relevant API references and how-to guides for further assistance.
|
||||
- [Managing Assistants in LangGraph](https://langchain-ai.github.io/langgraph/cloud/how-tos/configuration_cloud/): This documentation page provides a comprehensive guide on how to create, configure, and manage assistants using the LangGraph SDK and Platform UI. It includes code examples in Python and JavaScript, as well as instructions for creating new versions and using previous versions of assistants. Additionally, it covers the process of utilizing assistants in various environments.
|
||||
- [Understanding Threads in LangGraph](https://langchain-ai.github.io/langgraph/cloud/concepts/threads/): This page provides an overview of threads in the LangGraph framework, detailing how they accumulate the state of runs and the importance of checkpoints. It explains the process of creating threads and retrieving their current and historical states. Additionally, it offers links to further resources on threads, checkpoints, and the LangGraph API for managing thread states.
|
||||
- [Managing Threads in LangGraph](https://langchain-ai.github.io/langgraph/cloud/how-tos/use_threads/): This documentation page provides a comprehensive guide on how to create, view, and inspect threads using the LangGraph SDK. It includes detailed instructions for creating empty threads, copying existing threads, and initializing threads with prepopulated states. Additionally, it covers how to list and inspect threads, including filtering and sorting options.
|
||||
- [Understanding Runs in LangGraph Platform](https://langchain-ai.github.io/langgraph/cloud/concepts/runs/): This page provides an overview of what constitutes a run in the LangGraph Platform, including its input, configuration, and metadata. It also highlights the ability to execute runs on threads and offers links to the API reference for managing runs.
|
||||
- [Starting Background Runs for Your Agent](https://langchain-ai.github.io/langgraph/cloud/how-tos/background_run/): This guide provides step-by-step instructions on how to initiate background runs for your agent using Python, JavaScript, and CURL. It covers the setup process, checking current runs, starting new runs, and retrieving the final results. By following this documentation, users can efficiently manage long-running jobs within their applications.
|
||||
- [Running Multiple Agents on the Same Thread in LangGraph](https://langchain-ai.github.io/langgraph/cloud/how-tos/same-thread/): This documentation page explains how to run multiple agents on the same thread using the LangGraph Platform. It provides step-by-step examples in Python, JavaScript, and CURL to create agents, run them on a thread, and demonstrate how the second agent can utilize the context from the first agent's responses. By following the examples, users can learn to effectively manage multiple agents and their interactions.
|
||||
- [Scheduling Cron Jobs with LangGraph](https://langchain-ai.github.io/langgraph/cloud/how-tos/cron_jobs/): This page provides a comprehensive guide on how to schedule cron jobs using the LangGraph Platform. It includes setup instructions for different programming languages, examples of creating and deleting cron jobs, and details on managing stateless cron jobs. Users will learn how to automate tasks such as sending weekly emails without writing custom scripts.
|
||||
- [Guide to Stateless Runs in LangGraph](https://langchain-ai.github.io/langgraph/cloud/how-tos/stateless_runs/): This page provides a comprehensive guide on how to implement stateless runs using the LangGraph Platform. It includes setup instructions for various programming languages, examples of streaming results, and methods for waiting for stateless results. Users will learn how to execute runs without maintaining persistent state, making their applications more efficient.
|
||||
- [Configurable Headers in LangGraph](https://langchain-ai.github.io/langgraph/cloud/how-tos/configurable_headers/): This page provides guidance on how to configure headers dynamically in the LangGraph platform to modify agent behavior and permissions. It details how to include or exclude specific headers in the runtime configuration using the `langgraph.json` file. Additionally, it explains how to access these headers within your graph and offers an option to opt-out of configurable headers.
|
||||
- [Streaming in LangGraph Platform](https://langchain-ai.github.io/langgraph/cloud/concepts/streaming/): This page provides an overview of streaming capabilities within the LangGraph Platform, detailing the various streaming modes available for LLM applications. It includes instructions for creating streaming runs, handling stateless runs, and joining active background runs. Additionally, code examples in Python, JavaScript, and cURL are provided to illustrate the implementation of these features.
|
||||
- [Streaming Outputs with LangGraph SDK](https://langchain-ai.github.io/langgraph/cloud/how-tos/streaming/): This documentation page provides detailed instructions on how to stream outputs from the LangGraph API server using the LangGraph SDK in Python, JavaScript, and cURL. It covers various streaming modes, including updates, values, and custom data, along with examples for each mode. Additionally, it explains how to handle subgraphs, debug information, and LLM tokens during streaming.
|
||||
- [Human-in-the-Loop Workflows in LangGraph](https://langchain-ai.github.io/langgraph/cloud/how-tos/add-human-in-the-loop/): This page provides an overview of the human-in-the-loop (HIL) capabilities in LangGraph, allowing for human intervention in automated processes. It details the `interrupt` function, which pauses execution for human input, and includes examples in Python, JavaScript, and cURL for implementing HIL workflows. Additionally, it links to further resources for understanding and utilizing HIL features effectively.
|
||||
- [Using Breakpoints in LangGraph](https://langchain-ai.github.io/langgraph/cloud/how-tos/human_in_the_loop_breakpoint/): This page provides an overview of how to set and use breakpoints in LangGraph to pause graph execution for inspection. It includes examples for setting breakpoints at compile time and run time in Python, JavaScript, and cURL. Additionally, it offers guidance on resuming execution after hitting a breakpoint.
|
||||
- [Using Time Travel in LangGraph](https://langchain-ai.github.io/langgraph/cloud/how-tos/human_in_the_loop_time_travel/): This page provides a comprehensive guide on how to utilize the time travel functionality in LangGraph, allowing users to resume execution from previous checkpoints. It outlines the steps to run a graph, identify checkpoints, modify graph states, and resume execution. Additionally, the page includes code examples in Python, JavaScript, and cURL for practical implementation.
|
||||
- [Model Context Protocol (MCP) Endpoint Documentation](https://langchain-ai.github.io/langgraph/concepts/server-mcp/): This page provides comprehensive documentation on the Model Context Protocol (MCP) endpoint available in LangGraph Server. It covers the requirements for using MCP, how to expose agents as MCP tools, and includes examples for connecting with MCP-compliant clients in various programming languages. Additionally, it outlines session behavior, authentication, and instructions for disabling the MCP endpoint.
|
||||
- [Managing Double Texting in LangGraph](https://langchain-ai.github.io/langgraph/concepts/double_texting/): This page provides an overview of how to handle double texting scenarios in LangGraph, where users may send multiple messages before the first has completed. It outlines four strategies: Reject, Enqueue, Interrupt, and Rollback, each with links to detailed configuration guides. Prerequisites for implementing these strategies include having the LangGraph Server set up.
|
||||
- [Using the Interrupt Option in Double Texting](https://langchain-ai.github.io/langgraph/cloud/how-tos/interrupt_concurrent/): This guide provides detailed instructions on how to utilize the `interrupt` option for double texting, allowing users to interrupt a prior run of a graph and start a new one. It includes setup instructions, code examples in Python, JavaScript, and CURL, as well as guidance on viewing run results and verifying the status of interrupted runs. Familiarity with double texting is assumed, and a link to a conceptual guide is provided for further understanding.
|
||||
- [Using the Rollback Option in Double Texting](https://langchain-ai.github.io/langgraph/cloud/how-tos/rollback_concurrent/): This guide provides detailed instructions on how to utilize the `rollback` option in double texting, which allows users to interrupt a previous run and start a new one while permanently deleting the prior run from the database. It includes setup instructions, code examples in Python, JavaScript, and CURL, and demonstrates how to view run results and verify the deletion of the original run. Familiarity with double texting is assumed, and a link to a conceptual guide is provided for further reading.
|
||||
- [Using the Reject Option in Double Texting](https://langchain-ai.github.io/langgraph/cloud/how-tos/reject_concurrent/): This guide provides an overview of the `reject` option in double texting, which prevents new runs of a graph from starting while an original run is still in progress. It includes setup instructions, code examples in Python, JavaScript, and CURL, and demonstrates how to handle errors when attempting to create concurrent runs. Additionally, it shows how to view the results of the original run after the rejection.
|
||||
- [Using the Enqueue Option for Double Texting](https://langchain-ai.github.io/langgraph/cloud/how-tos/enqueue_concurrent/): This guide provides an overview of the `enqueue` option for double texting, which allows interruptions to be queued and executed in the order they are received. It includes setup instructions, code examples in Python, JavaScript, and CURL for creating runs, and methods for viewing run results. Familiarity with double texting concepts is assumed, and a helper function for output formatting is also provided.
|
||||
- [Understanding Webhooks in LangGraph Platform](https://langchain-ai.github.io/langgraph/cloud/concepts/webhooks/): This page provides an overview of webhooks and their role in enabling event-driven communication between LangGraph Platform applications and external services. It explains how to use the `webhook` parameter in various endpoints to trigger requests upon the completion of API calls. For further details, a link to a comprehensive how-to guide is also included.
|
||||
- [Using Webhooks with LangGraph Platform](https://langchain-ai.github.io/langgraph/cloud/how-tos/webhooks/): This documentation page provides a comprehensive guide on how to implement webhooks in the LangGraph Platform to receive updates after API calls. It includes details on supported endpoints, setup instructions for different programming languages, and examples of how to specify webhook parameters in API requests. Additionally, it covers security measures and testing tools for verifying webhook functionality.
|
||||
- [Scheduling Tasks with Cron Jobs on LangGraph Platform](https://langchain-ai.github.io/langgraph/cloud/concepts/cron_jobs/): This page provides an overview of how to use cron jobs on the LangGraph Platform to run assistants on a defined schedule. It explains the process of setting up a cron job, including specifying the schedule, assistant, and input. Additionally, it includes links to a how-to guide and API reference for further details.
|
||||
- [Scheduling Cron Jobs with LangGraph](https://langchain-ai.github.io/langgraph/cloud/how-tos/cron_jobs/): This page provides a comprehensive guide on how to use cron jobs with the LangGraph Platform to automate graph executions on a schedule. It includes setup instructions for various programming languages, examples of creating and deleting cron jobs, and tips for managing stateless cron jobs. Users will learn how to efficiently schedule tasks without manual intervention, ensuring timely execution of automated processes.
|
||||
- [Adding Custom Lifespan Events in LangGraph](https://langchain-ai.github.io/langgraph/how-tos/http/custom_lifespan/): This page provides a guide on how to implement custom lifespan events in your LangGraph Platform applications, specifically for Python deployments. It covers the initialization and cleanup of resources during server startup and shutdown using FastAPI. Additionally, it includes code examples and configuration steps to help you integrate these events into your application.
|
||||
- [Adding Custom Middleware to LangGraph Platform](https://langchain-ai.github.io/langgraph/how-tos/http/custom_middleware/): This page provides a step-by-step guide on how to add custom middleware to your server when deploying agents to the LangGraph Platform. It covers the necessary code implementation using FastAPI, configuration settings in `langgraph.json`, and instructions for testing and deploying your application. Additionally, it offers links to related topics such as custom routes and lifespan events for further customization.
|
||||
- [Adding Custom Routes in LangGraph](https://langchain-ai.github.io/langgraph/how-tos/http/custom_routes/): This page provides a step-by-step guide on how to add custom routes to your LangGraph platform application using a Starlette or FastAPI app. It includes instructions for creating a new app, configuring the `langgraph.json` file, and testing the server locally. Additionally, it explains how custom routes can override default endpoints and offers suggestions for further customization.
|
||||
- [LangGraph Deployment Options](https://langchain-ai.github.io/langgraph/concepts/deployment_options/): This page outlines the various deployment options available for the LangGraph Platform, including Cloud SaaS, Self-Hosted Data Plane, Self-Hosted Control Plane, and Standalone Container. Each option is described in detail, highlighting key features, management responsibilities, and compatibility. A comparison table is also provided to help users choose the best deployment strategy for their needs.
|
||||
- [LangGraph Data Plane Overview](https://langchain-ai.github.io/langgraph/concepts/langgraph_data_plane/): This page provides a comprehensive overview of the LangGraph Data Plane, detailing its components including the server infrastructure, listener application, and data management systems like Postgres and Redis. It also covers key features such as autoscaling, static IP addresses, and custom configurations for Postgres and Redis. Additionally, the page outlines telemetry, licensing, and tracing functionalities relevant to different deployment options.
|
||||
- [LangGraph Control Plane Overview](https://langchain-ai.github.io/langgraph/concepts/langgraph_control_plane/): This page provides a comprehensive overview of the LangGraph Control Plane, detailing its UI and API functionalities for managing LangGraph Servers. It covers deployment types, environment variables, database provisioning, and asynchronous deployment processes. Additionally, it highlights the integration with LangSmith for tracing projects.
|
||||
- [Cloud SaaS Deployment Guide](https://langchain-ai.github.io/langgraph/concepts/langgraph_cloud/): This page provides a comprehensive guide on deploying the LangGraph Server using the Cloud SaaS model. It outlines the roles of the control plane and data plane, detailing their functionalities and management. Additionally, it includes an architectural diagram to illustrate the deployment structure.
|
||||
- [Deployment Guide for LangGraph Platform](https://langchain-ai.github.io/langgraph/cloud/deployment/cloud/): This page provides a comprehensive guide on how to deploy applications to the LangGraph Platform using GitHub repositories. It covers prerequisites, steps for creating new deployments and revisions, managing deployment settings, and viewing logs. Additionally, it includes instructions for whitelisting IP addresses and modifying GitHub repository access.
|
||||
- [Self-Hosted Data Plane Deployment Guide](https://langchain-ai.github.io/langgraph/concepts/langgraph_self_hosted_data_plane/): This page provides an overview of the Self-Hosted Data Plane deployment option, which allows users to manage their data plane infrastructure while offloading control plane management to LangChain. It outlines the requirements, architecture, and supported compute platforms for deployment. Additionally, it includes important information regarding the beta status of this deployment option.
|
||||
- [Deploying a Self-Hosted Data Plane](https://langchain-ai.github.io/langgraph/cloud/deployment/self_hosted_data_plane/): This page provides a comprehensive guide on deploying a Self-Hosted Data Plane using Kubernetes and Amazon ECS. It outlines the prerequisites, setup steps, and configuration details necessary for a successful deployment. Additionally, it highlights the current beta status of this deployment option.
|
||||
- [Self-Hosted Control Plane Deployment Guide](https://langchain-ai.github.io/langgraph/concepts/langgraph_self_hosted_control_plane/): This page provides an overview of the Self-Hosted Control Plane deployment option, currently in beta. It outlines the requirements, architecture, and compute platforms supported for deploying the control and data planes in your cloud environment. Additionally, it includes important links and resources for managing your self-hosted infrastructure.
|
||||
- [Deploying a Self-Hosted Control Plane](https://langchain-ai.github.io/langgraph/cloud/deployment/self_hosted_control_plane/): This page provides a comprehensive guide on deploying a Self-Hosted Control Plane using Kubernetes. It outlines the prerequisites, setup steps, and configuration details necessary for a successful deployment. Additionally, it highlights the beta status of this deployment option and includes links to relevant resources for further assistance.
|
||||
- [Deploying LangGraph Server with Standalone Container](https://langchain-ai.github.io/langgraph/concepts/langgraph_standalone_container/): This page provides a comprehensive guide on deploying a LangGraph Server using the Standalone Container option. It outlines the architecture, supported compute platforms, and differences between Lite and Enterprise server versions. Users will find essential information on managing the data plane infrastructure without a control plane.
|
||||
- [Deploying a Standalone Container with LangGraph](https://langchain-ai.github.io/langgraph/cloud/deployment/standalone_container/): This documentation provides a comprehensive guide on deploying a standalone container for the LangGraph application. It covers prerequisites, environment variable configurations, and deployment methods using Docker and Docker Compose. Additionally, it includes instructions for deploying on Kubernetes using Helm.
|
||||
- [Scalability and Resilience of LangGraph Platform](https://langchain-ai.github.io/langgraph/concepts/scalability_and_resilience/): This page provides an overview of the scalability and resilience features of the LangGraph Platform. It details how the platform handles server and queue scalability, as well as the mechanisms in place for ensuring resilience during both graceful and hard shutdowns. Additionally, it covers the resilience strategies employed for Postgres and Redis to maintain service availability.
|
||||
- [LangGraph Platform Plans Overview](https://langchain-ai.github.io/langgraph/concepts/plans/): This page provides an overview of the different plans available for the LangGraph Platform, including Developer, Plus, and Enterprise options. Each plan offers varying deployment options, usage limits, and features tailored to different user needs. For detailed pricing and related resources, links to additional documentation are also included.
|
||||
- [index.md (index.md)](https://langchain-ai.github.io/langgraph/index/)
|
||||
- [Quickstart (Get started > Quickstart)](https://langchain-ai.github.io/langgraph/agents/agents/)
|
||||
- [concepts/why-langgraph.md (Get started > LangGraph basics > concepts/why-langgraph.md)](https://langchain-ai.github.io/langgraph/concepts/why-langgraph/)
|
||||
- [Build a basic chatbot (Get started > LangGraph basics > Build a basic chatbot)](https://langchain-ai.github.io/langgraph/tutorials/get-started/1-build-basic-chatbot/)
|
||||
- [tutorials/get-started/2-add-tools.md (Get started > LangGraph basics > tutorials/get-started/2-add-tools.md)](https://langchain-ai.github.io/langgraph/tutorials/get-started/2-add-tools/)
|
||||
- [tutorials/get-started/3-add-memory.md (Get started > LangGraph basics > tutorials/get-started/3-add-memory.md)](https://langchain-ai.github.io/langgraph/tutorials/get-started/3-add-memory/)
|
||||
- [Add human-in-the-loop (Get started > LangGraph basics > Add human-in-the-loop)](https://langchain-ai.github.io/langgraph/tutorials/get-started/4-human-in-the-loop/)
|
||||
- [tutorials/get-started/5-customize-state.md (Get started > LangGraph basics > tutorials/get-started/5-customize-state.md)](https://langchain-ai.github.io/langgraph/tutorials/get-started/5-customize-state/)
|
||||
- [tutorials/get-started/6-time-travel.md (Get started > LangGraph basics > tutorials/get-started/6-time-travel.md)](https://langchain-ai.github.io/langgraph/tutorials/get-started/6-time-travel/)
|
||||
- [Deployment (Get started > Deployment)](https://langchain-ai.github.io/langgraph/tutorials/deployment/)
|
||||
- [Overview (Prebuilt agents > Overview)](https://langchain-ai.github.io/langgraph/agents/overview/)
|
||||
- [agents/run_agents.md (Prebuilt agents > agents/run_agents.md)](https://langchain-ai.github.io/langgraph/agents/run_agents/)
|
||||
- [agents/streaming.md (Prebuilt agents > agents/streaming.md)](https://langchain-ai.github.io/langgraph/agents/streaming/)
|
||||
- [agents/models.md (Prebuilt agents > agents/models.md)](https://langchain-ai.github.io/langgraph/agents/models/)
|
||||
- [agents/tools.md (Prebuilt agents > agents/tools.md)](https://langchain-ai.github.io/langgraph/agents/tools/)
|
||||
- [agents/mcp.md (Prebuilt agents > agents/mcp.md)](https://langchain-ai.github.io/langgraph/agents/mcp/)
|
||||
- [agents/context.md (Prebuilt agents > agents/context.md)](https://langchain-ai.github.io/langgraph/agents/context/)
|
||||
- [agents/memory.md (Prebuilt agents > agents/memory.md)](https://langchain-ai.github.io/langgraph/agents/memory/)
|
||||
- [agents/human-in-the-loop.md (Prebuilt agents > agents/human-in-the-loop.md)](https://langchain-ai.github.io/langgraph/agents/human-in-the-loop/)
|
||||
- [agents/multi-agent.md (Prebuilt agents > agents/multi-agent.md)](https://langchain-ai.github.io/langgraph/agents/multi-agent/)
|
||||
- [agents/evals.md (Prebuilt agents > agents/evals.md)](https://langchain-ai.github.io/langgraph/agents/evals/)
|
||||
- [agents/deployment.md (Prebuilt agents > agents/deployment.md)](https://langchain-ai.github.io/langgraph/agents/deployment/)
|
||||
- [agents/ui.md (Prebuilt agents > agents/ui.md)](https://langchain-ai.github.io/langgraph/agents/ui/)
|
||||
- [Overview (LangGraph framework > Agent architectures > Overview)](https://langchain-ai.github.io/langgraph/concepts/agentic_concepts/)
|
||||
- [Workflows & agents (LangGraph framework > Agent architectures > Workflows & agents)](https://langchain-ai.github.io/langgraph/tutorials/workflows/)
|
||||
- [Overview (LangGraph framework > Graphs > Overview)](https://langchain-ai.github.io/langgraph/concepts/low_level/)
|
||||
- [Runtime overview (LangGraph framework > Graphs > Runtime overview)](https://langchain-ai.github.io/langgraph/concepts/pregel/)
|
||||
- [Use the Graph API (LangGraph framework > Graphs > Use the Graph API)](https://langchain-ai.github.io/langgraph/how-tos/graph-api/)
|
||||
- [Overview (LangGraph framework > Streaming > Overview)](https://langchain-ai.github.io/langgraph/concepts/streaming/)
|
||||
- [Stream outputs (LangGraph framework > Streaming > Stream outputs)](https://langchain-ai.github.io/langgraph/how-tos/streaming/)
|
||||
- [Overview (LangGraph framework > Persistence > Overview)](https://langchain-ai.github.io/langgraph/concepts/persistence/)
|
||||
- [concepts/durable_execution.md (LangGraph framework > Persistence > concepts/durable_execution.md)](https://langchain-ai.github.io/langgraph/concepts/durable_execution/)
|
||||
- [how-tos/persistence.ipynb (LangGraph framework > Persistence > how-tos/persistence.ipynb)](https://langchain-ai.github.io/langgraph/how-tos/persistence/)
|
||||
- [Overview (LangGraph framework > Memory > Overview)](https://langchain-ai.github.io/langgraph/concepts/memory/)
|
||||
- [Manage memory (LangGraph framework > Memory > Manage memory)](https://langchain-ai.github.io/langgraph/how-tos/memory/)
|
||||
- [Overview (LangGraph framework > Human-in-the-loop > Overview)](https://langchain-ai.github.io/langgraph/concepts/human_in_the_loop/)
|
||||
- [how-tos/human_in_the_loop/add-human-in-the-loop.md (LangGraph framework > Human-in-the-loop > how-tos/human_in_the_loop/add-human-in-the-loop.md)](https://langchain-ai.github.io/langgraph/how-tos/human_in_the_loop/add-human-in-the-loop/)
|
||||
- [Overview (LangGraph framework > Breakpoints > Overview)](https://langchain-ai.github.io/langgraph/concepts/breakpoints/)
|
||||
- [how-tos/human_in_the_loop/breakpoints.ipynb (LangGraph framework > Breakpoints > how-tos/human_in_the_loop/breakpoints.ipynb)](https://langchain-ai.github.io/langgraph/how-tos/human_in_the_loop/breakpoints/)
|
||||
- [Overview (LangGraph framework > Time travel > Overview)](https://langchain-ai.github.io/langgraph/concepts/time-travel/)
|
||||
- [how-tos/human_in_the_loop/time-travel.ipynb (LangGraph framework > Time travel > how-tos/human_in_the_loop/time-travel.ipynb)](https://langchain-ai.github.io/langgraph/how-tos/human_in_the_loop/time-travel/)
|
||||
- [Overview (LangGraph framework > Tools > Overview)](https://langchain-ai.github.io/langgraph/concepts/tools/)
|
||||
- [how-tos/tool-calling.ipynb (LangGraph framework > Tools > how-tos/tool-calling.ipynb)](https://langchain-ai.github.io/langgraph/how-tos/tool-calling/)
|
||||
- [Overview (LangGraph framework > Subgraphs > Overview)](https://langchain-ai.github.io/langgraph/concepts/subgraphs/)
|
||||
- [how-tos/subgraph.ipynb (LangGraph framework > Subgraphs > how-tos/subgraph.ipynb)](https://langchain-ai.github.io/langgraph/how-tos/subgraph/)
|
||||
- [Overview (LangGraph framework > Multi-agent > Overview)](https://langchain-ai.github.io/langgraph/concepts/multi_agent/)
|
||||
- [how-tos/multi_agent.ipynb (LangGraph framework > Multi-agent > how-tos/multi_agent.ipynb)](https://langchain-ai.github.io/langgraph/how-tos/multi_agent/)
|
||||
- [Overview (LangGraph framework > Functional API > Overview)](https://langchain-ai.github.io/langgraph/concepts/functional_api/)
|
||||
- [how-tos/use-functional-api.md (LangGraph framework > Functional API > how-tos/use-functional-api.md)](https://langchain-ai.github.io/langgraph/how-tos/use-functional-api/)
|
||||
- [Overview (LangGraph Platform > Overview)](https://langchain-ai.github.io/langgraph/concepts/langgraph_platform/)
|
||||
- [Quickstart (LangGraph Platform > Get started > Quickstart)](https://langchain-ai.github.io/langgraph/tutorials/langgraph-platform/local-server/)
|
||||
- [Deployment quickstart (LangGraph Platform > Get started > Deployment quickstart)](https://langchain-ai.github.io/langgraph/cloud/quick_start/)
|
||||
- [Overview (LangGraph Platform > Components > Overview)](https://langchain-ai.github.io/langgraph/concepts/langgraph_components/)
|
||||
- [Overview (LangGraph Platform > Components > LangGraph Server > Overview)](https://langchain-ai.github.io/langgraph/concepts/langgraph_server/)
|
||||
- [Overview (LangGraph Platform > Components > LangGraph Server > Application structure > Overview)](https://langchain-ai.github.io/langgraph/concepts/application_structure/)
|
||||
- [cloud/deployment/setup.md (LangGraph Platform > Components > LangGraph Server > Application structure > cloud/deployment/setup.md)](https://langchain-ai.github.io/langgraph/cloud/deployment/setup/)
|
||||
- [cloud/deployment/setup_pyproject.md (LangGraph Platform > Components > LangGraph Server > Application structure > cloud/deployment/setup_pyproject.md)](https://langchain-ai.github.io/langgraph/cloud/deployment/setup_pyproject/)
|
||||
- [cloud/deployment/setup_javascript.md (LangGraph Platform > Components > LangGraph Server > Application structure > cloud/deployment/setup_javascript.md)](https://langchain-ai.github.io/langgraph/cloud/deployment/setup_javascript/)
|
||||
- [cloud/deployment/custom_docker.md (LangGraph Platform > Components > LangGraph Server > Application structure > cloud/deployment/custom_docker.md)](https://langchain-ai.github.io/langgraph/cloud/deployment/custom_docker/)
|
||||
- [LangGraph CLI (LangGraph Platform > Components > LangGraph CLI)](https://langchain-ai.github.io/langgraph/concepts/langgraph_cli/)
|
||||
- [Overview (LangGraph Platform > Components > LangGraph Studio > Overview)](https://langchain-ai.github.io/langgraph/concepts/langgraph_studio/)
|
||||
- [Quickstart (LangGraph Platform > Components > LangGraph Studio > Quickstart)](https://langchain-ai.github.io/langgraph/cloud/how-tos/studio/quick_start/)
|
||||
- [cloud/how-tos/invoke_studio.md (LangGraph Platform > Components > LangGraph Studio > cloud/how-tos/invoke_studio.md)](https://langchain-ai.github.io/langgraph/cloud/how-tos/invoke_studio/)
|
||||
- [cloud/how-tos/studio/manage_assistants.md (LangGraph Platform > Components > LangGraph Studio > cloud/how-tos/studio/manage_assistants.md)](https://langchain-ai.github.io/langgraph/cloud/how-tos/studio/manage_assistants/)
|
||||
- [cloud/how-tos/threads_studio.md (LangGraph Platform > Components > LangGraph Studio > cloud/how-tos/threads_studio.md)](https://langchain-ai.github.io/langgraph/cloud/how-tos/threads_studio/)
|
||||
- [cloud/how-tos/iterate_graph_studio.md (LangGraph Platform > Components > LangGraph Studio > cloud/how-tos/iterate_graph_studio.md)](https://langchain-ai.github.io/langgraph/cloud/how-tos/iterate_graph_studio/)
|
||||
- [cloud/how-tos/clone_traces_studio.md (LangGraph Platform > Components > LangGraph Studio > cloud/how-tos/clone_traces_studio.md)](https://langchain-ai.github.io/langgraph/cloud/how-tos/clone_traces_studio/)
|
||||
- [cloud/how-tos/datasets_studio.md (LangGraph Platform > Components > LangGraph Studio > cloud/how-tos/datasets_studio.md)](https://langchain-ai.github.io/langgraph/cloud/how-tos/datasets_studio/)
|
||||
- [LangGraph SDK (LangGraph Platform > Components > LangGraph SDK)](https://langchain-ai.github.io/langgraph/concepts/sdk/)
|
||||
- [Add semantic search (LangGraph Platform > Data management > Add semantic search)](https://langchain-ai.github.io/langgraph/cloud/deployment/semantic_search/)
|
||||
- [Add TTLs (LangGraph Platform > Data management > Add TTLs)](https://langchain-ai.github.io/langgraph/how-tos/ttl/configure_ttl/)
|
||||
- [Overview (LangGraph Platform > Authentication & access control > Overview)](https://langchain-ai.github.io/langgraph/concepts/auth/)
|
||||
- [how-tos/auth/custom_auth.md (LangGraph Platform > Authentication & access control > how-tos/auth/custom_auth.md)](https://langchain-ai.github.io/langgraph/how-tos/auth/custom_auth/)
|
||||
- [how-tos/auth/openapi_security.md (LangGraph Platform > Authentication & access control > how-tos/auth/openapi_security.md)](https://langchain-ai.github.io/langgraph/how-tos/auth/openapi_security/)
|
||||
- [Overview (LangGraph Platform > Assistants > Overview)](https://langchain-ai.github.io/langgraph/concepts/assistants/)
|
||||
- [cloud/how-tos/configuration_cloud.md (LangGraph Platform > Assistants > cloud/how-tos/configuration_cloud.md)](https://langchain-ai.github.io/langgraph/cloud/how-tos/configuration_cloud/)
|
||||
- [Overview (LangGraph Platform > Threads > Overview)](https://langchain-ai.github.io/langgraph/cloud/concepts/threads/)
|
||||
- [cloud/how-tos/use_threads.md (LangGraph Platform > Threads > cloud/how-tos/use_threads.md)](https://langchain-ai.github.io/langgraph/cloud/how-tos/use_threads/)
|
||||
- [Overview (LangGraph Platform > Runs > Overview)](https://langchain-ai.github.io/langgraph/cloud/concepts/runs/)
|
||||
- [cloud/how-tos/background_run.md (LangGraph Platform > Runs > cloud/how-tos/background_run.md)](https://langchain-ai.github.io/langgraph/cloud/how-tos/background_run/)
|
||||
- [cloud/how-tos/same-thread.md (LangGraph Platform > Runs > cloud/how-tos/same-thread.md)](https://langchain-ai.github.io/langgraph/cloud/how-tos/same-thread/)
|
||||
- [cloud/how-tos/cron_jobs.md (LangGraph Platform > Runs > cloud/how-tos/cron_jobs.md)](https://langchain-ai.github.io/langgraph/cloud/how-tos/cron_jobs/)
|
||||
- [cloud/how-tos/stateless_runs.md (LangGraph Platform > Runs > cloud/how-tos/stateless_runs.md)](https://langchain-ai.github.io/langgraph/cloud/how-tos/stateless_runs/)
|
||||
- [cloud/how-tos/configurable_headers.md (LangGraph Platform > Runs > cloud/how-tos/configurable_headers.md)](https://langchain-ai.github.io/langgraph/cloud/how-tos/configurable_headers/)
|
||||
- [Overview (LangGraph Platform > Streaming > Overview)](https://langchain-ai.github.io/langgraph/cloud/concepts/streaming/)
|
||||
- [cloud/how-tos/streaming.md (LangGraph Platform > Streaming > cloud/how-tos/streaming.md)](https://langchain-ai.github.io/langgraph/cloud/how-tos/streaming/)
|
||||
- [Human-in-the-loop (LangGraph Platform > Human-in-the-loop)](https://langchain-ai.github.io/langgraph/cloud/how-tos/add-human-in-the-loop/)
|
||||
- [Breakpoints (LangGraph Platform > Breakpoints)](https://langchain-ai.github.io/langgraph/cloud/how-tos/human_in_the_loop_breakpoint/)
|
||||
- [Time travel (LangGraph Platform > Time travel)](https://langchain-ai.github.io/langgraph/cloud/how-tos/human_in_the_loop_time_travel/)
|
||||
- [MCP (LangGraph Platform > MCP)](https://langchain-ai.github.io/langgraph/concepts/server-mcp/)
|
||||
- [Overview (LangGraph Platform > Double-texting > Overview)](https://langchain-ai.github.io/langgraph/concepts/double_texting/)
|
||||
- [cloud/how-tos/interrupt_concurrent.md (LangGraph Platform > Double-texting > cloud/how-tos/interrupt_concurrent.md)](https://langchain-ai.github.io/langgraph/cloud/how-tos/interrupt_concurrent/)
|
||||
- [cloud/how-tos/rollback_concurrent.md (LangGraph Platform > Double-texting > cloud/how-tos/rollback_concurrent.md)](https://langchain-ai.github.io/langgraph/cloud/how-tos/rollback_concurrent/)
|
||||
- [cloud/how-tos/reject_concurrent.md (LangGraph Platform > Double-texting > cloud/how-tos/reject_concurrent.md)](https://langchain-ai.github.io/langgraph/cloud/how-tos/reject_concurrent/)
|
||||
- [cloud/how-tos/enqueue_concurrent.md (LangGraph Platform > Double-texting > cloud/how-tos/enqueue_concurrent.md)](https://langchain-ai.github.io/langgraph/cloud/how-tos/enqueue_concurrent/)
|
||||
- [Overview (LangGraph Platform > Webhooks > Overview)](https://langchain-ai.github.io/langgraph/cloud/concepts/webhooks/)
|
||||
- [cloud/how-tos/webhooks.md (LangGraph Platform > Webhooks > cloud/how-tos/webhooks.md)](https://langchain-ai.github.io/langgraph/cloud/how-tos/webhooks/)
|
||||
- [Overview (LangGraph Platform > Cron jobs > Overview)](https://langchain-ai.github.io/langgraph/cloud/concepts/cron_jobs/)
|
||||
- [cloud/how-tos/cron_jobs.md (LangGraph Platform > Cron jobs > cloud/how-tos/cron_jobs.md)](https://langchain-ai.github.io/langgraph/cloud/how-tos/cron_jobs/)
|
||||
- [how-tos/http/custom_lifespan.md (LangGraph Platform > Server customization > how-tos/http/custom_lifespan.md)](https://langchain-ai.github.io/langgraph/how-tos/http/custom_lifespan/)
|
||||
- [how-tos/http/custom_middleware.md (LangGraph Platform > Server customization > how-tos/http/custom_middleware.md)](https://langchain-ai.github.io/langgraph/how-tos/http/custom_middleware/)
|
||||
- [how-tos/http/custom_routes.md (LangGraph Platform > Server customization > how-tos/http/custom_routes.md)](https://langchain-ai.github.io/langgraph/how-tos/http/custom_routes/)
|
||||
- [Overview (LangGraph Platform > Deployment > Overview)](https://langchain-ai.github.io/langgraph/concepts/deployment_options/)
|
||||
- [Data plane (LangGraph Platform > Deployment > Data plane)](https://langchain-ai.github.io/langgraph/concepts/langgraph_data_plane/)
|
||||
- [Control plane (LangGraph Platform > Deployment > Control plane)](https://langchain-ai.github.io/langgraph/concepts/langgraph_control_plane/)
|
||||
- [Overview (LangGraph Platform > Deployment > Deployment options > Cloud SaaS > Overview)](https://langchain-ai.github.io/langgraph/concepts/langgraph_cloud/)
|
||||
- [Deploy Cloud SaaS (LangGraph Platform > Deployment > Deployment options > Cloud SaaS > Deploy Cloud SaaS)](https://langchain-ai.github.io/langgraph/cloud/deployment/cloud/)
|
||||
- [Overview (LangGraph Platform > Deployment > Deployment options > Self-Hosted Data Plane > Overview)](https://langchain-ai.github.io/langgraph/concepts/langgraph_self_hosted_data_plane/)
|
||||
- [Deploy Self-Hosted Data Plane (LangGraph Platform > Deployment > Deployment options > Self-Hosted Data Plane > Deploy Self-Hosted Data Plane)](https://langchain-ai.github.io/langgraph/cloud/deployment/self_hosted_data_plane/)
|
||||
- [Overview (LangGraph Platform > Deployment > Deployment options > Self-Hosted Control Plane > Overview)](https://langchain-ai.github.io/langgraph/concepts/langgraph_self_hosted_control_plane/)
|
||||
- [Deploy Self-Hosted Control Plane (LangGraph Platform > Deployment > Deployment options > Self-Hosted Control Plane > Deploy Self-Hosted Control Plane)](https://langchain-ai.github.io/langgraph/cloud/deployment/self_hosted_control_plane/)
|
||||
- [Overview (LangGraph Platform > Deployment > Deployment options > Standalone Container > Overview)](https://langchain-ai.github.io/langgraph/concepts/langgraph_standalone_container/)
|
||||
- [Deploy Standalone Container (LangGraph Platform > Deployment > Deployment options > Standalone Container > Deploy Standalone Container)](https://langchain-ai.github.io/langgraph/cloud/deployment/standalone_container/)
|
||||
- [Scalability & resilience (LangGraph Platform > Deployment > Scalability & resilience)](https://langchain-ai.github.io/langgraph/concepts/scalability_and_resilience/)
|
||||
- [Plans & pricing (LangGraph Platform > Deployment > Plans & pricing)](https://langchain-ai.github.io/langgraph/concepts/plans/)
|
||||
|
||||
# Examples
|
||||
|
||||
- [Building an Agentic RAG System](https://langchain-ai.github.io/langgraph/tutorials/rag/langgraph_agentic_rag/): This tutorial guides you through the process of creating a retrieval agent (RAG) system using LangChain and LangGraph. You will learn how to fetch and preprocess documents, create a retriever tool, and build an agentic RAG that intelligently decides when to retrieve information or respond directly to user queries. By the end, you'll have a functional system capable of semantic search and context-aware responses.
|
||||
- [Building a Multi-Agent Supervisor System](https://langchain-ai.github.io/langgraph/tutorials/multi_agent/agent_supervisor/): This tutorial guides you through the process of creating a multi-agent supervisor system using specialized agents for research and math tasks. You will learn how to set up the environment, create individual worker agents, and implement a supervisor that orchestrates their interactions. By the end, you'll have a fully functional multi-agent architecture capable of handling complex queries.
|
||||
- [Building a SQL Agent with LangChain](https://langchain-ai.github.io/langgraph/tutorials/sql-agent/): This tutorial provides a step-by-step guide on how to create a SQL agent capable of answering questions about a SQL database. It covers the setup of necessary dependencies, configuration of a SQLite database, and the implementation of a prebuilt agent that interacts with the database to generate and execute queries. Additionally, it discusses customizing the agent for more control over its behavior.
|
||||
- [Custom Run ID, Tags, and Metadata for LangSmith Graph Runs](https://langchain-ai.github.io/langgraph/how-tos/run-id-langsmith/): This guide provides instructions on how to pass a custom run ID and set tags and metadata for graph runs in LangSmith. It covers prerequisites, configuration options, and includes code examples for setting up and running a graph with LangGraph. Additionally, it explains how to view and filter traces in the LangSmith platform.
|
||||
- [Custom Authentication Setup for Chatbots](https://langchain-ai.github.io/langgraph/tutorials/auth/getting_started/): This tutorial guides you through the process of setting up custom authentication for a chatbot using the LangGraph platform. You will learn how to implement token-based security to control user access, starting with a basic example and preparing for more advanced authentication methods in future tutorials. By the end, you'll have a functional chatbot that restricts access to authenticated users.
|
||||
- [Implementing Private Conversations in Chatbots](https://langchain-ai.github.io/langgraph/tutorials/auth/resource_auth/): This tutorial guides you through extending a chatbot to enable private conversations for each user by implementing resource-level access control. You'll learn how to add authorization handlers to ensure users can only access their own threads and test the functionality to confirm proper access restrictions. Additionally, the tutorial covers scoped authorization handlers for more granular control over resource access.
|
||||
- [Integrating OAuth2 Authentication with Supabase](https://langchain-ai.github.io/langgraph/tutorials/auth/add_auth_server/): This tutorial guides you through replacing hard-coded tokens with real user accounts using OAuth2 for secure authentication in your LangGraph application. You'll learn how to set up Supabase as your identity provider, implement token validation, and ensure proper user authorization. By the end, you'll have a production-ready authentication system that allows users to securely access their own data.
|
||||
- [Rebuilding Graphs at Runtime in LangGraph](https://langchain-ai.github.io/langgraph/cloud/deployment/graph_rebuild/): This guide explains how to rebuild your graph at runtime with different configurations in LangGraph. It covers the necessary prerequisites, how to define graphs, and the steps to modify your graph-making function for dynamic behavior based on user input. Additionally, it provides examples of both static and dynamic graph configurations.
|
||||
- [Interacting with RemoteGraph in LangGraph](https://langchain-ai.github.io/langgraph/how-tos/use-remote-graph/): This documentation page provides a comprehensive guide on how to interact with a LangGraph Platform deployment using the RemoteGraph interface. It covers the initialization of RemoteGraph, invoking the graph both asynchronously and synchronously, and utilizing it as a subgraph. Additionally, it includes code examples in Python and JavaScript to facilitate understanding and implementation.
|
||||
- [Deploying Agents on LangGraph Platform](https://langchain-ai.github.io/langgraph/how-tos/autogen-langgraph-platform/): This page provides a comprehensive guide on how to deploy agents like AutoGen and CrewAI using the LangGraph Platform. It covers the necessary setup, agent definition, and wrapping the agent in a LangGraph node for deployment. Additionally, it highlights the benefits of using LangGraph for scalable infrastructure and memory support.
|
||||
- [Integrating LangGraph with React: A Comprehensive Guide](https://langchain-ai.github.io/langgraph/cloud/how-tos/use_stream_react/): This documentation provides a detailed guide on how to integrate the LangGraph platform into your React applications using the `useStream()` hook. It covers installation, key features, example implementations, and customization options for building chat experiences. Additionally, it includes advanced topics such as event handling, TypeScript support, and managing conversation threads.
|
||||
- [Implementing Generative User Interfaces with LangGraph](https://langchain-ai.github.io/langgraph/cloud/how-tos/generative_ui_react/): This documentation provides a comprehensive guide on how to implement Generative User Interfaces (Generative UI) using the LangGraph platform. It covers prerequisites, step-by-step tutorials for defining UI components, sending them in graphs, and handling them in React applications. Additionally, it includes how-to guides for customizing components and managing UI state effectively.
|
||||
- [Agentic RAG (Agentic RAG)](https://langchain-ai.github.io/langgraph/tutorials/rag/langgraph_agentic_rag/)
|
||||
- [Agent Supervisor (Agent Supervisor)](https://langchain-ai.github.io/langgraph/tutorials/multi_agent/agent_supervisor/)
|
||||
- [SQL agent (SQL agent)](https://langchain-ai.github.io/langgraph/tutorials/sql-agent/)
|
||||
- [Graph runs in LangSmith (Graph runs in LangSmith)](https://langchain-ai.github.io/langgraph/how-tos/run-id-langsmith/)
|
||||
- [tutorials/auth/getting_started.md (LangGraph Platform > Authentication > tutorials/auth/getting_started.md)](https://langchain-ai.github.io/langgraph/tutorials/auth/getting_started/)
|
||||
- [tutorials/auth/resource_auth.md (LangGraph Platform > Authentication > tutorials/auth/resource_auth.md)](https://langchain-ai.github.io/langgraph/tutorials/auth/resource_auth/)
|
||||
- [tutorials/auth/add_auth_server.md (LangGraph Platform > Authentication > tutorials/auth/add_auth_server.md)](https://langchain-ai.github.io/langgraph/tutorials/auth/add_auth_server/)
|
||||
- [Rebuild graph at runtime (LangGraph Platform > Rebuild graph at runtime)](https://langchain-ai.github.io/langgraph/cloud/deployment/graph_rebuild/)
|
||||
- [Use RemoteGraph (LangGraph Platform > Use RemoteGraph)](https://langchain-ai.github.io/langgraph/how-tos/use-remote-graph/)
|
||||
- [Deploy CrewAI, AutoGen, and other frameworks (LangGraph Platform > Deploy CrewAI, AutoGen, and other frameworks)](https://langchain-ai.github.io/langgraph/how-tos/autogen-langgraph-platform/)
|
||||
- [Integrate LangGraph into a React app (LangGraph Platform > Front-end and generative UI > Integrate LangGraph into a React app)](https://langchain-ai.github.io/langgraph/cloud/how-tos/use_stream_react/)
|
||||
- [Implement generative UI with LangGraph (LangGraph Platform > Front-end and generative UI > Implement generative UI with LangGraph)](https://langchain-ai.github.io/langgraph/cloud/how-tos/generative_ui_react/)
|
||||
|
||||
# Resources
|
||||
|
||||
- [LangGraph FAQ](https://langchain-ai.github.io/langgraph/concepts/faq/): This FAQ page provides answers to common questions about LangGraph, an orchestration framework for complex agentic systems. It covers topics such as the differences between LangGraph and LangChain, performance impacts, open-source status, and compatibility with various LLMs. Additionally, it outlines the distinctions between LangGraph and LangGraph Platform, including features and deployment options.
|
||||
- [Getting Started with LangGraph Templates](https://langchain-ai.github.io/langgraph/concepts/template_applications/): This page provides an overview of open source reference applications known as templates, designed to help users quickly build applications with LangGraph. It includes installation instructions for the LangGraph CLI, a list of available templates with their descriptions, and guidance on creating and deploying a new LangGraph app. Users can find links to repositories for each template and next steps for customizing their applications.
|
||||
- [Guide to Using llms.txt and llms-full.txt for LLMs](https://langchain-ai.github.io/langgraph/llms-txt-overview/): This page provides an overview of the `llms.txt` and `llms-full.txt` formats, which facilitate access to programming documentation for large language models (LLMs) and agents. It outlines the differences between the two formats, usage instructions via an MCP server, and best practices for integrating these files into integrated development environments (IDEs). Additionally, it highlights considerations for managing large documentation files effectively.
|
||||
- [Community Agents for LangGraph](https://langchain-ai.github.io/langgraph/agents/prebuilt/): This page provides a list of community-built libraries that extend the functionality of LangGraph. Each entry includes the library name, GitHub URL, a brief description, and additional metrics like weekly downloads and stars. Additionally, it outlines how to contribute your own library to the LangGraph documentation.
|
||||
- [LangGraph Error Reference Guide](https://langchain-ai.github.io/langgraph/troubleshooting/errors/index/): This page serves as a comprehensive reference for resolving common errors encountered while using the LangGraph platform. It includes a list of error codes and links to detailed guides for troubleshooting specific issues. Users can find solutions for errors related to graph recursion, concurrent updates, node return values, and more.
|
||||
- [Handling Recursion Limits in LangGraph](https://langchain-ai.github.io/langgraph/troubleshooting/errors/GRAPH_RECURSION_LIMIT/): This page provides guidance on managing recursion limits in LangGraph's StateGraph. It explains how to identify potential infinite loops in your graph and offers solutions for increasing the recursion limit when working with complex graphs. Additionally, it includes code examples to illustrate the concepts discussed.
|
||||
- [Handling INVALID_CONCURRENT_GRAPH_UPDATE in LangGraph](https://langchain-ai.github.io/langgraph/troubleshooting/errors/INVALID_CONCURRENT_GRAPH_UPDATE/): This page explains the INVALID_CONCURRENT_GRAPH_UPDATE error that occurs in LangGraph when multiple nodes attempt to update the same state property concurrently. It provides an example of how this error can arise and offers a solution by using a reducer to combine values from parallel node executions. Additionally, troubleshooting tips are included to help resolve this issue.
|
||||
- [Handling Invalid Node Return Values in LangGraph](https://langchain-ai.github.io/langgraph/troubleshooting/errors/INVALID_GRAPH_NODE_RETURN_VALUE/): This page provides guidance on the error encountered when a LangGraph node returns a non-dict value. It includes an example of incorrect node implementation and the resulting error message. Additionally, troubleshooting tips are offered to ensure that all nodes return the expected dictionary format.
|
||||
- [Handling Multiple Subgraphs in LangGraph](https://langchain-ai.github.io/langgraph/troubleshooting/errors/MULTIPLE_SUBGRAPHS/): This page discusses the limitations of calling multiple subgraphs within a single LangGraph node when checkpointing is enabled. It provides troubleshooting tips to resolve related errors, including suggestions for compiling subgraphs without checkpointing and using the Send API for graph calls.
|
||||
- [Handling INVALID_CHAT_HISTORY Error in create_react_agent](https://langchain-ai.github.io/langgraph/troubleshooting/errors/INVALID_CHAT_HISTORY/): This page provides an overview of the INVALID_CHAT_HISTORY error encountered in the create_react_agent function when a malformed list of messages is passed. It outlines the potential causes of the error and offers troubleshooting steps to resolve it. Users can learn how to properly invoke the graph and manage tool calls to avoid this issue.
|
||||
- [Handling INVALID_LICENSE Error in LangGraph Platform](https://langchain-ai.github.io/langgraph/troubleshooting/errors/INVALID_LICENSE/): This page provides guidance on troubleshooting the INVALID_LICENSE error encountered when starting a self-hosted LangGraph Platform server. It outlines the scenarios in which this error may occur and offers solutions based on different deployment types. Additionally, it includes steps to verify the necessary credentials for successful deployment.
|
||||
- [LangGraph Studio Troubleshooting Guide](https://langchain-ai.github.io/langgraph/troubleshooting/studio/): This page provides troubleshooting solutions for common connection issues encountered in LangGraph Studio, particularly with Safari and Brave browsers. It also addresses potential graph edge issues and offers methods to define routing paths for conditional edges. Users can find step-by-step instructions for resolving these issues using Cloudflare Tunnel and browser settings.
|
||||
- [LangGraph Case Studies](https://langchain-ai.github.io/langgraph/adopters/): This page provides a comprehensive list of companies that have successfully implemented LangGraph, showcasing their unique use cases and the benefits they have achieved. Each entry includes links to detailed case studies or blog posts for further reading. If your company uses LangGraph, you are encouraged to share your success story to contribute to this growing collection.
|
||||
- [concepts/faq.md (concepts/faq.md)](https://langchain-ai.github.io/langgraph/concepts/faq/)
|
||||
- [Template applications (Template applications)](https://langchain-ai.github.io/langgraph/concepts/template_applications/)
|
||||
- [llms.txt (llms.txt)](https://langchain-ai.github.io/langgraph/llms-txt-overview/)
|
||||
- [agents/prebuilt.md (agents/prebuilt.md)](https://langchain-ai.github.io/langgraph/agents/prebuilt/)
|
||||
- [troubleshooting/errors/index.md (Troubleshooting > Errors > troubleshooting/errors/index.md)](https://langchain-ai.github.io/langgraph/troubleshooting/errors/index/)
|
||||
- [troubleshooting/errors/GRAPH_RECURSION_LIMIT.md (Troubleshooting > Errors > troubleshooting/errors/GRAPH_RECURSION_LIMIT.md)](https://langchain-ai.github.io/langgraph/troubleshooting/errors/GRAPH_RECURSION_LIMIT/)
|
||||
- [troubleshooting/errors/INVALID_CONCURRENT_GRAPH_UPDATE.md (Troubleshooting > Errors > troubleshooting/errors/INVALID_CONCURRENT_GRAPH_UPDATE.md)](https://langchain-ai.github.io/langgraph/troubleshooting/errors/INVALID_CONCURRENT_GRAPH_UPDATE/)
|
||||
- [troubleshooting/errors/INVALID_GRAPH_NODE_RETURN_VALUE.md (Troubleshooting > Errors > troubleshooting/errors/INVALID_GRAPH_NODE_RETURN_VALUE.md)](https://langchain-ai.github.io/langgraph/troubleshooting/errors/INVALID_GRAPH_NODE_RETURN_VALUE/)
|
||||
- [troubleshooting/errors/MULTIPLE_SUBGRAPHS.md (Troubleshooting > Errors > troubleshooting/errors/MULTIPLE_SUBGRAPHS.md)](https://langchain-ai.github.io/langgraph/troubleshooting/errors/MULTIPLE_SUBGRAPHS/)
|
||||
- [troubleshooting/errors/INVALID_CHAT_HISTORY.md (Troubleshooting > Errors > troubleshooting/errors/INVALID_CHAT_HISTORY.md)](https://langchain-ai.github.io/langgraph/troubleshooting/errors/INVALID_CHAT_HISTORY/)
|
||||
- [troubleshooting/errors/INVALID_LICENSE.md (Troubleshooting > Errors > troubleshooting/errors/INVALID_LICENSE.md)](https://langchain-ai.github.io/langgraph/troubleshooting/errors/INVALID_LICENSE/)
|
||||
- [LangGraph Studio (Troubleshooting > LangGraph Studio)](https://langchain-ai.github.io/langgraph/troubleshooting/studio/)
|
||||
- [LangGraph Academy course (Learn > LangGraph Academy course)](https://langchain-ai.github.io/langgraph/https://academy.langchain.com/courses/intro-to-langgraph/)
|
||||
- [Case studies (Learn > Case studies)](https://langchain-ai.github.io/langgraph/adopters/)
|
||||
|
||||
@@ -12,18 +12,12 @@
|
||||
options:
|
||||
members:
|
||||
- SerializerProtocol
|
||||
- CipherProtocol
|
||||
|
||||
::: langgraph.checkpoint.serde.jsonplus
|
||||
options:
|
||||
members:
|
||||
- JsonPlusSerializer
|
||||
|
||||
::: langgraph.checkpoint.serde.encrypted
|
||||
options:
|
||||
members:
|
||||
- EncryptedSerializer
|
||||
|
||||
::: langgraph.checkpoint.memory
|
||||
|
||||
::: langgraph.checkpoint.sqlite
|
||||
@@ -38,4 +32,4 @@
|
||||
::: langgraph.checkpoint.postgres.aio
|
||||
options:
|
||||
members:
|
||||
- AsyncPostgresSaver
|
||||
- AsyncPostgresSaver
|
||||
@@ -36,6 +36,41 @@
|
||||
- aget_subgraphs
|
||||
- with_config
|
||||
|
||||
::: langgraph.graph.graph.Graph
|
||||
options:
|
||||
show_if_no_docstring: true
|
||||
show_root_heading: true
|
||||
show_root_full_path: false
|
||||
members:
|
||||
- add_node
|
||||
- add_edge
|
||||
- add_conditional_edges
|
||||
- compile
|
||||
|
||||
::: langgraph.graph.graph.CompiledGraph
|
||||
options:
|
||||
show_if_no_docstring: true
|
||||
show_root_heading: true
|
||||
show_root_full_path: false
|
||||
members:
|
||||
- stream
|
||||
- astream
|
||||
- invoke
|
||||
- ainvoke
|
||||
- get_state
|
||||
- aget_state
|
||||
- get_state_history
|
||||
- aget_state_history
|
||||
- update_state
|
||||
- aupdate_state
|
||||
- bulk_update_state
|
||||
- abulk_update_state
|
||||
- get_graph
|
||||
- aget_graph
|
||||
- get_subgraphs
|
||||
- aget_subgraphs
|
||||
- with_config
|
||||
|
||||
::: langgraph.graph.message
|
||||
options:
|
||||
members:
|
||||
|
||||
@@ -22,7 +22,7 @@ Welcome to the LangGraph reference docs! These pages detail the core interfaces
|
||||
|
||||
## LangGraph
|
||||
|
||||
The core APIs for the LangGraph open source library.
|
||||
The core APIs for the LangGraph opens source library.
|
||||
|
||||
- [Graphs](graphs.md): Main graph abstraction and usage.
|
||||
- [Functional API](func.md): Functional programming interface for graphs.
|
||||
|
||||
@@ -1,21 +1,5 @@
|
||||
# Pregel
|
||||
|
||||
::: langgraph.pregel.NodeBuilder
|
||||
options:
|
||||
show_if_no_docstring: true
|
||||
show_root_heading: true
|
||||
show_root_full_path: false
|
||||
members:
|
||||
- subscribe_only
|
||||
- subscribe_to
|
||||
- read_from
|
||||
- do
|
||||
- write_to
|
||||
- meta
|
||||
- retry
|
||||
- cache
|
||||
- build
|
||||
|
||||
::: langgraph.pregel.Pregel
|
||||
options:
|
||||
show_if_no_docstring: true
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
.agent-layout {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
gap: 1rem;
|
||||
align-items: flex-start;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.agent-layout h3 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.agent-graph-features {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
padding: 1rem;
|
||||
max-width: 300px;
|
||||
flex-shrink: 0;
|
||||
|
||||
border: 1px solid var(--md-default-fg-color--lightest);
|
||||
border-radius: 0.5rem;
|
||||
background-color: var(--md-default-bg-color);
|
||||
}
|
||||
|
||||
.agent-graph-features label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
font-size: 0.9rem;
|
||||
color: var(--md-typeset-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.agent-graph-features input[type="checkbox"] {
|
||||
accent-color: var(--md-accent-fg-color);
|
||||
transform: scale(1.2);
|
||||
}
|
||||
|
||||
.agent-graph-container {
|
||||
flex: 1 1 50%;
|
||||
max-width: 70%;
|
||||
padding: 1rem;
|
||||
|
||||
overflow: auto;
|
||||
height: auto;
|
||||
box-sizing: border-box;
|
||||
|
||||
border: 1px solid var(--md-default-fg-color--lightest);
|
||||
border-radius: 0.5rem;
|
||||
background-color: var(--md-default-bg-color);
|
||||
}
|
||||
|
||||
.agent-graph-container img {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
@@ -580,7 +580,9 @@
|
||||
" ]\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"evaluator = prompt | ChatOpenAI(model=\"gpt-4o\").with_structured_output(RedTeamingResult)\n",
|
||||
"evaluator = prompt | ChatOpenAI(model=\"gpt-4-turbo-preview\").with_structured_output(\n",
|
||||
" RedTeamingResult, method=\"function_calling\"\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def did_resist(run, example):\n",
|
||||
|
||||
@@ -833,7 +833,7 @@
|
||||
"@tool\n",
|
||||
"def book_excursion(recommendation_id: int) -> str:\n",
|
||||
" \"\"\"\n",
|
||||
" Book an excursion by its recommendation ID.\n",
|
||||
" Book a excursion by its recommendation ID.\n",
|
||||
"\n",
|
||||
" Args:\n",
|
||||
" recommendation_id (int): The ID of the trip recommendation to book.\n",
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 2,
|
||||
"id": "baf669a0-04ee-492d-80d8-8fcb658ed128",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
@@ -313,8 +313,8 @@
|
||||
"\n",
|
||||
" builder.add_edge(\"finalizer\", END)\n",
|
||||
"\n",
|
||||
" # These functions let the step be used in a\n",
|
||||
" # StateGraph with 'messages' as the key.\n",
|
||||
" # These functions let the step be used in a MessageGraph\n",
|
||||
" # or a StateGraph with 'messages' as the key.\n",
|
||||
" def encode(x: Union[Sequence[AnyMessage], PromptValue]) -> dict:\n",
|
||||
" \"\"\"Ensure the input is the correct format.\"\"\"\n",
|
||||
" if isinstance(x, PromptValue):\n",
|
||||
|
||||
@@ -1,29 +1,21 @@
|
||||
# Build a basic chatbot
|
||||
|
||||
In this tutorial, you will build a basic chatbot. This chatbot is the basis for the following series of tutorials where you will progressively add more sophisticated capabilities, and be introduced to key LangGraph concepts along the way. Let's dive in! 🌟
|
||||
In this tutorial, you will build a basic chatbot. This chatbot is the basis for the following series of tutorials where you will progressively add more sophisticated capabilities, and be introduced to key LangGraph concepts along the way. Let’s dive in! 🌟
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before you start this tutorial, ensure you have access to a LLM that supports
|
||||
tool-calling features, such as [OpenAI](https://platform.openai.com/api-keys),
|
||||
[Anthropic](https://console.anthropic.com/settings/keys), or
|
||||
[Anthropic](https://console.anthropic.com/settings/admin-keys), or
|
||||
[Google Gemini](https://ai.google.dev/gemini-api/docs/api-key).
|
||||
|
||||
## 1. Install packages
|
||||
|
||||
Install the required packages:
|
||||
|
||||
:::python
|
||||
```bash
|
||||
pip install -U langgraph langsmith
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```bash
|
||||
npm install @langchain/langgraph @langchain/core langsmith
|
||||
```
|
||||
:::
|
||||
|
||||
!!! tip
|
||||
|
||||
@@ -35,13 +27,12 @@ Now you can create a basic chatbot using LangGraph. This chatbot will respond di
|
||||
|
||||
Start by creating a `StateGraph`. A `StateGraph` object defines the structure of our chatbot as a "state machine". We'll add `nodes` to represent the llm and functions our chatbot can call and `edges` to specify how the bot should transition between these functions.
|
||||
|
||||
:::python
|
||||
```python
|
||||
from typing import Annotated
|
||||
|
||||
from typing_extensions import TypedDict
|
||||
|
||||
from langgraph.graph import StateGraph, START, END
|
||||
from langgraph.graph import StateGraph, START
|
||||
from langgraph.graph.message import add_messages
|
||||
|
||||
|
||||
@@ -54,53 +45,24 @@ class State(TypedDict):
|
||||
|
||||
graph_builder = StateGraph(State)
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
import { Annotation } from "@langchain/langgraph";
|
||||
import { BaseMessage } from "@langchain/core/messages";
|
||||
import { StateGraph, START, END } from "@langchain/langgraph";
|
||||
|
||||
const StateAnnotation = Annotation.Root({
|
||||
// Messages have the type "BaseMessage[]". The messagesStateReducer function
|
||||
// defines how this state key should be updated
|
||||
// (in this case, it appends messages to the list, rather than overwriting them)
|
||||
messages: Annotation<BaseMessage[]>({
|
||||
reducer: (x, y) => x.concat(y),
|
||||
}),
|
||||
});
|
||||
|
||||
const graphBuilder = new StateGraph(StateAnnotation);
|
||||
```
|
||||
:::
|
||||
|
||||
Our graph can now handle two key tasks:
|
||||
|
||||
1. Each `node` can receive the current `State` as input and output an update to the state.
|
||||
2. Updates to `messages` will be appended to the existing list rather than overwriting it, thanks to the prebuilt function used with the annotation.
|
||||
2. Updates to `messages` will be appended to the existing list rather than overwriting it, thanks to the prebuilt [`add_messages`](https://langchain-ai.github.io/langgraph/reference/graphs/?h=add+messages#add_messages) function used with the `Annotated` syntax.
|
||||
|
||||
------
|
||||
|
||||
!!! tip "Concept"
|
||||
|
||||
When defining a graph, the first step is to define its `State`. The `State` includes the graph's schema and [reducer functions](https://langchain-ai.github.io/langgraph/concepts/low_level/#reducers) that handle state updates. Keys without a reducer annotation will overwrite previous values. To learn more about state, reducers, and related concepts, see [LangGraph reference docs](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.message.add_messages).
|
||||
|
||||
:::python
|
||||
In our example, `State` is a `TypedDict` with one key: `messages`. The [`add_messages`](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.message.add_messages) reducer function is used to append new messages to the list instead of overwriting it.
|
||||
:::
|
||||
|
||||
:::js
|
||||
In our example, `StateAnnotation` defines a state with one key: `messages`. The reducer function is used to append new messages to the list instead of overwriting it.
|
||||
:::
|
||||
When defining a graph, the first step is to define its `State`. The `State` includes the graph's schema and [reducer functions](https://langchain-ai.github.io/langgraph/concepts/low_level/#reducers) that handle state updates. In our example, `State` is a `TypedDict` with one key: `messages`. The [`add_messages`](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.message.add_messages) reducer function is used to append new messages to the list instead of overwriting it. Keys without a reducer annotation will overwrite previous values. To learn more about state, reducers, and related concepts, see [LangGraph reference docs](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.message.add_messages).
|
||||
|
||||
## 3. Add a node
|
||||
|
||||
Next, add a "`chatbot`" node. **Nodes** represent units of work and are typically regular functions.
|
||||
Next, add a "`chatbot`" node. **Nodes** represent units of work and are typically regular Python functions.
|
||||
|
||||
Let's first select a chat model:
|
||||
|
||||
:::python
|
||||
{!snippets/chat_model_tabs.md!}
|
||||
|
||||
<!---
|
||||
@@ -110,21 +72,10 @@ from langchain.chat_models import init_chat_model
|
||||
llm = init_chat_model("anthropic:claude-3-5-sonnet-latest")
|
||||
```
|
||||
-->
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
import { ChatAnthropic } from "@langchain/anthropic";
|
||||
|
||||
const llm = new ChatAnthropic({
|
||||
model: "claude-3-5-sonnet-latest",
|
||||
});
|
||||
```
|
||||
:::
|
||||
|
||||
We can now incorporate the chat model into a simple node:
|
||||
|
||||
:::python
|
||||
```python
|
||||
|
||||
def chatbot(state: State):
|
||||
@@ -136,87 +87,32 @@ def chatbot(state: State):
|
||||
# the node is used.
|
||||
graph_builder.add_node("chatbot", chatbot)
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
const chatbot = async (state: typeof StateAnnotation.State) => {
|
||||
return { messages: [await llm.invoke(state.messages)] };
|
||||
};
|
||||
|
||||
// The first argument is the unique node name
|
||||
// The second argument is the function or object that will be called whenever
|
||||
// the node is used.
|
||||
graphBuilder.addNode("chatbot", chatbot);
|
||||
```
|
||||
:::
|
||||
|
||||
**Notice** how the `chatbot` node function takes the current `State` as input and returns a dictionary containing an updated `messages` list under the key "messages". This is the basic pattern for all LangGraph node functions.
|
||||
|
||||
:::python
|
||||
The `add_messages` function in our `State` will append the LLM's response messages to whatever messages are already in the state.
|
||||
:::
|
||||
|
||||
:::js
|
||||
The reducer function in our `StateAnnotation` will append the LLM's response messages to whatever messages are already in the state.
|
||||
:::
|
||||
|
||||
## 4. Add an `entry` point
|
||||
|
||||
Add an `entry` point to tell the graph **where to start its work** each time it is run:
|
||||
|
||||
:::python
|
||||
```python
|
||||
graph_builder.add_edge(START, "chatbot")
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
graphBuilder.addEdge(START, "chatbot");
|
||||
```
|
||||
:::
|
||||
|
||||
## 5. Add an `exit` point
|
||||
|
||||
Add an `exit` point to indicate **where the graph should finish execution**. This is helpful for more complex flows, but even in a simple graph like this, adding an end node improves clarity.
|
||||
|
||||
:::python
|
||||
```python
|
||||
graph_builder.add_edge("chatbot", END)
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
graphBuilder.addEdge("chatbot", END);
|
||||
```
|
||||
:::
|
||||
|
||||
This tells the graph to terminate after running the chatbot node.
|
||||
|
||||
## 6. Compile the graph
|
||||
## 5. Compile the graph
|
||||
|
||||
Before running the graph, we'll need to compile it. We can do so by calling `compile()`
|
||||
on the graph builder. This creates a `CompiledGraph` we can invoke on our state.
|
||||
|
||||
:::python
|
||||
```python
|
||||
graph = graph_builder.compile()
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
const graph = graphBuilder.compile();
|
||||
```
|
||||
:::
|
||||
|
||||
## 7. Visualize the graph (optional)
|
||||
## 6. Visualize the graph (optional)
|
||||
|
||||
You can visualize the graph using the `get_graph` method and one of the "draw" methods, like `draw_ascii` or `draw_png`. The `draw` methods each require additional dependencies.
|
||||
|
||||
:::python
|
||||
```python
|
||||
from IPython.display import Image, display
|
||||
|
||||
@@ -226,31 +122,14 @@ except Exception:
|
||||
# This requires some extra dependencies and is optional
|
||||
pass
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
import * as tslab from "tslab";
|
||||
|
||||
try {
|
||||
const drawableGraph = graph.getGraph();
|
||||
const image = await drawableGraph.drawMermaidPng();
|
||||
const arrayBuffer = await image.arrayBuffer();
|
||||
await tslab.display.png(new Uint8Array(arrayBuffer));
|
||||
} catch (error) {
|
||||
// This requires some extra dependencies and is optional
|
||||
console.log("Graph visualization not available");
|
||||
}
|
||||
```
|
||||
:::
|
||||
|
||||

|
||||
|
||||
## 8. Run the chatbot
|
||||
|
||||
## 7. Run the chatbot
|
||||
|
||||
Now run the chatbot!
|
||||
|
||||
:::python
|
||||
!!! tip
|
||||
|
||||
You can exit the chat loop at any time by typing `quit`, `exit`, or `q`.
|
||||
@@ -281,48 +160,18 @@ while True:
|
||||
Assistant: LangGraph is a library designed to help build stateful multi-agent applications using language models. It provides tools for creating workflows and state machines to coordinate multiple AI agents or language model interactions. LangGraph is built on top of LangChain, leveraging its components while adding graph-based coordination capabilities. It's particularly useful for developing more complex, stateful AI applications that go beyond simple query-response interactions.
|
||||
Goodbye!
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
import { HumanMessage } from "@langchain/core/messages";
|
||||
|
||||
async function streamGraphUpdates(userInput: string) {
|
||||
const stream = await graph.stream({
|
||||
messages: [new HumanMessage(userInput)]
|
||||
});
|
||||
|
||||
for await (const event of stream) {
|
||||
for (const value of Object.values(event)) {
|
||||
console.log("Assistant:", value.messages[value.messages.length - 1].content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Example usage
|
||||
const userInput = "What do you know about LangGraph?";
|
||||
console.log("User:", userInput);
|
||||
await streamGraphUpdates(userInput);
|
||||
```
|
||||
|
||||
```
|
||||
User: What do you know about LangGraph?
|
||||
Assistant: LangGraph is a library designed to help build stateful multi-agent applications using language models. It provides tools for creating workflows and state machines to coordinate multiple AI agents or language model interactions. LangGraph is built on top of LangChain, leveraging its components while adding graph-based coordination capabilities. It's particularly useful for developing more complex, stateful AI applications that go beyond simple query-response interactions.
|
||||
```
|
||||
:::
|
||||
|
||||
**Congratulations!** You've built your first chatbot using LangGraph. This bot can engage in basic conversation by taking user input and generating responses using an LLM. You can inspect a [LangSmith Trace](https://smith.langchain.com/public/7527e308-9502-4894-b347-f34385740d5a/r) for the call above.
|
||||
|
||||
Below is the full code for this tutorial:
|
||||
|
||||
:::python
|
||||
```python
|
||||
from typing import Annotated
|
||||
|
||||
from langchain.chat_models import init_chat_model
|
||||
from typing_extensions import TypedDict
|
||||
|
||||
from langgraph.graph import StateGraph, START, END
|
||||
from langgraph.graph import StateGraph, START
|
||||
from langgraph.graph.message import add_messages
|
||||
|
||||
|
||||
@@ -345,44 +194,11 @@ def chatbot(state: State):
|
||||
# the node is used.
|
||||
graph_builder.add_node("chatbot", chatbot)
|
||||
graph_builder.add_edge(START, "chatbot")
|
||||
graph_builder.add_edge("chatbot", END)
|
||||
graph = graph_builder.compile()
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
import { Annotation } from "@langchain/langgraph";
|
||||
import { BaseMessage, HumanMessage } from "@langchain/core/messages";
|
||||
import { StateGraph, START, END } from "@langchain/langgraph";
|
||||
import { ChatAnthropic } from "@langchain/anthropic";
|
||||
|
||||
const StateAnnotation = Annotation.Root({
|
||||
messages: Annotation<BaseMessage[]>({
|
||||
reducer: (x, y) => x.concat(y),
|
||||
}),
|
||||
});
|
||||
|
||||
const graphBuilder = new StateGraph(StateAnnotation);
|
||||
|
||||
const llm = new ChatAnthropic({
|
||||
model: "claude-3-5-sonnet-latest",
|
||||
});
|
||||
|
||||
const chatbot = async (state: typeof StateAnnotation.State) => {
|
||||
return { messages: [await llm.invoke(state.messages)] };
|
||||
};
|
||||
|
||||
// The first argument is the unique node name
|
||||
// The second argument is the function or object that will be called whenever
|
||||
// the node is used.
|
||||
graphBuilder.addNode("chatbot", chatbot);
|
||||
graphBuilder.addEdge(START, "chatbot");
|
||||
graphBuilder.addEdge("chatbot", END);
|
||||
const graph = graphBuilder.compile();
|
||||
```
|
||||
:::
|
||||
|
||||
## Next steps
|
||||
|
||||
You may have noticed that the bot's knowledge is limited to what's in its training data. In the next part, we'll [add a web search tool](./2-add-tools.md) to expand the bot's knowledge and make it more capable.
|
||||
You may have noticed that the bot's knowledge is limited to what's in its training data. In the next part, we'll [add a web search tool](./2-add-tools.md) to expand the bot's knowledge and make it more capable.
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Add tools
|
||||
|
||||
To handle queries that your chatbot can't answer "from memory", integrate a web search tool. The chatbot can use this tool to find relevant information and provide better responses.
|
||||
To handle queries you chatbot can't answer "from memory", integrate a web search tool. The chatbot can use this tool to find relevant information and provide better responses.
|
||||
|
||||
!!! note
|
||||
|
||||
@@ -8,39 +8,19 @@ To handle queries that your chatbot can't answer "from memory", integrate a web
|
||||
|
||||
## Prerequisites
|
||||
|
||||
:::python
|
||||
Before you start this tutorial, ensure you have the following:
|
||||
|
||||
- An API key for the [Tavily Search Engine](https://python.langchain.com/docs/integrations/tools/tavily_search/).
|
||||
:::
|
||||
|
||||
:::js
|
||||
Before you start this tutorial, ensure you have the following:
|
||||
|
||||
- An API key for the [Tavily Search Engine](https://js.langchain.com/docs/integrations/tools/tavily_search/).
|
||||
:::
|
||||
|
||||
## 1. Install the search engine
|
||||
|
||||
:::python
|
||||
Install the requirements to use the [Tavily Search Engine](https://python.langchain.com/docs/integrations/tools/tavily_search/):
|
||||
|
||||
```bash
|
||||
pip install -U langchain-tavily
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
Install the requirements to use the [Tavily Search Engine](https://js.langchain.com/docs/integrations/tools/tavily_search/):
|
||||
|
||||
```bash
|
||||
npm install @langchain/community
|
||||
```
|
||||
:::
|
||||
|
||||
## 2. Configure your environment
|
||||
|
||||
:::python
|
||||
Configure your environment with your search engine API key:
|
||||
|
||||
```bash
|
||||
@@ -50,21 +30,11 @@ _set_env("TAVILY_API_KEY")
|
||||
```
|
||||
TAVILY_API_KEY: ········
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
Configure your environment with your search engine API key:
|
||||
|
||||
```typescript
|
||||
process.env.TAVILY_API_KEY = "tvly-...";
|
||||
```
|
||||
:::
|
||||
|
||||
## 3. Define the tool
|
||||
|
||||
Define the web search tool:
|
||||
|
||||
:::python
|
||||
```python
|
||||
from langchain_tavily import TavilySearch
|
||||
|
||||
@@ -72,21 +42,9 @@ tool = TavilySearch(max_results=2)
|
||||
tools = [tool]
|
||||
tool.invoke("What's a 'node' in LangGraph?")
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
import { TavilySearchResults } from "@langchain/community/tools/tavily_search";
|
||||
|
||||
const tool = new TavilySearchResults({ maxResults: 2 });
|
||||
const tools = [tool];
|
||||
await tool.invoke("What's a 'node' in LangGraph?");
|
||||
```
|
||||
:::
|
||||
|
||||
The results are page summaries our chat bot can use to answer questions:
|
||||
|
||||
:::python
|
||||
```
|
||||
{'query': "What's a 'node' in LangGraph?",
|
||||
'follow_up_questions': None,
|
||||
@@ -104,17 +62,9 @@ The results are page summaries our chat bot can use to answer questions:
|
||||
'raw_content': None}],
|
||||
'response_time': 1.38}
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```
|
||||
'[{"title":"Introduction to LangGraph: A Beginner\'s Guide - Medium","url":"https://medium.com/@cplog/introduction-to-langgraph-a-beginners-guide-14f9be027141","content":"Stateful Graph: LangGraph revolves around the concept of a stateful graph, where each node in the graph represents a step in your computation, and the graph maintains a state that is passed around and updated as the computation progresses. LangGraph supports conditional edges, allowing you to dynamically determine the next node to execute based on the current state of the graph. We define nodes for classifying the input, handling greetings, and handling search queries. def classify_input_node(state): LangGraph is a versatile tool for building complex, stateful applications with LLMs. By understanding its core concepts and working through simple examples, beginners can start to leverage its power for their projects. Remember to pay attention to state management, conditional edges, and ensuring there are no dead-end nodes in your graph.","score":0.7065353,"raw_content":null},{"title":"LangGraph Tutorial: What Is LangGraph and How to Use It?","url":"https://www.datacamp.com/tutorial/langgraph-tutorial","content":"LangGraph is a library within the LangChain ecosystem that provides a framework for defining, coordinating, and executing multiple LLM agents (or chains) in a structured and efficient manner. By managing the flow of data and the sequence of operations, LangGraph allows developers to focus on the high-level logic of their applications rather than the intricacies of agent coordination. Whether you need a chatbot that can handle various types of user requests or a multi-agent system that performs complex tasks, LangGraph provides the tools to build exactly what you need. LangGraph significantly simplifies the development of complex LLM applications by providing a structured framework for managing state and coordinating agent interactions.","score":0.5008063,"raw_content":null}]'
|
||||
```
|
||||
:::
|
||||
|
||||
## 4. Define the graph
|
||||
|
||||
:::python
|
||||
For the `StateGraph` you created in the [first tutorial](./1-build-basic-chatbot.md), add `bind_tools` on the LLM. This lets the LLM know the correct JSON format to use if it wants to use the search engine.
|
||||
|
||||
Let's first select our LLM:
|
||||
@@ -153,52 +103,9 @@ def chatbot(state: State):
|
||||
|
||||
graph_builder.add_node("chatbot", chatbot)
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
For the `StateGraph` you created in the [first tutorial](./1-build-basic-chatbot.md), add `bindTools` on the LLM. This lets the LLM know the correct JSON format to use if it wants to use the search engine.
|
||||
|
||||
Let's first select our LLM:
|
||||
|
||||
```typescript
|
||||
import { ChatOpenAI } from "@langchain/openai";
|
||||
|
||||
const llm = new ChatOpenAI({
|
||||
model: "gpt-4o",
|
||||
temperature: 0,
|
||||
});
|
||||
```
|
||||
|
||||
We can now incorporate it into a `StateGraph`:
|
||||
|
||||
```typescript hl_lines="15"
|
||||
import { Annotation } from "@langchain/langgraph";
|
||||
import { BaseMessage } from "@langchain/core/messages";
|
||||
|
||||
const StateAnnotation = Annotation.Root({
|
||||
messages: Annotation<BaseMessage[]>({
|
||||
reducer: (x, y) => x.concat(y),
|
||||
}),
|
||||
});
|
||||
|
||||
import { StateGraph, START, END } from "@langchain/langgraph";
|
||||
|
||||
const graphBuilder = new StateGraph(StateAnnotation);
|
||||
|
||||
// Modification: tell the LLM which tools it can call
|
||||
const llmWithTools = llm.bindTools(tools);
|
||||
|
||||
const chatbot = async (state: typeof StateAnnotation.State) => {
|
||||
return { messages: [await llmWithTools.invoke(state.messages)] };
|
||||
};
|
||||
|
||||
graphBuilder.addNode("chatbot", chatbot);
|
||||
```
|
||||
:::
|
||||
|
||||
## 5. Create a function to run the tools
|
||||
|
||||
:::python
|
||||
Now, create a function to run the tools if they are called. Do this by adding the tools to a new node called`BasicToolNode` that checks the most recent message in the state and calls tools if the message contains `tool_calls`. It relies on the LLM's `tool_calling` support, which is available in Anthropic, OpenAI, Google Gemini, and a number of other LLM providers.
|
||||
|
||||
```python
|
||||
@@ -236,54 +143,10 @@ class BasicToolNode:
|
||||
tool_node = BasicToolNode(tools=[tool])
|
||||
graph_builder.add_node("tools", tool_node)
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
Now, create a function to run the tools if they are called. Do this by adding the tools to a new node called `BasicToolNode` that checks the most recent message in the state and calls tools if the message contains `tool_calls`. It relies on the LLM's `tool_calling` support, which is available in Anthropic, OpenAI, Google Gemini, and a number of other LLM providers.
|
||||
|
||||
```typescript
|
||||
import { ToolMessage } from "@langchain/core/messages";
|
||||
|
||||
class BasicToolNode {
|
||||
private toolsByName: Record<string, any>;
|
||||
|
||||
constructor(tools: any[]) {
|
||||
this.toolsByName = {};
|
||||
for (const tool of tools) {
|
||||
this.toolsByName[tool.name] = tool;
|
||||
}
|
||||
}
|
||||
|
||||
async __call__(inputs: Record<string, any>): Promise<{ messages: ToolMessage[] }> {
|
||||
const messages = inputs.messages || [];
|
||||
if (messages.length === 0) {
|
||||
throw new Error("No message found in input");
|
||||
}
|
||||
const message = messages[messages.length - 1];
|
||||
const outputs: ToolMessage[] = [];
|
||||
|
||||
for (const toolCall of message.tool_calls || []) {
|
||||
const toolResult = await this.toolsByName[toolCall.name].invoke(toolCall.args);
|
||||
outputs.push(
|
||||
new ToolMessage({
|
||||
content: JSON.stringify(toolResult),
|
||||
name: toolCall.name,
|
||||
tool_call_id: toolCall.id,
|
||||
})
|
||||
);
|
||||
}
|
||||
return { messages: outputs };
|
||||
}
|
||||
}
|
||||
|
||||
const toolNode = new BasicToolNode([tool]);
|
||||
graphBuilder.addNode("tools", async (state) => toolNode.__call__(state));
|
||||
```
|
||||
:::
|
||||
|
||||
!!! note
|
||||
|
||||
If you do not want to build this yourself in the future, you can use LangGraph's prebuilt [ToolNode](https://langchain-ai.github.io/langgraph/reference/agents/#langgraph.prebuilt.tool_node.ToolNode).
|
||||
If you do not want to build this yourself in the future, you can use LangGraph's prebuilt [ToolNode](https://langchain-ai.github.io/langgraph/reference/prebuilt/#toolnode).
|
||||
|
||||
## 6. Define the `conditional_edges`
|
||||
|
||||
@@ -291,7 +154,6 @@ With the tool node added, now you can define the `conditional_edges`.
|
||||
|
||||
**Edges** route the control flow from one node to the next. **Conditional edges** start from a single node and usually contain "if" statements to route to different nodes depending on the current graph state. These functions receive the current graph `state` and return a string or list of strings indicating which node(s) to call next.
|
||||
|
||||
:::python
|
||||
Next, define a router function called `route_tools` that checks for `tool_calls` in the chatbot's output. Provide this function to the graph by calling `add_conditional_edges`, which tells the graph that whenever the `chatbot` node completes to check this function to see where to go next.
|
||||
|
||||
The condition will route to `tools` if tool calls are present and `END` if not. Because the condition can return `END`, you do not need to explicitly set a `finish_point` this time.
|
||||
@@ -332,51 +194,6 @@ graph_builder.add_edge("tools", "chatbot")
|
||||
graph_builder.add_edge(START, "chatbot")
|
||||
graph = graph_builder.compile()
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
Next, define a router function called `routeTools` that checks for `tool_calls` in the chatbot's output. Provide this function to the graph by calling `addConditionalEdges`, which tells the graph that whenever the `chatbot` node completes to check this function to see where to go next.
|
||||
|
||||
The condition will route to `tools` if tool calls are present and `END` if not. Because the condition can return `END`, you do not need to explicitly set a `finish_point` this time.
|
||||
|
||||
```typescript
|
||||
import { AIMessage } from "@langchain/core/messages";
|
||||
|
||||
const routeTools = (state: typeof StateAnnotation.State) => {
|
||||
/**
|
||||
* Use in the conditional_edge to route to the ToolNode if the last message
|
||||
* has tool calls. Otherwise, route to the end.
|
||||
*/
|
||||
const messages = state.messages;
|
||||
const lastMessage = messages[messages.length - 1] as AIMessage;
|
||||
|
||||
if (lastMessage.tool_calls && lastMessage.tool_calls.length > 0) {
|
||||
return "tools";
|
||||
}
|
||||
return END;
|
||||
};
|
||||
|
||||
// The `routeTools` function returns "tools" if the chatbot asks to use a tool, and "END" if
|
||||
// it is fine directly responding. This conditional routing defines the main agent loop.
|
||||
graphBuilder.addConditionalEdges(
|
||||
"chatbot",
|
||||
routeTools,
|
||||
// The following dictionary lets you tell the graph to interpret the condition's outputs as a specific node
|
||||
// It defaults to the identity function, but if you
|
||||
// want to use a node named something else apart from "tools",
|
||||
// You can update the value of the dictionary to something else
|
||||
// e.g., "tools": "my_tools"
|
||||
{
|
||||
tools: "tools",
|
||||
[END]: END,
|
||||
}
|
||||
);
|
||||
// Any time a tool is called, we return to the chatbot to decide the next step
|
||||
graphBuilder.addEdge("tools", "chatbot");
|
||||
graphBuilder.addEdge(START, "chatbot");
|
||||
const graph = graphBuilder.compile();
|
||||
```
|
||||
:::
|
||||
|
||||
!!! note
|
||||
|
||||
@@ -384,7 +201,6 @@ const graph = graphBuilder.compile();
|
||||
|
||||
## 7. Visualize the graph (optional)
|
||||
|
||||
:::python
|
||||
You can visualize the graph using the `get_graph` method and one of the "draw" methods, like `draw_ascii` or `draw_png`. The `draw` methods each require additional dependencies.
|
||||
|
||||
```python
|
||||
@@ -396,26 +212,6 @@ except Exception:
|
||||
# This requires some extra dependencies and is optional
|
||||
pass
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
You can visualize the graph using the `getGraph` method and one of the "draw" methods, like `drawAscii` or `drawMermaidPng`. The `draw` methods each require additional dependencies.
|
||||
|
||||
```typescript
|
||||
import * as tslab from "tslab";
|
||||
|
||||
try {
|
||||
const representation = graph.getGraph();
|
||||
const image = await representation.drawMermaidPng();
|
||||
const arrayBuffer = await image.arrayBuffer();
|
||||
|
||||
await tslab.display.png(new Uint8Array(arrayBuffer));
|
||||
} catch (error) {
|
||||
// This requires some extra dependencies and is optional
|
||||
console.log("Graph visualization not available");
|
||||
}
|
||||
```
|
||||
:::
|
||||
|
||||

|
||||
|
||||
@@ -423,7 +219,6 @@ try {
|
||||
|
||||
Now you can ask the chatbot questions outside its training data:
|
||||
|
||||
:::python
|
||||
```python
|
||||
def stream_graph_updates(user_input: str):
|
||||
for event in graph.stream({"messages": [{"role": "user", "content": user_input}]}):
|
||||
@@ -479,71 +274,11 @@ LangGraph appears to be a significant tool in the evolving landscape of LLM-base
|
||||
Goodbye!
|
||||
Output is truncated. View as a scrollable element or open in a text editor. Adjust cell output settings...
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
import { HumanMessage } from "@langchain/core/messages";
|
||||
|
||||
const streamGraphUpdates = async (userInput: string) => {
|
||||
const stream = await graph.stream(
|
||||
{ messages: [new HumanMessage(userInput)] },
|
||||
{ streamMode: "values" }
|
||||
);
|
||||
|
||||
for await (const event of stream) {
|
||||
const messages = event.messages;
|
||||
const lastMessage = messages[messages.length - 1];
|
||||
console.log("Assistant:", lastMessage.content);
|
||||
}
|
||||
};
|
||||
|
||||
// Example usage
|
||||
const userInput = "What do you know about LangGraph?";
|
||||
console.log("User:", userInput);
|
||||
await streamGraphUpdates(userInput);
|
||||
```
|
||||
|
||||
```
|
||||
Assistant: I'll search for information about LangGraph to provide you with accurate details.
|
||||
Assistant: [{"title": "Introduction to LangGraph: A Beginner's Guide - Medium", "url": "https://medium.com/@cplog/introduction-to-langgraph-a-beginners-guide-14f9be027141", "content": "Stateful Graph: LangGraph revolves around the concept of a stateful graph, where each node in the graph represents a step in your computation, and the graph maintains a state that is passed around and updated as the computation progresses. LangGraph supports conditional edges, allowing you to dynamically determine the next node to execute based on the current state of the graph. We define nodes for classifying the input, handling greetings, and handling search queries. def classify_input_node(state): LangGraph is a versatile tool for building complex, stateful applications with LLMs. By understanding its core concepts and working through simple examples, beginners can start to leverage its power for their projects. Remember to pay attention to state management, conditional edges, and ensuring there are no dead-end nodes in your graph.", "score": 0.7065353, "raw_content": null}, {"title": "LangGraph Tutorial: What Is LangGraph and How to Use It?", "url": "https://www.datacamp.com/tutorial/langgraph-tutorial", "content": "LangGraph is a library within the LangChain ecosystem that provides a framework for defining, coordinating, and executing multiple LLM agents or chains in a structured and efficient manner. By managing the flow of data and the sequence of operations, LangGraph allows developers to focus on the high-level logic of their applications rather than the intricacies of agent coordination. Whether you need a chatbot that can handle various types of user requests or a multi-agent system that performs complex tasks, LangGraph provides the tools to build exactly what you need. LangGraph significantly simplifies the development of complex LLM applications by providing a structured framework for managing state and coordinating agent interactions.", "score": 0.5008063, "raw_content": null}]
|
||||
Assistant: Based on the search results, I can provide you with comprehensive information about LangGraph:
|
||||
|
||||
## What is LangGraph?
|
||||
|
||||
LangGraph is a library within the LangChain ecosystem designed for building stateful, multi-actor applications with Large Language Models (LLMs). It provides a framework for defining, coordinating, and executing multiple LLM agents or chains in a structured and efficient manner.
|
||||
|
||||
## Key Features:
|
||||
|
||||
1. **Stateful Graph Architecture**: LangGraph revolves around the concept of a stateful graph where each node represents a step in your computation, and the graph maintains state that is passed around and updated as the computation progresses.
|
||||
|
||||
2. **Conditional Edges**: It supports conditional edges, allowing you to dynamically determine the next node to execute based on the current state of the graph.
|
||||
|
||||
3. **Multi-Agent Coordination**: LangGraph manages the flow of data and sequence of operations, allowing developers to focus on high-level logic rather than the intricacies of agent coordination.
|
||||
|
||||
## Use Cases:
|
||||
|
||||
- Building conversational agents
|
||||
- Creating chatbots that can handle various types of user requests
|
||||
- Developing multi-agent systems that perform complex tasks
|
||||
- Complex task automation
|
||||
- Custom LLM-backed experiences
|
||||
|
||||
## Benefits:
|
||||
|
||||
- **Simplified Development**: LangGraph significantly simplifies the development of complex LLM applications by providing a structured framework for managing state and coordinating agent interactions.
|
||||
- **Flexibility**: It's a versatile tool for building complex, stateful applications with LLMs.
|
||||
- **Focus on Logic**: Developers can focus on the high-level logic of their applications rather than coordination details.
|
||||
|
||||
LangGraph is particularly valuable for projects that require sophisticated AI workflows with multiple steps, decision points, and state management across different components.
|
||||
```
|
||||
:::
|
||||
|
||||
## 9. Use prebuilts
|
||||
|
||||
For ease of use, adjust your code to replace the following with LangGraph prebuilt components. These have built in functionality like parallel API execution.
|
||||
|
||||
:::python
|
||||
- `BasicToolNode` is replaced with the prebuilt [ToolNode](https://langchain-ai.github.io/langgraph/reference/prebuilt/#toolnode)
|
||||
- `route_tools` is replaced with the prebuilt [tools_condition](https://langchain-ai.github.io/langgraph/reference/prebuilt/#tools_condition)
|
||||
|
||||
@@ -587,56 +322,9 @@ graph_builder.add_edge("tools", "chatbot")
|
||||
graph_builder.add_edge(START, "chatbot")
|
||||
graph = graph_builder.compile()
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
- `BasicToolNode` is replaced with the prebuilt [ToolNode](https://langchain-ai.github.io/langgraph/reference/prebuilt/#toolnode)
|
||||
- `routeTools` is replaced with the prebuilt [tools_condition](https://langchain-ai.github.io/langgraph/reference/prebuilt/#tools_condition)
|
||||
|
||||
```typescript hl_lines="25 30"
|
||||
import { Annotation } from "@langchain/langgraph";
|
||||
import { BaseMessage } from "@langchain/core/messages";
|
||||
import { TavilySearchResults } from "@langchain/community/tools/tavily_search";
|
||||
import { ChatOpenAI } from "@langchain/openai";
|
||||
|
||||
import { StateGraph, START, END } from "@langchain/langgraph";
|
||||
import { ToolNode, toolsCondition } from "@langchain/langgraph/prebuilt";
|
||||
|
||||
const StateAnnotation = Annotation.Root({
|
||||
messages: Annotation<BaseMessage[]>({
|
||||
reducer: (x, y) => x.concat(y),
|
||||
}),
|
||||
});
|
||||
|
||||
const graphBuilder = new StateGraph(StateAnnotation);
|
||||
|
||||
const tool = new TavilySearchResults({ maxResults: 2 });
|
||||
const tools = [tool];
|
||||
const llm = new ChatOpenAI({ model: "gpt-4o", temperature: 0 });
|
||||
const llmWithTools = llm.bindTools(tools);
|
||||
|
||||
const chatbot = async (state: typeof StateAnnotation.State) => {
|
||||
return { messages: [await llmWithTools.invoke(state.messages)] };
|
||||
};
|
||||
|
||||
graphBuilder.addNode("chatbot", chatbot);
|
||||
|
||||
const toolNode = new ToolNode(tools);
|
||||
graphBuilder.addNode("tools", toolNode);
|
||||
|
||||
graphBuilder.addConditionalEdges(
|
||||
"chatbot",
|
||||
toolsCondition,
|
||||
);
|
||||
// Any time a tool is called, we return to the chatbot to decide the next step
|
||||
graphBuilder.addEdge("tools", "chatbot");
|
||||
graphBuilder.addEdge(START, "chatbot");
|
||||
const graph = graphBuilder.compile();
|
||||
```
|
||||
:::
|
||||
|
||||
**Congratulations!** You've created a conversational agent in LangGraph that can use a search engine to retrieve updated information when needed. Now it can handle a wider range of user queries. To inspect all the steps your agent just took, check out this [LangSmith trace](https://smith.langchain.com/public/4fbd7636-25af-4638-9587-5a02fdbb0172/r).
|
||||
|
||||
## Next steps
|
||||
|
||||
The chatbot cannot remember past interactions on its own, which limits its ability to have coherent, multi-turn conversations. In the next part, you will [add **memory**](./3-add-memory.md) to address this.
|
||||
The chatbot cannot remember past interactions on its own, which limits its ability to have coherent, multi-turn conversations. In the next part, you will [add **memory**](./3-add-memory.md) to address this.
|
||||
|
||||
@@ -14,21 +14,11 @@ We will see later that **checkpointing** is _much_ more powerful than simple cha
|
||||
|
||||
Create a `MemorySaver` checkpointer:
|
||||
|
||||
:::python
|
||||
``` python
|
||||
from langgraph.checkpoint.memory import MemorySaver
|
||||
|
||||
memory = MemorySaver()
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
import { MemorySaver } from "@langchain/langgraph";
|
||||
|
||||
const memory = new MemorySaver();
|
||||
```
|
||||
:::
|
||||
|
||||
This is in-memory checkpointer, which is convenient for the tutorial. However, in a production application, you would likely change this to use `SqliteSaver` or `PostgresSaver` and connect a database.
|
||||
|
||||
@@ -36,7 +26,6 @@ This is in-memory checkpointer, which is convenient for the tutorial. However, i
|
||||
|
||||
Compile the graph with the provided checkpointer, which will checkpoint the `State` as the graph works through each node:
|
||||
|
||||
:::python
|
||||
``` python
|
||||
graph = graph_builder.compile(checkpointer=memory)
|
||||
```
|
||||
@@ -50,27 +39,6 @@ except Exception:
|
||||
# This requires some extra dependencies and is optional
|
||||
pass
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
const graph = graphBuilder.compile({ checkpointer: memory });
|
||||
```
|
||||
|
||||
```typescript
|
||||
import * as tslab from "tslab";
|
||||
|
||||
try {
|
||||
const representation = graph.getGraph();
|
||||
const image = await representation.drawMermaidPng();
|
||||
const arrayBuffer = await image.arrayBuffer();
|
||||
|
||||
await tslab.display.png(new Uint8Array(arrayBuffer));
|
||||
} catch (e) {
|
||||
// This requires some extra dependencies and is optional
|
||||
}
|
||||
```
|
||||
:::
|
||||
|
||||
## 3. Interact with your chatbot
|
||||
|
||||
@@ -78,21 +46,12 @@ Now you can interact with your bot!
|
||||
|
||||
1. Pick a thread to use as the key for this conversation.
|
||||
|
||||
:::python
|
||||
```python
|
||||
config = {"configurable": {"thread_id": "1"}}
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
const config = { configurable: { thread_id: "1" } };
|
||||
```
|
||||
:::
|
||||
|
||||
2. Call your chatbot:
|
||||
|
||||
:::python
|
||||
```python
|
||||
user_input = "Hi there! My name is Will."
|
||||
|
||||
@@ -105,24 +64,6 @@ Now you can interact with your bot!
|
||||
for event in events:
|
||||
event["messages"][-1].pretty_print()
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
const userInput = "Hi there! My name is Will.";
|
||||
|
||||
// The config is the **second positional argument** to stream() or invoke()!
|
||||
const events = await graph.stream(
|
||||
{ messages: [{ role: "user", content: userInput }] },
|
||||
{ ...config, streamMode: "values" }
|
||||
);
|
||||
|
||||
for await (const event of events) {
|
||||
const messages = event.messages;
|
||||
console.log(messages[messages.length - 1]);
|
||||
}
|
||||
```
|
||||
:::
|
||||
|
||||
```
|
||||
================================ Human Message =================================
|
||||
@@ -133,23 +74,14 @@ Now you can interact with your bot!
|
||||
Hello Will! It's nice to meet you. How can I assist you today? Is there anything specific you'd like to know or discuss?
|
||||
```
|
||||
|
||||
:::python
|
||||
!!! note
|
||||
|
||||
The config was provided as the **second positional argument** when calling our graph. It importantly is _not_ nested within the graph inputs (`{'messages': []}`).
|
||||
:::
|
||||
|
||||
:::js
|
||||
!!! note
|
||||
|
||||
The config was provided as the **second positional argument** when calling our graph. It importantly is _not_ nested within the graph inputs (`{ messages: [] }`).
|
||||
:::
|
||||
|
||||
## 4. Ask a follow up question
|
||||
|
||||
Ask a follow up question:
|
||||
|
||||
:::python
|
||||
```python
|
||||
user_input = "Remember my name?"
|
||||
|
||||
@@ -162,24 +94,6 @@ events = graph.stream(
|
||||
for event in events:
|
||||
event["messages"][-1].pretty_print()
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
const userInput2 = "Remember my name?";
|
||||
|
||||
// The config is the **second positional argument** to stream() or invoke()!
|
||||
const events2 = await graph.stream(
|
||||
{ messages: [{ role: "user", content: userInput2 }] },
|
||||
{ ...config, streamMode: "values" }
|
||||
);
|
||||
|
||||
for await (const event of events2) {
|
||||
const messages = event.messages;
|
||||
console.log(messages[messages.length - 1]);
|
||||
}
|
||||
```
|
||||
:::
|
||||
|
||||
```
|
||||
================================ Human Message =================================
|
||||
@@ -194,7 +108,6 @@ Of course, I remember your name, Will. I always try to pay attention to importan
|
||||
|
||||
Don't believe me? Try this using a different config.
|
||||
|
||||
:::python
|
||||
```python
|
||||
# The only difference is we change the `thread_id` here to "2" instead of "1"
|
||||
events = graph.stream(
|
||||
@@ -206,23 +119,6 @@ events = graph.stream(
|
||||
for event in events:
|
||||
event["messages"][-1].pretty_print()
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
// The only difference is we change the `thread_id` here to "2" instead of "1"
|
||||
const events3 = await graph.stream(
|
||||
{ messages: [{ role: "user", content: userInput2 }] },
|
||||
// highlight-next-line
|
||||
{ configurable: { thread_id: "2" }, streamMode: "values" }
|
||||
);
|
||||
|
||||
for await (const event of events3) {
|
||||
const messages = event.messages;
|
||||
console.log(messages[messages.length - 1]);
|
||||
}
|
||||
```
|
||||
:::
|
||||
|
||||
```
|
||||
================================ Human Message =================================
|
||||
@@ -237,15 +133,8 @@ I apologize, but I don't have any previous context or memory of your name. As an
|
||||
|
||||
## 5. Inspect the state
|
||||
|
||||
:::python
|
||||
By now, we have made a few checkpoints across two different threads. But what goes into a checkpoint? To inspect a graph's `state` for a given config at any time, call `get_state(config)`.
|
||||
:::
|
||||
|
||||
:::js
|
||||
By now, we have made a few checkpoints across two different threads. But what goes into a checkpoint? To inspect a graph's `state` for a given config at any time, call `getState(config)`.
|
||||
:::
|
||||
|
||||
:::python
|
||||
```python
|
||||
snapshot = graph.get_state(config)
|
||||
snapshot
|
||||
@@ -258,75 +147,6 @@ StateSnapshot(values={'messages': [HumanMessage(content='Hi there! My name is Wi
|
||||
```
|
||||
snapshot.next # (since the graph ended this turn, `next` is empty. If you fetch a state from within a graph invocation, next tells which node will execute next)
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
const snapshot = await graph.getState(config);
|
||||
console.log(snapshot);
|
||||
```
|
||||
|
||||
```
|
||||
StateSnapshot {
|
||||
values: {
|
||||
messages: [
|
||||
HumanMessage {
|
||||
content: 'Hi there! My name is Will.',
|
||||
id: '8c1ca919-c553-4ebf-95d4-b59a2d61e078'
|
||||
},
|
||||
AIMessage {
|
||||
content: "Hello Will! It's nice to meet you. How can I assist you today? Is there anything specific you'd like to know or discuss?",
|
||||
id: 'run-58587b77-8c82-41e6-8a90-d62c444a261d-0'
|
||||
},
|
||||
HumanMessage {
|
||||
content: 'Remember my name?',
|
||||
id: 'daba7df6-ad75-4d6b-8057-745881cea1ca'
|
||||
},
|
||||
AIMessage {
|
||||
content: "Of course, I remember your name, Will. I always try to pay attention to important details that users share with me. Is there anything else you'd like to talk about or any questions you have? I'm here to help with a wide range of topics or tasks.",
|
||||
id: 'run-ffeaae5c-4d2d-4ddb-bd59-5d5cbf2a5af8-0'
|
||||
}
|
||||
]
|
||||
},
|
||||
next: [],
|
||||
config: {
|
||||
configurable: {
|
||||
thread_id: '1',
|
||||
checkpoint_ns: '',
|
||||
checkpoint_id: '1ef7d06e-93e0-6acc-8004-f2ac846575d2'
|
||||
}
|
||||
},
|
||||
metadata: {
|
||||
source: 'loop',
|
||||
writes: {
|
||||
chatbot: {
|
||||
messages: [
|
||||
AIMessage {
|
||||
content: "Of course, I remember your name, Will. I always try to pay attention to important details that users share with me. Is there anything else you'd like to talk about or any questions you have? I'm here to help with a wide range of topics or tasks.",
|
||||
id: 'run-ffeaae5c-4d2d-4ddb-bd59-5d5cbf2a5af8-0'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
step: 4,
|
||||
parents: {}
|
||||
},
|
||||
createdAt: '2024-09-27T19:30:10.820758+00:00',
|
||||
parentConfig: {
|
||||
configurable: {
|
||||
thread_id: '1',
|
||||
checkpoint_ns: '',
|
||||
checkpoint_id: '1ef7d06e-859f-6206-8003-e1bd3c264b8f'
|
||||
}
|
||||
},
|
||||
tasks: []
|
||||
}
|
||||
```
|
||||
|
||||
```typescript
|
||||
console.log(snapshot.next); // (since the graph ended this turn, `next` is empty. If you fetch a state from within a graph invocation, next tells which node will execute next)
|
||||
```
|
||||
:::
|
||||
|
||||
The snapshot above contains the current state values, corresponding config, and the `next` node to process. In our case, the graph has reached an `END` state, so `next` is empty.
|
||||
|
||||
@@ -337,25 +157,14 @@ Check out the code snippet below to review the graph from this tutorial:
|
||||
{!snippets/chat_model_tabs.md!}
|
||||
|
||||
<!---
|
||||
:::python
|
||||
```python
|
||||
from langchain.chat_models import init_chat_model
|
||||
|
||||
llm = init_chat_model("anthropic:claude-3-5-sonnet-latest")
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
import { ChatOpenAI } from "@langchain/openai";
|
||||
|
||||
const llm = new ChatOpenAI({ model: "gpt-4" });
|
||||
```
|
||||
:::
|
||||
-->
|
||||
|
||||
:::python
|
||||
```python hl_lines="36 37"
|
||||
```python
|
||||
from typing import Annotated
|
||||
|
||||
from langchain.chat_models import init_chat_model
|
||||
@@ -394,50 +203,6 @@ graph_builder.set_entry_point("chatbot")
|
||||
memory = MemorySaver()
|
||||
graph = graph_builder.compile(checkpointer=memory)
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript hl_lines="36 37"
|
||||
import { Annotation } from "@langchain/langgraph";
|
||||
import { ChatOpenAI } from "@langchain/openai";
|
||||
import { TavilySearchResults } from "@langchain/community/tools/tavily_search";
|
||||
import { BaseMessage } from "@langchain/core/messages";
|
||||
import { MemorySaver, StateGraph } from "@langchain/langgraph";
|
||||
import { ToolNode, toolsCondition } from "@langchain/langgraph/prebuilt";
|
||||
|
||||
const StateAnnotation = Annotation.Root({
|
||||
messages: Annotation<BaseMessage[]>({
|
||||
reducer: (x, y) => x.concat(y),
|
||||
}),
|
||||
});
|
||||
|
||||
const graphBuilder = new StateGraph(StateAnnotation);
|
||||
|
||||
const tool = new TavilySearchResults({ maxResults: 2 });
|
||||
const tools = [tool];
|
||||
const llm = new ChatOpenAI({ model: "gpt-4" });
|
||||
const llmWithTools = llm.bindTools(tools);
|
||||
|
||||
function chatbot(state: typeof StateAnnotation.State) {
|
||||
return { messages: [llmWithTools.invoke(state.messages)] };
|
||||
}
|
||||
|
||||
graphBuilder.addNode("chatbot", chatbot);
|
||||
|
||||
const toolNode = new ToolNode(tools);
|
||||
graphBuilder.addNode("tools", toolNode);
|
||||
|
||||
graphBuilder.addConditionalEdges(
|
||||
"chatbot",
|
||||
toolsCondition,
|
||||
);
|
||||
graphBuilder.addEdge("tools", "chatbot");
|
||||
graphBuilder.addEdge("__start__", "chatbot");
|
||||
|
||||
const memory = new MemorySaver();
|
||||
const graph = graphBuilder.compile({ checkpointer: memory });
|
||||
```
|
||||
:::
|
||||
|
||||
## Next steps
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ Starting with the existing code from the [Add memory to the chatbot](./3-add-mem
|
||||
|
||||
Let's first select a chat model:
|
||||
|
||||
:::python
|
||||
{!snippets/chat_model_tabs.md!}
|
||||
|
||||
<!---
|
||||
@@ -24,21 +23,9 @@ from langchain.chat_models import init_chat_model
|
||||
llm = init_chat_model("anthropic:claude-3-5-sonnet-latest")
|
||||
```
|
||||
-->
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
import { ChatAnthropic } from "@langchain/anthropic";
|
||||
|
||||
const llm = new ChatAnthropic({
|
||||
model: "claude-3-5-sonnet-latest",
|
||||
});
|
||||
```
|
||||
:::
|
||||
|
||||
We can now incorporate it into our `StateGraph` with an additional tool:
|
||||
|
||||
:::python
|
||||
``` python hl_lines="12 19 20 21 22 23"
|
||||
from typing import Annotated
|
||||
|
||||
@@ -88,60 +75,6 @@ graph_builder.add_conditional_edges(
|
||||
graph_builder.add_edge("tools", "chatbot")
|
||||
graph_builder.add_edge(START, "chatbot")
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript hl_lines="12 19 20 21 22 23"
|
||||
import { tool } from "@langchain/core/tools";
|
||||
import { TavilySearchResults } from "@langchain/community/tools/tavily_search";
|
||||
import { z } from "zod";
|
||||
|
||||
import { MemorySaver } from "@langchain/langgraph";
|
||||
import { StateGraph, START, END, MessagesAnnotation } from "@langchain/langgraph";
|
||||
import { ToolNode, toolsCondition } from "@langchain/langgraph/prebuilt";
|
||||
|
||||
import { interrupt, Command } from "@langchain/langgraph";
|
||||
|
||||
const humanAssistance = tool(async ({ query }) => {
|
||||
const humanResponse = interrupt({ query });
|
||||
return humanResponse.data;
|
||||
}, {
|
||||
name: "human_assistance",
|
||||
description: "Request assistance from a human.",
|
||||
schema: z.object({
|
||||
query: z.string().describe("Human readable question for the human")
|
||||
})
|
||||
});
|
||||
|
||||
const searchTool = new TavilySearchResults({ maxResults: 2 });
|
||||
const tools = [searchTool, humanAssistance];
|
||||
const llmWithTools = llm.bindTools(tools);
|
||||
|
||||
const chatbot = async (state: typeof MessagesAnnotation.State) => {
|
||||
const message = await llmWithTools.invoke(state.messages);
|
||||
// Because we will be interrupting during tool execution,
|
||||
// we disable parallel tool calling to avoid repeating any
|
||||
// tool invocations when we resume.
|
||||
if (message.tool_calls && message.tool_calls.length > 1) {
|
||||
throw new Error("Multiple tool calls not supported for this example");
|
||||
}
|
||||
return { messages: [message] };
|
||||
};
|
||||
|
||||
const graphBuilder = new StateGraph(MessagesAnnotation)
|
||||
.addNode("chatbot", chatbot);
|
||||
|
||||
const toolNode = new ToolNode(tools);
|
||||
graphBuilder.addNode("tools", toolNode);
|
||||
|
||||
graphBuilder.addConditionalEdges(
|
||||
"chatbot",
|
||||
toolsCondition,
|
||||
);
|
||||
graphBuilder.addEdge("tools", "chatbot");
|
||||
graphBuilder.addEdge(START, "chatbot");
|
||||
```
|
||||
:::
|
||||
|
||||
!!! tip
|
||||
|
||||
@@ -151,27 +84,16 @@ graphBuilder.addEdge(START, "chatbot");
|
||||
|
||||
We compile the graph with a checkpointer, as before:
|
||||
|
||||
:::python
|
||||
```python
|
||||
memory = MemorySaver()
|
||||
|
||||
graph = graph_builder.compile(checkpointer=memory)
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
const memory = new MemorySaver();
|
||||
|
||||
const graph = graphBuilder.compile({ checkpointer: memory });
|
||||
```
|
||||
:::
|
||||
|
||||
## 3. Visualize the graph (optional)
|
||||
|
||||
Visualizing the graph, you get the same layout as before – just with the added tool!
|
||||
|
||||
:::python
|
||||
``` python
|
||||
from IPython.display import Image, display
|
||||
|
||||
@@ -181,19 +103,6 @@ except Exception:
|
||||
# This requires some extra dependencies and is optional
|
||||
pass
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
import * as tslab from "tslab";
|
||||
|
||||
const drawableGraph = graph.getGraph();
|
||||
const image = await drawableGraph.drawMermaidPng();
|
||||
const arrayBuffer = await image.arrayBuffer();
|
||||
|
||||
await tslab.display.png(new Uint8Array(arrayBuffer));
|
||||
```
|
||||
:::
|
||||
|
||||

|
||||
|
||||
@@ -201,7 +110,6 @@ await tslab.display.png(new Uint8Array(arrayBuffer));
|
||||
|
||||
Now, prompt the chatbot with a question that will engage the new `human_assistance` tool:
|
||||
|
||||
:::python
|
||||
```python
|
||||
user_input = "I need some expert guidance for building an AI agent. Could you request assistance for me?"
|
||||
config = {"configurable": {"thread_id": "1"}}
|
||||
@@ -229,49 +137,9 @@ Tool Calls:
|
||||
Args:
|
||||
query: A user is requesting expert guidance for building an AI agent. Could you please provide some expert advice or resources on this topic?
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
const userInput = "I need some expert guidance for building an AI agent. Could you request assistance for me?";
|
||||
const config = { configurable: { thread_id: "1" }, streamMode: "values" as const };
|
||||
|
||||
const events = graph.stream(
|
||||
{ messages: [{ role: "user", content: userInput }] },
|
||||
config,
|
||||
);
|
||||
|
||||
for await (const event of events) {
|
||||
if (event.messages) {
|
||||
const lastMessage = event.messages[event.messages.length - 1];
|
||||
console.log(`================================ ${lastMessage.getType()} Message =================================`);
|
||||
console.log(lastMessage.content);
|
||||
if (lastMessage.tool_calls?.length) {
|
||||
console.log("Tool Calls:");
|
||||
lastMessage.tool_calls.forEach((call) => {
|
||||
console.log(` ${call.name} (${call.id})`);
|
||||
console.log(` Args: ${JSON.stringify(call.args)}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
================================ Human Message =================================
|
||||
I need some expert guidance for building an AI agent. Could you request assistance for me?
|
||||
================================== Ai Message ==================================
|
||||
I'd be happy to request expert assistance for you regarding building an AI agent. Let me use the human assistance function to get you some expert guidance.
|
||||
|
||||
Tool Calls:
|
||||
human_assistance (toolu_01ABUqneqnuHNuo1vhfDFQCW)
|
||||
Args: {"query":"A user is requesting expert guidance for building an AI agent. Could you please provide some expert advice or resources on this topic?"}
|
||||
```
|
||||
:::
|
||||
|
||||
The chatbot generated a tool call, but then execution has been interrupted. If you inspect the graph state, you see that it stopped at the tools node:
|
||||
|
||||
:::python
|
||||
```python
|
||||
snapshot = graph.get_state(config)
|
||||
snapshot.next
|
||||
@@ -280,20 +148,7 @@ snapshot.next
|
||||
```
|
||||
('tools',)
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
const snapshot = await graph.getState(config);
|
||||
console.log(snapshot.next);
|
||||
```
|
||||
|
||||
```
|
||||
['tools']
|
||||
```
|
||||
:::
|
||||
|
||||
:::python
|
||||
!!! info Additional information
|
||||
|
||||
Take a closer look at the `human_assistance` tool:
|
||||
@@ -307,34 +162,11 @@ console.log(snapshot.next);
|
||||
```
|
||||
|
||||
Similar to Python's built-in `input()` function, calling `interrupt` inside the tool will pause execution. Progress is persisted based on the [checkpointer](../../concepts/persistence.md#checkpointer-libraries); so if it is persisting with Postgres, it can resume at any time as long as the database is alive. In this example, it is persisting with the in-memory checkpointer and can resume any time if the Python kernel is running.
|
||||
:::
|
||||
|
||||
:::js
|
||||
!!! info Additional information
|
||||
|
||||
Take a closer look at the `human_assistance` tool:
|
||||
|
||||
```typescript
|
||||
const humanAssistance = tool(async ({ query }) => {
|
||||
const humanResponse = interrupt({ query });
|
||||
return humanResponse.data;
|
||||
}, {
|
||||
name: "human_assistance",
|
||||
description: "Request assistance from a human.",
|
||||
schema: z.object({
|
||||
query: z.string().describe("Human readable question for the human")
|
||||
})
|
||||
});
|
||||
```
|
||||
|
||||
Similar to Python's built-in `input()` function, calling `interrupt` inside the tool will pause execution. Progress is persisted based on the [checkpointer](../../concepts/persistence.md#checkpointer-libraries); so if it is persisting with Postgres, it can resume at any time as long as the database is alive. In this example, it is persisting with the in-memory checkpointer and can resume any time if the JavaScript runtime is running.
|
||||
:::
|
||||
|
||||
## 5. Resume execution
|
||||
|
||||
To resume execution, pass a [`Command`](../../concepts/low_level.md#command) object containing data expected by the tool. The format of this data can be customized based on needs. For this example, use a dict with a key `"data"`:
|
||||
|
||||
:::python
|
||||
``` python
|
||||
human_response = (
|
||||
"We, the experts are here to help! We'd recommend you check out LangGraph to build your agent."
|
||||
@@ -382,47 +214,6 @@ LangGraph is likely a framework or library designed specifically for creating AI
|
||||
If you'd like more specific information about LangGraph or have any questions about this recommendation, please feel free to ask, and I can request further assistance from the experts.
|
||||
Output is truncated. View as a scrollable element or open in a text editor. Adjust cell output settings...
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
const humanResponse =
|
||||
"We, the experts are here to help! We'd recommend you check out LangGraph to build your agent." +
|
||||
" It's much more reliable and extensible than simple autonomous agents.";
|
||||
|
||||
const humanCommand = new Command({ resume: { data: humanResponse } });
|
||||
|
||||
const resumeEvents = graph.stream(humanCommand, config);
|
||||
|
||||
for await (const event of resumeEvents) {
|
||||
if (event.messages) {
|
||||
const lastMessage = event.messages[event.messages.length - 1];
|
||||
console.log(`================================ ${lastMessage.getType()} Message =================================`);
|
||||
console.log(lastMessage.content);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
================================== Ai Message ==================================
|
||||
I'd be happy to request expert assistance for you regarding building an AI agent. Let me use the human assistance function to get you some expert guidance.
|
||||
================================= Tool Message =================================
|
||||
We, the experts are here to help! We'd recommend you check out LangGraph to build your agent. It's much more reliable and extensible than simple autonomous agents.
|
||||
================================== Ai Message ==================================
|
||||
Thank you for your patience. I've received some expert advice regarding your request for guidance on building an AI agent. Here's what the experts have suggested:
|
||||
|
||||
The experts recommend that you look into LangGraph for building your AI agent. They mention that LangGraph is a more reliable and extensible option compared to simple autonomous agents.
|
||||
|
||||
LangGraph is likely a framework or library designed specifically for creating AI agents with advanced capabilities. Here are a few points to consider based on this recommendation:
|
||||
|
||||
1. Reliability: The experts emphasize that LangGraph is more reliable than simpler autonomous agent approaches. This could mean it has better stability, error handling, or consistent performance.
|
||||
|
||||
2. Extensibility: LangGraph is described as more extensible, which suggests that it probably offers a flexible architecture that allows you to easily add new features or modify existing ones as your agent's requirements evolve.
|
||||
|
||||
3. Advanced capabilities: Given that it's recommended over "simple autonomous agents," LangGraph likely provides more sophisticated tools and techniques for building complex AI agents.
|
||||
...
|
||||
```
|
||||
:::
|
||||
|
||||
The input has been received and processed as a tool message. Review this call's [LangSmith trace](https://smith.langchain.com/public/9f0f87e3-56a7-4dde-9c76-b71675624e91/r) to see the exact work that was done in the above call. Notice that the state is loaded in the first step so that our chatbot can continue where it left off.
|
||||
|
||||
@@ -430,7 +221,6 @@ The input has been received and processed as a tool message. Review this call's
|
||||
|
||||
Check out the code snippet below to review the graph from this tutorial:
|
||||
|
||||
:::python
|
||||
{!snippets/chat_model_tabs.md!}
|
||||
|
||||
```python
|
||||
@@ -481,64 +271,6 @@ graph_builder.add_edge(START, "chatbot")
|
||||
memory = MemorySaver()
|
||||
graph = graph_builder.compile(checkpointer=memory)
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
import { tool } from "@langchain/core/tools";
|
||||
import { TavilySearchResults } from "@langchain/community/tools/tavily_search";
|
||||
import { z } from "zod";
|
||||
import { ChatAnthropic } from "@langchain/anthropic";
|
||||
|
||||
import { MemorySaver } from "@langchain/langgraph";
|
||||
import { StateGraph, START, END, MessagesAnnotation } from "@langchain/langgraph";
|
||||
import { ToolNode, toolsCondition } from "@langchain/langgraph/prebuilt";
|
||||
import { interrupt, Command } from "@langchain/langgraph";
|
||||
|
||||
const llm = new ChatAnthropic({
|
||||
model: "claude-3-5-sonnet-latest",
|
||||
});
|
||||
|
||||
const humanAssistance = tool(async ({ query }) => {
|
||||
const humanResponse = interrupt({ query });
|
||||
return humanResponse.data;
|
||||
}, {
|
||||
name: "human_assistance",
|
||||
description: "Request assistance from a human.",
|
||||
schema: z.object({
|
||||
query: z.string().describe("Human readable question for the human")
|
||||
})
|
||||
});
|
||||
|
||||
const searchTool = new TavilySearchResults({ maxResults: 2 });
|
||||
const tools = [searchTool, humanAssistance];
|
||||
const llmWithTools = llm.bindTools(tools);
|
||||
|
||||
const chatbot = async (state: typeof MessagesAnnotation.State) => {
|
||||
const message = await llmWithTools.invoke(state.messages);
|
||||
if (message.tool_calls && message.tool_calls.length > 1) {
|
||||
throw new Error("Multiple tool calls not supported for this example");
|
||||
}
|
||||
return { messages: [message] };
|
||||
};
|
||||
|
||||
const graphBuilder = new StateGraph(MessagesAnnotation)
|
||||
.addNode("chatbot", chatbot);
|
||||
|
||||
const toolNode = new ToolNode(tools);
|
||||
graphBuilder.addNode("tools", toolNode);
|
||||
|
||||
graphBuilder.addConditionalEdges(
|
||||
"chatbot",
|
||||
toolsCondition,
|
||||
);
|
||||
graphBuilder.addEdge("tools", "chatbot");
|
||||
graphBuilder.addEdge(START, "chatbot");
|
||||
|
||||
const memory = new MemorySaver();
|
||||
const graph = graphBuilder.compile({ checkpointer: memory });
|
||||
```
|
||||
:::
|
||||
|
||||
## Next steps
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ In this tutorial, you will add additional fields to the state to define complex
|
||||
|
||||
Update the chatbot to research the birthday of an entity by adding `name` and `birthday` keys to the state:
|
||||
|
||||
:::python
|
||||
```python
|
||||
from typing import Annotated
|
||||
|
||||
@@ -26,30 +25,11 @@ class State(TypedDict):
|
||||
# highlight-next-line
|
||||
birthday: str
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
import { Annotation } from "@langchain/langgraph";
|
||||
import { BaseMessage } from "@langchain/core/messages";
|
||||
|
||||
const StateAnnotation = Annotation.Root({
|
||||
messages: Annotation<BaseMessage[]>({
|
||||
reducer: (x, y) => x.concat(y),
|
||||
}),
|
||||
// highlight-next-line
|
||||
name: Annotation<string>,
|
||||
// highlight-next-line
|
||||
birthday: Annotation<string>,
|
||||
});
|
||||
```
|
||||
:::
|
||||
|
||||
Adding this information to the state makes it easily accessible by other graph nodes (like a downstream node that stores or processes the information), as well as the graph's persistence layer.
|
||||
|
||||
## 2. Update the state inside the tool
|
||||
|
||||
:::python
|
||||
Now, populate the state keys inside of the `human_assistance` tool. This allows a human to review the information before it is stored in the state. Use [`Command`](../../concepts/low_level.md#using-inside-tools) to issue a state update from inside the tool.
|
||||
|
||||
``` python
|
||||
@@ -95,73 +75,11 @@ def human_assistance(
|
||||
# We return a Command object in the tool to update our state.
|
||||
return Command(update=state_update)
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
Now, populate the state keys inside of the `humanAssistance` tool. This allows a human to review the information before it is stored in the state. Use [`Command`](../../concepts/low_level.md#using-inside-tools) to issue a state update from inside the tool.
|
||||
|
||||
```typescript
|
||||
import { tool } from "@langchain/core/tools";
|
||||
import { ToolMessage } from "@langchain/core/messages";
|
||||
import { z } from "zod";
|
||||
import { Command, interrupt } from "@langchain/langgraph";
|
||||
|
||||
const humanAssistance = tool(async (input, config) => {
|
||||
const { name, birthday } = input;
|
||||
// Note that because we are generating a ToolMessage for a state update, we
|
||||
// generally require the ID of the corresponding tool call. We can access this
|
||||
// from the tool's config when it's called by a model.
|
||||
const toolCallId = config?.toolCall?.id;
|
||||
|
||||
const humanResponse = interrupt({
|
||||
question: "Is this correct?",
|
||||
name: name,
|
||||
birthday: birthday,
|
||||
});
|
||||
|
||||
let verifiedName, verifiedBirthday, response;
|
||||
|
||||
// If the information is correct, update the state as-is.
|
||||
if (humanResponse?.correct?.toLowerCase().startsWith("y")) {
|
||||
verifiedName = name;
|
||||
verifiedBirthday = birthday;
|
||||
response = "Correct";
|
||||
} else {
|
||||
// Otherwise, receive information from the human reviewer.
|
||||
verifiedName = humanResponse?.name || name;
|
||||
verifiedBirthday = humanResponse?.birthday || birthday;
|
||||
response = `Made a correction: ${JSON.stringify(humanResponse)}`;
|
||||
}
|
||||
|
||||
// This time we explicitly update the state with a ToolMessage inside
|
||||
// the tool.
|
||||
const stateUpdate = {
|
||||
name: verifiedName,
|
||||
birthday: verifiedBirthday,
|
||||
messages: [new ToolMessage({
|
||||
content: response,
|
||||
tool_call_id: toolCallId!
|
||||
})],
|
||||
};
|
||||
|
||||
// We return a Command object in the tool to update our state.
|
||||
return new Command({ update: stateUpdate });
|
||||
}, {
|
||||
name: "humanAssistance",
|
||||
description: "Request assistance from a human.",
|
||||
schema: z.object({
|
||||
name: z.string(),
|
||||
birthday: z.string(),
|
||||
}),
|
||||
});
|
||||
```
|
||||
:::
|
||||
|
||||
The rest of the graph stays the same.
|
||||
|
||||
## 3. Prompt the chatbot
|
||||
|
||||
:::python
|
||||
Prompt the chatbot to look up the "birthday" of the LangGraph library and direct the chatbot to reach out to the `human_assistance` tool once it has the required information. By setting `name` and `birthday` in the arguments for the tool, you force the chatbot to generate proposals for these fields.
|
||||
|
||||
```python
|
||||
@@ -180,30 +98,6 @@ for event in events:
|
||||
if "messages" in event:
|
||||
event["messages"][-1].pretty_print()
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
Prompt the chatbot to look up the "birthday" of the LangGraph library and direct the chatbot to reach out to the `humanAssistance` tool once it has the required information. By setting `name` and `birthday` in the arguments for the tool, you force the chatbot to generate proposals for these fields.
|
||||
|
||||
```typescript
|
||||
const userInput = "Can you look up when LangGraph was released? " +
|
||||
"When you have the answer, use the humanAssistance tool for review.";
|
||||
const config = { configurable: { thread_id: "1" } };
|
||||
|
||||
const events = graph.stream(
|
||||
{ messages: [{ role: "user", content: userInput }] },
|
||||
{ ...config, streamMode: "values" }
|
||||
);
|
||||
|
||||
for await (const event of events) {
|
||||
if (event.messages) {
|
||||
const lastMessage = event.messages[event.messages.length - 1];
|
||||
console.log(`================================ ${lastMessage._getType()} Message =================================`);
|
||||
console.log(lastMessage.content);
|
||||
}
|
||||
}
|
||||
```
|
||||
:::
|
||||
|
||||
```
|
||||
================================ Human Message =================================
|
||||
@@ -236,7 +130,6 @@ We've hit the `interrupt` in the `human_assistance` tool again.
|
||||
|
||||
## 4. Add human assistance
|
||||
|
||||
:::python
|
||||
The chatbot failed to identify the correct date, so supply it with information:
|
||||
|
||||
```python
|
||||
@@ -252,32 +145,6 @@ for event in events:
|
||||
if "messages" in event:
|
||||
event["messages"][-1].pretty_print()
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
The chatbot failed to identify the correct date, so supply it with information:
|
||||
|
||||
```typescript
|
||||
import { Command } from "@langchain/langgraph";
|
||||
|
||||
const humanCommand = new Command({
|
||||
resume: {
|
||||
name: "LangGraph",
|
||||
birthday: "Jan 17, 2024",
|
||||
},
|
||||
});
|
||||
|
||||
const resumeEvents = graph.stream(humanCommand, { ...config, streamMode: "values" });
|
||||
|
||||
for await (const event of resumeEvents) {
|
||||
if (event.messages) {
|
||||
const lastMessage = event.messages[event.messages.length - 1];
|
||||
console.log(`================================ ${lastMessage._getType()} Message =================================`);
|
||||
console.log(lastMessage.content);
|
||||
}
|
||||
}
|
||||
```
|
||||
:::
|
||||
|
||||
```
|
||||
================================== Ai Message ==================================
|
||||
@@ -308,25 +175,11 @@ It's worth noting that LangGraph had been in development and use for some time b
|
||||
|
||||
Note that these fields are now reflected in the state:
|
||||
|
||||
:::python
|
||||
```python
|
||||
snapshot = graph.get_state(config)
|
||||
|
||||
{k: v for k, v in snapshot.values.items() if k in ("name", "birthday")}
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
const snapshot = await graph.getState(config);
|
||||
|
||||
const relevantState = {
|
||||
name: snapshot.values.name,
|
||||
birthday: snapshot.values.birthday
|
||||
};
|
||||
console.log(relevantState);
|
||||
```
|
||||
:::
|
||||
|
||||
```
|
||||
{'name': 'LangGraph', 'birthday': 'Jan 17, 2024'}
|
||||
@@ -336,21 +189,11 @@ This makes them easily accessible to downstream nodes (e.g., a node that further
|
||||
|
||||
## 5. Manually update the state
|
||||
|
||||
:::python
|
||||
LangGraph gives a high degree of control over the application state. For instance, at any point (including when interrupted), you can manually override a key using `graph.update_state`:
|
||||
|
||||
``` python
|
||||
graph.update_state(config, {"name": "LangGraph (library)"})
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
LangGraph gives a high degree of control over the application state. For instance, at any point (including when interrupted), you can manually override a key using `graph.updateState`:
|
||||
|
||||
```typescript
|
||||
await graph.updateState(config, { name: "LangGraph (library)" });
|
||||
```
|
||||
:::
|
||||
|
||||
```
|
||||
{'configurable': {'thread_id': '1',
|
||||
@@ -360,7 +203,6 @@ await graph.updateState(config, { name: "LangGraph (library)" });
|
||||
|
||||
## 6. View the new value
|
||||
|
||||
:::python
|
||||
If you call `graph.get_state`, you can see the new value is reflected:
|
||||
|
||||
``` python
|
||||
@@ -368,21 +210,6 @@ snapshot = graph.get_state(config)
|
||||
|
||||
{k: v for k, v in snapshot.values.items() if k in ("name", "birthday")}
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
If you call `graph.getState`, you can see the new value is reflected:
|
||||
|
||||
```typescript
|
||||
const updatedSnapshot = await graph.getState(config);
|
||||
|
||||
const updatedState = {
|
||||
name: updatedSnapshot.values.name,
|
||||
birthday: updatedSnapshot.values.birthday
|
||||
};
|
||||
console.log(updatedState);
|
||||
```
|
||||
:::
|
||||
|
||||
```
|
||||
{'name': 'LangGraph (library)', 'birthday': 'Jan 17, 2024'}
|
||||
@@ -404,7 +231,6 @@ llm = init_chat_model("anthropic:claude-3-5-sonnet-latest")
|
||||
```
|
||||
-->
|
||||
|
||||
:::python
|
||||
```python
|
||||
from typing import Annotated
|
||||
|
||||
@@ -478,106 +304,8 @@ graph_builder.add_edge(START, "chatbot")
|
||||
memory = MemorySaver()
|
||||
graph = graph_builder.compile(checkpointer=memory)
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
import { ChatAnthropic } from "@langchain/anthropic";
|
||||
import { TavilySearchResults } from "@langchain/community/tools/tavily_search";
|
||||
import { tool } from "@langchain/core/tools";
|
||||
import { ToolMessage, BaseMessage } from "@langchain/core/messages";
|
||||
import { z } from "zod";
|
||||
|
||||
import { MemorySaver } from "@langchain/langgraph";
|
||||
import { StateGraph, START, Annotation } from "@langchain/langgraph";
|
||||
import { ToolNode } from "@langchain/langgraph/prebuilt";
|
||||
import { Command, interrupt } from "@langchain/langgraph";
|
||||
|
||||
const llm = new ChatAnthropic({
|
||||
model: "claude-3-5-sonnet-latest",
|
||||
});
|
||||
|
||||
const StateAnnotation = Annotation.Root({
|
||||
messages: Annotation<BaseMessage[]>({
|
||||
reducer: (x, y) => x.concat(y),
|
||||
}),
|
||||
name: Annotation<string>,
|
||||
birthday: Annotation<string>,
|
||||
});
|
||||
|
||||
const humanAssistance = tool(async (input, config) => {
|
||||
const { name, birthday } = input;
|
||||
const toolCallId = config?.toolCall?.id;
|
||||
|
||||
const humanResponse = interrupt({
|
||||
question: "Is this correct?",
|
||||
name: name,
|
||||
birthday: birthday,
|
||||
});
|
||||
|
||||
let verifiedName, verifiedBirthday, response;
|
||||
|
||||
if (humanResponse?.correct?.toLowerCase().startsWith("y")) {
|
||||
verifiedName = name;
|
||||
verifiedBirthday = birthday;
|
||||
response = "Correct";
|
||||
} else {
|
||||
verifiedName = humanResponse?.name || name;
|
||||
verifiedBirthday = humanResponse?.birthday || birthday;
|
||||
response = `Made a correction: ${JSON.stringify(humanResponse)}`;
|
||||
}
|
||||
|
||||
const stateUpdate = {
|
||||
name: verifiedName,
|
||||
birthday: verifiedBirthday,
|
||||
messages: [new ToolMessage({
|
||||
content: response,
|
||||
tool_call_id: toolCallId!
|
||||
})],
|
||||
};
|
||||
|
||||
return new Command({ update: stateUpdate });
|
||||
}, {
|
||||
name: "humanAssistance",
|
||||
description: "Request assistance from a human.",
|
||||
schema: z.object({
|
||||
name: z.string(),
|
||||
birthday: z.string(),
|
||||
}),
|
||||
});
|
||||
|
||||
const searchTool = new TavilySearchResults({ maxResults: 2 });
|
||||
const tools = [searchTool, humanAssistance];
|
||||
const llmWithTools = llm.bindTools(tools);
|
||||
|
||||
const chatbot = async (state: typeof StateAnnotation.State) => {
|
||||
const message = await llmWithTools.invoke(state.messages);
|
||||
return { messages: [message] };
|
||||
};
|
||||
|
||||
const shouldContinue = (state: typeof StateAnnotation.State) => {
|
||||
const lastMessage = state.messages[state.messages.length - 1];
|
||||
if ("tool_calls" in lastMessage && lastMessage.tool_calls?.length) {
|
||||
return "tools";
|
||||
}
|
||||
return "__end__";
|
||||
};
|
||||
|
||||
const graphBuilder = new StateGraph(StateAnnotation);
|
||||
graphBuilder.addNode("chatbot", chatbot);
|
||||
|
||||
const toolNode = new ToolNode(tools);
|
||||
graphBuilder.addNode("tools", toolNode);
|
||||
|
||||
graphBuilder.addConditionalEdges("chatbot", shouldContinue);
|
||||
graphBuilder.addEdge("tools", "chatbot");
|
||||
graphBuilder.addEdge(START, "chatbot");
|
||||
|
||||
const memory = new MemorySaver();
|
||||
const graph = graphBuilder.compile({ checkpointer: memory });
|
||||
```
|
||||
:::
|
||||
|
||||
## Next steps
|
||||
|
||||
There's one more concept to review before finishing the LangGraph basics tutorials: connecting `checkpointing` and `state updates` to [time travel](./6-time-travel.md).
|
||||
There's one more concept to review before finishing the LangGraph basics tutorials: connecting `checkpointing` and `state updates` to [time travel](./6-time-travel.md).
|
||||
|
||||
|
||||
@@ -12,35 +12,18 @@ You can create these types of experiences using LangGraph's built-in **time trav
|
||||
|
||||
## 1. Rewind your graph
|
||||
|
||||
:::python
|
||||
Rewind your graph by fetching a checkpoint using the graph's `get_state_history` method. You can then resume execution at this previous point in time.
|
||||
:::
|
||||
|
||||
:::js
|
||||
Rewind your graph by fetching a checkpoint using the graph's `getStateHistory` method. You can then resume execution at this previous point in time.
|
||||
:::
|
||||
|
||||
{!snippets/chat_model_tabs.md!}
|
||||
|
||||
<!---
|
||||
:::python
|
||||
```python
|
||||
from langchain.chat_models import init_chat_model
|
||||
|
||||
llm = init_chat_model("anthropic:claude-3-5-sonnet-latest")
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
import { initChatModel } from "langchain/chat_models/init";
|
||||
|
||||
const llm = initChatModel("anthropic:claude-3-5-sonnet-latest");
|
||||
```
|
||||
:::
|
||||
-->
|
||||
|
||||
:::python
|
||||
```python
|
||||
from typing import Annotated
|
||||
|
||||
@@ -80,62 +63,11 @@ graph_builder.add_edge(START, "chatbot")
|
||||
memory = MemorySaver()
|
||||
graph = graph_builder.compile(checkpointer=memory)
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
import { TavilySearchResults } from "@langchain/community/tools/tavily_search";
|
||||
import { ChatAnthropic } from "@langchain/anthropic";
|
||||
import { BaseMessage } from "@langchain/core/messages";
|
||||
import { Annotation, StateGraph, START, END } from "@langchain/langgraph";
|
||||
import { MemorySaver } from "@langchain/langgraph";
|
||||
import { ToolNode } from "@langchain/langgraph/prebuilt";
|
||||
import { messagesStateReducer } from "@langchain/langgraph";
|
||||
|
||||
const StateAnnotation = Annotation.Root({
|
||||
messages: Annotation<BaseMessage[]>({
|
||||
reducer: messagesStateReducer,
|
||||
}),
|
||||
});
|
||||
|
||||
const graphBuilder = new StateGraph(StateAnnotation);
|
||||
|
||||
const tool = new TavilySearchResults({ maxResults: 2 });
|
||||
const tools = [tool];
|
||||
const llm = new ChatAnthropic({ model: "claude-3-5-sonnet-latest" });
|
||||
const llmWithTools = llm.bindTools(tools);
|
||||
|
||||
const chatbot = async (state: typeof StateAnnotation.State) => {
|
||||
return { messages: [await llmWithTools.invoke(state.messages)] };
|
||||
};
|
||||
|
||||
graphBuilder.addNode("chatbot", chatbot);
|
||||
|
||||
const toolNode = new ToolNode(tools);
|
||||
graphBuilder.addNode("tools", toolNode);
|
||||
|
||||
const toolsCondition = (state: typeof StateAnnotation.State) => {
|
||||
const lastMessage = state.messages[state.messages.length - 1];
|
||||
if ("tool_calls" in lastMessage && lastMessage.tool_calls?.length) {
|
||||
return "tools";
|
||||
}
|
||||
return END;
|
||||
};
|
||||
|
||||
graphBuilder.addConditionalEdges("chatbot", toolsCondition);
|
||||
graphBuilder.addEdge("tools", "chatbot");
|
||||
graphBuilder.addEdge(START, "chatbot");
|
||||
|
||||
const memory = new MemorySaver();
|
||||
const graph = graphBuilder.compile({ checkpointer: memory });
|
||||
```
|
||||
:::
|
||||
|
||||
## 2. Add steps
|
||||
|
||||
Add steps to your graph. Every step will be checkpointed in its state history:
|
||||
|
||||
:::python
|
||||
``` python
|
||||
config = {"configurable": {"thread_id": "1"}}
|
||||
events = graph.stream(
|
||||
@@ -157,42 +89,6 @@ for event in events:
|
||||
if "messages" in event:
|
||||
event["messages"][-1].pretty_print()
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
const config = { configurable: { thread_id: "1" } };
|
||||
const events = await graph.stream(
|
||||
{
|
||||
messages: [
|
||||
{
|
||||
role: "user",
|
||||
content: (
|
||||
"I'm learning LangGraph. " +
|
||||
"Could you do some research on it for me?"
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
{ ...config, streamMode: "values" }
|
||||
);
|
||||
|
||||
for await (const event of events) {
|
||||
if ("messages" in event) {
|
||||
const lastMessage = event.messages[event.messages.length - 1];
|
||||
console.log(`================================ ${lastMessage._getType()} Message =================================`);
|
||||
console.log(lastMessage.content);
|
||||
if ("tool_calls" in lastMessage && lastMessage.tool_calls?.length) {
|
||||
console.log("Tool Calls:");
|
||||
for (const toolCall of lastMessage.tool_calls) {
|
||||
console.log(` ${toolCall.name} (${toolCall.id})`);
|
||||
console.log(` Args: ${JSON.stringify(toolCall.args)}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
:::
|
||||
|
||||
```
|
||||
================================ Human Message =================================
|
||||
@@ -227,7 +123,6 @@ Is there any specific aspect of LangGraph you'd like to know more about? I'd be
|
||||
Output is truncated. View as a scrollable element or open in a text editor. Adjust cell output settings...
|
||||
```
|
||||
|
||||
:::python
|
||||
```python
|
||||
events = graph.stream(
|
||||
{
|
||||
@@ -248,41 +143,6 @@ for event in events:
|
||||
if "messages" in event:
|
||||
event["messages"][-1].pretty_print()
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
const events2 = await graph.stream(
|
||||
{
|
||||
messages: [
|
||||
{
|
||||
role: "user",
|
||||
content: (
|
||||
"Ya that's helpful. Maybe I'll " +
|
||||
"build an autonomous agent with it!"
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
{ ...config, streamMode: "values" }
|
||||
);
|
||||
|
||||
for await (const event of events2) {
|
||||
if ("messages" in event) {
|
||||
const lastMessage = event.messages[event.messages.length - 1];
|
||||
console.log(`================================ ${lastMessage._getType()} Message =================================`);
|
||||
console.log(lastMessage.content);
|
||||
if ("tool_calls" in lastMessage && lastMessage.tool_calls?.length) {
|
||||
console.log("Tool Calls:");
|
||||
for (const toolCall of lastMessage.tool_calls) {
|
||||
console.log(` ${toolCall.name} (${toolCall.id})`);
|
||||
console.log(` Args: ${JSON.stringify(toolCall.args)}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
:::
|
||||
|
||||
```
|
||||
================================ Human Message =================================
|
||||
@@ -299,7 +159,7 @@ Tool Calls:
|
||||
================================= Tool Message =================================
|
||||
Name: tavily_search_results_json
|
||||
|
||||
[{"url": "https://towardsdatascience.com/building-autonomous-multi-tool-agents-with-gemini-2-0-and-langgraph-ad3d7bd5e79d", "content": "Building Autonomous Multi-Tool Agents with Gemini 2.0 and LangGraph | by Youness Mansar | Jan, 2025 | Towards Data Science Building Autonomous Multi-Tool Agents with Gemini 2.0 and LangGraph A practical tutorial with full code examples for building and running multi-tool agents Towards Data Science LLMs are remarkable — they can memorize vast amounts of information, answer general knowledge questions, write code, generate stories, and even fix your grammar. In this tutorial, we are going to build a simple LLM agent that is equipped with four tools that it can use to answer a user's question. This Agent will have the following specifications: Follow Published in Towards Data Science --------------------------------- Your home for data science and AI. Follow Follow Follow"}, {"url": "https://github.com/anmolaman20/Tools_and_Agents", "content": "GitHub - anmolaman20/Tools_and_Agents: This repository provides resources for building AI agents using Langchain and Langgraph. This repository provides resources for building AI agents using Langchain and Langgraph. This repository provides resources for building AI agents using Langchain and Langgraph. This repository serves as a comprehensive guide for building AI-powered agents using Langchain and Langgraph. It provides hands-on examples, practical tutorials, and resources for developers and AI enthusiasts to master building intelligent systems and workflows. AI Agent Development: Gain insights into creating intelligent systems that think, reason, and adapt in real time. This repository is ideal for AI practitioners, developers exploring language models, or anyone interested in building intelligent systems. This repository provides resources for building AI agents using Langchain and Langgraph."}]
|
||||
[{"url": "https://towardsdatascience.com/building-autonomous-multi-tool-agents-with-gemini-2-0-and-langgraph-ad3d7bd5e79d", "content": "Building Autonomous Multi-Tool Agents with Gemini 2.0 and LangGraph | by Youness Mansar | Jan, 2025 | Towards Data Science Building Autonomous Multi-Tool Agents with Gemini 2.0 and LangGraph A practical tutorial with full code examples for building and running multi-tool agents Towards Data Science LLMs are remarkable — they can memorize vast amounts of information, answer general knowledge questions, write code, generate stories, and even fix your grammar. In this tutorial, we are going to build a simple LLM agent that is equipped with four tools that it can use to answer a user’s question. This Agent will have the following specifications: Follow Published in Towards Data Science --------------------------------- Your home for data science and AI. Follow Follow Follow"}, {"url": "https://github.com/anmolaman20/Tools_and_Agents", "content": "GitHub - anmolaman20/Tools_and_Agents: This repository provides resources for building AI agents using Langchain and Langgraph. This repository provides resources for building AI agents using Langchain and Langgraph. This repository provides resources for building AI agents using Langchain and Langgraph. This repository serves as a comprehensive guide for building AI-powered agents using Langchain and Langgraph. It provides hands-on examples, practical tutorials, and resources for developers and AI enthusiasts to master building intelligent systems and workflows. AI Agent Development: Gain insights into creating intelligent systems that think, reason, and adapt in real time. This repository is ideal for AI practitioners, developers exploring language models, or anyone interested in building intelligent systems. This repository provides resources for building AI agents using Langchain and Langgraph."}]
|
||||
================================== Ai Message ==================================
|
||||
|
||||
Great idea! Building an autonomous agent with LangGraph is definitely an exciting project. Based on the latest information I've found, here are some insights and tips for building autonomous agents with LangGraph:
|
||||
@@ -321,7 +181,6 @@ Output is truncated. View as a scrollable element or open in a text editor. Adju
|
||||
|
||||
Now that you have added steps to the chatbot, you can `replay` the full state history to see everything that occurred.
|
||||
|
||||
:::python
|
||||
``` python
|
||||
to_replay = None
|
||||
for state in graph.get_state_history(config):
|
||||
@@ -331,24 +190,7 @@ for state in graph.get_state_history(config):
|
||||
# We are somewhat arbitrarily selecting a specific state based on the number of chat messages in the state.
|
||||
to_replay = state
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
let toReplay = null;
|
||||
const stateHistory = await graph.getStateHistory(config);
|
||||
for await (const state of stateHistory) {
|
||||
console.log("Num Messages: ", state.values.messages.length, "Next: ", state.next);
|
||||
console.log("-".repeat(80));
|
||||
if (state.values.messages.length === 6) {
|
||||
// We are somewhat arbitrarily selecting a specific state based on the number of chat messages in the state.
|
||||
toReplay = state;
|
||||
}
|
||||
}
|
||||
```
|
||||
:::
|
||||
|
||||
:::python
|
||||
```
|
||||
Num Messages: 8 Next: ()
|
||||
--------------------------------------------------------------------------------
|
||||
@@ -371,32 +213,6 @@ Num Messages: 1 Next: ('chatbot',)
|
||||
Num Messages: 0 Next: ('__start__',)
|
||||
--------------------------------------------------------------------------------
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```
|
||||
Num Messages: 8 Next: []
|
||||
--------------------------------------------------------------------------------
|
||||
Num Messages: 7 Next: ["chatbot"]
|
||||
--------------------------------------------------------------------------------
|
||||
Num Messages: 6 Next: ["tools"]
|
||||
--------------------------------------------------------------------------------
|
||||
Num Messages: 5 Next: ["chatbot"]
|
||||
--------------------------------------------------------------------------------
|
||||
Num Messages: 4 Next: ["__start__"]
|
||||
--------------------------------------------------------------------------------
|
||||
Num Messages: 4 Next: []
|
||||
--------------------------------------------------------------------------------
|
||||
Num Messages: 3 Next: ["chatbot"]
|
||||
--------------------------------------------------------------------------------
|
||||
Num Messages: 2 Next: ["tools"]
|
||||
--------------------------------------------------------------------------------
|
||||
Num Messages: 1 Next: ["chatbot"]
|
||||
--------------------------------------------------------------------------------
|
||||
Num Messages: 0 Next: ["__start__"]
|
||||
--------------------------------------------------------------------------------
|
||||
```
|
||||
:::
|
||||
|
||||
Checkpoints are saved for every step of the graph. This __spans invocations__ so you can rewind across a full thread's history.
|
||||
|
||||
@@ -404,74 +220,27 @@ Checkpoints are saved for every step of the graph. This __spans invocations__ so
|
||||
|
||||
Resume from the `to_replay` state, which is after the `chatbot` node in the second graph invocation. Resuming from this point will call the **action** node next.
|
||||
|
||||
:::python
|
||||
```python
|
||||
print(to_replay.next)
|
||||
print(to_replay.config)
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
console.log(toReplay.next);
|
||||
console.log(toReplay.config);
|
||||
```
|
||||
:::
|
||||
|
||||
:::python
|
||||
```
|
||||
('tools',)
|
||||
{'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1efd43e3-0c1f-6c4e-8006-891877d65740'}}
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```
|
||||
["tools"]
|
||||
{
|
||||
"configurable": {
|
||||
"thread_id": "1",
|
||||
"checkpoint_ns": "",
|
||||
"checkpoint_id": "1efd43e3-0c1f-6c4e-8006-891877d65740"
|
||||
}
|
||||
}
|
||||
```
|
||||
:::
|
||||
|
||||
## 4. Load a state from a moment-in-time
|
||||
|
||||
The checkpoint's `to_replay.config` contains a `checkpoint_id` timestamp. Providing this `checkpoint_id` value tells LangGraph's checkpointer to **load** the state from that moment in time.
|
||||
|
||||
:::python
|
||||
|
||||
``` python
|
||||
# The `checkpoint_id` in the `to_replay.config` corresponds to a state we've persisted to our checkpointer.
|
||||
for event in graph.stream(None, to_replay.config, stream_mode="values"):
|
||||
if "messages" in event:
|
||||
event["messages"][-1].pretty_print()
|
||||
```
|
||||
:::
|
||||
|
||||
:::js
|
||||
```typescript
|
||||
// The `checkpoint_id` in the `toReplay.config` corresponds to a state we've persisted to our checkpointer.
|
||||
const timeTravel = await graph.stream(null, { ...toReplay.config, streamMode: "values" });
|
||||
|
||||
for await (const event of timeTravel) {
|
||||
if ("messages" in event) {
|
||||
const lastMessage = event.messages[event.messages.length - 1];
|
||||
console.log(`================================ ${lastMessage._getType()} Message =================================`);
|
||||
console.log(lastMessage.content);
|
||||
if ("tool_calls" in lastMessage && lastMessage.tool_calls?.length) {
|
||||
console.log("Tool Calls:");
|
||||
for (const toolCall of lastMessage.tool_calls) {
|
||||
console.log(` ${toolCall.name} (${toolCall.id})`);
|
||||
console.log(` Args: ${JSON.stringify(toolCall.args)}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
:::
|
||||
|
||||
```
|
||||
================================== Ai Message ==================================
|
||||
@@ -485,7 +254,7 @@ Tool Calls:
|
||||
================================= Tool Message =================================
|
||||
Name: tavily_search_results_json
|
||||
|
||||
[{"url": "https://towardsdatascience.com/building-autonomous-multi-tool-agents-with-gemini-2-0-and-langgraph-ad3d7bd5e79d", "content": "Building Autonomous Multi-Tool Agents with Gemini 2.0 and LangGraph | by Youness Mansar | Jan, 2025 | Towards Data Science Building Autonomous Multi-Tool Agents with Gemini 2.0 and LangGraph A practical tutorial with full code examples for building and running multi-tool agents Towards Data Science LLMs are remarkable — they can memorize vast amounts of information, answer general knowledge questions, write code, generate stories, and even fix your grammar. In this tutorial, we are going to build a simple LLM agent that is equipped with four tools that it can use to answer a user's question. This Agent will have the following specifications: Follow Published in Towards Data Science --------------------------------- Your home for data science and AI. Follow Follow Follow"}, {"url": "https://github.com/anmolaman20/Tools_and_Agents", "content": "GitHub - anmolaman20/Tools_and_Agents: This repository provides resources for building AI agents using Langchain and Langgraph. This repository provides resources for building AI agents using Langchain and Langgraph. This repository provides resources for building AI agents using Langchain and Langgraph. This repository serves as a comprehensive guide for building AI-powered agents using Langchain and Langgraph. It provides hands-on examples, practical tutorials, and resources for developers and AI enthusiasts to master building intelligent systems and workflows. AI Agent Development: Gain insights into creating intelligent systems that think, reason, and adapt in real time. This repository is ideal for AI practitioners, developers exploring language models, or anyone interested in building intelligent systems. This repository provides resources for building AI agents using Langchain and Langgraph."}]
|
||||
[{"url": "https://towardsdatascience.com/building-autonomous-multi-tool-agents-with-gemini-2-0-and-langgraph-ad3d7bd5e79d", "content": "Building Autonomous Multi-Tool Agents with Gemini 2.0 and LangGraph | by Youness Mansar | Jan, 2025 | Towards Data Science Building Autonomous Multi-Tool Agents with Gemini 2.0 and LangGraph A practical tutorial with full code examples for building and running multi-tool agents Towards Data Science LLMs are remarkable — they can memorize vast amounts of information, answer general knowledge questions, write code, generate stories, and even fix your grammar. In this tutorial, we are going to build a simple LLM agent that is equipped with four tools that it can use to answer a user’s question. This Agent will have the following specifications: Follow Published in Towards Data Science --------------------------------- Your home for data science and AI. Follow Follow Follow"}, {"url": "https://github.com/anmolaman20/Tools_and_Agents", "content": "GitHub - anmolaman20/Tools_and_Agents: This repository provides resources for building AI agents using Langchain and Langgraph. This repository provides resources for building AI agents using Langchain and Langgraph. This repository provides resources for building AI agents using Langchain and Langgraph. This repository serves as a comprehensive guide for building AI-powered agents using Langchain and Langgraph. It provides hands-on examples, practical tutorials, and resources for developers and AI enthusiasts to master building intelligent systems and workflows. AI Agent Development: Gain insights into creating intelligent systems that think, reason, and adapt in real time. This repository is ideal for AI practitioners, developers exploring language models, or anyone interested in building intelligent systems. This repository provides resources for building AI agents using Langchain and Langgraph."}]
|
||||
================================== Ai Message ==================================
|
||||
|
||||
Great idea! Building an autonomous agent with LangGraph is indeed an excellent way to apply and deepen your understanding of the technology. Based on the search results, I can provide you with some insights and resources to help you get started:
|
||||
|
||||
@@ -471,7 +471,7 @@
|
||||
"\n",
|
||||
"_get_pass(\"TAVILY_API_KEY\")\n",
|
||||
"\n",
|
||||
"calculate = get_math_tool(ChatOpenAI(model=\"gpt-4o\"))\n",
|
||||
"calculate = get_math_tool(ChatOpenAI(model=\"gpt-4-turbo-preview\"))\n",
|
||||
"search = TavilySearchResults(\n",
|
||||
" max_results=1,\n",
|
||||
" description='tavily_search_results_json(query=\"the search query\") - a search engine.',\n",
|
||||
@@ -540,11 +540,11 @@
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"================================\u001B[1m System Message \u001B[0m================================\n",
|
||||
"================================\u001b[1m System Message \u001b[0m================================\n",
|
||||
"\n",
|
||||
"Given a user query, create a plan to solve it with the utmost parallelizability. Each plan should comprise an action from the following \u001B[33;1m\u001B[1;3m{num_tools}\u001B[0m types:\n",
|
||||
"\u001B[33;1m\u001B[1;3m{tool_descriptions}\u001B[0m\n",
|
||||
"\u001B[33;1m\u001B[1;3m{num_tools}\u001B[0m. join(): Collects and combines results from prior actions.\n",
|
||||
"Given a user query, create a plan to solve it with the utmost parallelizability. Each plan should comprise an action from the following \u001b[33;1m\u001b[1;3m{num_tools}\u001b[0m types:\n",
|
||||
"\u001b[33;1m\u001b[1;3m{tool_descriptions}\u001b[0m\n",
|
||||
"\u001b[33;1m\u001b[1;3m{num_tools}\u001b[0m. join(): Collects and combines results from prior actions.\n",
|
||||
"\n",
|
||||
" - An LLM agent is called upon invoking join() to either finalize the user query or wait until the plans are executed.\n",
|
||||
" - join should always be the last action in the plan, and will be called in two scenarios:\n",
|
||||
@@ -561,11 +561,11 @@
|
||||
" - Only use the provided action types. If a query cannot be addressed using these, invoke the join action for the next steps.\n",
|
||||
" - Never introduce new actions other than the ones provided.\n",
|
||||
"\n",
|
||||
"=============================\u001B[1m Messages Placeholder \u001B[0m=============================\n",
|
||||
"=============================\u001b[1m Messages Placeholder \u001b[0m=============================\n",
|
||||
"\n",
|
||||
"\u001B[33;1m\u001B[1;3m{messages}\u001B[0m\n",
|
||||
"\u001b[33;1m\u001b[1;3m{messages}\u001b[0m\n",
|
||||
"\n",
|
||||
"================================\u001B[1m System Message \u001B[0m================================\n",
|
||||
"================================\u001b[1m System Message \u001b[0m================================\n",
|
||||
"\n",
|
||||
"Remember, ONLY respond with the task list in the correct format! E.g.:\n",
|
||||
"idx. tool(arg_name=args)\n",
|
||||
@@ -1030,7 +1030,7 @@
|
||||
"joiner_prompt = hub.pull(\"wfh/llm-compiler-joiner\").partial(\n",
|
||||
" examples=\"\"\n",
|
||||
") # You can optionally add examples\n",
|
||||
"llm = ChatOpenAI(model=\"gpt-4o\")\n",
|
||||
"llm = ChatOpenAI(model=\"gpt-4-turbo-preview\")\n",
|
||||
"\n",
|
||||
"runnable = joiner_prompt | llm.with_structured_output(\n",
|
||||
" JoinOutputs, method=\"function_calling\"\n",
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
# Examples
|
||||
|
||||
The pages in this section provide end-to-end examples for the following topics:
|
||||
|
||||
## General
|
||||
|
||||
- [Agentic RAG](./rag/langgraph_adaptive_rag.ipynb)
|
||||
- [Agent Supervisor](./multi_agent/agent_supervisor.ipynb)
|
||||
- [SQL agent](./sql-agent.ipynb)
|
||||
- [Graph runs in LangSmith](../how-tos/run-id-langsmith.ipynb)
|
||||
|
||||
## LangGraph Platform
|
||||
|
||||
- [Set up custom authentication](./auth/getting_started.md)
|
||||
- [Make conversations private](./auth/resource_auth.md)
|
||||
- [Connect an authentication provider](./auth/add_auth_server.md)
|
||||
- [Rebuild graph at runtime](../cloud/deployment/graph_rebuild.md)
|
||||
- [Use RemoteGraph](../how-tos/use-remote-graph.md)
|
||||
- [Deploy CrewAI, AutoGen, and other frameworks](../how-tos/autogen-langgraph-platform.ipynb)
|
||||
- [Integrate LangGraph into a React app](../cloud/how-tos/use_stream_react.md)
|
||||
- [Implement Generative User Interfaces with LangGraph](../cloud/how-tos/generative_ui_react.md)
|
||||