著者: @hi_im_isaac_、@learnwdaniel、@gaozenghao
※注:本技術ブログのインタラクティブ版はこちらからご覧いただけます: https://www.cerebras.ai/blog/how-we-built-our-knowledge-base
社員は毎日、社内ナレッジベースに 15,000 件以上の質問を投げかけています。このナレッジベースは、3 か月前にローンチして以来、同社で最も広く使われる社内ツールの 1 つになりました。人間、自動化、エージェントによって利用されています。
Cerebras では、データセンター運用、チップ設計、ハードウェア、トレーニング、推論、クラウドプラットフォームなど、さまざまなチームが連携して働いています。毎年何百人もの新入社員が加わる中、コミュニケーションチャンネルは同じ質問で溢れかえっていました。
- 「X はどこにありますか?」
- 「Y の専門家は誰ですか?」
- 「Z とは何ですか?」

私たちは、人と人、人とシステムを有益な情報に結びつけるために、Cerebras Knowledge を構築しました。
データが存在する場所でデータと向き合う
組織内で情報を見つけるのは困難です。データはさまざまなツールに散らばっており、四半期ごとに誰かが同じ素晴らしい解決策を提案します。「すべての情報を一箇所にまとめるために、すべてを 1 つのプラットフォームに記録しよう」というものです。しかし、単一の真実の情報源という夢は、実際にはほとんど機能しません。
情報は、便利で人間工学的な場所で生成されます。ドキュメントへの提案編集、Slack のスレッド、GitHub のコード参照、Jira のステータスメタデータなどです。これらのプラットフォームは、それぞれの特定の領域に合わせて作られ、長年の製品エンジニアリングと分析によって最適化されています。Google Docs でプルリクエストについて議論するのは、ひどい体験になるでしょう。
そこで私たちは、既存の行動を最小限に変更するだけで済むシステムの設計に着手しました。データ収集の面では、各プラットフォームから直接データを抽出することを意味しました。
ナレッジベースの構造
私たちのナレッジベースは、3 つの機能を提供します。
- 社内データを収集・保存するためのプラットフォーム。
- そのデータをクエリするためのプラットフォーム。
- 認証と認可を実施し、監査と分析を行うレイヤー。
中核となるのは、多くのソースからの埋め込み、生の要約、メタデータを保持する単一の Postgres テーブルです。システムは継続的に会社全体からデータを取り込み、クエリ可能なデータストアを維持します。
私たちは、シンプルでありながら、ほとんどの形式のデータで動作するデータインターフェースを求めていました。また、Cerebras の他の開発者がカスタムコネクタを構築できるようにもしたかったのです。結果は意図的にシンプルになりました。Slack のスレッドからネットリストまで、すべてのソースが同じ埋め込みテーブルに格納され、そのテーブル内のものはすべて、同じインターフェースを通じて即座にクエリ可能になります。

各データソースは、データの内容、データへの接続方法、データを取得する頻度を定義します。結果として得られる各埋め込み行は、Slack、コードリポジトリ、ドキュメントシステム、カスタムデータベースのいずれから来たものであっても、同じインターフェースに従います。
非構造化 Slack 会話の処理方法
Slack は、私たちが設計する必要があった最も重要なデータソースでした。Slack は、会社全体で最新のエンジニアリング議論が行われる場所だからです。

最初に、生のテキストに対する単純な埋め込みで十分に機能するかどうかをテストしました。しかし、関連するすべてのデータをマッチングするには、ベクトル検索だけでは不十分であることにすぐに気づきました。
Slack メッセージには、いくつかの課題があります。
- 情報密度は大きく異なります。「はい、そうですね、マイク」というメッセージもあれば、詳細なカーネルの説明もメッセージです。
- メッセージの長さはさまざまで、短いメッセージが、より長く詳細なメッセージをコサイン類似度で上回ることがよくあります。
- メッセージの意味は、周囲の会話に依存することがよくあります。
ハイブリッドアプローチが必要でした。私たちは Slack の取り込みを構築し、すべてのスレッドが複数の検索技術によって同時に検索可能になるようにしました。各技術は、他の技術の弱点を補います。
- 全文検索は、埋め込みがぼやかしてしまう正確なトークンを捕捉します: エラー文字列、フラグ名、ホスト名などです。エンジニアがリテラルなエラーメッセージを貼り付けた場合、正確な字句一致がほぼ常に最良の証拠であり、いかなる意味的類似性もそれを上回るべきではありません。
- 埋め込み検索は、言い換えを捕捉します。 「マニフェストロード後に復元がハングする」と尋ねる人と、「チェックポイントが NFS マウントでストールする」と答えた人は、語彙を共有しないかもしれません。ベクトル類似性は、異なる言葉で書かれた質問と回答を結びつけるものです。(1)
- 逆文書頻度は、シグナルとフィラーを分離します。 あいまいな設定フラグのような稀なトークンを中心に構築された短いメッセージは、ランク付けされる価値があります。「了解、ありがとう!」は、埋め込み空間では多くのクエリに近い位置にありますが、用語の希少性を考慮するとスコアはほぼゼロになります。
- 経過時間による減衰は、Slack の回答に有効期限があることをエンコードします。 2 つのスレッドが同じ質問に答えている場合、6 か月前のスレッドは、もはや存在しないインフラストラクチャを説明しているかもしれません。関連性がそれ以外で等しい場合、新しいスレッドが優先されます。

単一のスコアラーだけに依存することはありません。各技術は同じコーパスの独自のランク付けビューを生成し、これらのビューはクエリ時に融合されます(再ランキングを参照)。
Socket モード
データをリアルタイムで収集するために、Slack ボットをワークスペースにインストールし、Socket モードで実行しました。Slack はすべてのメッセージイベントを永続的な WebSocket 経由でプッシュするため、Web API をポーリングしてレート制限に達することなく、リアルタイムの更新を取得できます。
イベントが到着すると、すぐに確認応答し、安定したイベント ID を使用して重複排除し、メッセージを取り込みコンシューマーにマークします。
取り込みコンシューマーは、新しいメッセージを単独で保存するわけではありません。メッセージが属するスレッドを解決し、親とすべての返信を含む会話全体を Slack API から再取得します。そして、スレッド全体を 1 行として書き戻します。したがって、既存のスレッドへの返信は、親とすべての兄弟を再プルするため、保存されたコンテンツ、参加者リスト、最終アクティビティタイムスタンプは常に完全な会話を反映します。
私たちのシステム内のすべての Slack チャンネルには、独自のデータソースがあります。これにより、データの鮮度を細かく調整できます。たとえば、チームは、忙しいインシデントチャンネルをより頻繁に取り込むことを選択できます。
スレッドとメッセージ
生の Slack テキストは、着地するとすぐにキーワード検索可能になります。これは、生のコンテンツに対して Postgres 全文(GIN)インデックスを維持しているためです。ただし、有用なベクトル検索を可能にするために、いくつかの追加処理を行います。(8)
蒸留中に、LLM は完全なスレッドから構造化データを抽出します。
- エンジニアが実際に検索するであろう 1 行の質問。
- 短い要約。
- 解決策。
- 言及されているシステムとコード参照。

これらのデータポイントを埋め込み、共有埋め込みテーブルに書き込みます。元のトランスクリプトは直接埋め込まれません。私たちの実験では、スレッドが一貫した形式に正規化されたときに、精度が大幅に向上しました。(7,9) 追加のメタデータは、意味的マッチングにより有用なシグナルを提供します。
バースティング
この時点で Slack 検索は良好でしたが、同じ問題に繰り返し直面していました。長いスレッド内の重要なメッセージが、スレッドレベルの要約に常に表現されているとは限らないということです。
個々のメッセージからのシグナルを強化するために、バースティングを使用します。バーストとは、同じ作成者からの連続したメッセージの実行です。スレッドトピックをコンテキストとして先頭に追加して、個々のバーストを埋め込みます。(2) なぜなら、回答が、その語彙がスレッド要約に決して含まれないような、1 つの脇道のメッセージに存在することがあるからです。バースト埋め込みにより、そのメッセージが単独で見つけられるようになります。
低シグナルのデータがデータベースに到達するのを防ぐために、各バーストはシグナルの加重組み合わせに対してスコアリングされ、埋め込まれる前にしきい値をクリアする必要があります。
- コーパス全体で比較的稀なトークン(IDF が 4.0 以上)を含む。
- 結合されたバーストが少なくとも 200 文字である。
- バースト内の 1 つ以上のメッセージにリアクションがあり、ソーシャルブーストを提供する。

蒸留後、条件を満たすバーストは埋め込まれ、スレッドレベルのレコードとともに埋め込みテーブルに保存されます。
コードリポジトリ
当初、コードリポジトリの埋め込みが必要かどうか議論しました。Claude Code や他のコマンドラインツールの台頭により、「grep さえあれば十分」と思われる中で、コード埋め込みを作成することは直感に反しているように感じられました。業界の他の人々と話し、大規模コードベースにおけるセマンティック検索に関する Cursor の調査結果を読んだ後、試してみることにしました。
私たちには多くの内部リポジトリがあり、中には 40 GB を超えるものもあります。主な懸念は、それらを効率的に最新の状態に保つ方法でした。
コード埋め込みを維持するための @cocoindex_io の使用
いくつかの実験の後、コードベースのベクトル化に特化したオープンソースのドキュメント埋め込みフレームワークである CocoIndex に落ち着きました。
各リポジトリについて、言語固有の正規表現境界を使用して、粗いものから細かいものへとコードを分割します。スプリッターは、最初にクラスなどのより高いレベルの境界を試みます。結果のチャンクがまだ大きすぎる場合は、メソッド境界、次により小さなブロックにフォールバックします。結果のチャンクを埋め込み、ベクトルを Postgres に書き込みます。単一のファイルから、ファイルレベルや関数レベルのレコードなど、異なる具体性レベルで複数の埋め込みが生成される場合があります。

CocoIndex は、Postgres で同期メタデータを追跡します。各コミット時に、リポジトリ全体を再計算する代わりに、変更されたコードチャンクのみを再埋め込み、再エクスポートします。同期状態と埋め込みストアが同じデータベースに存在するため、これは特にうまく機能しました。
コードベースの数が増えるにつれて、リポジトリのオンボーディングを、チームが自分で提出できる設定ファイルに移行しました。これには、ファイルパスレベルでの許可リストと拒否リストが含まれます。
カスタムデータソース
一部のチームはすでに独自のデータベースを持っており、ナレッジベースに参加するためだけにデータを Slack やドキュメントシステムに移動したくありませんでした。彼らは、既存のテーブルに対して同じクエリサーフェスを求めていました。
これをサポートするために、カスタムソースをプラグインスクリプトとして扱います。チームは、自身のシステムから読み取り、埋め込みテーブルと同じ形状の行を出力する方法を知っている小さな Python モジュールと、対応するデータソースエントリを含むプルリクエストを開きます。
スクリプトが他のすべての埋め込み行と同じスキーマを使用して共有データベースに書き込む限り、スタックの残りの部分は変更なしで機能します。データは、システム内の他の特別な処理を必要とせずに、Slack、コード、ドキュメントと一緒にクエリ可能になります。
計画とツールのファンアウト
すべてのクエリに対して、最初に短い計画パスを実行し、LLM がどのツールとデータソースが重要かを判断します。主なツールは次のとおりです。
- subsystem_index: ファイルごとの LLM 要約。
- search: Slack、wiki、コード、およびその他のインデックス化されたソースにわたる統合ベクトルパイプライン。内部でマージおよび再ランク付けされます。
- search_slack: Slack の直接検索。
- search_code: ソースリポジトリに対する ripgrep。
- recent_prs: 質問に関連する最近のプルリクエスト。
- who_knows: トピックに関する実証済みの専門知識を持つ人々。
プランナーは、インデックス化した内容のコンパクトな説明(どのプロジェクトが存在するか、各プロジェクトでどのソースが利用可能か、各ソースが何の回答に優れているか)に基づいて動作します。ユーザーのクエリとアクティブスコープを考慮して、ツール選択を出力します。エグゼキュータはそれらを並行してファンアウトし、共通の証拠形式に正規化し、最終的な合成 LLM に渡します。(4)

再ランキング
ドキュメントは、クエリと語彙を共有しているが、異なる質問に答えているという理由だけで、上位に浮上することがあります。再ランキングの前に、相互ランク融合(RRF)を使用して、検索エンジンの互換性のない結果リストを結合します。すべてのドキュメントについて、それが表示される各リストに対して、重み / (60 + 順位) を追加します。デフォルトの重みは 1.0、平滑化定数は 60 です。

平滑化定数により、単一の強い投票よりもコンセンサスが重要になります。複数の検索エンジンで上位に表示されるドキュメントは、そのうちの 1 つだけで 1 位になるドキュメントよりも勝る可能性があります。次に、重複するチャンクを 1 つのソースにマージし、各ファイルが貢献できる結果数を制限し、より多様性のある上位 20 件を生成します。
元のクエリとそれらの候補を小さな再ランカーモデルに送信します。各ドキュメントに 0 から 10 までのスコアを付け、上位 10 件を保持します。(6)
ランキングが確定したら、勝者にコンテキストを追加します。たとえば、wiki セクションに一致した場合、隣接する 2 つのセクションも取り込み、チャンク分割で分離された見出し、前提条件、注意事項が失われないようにします。これにより、読者は、重要なコンテキストが欠落した孤立した段落ではなく、完全なスニペットを得ることができます。
つまり、検索の出力は、豊富な証拠パケットです。異なる検索エンジンから融合され、ソースレベルで重複排除され、実際の質問に対して再ランク付けされ、その後に周囲のコンテキストで拡張された結果です。
MCP
MCP 統合では、検索ビルディングブロックを 1 つの「この質問に答える」エンドポイントの背後に隠すのではなく、直接ツールとして公開します。これらのツールは意図的にシンプルで、可能な限り LLM フリーであるため、クライアントは迅速かつ低コストでクエリを実行できます。(5)
各 MCP ツールは、search_slack、search_code、search、who_knows などの 1 つの基礎となる検索プリミティブに対応します。ツールの入力と出力は、狭く、構造化され、安定しており、ツール自体に追加のオーケストレーションロジックを埋め込むことなく、任意のクライアントやエージェントから簡単に呼び出せます。
ほとんどのツールは、ベクトル検索、字句検索、ripgrep などの 1 つのクエリパイプラインを実行し、軽量なスコアリングヒューリスティックを適用し、生の証拠行を返します。
Claude Code、または MCP 互換のエージェントが、オーケストレーションエンジンになります。どのツールをどの順序で呼び出すか、結果をどのように組み立てて最終的な回答やコード編集にするかを決定します。検索レイヤー自体は、リクエストを処理するためにそれらの LLM の決定に依存しません。
Web UI
Web UI では、同じツールが存在しますが、ユーザーのすべての質問に対してエンドツーエンドで実行される完全なクエリパイプラインに接続されています。UI エージェントは、プランナーとエグゼキュータのステップを所有します。
- プランナー: 軽量な LLM パスがクエリとアクティブプロジェクトを検査し、search、search_slack、subsystem_index などのどの検索ツールを呼び出すかを選択します。
- エグゼキュータ: システムはそれらのツール呼び出しを並行してファンアウトし、結果を収集し、スコア、新しさ、ソースヒントを含む共有証拠スキーマに正規化します。
- 合成: 最終的な LLM パスが、型付けされた証拠バンドルと元の質問を受け取り、UI に表示される回答(引用、注意事項、クロスソース合成を含む)を生成します。
ユーザーの視点から見ると、Web UI は単に「質問して回答を得る」だけです。内部では、MCP クライアントが明示的に再現できるのと同じ、プランナー → エグゼキュータ → シンセサイザーのパターンを実行しています。

組織化
コーパスが成長するにつれて、「すべてをすべて検索する」ことは急速に有用でなくなりました。コンパイラチームのエンジニアは、インフラストラクチャのランブックを結果に表示されたくありませんでしたし、その逆も同様です。プロジェクトは、デフォルトで検索を関連性のあるものにする方法です。
プロジェクトとスコープ検索
プロジェクトを、クエリが実行されるワークスペースを整理する主要な方法として導入しました。プロジェクトとは、チームやイニシアチブに関連する特定の Slack チャンネル、コードリポジトリ、内部データベース、ドキュメントスペースなどのデータソースの名前付きバンドルです。
プロジェクトは意図的に軽量です。共有インシデントチャンネルや中央プラットフォームリポジトリなどの同じデータソースは、複製される代わりに、複数のプロジェクトから参照できます。

オンボーディングとデフォルト
オンボーディング中、ユーザーは自分の作業方法に合ったデフォルトプロジェクト(ML トレーニングインフラストラクチャ、コンパイラ、データセンター運用など)を選択または作成するように求められます。
そのデフォルトプロジェクトはユーザープロファイルに保存され、クエリのスコープを自動的に設定します。新しいエンジニアは、どの Slack チャンネル、リポジトリ、ドキュメントスペースが重要かを最初に学ぶ必要なく、高シグナルの回答を得ることができます。
最後に
結局のところ、このナレッジベースが機能するのは、すべてを 1 つの rigid なシステムに強制するのではなく、情報がすでに存在する場所で人々と向き合うからです。さまざまな検索技術を組み合わせることで、証拠を迅速に表面化できます。その結果、実際の企業データに対して十分に柔軟でありながら、Cerebras が成長し続けても有用であり続けるのに十分に構造化された検索体験が実現しました。
ここまで読んで、この分野に興味を持たれた方は、ai/growth チームが採用中です。ご興味があれば、@learnwdaniel までお問い合わせください。
参考文献
- Malkov と Yashunin、Efficient and Robust Approximate Nearest Neighbor Search Using Hierarchical Navigable Small World Graphs、arXiv:1603.09320 / IEEE TPAMI 2018。
- Anthropic、Introducing Contextual Retrieval、2024。
- Cormack、Clarke、Büttcher、Reciprocal Rank Fusion Outperforms Condorcet and Individual Rank Learning Methods、SIGIR 2009。
- Li ら、Search-o1: Agentic Search-Enhanced Large Reasoning Models、arXiv:2501.05366、2025。
- Anthropic、Code Execution with MCP、2025。
- Liu ら、Lost in the Middle: How Language Models Use Long Contexts、arXiv:2307.03172、2023。
- Anthropic、Use XML Tags。
- Salesforce/Slack Engineering、How Slack AI Processes Billions of Messages。
- Improving Agents、Best Nested Data Format。
- Cursor、Improving Agent with Semantic Search、2025。





