Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,7 @@ pyrightconfig.json

# spec-workflow tool artifacts
.spec-workflow

# Local-only examples
examples/session_service_with_advanced_memory_sql/
examples/session_service_with_advanced_memory_redis/
2 changes: 1 addition & 1 deletion README.zh_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,7 @@ skill_tool_set = SkillToolSet(repository=repository, run_tool_kwargs=tool_kwargs

建议先看:

- Session:[examples/session_service_with_in_memory](./examples/session_service_with_in_memory/README.md) / [examples/session_service_with_redis](./examples/session_service_with_redis/README.md) / [examples/session_service_with_sql](./examples/session_service_with_sql/README.md) / [examples/session_summarizer](./examples/session_summarizer/README.md) / [examples/session_state](./examples/session_state/README.md)
- Session:[examples/session_service_with_in_memory](./examples/session_service_with_in_memory/README.md) / [examples/session_service_with_redis](./examples/session_service_with_redis/README.md) / [examples/session_service_with_sql](./examples/session_service_with_sql/README.md) / [Advanced Memory Redis 压缩](./examples/session_service_with_advanced_memory_redis/README.md) / [Advanced Memory SQL 压缩](./examples/session_service_with_advanced_memory_sql/README.md) / [examples/session_summarizer](./examples/session_summarizer/README.md) / [examples/session_state](./examples/session_state/README.md)
- Memory: [examples/memory_service_with_in_memory](./examples/memory_service_with_in_memory/README.md) / [examples/memory_service_with_redis](./examples/memory_service_with_redis/README.md) / [examples/memory_service_with_sql](./examples/memory_service_with_sql/README.md) / [examples/memory_service_with_mem0](./examples/memory_service_with_mem0/README.md) / [examples/memory_service_with_mempalace](./examples/memory_service_with_mempalace/README.md)
- Knowledge:[examples/knowledge_with_documentloader](./examples/knowledge_with_documentloader/README.md) / [examples/knowledge_with_vectorstore](./examples/knowledge_with_vectorstore/README.md) / [examples/knowledge_with_rag_agent](./examples/knowledge_with_rag_agent/README.md) / [examples/knowledge_with_searchtool_rag_agent](./examples/knowledge_with_searchtool_rag_agent/README.md) / [examples/knowledge_with_prompt_template](./examples/knowledge_with_prompt_template/README.md) / [examples/knowledge_with_custom_components](./examples/knowledge_with_custom_components/README.md)

Expand Down
6 changes: 1 addition & 5 deletions examples/memory_service_with_advanced_memory/.env
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
# Set TRPC_AGENT_API_KEY, TRPC_AGENT_BASE_URL, and TRPC_AGENT_MODEL_NAME.
TRPC_AGENT_API_KEY=
TRPC_AGENT_BASE_URL=
TRPC_AGENT_MODEL_NAME=
# Optional: enable token-based context budgeting for Advanced Memory.
# Set both model limits to enable token-based context budgeting.
TRPC_AGENT_MODEL_CONTEXT_WINDOW_TOKENS=
TRPC_AGENT_MAX_OUTPUT_TOKENS=
TRPC_AGENT_MODEL_NAME=
304 changes: 96 additions & 208 deletions examples/memory_service_with_advanced_memory/README.md

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions examples/memory_service_with_advanced_memory/agent/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

from trpc_agent_sdk.agents import LlmAgent
from trpc_agent_sdk.models import OpenAIModel
from trpc_agent_sdk.sessions.compact import AdvancedAutoCompactSummarizerFilter

from .config import get_model_config
from .prompts import INSTRUCTION
Expand All @@ -22,6 +23,7 @@ def create_agent() -> LlmAgent:
model_name=model_name,
api_key=api_key,
base_url=base_url,
filters=[AdvancedAutoCompactSummarizerFilter()],
),
instruction=INSTRUCTION,
)
51 changes: 37 additions & 14 deletions examples/memory_service_with_advanced_memory/run_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,50 @@
from pathlib import Path

from dotenv import load_dotenv
from trpc_agent_sdk.memory import AdvancedMemoryConfig
from trpc_agent_sdk.sessions import AdvancedMemorySessionService
from trpc_agent_sdk.memory.advanced_memory import AdvancedMemoryServiceConfig
from trpc_agent_sdk.memory import AdvancedMemoryService
from trpc_agent_sdk.sessions import InMemorySessionService
from trpc_agent_sdk.sessions import SessionServiceConfig
from trpc_agent_sdk.sessions.compact import AdvancedAutoCompactSummarizer
from trpc_agent_sdk.sessions.compact import AdvancedAutoCompactSummarizerConfig
from trpc_agent_sdk.sessions.compact import AdvancedAutoCompactSummarizerManager
from trpc_agent_sdk.types import Content
from trpc_agent_sdk.types import Part

from agent.agent import create_agent

load_dotenv()
load_dotenv(Path(__file__).with_name(".env"), override=True)


def create_session_service() -> AdvancedMemorySessionService:
"""Create the persistent Advanced Memory session service."""
return AdvancedMemorySessionService(
config=AdvancedMemoryConfig(root_dir=Path(__file__).resolve().parent),
session_config=SessionServiceConfig(ttl=SessionServiceConfig.create_ttl_config(
ttl_seconds=60,
cleanup_interval_seconds=5,
)),
def create_session_service() -> InMemorySessionService:
"""Create the session service with the independent Compact manager."""
compact_manager = AdvancedAutoCompactSummarizerManager(
summarizer=AdvancedAutoCompactSummarizer(
config=AdvancedAutoCompactSummarizerConfig(),
),
)
return InMemorySessionService(
session_config=SessionServiceConfig(
ttl=SessionServiceConfig.create_ttl_config(
enable=True,
ttl_seconds=60,
cleanup_interval_seconds=5,
),
store_historical_events=True,
),
summarizer_manager=compact_manager,
)


def create_memory_service() -> AdvancedMemoryService:
"""Create the independent long-term Advanced Memory service."""
memory_config = AdvancedMemoryServiceConfig(
root_dir=Path(__file__).resolve().parent,
memory_ttl_seconds=120,
memory_focus_instruction=("特别关注并主动记住用户长期稳定的兴趣爱好、"
"编程语言偏好、开发习惯和测试习惯。"),
)
return AdvancedMemoryService(config=memory_config)


async def run_turn(runner, *, user_id: str, session_id: str, prompt: str) -> None:
Expand All @@ -57,12 +81,14 @@ async def main() -> None:
"""Run two independent sessions sharing Advanced Memory."""
agent = create_agent()
session_service = create_session_service()
memory_service = create_memory_service()

from trpc_agent_sdk.runners import Runner
runner = Runner(
app_name="advanced_memory_demo",
agent=agent,
session_service=session_service,
memory_service=memory_service,
)
try:
session_one_prompts = [
Expand Down Expand Up @@ -95,9 +121,6 @@ async def main() -> None:
prompt="What do you remember about my favorite programming language?",
)

print("\n⏳ Waiting for the session TTL cleanup...")
await asyncio.sleep(125)
print("🧹 Expired Advanced Memory sessions should now be removed.")
finally:
await runner.close()

Expand Down
6 changes: 6 additions & 0 deletions examples/memory_service_with_advanced_memory_redis/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
REDIS_URL=

# Set TRPC_AGENT_API_KEY, TRPC_AGENT_BASE_URL, and TRPC_AGENT_MODEL_NAME.
TRPC_AGENT_API_KEY=
TRPC_AGENT_BASE_URL=
TRPC_AGENT_MODEL_NAME=
190 changes: 190 additions & 0 deletions examples/memory_service_with_advanced_memory_redis/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
# Advanced Memory Redis 持久化示例

本示例演示如何使用 `AdvancedMemoryService` 将长期记忆保存到 Redis,实现跨会话、跨 Python 进程的持久化记忆。

## 关键特性

- **主动式记忆**:Agent 根据对话内容主动调用工具保存长期有效的信息。
- **记忆分类**:每条记忆包含名称、描述、类型、摘要和详细内容。
- **基于记忆索引的记忆召回**:先读取 Redis 中的 `MEMORY.md` 索引,
再读取与问题相关的记忆内容。
- **Redis 持久化**:多个进程或实例使用相同的 Redis、应用名和用户 ID时,可以访问同一份长期记忆。

## Agent 层级结构说明

`AdvancedMemoryService` 通过 `Runner` 绑定到 Agent,并根据配置使用 Redis 保存记忆索引和记忆主题。Agent 通过三个工具主动管理长期记忆。

## 关键代码解释

### `save_memory`

保存或更新一条长期记忆,同时更新 Redis 中的记忆索引。

### `list_memory_index`

读取当前用户的记忆索引,帮助 Agent 找到与当前问题相关的记忆文件。

### `read_memory`

根据索引中的文件名读取完整记忆内容。

## 环境要求

- Python 3.10 或更高版本
- 可访问的 Redis 服务
- 一个可访问的 OpenAI 兼容模型服务

**启动本地 Redis:**

```bash
docker run --name advanced-memory-redis \
-p 6379:6379 \
-d redis:7-alpine
```

然后在当前目录的 `.env` 中配置:

```dotenv
REDIS_URL=redis://localhost:6379/0
```

如果容器已经存在,执行:

```bash
docker start advanced-memory-redis
```

检查 Redis:

```bash
docker exec advanced-memory-redis redis-cli PING
# PONG
```

如果使用已有的**远程 Redis 服务**,不需要执行 Docker 命令,只需要在当前目录的`.env` 中配置 Redis 连接信息:

```dotenv
REDIS_URL=redis://:password@redis.example.com:6379/0
```

如果 Redis 使用 ACL 用户名和密码:

```dotenv
REDIS_URL=redis://username:password@redis.example.com:6379/0
```

启用 TLS 时使用 `rediss` 协议:

```dotenv
REDIS_URL=rediss://username:password@redis.example.com:6380/0
```

也可以拆分配置:

```dotenv
REDIS_HOST=redis.example.com
REDIS_PORT=6379
REDIS_DB=0
REDIS_USER=your-user
REDIS_PASSWORD=your-password
REDIS_TLS=false
```

代码会优先使用 `REDIS_URL`;未设置时,才会根据这些字段构造连接串。密码包含 `@`、`:`、`/`、`#` 等特殊字符时,需要进行 URL 编码。

## 模型配置

在当前目录的 `.env` 中配置:

```dotenv
TRPC_AGENT_API_KEY=your-api-key
TRPC_AGENT_BASE_URL=https://your-llm-endpoint/v1
TRPC_AGENT_MODEL_NAME=your-model-name
```

Redis 配置请参考上面的本地 Redis 或远程 Redis 配置方式。

## 代码构建

```bash
git clone https://github.com/trpc-group/trpc-agent-python.git
cd trpc-agent-python
./build.sh
source .venv/bin/activate
```

如果已经在当前项目中创建了 Python 3.10+ 虚拟环境,也可以直接安装:

```bash
python -m pip install -e .
```

## 运行

```bash
cd examples/memory_service_with_advanced_memory_redis
source ../../.venv/bin/activate
python run_agent.py
```

脚本会依次启动写入和读取两个独立进程,验证 Redis 中的记忆可以跨进程和不同会话读取。也可以单独运行某个阶段:

```bash
python run_agent.py --phase write
python run_agent.py --phase read
```

## Redis 中的存储

记忆索引和主题内容会以 Redis key 保存,key 前缀为:

```text
advanced-memory-redis-demo:v1:*
```

查看本示例写入的 key:

```bash
docker exec advanced-memory-redis redis-cli --scan \
--pattern 'advanced-memory-redis-demo:v1:*'
```

示例中的记忆 TTL 在代码的 `AdvancedMemoryServiceConfig` 中配置为 `memory_ttl_seconds=120`。

## 运行结果(实测)

```txt
==================== WRITE PROCESS ====================

----- Runner A, query 1 -----

📝 user: Do you remember my name?
🤖 Assistant:


🔧 tool call: list_memory_index({})
📊 Tool Result: {'index_path': 'advanced-memory://redis/advanced-memory-redis-demo:v1:{advanced-memory-redis-demo:redis-demo-user}:memory:MEMORY.md', 'index': ''}
🤖 Assistant: I checked my long-term memory, but it looks like I don't have any record of your name yet — my memory index is currently empty.

If you'd like, tell me your name (or anything else you'd like me to remember about you), and I'll save it for future conversations. 😊

......

==================== READ PROCESS ====================

----- Runner B, query 1 -----

📝 user: Do you remember my name?
🔧 tool call: read_memory({'filename': 'user-identity.md'})
📊 Tool Result: {'found': True, 'filename': 'user-identity.md', 'content': "---\nname: User identity\ndescription: Alice's name and basic identity for personalization.\ntype: user\nupdated_at: 2026-09-11T05:54:20.441889+00:00\n---\nThe user's name is Alice. She introduced herself on first contact. Use this name for personalized responses.\n", 'updated_at': '2026-09-11T05:54:20.441889+00:00', 'freshness': 'today', 'freshness_notice': 'This memory was last updated today. It is a point-in-time observation and may no longer reflect the current state. Verify it when necessary, and update this memory if it is outdated or incorrect.'}
🤖 Assistant: Yes, I remember! Your name is **Alice**. 😊

I've stored that in my long-term memory so I can personalize my responses for you. Is there anything else I can help you with?

----- Runner B, query 2 -----

📝 user: Do you remember my favorite color?
🔧 tool call: read_memory({'filename': 'favorite-color.md'})
📊 Tool Result: {'found': True, 'filename': 'favorite-color.md', 'content': "---\nname: Favorite color\ndescription: Alice's favorite color.\ntype: user\nupdated_at: 2026-09-11T05:54:24.620584+00:00\n---\nAlice's favorite color is blue.\n", 'updated_at': '2026-09-11T05:54:24.620584+00:00', 'freshness': 'today', 'freshness_notice': 'This memory was last updated today. It is a point-in-time observation and may no longer reflect the current state. Verify it when necessary, and update this memory if it is outdated or incorrect.'}
🤖 Assistant: Yes, I remember! Your favorite color is **blue**. 💙
```
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Agent package for the Redis Advanced Memory example."""
27 changes: 27 additions & 0 deletions examples/memory_service_with_advanced_memory_redis/agent/agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"""Agent definition for the Redis Advanced Memory example."""

import os

from trpc_agent_sdk.agents import LlmAgent
from trpc_agent_sdk.models import OpenAIModel
from trpc_agent_sdk.tools import FunctionTool

from .tools import get_weather_report


def create_agent() -> LlmAgent:
"""Create an agent whose Runner installs Advanced Memory tools."""
api_key = os.getenv("TRPC_AGENT_API_KEY", "")
base_url = os.getenv("TRPC_AGENT_BASE_URL", "")
model_name = os.getenv("TRPC_AGENT_MODEL_NAME", "")
if not api_key or not base_url or not model_name:
raise ValueError("TRPC_AGENT_API_KEY, TRPC_AGENT_BASE_URL, and TRPC_AGENT_MODEL_NAME must be set")
return LlmAgent(
name="advanced_memory_redis_assistant",
description="A Redis-backed Advanced Memory demonstration assistant",
model=OpenAIModel(model_name=model_name, api_key=api_key, base_url=base_url),
instruction=("When the user asks you to remember a durable personal preference or fact, use save_memory. "
"When the user asks what you remember, use list_memory_index first and read_memory for the "
"relevant file. Always answer using the tool result."),
tools=[FunctionTool(get_weather_report)],
)
21 changes: 21 additions & 0 deletions examples/memory_service_with_advanced_memory_redis/agent/tools.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"""Tools for the Advanced Memory Redis example."""


def get_weather_report(city: str) -> dict:
"""Return a small deterministic weather report for a city."""
if city.lower() == "london":
return {
"status":
"success",
"report": ("The current weather in London is cloudy with a temperature of "
"18 degrees Celsius and a chance of rain."),
}
if city.lower() == "paris":
return {
"status": "success",
"report": "The weather in Paris is sunny with a temperature of 25 degrees Celsius.",
}
return {
"status": "error",
"error_message": f"Weather information for '{city}' is not available.",
}
Loading
Loading