diff --git a/docs/docs/agents/agents.md b/docs/docs/agents/agents.md index acf2aac92..73935c650 100644 --- a/docs/docs/agents/agents.md +++ b/docs/docs/agents/agents.md @@ -112,7 +112,7 @@ from langgraph.prebuilt import create_react_agent # highlight-next-line def prompt(state: AgentState, config: RunnableConfig) -> list[AnyMessage]: # (1)! - user_name = config.get("configurable", {}).get("user_name") + user_name = config["configurable"].get("user_name") system_msg = f"You are a helpful assistant. Address the user as {user_name}." return [{"role": "system", "content": system_msg}] + state["messages"] diff --git a/docs/docs/agents/context.md b/docs/docs/agents/context.md index 2415854c0..cd74ab297 100644 --- a/docs/docs/agents/context.md +++ b/docs/docs/agents/context.md @@ -107,7 +107,7 @@ Common use cases: config: RunnableConfig, ) -> list[AnyMessage]: # highlight-next-line - user_name = config.get("configurable", {}).get("user_name") + user_name = config["configurable"].get("user_name") system_msg = f"You are a helpful assistant. User's name is {user_name}" return [{"role": "system", "content": system_msg}] + state["messages"] @@ -162,7 +162,7 @@ Common use cases: }) ``` -## Tools +## Accessing Context in Tools Tools can access context through special parameter **annotations**. @@ -183,7 +183,7 @@ Tools can access context through special parameter **annotations**. ) -> str: """Look up user info.""" # highlight-next-line - user_id = config.get("configurable", {}).get("user_id") + user_id = config["configurable"].get("user_id") return "User is John Smith" if user_id == "user_123" else "Unknown user" agent = create_react_agent( @@ -231,66 +231,6 @@ Tools can access context through special parameter **annotations**. }) ``` +### Update Context from Tools -## Update context from tools - -Tools can modify the agent's state during execution. This is useful for persisting intermediate results or making information accessible to subsequent tools or prompts. - -```python -from typing import Annotated -from langchain_core.tools import InjectedToolCallId -from langchain_core.messages import ToolMessage -from langgraph.prebuilt import InjectedState -from langgraph.types import Command - -class CustomState(AgentState): - # highlight-next-line - user_name: str - -def get_user_info( - # highlight-next-line - tool_call_id: Annotated[str, InjectedToolCallId], - # highlight-next-line - config: RunnableConfig -) -> Command: - """Look up user info.""" - # highlight-next-line - user_id = config.get("configurable", {}).get("user_id") - name = "John Smith" if user_id == "user_123" else "Unknown user" - return Command(update={ - # highlight-next-line - "user_name": name, - # update the message history - # highlight-next-line - "messages": [ - ToolMessage( - "Successfully looked up user information", - # highlight-next-line - tool_call_id=tool_call_id - ) - ] - }) - -def greet( - # highlight-next-line - state: Annotated[CustomState, InjectedState] -) -> str: - """Use this to greet the user once you found their info.""" - user_name = state["user_name"] - return f"Hello {user_name}!" - -agent = create_react_agent( - model="anthropic:claude-3-7-sonnet-latest", - tools=[get_user_info, greet], - # highlight-next-line - state_schema=CustomState -) - -agent.invoke( - {"messages": [{"role": "user", "content": "greet the user"}]}, - # highlight-next-line - config={"configurable": {"user_id": "user_123"}} -) -``` - -For more details, see [how to update state from tools](../how-tos/update-state-from-tools.ipynb). \ No newline at end of file +Tools can update agent's context (state and long-term memory) during execution. This is useful for persisting intermediate results or making information accessible to subsequent tools or prompts. See [Memory](./memory.md#read-short-term) guide for more information. \ No newline at end of file diff --git a/docs/docs/agents/memory.md b/docs/docs/agents/memory.md index 81f3801ec..9b9b33144 100644 --- a/docs/docs/agents/memory.md +++ b/docs/docs/agents/memory.md @@ -149,6 +149,104 @@ agent = create_react_agent( To learn more about using `pre_model_hook` for managing message history, see this [how-to guide](../how-tos/create-react-agent-manage-message-history.ipynb) +### Read in tools { #read-short-term } + +LangGraph allows agent to access its short-term memory (state) inside the tools. + +```python +from typing import Annotated +from langgraph.prebuilt import InjectedState, create_react_agent + +class CustomState(AgentState): + # highlight-next-line + user_id: str + +def get_user_info( + # highlight-next-line + state: Annotated[CustomState, InjectedState] +) -> str: + """Look up user info.""" + # highlight-next-line + user_id = state["user_id"] + return "User is John Smith" if user_id == "user_123" else "Unknown user" + +agent = create_react_agent( + model="anthropic:claude-3-7-sonnet-latest", + tools=[get_user_info], + # highlight-next-line + state_schema=CustomState, +) + +agent.invoke({ + "messages": "look up user information", + # highlight-next-line + "user_id": "user_123" +}) +``` + +See the [Context](./context.md#__tabbed_2_2) guide for more information. + +### Write from tools { #write-short-term } + +To modify the agent's short-term memory (state) during execution, you can return state updates directly from the tools. This is useful for persisting intermediate results or making information accessible to subsequent tools or prompts. + +```python +from typing import Annotated +from langchain_core.tools import InjectedToolCallId +from langchain_core.runnables import RunnableConfig +from langchain_core.messages import ToolMessage +from langgraph.prebuilt import InjectedState, create_react_agent +from langgraph.prebuilt.chat_agent_executor import AgentState +from langgraph.types import Command + +class CustomState(AgentState): + # highlight-next-line + user_name: str + +def update_user_info( + tool_call_id: Annotated[str, InjectedToolCallId], + config: RunnableConfig +) -> Command: + """Look up and update user info.""" + user_id = config["configurable"].get("user_id") + name = "John Smith" if user_id == "user_123" else "Unknown user" + # highlight-next-line + return Command(update={ + # highlight-next-line + "user_name": name, + # update the message history + "messages": [ + ToolMessage( + "Successfully looked up user information", + tool_call_id=tool_call_id + ) + ] + }) + +def greet( + # highlight-next-line + state: Annotated[CustomState, InjectedState] +) -> str: + """Use this to greet the user once you found their info.""" + user_name = state["user_name"] + return f"Hello {user_name}!" + +agent = create_react_agent( + model="anthropic:claude-3-7-sonnet-latest", + tools=[get_user_info, greet], + # highlight-next-line + state_schema=CustomState +) + +agent.invoke( + {"messages": [{"role": "user", "content": "greet the user"}]}, + # highlight-next-line + config={"configurable": {"user_id": "user_123"}} +) +``` + +For more details, see [how to update state from tools](../how-tos/update-state-from-tools.ipynb). + ## Long-term memory Use long-term memory to store user-specific or application-specific data across conversations. This is useful for applications like chatbots, where you want to remember user preferences or other information. @@ -158,9 +256,10 @@ To use long-term memory, you need to: 1. [Configure a store](../how-tos/cross-thread-persistence.ipynb) to persist data across invocations. 2. Use the [`get_store`][langgraph.config.get_store] function to access the store from within tools or prompts. -### Reading +### Read { #read-long-term } ```python title="A tool the agent can use to look up user information" +from langchain_core.runnables import RunnableConfig from langgraph.config import get_store from langgraph.prebuilt import create_react_agent from langgraph.store.memory import InMemoryStore @@ -183,7 +282,7 @@ def get_user_info(config: RunnableConfig) -> str: # Same as that provided to `create_react_agent` # highlight-next-line store = get_store() # (6)! - user_id = config.get("configurable", {}).get("user_id") + user_id = config["configurable"].get("user_id") # highlight-next-line user_info = store.get(("users",), user_id) # (7)! return str(user_info.value) if user_info else "Unknown user" @@ -212,7 +311,7 @@ agent.invoke( 7. The `get` method is used to retrieve data from the store. The first argument is the namespace, and the second argument is the key. This will return a `StoreValue` object, which contains the value and metadata about the value. 8. The `store` is passed to the agent. This enables the agent to access the store when running tools. You can also use the `get_store` function to access the store from anywhere in your code. -### Writing +### Write { #write-long-term } ```python title="Example of a tool that updates user information" from typing_extensions import TypedDict @@ -231,7 +330,7 @@ def save_user_info(user_info: UserInfo, config: RunnableConfig) -> str: # (3)! # Same as that provided to `create_react_agent` # highlight-next-line store = get_store() # (4)! - user_id = config.get("configurable", {}).get("user_id") + user_id = config["configurable"].get("user_id") # highlight-next-line store.put(("users",), user_id, user_info) # (5)! return "Successfully saved user info." diff --git a/docs/docs/agents/tools.md b/docs/docs/agents/tools.md index 623e6396a..71279f5cb 100644 --- a/docs/docs/agents/tools.md +++ b/docs/docs/agents/tools.md @@ -271,6 +271,13 @@ By default, the agent will catch all exceptions raised during tool calls and wil 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.