mirror of
https://github.com/langchain-ai/langgraph.git
synced 2026-10-03 06:55:13 +02:00
Compare commits
262
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0b8634b4c6 | ||
|
|
bc3ef7f913 | ||
|
|
0dda1b4b1e | ||
|
|
d22c2c4dac | ||
|
|
db03dccb2b | ||
|
|
c79c9ea733 | ||
|
|
b115e1dcde | ||
|
|
3b59213311 | ||
|
|
0c0e5a299d | ||
|
|
69d4c37d25 | ||
|
|
0e7554a1a1 | ||
|
|
596c60a65c | ||
|
|
e45797ce19 | ||
|
|
e746b54a57 | ||
|
|
c88e22ffa7 | ||
|
|
dfdeb6a6f1 | ||
|
|
1309243b29 | ||
|
|
ba08acb71c | ||
|
|
dd64636ca8 | ||
|
|
664475887d | ||
|
|
3d3a2bfacd | ||
|
|
771c6150a4 | ||
|
|
edfb65fd3a | ||
|
|
0f92470e49 | ||
|
|
dfcaf97c73 | ||
|
|
63a0028372 | ||
|
|
1134017d07 | ||
|
|
bbe90e04ca | ||
|
|
33feba4877 | ||
|
|
905fcb3d02 | ||
|
|
543d7d85af | ||
|
|
4fec8e9dec | ||
|
|
c137169325 | ||
|
|
1e2672e63d | ||
|
|
06803ab683 | ||
|
|
3488ee47e0 | ||
|
|
289bdd0cea | ||
|
|
417103066b | ||
|
|
25a59447c1 | ||
|
|
21906d2b7b | ||
|
|
0cad7019cb | ||
|
|
7e735672bf | ||
|
|
5498893780 | ||
|
|
e80f47aa01 | ||
|
|
a0b2f742a3 | ||
|
|
b7973d65db | ||
|
|
3fa3a586b5 | ||
|
|
053b606b46 | ||
|
|
4548a0ebe8 | ||
|
|
0171e9a323 | ||
|
|
c439cb0872 | ||
|
|
2a4d7e8889 | ||
|
|
7f3578e0f1 | ||
|
|
e2f96b5ae5 | ||
|
|
0d5f7e55bf | ||
|
|
9209f11187 | ||
|
|
bb1c5b8cdf | ||
|
|
d6bb008ff4 | ||
|
|
6130e08fa6 | ||
|
|
3ad061f0d7 | ||
|
|
116b5d1cac | ||
|
|
0aff02e180 | ||
|
|
074af5c122 | ||
|
|
29ffaa0e0b | ||
|
|
45cd4e1928 | ||
|
|
480271f753 | ||
|
|
66fdf60e47 | ||
|
|
0894daf3fc | ||
|
|
850c55d630 | ||
|
|
c0d65ff409 | ||
|
|
be7b60a722 | ||
|
|
d467ec6556 | ||
|
|
b8683ab67a | ||
|
|
6a9ca8d67e | ||
|
|
3b98044f2f | ||
|
|
a4a8934bd3 | ||
|
|
470b9a4b97 | ||
|
|
516175780d | ||
|
|
571780f74c | ||
|
|
d719438307 | ||
|
|
85c809a651 | ||
|
|
0441fd156f | ||
|
|
37b5d3886c | ||
|
|
b95267a3cc | ||
|
|
2e33c520a5 | ||
|
|
67b1dc602e | ||
|
|
1519b90414 | ||
|
|
0035ab9825 | ||
|
|
c42cd57a32 | ||
|
|
acc56e094a | ||
|
|
6b30d4fd8f | ||
|
|
fcc37cd06b | ||
|
|
c17ee1bf5a | ||
|
|
88c603b00b | ||
|
|
c12f7cb2b9 | ||
|
|
6d7d689578 | ||
|
|
f1b7eca7fc | ||
|
|
93766a6df1 | ||
|
|
a9d4e0da29 | ||
|
|
9105e60a34 | ||
|
|
b735452153 | ||
|
|
5920d8aa92 | ||
|
|
533f5b3d6f | ||
|
|
be5889a7df | ||
|
|
0bf268feca | ||
|
|
5e7566f4a3 | ||
|
|
494c8ef0d2 | ||
|
|
45e60ff9e1 | ||
|
|
194c4c1d1c | ||
|
|
1a76f6a92a | ||
|
|
aedf974dfd | ||
|
|
c0b6a85488 | ||
|
|
9fde14079a | ||
|
|
02f3944e88 | ||
|
|
1ea5812ed0 | ||
|
|
314115513c | ||
|
|
161a1e3af6 | ||
|
|
f8995f234c | ||
|
|
5f1d76ba3b | ||
|
|
13ebe1ad8c | ||
|
|
ae2b766d0f | ||
|
|
b211d4e767 | ||
|
|
0b609646d5 | ||
|
|
5ab5da767b | ||
|
|
a534807ec9 | ||
|
|
89e827bd15 | ||
|
|
d4018497a9 | ||
|
|
7080eaa79e | ||
|
|
9c6e8d5237 | ||
|
|
ae3c2e0b89 | ||
|
|
cd2847ee07 | ||
|
|
7335b80586 | ||
|
|
394ea1c12b | ||
|
|
b00ea605e2 | ||
|
|
bb990715f1 | ||
|
|
fce7652b7c | ||
|
|
8837b8534f | ||
|
|
4473db6361 | ||
|
|
c31c940bbb | ||
|
|
5c18123bb7 | ||
|
|
7ba5636200 | ||
|
|
37c215b5a2 | ||
|
|
f528f5ebd6 | ||
|
|
cd28bef155 | ||
|
|
3a74514bc3 | ||
|
|
2b759a2a33 | ||
|
|
723cff9001 | ||
|
|
7d27d108fc | ||
|
|
f4b480c4b8 | ||
|
|
8c560ef62a | ||
|
|
1e324b681a | ||
|
|
6002aebec5 | ||
|
|
b438210a0d | ||
|
|
b908e96541 | ||
|
|
70dc0323c1 | ||
|
|
a75e40192f | ||
|
|
952017fbe2 | ||
|
|
36bd88287f | ||
|
|
5e5840805e | ||
|
|
7828003958 | ||
|
|
e5e78e4192 | ||
|
|
e2b14a9499 | ||
|
|
2563301f39 | ||
|
|
bbbadc3db9 | ||
|
|
b4cb4e72ab | ||
|
|
7e45a0530b | ||
|
|
dd059fea3c | ||
|
|
871b1dccd8 | ||
|
|
f8b5e05c47 | ||
|
|
6cde3ee7a3 | ||
|
|
d44581d754 | ||
|
|
dc787b5aa6 | ||
|
|
0d6af09187 | ||
|
|
469576f966 | ||
|
|
f00b994692 | ||
|
|
7d6243e6b4 | ||
|
|
8fd50a50d4 | ||
|
|
eaa1b37645 | ||
|
|
21f762140a | ||
|
|
5973fcb0ae | ||
|
|
624c688013 | ||
|
|
d05b323b88 | ||
|
|
765bc3b9e0 | ||
|
|
78d3d8c802 | ||
|
|
3b85c83d51 | ||
|
|
08f88ce8da | ||
|
|
d661d528b2 | ||
|
|
5cbf31e8a4 | ||
|
|
a5e6223569 | ||
|
|
afb83d2201 | ||
|
|
1e8f5dd2b6 | ||
|
|
574a9246a6 | ||
|
|
c46f7a4c3d | ||
|
|
8e82c7d1a0 | ||
|
|
2066e4c018 | ||
|
|
f8fae30aa9 | ||
|
|
2615c7046c | ||
|
|
05f3904d09 | ||
|
|
583fe9fd84 | ||
|
|
0afc4ebda3 | ||
|
|
d55cafad29 | ||
|
|
1b961f68b9 | ||
|
|
045d6dfb82 | ||
|
|
26d5fccfa0 | ||
|
|
76661f4c9c | ||
|
|
9320bedd2a | ||
|
|
3737d886e7 | ||
|
|
8386eaceab | ||
|
|
c32677c92d | ||
|
|
e384ccacaf | ||
|
|
dc95f95181 | ||
|
|
2e4645ce61 | ||
|
|
efb282a197 | ||
|
|
89ce6ea2a8 | ||
|
|
197b01e985 | ||
|
|
1e87312d1f | ||
|
|
bcc6485f6c | ||
|
|
ce5f248e3b | ||
|
|
5602c29668 | ||
|
|
bc404d14f6 | ||
|
|
19ca6b416b | ||
|
|
936176eb21 | ||
|
|
4e8fbe4525 | ||
|
|
85522ec6a6 | ||
|
|
0f8f5444bc | ||
|
|
bc17c3522b | ||
|
|
8c11c1155a | ||
|
|
9c79d887a0 | ||
|
|
889b40e7a8 | ||
|
|
2553ae0b87 | ||
|
|
3e4b69af3f | ||
|
|
0c6367c186 | ||
|
|
99860b5713 | ||
|
|
a69860baa6 | ||
|
|
6fc21046cd | ||
|
|
754420e9a2 | ||
|
|
15126ad827 | ||
|
|
6633173918 | ||
|
|
0139e11ae5 | ||
|
|
bfbe55ab64 | ||
|
|
36478eb745 | ||
|
|
8fb91569b9 | ||
|
|
9bf6728354 | ||
|
|
126a8f5bc6 | ||
|
|
9170f636d0 | ||
|
|
8207d3fefb | ||
|
|
ade3f372a5 | ||
|
|
3a55d1137b | ||
|
|
bece43dc67 | ||
|
|
913b8d5e95 | ||
|
|
29f6ea7f61 | ||
|
|
3c0d9346c2 | ||
|
|
0ebb78d9b2 | ||
|
|
70153ceba2 | ||
|
|
a9c87ed8b6 | ||
|
|
837fe59e24 | ||
|
|
596a26461c | ||
|
|
1ba2b3fba9 | ||
|
|
364fdf5dfe | ||
|
|
fe5d303ccd | ||
|
|
c9fa11ae7d | ||
|
|
988805d60b |
@@ -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: ["02 Bug Report"]
|
||||
labels: [pending,bug]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
blank_issues_enabled: false
|
||||
blank_issues_enabled: true
|
||||
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: [03 - Documentation]
|
||||
labels: [documentation]
|
||||
|
||||
body:
|
||||
- type: textarea
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# 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@v3
|
||||
uses: actions/cache@v4
|
||||
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@v3
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
SEGMENT_DOWNLOAD_TIMEOUT_MIN: "2"
|
||||
with:
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
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,7 +35,6 @@ jobs:
|
||||
- 'libs/checkpoint/**'
|
||||
- 'libs/checkpoint-sqlite/**'
|
||||
- 'libs/checkpoint-postgres/**'
|
||||
- 'libs/scheduler-kafka/**'
|
||||
- 'libs/prebuilt/**'
|
||||
sdk-js:
|
||||
- 'libs/sdk-js/**'
|
||||
@@ -53,7 +52,7 @@ jobs:
|
||||
"libs/checkpoint",
|
||||
"libs/checkpoint-sqlite",
|
||||
"libs/checkpoint-postgres",
|
||||
"libs/scheduler-kafka",
|
||||
|
||||
"libs/prebuilt",
|
||||
]
|
||||
if: needs.changes.outputs.python == 'true'
|
||||
@@ -89,14 +88,6 @@ 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'
|
||||
@@ -166,9 +157,9 @@ jobs:
|
||||
run:
|
||||
working-directory: ${{ matrix.working-directory }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup Node.js (LTS)
|
||||
uses: actions/setup-node@v3
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
cache: "yarn"
|
||||
@@ -192,9 +183,9 @@ jobs:
|
||||
run:
|
||||
working-directory: ${{ matrix.working-directory }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup Node.js (LTS)
|
||||
uses: actions/setup-node@v3
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
cache: "yarn"
|
||||
@@ -212,7 +203,6 @@ jobs:
|
||||
lint-js,
|
||||
test,
|
||||
test-langgraph,
|
||||
test-scheduler-kafka,
|
||||
check-sdk-methods,
|
||||
check-schema,
|
||||
integration-test,
|
||||
|
||||
@@ -4,9 +4,11 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- v0
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- v0
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
@@ -82,9 +84,9 @@ jobs:
|
||||
run: make llms-text
|
||||
- name: Build site
|
||||
run: |
|
||||
# If this is main branch, then we want to download stats. we do this
|
||||
# If this is v0 branch, then we want to download stats. we do this
|
||||
# with the env variable DOWNLOAD_STATS=true
|
||||
if [ "${{ github.ref }}" == "refs/heads/main" ]; then
|
||||
if [ "${{ github.ref }}" == "refs/heads/v0" ]; then
|
||||
DOWNLOAD_STATS=true make build-docs
|
||||
else
|
||||
make build-docs
|
||||
@@ -144,8 +146,8 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Configure GitHub Pages
|
||||
if: github.ref == 'refs/heads/main'
|
||||
uses: actions/configure-pages@v4
|
||||
if: github.ref == 'refs/heads/v0'
|
||||
uses: actions/configure-pages@v5
|
||||
|
||||
- name: Upload Pages Artifact
|
||||
# if: github.ref == 'refs/heads/main'
|
||||
@@ -154,6 +156,6 @@ jobs:
|
||||
path: ./docs/site/
|
||||
|
||||
- name: Deploy to GitHub Pages
|
||||
if: github.ref == 'refs/heads/main'
|
||||
if: github.ref == 'refs/heads/v0'
|
||||
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@v3
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
cache: "yarn"
|
||||
|
||||
@@ -181,3 +181,4 @@ Chinook.db
|
||||
.vercel
|
||||
.turbo
|
||||
.editorconfig
|
||||
.scratch
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
# 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.
|
||||
+1
-1
@@ -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 they way they do.
|
||||
impart perspective to the user rather than to finish a practical project. These guides should cover **why** things work the way they do.
|
||||
|
||||
|
||||
To quote the Diataxis website:
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
# 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,7 +12,6 @@
|
||||
[](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.
|
||||
|
||||
@@ -74,7 +73,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/): Guided examples on getting started with LangGraph.
|
||||
- [Examples](https://langchain-ai.github.io/langgraph/tutorials/overview/): 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,9 +1,16 @@
|
||||
"""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
|
||||
|
||||
@@ -54,6 +61,7 @@ REDIRECT_MAP = {
|
||||
"how-tos/subgraph-persistence.ipynb": "how-tos/persistence.ipynb#use-with-subgraphs",
|
||||
"how-tos/cross-thread-persistence.ipynb": "how-tos/persistence.ipynb#add-long-term-memory",
|
||||
"cloud/how-tos/copy_threads": "cloud/how-tos/use_threads",
|
||||
"cloud/concepts/threads.md": "concepts/persistence.md#threads",
|
||||
# tool calling how-tos
|
||||
"how-tos/tool-calling-errors.ipynb": "how-tos/tool-calling.ipynb#handle-errors",
|
||||
"how-tos/pass-config-to-tools.ipynb": "how-tos/tool-calling.ipynb#access-config",
|
||||
@@ -79,6 +87,8 @@ REDIRECT_MAP = {
|
||||
"cloud/how-tos/stream_events.md": "cloud/how-tos/streaming.md#stream-events",
|
||||
"cloud/how-tos/stream_debug.md": "cloud/how-tos/streaming.md#debug",
|
||||
"cloud/how-tos/stream_multiple.md": "cloud/how-tos/streaming.md#stream-multiple-modes",
|
||||
"cloud/concepts/streaming.md": "concepts/streaming.md",
|
||||
"agents/streaming.md": "how-tos/streaming.md",
|
||||
# prebuit redirects
|
||||
"how-tos/create-react-agent.ipynb": "agents/agents.md#basic-configuration",
|
||||
"how-tos/create-react-agent-memory.ipynb": "agents/memory.md",
|
||||
@@ -100,9 +110,10 @@ REDIRECT_MAP = {
|
||||
# deployment redirects
|
||||
"how-tos/deploy-self-hosted.md": "cloud/deployment/self_hosted_data_plane.md",
|
||||
"concepts/self_hosted.md": "concepts/langgraph_self_hosted_data_plane.md",
|
||||
"tutorials/deployment.md": "concepts/deployment_options.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",
|
||||
"cloud/concepts/runs.md": "concepts/assistants.md#execution",
|
||||
}
|
||||
|
||||
|
||||
@@ -292,7 +303,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)
|
||||
@@ -308,6 +319,52 @@ 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")
|
||||
@@ -324,4 +381,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)
|
||||
|
||||
@@ -15,7 +15,7 @@ This guide shows you how to set up and use LangGraph's **prebuilt**, **reusable*
|
||||
|
||||
Before you start this tutorial, ensure you have the following:
|
||||
|
||||
- An [Anthropic](https://console.anthropic.com/settings/admin-keys) API key
|
||||
- An [Anthropic](https://console.anthropic.com/settings/keys) API key
|
||||
|
||||
## 1. Install dependencies
|
||||
|
||||
|
||||
@@ -89,4 +89,4 @@ LangGraph Studio Web is a specialized UI that you can connect to LangGraph API s
|
||||
|
||||
## Deployment
|
||||
|
||||
Once your LangGraph app is running locally, you can deploy it using LangGraph Platform. Refer to the [deployment options guide](../tutorials/deployment.md) for detailed instructions on all supported deployment models.
|
||||
Once your LangGraph app is running locally, you can deploy it using LangGraph Platform. Refer to the [deployment options guide](../concepts/deployment_options.md) for detailed instructions on all supported deployment models.
|
||||
|
||||
@@ -38,7 +38,7 @@ client = MultiServerMCPClient(
|
||||
"transport": "stdio",
|
||||
},
|
||||
"weather": {
|
||||
# Ensure your start your weather server on port 8000
|
||||
# Ensure you start your weather server on port 8000
|
||||
"url": "http://localhost:8000/mcp",
|
||||
"transport": "streamable_http",
|
||||
}
|
||||
|
||||
@@ -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. Please note that
|
||||
2. The `checkpointer` is passed to the agent. This enables the agent to persist its state across invocations.
|
||||
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 providers a production-ready checkpointer"
|
||||
!!! Note "LangGraph Platform provides 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 composing 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 compose 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.
|
||||
|
||||
|
||||
@@ -29,10 +29,10 @@ LangGraph includes several capabilities essential for building robust, productio
|
||||
|
||||
- [**Memory integration**](./memory.md): Native support for *short-term* (session-based) and *long-term* (persistent across sessions) memory, enabling stateful behaviors in chatbots and assistants.
|
||||
- [**Human-in-the-loop control**](./human-in-the-loop.md): Execution can pause *indefinitely* to await human feedback—unlike websocket-based solutions limited to real-time interaction. This enables asynchronous approval, correction, or intervention at any point in the workflow.
|
||||
- [**Streaming support**](./streaming.md): Real-time streaming of agent state, model tokens, tool outputs, or combined streams.
|
||||
- [**Streaming support**](../how-tos/streaming.md): Real-time streaming of agent state, model tokens, tool outputs, or combined streams.
|
||||
- [**Deployment tooling**](./deployment.md): Includes infrastructure-free deployment tools. [**LangGraph Platform**](https://langchain-ai.github.io/langgraph/concepts/langgraph_platform/) supports testing, debugging, and deployment.
|
||||
- **[Studio](https://langchain-ai.github.io/langgraph/concepts/langgraph_studio/)**: A visual IDE for inspecting and debugging workflows.
|
||||
- Supports multiple [**deployment options**](https://langchain-ai.github.io/langgraph/tutorials/deployment/) for production.
|
||||
- Supports multiple [**deployment options**](https://langchain-ai.github.io/langgraph/concepts/deployment_options.md) for production.
|
||||
|
||||
## High-level building blocks
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ Streaming is available in both sync and async modes:
|
||||
|
||||
!!! tip
|
||||
|
||||
For full details, see the [streaming guide](./streaming.md).
|
||||
For full details, see the [streaming guide](../how-tos/streaming.md).
|
||||
|
||||
## Max iterations
|
||||
|
||||
|
||||
@@ -1,223 +0,0 @@
|
||||
---
|
||||
search:
|
||||
boost: 2
|
||||
tags:
|
||||
- agent
|
||||
hide:
|
||||
- tags
|
||||
---
|
||||
|
||||
# Streaming
|
||||
|
||||
Streaming is key to building responsive applications. There are a few types of data you’ll want to stream:
|
||||
|
||||
1. [**Agent progress**](#agent-progress) — get updates after each node in the agent graph is executed.
|
||||
2. [**LLM tokens**](#llm-tokens) — stream tokens as they are generated by the language model.
|
||||
3. [**Custom updates**](#tool-updates) — emit custom data from tools during execution (e.g., "Fetched 10/100 records")
|
||||
|
||||
You can stream [more than one type of data](#stream-multiple-modes) at a time.
|
||||
|
||||
|
||||
<figure markdown="1">
|
||||
{: style="max-height:300px"}
|
||||
<figcaption>
|
||||
Waiting is for pigeons.
|
||||
</figcaption>
|
||||
</figure>
|
||||
|
||||
## Agent progress
|
||||
|
||||
To stream agent progress, use the [`stream()`][langgraph.graph.state.CompiledStateGraph.stream] or [`astream()`][langgraph.graph.state.CompiledStateGraph.astream] methods with [`stream_mode="updates"`](https://langchain-ai.github.io/langgraph/how-tos/streaming/#updates). This emits an event after every agent step.
|
||||
|
||||
For example, if you have an agent that calls a tool once, you should see the following updates:
|
||||
|
||||
* **LLM node**: AI message with tool call requests
|
||||
* **Tool node**: Tool message with execution result
|
||||
* **LLM node**: Final AI response
|
||||
|
||||
=== "Sync"
|
||||
|
||||
```python
|
||||
agent = create_react_agent(
|
||||
model="anthropic:claude-3-7-sonnet-latest",
|
||||
tools=[get_weather],
|
||||
)
|
||||
# highlight-next-line
|
||||
for chunk in agent.stream(
|
||||
{"messages": [{"role": "user", "content": "what is the weather in sf"}]},
|
||||
# highlight-next-line
|
||||
stream_mode="updates"
|
||||
):
|
||||
print(chunk)
|
||||
print("\n")
|
||||
```
|
||||
|
||||
=== "Async"
|
||||
|
||||
```python
|
||||
agent = create_react_agent(
|
||||
model="anthropic:claude-3-7-sonnet-latest",
|
||||
tools=[get_weather],
|
||||
)
|
||||
# highlight-next-line
|
||||
async for chunk in agent.astream(
|
||||
{"messages": [{"role": "user", "content": "what is the weather in sf"}]},
|
||||
# highlight-next-line
|
||||
stream_mode="updates"
|
||||
):
|
||||
print(chunk)
|
||||
print("\n")
|
||||
```
|
||||
|
||||
## LLM tokens
|
||||
|
||||
To stream tokens as they are produced by the LLM, use `stream_mode="messages"`:
|
||||
|
||||
=== "Sync"
|
||||
|
||||
```python
|
||||
agent = create_react_agent(
|
||||
model="anthropic:claude-3-7-sonnet-latest",
|
||||
tools=[get_weather],
|
||||
)
|
||||
# highlight-next-line
|
||||
for token, metadata in agent.stream(
|
||||
{"messages": [{"role": "user", "content": "what is the weather in sf"}]},
|
||||
# highlight-next-line
|
||||
stream_mode="messages"
|
||||
):
|
||||
print("Token", token)
|
||||
print("Metadata", metadata)
|
||||
print("\n")
|
||||
```
|
||||
|
||||
=== "Async"
|
||||
|
||||
```python
|
||||
agent = create_react_agent(
|
||||
model="anthropic:claude-3-7-sonnet-latest",
|
||||
tools=[get_weather],
|
||||
)
|
||||
# highlight-next-line
|
||||
async for token, metadata in agent.astream(
|
||||
{"messages": [{"role": "user", "content": "what is the weather in sf"}]},
|
||||
# highlight-next-line
|
||||
stream_mode="messages"
|
||||
):
|
||||
print("Token", token)
|
||||
print("Metadata", metadata)
|
||||
print("\n")
|
||||
```
|
||||
|
||||
## Tool updates
|
||||
|
||||
To stream updates from tools as they are executed, you can use [get_stream_writer][langgraph.config.get_stream_writer].
|
||||
|
||||
=== "Sync"
|
||||
|
||||
```python
|
||||
# highlight-next-line
|
||||
from langgraph.config import get_stream_writer
|
||||
|
||||
def get_weather(city: str) -> str:
|
||||
"""Get weather for a given city."""
|
||||
# highlight-next-line
|
||||
writer = get_stream_writer()
|
||||
# stream any arbitrary data
|
||||
# highlight-next-line
|
||||
writer(f"Looking up data for city: {city}")
|
||||
return f"It's always sunny in {city}!"
|
||||
|
||||
agent = create_react_agent(
|
||||
model="anthropic:claude-3-7-sonnet-latest",
|
||||
tools=[get_weather],
|
||||
)
|
||||
|
||||
for chunk in agent.stream(
|
||||
{"messages": [{"role": "user", "content": "what is the weather in sf"}]},
|
||||
# highlight-next-line
|
||||
stream_mode="custom"
|
||||
):
|
||||
print(chunk)
|
||||
print("\n")
|
||||
```
|
||||
|
||||
=== "Async"
|
||||
|
||||
```python
|
||||
# highlight-next-line
|
||||
from langgraph.config import get_stream_writer
|
||||
|
||||
def get_weather(city: str) -> str:
|
||||
"""Get weather for a given city."""
|
||||
# highlight-next-line
|
||||
writer = get_stream_writer()
|
||||
# stream any arbitrary data
|
||||
# highlight-next-line
|
||||
writer(f"Looking up data for city: {city}")
|
||||
return f"It's always sunny in {city}!"
|
||||
|
||||
agent = create_react_agent(
|
||||
model="anthropic:claude-3-7-sonnet-latest",
|
||||
tools=[get_weather],
|
||||
)
|
||||
|
||||
async for chunk in agent.astream(
|
||||
{"messages": [{"role": "user", "content": "what is the weather in sf"}]},
|
||||
# highlight-next-line
|
||||
stream_mode="custom"
|
||||
):
|
||||
print(chunk)
|
||||
print("\n")
|
||||
```
|
||||
|
||||
!!! Note
|
||||
If you add `get_stream_writer` inside your tool, you won't be able to invoke the tool outside of a LangGraph execution context.
|
||||
|
||||
## Stream multiple modes
|
||||
|
||||
You can specify multiple streaming modes by passing stream mode as a list: `stream_mode=["updates", "messages", "custom"]`:
|
||||
|
||||
=== "Sync"
|
||||
|
||||
```python
|
||||
agent = create_react_agent(
|
||||
model="anthropic:claude-3-7-sonnet-latest",
|
||||
tools=[get_weather],
|
||||
)
|
||||
|
||||
for stream_mode, chunk in agent.stream(
|
||||
{"messages": [{"role": "user", "content": "what is the weather in sf"}]},
|
||||
# highlight-next-line
|
||||
stream_mode=["updates", "messages", "custom"]
|
||||
):
|
||||
print(chunk)
|
||||
print("\n")
|
||||
```
|
||||
|
||||
=== "Async"
|
||||
|
||||
```python
|
||||
agent = create_react_agent(
|
||||
model="anthropic:claude-3-7-sonnet-latest",
|
||||
tools=[get_weather],
|
||||
)
|
||||
|
||||
async for stream_mode, chunk in agent.astream(
|
||||
{"messages": [{"role": "user", "content": "what is the weather in sf"}]},
|
||||
# highlight-next-line
|
||||
stream_mode=["updates", "messages", "custom"]
|
||||
):
|
||||
print(chunk)
|
||||
print("\n")
|
||||
```
|
||||
|
||||
## Disable streaming
|
||||
|
||||
In some applications you might need to disable streaming of individual tokens for a given model. This is useful in [multi-agent](./multi-agent.md) systems to control which agents stream their output.
|
||||
|
||||
See the [Models](./models.md#disable-streaming) guide to learn how to disable streaming.
|
||||
|
||||
## Additional resources
|
||||
|
||||
* [Streaming in LangGraph](https://langchain-ai.github.io/langgraph/how-tos/streaming)
|
||||
+1
-296
@@ -1,296 +1 @@
|
||||
---
|
||||
search:
|
||||
boost: 2
|
||||
tags:
|
||||
- agent
|
||||
hide:
|
||||
- tags
|
||||
---
|
||||
|
||||
# Tools
|
||||
|
||||
[Tools](https://python.langchain.com/docs/concepts/tools/) are a way to encapsulate a function and its input schema in a way that can be passed to a chat model that supports tool calling. This allows the model to request the execution of this function with specific inputs.
|
||||
|
||||
You can either [define your own tools](#define-simple-tools) or use [prebuilt integrations](#prebuilt-tools) that LangChain provides.
|
||||
|
||||
## Define simple tools
|
||||
|
||||
You can pass a vanilla function to `create_react_agent` to use as a tool:
|
||||
|
||||
```python
|
||||
from langgraph.prebuilt import create_react_agent
|
||||
|
||||
def multiply(a: int, b: int) -> int:
|
||||
"""Multiply two numbers."""
|
||||
return a * b
|
||||
|
||||
create_react_agent(
|
||||
model="anthropic:claude-3-7-sonnet",
|
||||
tools=[multiply]
|
||||
)
|
||||
```
|
||||
|
||||
`create_react_agent` automatically converts vanilla functions to [LangChain tools](https://python.langchain.com/docs/concepts/tools/#tool-interface).
|
||||
|
||||
## Customize tools
|
||||
|
||||
For more control over tool behavior, use the `@tool` decorator:
|
||||
|
||||
```python
|
||||
# highlight-next-line
|
||||
from langchain_core.tools import tool
|
||||
|
||||
# highlight-next-line
|
||||
@tool("multiply_tool", parse_docstring=True)
|
||||
def multiply(a: int, b: int) -> int:
|
||||
"""Multiply two numbers.
|
||||
|
||||
Args:
|
||||
a: First operand
|
||||
b: Second operand
|
||||
"""
|
||||
return a * b
|
||||
```
|
||||
|
||||
You can also define a custom input schema using Pydantic:
|
||||
|
||||
```python
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
class MultiplyInputSchema(BaseModel):
|
||||
"""Multiply two numbers"""
|
||||
a: int = Field(description="First operand")
|
||||
b: int = Field(description="Second operand")
|
||||
|
||||
# highlight-next-line
|
||||
@tool("multiply_tool", args_schema=MultiplyInputSchema)
|
||||
def multiply(a: int, b: int) -> int:
|
||||
return a * b
|
||||
```
|
||||
|
||||
For additional customization, refer to the [custom tools guide](https://python.langchain.com/docs/how_to/custom_tools/).
|
||||
|
||||
## Hide arguments from the model
|
||||
|
||||
Some tools require runtime-only arguments (e.g., user ID or session context) that should not be controllable by the model.
|
||||
|
||||
You can put these arguments in the `state` or `config` of the agent, and access
|
||||
this information inside the tool:
|
||||
|
||||
```python
|
||||
from langgraph.prebuilt import InjectedState
|
||||
from langgraph.prebuilt.chat_agent_executor import AgentState
|
||||
from langchain_core.runnables import RunnableConfig
|
||||
|
||||
def my_tool(
|
||||
# This will be populated by an LLM
|
||||
tool_arg: str,
|
||||
# access information that's dynamically updated inside the agent
|
||||
# highlight-next-line
|
||||
state: Annotated[AgentState, InjectedState],
|
||||
# access static data that is passed at agent invocation
|
||||
# highlight-next-line
|
||||
config: RunnableConfig,
|
||||
) -> str:
|
||||
"""My tool."""
|
||||
do_something_with_state(state["messages"])
|
||||
do_something_with_config(config)
|
||||
...
|
||||
```
|
||||
|
||||
## Disable parallel tool calling
|
||||
|
||||
Some model providers support executing multiple tools in parallel, but
|
||||
allow users to disable this feature.
|
||||
|
||||
For supported providers, you can disable parallel tool calling by setting `parallel_tool_calls=False` via the `model.bind_tools()` method:
|
||||
|
||||
```python
|
||||
from langchain.chat_models import init_chat_model
|
||||
|
||||
def add(a: int, b: int) -> int:
|
||||
"""Add two numbers"""
|
||||
return a + b
|
||||
|
||||
def multiply(a: int, b: int) -> int:
|
||||
"""Multiply two numbers."""
|
||||
return a * b
|
||||
|
||||
model = init_chat_model("anthropic:claude-3-5-sonnet-latest", temperature=0)
|
||||
tools = [add, multiply]
|
||||
agent = create_react_agent(
|
||||
# disable parallel tool calls
|
||||
# highlight-next-line
|
||||
model=model.bind_tools(tools, parallel_tool_calls=False),
|
||||
tools=tools
|
||||
)
|
||||
|
||||
agent.invoke(
|
||||
{"messages": [{"role": "user", "content": "what's 3 + 5 and 4 * 7?"}]}
|
||||
)
|
||||
```
|
||||
|
||||
## Return tool results directly
|
||||
|
||||
Use `return_direct=True` to return tool results immediately and stop the agent loop:
|
||||
|
||||
```python
|
||||
from langchain_core.tools import tool
|
||||
|
||||
# highlight-next-line
|
||||
@tool(return_direct=True)
|
||||
def add(a: int, b: int) -> int:
|
||||
"""Add two numbers"""
|
||||
return a + b
|
||||
|
||||
agent = create_react_agent(
|
||||
model="anthropic:claude-3-7-sonnet-latest",
|
||||
tools=[add]
|
||||
)
|
||||
|
||||
agent.invoke(
|
||||
{"messages": [{"role": "user", "content": "what's 3 + 5?"}]}
|
||||
)
|
||||
```
|
||||
|
||||
## Force tool use
|
||||
|
||||
To force the agent to use specific tools, you can set the `tool_choice` option in `model.bind_tools()`:
|
||||
|
||||
```python
|
||||
from langchain_core.tools import tool
|
||||
|
||||
# highlight-next-line
|
||||
@tool(return_direct=True)
|
||||
def greet(user_name: str) -> int:
|
||||
"""Greet user."""
|
||||
return f"Hello {user_name}!"
|
||||
|
||||
tools = [greet]
|
||||
|
||||
agent = create_react_agent(
|
||||
# highlight-next-line
|
||||
model=model.bind_tools(tools, tool_choice={"type": "tool", "name": "greet"}),
|
||||
tools=tools
|
||||
)
|
||||
|
||||
agent.invoke(
|
||||
{"messages": [{"role": "user", "content": "Hi, I am Bob"}]}
|
||||
)
|
||||
```
|
||||
|
||||
!!! Warning "Avoid infinite loops"
|
||||
|
||||
Forcing tool usage without stopping conditions can create infinite loops. Use one of the following safeguards:
|
||||
|
||||
- Mark the tool with [`return_direct=True`](#return-tool-results-directly) to end the loop after execution.
|
||||
- Set [`recursion_limit`](../concepts/low_level.md#recursion-limit) to restrict the number of execution steps.
|
||||
|
||||
## Handle tool errors
|
||||
|
||||
By default, the agent will catch all exceptions raised during tool calls and will pass those as tool messages to the LLM. To control how the errors are handled, you can use the prebuilt [`ToolNode`][langgraph.prebuilt.tool_node.ToolNode] — the node that executes tools inside `create_react_agent` — via its `handle_tool_errors` parameter:
|
||||
|
||||
=== "Enable error handling (default)"
|
||||
|
||||
```python
|
||||
from langgraph.prebuilt import create_react_agent
|
||||
|
||||
def multiply(a: int, b: int) -> int:
|
||||
"""Multiply two numbers."""
|
||||
if a == 42:
|
||||
raise ValueError("The ultimate error")
|
||||
return a * b
|
||||
|
||||
# Run with error handling (default)
|
||||
agent = create_react_agent(
|
||||
model="anthropic:claude-3-7-sonnet-latest",
|
||||
tools=[multiply]
|
||||
)
|
||||
agent.invoke(
|
||||
{"messages": [{"role": "user", "content": "what's 42 x 7?"}]}
|
||||
)
|
||||
```
|
||||
|
||||
=== "Disable error handling"
|
||||
|
||||
```python
|
||||
from langgraph.prebuilt import create_react_agent, ToolNode
|
||||
|
||||
def multiply(a: int, b: int) -> int:
|
||||
"""Multiply two numbers."""
|
||||
if a == 42:
|
||||
raise ValueError("The ultimate error")
|
||||
return a * b
|
||||
|
||||
# highlight-next-line
|
||||
tool_node = ToolNode(
|
||||
[multiply],
|
||||
# highlight-next-line
|
||||
handle_tool_errors=False # (1)!
|
||||
)
|
||||
agent_no_error_handling = create_react_agent(
|
||||
model="anthropic:claude-3-7-sonnet-latest",
|
||||
tools=tool_node
|
||||
)
|
||||
agent_no_error_handling.invoke(
|
||||
{"messages": [{"role": "user", "content": "what's 42 x 7?"}]}
|
||||
)
|
||||
```
|
||||
|
||||
1. This disables error handling (enabled by default). See all available strategies in the [API reference][langgraph.prebuilt.tool_node.ToolNode].
|
||||
|
||||
=== "Custom error handling"
|
||||
|
||||
```python
|
||||
from langgraph.prebuilt import create_react_agent, ToolNode
|
||||
|
||||
def multiply(a: int, b: int) -> int:
|
||||
"""Multiply two numbers."""
|
||||
if a == 42:
|
||||
raise ValueError("The ultimate error")
|
||||
return a * b
|
||||
|
||||
# highlight-next-line
|
||||
tool_node = ToolNode(
|
||||
[multiply],
|
||||
# highlight-next-line
|
||||
handle_tool_errors=(
|
||||
"Can't use 42 as a first operand, you must switch operands!" # (1)!
|
||||
)
|
||||
)
|
||||
agent_custom_error_handling = create_react_agent(
|
||||
model="anthropic:claude-3-7-sonnet-latest",
|
||||
tools=tool_node
|
||||
)
|
||||
agent_custom_error_handling.invoke(
|
||||
{"messages": [{"role": "user", "content": "what's 42 x 7?"}]}
|
||||
)
|
||||
```
|
||||
|
||||
1. This provides a custom message to send to the LLM in case of an exception. See all available strategies in the [API reference][langgraph.prebuilt.tool_node.ToolNode].
|
||||
|
||||
See [API reference][langgraph.prebuilt.tool_node.ToolNode] for more information on different tool error handling options.
|
||||
|
||||
## Working with memory
|
||||
|
||||
LangGraph allows access to short-term and long-term memory from tools. See [Memory](./memory.md) guide for more information on:
|
||||
|
||||
* how to [read](./memory.md#read-short-term) from and [write](./memory.md#write-short-term) to **short-term** memory
|
||||
* how to [read](./memory.md#read-long-term) from and [write](./memory.md#write-long-term) to **long-term** memory
|
||||
|
||||
## Prebuilt tools
|
||||
|
||||
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/).
|
||||
|
||||
Some commonly used tool categories include:
|
||||
|
||||
- **Search**: Bing, SerpAPI, Tavily
|
||||
- **Code interpreters**: Python REPL, Node.js REPL
|
||||
- **Databases**: SQL, MongoDB, Redis
|
||||
- **Web data**: Web scraping and browsing
|
||||
- **APIs**: OpenWeatherMap, NewsAPI, and others
|
||||
|
||||
These integrations can be configured and added to your agents using the same `tools` parameter shown in the examples above.
|
||||
|
||||
delete me
|
||||
@@ -1,5 +0,0 @@
|
||||
# Runs
|
||||
|
||||
A run is an invocation of an [assistant](../../concepts/assistants.md). Each run may have its own input, configuration, and metadata, which may affect execution and output of the underlying graph. A run can optionally be executed on a [thread](./threads.md).
|
||||
|
||||
The LangGraph Platform API provides several endpoints for creating and managing runs. See the [API reference](../../cloud/reference/api/api_ref.html#tag/thread-runs/) for more details.
|
||||
@@ -1,138 +0,0 @@
|
||||
# Streaming
|
||||
|
||||
Streaming is critical for making LLM applications feel responsive to end users.
|
||||
When creating a streaming run, the **streaming mode** determines what kinds of data are streamed back to the API client.
|
||||
|
||||
## Supported streaming modes
|
||||
|
||||
LangGraph Platform supports the following streaming modes:
|
||||
|
||||
| Mode | Description | LangGraph Library Method |
|
||||
|----------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------|
|
||||
| **`values`** | Stream the full graph state after each [super-step](https://langchain-ai.github.io/langgraph/concepts/low_level/#graphs). [Guide](../how-tos/streaming.md#stream-graph-state) | `.stream()` / `.astream()` with `stream_mode="values"` |
|
||||
| **`updates`** | Stream only the updates to the graph state after each node. [Guide](../how-tos/streaming.md#stream-graph-state) | `.stream()` / `.astream()` with `stream_mode="updates"` |
|
||||
| **`messages-tuple`** | Stream LLM tokens for any messages generated inside the graph (useful for chat apps). [Guide](../how-tos/streaming.md#messages) | `.stream()` / `.astream()` with `stream_mode="messages"` |
|
||||
| **`debug`** | Stream debug information throughout graph execution. [Guide](../how-tos/streaming.md#debug) | `.stream()` / `.astream()` with `stream_mode="debug"` |
|
||||
| **`custom`** | Stream custom data. [Guide](../../how-tos/streaming.md#stream-custom-data) | `.stream()` / `.astream()` with `stream_mode="custom"` |
|
||||
| **`events`** | Stream all events (including the state of the graph); mainly useful when migrating large LCEL apps. [Guide](../how-tos/streaming.md#stream-events) | `.astream_events()` |
|
||||
|
||||
✅ You can also **combine multiple modes** at the same time. See the [how-to guide](../how-tos/streaming.md#stream-multiple-modes) for configuration details.
|
||||
|
||||
## Stateless runs
|
||||
|
||||
If you don't want to **persist the outputs** of a streaming run in the [checkpointer](../../concepts/persistence.md) DB, you can create a stateless run without creating a thread:
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
from langgraph_sdk import get_client
|
||||
client = get_client(url=<DEPLOYMENT_URL>, api_key=<API_KEY>)
|
||||
|
||||
async for chunk in client.runs.stream(
|
||||
# highlight-next-line
|
||||
None, # (1)!
|
||||
assistant_id,
|
||||
input=inputs,
|
||||
stream_mode="updates"
|
||||
):
|
||||
print(chunk.data)
|
||||
```
|
||||
|
||||
1. We are passing `None` instead of a `thread_id` UUID.
|
||||
|
||||
=== "JavaScript"
|
||||
|
||||
```js
|
||||
import { Client } from "@langchain/langgraph-sdk";
|
||||
const client = new Client({ apiUrl: <DEPLOYMENT_URL>, apiKey: <API_KEY> });
|
||||
|
||||
// create a streaming run
|
||||
// highlight-next-line
|
||||
const streamResponse = client.runs.stream(
|
||||
// highlight-next-line
|
||||
null, // (1)!
|
||||
assistantID,
|
||||
{
|
||||
input,
|
||||
streamMode: "updates"
|
||||
}
|
||||
);
|
||||
for await (const chunk of streamResponse) {
|
||||
console.log(chunk.data);
|
||||
}
|
||||
```
|
||||
|
||||
1. We are passing `None` instead of a `thread_id` UUID.
|
||||
|
||||
=== "cURL"
|
||||
|
||||
```bash
|
||||
curl --request POST \
|
||||
--url <DEPLOYMENT_URL>/runs/stream \
|
||||
--header 'Content-Type: application/json' \
|
||||
--header 'x-api-key: <API_KEY>'
|
||||
--data "{
|
||||
\"assistant_id\": \"agent\",
|
||||
\"input\": <inputs>,
|
||||
\"stream_mode\": \"updates\"
|
||||
}"
|
||||
```
|
||||
|
||||
## Join and stream
|
||||
|
||||
LangGraph Platform allows you to join an active [background run](../how-tos/background_run.md) and stream outputs from it. To do so, you can use [LangGraph SDK's](https://langchain-ai.github.io/langgraph/cloud/reference/sdk/python_sdk_ref/) `client.runs.join_stream` method:
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
from langgraph_sdk import get_client
|
||||
client = get_client(url=<DEPLOYMENT_URL>, api_key=<API_KEY>)
|
||||
|
||||
# highlight-next-line
|
||||
async for chunk in client.runs.join_stream(
|
||||
thread_id,
|
||||
# highlight-next-line
|
||||
run_id, # (1)!
|
||||
):
|
||||
print(chunk)
|
||||
```
|
||||
|
||||
1. This is the `run_id` of an existing run you want to join.
|
||||
|
||||
|
||||
=== "JavaScript"
|
||||
|
||||
```js
|
||||
import { Client } from "@langchain/langgraph-sdk";
|
||||
const client = new Client({ apiUrl: <DEPLOYMENT_URL>, apiKey: <API_KEY> });
|
||||
|
||||
// highlight-next-line
|
||||
const streamResponse = client.runs.joinStream(
|
||||
threadID,
|
||||
// highlight-next-line
|
||||
runId // (1)!
|
||||
);
|
||||
for await (const chunk of streamResponse) {
|
||||
console.log(chunk);
|
||||
}
|
||||
```
|
||||
|
||||
1. This is the `run_id` of an existing run you want to join.
|
||||
|
||||
=== "cURL"
|
||||
|
||||
```bash
|
||||
curl --request GET \
|
||||
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/<RUN_ID>/stream \
|
||||
--header 'Content-Type: application/json' \
|
||||
--header 'x-api-key: <API_KEY>'
|
||||
```
|
||||
|
||||
!!! warning "Outputs not buffered"
|
||||
|
||||
When you use `.join_stream`, output is not buffered, so any output produced before joining will not be received.
|
||||
|
||||
## API Reference
|
||||
|
||||
For API usage and implementation, refer to the [API reference](../reference/api/api_ref.html#tag/thread-runs/POST/threads/{thread_id}/runs/stream).
|
||||
|
||||
@@ -62,6 +62,15 @@ Starting from the `LangGraph Platform` view...
|
||||
1. In the panel, select the `Server` tab to view server logs for the revision. Server logs are only available after a revision has been deployed.
|
||||
1. Within the `Server` tab, adjust the date/time range picker as needed. By default, the date/time range picker is set to the `Last 7 days`.
|
||||
|
||||
## View Deployment Metrics
|
||||
|
||||
Starting from the <a href="https://smith.langchain.com/" target="_blank">LangSmith UI</a>...
|
||||
|
||||
1. In the left-hand navigation panel, select `LangGraph Platform`. The `LangGraph Platform` view contains a list of existing LangGraph Platform deployments.
|
||||
1. Select an existing deployment to monitor.
|
||||
1. Select the `Monitoring` tab to view the deployment metrics. See a list of [all available metrics](../../concepts/langgraph_control_plane.md#monitoring).
|
||||
1. Within the `Monitoring` tab, use the date/time range picker as needed. By default, the date/time range picker is set to the `Last 15 minutes`.
|
||||
|
||||
## Interrupt Revision
|
||||
|
||||
Interrupting a revision will stop deployment of the revision.
|
||||
|
||||
@@ -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 `jpeq` or `png` image formats.
|
||||
This would install the system packages required to use Pillow if we were working with `jpeg` or `png` image formats.
|
||||
@@ -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.
|
||||
|
||||
!!! important "Beta"
|
||||
The Self-Hosted Control Plane deployment option is currently in beta stage.
|
||||
!!! info "Important"
|
||||
The Self-Hosted Control Plane deployment option is currently in beta stage and requires an [Enterprise](../../concepts/plans.md) plan.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
@@ -30,18 +30,17 @@ 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.
|
||||
1. Two additional images will be used by the chart. Use the images that are specified in the latest release.
|
||||
|
||||
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 `values.yaml` file, enable the `langgraphPlatform` option. Note that you must also have a valid ingress setup:
|
||||
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:
|
||||
|
||||
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.
|
||||
|
||||
!!! important "Beta"
|
||||
The Self-Hosted Data Plane deployment option is currently in beta stage.
|
||||
!!! info "Important"
|
||||
The Self-Hosted Data Plane deployment option is currently in beta stage and requires an [Enterprise](../../concepts/plans.md) plan.
|
||||
|
||||
## 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 [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).
|
||||
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).
|
||||
|
||||
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):
|
||||
|
||||
|
||||
@@ -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 [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).
|
||||
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).
|
||||
|
||||
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):
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ For more information on breakpoints see [here](../../concepts/breakpoints.md).
|
||||
|
||||
### Submit run
|
||||
|
||||
To submit the run with the specified input and run settings, click the "Submit" button. This will add a [run](../concepts/runs.md) to the existing selected [thread](../concepts/threads.md). If no thread is currently selected, a new one will be created.
|
||||
To submit the run with the specified input and run settings, click the "Submit" button. This will add a [run](../concepts/runs.md) to the existing selected [thread](../../concepts/persistence.md#threads). If no thread is currently selected, a new one will be created.
|
||||
|
||||
To cancel the ongoing run, click the "Cancel" button.
|
||||
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
# Stream outputs
|
||||
# Streaming API
|
||||
|
||||
## Streaming API
|
||||
[LangGraph SDK](https://langchain-ai.github.io/langgraph/cloud/reference/sdk/python_sdk_ref/) allows you to [stream outputs](../../concepts/streaming.md) from the LangGraph API server.
|
||||
|
||||
[LangGraph SDK](https://langchain-ai.github.io/langgraph/cloud/reference/sdk/python_sdk_ref/) allows you to stream outputs from the LangGraph API server.
|
||||
!!! note
|
||||
|
||||
LangGraph SDK and LangGraph Server are a part of [LangGraph Platform](../../concepts/langgraph_platform.md).
|
||||
|
||||
## Basic usage
|
||||
|
||||
Basic usage example:
|
||||
|
||||
@@ -833,3 +837,121 @@ To stream all events, including the state of the graph:
|
||||
\"stream_mode\": \"events\"
|
||||
}"
|
||||
```
|
||||
|
||||
## Stateless runs
|
||||
|
||||
If you don't want to **persist the outputs** of a streaming run in the [checkpointer](../../concepts/persistence.md) DB, you can create a stateless run without creating a thread:
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
from langgraph_sdk import get_client
|
||||
client = get_client(url=<DEPLOYMENT_URL>, api_key=<API_KEY>)
|
||||
|
||||
async for chunk in client.runs.stream(
|
||||
# highlight-next-line
|
||||
None, # (1)!
|
||||
assistant_id,
|
||||
input=inputs,
|
||||
stream_mode="updates"
|
||||
):
|
||||
print(chunk.data)
|
||||
```
|
||||
|
||||
1. We are passing `None` instead of a `thread_id` UUID.
|
||||
|
||||
=== "JavaScript"
|
||||
|
||||
```js
|
||||
import { Client } from "@langchain/langgraph-sdk";
|
||||
const client = new Client({ apiUrl: <DEPLOYMENT_URL>, apiKey: <API_KEY> });
|
||||
|
||||
// create a streaming run
|
||||
// highlight-next-line
|
||||
const streamResponse = client.runs.stream(
|
||||
// highlight-next-line
|
||||
null, // (1)!
|
||||
assistantID,
|
||||
{
|
||||
input,
|
||||
streamMode: "updates"
|
||||
}
|
||||
);
|
||||
for await (const chunk of streamResponse) {
|
||||
console.log(chunk.data);
|
||||
}
|
||||
```
|
||||
|
||||
1. We are passing `None` instead of a `thread_id` UUID.
|
||||
|
||||
=== "cURL"
|
||||
|
||||
```bash
|
||||
curl --request POST \
|
||||
--url <DEPLOYMENT_URL>/runs/stream \
|
||||
--header 'Content-Type: application/json' \
|
||||
--header 'x-api-key: <API_KEY>'
|
||||
--data "{
|
||||
\"assistant_id\": \"agent\",
|
||||
\"input\": <inputs>,
|
||||
\"stream_mode\": \"updates\"
|
||||
}"
|
||||
```
|
||||
|
||||
## Join and stream
|
||||
|
||||
LangGraph Platform allows you to join an active [background run](../how-tos/background_run.md) and stream outputs from it. To do so, you can use [LangGraph SDK's](https://langchain-ai.github.io/langgraph/cloud/reference/sdk/python_sdk_ref/) `client.runs.join_stream` method:
|
||||
|
||||
=== "Python"
|
||||
|
||||
```python
|
||||
from langgraph_sdk import get_client
|
||||
client = get_client(url=<DEPLOYMENT_URL>, api_key=<API_KEY>)
|
||||
|
||||
# highlight-next-line
|
||||
async for chunk in client.runs.join_stream(
|
||||
thread_id,
|
||||
# highlight-next-line
|
||||
run_id, # (1)!
|
||||
):
|
||||
print(chunk)
|
||||
```
|
||||
|
||||
1. This is the `run_id` of an existing run you want to join.
|
||||
|
||||
|
||||
=== "JavaScript"
|
||||
|
||||
```js
|
||||
import { Client } from "@langchain/langgraph-sdk";
|
||||
const client = new Client({ apiUrl: <DEPLOYMENT_URL>, apiKey: <API_KEY> });
|
||||
|
||||
// highlight-next-line
|
||||
const streamResponse = client.runs.joinStream(
|
||||
threadID,
|
||||
// highlight-next-line
|
||||
runId // (1)!
|
||||
);
|
||||
for await (const chunk of streamResponse) {
|
||||
console.log(chunk);
|
||||
}
|
||||
```
|
||||
|
||||
1. This is the `run_id` of an existing run you want to join.
|
||||
|
||||
=== "cURL"
|
||||
|
||||
```bash
|
||||
curl --request GET \
|
||||
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/<RUN_ID>/stream \
|
||||
--header 'Content-Type: application/json' \
|
||||
--header 'x-api-key: <API_KEY>'
|
||||
```
|
||||
|
||||
!!! warning "Outputs not buffered"
|
||||
|
||||
When you use `.join_stream`, output is not buffered, so any output produced before joining will not be received.
|
||||
|
||||
## API Reference
|
||||
|
||||
For API usage and implementation, refer to the [API reference](../reference/api/api_ref.html#tag/thread-runs/POST/threads/{thread_id}/runs/stream).
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ LangGraph Studio is accessed from the LangSmith UI, within the LangGraph Platfor
|
||||
|
||||
For applications that are [deployed](../../quick_start.md) on LangGraph Platform, you can access Studio as part of that deployment. To do so, navigate to the deployment in LangGraph Platform within the LangSmith UI and click the "LangGraph Studio" button.
|
||||
|
||||
This will load the Studio UI connected to your live deployment, allowing you to create, read, and update the [threads](../../concepts/threads.md), [assistants](../../../concepts/assistants.md), and [memory](../../../concepts//memory.md) in that deployment.
|
||||
This will load the Studio UI connected to your live deployment, allowing you to create, read, and update the [threads](../../../concepts/persistence.md#threads), [assistants](../../../concepts/assistants.md), and [memory](../../../concepts//memory.md) in that deployment.
|
||||
|
||||
## Local development server
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
# Run experiments over a dataset
|
||||
|
||||
LangGraph Studio supports evaluations by allowing you to run your assistant over a pre-defined LangSmith dataset. This enables you to understand how your application performs over a variety of inputs, compare the results to reference outputs, and score the results using [evaluators](../../../agents/evals.md).
|
||||
|
||||
This guide shows you how to run an experiment end-to-end from Studio.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before running an experiment, ensure you have the following:
|
||||
|
||||
1. **A LangSmith dataset**: Your dataset should contain the inputs you want to test and optionally, reference outputs for comparison.
|
||||
|
||||
- The schema for the inputs must match the required input schema for the assistant. For more information on schemas, see [here](../../../concepts/low_level.md#schema).
|
||||
- For more on creating datasets, see [How to Manage Datasets](https://docs.smith.langchain.com/evaluation/how_to_guides/manage_datasets_in_application#set-up-your-dataset).
|
||||
|
||||
2. **(Optional) Evaluators**: You can attach evaluators (e.g., LLM-as-a-Judge, heuristics, or custom functions) to your dataset in LangSmith. These will run automatically after the graph has processed all inputs.
|
||||
|
||||
- To learn more, read about [Evaluation Concepts](https://docs.smith.langchain.com/evaluation/concepts#evaluators).
|
||||
|
||||
3. **A running application**: The experiment can be run against:
|
||||
- An application deployed on [LangGraph Platform](../../quick_start.md).
|
||||
- A locally running application started via the [langgraph-cli](../../../tutorials/langgraph-platform/local-server.md).
|
||||
|
||||
---
|
||||
|
||||
## Step-by-step guide
|
||||
|
||||
### 1. Launch the experiment
|
||||
|
||||
Click the **Run experiment** button in the top right corner of the Studio page.
|
||||
|
||||
### 2. Select your dataset
|
||||
|
||||
In the modal that appears, select the dataset (or a specific dataset split) to use for the experiment and click **Start**.
|
||||
|
||||
### 3. Monitor the progress
|
||||
|
||||
All of the inputs in the dataset will now be run against the active assistant. Monitor the experiment's progress via the badge in the top right corner.
|
||||
|
||||
You can continue to work in Studio while the experiment runs in the background. Click the arrow icon button at any time to navigate to LangSmith and view the detailed experiment results.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Run experiment" button is disabled
|
||||
|
||||
If the "Run experiment" button is disabled, check the following:
|
||||
|
||||
- **Deployed application**: If your application is deployed on LangGraph Platform, you may need to create a new revision to enable this feature.
|
||||
- **Local development server**: If you are running your application locally, make sure you have upgraded to the latest version of the `langgraph-cli` (`pip install -U langgraph-cli`). Additionally, ensure you have tracing enabled by setting the `LANGSMITH_API_KEY` in your project's `.env` file.
|
||||
|
||||
### Evaluator results are missing
|
||||
|
||||
When you run an experiment, any attached evaluators are scheduled for execution in a queue. If you don't see results immediately, it likely means they are still pending.
|
||||
@@ -1,10 +1,6 @@
|
||||
# Manage threads
|
||||
|
||||
!!! info "Prerequisites"
|
||||
|
||||
- [Threads Overview](../concepts/threads.md)
|
||||
|
||||
Studio allows you to view threads from the server and edit their state.
|
||||
Studio allows you to view [threads](../../concepts/persistence.md#threads) from the server and edit their state.
|
||||
|
||||
## View threads
|
||||
|
||||
|
||||
@@ -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,6 +113,115 @@ 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:
|
||||
@@ -127,7 +236,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.
|
||||
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
# Use threads
|
||||
|
||||
!!! info "Prerequisites"
|
||||
|
||||
- [Threads Overview](../concepts/threads.md)
|
||||
|
||||
In this guide, we will show how to create, view, and inspect threads.
|
||||
In this guide, we will show how to create, view, and inspect [threads](../../concepts/persistence.md#threads).
|
||||
|
||||
## Create a thread
|
||||
|
||||
|
||||
@@ -3818,6 +3818,14 @@
|
||||
"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,
|
||||
|
||||
@@ -43,6 +43,7 @@ The LangGraph CLI requires a JSON configuration file that follows this [schema](
|
||||
| <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;">`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`) |
|
||||
@@ -79,6 +80,20 @@ 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,3 +123,12 @@ 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 you graph
|
||||
│ │ ├── nodes.py # node functions for your graph
|
||||
│ │ └── state.py # state definition of your graph
|
||||
│ ├── __init__.py
|
||||
│ └── agent.py # code for constructing your graph
|
||||
|
||||
@@ -1,29 +1,31 @@
|
||||
# Assistants
|
||||
|
||||
!!! info "Prerequisites"
|
||||
**Assistants** allow you to manage configurations (like prompts, LLM selection, tools) separately from your graph's core logic, enabling rapid changes that don't alter the graph architecture. It is a way to create multiple specialized versions of the same graph architecture, each optimized for different use cases through configuration variations rather than structural changes.
|
||||
|
||||
- [LangGraph Server](./langgraph_server.md)
|
||||
- [Configuration](./low_level.md#configuration)
|
||||
|
||||
When building agents, it is common to make rapid changes that _do not_ alter the graph logic. For example, simply changing prompts or the LLM selection can have significant impacts on the behavior of the agent but does not require updating your graph's architecture. Assistants offer a straightforward way to manage these configurations separately from your graph's core logic.
|
||||
|
||||
Imagine a general-purpose writing agent built on a common graph architecture. While the structure remains the same, different writing styles—such as blog posts and tweets—require tailored configurations to optimize performance. To support these variations, you can create multiple assistants (e.g., one for blogs and another for tweets) that share the underlying graph but differ in model selection and system prompt.
|
||||
For example, imagine a general-purpose writing agent built on a common graph architecture. While the structure remains the same, different writing styles—such as blog posts and tweets—require tailored configurations to optimize performance. To support these variations, you can create multiple assistants (e.g., one for blogs and another for tweets) that share the underlying graph but differ in model selection and system prompt.
|
||||
|
||||

|
||||
|
||||
## Configuring assistants
|
||||
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.
|
||||
|
||||
!!! info
|
||||
|
||||
Assistants are a [LangGraph Platform](langgraph_platform.md) concept. They are not available in the open source LangGraph library.
|
||||
|
||||
## Configuration
|
||||
|
||||
Assistants build on the LangGraph open source concept of [configuration](low_level.md#configuration).
|
||||
While configuration is available in the open source LangGraph library, assistants are only present in [LangGraph Platform](langgraph_platform.md).
|
||||
This is due to the fact that assistants are tightly coupled to your deployed graph. Upon deployment, LangGraph Server will automatically create a default assistant for each graph using the graph's default configuration settings.
|
||||
While configuration is available in the open source LangGraph library, assistants are only present in [LangGraph Platform](langgraph_platform.md). This is due to the fact that assistants are tightly coupled to your deployed graph. Upon deployment, LangGraph Server will automatically create a default assistant for each graph using the graph's default configuration settings.
|
||||
|
||||
In practice, an assistant is just an _instance_ of a graph with a specific configuration. Therefore, multiple assistants can reference the same graph but can contain different configurations (e.g. prompts, models, tools). The LangGraph Server API provides several endpoints for creating and managing assistants. See the [API reference](../cloud/reference/api/api_ref.html) and [this how-to](../cloud/how-tos/configuration_cloud.md) for more details on how to create assistants.
|
||||
|
||||
## Versioning assistants
|
||||
## Versioning
|
||||
|
||||
Assistants support versioning to track changes over time.
|
||||
Once you've created an assistant, subsequent edits to that assistant will create new versions. See [this how-to](../cloud/how-tos/configuration_cloud.md#create-a-new-version-for-your-assistant) for more details on how to manage assistant versions.
|
||||
|
||||
## Learn more
|
||||
## Execution
|
||||
|
||||
* 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.
|
||||
A **run** is an invocation of an assistant. Each run may have its own input, configuration, and metadata, which may affect execution and output of the underlying graph. A run can optionally be executed on a [thread](../../concepts/persistence.md#threads).
|
||||
|
||||
The LangGraph Platform API provides several endpoints for creating and managing runs. See the [API reference](../../cloud/reference/api/api_ref.html#tag/thread-runs/) 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 thread, create runs on threads
|
||||
1. Authenticated users are able to create threads, read threads, and 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.
|
||||
|
||||
|
||||
@@ -5,7 +5,16 @@ search:
|
||||
|
||||
# Deployment Options
|
||||
|
||||
There are 4 main options for deploying with the LangGraph Platform:
|
||||
## Free deployment
|
||||
|
||||
There are two free options for deploying LangGraph applications via the LangGraph Server:
|
||||
|
||||
1. [Local](../tutorials/langgraph-platform/local-server.md): Deploy for local testing and development.
|
||||
1. [Standalone Container (Lite)](../concepts/langgraph_standalone_container.md): A limited version of Standalone Container for deployments unlikely to see more that 1 million node executions per year and that do not need crons and other enterprise features. Standalone Container (Lite) deployment option is free with a LangSmith API key.
|
||||
|
||||
## Production deployment
|
||||
|
||||
There are 4 main options for deploying with the [LangGraph Platform](langgraph_platform.md):
|
||||
|
||||
1. [Cloud SaaS](#cloud-saas)
|
||||
|
||||
@@ -22,7 +31,7 @@ A quick comparison:
|
||||
|----------------------|----------------|----------------------------|-------------------------------|--------------------------|
|
||||
| **[Control plane UI/API](../concepts/langgraph_control_plane.md)** | Yes | Yes | Yes | No |
|
||||
| **CI/CD** | Managed internally by platform | Managed externally by you | Managed externally by you | Managed externally by you |
|
||||
| **Data/compute residency** | LangChain’s cloud | Your cloud | Your cloud | Your cloud |
|
||||
| **Data/compute residency** | LangChain's cloud | Your cloud | Your cloud | Your cloud |
|
||||
| **LangSmith compatibility** | Trace to LangSmith SaaS | Trace to LangSmith SaaS | Trace to Self-Hosted LangSmith | Optional tracing |
|
||||
| **[Server version compatibility](../concepts/langgraph_server.md#server-versions)** | Enterprise | Enterprise | Enterprise | Lite, Enterprise |
|
||||
| **[Pricing](https://www.langchain.com/pricing-langgraph-platform)** | Plus | Enterprise | Enterprise | Developer |
|
||||
@@ -40,8 +49,8 @@ For more information, please see:
|
||||
|
||||
## Self-Hosted Data Plane
|
||||
|
||||
!!! important "Beta"
|
||||
The Self-Hosted Data Plane deployment option is currently in beta stage.
|
||||
!!! info "Important"
|
||||
The Self-Hosted Data Plane deployment option is currently in beta stage and requires an [Enterprise](../concepts/plans.md) plan.
|
||||
|
||||
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 +65,10 @@ For more information, please see:
|
||||
|
||||
## Self-Hosted Control Plane
|
||||
|
||||
!!! important "Beta"
|
||||
The Self-Hosted Control Plane deployment option is currently in beta stage.
|
||||
!!! info "Important"
|
||||
The Self-Hosted Control Plane deployment option is currently in beta stage and requires an [Enterprise](../concepts/plans.md) plan.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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 to LangSmith
|
||||
## Can I use LangGraph Studio without logging in 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 the state associated with the previous `checkpoint` for the given thread. See [short-term-memory](#short-term-memory). |
|
||||
| **previous** | Access 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. |
|
||||
|
||||
@@ -19,6 +19,7 @@ From the control plane UI, you can:
|
||||
- Update a deployment.
|
||||
- Update environment variables for a deployment.
|
||||
- View build and server logs of a deployment.
|
||||
- View deployment metrics like CPU and memory usage.
|
||||
- Delete a deployment.
|
||||
|
||||
The Control Plane UI is embedded in [LangSmith](https://docs.smith.langchain.com/langgraph_cloud).
|
||||
@@ -47,17 +48,22 @@ 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** |
|
||||
|---------------------|---------|------------|---------------------|
|
||||
| Development | 1 CPU | 1 GB | Up to 1 container |
|
||||
| Production | 2 CPU | 2 GB | Up to 10 containers |
|
||||
| **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) |
|
||||
|
||||
CPU and memory resources are per container.
|
||||
|
||||
!!! info "For [Cloud SaaS](../concepts/langgraph_cloud.md)"
|
||||
!!! warning "Immutable Deployment Type"
|
||||
|
||||
Once a deployment is created, the deployment type cannot be changed.
|
||||
|
||||
!!! info "Resource Customization"
|
||||
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.
|
||||
|
||||
!!! info
|
||||
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.
|
||||
|
||||
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
|
||||
@@ -83,6 +89,15 @@ Infrastructure for deployments and revisions are provisioned and deployed asynch
|
||||
|
||||
The control plane and [LangGraph Data Plane](./langgraph_data_plane.md) "listener" application coordinate to achieve asynchronous deployments.
|
||||
|
||||
### Monitoring
|
||||
|
||||
After a deployment is ready, the control plane monitors the deployment and records various metrics, such as:
|
||||
|
||||
- CPU and memory usage of the deployment.
|
||||
- Number of container restarts.
|
||||
|
||||
These metrics are displayed as charts in the Control Plane UI.
|
||||
|
||||
### LangSmith Integration
|
||||
|
||||
A [LangSmith](https://docs.smith.langchain.com/) tracing project is automatically created for each deployment. The tracing project has the same name as the deployment. When creating a deployment, the `LANGCHAIN_TRACING` and `LANGSMITH_API_KEY`/`LANGCHAIN_API_KEY` environment variables do not need to be specified; they are set automatically by the control plane.
|
||||
|
||||
@@ -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 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 components 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 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 it 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 most number of containers.
|
||||
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.
|
||||
|
||||
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 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 to run a LangGraph application locally.
|
||||
|
||||
## Why use LangGraph Platform?
|
||||
|
||||
@@ -17,7 +17,7 @@ Develop, deploy, scale, and manage agents with **LangGraph Platform** — the pu
|
||||
|
||||
LangGraph Platform makes it easy to get your agent running in production — whether it’s built with LangGraph or another framework — so you can focus on your app logic, not infrastructure. Deploy with one click to get a live endpoint, and use our robust APIs and built-in task queues to handle production scale.
|
||||
|
||||
- **[Streaming Support](../cloud/concepts/streaming.md)**: As agents grow more sophisticated, they often benefit from streaming both token outputs and intermediate states back to the user. Without this, users are left waiting for potentially long operations with no feedback. LangGraph Server provides multiple streaming modes optimized for various application needs.
|
||||
- **[Streaming Support](../cloud/how-tos/streaming.md)**: As agents grow more sophisticated, they often benefit from streaming both token outputs and intermediate states back to the user. Without this, users are left waiting for potentially long operations with no feedback. LangGraph Server provides multiple streaming modes optimized for various application needs.
|
||||
|
||||
- **[Background Runs](../cloud/how-tos/background_run.md)**: For agents that take longer to process (e.g., hours), maintaining an open connection can be impractical. The LangGraph Server supports launching agent runs in the background and provides both polling endpoints and webhooks to monitor run status effectively.
|
||||
|
||||
@@ -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,17 +2,19 @@
|
||||
|
||||
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).
|
||||
|
||||
!!! important "Beta"
|
||||
The Self-Hosted Control Plane deployment option is currently in beta stage.
|
||||
!!! info "Important"
|
||||
The Self-Hosted Control Plane deployment option is currently in beta stage and requires an [Enterprise](plans.md) plan.
|
||||
|
||||
## 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 give 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 gives 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) |
|
||||
|-------------------|-------------------|------------|
|
||||
@@ -29,4 +31,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 deploy to Kubernetes, you can use this [Helm chart](https://github.com/langchain-ai/helm/blob/main/charts/langgraph-cloud/README.md).
|
||||
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).
|
||||
@@ -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).
|
||||
|
||||
!!! important "Beta"
|
||||
The Self-Hosted Data Plane deployment option is currently in beta stage.
|
||||
!!! info "Important"
|
||||
The Self-Hosted Data Plane deployment option is currently in beta stage and requires an [Enterprise](plans.md) plan.
|
||||
|
||||
## 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 use this [Helm chart](https://github.com/langchain-ai/helm/blob/main/charts/langgraph-cloud/README.md).
|
||||
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).
|
||||
@@ -7,7 +7,7 @@ search:
|
||||
|
||||
**LangGraph Server** offers an API for creating and managing agent-based applications. It is built on the concept of [assistants](assistants.md), which are agents configured for specific tasks, and includes built-in [persistence](persistence.md#memory-store) and a **task queue**. This versatile API supports a wide range of agentic application use cases, from background processing to real-time interactions.
|
||||
|
||||
Use LangGraph Server to create and manage [assistants](assistants.md), [threads](../cloud/concepts/threads.md), [runs](../cloud/concepts/runs.md), [cron jobs](../cloud/concepts/cron_jobs.md), [webhooks](../cloud/concepts/webhooks.md), and more.
|
||||
Use LangGraph Server to create and manage [assistants](assistants.md), [threads](./persistence.md#threads), [runs](../cloud/concepts/runs.md), [cron jobs](../cloud/concepts/cron_jobs.md), [webhooks](../cloud/concepts/webhooks.md), and more.
|
||||
|
||||
!!! tip "API reference"
|
||||
|
||||
@@ -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,9 +21,10 @@ 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.md)
|
||||
- [Manage assistants](../cloud/how-tos/studio/manage_assistants.md)
|
||||
- [Manage threads](../cloud/how-tos/threads_studio.md)
|
||||
- [Iterate on prompts](../cloud/how-tos/iterate_graph_studio.md)
|
||||
- [Run experiments over a dataset](../cloud/how-tos/studio/run_evals.md)
|
||||
- Manage [long term memory](memory.md)
|
||||
- Debug agent state via [time travel](time-travel.md)
|
||||
|
||||
@@ -33,7 +34,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 an 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 and playground).
|
||||
|
||||
### Chat mode
|
||||
|
||||
@@ -41,4 +42,4 @@ Chat mode is a simpler UI for iterating on and testing chat-specific agents. It
|
||||
|
||||
## Learn more
|
||||
|
||||
- See this guide on how to [get started](../cloud/how-tos/studio/quick_start.md) with LangGraph Studio.
|
||||
- See this guide on how to [get started](../cloud/how-tos/studio/quick_start.md) with LangGraph Studio.
|
||||
|
||||
@@ -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=InputState,output=OutputState)
|
||||
builder = StateGraph(OverallState,input_schema=InputState,output_schema=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 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 the state channels defined at initialization, which includes `OverallState` and the filters `InputState` and `OutputState`.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
### 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 it's 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 its reducer function.
|
||||
|
||||
```python
|
||||
from langchain_core.messages import AnyMessage
|
||||
@@ -197,19 +197,25 @@ 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
|
||||
|
||||
builder = StateGraph(dict)
|
||||
class State(TypedDict):
|
||||
input: str
|
||||
results: str
|
||||
|
||||
builder = StateGraph(State)
|
||||
|
||||
|
||||
def my_node(state: dict, config: RunnableConfig):
|
||||
def my_node(state: State, 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: dict):
|
||||
def my_other_node(state: State):
|
||||
return state
|
||||
|
||||
|
||||
|
||||
@@ -15,15 +15,19 @@ LangGraph has a built-in persistence layer, implemented through checkpointers. W
|
||||
|
||||
## Threads
|
||||
|
||||
A thread is a unique ID or [thread identifier](#threads) assigned to each checkpoint saved by a checkpointer. When invoking graph with a checkpointer, you **must** specify a `thread_id` as part of the `configurable` portion of the config:
|
||||
A thread is a unique ID or thread identifier assigned to each checkpoint saved by a checkpointer. It contains the accumulated state of a sequence of [runs](../cloud/concepts/runs.md). When a run is executed, the [state](../concepts/low_level.md#state) of the underlying graph of the assistant will be persisted to the thread.
|
||||
|
||||
When invoking graph with a checkpointer, you **must** specify a `thread_id` as part of the `configurable` portion of the config:
|
||||
|
||||
```python
|
||||
{"configurable": {"thread_id": "1"}}
|
||||
```
|
||||
|
||||
A thread's current and historical state can be retrieved. To persist state, a thread must be created prior to executing a run. The LangGraph Platform API provides several endpoints for creating and managing threads and thread state. See the [API reference](../cloud/reference/api/api_ref.html#tag/threads) for more details.
|
||||
|
||||
## Checkpoints
|
||||
|
||||
Checkpoint is a snapshot of the graph state saved at each super-step and is represented by `StateSnapshot` object with the following key properties:
|
||||
The state of a thread at a particular point in time is called a checkpoint. Checkpoint is a snapshot of the graph state saved at each super-step and is represented by `StateSnapshot` object with the following key properties:
|
||||
|
||||
- `config`: Config associated with this checkpoint.
|
||||
- `metadata`: Metadata associated with this checkpoint.
|
||||
@@ -31,6 +35,8 @@ Checkpoint is a snapshot of the graph state saved at each super-step and is repr
|
||||
- `next` A tuple of the node names to execute next in the graph.
|
||||
- `tasks`: A tuple of `PregelTask` objects that contain information about next tasks to be executed. If the step was previously attempted, it will include error information. If a graph was interrupted [dynamically](../how-tos/human_in_the_loop/breakpoints.ipynb#dynamic-breakpoints) from within a node, tasks will contain additional data associated with interrupts.
|
||||
|
||||
Checkpoints are persisted and can be used to restore the state of a thread at a later time.
|
||||
|
||||
Let's see what checkpoints are saved when a simple graph is invoked as follows:
|
||||
|
||||
```python
|
||||
@@ -383,7 +389,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 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 memories are returned as a list of objects that can be converted to a dictionary.
|
||||
|
||||
```python
|
||||
memories[-1].dict()
|
||||
@@ -470,9 +476,51 @@ 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, Channel
|
||||
from langgraph.pregel import Pregel, NodeBuilder
|
||||
|
||||
node1 = (
|
||||
Channel.subscribe_to("a")
|
||||
| (lambda x: x + x)
|
||||
| Channel.write_to("b")
|
||||
NodeBuilder().subscribe_only("a")
|
||||
.do(lambda x: x + x)
|
||||
.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, Channel
|
||||
from langgraph.pregel import Pregel, NodeBuilder
|
||||
|
||||
node1 = (
|
||||
Channel.subscribe_to("a")
|
||||
| (lambda x: x + x)
|
||||
| Channel.write_to("b")
|
||||
NodeBuilder().subscribe_only("a")
|
||||
.do(lambda x: x + x)
|
||||
.write_to("b")
|
||||
)
|
||||
|
||||
node2 = (
|
||||
Channel.subscribe_to("b")
|
||||
| (lambda x: x + x)
|
||||
| Channel.write_to("c")
|
||||
NodeBuilder().subscribe_only("b")
|
||||
.do(lambda x: x + x)
|
||||
.write_to("c")
|
||||
)
|
||||
|
||||
|
||||
@@ -115,23 +115,18 @@ 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, Channel
|
||||
from langgraph.pregel import Pregel, NodeBuilder
|
||||
|
||||
node1 = (
|
||||
Channel.subscribe_to("a")
|
||||
| (lambda x: x + x)
|
||||
| {
|
||||
"b": Channel.write_to("b"),
|
||||
"c": Channel.write_to("c")
|
||||
}
|
||||
NodeBuilder().subscribe_only("a")
|
||||
.do(lambda x: x + x)
|
||||
.write_to("b", "c")
|
||||
)
|
||||
|
||||
node2 = (
|
||||
Channel.subscribe_to("b")
|
||||
| (lambda x: x + x)
|
||||
| {
|
||||
"c": Channel.write_to("c"),
|
||||
}
|
||||
NodeBuilder().subscribe_to("b")
|
||||
.do(lambda x: x["b"] + x["b"])
|
||||
.write_to("c")
|
||||
)
|
||||
|
||||
app = Pregel(
|
||||
@@ -158,24 +153,19 @@ 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, Channel
|
||||
from langgraph.pregel import Pregel, NodeBuilder
|
||||
|
||||
|
||||
node1 = (
|
||||
Channel.subscribe_to("a")
|
||||
| (lambda x: x + x)
|
||||
| {
|
||||
"b": Channel.write_to("b"),
|
||||
"c": Channel.write_to("c")
|
||||
}
|
||||
NodeBuilder().subscribe_only("a")
|
||||
.do(lambda x: x + x)
|
||||
.write_to("b", "c")
|
||||
)
|
||||
|
||||
node2 = (
|
||||
Channel.subscribe_to("b")
|
||||
| (lambda x: x + x)
|
||||
| {
|
||||
"c": Channel.write_to("c"),
|
||||
}
|
||||
NodeBuilder().subscribe_only("b")
|
||||
.do(lambda x: x + x)
|
||||
.write_to("c")
|
||||
)
|
||||
|
||||
def reducer(current, update):
|
||||
@@ -197,8 +187,7 @@ 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
|
||||
@@ -207,12 +196,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, Channel, ChannelWrite, ChannelWriteEntry
|
||||
from langgraph.pregel import Pregel, NodeBuilder, ChannelWriteEntry
|
||||
|
||||
example_node = (
|
||||
Channel.subscribe_to("value")
|
||||
| (lambda x: x + x if len(x) < 10 else None)
|
||||
| ChannelWrite(writes=[ChannelWriteEntry(channel="value", skip_none=True)])
|
||||
NodeBuilder().subscribe_only("value")
|
||||
.do(lambda x: x + x if len(x) < 10 else None)
|
||||
.write_to(ChannelWriteEntry("value", skip_none=True))
|
||||
)
|
||||
|
||||
app = Pregel(
|
||||
@@ -235,7 +224,6 @@ 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.
|
||||
@@ -266,7 +254,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()
|
||||
```
|
||||
@@ -279,7 +267,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>}
|
||||
@@ -310,7 +298,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
|
||||
@@ -339,8 +327,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 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.
|
||||
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.
|
||||
|
||||
## 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=InputState, output=OutputState)
|
||||
builder = StateGraph(OverallState, input_schema=InputState, output_schema=OutputState)
|
||||
builder.add_node(answer_node)
|
||||
builder.add_edge(START, "answer_node")
|
||||
builder.add_edge("answer_node", END)
|
||||
|
||||
@@ -18,6 +18,6 @@ There are three main categories of data you can stream:
|
||||
|
||||
- [**Stream LLM tokens**](../how-tos/streaming.md#messages) — capture token streams from anywhere: inside nodes, subgraphs, or tools.
|
||||
- [**Emit progress notifications from tools**](../how-tos/streaming.md#stream-custom-data) — send custom updates or progress signals directly from tool functions.
|
||||
- [**Stream from subgraphs**](../how-tos/streaming.md#subgraphs) — include outputs from both the parent graph and any nested subgraphs.
|
||||
- [**Stream from subgraphs**](../how-tos/streaming.md#stream-subgraph-outputs) — include outputs from both the parent graph and any nested subgraphs.
|
||||
- [**Use any LLM**](../how-tos/streaming.md#use-with-any-llm) — stream tokens from any LLM, even if it's not a LangChain model using the `custom` streaming mode.
|
||||
- [**Use multiple streaming modes**](../how-tos/streaming.md#stream-multiple-modes) — choose from `values` (full state), `updates` (state deltas), `messages` (LLM tokens + metadata), `custom` (arbitrary user data), or `debug` (detailed traces).
|
||||
@@ -59,8 +59,9 @@ 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(State)
|
||||
subgraph_builder.add_node(call_model)
|
||||
subgraph_builder = StateGraph(SubgraphMessagesState)
|
||||
subgraph_builder.add_node("call_model_from_subgraph", call_model)
|
||||
subgraph_builder.add_edge(START, "call_model_from_subgraph")
|
||||
...
|
||||
# highlight-next-line
|
||||
subgraph = subgraph_builder.compile()
|
||||
|
||||
+40
-38
@@ -1,62 +1,64 @@
|
||||
# Tools
|
||||
|
||||
Many AI applications interact directly with humans. In these cases, it is appropriate for models to respond in natural language.
|
||||
But what about cases where we want a model to also interact *directly* with systems, such as databases or an API?
|
||||
These systems often have a particular input schema; for example, APIs frequently have a required payload structure. You can use [tool calling](https://platform.openai.com/docs/guides/function-calling/example-use-cases) to request model responses that match a particular schema.
|
||||
Many AI applications interact with users via natural language. However, some use cases require models to interface directly with external systems—such as APIs, databases, or file systems—using structured input. In these scenarios, **tool calling** enables models to generate requests that conform to a specified input schema.
|
||||
|
||||
[Tools](https://python.langchain.com/docs/concepts/tools/) are a way to encapsulate a function and its input schema in a way that can be passed to a chat model that supports tool calling. This allows the model to request the execution of this function with specific inputs.
|
||||
|
||||
**Tools** can be passed to [chat models](https://python.langchain.com/docs/concepts/chat_models) that support [tool calling](https://python.langchain.com/docs/concepts/tool_calling) allowing the model to request the execution of a specific function with specific inputs.
|
||||
|
||||
You can [create custom tools](https://python.langchain.com/docs/how_to/custom_tools/) or use [prebuilt](#prebuilt-tools) tools.
|
||||
[Tools](https://python.langchain.com/docs/concepts/tools/) encapsulate a callable function and its input schema. These can be passed to compatible [chat models](https://python.langchain.com/docs/concepts/chat_models), allowing the model to decide whether to invoke a tool and with what arguments.
|
||||
|
||||
## Tool calling
|
||||
|
||||

|
||||
|
||||
A key principle of tool calling is that the model decides when to use a tool based on the input's relevance. The model doesn't always need to call a tool.
|
||||
For example, given an input that is *irrelevant to the tool*, the model would not call the tool:
|
||||
Tool calling is typically **conditional**. Based on the user input and available tools, the model may choose to issue a tool call request. This request is returned in an `AIMessage` object, which includes a `tool_calls` field that specifies the tool name and input arguments:
|
||||
|
||||
```python
|
||||
result = llm_with_tools.invoke("Hello world!")
|
||||
llm_with_tools.invoke("What is 2 multiplied by 3?")
|
||||
# -> AIMessage(tool_calls=[{'name': 'multiply', 'args': {'a': 2, 'b': 3}, ...}])
|
||||
```
|
||||
|
||||
The result would be an `AIMessage` containing the model's response in natural language (e.g., "Hello!").
|
||||
However, if we pass an input *relevant to the tool*, the model should choose to call it:
|
||||
If the input is unrelated to any tool, the model returns only a natural language message:
|
||||
|
||||
```python
|
||||
result = llm_with_tools.invoke("What is 2 multiplied by 3?")
|
||||
llm_with_tools.invoke("Hello world!") # -> AIMessage(content="Hello!")
|
||||
```
|
||||
|
||||
As before, the output `result` will be an `AIMessage`.
|
||||
But, if the tool was called, `result` will have a `tool_calls` attribute.
|
||||
This attribute includes everything needed to execute the tool, including the tool name and input arguments:
|
||||
Importantly, the model does not execute the tool—it only generates a request. A separate executor (such as a runtime or agent) is responsible for handling the tool call and returning the result.
|
||||
|
||||
```
|
||||
result.tool_calls
|
||||
{'name': 'multiply', 'args': {'a': 2, 'b': 3}, 'id': 'xxx', 'type': 'tool_call'}
|
||||
```
|
||||
|
||||
For more details on usage, see the [how-to guide](../how-tos/tool-calling.ipynb).
|
||||
|
||||
## Execute tools
|
||||
|
||||
LangGraph offers pre-built components — [`ToolNode`][langgraph.prebuilt.tool_node.ToolNode] and [`create_react_agent`][langgraph.prebuilt.chat_agent_executor.create_react_agent] — that invoke the tools on behalf of the user.
|
||||
|
||||
See this [how-to guide](../how-tos/tool-calling.ipynb#use-prebuilt-toolnode) on tool calling.
|
||||
See the [tool calling guide](../how-tos/tool-calling.md) for more details.
|
||||
|
||||
## Prebuilt tools
|
||||
|
||||
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 provides prebuilt tool integrations for common external systems including APIs, databases, file systems, and web data.
|
||||
|
||||
You can browse the full list of available integrations in the [LangChain integrations directory](https://python.langchain.com/docs/integrations/tools/).
|
||||
Browse the [integrations directory](https://python.langchain.com/docs/integrations/tools/) for available tools.
|
||||
|
||||
Some commonly used tool categories include:
|
||||
Common categories:
|
||||
|
||||
- **Search**: Bing, SerpAPI, Tavily
|
||||
- **Code interpreters**: Python REPL, Node.js REPL
|
||||
- **Databases**: SQL, MongoDB, Redis
|
||||
- **Web data**: Web scraping and browsing
|
||||
- **APIs**: OpenWeatherMap, NewsAPI, and others
|
||||
* **Search**: Bing, SerpAPI, Tavily
|
||||
* **Code execution**: Python REPL, Node.js REPL
|
||||
* **Databases**: SQL, MongoDB, Redis
|
||||
* **Web data**: Scraping and browsing
|
||||
* **APIs**: OpenWeatherMap, NewsAPI, etc.
|
||||
|
||||
These integrations can be configured and added to your agents using the same `tools` parameter shown in the examples above.
|
||||
## Custom tools
|
||||
|
||||
You can define custom tools using the `@tool` decorator or plain Python functions. For example:
|
||||
|
||||
```python
|
||||
from langchain_core.tools import tool
|
||||
|
||||
@tool
|
||||
def multiply(a: int, b: int) -> int:
|
||||
"""Multiply two numbers."""
|
||||
return a * b
|
||||
```
|
||||
|
||||
See the [tool calling guide](../how-tos/tool-calling.md) for more details.
|
||||
|
||||
## Tool execution
|
||||
|
||||
While the model determines *when* to call a tool, **execution** of the tool call must be handled by a runtime component.
|
||||
|
||||
LangGraph provides prebuilt components for this:
|
||||
|
||||
* [`ToolNode`][oolNode]: Executes tools based on AI tool calls.
|
||||
* [`create_react_agent`][create_react_agent]: Constructs a full agent that manages tool calling automatically.
|
||||
|
||||
@@ -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 the required authorization information based on your chosen scheme.
|
||||
Once you've set up authentication in your server, requests must include 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": 6,
|
||||
"execution_count": null,
|
||||
"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=InputState, output=OutputState)\n",
|
||||
"builder = StateGraph(OverallState, input_schema=InputState, output_schema=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` 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",
|
||||
"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",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"from langgraph.pregel import RetryPolicy\n",
|
||||
@@ -1206,7 +1206,7 @@
|
||||
"builder.add_node(\n",
|
||||
" \"node_name\",\n",
|
||||
" node_function,\n",
|
||||
" retry=RetryPolicy(),\n",
|
||||
" retry_policy=RetryPolicy(),\n",
|
||||
")\n",
|
||||
"```"
|
||||
]
|
||||
@@ -1241,7 +1241,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"execution_count": null,
|
||||
"id": "ad92598c-b688-42fa-aae0-9de36273d584",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
@@ -1276,9 +1276,9 @@
|
||||
"builder.add_node(\n",
|
||||
" \"query_database\",\n",
|
||||
" query_database,\n",
|
||||
" retry=RetryPolicy(retry_on=sqlite3.OperationalError),\n",
|
||||
" retry_policy=RetryPolicy(retry_on=sqlite3.OperationalError),\n",
|
||||
")\n",
|
||||
"builder.add_node(\"model\", call_model, retry=RetryPolicy(max_attempts=5))\n",
|
||||
"builder.add_node(\"model\", call_model, retry_policy=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 \"a\"\n",
|
||||
" return \"b\"\n",
|
||||
"\n",
|
||||
"builder.add_edge(START, \"a\")\n",
|
||||
"builder.add_conditional_edges(\"a\", route)\n",
|
||||
@@ -2950,16 +2950,6 @@
|
||||
" 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,
|
||||
@@ -3426,7 +3416,7 @@
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"display_name": ".venv",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
@@ -3440,7 +3430,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.4"
|
||||
"version": "3.9.6"
|
||||
}
|
||||
},
|
||||
"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.graph.CompiledGraph.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.state.CompiledStateGraph.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.graph.CompiledGraph.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.state.CompiledStateGraph.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": 46,
|
||||
"execution_count": null,
|
||||
"id": "1954a5f1-91e4-4b32-9be9-c8bc1cc43cb5",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
@@ -465,7 +465,9 @@
|
||||
"\n",
|
||||
"graph_builder = StateGraph(State)\n",
|
||||
"graph_builder.add_node(\"agent\", agent)\n",
|
||||
"graph_builder.add_node(\"select_tools\", select_tools, retry=RetryPolicy(max_attempts=3))\n",
|
||||
"graph_builder.add_node(\n",
|
||||
" \"select_tools\", select_tools, retry_policy=RetryPolicy(max_attempts=3)\n",
|
||||
")\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 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 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,7 +739,6 @@
|
||||
" '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",
|
||||
@@ -856,7 +855,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.')]}, 'pending_sends': []\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",
|
||||
" },\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",
|
||||
@@ -870,8 +869,7 @@
|
||||
" '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",
|
||||
" 'pending_sends': []\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",
|
||||
" }, \n",
|
||||
" metadata={'source': 'loop', 'writes': None, 'step': 3, 'parents': {}, 'thread_id': '1'}, \n",
|
||||
" parent_config={...}, \n",
|
||||
@@ -885,8 +883,7 @@
|
||||
" '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",
|
||||
" 'pending_sends': []\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",
|
||||
" }, \n",
|
||||
" metadata={'source': 'input', 'writes': {'__start__': {'messages': [{'role': 'user', 'content': \"what's my name?\"}]}}, 'step': 2, 'parents': {}, 'thread_id': '1'}, \n",
|
||||
" parent_config={...}, \n",
|
||||
@@ -900,8 +897,7 @@
|
||||
" '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",
|
||||
" 'pending_sends': []\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",
|
||||
" }, \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",
|
||||
@@ -915,8 +911,7 @@
|
||||
" '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",
|
||||
" 'pending_sends': []\n",
|
||||
" 'channel_values': {'messages': [HumanMessage(content=\"hi! I'm bob\")], 'branch:to:call_model': None}\n",
|
||||
" }, \n",
|
||||
" metadata={'source': 'loop', 'writes': None, 'step': 0, 'parents': {}, 'thread_id': '1'}, \n",
|
||||
" parent_config={...}, \n",
|
||||
@@ -930,8 +925,7 @@
|
||||
" '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",
|
||||
" 'pending_sends': []\n",
|
||||
" 'channel_values': {'__start__': {'messages': [{'role': 'user', 'content': \"hi! I'm bob\"}]}}\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",
|
||||
@@ -1113,10 +1107,10 @@
|
||||
"source": [
|
||||
"### Use in production\n",
|
||||
"\n",
|
||||
"In production, you would want to use a checkpointer backed by a database:\n",
|
||||
"In production, you would want to use a store backed by a database:\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"from langgraph.checkpoint.postgres import PostgresSaver\n",
|
||||
"from langgraph.store.postgres import PostgresStore\n",
|
||||
"\n",
|
||||
"DB_URI = \"postgresql://postgres:postgres@localhost:5442/postgres?sslmode=disable\"\n",
|
||||
"# highlight-next-line\n",
|
||||
|
||||
+223
-25
@@ -1,11 +1,220 @@
|
||||
# Stream outputs
|
||||
|
||||
## Streaming API
|
||||
You can [stream outputs](../concepts/streaming.md) from a LangGraph agent or workflow.
|
||||
|
||||
## Supported stream modes
|
||||
|
||||
Pass one or more of the following stream modes as a list to the [`stream()`][langgraph.graph.state.CompiledStateGraph.stream] or [`astream()`][langgraph.graph.state.CompiledStateGraph.astream] methods:
|
||||
|
||||
| Mode | Description |
|
||||
|------|-------------|
|
||||
| `values` | Streams the full value of the state after each step of the graph. |
|
||||
| `updates` | Streams the updates to the state after each step of the graph. If multiple updates are made in the same step (e.g., multiple nodes are run), those updates are streamed separately. |
|
||||
| `custom` | Streams custom data from inside your graph nodes. |
|
||||
| `messages` | Streams 2-tuples (LLM token, metadata) from any graph nodes where an LLM is invoked. |
|
||||
| `debug` | Streams as much information as possible throughout the execution of the graph.
|
||||
|
||||
## Stream from an agent
|
||||
|
||||
### Agent progress
|
||||
|
||||
To stream agent progress, use the [`stream()`][langgraph.graph.state.CompiledStateGraph.stream] or [`astream()`][langgraph.graph.state.CompiledStateGraph.astream] methods with `stream_mode="updates"`. This emits an event after every agent step.
|
||||
|
||||
For example, if you have an agent that calls a tool once, you should see the following updates:
|
||||
|
||||
* **LLM node**: AI message with tool call requests
|
||||
* **Tool node**: Tool message with execution result
|
||||
* **LLM node**: Final AI response
|
||||
|
||||
=== "Sync"
|
||||
|
||||
```python
|
||||
agent = create_react_agent(
|
||||
model="anthropic:claude-3-7-sonnet-latest",
|
||||
tools=[get_weather],
|
||||
)
|
||||
# highlight-next-line
|
||||
for chunk in agent.stream(
|
||||
{"messages": [{"role": "user", "content": "what is the weather in sf"}]},
|
||||
# highlight-next-line
|
||||
stream_mode="updates"
|
||||
):
|
||||
print(chunk)
|
||||
print("\n")
|
||||
```
|
||||
|
||||
=== "Async"
|
||||
|
||||
```python
|
||||
agent = create_react_agent(
|
||||
model="anthropic:claude-3-7-sonnet-latest",
|
||||
tools=[get_weather],
|
||||
)
|
||||
# highlight-next-line
|
||||
async for chunk in agent.astream(
|
||||
{"messages": [{"role": "user", "content": "what is the weather in sf"}]},
|
||||
# highlight-next-line
|
||||
stream_mode="updates"
|
||||
):
|
||||
print(chunk)
|
||||
print("\n")
|
||||
```
|
||||
|
||||
### LLM tokens
|
||||
|
||||
To stream tokens as they are produced by the LLM, use `stream_mode="messages"`:
|
||||
|
||||
=== "Sync"
|
||||
|
||||
```python
|
||||
agent = create_react_agent(
|
||||
model="anthropic:claude-3-7-sonnet-latest",
|
||||
tools=[get_weather],
|
||||
)
|
||||
# highlight-next-line
|
||||
for token, metadata in agent.stream(
|
||||
{"messages": [{"role": "user", "content": "what is the weather in sf"}]},
|
||||
# highlight-next-line
|
||||
stream_mode="messages"
|
||||
):
|
||||
print("Token", token)
|
||||
print("Metadata", metadata)
|
||||
print("\n")
|
||||
```
|
||||
|
||||
=== "Async"
|
||||
|
||||
```python
|
||||
agent = create_react_agent(
|
||||
model="anthropic:claude-3-7-sonnet-latest",
|
||||
tools=[get_weather],
|
||||
)
|
||||
# highlight-next-line
|
||||
async for token, metadata in agent.astream(
|
||||
{"messages": [{"role": "user", "content": "what is the weather in sf"}]},
|
||||
# highlight-next-line
|
||||
stream_mode="messages"
|
||||
):
|
||||
print("Token", token)
|
||||
print("Metadata", metadata)
|
||||
print("\n")
|
||||
```
|
||||
|
||||
### Tool updates
|
||||
|
||||
To stream updates from tools as they are executed, you can use [get_stream_writer][langgraph.config.get_stream_writer].
|
||||
|
||||
=== "Sync"
|
||||
|
||||
```python
|
||||
# highlight-next-line
|
||||
from langgraph.config import get_stream_writer
|
||||
|
||||
def get_weather(city: str) -> str:
|
||||
"""Get weather for a given city."""
|
||||
# highlight-next-line
|
||||
writer = get_stream_writer()
|
||||
# stream any arbitrary data
|
||||
# highlight-next-line
|
||||
writer(f"Looking up data for city: {city}")
|
||||
return f"It's always sunny in {city}!"
|
||||
|
||||
agent = create_react_agent(
|
||||
model="anthropic:claude-3-7-sonnet-latest",
|
||||
tools=[get_weather],
|
||||
)
|
||||
|
||||
for chunk in agent.stream(
|
||||
{"messages": [{"role": "user", "content": "what is the weather in sf"}]},
|
||||
# highlight-next-line
|
||||
stream_mode="custom"
|
||||
):
|
||||
print(chunk)
|
||||
print("\n")
|
||||
```
|
||||
|
||||
=== "Async"
|
||||
|
||||
```python
|
||||
# highlight-next-line
|
||||
from langgraph.config import get_stream_writer
|
||||
|
||||
def get_weather(city: str) -> str:
|
||||
"""Get weather for a given city."""
|
||||
# highlight-next-line
|
||||
writer = get_stream_writer()
|
||||
# stream any arbitrary data
|
||||
# highlight-next-line
|
||||
writer(f"Looking up data for city: {city}")
|
||||
return f"It's always sunny in {city}!"
|
||||
|
||||
agent = create_react_agent(
|
||||
model="anthropic:claude-3-7-sonnet-latest",
|
||||
tools=[get_weather],
|
||||
)
|
||||
|
||||
async for chunk in agent.astream(
|
||||
{"messages": [{"role": "user", "content": "what is the weather in sf"}]},
|
||||
# highlight-next-line
|
||||
stream_mode="custom"
|
||||
):
|
||||
print(chunk)
|
||||
print("\n")
|
||||
```
|
||||
|
||||
!!! Note
|
||||
If you add `get_stream_writer` inside your tool, you won't be able to invoke the tool outside of a LangGraph execution context.
|
||||
|
||||
### Stream multiple modes
|
||||
|
||||
You can specify multiple streaming modes by passing stream mode as a list: `stream_mode=["updates", "messages", "custom"]`:
|
||||
|
||||
=== "Sync"
|
||||
|
||||
```python
|
||||
agent = create_react_agent(
|
||||
model="anthropic:claude-3-7-sonnet-latest",
|
||||
tools=[get_weather],
|
||||
)
|
||||
|
||||
for stream_mode, chunk in agent.stream(
|
||||
{"messages": [{"role": "user", "content": "what is the weather in sf"}]},
|
||||
# highlight-next-line
|
||||
stream_mode=["updates", "messages", "custom"]
|
||||
):
|
||||
print(chunk)
|
||||
print("\n")
|
||||
```
|
||||
|
||||
=== "Async"
|
||||
|
||||
```python
|
||||
agent = create_react_agent(
|
||||
model="anthropic:claude-3-7-sonnet-latest",
|
||||
tools=[get_weather],
|
||||
)
|
||||
|
||||
async for stream_mode, chunk in agent.astream(
|
||||
{"messages": [{"role": "user", "content": "what is the weather in sf"}]},
|
||||
# highlight-next-line
|
||||
stream_mode=["updates", "messages", "custom"]
|
||||
):
|
||||
print(chunk)
|
||||
print("\n")
|
||||
```
|
||||
|
||||
### Disable streaming
|
||||
|
||||
In some applications you might need to disable streaming of individual tokens for a given model. This is useful in [multi-agent](../agents/multi-agent.md) systems to control which agents stream their output.
|
||||
|
||||
See the [Models](../agents/models.md#disable-streaming) guide to learn how to disable streaming.
|
||||
|
||||
## Stream from a workflow
|
||||
|
||||
### Basic usage example
|
||||
|
||||
LangGraph graphs expose the [`.stream()`][langgraph.pregel.Pregel.stream] (sync) and [`.astream()`][langgraph.pregel.Pregel.astream] (async) methods to yield streamed outputs as iterators.
|
||||
|
||||
Basic usage example:
|
||||
|
||||
=== "Sync"
|
||||
|
||||
```python
|
||||
@@ -61,18 +270,7 @@ Basic usage example:
|
||||
```output
|
||||
{'refine_topic': {'topic': 'ice cream and cats'}}
|
||||
{'generate_joke': {'joke': 'This is a joke about ice cream and cats'}}
|
||||
```
|
||||
|
||||
|
||||
### Supported stream modes
|
||||
|
||||
| Mode | Description |
|
||||
|----------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| [`values`](#stream-graph-state) | Streams the full value of the state after each step of the graph. |
|
||||
| [`updates`](#stream-graph-state) | Streams the updates to the state after each step of the graph. If multiple updates are made in the same step (e.g., multiple nodes are run), those updates are streamed separately. |
|
||||
| [`custom`](#stream-custom-data) | Streams custom data from inside your graph nodes. |
|
||||
| [`messages`](#messages) | Streams 2-tuples (LLM token, metadata) from any graph nodes where an LLM is invoked. |
|
||||
| [`debug`](#debug) | Streams as much information as possible throughout the execution of the graph. |
|
||||
``` |
|
||||
|
||||
### Stream multiple modes
|
||||
|
||||
@@ -94,7 +292,7 @@ The streamed outputs will be tuples of `(mode, chunk)` where `mode` is the name
|
||||
print(chunk)
|
||||
```
|
||||
|
||||
## Stream graph state
|
||||
### Stream graph state
|
||||
|
||||
Use the stream modes `updates` and `values` to stream the state of the graph as it executes.
|
||||
|
||||
@@ -157,7 +355,7 @@ graph = (
|
||||
```
|
||||
|
||||
|
||||
## Subgraphs
|
||||
### Stream subgraph outputs
|
||||
|
||||
To include outputs from [subgraphs](../concepts/subgraphs.md) in the streamed outputs, you can set `subgraphs=True` in the `.stream()` method of the parent graph. This will stream outputs from both the parent graph and any subgraphs.
|
||||
|
||||
@@ -233,7 +431,7 @@ for chunk in graph.stream(
|
||||
|
||||
**Note** that we are receiving not just the node updates, but we also the namespaces which tell us what graph (or subgraph) we are streaming from.
|
||||
|
||||
## Debugging {#debug}
|
||||
### Debugging {#debug}
|
||||
|
||||
Use the `debug` streaming mode to stream as much information as possible throughout the execution of the graph. The streamed outputs include the name of the node as well as the full state.
|
||||
|
||||
@@ -247,7 +445,7 @@ for chunk in graph.stream(
|
||||
```
|
||||
|
||||
|
||||
## LLM tokens {#messages}
|
||||
### LLM tokens {#messages}
|
||||
|
||||
Use the `messages` streaming mode to stream Large Language Model (LLM) outputs **token by token** from any part of your graph, including nodes, tools, subgraphs, or tasks.
|
||||
|
||||
@@ -307,7 +505,7 @@ for message_chunk, metadata in graph.stream( # (2)!
|
||||
2. The "messages" stream mode returns an iterator of tuples `(message_chunk, metadata)` where `message_chunk` is the token streamed by the LLM and `metadata` is a dictionary with information about the graph node where the LLM was called and other information.
|
||||
|
||||
|
||||
### Filter by LLM invocation
|
||||
#### Filter by LLM invocation
|
||||
|
||||
You can associate `tags` with LLM invocations to filter the streamed tokens by LLM invocation.
|
||||
|
||||
@@ -391,7 +589,7 @@ async for msg, metadata in graph.astream( # (3)!
|
||||
4. The `stream_mode` is set to "messages" to stream LLM tokens. The `metadata` contains information about the LLM invocation, including the tags.
|
||||
|
||||
|
||||
### Filter by node
|
||||
#### Filter by node
|
||||
|
||||
To stream tokens only from specific nodes, use `stream_mode="messages"` and filter the outputs by the `langgraph_node` field in the streamed metadata:
|
||||
|
||||
@@ -464,7 +662,7 @@ for msg, metadata in graph.stream( # (1)!
|
||||
1. The "messages" stream mode returns a tuple of `(message_chunk, metadata)` where `message_chunk` is the token streamed by the LLM and `metadata` is a dictionary with information about the graph node where the LLM was called and other information.
|
||||
2. Filter the streamed tokens by the `langgraph_node` field in the metadata to only include the tokens from the `write_poem` node.
|
||||
|
||||
## Stream custom data
|
||||
### Stream custom data
|
||||
|
||||
To send **custom user-defined data** from inside a LangGraph node or tool, follow these steps:
|
||||
|
||||
@@ -541,7 +739,7 @@ To send **custom user-defined data** from inside a LangGraph node or tool, follo
|
||||
3. Emit another custom key-value pair.
|
||||
4. Set `stream_mode="custom"` to receive the custom data in the stream.
|
||||
|
||||
## Use with any LLM
|
||||
### Use with any LLM
|
||||
|
||||
You can use `stream_mode="custom"` to stream data from **any LLM API** — even if that API does **not** implement the LangChain chat model interface.
|
||||
|
||||
@@ -701,7 +899,7 @@ for chunk in graph.stream(
|
||||
```
|
||||
|
||||
|
||||
## Disable streaming for specific chat models
|
||||
### Disable streaming for specific chat models
|
||||
|
||||
If your application mixes models that support streaming with those that do not, you may need to explicitly disable streaming for
|
||||
models that do not support it.
|
||||
@@ -733,7 +931,7 @@ Set `disable_streaming=True` when initializing the model.
|
||||
1. Set `disable_streaming=True` to disable streaming for the chat model.
|
||||
|
||||
|
||||
## Async with Python < 3.11 { #async }
|
||||
### Async with Python < 3.11 { #async }
|
||||
|
||||
In Python versions < 3.11, [asyncio tasks](https://docs.python.org/3/library/asyncio-task.html#asyncio.create_task) do not support the `context` parameter.
|
||||
This limits LangGraph ability to automatically propagate context, and affects LangGraph’s streaming mechanisms in two key ways:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -321,7 +321,7 @@ attempts = 0
|
||||
# The default RetryPolicy is optimized for retrying specific network errors.
|
||||
retry_policy = RetryPolicy(retry_on=ValueError)
|
||||
|
||||
@task(retry=retry_policy)
|
||||
@task(retry_policy=retry_policy)
|
||||
def get_info():
|
||||
global attempts
|
||||
attempts += 1
|
||||
|
||||
@@ -12,12 +12,18 @@
|
||||
options:
|
||||
members:
|
||||
- SerializerProtocol
|
||||
- CipherProtocol
|
||||
|
||||
::: langgraph.checkpoint.serde.jsonplus
|
||||
options:
|
||||
members:
|
||||
- JsonPlusSerializer
|
||||
|
||||
::: langgraph.checkpoint.serde.encrypted
|
||||
options:
|
||||
members:
|
||||
- EncryptedSerializer
|
||||
|
||||
::: langgraph.checkpoint.memory
|
||||
|
||||
::: langgraph.checkpoint.sqlite
|
||||
@@ -32,4 +38,4 @@
|
||||
::: langgraph.checkpoint.postgres.aio
|
||||
options:
|
||||
members:
|
||||
- AsyncPostgresSaver
|
||||
- AsyncPostgresSaver
|
||||
|
||||
@@ -36,41 +36,6 @@
|
||||
- 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 opens source library.
|
||||
The core APIs for the LangGraph open source library.
|
||||
|
||||
- [Graphs](graphs.md): Main graph abstraction and usage.
|
||||
- [Functional API](func.md): Functional programming interface for graphs.
|
||||
|
||||
@@ -1,5 +1,21 @@
|
||||
# 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
-3
@@ -580,9 +580,7 @@
|
||||
" ]\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"evaluator = prompt | ChatOpenAI(model=\"gpt-4-turbo-preview\").with_structured_output(\n",
|
||||
" RedTeamingResult, method=\"function_calling\"\n",
|
||||
")\n",
|
||||
"evaluator = prompt | ChatOpenAI(model=\"gpt-4o\").with_structured_output(RedTeamingResult)\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 a excursion by its recommendation ID.\n",
|
||||
" Book an excursion by its recommendation ID.\n",
|
||||
"\n",
|
||||
" Args:\n",
|
||||
" recommendation_id (int): The ID of the trip recommendation to book.\n",
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
---
|
||||
search:
|
||||
boost: 2
|
||||
---
|
||||
|
||||
# Deployment 🚀
|
||||
|
||||
There are two free options for deploying LangGraph applications via the LangGraph Server:
|
||||
|
||||
- [Local](./langgraph-platform/local-server.md): Deploy for local testing and development.
|
||||
- [Standalone Container (Lite)](../concepts/langgraph_standalone_container.md): A limited version of Standalone Container for deployments unlikely to see more that 1 million node executions per year and that do not need crons and other enterprise features. Standalone Container (Lite) deployment option is free with a LangSmith API key.
|
||||
|
||||
## Other deployment options
|
||||
|
||||
Additionally, you can deploy to production with [LangGraph Platform](../concepts/langgraph_platform.md):
|
||||
|
||||
- [Cloud SaaS](../concepts/langgraph_cloud.md): Connect your GitHub repositories and deploy LangGraph Servers within LangChain's cloud. *We manage everything.*
|
||||
- [Self-Hosted Data Plane<sup>(Beta)</sup>](../concepts/langgraph_self_hosted_data_plane.md): Create deployments from the [Control Plane UI](../concepts/langgraph_control_plane.md#control-plane-ui) and deploy LangGraph Servers to **your** cloud. *We manage the [control plane](../concepts/langgraph_control_plane.md). You manage the deployments.*
|
||||
- [Self-Hosted Control Plane<sup>(Beta)</sup>](../concepts/langgraph_self_hosted_control_plane.md): Create deployments from a self-hosted [Control Plane UI](../concepts/langgraph_control_plane.md#control-plane-ui) and deploy LangGraph Servers to **your** cloud. *You manage everything.*
|
||||
- [Standalone Container](../concepts/langgraph_standalone_container.md): Deploy LangGraph Server Docker images however you like.
|
||||
|
||||
For more information, see [Deployment options](../concepts/deployment_options.md).
|
||||
@@ -6,7 +6,7 @@ In this tutorial, you will build a basic chatbot. This chatbot is the basis for
|
||||
|
||||
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/admin-keys), or
|
||||
[Anthropic](https://console.anthropic.com/settings/keys), or
|
||||
[Google Gemini](https://ai.google.dev/gemini-api/docs/api-key).
|
||||
|
||||
## 1. Install packages
|
||||
@@ -32,7 +32,7 @@ from typing import Annotated
|
||||
|
||||
from typing_extensions import TypedDict
|
||||
|
||||
from langgraph.graph import StateGraph, START
|
||||
from langgraph.graph import StateGraph, START, END
|
||||
from langgraph.graph.message import add_messages
|
||||
|
||||
|
||||
@@ -100,7 +100,16 @@ Add an `entry` point to tell the graph **where to start its work** each time it
|
||||
graph_builder.add_edge(START, "chatbot")
|
||||
```
|
||||
|
||||
## 5. Compile the graph
|
||||
## 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
|
||||
graph_builder.add_edge("chatbot", END)
|
||||
```
|
||||
This tells the graph to terminate after running the chatbot node.
|
||||
|
||||
## 6. 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.
|
||||
@@ -109,7 +118,7 @@ on the graph builder. This creates a `CompiledGraph` we can invoke on our state.
|
||||
graph = graph_builder.compile()
|
||||
```
|
||||
|
||||
## 6. Visualize the graph (optional)
|
||||
## 7. 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.
|
||||
|
||||
@@ -126,7 +135,7 @@ except Exception:
|
||||

|
||||
|
||||
|
||||
## 7. Run the chatbot
|
||||
## 8. Run the chatbot
|
||||
|
||||
Now run the chatbot!
|
||||
|
||||
@@ -171,7 +180,7 @@ from typing import Annotated
|
||||
from langchain.chat_models import init_chat_model
|
||||
from typing_extensions import TypedDict
|
||||
|
||||
from langgraph.graph import StateGraph, START
|
||||
from langgraph.graph import StateGraph, START, END
|
||||
from langgraph.graph.message import add_messages
|
||||
|
||||
|
||||
@@ -194,6 +203,7 @@ 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()
|
||||
```
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Add tools
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
!!! note
|
||||
|
||||
@@ -146,7 +146,7 @@ graph_builder.add_node("tools", tool_node)
|
||||
|
||||
!!! 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/prebuilt/#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/agents/#langgraph.prebuilt.tool_node.ToolNode).
|
||||
|
||||
## 6. Define the `conditional_edges`
|
||||
|
||||
|
||||
@@ -164,7 +164,7 @@ llm = init_chat_model("anthropic:claude-3-5-sonnet-latest")
|
||||
```
|
||||
-->
|
||||
|
||||
```python
|
||||
```python hl_lines="36 37"
|
||||
from typing import Annotated
|
||||
|
||||
from langchain.chat_models import init_chat_model
|
||||
@@ -206,4 +206,4 @@ graph = graph_builder.compile(checkpointer=memory)
|
||||
|
||||
## Next steps
|
||||
|
||||
In the next tutorial, you will [add human-in-the-loop to the chatbot](./4-human-in-the-loop.md) to handle situations where it may need guidance or verification before proceeding.
|
||||
In the next tutorial, you will [add human-in-the-loop to the chatbot](./4-human-in-the-loop.md) to handle situations where it may need guidance or verification before proceeding.
|
||||
|
||||
@@ -471,7 +471,7 @@
|
||||
"\n",
|
||||
"_get_pass(\"TAVILY_API_KEY\")\n",
|
||||
"\n",
|
||||
"calculate = get_math_tool(ChatOpenAI(model=\"gpt-4-turbo-preview\"))\n",
|
||||
"calculate = get_math_tool(ChatOpenAI(model=\"gpt-4o\"))\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-4-turbo-preview\")\n",
|
||||
"llm = ChatOpenAI(model=\"gpt-4o\")\n",
|
||||
"\n",
|
||||
"runnable = joiner_prompt | llm.with_structured_output(\n",
|
||||
" JoinOutputs, method=\"function_calling\"\n",
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,21 @@
|
||||
# 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)
|
||||
@@ -135,7 +135,6 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain import hub\n",
|
||||
"from langchain_openai import ChatOpenAI\n",
|
||||
"\n",
|
||||
"from langgraph.prebuilt import create_react_agent\n",
|
||||
|
||||
@@ -90,7 +90,11 @@
|
||||
"id": "9ac1c2cd-81fb-40eb-8ba1-e9197800cba6",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Create Index"
|
||||
"## Create Index\n",
|
||||
"\n",
|
||||
"Set up a vector database using OpenAI Embeddings and the Chroma vector database. \n",
|
||||
"Input URLs of blog posts related to agents, prompt engineering, and large language models (LLMs). \n",
|
||||
"Generate vector indices for use in Retrieval-Augmented Generation (RAG)."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -159,6 +163,21 @@
|
||||
"</div>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "6cdd5ac0-fa18-4ee9-8051-062a0c56268f",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Router for Query Analysis\n",
|
||||
"\n",
|
||||
"Let’s start with Routing. First, assign the query analysis to the LLM.\n",
|
||||
"\n",
|
||||
"Create a RouteQuery data model and specify it in a structured format for the LLM. The decision for routing should be embedded in the prompt. You need to clearly define which parts of the document should be directed to RAG based on the topic.\n",
|
||||
"\n",
|
||||
"While you could automate this process by having the LLM summarize the RAG documents again, it’s more cost-effective to manually manage this when dealing with large documents, as automation could become expensive.\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
@@ -219,6 +238,18 @@
|
||||
"print(question_router.invoke({\"question\": \"What are the types of agent memory?\"}))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "cb248c94-0b0c-4d86-8565-32aa8d7424e4",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Retrieval Grader\n",
|
||||
"\n",
|
||||
"After performing retrieval, evaluate the results. Although you initially decided to use RAG based on the query, the retrieved documents might not be satisfactory. Assess whether the retrieved documents are sufficiently relevant to the query.\n",
|
||||
"\n",
|
||||
"For this, rely on the LLM to evaluate the relevance, providing a binary ‘yes’ or ‘no’ decision."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
@@ -309,6 +340,17 @@
|
||||
"print(generation)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "cb0ab54a-4a4f-45fa-b1c5-cea1bf4c59d5",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Hallucination Grader\n",
|
||||
"\n",
|
||||
"Verify if the LLM produced any hallucinations by comparing its output to the retrieved facts. \n",
|
||||
"Provide the LLM’s evaluation in a binary ‘yes’ or ‘no’ format.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
@@ -357,6 +399,16 @@
|
||||
"hallucination_grader.invoke({\"documents\": docs, \"generation\": generation})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "4f58502a-c25f-4d80-a402-5583b0cd3e41",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Answer Grader\n",
|
||||
"\n",
|
||||
"Evaluate the answer finally."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
@@ -405,6 +457,18 @@
|
||||
"answer_grader.invoke({\"question\": question, \"generation\": generation})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "af77946c-2646-4039-86b0-e2fde1ab7459",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Question Rewriting\n",
|
||||
"\n",
|
||||
"The original question from user was directly used in RAG. \n",
|
||||
"However, the user’s question might not be in a form suitable for RAG. \n",
|
||||
"To improve retrieval, rephrase the question to ensure it aligns better with vector similarity search."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
@@ -450,7 +514,9 @@
|
||||
"id": "d07c0b31-b919-4498-869f-9673125c2473",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Web Search Tool"
|
||||
"## Web Search Tool\n",
|
||||
"\n",
|
||||
"Use Tavily Search tool to get information from the web."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -516,11 +582,13 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 12,
|
||||
"execution_count": null,
|
||||
"id": "b76b5ec3-0720-443d-85b1-c0e79659ca0a",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from pprint import pprint\n",
|
||||
"\n",
|
||||
"from langchain.schema import Document\n",
|
||||
"\n",
|
||||
"\n",
|
||||
@@ -796,7 +864,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 14,
|
||||
"execution_count": null,
|
||||
"id": "29acc541-d726-4b75-84d1-a215845fe88a",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
@@ -823,8 +891,6 @@
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from pprint import pprint\n",
|
||||
"\n",
|
||||
"# Run\n",
|
||||
"inputs = {\n",
|
||||
" \"question\": \"What player at the Bears expected to draft first in the 2024 NFL draft?\"\n",
|
||||
|
||||
@@ -185,7 +185,7 @@
|
||||
"\n",
|
||||
"\n",
|
||||
"# LLM with function call\n",
|
||||
"llm = ChatOpenAI(model=\"gpt-3.5-turbo-0125\", temperature=0)\n",
|
||||
"llm = ChatOpenAI(model=\"gpt-4o-mini\", temperature=0)\n",
|
||||
"structured_llm_grader = llm.with_structured_output(GradeDocuments)\n",
|
||||
"\n",
|
||||
"# Prompt\n",
|
||||
|
||||
@@ -389,7 +389,7 @@
|
||||
"text": [
|
||||
"{'generate': {'messages': [AIMessage(content='Title: The Little Prince: A Topical Allegory for Modern Life\\n\\nIntroduction:\\nAntoine de Saint-Exupéry\\'s \"The Little Prince\" is a classic novella that has captured the hearts of millions since its publication in 1943. While it might be easy to dismiss this work as a children\\'s story, its profound themes and timeless message make it a relevant and topical piece in modern life. This essay will explore the allegorical nature of \"The Little Prince\" and discuss how its message can be applied to the complexities of the modern world.\\n\\nBody Paragraph 1 - The Allegory of the Little Prince:\\n\"The Little Prince\" is an allegorical tale that explores various aspects of the human condition through its whimsical characters and situations. The Little Prince himself represents innocence, curiosity, and the importance of human connection. As the story unfolds, readers encounter different characters that symbolize various aspects of adult life, such as vanity, materialism, and authority. These representations allow the story to transcend age and culture, making it relatable to a wide range of readers, even in the modern context.\\n\\nBody Paragraph 2 - The Relevance of the Little Prince\\'s Message:\\nThe Little Prince\\'s message is centered around the importance of looking beyond superficial appearances and forming meaningful connections with others. In a world increasingly dominated by technology and social media, where surface-level interactions are commonplace, this message is more relevant than ever. The Little Prince encourages readers to cherish and nurture genuine relationships, reminding us that true happiness and fulfillment come from understanding and empathizing with others.\\n\\nBody Paragraph 3 - The Critique of Modern Society:\\n\"The Little Prince\" also offers a critique of modern society, highlighting the dangers of materialism, consumerism, and the pursuit of power. These themes resonate strongly in today\\'s world, where wealth inequality and environmental degradation are pressing issues. The story serves as a reminder that the pursuit of material possessions and status often comes at the expense of our own happiness and the well-being of our planet.\\n\\nConclusion:\\nIn conclusion, \"The Little Prince\" remains a topical and relevant work in modern life due to its allegorical nature, timeless message, and critique of modern society. Its exploration of human connections, materialism, and the pursuit of power offers valuable insights for readers of all ages. By embracing the story\\'s wisdom, we can better navigate the complexities of the modern world and foster a more compassionate, sustainable, and interconnected society.', response_metadata={'token_usage': {'prompt_tokens': 72, 'total_tokens': 632, 'completion_tokens': 560}, 'model_name': 'accounts/fireworks/models/mixtral-8x7b-instruct', 'system_fingerprint': '', 'finish_reason': 'stop', 'logprobs': None}, id='run-b39a25ab-24f6-42d0-96c2-0f74c3ecc8f7-0', usage_metadata={'input_tokens': 72, 'output_tokens': 560, 'total_tokens': 632})]}}\n",
|
||||
"---\n",
|
||||
"{'reflect': {'messages': [HumanMessage(content='Essay Critique and Recommendations:\\n\\nTitle: The Little Prince: A Topical Allegory for Modern Life\\n\\nIntroduction:\\nThe introduction effectively sets the stage for the essay by providing background information on \"The Little Prince\" and its relevance in modern life. However, consider adding a hook to engage the reader\\'s attention and create a stronger first impression.\\n\\nBody Paragraph 1 - The Allegory of the Little Prince:\\nThis paragraph provides a clear explanation of the allegorical nature of \"The Little Prince.\" To enhance this section, consider offering specific examples from the text to illustrate how the characters and situations symbolize various aspects of adult life. This will strengthen your analysis and make it more engaging for the reader.\\n\\nBody Paragraph 2 - The Relevance of the Little Prince\\'s Message:\\nThe relevance of the Little Prince\\'s message is well-articulated in this paragraph. To further strengthen your argument, consider discussing the consequences of ignoring this message in the context of modern society. This will help emphasize the importance of the Little Prince\\'s wisdom and its relevance to contemporary issues.\\n\\nBody Paragraph 3 - The Critique of Modern Society:\\nThis paragraph effectively highlights the story\\'s critique of modern society. To deepen your analysis, explore how the themes of materialism, consumerism, and the pursuit of power interconnect and contribute to the challenges faced by modern society. Additionally, consider discussing potential solutions or actions inspired by the Little Prince\\'s message that could help address these issues.\\n\\nConclusion:\\nThe conclusion effectively summarizes the main points of the essay and emphasizes the relevance of \"The Little Prince\" in modern life. To further enhance this section, consider incorporating a thought-provoking question or statement that encourages readers to reflect on the story\\'s message and its implications for their own lives.\\n\\nRecommendations:\\n1. Expand the essay to approximately 1,200-1,500 words to allow for a more in-depth analysis.\\n2. Incorporate specific examples and quotes from \"The Little Prince\" to support your arguments and engage the reader.\\n3. Ensure that each body paragraph contains a clear thesis statement, supporting evidence, and analysis.\\n4. Consider discussing counterarguments or potential criticisms of the Little Prince\\'s message to add depth and complexity to your essay.\\n5. Revise and edit the essay for clarity, coherence, and grammar.')]}}\n",
|
||||
"{'reflect': {'messages': [HumanMessage(content='Essay Critique and Recommendations:\\n\\nTitle: The Little Prince: A Topical Allegory for Modern Life\\n\\nIntroduction:\\nThe introduction effectively sets the stage for the essay by providing background information on \"The Little Prince\" and its relevance in modern life. However, consider adding a hook to engage the reader\\'s attention and create a stronger first impression.\\n\\nBody Paragraph 1 - The Allegory of the Little Prince:\\nThis paragraph provides a clear explanation of the allegorical nature of \"The Little Prince.\" To enhance this section, consider offering specific examples from the text to illustrate how the characters and situations symbolize various aspects of adult life. This will strengthen your analysis and make it more engaging for the reader.\\n\\nBody Paragraph 2 - The Relevance of the Little Prince\\'s Message:\\nThe relevance of the Little Prince\\'s message is well-articulated in this paragraph. To further strengthen your argument, consider discussing the consequences of ignoring this message in the context of modern society. This will help emphasize the importance of the Little Prince\\'s wisdom and its relevance to contemporary issues.\\n\\nBody Paragraph 3 - The Critique of Modern Society:\\nThis paragraph effectively highlights the story\\'s critique of modern society. To deepen your analysis, explore how themes of materialism, consumerism, and the pursuit of power interconnect and contribute to the challenges faced by modern society. Additionally, consider discussing potential solutions or actions inspired by the Little Prince\\'s message that could help address these issues.\\n\\nConclusion:\\nThe conclusion effectively summarizes the main points of the essay and emphasizes the relevance of \"The Little Prince\" in modern life. To further enhance this section, consider incorporating a thought-provoking question or statement that encourages readers to reflect on the story\\'s message and its implications for their own lives.\\n\\nRecommendations:\\n1. Expand the essay to approximately 1,200-1,500 words to allow for a more in-depth analysis.\\n2. Incorporate specific examples and quotes from \"The Little Prince\" to support your arguments and engage the reader.\\n3. Ensure that each body paragraph contains a clear thesis statement, supporting evidence, and analysis.\\n4. Consider discussing counterarguments or potential criticisms of the Little Prince\\'s message to add depth and complexity to your essay.\\n5. Revise and edit the essay for clarity, coherence, and grammar.')]}}\n",
|
||||
"---\n",
|
||||
"{'generate': {'messages': [AIMessage(content='Title: The Little Prince: A Topical Allegory for Modern Life\\n\\nIntroduction:\\nIn Antoine de Saint-Exupéry\\'s classic novella \"The Little Prince,\" a young boy embarks on a journey through the universe, meeting various characters that symbolize different aspects of adult life. This timeless tale, published in 1943, remains incredibly relevant in today\\'s modern world. Its allegorical nature, thought-provoking message, and critique of modern society offer invaluable insights for readers of all ages. This essay will explore the allegory of \"The Little Prince,\" analyze the relevance of its message, and discuss its critique of modern society, demonstrating its topicality in contemporary life.\\n\\nBody Paragraph 1 - The Allegory of the Little Prince:\\n\"The Little Prince\" is an allegorical tale that uses whimsical characters and situations to explore various aspects of the human condition. For instance, the king represents authority without substance, while the businessman embodies the futility of materialism. The fox, conversely, symbolizes the importance of forming genuine connections and nurturing meaningful relationships. These allegorical representations allow the story to transcend age and culture, making it relatable to a wide range of readers, even in the modern context.\\n\\nBody Paragraph 2 - The Relevance of the Little Prince\\'s Message:\\nThe Little Prince\\'s message is centered around the importance of looking beyond superficial appearances and forming meaningful connections with others. In a world increasingly dominated by technology and social media, where surface-level interactions are commonplace, this message is more relevant than ever. Neglecting this message can lead to feelings of isolation, loneliness, and dissatisfaction. By embracing the story\\'s wisdom, we can prioritize genuine relationships, fostering a more compassionate and interconnected society.\\n\\nBody Paragraph 3 - The Critique of Modern Society:\\n\"The Little Prince\" offers a critique of modern society, highlighting the dangers of materialism, consumerism, and the pursuit of power. These themes resonate strongly in today\\'s world, where wealth inequality and environmental degradation are pressing issues. The story serves as a reminder that the pursuit of material possessions and status often comes at the expense of our own happiness and the well-being of our planet. To address these challenges, we must reevaluate our priorities, focusing on sustainability, empathy, and the cultivation of meaningful relationships.\\n\\nConclusion:\\nIn conclusion, \"The Little Prince\" remains a topical and relevant work in modern life due to its allegorical nature, timeless message, and critique of modern society. Its exploration of human connections, materialism, and the pursuit of power offers valuable insights for readers of all ages. By embracing the story\\'s wisdom, we can better navigate the complexities of the modern world and foster a more compassionate, sustainable, and interconnected society. As the Little Prince so eloquently states, \"What is essential is invisible to the eye,\" reminding us that true happiness and fulfillment come from understanding and empathizing with others.\\n\\nExpanded Essay Recommendations:\\n\\n1. Expand the essay to approximately 1,200-1,500 words to allow for a more in-depth analysis.\\n2. Incorporate specific examples and quotes from \"The Little Prince\" to support your arguments and engage the reader. For instance, use quotes like, \"You become responsible, forever, for what you have tamed,\" to emphasize the importance of forming genuine connections.\\n3. Ensure that each body paragraph contains a clear thesis statement, supporting evidence, and analysis.\\n4. Consider discussing counterarguments or potential criticisms of the Little Prince\\'s message to add depth and complexity to your essay. For example, explore the idea that the pursuit of material possessions can provide a sense of security and comfort.\\n5. Revise and edit the essay for clarity, coherence, and grammar. Ensure that transitions between paragraphs are smooth and that your arguments flow logically.', response_metadata={'token_usage': {'prompt_tokens': 1168, 'total_tokens': 2044, 'completion_tokens': 876}, 'model_name': 'accounts/fireworks/models/mixtral-8x7b-instruct', 'system_fingerprint': '', 'finish_reason': 'stop', 'logprobs': None}, id='run-9bfc9ff2-3186-43f5-8b75-498d532d8d1a-0', usage_metadata={'input_tokens': 1168, 'output_tokens': 876, 'total_tokens': 2044})]}}\n",
|
||||
"---\n",
|
||||
@@ -478,7 +478,7 @@
|
||||
"The relevance of the Little Prince's message is well-articulated in this paragraph. To further strengthen your argument, consider discussing the consequences of ignoring this message in the context of modern society. This will help emphasize the importance of the Little Prince's wisdom and its relevance to contemporary issues.\n",
|
||||
"\n",
|
||||
"Body Paragraph 3 - The Critique of Modern Society:\n",
|
||||
"This paragraph effectively highlights the story's critique of modern society. To deepen your analysis, explore how the themes of materialism, consumerism, and the pursuit of power interconnect and contribute to the challenges faced by modern society. Additionally, consider discussing potential solutions or actions inspired by the Little Prince's message that could help address these issues.\n",
|
||||
"This paragraph effectively highlights the story's critique of modern society. To deepen your analysis, explore how themes of materialism, consumerism, and the pursuit of power interconnect and contribute to the challenges faced by modern society. Additionally, consider discussing potential solutions or actions inspired by the Little Prince's message that could help address these issues.\n",
|
||||
"\n",
|
||||
"Conclusion:\n",
|
||||
"The conclusion effectively summarizes the main points of the essay and emphasizes the relevance of \"The Little Prince\" in modern life. To further enhance this section, consider incorporating a thought-provoking question or statement that encourages readers to reflect on the story's message and its implications for their own lives.\n",
|
||||
|
||||
@@ -1758,7 +1758,7 @@
|
||||
"id": "4eb67198-c84f-458b-8baf-783d7246dddc",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Let's let the agent try again. Call `stream` with `None` to just use the inputs loaded from the memory. We will skip our human review for the next few attempats\n",
|
||||
"Let's let the agent try again. Call `stream` with `None` to just use the inputs loaded from the memory. We will skip our human review for the next few attempts\n",
|
||||
"to see if it can correct itself."
|
||||
]
|
||||
},
|
||||
|
||||
+140
-176
@@ -89,162 +89,145 @@ plugins:
|
||||
- "!^_"
|
||||
|
||||
nav:
|
||||
- Guides:
|
||||
- Get started:
|
||||
- index.md
|
||||
- Get started:
|
||||
- Quickstart: agents/agents.md
|
||||
- LangGraph basics:
|
||||
- concepts/why-langgraph.md
|
||||
- Build a basic chatbot: tutorials/get-started/1-build-basic-chatbot.md
|
||||
- tutorials/get-started/2-add-tools.md
|
||||
- tutorials/get-started/3-add-memory.md
|
||||
- Add human-in-the-loop: tutorials/get-started/4-human-in-the-loop.md
|
||||
- tutorials/get-started/5-customize-state.md
|
||||
- tutorials/get-started/6-time-travel.md
|
||||
- Deployment: tutorials/deployment.md
|
||||
- Prebuilt agents:
|
||||
- Overview: agents/overview.md
|
||||
- agents/run_agents.md
|
||||
- agents/streaming.md
|
||||
- agents/models.md
|
||||
- agents/tools.md
|
||||
- agents/mcp.md
|
||||
- agents/context.md
|
||||
- agents/memory.md
|
||||
- agents/human-in-the-loop.md
|
||||
- agents/multi-agent.md
|
||||
- agents/evals.md
|
||||
- agents/deployment.md
|
||||
- agents/ui.md
|
||||
- LangGraph framework:
|
||||
- Agent architectures:
|
||||
- Overview: concepts/agentic_concepts.md
|
||||
- Quickstarts:
|
||||
- Agent: agents/agents.md
|
||||
- Local server: tutorials/langgraph-platform/local-server.md
|
||||
- Deployment: cloud/quick_start.md
|
||||
- General concepts:
|
||||
- Common patterns:
|
||||
- Agent architectures: concepts/agentic_concepts.md
|
||||
- Workflows & agents: tutorials/workflows.md
|
||||
- Graphs:
|
||||
- Overview: concepts/low_level.md
|
||||
- Runtime overview: concepts/pregel.md
|
||||
- Use the Graph API: how-tos/graph-api.ipynb
|
||||
- Streaming:
|
||||
- Overview: concepts/streaming.md
|
||||
- "Stream outputs": how-tos/streaming.md
|
||||
- Persistence:
|
||||
- Overview: concepts/persistence.md
|
||||
- concepts/durable_execution.md
|
||||
- how-tos/persistence.ipynb
|
||||
- Memory:
|
||||
- Overview: concepts/memory.md
|
||||
- Manage memory: how-tos/memory.ipynb
|
||||
- Human-in-the-loop:
|
||||
- Overview: concepts/human_in_the_loop.md
|
||||
- how-tos/human_in_the_loop/add-human-in-the-loop.md
|
||||
- Breakpoints:
|
||||
- Overview: concepts/breakpoints.md
|
||||
- how-tos/human_in_the_loop/breakpoints.ipynb
|
||||
- Time travel:
|
||||
- Overview: concepts/time-travel.md
|
||||
- how-tos/human_in_the_loop/time-travel.ipynb
|
||||
- Tools:
|
||||
- Overview: concepts/tools.md
|
||||
- how-tos/tool-calling.ipynb
|
||||
- Subgraphs:
|
||||
- Overview: concepts/subgraphs.md
|
||||
- how-tos/subgraph.ipynb
|
||||
- Multi-agent:
|
||||
- Overview: concepts/multi_agent.md
|
||||
- how-tos/multi_agent.ipynb
|
||||
- Functional API:
|
||||
- Overview: concepts/functional_api.md
|
||||
- how-tos/use-functional-api.md
|
||||
|
||||
- LangGraph Platform:
|
||||
- Overview: concepts/langgraph_platform.md
|
||||
- Get started:
|
||||
- Quickstart: tutorials/langgraph-platform/local-server.md
|
||||
- Deployment quickstart: cloud/quick_start.md
|
||||
- Components:
|
||||
- Overview: concepts/langgraph_components.md
|
||||
- LangGraph Server:
|
||||
- Overview: concepts/langgraph_server.md
|
||||
- Application structure:
|
||||
- Overview: concepts/application_structure.md
|
||||
- cloud/deployment/setup.md
|
||||
- cloud/deployment/setup_pyproject.md
|
||||
- cloud/deployment/setup_javascript.md
|
||||
- cloud/deployment/custom_docker.md
|
||||
- LangGraph CLI: concepts/langgraph_cli.md
|
||||
- LangGraph Studio:
|
||||
- Overview: concepts/langgraph_studio.md
|
||||
- Quickstart: cloud/how-tos/studio/quick_start.md
|
||||
- cloud/how-tos/invoke_studio.md
|
||||
- cloud/how-tos/studio/manage_assistants.md
|
||||
- cloud/how-tos/threads_studio.md
|
||||
- cloud/how-tos/iterate_graph_studio.md
|
||||
- cloud/how-tos/clone_traces_studio.md
|
||||
- cloud/how-tos/datasets_studio.md
|
||||
- LangGraph SDK: concepts/sdk.md
|
||||
- Data management:
|
||||
- Add semantic search: cloud/deployment/semantic_search.md
|
||||
- Add TTLs: how-tos/ttl/configure_ttl.md
|
||||
- Agent development: agents/overview.md
|
||||
- Workflow orchestration:
|
||||
- Graphs: concepts/low_level.md
|
||||
- Subgraphs: concepts/subgraphs.md
|
||||
- Runtime: concepts/pregel.md
|
||||
- Functional API: concepts/functional_api.md
|
||||
- Core capabilities:
|
||||
- Streaming: concepts/streaming.md
|
||||
- Persistence: concepts/persistence.md
|
||||
- Durable execution: concepts/durable_execution.md
|
||||
- Memory: concepts/memory.md
|
||||
- Tools: concepts/tools.md
|
||||
- Human-in-the-loop: concepts/human_in_the_loop.md
|
||||
- Breakpoints: concepts/breakpoints.md
|
||||
- Time travel: concepts/time-travel.md
|
||||
- Multi-agent: concepts/multi_agent.md
|
||||
- Platform capabilities:
|
||||
- LangGraph Platform:
|
||||
- Overview: concepts/langgraph_platform.md
|
||||
- Components:
|
||||
- Overview: concepts/langgraph_components.md
|
||||
- LangGraph Server:
|
||||
- Overview: concepts/langgraph_server.md
|
||||
- Data plane: concepts/langgraph_data_plane.md
|
||||
- Control plane: concepts/langgraph_control_plane.md
|
||||
- LangGraph CLI: concepts/langgraph_cli.md
|
||||
- LangGraph Studio: concepts/langgraph_studio.md
|
||||
- LangGraph SDK: concepts/sdk.md
|
||||
- Plans & pricing: concepts/plans.md
|
||||
- Application structure: concepts/application_structure.md
|
||||
- Scalability & resilience: concepts/scalability_and_resilience.md
|
||||
- Authentication & access control: concepts/auth.md
|
||||
- Assistants: concepts/assistants.md
|
||||
- Double-texting: concepts/double_texting.md
|
||||
- Webhooks: cloud/concepts/webhooks.md
|
||||
- Cron jobs: cloud/concepts/cron_jobs.md
|
||||
- Deployment:
|
||||
- Overview: concepts/deployment_options.md
|
||||
- Deployment options:
|
||||
- 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
|
||||
- Standalone Container: concepts/langgraph_standalone_container.md
|
||||
|
||||
- Guides:
|
||||
- LangGraph APIs:
|
||||
- Use the Graph API: how-tos/graph-api.ipynb
|
||||
- Use the Functional API: how-tos/use-functional-api.md
|
||||
- Models:
|
||||
- Configure model: agents/models.md
|
||||
- Streaming:
|
||||
- Stream outputs: how-tos/streaming.md
|
||||
- Use Server API: cloud/how-tos/streaming.md
|
||||
- Context:
|
||||
- Use in agent: agents/context.md
|
||||
- Memory:
|
||||
- Basic implementation: agents/memory.md
|
||||
- Persistence: how-tos/persistence.ipynb # MERGE
|
||||
- Custom implementation: how-tos/memory.ipynb
|
||||
- Human-in-the-loop:
|
||||
- Add to agent: agents/human-in-the-loop.md
|
||||
- Add to workflow: how-tos/human_in_the_loop/add-human-in-the-loop.md
|
||||
- Use Server API: cloud/how-tos/add-human-in-the-loop.md
|
||||
- Time travel:
|
||||
- Use Server API: cloud/how-tos/human_in_the_loop_time_travel.md
|
||||
- Breakpoints:
|
||||
- Set breakpoints: how-tos/human_in_the_loop/breakpoints.ipynb
|
||||
- Use Server API: cloud/how-tos/human_in_the_loop_breakpoint.md
|
||||
- Tools:
|
||||
- Call tools: how-tos/tool-calling.md
|
||||
- Subgraphs:
|
||||
- Use subgraphs: how-tos/subgraph.ipynb
|
||||
- Multi-agent:
|
||||
- Prebuilt implementation: agents/multi-agent.md
|
||||
- Custom implementation: how-tos/multi_agent.ipynb
|
||||
- MCP:
|
||||
- Use MCP tools: agents/mcp.md
|
||||
- Server deployment via MCP: concepts/server-mcp.md
|
||||
- Deployment:
|
||||
- Basic deployment: agents/deployment.md
|
||||
- Set up your application:
|
||||
- Use requirements.txt: cloud/deployment/setup.md
|
||||
- Use pyproject.toml: cloud/deployment/setup_pyproject.md
|
||||
- Use JavaScript: cloud/deployment/setup_javascript.md
|
||||
- Use custom Docker: cloud/deployment/custom_docker.md
|
||||
- Deploy to production:
|
||||
- Cloud SaaS: cloud/deployment/cloud.md
|
||||
- Self-Hosted Data Plane: cloud/deployment/self_hosted_data_plane.md
|
||||
- Self-Hosted Control Plane: cloud/deployment/self_hosted_control_plane.md
|
||||
- Standalone Container: cloud/deployment/standalone_container.md
|
||||
- Evaluation:
|
||||
- Basic implementation: agents/evals.md
|
||||
- Platform capabilities:
|
||||
- LangGraph Studio:
|
||||
- Quickstart: cloud/how-tos/studio/quick_start.md
|
||||
- cloud/how-tos/invoke_studio.md
|
||||
- cloud/how-tos/studio/manage_assistants.md
|
||||
- cloud/how-tos/threads_studio.md
|
||||
- cloud/how-tos/iterate_graph_studio.md
|
||||
- cloud/how-tos/studio/run_evals.md
|
||||
- cloud/how-tos/clone_traces_studio.md
|
||||
- cloud/how-tos/datasets_studio.md
|
||||
- Authentication & access control:
|
||||
- Overview: concepts/auth.md
|
||||
- how-tos/auth/custom_auth.md
|
||||
- how-tos/auth/openapi_security.md
|
||||
- Assistants:
|
||||
- Overview: concepts/assistants.md
|
||||
- cloud/how-tos/configuration_cloud.md
|
||||
- Threads:
|
||||
- Overview: cloud/concepts/threads.md
|
||||
- cloud/how-tos/use_threads.md
|
||||
- Runs:
|
||||
- Overview: cloud/concepts/runs.md
|
||||
- cloud/how-tos/background_run.md
|
||||
- cloud/how-tos/same-thread.md
|
||||
- cloud/how-tos/cron_jobs.md
|
||||
- cloud/how-tos/stateless_runs.md
|
||||
- cloud/how-tos/configurable_headers.md
|
||||
- Streaming:
|
||||
- Overview: cloud/concepts/streaming.md
|
||||
- cloud/how-tos/streaming.md
|
||||
- Human-in-the-loop: cloud/how-tos/add-human-in-the-loop.md
|
||||
- Breakpoints: cloud/how-tos/human_in_the_loop_breakpoint.md
|
||||
- Time travel: cloud/how-tos/human_in_the_loop_time_travel.md
|
||||
- MCP: concepts/server-mcp.md
|
||||
- Threads: cloud/how-tos/use_threads.md
|
||||
- Runs:
|
||||
- cloud/how-tos/background_run.md
|
||||
- cloud/how-tos/same-thread.md
|
||||
- cloud/how-tos/cron_jobs.md
|
||||
- cloud/how-tos/stateless_runs.md
|
||||
- cloud/how-tos/configurable_headers.md
|
||||
- Double-texting:
|
||||
- Overview: concepts/double_texting.md
|
||||
- cloud/how-tos/interrupt_concurrent.md
|
||||
- cloud/how-tos/rollback_concurrent.md
|
||||
- cloud/how-tos/reject_concurrent.md
|
||||
- cloud/how-tos/enqueue_concurrent.md
|
||||
- Webhooks:
|
||||
- Overview: cloud/concepts/webhooks.md
|
||||
- cloud/how-tos/webhooks.md
|
||||
- Cron jobs:
|
||||
- Overview: cloud/concepts/cron_jobs.md
|
||||
- cloud/how-tos/cron_jobs.md
|
||||
- Webhooks: cloud/how-tos/webhooks.md
|
||||
- Cron jobs: cloud/how-tos/cron_jobs.md
|
||||
- Server customization:
|
||||
- how-tos/http/custom_lifespan.md
|
||||
- how-tos/http/custom_middleware.md
|
||||
- how-tos/http/custom_routes.md
|
||||
- Deployment:
|
||||
- Overview: concepts/deployment_options.md
|
||||
- Data plane: concepts/langgraph_data_plane.md
|
||||
- Control plane: concepts/langgraph_control_plane.md
|
||||
- Deployment options:
|
||||
- Cloud SaaS:
|
||||
- Overview: concepts/langgraph_cloud.md
|
||||
- Deploy Cloud SaaS: cloud/deployment/cloud.md
|
||||
- Self-Hosted Data Plane:
|
||||
- Overview: concepts/langgraph_self_hosted_data_plane.md
|
||||
- Deploy Self-Hosted Data Plane: cloud/deployment/self_hosted_data_plane.md
|
||||
- Self-Hosted Control Plane:
|
||||
- Overview: concepts/langgraph_self_hosted_control_plane.md
|
||||
- Deploy Self-Hosted Control Plane: cloud/deployment/self_hosted_control_plane.md
|
||||
- Standalone Container:
|
||||
- Overview: concepts/langgraph_standalone_container.md
|
||||
- Deploy Standalone Container: cloud/deployment/standalone_container.md
|
||||
- Scalability & resilience: concepts/scalability_and_resilience.md
|
||||
- Plans & pricing: concepts/plans.md
|
||||
|
||||
- Data management:
|
||||
- Add semantic search: cloud/deployment/semantic_search.md
|
||||
- Add TTLs: how-tos/ttl/configure_ttl.md
|
||||
|
||||
- Reference:
|
||||
- reference/index.md
|
||||
- LangGraph:
|
||||
@@ -273,9 +256,20 @@ nav:
|
||||
- Environment variables: cloud/reference/env_var.md
|
||||
|
||||
- Examples:
|
||||
- agents/run_agents.md
|
||||
- LangGraph basics:
|
||||
- concepts/why-langgraph.md
|
||||
- Build a basic chatbot: tutorials/get-started/1-build-basic-chatbot.md
|
||||
- tutorials/get-started/2-add-tools.md
|
||||
- tutorials/get-started/3-add-memory.md
|
||||
- Add human-in-the-loop: tutorials/get-started/4-human-in-the-loop.md
|
||||
- tutorials/get-started/5-customize-state.md
|
||||
- tutorials/get-started/6-time-travel.md
|
||||
- Template applications: concepts/template_applications.md # TODO: make tutorial
|
||||
- Agentic RAG: tutorials/rag/langgraph_agentic_rag.ipynb
|
||||
- Agent Supervisor: tutorials/multi_agent/agent_supervisor.ipynb
|
||||
- SQL agent: tutorials/sql-agent.ipynb
|
||||
- Prebuilt chat UI: agents/ui.md
|
||||
- Graph runs in LangSmith: how-tos/run-id-langsmith.ipynb
|
||||
- LangGraph Platform:
|
||||
- Authentication:
|
||||
@@ -290,11 +284,12 @@ nav:
|
||||
- Integrate LangGraph into a React app: cloud/how-tos/use_stream_react.md
|
||||
- Implement generative UI with LangGraph: cloud/how-tos/generative_ui_react.md
|
||||
|
||||
- Resources:
|
||||
- concepts/faq.md
|
||||
- Template applications: concepts/template_applications.md # TODO: make tutorial
|
||||
- llms.txt: llms-txt-overview.md
|
||||
- Additional resources:
|
||||
- agents/prebuilt.md # NOTE: prebuilt.md is auto-generated by `make build-prebuilt`
|
||||
- LangGraph Academy course: https://academy.langchain.com/courses/intro-to-langgraph
|
||||
- Case studies: adopters.md
|
||||
- concepts/faq.md
|
||||
- llms.txt: llms-txt-overview.md
|
||||
- Troubleshooting:
|
||||
- Errors:
|
||||
- troubleshooting/errors/index.md
|
||||
@@ -305,9 +300,7 @@ nav:
|
||||
- troubleshooting/errors/INVALID_CHAT_HISTORY.md
|
||||
- troubleshooting/errors/INVALID_LICENSE.md
|
||||
- LangGraph Studio: troubleshooting/studio.md
|
||||
- Learn:
|
||||
- LangGraph Academy course: https://academy.langchain.com/courses/intro-to-langgraph
|
||||
- Case studies: adopters.md
|
||||
|
||||
|
||||
markdown_extensions:
|
||||
- abbr
|
||||
@@ -364,16 +357,6 @@ markdown_extensions:
|
||||
hooks:
|
||||
- _scripts/notebook_hooks.py
|
||||
extra:
|
||||
consent:
|
||||
title: Cookie consent
|
||||
actions:
|
||||
- accept
|
||||
- reject
|
||||
description: >-
|
||||
We use cookies to recognize your repeated visits and preferences, as well
|
||||
as to measure the effectiveness of our documentation and whether users
|
||||
find what they're searching for. <strong>Clicking "Accept" makes our
|
||||
documentation better. Thank you!</strong> ❤️
|
||||
social:
|
||||
- icon: fontawesome/brands/js
|
||||
link: https://langchain-ai.github.io/langgraphjs/
|
||||
@@ -381,25 +364,6 @@ extra:
|
||||
link: https://github.com/langchain-ai/langgraph
|
||||
- icon: fontawesome/brands/twitter
|
||||
link: https://twitter.com/LangChainAI
|
||||
analytics:
|
||||
provider: google
|
||||
property: G-G8X6ELZYE0
|
||||
feedback:
|
||||
title: Was this page helpful?
|
||||
ratings:
|
||||
- icon: material/emoticon-happy-outline
|
||||
name: This page was helpful
|
||||
data: 1
|
||||
note: >-
|
||||
Thanks for your feedback!
|
||||
- icon: material/emoticon-sad-outline
|
||||
name: This page could be improved
|
||||
data: 0
|
||||
note: >-
|
||||
Thanks for your feedback! Please help us improve this page by adding to the discussion below.
|
||||
shared_analytics:
|
||||
provider: google
|
||||
property: G-47WX3HKKY2
|
||||
validation:
|
||||
# https://www.mkdocs.org/user-guide/configuration/
|
||||
# We are still raising for omitted files because they determine the breadcrumbs for pages.
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block analytics %}
|
||||
<!-- Google Tag Manager -->
|
||||
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
|
||||
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
|
||||
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
|
||||
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
|
||||
})(window,document,'script','dataLayer','GTM-T35S4S46');</script>
|
||||
<!-- End Google Tag Manager -->
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block extrahead %}
|
||||
<meta name="algolia-site-verification" content="165B7E7C89E49946" />
|
||||
<style>
|
||||
@@ -185,7 +196,6 @@
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
<div class="notebook-links">
|
||||
{% if page.nb_url %}
|
||||
@@ -209,7 +219,6 @@
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block announce %}
|
||||
<strong>We are growing and hiring for multiple roles for LangChain, LangGraph and LangSmith. <a href="https://www.langchain.com/careers" target="_blank" rel="noopener noreferrer"> Join our team!</a></strong>
|
||||
{% endblock %}
|
||||
|
||||
Generated
+3065
-3062
File diff suppressed because it is too large
Load Diff
@@ -184,7 +184,7 @@
|
||||
"\n",
|
||||
"\n",
|
||||
"# LLM with function call\n",
|
||||
"llm = ChatOpenAI(model=\"gpt-3.5-turbo-0125\", temperature=0)\n",
|
||||
"llm = ChatOpenAI(model=\"gpt-4o-mini\", temperature=0)\n",
|
||||
"structured_llm_router = llm.with_structured_output(RouteQuery)\n",
|
||||
"\n",
|
||||
"# Prompt\n",
|
||||
@@ -235,7 +235,7 @@
|
||||
"\n",
|
||||
"\n",
|
||||
"# LLM with function call\n",
|
||||
"llm = ChatOpenAI(model=\"gpt-3.5-turbo-0125\", temperature=0)\n",
|
||||
"llm = ChatOpenAI(model=\"gpt-4o-mini\", temperature=0)\n",
|
||||
"structured_llm_grader = llm.with_structured_output(GradeDocuments)\n",
|
||||
"\n",
|
||||
"# Prompt\n",
|
||||
@@ -328,7 +328,7 @@
|
||||
"\n",
|
||||
"\n",
|
||||
"# LLM with function call\n",
|
||||
"llm = ChatOpenAI(model=\"gpt-3.5-turbo-0125\", temperature=0)\n",
|
||||
"llm = ChatOpenAI(model=\"gpt-4o-mini\", temperature=0)\n",
|
||||
"structured_llm_grader = llm.with_structured_output(GradeHallucinations)\n",
|
||||
"\n",
|
||||
"# Prompt\n",
|
||||
@@ -376,7 +376,7 @@
|
||||
"\n",
|
||||
"\n",
|
||||
"# LLM with function call\n",
|
||||
"llm = ChatOpenAI(model=\"gpt-3.5-turbo-0125\", temperature=0)\n",
|
||||
"llm = ChatOpenAI(model=\"gpt-4o-mini\", temperature=0)\n",
|
||||
"structured_llm_grader = llm.with_structured_output(GradeAnswer)\n",
|
||||
"\n",
|
||||
"# Prompt\n",
|
||||
|
||||
@@ -200,11 +200,11 @@
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"********************Prompt[rlm/rag-prompt]********************\n",
|
||||
"================================\u001b[1m Human Message \u001b[0m=================================\n",
|
||||
"================================\u001B[1m Human Message \u001B[0m=================================\n",
|
||||
"\n",
|
||||
"You are an assistant for question-answering tasks. Use the following pieces of retrieved context to answer the question. If you don't know the answer, just say that you don't know. Use three sentences maximum and keep the answer concise.\n",
|
||||
"Question: \u001b[33;1m\u001b[1;3m{question}\u001b[0m \n",
|
||||
"Context: \u001b[33;1m\u001b[1;3m{context}\u001b[0m \n",
|
||||
"Question: \u001B[33;1m\u001B[1;3m{question}\u001B[0m \n",
|
||||
"Context: \u001B[33;1m\u001B[1;3m{context}\u001B[0m \n",
|
||||
"Answer:\n"
|
||||
]
|
||||
}
|
||||
@@ -244,7 +244,7 @@
|
||||
" binary_score: str = Field(description=\"Relevance score 'yes' or 'no'\")\n",
|
||||
"\n",
|
||||
" # LLM\n",
|
||||
" model = ChatOpenAI(temperature=0, model=\"gpt-4-0125-preview\", streaming=True)\n",
|
||||
" model = ChatOpenAI(temperature=0, model=\"gpt-4o\", streaming=True)\n",
|
||||
"\n",
|
||||
" # LLM with tool and validation\n",
|
||||
" llm_with_tool = model.with_structured_output(grade)\n",
|
||||
|
||||
@@ -171,7 +171,7 @@
|
||||
"\n",
|
||||
"\n",
|
||||
"# LLM with function call\n",
|
||||
"llm = ChatOpenAI(model=\"gpt-3.5-turbo-0125\", temperature=0)\n",
|
||||
"llm = ChatOpenAI(model=\"gpt-4o-mini\", temperature=0)\n",
|
||||
"structured_llm_grader = llm.with_structured_output(GradeDocuments)\n",
|
||||
"\n",
|
||||
"# Prompt\n",
|
||||
|
||||
@@ -191,7 +191,7 @@
|
||||
"\n",
|
||||
"\n",
|
||||
"# LLM with function call\n",
|
||||
"llm = ChatOpenAI(model=\"gpt-3.5-turbo-0125\", temperature=0)\n",
|
||||
"llm = ChatOpenAI(model=\"gpt-4o-mini\", temperature=0)\n",
|
||||
"structured_llm_grader = llm.with_structured_output(GradeDocuments)\n",
|
||||
"\n",
|
||||
"# Prompt\n",
|
||||
@@ -284,7 +284,7 @@
|
||||
"\n",
|
||||
"\n",
|
||||
"# LLM with function call\n",
|
||||
"llm = ChatOpenAI(model=\"gpt-3.5-turbo-0125\", temperature=0)\n",
|
||||
"llm = ChatOpenAI(model=\"gpt-4o-mini\", temperature=0)\n",
|
||||
"structured_llm_grader = llm.with_structured_output(GradeHallucinations)\n",
|
||||
"\n",
|
||||
"# Prompt\n",
|
||||
@@ -332,7 +332,7 @@
|
||||
"\n",
|
||||
"\n",
|
||||
"# LLM with function call\n",
|
||||
"llm = ChatOpenAI(model=\"gpt-3.5-turbo-0125\", temperature=0)\n",
|
||||
"llm = ChatOpenAI(model=\"gpt-4o-mini\", temperature=0)\n",
|
||||
"structured_llm_grader = llm.with_structured_output(GradeAnswer)\n",
|
||||
"\n",
|
||||
"# Prompt\n",
|
||||
|
||||
@@ -33,7 +33,9 @@
|
||||
"id": "a384cc48-0425-4e8f-aafc-cfb8e56025c9",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": ["%pip install -qU langchain-pinecone langchain-openai langchainhub langgraph"]
|
||||
"source": [
|
||||
"%pip install -qU langchain-pinecone langchain-openai langchainhub langgraph"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@@ -51,7 +53,9 @@
|
||||
"id": "ccc3dae5-1df6-48ca-af8a-50f0e6128876",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": ["import os\n\nos.environ[\"LANGCHAIN_TRACING_V2\"] = \"true\"\nos.environ[\"LANGCHAIN_ENDPOINT\"] = \"https://api.smith.langchain.com\"\nos.environ[\"LANGCHAIN_API_KEY\"] = \"<your-api-key>\""]
|
||||
"source": [
|
||||
"import os\n\nos.environ[\"LANGCHAIN_TRACING_V2\"] = \"true\"\nos.environ[\"LANGCHAIN_ENDPOINT\"] = \"https://api.smith.langchain.com\"\nos.environ[\"LANGCHAIN_API_KEY\"] = \"<your-api-key>\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -59,7 +63,9 @@
|
||||
"id": "88637820",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": ["import os\n\nos.environ[\"LANGCHAIN_PROJECT\"] = \"pinecone-devconnect\""]
|
||||
"source": [
|
||||
"import os\n\nos.environ[\"LANGCHAIN_PROJECT\"] = \"pinecone-devconnect\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@@ -77,7 +83,9 @@
|
||||
"id": "565a6d44-2c9f-4fff-b1ec-eea05df9350d",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": ["from langchain_openai import OpenAIEmbeddings\nfrom langchain_pinecone import PineconeVectorStore\n\n# use pinecone movies database\n\n# Add to vectorDB\nvectorstore = PineconeVectorStore(\n embedding=OpenAIEmbeddings(),\n index_name=\"sample-movies\",\n text_key=\"summary\",\n)\nretriever = vectorstore.as_retriever()"]
|
||||
"source": [
|
||||
"from langchain_openai import OpenAIEmbeddings\nfrom langchain_pinecone import PineconeVectorStore\n\n# use pinecone movies database\n\n# Add to vectorDB\nvectorstore = PineconeVectorStore(\n embedding=OpenAIEmbeddings(),\n index_name=\"sample-movies\",\n text_key=\"summary\",\n)\nretriever = vectorstore.as_retriever()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -104,7 +112,9 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": ["docs = retriever.invoke(\"James Cameron\")\nfor doc in docs:\n print(\"# \" + doc.metadata[\"title\"])\n print(doc.page_content)\n print()"]
|
||||
"source": [
|
||||
"docs = retriever.invoke(\"James Cameron\")\nfor doc in docs:\n print(\"# \" + doc.metadata[\"title\"])\n print(doc.page_content)\n print()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@@ -120,7 +130,32 @@
|
||||
"id": "1fafad21-60cc-483e-92a3-6a7edb1838e3",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": ["### Retrieval Grader\n\nfrom langchain import hub\nfrom langchain_core.pydantic_v1 import BaseModel, Field\nfrom langchain_openai import ChatOpenAI\n\n\n# Data model\nclass GradeDocuments(BaseModel):\n \"\"\"Binary score for relevance check on retrieved documents.\"\"\"\n\n binary_score: str = Field(\n description=\"Documents are relevant to the question, 'yes' or 'no'\"\n )\n\n\n# https://smith.langchain.com/hub/efriis/self-rag-retrieval-grader\ngrade_prompt = hub.pull(\"efriis/self-rag-retrieval-grader\")\n\n# LLM with function call\nllm = ChatOpenAI(model=\"gpt-3.5-turbo-0125\", temperature=0)\nstructured_llm_grader = llm.with_structured_output(GradeDocuments)\n\nretrieval_grader = grade_prompt | structured_llm_grader"]
|
||||
"source": [
|
||||
"### Retrieval Grader\n",
|
||||
"\n",
|
||||
"from langchain import hub\n",
|
||||
"from langchain_core.pydantic_v1 import BaseModel, Field\n",
|
||||
"from langchain_openai import ChatOpenAI\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Data model\n",
|
||||
"class GradeDocuments(BaseModel):\n",
|
||||
" \"\"\"Binary score for relevance check on retrieved documents.\"\"\"\n",
|
||||
"\n",
|
||||
" binary_score: str = Field(\n",
|
||||
" description=\"Documents are relevant to the question, 'yes' or 'no'\"\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# https://smith.langchain.com/hub/efriis/self-rag-retrieval-grader\n",
|
||||
"grade_prompt = hub.pull(\"efriis/self-rag-retrieval-grader\")\n",
|
||||
"\n",
|
||||
"# LLM with function call\n",
|
||||
"llm = ChatOpenAI(model=\"gpt-4o-mini\", temperature=0)\n",
|
||||
"structured_llm_grader = llm.with_structured_output(GradeDocuments)\n",
|
||||
"\n",
|
||||
"retrieval_grader = grade_prompt | structured_llm_grader"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -137,7 +172,9 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": ["# Test the retrieval grader\nquestion = \"movies starring jason momoa\"\ndocs = retriever.invoke(question)\ndoc_txt = docs[0].page_content\nprint(doc_txt)\nprint(retrieval_grader.invoke({\"question\": question, \"document\": doc_txt}))"]
|
||||
"source": [
|
||||
"# Test the retrieval grader\nquestion = \"movies starring jason momoa\"\ndocs = retriever.invoke(question)\ndoc_txt = docs[0].page_content\nprint(doc_txt)\nprint(retrieval_grader.invoke({\"question\": question, \"document\": doc_txt}))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@@ -163,7 +200,9 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": ["### Generate\n\nfrom langchain import hub\nfrom langchain_core.output_parsers import StrOutputParser\n\n# Prompt\nprompt = hub.pull(\"rlm/rag-prompt\")\n\n# LLM\nllm = ChatOpenAI(model_name=\"gpt-3.5-turbo\", temperature=0)\n\n# Chain\nrag_chain = prompt | llm | StrOutputParser()\n\n# Run\ngeneration = rag_chain.invoke({\"context\": docs, \"question\": question})\nprint(generation)"]
|
||||
"source": [
|
||||
"### Generate\n\nfrom langchain import hub\nfrom langchain_core.output_parsers import StrOutputParser\n\n# Prompt\nprompt = hub.pull(\"rlm/rag-prompt\")\n\n# LLM\nllm = ChatOpenAI(model_name=\"gpt-3.5-turbo\", temperature=0)\n\n# Chain\nrag_chain = prompt | llm | StrOutputParser()\n\n# Run\ngeneration = rag_chain.invoke({\"context\": docs, \"question\": question})\nprint(generation)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -189,7 +228,30 @@
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": ["### Hallucination Grader\n\n\n# Data model\nclass GradeHallucinations(BaseModel):\n \"\"\"Binary score for hallucination present in generation answer.\"\"\"\n\n binary_score: str = Field(\n description=\"Answer is grounded in the facts, 'yes' or 'no'\"\n )\n\n\n# LLM with function call\nllm = ChatOpenAI(model=\"gpt-3.5-turbo-0125\", temperature=0)\nstructured_llm_grader = llm.with_structured_output(GradeHallucinations)\n\n# https://smith.langchain.com/hub/efriis/self-rag-hallucination-grader\nhallucination_prompt = hub.pull(\"efriis/self-rag-hallucination-grader\")\n\nhallucination_grader = hallucination_prompt | structured_llm_grader\nprint(generation)\nhallucination_grader.invoke({\"documents\": docs, \"generation\": generation})"]
|
||||
"source": [
|
||||
"### Hallucination Grader\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Data model\n",
|
||||
"class GradeHallucinations(BaseModel):\n",
|
||||
" \"\"\"Binary score for hallucination present in generation answer.\"\"\"\n",
|
||||
"\n",
|
||||
" binary_score: str = Field(\n",
|
||||
" description=\"Answer is grounded in the facts, 'yes' or 'no'\"\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# LLM with function call\n",
|
||||
"llm = ChatOpenAI(model=\"gpt-4o-mini\", temperature=0)\n",
|
||||
"structured_llm_grader = llm.with_structured_output(GradeHallucinations)\n",
|
||||
"\n",
|
||||
"# https://smith.langchain.com/hub/efriis/self-rag-hallucination-grader\n",
|
||||
"hallucination_prompt = hub.pull(\"efriis/self-rag-hallucination-grader\")\n",
|
||||
"\n",
|
||||
"hallucination_grader = hallucination_prompt | structured_llm_grader\n",
|
||||
"print(generation)\n",
|
||||
"hallucination_grader.invoke({\"documents\": docs, \"generation\": generation})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -216,7 +278,31 @@
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": ["### Answer Grader\n\n\n# Data model\nclass GradeAnswer(BaseModel):\n \"\"\"Binary score to assess answer addresses question.\"\"\"\n\n binary_score: str = Field(\n description=\"Answer addresses the question, 'yes' or 'no'\"\n )\n\n\n# LLM with function call\nllm = ChatOpenAI(model=\"gpt-3.5-turbo-0125\", temperature=0)\nstructured_llm_grader = llm.with_structured_output(GradeAnswer)\n\n# Prompt\nanswer_prompt = hub.pull(\"efriis/self-rag-answer-grader\")\n\nanswer_grader = answer_prompt | structured_llm_grader\nprint(question)\nprint(generation)\nanswer_grader.invoke({\"question\": question, \"generation\": generation})"]
|
||||
"source": [
|
||||
"### Answer Grader\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Data model\n",
|
||||
"class GradeAnswer(BaseModel):\n",
|
||||
" \"\"\"Binary score to assess answer addresses question.\"\"\"\n",
|
||||
"\n",
|
||||
" binary_score: str = Field(\n",
|
||||
" description=\"Answer addresses the question, 'yes' or 'no'\"\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# LLM with function call\n",
|
||||
"llm = ChatOpenAI(model=\"gpt-4o-mini\", temperature=0)\n",
|
||||
"structured_llm_grader = llm.with_structured_output(GradeAnswer)\n",
|
||||
"\n",
|
||||
"# Prompt\n",
|
||||
"answer_prompt = hub.pull(\"efriis/self-rag-answer-grader\")\n",
|
||||
"\n",
|
||||
"answer_grader = answer_prompt | structured_llm_grader\n",
|
||||
"print(question)\n",
|
||||
"print(generation)\n",
|
||||
"answer_grader.invoke({\"question\": question, \"generation\": generation})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -242,7 +328,9 @@
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": ["### Question Re-writer\n\n# LLM\nllm = ChatOpenAI(model=\"gpt-3.5-turbo-0125\", temperature=0)\n\n# Prompt\nre_write_prompt = hub.pull(\"efriis/self-rag-question-rewriter\")\n\nquestion_rewriter = re_write_prompt | llm | StrOutputParser()\nprint(question)\nquestion_rewriter.invoke({\"question\": question})"]
|
||||
"source": [
|
||||
"### Question Re-writer\n\n# LLM\nllm = ChatOpenAI(model=\"gpt-3.5-turbo-0125\", temperature=0)\n\n# Prompt\nre_write_prompt = hub.pull(\"efriis/self-rag-question-rewriter\")\n\nquestion_rewriter = re_write_prompt | llm | StrOutputParser()\nprint(question)\nquestion_rewriter.invoke({\"question\": question})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@@ -262,7 +350,9 @@
|
||||
"id": "f1617e9e-66a8-4c1a-a1fe-cc936284c085",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": ["from typing import List\n\nfrom typing_extensions import TypedDict\n\n\nclass GraphState(TypedDict):\n \"\"\"\n Represents the state of our graph.\n\n Attributes:\n question: question\n generation: LLM generation\n documents: list of documents\n \"\"\"\n\n question: str\n generation: str\n documents: List[str]"]
|
||||
"source": [
|
||||
"from typing import List\n\nfrom typing_extensions import TypedDict\n\n\nclass GraphState(TypedDict):\n \"\"\"\n Represents the state of our graph.\n\n Attributes:\n question: question\n generation: LLM generation\n documents: list of documents\n \"\"\"\n\n question: str\n generation: str\n documents: List[str]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -270,7 +360,9 @@
|
||||
"id": "add509d8-6682-4127-8d95-13dd37d79702",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": ["### Nodes\n\n\ndef retrieve(state):\n \"\"\"\n Retrieve documents\n\n Args:\n state (dict): The current graph state\n\n Returns:\n state (dict): New key added to state, documents, that contains retrieved documents\n \"\"\"\n print(\"---RETRIEVE---\")\n question = state[\"question\"]\n\n # Retrieval\n documents = retriever.invoke(question)\n return {\"documents\": documents, \"question\": question}\n\n\ndef generate(state):\n \"\"\"\n Generate answer\n\n Args:\n state (dict): The current graph state\n\n Returns:\n state (dict): New key added to state, generation, that contains LLM generation\n \"\"\"\n print(\"---GENERATE---\")\n question = state[\"question\"]\n documents = state[\"documents\"]\n\n # RAG generation\n generation = rag_chain.invoke({\"context\": documents, \"question\": question})\n return {\"documents\": documents, \"question\": question, \"generation\": generation}\n\n\ndef grade_documents(state):\n \"\"\"\n Determines whether the retrieved documents are relevant to the question.\n\n Args:\n state (dict): The current graph state\n\n Returns:\n state (dict): Updates documents key with only filtered relevant documents\n \"\"\"\n\n print(\"---CHECK DOCUMENT RELEVANCE TO QUESTION---\")\n question = state[\"question\"]\n documents = state[\"documents\"]\n\n # Score each doc\n filtered_docs = []\n for d in documents:\n score = retrieval_grader.invoke(\n {\"question\": question, \"document\": d.page_content}\n )\n grade = score.binary_score\n if grade == \"yes\":\n print(\"---GRADE: DOCUMENT RELEVANT---\")\n filtered_docs.append(d)\n else:\n print(\"---GRADE: DOCUMENT NOT RELEVANT---\")\n continue\n return {\"documents\": filtered_docs, \"question\": question}\n\n\ndef transform_query(state):\n \"\"\"\n Transform the query to produce a better question.\n\n Args:\n state (dict): The current graph state\n\n Returns:\n state (dict): Updates question key with a re-phrased question\n \"\"\"\n\n print(\"---TRANSFORM QUERY---\")\n question = state[\"question\"]\n documents = state[\"documents\"]\n\n # Re-write question\n better_question = question_rewriter.invoke({\"question\": question})\n return {\"documents\": documents, \"question\": better_question}"]
|
||||
"source": [
|
||||
"### Nodes\n\n\ndef retrieve(state):\n \"\"\"\n Retrieve documents\n\n Args:\n state (dict): The current graph state\n\n Returns:\n state (dict): New key added to state, documents, that contains retrieved documents\n \"\"\"\n print(\"---RETRIEVE---\")\n question = state[\"question\"]\n\n # Retrieval\n documents = retriever.invoke(question)\n return {\"documents\": documents, \"question\": question}\n\n\ndef generate(state):\n \"\"\"\n Generate answer\n\n Args:\n state (dict): The current graph state\n\n Returns:\n state (dict): New key added to state, generation, that contains LLM generation\n \"\"\"\n print(\"---GENERATE---\")\n question = state[\"question\"]\n documents = state[\"documents\"]\n\n # RAG generation\n generation = rag_chain.invoke({\"context\": documents, \"question\": question})\n return {\"documents\": documents, \"question\": question, \"generation\": generation}\n\n\ndef grade_documents(state):\n \"\"\"\n Determines whether the retrieved documents are relevant to the question.\n\n Args:\n state (dict): The current graph state\n\n Returns:\n state (dict): Updates documents key with only filtered relevant documents\n \"\"\"\n\n print(\"---CHECK DOCUMENT RELEVANCE TO QUESTION---\")\n question = state[\"question\"]\n documents = state[\"documents\"]\n\n # Score each doc\n filtered_docs = []\n for d in documents:\n score = retrieval_grader.invoke(\n {\"question\": question, \"document\": d.page_content}\n )\n grade = score.binary_score\n if grade == \"yes\":\n print(\"---GRADE: DOCUMENT RELEVANT---\")\n filtered_docs.append(d)\n else:\n print(\"---GRADE: DOCUMENT NOT RELEVANT---\")\n continue\n return {\"documents\": filtered_docs, \"question\": question}\n\n\ndef transform_query(state):\n \"\"\"\n Transform the query to produce a better question.\n\n Args:\n state (dict): The current graph state\n\n Returns:\n state (dict): Updates question key with a re-phrased question\n \"\"\"\n\n print(\"---TRANSFORM QUERY---\")\n question = state[\"question\"]\n documents = state[\"documents\"]\n\n # Re-write question\n better_question = question_rewriter.invoke({\"question\": question})\n return {\"documents\": documents, \"question\": better_question}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -278,7 +370,9 @@
|
||||
"id": "09fc91b4",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": ["### Edges\n\n\ndef decide_to_generate(state):\n \"\"\"\n Determines whether to generate an answer, or re-generate a question.\n\n Args:\n state (dict): The current graph state\n\n Returns:\n str: Binary decision for next node to call\n \"\"\"\n\n print(\"---ASSESS GRADED DOCUMENTS---\")\n state[\"question\"]\n filtered_documents = state[\"documents\"]\n\n if not filtered_documents:\n # All documents have been filtered check_relevance\n # We will re-generate a new query\n print(\n \"---DECISION: ALL DOCUMENTS ARE NOT RELEVANT TO QUESTION, TRANSFORM QUERY---\"\n )\n return \"transform_query\"\n else:\n # We have relevant documents, so generate answer\n print(\"---DECISION: GENERATE---\")\n return \"generate\"\n\n\ndef grade_generation_v_documents_and_question(state):\n \"\"\"\n Determines whether the generation is grounded in the document and answers question.\n\n Args:\n state (dict): The current graph state\n\n Returns:\n str: Decision for next node to call\n \"\"\"\n\n print(\"---CHECK HALLUCINATIONS---\")\n question = state[\"question\"]\n documents = state[\"documents\"]\n generation = state[\"generation\"]\n\n score = hallucination_grader.invoke(\n {\"documents\": documents, \"generation\": generation}\n )\n grade = score.binary_score\n\n # Check hallucination\n if grade == \"yes\":\n print(\"---DECISION: GENERATION IS GROUNDED IN DOCUMENTS---\")\n # Check question-answering\n print(\"---GRADE GENERATION vs QUESTION---\")\n score = answer_grader.invoke({\"question\": question, \"generation\": generation})\n grade = score.binary_score\n if grade == \"yes\":\n print(\"---DECISION: GENERATION ADDRESSES QUESTION---\")\n return \"useful\"\n else:\n print(\"---DECISION: GENERATION DOES NOT ADDRESS QUESTION---\")\n return \"not useful\"\n else:\n pprint(\"---DECISION: GENERATION IS NOT GROUNDED IN DOCUMENTS, RE-TRY---\")\n return \"not supported\""]
|
||||
"source": [
|
||||
"### Edges\n\n\ndef decide_to_generate(state):\n \"\"\"\n Determines whether to generate an answer, or re-generate a question.\n\n Args:\n state (dict): The current graph state\n\n Returns:\n str: Binary decision for next node to call\n \"\"\"\n\n print(\"---ASSESS GRADED DOCUMENTS---\")\n state[\"question\"]\n filtered_documents = state[\"documents\"]\n\n if not filtered_documents:\n # All documents have been filtered check_relevance\n # We will re-generate a new query\n print(\n \"---DECISION: ALL DOCUMENTS ARE NOT RELEVANT TO QUESTION, TRANSFORM QUERY---\"\n )\n return \"transform_query\"\n else:\n # We have relevant documents, so generate answer\n print(\"---DECISION: GENERATE---\")\n return \"generate\"\n\n\ndef grade_generation_v_documents_and_question(state):\n \"\"\"\n Determines whether the generation is grounded in the document and answers question.\n\n Args:\n state (dict): The current graph state\n\n Returns:\n str: Decision for next node to call\n \"\"\"\n\n print(\"---CHECK HALLUCINATIONS---\")\n question = state[\"question\"]\n documents = state[\"documents\"]\n generation = state[\"generation\"]\n\n score = hallucination_grader.invoke(\n {\"documents\": documents, \"generation\": generation}\n )\n grade = score.binary_score\n\n # Check hallucination\n if grade == \"yes\":\n print(\"---DECISION: GENERATION IS GROUNDED IN DOCUMENTS---\")\n # Check question-answering\n print(\"---GRADE GENERATION vs QUESTION---\")\n score = answer_grader.invoke({\"question\": question, \"generation\": generation})\n grade = score.binary_score\n if grade == \"yes\":\n print(\"---DECISION: GENERATION ADDRESSES QUESTION---\")\n return \"useful\"\n else:\n print(\"---DECISION: GENERATION DOES NOT ADDRESS QUESTION---\")\n return \"not useful\"\n else:\n pprint(\"---DECISION: GENERATION IS NOT GROUNDED IN DOCUMENTS, RE-TRY---\")\n return \"not supported\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@@ -331,7 +425,9 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": ["from pprint import pprint\n\n# Run\ninputs = {\"question\": \"Movies that star Daniel Craig\"}\nfor output in app.stream(inputs):\n for key, value in output.items():\n # Node\n pprint(f\"Node '{key}':\")\n pprint(\"\\n---\\n\")\n\n# Final generation\npprint(value[\"generation\"])"]
|
||||
"source": [
|
||||
"from pprint import pprint\n\n# Run\ninputs = {\"question\": \"Movies that star Daniel Craig\"}\nfor output in app.stream(inputs):\n for key, value in output.items():\n # Node\n pprint(f\"Node '{key}':\")\n pprint(\"\\n---\\n\")\n\n# Final generation\npprint(value[\"generation\"])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -339,7 +435,9 @@
|
||||
"id": "4138bc51-8c84-4b8a-8d24-f7f470721f6f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": ["inputs = {\"question\": \"Which movies are about aliens?\"}\nfor output in app.stream(inputs):\n for key, value in output.items():\n # Node\n pprint(f\"Node '{key}':\")\n pprint(\"\\n---\\n\")\n\n# Final generation\npprint(value[\"generation\"])"]
|
||||
"source": [
|
||||
"inputs = {\"question\": \"Which movies are about aliens?\"}\nfor output in app.stream(inputs):\n for key, value in output.items():\n # Node\n pprint(f\"Node '{key}':\")\n pprint(\"\\n---\\n\")\n\n# Final generation\npprint(value[\"generation\"])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -347,7 +445,9 @@
|
||||
"id": "42369ab8-322d-434a-b5dd-2266e4cb2903",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [""]
|
||||
"source": [
|
||||
""
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user