- 人工智能
- AI Agent
- Agent 框架
- 工具调用
- 代码智能体
- MCP Clients
- Agent 沙箱
【免费下载链接】smolagents
🤗 smolagents: a barebones library for agents that think in code.
记忆是 Agent 的核心组件之一。一个 Agent 可以简单定义为"工具 + 提示词 + 记忆":它不仅拥有调用工具的能力,更重要的是具备对过往步骤的记忆,能够追溯完整的规划、执行与错误历史。本篇指南围绕 docs/source/zh/tutorials/memory.md 展开,结合 smolagents 源码深入讲解如何回放 Agent 的运行记录、如何在运行过程中动态读写与修改记忆,以及如何按步(step by step)手动驱动 Agent——读完你可以在自己的多步 Agent 应用中实现记忆审查、token 优化与长任务断点执行。
记忆在 Agent 中的角色:从结构看起
在动手之前,先理解 smolagents 中记忆的底层模型。Agent 的记忆由 src/smolagents/memory.py 中的AgentMemory类承载,它包含两个核心属性:
system_prompt:一个SystemPromptStep对象,保存系统提示词;steps:一个列表,依次存放 Agent 执行过程中产生的各类步骤对象。
所有步骤都继承自MemoryStep基类,当前仓库中主要有以下几种步骤类型:
| 步骤类 | 字段要点 | 含义 |
|---|---|---|
TaskStep | task、task_images | 一个(新的)任务及其可选图片 |
ActionStep | step_number、timing、model_output、tool_calls、code_action、observations、observations_images、error、token_usage、is_final_answer等 | Agent 思考、行动、观察结果的一个完整执行步 |
PlanningStep | plan、model_input_messages、model_output_message、timing、token_usage | 规划步骤,用于生成/更新计划 |
SystemPromptStep | system_prompt | 系统提示词步骤 |
FinalAnswerStep | output | 最终答案步骤 |
从 src/smolagents/agents.py 的_run_stream(L540-L611)可以看到,Agent 每完成一步(包括规划步骤),都会把对应的PlanningStep或ActionStep追加到agent.memory.steps,并调用_finalize_step写入时间戳与触发回调。而在每次向模型发起请求之前,write_memory_to_messages(L758-L770)会把整个记忆转换成消息列表喂给 LLM——这就是"记忆决定上下文"的直接体现。
由于 src/smolagents/init.py 中from .memory import *,你可以直接通过from smolagents import ActionStep, TaskStep, ...导入这些步骤类型。
回放 Agent 的记忆:审查一次运行
运行一个 Agent 之后,最基础的需求是"回顾它到底做了什么"。smolagents 提供了两种方式:
- 插装(instrumentation)可视化界面:通过 OpenTelemetry 标准将运行过程输出到可视化监控平台,支持对特定步骤进行缩放,详见 插装指南(inspect_runs)。
agent.replay()命令行回放:直接在控制台以结构化文本重放整段记忆。
使用 agent.replay()
在 Agent 完成运行之后,只需一行代码即可回放最近一次运行:
from smolagents import InferenceClientModel, CodeAgent agent = CodeAgent(tools=[], model=InferenceClientModel(), verbosity_level=0) result = agent.run("What's the 20th Fibonacci number?") # 回放最近一次运行 agent.replay()从源码看,agent.replay(detailed=False)(src/smolagents/agents.py L859-L866)实际上代理给AgentMemory.replay(logger, detailed)(src/smolagents/memory.py L248-L271),其行为要点:
- 依次打印系统提示词、每个
TaskStep、每个ActionStep(含步骤号、模型输出)以及PlanningStep(含计划内容); detailed=True时会额外打印每一步的model_input_messages(模型实际接收到的完整消息),可精确复现每一步的输入,但日志长度会指数级膨胀,源码注释明确警告"仅用于调试"。
导出整段代码与步骤数据
除回放外,AgentMemory还提供两个实用的审查方法:
return_full_code()(src/smolagents/memory.py L273-L277):把记忆里所有ActionStep的code_action拼接成一个完整脚本返回,方便检查 Agent 实际执行的全部代码;对应测试见 tests/test_memory.py 的test_return_all_code_actions。get_full_steps()/get_succinct_steps():前者返回包含model_input_messages的完整步骤字典列表,后者剔除模型输入消息、仅保留精简表示,适合序列化存档或传给他处。
动态修改 Agent 的记忆
许多高级应用场景需要对记忆进行动态读写:例如注入另一套上下文、清理过时的中间产物以节省 token,或在执行中途修正某一步的错误。
直接访问记忆对象
agent.memory暴露了全部记忆,你可以像操作普通 Python 对象一样读取它:
from smolagents import ActionStep system_prompt_step = agent.memory.system_prompt print("The system prompt given to the agent was:") print(system_prompt_step.system_prompt) task_step = agent.memory.steps[0] print("\n\nThe first task step was:") print(task_step.task) for step in agent.memory.steps: if isinstance(step, ActionStep): if step.error is not None: print(f"\nStep {step.step_number} got this error:\n{step.error}\n") else: print(f"\nStep {step.step_number} got these observations:\n{step.observations}\n")注意agent.memory.steps[0]通常是TaskStep(由run()在启动时追加),ActionStep从第 1 步开始。还可以用agent.memory.get_full_steps()拿到完整的步骤字典数据,例如传给监控系统或序列化保存。
记忆不仅可读,也可写:直接对steps列表、某个步骤的字段(如observations、observations_images)赋值即可。因为后续模型请求会通过write_memory_to_messages重新读取记忆,所以任何修改都会立即影响 Agent 的下一步行为。
通过步骤回调(step callbacks)动态修改记忆
更强大、更自动化的方式是步骤回调。回调函数可以直接在参数中拿到agent对象,因此能够访问任意记忆步骤并按需修改。
一个经典场景:监控网页浏览 Agent 每一步的屏幕截图,只保留最新截图、删除旧步骤的图片,从而节省 token 消耗。原文档给出了精炼版示例,而仓库中的完整可运行实现位于 src/smolagents/vision_web_browser.py(L66-L84),完整版如下:
import helium import PIL.Image from io import BytesIO from time import sleep def save_screenshot(memory_step: ActionStep, agent: CodeAgent) -> None: sleep(1.0) # 等待 JavaScript 动画完成后再截图 driver = helium.get_driver() current_step = memory_step.step_number if driver is not None: # 删除旧步骤的截图,保持日志精简、节省 token for previous_memory_step in agent.memory.steps: if isinstance(previous_memory_step, ActionStep) and previous_memory_step.step_number <= current_step - 2: previous_memory_step.observations_images = None png_bytes = driver.get_screenshot_as_png() image = PIL.Image.open(BytesIO(png_bytes)) print(f"Captured a browser screenshot: {image.size} pixels") memory_step.observations_images = [image.copy()] # 必须 copy,确保引用在步骤结束后仍有效 # 把当前 URL 一并写入观测 url_info = f"Current url: {driver.current_url}" memory_step.observations = ( url_info if memory_step.observations is None else memory_step.observations + "\n" + url_info )随后在初始化 Agent 时,把回调函数传入step_callbacks参数:
CodeAgent( tools=[WebSearchTool(), go_back, close_popups, search_item_ctrl_f], model=model, additional_authorized_imports=["helium"], step_callbacks=[save_screenshot], max_steps=20, verbosity_level=2, )回调机制的源码原理
step_callbacks的底层实现是 src/smolagents/memory.py 中的CallbackRegistry,初始化逻辑位于 src/smolagents/agents.py 的_setup_step_callbacks(L416-L434):
- 传入列表
[callback1, callback2, ...]时,全部注册到ActionStep上(向后兼容); - 传入字典
{step_cls: callback}时,可以针对TaskStep、PlanningStep等具体步骤类分别注册回调; - 无论是否显式传入,
Monitor.update_metrics都会被默认注册到ActionStep上,用于指标采集。
回调在_finalize_step(L620-L623)中通过self.step_callbacks.callback(memory_step, agent=self)触发。CallbackRegistry.callback还做了签名兼容处理:只接收一个参数的回调只拿到memory_step,接收多个参数的回调则额外拿到agent=self等关键字参数。
分步运行 Agent:手动驱动每一步
某些场景下你希望完全掌控执行节奏——例如某个工具调用可能耗时数天、需要断点续跑,或者你想在每一步之间更新记忆。smolagents 允许你逐步执行 Agent:
from smolagents import InferenceClientModel, CodeAgent, ActionStep, TaskStep agent = CodeAgent(tools=[], model=InferenceClientModel(), verbosity_level=1) print(agent.memory.system_prompt) task = "What is the 20th Fibonacci number?" # 你甚至可以在这里加载另一个 Agent 的记忆作为初始上下文: # agent.memory.steps = previous_agent.memory.steps # 开启一个新任务! agent.memory.steps.append(TaskStep(task=task, task_images=[])) final_answer = None step_number = 1 while final_answer is None and step_number <= 10: memory_step = ActionStep( step_number=step_number, observations_images=[], ) # 运行一步(思考 -> 行动 -> 观察) final_answer = agent.step(memory_step) agent.memory.steps.append(memory_step) step_number += 1 # 每一步之后都可以随意修改记忆! # 例如更新刚刚完成的那一步: # agent.memory.steps[-1] = ... print("The final answer is:", final_answer)关键点解读:
agent.step(memory_step)(src/smolagents/agents.py L782-L787)执行 ReAct 框架中的一步:Agent 思考、行动、观察结果;返回None表示这一步不是最终步,返回最终答案则循环结束。- 手动构造
ActionStep并传入step_number,因为自动运行时这一步号由_run_stream内部维护,手动模式下需要自己递增。 - 手动追加
TaskStep告诉 Agent 新任务已经开始,这与run()内部行为一致(见 L488)。 - 每步结束后你都能自由改写
agent.memory.steps,这是实现"跨步骤记忆注入"、"长任务恢复执行"的基础能力。注意你还需要手动维护循环上限(示例中为 10),与自动模式下的max_steps语义对应。 - 该模式尤其适合工具调用耗时极长(如数天)的任务:跑完一步即可保存记忆状态,下次从断点继续。
小结与进一步阅读
- 回放:
agent.replay()一行回放整段记忆;detailed=True可查看每步模型输入(仅限调试)。 - 审查:
agent.memory.system_prompt/agent.memory.steps直接读取;get_full_steps()/get_succinct_steps()/return_full_code()导出结构化数据。 - 动态修改:直接改
steps中的字段,或通过step_callbacks在每步结束后自动清理/注入内容(完整示例见 src/smolagents/vision_web_browser.py)。 - 分步运行:
agent.step(memory_step)手动驱动,配合TaskStep/ActionStep手动追加实现断点续跑。
若要更深入地验证这些行为,可阅读 tests/test_memory.py——它覆盖了AgentMemory初始化、return_full_code()拼接逻辑、ActionStep.dict()与to_messages()的消息转换、以及各步骤类的 JSON 序列化等关键行为。如果你需要将运行过程输出到可视化监控平台(OpenTelemetry / Phoenix / Langfuse),请继续阅读 插装指南(inspect_runs)。
- 人工智能
- AI Agent
- Agent 框架
- 工具调用
- 代码智能体
- MCP Clients
- Agent 沙箱
【免费下载链接】smolagents
🤗 smolagents: a barebones library for agents that think in code.
相关推荐
smolagents 记忆管理完全指南:回放、动态修改与逐步执行 Agent
smolagents 记忆管理完全指南:回放、动态修改与逐步执行 Agent Agent 本质上由几个简单组件构成:工具(tools)、提示词(prompts)
人工智能AI AgentAgent 框架工具调用代码智能体MCP ClientsAgent 沙箱smolagents 智能体记忆管理实战:重放、动态改写与逐步执行
smolagents 智能体记忆管理实战:重放、动态改写与逐步执行 smolagents 将智能体定义为“工具 + 提示词 + 记忆”的组合,其中 记忆 (me
人工智能AI AgentAgent 框架工具调用代码智能体MCP ClientsAgent 沙箱Agno × SurrealDB 记忆管理实战:从零实现 Agent 持久化记忆的完整指南
Agno × SurrealDB 记忆管理实战:从零实现 Agent 持久化记忆的完整指南 Agno(原 Phidata)将 SurrealDB 作为 Agen
人工智能大模型AI AgentAgent 框架多智能体工具调用RAGAgent 工作流Agent 记忆
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考