Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Agent 记忆能力实现 #104

Open
QingyaFan opened this issue Dec 23, 2024 · 0 comments
Open

Agent 记忆能力实现 #104

QingyaFan opened this issue Dec 23, 2024 · 0 comments

Comments

@QingyaFan
Copy link
Owner

QingyaFan commented Dec 23, 2024

什么是Agent的记忆能力

LLM 是无状态的,不同的 LLM 调用之间是没有关系。1 但 Agent 可以有状态,通常引入记忆机制来支持 Agent 的上下文记忆能力。这些记忆帮助 Agent 在会话或任务中保持连续性,做出更加智能的决策。

根据保存的周期,记忆可以分为 Short-Term Memory(STM-短期记忆)和 Long-Term Memory(LTM-长期记忆)。在 CoALA Agent 中把 Agent 的Memory 分为了 Working Memory、Semantic Memory、Episodic Memory 和 Procedural Memory 四种。working memory 可以视为 STM,其余三种是 LTM。

接下来我们主要讨论 CoALA 提出的 memory部分 的理念,并讨论实现。

各类 memory

Memory分类 作用 分类
Working memory - 工作内存 用于在当前决策周期中维护活跃且随时可用的信息。这些信息包括 prompt、从LTM 中检索得到的结果、上一个决策周期继承的核心信息。working memory 可以跨不同的LLM 调用,与 LTM 和其他接口交互,是连接智能体不同组件的核心枢纽 STM
Episodic memory - 情景记忆 简单来说情景记忆就是过往的经验,这些经验包括训练中的输入-输出对儿,历史事件流等。在决策周期的规划阶段,这些记忆可能会被检索到工作内存中以支持推理。智能体也可以将新的经验从工作内存写入情景记忆,作为学习的一种形式 LTM
Semantic memory - 语义记忆 语义记忆存储智能体关于世界和自身的知识。传统的 NLP 或强化学习(RL)方法会利用检索来进行推理或决策,并从外部数据库初始化语义记忆以提供知识支持。尽管这些方法通常使用的是固定的只读语义记忆,语言智能体也可以将从 LLM 推理中获取的新知识写入语义记忆,以学习的形式逐步构建其世界知识。 LTM
Procedural memory - 程序记忆 智能体包含两种形式的程序记忆:1. 存储在LLM权重中的隐式知识;2. 编写在智能体代码中的显式知识。显式知识可以进一步划分为两类:用于执行操作的过程(如推理、检索、交互和学习的过程),用于实现决策过程的代码。在决策周期中,可以通过推理操作访问 LLM,并检索和执行基于代码的各种过程。LTM中,向程序记忆写入新操作具有高风险,可能导致意外行为,因此设计者需要特别小心,而情景记忆和语义记忆更适合进行安全的学习。 LTM

记忆能力实现

短期记忆可以用Cache来实现

长期记忆可以用数据库来实现

langchain

LangChain 的 Memory 经历了两代:

  1. 第一代:在LangChain实现,比较符合直觉的一代实现。
  2. 第二代:在LangGraph实现,主要的概念是 checkpointer,封装的比较好,从使用上基本不会知道LangGraph的实现

第一代实现

设计目标:

Use Case Example
管理会话历史 存储 AI 和 User 之间的 N 轮对话
提取结构化信息 从会话历史获取一些结构化的信息

These memory abstractions lacked built-in support for multi-user, multi-conversation scenarios, which are essential for practical conversational AI systems. 2

这能处理基本的一个用户和AI对话的场景,但是对于复杂的场景下,可能是一个工作流程,流程中可能会有多人与多个AI Agent 交互,这一版的实现中难以区分不同的用户和Agent。

相关实现:

Number Memory Type Description
1 ConversationBufferMemory 内存中存储的对话历史
2 ConversationStringBufferMemory 在1 的基础上的一类,具体用处没看出来。。todo
3 ConversationBufferWindowMemory 基本和1一样,但是不会全量保存所有对话,只是保存最近的 N 轮 messages
4 ConversationTokenBufferMemory 如果说 1,2,3 是以 message 为最小单位保存的话,那么 4 就是以 token 为最小单位保存,为了不超过 input tokens 不超过模型限制
5 ConversationSummaryBufferMemory 不是直接存储 message,而是存储 message 总结后的结果,目的和 4 一样
6 VectorStoreRetrieverMemory 以向量的形式存储了所有的历史对话,每次有新的对话时,会根据 input 查询历史寻找关联的历史,用来辅助当前会话

llamaIndex

LlamaIndex 实现了四个类型的 memory:chat_memory_buffer,chat_summary_memory_buffer,vector_memory,simple_composable_memory,它们分别有自己的优缺点和使用场景。详细总结如下:

类型 功能描述 优势 劣势 使用场景
ChatMemoryBuffer 记录完整的对话历史 保留完整语境,适合精确任务 长对话性能下降 需要完整历史的任务
ChatSummaryMemoryBuffer 对历史进行摘要存储 高效存储,支持长会话 可能遗漏细节 长对话且关注高层次语境的任务
VectorMemory 语义向量化并存储 支持快速语义检索 嵌入生成和存储复杂 动态查询、多轮对话、语义关联强的任务
SimpleComposableMemory 组合多个记忆模块 提供高度灵活的自定义能力 实现复杂度高 多功能、复杂场景的任务

ChatSummaryMemoryBuffer 和 Vector Memory一般用作 LTM, chat_memory_buffer 一般用于 STM。

SimpleComposableMemory 的用例 3

from llama_index.core.memory import (
    VectorMemory,
    SimpleComposableMemory,
    ChatMemoryBuffer,
)
from llama_index.core.llms import ChatMessage
from llama_index.embeddings.openai import OpenAIEmbedding

vector_memory = VectorMemory.from_defaults(
    vector_store=None, # leave as None to use default in-memory vector store
    embed_model=OpenAIEmbedding(),
    retriever_kwargs={'similarity_top_k': 1},
)

msgs = [
    ChatMessage.from_str("You are a SOMEWHAT helpful assistant.", "system"),
    ChatMessage.from_str("Bob likes burgers.", "user"),
    ChatMessage.from_str("Indeed, Bob likes apples.", "assistant"),
    ChatMessage.from_str("Alice likes apples.", "user"),
]
vector_memory.set(msgs)

chat_memory_buffer = ChatMemoryBuffer.from_defaults()

composable_memory = SimpleComposableMemory.from_defaults(
    primary_memory=chat_memory_buffer,
    secondary_memory_sources=[vector_memory],
)

例中,primary_memory字如其名,是用于agent 主要的 chat buffer,secondary_memory_sources 只会被注入到 system role的message 中。操作 memory 中的内容:

msgs = [
    ChatMessage.from_str("You are a REALLY helpful assistant.", "system"),
    ChatMessage.from_str("Jerry likes juice.", "user"),
]
# load into all memory sources modules"
for m in msgs:
    composable_memory.put(m)
msgsss = composable_memory.get("What does Bob like?")

put 和 get 方法会从所有的 memory 中查找。

在 Agent中的使用

def multiply(a: int, b: int) -> int:
    """Multiply two integers and returns the result integer"""
    return a * b

def mystery(a: int, b: int) -> int:
    """Mystery function on two numbers"""
    return a**2 - b**2

multiply_tool = FunctionTool.from_defaults(fn=multiply)
mystery_tool = FunctionTool.from_defaults(fn=mystery)

llm = OpenAI(model="gpt-3.5-turbo-0613")
agent = FunctionCallingAgent.from_tools(
    [multiply_tool, mystery_tool],
    llm=llm,
    memory=composable_memory,
    verbose=True,
)

agent.chat("What is the mystery function on 5 and 6?")

todo: 没有体现 persist 操作

qwen-agent

实现 4

参考

Footnotes

  1. https://arxiv.org/abs/2309.02427

  2. https://python.langchain.com/docs/versions/migrating_memory/

  3. https://docs.llamaindex.ai/en/stable/examples/agent/memory/composable_memory/

  4. https://github.com/QwenLM/Qwen-Agent/blob/main/qwen_agent/memory/memory.py

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant