mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Python: Remove unsupported memory scoping params from mem0/redis samples and docs (#4367)
* Python: Remove unsupported memory scoping params from samples and docs Fixes #4353 The `Mem0ContextProvider` and `RedisContextProvider` no longer support `thread_id` or `scope_to_per_operation_thread_id` parameters. This commit updates the affected samples and READMEs to use only the currently supported API (`user_id`, `agent_id`, `application_id`). Changes: - mem0_sessions.py: Remove `thread_id` and `scope_to_per_operation_thread_id` from examples 1 and 2, rewrite to demonstrate user-scoped and agent-scoped memory patterns - redis_sessions.py: Update module docstring to remove references to removed thread scoping params - mem0/README.md: Update Memory Scoping docs to reflect current API - redis/README.md: Remove `thread_id` and `scope_to_per_operation_thread_id` references from docs * Address Copilot review: rename thread_scope functions, fix docstring - Rename `example_global_thread_scope` -> `example_global_memory_scope` - Rename `example_per_operation_thread_scope` -> `example_agent_scoped_memory` - Update example 2 docstring to mention `application_id` alongside `user_id` and `agent_id` since it's set in the provider config - Update module docstring scenario 2 to include `application_id` * fix: rebase onto main, address giles17 review feedback - Resolve merge conflicts by rebasing all 4 original files onto current main - Address giles17's agent review suggestions: - mem0_basic.py: update comment to remove thread_id from scoping list - mem0_oss.py: update comment to remove thread_id from scoping list - redis_sessions.py: rename Example 2 from "Agent-Scoped Memory" to "Hybrid Vector Search" to accurately describe what it demonstrates - redis/README.md: update Example 2 description to match renamed example --------- Co-authored-by: Tao Chen <taochen@microsoft.com> Co-authored-by: Giles Odigwe <79032838+giles17@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
Unverified
parent
3a49b1d6dd
commit
1e527a328c
@@ -9,7 +9,7 @@ This folder contains examples demonstrating how to use the Mem0 context provider
|
||||
| File | Description |
|
||||
|------|-------------|
|
||||
| [`mem0_basic.py`](mem0_basic.py) | Basic example of using Mem0 context provider to store and retrieve user preferences across different conversation threads. |
|
||||
| [`mem0_sessions.py`](mem0_sessions.py) | Advanced example demonstrating different thread scoping strategies with Mem0. Covers global thread scope (memories shared across all operations), per-operation thread scope (memories isolated per thread), and multiple agents with different memory configurations for personal vs. work contexts. |
|
||||
| [`mem0_sessions.py`](mem0_sessions.py) | Example demonstrating different memory scoping strategies with Mem0. Covers user-scoped memory (memories shared across all sessions for the same user), agent-scoped memory (memories isolated per agent), and multiple agents with different memory configurations for personal vs. work contexts. |
|
||||
| [`mem0_oss.py`](mem0_oss.py) | Example of using the Mem0 Open Source self-hosted version as the context provider. Demonstrates setup and configuration for local deployment. |
|
||||
|
||||
## Prerequisites
|
||||
@@ -40,16 +40,8 @@ Set the following environment variables:
|
||||
|
||||
### Memory Scoping
|
||||
|
||||
The Mem0 context provider supports different scoping strategies:
|
||||
The Mem0 context provider supports scoping via identifiers:
|
||||
|
||||
- **Global Scope** (`scope_to_per_operation_thread_id=False`): Memories are shared across all conversation threads
|
||||
- **Thread Scope** (`scope_to_per_operation_thread_id=True`): Memories are isolated per conversation thread
|
||||
|
||||
### Memory Association
|
||||
|
||||
Mem0 records can be associated with different identifiers:
|
||||
|
||||
- `user_id`: Associate memories with a specific user
|
||||
- `agent_id`: Associate memories with a specific agent
|
||||
- `thread_id`: Associate memories with a specific conversation thread
|
||||
- `application_id`: Associate memories with an application context
|
||||
- **User scope** (`user_id`): Associate memories with a specific user, shared across all sessions
|
||||
- **Agent scope** (`agent_id`): Isolate memories per agent persona
|
||||
- **Application scope** (`application_id`): Associate memories with an application context
|
||||
|
||||
@@ -31,7 +31,7 @@ def retrieve_company_report(company_code: str, detailed: bool) -> str:
|
||||
async def main() -> None:
|
||||
"""Example of memory usage with Mem0 context provider."""
|
||||
print("=== Mem0 Context Provider Example ===")
|
||||
# Each record in Mem0 should be associated with agent_id or user_id or application_id or thread_id.
|
||||
# Each record in Mem0 should be associated with agent_id or user_id or application_id.
|
||||
# In this example, we associate Mem0 records with user_id.
|
||||
user_id = str(uuid.uuid4())
|
||||
# For Azure authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
|
||||
|
||||
@@ -32,7 +32,7 @@ def retrieve_company_report(company_code: str, detailed: bool) -> str:
|
||||
async def main() -> None:
|
||||
"""Example of memory usage with local Mem0 OSS context provider."""
|
||||
print("=== Mem0 Context Provider Example ===")
|
||||
# Each record in Mem0 should be associated with agent_id or user_id or application_id or thread_id.
|
||||
# Each record in Mem0 should be associated with agent_id or user_id or application_id.
|
||||
# In this example, we associate Mem0 records with user_id.
|
||||
user_id = str(uuid.uuid4())
|
||||
# For Azure authentication, run `az login` command in terminal or replace AzureCliCredential with preferred
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import uuid
|
||||
|
||||
from agent_framework import Agent, tool
|
||||
from agent_framework.foundry import FoundryChatClient
|
||||
@@ -27,52 +26,49 @@ def get_user_preferences(user_id: str) -> str:
|
||||
return preferences.get(user_id, "No specific preferences found")
|
||||
|
||||
|
||||
async def example_global_thread_scope() -> None:
|
||||
"""Example 1: Global thread_id scope (memories shared across all operations)."""
|
||||
print("1. Global Thread Scope Example:")
|
||||
async def example_user_scoped_memory() -> None:
|
||||
"""Example 1: User-scoped memory (memories shared across all sessions for the same user)."""
|
||||
print("1. User-Scoped Memory Example:")
|
||||
print("-" * 40)
|
||||
|
||||
global_thread_id = str(uuid.uuid4())
|
||||
user_id = "user123"
|
||||
|
||||
async with (
|
||||
AzureCliCredential() as credential,
|
||||
Agent(
|
||||
client=FoundryChatClient(credential=credential),
|
||||
name="GlobalMemoryAssistant",
|
||||
name="UserMemoryAssistant",
|
||||
instructions="You are an assistant that remembers user preferences across conversations.",
|
||||
tools=get_user_preferences,
|
||||
context_providers=[
|
||||
Mem0ContextProvider(
|
||||
source_id="mem0",
|
||||
user_id=user_id,
|
||||
thread_id=global_thread_id,
|
||||
scope_to_per_operation_thread_id=False, # Share memories across all sessions
|
||||
)
|
||||
],
|
||||
) as global_agent,
|
||||
) as user_agent,
|
||||
):
|
||||
# Store some preferences in the global scope
|
||||
# Store some preferences
|
||||
query = "Remember that I prefer technical responses with code examples when discussing programming."
|
||||
print(f"User: {query}")
|
||||
result = await global_agent.run(query)
|
||||
result = await user_agent.run(query)
|
||||
print(f"Agent: {result}\n")
|
||||
|
||||
# Create a new session - but memories should still be accessible due to global scope
|
||||
new_session = global_agent.create_session()
|
||||
# Create a new session - memories should still be accessible via user_id scoping
|
||||
new_session = user_agent.create_session()
|
||||
query = "What do you know about my preferences?"
|
||||
print(f"User (new session): {query}")
|
||||
result = await global_agent.run(query, session=new_session)
|
||||
result = await user_agent.run(query, session=new_session)
|
||||
print(f"Agent: {result}\n")
|
||||
|
||||
|
||||
async def example_per_operation_thread_scope() -> None:
|
||||
"""Example 2: Per-operation thread scope (memories isolated per session).
|
||||
async def example_agent_scoped_memory() -> None:
|
||||
"""Example 2: Agent-scoped memory (memories isolated per agent_id).
|
||||
|
||||
Note: When scope_to_per_operation_thread_id=True, the provider is bound to a single session
|
||||
throughout its lifetime. Use the same session object for all operations with that provider.
|
||||
Note: Use different agent_id values to isolate memories between different
|
||||
agent personas, even when the user_id is the same.
|
||||
"""
|
||||
print("2. Per-Operation Thread Scope Example:")
|
||||
print("2. Agent-Scoped Memory Example:")
|
||||
print("-" * 40)
|
||||
|
||||
user_id = "user123"
|
||||
@@ -82,48 +78,45 @@ async def example_per_operation_thread_scope() -> None:
|
||||
Agent(
|
||||
client=FoundryChatClient(credential=credential),
|
||||
name="ScopedMemoryAssistant",
|
||||
instructions="You are an assistant with thread-scoped memory.",
|
||||
instructions="You are an assistant with agent-scoped memory.",
|
||||
tools=get_user_preferences,
|
||||
context_providers=[
|
||||
Mem0ContextProvider(
|
||||
source_id="mem0",
|
||||
user_id=user_id,
|
||||
scope_to_per_operation_thread_id=True, # Isolate memories per session
|
||||
agent_id="scoped_assistant",
|
||||
)
|
||||
],
|
||||
) as scoped_agent,
|
||||
):
|
||||
# Create a specific session for this scoped provider
|
||||
dedicated_session = scoped_agent.create_session()
|
||||
|
||||
# Store some information in the dedicated session
|
||||
# Store some information
|
||||
query = "Remember that for this conversation, I'm working on a Python project about data analysis."
|
||||
print(f"User (dedicated session): {query}")
|
||||
result = await scoped_agent.run(query, session=dedicated_session)
|
||||
print(f"User: {query}")
|
||||
result = await scoped_agent.run(query)
|
||||
print(f"Agent: {result}\n")
|
||||
|
||||
# Test memory retrieval in the same dedicated session
|
||||
# Test memory retrieval
|
||||
query = "What project am I working on?"
|
||||
print(f"User (same dedicated session): {query}")
|
||||
result = await scoped_agent.run(query, session=dedicated_session)
|
||||
print(f"User: {query}")
|
||||
result = await scoped_agent.run(query)
|
||||
print(f"Agent: {result}\n")
|
||||
|
||||
# Store more information in the same session
|
||||
# Store more information
|
||||
query = "Also remember that I prefer using pandas and matplotlib for this project."
|
||||
print(f"User (same dedicated session): {query}")
|
||||
result = await scoped_agent.run(query, session=dedicated_session)
|
||||
print(f"User: {query}")
|
||||
result = await scoped_agent.run(query)
|
||||
print(f"Agent: {result}\n")
|
||||
|
||||
# Test comprehensive memory retrieval
|
||||
query = "What do you know about my current project and preferences?"
|
||||
print(f"User (same dedicated session): {query}")
|
||||
result = await scoped_agent.run(query, session=dedicated_session)
|
||||
print(f"User: {query}")
|
||||
result = await scoped_agent.run(query)
|
||||
print(f"Agent: {result}\n")
|
||||
|
||||
|
||||
async def example_multiple_agents() -> None:
|
||||
"""Example 3: Multiple agents with different thread configurations."""
|
||||
print("3. Multiple Agents with Different Thread Configurations:")
|
||||
"""Example 3: Multiple agents with different memory configurations."""
|
||||
print("3. Multiple Agents with Different Memory Configurations:")
|
||||
print("-" * 40)
|
||||
|
||||
agent_id_1 = "agent_personal"
|
||||
@@ -178,11 +171,11 @@ async def example_multiple_agents() -> None:
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
"""Run all Mem0 thread management examples."""
|
||||
print("=== Mem0 Thread Management Example ===\n")
|
||||
"""Run all Mem0 memory management examples."""
|
||||
print("=== Mem0 Memory Management Example ===\n")
|
||||
|
||||
await example_global_thread_scope()
|
||||
await example_per_operation_thread_scope()
|
||||
await example_user_scoped_memory()
|
||||
await example_agent_scoped_memory()
|
||||
await example_multiple_agents()
|
||||
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ This folder contains an example demonstrating how to use the Redis context provi
|
||||
| [`azure_redis_conversation.py`](azure_redis_conversation.py) | Demonstrates conversation persistence with RedisHistoryProvider and Azure Redis with Azure AD (Entra ID) authentication using credential provider. |
|
||||
| [`redis_basics.py`](redis_basics.py) | Shows standalone provider usage and agent integration. Demonstrates writing messages to Redis, retrieving context via full‑text or hybrid vector search, and persisting preferences across threads. Also includes a simple tool example whose outputs are remembered. |
|
||||
| [`redis_conversation.py`](redis_conversation.py) | Simple example showing conversation persistence with RedisContextProvider using traditional connection string authentication. |
|
||||
| [`redis_sessions.py`](redis_sessions.py) | Demonstrates thread scoping. Includes: (1) global thread scope with a fixed `thread_id` shared across operations; (2) per‑operation thread scope where `scope_to_per_operation_thread_id=True` binds memory to a single thread for the provider's lifetime; and (3) multiple agents with isolated memory via different `agent_id` values. |
|
||||
| [`redis_sessions.py`](redis_sessions.py) | Demonstrates memory scoping strategies. Includes: (1) global memory scope with `application_id`, `agent_id`, and `user_id` shared across operations; (2) hybrid vector search using a custom OpenAI vectorizer for richer context retrieval; and (3) multiple agents with isolated memory via different `agent_id` values. |
|
||||
|
||||
|
||||
## Prerequisites
|
||||
@@ -61,8 +61,7 @@ The provider supports both full‑text only and hybrid vector search:
|
||||
|
||||
- Set `vectorizer_choice` to `"openai"` or `"hf"` to enable embeddings and hybrid search.
|
||||
- When using a vectorizer, also set `vector_field_name` (e.g., `"vector"`).
|
||||
- Partition fields for scoping memory: `application_id`, `agent_id`, `user_id`, `thread_id`.
|
||||
- Thread scoping: `scope_to_per_operation_thread_id=True` isolates memory per operation thread.
|
||||
- Partition fields for scoping memory: `application_id`, `agent_id`, `user_id`.
|
||||
- Index management: `index_name`, `overwrite_redis_index`, `drop_redis_index`.
|
||||
|
||||
## What the example does
|
||||
@@ -104,8 +103,8 @@ You should see the agent responses and, when using embeddings, context retrieved
|
||||
|
||||
### Memory scoping
|
||||
|
||||
- Global scope: set `application_id`, `agent_id`, `user_id`, or `thread_id` on the provider to filter memory.
|
||||
- Per‑operation thread scope: set `scope_to_per_operation_thread_id=True` to isolate memory to the current thread created by the framework.
|
||||
- Global scope: set `application_id`, `agent_id`, or `user_id` on the provider to filter memory.
|
||||
- Agent isolation: use different `agent_id` values to keep memories separated for different agent personas.
|
||||
|
||||
### Hybrid vector search (optional)
|
||||
|
||||
@@ -118,7 +117,7 @@ You should see the agent responses and, when using embeddings, context retrieved
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- Ensure at least one of `application_id`, `agent_id`, `user_id`, or `thread_id` is set; the provider requires a scope.
|
||||
- Ensure at least one of `application_id`, `agent_id`, or `user_id` is set; the provider requires a scope.
|
||||
- Verify `FOUNDRY_PROJECT_ENDPOINT` and `FOUNDRY_MODEL` are set for the chat client.
|
||||
- If using embeddings, verify `OPENAI_API_KEY` is set and reachable.
|
||||
- Make sure Redis exposes RediSearch (Redis Stack image or managed service with search enabled).
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Redis Context Provider: Thread scoping examples
|
||||
"""Redis Context Provider: Memory scoping examples
|
||||
|
||||
This sample demonstrates how conversational memory can be scoped when using the
|
||||
Redis context provider. It covers three scenarios:
|
||||
|
||||
1) Global thread scope
|
||||
- Provide a fixed thread_id to share memories across operations/threads.
|
||||
1) Global memory scope
|
||||
- Use application_id, agent_id, and user_id to share memories across
|
||||
all operations/sessions.
|
||||
|
||||
2) Per-operation thread scope
|
||||
- Enable scope_to_per_operation_thread_id to bind the provider to a single
|
||||
thread for the lifetime of that provider instance. Use the same thread
|
||||
object for reads/writes with that provider.
|
||||
2) Hybrid vector search
|
||||
- Use a custom OpenAI vectorizer with the provider for hybrid vector search.
|
||||
Demonstrates combining full-text and semantic search for richer context
|
||||
retrieval.
|
||||
|
||||
3) Multiple agents with isolated memory
|
||||
- Use different agent_id values to keep memories separated for different
|
||||
@@ -23,7 +24,7 @@ Requirements:
|
||||
- Optionally an OpenAI API key for the chat client in this demo
|
||||
|
||||
Run:
|
||||
python redis_threads.py
|
||||
python redis_sessions.py
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
@@ -55,9 +56,9 @@ def create_chat_client() -> FoundryChatClient:
|
||||
)
|
||||
|
||||
|
||||
async def example_global_thread_scope() -> None:
|
||||
"""Example 1: Global thread_id scope (memories shared across all operations)."""
|
||||
print("1. Global Thread Scope Example:")
|
||||
async def example_global_memory_scope() -> None:
|
||||
"""Example 1: Global memory scope (memories shared across all operations)."""
|
||||
print("1. Global Memory Scope Example:")
|
||||
print("-" * 40)
|
||||
|
||||
client = create_chat_client()
|
||||
@@ -99,13 +100,13 @@ async def example_global_thread_scope() -> None:
|
||||
await provider.redis_index.delete()
|
||||
|
||||
|
||||
async def example_per_operation_thread_scope() -> None:
|
||||
"""Example 2: Per-operation thread scope (memories isolated per session).
|
||||
async def example_hybrid_vector_search() -> None:
|
||||
"""Example 2: Hybrid vector search with custom vectorizer.
|
||||
|
||||
Note: When scope_to_per_operation_thread_id=True, the provider is bound to a single session
|
||||
throughout its lifetime. Use the same session object for all operations with that provider.
|
||||
Demonstrates using a custom OpenAI vectorizer for hybrid vector search,
|
||||
combining full-text and semantic search for richer context retrieval.
|
||||
"""
|
||||
print("2. Per-Operation Thread Scope Example:")
|
||||
print("2. Hybrid Vector Search Example:")
|
||||
print("-" * 40)
|
||||
|
||||
client = create_chat_client()
|
||||
@@ -131,36 +132,33 @@ async def example_per_operation_thread_scope() -> None:
|
||||
|
||||
agent = Agent(
|
||||
client=client,
|
||||
name="ScopedMemoryAssistant",
|
||||
instructions="You are an assistant with thread-scoped memory.",
|
||||
name="HybridSearchAssistant",
|
||||
instructions="You are an assistant with hybrid vector search for richer context retrieval.",
|
||||
context_providers=[provider],
|
||||
)
|
||||
|
||||
# Create a specific session for this scoped provider
|
||||
dedicated_session = agent.create_session()
|
||||
|
||||
# Store some information in the dedicated session
|
||||
# Store some information
|
||||
query = "Remember that for this conversation, I'm working on a Python project about data analysis."
|
||||
print(f"User (dedicated session): {query}")
|
||||
result = await agent.run(query, session=dedicated_session)
|
||||
print(f"User: {query}")
|
||||
result = await agent.run(query)
|
||||
print(f"Agent: {result}\n")
|
||||
|
||||
# Test memory retrieval in the same dedicated session
|
||||
# Test memory retrieval via hybrid search
|
||||
query = "What project am I working on?"
|
||||
print(f"User (same dedicated session): {query}")
|
||||
result = await agent.run(query, session=dedicated_session)
|
||||
print(f"User: {query}")
|
||||
result = await agent.run(query)
|
||||
print(f"Agent: {result}\n")
|
||||
|
||||
# Store more information in the same session
|
||||
# Store more information
|
||||
query = "Also remember that I prefer using pandas and matplotlib for this project."
|
||||
print(f"User (same dedicated session): {query}")
|
||||
result = await agent.run(query, session=dedicated_session)
|
||||
print(f"User: {query}")
|
||||
result = await agent.run(query)
|
||||
print(f"Agent: {result}\n")
|
||||
|
||||
# Test comprehensive memory retrieval
|
||||
query = "What do you know about my current project and preferences?"
|
||||
print(f"User (same dedicated session): {query}")
|
||||
result = await agent.run(query, session=dedicated_session)
|
||||
print(f"User: {query}")
|
||||
result = await agent.run(query)
|
||||
print(f"Agent: {result}\n")
|
||||
|
||||
# Clean up the Redis index
|
||||
@@ -168,8 +166,8 @@ async def example_per_operation_thread_scope() -> None:
|
||||
|
||||
|
||||
async def example_multiple_agents() -> None:
|
||||
"""Example 3: Multiple agents with different thread configurations (isolated via agent_id) but within 1 index."""
|
||||
print("3. Multiple Agents with Different Thread Configurations:")
|
||||
"""Example 3: Multiple agents with different memory configurations (isolated via agent_id) but within 1 index."""
|
||||
print("3. Multiple Agents with Different Memory Configurations:")
|
||||
print("-" * 40)
|
||||
|
||||
client = create_chat_client()
|
||||
@@ -247,9 +245,9 @@ async def example_multiple_agents() -> None:
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
print("=== Redis Thread Scoping Examples ===\n")
|
||||
await example_global_thread_scope()
|
||||
await example_per_operation_thread_scope()
|
||||
print("=== Redis Memory Scoping Examples ===\n")
|
||||
await example_global_memory_scope()
|
||||
await example_hybrid_vector_search()
|
||||
await example_multiple_agents()
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user