From feca5e19709f6c4c4ce8107f50131323a06ec935 Mon Sep 17 00:00:00 2001 From: William FH <13333726+hinthornw@users.noreply.github.com> Date: Wed, 26 Jun 2024 00:04:13 -0700 Subject: [PATCH] [Docs] Restore Linkcheck (#824) Plus: 1. Improve docstrings of add_node 2. Update crosslinking of sqlite and aiosqlite docstrings 3. Fix a bunch of links so we can turn on strict validation --- .github/workflows/link_check.yml | 47 ++-- docs/_scripts/copy_notebooks.py | 64 ++++- docs/docs/cloud/concepts/index.md | 44 ++-- docs/docs/cloud/deployment/cloud.md | 2 +- docs/docs/cloud/deployment/setup.md | 2 +- docs/docs/cloud/index.md | 4 +- docs/docs/concepts/agentic_concepts.md | 28 +-- docs/docs/concepts/high_level.md | 18 +- docs/docs/concepts/index.md | 84 +++---- docs/docs/concepts/low_level.md | 52 ++-- docs/mkdocs.yml | 223 +++++++++--------- examples/create-react-agent-hitl.ipynb | 2 +- examples/streaming-tokens.ipynb | 2 +- .../langgraph/checkpoint/aiosqlite.py | 6 +- libs/langgraph/langgraph/checkpoint/sqlite.py | 10 +- libs/langgraph/langgraph/graph/state.py | 47 +++- 16 files changed, 369 insertions(+), 266 deletions(-) diff --git a/.github/workflows/link_check.yml b/.github/workflows/link_check.yml index 34143b902..566ef6095 100644 --- a/.github/workflows/link_check.yml +++ b/.github/workflows/link_check.yml @@ -26,10 +26,10 @@ jobs: - name: Check links in Markdown files uses: gaurav-nelson/github-action-markdown-link-check@v1 with: - folder-path: 'examples/' + folder-path: "examples/" check-modified-files-only: ${{ github.event_name != 'schedule' }} - file-path: './README.md' - config-file: './.markdown-link-check.config.json' + file-path: "./README.md" + config-file: "./.markdown-link-check.config.json" notebook-link-check: runs-on: ubuntu-latest @@ -49,18 +49,29 @@ jobs: poetry install --with docs poetry run pip install -U pytest pytest-check-links langsmith langchain GitPython - # - name: Check links in notebooks - # env: - # LANGCHAIN_API_KEY: test - # run: | - # if [ "${{ github.event_name }}" != "schedule" ]; then - # git fetch origin main - # CHANGED_FILES=$(git diff --name-only origin/main | grep '\.ipynb$') - # if [ -n "$CHANGED_FILES" ]; then - # poetry run pytest -o python_files=non_python_only --check-links --check-links-ignore "https://(api|web)\.smith\.langchain\.com/.*" --check-links-ignore "https://x.com/.*" $CHANGED_FILES - # else - # echo "No notebook files changed." - # fi - # else - # poetry run pytest -o python_files=non_python_only --check-links --ignore="*.py" -k .ipynb --check-links-ignore "https://(api|web)\.smith\.langchain\.com/.*" --check-links-ignore "https://x.com/.*" ./examples - # fi + - name: Check links in notebooks + env: + LANGCHAIN_API_KEY: test + run: | + if [ "${{ github.event_name }}" == "schedule" ] || [ "${{ github.event_name }}" == "workflow_dispatch" ] || ([ "${{ github.event_name }}" == "push" ] && [ "${{ github.ref }}" == "refs/heads/main" ]); then + echo "Running link check on all notebooks in examples directory..." + poetry run pytest -v --check-links-ignore "https://(api|web)\.smith\.langchain\.com/.*" --check-links-ignore "https://x.com/.*" --check-links examples + else + echo "Fetching changes from origin/main..." + git fetch origin main + echo "Checking for changed notebook files..." + CHANGED_FILES=$(git diff --name-only origin/main | grep '\.ipynb$' || true) + echo "Changed files: ${CHANGED_FILES}" + if [ -n "${CHANGED_FILES}" ]; then + echo "Running link check on changed notebook files..." + poetry run pytest -v --check-links-ignore "https://(api|web)\.smith\.langchain\.com/.*" --check-links-ignore "https://x.com/.*" --check-links ${CHANGED_FILES} + PYTEST_EXIT_CODE=$? + echo "pytest exit code: ${PYTEST_EXIT_CODE}" + if [ ${PYTEST_EXIT_CODE} -ne 0 ]; then + echo "pytest failed with exit code ${PYTEST_EXIT_CODE}" + exit ${PYTEST_EXIT_CODE} + fi + else + echo "No notebook files changed." + fi + fi diff --git a/docs/_scripts/copy_notebooks.py b/docs/_scripts/copy_notebooks.py index 0af25ab33..0cda02595 100644 --- a/docs/_scripts/copy_notebooks.py +++ b/docs/_scripts/copy_notebooks.py @@ -1,4 +1,6 @@ +import json import os +import re import shutil from pathlib import Path @@ -77,6 +79,20 @@ _HIDE = set( "rag/langgraph_rag_agent_llama3_local.ipynb", "rag/langgraph_self_rag_pinecone_movies.ipynb", "rag/langgraph_adaptive_rag_cohere.ipynb", + "dynamically-returning-directly.ipynb", + "force-calling-a-tool-first.ipynb", + "managing-agent-steps.ipynb", + "pass-run-time-values-to-tools.ipynb", + "respond-in-format.ipynb", + "quickstart.ipynb", + "human-in-the-loop.ipynb", + "learning.ipynb", + "managing-conversation-history.ipynb", + "docs/quickstart.ipynb", + "tutorials/rag-agent-testing.ipynb", + "state-context-key.ipynb", + "time-travel.ipynb", + "code_assistant/langgraph_code_assistant_mistral.ipynb", ] ) @@ -98,6 +114,44 @@ def clean_notebooks(): os.rmdir(root) +def update_notebook_links(notebook_path): + with open(notebook_path, "r", encoding="utf-8") as f: + notebook = json.load(f) + + for cell in notebook["cells"]: + if cell["cell_type"] == "markdown": + for i, source in enumerate(cell["source"]): + # Update relative notebook links + cell["source"][i] = re.sub( + r"\[([^\]]+)\]\(([^:)]+\.ipynb)\)", + lambda m: transform_link(m.group(1), m.group(2)), + source, + ) + + with open(notebook_path, "w", encoding="utf-8") as f: + json.dump(notebook, f, indent=2) + + +def transform_link(text, link): + dir_path, filename = os.path.split(link) + + # Remove the .ipynb extension + filename_without_ext = os.path.splitext(filename)[0] + + # If it's a local link (starts with ./) + if link.startswith("./"): + # Change to parent directory and remove ./ prefix + new_link = f"../{filename_without_ext}/" + elif dir_path: + # If there's a directory path, keep it and add one more level up + new_link = f"../{dir_path}/{filename_without_ext}/" + else: + # If it's just a filename, simply go one level up + new_link = f"../{filename_without_ext}/" + + return f"[{text}]({new_link})" + + def copy_notebooks(): # Nested ones are mostly tutorials rn for root, dirs, files in os.walk(examples_dir): @@ -148,17 +202,9 @@ def copy_notebooks(): content = content.replace('src=\\"./img/', 'src=\\"../img/') with open(dst_path, "w") as f: f.write(content) + update_notebook_links(dst_path) dst_dir = dst_dir_ - # Top level notebooks are "how-to's" - # for file in examples_dir.iterdir(): - # if file.suffix.endswith(".ipynb") and not os.path.isdir( - # os.path.join(examples_dir, file) - # ): - # src_path = os.path.join(examples_dir, file) - # dst_path = os.path.join(docs_dir, "how-tos", file.name) - # shutil.copy(src_path, dst_path) - if __name__ == "__main__": clean_notebooks() diff --git a/docs/docs/cloud/concepts/index.md b/docs/docs/cloud/concepts/index.md index d1b771bdc..7588d3856 100644 --- a/docs/docs/cloud/concepts/index.md +++ b/docs/docs/cloud/concepts/index.md @@ -1,16 +1,20 @@ # API Concepts + This page describes the high-level concepts of the LangGraph Cloud API. The conceptual guide of LangGraph (Python library) is [here](../../concepts/index.md). ## Data Models + The LangGraph Cloud API consists of a few core data models: [Assistants](#assistants), [Threads](#threads), [Runs](#runs), and [Cron Jobs](#cron-jobs). ### Assistants -An assistant is a configured instance of a [`CompiledGraph`](../../../reference/graphs/#compiledgraph). It abstracts the cognitive architecture of the graph and contains instance specific configuration and metadata. Multiple assistants can reference the same graph but can contain different configuration and metadata, which may differentiate the behavior of the assistants. An assistant (i.e. the graph) is invoked as part of a run. + +An assistant is a configured instance of a [`CompiledGraph`][compiledgraph]. It abstracts the cognitive architecture of the graph and contains instance specific configuration and metadata. Multiple assistants can reference the same graph but can contain different configuration and metadata, which may differentiate the behavior of the assistants. An assistant (i.e. the graph) is invoked as part of a run. The LangGraph Cloud API provides several endpoints for creating and managing assistants. See the API reference for more details. ### Threads -A thread contains the accumulated state of a group of runs. If a run is executed on a thread, then the [state](../../../concepts/#persistence) of the underlying graph of the assistant will be persisted to the thread. A thread's current and historical state can be retrieved. To persist state, a thread must be created prior to executing a run. + +A thread contains the accumulated state of a group of runs. If a run is executed on a thread, then the [state][state] of the underlying graph of the assistant will be persisted to the thread. A thread's current and historical state can be retrieved. To persist state, a thread must be created prior to executing a run. The state of a thread at a particular point in time is called a checkpoint. @@ -19,6 +23,7 @@ For more on threads and checkpoints, see this section of the [LangGraph conceptu The LangGraph Cloud API provides several endpoints for creating and managing threads and thread state. See the API reference for more details. ### Runs + 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. The LangGraph Cloud API provides several endpoints for creating and managing runs. See the API reference for more details. @@ -30,36 +35,40 @@ It's often useful to run graphs on some schedule. LangGraph Cloud supports cron - Create a new thread with the specified assistant - Send the specified input to that thread -Note that this sends the same input to the thread every time. See the [How-to Guide](../how-tos/cloud_examples/cron_jobs/) for creating cron jobs. +Note that this sends the same input to the thread every time. See the [how-to guide](../how-tos/cloud_examples/cron_jobs.ipynb) for creating cron jobs. The LangGraph Cloud API provides several endpoints for creating and managing cron jobs. See the API reference for more details. ## Features + The LangGraph Cloud API offers several features to support complex agent architectures. ### Streaming -Streaming is critical for making LLM applications feel responsive to end users. When creating a streaming run, the streaming mode determines what data is streamed back to the API client. The LangGraph Cloud API supports five streaming modes. -- `values`: Stream the full state of the graph after each node is executed. See the [How-to Guide](../how-tos/cloud_examples/stream_values/) for streaming values. -- `messages`: Stream complete messages (at the end of node execution) as well as tokens for any messages generated inside a node. This mode is primarily meant for powering chat applications. This is only an option if your graph contains a `messages` key. See the [How-to Guide](../how-tos/cloud_examples/stream_messages/) for streaming messages. -- `updates`: Streams updates to the state of the graph after each node is executed. See the [How-to Guide](../how-tos/cloud_examples/stream_updates/) for streaming updates. -- `events`: Stream all events (including the state of the graph) after each node is executed. See the [How-to Guide](../how-tos/cloud_examples/stream_events/) for streaming events. This can be used to do token-by-token streaming for LLMs. -- `debug`: Stream debug events after each node is executed. See the [How-to Guide](../how-tos/cloud_examples/stream_debug/) for streaming debug events. +Streaming is critical for making LLM applications feel responsive to end users. When creating a streaming run, the streaming mode determines what data is streamed back to the API client. The LangGraph Cloud API supports five streaming modes. -You can also specify multiple streaming modes at the same time. See the [How-to Guide](../how-tos/cloud_examples/stream_multiple/) for configuring multiple streaming modes at the same time. +- `values`: Stream the full state of the graph after each node is executed. See the [how-to guide](../how-tos/cloud_examples/stream_values.ipynb) for streaming values. +- `messages`: Stream complete messages (at the end of node execution) as well as tokens for any messages generated inside a node. This mode is primarily meant for powering chat applications. This is only an option if your graph contains a `messages` key. See the [how-to guide](../how-tos/cloud_examples/stream_messages.ipynb) for streaming messages. +- `updates`: Streams updates to the state of the graph after each node is executed. See the [how-to guide](../how-tos/cloud_examples/stream_updates.ipynb) for streaming updates. +- `events`: Stream all events (including the state of the graph) after each node is executed. See the [how-to guide](../how-tos/cloud_examples/stream_events.ipynb) for streaming events. This can be used to do token-by-token streaming for LLMs. +- `debug`: Stream debug events after each node is executed. See the [how-to guide](../how-tos/cloud_examples/stream_debug.ipynb) for streaming debug events. + +You can also specify multiple streaming modes at the same time. See the [how-to guide](../how-tos/cloud_examples/stream_multiple.ipynb) for configuring multiple streaming modes at the same time. See the API reference for how to create streaming runs. ### Human-in-the-Loop -There are many occasions where the graph cannot run completely autonomously. For instance, the user might need to input some additional arguments to a function call, or select the next edge for the graph to continue on. In these instances, we need to insert some human in the loop interaction, which you can learn about in the [human in the loop how-tos](../how-tos/cloud_examples/human_in_the_loop_breakpoint). + +There are many occasions where the graph cannot run completely autonomously. For instance, the user might need to input some additional arguments to a function call, or select the next edge for the graph to continue on. In these instances, we need to insert some human in the loop interaction, which you can learn about in the [human in the loop how-tos](../how-tos/cloud_examples/human_in_the_loop_breakpoint.ipynb). ### Double Texting -Many times users might interact with your graph in unintended ways. For instance, a user may send one message and before the graph has finished running send a second message. To solve this issue of "double-texting" (i.e. prompting the graph a second time before the first run has finished), Langgraph has provided four different solutions, all of which are covered in the [Double Texting how-tos](../how-tos/cloud_examples/interrupt_concurrent/). These options are: -- `reject`: This is the simplest option, this just rejects any follow up runs and does not allow double texting. See the [How-to Guide](../how-tos/cloud_examples/reject_concurrent/) for configuring the reject double text option. -- `enqueue`: This is a relatively simple option which continues the first run until it completes the whole run, then sends the new input as a separate run. See the [How-to Guide](../how-tos/cloud_examples/enqueue_concurrent/) for configuring the enqueue double text option. -- `interrupt`: This option interrupts the current execution but saves all the work done up until that point. It then inserts the user input and continues from there. If you enable this option, your graph should be able to handle weird edge cases that may arise. See the [How-to Guide](../how-tos/cloud_examples/interrupt_concurrent/) for configuring the interrupt double text option. -- `rollback`: This option rolls back all work done up until that point. It then sends the user input in, basically as if it just followed the original run input. See the [How-to Guide](../how-tos/cloud_examples/rollback_concurrent/) for configuring the rollback double text option. +Many times users might interact with your graph in unintended ways. For instance, a user may send one message and before the graph has finished running send a second message. To solve this issue of "double-texting" (i.e. prompting the graph a second time before the first run has finished), Langgraph has provided four different solutions, all of which are covered in the [Double Texting how-tos](../how-tos/cloud_examples/interrupt_concurrent.ipynb). These options are: + +- `reject`: This is the simplest option, this just rejects any follow up runs and does not allow double texting. See the [how-to guide](../how-tos/cloud_examples/reject_concurrent.ipynb) for configuring the reject double text option. +- `enqueue`: This is a relatively simple option which continues the first run until it completes the whole run, then sends the new input as a separate run. See the [how-to guide](../how-tos/cloud_examples/enqueue_concurrent.ipynb) for configuring the enqueue double text option. +- `interrupt`: This option interrupts the current execution but saves all the work done up until that point. It then inserts the user input and continues from there. If you enable this option, your graph should be able to handle weird edge cases that may arise. See the [how-to guide](../how-tos/cloud_examples/interrupt_concurrent.ipynb) for configuring the interrupt double text option. +- `rollback`: This option rolls back all work done up until that point. It then sends the user input in, basically as if it just followed the original run input. See the [how-to guide](../how-tos/cloud_examples/rollback_concurrent.ipynb) for configuring the rollback double text option. ### Stateless Runs @@ -73,10 +82,11 @@ All runs use the built-in checkpointer to store checkpoints for runs. However, i Stateless runs are still retried as regular retries are per node, while everything still in memory, so doesn't use checkpoints. The only difference is in stateless background runs, if the task worker dies halfway (not because the run itself failed, for some external reason) then the whole run will be retried like any background run, but + - whereas a stateful background run would retry from the last successful checkpoint - a stateless background run would retry from the beginning -See the [How-to Guide](../how-tos/cloud_examples/stateless_runs/) for creating stateless runs. +See the [how-to guide](../how-tos/cloud_examples/stateless_runs.ipynb) for creating stateless runs. ## Deployment diff --git a/docs/docs/cloud/deployment/cloud.md b/docs/docs/cloud/deployment/cloud.md index 0d136d04b..e448049fe 100644 --- a/docs/docs/cloud/deployment/cloud.md +++ b/docs/docs/cloud/deployment/cloud.md @@ -29,7 +29,7 @@ Starting from the LangSmi ## Create New Revision -When [creating a new deployment](#create-a-new-deployment), a new revision is created by default. Subsequent revisions can be created to deploy new code changes. +When [creating a new deployment](#create-new-deployment), a new revision is created by default. Subsequent revisions can be created to deploy new code changes. Starting from the LangSmith UI... diff --git a/docs/docs/cloud/deployment/setup.md b/docs/docs/cloud/deployment/setup.md index c76a5e3d9..7ec47e8bb 100644 --- a/docs/docs/cloud/deployment/setup.md +++ b/docs/docs/cloud/deployment/setup.md @@ -39,7 +39,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](../../../reference/graphs/#compiledgraph) to be included in the LangGraph application. The variable names will be used later when creating the [LangGraph API configuration file](../reference/cli.md#configuration-file). +Implement your graphs! Graphs can be defined in a single file or multiple files. Make note of the variable names of each [CompiledGraph][compiledgraph] to be included in the LangGraph application. The variable names will be used later when creating the [LangGraph API configuration file](../reference/cli.md#configuration-file). Example `openai_agent.py` file: ```python diff --git a/docs/docs/cloud/index.md b/docs/docs/cloud/index.md index d8592e929..0a28639bc 100644 --- a/docs/docs/cloud/index.md +++ b/docs/docs/cloud/index.md @@ -28,6 +28,6 @@ The LangGraph Cloud API supports key LangGraph features in addition to new funct ## Documentation - [Tutorials](./quick_start.md): Learn to build and deploy applications for LangGraph Cloud. -- [How-to Guides](./deployment/setup/): Learn how to set up a LangGraph application for deployment and implement features of the LangGraph Cloud API such as streaming tokens, configuring double texting, and creating cron jobs. Go here if you want to copy and run a specific code snippet. -- [Conceptual Guides](./concepts/): In-depth explanations of the core data models (e.g. assistants) and key features (e.g. double texting) of the LangGraph Cloud API. +- [How-to Guides](./deployment/setup.md): Learn how to set up a LangGraph application for deployment and implement features of the LangGraph Cloud API such as streaming tokens, configuring double texting, and creating cron jobs. Go here if you want to copy and run a specific code snippet. +- [Conceptual Guides](./concepts/index.md): In-depth explanations of the core data models (e.g. assistants) and key features (e.g. double texting) of the LangGraph Cloud API. - [Reference](./reference/api/api_ref.md): References for the LangGraph Cloud API, the corresponding Python and JS/TS SDKs, the LangGraph CLI, and deployment environment variables. diff --git a/docs/docs/concepts/agentic_concepts.md b/docs/docs/concepts/agentic_concepts.md index a6580528a..aca45192f 100644 --- a/docs/docs/concepts/agentic_concepts.md +++ b/docs/docs/concepts/agentic_concepts.md @@ -16,21 +16,21 @@ Since LangGraph nodes can be arbitrary Python functions, you can do this however Memory is a key concept to agentic applications. Memory is important because end users often expect the application they are interacting with remember previous interactions. The most simple example of this is chatbots - they clearly need to remember previous messages in a conversation. -LangGraph is perfectly suited to give you full control over the memory of your application. With user defined [`State`](#state) you can specify the exact schema of the memory you want to retain. With [checkpointers](#checkpointer) you can store checkpoints of previous interactions and resume from there in follow up interactions. +LangGraph is perfectly suited to give you full control over the memory of your application. With user defined [`State`](./low_level.md#state) you can specify the exact schema of the memory you want to retain. With [checkpointers](./low_level.md#checkpointer) you can store checkpoints of previous interactions and resume from there in follow up interactions. -See [this guide](/langgraph/how-tos/persistence/) for how to add memory to your graph. +See [this guide](../how-tos/persistence.ipynb) for how to add memory to your graph. ## Human-in-the-loop -Agentic systems often require some human-in-the-loop (or "on-the-loop") interaction patterns. This is because agentic systems are still not super reliable, so having a human involved is required for any sensitive tasks/actions. These are all easily enabled in LangGraph, largely due to [checkpointers](#checkpointer). The reason a checkpointer is necessary is that a lot of these interaction patterns involve running a graph up until a certain point, waiting for some sort of human feedback, and then continuing. When you want to "continue" you will need to access the state of the graph previous to getting interrupted, and checkpointers are a built in, highly convenient way to do that. +Agentic systems often require some human-in-the-loop (or "on-the-loop") interaction patterns. This is because agentic systems are still not super reliable, so having a human involved is required for any sensitive tasks/actions. These are all easily enabled in LangGraph, largely due to [checkpointers](./low_level.md#checkpointer). The reason a checkpointer is necessary is that a lot of these interaction patterns involve running a graph up until a certain point, waiting for some sort of human feedback, and then continuing. When you want to "continue" you will need to access the state of the graph previous to getting interrupted, and checkpointers are a built in, highly convenient way to do that. There are a few common human-in-the-loop interaction patterns we see emerging. ### Approval -A basic one is to have the agent wait for approval before executing certain tools. This may be all tools, or just a subset of tools. This is generally recommend for more sensitive actions (like writing to a database). This can easily be done in LangGraph by setting a [breakpoint](#breakpoints) before specific nodes. +A basic one is to have the agent wait for approval before executing certain tools. This may be all tools, or just a subset of tools. This is generally recommend for more sensitive actions (like writing to a database). This can easily be done in LangGraph by setting a [breakpoint](./low_level.md#breakpoints) before specific nodes. -See [this guide](/langgraph/how-tos/human_in_the_loop/breakpoints) for how do this in LangGraph. +See [this guide](../how-tos/human_in_the_loop/breakpoints.ipynb) for how do this in LangGraph. ### Wait for input @@ -42,29 +42,27 @@ A similar one is to have the agent wait for human input. This can be done by: 4. Update the state with that user input, acting as that node 5. Resume execution -See [this guide](/langgraph/how-tos/human_in_the_loop/wait-user-input) for how do this in LangGraph. - +See [this guide](../how-tos/human_in_the_loop/wait-user-input.ipynb) for how do this in LangGraph. ### Edit agent actions -This is a more advanced interaction pattern. In this interaction pattern the human can actually edit some of the agent's previous decisions. This can be done either during the flow (after a [breakpoint](#breakpoints), part of the [approval](#approval) flow) or after the fact (as part of [time-travel](#time-travel)) - -See [this guide](/langgraph/how-tos/human_in_the_loop/edit-graph-state) for how do this in LangGraph. +This is a more advanced interaction pattern. In this interaction pattern the human can actually edit some of the agent's previous decisions. This can be done either during the flow (after a [breakpoint](./low_level.md#breakpoints), part of the [approval](#approval) flow) or after the fact (as part of [time-travel](#time-travel)) +See [this guide](../how-tos/human_in_the_loop/edit-graph-state.ipynb) for how do this in LangGraph. ### Time travel This is a pretty advanced interaction pattern. In this interaction pattern, the human can look back at the list of previous checkpoints, find one they like, optionally [edit it](#edit-agent-actions), and then resume execution from there. -See [this guide](/langgraph/how-tos/human_in_the_loop/time-travel) for how to do this in LangGraph. +See [this guide](../how-tos/human_in_the_loop/time-travel.ipynb) for how to do this in LangGraph. ## Map-Reduce A common pattern in agents is to generate a list of objects, do some work on each of those objects, and then combine the results. This is very similar to the common [map-reduce](https://en.wikipedia.org/wiki/MapReduce) operation. This can be tricky for a few reasons. First, it can be tough to define a structured graph ahead of time because the length of the list of objects may be unknown. Second, in order to do this map-reduce you need multiple versions of the state to exist... but the graph shares a common shared state, so how can this be? -LangGraph supports this via the [Send](#send) api. This can be used to allow a conditional edge to Send multiple different states to multiple nodes. The state it sends can be different from the state of the core graph. +LangGraph supports this via the [Send](./low_level.md#send) api. This can be used to allow a conditional edge to Send multiple different states to multiple nodes. The state it sends can be different from the state of the core graph. -See a how-to guide for this [here](/langgraph/how-tos/map-reduce) +See a how-to guide for this [here](../how-tos/map-reduce.ipynb) ## Multi-agent @@ -88,7 +86,7 @@ This "reflection" step often uses an LLM, but doesn't have to. A good example of One of the most common agent architectures is what is commonly called the ReAct agent architecture. In this architecture, an LLM is called repeatedly in a while-loop. At each step the agent decides which tools to call, and what the inputs to those tools should be. Those tools are then executed, and the outputs are fed back into the LLM as observations. The while-loop terminates when the agent decides it is not worth calling any more tools. -One of the few high level, pre-built agents we have in LangGraph - you can use it with [`create_react_agent`](/langgraph/reference/prebuilt#create_react_agent) +One of the few high level, pre-built agents we have in LangGraph - you can use it with [`create_react_agent`](../reference/prebuilt.md#create_react_agent) This is named after and based on the [ReAct](https://arxiv.org/abs/2210.03629) paper. However, there are several differences between this paper and our implementation: @@ -98,4 +96,4 @@ This is named after and based on the [ReAct](https://arxiv.org/abs/2210.03629) p - Forth, the paper only looks at calling a single tool at the time, largely due to limitations in LLMs performance at the time. Our implementation allows for calling multiple tools at a time. - Finally, the paper asked the LLM to explicitly generate a "Thought" step before deciding which tools to call. This is the "Reasoning" part of "ReAct". Our implementation does not do this by default, largely because LLMs have gotten much better and that is not as necessary. Of course, if you wish to prompt it do so, you certainly can. -See [this guide](/langgraph/how-tos/human_in_the_loop/time-travel) for a full walkthrough of how to use the prebuilt ReAct agent. \ No newline at end of file +See [this guide](../how-tos/human_in_the_loop/time-travel.ipynb) for a full walkthrough of how to use the prebuilt ReAct agent. diff --git a/docs/docs/concepts/high_level.md b/docs/docs/concepts/high_level.md index 70c6e48e8..69d76f78f 100644 --- a/docs/docs/concepts/high_level.md +++ b/docs/docs/concepts/high_level.md @@ -17,18 +17,18 @@ If these decisions are being made in a loop, then its even more agentic! There are other concepts often associated with being agentic, but we would argue these are a by-product of the above definition: -- [Tool calling](/langgraph/concepts/agentic_concepts/#tool-calling): this is often how LLMs make decisions +- [Tool calling](agentic_concepts.md#tool-calling): this is often how LLMs make decisions - Action taking: often times, the LLMs' outputs are used as the input to an action -- [Memory](/langgraph/concepts/agentic_concepts/#memory): reliable systems need to have knowledge of things that occurred -- [Planning](/langgraph/concepts/agentic_concepts/#planning): planning steps (either explicit or implicit) are useful for ensuring that the LLM, when making decisions, makes them in the highest fidelity way. +- [Memory](agentic_concepts.md#memory): reliable systems need to have knowledge of things that occurred +- [Planning](agentic_concepts.md#planning): planning steps (either explicit or implicit) are useful for ensuring that the LLM, when making decisions, makes them in the highest fidelity way. ## Why LangGraph? LangGraph has several core principles that we believe make it the most suitable framework for building agentic applications: -- [Controllability](/langgraph/how-tos/#controllability) -- [Human-in-the-Loop](/langgraph/how-tos/#human-in-the-loop) -- [Streaming First](/langgraph/how-tos/#streaming) +- [Controllability](../how-tos/index.md#controllability) +- [Human-in-the-Loop](../how-tos/index.md#human-in-the-loop) +- [Streaming First](../how-tos/index.md#streaming) **Controllability** @@ -40,7 +40,7 @@ LangGraph comes with a built-in persistence layer as a first-class concept. This **Streaming First** -LangGraph comes with first class support for streaming. Agentic applications often take a while to run, and so giving the user some idea of what is happening is important, and streaming is a great way to do that. LangGraph supports streaming of both events ([like a tool call being taken](/langgraph/how-tos/stream-updates/)) as well as of [tokens that an LLM may emit](/langgraph/how-tos/streaming-tokens/). +LangGraph comes with first class support for streaming. Agentic applications often take a while to run, and so giving the user some idea of what is happening is important, and streaming is a great way to do that. LangGraph supports streaming of both events ([like a tool call being taken](../how-tos/stream-updates.ipynb)) as well as of [tokens that an LLM may emit](../how-tos/streaming-tokens.ipynb). ## Deployment @@ -48,8 +48,8 @@ So you've built your LangGraph object - now what? Now you need to deploy it. There are many ways to deploy LangGraph objects, and the right solution depends on your needs and use case. -We'll highlight two ways here: using [LangGraph Cloud](/langgraph/cloud) or rolling your own solution. +We'll highlight two ways here: using [LangGraph Cloud](../cloud/index.md) or rolling your own solution. -[LangGraph Cloud](/langgraph/cloud) is an opinionated way to deploy LangGraph objects from the LangChain team. Please see the [LangGraph Cloud documentation](/langgraph/cloud) for all the details about what it involves, to see if it is a good fit for you. +[LangGraph Cloud](../cloud/index.md) is an opinionated way to deploy LangGraph objects from the LangChain team. Please see the [LangGraph Cloud documentation](../cloud/index.md) for all the details about what it involves, to see if it is a good fit for you. If it is not a good fit, you may want to roll your own deployment. In this case, we would recommend using [FastAPI](https://fastapi.tiangolo.com/) to stand up a server. You can then call this graph from inside the FastAPI server as you see fit. \ No newline at end of file diff --git a/docs/docs/concepts/index.md b/docs/docs/concepts/index.md index 30f95698e..671b53f0f 100644 --- a/docs/docs/concepts/index.md +++ b/docs/docs/concepts/index.md @@ -7,51 +7,51 @@ There are three main parts to this concept guide. First, we'll discuss at a very LangGraph for Agentic Applications -- [What does it mean to be agentic?](high_level#what-does-it-mean-to-be-agentic) -- [Why LangGraph](high_level#why-langgraph) -- [Deployment](high_level#deployment) +- [What does it mean to be agentic?](high_level.md#what-does-it-mean-to-be-agentic) +- [Why LangGraph](high_level.md#why-langgraph) +- [Deployment](high_level.md#deployment) Low Level Concepts -- [Graphs](low_level#graphs) - - [StateGraph](low_level#stategraph) - - [MessageGraph](low_level#messagegraph) - - [Compiling Your Graph](low_level#compiling-your-graph) -- [State](low_level#state) - - [Schema](low_level#schema) - - [Reducers](low_level#reducers) - - [MessageState](low_level#messagestate) -- [Nodes](low_level#nodes) - - [`START` node](low_level#start-node) - - [`END` node](low_level#end-node) -- [Edges](low_level#edges) - - [Normal Edges](low_level#normal-edges) - - [Conditional Edges](low_level#conditional-edges) - - [Entry Point](low_level#entry-point) - - [Conditional Entry Point](low_level#conditional-entry-point) -- [Send](low_level#send) -- [Checkpointer](low_level#checkpointer) -- [Threads](low_level#threads) -- [Checkpointer states](low_level#checkpointer-state) - - [Get state](low_level#get-state) - - [Get state history](low_level#get-state-history) - - [Update state](low_level#update-state) -- [Configuration](low_level#configuration) -- [Visualization](low_level#visualization) -- [Streaming](low_level#streaming) +- [Graphs](low_level.md#graphs) + - [StateGraph](low_level.md#stategraph) + - [MessageGraph](low_level.md#messagegraph) + - [Compiling Your Graph](low_level.md#compiling-your-graph) +- [State](low_level.md#state) + - [Schema](low_level.md#schema) + - [Reducers](low_level.md#reducers) + - [MessageState](low_level.md#messagestate) +- [Nodes](low_level.md#nodes) + - [`START` node](low_level.md#start-node) + - [`END` node](low_level.md#end-node) +- [Edges](low_level.md#edges) + - [Normal Edges](low_level.md#normal-edges) + - [Conditional Edges](low_level.md#conditional-edges) + - [Entry Point](low_level.md#entry-point) + - [Conditional Entry Point](low_level.md#conditional-entry-point) +- [Send](low_level.md#send) +- [Checkpointer](low_level.md#checkpointer) +- [Threads](low_level.md#threads) +- [Checkpointer states](low_level.md#checkpointer-state) + - [Get state](low_level.md#get-state) + - [Get state history](low_level.md#get-state-history) + - [Update state](low_level.md#update-state) +- [Configuration](low_level.md#configuration) +- [Visualization](low_level.md#visualization) +- [Streaming](low_level.md#streaming) Common Agentic Patterns -- [Structured output](agentic_concepts#structured-output) -- [Tool calling](agentic_concepts#tool-calling) -- [Memory](agentic_concepts#memory) -- [Human in the loop](agentic_concepts#human-in-the-loop) - - [Approval](agentic_concepts#approval) - - [Wait for input](agentic_concepts#wait-for-input) - - [Edit agent actions](agentic_concepts#edit-agent-actions) - - [Time travel](agentic_concepts#time-travel) -- [Map-Reduce](agentic_concepts#map-reduce) -- [Multi-agent](agentic_concepts#multi-agent) -- [Planning](agentic_concepts#planning) -- [Reflection](agentic_concepts#reflection) -- [Off-the-shelf ReAct Agent](agentic_concepts#react-agent) +- [Structured output](agentic_concepts.md#structured-output) +- [Tool calling](agentic_concepts.md#tool-calling) +- [Memory](agentic_concepts.md#memory) +- [Human in the loop](agentic_concepts.md#human-in-the-loop) + - [Approval](agentic_concepts.md#approval) + - [Wait for input](agentic_concepts.md#wait-for-input) + - [Edit agent actions](agentic_concepts.md#edit-agent-actions) + - [Time travel](agentic_concepts.md#time-travel) +- [Map-Reduce](agentic_concepts.md#map-reduce) +- [Multi-agent](agentic_concepts.md#multi-agent) +- [Planning](agentic_concepts.md#planning) +- [Reflection](agentic_concepts.md#reflection) +- [Off-the-shelf ReAct Agent](agentic_concepts.md#react-agent) diff --git a/docs/docs/concepts/low_level.md b/docs/docs/concepts/low_level.md index b1423c238..f3c49d381 100644 --- a/docs/docs/concepts/low_level.md +++ b/docs/docs/concepts/low_level.md @@ -42,7 +42,7 @@ The first thing you do when you define a graph is define the `State` of the grap ### Schema -The main documented way to specify the schema of a graph is by using `TypedDict`. However, we also support [using a Pydantic BaseModel](/langgraph/how-tos/state-model/) as your graph state to add **default values** and additional data validation. +The main documented way to specify the schema of a graph is by using `TypedDict`. However, we also support [using a Pydantic BaseModel](../how-tos/state-model.ipynb) as your graph state to add **default values** and additional data validation. ### Reducers @@ -60,7 +60,6 @@ class State(TypedDict): In this example, no reducer functions are specified for any key. Let's assume the input to the graph is `{"foo": 1, "bar": ["hi"]}`. Let's then assume the first `Node` returns `{"foo": 2}`. This is treated as an update to the state. Notice that the `Node` does not need to return the whole `State` schema - just an update. After applying this update, the `State` would then be `{"foo": 2, "bar": ["hi"]}`. If the second node returns `{"bar": ["bye"]}` then the `State` would then be `{"foo": 2, "bar": ["bye"]}` - **Example B:** ```python @@ -74,7 +73,6 @@ class State(TypedDict): In this example, we've used the `Annotated` type to specify a reducer function (`operator.add`) for the second key (`bar`). Note that the first key remains unchanged. Let's assume the input to the graph is `{"foo": 1, "bar": ["hi"]}`. Let's then assume the first `Node` returns `{"foo": 2}`. This is treated as an update to the state. Notice that the `Node` does not need to return the whole `State` schema - just an update. After applying this update, the `State` would then be `{"foo": 2, "bar": ["hi"]}`. If the second node returns `{"bar": ["bye"]}` then the `State` would then be `{"foo": 2, "bar": ["hi", "bye"]}`. Notice here that the `bar` key is updated by adding the two lists together. - ### MessageState `MessageState` is one of the few opinionated components in LangGraph. `MessageState` is a special state designed to make it easy to use a list of messages as a key in your state. Specifically, `MessageState` is defined as: @@ -103,7 +101,7 @@ class State(MessagesState): In LangGraph, nodes are typically python functions (sync or `async`) where the **first** positional argument is the [state](#state), and (optionally), the **second** positional argument is a "config", containing optional [configurable parameters](#configuration) (such as a `thread_id`). -Similar to `NetworkX`, you add these nodes to a graph using the [add_node](/langgraph/reference/graphs#langgraph.graph.MessageGraph) method: +Similar to `NetworkX`, you add these nodes to a graph using the [add_node][langgraph.graph.StateGraph.add_node] method: ```python from langchain_core.runnables import RunnableConfig @@ -127,7 +125,6 @@ builder.add_node("other_node", my_other_node) ... ``` - Behind the scenes, functions are converted to [RunnableLambda's](https://api.python.langchain.com/en/latest/runnables/langchain_core.runnables.base.RunnableLambda.html#langchain_core.runnables.base.RunnableLambda), which add batch and async support to your function, along with native tracing and debugging. If you add a node to graph without specifying a name, it will be given a default name equivalent to the function name. @@ -170,7 +167,7 @@ A node can have MULTIPLE outgoing edges. If a node has multiple out-going edges, ### Normal Edges -If you **always** want to go from node A to node B, you can use the [add_edge](/langgraph/reference/graphs#langgraph.graph.StateGraph.add_edge) method directly. +If you **always** want to go from node A to node B, you can use the [add_edge][langgraph.graph.StateGraph.add_edge] method directly. ```python graph.add_edge("node_a", "node_b") @@ -178,7 +175,7 @@ graph.add_edge("node_a", "node_b") ### Conditional Edges -If you want to **optionally** route to 1 or more edges (or optionally terminate), you can use the [add_conditional_edges](/langgraph/reference/graphs#langgraph.graph.StateGraph.add_conditional_edges) method. This method accepts the name of a node and a "routing function" to call after that node is executed: +If you want to **optionally** route to 1 or more edges (or optionally terminate), you can use the [add_conditional_edges][langgraph.graph.StateGraph.add_conditional_edges] method. This method accepts the name of a node and a "routing function" to call after that node is executed: ```python graph.add_edge("node_a", routing_function) @@ -196,7 +193,7 @@ graph.add_edge("node_a", routing_function, {True: "node_b", False: "node_c"}) ### Entry Point -The entry point is first node to call when the graph starts. You can use [`set_entry_point`](/langgraph/reference/graphs#langgraph.graph.StateGraph.set_entry_point) to specify this. +The entry point is first node to call when the graph starts. You can use [`set_entry_point`][langgraph.graph.StateGraph.set_entry_point] to specify this. ```python graph.set_entry_point("node_a") @@ -213,7 +210,7 @@ graph.add_edge(START, "node_a") ### Conditional Entry Point The conditional entry point is used when you want to specify a function to call to determine which node(s) should be called first. -You can use [`set_conditional_entry_point`](/langgraph/reference/graphs#langgraph.graph.StateGraph.set_conditional_entry_point) to specify this. +You can use [`set_conditional_entry_point`][langgraph.graph.StateGraph.set_conditional_entry_point] to specify this. ```python graph.set_conditional_entry_point(routing_function) @@ -229,7 +226,7 @@ graph.set_conditional_entry_point(routing_function, {True: "node_b", False: "nod By default, `Nodes` and `Edges` are defined ahead of time and operate on the same shared state. However, there can be cases where the exact edges are not known ahead of time and/or you may want different versions of `State` to exist at the same time. A common of example of this is with `map-reduce` design patterns. In this design pattern, a first node may generate a list of objects, and you may want to apply some other node to all those objects. The number of objects may be unknown ahead of time (meaning the number of edges may not be known) and the input `State` to the downstream `Node` should be different (one for each generated object). -To support this design pattern, LangGraph supports returning [`Send`](/langgraph/reference/graphs#send) objects from conditional edges. `Send` takes two arguments: first is the name of the node, and second is the state to pass to that node. +To support this design pattern, LangGraph supports returning [`Send`](../reference/graphs.md#send) objects from conditional edges. `Send` takes two arguments: first is the name of the node, and second is the state to pass to that node. ```python def continue_to_jokes(state: OverallState): @@ -240,15 +237,15 @@ graph.add_conditional_edges("node_a", continue_to_jokes) ## Checkpointer -One of the main benefits of LangGraph is that it comes backed by a persistence layer. This is accomplished via [checkpointers](/langgraph/reference/checkpoints#basecheckpointsaver). +One of the main benefits of LangGraph is that it comes backed by a persistence layer. This is accomplished via [checkpointers][basecheckpointsaver]. -Checkpointers can be used to save a _checkpoint_ of the state of a graph after all steps of the graph. This allows for several things. +Checkpointers can be used to save a _checkpoint_ of the state of a graph after all steps of the graph. This allows for several things. -First, it allows for [human-in-the-loop workflows](agentic_concepts#human-in-the-loop), as it allows humans to inspect, interrupt, and approve steps. Checkpointers are needed for these workflows as the human has to be able to view the state of a graph at any point in time, and the graph has to be to resume execution after the human has made any updates to the state. +First, it allows for [human-in-the-loop workflows](agentic_concepts.md#human-in-the-loop), as it allows humans to inspect, interrupt, and approve steps. Checkpointers are needed for these workflows as the human has to be able to view the state of a graph at any point in time, and the graph has to be to resume execution after the human has made any updates to the state. -Second, it allows for ["memory"](agentic_concepts#memory) between interactions. You can use checkpointers to create threads and save the state of a thread after a graph executes. In the case of repeated human interactions (like conversations) any follow up messages can be sent to that checkpoint, which will retain its memory of previous ones. +Second, it allows for ["memory"](agentic_concepts.md#memory) between interactions. You can use checkpointers to create threads and save the state of a thread after a graph executes. In the case of repeated human interactions (like conversations) any follow up messages can be sent to that checkpoint, which will retain its memory of previous ones. -See [this guide](/langgraph/how-tos/persistence) for how to add a checkpointer to your graph. +See [this guide](../how-tos/persistence.ipynb) for how to add a checkpointer to your graph. ## Threads @@ -266,7 +263,7 @@ config = {"configurable": {"thread_id": "a"}} graph.invoke(inputs, config=config) ``` -See [this guide](/langgraph/how-tos/persistence) for how to use threads. +See [this guide](../how-tos/persistence.ipynb) for how to use threads. ## Checkpointer state @@ -288,7 +285,7 @@ You can get the state of a checkpointer by calling `graph.get_state(config)`. Th ### Get state history -You can also call `graph.get_state_history(config)` to get a list of the history of the graph. The config should contain `thread_id`, and the state history will be fetched for that thread. +You can also call `graph.get_state_history(config)` to get a list of the history of the graph. The config should contain `thread_id`, and the state history will be fetched for that thread. ### Update state @@ -298,7 +295,6 @@ You can also interact with the state directly and update it. This takes three di - values - `as_node` - **config** The config should contain `thread_id` specifying which thread to update. @@ -318,13 +314,14 @@ class State(TypedDict): bar: Annotated[list[str], add] ``` -Let's now assume the current state of the graph is +Let's now assume the current state of the graph is ``` {"foo": 1, "bar": ["a"]} ``` If you update the state as below: + ``` graph.update_state(config, {"foo": 2, "bar": ["b"]}) ``` @@ -373,11 +370,11 @@ def node_a(state, config): ... ``` -See [this guide](/langgraph/how-tos/configuration) for a full breakdown on configuration +See [this guide](../how-tos/configuration.ipynb) for a full breakdown on configuration ## Breakpoints -It can often be useful to set breakpoints before or after certain nodes execute. This can be used to wait for human approval before continuing. These can be set when you ["compile" a graph](#compiling-your-graph). You can set breakpoints either *before* a node executes (using `interrupt_before`) or after a node executes (using `interrupt_after`.) +It can often be useful to set breakpoints before or after certain nodes execute. This can be used to wait for human approval before continuing. These can be set when you ["compile" a graph](#compiling-your-graph). You can set breakpoints either _before_ a node executes (using `interrupt_before`) or after a node executes (using `interrupt_after`.) You **MUST** use a [checkpoiner](#checkpointer) when using breakpoints. This is because your graph needs to be able to resume execution. @@ -391,21 +388,18 @@ graph.invoke(inputs, config=config) graph.invoke(None, config=config) ``` -See [this guide](/langgraph/how-tos/human_in_the_loop/breakpoints) for a full walkthrough of how to add breakpoints. +See [this guide](../how-tos/human_in_the_loop/breakpoints.ipynb) for a full walkthrough of how to add breakpoints. ## Visualization -It's often nice to be able to visualize graphs, especially as they get more complex. LangGraph comes with several built-in ways to visualize graphs. See [this how-to guide](https://langchain-ai.github.io/langgraph/how-tos/visualization/) for more info. - -See [this guide](/langgraph/how-tos/visualization) for how to visualize your graph. +It's often nice to be able to visualize graphs, especially as they get more complex. LangGraph comes with several built-in ways to visualize graphs. See [this how-to guide](../how-tos/visualization.ipynb) for more info. ## Streaming LangGraph is built with first class support for streaming. There are several different streaming modes that LangGraph supports: -- [`"values"`](/langgraph/how-tos/stream-values): This streams the full value of the state after each step of the graph. -- [`"updates`](/langgraph/how-tos/stream-updates): This 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) then those updates are streamed separately. +- [`"values"`](../how-tos/stream-values.ipynb): This streams the full value of the state after each step of the graph. +- [`"updates`](../how-tos/stream-updates.ipynb): This 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) then those updates are streamed separately. - `"debug"`: This streams as much information as possible throughout the execution of the graph. -In addition, you can use the [`astream_events`](https://langchain-ai.github.io/langgraph/how-tos/streaming-tokens/) method to stream back events that happen _inside_ nodes. This is useful for [streaming tokens of LLM calls](/langgraph/how-tos/streaming-tokens). - +In addition, you can use the [`astream_events`](../how-tos/streaming-events-from-within-tools.ipynb) method to stream back events that happen _inside_ nodes. This is useful for [streaming tokens of LLM calls](../how-tos/streaming-tokens.ipynb). diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 6951f7ac1..66fd78739 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -34,18 +34,18 @@ theme: - search.suggest - toc.follow palette: - - scheme: default - primary: white - accent: gray - toggle: - icon: material/brightness-7 - name: Switch to dark mode - - scheme: slate - primary: grey - accent: white - toggle: - icon: material/brightness-4 - name: Switch to light mode + - scheme: default + primary: white + accent: gray + toggle: + icon: material/brightness-7 + name: Switch to dark mode + - scheme: slate + primary: grey + accent: white + toggle: + icon: material/brightness-4 + name: Switch to light mode font: text: "Public Sans" code: "Roboto Mono" @@ -60,7 +60,7 @@ plugins: - https://docs.python.org/3/objects.inv - https://api.python.langchain.com/en/latest/objects.inv options: - members_order: source + members_order: source allow_inspection: true heading_level: 3 show_bases: true @@ -68,9 +68,9 @@ plugins: inherited_members: true # merge_init_into_class: true selection: - docstring_style: google + docstring_style: google docstring_section_style: list - show_root_toc_entry: false + show_root_toc_entry: false # show_signature_annotations: true # show_symbol_type_heading: true show_symbol_type_toc: true @@ -81,10 +81,10 @@ plugins: include_source: True include_requirejs: true nav: - - Home: - - 'index.md' + - Home: + - "index.md" - Tutorials: - - 'tutorials/index.md' + - "tutorials/index.md" - Introduction: tutorials/introduction.ipynb - Chatbots: - Customer Support: tutorials/customer-support/customer-support.ipynb @@ -100,115 +100,113 @@ nav: - Self-RAG using local LLMs: tutorials/rag/langgraph_self_rag_local.ipynb - SQL Agent: tutorials/sql-agent.ipynb - Agent Architectures: - - Multi-Agent Systems: - - Collaboration: tutorials/multi_agent/multi-agent-collaboration.ipynb - - Supervision: tutorials/multi_agent/agent_supervisor.ipynb - - Hierarchical Teams: tutorials/multi_agent/hierarchical_agent_teams.ipynb - - Planning Agents: - - Plan-and-Execute: tutorials/plan-and-execute/plan-and-execute.ipynb - - Reasoning without Observation: tutorials/rewoo/rewoo.ipynb - - LLMCompiler: tutorials/llm-compiler/LLMCompiler.ipynb - - Reflection & Critique: - - Basic Reflection: tutorials/reflection/reflection.ipynb - - Reflexion: tutorials/reflexion/reflexion.ipynb - - Language Agent Tree Search: tutorials/lats/lats.ipynb - - Self-Discover Agent: tutorials/self-discover/self-discover.ipynb + - Multi-Agent Systems: + - Collaboration: tutorials/multi_agent/multi-agent-collaboration.ipynb + - Supervision: tutorials/multi_agent/agent_supervisor.ipynb + - Hierarchical Teams: tutorials/multi_agent/hierarchical_agent_teams.ipynb + - Planning Agents: + - Plan-and-Execute: tutorials/plan-and-execute/plan-and-execute.ipynb + - Reasoning without Observation: tutorials/rewoo/rewoo.ipynb + - LLMCompiler: tutorials/llm-compiler/LLMCompiler.ipynb + - Reflection & Critique: + - Basic Reflection: tutorials/reflection/reflection.ipynb + - Reflexion: tutorials/reflexion/reflexion.ipynb + - Language Agent Tree Search: tutorials/lats/lats.ipynb + - Self-Discover Agent: tutorials/self-discover/self-discover.ipynb - Evaluation & Analysis: - Chatbot Evaluation via Simulation: - Agent-based: tutorials/chatbot-simulation-evaluation/agent-simulation-evaluation.ipynb - In LangSmith: tutorials/chatbot-simulation-evaluation/langsmith-agent-simulation-evaluation.ipynb - Experimental: - - Web Research (STORM): tutorials/storm/storm.ipynb - - TNT-LLM: tutorials/tnt-llm/tnt-llm.ipynb - - Web Navigation: tutorials/web-navigation/web_voyager.ipynb - - Competitive Programming: tutorials/usaco/usaco.ipynb - - Extract structured output: tutorials/extraction/retries.ipynb + - Web Research (STORM): tutorials/storm/storm.ipynb + - TNT-LLM: tutorials/tnt-llm/tnt-llm.ipynb + - Web Navigation: tutorials/web-navigation/web_voyager.ipynb + - Competitive Programming: tutorials/usaco/usaco.ipynb + - Extract structured output: tutorials/extraction/retries.ipynb - "How-to Guides": - - 'how-tos/index.md' - - Controllability: - - Create subgraphs: how-tos/subgraph.ipynb - - Create branches for parallel execution: how-tos/branching.ipynb - - Create map-reduce branches for parallel execution: how-tos/map-reduce.ipynb - - Human-in-the-loop: - - Add persistence ("memory"): how-tos/persistence.ipynb - - Add breakpoints: how-tos/human_in_the_loop/breakpoints.ipynb - - Wait for user input: how-tos/human_in_the_loop/wait-user-input.ipynb - - View and update past graph state: how-tos/human_in_the_loop/time-travel.ipynb - - Edit graph state: how-tos/human_in_the_loop/edit-graph-state.ipynb - - Streaming: - - Stream full state: how-tos/stream-values.ipynb - - Stream state updates: how-tos/stream-updates.ipynb - - Stream LLM tokens: how-tos/streaming-tokens.ipynb - - Stream arbitrarily nested content: how-tos/streaming-content.ipynb - - Configure multiple streaming modes: how-tos/stream-multiple.ipynb - - Stream events from within tools: how-tos/streaming-events-from-within-tools.ipynb - - Other: - - Run graph asynchronously: how-tos/async.ipynb - - Visualize your graph: how-tos/visualization.ipynb - - Add runtime configuration: how-tos/configuration.ipynb - - Use Pydantic model as state: how-tos/state-model.ipynb - - Prebuilt ReAct Agent: - - Create a ReAct agent: how-tos/create-react-agent.ipynb - - Add memory to a ReAct agent: how-tos/create-react-agent-memory.ipynb - - Add a system prompt to a ReAct agent: how-tos/create-react-agent-system-prompt.ipynb - - Add human-in-the-Loop to a ReAct agent: how-tos/create-react-agent-hitl.ipynb - - 'Conceptual Guides': - - 'concepts/index.md' - - LangGraph for Agentic Applications: concepts/high_level.md - - Low Level LangGraph Concepts: concepts/low_level.md - - Common Agentic Patterns: concepts/agentic_concepts.md + - "how-tos/index.md" + - Controllability: + - Create subgraphs: how-tos/subgraph.ipynb + - Create branches for parallel execution: how-tos/branching.ipynb + - Create map-reduce branches for parallel execution: how-tos/map-reduce.ipynb + - Human-in-the-loop: + - Add persistence ("memory"): how-tos/persistence.ipynb + - Add breakpoints: how-tos/human_in_the_loop/breakpoints.ipynb + - Wait for user input: how-tos/human_in_the_loop/wait-user-input.ipynb + - View and update past graph state: how-tos/human_in_the_loop/time-travel.ipynb + - Edit graph state: how-tos/human_in_the_loop/edit-graph-state.ipynb + - Streaming: + - Stream full state: how-tos/stream-values.ipynb + - Stream state updates: how-tos/stream-updates.ipynb + - Stream LLM tokens: how-tos/streaming-tokens.ipynb + - Stream arbitrarily nested content: how-tos/streaming-content.ipynb + - Configure multiple streaming modes: how-tos/stream-multiple.ipynb + - Stream events from within tools: how-tos/streaming-events-from-within-tools.ipynb + - Other: + - Run graph asynchronously: how-tos/async.ipynb + - Visualize your graph: how-tos/visualization.ipynb + - Add runtime configuration: how-tos/configuration.ipynb + - Use Pydantic model as state: how-tos/state-model.ipynb + - Prebuilt ReAct Agent: + - Create a ReAct agent: how-tos/create-react-agent.ipynb + - Add memory to a ReAct agent: how-tos/create-react-agent-memory.ipynb + - Add a system prompt to a ReAct agent: how-tos/create-react-agent-system-prompt.ipynb + - Add human-in-the-Loop to a ReAct agent: how-tos/create-react-agent-hitl.ipynb + - "Conceptual Guides": + - "concepts/index.md" + - LangGraph for Agentic Applications: concepts/high_level.md + - Low Level LangGraph Concepts: concepts/low_level.md + - Common Agentic Patterns: concepts/agentic_concepts.md - Reference: - Graphs: reference/graphs.md - Checkpointing: reference/checkpoints.md - Prebuilt Components: reference/prebuilt.md - Errors: reference/errors.md - - 'Cloud (alpha)': - - 'cloud/index.md' + - "Cloud (alpha)": + - "cloud/index.md" - Tutorials: - - Quick Start: 'cloud/quick_start.md' + - Quick Start: "cloud/quick_start.md" - How-to Guides: - Deployment: - - Setup App: 'cloud/deployment/setup.md' - - Deploy to Cloud: 'cloud/deployment/cloud.md' - - Test with Studio: 'cloud/deployment/studio.md' - - Self-Host: 'cloud/deployment/self_hosted.md' + - Setup App: "cloud/deployment/setup.md" + - Deploy to Cloud: "cloud/deployment/cloud.md" + - Test with Studio: "cloud/deployment/studio.md" + - Self-Host: "cloud/deployment/self_hosted.md" - Streaming: - - Stream Values: 'cloud/how-tos/cloud_examples/stream_values.ipynb' - - Stream Updates: 'cloud/how-tos/cloud_examples/stream_updates.ipynb' - - Stream Messages: 'cloud/how-tos/cloud_examples/stream_messages.ipynb' - - Stream Events: 'cloud/how-tos/cloud_examples/stream_events.ipynb' - - Stream Debug: 'cloud/how-tos/cloud_examples/stream_debug.ipynb' - - Multiple Modes: 'cloud/how-tos/cloud_examples/stream_multiple.ipynb' - - Double Texting: - - Interrupt: 'cloud/how-tos/cloud_examples/interrupt_concurrent.ipynb' - - Rollback: 'cloud/how-tos/cloud_examples/rollback_concurrent.ipynb' - - Reject: 'cloud/how-tos/cloud_examples/reject_concurrent.ipynb' - - Enqueue: 'cloud/how-tos/cloud_examples/enqueue_concurrent.ipynb' - - Run Agent in Background: 'cloud/how-tos/cloud_examples/background_run.ipynb' - - Run Multiple Agents in Thread: 'cloud/how-tos/cloud_examples/same-thread.ipynb' + - Stream Values: "cloud/how-tos/cloud_examples/stream_values.ipynb" + - Stream Updates: "cloud/how-tos/cloud_examples/stream_updates.ipynb" + - Stream Messages: "cloud/how-tos/cloud_examples/stream_messages.ipynb" + - Stream Events: "cloud/how-tos/cloud_examples/stream_events.ipynb" + - Stream Debug: "cloud/how-tos/cloud_examples/stream_debug.ipynb" + - Multiple Modes: "cloud/how-tos/cloud_examples/stream_multiple.ipynb" + - Double Texting: + - Interrupt: "cloud/how-tos/cloud_examples/interrupt_concurrent.ipynb" + - Rollback: "cloud/how-tos/cloud_examples/rollback_concurrent.ipynb" + - Reject: "cloud/how-tos/cloud_examples/reject_concurrent.ipynb" + - Enqueue: "cloud/how-tos/cloud_examples/enqueue_concurrent.ipynb" + - Run Agent in Background: "cloud/how-tos/cloud_examples/background_run.ipynb" + - Run Multiple Agents in Thread: "cloud/how-tos/cloud_examples/same-thread.ipynb" - Human-in-the-Loop: - - Add Breakpoint: 'cloud/how-tos/cloud_examples/human_in_the_loop_breakpoint.ipynb' - - Wait for User Input: 'cloud/how-tos/cloud_examples/human_in_the_loop_user_input.ipynb' - - Edit Graph State: 'cloud/how-tos/cloud_examples/human_in_the_loop_edit_state.ipynb' - - Replay and Branch from Prior States: 'cloud/how-tos/cloud_examples/human_in_the_loop_time_travel.ipynb' - - Create Agents with Configuration: 'cloud/how-tos/cloud_examples/configuration_cloud.ipynb' - - Convert LangGraph calls to LangGraph Cloud calls: 'cloud/how-tos/cloud_examples/langgraph_to_langgraph_cloud.ipynb' - - Create Cron Jobs: 'cloud/how-tos/cloud_examples/cron_jobs.ipynb' - - Create Stateless Runs: 'cloud/how-tos/cloud_examples/stateless_runs.ipynb' + - Add Breakpoint: "cloud/how-tos/cloud_examples/human_in_the_loop_breakpoint.ipynb" + - Wait for User Input: "cloud/how-tos/cloud_examples/human_in_the_loop_user_input.ipynb" + - Edit Graph State: "cloud/how-tos/cloud_examples/human_in_the_loop_edit_state.ipynb" + - Replay and Branch from Prior States: "cloud/how-tos/cloud_examples/human_in_the_loop_time_travel.ipynb" + - Create Agents with Configuration: "cloud/how-tos/cloud_examples/configuration_cloud.ipynb" + - Convert LangGraph calls to LangGraph Cloud calls: "cloud/how-tos/cloud_examples/langgraph_to_langgraph_cloud.ipynb" + - Create Cron Jobs: "cloud/how-tos/cloud_examples/cron_jobs.ipynb" + - Create Stateless Runs: "cloud/how-tos/cloud_examples/stateless_runs.ipynb" - SDK: - - Python: 'cloud/sdk/python_sdk.ipynb' - - JS/TS: 'cloud/sdk/js_sdk.ipynb' - - Conceptual Guides: - 'cloud/concepts/index.md' + - Python: "cloud/sdk/python_sdk.ipynb" + - JS/TS: "cloud/sdk/js_sdk.ipynb" + - Conceptual Guides: "cloud/concepts/index.md" - Reference: - - API: 'cloud/reference/api/api_ref.md' + - API: "cloud/reference/api/api_ref.md" - SDK: - - Python: 'cloud/reference/sdk/python_sdk_ref.md' - - JS/TS: 'cloud/reference/sdk/js_ts_sdk_ref.md' - - CLI: 'cloud/reference/cli.md' - - Environment Variables: 'cloud/reference/env_var.md' - + - Python: "cloud/reference/sdk/python_sdk_ref.md" + - JS/TS: "cloud/reference/sdk/js_ts_sdk_ref.md" + - CLI: "cloud/reference/cli.md" + - Environment Variables: "cloud/reference/env_var.md" markdown_extensions: - abbr @@ -239,7 +237,7 @@ markdown_extensions: - pymdownx.magiclink: normalize_issue_symbols: true repo_url_shorthand: true - user: langchain-ai + user: langchain-ai repo: langgraph - pymdownx.mark - pymdownx.smartsymbols @@ -264,7 +262,7 @@ extra_css: extra: social: - - icon: fontawesome/brands/js + - icon: fontawesome/brands/js link: https://langchain-ai.github.io/langgraphjs/ - icon: fontawesome/brands/github link: https://github.com/langchain-ai/langgraph @@ -284,5 +282,10 @@ extra: - icon: material/emoticon-sad-outline name: This page could be improved data: 0 - note: >- + note: >- Thanks for your feedback! Please help us improve this page by adding to the discussion below. +validation: + omitted_files: warn + absolute_links: warn + unrecognized_links: warn + anchors: warn diff --git a/examples/create-react-agent-hitl.ipynb b/examples/create-react-agent-hitl.ipynb index 21ac07472..fd0ef87de 100644 --- a/examples/create-react-agent-hitl.ipynb +++ b/examples/create-react-agent-hitl.ipynb @@ -7,7 +7,7 @@ "source": [ "# How to add human-in-the-loop processes to the prebuilt ReAct agent\n", "\n", - "This tutorial will show how to add human-in-the-loop processes to the prebuilt ReAct agent. Please see [this tutorial](create-react-agent) for how to get started with the prebuilt ReAct agent\n", + "This tutorial will show how to add human-in-the-loop processes to the prebuilt ReAct agent. Please see [this tutorial](./create-react-agent.ipynb) for how to get started with the prebuilt ReAct agent\n", "\n", "You can add a a breakpoint before tools are called by passing `interrupt_before=[\"tools\"]` to `create_react_agent`. Note that you need to be using a checkpointer for this to work." ] diff --git a/examples/streaming-tokens.ipynb b/examples/streaming-tokens.ipynb index 67e8a34cc..aee396fd1 100644 --- a/examples/streaming-tokens.ipynb +++ b/examples/streaming-tokens.ipynb @@ -457,7 +457,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.1" + "version": "3.12.2" } }, "nbformat": 4, diff --git a/libs/langgraph/langgraph/checkpoint/aiosqlite.py b/libs/langgraph/langgraph/checkpoint/aiosqlite.py index 73341a560..ad0fe7bb6 100644 --- a/libs/langgraph/langgraph/checkpoint/aiosqlite.py +++ b/libs/langgraph/langgraph/checkpoint/aiosqlite.py @@ -27,7 +27,7 @@ def not_implemented_sync_method(func: T) -> T: "The AsyncSqliteSaver does not support synchronous methods. " "Consider using the SqliteSaver instead.\n" "from langgraph.checkpoint.sqlite import SqliteSaver\n" - "See https://langchain-ai.github.io/langgraph/reference/checkpoints/#sqlitesaver " + "See https://langchain-ai.github.io/langgraph/reference/checkpoints/langgraph.checkpoint.sqlite.SqliteSaver " "for more information." ) @@ -135,7 +135,7 @@ class AsyncSqliteSaver(BaseCheckpointSaver, AbstractAsyncContextManager): Note: This method is not implemented for the AsyncSqliteSaver. Use `aget` instead. - Or consider using the [SqliteSaver](#sqlitesaver) checkpointer. + Or consider using the [SqliteSaver][sqlitesaver] checkpointer. """ @not_implemented_sync_method @@ -151,7 +151,7 @@ class AsyncSqliteSaver(BaseCheckpointSaver, AbstractAsyncContextManager): Note: This method is not implemented for the AsyncSqliteSaver. Use `alist` instead. - Or consider using the [SqliteSaver](#sqlitesaver) checkpointer. + Or consider using the [SqliteSaver][sqlitesaver] checkpointer. """ @not_implemented_sync_method diff --git a/libs/langgraph/langgraph/checkpoint/sqlite.py b/libs/langgraph/langgraph/checkpoint/sqlite.py index e13f14bf9..6a4c35c85 100644 --- a/libs/langgraph/langgraph/checkpoint/sqlite.py +++ b/libs/langgraph/langgraph/checkpoint/sqlite.py @@ -56,7 +56,7 @@ _AIO_ERROR_MSG = ( "from langgraph.checkpoint.aiosqlite import AsyncSqliteSaver\n" "Note: AsyncSqliteSaver requires the aiosqlite package to use.\n" "Install with:\n`pip install aiosqlite`\n" - "See https://langchain-ai.github.io/langgraph/reference/checkpoints/#asyncsqlitesaver" + "See https://langchain-ai.github.io/langgraph/reference/checkpoints/asyncsqlitesaver" "for more information." ) @@ -69,7 +69,7 @@ class SqliteSaver(BaseCheckpointSaver, AbstractContextManager): (demos and small projects) and does not scale to multiple threads. For a similar sqlite saver with `async` support, - consider using AsyncSqliteSaver. + consider using [AsyncSqliteSaver][asyncsqlitesaver]. Args: conn (sqlite3.Connection): The SQLite database connection. @@ -399,7 +399,7 @@ class SqliteSaver(BaseCheckpointSaver, AbstractContextManager): Note: This async method is not supported by the SqliteSaver class. - Use get_tuple() instead, or consider using [AsyncSqliteSaver](#asyncsqlitesaver). + Use get_tuple() instead, or consider using [AsyncSqliteSaver][asyncsqlitesaver]. """ raise NotImplementedError(_AIO_ERROR_MSG) @@ -415,7 +415,7 @@ class SqliteSaver(BaseCheckpointSaver, AbstractContextManager): Note: This async method is not supported by the SqliteSaver class. - Use list() instead, or consider using [AsyncSqliteSaver](#asyncsqlitesaver). + Use list() instead, or consider using [AsyncSqliteSaver][asyncsqlitesaver]. """ raise NotImplementedError(_AIO_ERROR_MSG) yield @@ -430,7 +430,7 @@ class SqliteSaver(BaseCheckpointSaver, AbstractContextManager): Note: This async method is not supported by the SqliteSaver class. - Use put() instead, or consider using [AsyncSqliteSaver](#asyncsqlitesaver). + Use put() instead, or consider using [AsyncSqliteSaver][asyncsqlitesaver]. """ raise NotImplementedError(_AIO_ERROR_MSG) diff --git a/libs/langgraph/langgraph/graph/state.py b/libs/langgraph/langgraph/graph/state.py index c916c536d..93ec408d1 100644 --- a/libs/langgraph/langgraph/graph/state.py +++ b/libs/langgraph/langgraph/graph/state.py @@ -154,6 +154,45 @@ class StateGraph(Graph): def add_node( self, node: Union[str, RunnableLike], action: Optional[RunnableLike] = None ) -> None: + """Adds a new node to the state graph. + + Will take the name of the function/runnable as the node name. + + Args: + node (Union[str, RunnableLike)]: The function or runnable this node will run. + action (Optional[RunnableLike]): The action associated with the node. (default: None) + Raises: + ValueError: If the key is already being used as a state key. + + + Examples: + ```pycon + >>> from langgraph.graph import START, StateGraph + ... + >>> def my_node(state, config): + ... return {"x": state["x"] + 1} + ... + >>> builder = StateGraph(dict) + >>> builder.add_node(my_node) # node name will be 'my_node' + >>> builder.add_edge(START, "my_node") + >>> graph = builder.compile() + >>> graph.invoke({"x": 1}) + {'x': 2} + ``` + Customize the name: + + ```pycon + >>> builder = StateGraph(dict) + >>> builder.add_node("my_fair_node", my_node) + >>> builder.add_edge(START, "my_fair_node") + >>> graph = builder.compile() + >>> graph.invoke({"x": 1}) + {'x': 2} + ``` + + Returns: + None + """ if not isinstance(node, str): action = node if isinstance(action, Runnable): @@ -393,9 +432,11 @@ class CompiledStateGraph(CompiledGraph): def branch_writer(packets: list[Union[str, Send]]) -> Optional[ChannelWrite]: if filtered := [p for p in packets if p != END]: writes = [ - ChannelWriteEntry(f"branch:{start}:{name}:{p}", start) - if not isinstance(p, Send) - else p + ( + ChannelWriteEntry(f"branch:{start}:{name}:{p}", start) + if not isinstance(p, Send) + else p + ) for p in filtered ] if branch.then and branch.then != END: