본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 16. 05:55

내 북마크 엔진이 조각난 정보(Chunks)만 반환하기에, 답변을 생성하는 엔드포인트를 하나 추가했다

요약

하이브리드 검색과 재순위화 과정을 거친 검색 엔진에 Gemma 4 MoE를 활용한 답변 생성 엔드포인트를 추가하여 정보를 종합하는 과정을 구현했습니다. 사고 모델의 특성을 고려해 토큰 예산을 조정함으로써 검색된 청크를 바탕으로 정확한 답변을 생성하도록 최적화했습니다.

핵심 포인트

  • 하이브리드 검색과 크로스 인코더 재순위화 파이프라인 구축
  • Gemma 4 MoE를 활용한 검색 결과의 자동 종합(Synthesis) 기능 구현
  • 사고 모델의 추론 토큰 소모를 고려한 max_tokens 설정 최적화
  • 저장된 문서와 생성된 성찰(Reflection) 데이터를 결합한 복리 효과 구현

검색은 당신이 직접 읽어야 하는 것들을 반환합니다. 답변 엔진(Answer engine)은 당신을 대신해 그것들을 읽어줍니다.

나는 5만 개의 저장된 트윗을 기반으로 검색 엔진을 구축했습니다. 질문을 던지면 하이브리드 검색 (Hybrid retrieval; BM25 키워드 검색과 벡터 검색의 결합)을 통해 찾아낸 가장 관련성 높은 5개의 청크(Chunks)를 반환하며, 이는 크로스 인코더(Cross-encoder)에 의해 재순위화(Reranked)됩니다. 또한 Gemma 4 MoE 레이어가 백그라운드에서 이미 실행되며, 저장된 문서들이 서로 어떻게 연결되는지에 대한 자체적인 성찰(Reflections)을 작성합니다. 당신은 순위가 매겨진 청크들을 돌려받습니다. 그런 다음 당신이 그것들을 읽고 종합(Synthesise)해야 합니다.

그 마지막 단계가 나를 괴롭혔습니다. 모델은 성찰을 생성할 때 이미 종합을 수행합니다. 검색은 이미 작동하고 있습니다. 유일하게 빠진 조각은 쿼리 시점에 이들을 서로 연결하는 것이었습니다.

그래서 나는 POST /search?mode=answer를 추가했습니다.

작동 방식

검색 파이프라인은 동일합니다. 재순위화된 상위 5개의 청크를 가져옵니다. 그다음 청크를 가공되지 않은 상태로 반환하는 대신, Gemma 4 MoE가 이를 읽고 당신이 저장한 내용에 근거하여 직접적인 답변을 생성합니다.

const prompt =
  `Answer the question below using only the sources provided. ` +
  `If the sources don't contain the answer, say so directly.\n\n` +
...

max_tokens: 512 설정 시 빈 답변이 반환되었습니다. Gemma 4는 사고 모델(Thinking model)입니다. 즉, 출력을 생성하기 전에 내부적인 추론(Internal reasoning)에 토큰 예산을 소모합니다. max_tokens: 2048로 설정하니 해결되었습니다. 성찰 엔진(Reflection engine)도 동일한 문제에 부딪혔고, 동일한 방식으로 해결했습니다.

결과물

라이브 인덱스를 대상으로 세 가지 쿼리를 실행했습니다.

"일관성과 매일 나타나는 것에 대해 사람들이 뭐라고 하나요?"

"일관성이 승리합니다. 어떤 사람들은 옳은 말들을 늘어놓지만 결코 자신의 말에 부합하지 못하는 반면, 다른 이들은 한마디 말도 없이 모든 것을 올바르게 해냅니다."

두 개의 트윗이 깔끔하게 종합되었습니다. 인덱스 외부에서 환각(Hallucination)된 내용은 없었습니다.

"돈과 부를 쌓는 것에 대해 사람들이 뭐라고 하나요?"

"논의에는 나이라(Naira) 가치 하락에 대한 좌절감, 구매력 감소, 그리고 금융 전문 지식 및 소셜 미디어 수익에 관한 논쟁이 포함됩니다. 어떤 이들은 특정 수준의 정기적인 금액만 있으면 생활을 유지하는 데 충분하며, 그 이상의 금액은 불필요하다고 제안합니다. 부를 쌓는 것에 대해서는, 가치를 제공해야 하며 수요와 공급 관계에서 공급(Supply)의 역할을 해야 한다고 제안합니다."

이 질문은 가공되지 않은 트윗(raw tweets)과 함께 성찰 문서(reflection document)를 끌어올렸습니다. 이는 엔진이 CBEX 관련 트윗으로부터 이미 생성하여 인덱스(Index)에 다시 저장해 두었던 reflection 유형의 엔트리였습니다. 답변은 가공되지 않은 저장된 콘텐츠와 이전에 생성된 통찰(Insight)이라는 두 계층 모두에서 정보를 가져왔습니다. 이것이 바로 시스템이 스스로 복리(Compounding)를 일으키는 방식입니다.

"프로그래밍을 배우는 가장 좋은 방법은 무엇인가요?"

"구글에서 검색하고, 영상을 찾고, 코딩하면서 시청하고, 반복하세요."

빈약합니다. 검색(Retrieval) 결과가 "프로그래밍을 독학하셨나요?", "코딩 학습 팁 🧵"와 같은 표면적인 트윗들과 매칭되었습니다. 실질적인 내용이 아니었습니다. 모델은 받은 정보 그대로 정직하게 답변했습니다. 답변은 기술적으로는 근거가 있습니다. 다만 유용하지 않을 뿐입니다.

솔직한 평가

실질적인 저장 콘텐츠가 있는 주제에 대해서는 잘 작동합니다. 위 프로그래밍 질문처럼 표면적인 매칭이 일어나는 경우에는 빈약한 답변을 반환합니다. 합성(Synthesis)은 제 역할을 다했습니다. 단지 인덱스에 아직 깊이(Depth)가 없을 뿐입니다.

대부분의 쿼리에 대한 검색 점수(Retrieval scores)는 낮습니다 (0.006–0.013 범위). 이는 인덱스를 구축할 때 사용한 임베딩 모델(Embedding model)인 bge-small(384 차원) 때문입니다. 이는 정밀도보다 속도에 초점을 맞춘 예전 기본 모델입니다. 임베딩(Embeddings)은 엔진이 텍스트를 비교 가능한 숫자로 변환하는 방식입니다. 차원(Dimensions)이 더 많을수록 의미의 미묘한 차이를 포착할 수 있는 공간이 더 넓어집니다. 인덱스는 5만 개의 트윗을 모두 다시 수집(Re-ingesting)하지 않고서는 모델을 바꿀 수 없습니다. 제가 결국 qwen3-0.6b(1024 차원)로 마이그레이션하게 되면, 검색 정밀도가 먼저 향상되고 그에 따라 답변 품질이 뒤따라 개선될 것입니다.

현재로서는: 엔드포인트는 작동합니다. 인덱스에 깊이가 있는 주제에 대해서는 강력하며, 그렇지 않은 주제에 대해서는 정직합니다.

이것이 아닌 것

모든 답변과 함께 출처(Sources)가 함께 반환됩니다. 모델을 검증하고, 점수(Scores)를 확인하며, 원본 청크(Chunks)를 읽어보세요. 그리고 이것은 오픈 웹(Open web)에 대한 검색이 아닙니다. 모든 답변은 당신이 저장하기로 선택한 무언가로 거슬러 올라갑니다. 프롬프트(Prompt)가 인덱스(Index) 외부의 정보를 전혀 제공하지 않기 때문에, 모델은 인덱스 외부의 정보로 환각(Hallucination)을 일으킬 수 없습니다. 근거 설정(Grounding)은 단순히 지시된 것이 아니라 구조적입니다.

다음 단계

현재 답변 품질의 한계는 검색(Retrieval) 품질에 달려 있습니다. 다음 단계는 간극 탐지(Gap detection)입니다. 이는 인덱스 내에서 가장 지속적으로 답변되지 않은 세 가지 질문을 표면화하여, 인덱스가 어느 부분에서 깊이가 있고 어느 부분에서 부족한지를 보여주는 주간 점검 프로세스입니다. 이 엔드포인트(Endpoint)는 매 쿼리마다 이러한 간극을 실시간으로 가시화합니다. 간극 탐지는 매주 이를 체계적으로 매핑할 것입니다.

엔드포인트가 활성화되었습니다. 쿼리를 보내보세요:

POST /search?mode=answer
{ "query": "여기에 질문을 입력하세요" }

답변과 함께 출처 청크(Source chunks)가 반환됩니다. 답변을 합성(Synthesise)하는 데 사용된 모델은 @cf/google/gemma-4-26b-a4b-it입니다. 동일한 워커(Worker), 동일한 월 $5입니다.

인덱스에는 2016년까지 거슬러 올라가는 5만 개의 저장된 트윗이 있습니다. 당신이 받는 결과는 그 범위 내로 제한됩니다. Google은 인터넷을 검색하지만, 이것은 당신이 보관할 가치가 있다고 결정한 것을 검색합니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0