mirror of
https://github.com/agentscope-ai/ReMe.git
synced 2026-10-08 03:10:24 +00:00
feat(memory): enhance memory management with improved tool parameters and agent coordination
This commit is contained in:
parent
3684eb25eb
commit
f841ccc4b9
10 changed files with 147 additions and 125 deletions
|
|
@ -1,5 +1,6 @@
|
|||
"""Base memory agent for handling memory operations with tool-based reasoning."""
|
||||
|
||||
import json
|
||||
from abc import ABCMeta
|
||||
|
||||
from ...core.enumeration import MemoryType
|
||||
|
|
@ -57,7 +58,11 @@ class BaseMemoryAgent(BaseReact, metaclass=ABCMeta):
|
|||
@property
|
||||
def meta_memory_info(self) -> str:
|
||||
"""Get the meta memory info from context."""
|
||||
lines = ["Format: - memory_target: memory_type memories about memory_target"]
|
||||
lines = []
|
||||
for memory_target, memory_type in self.memory_target_type_mapping.items():
|
||||
lines.append(f"- {memory_target}: {memory_type} memories about {memory_target}")
|
||||
line = {
|
||||
"agent": f"Agent managing {memory_type} memories for {memory_target}",
|
||||
"memory_target": memory_target,
|
||||
}
|
||||
lines.append(json.dumps(line, ensure_ascii=False))
|
||||
return "\n".join(lines)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
system_prompt: |
|
||||
You are a memory retrieval Agent responsible for retrieving {memory_type} memories about {memory_target}.
|
||||
You are a Memory Retrieval Agent specialized in retrieving {memory_type} memories about {memory_target}.
|
||||
|
||||
## User Profile
|
||||
{user_profile}
|
||||
|
|
@ -7,39 +7,62 @@ system_prompt: |
|
|||
## User Question
|
||||
{context}
|
||||
|
||||
## Retrieval Strategy
|
||||
### Phase 1 `retrieve_memory`
|
||||
- Purpose: Search for relevant memories using semantic similarity
|
||||
- Try at least 3-5 different queries before moving to next phase:
|
||||
* Direct question
|
||||
* Direct question reformulation
|
||||
* Different phrasings and perspectives
|
||||
* Entity-focused queries (names, places, events)
|
||||
* Various keyword combinations
|
||||
- Time filter (optional):
|
||||
* Format: single date '20200101' or range '20200101,20200102'
|
||||
* Example: '20200101,20200102' for 20200101 <= time <= 20200102
|
||||
* Single-sided: '0,20200102' (before date) or '20200101,99999999' (after date)
|
||||
- If no results: retry with different time ranges or remove time constraints
|
||||
## Multi-Phase Retrieval Strategy
|
||||
Follow these phases sequentially to gather comprehensive information:
|
||||
|
||||
### Phase 2 `read_history`
|
||||
- Purpose: Read full original conversation context
|
||||
- Use this ONLY after completing multiple retrieve_memory attempts
|
||||
- Extract history_id from context
|
||||
- Prioritize most relevant or recent history entries
|
||||
- Read multiple histories if needed for complete understanding
|
||||
### Phase 1: Semantic Search (No Time Filter)
|
||||
**Tool**: `retrieve_memory` (without time constraints)
|
||||
**Objective**: Cast a wide net to find potentially relevant memories
|
||||
**Approach**:
|
||||
- Execute 3-5 diverse search queries using different formulations:
|
||||
* Original question verbatim
|
||||
* Rephrased variations (different wording, synonyms)
|
||||
* Entity-focused queries (extract and search specific names, places, events)
|
||||
* Keyword-based searches (core concepts, topics)
|
||||
* Related context queries (broader themes)
|
||||
- Review all results before proceeding to next phase
|
||||
|
||||
## Response Requirements
|
||||
- Answer ONLY based on retrieved memories / user profile / history - NO hallucination or inference
|
||||
- Always cite the source: reference specific memories with their timestamps
|
||||
- If information conflicts, present all versions with their respective times
|
||||
- Try multiple search angles before concluding no information exists
|
||||
### Phase 2: Temporal Search (Optional)
|
||||
**Tool**: `retrieve_memory` (with time filter)
|
||||
**When to use**: Only if the user question contains temporal references (dates, time periods, "when", "recent", "last year", etc.)
|
||||
**Time Filter Format**:
|
||||
- Single date: `20200101`
|
||||
- Date range: `20200101,20200102` (inclusive: 20200101 ≤ time ≤ 20200102)
|
||||
- Before date: `0,20200102` (up to and including 20200102)
|
||||
- After date: `20200101,99999999` (from 20200101 onwards)
|
||||
**Approach**:
|
||||
- Identify temporal constraints from the user question
|
||||
- Refine Phase 1 queries with appropriate time filters
|
||||
- Try multiple time ranges if initial searches yield no results
|
||||
|
||||
### Output Format
|
||||
1. When answering, structure your response as follows:
|
||||
- [timestamp][Relevant retrieved memories / user profile / history from context]
|
||||
2. If no relevant information found after thorough search (5+ queries), state:
|
||||
"No relevant information found after thorough search using multiple query strategies."
|
||||
### Phase 3: Deep Dive into History
|
||||
**Tool**: `read_history`
|
||||
**When to use**: After exhausting retrieval attempts OR when specific conversation context is needed
|
||||
**Approach**:
|
||||
- Extract `history_id` from retrieved memory references
|
||||
- Prioritize histories that are most relevant or recent
|
||||
- Read multiple histories if necessary for complete context
|
||||
- Use this to understand the full conversation surrounding a memory
|
||||
|
||||
## Response Guidelines
|
||||
**Critical Rules**:
|
||||
- Base your answer EXCLUSIVELY on retrieved memories, user profile, and history data
|
||||
- Never infer, assume, or hallucinate information
|
||||
- Always cite sources with timestamps: `[timestamp] Memory content`
|
||||
- Present conflicting information transparently with respective timestamps
|
||||
- Exhaust all search strategies before concluding information doesn't exist
|
||||
|
||||
**Output Format**:
|
||||
When information is found:
|
||||
```
|
||||
[timestamp] Relevant memory/profile/history content
|
||||
[timestamp] Additional relevant content
|
||||
```
|
||||
|
||||
When no information is found after thorough search (5+ queries across phases):
|
||||
```
|
||||
No relevant information found after exhaustive search using multiple query strategies and retrieval phases.
|
||||
```
|
||||
|
||||
user_message: |
|
||||
Answer the question following the retrieval strategy and response requirements above.
|
||||
Retrieve relevant memories following the multi-phase strategy outlined above.
|
||||
|
|
@ -99,6 +99,7 @@ class PersonalSummarizer(BaseMemoryAgent):
|
|||
else:
|
||||
tools_s2, messages_s2, success_s2 = [], [], True
|
||||
|
||||
answer = (messages_s1[-1].content if success_s1 else "") + (messages_s2[-1].content if success_s2 else "")
|
||||
success = success_s1 and success_s2
|
||||
messages = messages_s1 + messages_s2
|
||||
tools = tools_s1 + tools_s2
|
||||
|
|
@ -108,8 +109,9 @@ class PersonalSummarizer(BaseMemoryAgent):
|
|||
memory_nodes.extend(tool.memory_nodes)
|
||||
|
||||
return {
|
||||
"answer": memory_nodes,
|
||||
"answer": answer,
|
||||
"success": success,
|
||||
"messages": messages,
|
||||
"tools": tools,
|
||||
"memory_nodes": memory_nodes,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,51 +1,5 @@
|
|||
system_prompt_s1_zh: |
|
||||
你是一个记忆Agent,负责管理关于 {memory_target} 的 {memory_type} 类型记忆。
|
||||
|
||||
## 最新对话
|
||||
Format: round<index> [<timestamp>] <role/name>: <content>
|
||||
{context}
|
||||
|
||||
## 任务
|
||||
### 步骤1
|
||||
根据`最新对话`的内容,在 `add_draft_and_retrieve_similar_memory` 中创建记忆草稿 `memory_draft`。
|
||||
工具会根据memory_draft的内容行向量检索,返回历史相似记忆,确保在第二步的时候更好的管理记忆库记忆。
|
||||
|
||||
### 步骤2
|
||||
使用`update_memory`更新向量库记忆。
|
||||
通过`memory_ids_to_delete`删除历史记忆,`memories_to_add`添加新记忆,包括message_time和memory_content。
|
||||
要求:
|
||||
- 原样提取最新对话中的内容,不得推断、假设或编造。
|
||||
- 最后记忆库包含所有的历史记忆和新的记忆,例如记录在同一个主题下用户不同时间的变化。
|
||||
- 最后记忆库有比较好的组织,同一主题的记忆放到同一条中,不要有重复/多余的记忆。
|
||||
|
||||
user_message_s1_zh: |
|
||||
严格按照步骤1和步骤2完成任务
|
||||
|
||||
system_prompt_s2_zh: |
|
||||
你是一个Profile Agent,负责管理关于 {memory_target} 的 Profile。
|
||||
|
||||
## 最新对话
|
||||
Format: round<index> [<timestamp>] <role/name>: <content>
|
||||
{context}
|
||||
|
||||
## 任务
|
||||
### 步骤1
|
||||
根据`最新对话`的内容,在 `add_draft_and_read_all_profiles` 中创建记忆草稿 `profile_draft`。
|
||||
工具会直接返回所有的Profile,确保在第二步的时候更好的管理Profile。
|
||||
|
||||
### 步骤2
|
||||
使用`update_profile`更新profile库。
|
||||
通过`profile_ids_to_delete`删除历史Profile,`profiles_to_add`添加新Profile,包括message_time、profile_key和profile_value。
|
||||
要求:
|
||||
- 原样提取最新对话中的内容,不得推断、假设或编造。
|
||||
- 最后Profile库只保留用户最新的状态。例如用户开始喜欢吃苹果,后来只吃喜欢香蕉,可以记录:水果偏好:香蕉
|
||||
- 最后Profile库有比较好的组织,同一主题的Profile放到同一条中,不要有重复/多余的Profile。
|
||||
|
||||
user_message_s2_zh: |
|
||||
严格按照步骤1和步骤2完成任务
|
||||
|
||||
system_prompt_s1: |
|
||||
You are a Memory Agent responsible for managing {memory_type} type memories about {memory_target}.
|
||||
You are a Memory Agent responsible for managing {memory_type} memories about {memory_target}.
|
||||
|
||||
## Latest Conversation
|
||||
Format: round<index> [<timestamp>] <role/name>: <content>
|
||||
|
|
@ -53,22 +7,23 @@ system_prompt_s1: |
|
|||
|
||||
## Task
|
||||
### Step 1
|
||||
Based on the content of `Latest Conversation`, create a memory draft `memory_draft` in `add_draft_and_retrieve_similar_memory`.
|
||||
The tool will perform vector retrieval based on the content of memory_draft and return historically similar memories to better manage the memory store in Step 2.
|
||||
Create a memory draft in `add_draft_and_retrieve_similar_memory` based on the latest conversation.
|
||||
Use actual names from the conversation (e.g., "Bob likes apples") instead of generic references (e.g., "user likes apples"). Always record memories with real names.
|
||||
The tool will retrieve similar historical memories via vector search to help you consolidate the memory store in Step 2.
|
||||
|
||||
### Step 2
|
||||
Use `update_memory` to update the vector store memories.
|
||||
Delete historical memories through `memory_ids_to_delete`, add new memories through `memories_to_add`, including message_time and memory_content.
|
||||
Update the vector store using `update_memory`.
|
||||
Remove outdated memories via `memory_ids_to_delete` and add new ones via `memories_to_add` with their message_time and memory_content.
|
||||
Requirements:
|
||||
- Extract content from the latest conversation as-is, without inference, assumption, or fabrication.
|
||||
- The final memory store should contain all historical memories and new memories, for example, recording user changes at different times under the same topic.
|
||||
- The final memory store should be well-organized, with memories on the same topic placed in one entry, without duplicate/redundant memories.
|
||||
- Extract only what's explicitly stated in the conversation—no inferences, assumptions, or fabrications.
|
||||
- Preserve all relevant historical and new memories, capturing how things change over time within the same topic.
|
||||
- Keep the memory store well-organized: group related memories together and eliminate redundancy.
|
||||
|
||||
user_message_s1: |
|
||||
Strictly complete the task following Step 1 and Step 2
|
||||
Complete the task by following Step 1 and Step 2 in order
|
||||
|
||||
system_prompt_s2: |
|
||||
You are a Profile Agent responsible for managing the Profile about {memory_target}.
|
||||
You are a Profile Agent responsible for managing profiles about {memory_target}.
|
||||
|
||||
## Latest Conversation
|
||||
Format: round<index> [<timestamp>] <role/name>: <content>
|
||||
|
|
@ -76,16 +31,15 @@ system_prompt_s2: |
|
|||
|
||||
## Task
|
||||
### Step 1
|
||||
Based on the content of `Latest Conversation`, create a profile draft `profile_draft` in `add_draft_and_read_all_profiles`.
|
||||
The tool will directly return all Profiles to better manage the Profile store in Step 2.
|
||||
Create a profile draft in `add_draft_and_read_all_profiles` based on the latest conversation.
|
||||
The tool will return all existing profiles to help you maintain the profile store in Step 2.
|
||||
|
||||
### Step 2
|
||||
Use `update_profile` to update the profile store.
|
||||
Delete historical Profiles through `profile_ids_to_delete`, add new Profiles through `profiles_to_add`, including message_time, profile_key, and profile_value.
|
||||
Update the profile store using `update_profile`.
|
||||
Remove conflicting or redundant entries profiles via `profile_ids_to_delete` and add new ones via `profiles_to_add` with their message_time, profile_key, and profile_value.
|
||||
Requirements:
|
||||
- Extract content from the latest conversation as-is, without inference, assumption, or fabrication.
|
||||
- The final Profile store should only keep the user's latest state. For example, if the user initially liked apples but later only likes bananas, record: Fruit preference: banana
|
||||
- The final Profile store should be well-organized, with Profiles on the same topic placed in one entry, without duplicate/redundant Profiles.
|
||||
- Extract only what's explicitly stated in the conversation—no inferences, assumptions, or fabrications.
|
||||
- Keep the profile store well-organized: group related profiles together and eliminate duplicates.
|
||||
|
||||
user_message_s2: |
|
||||
Strictly complete the task following Step 1 and Step 2
|
||||
Complete the task by following Step 1 and Step 2 in order
|
||||
|
|
|
|||
|
|
@ -5,15 +5,21 @@ system_prompt: |
|
|||
{context}
|
||||
|
||||
## Available Memory Agents
|
||||
Each line indicates a specialized Memory Agent that is an expert for retrieving memories about a specific memory_target.
|
||||
Each line below is a JSON object representing a specialized Memory Agent:
|
||||
- `agent`: Description of what this agent specializes in
|
||||
- `memory_target`: The unique identifier for this agent (THIS IS WHAT YOU MUST USE)
|
||||
|
||||
{meta_memory_info}
|
||||
|
||||
## Your Task
|
||||
Analyze the context and delegate retrieval tasks to appropriate specialized agents:
|
||||
1. Examine the context content and identify which memory_target(s) are relevant for retrieving information
|
||||
1. Examine the context content and identify which memory_target(s) from the "Available Memory Agents" list above should be queried for relevant information
|
||||
2. For each relevant memory_target, delegate the retrieval task to its corresponding specialized agent
|
||||
- The memory_target must **exactly match** existing entries in the "Available Memory Agents" listed above
|
||||
- Do NOT delegate to agents that don't exist above
|
||||
- **CRITICAL**: The memory_target must be EXACTLY one of the `memory_target` field values from the JSON objects listed in "Available Memory Agents" above
|
||||
- **DO NOT** extract or create new memory_target names from the context content
|
||||
- **DO NOT** use topic names, entity names, descriptions, or any other identifiers from the context as memory_targets
|
||||
- **DO NOT** use the agent description text as memory_target
|
||||
- **ONLY** use the exact string values from the `memory_target` fields in the JSON objects above
|
||||
- Each memory_target should be assigned **only once** - do not duplicate assignments
|
||||
3. Use the `delegate_task` tool **once** with all relevant memory_target(s) to enable parallel processing by specialized agents
|
||||
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ class ReMeSummarizer(BaseMemoryAgent):
|
|||
success = success and agent.response.success
|
||||
messages.extend(agent.response.metadata["messages"])
|
||||
tools.extend(agent.response.metadata["tools"])
|
||||
memory_nodes.extend(agent.response.answer)
|
||||
memory_nodes.extend(agent.response.metadata["memory_nodes"])
|
||||
|
||||
return {
|
||||
"answer": memory_nodes,
|
||||
|
|
|
|||
|
|
@ -5,15 +5,21 @@ system_prompt: |
|
|||
{context}
|
||||
|
||||
## Available Memory Agents
|
||||
Each line indicates a specialized Memory Agent that is an expert for summarizing memories about a specific memory_target.
|
||||
Each line below is a JSON object representing a specialized Memory Agent:
|
||||
- `agent`: Description of what this agent specializes in
|
||||
- `memory_target`: The unique identifier for this agent (THIS IS WHAT YOU MUST USE)
|
||||
|
||||
{meta_memory_info}
|
||||
|
||||
## Your Task
|
||||
Analyze the context and delegate summarization tasks to appropriate specialized agents:
|
||||
1. Examine the context content and identify which memory_target(s) are relevant for storing information
|
||||
1. Examine the context content and identify which memory_target(s) from the "Available Memory Agents" list above should receive this information
|
||||
2. For each relevant memory_target, delegate the summarization task to its corresponding specialized agent
|
||||
- The memory_target must **exactly match** existing entries in the "Available Memory Agents" listed above
|
||||
- Do NOT delegate to agents that don't exist above
|
||||
- **CRITICAL**: The memory_target must be EXACTLY one of the `memory_target` field values from the JSON objects listed in "Available Memory Agents" above
|
||||
- **DO NOT** extract or create new memory_target names from the context content
|
||||
- **DO NOT** use topic names, preference categories, descriptions, or any other identifiers from the context as memory_targets
|
||||
- **DO NOT** use the agent description text as memory_target
|
||||
- **ONLY** use the exact string values from the `memory_target` fields in the JSON objects above
|
||||
- Each memory_target should be assigned **only once** - do not duplicate assignments
|
||||
3. Use the `delegate_task` tool **once** with all relevant memory_target(s) to enable parallel processing by specialized agents
|
||||
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ class ReMe(Application):
|
|||
user_name: str | list[str] = "",
|
||||
task_name: str | list[str] = "",
|
||||
tool_name: str | list[str] = "",
|
||||
enable_thinking_params: bool = False,
|
||||
enable_thinking_params: bool = True,
|
||||
version: str = "default",
|
||||
retrieve_top_k: int = 20,
|
||||
return_dict: bool = False,
|
||||
|
|
@ -211,7 +211,7 @@ class ReMe(Application):
|
|||
user_name: str | list[str] = "",
|
||||
task_name: str | list[str] = "",
|
||||
tool_name: str | list[str] = "",
|
||||
enable_thinking_params: bool = False,
|
||||
enable_thinking_params: bool = True,
|
||||
version: str = "default",
|
||||
retrieve_top_k: int = 20,
|
||||
enable_time_filter: bool = True,
|
||||
|
|
|
|||
|
|
@ -11,25 +11,43 @@ from ...core.utils import deduplicate_memories
|
|||
class AddDraftAndRetrieveSimilarMemory(BaseMemoryTool):
|
||||
"""Tool to add draft memory and retrieve similar memories"""
|
||||
|
||||
def __init__(self, top_k: int = 20, enable_memory_target: bool = False, **kwargs):
|
||||
def __init__(
|
||||
self,
|
||||
top_k: int = 20,
|
||||
enable_memory_target: bool = False,
|
||||
enable_when_to_use: bool = False,
|
||||
**kwargs,
|
||||
):
|
||||
super().__init__(**kwargs)
|
||||
self.top_k: int = top_k
|
||||
self.enable_memory_target: bool = enable_memory_target
|
||||
self.enable_when_to_use: bool = enable_when_to_use
|
||||
|
||||
def _build_query_parameters(self) -> dict:
|
||||
"""Build the query parameters schema"""
|
||||
properties = {
|
||||
"memory_draft": {
|
||||
"message_time": {
|
||||
"type": "string",
|
||||
"description": "memory_draft",
|
||||
"description": "message time, e.g. '2020-01-01 00:00:00'",
|
||||
},
|
||||
"memory_content": {
|
||||
"type": "string",
|
||||
"description": "content of the memory.",
|
||||
},
|
||||
}
|
||||
required = ["memory_draft"]
|
||||
required = ["message_time", "memory_content"]
|
||||
|
||||
if self.enable_when_to_use:
|
||||
properties["when_to_use"] = {
|
||||
"type": "string",
|
||||
"description": "description of when to use this memory.",
|
||||
}
|
||||
required.append("when_to_use")
|
||||
|
||||
if self.enable_memory_target:
|
||||
properties["memory_target"] = {
|
||||
"type": "string",
|
||||
"description": "memory_target",
|
||||
"description": "target memory type for this memory.",
|
||||
}
|
||||
required.append("memory_target")
|
||||
|
||||
|
|
@ -56,7 +74,7 @@ class AddDraftAndRetrieveSimilarMemory(BaseMemoryTool):
|
|||
"properties": {
|
||||
"draft_items": {
|
||||
"type": "array",
|
||||
"description": "List of draft memory items.",
|
||||
"description": "draft_items",
|
||||
"items": self._build_query_parameters(),
|
||||
},
|
||||
},
|
||||
|
|
@ -82,7 +100,7 @@ class AddDraftAndRetrieveSimilarMemory(BaseMemoryTool):
|
|||
|
||||
queries_by_target[target].append(
|
||||
{
|
||||
"query": item["memory_draft"],
|
||||
"query": item["memory_content"],
|
||||
"limit": self.top_k,
|
||||
"filters": {},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -31,24 +31,32 @@ class DelegateTask(BaseMemoryTool):
|
|||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"memory_target_tasks": {
|
||||
"tasks": {
|
||||
"type": "array",
|
||||
"description": "List of memory_target tasks to delegate to specific memory agents",
|
||||
"description": "List of tasks to delegate to specific memory agents",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A memory_target identifier to delegate to the corresponding agent",
|
||||
"type": "object",
|
||||
"description": "A task item",
|
||||
"properties": {
|
||||
"memory_target": {
|
||||
"type": "string",
|
||||
"description": "The memory_target identifier to "
|
||||
"delegate to the corresponding agent",
|
||||
},
|
||||
},
|
||||
"required": ["memory_target"],
|
||||
},
|
||||
},
|
||||
},
|
||||
"required": ["memory_target_tasks"],
|
||||
"required": ["tasks"],
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
async def execute(self):
|
||||
# Deduplicate and validate memory_target_tasks
|
||||
memory_target_tasks = self.context.get("memory_target_tasks", [])
|
||||
memory_target_tasks = sorted(set(memory_target_tasks))
|
||||
# Deduplicate and validate tasks
|
||||
tasks = self.context.get("tasks", [])
|
||||
memory_target_tasks = sorted(set(task["memory_target"] for task in tasks))
|
||||
|
||||
# Submit memory_target_tasks to agents
|
||||
agent_list: list[BaseMemoryAgent] = []
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue