Azure AI 검색의 RAG(검색 보강 세대)

RAG(검색 확대 생성)는 접지 데이터를 제공하는 정보 검색 시스템을 추가하여 ChatGPT와 같은 LLM(대규모 언어 모델)의 기능을 보강하는 아키텍처입니다. 정보 검색 시스템을 추가하면 응답을 작성할 때 LLM에서 사용하는 접지 데이터를 제어할 수 있습니다. 엔터프라이즈 솔루션의 경우 RAG 아키텍처는 해당 콘텐츠에 대한 모델을 포함하는 경우 생성 AI를 벡터화된 문서 및 이미지에서 가져온 엔터프라이즈 콘텐츠 및 기타 데이터 형식으로 제한할 수 있음을 의미합니다.

LLM에 대한 입력을 결정하므로 사용할 정보 검색 시스템에 대한 결정이 중요합니다. 정보 검색 시스템은 다음을 제공해야 합니다.

  • 필요한 빈도로 모든 콘텐츠에 대해 대규모로 로드 및 새로 고침하는 인덱싱 전략입니다.

  • 쿼리 기능 및 관련성 튜닝 시스템은 LLM 입력의 토큰 길이 요구 사항을 충족하는 데 필요한 짧은 형식으로 관련 결과를 반환해야 합니다.

  • 데이터 및 작업 모두에 대한 보안, 글로벌 도달률 및 안정성.

  • 인덱싱을 위한 포함 모델 및 검색을 위한 채팅 모델 또는 언어 이해 모델과의 통합

Azure AI 검색은 RAG 아키텍처에서 정보 검색을 위한 검증된 솔루션입니다. Azure 클라우드의 인프라 및 보안과 함께 인덱싱 및 쿼리 기능을 제공합니다. 코드 및 기타 구성 요소를 통해 독점 콘텐츠에 대한 생성 AI의 모든 요소를 포함하는 포괄적인 RAG 솔루션을 디자인할 수 있습니다.

참고 항목

부조종사 및 RAG 개념이 새로운가요? 생성 AI 앱에 대한 벡터 검색 및 최신 상태 검색을 확인하세요.

Microsoft에는 RAG 솔루션에서 Azure AI 검색을 사용하기 위한 몇 가지 기본 제공 구현이 있습니다.

큐레이팅된 접근 방식을 사용하면 간단하게 시작할 수 있지만 아키텍처를 보다 잘 제어하려면 사용자 지정 솔루션이 필요합니다. 이러한 템플릿은 다음에서 엔드 투 엔드 솔루션을 만듭니다.

이 문서의 나머지 부분에서는 Azure AI 검색이 사용자 지정 RAG 솔루션에 어떻게 적합한지 살펴봅니다.

패턴에 대한 대략적인 요약은 다음과 같습니다.

  • 사용자 질문 또는 요청(프롬프트)으로 시작합니다.
  • Azure AI 검색로 보내 관련 정보를 찾습니다.
  • 순위가 가장 높은 검색 결과를 LLM에 보냅니다.
  • LLM의 자연어 이해 및 추론 기능을 사용하여 초기 프롬프트에 대한 응답을 생성합니다.

Azure AI 검색은 LLM 프롬프트에 입력을 제공하지만 모델을 학습하지는 않습니다. RAG 아키텍처에는 추가 학습이 없습니다. LLM은 공용 데이터를 사용하여 미리 학습되지만 리트리버의 정보로 보강되는 응답을 생성합니다.

Azure AI 검색을 포함하는 RAG 패턴에는 다음 그림에 표시된 요소가 있습니다.

검색 및 ChatGPT를 사용한 정보 검색 아키텍처 다이어그램.

  • 사용자 환경을 위한 앱 UX(웹앱)
  • 앱 서버 또는 오케스트레이터(통합 및 조정 계층)
  • Azure AI 검색(정보 검색 시스템)
  • Azure OpenAI(생성 AI용 LLM)

웹앱은 프레젠테이션, 컨텍스트 및 사용자 상호 작용을 제공하는 사용자 환경을 제공합니다. 사용자의 질문 또는 프롬프트는 여기에서 시작합니다. 입력은 통합 계층을 통과하여 먼저 정보 검색으로 이동하여 검색 결과를 가져올 뿐만 아니라 LLM으로 이동하여 컨텍스트와 의도를 설정합니다.

앱 서버 또는 오케스트레이터는 정보 검색과 LLM 간의 핸드오프를 조정하는 통합 코드입니다. 한 가지 옵션은 LangChain을 사용하여 워크플로를 조정하는 것입니다. LangChain은 Azure AI 검색과 통합되어 Azure AI 검색을 워크플로에 검색자로 쉽게 포함할 수 있습니다. 의미 체계 커널은 또 다른 옵션입니다.

정보 검색 시스템은 검색 가능한 인덱스, 쿼리 논리 및 페이로드(쿼리 응답)를 제공합니다. 검색 인덱스에는 벡터 또는 비벡터 콘텐츠가 포함될 수 있습니다. 대부분의 샘플 및 데모에는 벡터 필드가 포함되어 있지만 요구 사항은 아닙니다. 쿼리는 키워드(또는 용어) 및 벡터 쿼리를 처리할 수 있는 Azure AI 검색의 기존 검색 엔진을 사용하여 실행됩니다. 인덱스는 사용자가 정의한 스키마를 기반으로 미리 만들어지고 파일, 데이터베이스 또는 스토리지에서 제공되는 콘텐츠와 함께 로드됩니다.

LLM은 원래 프롬프트와 Azure AI 검색의 결과를 받습니다. LLM은 결과를 분석하고 응답을 작성합니다. LLM이 ChatGPT인 경우 사용자 상호 작용은 앞뒤로 대화일 수 있습니다. Davinci를 사용하는 경우 프롬프트가 완전히 구성된 답변일 수 있습니다. Azure 솔루션은 Azure OpenAI를 사용할 가능성이 높지만 이 특정 서비스에 대한 하드 종속성은 없습니다.

Azure AI 검색은 프롬프트 흐름 또는 채팅 유지를 위한 네이티브 LLM 통합을 제공하지 않으므로 오케스트레이션 및 상태를 처리하는 코드를 작성해야 합니다. 데모 원본(Azure-Samples/azure-search-openai-demo)에서 전체 솔루션에 수반되는 청사진을 검토할 수 있습니다. 또한 LLM과 통합되는 RAG 기반 Azure AI 검색 솔루션을 만들려면 Azure AI 스튜디오 또는 Azure OpenAI Studio를 사용하는 것이 좋습니다.

Azure AI 검색에서 검색 가능한 모든 콘텐츠는 검색 서비스에 호스트되는 검색 인덱스로 저장됩니다. 검색 인덱스는 응답 시간이 밀리초인 빠른 쿼리를 위해 설계되었기 때문에 해당 목표를 지원하기 위해 내부 데이터 구조가 존재합니다. 이를 위해 검색 인덱스는 전체 PDF 또는 이미지와 같은 전체 콘텐츠 파일이 아닌 인덱싱된 콘텐츠를 저장합니다. 내부적으로 데이터 구조에는 토큰화된 텍스트의 반전된 인덱스, 포함을 위한 벡터 인덱스 및 축자 일치가 필요한 경우(예: 필터, 유사 항목 검색, 정규식 쿼리) 변경되지 않은 텍스트가 포함됩니다.

RAG 솔루션에 대한 데이터를 설정할 때 Azure AI 검색에서 인덱스 만들기 및 로드 기능을 사용합니다. 인덱스로는 원본 콘텐츠를 복제하거나 나타내는 필드가 포함됩니다. 인덱스 필드는 단순 전송(원본 문서의 제목 또는 설명이 검색 인덱스의 제목 또는 설명이 됨)이거나, 이미지의 표현이나 텍스트 설명을 생성하는 벡터화 또는 기술 처리와 같은 외부 프로세스의 출력을 필드에 포함할 수 있습니다.

검색하려는 콘텐츠 종류를 알고 있으므로 각 콘텐츠 형식에 적용할 수 있는 인덱싱 기능을 고려합니다.

내용 유형 인덱싱됨 기능
text 토큰, 변환되지 않은 텍스트 인덱서는 Azure Storage 및 Cosmos DB와 같은 다른 Azure 리소스에서 일반 텍스트를 가져올 수 있습니다. JSON 콘텐츠를 인덱스로 푸시할 수도 있습니다. 진행 중인 텍스트를 수정하려면 분석기정규화를 사용하여 인덱싱하는 동안 어휘 처리를 추가합니다. 동의어 맵은 원본 문서에 쿼리에 사용될 수 있는 용어가 누락된 경우에 유용합니다.
text 벡터 1 텍스트를 외부적으로 청크 및 벡터화한 다음 인덱스 내의 벡터 필드로 인덱싱할 수 있습니다.
이미지 토큰, 변경되지 않은 텍스트 2 OCR 및 이미지 분석을 위한 기술은 텍스트 인식 또는 이미지 특성에 대한 이미지를 처리할 수 있습니다. 이미지 정보는 검색 가능한 텍스트로 변환되고 인덱스로 추가됩니다. 기술에는 인덱서 요구 사항이 있습니다.
이미지 벡터 1 이미지는 이미지 콘텐츠의 수학 표현을 위해 외부에서 벡터화한 다음 인덱스의 벡터 필드로 인덱싱할 수 있습니다. OpenAI CLIP과 같은 오픈 소스 모델을 사용하여 텍스트와 이미지를 동일한 포함 공간에 벡터화할 수 있습니다.

1 일반적으로 사용 가능한 벡터 지원 기능을 사용하려면 데이터 청크 및 벡터화를 위해 다른 라이브러리 또는 모델을 호출해야 합니다. 그러나 통합 벡터화(미리 보기)는 이러한 단계를 포함합니다. 두 방법을 모두 보여주는 코드 샘플은 azure-search-vectors 리포지토리를 참조하세요.

2기술AI 보강을 기본적으로 지원합니다. OCR 및 이미지 분석의 경우 인덱싱 파이프라인은 Azure AI Vision API에 대한 내부 호출을 수행합니다. 이러한 기술은 처리를 위해 추출된 이미지를 Azure AI에 전달하고, Azure AI 검색에서 인덱싱된 텍스트로 출력을 받습니다.

벡터는 콘텐츠가 수학 표현으로 보편적으로 표현되기 때문에 서로 다른 콘텐츠(여러 파일 형식 및 언어)에 가장 적합한 숙박 시설을 제공합니다. 벡터는 벡터 쿼리와 가장 유사한 좌표에서 일치하는 유사성 검색도 지원합니다. 토큰화된 용어와 일치하는 키워드 검색(또는 용어 검색)에 비해 유사성 검색은 더 미묘합니다. 콘텐츠 또는 쿼리에 모호성 또는 해석 요구 사항이 있는 경우 더 나은 선택입니다.

데이터가 검색 인덱스로 저장되면 Azure AI 검색의 쿼리 기능을 사용하여 콘텐츠를 검색합니다.

비 RAG 패턴에서 쿼리는 검색 클라이언트에서 왕복합니다. 쿼리가 제출되고, 검색 엔진에서 실행되며, 응답이 클라이언트 애플리케이션에 반환됩니다. 응답 또는 검색 결과는 인덱스의 축자 콘텐츠로만 구성됩니다.

RAG 패턴에서 쿼리 및 응답은 검색 엔진과 LLM 간에 조정됩니다. 사용자의 질문 또는 쿼리는 검색 엔진과 LLM에 프롬프트로 전달됩니다. 검색 결과는 검색 엔진에서 돌아와 LLM으로 리디렉션됩니다. 사용자에게 반환되는 응답은 LLM의 합계 또는 답변인 생성 AI입니다.

Azure AI 검색에는 의미 체계 또는 벡터 검색이 아닌 새 답변을 구성하는 쿼리 유형이 없습니다. LLM만 생성 AI를 제공합니다. 쿼리를 작성하는 데 사용되는 Azure AI 검색의 기능은 다음과 같습니다.

쿼리 기능 목적 사용하는 이유
단순 또는 전체 Lucene 구문 텍스트 및 비벡터 숫자 콘텐츠에 대한 쿼리 실행 전체 텍스트 검색은 유사한 일치 항목보다는 정확한 일치 항목에 가장 적합합니다. 전체 텍스트 검색 쿼리는 BM25 알고리즘을 사용하여 순위가 매겨지고 점수 매기기 프로필을 통한 관련성 튜닝을 지원합니다. 필터 및 패싯도 지원합니다.
필터패싯 텍스트 또는 숫자(비벡터) 필드에만 적용됩니다. 포함 또는 제외 조건에 따라 검색 노출 영역을 줄입니다. 쿼리에 정밀도를 추가합니다.
의미 체계 순위 의미 체계 모델을 사용하여 BM25 결과 집합의 순위를 다시 지정합니다. LLM 입력으로 유용한 짧은 형식 캡션 및 답변을 생성합니다. 점수 매기기 프로필보다 쉽고 콘텐츠에 따라 관련성 튜닝을 위한 보다 안정적인 기술입니다.
벡터 검색 쿼리 문자열이 하나 이상의 벡터인 유사성 검색을 위해 벡터 필드에 대한 쿼리 실행 벡터는 모든 형식의 콘텐츠를 모든 언어로 나타낼 수 있습니다.
하이브리드 검색 위의 쿼리 기술을 모두 결합합니다. 벡터 및 비벡터 쿼리는 병렬로 실행되며 통합된 결과 집합에 반환됩니다. 정밀도 및 재현율에서 가장 큰 이득은 하이브리드 쿼리를 통해서입니다.

쿼리 응답 구조화

쿼리의 응답은 LLM에 대한 입력을 제공하므로 검색 결과의 품질이 성공에 매우 중요합니다. 결과는 테이블 형식 행 집합입니다. 결과의 컴퍼지션 또는 구조는 다음에 따라 달라집니다.

  • 응답에 포함되는 인덱스의 부분을 결정하는 필드.
  • 인덱스의 일치 항목을 나타내는 행.

특성이 "검색 가능"인 경우 검색 결과에 필드가 표시됩니다. 인덱스 스키마의 필드 정의에는 특성이 있으며 응답에 필드가 사용되는지 여부를 결정합니다. "검색 가능한" 필드만 전체 텍스트 또는 벡터 쿼리 결과에 반환됩니다. 기본적으로 "검색 가능한" 모든 필드가 반환되지만 "선택"을 사용하여 하위 집합을 지정할 수 있습니다. "검색 가능" 외에 필드에는 제한이 없습니다. 필드는 길이 또는 형식일 수 있습니다. 길이와 관련하여 Azure AI 검색에는 최대 필드 길이 제한이 없지만 API 요청의 크기에는 제한이 있습니다.

행은 쿼리와 일치하며 관련성, 유사성 또는 둘 다에 따라 순위가 매겨집니다. 기본적으로 결과는 전체 텍스트 검색의 상위 50개 일치 항목 또는 벡터 검색의 k 가장 인접한 일치 항목으로 제한됩니다. 기본값을 변경하여 최대 1,000개의 문서까지 제한을 늘리거나 줄일 수 있습니다. 위쪽 및 페이징 매개 변수를 건너뛰어 결과를 일련의 페이징된 결과로 검색할 수도 있습니다.

관련성을 기준으로 순위 지정

복잡한 프로세스, 많은 양의 데이터 및 밀리초 응답에 대한 기대치를 사용하는 경우 각 단계에서 가치를 추가하고 최종 결과의 품질을 향상시키는 것이 중요합니다. 정보 검색 쪽에서 관련성 튜닝은 LLM에 전송된 결과의 품질을 향상시키는 작업입니다. 가장 관련성이 있거나 가장 유사한 문서만 결과에 포함되어야 합니다.

관련성은 키워드(비벡터) 검색 및 하이브리드 쿼리(비벡터 필드)에 적용됩니다. Azure AI 검색에서는 유사성 검색 및 벡터 쿼리에 대한 관련성 튜닝이 없습니다. BM25 순위는 전체 텍스트 검색에 대한 순위 알고리즘입니다.

관련성 튜닝은 BM25 순위를 향상시키는 기능을 통해 지원됩니다. 이 접근 방식은 다음과 같습니다.

  • 일치 항목이 특정 검색 필드 또는 다른 조건에 있는 경우 검색 점수를 높이는 점수 매기기 프로필입니다.
  • Bing의 의미 체계 모델을 사용하여 BM25 결과 집합의 순위를 다시 매기는 의미 체계 순위는 원래 쿼리에 더 적합한 의미 체계를 위해 결과를 다시 정렬합니다.

비교 및 벤치마크 테스트에서 텍스트 및 벡터 필드가 있는 하이브리드 쿼리는 BM25 순위 결과에 대한 의미 체계 순위로 보완되어 가장 관련성이 높은 결과를 생성합니다.

RAG 시나리오에 대한 Azure AI 검색 쿼리의 예제 코드

다음 코드는 데모 사이트에서 retrievethenread.py 파일에서 복사 됩니다. 하이브리드 쿼리 검색 결과에서 LLM에 대한 content를 생성합니다. 더 간단한 쿼리를 작성할 수 있지만 이 예제는 의미 체계 재전송 및 맞춤법 검사를 사용하여 벡터 검색 및 키워드 검색을 포함합니다. 데모에서 이 쿼리는 초기 콘텐츠를 가져오는 데 사용됩니다.

# Use semantic ranker if requested and if retrieval mode is text or hybrid (vectors + text)
if overrides.get("semantic_ranker") and has_text:
    r = await self.search_client.search(query_text,
                                  filter=filter,
                                  query_type=QueryType.SEMANTIC,
                                  query_language="en-us",
                                  query_speller="lexicon",
                                  semantic_configuration_name="default",
                                  top=top,
                                  query_caption="extractive|highlight-false" if use_semantic_captions else None,
                                  vector=query_vector,
                                  top_k=50 if query_vector else None,
                                  vector_fields="embedding" if query_vector else None)
else:
    r = await self.search_client.search(query_text,
                                  filter=filter,
                                  top=top,
                                  vector=query_vector,
                                  top_k=50 if query_vector else None,
                                  vector_fields="embedding" if query_vector else None)
if use_semantic_captions:
    results = [doc[self.sourcepage_field] + ": " + nonewlines(" . ".join([c.text for c in doc['@search.captions']])) async for doc in r]
else:
    results = [doc[self.sourcepage_field] + ": " + nonewlines(doc[self.content_field]) async for doc in r]
content = "\n".join(results)

통합 코드 및 LLM

Azure AI 검색을 포함하는 RAG 솔루션에는 완전한 솔루션을 만들려면 다른 구성 요소와 코드가 필요합니다. 이전 섹션에서는 Azure AI 검색을 통한 정보 검색과 검색 가능한 콘텐츠를 만들고 쿼리하는 데 사용되는 기능에 대해 설명한 반면, 이 섹션에서는 LLM 통합 및 상호 작용을 소개합니다.

데모 리포지토리의 Notebook은 검색 결과를 LLM에 전달하는 패턴을 표시하기 때문에 좋은 시작점입니다. RAG 솔루션의 코드 대부분은 LLM에 대한 호출로 구성되므로 이 문서의 범위를 벗어나는 API의 작동 방식을 이해해야 합니다.

chat-read-retrieve-read.ipynb Notebook의 다음 셀 블록은 채팅 세션의 컨텍스트에서 검색 호출을 보여줍니다.

# Execute this cell multiple times updating user_input to accumulate chat history
user_input = "Does my plan cover annual eye exams?"

# Exclude category, to simulate scenarios where there's a set of docs you can't see
exclude_category = None

if len(history) > 0:
    completion = openai.Completion.create(
        engine=AZURE_OPENAI_GPT_DEPLOYMENT,
        prompt=summary_prompt_template.format(summary="\n".join(history), question=user_input),
        temperature=0.7,
        max_tokens=32,
        stop=["\n"])
    search = completion.choices[0].text
else:
    search = user_input

# Alternatively simply use search_client.search(q, top=3) if not using semantic ranking
print("Searching:", search)
print("-------------------")
filter = "category ne '{}'".format(exclude_category.replace("'", "''")) if exclude_category else None
r = search_client.search(search, 
                         filter=filter,
                         query_type=QueryType.SEMANTIC, 
                         query_language="en-us", 
                         query_speller="lexicon", 
                         semantic_configuration_name="default", 
                         top=3)
results = [doc[KB_FIELDS_SOURCEPAGE] + ": " + doc[KB_FIELDS_CONTENT].replace("\n", "").replace("\r", "") for doc in r]
content = "\n".join(results)

prompt = prompt_prefix.format(sources=content) + prompt_history + user_input + turn_suffix

completion = openai.Completion.create(
    engine=AZURE_OPENAI_CHATGPT_DEPLOYMENT, 
    prompt=prompt, 
    temperature=0.7, 
    max_tokens=1024,
    stop=["<|im_end|>", "<|im_start|>"])

prompt_history += user_input + turn_suffix + completion.choices[0].text + "\n<|im_end|>" + turn_prefix
history.append("user: " + user_input)
history.append("assistant: " + completion.choices[0].text)

print("\n-------------------\n".join(history))
print("\n-------------------\nPrompt:\n" + prompt)

시작하는 방법

  • 인덱싱 개념 및 전략을 검토하여 데이터를 수집하고 새로 고치는 방법을 결정합니다. 벡터 검색, 키워드 검색 또는 하이브리드 검색을 사용할지 여부를 결정합니다. 검색해야 하는 콘텐츠의 종류와 실행하려는 쿼리 유형에 따라 인덱스 디자인이 결정됩니다.

  • 쿼리 만들기를 검토하여 검색 요청 구문 및 요구 사항을 자세히 알아봅니다.

참고 항목

일부 Azure AI 검색 기능은 인간 상호 작용을 위한 것이며 RAG 패턴에서는 유용하지 않습니다. 특히 자동 완성 및 제안을 건너뛸 수 있습니다. 패싯 및 orderby와 같은 다른 기능은 유용할 수 있지만 RAG 시나리오에서는 일반적이지 않습니다.

참고 항목