How Cerebras Built Its Enterprise Knowledge Base

Author: Isaac Tai, Daniel Kim, Mike Gao (Cerebras) | Source: cerebras.ai/blog | Published: (미기재)


한 줄 요약

“모든 걸 한 플랫폼에 기록하자”는 단일 진실 공급원의 꿈 대신 데이터가 이미 사는 곳에서 만나되, 모든 소스를 하나의 embeddings 테이블 인터페이스로 정규화하고 full-text·벡터·IDF·age decay를 RRF로 융합해 쓰는 사내 지식 베이스.

핵심 주장/내용

  • 단일 소스의 꿈은 거의 통하지 않는다: 정보는 편리하고 자연스러운 곳에서 생성된다 — 문서의 수정 제안, Slack 스레드, GitHub의 코드 참조, Jira의 상태 메타데이터. 이 플랫폼들은 각자의 도메인에 맞춰 수년간 최적화되었다. PR 논의를 Google Docs에서 하는 건 끔찍한 경험이다. 그래서 기존 행동을 최소한으로 바꾸는 시스템을 설계했다 — 각 플랫폼에서 직접 데이터를 추출
  • 아키텍처의 핵심 단순함: Slack 스레드부터 넷리스트까지 모든 소스가 같은 embeddings 테이블(단일 Postgres 테이블)에 랜딩하고, 그 테이블에 있는 건 무엇이든 즉시 같은 인터페이스로 쿼리 가능. 소스마다 “무엇인지, 어떻게 연결하는지, 얼마나 자주 가져오는지”를 정의하면 되고, 결과 row는 출처와 무관하게 같은 인터페이스를 따른다
  • Slack — 벡터 검색만으로는 부족했다: ① 정보 밀도 편차가 극심(“hey yeah sure mike”와 상세한 커널 설명이 둘 다 메시지) ② 길이 편차 때문에 짧은 메시지가 코사인 유사도에서 길고 상세한 메시지를 자주 이긴다 ③ 메시지 의미가 주변 대화에 의존
    • 하이브리드 4종 (각 기법이 다른 기법의 약점을 메움):
      • full-text — 임베딩이 뭉개는 정확한 토큰(에러 문자열, 플래그 이름, 호스트명)을 잡는다. 엔지니어가 문자 그대로의 에러 메시지를 붙여넣으면 어떤 의미 유사도도 정확한 어휘 매치를 이겨서는 안 된다
      • embedding — 패러프레이즈를 잡는다. “restore hangs after manifest load”라고 묻는 사람과 “checkpoint stalls on the NFS mount”라고 답한 사람은 어휘를 공유하지 않을 수 있다
      • IDF — 신호와 잡음을 분리. 희귀 토큰(모호한 config 플래그) 중심의 짧은 메시지는 순위에 올라야 하고, “sounds good, thanks!”는 임베딩 공간에서 많은 쿼리에 가깝지만 term rarity를 고려하면 0에 가깝게 떨어진다
      • age decay — Slack 답변은 만료된다. 두 스레드가 같은 질문에 답할 수 있고 6개월 전 것은 더 이상 존재하지 않는 인프라를 설명할 수 있다
    • 어떤 스코어러도 단독으로 신뢰되지 않는다 — 각각이 같은 코퍼스에 대한 자기 랭킹 뷰를 만들고 쿼리 시점에 융합
  • Socket Mode 수집: Slack 봇을 Socket Mode로 돌려 영구 WebSocket으로 모든 메시지 이벤트를 푸시받음(Web API 폴링과 rate limit 소모 없음). 이벤트가 오면 즉시 ack하고 안정적 event ID로 중복 제거. ingest consumer는 새 메시지를 고립적으로 저장하지 않고 그 메시지가 속한 스레드를 해석해 부모와 모든 답글을 포함한 전체 대화를 Slack API에서 다시 가져와 한 row로 쓴다 → 저장된 내용·참여자 목록·마지막 활동 타임스탬프가 항상 완전한 대화를 반영. 채널마다 자기 데이터 소스라서 바쁜 인시던트 채널은 더 자주 수집하는 식으로 신선도를 세밀 조정
  • Distillation — 원본 트랜스크립트를 직접 임베딩하지 않는다: LLM이 전체 스레드에서 ① 엔지니어가 실제로 검색할 법한 한 줄 질문 ② 짧은 요약 ③ resolution ④ 언급된 시스템·코드 참조를 추출. 스레드를 일관된 포맷으로 정규화했을 때 정확도가 유의미하게 올랐고, 추가 메타데이터가 의미 매치에 유용한 신호를 더 준다. 원시 텍스트는 Postgres full-text(GIN) 인덱스로 랜딩 즉시 키워드 검색 가능
  • Bursting: 긴 스레드 안의 중요한 메시지가 스레드 레벨 요약에 항상 표현되지는 않았다. burst = 같은 작성자의 연속 메시지 묶음이고, 스레드 주제를 컨텍스트로 앞에 붙여 개별 burst를 임베딩한다 — 답이 어휘가 스레드 요약에 전혀 들어가지 않은 곁가지 메시지 하나에 있을 때 그 메시지를 독립적으로 찾을 수 있게 한다. 저신호 데이터를 막기 위해 가중 조합 점수가 임계를 넘어야 임베딩: 코퍼스 전반에서 IDF 4.0 이상의 희귀 토큰 포함, 결합 burst 200자 이상, 리액션이 있으면 소셜 부스트
  • 코드 리포지토리 — “grep is all you need”인가: Claude Code 같은 CLI 도구의 부상으로 코드 임베딩이 반직관적으로 느껴졌지만, 업계 대화와 Cursor의 대규모 코드베이스 시맨틱 검색 findings를 읽고 시도. 언어별 정규식 경계를 거친 것에서 세밀한 것 순으로 적용(클래스 같은 상위 경계를 먼저 시도하고 청크가 여전히 크면 메서드 경계, 그다음 더 작은 블록으로 폴백) → 파일 하나가 파일 레벨·함수 레벨 등 여러 특이도의 임베딩을 생성. CocoIndex가 동기화 메타데이터를 Postgres에 추적해 커밋마다 바뀐 청크만 재임베딩 — 동기화 상태와 임베딩 스토어가 같은 DB에 사는 게 특히 잘 맞았다
  • 커스텀 소스는 플러그인 스크립트: 자기 DB를 이미 가진 팀이 데이터를 옮기지 않고 같은 쿼리 표면을 원했다. 팀이 자기 시스템을 읽어 embeddings 테이블 모양의 row를 뱉는 작은 Python 모듈을 PR로 올리면 된다. 같은 스키마로 공유 DB에 쓰기만 하면 나머지 스택은 변경 없이 동작한다
  • Planning → 팬아웃 → 정규화 → synthesis: 쿼리마다 짧은 플래닝 패스에서 LLM이 어떤 툴·데이터 소스가 중요할지 결정. 툴은 subsystem_index(파일별 LLM 요약), search(통합 벡터 파이프라인), search_slack, search_code(ripgrep), recent_prs, who_knows(주제별 입증된 전문성을 가진 사람). 플래너는 무엇이 인덱싱되어 있는지에 대한 컴팩트한 설명(어떤 프로젝트가 있는지, 각 프로젝트에 어떤 소스가 있는지, 각 소스가 무엇에 답하기 좋은지) 위에서 동작
  • Reranking: 문서는 다른 질문에 답하면서 단지 쿼리와 어휘를 공유한다는 이유로 상위에 뜰 수 있다. 리랭킹 전에 서로 호환되지 않는 결과 리스트들을 RRF(reciprocal rank fusion) 로 합친다 — 문서마다 등장한 각 리스트에 대해 weight / (60 + rank)를 더함(기본 가중치 1.0, 스무딩 상수 60). 스무딩 상수가 단일한 강한 투표보다 합의를 더 중요하게 만든다 — 여러 리트리버에서 상위에 뜬 문서가 하나에서만 1위인 문서를 이길 수 있다. 그 다음 중복 청크를 소스 단위로 병합하고 파일당 기여 결과 수를 캡해 더 다양한 top 20을 만들고, 작은 리랭커 모델이 0~10점을 매겨 top 10을 남긴다
    • 랭킹이 끝난 뒤 승자에게 컨텍스트를 되돌려준다 — 위키 섹션이 매치되면 인접한 두 섹션을 끌어와 청킹이 분리해버린 제목·전제조건·주의사항을 잃지 않게. 중요한 맥락이 빠진 외로운 문단 대신 완결된 스니펫을 준다
  • MCP vs Web UI — 오케스트레이션을 누가 소유하는가:
    • MCP — 검색 빌딩 블록을 하나의 “이 질문에 답해줘” 엔드포인트 뒤에 숨기지 않고 직접 툴로 노출. 툴은 의도적으로 단순하고 가능한 한 LLM-free해서 클라이언트가 빠르고 싸게 질의할 수 있다. 입출력은 좁고 구조화되고 안정적. Claude Code 같은 MCP 호환 에이전트가 오케스트레이션 엔진이 된다 — 어떤 툴을 어떤 순서로 부를지, 결과를 어떻게 조립할지 결정. 검색 레이어 자체는 요청을 서빙하기 위해 그 LLM 결정에 의존하지 않는다
    • Web UI — 같은 툴이 존재하지만 완전한 쿼리 파이프라인에 연결. UI 에이전트가 planner(어떤 툴을 부를지) → executor(병렬 팬아웃 후 점수·최신성·소스 힌트를 담은 공유 evidence 스키마로 정규화) → synthesis(인용·주의사항·크로스소스 종합을 포함한 답변)를 소유
  • Projects — “모든 곳에서 모든 것을 검색”이 급속히 무용해졌다: 컴파일러 팀 엔지니어는 결과에 인프라 런북이 나오길 원하지 않는다. project = 이름 붙은 데이터 소스 묶음(특정 Slack 채널, 코드 리포, 사내 DB, 문서 공간). 의도적으로 가볍게 만들어 같은 데이터 소스(공유 인시던트 채널, 중앙 플랫폼 리포)를 복제하지 않고 여러 프로젝트가 참조할 수 있다. 온보딩 때 기본 프로젝트를 고르게 해 사용자 프로필에 저장하고 쿼리를 자동 스코핑 → 신규 엔지니어가 어떤 Slack 채널·리포·문서 공간이 중요한지 먼저 배우지 않고도 고신호 답변을 받는다

주요 수치 / 사실

  • 직원들이 매일 15,000개 이상의 질문을 던지고, 출시 3개월 만에 사내에서 가장 널리 채택된 도구 중 하나가 됨. 사람·자동화·에이전트가 모두 사용
  • 일부 사내 리포지토리는 40GB 이상
  • burst 임계 기준: IDF ≥ 4.0 희귀 토큰, 결합 200자 이상, 리액션 존재
  • RRF 공식: weight / (60 + rank), 기본 weight 1.0, 스무딩 상수 60
  • 참고 문헌으로 HNSW, Anthropic Contextual Retrieval, RRF(SIGIR 2009), Search-o1, Code Execution with MCP, Lost in the Middle, Cursor의 semantic search 글을 인용

관련 위키


Source: 원문 보기