Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shared state conceptual docs #1958

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open

Conversation

rlancemartin
Copy link
Contributor

No description provided.

docs/docs/concepts/persistence.md Show resolved Hide resolved
Persistence is critical sustaining a long-running chat sessions. For example, a chat between a user and an AI assistant may have interruptions. Persistence ensures that a user can continue that particular chat session at any later point in time. However, what happens if a user initiates a new chat session with an assistant? This spawns a new thread, and the information from the previous session (thread) is not retained. This motivates the need for a memory service that can maintain data across chat sessions (threads).
Persistence is critical sustaining a long-running chat sessions. For example, a chat between a user and an AI assistant may have interruptions. Persistence ensures that a user can continue that particular chat session at any later point in time. However, what happens if a user initiates a new chat session with an assistant? This spawns a new thread, and the information from the previous session (thread) is not retained. This motivates the need for a memory that can maintain data across chat sessions (threads).

For this, we can use LangGraph's `Store` interface to save and retrieve information across threads. Shared information can be namespaced by, for example, `user_id` to retain user-specific information across threads. See more detail in the [persistence conceptual guide](https://langchain-ai.github.io/langgraph/concepts/persistence/#persistence) and this [how-to guide on shared state](../how-tos/memory/shared-state.ipynb).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you have a code snippet for the checkpointer, i would do the same for here

also, now that we have this, i would add more concrete examples for the two below

also id maybe rename "metaprompting" to "update own instructions" or something?

docs/docs/concepts/memory.md Outdated Show resolved Hide resolved

## Meta-prompting
For this, we can use LangGraph's `Store` interface to save and retrieve information across threads. Shared information can be namespaced by, for example, `user_id` to retain user-specific information across threads. Let's show how to use the `Store` interface to save and retrieve information.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have an API reference that we can link Store interface to?

namespace_for_memory = (user_id, "memories")

# Save memories
memory_id = str(uuid.uuid4())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there's a single sentence answer to the question why is the key not a tuple? Why has the key been broken into a namespace (tuple) and a string.

in_memory_store.put(namespace_for_memory, memory_id, memory)

# Retrieve memories
memories = in_memory_store.search(namespace_for_memory)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does search return without a query?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it always returns a list of items. Default is listing

docs/docs/concepts/persistence.md Outdated Show resolved Hide resolved
docs/docs/concepts/persistence.md Outdated Show resolved Hide resolved
namespace_for_memory = (user_id, "memories")
```

We use the `store.put` to save memories to our namespace in the store. When we do this, we specify the namespace, as defined above, and a key-value pair for the memory: the key is simply a unique identifier for the memory (`memory_id`) and the value (a dictionary) is the memory itself.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The full key words out to be:

(user_id, "memories", "some_random_uuid", "food_preference")

Does structuring memories as:

{
   'type': "food_preference",
  "value": "I like pizza"
}

work with respect to the memory store API? (e.g., does search work as expected etc.)

cc @hinthornw

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can either put food preference in the namespace (so you can search in that directory) or as a key and do filter of {"type", "food_preference"}

More flexible if it's in the body

in_memory_store.put(namespace_for_memory, memory_id, memory)
```

We can read out memories in our namespace using `store.search`, which will return all memories for a given user as a list. The most recent memory is the last in the list.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • This looks like a list API. Does search support queries?
  • Is it all memories or is there a page size?

Copy link
Contributor

@hinthornw hinthornw Oct 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not yet - just filtering, limit, offset.

search query & additional things to be added

docs/docs/concepts/persistence.md Outdated Show resolved Hide resolved

# Let's say hi again
for update in graph.stream(
{"messages": [{"role": "user", "content": "hi, tell me about my memories"}]}, config, stream_mode="updates"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The input into the graph is messages in the format of dicts.

I think that the schema of the graph is MessagesState -- which doesn't support the dict notation probably?

class MessagesState(TypedDict):
    messages: Annotated[list[AnyMessage], add_messages]
AnyMessage = Annotated[
    Union[
        Annotated[AIMessage, Tag(tag="ai")],
        Annotated[HumanMessage, Tag(tag="human")],
        Annotated[ChatMessage, Tag(tag="chat")],
        Annotated[SystemMessage, Tag(tag="system")],
        Annotated[FunctionMessage, Tag(tag="function")],
        Annotated[ToolMessage, Tag(tag="tool")],
        Annotated[AIMessageChunk, Tag(tag="AIMessageChunk")],
        Annotated[HumanMessageChunk, Tag(tag="HumanMessageChunk")],
        Annotated[ChatMessageChunk, Tag(tag="ChatMessageChunk")],
        Annotated[SystemMessageChunk, Tag(tag="SystemMessageChunk")],
        Annotated[FunctionMessageChunk, Tag(tag="FunctionMessageChunk")],
        Annotated[ToolMessageChunk, Tag(tag="ToolMessageChunk")],
    ],
    Field(discriminator=Discriminator(_get_type)),
]

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cc @vbarda / @hinthornw IMO this is a problem if we start using dict notation

Copy link
Contributor

@hinthornw hinthornw Oct 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just ran into mypy anger from this type of thing where BaseMessgae isn't included either.

I think we can use from langgraph.graph.mesages import Messages which is a union of that and "messagelikedict" or something

It's frustrating that core doesn't have a single type for this

@eyurtsev
Copy link
Contributor

eyurtsev commented Oct 2, 2024

@rlancemartin I think this is looking great! Just a few nits and tagged @hinthornw in a few places for clarification on API

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants