ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

CAMEL memories 记忆系统源码深度解析:MemoryBlock、AgentMemory 与上下文构建器全指南

CAMEL memories 记忆系统源码深度解析:MemoryBlock、AgentMemory 与上下文构建器全指南 CAMEL memories 记忆系统源码深度解析MemoryBlock、AgentMemory 与上下文构建器全指南【免费下载链接】camel CAMEL: The first and the best multi-agent framework. Finding the Scaling Law of Agents. https://www.camel-ai.org项目地址: https://gitcode.com/GitHub_Trending/ca/camel导读本文以 CAMEL 多智能体框架的记忆子系统camel.memories包为核心系统梳理其分层架构从最底层的MemoryRecord/ContextRecord数据单元到MemoryBlockChatHistoryBlock、VectorDBBlock与AgentMemoryChatHistoryMemory、VectorDBMemory、LongtermAgentMemory两级抽象再到负责将记忆装配为模型上下文的ScoreBasedContextCreator。读完本文你将掌握 CAMEL 记忆系统各核心类的职责、关键参数window_size、retrieve_limit、keep_rate、token_limit等与调用关系并能结合源码与示例把三类记忆接入ChatAgent实际使用。camel.memories包的 API 文档骨架定义在 docs/camel.memories.rst其中列出了两个子包blocks、context_creators与三个子模块agent_memories、base、records本文即沿此结构展开并深入对应源码进行实现级解读。一、记忆系统的整体架构三级分层从 camel/memories/init.py 的导出列表可以清楚看到整个包的公开 APIfrom .agent_memories import ( ChatHistoryMemory, LongtermAgentMemory, VectorDBMemory, ) from .base import AgentMemory, BaseContextCreator, MemoryBlock from .blocks.chat_history_block import ChatHistoryBlock from .blocks.vectordb_block import VectorDBBlock from .context_creators.score_based import ScoreBasedContextCreator from .records import ContextRecord, MemoryRecordCAMEL 的记忆系统遵循数据记录 → 存储块 → 记忆对象 → 上下文构建的分层设计层级核心类职责数据单元MemoryRecord、ContextRecord定义一条记忆消息内容、角色、UUID、时间戳等与一次检索结果记录 相似度分数存储块MemoryBlock→ChatHistoryBlock、VectorDBBlock只负责写与清空不做读取抽象因为不同块的检索形态不同记忆对象AgentMemory→ChatHistoryMemory、VectorDBMemory、LongtermAgentMemory面向 Agent 的封装提供retrieve()与get_context_creator()上下文构建BaseContextCreator→ScoreBasedContextCreator把检索出的记录按 token 预算组装成模型可用的OpenAIMessage列表二、数据单元MemoryRecord 与 ContextRecordMemoryRecord是 CAMEL 记忆系统中最基本的存储单元定义在 camel/memories/records.py基于 PydanticBaseModel构建字段如下字段类型说明messageBaseMessage记录的主体内容普通消息或FunctionCallingMessage工具调用消息role_at_backendOpenAIBackendRole该消息在 OpenAI 后端扮演的角色与 CAMEL 角色扮演体系中的RoleType不同uuidUUID唯一标识默认uuid4()随机生成extra_infoDict[str, str]附加键值对信息默认为空字典timestampfloat创建时间戳默认取纳秒级精度time.time_ns() / 1e9agent_idstr与该记忆关联的 Agent 标识默认为空字符串MemoryRecord提供了三种关键方法to_dict()序列化为字典message字段中会额外写入__class__键记录消息类名BaseMessage或FunctionCallingMessagerole_at_backend写为枚举值用于持久化存储如 ChatHistoryBlock.write_records 就是先把记录to_dict()再交给 KV 存储save()。from_dict()从字典还原记录。源码中可以看到它做了大量反序列化工作把role_type字符串转回RoleType枚举、把 base64/URL 形式的图片列表还原为PIL.Image、把 base64 视频字节还原为原始字节并将非构造参数合并进meta_dict。这意味着记忆记录支持多模态消息的持久化与恢复。to_openai_message()调用内部message.to_openai_message(role_at_backend)把记录转换为模型输入所需的OpenAIMessage。ContextRecord则是检索结果的载体records.py#L187-L195包含三个字段memory_record命中的记忆、score相关度/保留度分数、timestamp。它的语义是这条记忆以多大权重进入上下文。三、存储块抽象MemoryBlockMemoryBlock定义在 camel/memories/base.py是所有记忆存储块的抽象基类。它的设计意图非常明确只定义写与清空刻意不定义读取接口因为不同类型的存储块如按时间线排列的聊天记录 vs 按向量相似度查询的数据库检索形态差异过大。class MemoryBlock(ABC): abstractmethod def write_records(self, records: List[MemoryRecord]) - None: ... def write_record(self, record: MemoryRecord) - None: # 默认实现把单条记录包装成列表转发给 write_records self.write_records([record]) def pop_records(self, count: int) - List[MemoryRecord]: # 默认抛 NotImplementedError由子类决定是否支持 raise NotImplementedError def remove_records_by_indices(self, indices: List[int]) - List[MemoryRecord]: raise NotImplementedError abstractmethod def clear(self) - None: ...其中write_record是便捷方法默认将单条记录包装成列表后调用write_records。pop_records与remove_records_by_indices是可选的回滚/删除能力默认不实现由子类按需覆写——这正是后面VectorDBMemory不支持历史删除操作的原因所在。3.1 ChatHistoryBlock基于 KV 存储的对话历史块ChatHistoryBlockcamel/memories/blocks/chat_history_block.py维护有序的对话历史底层使用键值存储BaseKeyValueStorage默认是内存版InMemoryKeyValueStorage。构造函数有两个参数storageKV 存储后端为None时使用InMemoryKeyValueStorage()。keep_rate历史消息的分数衰减率默认0.9。源码校验其必须在[0, 1]区间否则抛出ValueError。语义是离当前时刻最近的记录分数为1.0每向前回溯一条分数乘一次keep_rate。keep_rate越大历史消息在上下文创建时被保留的概率越高。retrieve(window_sizeNone)的窗口逻辑值得细读从存储load()所有记录字典空存储返回空列表空记忆是合法状态。若指定window_size非负整数先判断首条记录是否为SYSTEM/DEVELOPER角色如果是则始终保留首条系统消息再从剩余消息中截取最近window_size条。例如输入[system_msg, u1, u2, u3, u4]、window_size2时结果为[system_msg, u3, u4]若首条是USER则直接取最后window_size条。给每条记录打分系统消息恒为1.0永久保留其余消息分数按keep_rate逐级衰减。返回List[ContextRecord]按时间顺序排列。此外它还实现了pop_records从尾部弹出最近 N 条同样保护首条系统消息与remove_records_by_indices按索引删除索引 0 的系统/开发者消息受保护不可删两者都会把剩余记录写回存储。3.2 VectorDBBlock基于向量检索的记忆块VectorDBBlockcamel/memories/blocks/vectordb_block.py用 embedding 把消息向量化后存入向量数据库实现语义相似检索storageBaseVectorStorage默认使用QdrantStorage(vector_dim...)向量维度由 embedding 输出维度决定。embeddingBaseEmbedding默认OpenAIEmbedding()。构造时执行self.vector_dim self.embedding.get_output_dim()即向量库维度与 embedding 输出强绑定替换 embedding 时需注意维度一致。write_records会先过滤掉内容为空或全空白的记录record.message.content and record.message.content.strip()然后把每条记录 embedding 成向量连同record.to_dict()载荷与str(record.uuid)作为 ID 写入存储v_records [ VectorRecord( vectorself.embedding.embed(record.message.content), payloadrecord.to_dict(), idstr(record.uuid), ) for record in valid_records ] self.storage.add(v_records)retrieve(keyword, limit3)则把查询关键词 embedding 后构造VectorDBQuery(query_vector..., top_klimit)提交给存储查询返回的每个结果包装成ContextRecord其中score取向量相似度timestamp取载荷中的原始时间戳。四、Agent 记忆抽象AgentMemory 与三类实现AgentMemorycamel/memories/base.py#L134-L196继承MemoryBlock是专为直接接入 Agent 设计的记忆形态。它在存储块之上补充了两个关键抽象agent_id属性 setter标识记忆归属的 Agent。retrieve()从记忆取回List[ContextRecord]供创建模型上下文使用。get_context_creator()返回对应的上下文构建器。它内置了一个便捷方法get_context()把检索与装配串成一条流水线def get_context(self) - Tuple[List[OpenAIMessage], int]: return self.get_context_creator().create_context(self.retrieve())返回(OpenAIMessage 列表, 总 token 数)。另有clean_tool_calls()可选方法默认空实现向后兼容用于清理工具调用相关消息以节省 token。__repr__实现也值得一提当agent_id存在时输出ClassName(agent_idid)便于日志排查。4.1 ChatHistoryMemory会话级短时记忆ChatHistoryMemorycamel/memories/agent_memories.py#L26-L148是ChatHistoryBlock的 Agent 封装构造参数参数类型默认值说明context_creatorBaseContextCreator必填模型上下文构建器storageBaseKeyValueStorageNone聊天历史存储后端缺省为内存 KVwindow_sizeintNone检索最近 N 条消息None表示取全部历史agent_idstrNone关联 Agent 标识window_size有严格校验非整数抛TypeError负数抛ValueError。retrieve()调用底层块的窗口检索并在恰好取满window_size条时发出UserWarning提示部分更早的消息未被纳入上下文建议调大窗口。write_records有一个贴心的自动化处理若记录agent_id为空而记忆本身有agent_id则自动补写归属。clean_tool_calls()的实现值得关注它会扫描存储中的所有记录删除所有FUNCTION/TOOL角色的消息以及携带tool_calls的ASSISTANT消息含FunctionCallingMessage且带args的记录再把剩余记录写回存储从而在工具调用频繁的场景显著节省 token。4.2 VectorDBMemory语义级长期记忆VectorDBMemorycamel/memories/agent_memories.py#L151-L226是VectorDBBlock的 Agent 封装。构造参数参数类型默认值说明context_creatorBaseContextCreator必填上下文构建器storageBaseVectorStorageNone向量存储缺省为 Qdrantretrieve_limitint3最多加入上下文的相似消息条数agent_idstrNoneAgent 标识它的检索策略是主题跟随内部维护_current_topic字段write_records时假设最后一条用户输入就是当前主题将其内容赋给_current_topicretrieve()时以该主题为关键词做向量检索。注释明确提示最近的消息不会立即加入上下文需要等后续查询命中这是向量记忆的固有特性。值得注意的是其能力边界pop_records与remove_records_by_indices都直接抛出NotImplementedError即向量数据库记忆不支持按时间回滚或按索引删除历史记录——从源码结构看这是为了防止破坏向量索引的一致性。4.3 LongtermAgentMemory短时 长期的组合记忆LongtermAgentMemorycamel/memories/agent_memories.py#L229-L321是前两者的组合用对话历史块 向量库块同时服务短期上下文与长期语义回忆def __init__( self, context_creator: BaseContextCreator, chat_history_block: Optional[ChatHistoryBlock] None, vector_db_block: Optional[VectorDBBlock] None, retrieve_limit: int 3, agent_id: Optional[str] None, ) - None: self.chat_history_block chat_history_block or ChatHistoryBlock() self.vector_db_block vector_db_block or VectorDBBlock() ...其retrieve()的组合逻辑很巧妙chat_history self.chat_history_block.retrieve() vector_db_retrieve self.vector_db_block.retrieve(self._current_topic, self.retrieve_limit) return chat_history[:1] vector_db_retrieve chat_history[1:]即首条通常是系统消息保持在最前中间插入向量检索的长期记忆其后接其余聊天历史让最近的短时上下文与语义相关的老记忆按序拼装。write_records则同时写入两个块并同步更新_current_topic。clear()同时清空两个块pop_records/remove_records_by_indices只作用于聊天历史块向量记忆保持只增特性。五、上下文构建器BaseContextCreator 与 ScoreBasedContextCreatorBaseContextCreatorcamel/memories/base.py#L80-L131抽象了从检索记录生成符合 token 预算的模型上下文的策略要求子类实现三个成员token_counterBaseTokenCountertoken 计数实例token_limitint允许生成上下文的最大 token 数create_context(records)→(List[OpenAIMessage], int)从ContextRecord列表构造上下文输出消息顺序须与输入一致。唯一的内置实现ScoreBasedContextCreator位于 camel/memories/context_creators/score_based.py其create_context的装配逻辑为遍历记录单独抽出第一条SYSTEM角色的记录放在最前作为系统提示词其余记录按timestamp升序排序依次调用memory_record.to_openai_message()转成OpenAIMessage无消息时返回([], 0)。该实现还内置了token 计数缓存机制以降低重复计数的开销源码 docstring 明确说明这是为减少昂贵的重复 token 计数而设计通过set_cached_token_count(token_count, message_count)记录上一次 LLM 响应的总 token 数与消息条数由外部调用方注入见下节 Agent 集成。create_context命中缓存时消息条数相同直接复用缓存值消息变多则用_estimate_message_tokens对新增消息做字符级估算并增量累加消息变少说明缓存失效回退到完整计数。_estimate_message_tokens采用约 2 字符/token 的保守近似兼容 ASCII 约 4 字符/token 与中日韩文本约 1-2 字符/token每条消息加 4 token 开销多模态image_url部分按 1500 token 保守估算tool_calls文本同样按字符估算。clear_cache()用于显式清空缓存。token_limit在构造时被要求传入token_counter通常为OpenAITokenCounter(ModelType.GPT_4O_MINI)之类但源码注释说明它保留仅用于 API 兼容当前实现不再用它过滤记录——记录筛选主要由各记忆的window_size/retrieve_limit完成。六、实战把记忆接入 ChatAgentcamel.memories各组件最常见的用法是作为ChatAgent的记忆后端。官方示例 examples/memories/agent_memory_example.py 展示了标准接入流程from camel.agents import ChatAgent from camel.memories import ChatHistoryMemory from camel.memories.context_creators.score_based import ScoreBasedContextCreator from camel.models.model_factory import ModelFactory from camel.types import ModelPlatformType, ModelType from camel.utils import OpenAITokenCounter context_creator ScoreBasedContextCreator( token_counterOpenAITokenCounter(ModelType.GPT_4O_MINI), token_limit1024, ) model ModelFactory.create( model_platformModelPlatformType.OPENAI, model_typeModelType.GPT_4O_MINI, ) agent ChatAgent( system_messageYou are a helpful assistant, agent_id001, modelmodel, )ChatAgent在未显式传入memory时默认构造ChatHistoryMemory示例中 agent 的agent_id001会被写入记忆记录的agent_id字段。随后可进行多轮对话让记录累积并演示了三项记忆能力持久化到 JSONagent.save_memory(save_path)把记忆序列化为chat_agent_memory.json从文件恢复新建ChatAgent后调用agent.load_memory_from_path(save_path)新 Agent 能回忆出Banana is a countryCAMEL lives in Banana等旧对话内容记忆对象迁移通过another_agent.memory取出另一 Agent 的AgentMemory实例再调用new_agent.load_memory(second_agent_memory)完成记忆对象级移植。向量记忆的接入方式见 examples/memories/agent_memory_vector_db_example.pyfrom camel.memories import VectorDBMemory from camel.storages.vectordb_storages import QdrantStorage vector_storage QdrantStorage( vector_dim1536, # 与 embedding 输出维度一致 path:memory:, # 生产环境改为真实目录或远端 ) agent1_memory VectorDBMemory( context_creatorcontext_creator, storagevector_storage, retrieve_limit2, agent_idagent1.agent_id, ) agent1.memory agent1_memory该示例还演示了复活场景用相同agent_id与同一底层vector_storage新建 Agentload_memory_from_path重放存储的MemoryRecord后新 Agent 能通过语义检索回忆起海豚回声定位鲸鱼是最大哺乳动物等知识。关于ScoreBasedContextCreator的 token 缓存可参考 examples/agents/chatagent_request_usage_callback.py 一类用法在请求回调中拿到 LLM 响应usage后调用set_cached_token_count注入计数使后续上下文构建复用缓存减少重复 token 计算。七、测试与文档索引如何继续深入仓库为记忆系统提供了完整测试覆盖可作为理解行为的活文档test/memories/test_agent_memories.py覆盖ChatHistoryMemory、VectorDBMemory、LongtermAgentMemory三类 Agent 记忆的读写、检索与组合行为test/memories/test_chat_history_memory.py验证窗口截断、系统消息保护、pop_records/按索引删除等边界行为test/memories/test_vector_db_memory.py验证向量写入过滤、相似度检索与retrieve_limit生效。API 文档层面除本文依据的 docs/camel.memories.rst 外子包文档 docs/camel.memories.blocks.rst 与 docs/camel.memories.context_creators.rst 分别对应两个子包其 modules 索引由 docs/modules.rst 统一组织。若需在运行时查看类签名与默认值可直接在 Python 中执行python -c from camel.memories import ChatHistoryMemory, VectorDBMemory, LongtermAgentMemory; help(ChatHistoryMemory)等命令。八、小结记忆选型速查场景推荐记忆关键参数普通多轮对话只需近期上下文ChatHistoryMemorywindow_size控制最近消息条数需要跨会话语义回忆长期记忆VectorDBMemoryretrieve_limit控制每次检索条数embedding 与向量维度需匹配既要短期上下文又要长期语义记忆LongtermAgentMemoryretrieve_limit控制向量部分聊天历史默认全量需要工具调用消息清理以省 token任选 clean_tool_calls()—需要记忆持久化/迁移任选 save_memory/load_memory_from_path/load_memoryagent_id保持一致以确保归属正确整体来看camel.memories的设计遵循存储块与读取策略解耦、短时记忆与长期记忆互补、上下文构建与 token 预算分离三条主线MemoryBlock只管写入与清空AgentMemory定义面向 Agent 的检索接口BaseContextCreator负责最终把记忆装配成模型输入。理解这条链路后你便可以在 CAMEL 中自由组合记忆后端与上下文策略构建具备持久化记忆能力的多智能体应用。【免费下载链接】camel CAMEL: The first and the best multi-agent framework. Finding the Scaling Law of Agents. https://www.camel-ai.org项目地址: https://gitcode.com/GitHub_Trending/ca/camel创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表