Damn AgentBeta

工具调用与记忆

工具和记忆决定了智能体能否可靠接触外部世界并保留状态。

工具调用和记忆是 Agent 从“会回答”走向“会做事”的关键。

工具调用

工具不是函数列表那么简单。每个工具都应该定义:

  • 输入 schema。
  • 输出 schema。
  • 权限范围。
  • 超时和重试策略。
  • 失败语义。
  • 是否需要人工确认。
tool-schema.ts
type ToolDefinition<Input, Output> = {
  name: string;
  description: string;
  inputSchema: Input;
  run(input: Input): Promise<Output>;
  risk: "low" | "medium" | "high";
};

高风险工具,例如删除文件、部署服务、转账、发邮件,应该在执行前进入确认流程。

工具注册表

生产级 Agent 不应该让模型凭空猜工具。工具应进入注册表,由编排层统一查找、校验和执行:

字段作用
name稳定标识,供模型和编排层匹配
description告诉模型何时使用、何时不要使用
inputSchema约束参数类型、必填项和枚举值
outputSchema约束返回结构,方便后续观察回填
risk标记只读、写入、高风险或需要审批
timeout防止工具挂起拖死整个 Loop
retryPolicy定义哪些错误可重试、最多重试几次

工具描述要写给模型看,但安全策略要写在代码里。提示词可以提醒模型不要越权,真正的越权拦截必须由工具执行层负责。

工具结果的回填

工具执行后,不要直接把原始输出全部塞回上下文。建议统一成 observation:

{
  "tool": "search_docs",
  "ok": true,
  "summary": "找到 3 个相关页面,最相关的是 context-engineering.mdx。",
  "evidence": [
    {
      "path": "content/docs/practices/context-engineering.mdx",
      "lines": "12-38"
    }
  ],
  "truncated": false
}

这样模型能继续推理,系统也能审计证据来源。对于大文件、日志、网页抓取结果,应保留原始位置引用,而不是复制全部内容。

记忆类型

类型生命周期例子
上下文窗口单次推理当前任务说明、工具结果
会话状态一次任务已完成步骤、失败原因
长期记忆跨会话用户偏好、项目约定
审计轨迹长期保存工具输入输出、审批记录

设计原则

记忆不是越多越好。好的记忆系统应该能回答:

  1. 为什么要记。
  2. 谁能读取。
  3. 多久过期。
  4. 如何纠错。
  5. 如何避免污染下一次任务。

记忆生命周期

记忆系统需要完整生命周期,而不是只有“写入”:

  1. 捕获:从用户反馈、工具结果、任务总结中提取候选记忆。
  2. 筛选:判断是否稳定、是否与未来任务相关、是否含敏感信息。
  3. 存储:标注来源、时间、适用范围、置信度和过期条件。
  4. 检索:按当前任务选择性注入,不把全部记忆塞进 prompt。
  5. 纠错:当用户否认或证据冲突时,更新或废弃旧记忆。
  6. 清理:过期、敏感、低价值记忆应可删除或归档。

记忆如果不能纠错,就会从“经验”变成“污染源”。

与上下文工程的关系

记忆是原材料,上下文工程是装配方式。不要把所有记忆都塞进 prompt,而是按任务目标、风险等级和 token 预算选择性注入。

常见失败模式

失败模式表现处理方式
工具过宽模型能直接调用高风险动作按任务暴露最小工具集
参数幻觉模型生成不存在字段或路径schema 校验、枚举约束、错误回填
记忆过期旧项目约定影响新任务给记忆加时间和适用范围
隐私泄露敏感信息被长期保存或回灌分类、脱敏、最小注入
上下文污染无关记忆挤占窗口检索排序和人工可见摘要

检查清单

  • 是否所有工具都有 schema、错误语义、权限和超时。
  • 是否区分只读工具、写入工具和不可逆工具。
  • 是否将工具结果结构化成 observation。
  • 是否给长期记忆记录来源、时间、适用范围和纠错方式。
  • 是否能解释本轮为什么注入某条记忆。
  • 是否能删除或覆盖错误记忆。

延伸阅读

On this page