Skip to content

Add ChromaDBVectorMemory in Extensions#5308

Merged
victordibia merged 11 commits intomainfrom
chromadb_memory_ext_vd
Mar 1, 2025
Merged

Add ChromaDBVectorMemory in Extensions#5308
victordibia merged 11 commits intomainfrom
chromadb_memory_ext_vd

Conversation

@victordibia
Copy link
Copy Markdown
Contributor

@victordibia victordibia commented Jan 31, 2025

Why are these changes needed?

Shows an example of how to use the Memory interface to implement a just-in-time vector memory based on chromadb.

import os
from pathlib import Path

from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.ui import Console
from autogen_core.memory import MemoryContent, MemoryMimeType
from autogen_ext.memory.chromadb import ChromaDBVectorMemory, PersistentChromaDBVectorMemoryConfig
from autogen_ext.models.openai import OpenAIChatCompletionClient

# Initialize ChromaDB memory with custom config
chroma_user_memory = ChromaDBVectorMemory(
    config=PersistentChromaDBVectorMemoryConfig(
        collection_name="preferences",
        persistence_path=os.path.join(str(Path.home()), ".chromadb_autogen"),
        k=2,  # Return top  k results
        score_threshold=0.4,  # Minimum similarity score
    )
)
# a HttpChromaDBVectorMemoryConfig is also supported for connecting to a remote ChromaDB server

# Add user preferences to memory
await chroma_user_memory.add(
    MemoryContent(
        content="The weather should be in metric units",
        mime_type=MemoryMimeType.TEXT,
        metadata={"category": "preferences", "type": "units"},
    )
)

await chroma_user_memory.add(
    MemoryContent(
        content="Meal recipe must be vegan",
        mime_type=MemoryMimeType.TEXT,
        metadata={"category": "preferences", "type": "dietary"},
    )
)


# Create assistant agent with ChromaDB memory
assistant_agent = AssistantAgent(
    name="assistant_agent",
    model_client=OpenAIChatCompletionClient(
        model="gpt-4o",
    ),
    tools=[get_weather],
    memory=[user_memory],
)

stream = assistant_agent.run_stream(task="What is the weather in New York?")
await Console(stream)

await user_memory.close()
 ---------- user ----------
What is the weather in New York?
---------- assistant_agent ----------
[MemoryContent(content='The weather should be in metric units', mime_type='MemoryMimeType.TEXT', metadata={'category': 'preferences', 'mime_type': 'MemoryMimeType.TEXT', 'type': 'units', 'score': 0.4342913043162201, 'id': '8a8d683c-5866-41e1-ac17-08c4fda6da86'}), MemoryContent(content='The weather should be in metric units', mime_type='MemoryMimeType.TEXT', metadata={'category': 'preferences', 'mime_type': 'MemoryMimeType.TEXT', 'type': 'units', 'score': 0.4342913043162201, 'id': 'f27af42c-cb63-46f0-b26b-ffcc09955ca1'})]
---------- assistant_agent ----------
[FunctionCall(id='call_a8U3YEj2dxA065vyzdfXDtNf', arguments='{"city":"New York","units":"metric"}', name='get_weather')]
---------- assistant_agent ----------
[FunctionExecutionResult(content='The weather in New York is 23 °C and Sunny.', call_id='call_a8U3YEj2dxA065vyzdfXDtNf', is_error=False)]
---------- assistant_agent ----------
The weather in New York is 23 °C and Sunny.

Note that MemoryContent object in the MemoryQuery events have useful metadata like the score and id retrieved memories.

Related issue number

Checks

@codecov
Copy link
Copy Markdown

codecov bot commented Jan 31, 2025

Codecov Report

Attention: Patch coverage is 82.92683% with 28 lines in your changes missing coverage. Please review.

Project coverage is 75.08%. Comparing base (7bbf8e0) to head (196aabd).
Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...ges/autogen-ext/src/autogen_ext/memory/chromadb.py 82.92% 28 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #5308      +/-   ##
==========================================
+ Coverage   74.96%   75.08%   +0.11%     
==========================================
  Files         175      176       +1     
  Lines       11158    11322     +164     
==========================================
+ Hits         8365     8501     +136     
- Misses       2793     2821      +28     
Flag Coverage Δ
unittests 75.08% <82.92%> (+0.11%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@victordibia victordibia changed the title Add Example ChromadbMemory in Extensions [Draft] Add Example ChromadbMemory in Extensions Jan 31, 2025
@EItanya EItanya mentioned this pull request Feb 5, 2025
3 tasks
@gagb
Copy link
Copy Markdown
Collaborator

gagb commented Feb 13, 2025

@rickyloynd-microsoft and I discussed this PR and PR #5227.

As a user I need:
clarity -- which memory interface to use when
consistency -- no concept/code duplication

We tried the ListMemory() interface in core and the metadata field in it is useful for storing (task, insight) tuples. That replicated some of the features in #5227 but not all. We should improve clarity about this and consistency between the two APIs.

cc: @ekzhu @jackgerrits

@gagb
Copy link
Copy Markdown
Collaborator

gagb commented Feb 13, 2025

Here is the script we tried. cc @rickyloynd-microsoft

from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.ui import Console
from autogen_core.memory import ListMemory, MemoryContent, MemoryMimeType, MemoryQueryResult, UpdateContextResult
from autogen_ext.models.openai import OpenAIChatCompletionClient
from autogen_core.model_context import ChatCompletionContext
from autogen_core.models import SystemMessage


class CustomListMemory(ListMemory):


     async def update_context(
        self,
        model_context: ChatCompletionContext,
    ) -> UpdateContextResult:
        """Update the model context by appending memory content.

        This method mutates the provided model_context by adding all memories as a
        SystemMessage.

        Args:
            model_context: The context to update. Will be mutated if memories exist.

        Returns:
            UpdateContextResult containing the memories that were added to the context
        """

        if not self._contents:
            return UpdateContextResult(memories=MemoryQueryResult(results=[]))

        memory_strings = [f"{i}. {str(memory.content) + str(memory.metadata['plan']) if memory.metadata else ''}" for i, memory in enumerate(self._contents, 1)]

        if memory_strings:
            memory_context = "\nRelevant memory content (in chronological order):\n" + "\n".join(memory_strings) + "\n"
            await model_context.add_message(SystemMessage(content=memory_context))

        return UpdateContextResult(memories=MemoryQueryResult(results=self._contents))



async def main():
    # Initialize user memory
    # user_memory = ListMemory()

    user_memory = CustomListMemory()

    # Add user preferences to memory
    await user_memory.add(MemoryContent(content="plan for ordering peripherals from favorite website",
    metadata={"plan": "go to amazon.com > search for peripherals > order"}, 
    mime_type=MemoryMimeType.TEXT))

    await user_memory.add(MemoryContent(content="order meal from grubhub",
    metadata={"plan": "go to grubhub.com > order meal"},
    mime_type=MemoryMimeType.TEXT))

    assistant_agent = AssistantAgent(
        name="assistant_agent",
        model_client=OpenAIChatCompletionClient(
            model="gpt-4o-2024-08-06",
        ),
        memory=[user_memory],
    )

    # Run the agent with a task.
    stream = assistant_agent.run_stream(task="Create a plan to order a keyboard from my favorite website?")
    await Console(stream)

if __name__ == "__main__":
    import asyncio

    asyncio.run(main())

@victordibia
Copy link
Copy Markdown
Contributor Author

@gagb , thanks for the excellent example above - it indeed is in the spirit of the Memory interface. It would be great to figure out what is needed to cover functionality that is left.

Is your question on consistency related when do we use the Memory interface vs Task Centric Memory #5227 ?
I think a good way to look at it is the Memory is a base interface we provide so that anyone can inherit from it and built Memory implementations that work with the framework (and example of this being compatibility with AgentChat AssistantAgent like your example shows).

If you'd like your Memory implementation pluggable across the ecosystem, inherit from Memory

What do you think?

@gagb
Copy link
Copy Markdown
Collaborator

gagb commented Feb 15, 2025

Yeah I agree with you.

I think it would be great if Ricky's PR was using this interface.

And if that is not possible there need to be a clear reason.

@rickyloynd-microsoft rickyloynd-microsoft added the memory Covering all aspects of fast learning for agents label Feb 23, 2025
@husseinmozannar
Copy link
Copy Markdown
Contributor

@victordibia thanks for the PR! I noticed it is still in draft, are you planning on more features or are you waiting on further review/testing? If so, I can help with the later.

@victordibia
Copy link
Copy Markdown
Contributor Author

I recall having some mypy/pyright errors I needed to address. Will get back to it this today/tomorrow and share where I need help, thanks!

Copy link
Copy Markdown
Contributor

@rickyloynd-microsoft rickyloynd-microsoft left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works great!

I've tested this extensively, and used it as a template for a new Teachability(Memory) class that connects Task-Centric Memory to AssistantAgent, making the AssistantAgent fully teachable from user interactions.

@rickyloynd-microsoft
Copy link
Copy Markdown
Contributor

rickyloynd-microsoft commented Feb 26, 2025

Yeah I agree with you.

I think it would be great if Ricky's PR was using this interface.

And if that is not possible there need to be a clear reason.

As mentioned in my review, my PR #5227 now includes a Teachability(Memory) class using the same Memory interface. It's too narrow to support other features of Task-Centric Memory like self-teaching and full portability (usable by any agent or app), but a fully teachable AssistantAgent is good for users.

@victordibia
Copy link
Copy Markdown
Contributor Author

Thanks @rickyloynd-microsoft ,
I have made some minor updates and fixes mypy/pyright issues and updated tests.
It is now ready for review.

@husseinmozannar , @lspinheiro

@victordibia victordibia changed the title [Draft] Add Example ChromadbMemory in Extensions Add ChromadbMemory in Extensions Feb 27, 2025
@ekzhu ekzhu self-requested a review February 27, 2025 01:13
Comment thread python/packages/autogen-ext/src/autogen_ext/memory/chromadb.py
Comment thread python/packages/autogen-ext/pyproject.toml Outdated
@lspinheiro
Copy link
Copy Markdown
Collaborator

lspinheiro commented Feb 27, 2025

LGTM.

One design question I have is if we have any thoughts about how we could let users better customise memory manipulation. I tend to think that the vectordb part is more about the memory storage, but users may want explore different ways of memory formation and retrieval such as summarising memory of assigning importance to memory events, etc. I'm curious if the interface can allow this type of customisation in the future.

Edit: I think the add/update_context methods leave room for that but we don't seem to give much user flexibility to customise what happens in those methods right now.

@victordibia victordibia changed the title Add ChromadbMemory in Extensions Add ChromaDBVectorMemory in Extensions Feb 27, 2025
Comment thread python/packages/autogen-ext/src/autogen_ext/memory/chromadb.py Outdated
@victordibia victordibia requested a review from ekzhu March 1, 2025 00:09
@victordibia victordibia merged commit 78ef148 into main Mar 1, 2025
@victordibia victordibia deleted the chromadb_memory_ext_vd branch March 1, 2025 15:41
@victordibia victordibia mentioned this pull request Mar 13, 2025
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

memory Covering all aspects of fast learning for agents

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants