텍스트 검색(Text Search)이란 무엇인가요?

텍스트 검색(Text Search)이란 무엇인가요? (Preview)

LLM은 고정된 훈련 데이터셋으로 학습해요. 그래서 사용자의 질문에 정확히 답하려면 추가 데이터가 필요할 때가 있어요. Semantic Kernel은 LLM을 호출할 때 검색을 통합할 수 있는 능력을 제공해요.

이렇게 LLM에 추가 컨텍스트를 제공하는 과정을 RAG(Retrieval-Augmented Generation, 검색 증강 생성) 라고 불러요. RAG는 보통 현재 사용자 질문과 관련된 추가 데이터를 검색해, 그 데이터를 LLM에 보내는 프롬프트에 덧붙이는 방식으로 동작해요. 그러면 LLM이 자기 훈련 지식과 추가 컨텍스트를 함께 써서 더 정확한 답을 만들 수 있어요.

이게 중요해지는 대표적인 경우는 질문이 LLM 훈련 데이터에 없는 최신 정보와 관련됐을 때예요. 적절한 텍스트 검색을 수행하고 결과를 사용자 질문과 함께 전달하면, 훨씬 정확한 응답을 얻을 수 있어요.

Semantic Kernel의 텍스트 검색은 웹 검색이나 벡터 데이터베이스를 이용해 검색하고 앱에 RAG를 쉽게 추가할 수 있게 해 줘요.

텍스트 검색과 벡터 검색의 차이

Semantic Kernel은 서로 다른 추상화 수준에서 데이터 검색 API를 제공해요. 여기서 두 검색의 위치 차이가 갈려요.

텍스트 검색은 스택에서 높은 수준에 있어요. 입력이 텍스트이고 기본적인 필터링을 지원하죠. 여러 종류의 출력을 지원하는데, 단순한 문자열만 반환하는 것도 가능해요. 덕분에 웹 검색 엔진과 벡터 스토어 모두를 텍스트 검색 구현으로 넣을 수 있어요. 텍스트 검색의 주요 목표는 채팅 완성에 플러그인으로 노출될 수 있는 단순한 인터페이스를 제공하는 거예요.

벡터 검색은 스택에서 더 낮은 수준에 위치해요. 입력이 벡터이고 기본 필터링에 더해, 저장소에서 입력 벡터와 비교할 벡터를 고를 수도 있어요. 반환 값은 저장소의 데이터를 담은 데이터 모델이에요.

벡터 스토어로 RAG를 하고 싶다면 텍스트 검색과 벡터 검색을 함께 쓰는 게 자연스러워요. 벡터 검색을 지원하는 벡터 스토어 컬렉션을 텍스트 검색으로 감싸고, 그 텍스트 검색을 채팅 완성에 플러그인으로 노출하는 방식이죠. Semantic Kernel은 이걸 아웃-오브-더-박스로 쉽게 지원해요.

웹 텍스트 검색으로 RAG 구현하기

Bing이나 Google 검색을 이용해 웹 검색을 수행하는 예시를 볼게요. 검색 결과에는 웹페이지 내용을 설명하는 텍스트 스니펫이 담겨요. 다만 이는 제한된 컨텍스트, 즉 웹페이지 내용의 일부일 뿐이고 정보 출처로의 링크는 없어요.

먼저 Bing 텍스트 검색 인스턴스를 만들어 검색을 수행해요.

using Microsoft.SemanticKernel.Data;
using Microsoft.SemanticKernel.Plugins.Web.Bing;

// Bing 검색을 이용한 ITextSearch 인스턴스 생성
var textSearch = new BingTextSearch(apiKey: "<YOUR Bing API Key>");

var query = "What is the Semantic Kernel?";

// 검색 실행 및 결과 반환
KernelSearchResults<string> searchResults = await textSearch.SearchAsync(query, new() { Top = 4 });
await foreach (string result in searchResults.Results)
{
    Console.WriteLine(result);
}

Google은 GoogleTextSearch(searchEngineId: ..., apiKey: ...)로 만들 수 있어요.

검색 결과로 프롬프트에 맥락 더하기

이제 웹 텍스트 검색에서 플러그인을 만들어 검색 결과를 프롬프트에 추가해 볼게요. 흐름은 이렇습니다.

  1. OpenAI 서비스를 등록한 Kernel을 만든다. gpt-4o 모델을 호출할 거예요.
  2. 텍스트 검색 인스턴스를 만든다.
  3. 텍스트 검색 인스턴스에서 Search 플러그인을 만든다.
  4. 검색 플러그인을 질문과 함께 호출해, 검색 결과와 원래 질문을 프롬프트에 포함하는 프롬프트 템플릿을 만든다.
  5. 프롬프트를 호출해 응답을 보여준다.
using Microsoft.SemanticKernel.Data;
using Microsoft.SemanticKernel.Plugins.Web.Bing;

// OpenAI 채팅 완성 커널 생성
IKernelBuilder kernelBuilder = Kernel.CreateBuilder();
kernelBuilder.AddOpenAIChatCompletion(
        modelId: "gpt-4o",
        apiKey: "<YOUR OpenAI API Key>");
Kernel kernel = kernelBuilder.Build();

// Bing 검색을 이용한 텍스트 검색 생성
var textSearch = new BingTextSearch(apiKey: "<YOUR Bing API Key>");

// 텍스트 검색으로 검색 플러그인을 만들어 커널에 추가
var searchPlugin = textSearch.CreateWithSearch("SearchPlugin");
kernel.Plugins.Add(searchPlugin);

// 프롬프트를 호출해 텍스트 검색 플러그인으로 근거(grounding) 정보 제공
var query = "What is the Semantic Kernel?";
var prompt = "{{SearchPlugin.Search $query}}. {{$query}}";
KernelArguments arguments = new() { { "query", query } };
Console.WriteLine(await kernel.InvokePromptAsync(prompt, arguments));

이렇게 하면 모델이 웹 검색에서 얻은 최신 정보에 근거한 응답을 보여줘요. 다만 이 샘플에는 세 가지 한계가 있어요. 첫째, 근거 컨텍스트로 쓰인 웹페이지를 보여주는 인용(citation)이 응답에 없어요. 둘째, 어떤 웹사이트의 데이터든 포함 되기 때문에 신뢰할 만한 사이트로 제한하는 게 더 좋아요. 셋째, 각 웹페이지의 스니펫만 근거로 쓰여서 정확한 답에 필요한 데이터가 스니펫에 없을 수 있어요. 이 문제들의 해결법은 텍스트 검색 플러그인 문서에서 다룹니다.

출처: https://learn.microsoft.com/en-us/semantic-kernel/concepts/text-search/