Skip to content

Introduce the LLM session manager classes #141

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

Merged
merged 41 commits into from
Jul 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
26c656b
wip: defining base session manager class methods
justin-cechmanek Apr 16, 2024
872e0fe
removes base session manager parent class
justin-cechmanek Apr 22, 2024
65177b2
adds proposed schema to sesssion manager description
justin-cechmanek Apr 22, 2024
ebc07d6
adds session manager init
justin-cechmanek Apr 25, 2024
9dbc928
wip: minimal working session manager
justin-cechmanek Apr 26, 2024
bb467c2
wip: adding full conversation history, and cleans up scoping
justin-cechmanek Apr 30, 2024
4ed6208
minor clean up
justin-cechmanek May 1, 2024
2c5c52a
wip: initial notebook demo on semantic session manager
justin-cechmanek May 1, 2024
4d0b9ce
wip: continues session manager work
justin-cechmanek May 2, 2024
ba2575a
cleans up first session manager notebook
justin-cechmanek May 2, 2024
5fda1ec
makes scope configurable on each call to fetch_context
justin-cechmanek May 3, 2024
37ae270
improves scope settings
justin-cechmanek May 4, 2024
4e432a4
adds notebook example of controling session access scope
justin-cechmanek May 4, 2024
3d404e7
formatting
justin-cechmanek May 6, 2024
c20d23e
mypy formatting
justin-cechmanek May 6, 2024
29b4a05
black formatting
justin-cechmanek May 6, 2024
e612195
bumps notebook number
justin-cechmanek May 6, 2024
45427ad
corrects method name
justin-cechmanek May 6, 2024
d9aacf9
sets an asymetric retrieval model as default vectorizer
justin-cechmanek May 7, 2024
3a117eb
Merge branch 'main' into jc/semantic-session-manager
justin-cechmanek May 8, 2024
f99967f
moves recency sorting into Redis query
justin-cechmanek May 8, 2024
5d4f34b
adds session manager notebook examples to index
justin-cechmanek May 8, 2024
dff924c
wip:refactor into multiple classes
justin-cechmanek May 15, 2024
c8b9325
Merge branch 'main' into jc/semantic-session-manager
justin-cechmanek May 15, 2024
6e8ca02
refactors session managers into multiple classes
justin-cechmanek May 27, 2024
90cfe59
adds tests for session managers
justin-cechmanek May 28, 2024
b2e80b5
removes redundant notebook
justin-cechmanek May 28, 2024
d898941
formatting
justin-cechmanek May 28, 2024
46fb9b5
formatting
justin-cechmanek May 28, 2024
58be5b7
fixes failing test
justin-cechmanek May 28, 2024
ce09632
changes user_id, session_id to user_tag, session_tag. Adds pydantic v…
justin-cechmanek May 29, 2024
d32b12e
makes system preamble fully optional, empty if not set
justin-cechmanek May 29, 2024
a5fb413
renames methods & properties to align with OpenAI and LangChain
justin-cechmanek Jun 12, 2024
c683532
changes session managers to match langchain chat history api
justin-cechmanek Jun 14, 2024
d666fad
adds messages property to match langchain
justin-cechmanek Jun 17, 2024
158eb52
adds test coverage for messages property
justin-cechmanek Jun 17, 2024
60a1a00
adds optional tool message type
justin-cechmanek Jun 28, 2024
85ba8d0
Merge branch 'main' into jc/semantic-session-manager
justin-cechmanek Jun 28, 2024
241199e
Bugfix in setting vectorizer. Uses index key_separator
justin-cechmanek Jul 2, 2024
5c5a385
updates doc strings
justin-cechmanek Jul 3, 2024
a0d0a21
empty arrary is returned when top_k=0
justin-cechmanek Jul 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,15 @@ def clear_db(redis):
redis.flushall()
yield
redis.flushall()

@pytest.fixture
def app_name():
return "test_app"

@pytest.fixture
def session_tag():
return "123"

@pytest.fixture
def user_tag():
return "abc"
1 change: 1 addition & 0 deletions docs/user_guide/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@ llmcache_03
vectorizers_04
hash_vs_json_05
rerankers_06
session_manager_07
```

615 changes: 615 additions & 0 deletions docs/user_guide/session_manager_07.ipynb

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions redisvl/extensions/session_manager/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from redisvl.extensions.session_manager.base_session import BaseSessionManager
from redisvl.extensions.session_manager.semantic_session import SemanticSessionManager
from redisvl.extensions.session_manager.standard_session import StandardSessionManager

__all__ = ["BaseSessionManager", "StandardSessionManager", "SemanticSessionManager"]
173 changes: 173 additions & 0 deletions redisvl/extensions/session_manager/base_session.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
from typing import Any, Dict, List, Optional, Union

from redis import Redis


class BaseSessionManager:
id_field_name: str = "id_field"
role_field_name: str = "role"
content_field_name: str = "content"
tool_field_name: str = "tool_call_id"
timestamp_field_name: str = "timestamp"

def __init__(
self,
name: str,
session_tag: str,
user_tag: str,
):
"""Initialize session memory with index

Session Manager stores the current and previous user text prompts and
LLM responses to allow for enriching future prompts with session
context. Session history is stored in individual user or LLM prompts and
responses.

Args:
name (str): The name of the session manager index.
session_tag (str): Tag to be added to entries to link to a specific
session.
user_tag (str): Tag to be added to entries to link to a specific user.
"""
self._name = name
self._user_tag = user_tag
self._session_tag = session_tag

def set_scope(
self,
session_tag: Optional[str] = None,
user_tag: Optional[str] = None,
) -> None:
"""Set the filter to apply to querries based on the desired scope.

This new scope persists until another call to set_scope is made, or if
scope specified in calls to get_recent.

Args:
session_tag (str): Id of the specific session to filter to. Default is
None.
user_tag (str): Id of the specific user to filter to. Default is None.
"""
raise NotImplementedError

def clear(self) -> None:
"""Clears the chat session history."""
raise NotImplementedError

def delete(self) -> None:
"""Clear all conversation history and remove any search indices."""
raise NotImplementedError

def drop(self, id_field: Optional[str] = None) -> None:
"""Remove a specific exchange from the conversation history.

Args:
id_field (Optional[str]): The id_field of the entry to delete.
If None then the last entry is deleted.
"""
raise NotImplementedError

@property
def messages(self) -> Union[List[str], List[Dict[str, str]]]:
"""Returns the full chat history."""
raise NotImplementedError

def get_recent(
self,
top_k: int = 5,
session_tag: Optional[str] = None,
user_tag: Optional[str] = None,
as_text: bool = False,
raw: bool = False,
) -> Union[List[str], List[Dict[str, str]]]:
"""Retreive the recent conversation history in sequential order.

Args:
top_k (int): The number of previous exchanges to return. Default is 5.
Note that one exchange contains both a prompt and response.
session_tag (str): Tag to be added to entries to link to a specific
session.
user_tag (str): Tag to be added to entries to link to a specific user.
as_text (bool): Whether to return the conversation as a single string,
or list of alternating prompts and responses.
raw (bool): Whether to return the full Redis hash entry or just the
prompt and response

Returns:
Union[str, List[str]]: A single string transcription of the session
or list of strings if as_text is false.

Raises:
ValueError: If top_k is not an integer greater than or equal to 0.
"""
raise NotImplementedError

def _format_context(
self, hits: List[Dict[str, Any]], as_text: bool
) -> Union[List[str], List[Dict[str, str]]]:
"""Extracts the prompt and response fields from the Redis hashes and
formats them as either flat dictionaries or strings.

Args:
hits (List): The hashes containing prompt & response pairs from
recent conversation history.
as_text (bool): Whether to return the conversation as a single string,
or list of alternating prompts and responses.
Returns:
Union[str, List[str]]: A single string transcription of the session
or list of strings if as_text is false.
"""
if as_text:
text_statements = []
for hit in hits:
text_statements.append(hit[self.content_field_name])
return text_statements
else:
statements = []
for hit in hits:
statements.append(
{
self.role_field_name: hit[self.role_field_name],
self.content_field_name: hit[self.content_field_name],
}
)
if (
hasattr(hit, self.tool_field_name)
or isinstance(hit, dict)
and self.tool_field_name in hit
):
statements[-1].update(
{self.tool_field_name: hit[self.tool_field_name]}
)
return statements

def store(self, prompt: str, response: str) -> None:
"""Insert a prompt:response pair into the session memory. A timestamp
is associated with each exchange so that they can be later sorted
in sequential ordering after retrieval.

Args:
prompt (str): The user prompt to the LLM.
response (str): The corresponding LLM response.
"""
raise NotImplementedError

def add_messages(self, messages: List[Dict[str, str]]) -> None:
"""Insert a list of prompts and responses into the session memory.
A timestamp is associated with each so that they can be later sorted
in sequential ordering after retrieval.

Args:
messages (List[Dict[str, str]]): The list of user prompts and LLM responses.
"""
raise NotImplementedError

def add_message(self, message: Dict[str, str]) -> None:
"""Insert a single prompt or response into the session memory.
A timestamp is associated with it so that it can be later sorted
in sequential ordering after retrieval.

Args:
message (Dict[str,str]): The user prompt or LLM response.
"""
raise NotImplementedError
Loading
Loading