模型接口与记忆
两个支撑性子系统:Model 让 agent 不关心背后是哪家 LLM;Memory 让 agent 的每一步既能存下来(回放/序列化),又能变回对话喂给模型。它们是循环(
01)两端的适配层。
1. Model:把各家 LLM 抹平成一个接口
1.1 要解决的小问题
OpenAI、Anthropic、HF Inference、本地 Transformers……每家 API 的入参名、消息格式、工具调用返回都不一样。agent 循环不该被这些差异污染。Model 基类(models.py:452)定义一个统一契约:
进:一列
ChatMessage+(可选)停止序列、response_format、可调工具。出:一个ChatMessage。
核心方法就一个 generate(models.py:553),各家子类实现自己那版。
1.2 统一契约
| 子类 | 背后 | 文件位置 |
|---|---|---|
InferenceClientModel | HF Inference Providers | models.py:1456 |
LiteLLMModel | LiteLLM(100+ 家) | models.py:1205 |
OpenAIModel / AzureOpenAIModel | OpenAI 兼容端点 | models.py:1646 / 1799 |
AmazonBedrockModel | AWS Bedrock | models.py:1859 |
TransformersModel / VLLMModel / MLXModel | 本地推理 | models.py:860 / 633 / 751 |
1.3 两处抹平差异的关键点
入参装配 _prepare_completion_kwargs(models.py:502):把内部的 ChatMessage 列表清洗成各家要的 dict(get_clean_message_list,:332,处理角色映射、图片转 URL、内容扁平化),再按明确的优先级合并 stop、tools、response_format 和用户 kwargs。工具在这里被转成 JSON schema 塞进 tools 字段(:539-542)。
出参兜底 parse_tool_calls(models.py:583):有些模型不返回结构化 tool_calls,而是把工具调用写在文本里。这个方法从文本里把工具名和参数解析出来,补成标准 tool_calls——让 ToolCallingAgent 即便对着「不太会 function calling」的模型也能工作(agents.py:1327-1331 会调它)。
还有 supports_stop_parameter(models.py:418)这类小适配:某些模型不接受 stop 参数,就自动不传。这些琐碎补丁正是「统一接口」的成本所在。
2. Memory:存储与上下文两用
2.1 要解决的小问题
agent 每一步产生一堆东西:模型说了什么、调了什么工具、观测是什么、有没有报错。这些既要存起来(回放、调试、序列化到 Hub),又要在下一步变回对话喂给模型。两个用途、一份数据。
2.2 每步是一个结构化对象
AgentMemory(memory.py:214)持有一个 steps 列表,元素是几种 MemoryStep:
| 步类型 | 存什么 | 符号 |
|---|---|---|
SystemPromptStep | 系统提示 | memory.py:199 |
TaskStep | 用户任务(可带图) | memory.py:186 |
PlanningStep | 一次规划的产出 | memory.py:153 |
ActionStep | 一个行动步的全部:模型输出、工具调用、代码、观测、错误、token 用量 | memory.py:51 |
FinalAnswerStep | 最终答案 | memory.py:209 |
2.3 关键机制:同一步,两种投影
每个步类型都实现 to_messages(),把自己变回模型能读的 ChatMessage。循环开头的 write_memory_to_messages(agents.py:758)就是把系统提示 + 每一步的 to_messages() 顺次拼成完整对话历史。
以 ActionStep.to_messages(memory.py:92)为例,它把一步拆成多条消息:
ActionStep
├─ model_output → assistant 消息(模型那段思考+代码)
├─ tool_calls → "Calling tools: [...]"
├─ observations → "Observation:\n..."(工具/执行结果)
└─ error → "Error:\n... Now let's retry: 别重复之前的错"