---
title: AI Agent 时代的知识库：回忆、验证与写回
description: 从 ChatCrystal 的 MCP 工具和任务记忆实现出发，设计有范围、有证据、可修订的记忆循环，区分工具能力与自动化承诺。
image: "https://zengliangyi.com/og/blog/agent-knowledge-memory-loop.png"
---

一个有用的 Agent 知识库，应该帮助它在开始任务时找到适用的历史经验，在结束任务时留下可复用的结论。但“存得更多”不等于“记得更准”：旧版本的方案、一次性的环境检查和未经验证的猜测，都可能干扰下一次任务。

我更关心三个问题：这次该回忆什么、哪些材料可以相信、什么结果值得写回。本文以 [ChatCrystal](/projects/chatcrystal) 提交 [`7642768`](https://github.com/ZengLiangYi/ChatCrystal/tree/764276814e5c5a33ecbfeae63754f74b9261a3a8) 的 MCP 与任务记忆实现为例，区分已有能力和仍需调用方负责的工作。

## 工具接口让知识可调用，但不保证自动调用

MCP 为客户端提供发现和调用工具的协议。协议不会规定每个任务开始时必须回忆，也不会保证任务结束后自动写入；何时调用取决于客户端、模型、提示和工作流配置。[MCP 工具规范](https://modelcontextprotocol.io/specification/2025-06-18/server/tools)

ChatCrystal 的 [MCP 服务](https://github.com/ZengLiangYi/ChatCrystal/blob/764276814e5c5a33ecbfeae63754f74b9261a3a8/server/src/cli/mcp/server.ts) 提供这些入口：

| 工具 | 当前用途 |

| --- | --- |

| `search_knowledge` | 通过自然语言查询执行语义搜索 |

| `get_note` | 按 ID 读取笔记详情 |

| `list_notes` | 按标签或 `LIKE` 模式筛选并分页 |

| `get_relations` | 读取笔记关系 |

| `recall_for_task` | 按任务信息组织项目与全局记忆结果 |

| `validate_task_memory` | 对候选任务记忆做预检查 |

| `write_task_memory` | 校验后处理写回，可能创建、合并或跳过 |

当前 `list_notes` 的参数是 `tag`、`search` 和 `page`，不应承诺它提供时间范围筛选。`search` 在标题和摘要上使用 SQL `LIKE` 匹配，输入中的 `%` 和 `_` 会作为通配符，因此它并非严格的字面字符串查找。描述接口时，以实际参数和返回结果为准，比笼统说“Agent 已有长期记忆”更有用。

## 回忆需要范围和失败状态

[任务回忆实现](https://github.com/ZengLiangYi/ChatCrystal/blob/764276814e5c5a33ecbfeae63754f74b9261a3a8/server/src/services/memory/recall.ts) 使用任务目标和错误特征形成查询，结合项目身份，将结果组织为 `project_memories` 和 `global_memories`。项目身份可帮助避免把另一个项目的特定做法直接套过来。

但这仍是候选召回。当前流程先执行搜索，再按范围筛选结果，并不是对当前项目的全部笔记做穷尽检索。结果为空时，只能说明这次调用没有找到可返回的记忆。

如果无法确定项目身份，响应会给出警告并只返回全局匹配。语义检索不可用时，也会通过警告说明原因。调用方要区分“没有相关经验”和“检索没有成功”，否则一次模型服务故障可能被误读为知识库没有记录。

## 先验证任务，再验证记忆

回忆得到的旧笔记应该帮助提出假设，而不能替代本次验证。比如历史笔记建议把服务绑定到 IPv4，本次仍需确认报错地址、监听地址和实际运行环境，不能只因为曾经有效就直接修改配置。

任务结束后，再把结论整理成别人能够复用的材料。下面是记录结构的示意，不是工具请求 JSON：



```text
触发条件：什么操作、版本或输入会出现问题  
  观察证据：错误、日志、复现与失败检查  
  采取的修改：具体改动及其作用机制  
  验证结果：哪些检查通过，哪些尚未执行  
  适用范围：项目特例还是可迁移的经验
```



“修好了”“构建通过”缺少复用条件。相反，过度推广也有风险：一次环境中的修复不自动成为所有项目的规则。记忆应保留这个范围，而不是只保留一个听起来确定的结论。

## 质量检查不等于事实认证

当前实现并非把所有质量判断都交给 LLM。[预检查](https://github.com/ZengLiangYi/ChatCrystal/blob/764276814e5c5a33ecbfeae63754f74b9261a3a8/server/src/services/memory/preflight.ts) 和[笔记质量规则](https://github.com/ZengLiangYi/ChatCrystal/blob/764276814e5c5a33ecbfeae63754f74b9261a3a8/server/src/services/memory/quality.ts) 包含明确的程序判断，检查具体性、占位内容和可迁移的行动等信号；自动与手动模式也有不同处理。

通过这些检查，只能说明内容符合一定的写入标准，不能证明技术结论已在真实环境验证。字段齐全、语言具体的错误结论仍可能通过；某条新经验也不应仅因为尚无关联笔记就被视为没有价值。

[写回实现](https://github.com/ZengLiangYi/ChatCrystal/blob/764276814e5c5a33ecbfeae63754f74b9261a3a8/server/src/services/memory/writeback.ts) 会再次执行校验。调用方需要读取决策、原因和警告，不能把“工具调用成功返回”当成“一定创建了新笔记”。对跳过、合并和后续向量处理的状态，也应保留可检查的结果。

这里还有一个失败边界：笔记先保存，再生成向量。如果后一步报错，写回调用可能失败，但笔记已经存在。自动模式会保留索引待完成的回执，用相同的 `source_agent` 和 `source_run_key` 重试时可继续生成向量。调用方应先核对已有记录与回执，避免把错误响应解释成没有写入，再用新的运行标识重复创建笔记。

## 记忆是证据，不是新的指令来源

知识库内容可能来自旧对话、导入文件或模型摘要。即使它是自己保存的，也可能带有已经过期的命令，或被引用的提示文本。Agent 应将其作为待判断的材料，不能把笔记里的指令提升为当前任务的授权。

一个合理的使用顺序是：先看摘要与来源，再按需读取正文，确认适用范围后决定是否执行。影响外部系统的操作仍遵守当前任务的权限与确认要求，不因“记忆里这样写过”就自动获得许可。

写回时也要注意循环放大：Agent 读到一条猜测，生成另一条同义总结，再把两者当作相互佐证，会制造虚假的确信。保留原始证据、识别重复、修订过期内容，比单纯增加笔记数量重要。

## 用一次完整任务检验记忆循环

先选择一个熟悉的小任务，记录调用过程：是否真的调用了回忆工具、返回了什么、哪些材料被采纳、实际如何验证，以及写回最终作出了什么决策。再补一个没有匹配结果的任务和一个应被跳过的低价值写回。

离线能力也应沿着调用链检查。本地数据库与索引不保证查询模型、摘要模型和 Agent 本身都离线可用；具体数据流见[本地优先与隐私边界](/blog/local-first-ai-data-boundaries)。关系扩展如何补充候选材料，见 [RAG 与知识图谱](/blog/rag-and-knowledge-graphs)。

我希望知识库留下的是带条件、带证据、可以更新的经验。它可以减少重复调查，但仍需要当前任务中的验证来决定是否采用。

分享：

##  相关文章

[##  MCP 协议的边界：发现、实例身份与调用权限

对照 ChatCrystal 的七个 MCP 工具，用固定 SDK 的内存传输验证同名工具可指向不同实例，并区分参数 schema、行为提示与应用权限。          曾亮懿       2026年10月7日      阅读约 4 分钟

#ChatCrystal

#MCP

#Node.js](/blog/mcp-protocol-boundaries)    [##  实现最小 MCP Server：注册工具与验证 stdio 调用

用固定版本 TypeScript SDK 编写一个离线加法工具，从客户端完成初始化、发现、调用与参数错误检查，再对照 ChatCrystal 的适配边界。          曾亮懿       2026年10月6日      阅读约 4 分钟

#ChatCrystal

#MCP

#Node.js](/blog/mcp-server-implementation)    [##  ChatCrystal 入门：从安装到第一条可搜索笔记

按 ChatCrystal 0.6.1 的实际 CLI，依次验证安装、服务、两类模型、导入、摘要与搜索，区分 npm 包和桌面应用的使用入口。          曾亮懿       2026年10月3日      阅读约 5 分钟

#ChatCrystal

#Node.js

#知识管理](/blog/chatcrystal-getting-started)

##  从文章到代码

到我的 GitHub 看看 ChatCrystal、开发者工具和日常学习记录，欢迎交流实现细节。

[访问我的 GitHub](https://github.com/ZengLiangYi)

```json
{
  "@context": "https://schema.org",
  "@type": "WebSite",
  "name": "ZengLiangYi Blog",
  "alternateName": [
    "Zeng Liangyi",
    "ZengLiangYi",
    "zengliangyi.com"
  ],
  "url": "https://zengliangyi.com",
  "description": "曾亮懿的个人网站。记录 AI Native 探索、开发者工具与全栈产品实践。"
}
{
  "@context": "https://schema.org",
  "@type": "BlogPosting",
  "headline": "AI Agent 时代的知识库：回忆、验证与写回",
  "description": "从 ChatCrystal 的 MCP 工具和任务记忆实现出发，设计有范围、有证据、可修订的记忆循环，区分工具能力与自动化承诺。",
  "url": "https://zengliangyi.com/blog/agent-knowledge-memory-loop/",
  "image": "https://zengliangyi.com/images/blog/agent-knowledge-memory-loop.svg",
  "datePublished": "2026-06-05T01:00:00.000Z",
  "dateModified": "2026-10-03T00:00:00.000Z",
  "author": {
    "@type": "Person",
    "name": "曾亮懿",
    "url": "https://zengliangyi.com/about"
  },
  "publisher": {
    "@type": "Organization",
    "name": "ZengLiangYi Blog",
    "logo": {
      "@type": "ImageObject",
      "url": "https://zengliangyi.com/favicon-96x96.png"
    }
  },
  "mainEntityOfPage": {
    "@type": "WebPage",
    "@id": "https://zengliangyi.com/blog/agent-knowledge-memory-loop/"
  }
}
{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [
    {
      "@type": "ListItem",
      "position": 1,
      "name": "首页",
      "item": "https://zengliangyi.com/"
    },
    {
      "@type": "ListItem",
      "position": 2,
      "name": "文章",
      "item": "https://zengliangyi.com/blog"
    },
    {
      "@type": "ListItem",
      "position": 3,
      "name": "AI Agent 时代的知识库：回忆、验证与写回",
      "item": "https://zengliangyi.com/blog/agent-knowledge-memory-loop/"
    }
  ]
}
```
