在这篇文章中,我将向你展示如何为 AI 系统添加内存。我将向你介绍如何解决这一难题,你将看到如何为你的项目做同样的事情。
什么是人工智能代理的 "记忆"?
人类的记忆可以帮助我们回忆起过去发生的事情,而对于人工智能代理来说,记忆则涉及跟踪以前的反应和输入。一种简单但有缺陷的方法是将过去的反应存储在一个列表中,并将其作为人工智能代理的检索器。这种方法会让上下文窗口很快被无关信息填满,从而导致反应不够准确。
许多框架都提供了管理语言模型内存的解决方案,例如 mem0。
内存可以有多种分类方式。例如,你可以为每个用户、每个代理或每种请求类型建立单独的内存系统。这种方法有助于保持记忆的有序性,并与特定的上下文或交互相关。
如何为人工智能代理系统设计内存?
为了决定内存管道的精确设计,你需要考虑以下因素:
自动分析仪回顾
为了解释我所做的设计选择,让我先简要介绍一下 Auto-Analyst 系统,我为该系统开发了内存组件。
系统中共有 6 个代理,规划代理将用户查询委托给 4 个分析代理(统计、数据预处理、可视化和机器学习),还有一个代理负责纠正分析代理的错误,并将输出附加到一个脚本中执行。
为系统添加内存的原因:
内存架构
为了解决上述三个问题,我决定使用两种类型的存储器:
短期记忆
如图所示,代理的回复会转到 "汇总器",后者会将回复添加到包含以前互动的列表/检索器中。同时,代理会在提示中获取最新的交互信息,以帮助它更好地理解用户的问题。
使用摘要器的好处是,它有助于管理冗长的代理回复,其中包括 Python 代码和注释。虽然可能会增加一些延迟,但可以减少节省标记成本(可以使用更便宜的模型进行摘要)和上下文窗口的问题。
你可以调整摘要大小,并根据所需的用户体验来决定在代理提示中包含多少之前的交互。
# I used dspy to implement this, but you can easily abstract this for LangChain
# llama-index
import dspy
# This is the dspy signature for the summarizer,
# You define the prompt between """ """ after function header
# then you define inputs/outputs and give them a description
class memory_summarize_agent(dspy.Signature):
"""
You are an AI agent which helps summarize other agent responses and user-input.
Keep these instructions in mind:
- Analyze the provided text.
- Present the extracted details in bullet points:
- Agent: Include agent name
- User Goal: The user query/goal summarized, with only important information retained
- Stack_Used: All python packages used
- Actions: What actions did the agent_name take, summarize them like "Agent visualized a line chart using plotly"
"""
agent_response = dspy.InputField(desc="What the agents output, commentary and code")
user_goal = dspy.InputField(desc= "User query or intended goal")
summary = dspy.OutputField(desc ="The summary generated in the format requested")
# In dspy you add signatures to modules to build a LLM program
# I am using the pre-defined ChainOfThough module in DSPy
summarizer = dspy.ChainOfThought(memory_summarize_agent)
# Below is the example of giving the summarizer some text to summarize
# suppose we give this query to the ML agent in the auto-analyst system
# The dataset is about layoffs
user_query = "What is happening to layoffs?"
# Suppose this is the response we got from the ML agent or any other agent
# It is quite long and approximately 600 tokens
agent_response ="""Agent_Name: sk_learn_agent
The analysis will include:
1. Data cleaning and preprocessing to handle any missing values.
2. Exploratory data analysis (EDA) to visualize the trends in layoffs over time.
3. Grouping the data by relevant categories (like state and industry) to see how layoffs are distributed.
4. Plotting the results to provide a clear visual representation of the findings.
```python
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
# Assuming df_1 is the DataFrame containing the dataset
df = df_1.copy()
# Step 1: Data Cleaning
# Check for missing values
print(df.isnull().sum())
# Drop rows with missing values in critical columns
df.dropna(subset=['Number_of_Workers', 'Received_Date', 'Layoff_Closure'], inplace=True)
# Step 2: Convert 'Received_Date' to datetime
df['Received_Date'] = pd.to_datetime(df['Received_Date'])
# Step 3: Exploratory Data Analysis
# 3.1: Trend of layoffs over time
layoffs_over_time = df.groupby(df['Received_Date'].dt.to_period('M')).size()
layoffs_over_time.plot(kind='line', figsize=(12, 6), title='Monthly Layoffs Over Time')
plt.xlabel('Date')
plt.ylabel('Number of Layoffs')
plt.grid()
plt.show()
# 3.2: Distribution of layoffs by state
plt.figure(figsize=(12, 6))
sns.countplot(data=df, x='State', order=df['State'].value_counts().index)
plt.title('Distribution of Layoffs by State')
plt.xticks(rotation=45)
plt.ylabel('Number of Layoffs')
plt.show()
# 3.3: Distribution of layoffs by industry
plt.figure(figsize=(12, 6))
sns.countplot(data=df, x='Industry', order=df['Industry'].value_counts().index)
plt.title('Distribution of Layoffs by Industry')
plt.xticks(rotation=45)
plt.ylabel('Number of Layoffs')
plt.show()
# Step 4: Summary statistics
summary_stats = df.describe(include='all')
print(summary_stats)
```
This code will help us understand the trends and distributions of layoffs in the dataset, providing insights into how layoffs are changing over time and across different states and industries.
"""
# putting the query + agent_response in the summarizer
response=summarizer(user_goal = user_query, agent_response=agent_response)
# Below you can find the image of the summarizer
以下是代码生成的结果
使用摘要器后,你可以在 ChatGPT 4o-mini 的上下文窗口中容纳约 100 次以前的交互。因此,在用户经常参考以往交互的应用程序(如自动分析器)中,这将大大提升用户体验。
这些摘要有助于了解应用程序与用户之间的行为,也可用于根据用户的具体情况建立更长的记忆系统。
在与我的同事和朋友一起测试自动分析器后,我发现 LLM 生成的代码经常出现故障。虽然使用 LLM 自动修复功能解决了一些错误,但其他错误依然存在。许多用户报告说,即使修复了提示中的问题,系统还是会重复同样的错误。为了解决这个问题,我决定创建一个单独的错误知识库。之所以称之为 "记忆库",是因为它可以跟踪特定用户的错误历史。由于用户往往拥有导致特定错误的独特数据,因此该系统既可以作为全球代码修复库,也可以在单个用户层面发挥作用。
与短期记忆的例子一样,将有一个 LLM 来 "总结 "代码修正,下面是总结代理的提示。
#Using DSPy again
class error_memory_agent(dspy.Signature):
"""
Prompt for error_summarize Agent:
Agent Name: error_summarize
Purpose: To generate a concise summary of an error in Python code and provide a clear correction, along with relevant metadata and user query information. This summary will help in understanding the error and applying the correction.
Input Data:
Incorrect Python Code: (A snippet of code that produced an error)
Meta Data:
Agent Name: (Name of the agent that processed the code)
Agent Version: (Version of the agent that processed the code)
Timestamp: (When the error occurred)
User Query: (The query or task that led to the incorrect code execution)
Human-Defined Correction: (The corrected code or solution provided by a human expert)
Processing Instructions:
Error Analysis:
Analyze the incorrect Python code to determine the type of error and its cause.
Summary Creation:
Generate a brief summary of the error, highlighting the key issue in the code.
Provide a short explanation of the correction that resolves the issue.
Output Formatting:
Format the summary to include:
Error Summary: A concise description of the error.
Correction: A brief explanation of how to correct the error.
Integration:
Ensure the summary is clear and informative for future reference.
Output Data:
Error Summary:
Error Summary: (Brief description of the error)
Correction: (Concise explanation of the fix)
Example Output:
Error Summary: The IndexError occurred because the code attempted to access an element at an index that is out of range for the list.
Correction: Ensure the index is within the bounds of the list. For example, use if index < len(my_list): to check the index before accessing the list element.
"""
incorrect_code = dspy.InputField(desc="Error causing code")
error_metadata = dspy.InputField(desc="The description of the error generated, with user/agent information for context")
correction = dspy.InputField(desc="Correction suggested by AI or done manually by human")
summary = dspy.OutputField(desc="The description which must contain information about the error and how to correct it")
你可以将这些摘要加载到任何向量存储中,如 pinecone、qdrant 或 chromadb;你可以在需要时检索相关上下文。
结论
从表面上看,内存似乎是一种可根据用户或系统行为进行更新的实时检索器。然而,实现它还需要额外的步骤。本文旨在将这一概念细分为不同类别,并重点介绍应牢记的技术注意事项。自动分析器的实现旨在分享我在内存方面的经验,尤其是当你的用例比较特殊,无法直接使用预包装内存检索器时。