[dev] add history_message_strategy to chat with memory func

This commit is contained in:
jinli.yl 2024-07-29 00:57:23 +08:00
parent ec5d769564
commit d2cd11707b
9 changed files with 63 additions and 26 deletions

View file

@ -54,7 +54,7 @@ def chat_example4():
memory_chat.memory_service.consolidate_memory()
response = memory_chat.chat_with_memory(query="你知道我的乐器爱好是什么?",
add_messages=False)
history_message_strategy=None)
print("回答2\n" + response.message.content)
print("记忆2\n" + response.meta_data["memories"])

View file

@ -1,4 +1,4 @@
from typing import List, Optional
from typing import List, Optional, Literal
from memoryscope.constants.common_constants import MEMORIES
from memoryscope.constants.language_constants import DEFAULT_HUMAN_NAME
@ -126,7 +126,7 @@ class ApiMemoryChat(BaseMemoryChat):
system_prompt: Optional[str] = None,
memory_prompt: Optional[str] = None,
extra_memories: Optional[str] = None,
add_messages: bool = True,
history_message_strategy: Literal["auto", None] | int = "auto",
remember_response: bool = True,
**kwargs):
"""
@ -138,7 +138,11 @@ class ApiMemoryChat(BaseMemoryChat):
system_prompt (str, optional): System prompt. Defaults to the system_prompt in "memory_chat_prompt.yaml".
memory_prompt (str, optional): Memory prompt. Defaults to the memory_prompt in "memory_chat_prompt.yaml".
extra_memories (str, optional): Manually added user memory in this function.
add_messages (bool, optional): whether add not memorized messages to LLM.
history_message_strategy ("auto", None, int):
- If it is set to "auto" the history messages in the conversation will retain those that have not
yet been summarized. Default to "auto".
- If it is set to None no conversation history will be saved.
- If it is set to an integer value "n", the most recent "n" messages will be retained.
remember_response (bool, optional): Flag indicating whether to save the AI's response to memory.
Defaults to False.
Returns:
@ -181,8 +185,15 @@ class ApiMemoryChat(BaseMemoryChat):
chat_messages.append(system_message)
# Include past conversation history in the message list
if add_messages:
history_messages = self.memory_service.read_message()
if history_message_strategy:
history_messages = []
if history_message_strategy == "auto":
history_messages = self.memory_service.read_message()
elif isinstance(history_message_strategy, int):
history_messages = self.memory_service.chat_messages[-history_message_strategy:]
if history_messages:
chat_messages.extend(history_messages)

View file

@ -1,5 +1,5 @@
from abc import ABCMeta, abstractmethod
from typing import Optional
from typing import Optional, Literal
from memoryscope.core.service.base_memory_service import BaseMemoryService
from memoryscope.core.utils.logger import Logger
@ -32,9 +32,30 @@ class BaseMemoryChat(metaclass=ABCMeta):
system_prompt: Optional[str] = None,
memory_prompt: Optional[str] = None,
extra_memories: Optional[str] = None,
add_messages: bool = True,
history_message_strategy: Literal["auto", None] | int = "auto",
remember_response: bool = True,
**kwargs):
"""
The core function that carries out conversation with memory accepts user queries through query and returns the
conversation results through model_response. The retrieved memories are stored in the memories within meta_data.
Args:
query (str, optional): User's query, includes the user's question.
role_name (str, optional): User's role name.
system_prompt (str, optional): System prompt. Defaults to the system_prompt in "memory_chat_prompt.yaml".
memory_prompt (str, optional): Memory prompt. Defaults to the memory_prompt in "memory_chat_prompt.yaml".
extra_memories (str, optional): Manually added user memory in this function.
history_message_strategy ("auto", None, int):
- If it is set to "auto" the history messages in the conversation will retain those that have not
yet been summarized. Default to "auto".
- If it is set to None no conversation history will be saved.
- If it is set to an integer value "n", the most recent "n" messages will be retained.
remember_response (bool, optional): Flag indicating whether to save the AI's response to memory.
Defaults to False.
Returns:
- ModelResponse: In non-streaming mode, returns a complete AI response.
- ModelResponseGen: In streaming mode, returns a generator yielding AI response parts.
- Memories: To obtain the memory by invoking the method of model_response.meta_data[MEMORIES]
"""
raise NotImplementedError
def run(self):

View file

@ -1,6 +1,6 @@
import os
import time
from typing import Optional
from typing import Optional, Literal
import questionary
@ -40,7 +40,7 @@ class CliMemoryChat(ApiMemoryChat):
system_prompt: Optional[str] = None,
memory_prompt: Optional[str] = None,
extra_memories: Optional[str] = None,
add_messages: bool = True,
history_message_strategy: Literal["auto", None] | int = "auto",
remember_response: bool = True,
**kwargs):
resp = super().chat_with_memory(query=query,
@ -48,7 +48,7 @@ class CliMemoryChat(ApiMemoryChat):
system_prompt=system_prompt,
memory_prompt=memory_prompt,
extra_memories=extra_memories,
add_messages=add_messages,
history_message_strategy=history_message_strategy,
remember_response=remember_response,
**kwargs)

View file

@ -103,7 +103,7 @@ class BackendOperation(BaseWorkflow, BaseOperation):
if self._loop_switch:
self.run_operation()
def run_operation_backend(self):
def start_operation_backend(self):
"""
Initiates the background operation loop if it's not already running.
Sets the _loop_switch to True and submits the _loop_operation to a thread from the global thread pool.

View file

@ -50,7 +50,7 @@ class BaseOperation(metaclass=ABCMeta):
"""
raise NotImplementedError
def run_operation_backend(self):
def start_operation_backend(self):
"""
Placeholder method for running an operation specific to the backend.
Intended to be overridden by subclasses if backend operations are required.

View file

@ -28,6 +28,7 @@ class BaseMemoryService(metaclass=ABCMeta):
self.kwargs = kwargs
self._operation_dict: Dict[str, BaseOperation] = {}
self.chat_messages: List[Message] = []
self.logger = Logger.get_logger()
@property
@ -51,7 +52,7 @@ class BaseMemoryService(metaclass=ABCMeta):
def init_service(self, **kwargs):
raise NotImplementedError
def start_backend_service(self):
def start_backend_service(self, name: str = None):
pass
def stop_backend_service(self, wait_service_end: bool = False):

View file

@ -37,7 +37,6 @@ class MemoryScopeService(BaseMemoryService):
if assistant_name:
self.context.meta_data["assistant_name"] = assistant_name
self.chat_messages: List[Message] = []
self.message_lock = threading.Lock()
def add_messages(self, messages: List[Message] | Message):
@ -89,13 +88,17 @@ class MemoryScopeService(BaseMemoryService):
for name, operation_config in self.memory_operations_conf.items():
self.register_operation(name, operation_config, **kwargs)
def start_backend_service(self):
def start_backend_service(self, name: str = None):
"""
Start all backend operations.
"""
for _, operation in self._operation_dict.items():
if operation.operation_type == "backend":
operation.run_operation_backend()
for op_name, operation in self._operation_dict.items():
if name:
if op_name == name:
operation.start_operation_backend()
else:
if operation.operation_type == "backend":
operation.start_operation_backend()
def stop_backend_service(self, wait_service_end: bool = False):
"""

View file

@ -56,14 +56,15 @@ class UpdateInsightWorker(MemoryBaseWorker):
return insight_node, filtered_nodes, max_score
if use_dummy_ranker:
key_vector: List[float] = self.embedding_model.call(text=insight_node.key).embedding_results
if not key_vector:
self.logger.warning(f"embedding call {insight_node.key} failed!")
return insight_node, filtered_nodes, max_score
if not insight_node.key_vector:
key_vector: List[float] = self.embedding_model.call(text=insight_node.key).embedding_results
if not key_vector:
self.logger.warning(f"embedding call {insight_node.key} failed!")
return insight_node, filtered_nodes, max_score
insight_node.key_vector = key_vector
documents_vector = [x.vector for x in obs_nodes]
score_recall_list = cosine_similarity(key_vector, documents_vector)
insight_node.key_vector = key_vector
score_recall_list = cosine_similarity(insight_node.key_vector, [x.vector for x in obs_nodes])
assert len(score_recall_list) == len(obs_nodes), \
f"size is not as excepted. {len(score_recall_list)} v.s. {len(obs_nodes)}"