diff --git a/README.md b/README.md
index 55b45da7..9f223710 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
-
+
@@ -28,7 +28,7 @@ Personal memory helps "**understand user preferences**", task memory helps agent
## 📰 Latest Updates
-- **[2025-10]** 🚀 ReMe v0.1.10.5 released! Core enhancement: direct Python import support. You can now use ReMe without starting an HTTP or MCP service - simply `from reme_ai import ReMeApp` and call methods directly in your Python code.
+- **[2025-10]** 🚀 ReMe v0.1.10.6 released! Core enhancement: direct Python import support. You can now use ReMe without starting an HTTP or MCP service - simply `from reme_ai import ReMeApp` and call methods directly in your Python code.
- **[2025-10]** 🔧 Tool Memory support is now available! Enables data-driven tool selection and parameter optimization through historical performance tracking. Check out the [Tool Memory Guide](docs/tool_memory/tool_memory.md) and [benchmark results](docs/tool_memory/tool_bench.md).
- **[2025-09]** 🎉 ReMe v0.1.9 has been officially released, adding support for asynchronous operations. It has also been
integrated into the memory service of agentscope-runtime.
@@ -685,8 +685,8 @@ You can find more details on reproducing the experiment in [quickstart.md](docs/
### 🧊 [Frozenlake Experiment](docs/cookbook/frozenlake/quickstart.md)
-| without ReMe | with ReMe |
-|:--------------------------------------------------------------------------------------------:|:--------------------------------------------------------------------------------------------:|
+| without ReMe | with ReMe |
+|:----------------------------------------------------------------------------------------------------:|:----------------------------------------------------------------------------------------------------:|
| 
| 
|
We tested on 100 random frozenlake maps using qwen3-8b:
@@ -711,10 +711,10 @@ We tested ReMe on BFCL-V3 multi-turn-base (randomly split 50train/150val) using
We evaluated Tool Memory effectiveness using a controlled benchmark with three mock search tools using Qwen3-30B-Instruct:
-| Scenario | Avg Score | Improvement |
-|-----------------------|-----------|--------------------|
-| Train (No Memory) | 0.650 | - |
-| Test (No Memory) | 0.672 | Baseline |
+| Scenario | Avg Score | Improvement |
+|------------------------|-----------|-------------|
+| Train (No Memory) | 0.650 | - |
+| Test (No Memory) | 0.672 | Baseline |
| **Test (With Memory)** | **0.772** | **+14.88%** |
**Key Findings:**
diff --git a/cookbook/simple_demo/import_usage_demo.py b/cookbook/simple_demo/import_usage_demo.py
index 0eead058..2781b804 100644
--- a/cookbook/simple_demo/import_usage_demo.py
+++ b/cookbook/simple_demo/import_usage_demo.py
@@ -7,7 +7,7 @@ from reme_ai import ReMeApp
# Task Memory Management Examples
# ============================================
-async def summary_task_memory():
+async def summary_task_memory(app: ReMeApp):
"""
Experience Summarizer: Learn from execution trajectories
@@ -20,28 +20,23 @@ async def summary_task_memory():
]
}'
"""
- async with ReMeApp(
- "llm.default.model_name=qwen3-30b-a3b-thinking-2507",
- "embedding_model.default.model_name=text-embedding-v4",
- "vector_store.default.backend=memory"
- ) as app:
- result = await app.async_execute(
- name="summary_task_memory",
- workspace_id="task_workspace",
- trajectories=[
- {
- "messages": [
- {"role": "user", "content": "Help me create a project plan"}
- ],
- "score": 1.0
- }
- ]
- )
- print("Summary Task Memory Result:")
- print(result)
+ result = await app.async_execute(
+ name="summary_task_memory",
+ workspace_id="task_workspace",
+ trajectories=[
+ {
+ "messages": [
+ {"role": "user", "content": "Help me create a project plan"}
+ ],
+ "score": 1.0
+ }
+ ]
+ )
+ print("Summary Task Memory Result:")
+ print(result["answer"])
-async def retrieve_task_memory():
+async def retrieve_task_memory(app: ReMeApp):
"""
Retriever: Get relevant memories
@@ -53,26 +48,21 @@ async def retrieve_task_memory():
"top_k": 1
}'
"""
- async with ReMeApp(
- "llm.default.model_name=qwen3-30b-a3b-thinking-2507",
- "embedding_model.default.model_name=text-embedding-v4",
- "vector_store.default.backend=memory"
- ) as app:
- result = await app.async_execute(
- name="retrieve_task_memory",
- workspace_id="task_workspace",
- query="How to efficiently manage project progress?",
- top_k=1
- )
- print("Retrieve Task Memory Result:")
- print(result)
+ result = await app.async_execute(
+ name="retrieve_task_memory",
+ workspace_id="task_workspace",
+ query="How to efficiently manage project progress?",
+ top_k=1
+ )
+ print("Retrieve Task Memory Result:")
+ print(result["answer"])
# ============================================
# Personal Memory Management Examples
# ============================================
-async def summary_personal_memory():
+async def summary_personal_memory(app: ReMeApp):
"""
Memory Integration: Learn from user interactions
@@ -88,29 +78,24 @@ async def summary_personal_memory():
]
}'
"""
- async with ReMeApp(
- "llm.default.model_name=qwen3-30b-a3b-thinking-2507",
- "embedding_model.default.model_name=text-embedding-v4",
- "vector_store.default.backend=memory"
- ) as app:
- result = await app.async_execute(
- name="summary_personal_memory",
- workspace_id="task_workspace",
- trajectories=[
- {
- "messages": [
- {"role": "user", "content": "I like to drink coffee while working in the morning"},
- {"role": "assistant",
- "content": "I understand, you prefer to start your workday with coffee to stay energized"}
- ]
- }
- ]
- )
- print("Summary Personal Memory Result:")
- print(result)
+ result = await app.async_execute(
+ name="summary_personal_memory",
+ workspace_id="task_workspace",
+ trajectories=[
+ {
+ "messages": [
+ {"role": "user", "content": "I like to drink coffee while working in the morning"},
+ {"role": "assistant",
+ "content": "I understand, you prefer to start your workday with coffee to stay energized"}
+ ]
+ }
+ ]
+ )
+ print("Summary Personal Memory Result:")
+ print(result["answer"])
-async def retrieve_personal_memory():
+async def retrieve_personal_memory(app: ReMeApp):
"""
Memory Retrieval: Get personal memory fragments
@@ -122,26 +107,21 @@ async def retrieve_personal_memory():
"top_k": 5
}'
"""
- async with ReMeApp(
- "llm.default.model_name=qwen3-30b-a3b-thinking-2507",
- "embedding_model.default.model_name=text-embedding-v4",
- "vector_store.default.backend=memory"
- ) as app:
- result = await app.async_execute(
- name="retrieve_personal_memory",
- workspace_id="task_workspace",
- query="What are the user's work habits?",
- top_k=5
- )
- print("Retrieve Personal Memory Result:")
- print(result)
+ result = await app.async_execute(
+ name="retrieve_personal_memory",
+ workspace_id="task_workspace",
+ query="What are the user's work habits?",
+ top_k=5
+ )
+ print("Retrieve Personal Memory Result:")
+ print(result["answer"])
# ============================================
# Tool Memory Management Examples
# ============================================
-async def add_tool_call_result():
+async def add_tool_call_result(app: ReMeApp):
"""
Record tool execution results
@@ -162,31 +142,26 @@ async def add_tool_call_result():
]
}'
"""
- async with ReMeApp(
- "llm.default.model_name=qwen3-30b-a3b-thinking-2507",
- "embedding_model.default.model_name=text-embedding-v4",
- "vector_store.default.backend=memory"
- ) as app:
- result = await app.async_execute(
- name="add_tool_call_result",
- workspace_id="tool_workspace",
- tool_call_results=[
- {
- "create_time": "2025-10-21 10:30:00",
- "tool_name": "web_search",
- "input": {"query": "Python asyncio tutorial", "max_results": 10},
- "output": "Found 10 relevant results...",
- "token_cost": 150,
- "success": True,
- "time_cost": 2.3
- }
- ]
- )
- print("Add Tool Call Result:")
- print(result)
+ result = await app.async_execute(
+ name="add_tool_call_result",
+ workspace_id="tool_workspace",
+ tool_call_results=[
+ {
+ "create_time": "2025-10-21 10:30:00",
+ "tool_name": "web_search",
+ "input": {"query": "Python asyncio tutorial", "max_results": 10},
+ "output": "Found 10 relevant results...",
+ "token_cost": 150,
+ "success": True,
+ "time_cost": 2.3
+ }
+ ]
+ )
+ print("Add Tool Call Result:")
+ print(result["answer"])
-async def summary_tool_memory():
+async def summary_tool_memory(app: ReMeApp):
"""
Generate usage guidelines from history
@@ -197,21 +172,16 @@ async def summary_tool_memory():
"tool_names": "web_search"
}'
"""
- async with ReMeApp(
- "llm.default.model_name=qwen3-30b-a3b-thinking-2507",
- "embedding_model.default.model_name=text-embedding-v4",
- "vector_store.default.backend=memory"
- ) as app:
- result = await app.async_execute(
- name="summary_tool_memory",
- workspace_id="tool_workspace",
- tool_names="web_search"
- )
- print("Summary Tool Memory Result:")
- print(result)
+ result = await app.async_execute(
+ name="summary_tool_memory",
+ workspace_id="tool_workspace",
+ tool_names="web_search"
+ )
+ print("Summary Tool Memory Result:")
+ print(result["answer"])
-async def retrieve_tool_memory():
+async def retrieve_tool_memory(app: ReMeApp):
"""
Retrieve tool guidelines before use
@@ -222,25 +192,20 @@ async def retrieve_tool_memory():
"tool_names": "web_search"
}'
"""
- async with ReMeApp(
- "llm.default.model_name=qwen3-30b-a3b-thinking-2507",
- "embedding_model.default.model_name=text-embedding-v4",
- "vector_store.default.backend=memory"
- ) as app:
- result = await app.async_execute(
- name="retrieve_tool_memory",
- workspace_id="tool_workspace",
- tool_names="web_search"
- )
- print("Retrieve Tool Memory Result:")
- print(result)
+ result = await app.async_execute(
+ name="retrieve_tool_memory",
+ workspace_id="tool_workspace",
+ tool_names="web_search"
+ )
+ print("Retrieve Tool Memory Result:")
+ print(result["answer"])
# ============================================
# Vector Store Management Example
# ============================================
-async def load_vector_store():
+async def load_vector_store(app: ReMeApp):
"""
Load pre-built memories
@@ -252,19 +217,14 @@ async def load_vector_store():
"path": "./docs/library/"
}'
"""
- async with ReMeApp(
- "llm.default.model_name=qwen3-30b-a3b-thinking-2507",
- "embedding_model.default.model_name=text-embedding-v4",
- "vector_store.default.backend=memory"
- ) as app:
- result = await app.async_execute(
- name="vector_store",
- workspace_id="appworld",
- action="load",
- path="./docs/library/"
- )
- print("Load Vector Store Result:")
- print(result)
+ result = await app.async_execute(
+ name="vector_store",
+ workspace_id="appworld",
+ action="load",
+ path="./docs/library/"
+ )
+ print("Load Vector Store Result:")
+ print(result["answer"])
# ============================================
@@ -273,33 +233,33 @@ async def load_vector_store():
async def main():
"""Run all examples"""
- print("=" * 60)
- print("Task Memory Examples")
- print("=" * 60)
- await summary_task_memory()
- print("\n")
- await retrieve_task_memory()
-
- print("\n" + "=" * 60)
- print("Personal Memory Examples")
- print("=" * 60)
- await summary_personal_memory()
- print("\n")
- await retrieve_personal_memory()
-
- print("\n" + "=" * 60)
- print("Tool Memory Examples")
- print("=" * 60)
- await add_tool_call_result()
- print("\n")
- await summary_tool_memory()
- print("\n")
- await retrieve_tool_memory()
-
- print("\n" + "=" * 60)
- print("Vector Store Examples")
- print("=" * 60)
- await load_vector_store()
+ async with ReMeApp(
+ "llm.default.model_name=qwen3-30b-a3b-thinking-2507",
+ "embedding_model.default.model_name=text-embedding-v4",
+ "vector_store.default.backend=memory"
+ ) as app:
+ print("=" * 60)
+ print("Task Memory Examples")
+ print("=" * 60)
+ await summary_task_memory(app)
+ print("\n")
+ await retrieve_task_memory(app)
+
+ print("\n" + "=" * 60)
+ print("Personal Memory Examples")
+ print("=" * 60)
+ await summary_personal_memory(app)
+ print("\n")
+ await retrieve_personal_memory(app)
+
+ print("\n" + "=" * 60)
+ print("Tool Memory Examples")
+ print("=" * 60)
+ await add_tool_call_result(app)
+ print("\n")
+ await summary_tool_memory(app)
+ print("\n")
+ await retrieve_tool_memory(app)
if __name__ == "__main__":
diff --git a/docs/index.md b/docs/index.md
index de898700..c56177a1 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -17,7 +17,7 @@ kernelspec:
diff --git a/pyproject.toml b/pyproject.toml
index 4bafc5b5..1d6e58c1 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "reme_ai"
-version = "0.1.10.5"
+version = "0.1.10.6"
description = "Remember me"
authors = [
{ name = "jinli.yl", email = "jinli.yl@alibaba-inc.com" },
diff --git a/reme_ai/__init__.py b/reme_ai/__init__.py
index f7ea22f2..1fc69579 100644
--- a/reme_ai/__init__.py
+++ b/reme_ai/__init__.py
@@ -2,7 +2,7 @@ import os
os.environ["FLOW_APP_NAME"] = "ReMe"
-__version__ = "0.1.10.5"
+__version__ = "0.1.10.6"
from reme_ai.app import ReMeApp
from . import agent
diff --git a/reme_ai/retrieve/tool/retrieve_tool_memory_op.py b/reme_ai/retrieve/tool/retrieve_tool_memory_op.py
index 1b909a01..558284a9 100644
--- a/reme_ai/retrieve/tool/retrieve_tool_memory_op.py
+++ b/reme_ai/retrieve/tool/retrieve_tool_memory_op.py
@@ -14,6 +14,20 @@ class RetrieveToolMemoryOp(BaseAsyncOp):
def __init__(self, **kwargs):
super().__init__(**kwargs)
+ def _format_tool_memories(self, memories: List[ToolMemory]) -> str:
+ """Format tool memories into a structured document format"""
+ lines = []
+ lines.append(f"Retrieved {len(memories)} tool memory(ies):\n")
+
+ for idx, memory in enumerate(memories, 1):
+ lines.append(f"Tool: {memory.when_to_use}")
+ lines.append(memory.content)
+
+ if idx < len(memories):
+ lines.append("\n---\n")
+
+ return "\n".join(lines)
+
async def async_execute(self):
tool_names: str = self.context.get("tool_names", "")
workspace_id: str = self.context.workspace_id
@@ -59,8 +73,11 @@ class RetrieveToolMemoryOp(BaseAsyncOp):
self.context.response.success = False
return
+ # Format tool memories as document
+ formatted_answer = self._format_tool_memories(matched_tool_memories)
+
# Set response
- self.context.response.answer = f"Successfully retrieved {len(matched_tool_memories)} tool memories"
+ self.context.response.answer = formatted_answer
self.context.response.success = True
self.context.response.metadata["memory_list"] = matched_tool_memories
diff --git a/reme_ai/summary/tool/parse_tool_call_result_op.py b/reme_ai/summary/tool/parse_tool_call_result_op.py
index e40c2812..566f367a 100644
--- a/reme_ai/summary/tool/parse_tool_call_result_op.py
+++ b/reme_ai/summary/tool/parse_tool_call_result_op.py
@@ -24,6 +24,37 @@ class ParseToolCallResultOp(BaseAsyncOp):
self.max_history_tool_call_cnt: int = max_history_tool_call_cnt
self.evaluation_sleep_interval: float = evaluation_sleep_interval
+ def _format_tool_memories_summary(self, memory_list: List[ToolMemory], deleted_memory_ids: List[str]) -> str:
+ """Format tool memories update summary"""
+ lines = []
+
+ # 统计信息
+ total_tools = len(memory_list)
+ updated_tools = len(deleted_memory_ids)
+ new_tools = total_tools - updated_tools
+
+ lines.append(f"Processed {total_tools} tool(s): {updated_tools} updated, {new_tools} newly created\n")
+
+ # 详细信息
+ for idx, memory in enumerate(memory_list, 1):
+ is_updated = memory.memory_id in deleted_memory_ids
+ status = "Updated" if is_updated else "New"
+
+ lines.append(f"[{status}] {memory.when_to_use}")
+ lines.append(f" Total calls: {len(memory.tool_call_results)}")
+
+ # 显示最近添加的调用结果统计
+ if memory.tool_call_results:
+ recent_results = memory.tool_call_results[-3:]
+ success_count = sum(1 for r in recent_results if r.success)
+ avg_score = sum(r.score for r in recent_results) / len(recent_results)
+ lines.append(f" Recent calls: {success_count}/{len(recent_results)} successful, avg score: {avg_score:.2f}")
+
+ if idx < len(memory_list):
+ lines.append("")
+
+ return "\n".join(lines)
+
async def _evaluate_single_tool_call(self, tool_call_result: ToolCallResult, index: int) -> ToolCallResult:
await asyncio.sleep(self.evaluation_sleep_interval * index)
@@ -127,7 +158,12 @@ class ParseToolCallResultOp(BaseAsyncOp):
all_memory_list.append(tool_memory)
+ # 格式化结果信息
+ formatted_answer = self._format_tool_memories_summary(all_memory_list, all_deleted_memory_ids)
+
# 设置返回结果
+ self.context.response.answer = formatted_answer
+ self.context.response.success = True
self.context.response.metadata["deleted_memory_ids"] = all_deleted_memory_ids
self.context.response.metadata["memory_list"] = all_memory_list
diff --git a/reme_ai/summary/tool/summary_tool_memory_op.py b/reme_ai/summary/tool/summary_tool_memory_op.py
index 893337ea..5da760cb 100644
--- a/reme_ai/summary/tool/summary_tool_memory_op.py
+++ b/reme_ai/summary/tool/summary_tool_memory_op.py
@@ -23,6 +23,25 @@ class SummaryToolMemoryOp(BaseAsyncOp):
self.recent_call_count: int = recent_call_count
self.summary_sleep_interval: float = summary_sleep_interval
+ def _format_summary_result(self, summarized_memories: List[ToolMemory], skipped_memories: List[ToolMemory]) -> str:
+ """Format tool memory summary result"""
+ lines = []
+
+ # 统计信息
+ total_tools = len(summarized_memories) + len(skipped_memories)
+ lines.append(f"Processed {total_tools} tool(s): {len(summarized_memories)} summarized, {len(skipped_memories)} skipped\n")
+
+ # 显示已总结的工具详细信息
+ if summarized_memories:
+ for idx, memory in enumerate(summarized_memories, 1):
+ lines.append(f"Tool: {memory.when_to_use}")
+ lines.append(memory.content)
+
+ if idx < len(summarized_memories):
+ lines.append("\n---\n")
+
+ return "\n".join(lines)
+
@staticmethod
def _format_call_summaries_markdown(recent_calls: List) -> str:
"""Format tool call summaries as markdown."""
@@ -180,10 +199,11 @@ class SummaryToolMemoryOp(BaseAsyncOp):
# Combine summarized and skipped memories
all_memories = valid_summarized_memories + tools_skipped
+ # Format summary result
+ formatted_answer = self._format_summary_result(valid_summarized_memories, tools_skipped)
+
# Set response
- self.context.response.answer = (f"Successfully processed {len(all_memories)} tool memories: "
- f"{len(valid_summarized_memories)} summarized, "
- f"{len(tools_skipped)} skipped (already up-to-date)")
+ self.context.response.answer = formatted_answer
self.context.response.success = True
self.context.response.metadata["memory_list"] = all_memories
self.context.response.metadata["deleted_memory_ids"] = [m.memory_id for m in all_memories]