3_optimization-design-ptn/04_memory-management/01_chat-memory-AutoGen.ipynb (339 lines of code) (raw):

{ "cells": [ { "cell_type": "markdown", "id": "ea566837", "metadata": {}, "source": [ "# Long-term Chat Memory Agent with AutoGen\n", "---\n", "\n", "This example demonstrates how to create a long-term chat memory agent using the AutoGen framework. The agent is designed to remember past interactions and provide contextually relevant responses over time.\n", "\n", "- Reference: https://microsoft.github.io/autogen/stable//user-guide/agentchat-user-guide/memory.html" ] }, { "cell_type": "code", "execution_count": null, "id": "f2d5666f", "metadata": {}, "outputs": [], "source": [ "from autogen_agentchat.agents import AssistantAgent\n", "from autogen_agentchat.ui import Console\n", "from autogen_core.memory import ListMemory, MemoryContent, MemoryMimeType\n", "from autogen_core.memory import Memory, MemoryContent, MemoryMimeType\n", "\n", "from autogen_ext.models.openai import AzureOpenAIChatCompletionClient\n", "from IPython.display import display, Markdown" ] }, { "cell_type": "markdown", "id": "13563eae", "metadata": {}, "source": [ "<br>\n", "\n", "## 🧪 1. Preparation and Define the Agentic Architecture\n", "---\n", "### Initialize the Memory\n", "\n", "You can implement your own custom memory store based on the memory protocol. For example, you can implement a custom memory store that uses a vector database to store and retrieve information, or a memory store that uses machine learning models to generate personalized responses based on user preferences, etc. This example implements a memory store based on FAISS, which is not yet supported by AutoGen (as of April 2025). \n", "\n", "> **Note: There may be errors in the implementation, so please use it only for reference.**" ] }, { "cell_type": "code", "execution_count": null, "id": "5c21e486", "metadata": {}, "outputs": [], "source": [ "from src.faiss import FAISSVectorMemoryConfig, FAISSVectorMemory\n", "\n", "MEMORY_DB = \"list\" # or \"list\"\n", "assert MEMORY_DB in [\"faiss\", \"list\"], f\"Unsupported memory db: {MEMORY_DB}\"\n", "\n", "if MEMORY_DB == \"faiss\":\n", " print(\n", " \"=== Using Custom FAISS vector memory. You can refer to src/faiss.py for more details.\"\n", " )\n", " user_memory = FAISSVectorMemory(\n", " config=FAISSVectorMemoryConfig(\n", " emb_model_name=\"text-embedding-3-large\",\n", " dimension=3072,\n", " use_gpu=False,\n", " top_k=2,\n", " score_threshold=0.3,\n", " )\n", " )\n", "elif MEMORY_DB == \"list\":\n", " print(\"=== Using Built-in List memory\")\n", "\n", " user_memory = ListMemory()\n", "\n", "await user_memory.clear()" ] }, { "cell_type": "markdown", "id": "6bf998bb", "metadata": {}, "source": [ "### Add some initial memory content" ] }, { "cell_type": "code", "execution_count": null, "id": "1f698700", "metadata": {}, "outputs": [], "source": [ "async def add_memory(user_memory, content, metadata, mime_type=MemoryMimeType.TEXT):\n", " await user_memory.add(\n", " MemoryContent(\n", " content=content,\n", " mime_type=mime_type,\n", " metadata=metadata,\n", " )\n", " )" ] }, { "cell_type": "markdown", "id": "8adf5114", "metadata": {}, "source": [ "Baseline: You can add memory with the text format." ] }, { "cell_type": "code", "execution_count": null, "id": "c7d84705", "metadata": {}, "outputs": [], "source": [ "await add_memory(\n", " user_memory,\n", " \"Daekeun provides AIML technology support. Hyo is a big fan of Microsoft.\",\n", " {\"user_id\": \"1\"},\n", " MemoryMimeType.TEXT,\n", ")\n", "await add_memory(\n", " user_memory,\n", " \"Daekeun is interested in AutoGen and Semantic Kernel\",\n", " {\"user_id\": \"1\"},\n", " MemoryMimeType.TEXT,\n", ")" ] }, { "cell_type": "markdown", "id": "f0263aec", "metadata": {}, "source": [ "You can also add memory with JSON format. The memory content can be a list of dictionaries." ] }, { "cell_type": "code", "execution_count": null, "id": "c17bc0d4", "metadata": {}, "outputs": [], "source": [ "from azure_genai_utils.tools import BingSearch\n", "\n", "web_search_tool = BingSearch(\n", " max_results=2,\n", " locale=\"en-US\",\n", " include_news=False,\n", " include_entity=False,\n", " format_output=False,\n", ")\n", "\n", "# Define the tools to be used in the state graph\n", "query = \"What is AutoGen's main feature?\"\n", "results = web_search_tool.invoke(query)\n", "\n", "for i in range(1, len(results)):\n", " await add_memory(user_memory, results[i], {\"user_id\": \"1\"}, MemoryMimeType.JSON)" ] }, { "cell_type": "markdown", "id": "f6ee35d4", "metadata": {}, "source": [ "### Define the tools" ] }, { "cell_type": "code", "execution_count": null, "id": "47033a79", "metadata": {}, "outputs": [], "source": [ "from autogen_core.tools import FunctionTool\n", "\n", "\n", "def arxiv_search(query: str, max_results: int = 2) -> list: # type: ignore[type-arg]\n", " \"\"\"\n", " Search Arxiv for papers and return the results including abstracts.\n", " \"\"\"\n", " import arxiv\n", "\n", " client = arxiv.Client()\n", " search = arxiv.Search(\n", " query=query, max_results=max_results, sort_by=arxiv.SortCriterion.Relevance\n", " )\n", "\n", " results = []\n", " for paper in client.results(search):\n", " results.append(\n", " {\n", " \"title\": paper.title,\n", " \"authors\": [author.name for author in paper.authors],\n", " \"published\": paper.published.strftime(\"%Y-%m-%d\"),\n", " \"abstract\": paper.summary,\n", " \"pdf_url\": paper.pdf_url,\n", " }\n", " )\n", "\n", " # # Write results to a file\n", " # with open('arxiv_search_results.json', 'w') as f:\n", " # json.dump(results, f, indent=2)\n", "\n", " return results\n", "\n", "\n", "async def get_weather(city: str, units: str = \"imperial\") -> str:\n", " if units == \"imperial\":\n", " return f\"The weather in {city} is 73 °F and Sunny.\"\n", " elif units == \"metric\":\n", " return f\"The weather in {city} is 23 °C and Sunny.\"\n", " else:\n", " return f\"Sorry, I don't know the weather in {city}.\"\n", "\n", "\n", "arxiv_search_tool = FunctionTool(\n", " arxiv_search,\n", " description=\"Search Arxiv for papers related to a given topic, including abstracts\",\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "7552c9ec", "metadata": {}, "outputs": [], "source": [ "model_client = AzureOpenAIChatCompletionClient(\n", " model=\"gpt-4o-mini\",\n", " temperature=0.1,\n", " max_tokens=500,\n", " top_p=1,\n", ")\n", "\n", "assistant_agent = AssistantAgent(\n", " name=\"assistant_agent\",\n", " description=\"An assistant agent that can answer questions and provide information.\",\n", " model_client=model_client,\n", " tools=[get_weather, arxiv_search_tool],\n", " memory=[user_memory],\n", ")" ] }, { "cell_type": "markdown", "id": "6cde6076", "metadata": {}, "source": [ "<br>\n", "\n", "## 🧪 2. Run the agent with a task.\n", "---" ] }, { "cell_type": "code", "execution_count": null, "id": "798ba815", "metadata": {}, "outputs": [], "source": [ "stream = assistant_agent.run_stream(task=\"What is AutoGen?\")\n", "await Console(stream)" ] }, { "cell_type": "code", "execution_count": null, "id": "c6d9a937", "metadata": {}, "outputs": [], "source": [ "message = await assistant_agent._model_context.get_messages()\n", "display(Markdown(message[-1].content))" ] }, { "cell_type": "markdown", "id": "734617dc", "metadata": {}, "source": [ "### This below code cell checks if the memory is working." ] }, { "cell_type": "code", "execution_count": null, "id": "1f3731e4", "metadata": {}, "outputs": [], "source": [ "stream = assistant_agent.run_stream(task=\"Who is Daekeun?\")\n", "await Console(stream)" ] }, { "cell_type": "code", "execution_count": null, "id": "7795a969", "metadata": {}, "outputs": [], "source": [ "message = await assistant_agent._model_context.get_messages()\n", "display(Markdown(message[-1].content))" ] } ], "metadata": { "kernelspec": { "display_name": "py312-dev", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.2" } }, "nbformat": 4, "nbformat_minor": 5 }