> 백엔드 개발 > 파이썬 튜토리얼 > 검색 증강 생성(RAG)에 대한 궁극적인 가이드

검색 증강 생성(RAG)에 대한 궁극적인 가이드

Barbara Streisand
풀어 주다: 2024-12-21 18:55:10
원래의
839명이 탐색했습니다.

OpenAI의 ChatGPT와 같은 생성 AI 모델의 급속한 발전으로 자연어 처리에 혁명이 일어나 이러한 시스템이 일관되고 상황에 맞는 응답을 생성할 수 있게 되었습니다. 그러나 최첨단 모델이라 할지라도 도메인별 쿼리를 처리하거나 매우 정확한 정보를 제공하는 데에는 한계가 있습니다. 이는 모델이 부정확하거나 조작된 세부 정보를 생성하는 경우인 환각과 같은 문제로 이어지는 경우가 많습니다.

이러한 격차를 해소하기 위해 설계된 혁신적인 프레임워크인 검색 증강 생성(RAG)입니다. RAG는 ​​외부 데이터 소스를 완벽하게 통합함으로써 생성 모델이 실시간 틈새 정보를 검색할 수 있도록 지원하여 정확성과 신뢰성을 크게 향상시킵니다.

이 기사에서는 RAG의 메커니즘을 자세히 알아보고, 아키텍처를 탐구하며, RAG 제작에 영감을 준 기존 생성 모델의 한계에 대해 논의합니다. 또한 실제 구현, 고급 기술 및 평가 방법을 강조하여 RAG가 AI가 전문 데이터와 상호 작용하는 방식을 어떻게 변화시키고 있는지 보여줄 것입니다.

시작하기

목차

  • RAG란
  • RAG 아키텍처
  • RAG 프로세스 흐름
  • RAG 대 미세 조정
  • RAG의 종류
  • RAG의 응용
  • RAG로 PDF 채팅 시스템 구축
  • 리소스

RAG 란 무엇입니까?

검색 증강 생성(RAG)은 외부 데이터의 실시간 검색을 통합하여 생성 AI 모델의 기능을 향상시키는 고급 프레임워크입니다. 생성 모델은 일관되고 인간과 유사한 텍스트를 생성하는 데 탁월하지만 정확한 최신 정보 또는 도메인별 정보를 제공하라는 요청을 받으면 실패할 수 있습니다. RAG가 개입하여 응답이 창의적일 뿐만 아니라 신뢰할 수 있고 관련성이 높은 소스에 기반을 두도록 보장합니다.

RAG는 생성 모델을 일반적으로 벡터 데이터베이스 또는 검색 시스템으로 구동되는 검색 메커니즘과 연결하여 작동합니다. 쿼리가 수신되면 검색 구성 요소는 방대한 외부 데이터 세트를 검색하여 관련 정보를 가져옵니다. 그런 다음 생성 모델은 이 데이터를 합성하여 정확하고 상황에 맞는 통찰력을 갖춘 출력을 생성합니다.

환각 및 제한된 도메인 지식과 같은 주요 문제를 해결함으로써 RAG는 전문 분야에서 탁월한 생성 모델의 잠재력을 발휘합니다. 이 애플리케이션은 정확한 답변으로 고객 지원을 자동화하는 것부터 연구자가 필요에 따라 엄선된 지식에 액세스할 수 있도록 하는 등 다양한 산업에 걸쳐 있습니다. RAG는 ​​실제 시나리오에서 AI 시스템을 더욱 지능적이고 신뢰할 수 있으며 유용하게 만드는 데 있어서 중요한 진전을 나타냅니다.

RAG의 아키텍처

RAG 아키텍처에 대한 명확한 이해는 RAG 아키텍처의 잠재력과 이점을 최대한 활용하는 데 필수적입니다. 기본적으로 프레임워크는 정보 처리의 원활한 흐름에서 함께 작동하는 검색기와 생성기라는 두 가지 주요 구성 요소를 기반으로 구축되었습니다.

전체 프로세스는 다음과 같습니다.
The ultimate guide to Retrieval-Augmented Generation (RAG)
출처: https://weaviate.io/blog/introduction-to-rag

  • 검색 — RAG의 추론 단계는 사용자 쿼리와 관련된 데이터를 외부 지식 소스에서 가져오는 검색으로 시작됩니다. 기본 RAG 설정에서는 유사성 검색이 일반적으로 사용되며, 쿼리와 외부 데이터를 동일한 벡터 공간에 삽입하여 가장 가까운 일치 항목을 식별합니다. Retriever는 Sparse Retrieval 및 Dense Retrieval과 같은 방법을 사용하여 문서를 가져오는 데 중요한 역할을 합니다. TF-IDF 또는 BM25와 같은 기술을 사용하는 희소 검색은 정확한 단어 일치에 의존하지만 동의어 및 의역에 어려움을 겪는 반면, 밀도 검색은 BERT 또는 RoBERTa와 같은 변환기 모델을 활용하여 의미론적 벡터 표현을 생성하여 보다 정확하고 미묘한 일치를 가능하게 합니다.
  • 증강 — 외부 소스에서 가장 관련성이 높은 데이터 포인트를 검색한 후 증강 프로세스는 이 정보를 사전 정의된 프롬프트 템플릿에 삽입하여 통합합니다.
  • 세대 — 생성 단계에서 모델은 증강 프롬프트를 사용하여 내부 언어 이해와 검색된 외부 데이터를 결합하여 일관되고 상황에 맞게 정확한 응답을 만듭니다. 증강이 외부 사실을 통합하는 반면, 생성은 이 풍부한 정보를 사용자의 쿼리에 맞는 자연스럽고 인간과 유사한 텍스트로 변환합니다.

RAG 프로세스 흐름

아래 그림에 설명된 RAG 프로세스 흐름의 모든 단계와 필수 구성 요소가 나와 있습니다.

The ultimate guide to Retrieval-Augmented Generation (RAG)
출처: https://www.griddynamics.com/blog/retrieval-augmented- Generation-llm

  • 문서 로드: RAG 프로세스의 첫 번째 단계에는 저장소에서 문서 로드, 추출, 구문 분석, 정리 및 문서 분할을 위한 텍스트 서식 지정이 포함된 데이터 준비가 포함됩니다. 텍스트 데이터는 일반 텍스트, PDF, Word 문서, CSV, JSON, HTML, Markdown 또는 프로그래밍 코드와 같은 다양한 형식으로 제공될 수 있습니다. LLM을 위한 이러한 다양한 소스를 준비하려면 일반적으로 추출, 구문 분석 및 정리를 통해 소스를 일반 텍스트로 변환해야 합니다.
  • 문서 분할: 문서는 텍스트 분할 또는 청킹을 통해 더 작고 관리 가능한 세그먼트로 분할됩니다. 이는 대규모 문서를 처리하고 LLM의 토큰 제한(예: GPT-3의 2048 토큰)을 준수하는 데 필수적입니다. 전략에는 고정 크기 또는 콘텐츠 인식 청킹이 포함되며 접근 방식은 데이터의 구조 및 요구 사항에 따라 달라집니다. The ultimate guide to Retrieval-Augmented Generation (RAG)

문서를 더 작은 덩어리로 나누는 것은 간단해 보일 수 있지만 문장을 부적절하게 나누는 것을 방지하려면 의미론을 신중하게 고려해야 하며, 이는 질문 답변과 같은 후속 단계에 영향을 미칠 수 있습니다. 순진한 고정 크기 청킹 접근 방식은 각 청크에 불완전한 정보를 초래할 수 있습니다. 대부분의 문서 분할 알고리즘은 청크 크기와 겹침을 사용합니다. 여기서 청크 크기는 문자, 단어 또는 토큰 수에 따라 결정되며 겹침은 인접한 청크 간에 텍스트를 공유하여 연속성을 보장합니다. 이 전략은 청크 전반에 걸쳐 의미적 맥락을 보존합니다.

  • 텍스트 임베딩: 텍스트 청크는 의미 유사성을 쉽게 비교할 수 있는 방식으로 각 청크를 나타내는 벡터 임베딩으로 변환됩니다. 벡터 임베딩은 텍스트와 같은 복잡한 데이터를 유사한 데이터 포인트가 함께 클러스터되는 수학적 공간으로 매핑합니다. 이 프로세스는 텍스트의 의미론적 의미를 포착하므로 단어가 다르더라도 유사한 의미를 가진 문장이 벡터 공간에서 서로 가깝게 매핑됩니다. 예를 들어, "고양이가 쥐를 쫓는다"와 "고양이가 설치류를 쫓는다"는 표현은 다르지만 가까운 지점으로 매핑됩니다.

The ultimate guide to Retrieval-Augmented Generation (RAG)
출처: https://www.griddynamics.com/blog/retrieval-augmented- Generation-llm

  • 벡터 스토어: 문서를 분할하여 벡터 임베딩으로 변환한 후 벡터 저장 및 관리를 위한 전문 데이터베이스인 벡터 스토어에 저장합니다. 벡터 저장소를 사용하면 유사한 벡터를 효율적으로 검색할 수 있으며 이는 RAG 모델 실행에 중요합니다. 벡터 저장소 선택은 데이터 규모 및 사용 가능한 계산 리소스와 같은 요소에 따라 달라집니다.

중요한 벡터 데이터베이스 중 일부는 다음과 같습니다.

  • FAISS: Facebook AI가 개발한 FAISS는 대규모 고차원 벡터 컬렉션을 효율적으로 관리하고 고차원 환경에서 유사성 검색 및 클러스터링을 수행합니다. 메모리 사용량과 쿼리 기간을 최적화하여 수십억 개의 벡터를 처리하는 데 적합합니다.
  • Chroma: 오픈 소스 인메모리 벡터 데이터베이스인 Chroma는 LLM 애플리케이션용으로 설계되었으며 벡터 저장, 검색 및 검색을 위한 확장 가능한 플랫폼을 제공합니다. 클라우드와 온프레미스 배포를 모두 지원하며 다양한 데이터 유형과 형식을 다용도로 처리할 수 있습니다.
  • Weaviate: 자체 호스팅 또는 완전 관리가 가능한 오픈 소스 벡터 데이터베이스입니다. 고성능, 확장성, 유연성에 중점을 두고 광범위한 데이터 유형과 애플리케이션을 지원합니다. 벡터와 객체를 모두 저장할 수 있어 벡터 기반 검색 기술과 키워드 기반 검색 기술을 결합할 수 있습니다.
  • Pinecone: 대규모 ML 애플리케이션의 개발 및 배포를 단순화하도록 설계된 클라우드 기반 관리형 벡터 데이터베이스입니다. 많은 벡터 데이터베이스와 달리 Pinecone은 독점적인 비공개 소스 코드를 사용합니다. 고차원 벡터를 처리하는 데 탁월하며 유사성 검색, 추천 시스템, 개인화, 의미 검색과 같은 애플리케이션에 적합합니다. Pinecone에는 단일 단계 필터링 기능도 있습니다.
  • 문서 검색: 문서 검색이나 질문 답변과 같은 정보 검색 시스템의 검색 프로세스는 문서 인덱싱과 동일한 임베딩 모델을 사용하여 쿼리가 수신되고 벡터로 변환될 때 시작됩니다. 쿼리 벡터를 인덱스(벡터 저장소)에 저장된 청크 벡터와 비교하여 관련 문서 청크를 반환하는 것이 목표입니다. 검색자의 역할은 문서를 저장하지 않고 관련 문서 청크의 ID를 식별하고 반환하는 것입니다. 유사성 검색(코사인 유사성 기반), 특정 유사성 점수를 초과하는 문서만 반환하는 임계값 기반 검색 등 다양한 검색 방법을 사용할 수 있습니다. 또한 LLM 지원 검색은 콘텐츠 및 메타데이터 필터링과 관련된 쿼리에 유용합니다.

The ultimate guide to Retrieval-Augmented Generation (RAG)
출처: https://www.griddynamics.com/blog/retrieval-augmented- Generation-llm

  • 답변 생성: 검색 프로세스에서 관련 문서 덩어리가 사용자 쿼리와 결합되어 LLM에 대한 컨텍스트와 프롬프트를 생성합니다. LangChain의 "Stuff" 방법이라고 하는 가장 간단한 접근 방식은 직접적이고 간단한 답변을 위해 모든 청크를 동일한 컨텍스트 창으로 집중시키는 것입니다. 그러나 이 방법은 컨텍스트 창 제한으로 인해 대량의 문서와 복잡한 쿼리를 처리하는 데 어려움을 겪습니다. 이 문제를 해결하기 위해 Map-reduce, Refine 및 Map-rerank와 같은 대체 방법이 사용됩니다. Map-reduce는 문서를 LLM에 별도로 보낸 다음 응답을 결합합니다. Refine은 답변을 구체화하기 위해 프롬프트를 반복적으로 업데이트하는 반면 Map-rerank는 관련성을 기준으로 문서의 순위를 매기므로 여러 가지 설득력 있는 답변에 이상적입니다.

The ultimate guide to Retrieval-Augmented Generation (RAG)

RAG 대 미세 조정

RAG(Retrieval-Augmented Generation)와 미세 조정은 LLM 기능을 확장하는 두 가지 주요 방법이며 각각 서로 다른 시나리오에 적합합니다. 미세 조정에는 전문적인 작업을 수행하기 위해 도메인별 데이터에 대한 LLM 재교육이 포함되며, 이는 특정 톤이나 스타일이 필요한 브랜딩 또는 창의적 글쓰기와 같은 정적이고 좁은 사용 사례에 이상적입니다. 그러나 비용이 많이 들고 시간이 많이 걸리며 자주 업데이트되는 동적 데이터에는 적합하지 않습니다.

반면 RAG는 모델 가중치를 수정하지 않고 외부 데이터를 동적으로 검색하여 LLM을 향상시켜 비용 효율적이고 법률, 금융 또는 고객 서비스 애플리케이션과 같은 실시간 데이터 기반 환경에 이상적입니다. RAG를 사용하면 LLM이 구조화되지 않은 대규모 내부 문서 모음을 처리할 수 있어 지저분한 데이터 저장소를 탐색하는 기존 방법에 비해 상당한 이점을 제공합니다.

미세 조정은 미묘하고 일관된 출력을 생성하는 데 탁월한 반면, RAG는 외부 지식 기반을 활용하여 정확한 최신 정보를 제공합니다. 실제로 RAG는 실시간 적응형 응답이 필요한 애플리케이션, 특히 방대한 비정형 데이터를 관리하는 기업에서 선호되는 선택인 경우가 많습니다.

RAG의 종류

검색 증강 생성(RAG) 접근 방식에는 여러 유형이 있으며 각각 특정 사용 사례와 목표에 맞게 조정됩니다. 기본 유형은 다음과 같습니다.

The ultimate guide to Retrieval-Augmented Generation (RAG)
출처: https://x.com/weaviate_io/status/1866528335884325070

  • 네이티브 RAG: 검색-증강 생성 시스템의 검색 및 생성 구성 요소가 동일한 아키텍처 내에서 원활하게 작동하도록 설계된 긴밀하게 통합된 접근 방식을 의미합니다. 외부 도구나 API에 의존하는 기존 구현과 달리 기본 RAG는 검색 메커니즘과 생성 모델 간의 상호 작용을 최적화하여 처리 속도를 높이고 상황별 관련성을 향상시킵니다. 이 접근 방식은 종종 인메모리 처리 또는 고도로 최적화된 로컬 데이터베이스를 사용하여 대기 시간과 리소스 오버헤드를 줄입니다. 기본 RAG 시스템은 일반적으로 특정 사용 사례에 맞게 조정되어 타사 서비스에 대한 종속성을 제거하여 향상된 효율성, 정확성 및 비용 효율성을 제공합니다.
  • RAG 검색 및 순위 재지정: 검색 프로세스를 개선하여 정확성과 관련성을 높이는 데 중점을 둡니다. 이 방법에서는 일반적으로 임베딩 공간의 코사인 유사성에 의해 결정되는 쿼리의 의미 유사성을 기반으로 문서 또는 청크의 초기 세트가 검색됩니다. 그 후, 재순위 모델은 쿼리에 대한 문맥 관련성을 기반으로 검색된 문서의 순서를 변경합니다. 이 순위 재지정 단계에서는 딥 러닝 모델이나 변환기를 활용하는 경우가 많아 기본 유사성 측정항목을 넘어 더욱 미묘한 순위 지정이 가능합니다. 가장 관련성이 높은 문서의 우선순위를 지정함으로써 이 접근 방식은 생성 모델이 상황에 맞게 풍부한 입력을 받도록 보장하여 응답 품질을 크게 향상시킵니다.
  • 멀티모달 RAG: 텍스트, 이미지, 오디오 또는 비디오와 같은 여러 데이터 양식을 검색 증강 생성 파이프라인에 통합하여 기존 RAG 패러다임을 확장합니다. 이를 통해 시스템은 다양한 형태의 데이터를 통합하는 응답을 검색하고 생성할 수 있습니다. 예를 들어, 이미지 기반 쿼리와 관련된 시나리오에서 시스템은 보다 포괄적인 답변을 생성하기 위해 텍스트 콘텐츠와 함께 관련 이미지를 검색할 수 있습니다. 다중 모드 RAG는 텍스트 정보와 시각적 정보의 조합에 통찰력이 의존하는 경우가 많은 전자 상거래, 의료 영상, 멀티미디어 콘텐츠 분석과 같은 영역에서 특히 유용합니다.
  • 그래프 RAG: 그래프 기반 데이터 구조를 활용하여 엔터티 간의 관계 및 연결을 기반으로 정보를 모델링하고 검색합니다. 이 접근 방식에서 지식은 노드가 개체(예: 개념, 문서 또는 개체)를 나타내고 가장자리가 해당 관계(예: 의미, 계층 또는 시간)를 캡처하는 그래프로 구성됩니다. 쿼리는 입력과 관련된 하위 그래프 또는 경로를 식별하기 위해 처리되며, 이러한 하위 그래프는 생성 모델에 입력됩니다. 이 방법은 관계형 통찰력이 중요한 과학 연구, 소셜 네트워크, 지식 관리와 같은 영역에서 특히 유용합니다.
  • 하이브리드 RAG: 조밀 검색 및 희소 검색과 같은 여러 검색 기술을 결합하여 다양한 쿼리 유형 전반에 걸쳐 성능을 향상합니다. 밀집 검색은 벡터 임베딩을 사용하여 의미적 유사성을 포착하는 반면, 희소 검색은 정확한 일치를 위해 BM25와 같은 키워드 기반 방법을 사용합니다. 이러한 방법을 통합함으로써 Hybrid RAG는 정밀도와 재현율의 균형을 유지하여 쿼리가 매우 구체적이거나 추상적일 수 있는 시나리오에서 다용도로 사용할 수 있습니다. 검색 중에 높은 수준의 의미와 특정 키워드를 모두 고려하므로 이기종 데이터가 있는 환경에서 특히 효과적입니다.
  • 에이전트 RAG(라우터): 의사 결정 계층을 사용하여 쿼리의 특성에 따라 적절한 검색 및 생성 모듈로 쿼리를 동적으로 라우팅합니다. 라우터는 들어오는 쿼리를 분석하여 다양한 검색 방법, 데이터 소스 또는 특수 생성 모델이 포함될 수 있는 최적의 처리 경로를 결정합니다. 이러한 접근 방식을 통해 시스템은 각 쿼리의 특정 요구 사항에 맞게 작업을 맞춤화하여 다양한 애플리케이션에서 효율성과 정확성을 향상시킵니다.
  • 에이전트 RAG(다중 에이전트 RAG): 다중 에이전트 RAG에는 여러 전문 에이전트가 검색 및 생성 프로세스의 고유한 측면을 처리하는 협업 프레임워크가 포함됩니다. 각 에이전트는 특정 도메인에서 데이터 검색, 결과 순위 재지정, 특정 스타일로 응답 생성 등 특정 작업을 담당합니다. 이러한 에이전트는 응집력 있는 결과를 제공하기 위해 의사소통하고 협력합니다. 다중 에이전트 RAG는 시스템이 다양한 에이전트의 전문 지식을 활용하여 포괄적이고 미묘한 응답을 제공할 수 있도록 하므로 복잡한 다중 도메인 쿼리에 특히 강력합니다.

RAG의 응용

검색 증강 생성(RAG) 프레임워크는 외부 지식을 생성 언어 모델에 동적으로 통합하는 기능으로 인해 다양한 산업 전반에 걸쳐 다양하게 적용됩니다. 다음은 몇 가지 주요 응용 프로그램입니다.

  • 고객 지원 및 서비스: RAG 시스템은 제품 설명서, 지식 기반 및 회사 정책 문서에서 관련 데이터를 검색하여 복잡한 쿼리에 응답할 수 있는 지능형 챗봇을 만들기 위해 고객 지원에 널리 사용됩니다. 이를 통해 고객은 정확한 최신 정보를 받을 수 있어 고객 경험이 향상됩니다.
  • 법률 문서 분석: 법률 분야에서 RAG는 판례법, 계약서, 법률 문서 등 방대한 자료에서 요약이나 답변을 구문 분석하고, 검색하고, 생성할 수 있습니다. 법률 조사 수행, 계약서 초안 작성 및 규정 준수 보장에 특히 유용합니다.
  • 재무 분석: RAG는 금융 서비스 분야에서 수익 보고서, 시장 동향 및 규제 문서를 분석하는 데 사용됩니다. 관련 재무 데이터를 검색함으로써 분석가는 통찰력, 보고서를 생성하거나 시장 성과에 대한 질문에 대한 실시간 답변을 생성하는 데 도움을 줄 수 있습니다.
  • 의료 및 의료 진단: 의료 분야에서 RAG는 의학 문헌, 환자 기록 및 치료 지침에서 정보를 검색하고 종합하는 데 활용됩니다. 이는 진단 지원, 약물 발견 및 맞춤형 치료 권장 사항을 지원하여 임상의가 가장 관련성이 높은 최신 데이터에 액세스할 수 있도록 합니다.
  • 교육 및 온라인 학습: RAG 기반 도구는 강좌 자료를 검색하고 맞춤형 답변 또는 학습 가이드를 생성하여 맞춤형 교육을 지원합니다. 사용자 쿼리를 기반으로 상황에 맞는 설명과 동적 콘텐츠를 제공하여 학습 플랫폼을 향상시킬 수 있습니다.
  • 전자상거래 및 소매: 전자상거래에서 RAG 시스템은 카탈로그 및 고객 리뷰에서 데이터를 검색하여 제품 검색 및 추천 엔진을 개선합니다. 또한 사용자 선호도에 따라 맞춤형 제품 제안을 제공하는 대화형 쇼핑 도우미도 가능합니다.
  • 지능형 가상 비서: RAG는 특히 실시간 날씨 업데이트나 지역 비즈니스 정보와 같은 외부 지식이 필요한 쿼리에 대해 정확하고 상황에 맞는 응답을 제공하여 Alexa 또는 Siri와 같은 가상 비서를 향상시킵니다.

RAG를 사용하여 PDF 채팅 시스템 구축

이 섹션에서는 PDF의 내용을 이해하고 RAG(Retrieval-Augmented Generation)를 사용하여 해당 내용을 기반으로 사용자 쿼리에 응답할 수 있는 효율적인 애플리케이션을 개발합니다. 구현에서는 LangChain 플랫폼을 활용하여 LLM 및 벡터 저장소와의 상호 작용을 촉진합니다. 효율적인 정보 검색을 위해 OpenAI의 LLM과 임베딩 모델을 활용하여 FAISS 벡터 저장소를 구축하겠습니다.

종속성 설치

  • 다음 명령을 실행하여 가상 환경을 생성하고 활성화하세요.
python -m venv venv
source venv/bin/activate #for ubuntu
venv/Scripts/activate #for windows
로그인 후 복사
  • pip를 사용하여 langchain, langchain_community, openai, faiss-cpu, PyPDF2, streamlit, python-dotenv, tiktoken 라이브러리를 설치하세요.
pip install langchain langchain_community openai faiss-cpu PyPDF2 streamlit python-dotenv tiktoken
로그인 후 복사

환경 및 자격 증명 설정

  • .env라는 파일을 만듭니다. 이 파일은 OpenAI 키, 모델, 임베딩을 포함한 환경 변수를 저장합니다.
  • .env 파일을 열고 다음 코드를 추가하여 OpenAI 자격 증명을 지정하세요.
OPENAI_API_KEY=sk-proj-xcQxBf5LslO62At...
OPENAI_MODEL_NAME=gpt-3.5-turbo
OPENAI_EMBEDDING_MODEL_NAME=text-embedding-3-small
로그인 후 복사

환경 변수 가져오기

  • app.py라는 파일을 만듭니다.
  • 환경 변수에 OpenAI 자격 증명을 추가합니다.
from dotenv import load_dotenv
import os
load_dotenv()
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
OPENAI_MODEL_NAME = os.getenv("OPENAI_MODEL_NAME")
OPENAI_EMBEDDING_MODEL_NAME = os.getenv("OPENAI_EMBEDDING_MODEL_NAME")
로그인 후 복사

필수 라이브러리 가져오기

langchain, streamlit, pyPDF와 같은 PDF 처리 및 앱 구축을 위한 필수 라이브러리를 가져옵니다.

import streamlit as st
from PyPDF2 import PdfReader
from langchain.text_splitter import CharacterTextSplitter
from langchain.prompts import PromptTemplate
from langchain_community.embeddings import OpenAIEmbeddings
from langchain_community.vectorstores import FAISS
from langchain.memory import ConversationBufferMemory
from langchain.chains import ConversationalRetrievalChain
from langchain_community.chat_models import ChatOpenAI
from htmlTemplates import bot_template, user_template, css
로그인 후 복사

PDF에서 텍스트를 추출하는 기능 정의

  • PyPDF2를 사용하여 업로드된 PDF 파일에서 텍스트를 추출합니다.
def get_pdf_text(pdf_files):
    text = ""
    for pdf_file in pdf_files:
        reader = PdfReader(pdf_file)
        for page in reader.pages:
            text += page.extract_text()
    return text
로그인 후 복사

추출된 텍스트를 청크로 분할하기

LangChain의 CharacterTextSplitter를 사용하여 큰 텍스트를 더 작고 관리 가능한 덩어리로 나눕니다.

def get_chunk_text(text):
    text_splitter = CharacterTextSplitter(
        separator="\n",
        chunk_size=1000,
        chunk_overlap=200,
        length_function=len
    )
    chunks = text_splitter.split_text(text)
    return chunks
로그인 후 복사

텍스트 임베딩을 위한 벡터 저장소 만들기

FAISS를 사용하여 텍스트 청크에 대한 임베딩을 생성하고 이를 벡터 데이터베이스에 저장합니다.

def get_vector_store(text_chunks):
    embeddings = OpenAIEmbeddings(openai_api_key=OPENAI_API_KEY, model=OPENAI_EMBEDDING_MODEL_NAME)
    vectorstore = FAISS.from_texts(texts=text_chunks, embedding=embeddings)
    return vectorstore
로그인 후 복사

대화형 검색 체인 구축

벡터 저장소에서 정보를 검색하고 LLM을 통해 사용자와 상호작용하는 체인을 정의합니다.

def get_conversation_chain(vector_store):
    llm = ChatOpenAI(openai_api_key=OPENAI_API_KEY, model_name=OPENAI_MODEL_NAME, temperature=0)
    memory = ConversationBufferMemory(memory_key='chat_history', return_messages=True)
    system_template  =  """
    Use  the following pieces of context and chat history to answer the question at the end. 
    If you don't know the answer, just say that you don't know, don't try to make up an answer.

    Context: {context}

    Chat history: {chat_history}

    Question: {question}
    Helpful Answer:
    """
    prompt = PromptTemplate(
        template=system_template,
        input_variables=["context", "question",  "chat_history"],
    )
    conversation_chain = ConversationalRetrievalChain.from_llm(
        verbose = True,
        llm=llm,
        retriever=vector_store.as_retriever(),
        memory=memory,
        combine_docs_chain_kwargs={"prompt": prompt}
    )
    return conversation_chain
로그인 후 복사

사용자 쿼리 처리

사용자 입력을 처리하여 대화 체인에 전달하고 채팅 기록을 업데이트합니다.

def handle_user_input(question):
    try:
        response = st.session_state.conversation({'question': question})
        st.session_state.chat_history = response['chat_history']
    except Exception as e:
        st.error('Please select PDF and click on Process.')
로그인 후 복사

효율적인 채팅을 위한 사용자 정의 HTML 템플릿 만들기

CSS를 사용하여 사용자와 봇 메시지 모두에 대한 맞춤 채팅 인터페이스를 만들려면 맞춤 템플릿을 디자인하고 CSS로 스타일을 지정하세요.

  • htmlTemplates.py라는 파일을 만들고 다음 코드를 추가합니다.
css = '''
<style>
.chat-message {
    padding: 1rem; border-radius: 0.5rem; margin-bottom: 1rem; display: flex
}
.chat-message.user {
    background-color: #2b313e
}
.chat-message.bot {
    background-color: #475063
}
.chat-message .avatar {
  width: 10%;
}
.chat-message .avatar img {
  max-width: 30px;
  max-height: 30px;
  border-radius: 50%;
  object-fit: cover;
}
.chat-message .message {
  width: 90%;
  padding: 0 1rem;
  color: #fff;
}
'''

bot_template = '''
<div>



<h3>
  
  
  Displaying chat history
</h3>

<p>Show the user and AI conversation history in a reverse order with HTML templates for formatting.<br>
</p>

<pre class="brush:php;toolbar:false">def display_chat_history():
    if st.session_state.chat_history:
        reversed_history = st.session_state.chat_history[::-1]

        formatted_history = []
        for i in range(0, len(reversed_history), 2):
            chat_pair = {
                "AIMessage": reversed_history[i].content,
                "HumanMessage": reversed_history[i + 1].content
            }
            formatted_history.append(chat_pair)

        for i, message in enumerate(formatted_history):
            st.write(user_template.replace("{{MSG}}", message['HumanMessage']), unsafe_allow_html=True)
            st.write(bot_template.replace("{{MSG}}", message['AIMessage']), unsafe_allow_html=True)
로그인 후 복사

Streamlit 앱 인터페이스 구축

파일 업로드, 질문 입력, 채팅 기록 표시를 위한 기본 앱 인터페이스를 설정합니다.

def main():
    st.set_page_config(page_title='Chat with PDFs', page_icon=':books:')
    st.write(css, unsafe_allow_html=True)

    if "conversation" not in st.session_state:
        st.session_state.conversation = None
    if "chat_history" not in st.session_state:
        st.session_state.chat_history = None

    st.header('Chat with PDFs :books:')

    question = st.text_input("Ask anything to your PDF:")
    if question:
        handle_user_input(question)

    if st.session_state.chat_history is not None:
        display_chat_history()

    with st.sidebar:
        st.subheader("Upload your Documents Here: ")
        pdf_files = st.file_uploader("Choose your PDF Files and Press Process button", type=['pdf'], accept_multiple_files=True)

        if pdf_files and st.button("Process"):
            with st.spinner("Processing your PDFs..."):
                try:
                    # Get PDF Text
                    raw_text = get_pdf_text(pdf_files)
                    # Get Text Chunks
                    text_chunks = get_chunk_text(raw_text)
                    # Create Vector Store
                    vector_store = get_vector_store(text_chunks)
                    st.success("Your PDFs have been processed successfully. You can ask questions now.")
                    # Create conversation chain
                    st.session_state.conversation = get_conversation_chain(vector_store)
                except Exception as e:
                    st.error(f"An error occurred: {e}")

if __name__ == '__main__':
    main()
로그인 후 복사

PDF 채팅 애플리케이션의 전체 코드

다음은 PDF 채팅 애플리케이션의 전체 코드 구현입니다. 환경 변수 설정, 텍스트 추출, 벡터 저장 및 RAG 기능을 간소화된 솔루션에 통합합니다.

from dotenv import load_dotenv
import os
load_dotenv()
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
OPENAI_MODEL_NAME = os.getenv("OPENAI_MODEL_NAME")
OPENAI_EMBEDDING_MODEL_NAME = os.getenv("OPENAI_EMBEDDING_MODEL_NAME")

import streamlit as st
from PyPDF2 import PdfReader
from langchain.text_splitter import CharacterTextSplitter
from langchain.prompts import PromptTemplate
from langchain_community.embeddings import OpenAIEmbeddings
from langchain_community.vectorstores import FAISS
from langchain.memory import ConversationBufferMemory
from langchain.chains import ConversationalRetrievalChain
from langchain_community.chat_models import ChatOpenAI
from htmlTemplates import bot_template, user_template, css

def get_pdf_text(pdf_files):
    text = ""
    for pdf_file in pdf_files:
        reader = PdfReader(pdf_file)
        for page in reader.pages:
            text += page.extract_text()
    return text

def get_chunk_text(text):
    text_splitter = CharacterTextSplitter(
        separator="\n",
        chunk_size=1000,
        chunk_overlap=200,
        length_function=len
    )
    chunks = text_splitter.split_text(text)
    return chunks

def get_vector_store(text_chunks):
    embeddings = OpenAIEmbeddings(openai_api_key=OPENAI_API_KEY, model=OPENAI_EMBEDDING_MODEL_NAME)
    vectorstore = FAISS.from_texts(texts=text_chunks, embedding=embeddings)
    return vectorstore

def get_conversation_chain(vector_store):
    llm = ChatOpenAI(openai_api_key=OPENAI_API_KEY, model_name=OPENAI_MODEL_NAME, temperature=0)
    memory = ConversationBufferMemory(memory_key='chat_history', return_messages=True)
    system_template  =  """
    Use  the following pieces of context and chat history to answer the question at the end. 
    If you don't know the answer, just say that you don't know, don't try to make up an answer.

    Context: {context}

    Chat history: {chat_history}

    Question: {question}
    Helpful Answer:
    """
    prompt = PromptTemplate(
        template=system_template,
        input_variables=["context", "question",  "chat_history"],
    )
    conversation_chain = ConversationalRetrievalChain.from_llm(
        verbose = True,
        llm=llm,
        retriever=vector_store.as_retriever(),
        memory=memory,
        combine_docs_chain_kwargs={"prompt": prompt}
    )
    return conversation_chain

def handle_user_input(question):
    try: 
        response = st.session_state.conversation({'question': question})
        st.session_state.chat_history = response['chat_history']
    except Exception as e:
        st.error('Please select PDF and click on OK.')

def display_chat_history():
    if st.session_state.chat_history:
        reversed_history = st.session_state.chat_history[::-1]

        formatted_history = []
        for i in range(0, len(reversed_history), 2):
            chat_pair = {
                "AIMessage": reversed_history[i].content,
                "HumanMessage": reversed_history[i + 1].content
            }
            formatted_history.append(chat_pair)

        for i, message in enumerate(formatted_history):
            st.write(user_template.replace("{{MSG}}", message['HumanMessage']), unsafe_allow_html=True)
            st.write(bot_template.replace("{{MSG}}", message['AIMessage']), unsafe_allow_html=True)

def main():
    st.set_page_config(page_title='Chat with PDFs', page_icon=':books:')
    st.write(css, unsafe_allow_html=True)

    if "conversation" not in st.session_state:
        st.session_state.conversation = None
    if "chat_history" not in st.session_state:
        st.session_state.chat_history = None

    st.header('Chat with PDFs :books:')

    question = st.text_input("Ask anything to your PDF:")
    if question:
        handle_user_input(question)

    if st.session_state.chat_history is not None:
        display_chat_history()

    with st.sidebar:
        st.subheader("Upload your Documents Here: ")
        pdf_files = st.file_uploader("Choose your PDF Files and Press Process button", type=['pdf'], accept_multiple_files=True)

        if pdf_files and st.button("Process"):
            with st.spinner("Processing your PDFs..."):
                try:
                    # Get PDF Text
                    raw_text = get_pdf_text(pdf_files)
                    # Get Text Chunks
                    text_chunks = get_chunk_text(raw_text)
                    # Create Vector Store
                    vector_store = get_vector_store(text_chunks)
                    st.success("Your PDFs have been processed successfully. You can ask questions now.")
                    # Create conversation chain
                    st.session_state.conversation = get_conversation_chain(vector_store)
                except Exception as e:
                    st.error(f"An error occurred: {e}")

if __name__ == '__main__':
    main()

로그인 후 복사

애플리케이션 실행

다음 명령을 사용하여 Streamlit으로 앱을 실행합니다.

streamlit run app.py
로그인 후 복사

다음과 같이 출력됩니다.
The ultimate guide to Retrieval-Augmented Generation (RAG)

이 글을 읽어주셔서 감사합니다!!

콘텐츠를 검토해 주신 Gowri M Bhatt에게 감사드립니다.

이 기사가 마음에 드셨다면 하트 버튼♥을 눌러 다른 사람들이 찾을 수 있도록 공유해주세요!

이 튜토리얼의 전체 소스 코드는 여기에서 확인할 수 있습니다.

codemaker2015/pdf-chat-using-RAG | github.com

자원

  • RAG 및 LLM 비즈니스 프로세스 자동화: 기술 전략 - Grid Dynamics | www.griddynamics.com
  • 검색 증강 생성(RAG) 소개 | 위비에이트
  • 증강 언어 모델의 기술, 과제 및 미래 - Gradient Flow
  • 행성 규모의 검색 증강 세대 | 아르쿠스

위 내용은 검색 증강 생성(RAG)에 대한 궁극적인 가이드의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

원천:dev.to
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
저자별 최신 기사
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿