read

Clawdbot 的核心是决策:如何理解收到的消息,并决定下一步做什么。

这篇文档解释两件事:

  • 意图识别:Clawdbot 如何区分“需要精确执行的指令”和“需要理解与规划的开放式任务”。
  • Memory Search:当任务需要回忆信息时,Clawdbot 如何从长期记忆中高效检索相关片段(memory_search / memory_get)。

本文遵循“认知带宽友好”原则:先看标题和图,需要时再读正文。

Repo: clawdbot/clawdbot

0) 一句话心智模型

规则处理确定性指令,用 LLM 处理开放式任务。


一、高层组件概览

总体架构

下图展示了 Clawdbot 的核心组件及其交互关系,从消息输入到最终行动。

flowchart TD
    In[Channel 输入<br/>Channel Plugins] --> GW[Gateway / Runtime]
    GW --> AR[决策层 Auto-reply<br/>识别意图与执行指令]

    AR -->|控制意图| Ctrl[执行控制命令<br/>status model stop]
    AR -->|任务意图| Agent[任务层 Agent<br/>理解 规划 执行]

    Agent --> Tools[工具层 Tools<br/>提供扩展能力]

    Tools --> Memory[记忆工具<br/>memory_search memory_get]
    Tools --> Exec[执行工具<br/>exec browser]
    Tools --> Cron[定时工具<br/>cron]

    Ctrl --> Out[Channel 回复或动作]
    Agent --> Out
    Out --> In
  • Channel Plugins:负责与具体平台(如 Discord、Slack)交互,收发消息和执行平台特定动作。
  • Auto-reply:决策流水线,负责识别消息意图,判断是否响应、是否为指令,以及是否授权。
  • Agent:当任务需要理解和规划时,由它组装 prompt、调用 LLM,并管理工具的执行。
  • Tools:为 Agent 提供扩展能力,例如使用 memory_search 检索记忆、使用 exec 执行代码等。

消息 → 决策 → 行动

此流程展示了一条消息从接收到响应的完整生命周期,分为三个主要阶段。

flowchart TD
    subgraph A[阶段一 消息]
        M1[Channel 原始消息] --> M2[标准化封装<br/>Envelope]
    end

    subgraph B[阶段二 决策]
        M2 --> D1[Auto-reply 决策]
        D1 --> D2{需要回应}
        D2 -- 否 --> Z1[忽略]
        D2 -- 是 --> D3{是指令}
        D3 -- 是 --> C1[执行控制命令]
        D3 -- 否 --> D4{已授权}
        D4 -- 否 --> Z2[拒绝或沉默]
        D4 -- 是 --> A1[启动 Agent]
    end

    subgraph C[阶段三 行动]
        A1 --> T1{调用工具}
        T1 -- 是 --> S1[执行工具<br/>memory_search browser exec]
        T1 -- 否 --> R1[生成回复]
        S1 --> R1
        C1 --> R1
        R1 --> O1[发送回复或执行动作]
    end

    O1 --> M1

各阶段的输入与输出

  • 消息阶段
    • 输入:来自平台的原始事件,例如消息文本、附件、发送者、上下文等。
    • 输出:标准化的消息对象 Envelope,屏蔽平台差异。
  • 决策阶段
    • 输入Envelope 与运行时上下文,例如是否被@、是否私聊、权限状态等。
    • 输出:一个明确的决策分支:忽略、执行指令、或启动 Agent
  • 行动阶段
    • 输入:来自决策层的具体指令,或来自 Agent 的执行计划。
    • 输出:可见的副作用,例如发送回复、调用工具、创建定时任务。

二、意图识别:Clawdbot 实际上做了什么

Clawdbot 的意图识别是分层的,旨在兼顾效率与智能。

  1. 规则层 控制意图:通过固定规则快速、可靠地识别命令,实现确定性行为。
  2. LLM 层 任务意图:如果消息不是命令,则交由 Agent 利用 LLM 的理解能力来推断任务。

2.1 控制意图:用规则识别指令

Clawdbot 将两类文本模式视为控制意图

  • 整条消息是命令:例如 /statusstop。通过 hasControlCommand 将消息标准化后,与命令注册表进行精确匹配。
  • 消息中包含指令 token:通过 hasInlineCommandTokens 使用宽泛的正则表达式进行快速粗筛。此步骤允许误判,目的是尽早识别可能需要立即处理的消息,而无需等待 LLM。

这种设计的目的是保证核心控制命令的可靠性,并避免在明显无需 Agent 的消息上浪费 LLM 资源。

2.2 触发条件:何时响应消息

Clawdbot 并非对所有消息都响应。它依赖 Auto-reply 流水线中的触发逻辑来决定是否行动。

常见的触发条件包括:

  • 消息明确指向 bot,例如被@、在私聊中、或在已激活的群聊中。
  • 消息包含控制命令或疑似指令。

在其他情况下,它会保持沉默,以避免干扰。

2.3 任务意图:用 LLM 理解开放式任务

当一条消息通过所有前置检查并被分派给 Agent 时,任务意图的识别就交给了 LLM。

  • Agent 会结合 system prompt 与历史消息来理解用户的完整任务。
  • system prompt 中可以包含硬性规定,例如“当需要回忆信息时,必须先调用 memory_search 再调用 memory_get”。

总结:控制意图由规则系统处理,任务意图由 LLM 处理。

三、搜索:memory_search 为什么快

memory_search 是 Clawdbot 赋予 Agent可检索长期记忆。当任务需要回忆“我们上次讨论过什么”或“找到那个 TODO”时,Agent 会先用 memory_search 在记忆文件中定位相关片段,再用 memory_get 安全地读取原文。这确保了回复建立在事实之上,而不是凭空猜测。

这里的“快”,来自高效的索引与混合检索机制。

3.1 工具接口:memory_searchmemory_get

Agent 通过两个工具与记忆系统交互:

  • memory_search:输入查询 query,可选 maxResultsminScore,返回相关片段的列表,包含路径、行号与分数。
  • memory_get:根据 memory_search 返回的路径与行号范围,安全地读取原始内容。

3.2 索引结构:SQLite + FTS + 向量

每个 Agent 的记忆存储在独立的 SQLite 数据库中,路径为 ~/.clawdbot/memory/{agentId}.sqlite

其核心表结构包括:

  • chunks:内容分块表,存储 Markdown 内容块、文件路径及起止行号。
  • chunks_fts:全文检索表,使用 FTS5 提供关键词检索与 BM25 排序。
  • chunks_vec:向量索引表,使用 sqlite-vec 存储 embedding 向量并进行相似度检索。
  • embedding_cache:embedding 缓存表,避免对相同内容重复计算 embedding。

索引构建流水线

下图描述了从源文件到可搜索索引的完整处理流程。

flowchart TD
    subgraph Src[数据源]
        A[源文件<br/>MEMORY.md 与 memory 目录] 
        C[可选源<br/>会话转录]
    end

    subgraph Proc[处理与存储]
        B[内容分块] 
        D[计算 embedding] 
        E[写入 SQLite]
    end

    subgraph Idx[索引与缓存]
        F[创建 FTS 索引]
        G[创建向量索引]
        H[写入 embedding 缓存]
    end

    I[文件监听] --> B
    A --> B
    C --> B
    B --> D
    D --> E
    E --> F
    E --> G
    E --> H

3.4 查询流程:混合检索如何工作

MemoryIndexManager.search 方法采用混合检索策略,结合了关键词和语义搜索的优点:

  1. 关键词搜索:首先,使用 FTS5 快速召回包含相关关键词的候选片段。
  2. 向量搜索:然后,将 query 文本向量化,在 sqlite-vec 中进行语义相似度检索。
  3. 融合排序:最后,按预设权重融合两路结果,并根据 minScore 过滤,得到最终排序列表。

查询时序图

此图展示了当 Agent 调用 memory_search 时,各组件间的交互顺序。

sequenceDiagram
    participant Agent
    participant Tool as memory_search
    participant Manager as MemoryIndexManager
    participant DB as SQLite
    participant Emb as Embeddings

    Agent->>Tool: tool call query
    Tool->>Manager: search query
    Manager->>Manager: sync if needed
    Manager->>DB: keyword search
    Manager->>Emb: embed query
    Emb-->>Manager: query vector
    Manager->>DB: vector search
    Manager->>Manager: merge results
    Manager-->>Tool: top snippets
    Tool-->>Agent: JSON results

3.5 新鲜度:Watcher 与增量同步

为了在不阻塞用户查询的前提下保持索引最新,系统采用异步、增量的更新机制:

  • 文件监听:通过 chokidar 监听记忆文件的变化,触发增量索引。
  • 防抖处理:合并短时间内发生的多次文件修改,避免不必要的重复索引。
  • 后台同步:索引过程在后台进行,最大程度减少对前台查询性能的影响。

四、代码阅读入口

  • 理解命令与指令识别
    • src/auto-reply/command-detection.tscommands-registry.data.ts 开始。
  • 添加新的快捷指令
    • 参考 src/auto-reply/reply/directive.parse.test.ts 中的测试用例。
  • 调整搜索排序或权重
    • 查看 src/memory/hybrid.tssrc/memory/manager.ts
  • 修改分块大小或 embedding 配置
    • 默认值与解析逻辑位于 src/agents/memory-search.ts

五、核心术语

  • 控制意图:可通过固定规则解析的命令或指令。
  • 任务意图:需要由 LLM 推理和理解的开放式任务。
  • FTS5:SQLite 内置的全文搜索引擎。BM25 是其默认使用的相关性排序算法。
  • sqlite-vec:一个为 SQLite 提供向量相似度搜索功能的开源扩展。
  • 混合检索:一种结合了关键词搜索与向量语义搜索的策略,旨在提高检索的准确性和相关性。

附录:关键文件地图

  • 命令检测:src/auto-reply/command-detection.ts
  • Memory 工具:src/agents/tools/memory-tool.ts
  • Memory 配置:src/agents/memory-search.ts
  • Memory 管理器:src/memory/manager.ts
  • 混合检索逻辑:src/memory/hybrid.ts
Blog Logo

勒西


Published

Image

Mind Defy

科技新闻 | 技术博客 | 哲学与AI | 投资金融

Back to Overview