1. Retrieval Augmented Generation (RAG)란?
RAG는 단순히 AI 모델이 질문에 답변을 생성하는 것뿐만 아니라, 외부 데이터를 참조하여 답변의 정확도와 신뢰성을 높이는 기법입니다.
대규모 언어 모델(LLM)이 자체 학습한 데이터만으로는 최신 정보나 특정한 데이터베이스를 활용할 수 없을 때, 추가적인 외부 데이터 검색을 통해 더 나은 답변을 제공할 수 있습니다.
2. RAG의 구조
RAG는 크게 두 가지 단계로 나눌 수 있습니다:
- 데이터 검색 (Retrieval): 사용자 질문에 관련된 데이터를 외부 데이터베이스, 문서, API 등에서 검색합니다.
이렇게 검색된 데이터는 구조화된 데이터(예: 데이터베이스) 또는 비구조화된 데이터(예: 문서)일 수 있습니다. - 응답 생성 (Generation): 검색된 데이터를 AI 모델(LLM)이 참조하여 질문에 맞는 답변을 생성합니다.
이 과정에서 모델은 검색된 정보를 바탕으로 보다 정확하고 구체적인 응답을 할 수 있게 됩니다.
3. 동작 과정
- User (사용자): 사용자가 질문을 입력합니다. 예를 들어, "최근에 출시된 스마트폰 정보 알려줘"라는 질문을 할 수 있습니다.
- Query (쿼리): 사용자의 질문이 Index(색인) 시스템으로 전달됩니다. 이 단계에서 AI는 어떤 외부 데이터를 참조할지 결정합니다.
- Index (색인): 이 부분은 외부 데이터베이스, 문서, API 등에서 관련 데이터를 검색하는 역할을 합니다.
데이터는 구조화된 데이터(예: DB), 비구조화된 데이터(예: 문서), 또는 프로그램을 통해 접근 가능한 데이터(API)에서 검색됩니다. - Prompt + Query + Relevant Data: 검색된 관련 데이터는 다시 AI 모델(LLM)에게 제공됩니다.
AI는 이 데이터를 참조하여 사용자의 질문에 적합한 응답을 생성합니다. - Response (응답): AI 모델은 검색된 데이터를 바탕으로 더 정확한 답변을 생성하고, 이를 사용자에게 전달합니다.
4. Python을 이용한 RAG 구현 예시
아래는 Python을 사용하여 RAG를 간단하게 구현하는 코드 예시입니다. 이 코드는 외부 데이터베이스에서 정보를 검색하고, 해당 정보를 바탕으로 AI 모델이 응답을 생성하는 흐름을 보여줍니다.
import openai
import some_search_api # 예시로, 외부 검색 API를 사용한다고 가정합니다.
# OpenAI API 키 설정
openai.api_key = 'your-api-key'
# 사용자의 질문 입력
user_query = "최근 출시된 스마트폰 정보를 알려줘"
# 외부 데이터에서 관련 정보 검색
search_results = some_search_api.search(user_query)
# 검색된 결과를 사용해 메시지 구성
messages = [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": user_query},
{"role": "assistant", "content": f"Here is what I found: {search_results}"}
]
# Chat Completion API 호출
response = openai.ChatCompletion.create(
model="gpt-4",
messages=messages
)
# AI의 응답 출력
print(response['choices'][0]['message']['content'])
5. 코드 설명
- 외부 데이터 검색: some_search_api는 외부 데이터베이스에서 사용자 질문과 관련된 정보를 검색하는 API입니다. 실제로 사용할 API는 필요에 따라 다를 수 있습니다(예: 뉴스 검색 API, 회사 데이터 API 등).
- 검색된 데이터를 AI에게 전달: 검색된 데이터는 search_results에 저장된 후, AI 모델에게 메시지로 전달됩니다. 이 데이터를 바탕으로 AI는 사용자의 질문에 맞는 답변을 생성하게 됩니다.
- AI 모델의 응답 생성: OpenAI의 GPT-4 모델을 사용하여 사용자의 질문과 검색된 데이터를 조합해 최종 응답을 생성합니다.
너무 길면 청크를 나눠서 저장하면 된다!
→ 메모리, 로컬, 원격에서 가져오는 법 3가지 방법이 있는데 실습에서는 메모리에 올려서 사용하는 것으로 진행함
6. LlamaIndex와 SentenceSplitter를 활용한 벡터화 및 데이터 검색
더 손쉬운 LLM 사용을 위한 프레임워크인 LlamaIndex 라이브러리를 활용하여 텍스트 데이터를 벡터화하고, 이를 통해 효율적인 데이터 검색을 수행하는 방법을 보겠습니다.
특히 SentenceSplitter를 사용하여 데이터를 적절한 크기로 분할하고 벡터 저장소에 저장하는 과정을 중점적으로 다룹니다.
from llama_index.core.node_parser import SentenceSplitter
# define embedding function
embed_model = OpenAIEmbedding(
model="text-embedding-3-small",
)
# load documents
documents = SimpleDirectoryReader("/Drive/Codes/data").load_data()
# set up ChromaVectorStore and load in data
vector_store = ChromaVectorStore(chroma_collection=chroma_collection)
storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex.from_documents(
documents,
storage_context=storage_context,
embed_model=embed_model,
transformations=[SentenceSplitter(chunk_size=512)]
)
# Query Data
query_engine = index.as_query_engine()
response = query_engine.query("프롬프트 엔지니어링이 무엇인가요?")
display(Markdown(f"{response}"))
1) 임베딩 모델 설정
embed_model = OpenAIEmbedding(
model="text-embedding-3-small",
)
OpenAIEmbedding을 사용하여 텍스트 데이터를 벡터로 변환하는 모델을 설정합니다.
이 예시에서는 "text-embedding-3-small" 모델을 사용해 임베딩을 수행합니다.
임베딩이란 텍스트를 벡터로 변환하여 기계 학습 모델이 이해할 수 있게 만드는 작업입니다.
2) 문서 데이터 로딩
documents = SimpleDirectoryReader("/content/drive/MyDrive/Lecture/Kakao_LLM/Codes/data").load_data()
SimpleDirectoryReader를 사용해 지정된 경로에 있는 데이터를 불러옵니다.
load_data() 메서드는 해당 디렉터리에서 문서 파일을 읽어와 벡터화에 사용할 수 있도록 준비합니다.
3) ChromaVectorStore 및 벡터 저장소 설정
vector_store = ChromaVectorStore(chroma_collection=chroma_collection)
storage_context = StorageContext.from_defaults(vector_store=vector_store)
ChromaVectorStore는 벡터화된 데이터를 저장하는 저장소입니다.
이 코드는 저장소를 초기화하고, 이를 StorageContext에 연결하여 데이터를 저장하거나 검색할 수 있는 환경을 구성합니다.
4) 문서 데이터를 벡터 저장소에 로드
index = VectorStoreIndex.from_documents(
documents,
storage_context=storage_context,
embed_model=embed_model,
transformations=[SentenceSplitter(chunk_size=512)]
)
VectorStoreIndex는 문서 데이터를 벡터화하여 벡터 저장소에 로드합니다.
여기서 중요한 부분은 SentenceSplitter를 사용해 문서 데이터를 512 토큰 크기로 분할하는 작업입니다.
긴 텍스트는 모델이 처리하기 어려울 수 있기 때문에, 이를 적절히 나누어 벡터화하는 것이 중요합니다.
5) 쿼리 엔진을 사용한 데이터 검색
query_engine = index.as_query_engine()
response = query_engine.query("프롬프트 엔지니어링이 무엇인가요?")
Query Engine을 사용해 벡터 저장소에서 데이터를 검색합니다.
"프롬프트 엔지니어링이 무엇인가요?"라는 질문을 입력하면, 저장된 벡터 데이터 중 관련된 정보를 검색하여 응답을 반환합니다.
6) 결과 출력
display(Markdown(f"{response}"))
검색 결과를 Markdown 형식으로 출력하는 코드입니다. 이 코드는 응답을 사용자에게 보기 쉽게 표시해 줍니다.
이 코드를 통해 LlamaIndex와 SentenceSplitter를 활용하여 긴 텍스트 데이터를 적절히 분할하고, 벡터화하여 효율적으로 검색하는 방법을 설명했습니다. 이 과정은 대규모 텍스트 데이터를 빠르게 처리하고 검색하는 데 매우 유용하며, 특히 AI 기반 검색 시스템에서 큰 도움이 됩니다.
7. RAG의 장점
- 더 높은 정확도: AI 모델이 자체 학습한 지식에만 의존하는 것이 아니라, 외부 데이터를 참조함으로써 최신 정보와 세부적인 답변을 제공할 수 있습니다.
- 구체적인 답변: 특정 데이터베이스나 API를 활용하여 사용자 질문에 대한 구체적이고 신뢰성 있는 정보를 제공할 수 있습니다.
- 확장성: 다양한 외부 데이터 소스를 쉽게 추가할 수 있어, AI 모델의 능력을 확장할 수 있습니다. 예를 들어, 특정 산업 분야의 데이터를 참조하도록 설정할 수 있습니다.
'IT 기술 > AI' 카테고리의 다른 글
[AI] LLM 어플리케이션 개발을 위한 준비, sLLM이란? (4) | 2024.09.25 |
---|---|
[AI] AI 모델 테스트 및 레드팀의 필요성 (4) | 2024.09.17 |
[AI] Chat API (3) | 2024.09.13 |
[AI] ChatGPT, Bard, Claude, LLaMA 비교 (8) | 2024.09.12 |
[AI] OpenAI Playground (2) | 2024.06.05 |