feat(reme_ai): update version to 0.1.10.6 and enhance tool memory operations

This commit is contained in:
jinli.yl 2025-10-27 21:12:11 +08:00
parent 93154da4d8
commit 7e82a3179e
8 changed files with 207 additions and 174 deletions

View file

@ -4,7 +4,7 @@
<p align="center">
<a href="https://pypi.org/project/reme-ai/"><img src="https://img.shields.io/badge/python-3.12+-blue" alt="Python Version"></a>
<a href="https://pypi.org/project/reme-ai/"><img src="https://img.shields.io/badge/pypi-v0.1.10.5-blue?logo=pypi" alt="PyPI Version"></a>
<a href="https://pypi.org/project/reme-ai/"><img src="https://img.shields.io/badge/pypi-v0.1.10.6-blue?logo=pypi" alt="PyPI Version"></a>
<a href="./LICENSE"><img src="https://img.shields.io/badge/license-Apache--2.0-black" alt="License"></a>
<a href="https://github.com/modelscope/ReMe"><img src="https://img.shields.io/github/stars/modelscope/ReMe?style=social" alt="GitHub Stars"></a>
</p>
@ -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 |
|:----------------------------------------------------------------------------------------------------:|:----------------------------------------------------------------------------------------------------:|
| <p align="center"><img src="docs/_static/figure/frozenlake_failure.gif" alt="GIF 1" width="30%"></p> | <p align="center"><img src="docs/_static/figure/frozenlake_success.gif" alt="GIF 2" width="30%"></p> |
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:**

View file

@ -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__":

View file

@ -17,7 +17,7 @@ kernelspec:
<div class="flex justify-center space-x-3">
<a href="https://pypi.org/project/reme-ai/"><img src="https://img.shields.io/badge/python-3.12+-blue" alt="Python Version"></a>
<a href="https://pypi.org/project/reme-ai/"><img src="https://img.shields.io/badge/pypi-v0.1.10.5-blue?logo=pypi" alt="PyPI Version"></a>
<a href="https://pypi.org/project/reme-ai/"><img src="https://img.shields.io/badge/pypi-v0.1.10.6-blue?logo=pypi" alt="PyPI Version"></a>
<a href="./LICENSE"><img src="https://img.shields.io/badge/license-Apache--2.0-black" alt="License"></a>
<a href="https://github.com/modelscope/ReMe"><img src="https://img.shields.io/github/stars/modelscope/ReMe?style=social" alt="GitHub Stars"></a>
</div>

View file

@ -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" },

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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]