Cerebras 如何构建其内部知识库

@cerebras
英语2天前 · 2026年7月16日
1.1M
2.6K
254
41
5.9K

TL;DR

Cerebras 详细介绍了其内部 AI 工具 Cerebras Knowledge 的构建过程,该工具利用混合检索流水线和 LLM 提炼技术,每天为员工解答 15,000 个问题。

作者:@hi_im_isaac_@learnwdaniel@gaozenghao

注:完整技术博客的交互版本可访问:https://www.cerebras.ai/blog/how-we-built-our-knowledge-base

员工每天向我们的内部知识库提问超过 15,000 次。自三个月前上线以来,它已成为公司内部最广泛使用的工具之一,被人类员工、自动化系统以及 Agents 共同使用。

在 Cerebras,我们的团队涵盖数据中心运营、芯片设计、硬件、训练、推理、云平台等多个领域。每年有数百名新员工加入,我们的沟通渠道里充斥着同样的问题:

  • “我在哪里可以找到 X?”
  • “谁是 Y 方面的专家?”
  • “Z 是什么?”
Cerebras - inline image

我们构建了 Cerebras Knowledge,帮助人们将人员和系统与有用的信息连接起来。

让数据触手可及

在企业内部找到信息很困难。数据分散在各种工具中,几乎每过一两个季度,就会有人提出同样的绝妙方案:把所有内容都记录在一个平台上,这样所有信息就集中在一个地方了。然而,单一真相源的梦想在实践中很少能实现。

信息是在最方便、最符合人体工程学的地方产生的:文档中的建议修改、Slack 中的讨论线程、GitHub 中的代码引用、Jira 中的状态元数据。这些平台专为各自的领域量身定制,经过多年的产品工程和分析而优化。在 Google Docs 中讨论 Pull Request 的体验会很糟糕。

因此,我们着手设计一个对现有行为改动最小的系统。在数据收集方面,这意味着直接从各个平台提取数据。

知识库的构成

我们的知识库提供三样东西:

  • 一个收集和存储内部数据的平台。
  • 一个查询这些数据的平台。
  • 一个强制执行身份验证和授权,并附带审计和分析的层。

核心是一个单一的 Postgres 表,它保存来自多个来源的嵌入向量、原始摘要和元数据。系统持续从公司各处摄入数据,并维护一个可供查询的数据存储。

我们想要一个简单但能处理大多数数据形式的数据接口。我们也希望 Cerebras 的其他开发者能够构建自定义连接器。结果故意设计得很简单:从 Slack 线程到网表(netlists),每个数据源都落入同一个嵌入表中,而该表中的任何内容都可以立即通过同一个接口查询:

Cerebras - inline image

每个数据源定义了数据是什么、如何连接到它以及应该多久获取一次。每个生成的嵌入行都遵循相同的接口,无论它来自 Slack、代码仓库、文档系统还是自定义数据库。

我们如何处理非结构化的 Slack 对话

Slack 是我们需要设计的最重要的数据源。它是全公司最前沿工程讨论的发生地。

Cerebras - inline image

我们最初测试了在原始文本上使用简单的嵌入是否足够好。我们很快意识到,仅靠向量搜索不足以匹配所有相关数据。

Slack 消息存在几个挑战:

  • 信息密度差异巨大:“嘿 是的 当然 迈克”和一段详细的内核解释都是消息。
  • 消息长度各不相同,较短的消息在余弦相似度上经常击败较长、更详细的消息。
  • 消息的含义通常取决于周围的对话上下文。

我们需要一种混合方法。我们构建了 Slack 摄入功能,使得每个线程都可以通过多种搜索技术同时检索,每种技术都弥补了其他技术的弱点:

  • 全文搜索捕获了嵌入向量模糊处理的确切词汇:错误字符串、标志名称、主机名。当工程师粘贴一条字面错误消息时,精确的词汇匹配几乎总是最好的证据,任何数量的语义相似性都不应超过它。
  • 嵌入搜索捕获了同义转述。问“恢复在清单加载后挂起”的人和回答“检查点在 NFS 挂载上停滞”的人可能永远不会共享词汇。向量相似性将一个问题与用不同措辞写成的答案联系起来。(1)
  • 逆文档频率将信号与填充内容分开。一条围绕稀有词构建的短消息,比如一个晦涩的配置标志,理应获得更高的排名。“听起来不错,谢谢!”在嵌入空间中与许多查询距离很近,但一旦考虑词汇稀有性,得分就接近零。
  • 时效衰减编码了 Slack 答案会过时这一事实。两个线程可能回答同一个问题,但六个月前的那个线程可能描述了已不存在的旧基础设施。当相关性相同时,较新的线程获胜。
Cerebras - inline image

没有任何一个评分器是独立可信的。每种技术都会对同一语料库产生自己的排名视图,这些视图在查询时被融合(参见重新排序)。

Socket 模式

为了实时收集数据,我们在工作空间中安装了一个 Slack 机器人,并以 Socket 模式运行。Slack 通过持久化的 WebSocket 将每条消息事件推送给我们的机器人,因此我们能够实时获取更新,而无需轮询 Web API 并消耗其速率限制。

当事件到达时,我们立即确认,使用稳定的事件 ID 进行去重,并将消息标记为待摄入消费者处理。

摄入消费者不会孤立地保存新消息。它会解析该消息所属的线程,并从 Slack API 重新获取整个对话,包括父消息和所有回复。然后它将整个线程作为一个行写回。因此,对现有线程的回复会重新拉取父线程及其所有兄弟消息,从而确保存储的内容、参与者列表和最后活动时间戳始终反映完整的对话。

我们系统中的每个 Slack 频道都有自己的数据源。这为数据新鲜度提供了精细的调优。例如,一个团队可以选择更频繁地摄入一个繁忙的事故频道。

线程与消息

原始 Slack 文本一旦落地即可进行关键词搜索,因为我们在原始内容上维护了一个 Postgres 全文(GIN)索引。然而,为了实现有用的向量搜索,我们还进行了一些额外的处理。(8)

在提炼(distillation)过程中,LLM 从完整线程中提取结构化数据:

  • 工程师实际会搜索的一行问题。
  • 一段简短摘要。
  • 解决方案。
  • 提到的系统和代码引用。
Cerebras - inline image

我们嵌入这些数据点,并将它们写入共享的嵌入表中。原始对话文本不会被直接嵌入。在我们的实验中,当线程被规范化为一致的格式时,准确性显著提高。(7,9) 额外的元数据也为语义匹配提供了更有用的信号。

爆发(Bursting)

此时 Slack 搜索已经很好,但我们不断遇到同样的问题:长线程中的重要消息并不总是体现在线程级摘要中。

为了增强单个消息的信号,我们使用了爆发(bursting)机制。一个爆发是指来自同一作者的一系列连续消息。我们将单个爆发与线程主题(作为上下文前置)一起嵌入,(2) 因为有时答案存在于某条偏离主题的消息中,其词汇从未出现在线程摘要里。爆发嵌入使那条消息可以独立被找到。

为了防止低信号数据进入数据库,每个爆发都会根据加权信号组合进行评分,并且必须超过一个阈值才能被嵌入:

  • 包含一个在语料库中相对稀有、IDF 至少为 4.0 的词汇。
  • 合并后的爆发至少包含 200 个字符。
  • 爆发中的一条或多条消息有表情反应,提供社交增强信号。
Cerebras - inline image

提炼之后,合格的爆发会被嵌入并存储在嵌入表中,与线程级记录并列。

代码仓库

最初我们争论过嵌入代码仓库是否必要。随着 Claude Code 和其他命令行工具的兴起,当看起来“grep 就是一切”时,创建代码嵌入似乎有些反直觉。在与行业其他人士交流并阅读了 Cursor 关于大型代码库中语义搜索的研究后,我们决定尝试一下。

我们有许多内部仓库,有些超过 40 GB。我们主要关心的是如何高效地保持它们的更新。

使用 @cocoindex_io 维护代码嵌入

经过几次实验,我们最终选择了 CocoIndex,这是一个专注于对代码库进行向量化的开源文档嵌入框架。

对于每个仓库,我们使用特定于语言的正则表达式边界(从粗粒度到细粒度)来分割代码。分割器首先尝试更高级别的边界,例如类。如果生成的块仍然太大,则会回退到方法边界,然后是更小的块。我们嵌入生成的块并将向量写入 Postgres。单个文件可能在不同粒度级别生成多个嵌入,例如文件级和函数级记录。

Cerebras - inline image

CocoIndex 在 Postgres 中跟踪同步元数据。每次提交时,它只重新嵌入和重新导出更改的代码块,而不是重新计算整个仓库。这对我们来说特别有效,因为同步状态和嵌入存储位于同一个数据库中。

随着代码库数量的增长,我们将仓库接入迁移到可以由团队自行提交的配置文件中,包括文件路径级别的允许列表和拒绝列表。

自定义数据源

一些团队已经拥有自己的数据库,并且不希望仅仅为了参与知识库而将数据迁移到 Slack 或文档系统中。他们希望对自己现有的表也能使用相同的查询界面。

为了支持这一点,我们将自定义源视为插件脚本。团队提交一个包含小型 Python 模块的 Pull Request,该模块知道如何从其系统中读取数据,并生成形如我们嵌入表的行,同时还有匹配的数据源条目。

只要脚本使用与所有其他嵌入行相同的模式写入共享数据库,其余堆栈就可以保持不变。数据变得可以与 Slack、代码和文档一起查询,而无需在系统其他部分进行特殊处理。

规划与工具扇出

对于每个查询,我们首先运行一个简短的规划过程,LLM 会决定哪些工具和数据源可能重要。主要工具有:

  • subsystem_index:每个文件的 LLM 摘要。
  • search:跨 Slack、Wiki、代码和其他索引源(已合并并在内部重新排序)的统一向量管道。
  • search_slack:直接 Slack 检索。
  • search_code:对源代码仓库进行 ripgrep 搜索。
  • recent_prs:与问题相关的近期 Pull Request。
  • who_knows:某个主题上具备专业知识的人员。

规划器基于我们已索引内容的简洁描述进行工作:存在哪些项目、每个项目中有哪些可用的源、以及每个源擅长回答什么问题。根据用户的查询和当前作用域,它输出工具选择,执行器会并行扇出这些工具,将其规范化为通用的证据格式,并传递给最终的合成 LLM。(4)

Cerebras - inline image

重新排序

一个文档可能会仅仅因为与查询共享词汇但却回答了一个不同的问题而出现在顶部附近。在重新排序之前,我们使用倒数排序融合(RRF)来合并检索器的不兼容结果列表。对于每个文档,我们根据它出现的每个列表,计算权重 / (60 + 排名),默认权重为 1.0,平滑常数为 60。

Cerebras - inline image

平滑常数使得共识比单个高票更重要:一个在多个检索器中都排在靠前位置的文档,可以击败一个仅在一个检索器中排名第一的文档。然后我们将重复的块合并回一个源,限制每个文件可以贡献的结果数量,最终得到一个更多样化的前二十名。

我们将原始查询和这些候选结果发送给一个小型重排序模型。它给每个文档打 0 到 10 分,我们保留前十名。(6)

一旦排名确定,我们将上下文添加回胜出的文档。例如,如果我们匹配到一个 Wiki 部分,我们会拉取相邻的两个部分,这样分割导致的标题、前置条件和注意事项就不会丢失。这为读者提供了完整的片段,而不是一个缺少重要上下文的孤立段落。

因此,搜索的输出是一个丰富的证据包:来自不同检索器的融合结果,在源级别去重,针对实际问题重新排序,然后才用周围上下文进行扩展。

MCP

在 MCP 集成中,我们将检索构建块直接暴露为工具,而不是将它们隐藏在一个统一的“回答这个问题”端点后面。这些工具有意设计得简单且尽可能无 LLM 依赖,以便客户端能够快速廉价地查询它们。(5)

每个 MCP 工具对应一个底层检索原语,例如 search_slack、search_code、search 或 who_knows。工具的输入和输出都是狭窄、结构化且稳定的,这使得从任何客户端或 Agent 调用它们都变得容易,而无需在工具内部嵌入额外的编排逻辑。

大多数工具运行一个查询管道,例如向量搜索、词汇搜索或 ripgrep,应用轻量级评分启发式,并返回原始证据行。

Claude Code 或任何兼容 MCP 的 Agent 将成为编排引擎。它决定调用哪些工具、以什么顺序调用,以及如何将结果组装成最终答案或代码编辑。检索层本身不依赖这些 LLM 决策来服务请求。

Web UI

在 Web UI 中,同样的工具也存在,但它们连接到一个完整的查询管道,该管道对每个用户问题端到端地运行。UI Agent 拥有规划器和执行器步骤。

  • 规划器:一个轻量级的 LLM 过程检查查询和当前项目,然后选择调用哪些检索工具,例如 search、search_slack 和 subsystem_index。
  • 执行器:系统并行扇出这些工具调用,收集结果,并将它们规范化为带有分数、时效性和源提示的共享证据模式。
  • 合成:最后一个 LLM 过程接受类型化的证据包和原始问题,然后生成 UI 中显示的答案,包括引用、注意事项和跨源合成。

从用户的角度来看,Web UI 就是“提问并获得答案”。在底层,它运行着与 MCP 客户端可以显式复现的相同的规划器 → 执行器 → 合成器模式。

Cerebras - inline image

组织

随着语料库的增长,“搜索所有地方的所有内容”迅速变得不再有用。编译器团队的工程师不希望看到基础设施运行手册出现在他们的结果中,反之亦然。项目(Projects)是我们让搜索默认相关的方式。

项目与限定范围搜索

我们引入了项目(Projects)作为组织查询所运行的工作区的主要方式。项目是一个有名称的数据源集合:与某个团队或计划相关的特定 Slack 频道、代码仓库、内部数据库和文档空间。

项目在设计上轻量且灵活。同一个数据源(例如共享的事故频道或中央平台仓库)可以被多个项目引用,而无需重复。

Cerebras - inline image

入职引导与默认设置

在入职引导期间,用户会被提示选择或创建一个与他们工作方式匹配的默认项目,例如 ML 训练基础设施、编译器或数据中心运营。

该默认项目存储在用户个人资料中,并自动限定查询范围。新工程师无需先了解哪些 Slack 频道、仓库或文档空间是重要的,就能获得高信号答案。

最终思考

归根结底,这个知识库之所以奏效,是因为它主动适应信息原本存在的地方,而不是强迫所有内容进入一个僵化的系统。通过结合多种搜索技术,我们能够快速呈现证据。结果是提供了一种搜索体验,它足够灵活以适应真实的公司数据,同时又足够结构化,以便在 Cerebras 持续增长时保持有用。

如果你读到了这里并且对此感兴趣,我们的 AI 增长团队正在招聘——如果你有兴趣,请联系 @learnwdaniel

参考文献

  1. Malkov 和 Yashunin,高效且鲁棒的基于分层可导航小世界图的近似最近邻搜索,arXiv:1603.09320 / IEEE TPAMI 2018。
  2. Anthropic,引入上下文检索,2024。
  3. Cormack、Clarke 和 Büttcher,互逆排名融合优于 Condorcet 和个体排名学习方法,SIGIR 2009。
  4. Li 等人,Search-o1:基于 Agent 搜索增强的大型推理模型,arXiv:2501.05366,2025。
  5. Anthropic,使用 MCP 执行代码,2025。
  6. Liu 等人,迷失在中间:语言模型如何使用长上下文,arXiv:2307.03172,2023。
  7. Anthropic,使用 XML 标签
  8. Salesforce/Slack 工程团队,[Slack AI 如何处理数十亿条消息]。
  9. Improving Agents,[最佳嵌套数据格式]。
  10. Cursor,通过语义搜索改进 Agent,2025。
二次创作

使用 YouMind 创作爆款文章

收集素材、拆解爆点、生成视觉资产、撰写内容,并在一个 AI 工作空间里完成分发。

了解 YouMind
写给创作者

把你的 Markdown 变成干净的 𝕏 文章

图片上传、表格、代码块,往 𝕏 上手动重排太痛苦。YouMind 把整篇 Markdown 一键转成干净、可直接发布的 𝕏 文章草稿。

试试 Markdown 转 𝕏

更多可拆解样本

近期爆款文章

探索更多爆款文章