Merge pull request #30 from modelscope/import_dev

feat(reme): implement ReMeApp and decouple flowllm dependencies
This commit is contained in:
Jiaji 2025-10-23 11:54:31 +08:00 committed by GitHub
commit b17876e161
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 512 additions and 46 deletions

164
README.md
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-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.2-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,6 +28,7 @@ Personal memory helps "**understand user preferences**", task memory helps agent
## 📰 Latest Updates
- **[2025-10]** 🚀 ReMe v0.1.10.2 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.
@ -166,6 +167,45 @@ response = requests.post("http://localhost:8002/retrieve_task_memory", json={
})
```
<details>
<summary>Python import version</summary>
```python
import asyncio
from reme_ai import ReMeApp
async def main():
async with ReMeApp() as app:
# Experience Summarizer: Learn from execution trajectories
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(result)
# Retriever: Get relevant memories
result = await app.async_execute(
name="retrieve_task_memory",
workspace_id="task_workspace",
query="How to efficiently manage project progress?",
top_k=1
)
print(result)
if __name__ == "__main__":
asyncio.run(main())
```
</details>
<details>
<summary>curl version</summary>
@ -255,6 +295,46 @@ response = requests.post("http://localhost:8002/retrieve_personal_memory", json=
})
```
<details>
<summary>Python import version</summary>
```python
import asyncio
from reme_ai import ReMeApp
async def main():
async with ReMeApp() as app:
# Memory Integration: Learn from user interactions
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(result)
# Memory Retrieval: Get personal memory fragments
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(result)
if __name__ == "__main__":
asyncio.run(main())
```
</details>
<details>
<summary>curl version</summary>
@ -359,6 +439,55 @@ response = requests.post("http://localhost:8002/retrieve_tool_memory", json={
})
```
<details>
<summary>Python import version</summary>
```python
import asyncio
from reme_ai import ReMeApp
async def main():
async with ReMeApp() as app:
# Record tool execution results
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(result)
# Generate usage guidelines from history
result = await app.async_execute(
name="summary_tool_memory",
workspace_id="tool_workspace",
tool_names="web_search"
)
print(result)
# Retrieve tool guidelines before use
result = await app.async_execute(
name="retrieve_tool_memory",
workspace_id="tool_workspace",
tool_names="web_search"
)
print(result)
if __name__ == "__main__":
asyncio.run(main())
```
</details>
<details>
<summary>curl version</summary>
@ -489,6 +618,39 @@ response = requests.post("http://localhost:8002/retrieve_task_memory", json={
})
```
<details>
<summary>Python import version</summary>
```python
import asyncio
from reme_ai import ReMeApp
async def main():
async with ReMeApp() as app:
# Load pre-built memories
result = await app.async_execute(
name="vector_store",
workspace_id="appworld",
action="load",
path="./docs/library/"
)
print(result)
# Query relevant memories
result = await app.async_execute(
name="retrieve_task_memory",
workspace_id="appworld",
query="How to navigate to settings and update user profile?",
top_k=1
)
print(result)
if __name__ == "__main__":
asyncio.run(main())
```
</details>
## 🧪 Experiments
### 🌍 [Appworld Experiment](docs/cookbook/appworld/quickstart.md)

View file

@ -0,0 +1,274 @@
import asyncio
from reme_ai import ReMeApp
# ============================================
# Task Memory Management Examples
# ============================================
async def summary_task_memory():
"""
Experience Summarizer: Learn from execution trajectories
curl -X POST http://localhost:8002/summary_task_memory \
-H "Content-Type: application/json" \
-d '{
"workspace_id": "task_workspace",
"trajectories": [
{"messages": [{"role": "user", "content": "Help me create a project plan"}], "score": 1.0}
]
}'
"""
async with ReMeApp() 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)
async def retrieve_task_memory():
"""
Retriever: Get relevant memories
curl -X POST http://localhost:8002/retrieve_task_memory \
-H "Content-Type: application/json" \
-d '{
"workspace_id": "task_workspace",
"query": "How to efficiently manage project progress?",
"top_k": 1
}'
"""
async with ReMeApp() 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)
# ============================================
# Personal Memory Management Examples
# ============================================
async def summary_personal_memory():
"""
Memory Integration: Learn from user interactions
curl -X POST http://localhost:8002/summary_personal_memory \
-H "Content-Type: application/json" \
-d '{
"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"}
]}
]
}'
"""
async with ReMeApp() 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)
async def retrieve_personal_memory():
"""
Memory Retrieval: Get personal memory fragments
curl -X POST http://localhost:8002/retrieve_personal_memory \
-H "Content-Type: application/json" \
-d '{
"workspace_id": "task_workspace",
"query": "What are the users work habits?",
"top_k": 5
}'
"""
async with ReMeApp() 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)
# ============================================
# Tool Memory Management Examples
# ============================================
async def add_tool_call_result():
"""
Record tool execution results
curl -X POST http://localhost:8002/add_tool_call_result \
-H "Content-Type: application/json" \
-d '{
"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
}
]
}'
"""
async with ReMeApp() 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)
async def summary_tool_memory():
"""
Generate usage guidelines from history
curl -X POST http://localhost:8002/summary_tool_memory \
-H "Content-Type: application/json" \
-d '{
"workspace_id": "tool_workspace",
"tool_names": "web_search"
}'
"""
async with ReMeApp() 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)
async def retrieve_tool_memory():
"""
Retrieve tool guidelines before use
curl -X POST http://localhost:8002/retrieve_tool_memory \
-H "Content-Type: application/json" \
-d '{
"workspace_id": "tool_workspace",
"tool_names": "web_search"
}'
"""
async with ReMeApp() 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)
# ============================================
# Vector Store Management Example
# ============================================
async def load_vector_store():
"""
Load pre-built memories
curl -X POST http://localhost:8002/vector_store \
-H "Content-Type: application/json" \
-d '{
"workspace_id": "appworld",
"action": "load",
"path": "./docs/library/"
}'
"""
async with ReMeApp() 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)
# ============================================
# Main Execution
# ============================================
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()
if __name__ == "__main__":
asyncio.run(main())

View file

@ -2,17 +2,17 @@
- [ ] P0 ReMe documentation style migration: Recommend using the same doc and jupyter structure as Agentscope Runtime @jiaji
- [ ] P0 ReMe integration with agentscope Personal/Task/Tool @jinli
- [ ] P0 ReMe sample library examples [show case](https://github.com/agentscope-ai/agentscope-samples/tree/main/functionality/long_term_memory_mem0)
- [ ] P0 Decouple flowllm dependencies
- [ ] P0 ReMe support for import, improve code documentation
- [ ] P1 ReMe integration with asio tool_memory
- [ ] P2 ReMe integration with agentscope-Runtime tool_memory
- [ ] P0 ReMe sample library examples [show case](https://github.com/agentscope-ai/agentscope-samples/tree/main/functionality/long_term_memory_mem0) @jinli
- [ ] P0 Decouple flowllm dependencies @jinli
- [ ] P0 ReMe support for import, improve code documentation @jinli
- [ ] P1 ReMe integration with asio tool_memory @jinli
- [ ] P2 ReMe integration with agentscope-Runtime tool_memory @jinli
- [ ] P0 Task Memory Research Paper @zhoyin
- [ ] P1 Context interface definition
- [ ] P1 Context interface definition @jinli
- [ ] P2 Database layer interface unification
- [ ] P2 Automatic Tool Exploration Mode
- [ ] P2 Mem-Agent Exploration
- [ ] P2 Database layer interface unification @jinli
- [ ] P2 Automatic Tool Exploration Mode @wangcan
- [ ] P2 Mem-Agent Exploration @weikang
- [ ] P2 Desktop Pet Personal Assistant

View file

@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "reme_ai"
version = "0.1.10.1"
version = "0.1.10.2"
description = "Remember me"
authors = [
{ name = "jinli.yl", email = "jinli.yl@alibaba-inc.com" },
@ -41,3 +41,5 @@ reme_ai = [
[project.scripts]
reme = "reme_ai.app:main"
# python -m build && twine upload dist/*

View file

@ -1,14 +1,7 @@
import warnings
from pydantic.warnings import PydanticDeprecatedSince20
warnings.filterwarnings("ignore", category=DeprecationWarning, module="websockets")
warnings.filterwarnings("ignore", category=DeprecationWarning, module="uvicorn")
warnings.filterwarnings("ignore", category=PydanticDeprecatedSince20)
from .app import ReMeApp
from . import agent
from . import retrieve
from . import summary
from . import vector_store
__version__ = "0.1.10.1"
__version__ = "0.1.10.2"

View file

@ -3,13 +3,12 @@ import json
import random
from typing import Dict, Any
from loguru import logger
from flowllm.context import FlowContext, C
from flowllm.enumeration.role import Role
from flowllm.op.base_async_tool_op import BaseAsyncToolOp
from flowllm.schema.message import Message
from flowllm.schema.tool_call import ToolCall
from loguru import logger
@C.register_op()
@ -254,9 +253,9 @@ class LLMMockSearchOp(BaseAsyncToolOp):
async def async_main():
from flowllm.app import FlowLLMApp
from reme_ai.app import ReMeApp
async with FlowLLMApp(load_default_config=True):
async with ReMeApp():
# Test with different query types
test_queries = [
"What is the capital of France?", # Simple

View file

@ -8,7 +8,6 @@ from flowllm.op.base_async_tool_op import BaseAsyncToolOp
from flowllm.schema.message import Message
from flowllm.schema.tool_call import ToolCall
from flowllm.utils.timer import Timer
from flowllm.utils.token_utils import TokenCounter
from loguru import logger
from reme_ai.agent.tools.mock_search_tools import SearchToolA, SearchToolB, SearchToolC
@ -99,7 +98,7 @@ class UseMockSearchOp(BaseAsyncToolOp):
selected_op_output = json.loads(selected_op.output)
content = selected_op_output["content"]
success = selected_op_output["success"]
token_cost = TokenCounter().count(content)
token_cost = len(content) // 4 # Estimate using a method where every 4 characters constitute one token.
time_cost = timer.time_cost
@ -118,9 +117,9 @@ class UseMockSearchOp(BaseAsyncToolOp):
async def async_main():
from flowllm.app import FlowLLMApp
from reme_ai.app import ReMeApp
async with FlowLLMApp(load_default_config=True):
async with ReMeApp():
test_queries = [
"What is the capital of France?",
"How does quantum computing work?",

View file

@ -1,15 +1,33 @@
import asyncio
import sys
from typing import List
from flowllm.app import FlowLLMApp
from flowllm import FlowLLMApp, C
from flowllm.schema.flow_response import FlowResponse
from loguru import logger
from reme_ai.config.config_parser import ConfigParser
class ReMeApp(FlowLLMApp):
def __init__(self, args: List[str] = None):
super().__init__(args=args, parser=ConfigParser)
self.registered_flows = C.flow_dict.keys()
logger.info(f"registered_flows={self.registered_flows}")
async def async_execute(self, name: str, **kwargs) -> dict:
assert name in self.registered_flows, f"Invalid flow_name={name} !"
result: FlowResponse = await self.async_execute_flow(name=name, **kwargs)
return result.model_dump()
def execute(self, name: str, **kwargs) -> dict:
return asyncio.run(self.async_execute(name=name, **kwargs))
def main():
with FlowLLMApp(args=sys.argv[1:], parser=ConfigParser) as app:
with ReMeApp(args=sys.argv[1:]) as app:
app.run_service()
if __name__ == "__main__":
main()
# python -m build && twine upload dist/*

View file

@ -185,12 +185,6 @@ llm:
params:
temperature: 0.6
wk1:
backend: openai_compatible
model_name: qwen3-30b-a3b-instruct-2507
params:
temperature: 0.6
qwen3_30b_instruct:
backend: openai_compatible
model_name: qwen3-30b-a3b-instruct-2507
@ -199,6 +193,30 @@ llm:
backend: openai_compatible
model_name: qwen3-30b-a3b-thinking-2507
qwen3_235b_instruct:
backend: openai_compatible
model_name: qwen3-235b-a22b-instruct-2507
qwen3_235b_thinking:
backend: openai_compatible
model_name: qwen3-235b-a22b-thinking-2507
qwen3_80b_instruct:
backend: openai_compatible
model_name: qwen3-next-80b-a3b-instruct
qwen3_80b_thinking:
backend: openai_compatible
model_name: qwen3-next-80b-a3b-thinking
qwen3_max_instruct:
backend: openai_compatible
model_name: qwen3-max
qwen25_max_instruct:
backend: openai_compatible
model_name: qwen-max-2025-01-25
embedding_model:
default:
backend: openai_compatible

View file

@ -1,16 +1,15 @@
from abc import abstractmethod, ABC
from typing import Optional, Dict, Any
from flowllm import FlowLLMApp
from pydantic import Field
from reme_ai.config.config_parser import ConfigParser
from reme_ai.app import ReMeApp
class AgentscopeRuntimeMemoryService(ABC):
def __init__(self):
self.app = FlowLLMApp(parser=ConfigParser, load_default_config=True)
self.app = ReMeApp()
self.session_id_dict: dict = {}
def add_session_memory_id(self, session_id: str, memory_id):

View file

@ -134,10 +134,11 @@ class ParseToolCallResultOp(BaseAsyncOp):
async def main():
"""Simple test for ParseToolCallResultOp"""
from flowllm.app import FlowLLMApp
from datetime import datetime
async with FlowLLMApp(load_default_config=True):
from reme_ai.app import ReMeApp
async with ReMeApp():
op = ParseToolCallResultOp()
# Create simple test data

View file

@ -195,13 +195,14 @@ class SummaryToolMemoryOp(BaseAsyncOp):
async def main():
from flowllm.app import FlowLLMApp
from reme_ai.summary.tool.parse_tool_call_result_op import ParseToolCallResultOp
from reme_ai.vector_store.update_vector_store_op import UpdateVectorStoreOp
from datetime import datetime, timedelta
import random
async with FlowLLMApp(load_default_config=True):
from reme_ai.app import ReMeApp
async with ReMeApp():
workspace_id = "test_workspace_complex"
tool_name = "web_search_tool"