乐于分享
好东西不私藏

OpenClaw AGENTS.md 文件加载顺序:你用对了吗?源码解析告诉你答案

OpenClaw AGENTS.md 文件加载顺序:你用对了吗?源码解析告诉你答案

OpenClaw AGENTS.md 文件加载顺序:你用对了吗?源码解析告诉你答案

阅读时间:10 分钟 | 技术深度:⭐⭐⭐⭐ | 适用版本:OpenClaw v2026.2+

一、一个令人困惑的问题

如果你在微信、知乎或 Reddit 上搜索 OpenClaw 教程,大概率会看到类似这样的写法:

# AGENTS.md## 每次启动必做1. 先读取 SOUL.md —— 确认身份2. 再读取 USER.md —— 了解用户3. 读取 memory/YYYY-MM-DD.md —— 回顾近期4. 如果是主会话,还要读取 MEMORY.md

这个思路看起来很合理:Agent 启动时执行一系列步骤

但问题是:这些"指令"真的最佳流程吗?

今天我们直接看源码,找到答案。


二、文件加载流程

关键发现:这个顺序是后端硬编码的,无法通过 AGENTS.md 改变。


三、源码解析

3.1 文件名是硬编码常量

// 文件名常量定义 - 系统内置,不可更改constDEFAULT_AGENTS_FILENAME = "AGENTS.md";constDEFAULT_SOUL_FILENAME = "SOUL.md";constDEFAULT_TOOLS_FILENAME = "TOOLS.md";constDEFAULT_IDENTITY_FILENAME = "IDENTITY.md";constDEFAULT_USER_FILENAME = "USER.md";constDEFAULT_HEARTBEAT_FILENAME = "HEARTBEAT.md";constDEFAULT_BOOTSTRAP_FILENAME = "BOOTSTRAP.md";constDEFAULT_MEMORY_FILENAME = "MEMORY.md";

解读:这些文件名是硬编码的常量。你不能通过配置改变它们,Agent 更不能"选择"先读哪个后读哪个。


3.2 加载顺序是固定的

// 启动时自动加载的文件列表 - 固定顺序,后端执行asyncfunctionloadWorkspaceBootstrapFiles(dir) {const entries = [    { nameDEFAULT_AGENTS_FILENAME, ... },    { nameDEFAULT_SOUL_FILENAME, ... },    { nameDEFAULT_TOOLS_FILENAME, ... },    { nameDEFAULT_IDENTITY_FILENAME, ... },    { nameDEFAULT_USER_FILENAME, ... },    { nameDEFAULT_HEARTBEAT_FILENAME, ... },    { nameDEFAULT_BOOTSTRAP_FILENAME, ... }  ];// 追加 MEMORY.md  entries.push(...awaitresolveMemoryBootstrapEntries(resolvedDir));// 遍历读取,返回文件内容// ...}

核心发现

  • 加载顺序是固定的:AGENTS.md → SOUL.md → TOOLS.md → ... 
  • 这是后端执行的函数,Agent 根本看不到这个执行过程
  • Agent 拿到的只是最终结果:文件内容被注入到 System Prompt

进阶说明:MEMORY.md 的特殊优先级

MEMORY.md 虽然是最后追加的,但它在 System Prompt 中会被加上特殊的 header(如 ## Long-term Memory),放置在 Project Context 的最前面,确保模型最先看到核心记忆。这是 OpenClaw 的设计哲学:长期记忆优先级最高。


3.3 memory_search 是工具,不是启动流程

// memory_search 是一个工具定义,不是启动流程return {label"Memory Search",name"memory_search",description"Mandatory recall step: semantically search MEMORY.md + memory/*.md...",parametersMemorySearchSchema,executeasync (_toolCallId, params) => {// 语义搜索实现...  }};

关键发现

  • memory_search 是一个工具,Agent 需要主动调用
  • 不会自动执行,需要 Agent 在需要时调用
  • 把它写在 AGENTS.md 里,只是建议 Agent 使用这个工具,不是强制执行

进阶说明:memory/ 目录的 QMD Backend

如果配置了 QMD (Quaternion Memory Database) backend,memory/ 目录下的文件会自动建立向量索引 collection。当 Agent 调用 memory_search 时,会进行 hybrid 检索(关键词 + 语义向量),返回最相关的记忆片段。这是按需检索,不是启动时全量加载。


3.4 Sub-Agent 禁用 memory 工具

constSUBAGENT_TOOL_DENY_ALWAYS = ["gateway","agents_list","memory_search",   // Sub-Agent 禁用"memory_get",      // Sub-Agent 禁用"sessions_send"];

意义

  • Sub-Agent 无法访问主 Agent 的记忆
  • 即使 AGENTS.md 里写了"搜索记忆",Sub-Agent 也做不到
  • 这是架构层面的安全隔离,不是可以通过配置绑过的规则

关键结论:如果你在 AGENTS.md 里写"启动时搜索记忆",而任务被派发给 Sub-Agent 执行,那 Sub-Agent 会直接报错或忽略这条指令——因为它根本没有 memory_search 工具。这再次证明:在 AGENTS.md 写启动流程,不仅无效,还可能造成混乱。


四、进阶架构图解


五、内容注入流程

关键理解:文件内容被原样注入,AGENTS.md 里的"指令"只是普通文本,不是可执行代码。


六、核心要点


七、文件职责分层

关键理解:每个文件有明确的职责边界,AGENTS.md 负责"行为准则",不是"启动脚本"。


八、正确 vs 错误写法


九、验证方法

验证示例

用户:请告诉我,你是怎么知道我的用户信息的?正确配置的 Agent:"系统在初始化时已将 USER.md 的内容注入到我的上下文,我可以直接看到您的偏好设置,无需再次读取。"错误配置的 Agent:"我正在调用工具读取 USER.md..."→ 这说明你的 AGENTS.md 误导了 Agent

十、总结清单


参考资料


创作声明:AI 辅助生成,仅代表作者个人观点。内容不构成专业建议,转载请注明出处。

引用链接

[1]Agent Workspace: https://docs.openclaw.ai/concepts/agent-workspace