跳到主要内容

地基 — 消息 / 记忆 / 模型 / 工具

这章讲什么: ChatAgentRolePlayingWorkforce 三层都站在同样四块地基上。看懂这四块,才能改动或扩展框架。

1. BaseMessage — 统一消息格式

小问题: OpenAI、Anthropic、本地模型的消息格式各不相同,框架内部不能到处写 if-else。

思路: 内部一律用 BaseMessage(一个 dataclass:role_name / role_type / content / 可选的图片、视频、推理痕迹,messages/base.py:54-90),要发给某家模型时再转成对应格式。

构造用工厂方法,语义清晰:

# 示意,基于真实 API
from camel.messages import BaseMessage

user_msg = BaseMessage.make_user_message(role_name="User", content="你好")
asst_msg = BaseMessage.make_assistant_message(role_name="Bot", content="在")

真实符号:BaseMessage.make_user_message(messages/base.py:92)、make_assistant_message。它还能转成 OpenAI 格式(to_openai_message)供模型后端消费。

2. AgentMemory — 历史 → 上下文

小问题: 记忆要存得下全部历史,但每次只能喂给模型「token 预算内」的一段。

思路:两层分工。

写入 读取(get_context)
──── ──────────────────
MemoryRecord ──▶ 存储 存储 ──▶ retrieve() 拿记录
(一条消息) (KV/向量) ──▶ ContextCreator 排序+算 token
──▶ (OpenAIMessage 列表, token 数)

三种现成记忆(memories/agent_memories.py):

记忆类存哪特点
ChatHistoryMemory键值存储(默认内存)最常用,可设 window_size 只取最近 N 条
VectorDBMemory向量库按当前话题语义检索相关历史
LongtermAgentMemory两者结合近期聊天 + 向量召回拼在一起

LongtermAgentMemory.retrieve(agent_memories.py:278)的拼法很巧:chat_history[:1] + 向量召回 + chat_history[1:]——把系统消息留在最前,中间插入召回的相关记忆,再接最近对话(agent_memories.py:291)。

上下文怎么算 token: ScoreBasedContextCreator.create_context(memories/context_creators/score_based.py:112)按时间戳排序、系统消息置顶,然后数 token。注意:这版不再按 token_limit 裁剪记录(注释明说 token_limit 仅保留兼容,score_based.py:35-37),裁剪交给 ChatAgent 的摘要压缩(见下)。它还缓存上次 LLM 用量、对新消息用「约 2 字符/token」估算以省去重复计数(_estimate_message_tokens,score_based.py:76)。

3. 上下文摘要压缩(精华)

小问题: 对话越来越长,迟早撑爆上下文窗口。

思路: 不是简单丢老消息,而是让 LLM 把老对话总结成一段摘要,用摘要替换原文,腾出空间。

触发点在每圈循环取上下文时——ChatAgent._get_context_with_summarization(chat_agent.py:1009):

  • 算出当前 token 数,和「下次摘要阈值」比(_calculate_next_summary_threshold,chat_agent.py:1081)。
  • 超阈值 → 调 self.summarize(...) 生成摘要,再 _update_memory_with_summary 用摘要重写记忆(chat_agent.py:1031-1041)。
  • 极端情况(摘要本身都超过 token_limit * summary_window_ratio)→ 做一次「全量压缩」(chat_agent.py:1020-1029)。
# 示意,非源码:压缩的判定逻辑
context, num_tokens = memory.get_context()
if num_tokens > next_summary_threshold(): # 太长了
summary = self.summarize() # 让 LLM 总结老对话
update_memory_with_summary(summary) # 用摘要替换原文
return memory.get_context() # 重新取,现在短了
return context, num_tokens

重点看:压缩发生在「发请求之前」,所以模型永远收到的是预算内的上下文,调用者无感。

4. BaseModelBackend — 40+ 家模型一个接口

小问题: 要支持 OpenAI、Anthropic、Gemini、本地 Ollama/vLLM…… 上层代码不该关心是哪家。

思路: 所有后端实现同一个 BaseModelBackend(models/base_model.py),核心是 run(messages, response_format, tools)ChatAgent 只调这一个方法(回看 01_get_model_response)。

怎么选后端: ModelFactory.create(model_platform, model_type)(models/model_factory.py)按平台枚举查表(_MODEL_PLATFORM_TO_CLASS_MAP,model_factory.py:78)实例化对应类。model_factory.py:18-66 那一长串 import 就是支持的全部后端清单。

# 示意,基于真实 API
from camel.models import ModelFactory
from camel.types import ModelPlatformType, ModelType

model = ModelFactory.create(
model_platform=ModelPlatformType.OPENAI,
model_type=ModelType.GPT_4O,
)
agent = ChatAgent("You are helpful.", model=model)

多后端负载均衡: ChatAgent 可接一个后端列表,由 ModelManager 按策略(默认 round_robin)轮流选(见 ChatAgent 构造参数 scheduling_strategy,chat_agent.py:419-420)。

5. FunctionTool — Python 函数 → 工具 schema

小问题: LLM 调工具需要 JSON schema(函数名、参数类型、描述),手写很烦。

思路: FunctionTool(toolkits/function_tool.py:517)从函数签名 + docstring 自动生成 OpenAI 工具 schema(get_openai_tool_schema,function_tool.py:228 / :792)。你只要写普通带类型注解和 docstring 的函数。

# 示意,基于真实用法
from camel.toolkits import FunctionTool

def add(a: int, b: int) -> int:
r"""两数相加。

Args:
a (int): 第一个数。
b (int): 第二个数。
"""
return a + b

agent = ChatAgent("...", tools=[FunctionTool(add)]) # 直接当工具用

成套的工具放在 BaseToolkit(toolkits/base.py:61),get_tools() 返回一组 FunctionTool。仓库里有 90+ 个工具箱(搜索、代码执行、浏览器……),camel/toolkits/ 下一个文件一个。

ChatAgent 把所有工具的 schema 汇总后随请求发出:_get_full_tool_schemas(chat_agent.py:931)= 外部工具 schema + 每个内部工具的 get_openai_tool_schema()

6. 这四块如何拼成一次 step

回到 01 的循环,现在每一步都能对上地基:

step 的一圈
───────────
① memory.get_context() ← §2 AgentMemory(+ §3 摘要压缩)
② model_backend.run( ← §4 BaseModelBackend
context,
tools=_get_full_tool_schemas()) ← §5 FunctionTool
③ 解析出 tool_call_requests / 最终消息 ← §1 BaseMessage 承载

7. 代码地图

主题文件符号
统一消息camel/messages/base.pyBaseMessage / make_user_message / to_openai_message
记忆基类camel/memories/base.pyAgentMemory / BaseContextCreator
三种记忆camel/memories/agent_memories.pyChatHistoryMemory / VectorDBMemory / LongtermAgentMemory
上下文构造camel/memories/context_creators/score_based.pyScoreBasedContextCreator.create_context
摘要压缩触发camel/agents/chat_agent.pyChatAgent._get_context_with_summarization
模型基类camel/models/base_model.pyBaseModelBackend.run
模型工厂camel/models/model_factory.pyModelFactory.create
工具封装camel/toolkits/function_tool.pyFunctionTool / get_openai_tool_schema
工具箱基类camel/toolkits/base.pyBaseToolkit.get_tools