· · ·
YC 的 CEO Garry Tan 说他花了 12 天,给自己的 AI Agent 造了一个"大脑"——45000 页,4383 个人物,723 家公司,21 个自动任务每天跑着。
Agent 会自动消化会议记录、邮件、推文,每天夜里自己整理知识、修复链接、补全关系图谱。第二天醒来,大脑比昨天更聪明。
我听到这段描述的时候,第一反应是:又来一个?
AI 圈最不缺的就是这种"宏大叙事"。说起来都很厉害,代码一读全是 TODO 和 mock。所以我决定用老规矩,把 GBrain 的源码从头到尾读一遍,看看这到底是"有料"还是"有吹"。
结果读完之后……说实话,我服了。
不是那种"完美无缺"的服——缺陷它确实有。但这个项目在几个关键的地方,做出了我在开源 Agent 项目里很少见到的工程判断。
下面一个一个说。
· · ·
先搞清楚它到底在干嘛
GBrain 解决的是一个很具体的问题:AI 很聪明,但是没有记忆。
你今天告诉 Claude"张三是我合伙人,在做 AI 芯片",明天再问,它一脸茫然。你昨天开会讨论的内容、上周读到的那篇文章、三个月前做的一个技术决策——对 AI 来说,这些全都不存在。
你可能会说:Claude 不是有 Project Knowledge 吗?确实有,但上限大约 200K token。如果你有 500 篇笔记,塞不进去。而且每次对话都要重新加载,效率很低。
GBrain 的做法是:不要把所有笔记塞进上下文,而是建一个可搜索的数据库,让 AI 按需查。
你的 markdown 笔记(git 仓库)│ gbrain import▼Postgres 数据库(页面 + 分块 + 向量 + 知识图谱)│ MCP 协议(30+ 个工具)▼Claude Code / Claude Desktop"我之前写过一篇关于 AI 芯片的分析"→ Claude 自动搜索 → 找到那篇 → 基于你的笔记回答
就这么简单。你在命令行跑 claude mcp add gbrain -- gbrain serve,Claude 就多了 30 个工具:搜索你的笔记、读某一篇、写入新页面、查人物关系。你正常聊天,Claude 自己知道什么时候该去你的知识库里找东西。
听起来是不是挺普通的?一个 RAG 系统嘛,LlamaIndex 也能做。
别急,魔鬼在细节里。
· · ·
500 篇笔记,它怎么找到你想要的那一篇
这是整个系统最核心的问题。上下文窗口有限,你不可能把 500 篇笔记全塞进去。那怎么精准找到相关的那几篇?
GBrain 的答案是一条五步搜索管道。我读完代码以后觉得这个设计确实讲究。
第一步:导入时,把文章切碎。
一篇 3000 字的笔记不是整篇存进数据库的,而是被切成大约 300 词一块的小片段。切的时候用 5 级分隔符——先按段落切,段落太长按行切,行太长按句子切,句子太长按分句切,最后才按词切。
为什么这么做?因为搜索时返回的不是整篇文章,而是最相关的那一小段。Claude 的上下文只需要放 20 个 300 词的片段,不是 500 篇完整文章。
3000字文章 → 切成 10 个 300 词的 chunk每个 chunk 独立生成向量嵌入每个 chunk 独立建全文索引搜索时按 chunk 粒度匹配,不是按文章粒度
第二步:搜索时,两条路并行。
你问"我之前分析过 AI 芯片",GBrain 同时跑两种搜索:
关键词搜索:Postgres 的 tsvector 全文索引,按词频排序
向量搜索:把问题变成向量,用 pgvector 找最相似的片段
关键词搜索擅长精确匹配(名字、日期、专有名词),向量搜索擅长语义匹配(换一种说法也能找到)。单独用哪个都有盲区,两个并行互补。
第三步:RRF 融合。
两条路的结果怎么合并?用信息检索领域的标准公式:score = Σ 1/(60 + rank)。
这个公式的妙处在于:一条结果如果在两种搜索里都排名靠前,它的融合分数会远高于只在一种搜索里排名高的结果。不需要调权重,不需要归一化,数学上就是对的。
第四步:来源权重。
这是我觉得最聪明的设计。融合完之后,GBrain 会根据内容的来源类型调整分数:
你自己写的原创笔记 × 1.5概念和框架文档 × 1.3人物/公司页面 × 1.2每日随笔 × 0.8推文备份 × 0.7聊天记录 × 0.5
为什么要这么做?因为一个真实的知识库里,大量内容是低质量的——推文、聊天碎片、转发的文章。如果不做来源权重,你问"我们对 AI 芯片有什么了解",返回的前 10 条很可能全是你和别人聊天时随口提到 AI 芯片的记录,而你精心写的《AI 芯片行业分析》反而排在后面。
这不是拍脑袋设的权重——这是在一个 45000 页的真实大脑上调出来的参数。作者自己每天用,搜索结果被聊天记录淹没了他会亲自感受到,然后调参数修。
第五步:4 层去重。
最后还有一个 4 层去重管道,防止搜索结果被同一篇文章的不同片段刷屏:
每篇文章最多保留 3 个最相关的片段文本相似度 > 85% 的片段去掉重复的同一类型的页面不能超过结果总数的 60%(保证多样性)每篇文章最终最多保留 2 个片段
然后还有一个"compiled truth 保证"——如果某篇文章的核心内容(你自己写的正文,不是时间线和元数据)在去重过程中被挤掉了,会强制换回来。因为那才是最有价值的部分。
读完这整条管道,我意识到一件事:大多数 RAG 系统的搜索就是"向量搜索 + top-K",GBrain 的搜索是一条经过生产环境打磨的、有五步精细控制的管道。 这不是写论文,这是真的被自己的搜索结果折磨过。
· · ·
一次定义,三处生效——我见过最干净的多入口设计
GBrain 同时有三个入口:CLI 命令行、MCP 协议(给 Claude 用)、HTTP API(给远程客户端用)。
大多数项目怎么做的?每个入口各写一套参数校验、各写一套错误处理、各写一套响应格式。刚开始还能保持一致,三个月后就开始漂移——CLI 支持某个参数但 MCP 不支持,HTTP 的错误码跟 CLI 的不一样,诸如此类。
GBrain 怎么做的?一个数组,定义 41 个操作,三个入口全部从这个数组自动生成。
// operations.ts — 唯一源头const operations: Operation[] = [{name: 'search',description: '...',params: { query: { type: 'string', required: true }, ... },handler: async (ctx, params) => { ... },},// ... 40 more];
MCP 服务器?35 行代码,直接从 operations 数组生成工具列表:
// server.ts — 整个 MCP 服务器server.setRequestHandler(ListToolsRequestSchema, async () => ({tools: buildToolDefs(operations), // 从 operations 自动生成}));server.setRequestHandler(CallToolRequestSchema, async (request) => {return dispatchToolCall(engine, name, params, { remote: true });});
调度器?104 行,做参数校验 + 构建上下文 + 调用 handler + 格式化结果。
加一个新操作只需要在 operations.ts 里加一个对象。CLI 命令、MCP 工具、HTTP 端点全自动出现。 不可能出现"CLI 有但 MCP 没有"的情况,因为它们读的是同一个数组。
这个设计叫 Contract-First(契约优先)。它不只是"少写代码"——它从根上消除了一整类 bug。41 个操作 × 3 个入口,如果各写各的就是 123 个需要保持同步的实现。Contract-First 让这变成 41 + 3(41 个定义 + 3 个薄薄的生成器)。
我在开源 Agent 项目里读过很多代码,这是我见过最干净的多入口方案。没有之一。
· · ·
自动建关系图谱,零 LLM 调用
GBrain 会从你的笔记里自动提取人物和公司之间的关系。但不是用 LLM 提取的——是用正则匹配。
你在笔记里写了:
会议上 [Alice Chen](people/alice-chen) 介绍了她 founded 的公司[NovaMind](companies/novamind)
GBrain 自动做这些事:
用正则提取 [Alice Chen](people/alice-chen) 和 [NovaMind](companies/novamind) 两个实体引用
从上下文文本里发现 founded 这个词
推断关系类型:people/alice-chen → companies/novamind,类型 = founded
页面类型是 meeting → 自动加一条 attended 关系
关系推断的规则很简单但很实用:
文本包含 founded / co-founded / started → founded文本包含 invested / backed / funded → invested_in文本包含 advises / mentor / board member → advises文本包含 works at / joined / employee → works_at都不匹配 → mentions
还有一层更聪明的:frontmatter 自动建图。如果你的人物页面写了 company: NovaMind,GBrain 会自动在 Alice 和 NovaMind 之间建一条 works_at 关系。一张 12 行的映射表覆盖了所有常见的实体关系模式:
// person 页面的 company 字段 → works_at 出边{ fields: ['company'], pageType: 'person', type: 'works_at', direction: 'outgoing' }// company 页面的 key_people 字段 → works_at 入边{ fields: ['key_people'], pageType: 'company', type: 'works_at', direction: 'incoming' }// meeting 页面的 attendees 字段 → attended 入边{ fields: ['attendees'], pageType: 'meeting', type: 'attended', direction: 'incoming' }
零 API 调用、零成本、零延迟。 提取 47000 条关系不花一分钱。这是一个很务实的判断——用正则虽然不如 LLM 理解深,但速度快三个数量级、成本低无数倍、结果确定性强。对于"谁在哪家公司工作"这类关系,正则完全够用。
· · ·
每个 CI 防护脚本背后,都是一次真实的事故
这是让我最有感触的部分。
GBrain 的 CI 流程里有好几个 bash 脚本,每个都很短(十几行),但每个都在防一个曾经真实发生过的 bug。
第一个:check-jsonb-pattern.sh
# 如果代码里出现 ${JSON.stringify(x)}::jsonb 这个模式就失败PATTERN='\$\{JSON\.stringify\([^)]*\)\}::jsonb'if grep -rEn "$PATTERN" src/; thenecho "ERROR: postgres.js v3 会对这个模式做双重编码,导致数据静默损坏"exit 1fi
这个脚本防的是 v0.12.0 的一个真实 bug:用 ${JSON.stringify(x)}::jsonb 写入 Postgres 时,postgres.js 会再 stringify 一次,导致数据库里存的是字符串而不是 JSON 对象。数据静默损坏——写入不报错,读取不报错,但数据全是错的。
修完 bug 之后,他们没有只修代码了事——而是写了一个 grep 脚本,永久禁止这个写法再次出现在代码库里。
第二个:max_stalled 防护
# 如果 schema 文件里出现 max_stalled DEFAULT 1 就失败MAX_STALLED_PATTERN='max_stalled\s+INTEGER\s+NOT\s+NULL\s+DEFAULT\s+1\b'if grep -rEn "$MAX_STALLED_PATTERN" src/schema.sql src/core/migrate.ts; thenecho "ERROR: DEFAULT 1 会导致 worker 被 kill 后任务永久标记为死亡"exit 1fi
这个防的是 #219:任务队列的 worker 进程被 SIGKILL 杀掉后,如果 max_stalled 默认值是 1,任务第一次失速就会被标记为"死亡",永远不会重试。改成 DEFAULT 5 之后,worker 有 5 次重试机会。
这些脚本加起来不到 50 行代码,但它们构成了一道"结构性防线"。 不是靠人记住"别这么写",而是靠机器在每次提交时自动检查。一个 grep 命令就能永久消灭一类 bug——这比任何 code review 都可靠。
而且每个脚本都有详细的注释,说明它防的是哪个 bug、是什么时候引入的、为什么这么写会出问题。这不是预防性的"最佳实践",这是事后验尸的产物。出 bug → 修 bug → 写防护 → 防护进 CI。工业级的质量循环。
· · ·
CHANGELOG 里最让我信服的一句话
v0.24.0 的 CHANGELOG 开头是这样写的:
**No new features. No new commands. Just the unsexy fixes that turn a feature release into a production release.**
没有新功能。没有新命令。只有那些不性感的修复。
然后它承认了一件事:
`gbrain routing-eval --llm` was a documented feature that did nothing. README, CHANGELOG, and CLI help all said it ran an LLM tie-break layer. The code returned structural-only results with no warning, no error, no signal at all.
翻译一下:我们的文档里写了这个功能存在,但代码里其实什么都没做。 README、CHANGELOG、CLI 帮助文档全在撒谎。现在我们修了——不是真的实现了这个功能,而是让它诚实地告诉你"这个功能还没实现"。
一个项目愿意在自己的发布说明里公开承认"我们的文档撒了谎"——这种诚实度,在开源项目里极其罕见。
大多数项目的做法是什么?悄悄改掉,不提。或者在 minor release 里混进去。GBrain 把它放在版本说明的第二段,黑纸白字。
这种态度比任何技术细节都更能说明一个项目的可信度。
· · ·
说完优点,说缺陷
扒底裤系列不会只报喜不报忧。GBrain 有几个真实的局限:
不支持 ChatGPT。 GBrain 通过 MCP 协议接入 AI,目前只有 Claude Desktop / Claude Code / Cursor 支持 MCP。ChatGPT 需要 OAuth 2.1,GBrain 还没实现。如果你的主力是 ChatGPT,用不了。
重名消歧靠人工。 如果你有两个叫 Alice Chen 的人,GBrain 不会自动问你说的是哪个。它通过 slug(文件路径)区分身份:people/alice-chen 和 people/alice-chen-stripe。但如果你笔记里只写了"Alice Chen",它会匹配到第一个。要准确指向,得用 markdown 链接格式 [Alice Chen](people/alice-chen-stripe)。
纯命令行,没有 GUI。 没有网页界面,没有知识图谱可视化。所有操作都在终端里。对不习惯命令行的人来说门槛很高。
Markdown-only。 你的笔记必须是 markdown 格式。用 Notion、飞书、Word 的人得先导出。GBrain 不直接对接这些工具。
29 个 Skill 本质上是 prompt 模板。 说是"技能",其实是写给 AI 读的 markdown 指令文件——什么时候触发、该调哪些工具、输出格式是什么。它们的价值完全取决于读它们的 AI 有多强。Skill 本身不执行任何逻辑。叫"29 个精心设计的 prompt 模板"更准确。
Minions 任务队列可能过度工程化。 用 Postgres 表做任务队列,实现了父子 DAG、级联取消、幂等键、静默时段、3 层失速检测。对一个个人知识库来说,可能不需要这么复杂的后台任务系统。
单人使用。 没有多用户、没有权限管理、没有协作。它是"个人大脑",不是"团队 wiki"。
这些缺陷是真实的。但请注意——这些缺陷没有一个是"工程质量差"导致的。 它们是设计选择的边界:选择了 MCP 就暂时失去了 ChatGPT 用户,选择了 slug 就需要人工消歧,选择了命令行就排除了非技术用户。
· · ·
它凭什么做到这么好?三个深层原因
读完整个项目之后,我一直在想一个问题:为什么这个项目的代码质量明显高于大多数同类项目?
想来想去,我觉得有三个深层原因。
原因一:使用者就是开发者
Garry Tan 不是在做一个给别人用的开源项目。他是在做他自己每天都在用的工具。那 45000 页是他真实的数据。搜索结果被聊天记录淹没了,他亲自感受到;关系图谱建错了,他亲自发现。
source-boost 的权重(originals 1.5,chat 0.5)不是拍脑袋定的。它是在每天的真实使用中,被自己的搜索结果折磨到受不了,然后一点一点调出来的。
这解释了为什么每个功能都解决真实问题而不是假想问题。
原因二:用 AI 开发 AI 基础设施,形成了质量飞轮
CLAUDE.md 有 971 行。这不是给人读的架构文档——这是给 Claude Code 读的工作指令。每次开发都是 Claude 读这个文件,然后改代码、跑测试、提交。
这创造了一个有趣的正循环:
文档必须准确,否则 AI 会写错代码
接口必须一致,否则 AI 无法推理
测试必须存在,否则无法验证 AI 的产出
你为了让 AI 高效地改代码,被迫把代码质量保持在极高水平。文档过时了?AI 产出错误代码 → 测试失败 → 你立刻发现文档需要更新。
用 AI 开发的项目,文档质量被倒逼到超过人类项目。 这不是自律的结果,是机制的结果。
原因三:每个 bug 变成永久防线
出 bug → 修 bug → 写一个 10 行的 grep 脚本 → 加进 CI → 这类 bug 永远不会再出现。
这不是大多数项目的做法。大多数项目是:出 bug → 修 bug → 靠 code review "记住别这么写"。然后六个月后新人加入,又写出一模一样的 bug。
GBrain 的方法很朴素但极其有效:不信任人的记忆,信任机器的检查。 50 行 bash 脚本,保护了整个代码库。
· · ·
最后
读了很多 AI Agent 项目的代码之后,我越来越觉得一件事:
好的 Agent 基础设施不是靠堆功能堆出来的,而是靠在真实使用中一个一个踩坑踩出来的。
GBrain 的搜索管道之所以有 5 步那么复杂,是因为作者被搜索结果折磨过。来源权重之所以存在,是因为聊天记录真的把原创内容淹没过。CI 防护脚本之所以存在,是因为数据真的静默损坏过。
没有哪个功能是"我觉得应该有"——每个功能都是"我不加这个活不下去"。
这是一个 YC CEO 给自己打造的工具,然后开源出来让其他人也能用。它的目标用户画像非常清楚:用 markdown 管理大量笔记、用 Claude Desktop/Code 做助手、希望 AI 能记住你所有积累的知识。
如果这不是你的场景,你不需要用它。但即使不用,你也可以从它身上学到三件事:
Contract-First:如果你的系统有多个入口,从第一天就该用一个数组生成一切
针对已知 bug 的 grep 防护:每个伤害过你的 bug 模式都值得一个 10 行的 CI 守卫
给 AI 写的文档要比给人写的更精确:因为 AI 不会"大概理解"
最后,分享一个判断 Agent 项目质量的简单方法:去读它的 CHANGELOG。
如果一个项目的 CHANGELOG 全是"added amazing feature X",小心。
如果它愿意写"No new features, just the unsexy fixes",而且敢承认"我们的文档曾经撒了谎"——
这个项目大概率是靠谱的。
我建了一个AI学习群,目前20来人,都是在真正动手学AI的人。如果你也在自己跑模型、写代码、做项目,欢迎加我微信,备注"你在做的AI方向",我拉你进群。纯围观的就不加了,群里大家都在真搞。
