ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

CAMEL 记忆系统中的 ScoreBasedContextCreator:基于分数的上下文构建策略解析

CAMEL 记忆系统中的 ScoreBasedContextCreator:基于分数的上下文构建策略解析 CAMEL 记忆系统中的 ScoreBasedContextCreator基于分数的上下文构建策略解析【免费下载链接】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 多智能体框架记忆模块中的核心组件ScoreBasedContextCreator深入讲解它在受限 token 预算下从聊天历史构建模型上下文的完整策略系统消息恒优先保留、低分消息优先被裁剪、最终输出保持时间顺序、工具调用与其响应必须成对保留。文章将从 API 文档骨架出发结合 score_based.py 源码实现、test_score_based.py 测试用例以及 chat_agent.py 中的真实调用链让你掌握该类的构造方式、缓存优化机制、在 Agent 记忆系统中的接入位置以及底层分数是如何由ChatHistoryBlock打出来的。ScoreBasedContextCreator 是什么ScoreBasedContextCreator是 CAMEL 记忆系统中上下文构建策略context creation strategy的默认实现定义于 camel/memories/context_creators/score_based.py继承自抽象基类BaseContextCreator见 camel/memories/base.py。它的职责是给定一组聊天历史记录ContextRecord生成一段会话上下文List[OpenAIMessage]并保证上下文的总 token 数不超过指定的上限。当总 token 数超限时它会依据消息的分数进行裁剪prune分数越低越先被丢弃。在 CAMEL 的记忆架构中BaseContextCreator是连接原始记忆记录与模型上下文之间的桥梁AgentMemory通过retrieve()从各记忆块Memory Block取出带分数的记录列表get_context()调用get_context_creator().create_context(self.retrieve())将记录转换为可直接送入大模型的 OpenAI 消息格式并返回总 token 数见 base.py。因此ScoreBasedContextCreator就是这条链路上把历史变成可消费上下文的最后一环。构造与核心参数def __init__(self, token_counter: BaseTokenCounter, token_limit: int) - None:构造时仅需两个参数参数类型说明token_counterBaseTokenCounter负责对消息进行 token 计数的实例如OpenAITokenCounter用于计算最终上下文的 token 总量token_limitint生成上下文允许的最大 token 数需要注意的是从源码看当前实现的token_limit仅为 API 兼容而保留不再直接参与记录过滤——真正约束上下文大小的逻辑由外部记忆层与 token 计数器协同完成见 score_based.py 的 docstring 说明No longer used to filter records。这一设计变化意味着如果你基于该类的历史文档假设传入token_limit就会自动截断记录那么在新版本中需要依赖其他机制如ChatHistoryMemory的窗口裁剪与摘要压缩来配合控制长度。类还对外暴露两个只读属性property def token_counter(self) - BaseTokenCounter: ... property def token_limit(self) - int: ...在 ChatAgent 中的默认接入方式ScoreBasedContextCreator是ChatAgent的默认上下文构建器。在 chat_agent.py 中Agent 初始化时会根据token_limit参数未指定则取模型后端自身的model_backend.token_limit实例化该类并连同window_size一起交给ChatHistoryMemoryif token_limit is not None: effective_token_limit token_limit else: effective_token_limit self.model_backend.token_limit context_creator ScoreBasedContextCreator( self.model_backend.token_counter, effective_token_limit, ) self._memory memory or ChatHistoryMemory( context_creator, window_sizemessage_window_size, agent_idself.agent_id, )这意味着只要使用默认配置创建 ChatAgent你的对话记忆上下文构建就已经跑在 ScoreBasedContextCreator 之上。此外memory_toolkit.py在从 JSON 加载记忆重建ChatHistoryMemory时也使用了该类见 memory_toolkit.py。create_context上下文构建主流程def create_context( self, records: List[ContextRecord], ) - Tuple[List[OpenAIMessage], int]:create_context是BaseContextCreator定义的核心抽象方法接收List[ContextRecord]返回(ordered_messages, total_tokens)二元组有序的 OpenAI 消息列表 最终上下文的总 token 数。ContextRecord是记忆检索的结果单元包含memory_record实际的记忆消息、score相关度分数与timestamp时间戳定义于 records.py。主流程步骤从 score_based.py 源码看其执行逻辑为分离系统消息遍历记录将第一个role_at_backend OpenAIBackendRole.SYSTEM的记录单独取出其余归入remaining_records按时间排序对剩余记录按timestamp升序排序组装消息系统消息若存在排在最前随后按时间顺序追加其余消息每条记录通过memory_record.to_openai_message()转为 OpenAI 消息格式计算 token 总量见下文缓存优化一节的分支逻辑空上下文短路若没有任何消息直接返回([], 0)。与文档策略的对应API 文档中概括的四大策略均能在实现与测试中得到印证系统消息恒优先保留create_context中系统记录被单独提取并始终放在消息列表首位测试 test_score_based.py 验证了含系统消息时输出顺序为[system, 其余按时间排序...]。低分消息优先被裁剪这是该类Score-based命名的由来——虽然当前create_context主流程本身不再主动按分数截断但分数体系由上游ChatHistoryBlock维护用于配合记忆层的窗口/摘要机制控制体积详见下文分数从何而来。输出保持时间顺序剩余记录按timestamp升序排序后输出测试用例test_score_based_context_creatortest_score_based.py在输入乱序、分数各异0.3/0.9/0.7的情况下断言输出严格等于按时间戳排序的结果证明输出顺序只由时间决定、与分数无关。工具调用与响应成对保留文档中列出的_group_tool_calls_and_responses与_truncate_with_tool_call_awareness两个私有方法正是为维持工具调用链的 API 兼容性而设计——前者基于tool_call_id聚合assistant 请求 工具响应含分块后者在按分数贪心选择消息时把整个工具调用组视为一个不可分割或可部分截断的整体避免出现只有请求没有响应的残缺上下文。token 计数的缓存优化机制create_context在计算 token 总量时并非每次都全量计数而是采用缓存 字符级估算的混合策略以降低高频调用 token counter 的开销缓存命中当_cached_token_count有效且当前消息数与缓存的消息数相等时直接返回缓存值增量估算当消息数变多时仅对新增加的消息用_estimate_message_tokens做字符级近似估算约 2 字符/token 的保守假设兼容 ASCII 约 4 字符/token 与 CJK 约 1–2 字符/token再加上缓存值返回缓存失效当消息数少于缓存时消息被移除说明缓存已过期回退到token_counter.count_tokens_from_messages(messages)的全量精确计算。_estimate_message_tokens还针对多模态内容做了保守估计image_url类型的图片按每张约 1500 token 估算非文本部分按len(str(part)) // 2处理tool_calls字段同样计入估算见 score_based.py。缓存从哪来与 LLM 响应的联动缓存数据并非凭空产生而是由ChatAgent在每次 LLM 响应后回填的。在 chat_agent.py 中_update_token_count_cache从响应的 usage 字典中取出prompt_tokens与completion_tokens求和后调用context_creator.set_cached_token_count(total_tokens, message_count 1)total_tokens prompt_tokens completion_tokens context_creator self.memory.get_context_creator() if hasattr(context_creator, set_cached_token_count): context_creator.set_cached_token_count(total_tokens, message_count 1)对应的两个管理方法set_cached_token_count(token_count, message_count)将 LLM 响应的真实 usageprompt completion与当时的消息数写入缓存clear_cache()清除缓存在 chat_agent.py 等位置如记忆被清空、上下文重置时被调用确保后续使用精确计数。这一机制的意义在于Agent 每轮与 LLM 交互后上一轮的真实 token 消耗可以近乎零成本地复用到下一轮上下文构建中只有新增消息才需要轻量估算从而显著减少重复调用 token counter 的开销。分数从何而来ChatHistoryBlock 的 keep_rate 打分要理解分数在上下文构建中的角色需要回溯分数的产生端。ScoreBasedContextCreator消费的ContextRecord.score主要由ChatHistoryBlock.retrieve()生成见 chat_history_block.py系统消息固定score 1.0恒保留其余消息从最近一条开始score初始为 1.0每向前一条就乘以keep_rate默认0.9即越新的消息分数越高keep_rate必须位于[0, 1]否则抛出ValueError见 chat_history_block.py。文档中所说in history memory, the score of each message decreases according to keep_rate. The newer the message, the higher the score正是这段逻辑的准确描述。keep_rate越大历史消息在裁剪时被保留下来的可能性越高。此外ChatHistoryBlock.retrieve()还支持window_size滑动窗口若首条消息是 SYSTEM/DEVELOPER 角色则先保留再取其余消息中最近的window_size条见 chat_history_block.py。窗口裁剪 分数标记 ScoreBasedContextCreator 的 token 计算共同构成 CAMEL 聊天记忆的默认上下文控制链路。类内部辅助方法速览API 文档中还列出了若干内部私有方法它们在类内部承担特定的子任务虽然不直接对用户暴露但理解它们有助于把握整体设计方法职责_group_tool_calls_and_responses(units)基于tool_call_id将 assistant 的请求消息与所有相关工具响应含分块聚合为组返回Dict[str, List[_ContextUnit]]_truncate_with_tool_call_awareness(regular_units, tool_call_groups, system_tokens)将工具调用组与独立消息视为待选条目按分数排序后贪心加入上下文若完整工具组放不下则尝试仅保留请求消息与尽可能多的最近响应分块Partial Truncation_extract_system_message(records)从记录中提取并校验系统消息返回(system_unit, [])或(None, [])_conversation_sort_key(unit)定义最终输出排序键主键为时间戳升序次键为分数降序返回(timestamp, -score)_assemble_output(context_units, system_unit)将排序后的常规消息与系统消息组装为最终列表并统计 token 数其中_conversation_sort_key的时间升序 分数降序双键排序正是输出保持时间顺序、同时高分数消息在时间相同的情况下优先这一语义的实现与测试中断言的按时间戳排序行为完全一致。实际使用一个可运行的最小示例结合测试用例的写法你可以这样独立使用ScoreBasedContextCreatorfrom camel.memories import ( ContextRecord, MemoryRecord, ScoreBasedContextCreator, ) from camel.messages import BaseMessage from camel.types import ModelType, OpenAIBackendRole, RoleType from camel.utils import OpenAITokenCounter # 1. 构造上下文构建器token 计数器 token 上限 context_creator ScoreBasedContextCreator( OpenAITokenCounter(ModelType.GPT_4), 15 ) # 2. 构造带分数与时间戳的记忆记录 context_records [ ContextRecord( memory_recordMemoryRecord( messageBaseMessage( test, RoleType.ASSISTANT, meta_dictNone, contentNice to meet you., ), role_at_backendOpenAIBackendRole.ASSISTANT, ), timestamp1.0, score0.3, ), ContextRecord( memory_recordMemoryRecord( messageBaseMessage( test, RoleType.ASSISTANT, meta_dictNone, contentHello world!, ), role_at_backendOpenAIBackendRole.ASSISTANT, ), timestamp2.0, score0.9, ), ] # 3. 构建上下文返回 (有序消息列表, 总token数) messages, total_tokens context_creator.create_context( recordscontext_records ) # messages 按时间戳升序排列与输入顺序无关在真实 Agent 场景中你通常不需要手动构造这些对象——ChatAgent在初始化时已经替你搭好了ScoreBasedContextCreator ChatHistoryMemory的默认组合你只需要在需要精细控制记忆时理解这个类在链路中的位置即可。小结与源码索引ScoreBasedContextCreator是 CAMEL 记忆系统默认且唯一的上下文构建器实现context_creators包目前仅导出该类见 context_creators/init.py。它以系统消息优先、时间顺序输出、分数辅助裁剪、工具调用成对保留为设计主线并通过响应 usage 缓存 字符级估算显著降低了多轮对话中的 token 计数开销。关键源码位置速查类实现camel/memories/context_creators/score_based.py抽象基类与记忆接口camel/memories/base.py记录数据结构MemoryRecord/ContextRecordcamel/memories/records.py分数产生端keep_rate打分与窗口裁剪camel/memories/blocks/chat_history_block.py单元测试test/memories/context_creators/test_score_based.py在ChatAgent中的默认装配与缓存联动camel/agents/chat_agent.py、camel/agents/chat_agent.py在MemoryToolkit记忆加载中的使用camel/toolkits/memory_toolkit.py【免费下载链接】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),仅供参考
返回列表