从架构到代码:深入理解 OpenClaw 的双源记忆系统

关注腾讯云开发者,一手技术干货提前解锁👇

使用完 OpenClaw 之后我最大的疑问是:一个 Agent 同时活跃在 Telegram、Slack、企微甚至本地 CLI 里,它是怎么“记住我是谁”的?这些记忆又是如何做到统一的?难道我一晚上花掉几十刀的 token 全都是因为他的上下文工程做的太烂?

更关键的是——它到底“记住”的是什么?是对话?是总结?还是被结构化后的知识?

01

背景介绍

OpenClaw (Moltbot/clawdbot)近日大火,想必也无需过多介绍,我们姑且将它简单理解成一个"个人 AI 助手",功能和 Cloude Code 类似,同样可以处理文件和编码,调用不同 Skills 和 MCP 帮用户处理日常任务。

关于 OpenClaw 的整体系统架构,已经有很多文章进行了解读和分析,其核心思想是通过统一的 Gateway 进程管理所有外部通讯平台的链接,通过 Agent Runtime 进行各个大模型的后台调用,所有产生的数据、记忆全部存储在本地磁盘上,其系统架构如下所示:

总结来看,OpenClaw 主要有以下三个优势:

  • 使用便捷性:接入了聊天工具,让用户可以随时随地通过自己熟悉的聊天应用与 OpenClaw 交互,让他去完成任务;

  • 主观能动性:可以帮用户完成定时任务,仅仅使用自然语言对话就可以让其创建任务,甚至会基于大模型来自主判断任务的紧急程度和执行顺序;

  • 长期记忆:可以把用户的交互过程记录在本地,并不断更新,以便在以后的日常对话中进行搜索,将相关记忆捞回上下文中。

如何让类似的智能体真正拥有"记忆",是目前 AI 领域最棘手的问题之一。在行业侧,我们也看到了很多有关 AI 陪伴类、AI 分身类、AI 个人助手类的应用出现,其核心难点也是在解决如何让大模型"记住"与用户有关的尽可能多的信息。当前 AI 类应用面临的核心困境在于:大多数系统只是简单的把"上下文窗口"当作作为的"记忆"。根据 Anthropic 最新的开发者调研,有 68% 的 AI 应用团队都在为"上下文丢失"的问题苦恼。但是,上下文的特点是临时的、有限的(Claude 200K tokens、GPT-4 128K tokens)、昂贵的——当对话超过限制,模型要么会遗忘早期信息,要么因为成本暴涨而不得不重置会话窗口。

而 OpenClaw 的记忆管理系统与上述不同,他将记忆从上下文中剥离出来,构建了一个分层的、可搜索的、持久化的知识管理架构。使得 Agent 能够 7*24h 不间断地积累知识、记住用户偏好、延续历史上下文等,真正实现了从“无状态工具”到“有记忆伙伴”的进化。接下来,主要会针对 OpenClaw 的记忆系统进行分析,从架构设计和工程实现层面展示这个由 AI 自己创造的“大脑”。

02

OpenClaw 关于“记忆”的定义

正如上文提到的,很多开发者会错误地把页面上的”上下文窗口“当作记忆的全部,但这并不准确。我们常说的上下文(Context)是指模型在单次请求中能看到的所有信息,比如系统提示词、历史对话、工具调用结果等。它的本质特征是:临时存在的(仅在当前请求有效)、容量受限的(Claude 200K tokens、GPT-4 128K tokens)、成本高昂的(每次请求都要重新传输和计算)。如果仅以此作为记忆的全部,试图将所有记录的信息都塞进上下文,这显然是不科学的,会很快遇到性能、成本瓶颈。

OpenClaw 所代表的应用,其对“记忆(Memory)”的定义是:持久存储在磁盘上的结构化信息。因此,只要有足够的存储空间,记忆就可以无限增长,能够跨会话保留,在使用时按需检索,且存储成本几乎为零。更为关键的是,这种记忆能够支持语音搜索,也就意味着不需要把所有历史信息都塞进上下文,只需要检索当前任务相关的片段。所以,可以将上下文理解成 AI 的“工作台”,决定当下能处理什么,而记忆则是 AI 的“知识库”,决定长期能积累什么。

这种对于记忆的架构创新,使得 OpenClaw 可以在多轮交互上始终保持上下文的轻量和聚焦,把长期的记忆信息放到可搜索的记忆层。在其 Github Issue #847 中有一份实验数据,有人测试了一个持续 72h 的自动化任务,传统的上下文方案因为 token 限制触发了 23 次会话重置,而基于记忆的方案仅仅触发了 3 次,而且每一次重置之后都能通过搜索恢复关键上下文信息。

讲到这就不能饶过一个重要的问题,既然 OpenClaw 已经在上下文和记忆存储上做了如此大的改造,为什么我们在实际使用时消耗依旧飞起?这难道不是说明他的上下文工程做的很烂吗?这是一个非常好的问题,我们一开始的理解没错:记忆层确实是为了"轻量化上下文"设计的,但实际上,记忆层只解决了一部分问题,还有很多其他因素在消耗 token,比如系统提示词、调用的工具信息、会话历史等,这一部分,在附录二中进行了详细说明。

03

记忆系统的存储架构

OpenClaw 的记忆系统采用了一个双源记忆架构的设计,其将记忆整体分为了两类:每日日志(动态记忆)和长期记忆(静态记忆)。

记忆类型

存储格式

存储路径

产生方式

静态记忆

Markdown 文件

~/.openclaw/workspace/MEMORY.md 和 memory/*.md

手动创建 + 自动生成

动态记忆

JSONL 文件

~/.openclaw/agents/{agentId}/sessions/*.jsonl

自动记录

从直觉上看,这是符合人类大脑的记忆机制的,人的记忆也是由一个个重点片段组成的,我们能记住的也只是某个特定的时刻、某件具体的事件,把这些片段串联起来才形成了人类所谓的记忆,至于每天发生的琐事,终究会随着时间而被淡忘。因此,此种记忆机制也可以说是实现了工程学和生物学上的高度统一。

   3.1 动态记忆的产生

每次用户与 Agent 交互时,系统会自动将对话内容追加到 JSONL 格式的会话日志文件中,这是最原始的、未经处理过的记忆,存储位置如下:

动态记忆的 JOSNL 格式示例如下:

{"type":"message","message":{"role":"user","content":"帮我写一个 Python 爬虫"}}{"type":"message","message":{"role":"assistant","content":"好的,我来帮你写..."}}{"type":"tool_call","tool":"bash","input":{"command":"python crawler.py"}}

代码实现方式如下:

export async function buildSessionEntry(absPath: string): Promise<SessionFileEntry | null> {  // 读取 JSONL 文件  const raw = await fs.readFile(absPath, "utf-8");  const lines = raw.split("\n");  const collected: string[] = [];
  for (const line of lines) {    const record = JSON.parse(line);    // 只提取 user 和 assistant 的消息    if (message.role === "user" || message.role === "assistant") {      const label = message.role === "user" ? "User" : "Assistant";      collected.push(`${label}: ${text}`);    }  }
  return {    path: sessionPathForFile(absPath),    hash: hashText(content),    content,  // "User: 帮我写... \n Assistant: 好的..."  };}

   3.2 静态记忆的产生

静态记忆是整个系统的长期记忆,可以理解成是在短期的琐碎记忆中提炼出来的需要系统重点记住的内容,比如用户的性格、身份信息、回答偏好等,其文件存储结构如下:

静态记忆的产生途径分为以下三种:

  • 途径一:用户手动创建。用户可以直接编辑 MEMORY.md 文件,写入需要 Agent 长期记住的信息,比如:“你要称呼我为老板”、“我喜欢简洁的回复”等。;

  • 途径二:session-memory Hook 自动转换。当用户执行 /new 命令重置会话时,系统会触发 session-memory Hook,自动将上一个会话的关键内容转换为 Markdown 文件。大致的流程为:

    • 读取会话日志:从 JSONL 文件中提取最近 N 条(默认 15 条)user/assistant 消息;

    • 生成语义化文件名:使用 LLM 根据对话内容生成描述性 slug(如 api-design、bug-fix);

    • 写入 Markdown 文件:生成 memory/YYYY-MM-DD-{slug}.md 文件。

  • 途径三:Memory Flush 自动写入(类似于记忆刷新)。这是一个非常关键的自动化机制,当会话上下文接近 token 限制时,系统会在压缩(compaction)前触发一个特殊的 Agent 回合,在该回合中,Agent 被明确指示:将需要持久保存的重要信息写入 memory/YYYY-MM-DD.md 文件。

特性

MEMORY.md

memory/*.md

用途

核心长期记忆

按时间组织的会话记忆

内容类型

用户偏好、重要信息、工作流程等

具体会话的摘要和细节

更新方式

用户手动维护为主

系统自动生成为主

命名规则

固定为 MEMORY.md

YYYY-MM-DD(-{slug}).md

检索优先级

平等,由向量相似度决定

整个静态记忆系统的设计核心在于途径三,往往“健忘”的问题就出在这一步,即如何进行历史对话信息的压缩。其实此处OpenClaw 的处理方法比较粗暴,是使用 LLM 直接对历史对话信息进行处理。

首先,通过 Memory Flush 进行一次记忆筛选,让 Agent 自己判断什么是"durable memories"(持久记忆),代码如下:

export const DEFAULT_MEMORY_FLUSH_PROMPT = [  "Pre-compaction memory flush.",  "Store durable memories now (use memory/YYYY-MM-DD.md; create memory/ if needed).",  `If nothing to store, reply with ${SILENT_REPLY_TOKEN}.`,].join(" ");

然后,最终压缩就是再使用 LLM 对历史消息进行有损摘要,这里的默认指令只要求保留 “decisions, TODOs, open questions, constraints”,不保留具体数值、时间点等细节,代码如下:

const MERGE_SUMMARIES_INSTRUCTIONS =  "Merge these partial summaries into a single cohesive summary. Preserve decisions," +  " TODOs, open questions, and any constraints.";

这正是 OpenClaw 在记忆上的平衡,通过把历史会话记录(JSONL 格式)压缩成记忆(Markdown 格式),来避免上下文溢出的问题,赋予系统记忆的能力,但与此同时带来的问题也显而易见,在进行压缩时难免会有信息的流失,这在大多数场景下是合理的,但对于"具体几点"这类精确信息确实是弱点。但并这不是 bug,而是在"长期记忆完整性"和"系统效率/成本"之间的设计取舍。用户如果有重要的精确信息,可以主动要求 Agent 记录到长期记忆中。

好了,现在解释了第一个问题,OpenClaw 到底记住的是什么信息,下面我们来看这些所谓的“记忆”是怎么在需要的时候被“记起来”的。

04

记忆信息的检索与调用

当产生并保存一个记忆文件(.md)时,后台会自动触发如下的索引构建流程,并在需要时进行检索:

   4.1 索引构建

默认情况下,只有 Markdown 文件会被索引,而 JSONL 会话日志不会被索引。Markdown 文件首先被分块(默认每个块包含 400 tokens,相邻块重叠 80 tokens),而后每个块同时生成向量 Embedding(支持三种,OpenAI、Gemini、本地) 和文本 Token,分别存入 sqlite-vec 和 FTS5 索引,这两个都是 SQLite 扩展,意味着整个系统只依赖一个轻量级数据库文件,不需要部署 ES 或者 Milvus。SQLite 数据库的核心 Schema 如下所示:

-- 文件元数据CREATE TABLE files (  path TEXT PRIMARY KEY,      -- 'memory/projects.md'  source TEXT NOT NULL,       -- 'memory' | 'sessions'  hash TEXT NOT NULL,         -- SHA256 用于增量更新  mtime INTEGER NOT NULL,  size INTEGER NOT NULL); -- 文本块(带 embedding)CREATE TABLE chunks (  id TEXT PRIMARY KEY,        -- UUID  path TEXT NOT NULL,         -- 来源文件  source TEXT NOT NULL,       -- 'memory' | 'sessions'  start_line INTEGER,  end_line INTEGER,  hash TEXT NOT NULL,  model TEXT NOT NULL,        -- 'text-embedding-3-small'  text TEXT NOT NULL,         -- 原文  embedding TEXT NOT NULL,    -- JSON 数组 [0.1, 0.2, ...]  updated_at INTEGER); -- 向量索引(sqlite-vec 扩展)CREATE VIRTUAL TABLE chunks_vec USING vec0(...); -- 全文索引(FTS5)CREATE VIRTUAL TABLE chunks_fts USING fts5(  path, source, model, text,  tokenize='porter unicode61');

对于具体的记忆索引实现流程,在附录一中进行了详细阐述。

   4.2 记忆搜索

OpenClaw 采用关键词 + 向量的混合加权搜索,结合了两者的优势。当 Agent 需要搜索记忆时,系统会启动两个搜索引擎:

  • 向量搜索:基于语义相似度。把之前向量化之后的内容通过计算余弦相似度找到意思相近的内容,这个直接依赖 sqlite-vec 的扩展实现,无需外部向量数据库;

  • BM25 关键词搜索:基于词频统计。使用 SQLite 内置的 FTS5 全文检索引擎,找到包含精确关键词的内容。

混合检索的代码实现方式如下:

async search(query: string, opts?: { maxResults?: number; minScore?: number }) {  // 1. 关键词搜索 (BM25)  const keywordResults = hybrid.enabled    ? await this.searchKeyword(cleaned, candidates)    : [];   // 2. 向量搜索  const queryVec = await this.embedQueryWithTimeout(cleaned);  const vectorResults = await this.searchVector(queryVec, candidates);   // 3. 混合排序  if (!hybrid.enabled) {    return vectorResults.filter(r => r.score >= minScore).slice(0, maxResults);  }   const merged = this.mergeHybridResults({    vector: vectorResults,    keyword: keywordResults,    vectorWeight: 0.7,  // 向量权重    textWeight: 0.3,    // 关键词权重  });   return merged.filter(r => r.score >= minScore).slice(0, maxResults);}

   4.3 加权融合

两个引擎的搜索结果按照 70:30 的权重合并,最终得分 = 0.7 向量相似度 + 0.3 BM25 得分,且只有得分超过 0.35 的结果才会被返回。混合排序实现方式如下所示:

const merged = Array.from(byId.values()).map((entry) => {  // 最终得分 = 向量权重 × 向量相似度 + 关键词权重 × BM25 得分  const score = vectorWeight * entry.vectorScore + textWeight * entry.textScore;  return { path, startLine, endLine, score, snippet, source };}); return merged.toSorted((a, b) => b.score - a.score);

系统默认的 70% 和 30% 的比例来自与内部测试的结果,在其模拟进行的 1000 次复杂查询测试中,纯向量搜索的召回率为 76%,纯 BM25 搜索的召回率为 68%,而 70/30 的混合策略召回率达到 89%。

   4.4 Agent 交互

基于上述介绍的记忆系统架构,在实际使用时,AI Agent 则是通过两个接口实现与整个记忆系统的交互。

两个核心工具

  • memory_search:语义搜索

此工具用来调用上述的记忆检索功能,工具的定义如下:

return {    label: "Memory Search",    name: "memory_search",    description:      "Mandatory recall step: semantically search MEMORY.md + memory/*.md (and optional session transcripts) before answering questions about prior work, decisions, dates, people, preferences, or todos; returns top snippets with path + lines.",    parameters: MemorySearchSchema,    execute: async (_toolCallId, params) => {      // 搜索查询文本(必填)      const query = readStringParam(params, "query", { required: true });      // 返回结果数量(默认 6)      const maxResults = readNumberParam(params, "maxResults");      // 最低相关度阈值(默认 0.35)      const minScore = readNumberParam(params, "minScore");      const { manager, error } = await getMemorySearchManager({        cfg,        agentId,      });      // ... 执行搜索      const results = await manager.search(query, {        maxResults,        minScore,        sessionKey: options.agentSessionKey,      });      return jsonResult({        results,        provider: status.provider,        model: status.model,        fallback: status.fallback,      });    },  };

返回格式如下:

{  "results": [    {      "path": "memory/2026-01-10.md",      "startLine": 15,      "endLine": 20,      "score": 0.85,      "snippet": "用户提到喜欢蓝色,特别是天空蓝...",      "source": "memory"    },    {      "path": "MEMORY.md",      "startLine": 5,      "endLine": 8,      "score": 0.72,      "snippet": "颜色偏好:蓝色系...",      "source": "memory"    }  ],  "provider": "openai",  "model": "text-embedding-3-small"}
  • memory_get:精确读取

此工具用来精准读取记忆文件,工具的定义如下:

return {    label: "Memory Get",    name: "memory_get",    description:      "Safe snippet read from MEMORY.md, memory/*.md, or configured memorySearch.extraPaths with optional from/lines; use after memory_search to pull only the needed lines and keep context small.",    parameters: MemoryGetSchema,    execute: async (_toolCallId, params) => {      // 文件相对路径(如 memory/2026-01-10.md)      const relPath = readStringParam(params, "path", { required: true });      // 起始行号      const from = readNumberParam(params, "from", { integer: true });      // 读取行数      const lines = readNumberParam(params, "lines", { integer: true });      // ... 读取文件      const result = await manager.readFile({        relPath,        from: from ?? undefined,        lines: lines ?? undefined,      });      return jsonResult(result);    },  };

返回的格式如下:

{  "text": "用户提到喜欢蓝色,特别是天空蓝。\n在选择UI时偏好冷色调。\n...",  "path": "memory/2026-01-10.md"}

Agent 记忆交互的指令约束

Agent 被明确指示必须在特定场景下使用记忆工具:

return [    "## Memory Recall",    "Before answering anything about prior work, decisions, dates, people, preferences, or todos: run memory_search on MEMORY.md + memory/*.md; then use memory_get to pull only the needed lines. If low confidence after search, say you checked.",    "",  ];

Agent 主动写入记忆

在 OpenClaw 的交互中,Agent 也可以主动写入记忆文件,使用标准的文件操作工具。比如,当 Agent 判断需要记住某些信息时,会使用 exec 或 write 工具写入对应的 memory/YYYY-MM-DD.md 文件,例如:

exec(command="echo '## 用户偏好\n- 喜欢蓝色' >> memory/...")write(path="memory/2026-02-05.md", content="用户喜欢蓝色")

而后 MemoryIndexManager 检测到文件变更 (fs.watch),会触发增量同步和更新 SQLite 索引,这在上文提到的 Memory Flush 场景中特别重要。

交互的安全边界

为了保证整个系统的安全边界,对 memory_get 制定了严格的路径限制,规定其只能读取到特定位置的文件:

async readFile(params: {    relPath: string;    from?: number;    lines?: number;  }): Promise<{ text: string; path: string }> {    // ... 路径验证    const inWorkspace =      relPath.length > 0 && !relPath.startsWith("..") && !path.isAbsolute(relPath);    const allowedWorkspace = inWorkspace && isMemoryPath(relPath);    // 只允许读取:    // 1. MEMORY.md / memory.md    // 2. memory/*.md    // 3. 配置的 extraPaths 中的 .md 文件    if (!allowedWorkspace && !allowedAdditional) {      throw new Error("path required");  // 安全限制    }    if (!absPath.endsWith(".md")) {      throw new Error("path required");  // 只允许 .md 文件    }    // ...  }

05

一个典型的记忆系统交互流程

场景:用户询问 "我之前说过喜欢什么颜色?"

不难看出,类似 OpenClaw 类型的个人助手,使用体验大大依赖于所选用的基础大模型的性能,如果选择某些开源的轻量化模型,很容易陷入复杂工具调用的死循环,而选择更优性能的闭源模型又会带来不可避免的成本开销,那么问题来了:C 端用户到底需不需要更高性能的模型?

06

附录一:记忆索引的实现流程

此部分,将结合具体的例子,详细整理记忆索引的完整流程。

首先我们假设一个场景,用户在 1 月 10 日与 Agent 进行了一次对话,讨论了需要 Agent 设置提醒的事项,在用户执行 /new 命令后,session-memory 会自动将该对话进行提取并转化为 Markdown 文件如下:

文件路径:

~/.openclaw/memory/2026-01-10-reminders.md

文件内容:

# Session: 2026-01-10 08:00:15 UTC ## Summary用户请求设置每日提醒,讨论了健身计划安排。 ## Key Points- 用户想要每天下午3点收到健身提醒- 健身计划包括:周一胸肌、周三背部、周五腿部- 用户偏好使用 Telegram 接收提醒通知 ## Conversation HighlightsUser: 帮我设置一个每日提醒,下午3点提醒我去健身Assistant: 好的,我已经为你设置了每日下午3点的健身提醒。 User: 对了,我的健身计划是周一练胸,周三练背,周五练腿Assistant: 明白了,我已记录你的健身计划安排。 ## Action Items- [x] 设置每日 15:00 健身提醒- [ ] 后续可添加具体训练动作细节

   6.1 Step 1: 文件发现与变更检测

当存入了新的记忆文件,会调用 sync() 方法,系统首先会扫描记忆目录,检测哪些文件需要索引,如果发现记忆文件没有变化,那么也就不需要重新构建一次索引。

  • 列出所有记忆文件:

找到所有和记忆有关的文件,为下一步的判重做准备:

const files = await listMemoryFiles(this.workspaceDir, this.settings.extraPaths);// 结果: ["~/.openclaw/MEMORY.md", "~/.openclaw/memory/2026-01-10-reminders.md", ...]
  • 构建文件元信息:

对每个文件调用 buildfileEntry(),只读取文件并计算整体 hash,不做分块等处理。

// buildFileEntry 实现const stat = await fs.stat(absPath);const content = await fs.readFile(absPath, "utf-8");  // 读取整个文件const hash = hashText(content);                        // 计算整个文件的 hashreturn {  path: "memory/2026-01-10-reminders.md",  absPath: "/Users/xxx/.openclaw/memory/2026-01-10-reminders.md",  mtimeMs: 1736496015000,  size: 847,  hash: "e4d909c290d0fb1ca068ffaddf22cbd0"  // 整个文件内容的 MD5};
  • 判断是否需要重新索引:

结合上述文件的 hash 就可以判断出新产生的记忆文件是否与原有的文件相同,如果相同就说明记忆没有变化,省去了重新索引这一步。

const record = this.db  .prepare(`SELECT hash FROM files WHERE path = ? AND source = ?`)  .get(entry.path, "memory"); // 情况A: 数据库中无记录,或 hash 不匹配 → 需要索引// 情况B: hash 匹配 → 跳过,无需重新索引if (!params.needsFullReindex && record?.hash === entry.hash) {  return;  // 跳过}await this.indexFile(entry, { source: "memory" });  // 需要索引

这个情境中我们假设记忆是新的,那么此时会输出结果:

[需要索引] memory/2026-01-10-reminders.md (hash: e4d909c290d0fb1ca068ffaddf22cbd0)

   6.2 Step 2: 文本分块

经过上一步,只有确定需要索引的文件,才会使用 indexFile() 方法进行分块处理。调用的分块函数如下:

const content = await fs.readFile(entry.absPath, "utf-8");const chunks = chunkMarkdown(content, this.settings.chunking);// 默认配置: { tokens: 400, overlap: 80 } export function chunkMarkdown(  content: string,  chunking: { tokens: number; overlap: number },): MemoryChunk[] {  const lines = content.split("\n");  const maxChars = Math.max(32, chunking.tokens * 4);  // 1600 chars  const overlapChars = Math.max(0, chunking.overlap * 4);  // 320 chars  const chunks: MemoryChunk[] = [];   let current: Array<{ line: string; lineNo: number }> = [];  let currentChars = 0;   const flush = () => {    // 将当前累积的行打包成一个 chunk    const text = current.map((entry) => entry.line).join("\n");    const startLine = firstEntry.lineNo;    const endLine = lastEntry.lineNo;    chunks.push({      startLine,      endLine,      text,      hash: hashText(text),  // SHA-256(chunk文本)    });  };   const carryOverlap = () => {    // 保留最后 overlapChars 个字符到下一个 chunk(滑动窗口)    // ...  };   for (let i = 0; i < lines.length; i += 1) {    // 逐行累积,超过 maxChars 就 flush    if (currentChars + lineSize > maxChars && current.length > 0) {      flush();      carryOverlap();  // 保留重叠部分    }    current.push({ line: segment, lineNo });    currentChars += lineSize;  }  flush();  // 最后一批  return chunks;}

上述步骤中的分块算法按照以下规则切分文本:

  1. 按行遍历,累积字符数(默认约为 tokens * 4 个字符);

  2. 遇到 Markdown 标题(#)时优先断开,保持语义完整;

  3. 块之间有重叠(默认约 overlap * 4 个字符),确保跨块检索的连续性。

按照实例文件,分块之后可能会被切分为 2 个块:

Chunk #

startLine

endLine

text(摘要)

hash

Chunk 0

1

12

# Session: 2026-01-10...<br>## Summary<br>## Key Points<br>- 用户想要每天下午3点...

7a8b9c...

Chunk 1

10

22

- 用户偏好使用 Telegram...<br>## Conversation Highlights<br>## Action Items

3d4e5f...

   6.3 Step 3: 向量化(Embedding)

上述每个 Chunk 的文本需要转化为向量,用于进行语义搜索。首先系统会先查询已有的 embedding_cache 表,看是否已经有相同文本的向量缓存:

const cached = this.loadEmbeddingCache(chunks.map(chunk => chunk.hash));// 如果 chunk.hash 在缓存中命中,直接复用向量,跳过 API 调用

对于缓存未命中的 Chunk,调用配置好的 embedding provider(如 OpenAI),返回向量化后的结果。

// 批量请求 embeddingconst batchEmbeddings = await this.provider.embedBatch([  "# Session: 2026-01-10 08:00:15 UTC\n\n## Summary\n用户请求设置每日提醒...",  "- 用户偏好使用 Telegram...\n\n## Conversation Highlights..."]); // 返回结果(1536维向量,text-embedding-3-small)// Chunk 0: [0.0234, -0.0567, 0.0891, ..., -0.0123]  (1536个浮点数)// Chunk 1: [0.0345, -0.0678, 0.0902, ..., -0.0234]  (1536个浮点数)

而后更新向量缓存:

this.upsertEmbeddingCache([  { hash: "7a8b9c...", embedding: [0.0234, -0.0567, ...] },  { hash: "3d4e5f...", embedding: [0.0345, -0.0678, ...] }]);

   6.4 Step 4: 持久化存储

向量化完成后,系统会将上述数据写入 SQLite 数据库中的三张表。

  • 生成 Chunk ID:

首先,需要先为每个 chunk 生成唯一的标识,其是由多个因素组合 hash 生成。

const id = hashText(  `${source}:${path}:${startLine}:${endLine}:${chunkHash}:${model}`); // Chunk 0 的 id 计算:// hashText("memory:memory/2026-01-10-reminders.md:1:12:7a8b9c...:text-embedding-3-small")// → "a1b2c3d4e5f6..." // Chunk 1 的 id 计算:// hashText("memory:memory/2026-01-10-reminders.md:10:22:3d4e5f...:text-embedding-3-small")// → "g7h8i9j0k1l2..."
  • 写入 chunks 主表:

主表中会存储每一个 chunk 所包含的/相关的完整元数据和向量(JSONL 字符串格式),比如在该例子中,存入主表的一条信息如下:

this.db.prepare(`  INSERT INTO chunks (id, path, source, start_line, end_line, hash, model, text, embedding, updated_at)  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(  "a1b2c3d4e5f6...",                    // id  "memory/2026-01-10-reminders.md",     // path  "memory",                              // source  1,                                     // start_line  12,                                    // end_line  "7a8b9c...",                          // chunk hash  "text-embedding-3-small",             // model  "# Session: 2026-01-10...",           // 原始文本  "[0.0234, -0.0567, ...]",             // 向量 (JSON 字符串)  1736496100000                          // updated_at);
  • 写入 chunks_vec 向量表:

此处的 sqlite_vec 为虚拟表,专门用于向量相似度(语义相似度)的搜索,表中存储的内容示例如下:

this.db.prepare(`INSERT INTO chunks_vec (id, embedding) VALUES (?, ?)`)  .run(    "a1b2c3d4e5f6...",           // 与 chunks 表相同的 id    vectorToBlob([0.0234, ...])  // 转换为二进制 BLOB 格式  );
  • 写入 chunks_fts 全文搜索表:

此处的 FTS5 也是虚拟表,而且 SQLite FTS5 会自动对 text 字段进行分词,不需要手动进行分词处理。

this.db.prepare(`  INSERT INTO chunks_fts (text, id, path, source, model, start_line, end_line)  VALUES (?, ?, ?, ?, ?, ?, ?)`).run(  "# Session: 2026-01-10...",           // text (FTS5 自动分词)  "a1b2c3d4e5f6...",                    // id (UNINDEXED,不分词)  "memory/2026-01-10-reminders.md",     // path (UNINDEXED)  "memory",                              // source (UNINDEXED)  "text-embedding-3-small",             // model (UNINDEXED)  1,                                     // start_line (UNINDEXED)  12                                     // end_line (UNINDEXED));

上述有些字段标记为 UNINDEXED,意味着不会参与全文搜索索引,只是作为元数据进行存储,方便后续 JOIN 查询和过滤,只有 text 字段会被 FTS5 分词和建立倒排索引。

  • 更新 files 表:

上述存储完成后,会再次记录文件级别的元信息,用于下次进行变更检测。

this.db.prepare(`  INSERT INTO files (path, source, hash, mtime, size) VALUES (?, ?, ?, ?, ?)  ON CONFLICT(path) DO UPDATE SET hash=excluded.hash, mtime=excluded.mtime, size=excluded.size`).run(  "memory/2026-01-10-reminders.md",  "memory",  "e4d909c290d0fb1ca068ffaddf22cbd0",  // 整个文件的 hash  1736496015000,  847);

   6.5 Step 5: 最终数据库状态

1、  files 表:

path

source

hash

mtime

size

memory/2026-01-10-reminders.md

memory

e4d909c290d0fb1ca068ffaddf22cbd0

1736496015000

847

2、 chunks 表(主表):

id

path

source

start_line

end_line

hash

model

text

embedding

a1b2c3d4e5f6

memory/2026-01-10-reminders.md

memory

1

12

7a8b9c...

text-embedding-3-small

# Session: 2026-01-10 08:00:15 UTC<br>## Summary<br>用户请求设置每日提醒...

[0.0234,-0.0567,...]

g7h8i9j0k1l2

memory/2026-01-10-reminders.md

memory

10

22

3d4e5f...

text-embedding-3-small

- 用户偏好使用 Telegram...<br>## Conversation Highlights<br>## Action Items

[0.0345,-0.0678,...]

3、 chunks_vec 表(sqlite-vec 向量表):

id

embedding (BLOB)

a1b2c3d4e5f6...

<binary: 1536 × float32 = 6144 bytes>

g7h8i9j0k1l2...

<binary: 1536 × float32 = 6144 bytes>

4、 chunks_fts 表(FTS5 全文索引表):

text

id

path

source

model

start_line

end_line

# Session: 2026-01-10...

a1b2c3d4e5f6

memory/2026-01-10-reminders.md

memory

text-embedding-3-small

1

12

- 用户偏好使用 Telegram...

g7h8i9j0k1l2

memory/2026-01-10-reminders.md

memory

text-embedding-3-small

10

22

注:在FTS5 内部会自动为 text 列建立倒排索引,如:

> - "健身" → [a1b2c3d4e5f6..., g7h8i9j0k1l2...]> - "提醒" → [a1b2c3d4e5f6...]> - "Telegram" → [g7h8i9j0k1l2...]

07

附录二:token 消耗的计算

首先列出在 OpenClaw 中 token 消耗的完整构成:

接下来我们逐项进行分析:

1、  System Prompt(系统提示词)

这是系统的固定开销,在每次请求前会从多处构建系统提示词,OpenClaw 规定构建系统提示词时,参考的每个文件最大 20000 字符,估算下来大概每次请求会有 5,000-25,000 字符是系统提示词。下表展示了 System Prompt 包含的内容:

组成部分

大小估算

说明

核心指令

~3,000 字符

安全规则、回复格式、消息路由等

工具说明列表

~2,000 字符

每个工具的简要说明

Skills 提示

可变

技能描述和位置

Bootstrap 文件

最大 20,000 字符

AGENTS.md, SOUL.md, IDENTITY.md 等

Runtime 信息

~500 字符

主机、时区、模型等

Sandbox 信息

~300 字符

沙箱配置

2、  工具定义(Tool Schemas)

OpenClaw 所调用的每个工具都有自己的 JSON Schema 定义,这些定义会随着每次请求被发送,估算下来每次请求中工具定义大约占 3000-5000 tokens 且无法压缩。OpenClaw 默认启用的部分工具如下所示:

工具

Schema 复杂度

估算 tokens

browser

非常复杂(16 种 action)

~800

exec

中等

~200

read/write/edit

简单

~300

message

复杂(多种 action)

~400

cron

中等

~200

memory_search/get

简单

~150

sessions_*

中等

~400

canvas

中等

~200

nodes

复杂

~300

...

...

...

3、  会话历史

即使有 Compaction 机制,但在触发压缩之前,会话历史依然在累积:

请求 1:System Prompt + 用户消息 1 + 回复 1请求 2:System Prompt + 用户消息 1 + 回复 1 + 用户消息 2 + 回复 2请求 3:System Prompt + 历史累积... + 用户消息 3...请求 N:触发 Compaction → 摘要替换历史

关键问题是,为了尽可能优化用户体验,这个压缩的阈值通常设定的非常高,比如默认是 20000 字符,这意味着系统会让历史累积到接近上下文窗口限制才压缩,在此之前 token 消耗持续增长。

4、  Memory Flush

在会话压缩前,调用的 Memory Flush 更是一个独立的 LLM 调用,这就使得每次压缩前会额外消耗一次完整的 LLM 调用成本:

export async function runMemoryFlushIfNeeded(params: {  cfg: OpenClawConfig;  followupRun: FollowupRun;  // ...}): Promise<SessionEntry | undefined> {  // 触发一个完整的 Agent 回合  // 包含 System Prompt + 工具 + 指令  await runEmbeddedPiAgent({    // ...    prompt: memoryFlushSettings.prompt,    // ...  });}

5、  记忆检索结果

当 Agent 使用 memory_search 与记忆系统交互时,返回的结果也会加入上下文:

用户: "我之前说过喜欢什么颜色?"         ↓Agent 调用: memory_search(query="喜欢的颜色")         ↓返回结果:   - memory/2026-01-10.md:15-20 (score: 0.85)    "用户提到喜欢蓝色,特别是天空蓝..."  - MEMORY.md:5-8 (score: 0.72)    "颜色偏好:蓝色系..."         ↓这些结果被加入上下文 → 消耗 token

6、  工具调用链

一个简单的任务也可能触发多次工具调用,每次调用都是:请求 + 响应,token 双向计费。

用户: "帮我查一下天气并发到 Telegram" 调用链:1. web_search("天气") → 返回结果 (+500 tokens)2. memory_search("用户位置") → 返回结果 (+200 tokens)  3. message(channel="telegram", ...) → 返回确认 (+100 tokens)

因此可以看出,记忆层确实实现了"轻量化上下文"的设计目标,但还有很多问题无法解决,比如:固定开销无法消除(System Prompt)、工具定义每次都要发送、压缩是惰性的、记忆检索是增量成本、工具调用有额外成本。记忆层的真正价值不是"降低单次成本",而是:使无限长的对话成为可能(没有记忆层,上下文会爆炸),同时保持相关信息的可访问性(压缩后仍可通过搜索找回),如果想显著降低成本,需要从减少固定开销(精简 System Prompt、禁用工具)和使用更便宜的模型入手。

(注:文中部分架构图借助 Nano Banana 2 生成,某些细节可能存在误差。)

-End-

原创作者|刘学楷

感谢你读到这里,不如关注一下?👇

图片

📢📢来抢开发者限席名额!点击下方图片直达👇

你对本文内容有哪些看法?同意、反对、困惑的地方是?欢迎留言,我们将邀请作者针对性回复你的评论,欢迎评论留言补充。我们将选取1则优质的评论,送出腾讯云定制文件袋套装1个(见下图)。3月26日中午12点开奖。

扫码领取腾讯云开发者专属服务器代金券!

图片

相关推荐

大模型的Agent Skill功能,在LLM HTTP底层交互流中是怎么承载的?

网络文章文本的 skill,昨天我实现了之后也就开始好奇起 Skills 的底层原理了——相比起各种花里胡哨的 agrnt 应用,我一直以来都很对大模型在纯粹的 HTTP 交互层面是如何交互的更感兴趣。Skill 的全部"魔法"都发生在 system prompt 的措辞和 SKILL.md 文件的编写质量上——本质上是一种 prompt engineering + 文件系统的组合。但是各种天花乱坠的 skills,是如何在底层的 HTTP 中,与大模型——这个只会嘴遁的工具交互的呢?

QcloudCommunity的博客 400

万字入门AI Infra:深入理解大模型中的数学与Infra优化

关注腾讯云开发者,一手技术干货提前解锁👇AI Infra科普、入门或者进阶 ~~ 不到 5 万字,带你融会贯通理解大模型的数学、算法、硬件到系统工程。任何问题欢迎沟通交流。可怕,我竟然有点认同这句话。当然大概率是因为姚顺宇太懂AI了,而我则是因为无知者无畏。不过仔细想想,大模型推理中的数学逻辑确实不复杂,很多原理只需要高中数学知识就能看懂。但是为什么像 vLLM 这种推理系统这么复杂呢?本文将拆解大模型中几个核心操作(RMSNorm、Softmax、Causal Mask、Sampling)背后的数学与

QcloudCommunity的博客 1156

平平无奇的源码,竟藏着Agent的核心秘密?

System Prompt 是剧本,Skill 是剧本的扩展包,Agent Loop 是演员按剧本行动。欢迎留言,我们将邀请作者针对性回复你的评论,我们将选取1则优质的评论,送出腾讯云定制文件袋套装。,让 Agent 能主动"巡逻",而不只是被动等待用户消息。OpenClaw 的 System Prompt 分层结构。的"行为底线",任何 Skill 或用户命令都无法覆盖它。精华 2:Skill 的"按需加载"避免 token 浪费。精华 1:System Prompt 是"分层乐高积木"

QcloudCommunity的博客 424

QQ音乐Harness Engineering实践

一个看似简单的需求,背后可能牵动服务调用链、配置、灰度、埋点、错误码、接口契约和历史兼容性。当 AI 开始快速生成大量代码,真正的瓶颈就不再是"写不出来",而是"看不完、想不清、管不住"。在对话式编码阶段,一种典型的工作模式逐渐流行:开发者把需求丢给 AI,扫一眼输出"看起来对"就直接采纳,不审 diff、不追问逻辑、不验证边界。以音乐商业化业务为例,一个需求可能从 TAPD 单开始,经过需求评审、技术方案、服务影响面分析、IDL 契约变更、业务代码实现、测试验证、CR、灰度上线,最后才进入稳定运行。

QcloudCommunity的博客 710

从Prompt、Context到Harness,工程的三次进化与终局之战

同时,强制要求散落各处的决策记录(Slack、邮件、文档)全部迁移至代码仓库,确保 Agent 的唯一信息来源是可信的、版本受控的仓库。更坑爹的是,研究表明,当上下文过长时,模型会出现"中间遗忘(Lost in the Middle)"现象:它对开头和结尾的内容记忆较好,对中间大段内容的关注度大幅下降。这篇文章,我想带你完整走一遍这三次进化的逻辑:它们分别解决了什么问题,它们之间是什么关系,它们的边界在哪里,以及:当三者融合,AI 工程师的终极形态究竟是什么?大语言模型的本质,就是这位金鱼助理。

QcloudCommunity的博客 712

让Skill自己训练自己:8阶段Loop、3层评测、5维AND门控,从此实现自进化

所以每一轮改动都是有据可查的,不是「感觉这里可以优化」,而是「Case 41 挂了,因为 agent 把离职问题路由到了邮箱分类,但正确答案在通讯录,所以我改 root_index.md 加个易混淆提示」。但让我最后决定把它记录下来的,不是这的个「吸收」过程,而是它真的在替我探索我不想费脑力触达的边界,这看起来更像是一个机器智能应该有的样子。不准跨层,每轮只改一层的东西。但我经过这 19 轮之后觉得,更准确的描述是互补——你在明处看着,AI 在暗处替你试错,你看不见的那一半就是 AI 能贡献的地方。

QcloudCommunity的博客 1118

只加两行代码,为什么要两天?一文深度理解业务系统的复杂性

关注腾讯云开发者,一手技术干货提前解锁👇业务系统复杂性一直是令开发者头痛的问题。复杂的不是增加一个需求需要耗费多少时间,而是在增加一个需求后带来的蝴蝶效应:其它功能会不会受到影响、要如何去找到这些影响,最终如何实现系统正常运行......功能之间隐秘增加的耦合、不可避免的代码腐化在导致业务复杂性增加。大家都在说的软件开发提效到底在提什么?程序员日常工作中应该如何提升开发效率?敏捷开发、瀑布流式开发孰是孰非?欢迎阅读。业务背景与目标我依然非常清晰地记得某个时候,我所在团队 Leader 曾讲过一段话:“我担

QcloudCommunity的博客 706

从零设计生产级 Multi-Agent Harness:架构、评估、记忆、成本与 MCP 工具接入全拆解

在 AI Agent 领域,Multi-Agent Harness 指的是把多个 Agent 的能力、工具、状态、通信、编排、监控统一收束在一个运行时之内的框架。第三,Agent 路由。一个输入框,一个大模型,几个工具,一段写得很漂亮的 System Prompt,再配上一个炫酷的前端,看起来就像一个能干活的“数字员工”。Multi-Agent 完全不一样——它有计划、有中间步骤、有工具调用、有 Agent 协作、有重试、有反思、有最终合成。增加 Budget、权限、重试、压缩、轨迹评估、审计、回归测试。

QcloudCommunity的博客 705

拆完Hermes源码,我发现Agent的“自我进化“根本不需要训练模型

两个月 5.2 万 Star,Hermes Agent 用一个"LLM 审判官"机制实现了 Agent 的自我进化——不改模型权重,只改"怎么用模型"的策略。OpenClaw(社区昵称"龙虾"🦞)是 2025-2026 年最火的开源 Agent 框架,30 万+ Star,插件市场 ClawHub 里有数千个插件,能接入 Telegram、WhatsApp、Slack、飞书、企业微信——几乎是一个"个人 AI 操作系统"。Skill 是英语写的,Memory 是英语写的,审查 Prompt 也是英语写的。

QcloudCommunity的博客 902

AI Infra 其实没有多少新东西

传统 Infra 追求横向扩展,而 AI Infra 呈现 “AI 大型机”特性,是因为传统后台服务的可以容忍毫秒级延迟,但 AI 集群不行,GPU 的算力是 CPU 的数百倍,微秒级的延时等待也会造成很大的算力损耗,需要硬件的高度集成。在可预见的1-3年的未来,这样的专用硬件+网络的集中式架构很难发生比较大的改变。与之相似,模型推理的批处理就是将多个输入样本打包(batch),将原本串行的 N 次轻量的推理计算,合并为 1 次重量的计算,实现单位时间内处理更多的请求,提高了 GPU 利用率。

QcloudCommunity的博客 818

程序员越早想通这些越好

永远没有正确架构,你永远无法偿还完所有的技术债务,如同你永远不会设计出完美的界面,请避开完美主义的陷阱,永远没有完美的代码,能够满足当前需求,又为未来不管是自己还是他人留有扩展空间,就很好了。我们努力的方向就是将现实世界映射到有限的数据结构中,这就需要用户自定义类型,如果你的代码中包含类似 trader portfolio 这样的概念,你就可以使用他们的名称来建模,而不是使用基本数据类型复杂嵌套表述你的目的。从另一个角度看,代码里的注释都是补丁,是碎片化的,局部的注释很难推导模块整体的顺序及耦合关系。

QcloudCommunity的博客 464

RAG已死?不,是Grep回归了!

这样一来可以直接复用已有的计算缓存,只为新增的增量部分付全价,前面累积的大头按约 1/10 的缓存价计费。所以实际的工具组合方式是灵活的:Grep(默认模式)→ Read 是最常见的路径,但 Grep(content 模式)可以独立使用,LLM 也可以直接调 Read(如果已经知道文件路径),或者一次同时发起多个 Grep 并行搜索。它从零开始构建自己的对话历史,不继承主对话的消息,这意味着它搜索过程中产生的大量 grep 结果、代码片段都留在自己的 context 里,主对话只收到一段总结性的文本结论。

QcloudCommunity的博客 570

深入浅出Harness Engineerring之核心模式与理念

在智能体生命周期的关键节点(如会话开始、工具调用后)自动触发预设动作(如代码格式化),由系统确保关键流程被执行,不依赖可能被模型遗忘的指令。简单讲就是利用向量存储这个技术,来实现模糊检索,原理是:即使字面不同,但语义相近的文本,其向量在数学空间中的位置也很接近。根据命令类型、参数和影响,自动评估其风险等级(安全、有风险、危险),并采取自动执行、请求确认或直接拦截等不同策略。关键特性是可隔离、可重建、可扩展。不是一次判断就定终身,允许你改变、允许情况复杂,通过不断观察、思考、调整,越来越懂真实的你。

QcloudCommunity的博客 621

Harness Engineering实践心得:如何高效驾驭AI?

但如果这些经验被拆成一条条 Rule、一个个 Skill、一项项 Script 检查——"XAML 不能有中文"、"编译要用这个路径的 MSBuild"、"SVN 命令必须带认证参数"——AI 就能在秒级时间里"吸收"十年的踩坑经验。然后可以看到下方的图,我的PM会很顺利的调度其他agent分别负责不同的事项,遇到问题的时候也能准确的找到合适的agent。MCP 本质上是在扩展 AI 的"感知范围"——Rule 管"该怎么做",Skill 管"怎么操作",MCP 管"能看到什么、能碰到什么"。

QcloudCommunity的博客 838

从第一性原理思考 Agentic Engineering

需要注意的是,这一结论是有条件的:如果 AI 缺乏领域知识,过早介入反而可能引入 1.2 节所述的"似是而非"损耗——因此上下文供给(实践 1)是 AI 全链条参与的前提,而非结果。通过一个专门的自迭代 Skill 实现——当 AI 在协作过程中识别到自己被纠正(用户否定了 AI 的输出并给出了正确方向),它自动评估这个错误的根因,搜索现有的 Rules 和 Skills 中是否已有针对该类问题的处理规则。事实上,越是复杂的项目,工程师的认知负担越重(公理 3),AI 分担认知负担的潜在边际价值也越大。

QcloudCommunity的博客 754

万字干货!Harness Engineering如何工程化落地?

关注腾讯云开发者,一手技术干货提前解锁👇Harness Engineering 的概念已经火了有一阵了,全网很多文章基本都是在讲理念,讲为什么今天做 AI 开发,不能只靠一段提示词,也不能把模型当一个“更聪明的代码补全”。但与此同时,一个问题也在持续地发酵:这个问题特别重要。因为 Harness 这个词听上去很大,很像一个抽象的方法论,但它如果不能落到工程、目录、文档、脚本、工作流里,那它最后就只是一句漂亮的话。事实上,不同项目落地出来的 Harness,表面上可能完全不一样。有的项目是 CI 很强,有的

QcloudCommunity的博客 1160

全方位对比:Hermes VS OpenClaw

多账号矩阵运营 如果你的业务涉及同时管理多个社交媒体账号、多个平台的内容分发、多渠道的客户互动——OpenClaw是目前市场上的"无可替代的底座"。一个有专业背景的个人,现在可以快速构建一个垂直领域的AI助手:比如"财务分析Hermes"、"法律咨询Hermes"、"技术架构Hermes",直接通过微信提供服务,积累自己的专业IP。跨平台生态融合 如果你的工作流涉及飞书、Slack、Discord等多个平台的深度集成,需要这些平台之间的数据流转和联动——OpenClaw的生态支持是强大的。

QcloudCommunity的博客 1216

一文讲透:Harness Engineering即控制论!

而研发模式的升级我认为将会是一个飞跃的过程,之所以现在我们仍然需要需要参与编码,一个非常大的原因就是缺乏传感器和基建,仍然需要人来串流程,比如需要人来验证UI是否正确、需要人来告诉AI代码不符合代码规范,因此在有些场景我们仍然感觉 AI 完成的很吃力,但这不是 AI 能力不行,而是我们并没有为 AI 提供友好的环境……控制论中的突变理论介绍了矫枉过正和飞跃现象之间的矛盾,如果质变中经历的中间过渡态是不稳定的,那么他就是一个飞跃的过程,如果中间过渡态是稳定的,那么他就是一个渐变的过程。但是这些阶段要解决的。

QcloudCommunity的博客 1201

神级开源插件!一句话让QClaw变3D小镇,Agent工作可视化,赛博云监工

这个架构是翻了几次车才想通的—原有AI的实现机制是用 setTimeout 猜动画时长导致了幽灵 NPC、工位撞车、越改越崩,后面我停下来换了思路,推翻原有的架构,按照“意图+回传”的架构进行重构,之前的问题一次性全部解决。15 天,我和 AI 吵了 185 次架, 4.5 万行代码,开发了一款 QClaw / OpenClaw 的UGC游戏插件,这可能是人类跟 Agents 交互的新范式,插件已完全开源,有需要的欢迎自取~我天天用,用着用着我就在思考,Agent 产品现在的交互体验,基本都一个样。

QcloudCommunity的博客 1193

一文搞懂Hermes:新顶流Agent如何从经验中自我进化

Voyager 是一个能在 Minecraft 中自主探索、学习技能、无限积累能力的 AI Agent,它提出了 "Skill Library"(技能库)的概念——Agent 将成功的行为序列编码为可复用的技能函数,存储在一个持续增长的代码库中。如果 Skill 的名称和描述不够精准,或者用户的任务描述与 Skill 的触发条件有语义差距,Agent 可能会错过相关的 Skill。如果进程在写入过程中崩溃,目标文件要么是旧内容(还没被替换),要么是新内容(替换已完成),绝不会出现写了一半的损坏文件。

QcloudCommunity的博客 2624

自掏腰包一万元,拥抱AI这一年,我的工具、实践和思考

其实也很好理解,过往的每个领域(比如前端、后端、设计、测试等等)都主要是这个领域的从业者在为它添砖加瓦,但是大模型时代的 AI 应用领域却几乎是所有使用 AI 的人类一起在迭代,无分领域,无分文理,无分老少。因为每个时期的 AI 都有着不同的特点,很多时候当我费尽心思去钻研,自以为有点弄明白 AI 应该怎么玩的时候,基座模型和行业范式常常就会迎来颠覆式的变革,很多过往的经验都会倾覆,然后只能从头再来。过去一年多,被热议的 AI 范式大概是沿着四个阶段递进演化,每一个阶段其实都在解决前一个阶段的核心问题。

QcloudCommunity的博客 626

办公Agent的CI/CD时刻到来了

核心观点是:企业给员工配了一堆 AI 工具,试点跑了几百个,但真正拖慢 AI 转型速度的瓶颈不在模型能力,在"最后一公里":AI 输出和实际工作流之间的那道鸿沟。代码写完,打个 tar 包,开 FTP 传到服务器上,SSH 进去解压,改配置文件,重启服务,刷一下页面祈祷别 500。你复制,切窗口,粘贴到腾讯文档里,发现 Markdown 格式全乱了,手动调标题层级,代码块重新标记语言类型,表格散架了重排一遍。模型是越来越聪明了,但"生成"到"落地"之间那段路,还是你自己在走,一步一步,手动搬运。

QcloudCommunity的博客 607

4亿token买来5个教训:让6个AI Agent连写4天代码发生了什么?

Watchdog 检测到崩溃 → 启动诊断 Agent 分析原因 → 诊断 Agent 跑满 20 轮没搞定 → Watchdog 判定“已修复”,重启系统 → 重启的系统因为诊断 Agent 留下的环境变量被继承,连续 3 次拒绝启动 → 触发连续失败保护退出 → Watchdog 第 3 次巡检,发现进程和记录文件都没了,尝试手动重启,自己也停了。启动前我翻了论文、做了架构设计、写了监控+修复异常的脚本。这个发现让我的情绪从沮丧变成了兴奋——不是那种"终于修好了"的释然,是"我找到根因了"的快感。

QcloudCommunity的博客 583

赛博斗蛐蛐:9大模型决战三国志,天命在谁?

我猜是这样的,当Gemini面临决策的时候,一系列关键词比如 守城,劣势,粮草,三国等等,在语义层面的关联性中LLM发现了竖壁清野这个关键词概率非常高,所以以此为策略,然后再根据这个策略完美执行操作。MiMo 的外交是三方中最精明的。Kimi作为国产模型,也同样颠覆了我对他的看法,最后的比赛他甚至一度是优势者,存在很多夺冠的可能性,要知道他的对手可是claude和gemini,而他经常出兵慢,回过头来想想或许正是他的策略,毕竟中后期他的优势都来自于稳健的发展和较少的战斗频率(和claude比).

QcloudCommunity的博客 870

Claude Code是怎么知道你在骂他的?这 12 条发现值得关注

确实存在——5,500+ 行,集成了消息队列、工具装配、MCP 编排、会话状态、权限、分析、文件持久化和优雅关闭,基本上一个文件干了所有事。对抗虚假声明——"不要在输出显示失败时声称所有测试通过,不要压缩或简化失败的检查来制造绿色结果"。完整的 KAIROS 是一个持续驻留的守护进程,能感知你在不在电脑前、主动寻找有用的工作做,更像是住在终端里的全职同事。源码里藏着一个叫 "Buddy" 的电子宠物系统,完整度令人惊讶——这不是一个 TODO,而是一个从数值系统到 ASCII 动画都实现了的完整功能。

QcloudCommunity的博客 700

逆向深扒Claude Code源码,我发现了什么!?

Anthropic 内部用户获得更严格的质量控制 prompt、更好的验证机制(独立 Verification Agent)、以及针对 model 弱点的专门对策(如 Capybara v8 的 29-30% 错误声明率对策)。这不是代码混乱的标志——它是整个 Agent Loop 的心脏,所有的流式处理、工具调度、上下文压缩、子代理管理都在这个文件中协调。这种"胖核心"设计是刻意的:保持核心循环的原子性,避免分散到多个模块导致的协调复杂度。核心价值:Fork 代理的工具输出不会回到主代理的上下文窗口。

QcloudCommunity的博客 885

一文讲透如何构建Harness——六大组件全解析

本文将从"裸模型的四个硬伤"出发,逐一拆解 Harness 的六大组件——文件系统、Bash + 沙箱、记忆(AGENTS.md)、Web Search + MCP、上下文工程、编排 + Hooks——带你看清 AI Agent 真正的竞争壁垒,不在模型层,而在 Harness 层。如果你用过 Agent 做复杂任务,你一定有过这样的体验:一开始 Agent 的表现很好,但随着对话变长,它开始"变笨"——遗忘之前的约定,重复之前犯过的错误,甚至对同一个问题给出前后矛盾的回答。对于简单的问答场景,这无所谓。

QcloudCommunity的博客 758

Harness Engineering 来了,SDD 还有意义吗?

他们的解法是把「品味」编码进规则,然后用一个定期运行的「doc-gardening」Agent 自动扫描漂移、发起修复 PR——「技术债务就像一笔高息贷款,不断地以小额贷款的方式偿还,总比让债务不断累积要好」。代码仓库本地的、已版本化的工件,才是 Agent 所能看到的全部。在 Vibe Coding 模式下(即不做规划、随意向 AI 提需求的开发方式),大量设计决策、跨服务约定、「为什么不选另一个方案」的讨论,全部停留在一次性的 AI 对话里——下一个人,或者下一次 AI 会话,完全无从获取。

QcloudCommunity的博客 417

零废话!一文讲透从0构建AI Agent

每个工具都要写一套"定义→解析→执行"的胶水代码。上下文管理就是在"记住足够多"和"别超标"之间找平衡,常见策略包括滑动窗口、摘要压缩、RAG 检索增强。上下文窗口是 Agent 的"工作记忆",但它有硬性限制。LLM 负责"动脑"决策,代码负责"动手"执行。这是从"聊天机器人"进化到"Agent"的关键一步。每次调 API 都把完整对话历史发过去,LLM 本身是无状态的,"记忆"完全靠客户端的数组模拟。这样 Agent 一开始就知道自己"在哪里"、"手头有什么",不需要先花一轮工具调用去探索环境。

QcloudCommunity的博客 709

距离AI把小编我裁掉还有72小时

这是一个基于 OpenClaw 开源生态打造的本地化 AI Agent 助手,已于上周开启全量公测,无需复杂配置,三步即可上手,自带安全防护,支持微信直连绑定,内置多款优质国产大模型,现阶段也是完全免费使用,基本上前面提到过的痛点都可以靠它解决。对了,这里特别强调一点,上面的截图让产品同事汗流浃背,再三找我确认 QClaw 思考过程中优美的“草”字说法,不会是默认出现的吧?AI 好,AI 得学,但更重要的是,在你的工作和生活里,哪些东西是能结构化地被 AI 所接入的,不要死守着那些脏活累活不放。

QcloudCommunity的博客 672
上一篇: 兄弟!你真的懂 Skill 吗?
下一篇: 龙虾盛宴下的冷思考
腾讯云开发者
腾讯云开发者 企业官方账号 企业官方账号
博客等级 码龄10年 6289粉丝 1962原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值