AgentScope深入分析-RAG和记忆

2025博客之星年度评选已开启 10w+人浏览 1.3k人参与

记忆与知识:RAG、Memory 与状态管理核心解析

请关注公众号【碳硅化合物AI

摘要

智能体需要"记忆"才能持续对话,需要"知识"才能回答专业问题。AgentScope 提供了完整的记忆系统和 RAG(检索增强生成)能力,让智能体既能记住对话历史,也能从知识库中检索相关信息。本文将深入分析 Memory、RAG 和状态管理三个核心系统的实现,包括它们的类设计、工作流程,以及嵌套状态管理这个巧妙的设计。通过阅读本文,你会理解智能体如何管理短期和长期记忆,如何从向量数据库中检索知识,以及状态序列化的实现原理。
image.png

入口类与类关系

记忆系统的类层次

AgentScope 的记忆系统分为短期记忆和长期记忆,它们都继承自 MemoryBase

image.png

RAG 系统的类层次

RAG 系统由知识库、文档读取器和向量存储组成:
image.png

关键代码:MemoryBase 接口

让我们看看 MemoryBase 定义了哪些核心方法:

class MemoryBase(StateModule):
    """The base class for memory in agentscope."""

    @abstractmethod
    async def add(self, *args: Any, **kwargs: Any) -> None:
        """Add items to the memory."""

    @abstractmethod
    async def delete(self, *args: Any, **kwargs: Any) -> None:
        """Delete items from the memory."""

    @abstractmethod
    async def retrieve(self, *args: Any, **kwargs: Any) -> None:
        """Retrieve items from the memory."""

    @abstractmethod
    async def size(self) -> int:
        """Get the size of the memory."""

    @abstractmethod
    async def clear(self) -> None:
        """Clear the memory content."""

    @abstractmethod
    async def get_memory(self, *args: Any, **kwargs: Any) -> list[Msg]:
        """Get the memory content."""

这个接口非常简洁,但涵盖了记忆系统的所有核心操作。InMemoryMemory 是内存实现,直接存储 Msg 对象列表。

关键流程分析

Memory 存储和检索流程

短期记忆的流程非常简单直接:
image.png

InMemoryMemory 的实现非常直观:

async def add(
    self,
    memories: Union[list[Msg], Msg, None],
    allow_duplicates: bool = False,
) -> None:
    """Add message into the memory."""
    if memories is None:
        return
    
    if isinstance(memories, Msg):
        memories = [memories]
    
    # 检查重复(默认不允许重复)
    if not allow_duplicates:
        existing_ids = [_.id for _ in self.content]
        memories = [_ for _ in memories if _.id not in existing_ids]
    self.content.extend(memories)

async def get_memory(self) -> list[Msg]:
    """Get the memory content."""
    return self.content

这种设计的好处是简单高效,适合大多数场景。如果需要持久化,可以使用长期记忆。

RAG 检索流程

RAG 的检索流程稍微复杂一些,涉及向量化和相似度搜索:

image.png

让我们看看 SimpleKnowledge 的检索实现:

async def retrieve(
    self,
    query: str,
    limit: int = 5,
    score_threshold: float | None = None,
    **kwargs: Any,
) -> list[Document]:
    """Retrieve relevant documents by the given queries."""
    # 1. 将查询向量化
    res_embedding = await self.embedding_model(
        [
            TextBlock(
                type="text",
                text=query,
            ),
        ],
    )
    # 2. 在向量数据库中搜索
    res = await self.embedding_store.search(
        res_embedding.embeddings[0],
        limit=limit,
        score_threshold=score_threshold,
        **kwargs,
    )
    return res

这个过程分为两步:

  1. 向量化查询:使用 EmbeddingModel 将文本查询转换为向量
  2. 相似度搜索:在向量数据库中找到最相似的文档

向量数据库(如 Qdrant、Milvus)使用高效的近似最近邻(ANN)算法,即使有百万级文档也能快速检索。

状态管理流程

状态管理的核心是序列化和反序列化:

image.png

关键技术点

1. RAG 的向量化存储和检索

RAG 系统的核心是向量相似度搜索。当你添加文档时:

# 1. 读取文档并分块
documents = await reader(text="...")

# 2. 向量化并存储
await knowledge.add_documents(documents)

add_documents 内部,会:

  1. 使用 EmbeddingModel 将每个文档块向量化
  2. 将向量和元数据存储到向量数据库
  3. 建立索引以支持快速检索

检索时,系统会:

  1. 将查询向量化
  2. 在向量数据库中搜索最相似的文档
  3. 根据相似度分数过滤结果

这种设计让智能体能够从大量文档中快速找到相关信息,而不需要遍历所有文档。

2. 短期记忆和长期记忆的区别

AgentScope 对短期记忆和长期记忆的区分很灵活:

  • 短期记忆(MemoryBase)

    • 存储对话历史
    • 通常保存在内存中(InMemoryMemory
    • 快速访问,但会话结束后丢失
    • 适合存储当前对话的上下文
  • 长期记忆(LongTermMemoryBase)

    • 持久化存储重要信息
    • 支持语义检索(如 Mem0、ReMe)
    • 可以跨会话使用
    • 适合存储用户偏好、历史经验等

实际上,AgentScope 并不强制区分它们。你可以只使用一个强大的记忆系统,也可以组合使用。这种设计体现了"需求驱动"的理念。

3. 嵌套状态管理机制

这是 AgentScope 的一个巧妙设计。StateModule 通过 __setattr__ 自动追踪子模块:

def __setattr__(self, key: str, value: Any) -> None:
    """Set attributes and record state modules."""
    if isinstance(value, StateModule):
        if not hasattr(self, "_module_dict"):
            raise AttributeError(...)
        self._module_dict[key] = value
    super().__setattr__(key, value)

当你创建一个 ReActAgent 时:

agent = ReActAgent(
    memory=InMemoryMemory(),  # 自动被追踪
    toolkit=Toolkit(),        # 自动被追踪
    ...
)

这些子模块会自动被纳入状态管理。当你调用 agent.state_dict() 时:

def state_dict(self) -> dict:
    """Get the state dictionary of the module."""
    state = {}
    for key in self._module_dict:
        attr = getattr(self, key, None)
        if isinstance(attr, StateModule):
            state[key] = attr.state_dict()  # 递归调用
    
    for key in self._attribute_dict:
        attr = getattr(self, key)
        to_json_function = self._attribute_dict[key].to_json
        if to_json_function is not None:
            state[key] = to_json_function(attr)
        else:
            state[key] = attr
    
    return state

这种递归设计让状态管理变得非常强大。你可以保存整个智能体的状态,包括它的记忆、工具集等所有子组件。

4. 状态序列化和反序列化

状态序列化支持两种方式:

  1. 自动序列化:对于 JSON 可序列化的属性,直接序列化
  2. 自定义序列化:通过 register_state 注册自定义的序列化函数
def register_state(
    self,
    attr_name: str,
    custom_to_json: Callable[[Any], JSONSerializableObject] | None = None,
    custom_from_json: Callable[[JSONSerializableObject], Any] | None = None,
) -> None:
    """Register an attribute to be tracked as a state variable."""
    attr = getattr(self, attr_name)
    
    if custom_to_json is None:
        # 确保属性是 JSON 可序列化的
        try:
            json.dumps(attr)
        except Exception as e:
            raise TypeError(...)
    
    self._attribute_dict[attr_name] = _JSONSerializeFunction(
        to_json=custom_to_json,
        load_json=custom_from_json,
    )

这种设计让你可以:

  • 保存复杂对象的状态
  • 控制序列化的粒度
  • 实现自定义的序列化逻辑

总结

Memory、RAG 和状态管理是 AgentScope 框架中非常重要的三个系统:

  1. Memory 系统:提供了灵活的短期和长期记忆管理,让智能体能够记住对话历史和重要信息
  2. RAG 系统:通过向量相似度搜索,让智能体能够从知识库中检索相关信息
  3. 状态管理:通过嵌套状态管理和自定义序列化,让智能体的状态可以完整保存和恢复

这三个系统的设计都体现了 AgentScope 的核心理念:模块化、透明、可扩展。在下一篇文章中,我们会分析模型、MCP 和工具系统的实现,这些组件为智能体提供了与外部世界交互的能力。


### 技术差异 #### 1. 核心机制 SELF-RAG 引入了自我反思机制,通过检索、生成批判三个核心组件来增强大型语言模型(LLM)的能力。该方法不仅利用外部知识库进行信息检索,还通过批判器对生成的内容进行评估,确保输出的准确性相关性[^4]。相比之下,自适应RAG(Adaptive-RAG)主要依赖于查询难度分类器来动态调整检索策略。这种方法根据查询的复杂程度选择不同的检索策略,以优化资源使用并提高效率[^3]。 #### 2. 训练方式 SELF-RAG 是通过端到端训练实现的,这意味着整个模型包括检索器、生成器批判器都被联合优化,从而更好地协同工作。这种训练方式使得模型能够学习何时以及如何有效地利用检索到的信息,并且可以通过生成特殊标记来指导这一过程[^4]。而自适应RAG通常是在预训练的基础上进行微调,其重点在于根据查询的难度级别调整检索参数,而不是全面重新训练整个系统。 #### 3. 反思与批判能力 SELF-RAG 的一个显著特点是它具备反思批判生成内容的能力。通过学习生成特定的反思标记,如是否需要进一步检索或确认输出的相关性,SELF-RAG 能够主动检查其输出的质量。这在传统的 RAG 方法中是不存在的,这些方法往往只是简单地将检索到的信息合并到生成过程中,而不考虑最终输出的实际质量[^4]。 #### 4. 检索策略 SELF-RAG 在检索时采用了一种更为精细的方式,它可以基于当前生成的内容决定是否需要更多的信息支持,并据此触发新的检索动作。这种方式允许模型根据实际需求灵活地获取信息,提高了信息利用效率。而自适应RAG则侧重于根据预先定义好的查询难度类别来调整检索深度,虽然也能达到一定的灵活性,但不如 SELF-RAG 那样具有动态性针对性[^3]。 ### 应用场景 #### 1. 复杂问答任务 对于像 PopQA 或 Bio 这样的复杂问答任务,其中涉及大量的专业知识详细的事实核查,SELF-RAG 表现出色,因为它可以有效地结合检索到的信息并批判性地评估生成的答案[^1]。自适应RAG同样适用于这类任务,但由于缺乏批判机制,可能无法保证所有答案都得到了充分的支持。 #### 2. 公共卫生与挑战性推理任务 在 PubHealth ARC-Challenge 等领域,要求模型不仅要提供正确的信息,还要能够处理深层次的理解推理问题。SELF-RAG 在这些方面表现优异,得益于它的多组件架构支持性的训练方法[^1]。自适应RAG也可以应用于这些场景,不过其性能可能会受到所选检索策略的影响较大。 #### 3. 个性化定制与数据规模影响 SELF-RAG 展示了良好的可扩展性适应性,在不同大小的数据集上均能保持稳定的表现。此外,它还能很好地适应用户的特定需求,例如通过修改批判标准来满足不同的应用要求[^1]。自适应RAG虽然也展示了不错的泛化能力,但在面对大规模数据集时可能需要更复杂的配置才能发挥最佳效果[^3]。 ```python # 示例代码:模拟两种技术的工作流程 def self_rag(query): # 初始化检索器、生成器批判器 retriever = Retriever() generator = Generator() critic = Critic() # 第一步 - 检索相关信息 retrieved_info = retriever.retrieve(query) # 第二步 - 生成初步回答 initial_answer = generator.generate(query, retrieved_info) # 第三步 - 批判并改进回答 refined_answer = critic.criticize(initial_answer, retrieved_info) return refined_answer def adaptive_rag(query, difficulty_level): # 根据查询难度选择合适的检索策略 if difficulty_level == 'easy': strategy = EasyStrategy() elif difficulty_level == 'medium': strategy = MediumStrategy() else: strategy = HardStrategy() # 使用选定策略执行检索 retriever = AdaptiveRetriever(strategy) retrieved_info = retriever.retrieve(query) # 生成最终回答 generator = Generator() answer = generator.generate(query, retrieved_info) return answer ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值