mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Python: Context providers abstraction and Mem0 implementation (#631)
* Added context provider abstractions * Added mem0 implementation * Example and small fixes * Added unit tests for agent * Added unit tests for mem0 provider * Updated README * Small doc updates * Update python/packages/mem0/agent_framework_mem0/_provider.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Small fixes in tests * Renaming based on PR feedback * Small fixes * Added tests for AggregateContextProvider * Small improvements * More improvements based on PR feedback * Small constant update * Added more examples * Added README for Mem0 examples * Small updates to API * Updated initialization logic * Updates for context manager * Updated Context class * Dependency update * Revert changes * Fixed tests --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Chris <66376200+crickman@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
Unverified
parent
89c8418705
commit
57d09afe04
@@ -0,0 +1,51 @@
|
||||
# Mem0 Context Provider Examples
|
||||
|
||||
[Mem0](https://mem0.ai/) is a self-improving memory layer for Large Language Models that enables applications to have long-term memory capabilities. The Agent Framework's Mem0 context provider integrates with Mem0's API to provide persistent memory across conversation sessions.
|
||||
|
||||
This folder contains examples demonstrating how to use the Mem0 context provider with the Agent Framework for persistent memory and context management across conversations.
|
||||
|
||||
## Examples
|
||||
|
||||
| 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_threads.py`](mem0_threads.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. |
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### Required Resources
|
||||
|
||||
1. [Mem0 API Key](https://app.mem0.ai/) - Sign up for a Mem0 account and get your API key
|
||||
2. Azure AI Foundry project endpoint (used in these examples)
|
||||
3. Azure CLI authentication (run `az login`)
|
||||
|
||||
## Configuration
|
||||
|
||||
### Environment Variables
|
||||
|
||||
Set the following environment variables:
|
||||
|
||||
**For Mem0:**
|
||||
- `MEM0_API_KEY`: Your Mem0 API key (alternatively, pass it as `api_key` parameter to `Mem0Provider`)
|
||||
|
||||
**For Azure AI Foundry:**
|
||||
- `FOUNDRY_PROJECT_ENDPOINT`: Your Azure AI Foundry project endpoint
|
||||
- `FOUNDRY_MODEL_DEPLOYMENT_NAME`: The name of your model deployment
|
||||
|
||||
## Key Concepts
|
||||
|
||||
### Memory Scoping
|
||||
|
||||
The Mem0 context provider supports different scoping strategies:
|
||||
|
||||
- **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
|
||||
@@ -0,0 +1,72 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import uuid
|
||||
|
||||
from agent_framework.foundry import FoundryChatClient
|
||||
from agent_framework.mem0 import Mem0Provider
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
|
||||
|
||||
def retrieve_company_report(company_code: str, detailed: bool) -> str:
|
||||
if company_code != "CNTS":
|
||||
raise ValueError("Company code not found")
|
||||
if not detailed:
|
||||
return "CNTS is a company that specializes in technology."
|
||||
return (
|
||||
"CNTS is a company that specializes in technology. "
|
||||
"It had a revenue of $10 million in 2022. It has 100 employees."
|
||||
)
|
||||
|
||||
|
||||
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.
|
||||
# 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
|
||||
# authentication option.
|
||||
# For Mem0 authentication, set Mem0 API key via "api_key" parameter or MEM0_API_KEY environment variable.
|
||||
async with (
|
||||
AzureCliCredential() as credential,
|
||||
FoundryChatClient(async_credential=credential).create_agent(
|
||||
name="FriendlyAssistant",
|
||||
instructions="You are a friendly assistant.",
|
||||
tools=retrieve_company_report,
|
||||
context_providers=Mem0Provider(user_id=user_id),
|
||||
) as agent,
|
||||
):
|
||||
# First ask the agent to retrieve a company report with no previous context.
|
||||
# The agent will not be able to invoke the tool, since it doesn't know
|
||||
# the company code or the report format, so it should ask for clarification.
|
||||
query = "Please retrieve my company report"
|
||||
print(f"User: {query}")
|
||||
result = await agent.run(query)
|
||||
print(f"Agent: {result}\n")
|
||||
|
||||
# Now tell the agent the company code and the report format that you want to use
|
||||
# and it should be able to invoke the tool and return the report.
|
||||
query = "I always work with CNTS and I always want a detailed report format. Please remember and retrieve it."
|
||||
print(f"User: {query}")
|
||||
result = await agent.run(query)
|
||||
print(f"Agent: {result}\n")
|
||||
|
||||
print("\nRequest within a new thread:")
|
||||
# Create a new thread for the agent.
|
||||
# The new thread has no context of the previous conversation.
|
||||
thread = agent.get_new_thread()
|
||||
|
||||
# Since we have the mem0 component in the thread, the agent should be able to
|
||||
# retrieve the company report without asking for clarification, as it will
|
||||
# be able to remember the user preferences from Mem0 component.
|
||||
query = "Please retrieve my company report"
|
||||
print(f"User: {query}")
|
||||
result = await agent.run(query, thread=thread)
|
||||
print(f"Agent: {result}\n")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,164 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import uuid
|
||||
|
||||
from agent_framework.foundry import FoundryChatClient
|
||||
from agent_framework.mem0 import Mem0Provider
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
|
||||
|
||||
def get_user_preferences(user_id: str) -> str:
|
||||
"""Mock function to get user preferences."""
|
||||
preferences = {
|
||||
"user123": "Prefers concise responses and technical details",
|
||||
"user456": "Likes detailed explanations with examples",
|
||||
}
|
||||
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:")
|
||||
print("-" * 40)
|
||||
|
||||
global_thread_id = str(uuid.uuid4())
|
||||
user_id = "user123"
|
||||
|
||||
async with (
|
||||
AzureCliCredential() as credential,
|
||||
FoundryChatClient(async_credential=credential).create_agent(
|
||||
name="GlobalMemoryAssistant",
|
||||
instructions="You are an assistant that remembers user preferences across conversations.",
|
||||
tools=get_user_preferences,
|
||||
context_providers=Mem0Provider(
|
||||
user_id=user_id,
|
||||
thread_id=global_thread_id,
|
||||
scope_to_per_operation_thread_id=False, # Share memories across all threads
|
||||
),
|
||||
) as global_agent,
|
||||
):
|
||||
# Store some preferences in the global scope
|
||||
query = "Remember that I prefer technical responses with code examples when discussing programming."
|
||||
print(f"User: {query}")
|
||||
result = await global_agent.run(query)
|
||||
print(f"Agent: {result}\n")
|
||||
|
||||
# Create a new thread - but memories should still be accessible due to global scope
|
||||
new_thread = global_agent.get_new_thread()
|
||||
query = "What do you know about my preferences?"
|
||||
print(f"User (new thread): {query}")
|
||||
result = await global_agent.run(query, thread=new_thread)
|
||||
print(f"Agent: {result}\n")
|
||||
|
||||
|
||||
async def example_per_operation_thread_scope() -> None:
|
||||
"""Example 2: Per-operation thread scope (memories isolated per thread).
|
||||
|
||||
Note: When scope_to_per_operation_thread_id=True, the provider is bound to a single thread
|
||||
throughout its lifetime. Use the same thread object for all operations with that provider.
|
||||
"""
|
||||
print("2. Per-Operation Thread Scope Example:")
|
||||
print("-" * 40)
|
||||
|
||||
user_id = "user123"
|
||||
|
||||
async with (
|
||||
AzureCliCredential() as credential,
|
||||
FoundryChatClient(async_credential=credential).create_agent(
|
||||
name="ScopedMemoryAssistant",
|
||||
instructions="You are an assistant with thread-scoped memory.",
|
||||
tools=get_user_preferences,
|
||||
context_providers=Mem0Provider(
|
||||
user_id=user_id,
|
||||
scope_to_per_operation_thread_id=True, # Isolate memories per thread
|
||||
),
|
||||
) as scoped_agent,
|
||||
):
|
||||
# Create a specific thread for this scoped provider
|
||||
dedicated_thread = scoped_agent.get_new_thread()
|
||||
|
||||
# Store some information in the dedicated thread
|
||||
query = "Remember that for this conversation, I'm working on a Python project about data analysis."
|
||||
print(f"User (dedicated thread): {query}")
|
||||
result = await scoped_agent.run(query, thread=dedicated_thread)
|
||||
print(f"Agent: {result}\n")
|
||||
|
||||
# Test memory retrieval in the same dedicated thread
|
||||
query = "What project am I working on?"
|
||||
print(f"User (same dedicated thread): {query}")
|
||||
result = await scoped_agent.run(query, thread=dedicated_thread)
|
||||
print(f"Agent: {result}\n")
|
||||
|
||||
# Store more information in the same thread
|
||||
query = "Also remember that I prefer using pandas and matplotlib for this project."
|
||||
print(f"User (same dedicated thread): {query}")
|
||||
result = await scoped_agent.run(query, thread=dedicated_thread)
|
||||
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 thread): {query}")
|
||||
result = await scoped_agent.run(query, thread=dedicated_thread)
|
||||
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:")
|
||||
print("-" * 40)
|
||||
|
||||
agent_id_1 = "agent_personal"
|
||||
agent_id_2 = "agent_work"
|
||||
|
||||
async with (
|
||||
AzureCliCredential() as credential,
|
||||
FoundryChatClient(async_credential=credential).create_agent(
|
||||
name="PersonalAssistant",
|
||||
instructions="You are a personal assistant that helps with personal tasks.",
|
||||
context_providers=Mem0Provider(
|
||||
agent_id=agent_id_1,
|
||||
),
|
||||
) as personal_agent,
|
||||
FoundryChatClient(async_credential=credential).create_agent(
|
||||
name="WorkAssistant",
|
||||
instructions="You are a work assistant that helps with professional tasks.",
|
||||
context_providers=Mem0Provider(
|
||||
agent_id=agent_id_2,
|
||||
),
|
||||
) as work_agent,
|
||||
):
|
||||
# Store personal information
|
||||
query = "Remember that I like to exercise at 6 AM and prefer outdoor activities."
|
||||
print(f"User to Personal Agent: {query}")
|
||||
result = await personal_agent.run(query)
|
||||
print(f"Personal Agent: {result}\n")
|
||||
|
||||
# Store work information
|
||||
query = "Remember that I have team meetings every Tuesday at 2 PM."
|
||||
print(f"User to Work Agent: {query}")
|
||||
result = await work_agent.run(query)
|
||||
print(f"Work Agent: {result}\n")
|
||||
|
||||
# Test memory isolation
|
||||
query = "What do you know about my schedule?"
|
||||
print(f"User to Personal Agent: {query}")
|
||||
result = await personal_agent.run(query)
|
||||
print(f"Personal Agent: {result}\n")
|
||||
|
||||
print(f"User to Work Agent: {query}")
|
||||
result = await work_agent.run(query)
|
||||
print(f"Work Agent: {result}\n")
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
"""Run all Mem0 thread management examples."""
|
||||
print("=== Mem0 Thread Management Example ===\n")
|
||||
|
||||
await example_global_thread_scope()
|
||||
await example_per_operation_thread_scope()
|
||||
await example_multiple_agents()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
Reference in New Issue
Block a user