关于 Builderforce Memory
Builderforce Memory 通过 MCP 向 Agent 和应用提供持久化记忆工具。可插拔后端及进程内、stdio 和 HTTP 传输支持不同宿主按需检索记忆。
主要功能
- 01排序并限制返回数量的记忆检索
- 02按键精确查找和按标签查找
- 03可选的记忆写入与删除工具
- 04可插拔记忆后端
- 05进程内、stdio 和 HTTP 传输
- 06可选的经历与技能工具
适用场景
- 01回答前检索相关的持久事实
- 02在不同 Agent 宿主间共享记忆存储
- 03通过联网的 HTTP 端点运行记忆工具
- 04存储演示并跟踪技能执行
MCP 相关
该服务向 MCP 客户端提供记忆检索、查找及可选的写入工具。它支持进程内、stdio 和 Streamable HTTP 传输,也可启用经历工具。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
npx -y @seanhogg/builderforce-memory-mcpBUILDERFORCE_MEMORY_FILEAbsolute path to the JSON snapshot that makes memory survive restarts. Defaults to ~/.builderforce-memory/memory.json, which every MCP host on the machine shares.BUILDERFORCE_MEMORY_READONLYSet to 1 to expose recall only (disables memory_remember and memory_forget).BUILDERFORCE_API_KEY密钥Builderforce tenant API key (bfk_*). When set, additionally exposes the token_usage and model_efficiency cost tools.本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
@seanhogg/builderforce-memory-mcp
将 @seanhogg/builderforce-memory 提供给任何 MCP 客户端。一个节省 Token 的工具核心,基于可插拔的 MemoryBackend,支持三种传输方式:
| 传输方式 | 工厂函数 | 使用方式 | 适用场景 |
|---|---|---|---|
| 进程内(Claude Agent SDK) | createMemoryMcpServer(backend) | 返回的 type:"sdk" 对象 | 使用 TypeScript 且在进程内运行 @anthropic-ai/claude-agent-sdk 的产品——延迟最低 |
| stdio | runStdio(backend) / npx @seanhogg/builderforce-memory-mcp | { type:"stdio", command, args } | 适用于任何语言/独立进程;将 SSM 和 IndexedDB 依赖与使用方解耦 |
| HTTP(Streamable) | createMemoryHttpHandler(backend, { authToken }) | { type:"http", url, headers } | 多租户/联网场景(builderforce.ai 托管、远程 Agent) |
技术报告与同行评审。 Evermind 技术报告的对抗性
PEER-REVIEW.md对此传输方式进行了评审。公开 HTTP 处理器前请注意:authToken检查使用非恒定时间字符串比较(存在计时侧信道),且处理器让所有租户共用一个backend,没有租户隔离——单个令牌即可读取所有租户的事实。尽管上方提到了“多租户”,真正的隔离(令牌→命名空间映射、恒定时间比较、速率限制)尚未实现。此问题在 Builderforce.ai 综合差距登记表中以EVM-3跟踪。**已在 v2026.6.34 中解决:**HTTP 处理器现在使用恒定时间令牌比较和按租户隔离的命名空间(见PEER-REVIEW.md中的解决方案附录)。
为什么这能节省 Token
外部记忆存储的意义在于按需获取,而不是将整个记忆文件固定放进每条提示词中。只有在召回具有选择性时,这种做法才有用,因此 tools.ts 会在服务端强制执行上限:
memory_recall返回排序后的 top-K(默认 5 条,设有硬性上限),而不是整个存储。- 每条记录的内容在进入上下文前都会截断(默认 500 个字符)。
- 没有“返回所有内容”的工具——一次性转储全部内容比直接内联更费资源。
memory_compact会将本地 Evermind 已吸收的事实缩减为一行指针存根,从而避免它继续占用上下文。此操作无损:必须先通过召回探测,原始内容也会归档(仍可召回)——详见下文。它会写入实时存储,确保记忆与磁盘快照保持一致。- 召回会先通过混合融合(BM25 ⊕ 可选 CPU SSM 嵌入、RRF、MMR)进行排序,再根据重要性加权(×(0.5+importance)),并按 90 天半衰期进行时效衰减——
createLocalMemoryStoreBackend({ ranking: false })可关闭这些信号。
工具描述采用指令式措辞(例如“在……之前调用此工具”),因为近期的 Claude 模型使用工具时更为谨慎;描述中的触发条件会影响应调用率。搭配提示词缓存(让各租户使用完全相同的工具集,以保留缓存前缀)和上下文编辑(删去过时的召回事实),才能充分发挥效果。
接口边界
所有内容都基于 MemoryBackend 编写:
interface MemoryBackend {
recall(query: string, topK: number): Promise<RecallHit[]>; // semantic
get(key: string): Promise<RecallHit | undefined>; // exact
recallByTag(tag: string, limit: number): Promise<RecallHit[]>;
remember?(input: RememberInput): Promise<void>; // optional → read-only backends omit
forget?(key: string): Promise<void>;
}
现在即可使用本地 MemoryStoreBackend(通过 @seanhogg/builderforce-memory 使用 IndexedDB);之后接入联网的 builderforce.ai 适配器时,无需更改工具或传输方式。
快速开始——通过 Claude Agent SDK 在进程内运行
import { query } from "@anthropic-ai/claude-agent-sdk";
import { createMemoryMcpServer, createLocalMemoryStoreBackend } from "@seanhogg/builderforce-memory-mcp";
const backend = await createLocalMemoryStoreBackend(); // IndexedDB (fake-indexeddb in Node)
const memory = await createMemoryMcpServer(backend); // type:"sdk" config
for await (const msg of query({
prompt: "What language does this user prefer? Check memory first.",
options: {
mcpServers: { builderforce_memory: memory },
allowedTools: ["mcp__builderforce_memory__*"], // auto-approve, no prompts
},
})) {
if (msg.type === "result" && msg.subtype === "success") console.log(msg.result);
}
快照由多方共享 — 服务会监视它
设置 persistFile 后,存储会驻留在内存中,而 JSON 快照是跨进程生命周期的事实来源。其他进程也会编辑该文件(BuilderForce VS Code 扩展会将已吸收的条目原地重写为存根),因此每次操作前,后端都会检查文件状态,如果文件在此期间发生变化,就从磁盘重新加载数据——否则,这个服务仍持有编辑前的内容,并会在下次写入时用它覆盖该文件。服务自身的写入会在落盘时立即记录标记(mtime + 大小 + 内容哈希),因此在稳定状态下只需执行一次 stat,也不会出现写入循环。
SSM 嵌入召回 — 无头主机(无 GPU)也能使用
未配置模型时,本地后端会以词法方式(BM25)为召回结果排序。指定一个 Evermind 检查点后,排序就会变为 SSM 嵌入的余弦排序,并与词法排序融合(倒数排名融合 — 稠密 ⊕ 稀疏,因此标识符和错误代码等精确词元仍能被捕获)。每个 memory_recall 结果都会注明所用的排序器,因此降级为词法排序时不会悄无声息:
Ranked by: semantic recall (SSM embedding fused with lexical).
Ranked by: lexical recall (fallback - no embedding model loaded).
stdio/HTTP 服务不需要 GPU。 EvermindLM 是纯 CPU 模型,其 EvermindLM.embed() 会对与 GPU HybridMambaModel.embed() 相同的隐藏状态进行均值池化和 L2 归一化,符合相同的接口约定。按以下方式配置:
| 环境变量 | 含义 |
|---|---|
BUILDERFORCE_MEMORY_MODEL | 包含 evermind-lm 的 .evermind 包路径。 |
BUILDERFORCE_MEMORY_TOKENIZER | 该检查点的分词器 JSON。默认值为 <model>.tokenizer.json。 |
BUILDERFORCE_MEMORY_VECTORS | 向量缓存路径。默认与内存快照位于同一目录。 |
向量缓存会跨进程生命周期保留(并记录模型指纹,因此经过调整的检查点会使缓存失效),因为若每个会话都启动子进程,并在首次召回时重新嵌入整个存储,其开销会超过它所替代的词法排序。
进程内宿主会直接传入嵌入器 — 复用已加载的 GPU Evermind 运行时,而不是再启动一个模型:
const backend = await createLocalMemoryStoreBackend({ runtime: ssmMemoryService.runtime });
无论采用哪种方式,随着模型不断调整或蒸馏,召回质量都会自动提升。
体验 — Evermind 做了什么(选择启用)
事实是一类已学习的条目;体验是另一类。片段是一段记录下来的演示(一个程序及使用者在其中执行的 UI 步骤),技能是 Train Once 从片段编译而来的内容(输入的值会成为参数,绝不存储机密,执行不可逆的点击前须经批准),而 运行是一次带有审计跟踪的执行。这一领域由 @seanhogg/builderforce-memory-engine 管理;此服务负责持久化并对外提供。
设置 BUILDERFORCE_MEMORY_EXPERIENCE=1 以注册这些工具(Synapse 已设置)。默认关闭,因此普通的编码 Agent 安装不会将它们纳入工具列表。
| 工具 | |
|---|---|
experience_info | 快照文件、屏幕截图文件夹、模型路径和计数。 |
experience_forget_all | 删除所有片段、屏幕截图、技能和运行(confirm: true)。不会触及记忆和模型。 |
episode_save / _list / _get / _forget | 演示。屏幕截图存放在 episodes/<id>/,并随片段一并删除。 |
skill_preview / _compile / _list / _get / _forget / _schedule、skills_due | Train Once 和例程。 |
run_start / _step / _finish / _list / _get | 运行及其审计跟踪(保留最新的 500 条)。 |
experience_train | 使用引擎唯一的适配方案,对私有模型(BUILDERFORCE_MEMORY_MODEL)进行适配,涵盖所有尚未学会的流程。先前的模型会保留为 <model>.prev。可选择启用 curate: true:先排除运行大多失败的流程及近似副本(彼此相似,或与最近学到的 200 个流程相似),并列出每个被排除的流程;下次会重新考虑这些流程。 |
数据与记忆快照一同存储为 experience.json(与 memory.json 一样,在各进程间共享),另存于 episodes/ 中。绝不会提供给 HTTP 处理程序中按令牌选择的租户。
一次性安装到任意 MCP 宿主(不只是 Claude)
# Auto-detect installed agents and register the memory server into each:
npx -y -p @seanhogg/builderforce-memory-mcp builderforce-memory-install
npx -y -p @seanhogg/builderforce-memory-mcp builderforce-memory-install --host=all
npx -y -p @seanhogg/builderforce-memory-mcp builderforce-memory-install --host=cursor,windsurf
将 stdio 服务条目写入每个宿主自己的配置文件,操作具备幂等性,并创建 .bak 备份。支持的宿主:Claude Code、Claude Desktop、Cursor、Windsurf、VS Code、Cline、Gemini CLI、Codex CLI。所有 Agent 都指向同一共享存储(resolveMemoryFile():~/.builderforce-memory/memory.json;如果实时存储位于旧版路径 ~/.claude/builderforce-memory/memory.json,则使用该路径;可通过 --memory-file / BUILDERFORCE_MEMORY_FILE 覆盖;钩子脚本采用相同的解析方式),因此一个 Agent 记住的事实也能被另一个 Agent 调用。--readonly 会移除写入工具;--local=<dist/bin/stdio.js> 则会在开发时运行代码检出版本。
同一启动规范也会导出,供编程方式使用:
buildServerSpec() / installMemoryServer()(参见 src/install/)。
Claude Code:“自驱动记忆组合”
注册服务后,Claude Code 就能使用记忆工具。对于 Claude Code,安装程序还会配置钩子,让记忆自驱动,而非仅提供建议(使用 --no-hooks 跳过):
| 钩子 | 行为 |
|---|---|
SessionStart | 注入重要持久记忆的摘要。 |
PreCompact | 窗口内容被总结前,先写入持久学习内容。 |
UserPromptSubmit | 上下文召回——根据提示词为记忆评分,并注入相关记忆,使存储的事实能在决策时刻被检索,而不仅仅是在会话开始时。 |
Stop | 自主捕获——如果用户的最后一条消息包含持久指令或纠正,且本轮尚未归并,就阻止停止,并提示调用 memory_remember。捕获通过 MCP 写入路径进行(不会与快照发生竞争);stop_hook_active 防护机制确保每轮最多只提醒一次。 |
这四个钩子都指向同一个生成的、无依赖的钩子脚本(~/.claude/builderforce-memory/bfmem-hook.mjs,包含四种模式),以及一个配套技能。具备幂等性,并安全创建 .bak 备份。源码位置:src/install/claude-hooks.ts(installClaudeCombo / bfmemHookSource)。
快速开始 — stdio(任何进程 / 语言)
npx -y @seanhogg/builderforce-memory-mcp # serves the local MemoryStore over stdio
mcpServers: {
builderforce_memory: { type: "stdio", command: "npx", args: ["-y", "@seanhogg/builderforce-memory-mcp"] },
}
环境变量:BUILDERFORCE_MEMORY_DB(数据库名称)、BUILDERFORCE_MEMORY_READONLY=1(移除写入工具)。
快速开始 — HTTP(多租户)
BUILDERFORCE_MEMORY_TOKEN=secret PORT=8787 npx @seanhogg/builderforce-memory-mcp-http
mcpServers: {
builderforce_memory: {
type: "http",
url: "http://localhost:8787",
headers: { Authorization: "Bearer secret" },
},
}
或者,在你自己的 Node/Express 服务上挂载 createMemoryHttpHandler(backend, { authToken }),使用任何后端(包括未来的远程后端)。
自定义 / 远程后端
实现 MemoryBackend,并将其传递给任何传输方式:
import { createMemoryMcpServer, type MemoryBackend } from "@seanhogg/builderforce-memory-mcp";
const remote: MemoryBackend = {
recall: (q, k) => bfClient.search(q, k),
get: (key) => bfClient.get(key),
recallByTag: (t, lim) => bfClient.byTag(t, lim),
remember: (input) => bfClient.put(input),
forget: (key) => bfClient.delete(key),
};
const server = await createMemoryMcpServer(remote);
压缩规则(@seanhogg/builderforce-memory-mcp/compaction)
memory_compact 写入的存根格式([absorbed→Evermind vN] <first line>)作为无依赖子路径发布。外部压缩器从中导入规则,因此其存根与服务生成的完全一致,彼此都不会重复生成存根。
无损契约(每个压缩器都必须按顺序执行):
planLosslessCompaction(candidates, { probe, version })— 结构规则(planCompaction:跳过存根,条目绝不增大)加上回忆探测:probeQuestionFor(key, content)会隐去事实中最具辨识度的词元,本地 Evermind 必须提供该词元(probePasses)。没有探测或答案错误,都会使事实保持未压缩状态(no_probe/probe_failed)。- 将每次写入的
archive行归档(将其mergeArchive到defaultArchiveFile(memoryFile)→memory.archive.json)——必须持久化,且先于任何存根写入。归档位于快照之外,只会合并,不会清理,因此可在快照重写、forget和 10,000 条目的上限之后保留。 - 写入存根。
读取时,存根会解析为其归档的原文(RecallHit.content = 全文,RecallHit.stub = 已存储的存根)。没有归档的存根属于 contentLost:工具和 Claude Code hooks 会将其标记为 CONTENT_LOST_LABEL — “(内容已丢失 — 依赖前请重新核实)”,hooks 还会降低其重要性。memory_restore(stdio 二进制文件使用 file,其他情况使用内联 json)可从 [{key, content}] 或 Evermind 协调器的 [{id, text}] mem: 转储中恢复文本:优先按 key 匹配(id 会移除其 mem: 前缀),否则根据存根指针按首行唯一匹配;文本会归档在存根旁,因此不会影响令牌节省。
每次覆盖共享存储文件(SharedJsonFile:快照、归档、experience.json)时,都会先将上一版本轮转保存为 <file>.bak.1 … .bak.3。
依赖项
@modelcontextprotocol/sdk + zod 是必需依赖。@anthropic-ai/claude-agent-sdk
(SDK 传输)、@seanhogg/builderforce-memory + fake-indexeddb(本地后端)是
可选 peer 依赖,会间接导入——仅安装传输方式 / 后端所需的依赖。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。