Coding/Study

[AI]RAG 기본 이론&실습(1)

후__아 2024. 8. 1. 16:06

RAG에 대해선 이전에 아주 짧게 다뤄봤어서 공부가 필요한 상황,,,

경진대회 문제라도 제대로 풀려면 해야된다 아자아자!!! (이제는 더 이상 물러설 곳이 없다)

 

https://hoooa.tistory.com/58에 이어서 LangChain과 관련된 RAG를 공부 및 실습해보고자 한다!

 

[AI]LangChain 기본 이론&실습(1)

※ Langchain 대규모 언어 모델(LLM)과 애플리케이션의 통합을 간소화하는 SDK API를 노출하여 기본 LLM의 구현 세부 사항을 요약 => 코드를 크게 변경하지 않고도 모델 교체/대체 가능≫ 언어모델 용도

hoooa.tistory.com

 

 

※ RAG(Retrieval-Augmented Generation)

기존의 LLM을 확장, 더욱 정화하고 풍부한 정보를 제공하기 위함

학습 데이터에 불포함된 외부 데이터실시간으로 검색(retrieval) & 답변 생성(generation)

≫ Hallucination 방지 & 최신 정보 반영

 

>> 기본 구조

- 검색 단계(Retrieval Phase): 질문/컨텍스트 in → 관련 외부 데이터 검색 from 검색 엔진/DB 등

- 생성 단계(Generation Phase): 검색 정보+기존 지식 → 주어진 질문에 대한 답변 생성

 

1. Load Data

RAG에 사용할 데이터 불러오기

# 데이터 로드
from langchain_community.document_loaders import WebBaseLoader
url = 'https://ko.wikipedia.org/wiki/%EC%9C%84%ED%82%A4%EB%B0%B1%EA%B3%BC:%EC%A0%95%EC%B1%85%EA%B3%BC_%EC%A7%80%EC%B9%A8'
loader = WebBaseLoader(url)

docs = loader.load()    # 웹페이지 텍스트 -> Documents
print(len(docs))
print(len(docs[0].page_content))
print(docs[0].page_content[5000:6000])
1
13153
좀 더 빠르게 강력한 수단을 이용해야 합니다. 특히 정책 문서에 명시된 원칙을 지키지 않는 것은 대부분의 경우 다른 사용자에게 받아들여지지 않습니다 (다른 분들에게 예외 상황임을 설득할 수 있다면 가능하기는 하지만요). 이는 당신을 포함해서 편집자 개개인이 정책과 지침을 직접 집행 및 적용한다는 것을 의미합니다.
특정 사용자가 명백히 정책에 반하는 행동을 하거나 정책과 상충되는 방식으로 지침을 어기는 경우, 특히 의도적이고 지속적으로 그런 행위를 하는 경우 해당 사용자는 관리자의 제재 조치로 일시적, 혹은 영구적으로 편집이 차단될 수 있습니다. 영어판을 비롯한 타 언어판에서는 일반적인 분쟁 해결 절차로 끝낼 수 없는 사안은 중재위원회가 개입하기도 합니다.

문서 내용
정책과 지침의 문서 내용은 처음 읽는 사용자라도 원칙과 규범을 잘 이해할 수 있도록 다음 원칙을 지켜야 합니다.

명확하게 작성하세요. 소수만 알아듣거나 준법률적인 단어, 혹은 지나치게 단순한 표현은 피해야 합니다. 명확하고, 직접적이고, 모호하지 않고, 구체적으로 작성하세요. 지나치게 상투적인 표현이나 일반론은 피하세요. 지침, 도움말 문서 및 기타 정보문 문서에서도 "해야 합니다" 혹은 "하지 말아야 합니다" 같이 직접적인 표현을 굳이 꺼릴 필요는 없습니다.
가능한 간결하게, 너무 단순하지는 않게. 정책이 중언부언하면 오해를 부릅니다. 불필요한 말은 생략하세요. 직접적이고 간결한 설명이 마구잡이식 예시 나열보다 더 이해하기 쉽습니다. 각주나 관련 문서 링크를 이용하여 더 상세히 설명할 수도 있습니다.
규칙을 만든 의도를 강조하세요. 사용자들이 상식대로 행동하리라 기대하세요. 정책의 의도가 명료하다면, 추가 설명은 필요 없죠. 즉 규칙을 '어떻게' 지키는지와 더불어 '왜' 지켜야 하는지 확실하게 밝혀야 합니다.
범위는 분명히, 중복은 피하기. 되도록 앞부분에서 정책 및 지침의 목적과 범위를 분명하게 밝혀야 합니다. 독자 대부분은 도입부 초반만 읽고 나가버리니까요. 각 정책 문서의 내용은 해당 정

 

2. Text Split

데이터를 Chunk로 분할

검색 효율성 ↑

# 텍스트 분할
from langchain.text_splitter import RecursiveCharacterTextSplitter

splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
splits = splitter.split_documents(docs)

print(len(splits))
print(splits[10])   # page_content: 분할된 텍스트 조각 / metadata: 원본 문서의 정보
18
page_content='제안과 채택
 백:아님 § 관료주의  문서를 참고하십시오. 단축백:제안
제안 문서란 정책과 지침으로 채택하자고 의견을 묻는 문서이나 아직 위키백과 내에 받아들여지는 원칙으로 확립되지는 않은 문서입니다. {{제안}} 틀을 붙여 공동체 내에서 정책이나 지침으로 채택할 지 의견을 물을 수 있습니다. 제안 문서는 정책과 지침이 아니므로 아무리 실제 있는 정책이나 지침을 요약하거나 인용해서 다른 문서에 쓴다고 해도 함부로 정책이나 지침 틀을 붙여서는 안 됩니다.
'제안'은 완전 새로운 원칙이라기보다, 기존의 불문율이나 토론 총의의 문서를 통한 구체화에 가깝습니다. 많은 사람들이 쉽게 제안을 받아들이도록 하기 위해서는, 기초적인 원칙을 우선 정하고 기본 틀을 짜야 합니다. 정책과 지침의 기본 원칙은 "왜 지켜야 하는가?", "어떻게 지켜야 하는가?" 두 가지입니다. 특정 원칙을 정책이나 지침으로 확립하기 위해서는 우선 저 두 가지 물음에 성실하게 답하는 제안 문서를 작성해야 합니다.
좋은 아이디어를 싣기 위해 사랑방이나 관련 위키프로젝트에 도움을 구해 피드백을 요청할 수 있습니다. 이 과정에서 공동체가 어느 정도 받아들일 수 있는 원칙이 구체화됩니다. 많은 이와의 토론을 통해 공감대가 형성되고 제안을 개선할 수 있습니다.
정책이나 지침은 위키백과 내의 모든 편집자들에게 적용되는 원칙이므로 높은 수준의 총의가 요구됩니다. 제안 문서가 잘 짜여졌고 충분히 논의되었다면, 더 많은 공동체의 편집자와 논의를 하기 위해 승격 제안을 올려야 합니다. 제안 문서 맨 위에 {{제안}}을 붙여 제안 안건임을 알려주고, 토론 문서에 {{의견 요청}}을 붙인 뒤 채택 제안에 관한 토론 문단을 새로 만들면 됩니다. 많은 편집자들에게 알리기 위해 관련 내용을 {{위키백과 소식}}에 올리고 사랑방에 이를 공지해야 하며, 합의가 있을 경우 미디어위키의 sitenotice(위키백과 최상단에 노출되는 구역)에 공지할 수도 있습니다.' metadata={'source': 'https://ko.wikipedia.org/wiki/%EC%9C%84%ED%82%A4%EB%B0%B1%EA%B3%BC:%EC%A0%95%EC%B1%85%EA%B3%BC_%EC%A7%80%EC%B9%A8', 'title': '위키백과:정책과 지침 - 위키백과, 우리 모두의 백과사전', 'language': 'ko'}

 

3. Indexing

분할 텍스트 → 검색 가능한 형태로 변환: 텍스트 - 임베딩 - 벡터저장소에 저장 - 유사성 검색검색 시간↓ 정확도↑

# indexing
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings

vs = Chroma.from_documents(documents=splits,
                           embedding=OpenAIEmbeddings())

docs = vs.similarity_search("격하 과정에 대해 설명해주세요.")
print(len(docs))  # 저장된 문서 중 가장 유사한 문서들 개수
print(docs[0].page_content)   # 그 중 가장 유사도가 높은 첫 번째 문서
4
격하
특정 정책이나 지침이 편집 관행이나 공동체 규범이 바뀌며 쓸모없어질 수 있고, 다른 문서가 개선되어 내용이 중복될 수 있으며, 불필요한 내용이 증식할 수도 있습니다. 이 경우 편집자들은 정책을 지침으로 격하하거나, 정책 또는 지침을 보충 설명, 정보문, 수필 또는 중단 문서로 격하할 것을 제안할 수 있습니다. 
격하 과정은 채택 과정과 비슷합니다. 일반적으로 토론 문서 내 논의가 시작되고 프로젝트 문서 상단에 {{새로운 토론|문단=진행 중인 토론 문단}} 틀을 붙여 공동체의 참여를 요청합니다. 논의가 충분히 이루어진 후, 제3의 편집자가 토론을 종료하고 평가한 후 상태 변경 총의가 형성되었는지 판단해야 합니다. 폐지된 정책이나 지침은 최상단에 {{중단}} 틀을 붙여 더 이상 사용하지 않는 정책/지침임을 알립니다.
소수의 공동체 인원만 지지하는 수필, 정보문 및 기타 비공식 문서는 일반적으로 주된 작성자의 사용자 이름공간으로 이동합니다. 이러한 논의는 일반적으로 해당 문서의 토론란에서 이루어지며, 간혹 위키백과:의견 요청을 통해 처리되기도 합니다.

같이 보기
위키백과:위키백과의 정책과 지침 목록
위키백과:의견 요청
수필

위키백과:제품, 절차, 정책
위키백과:위키백과 공동체의 기대와 규범
기타 링크

 

4. Retrieval & Generation

사용자 입력을 바탕으로 쿼리 생성 후, 인덱싱된 데이터에서 가장 관련성 높은 정보 검색 by LangChain의 Retriever()

# 검색&생성까지 포함된 전체 코드

from langchain_openai import ChatOpenAI
from langchain_community.document_loaders import WebBaseLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings

from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser

def format_docs(docs):  # doc 결합
  return '\n\n'.join(doc.page_content for doc in docs)

url = 'https://ko.wikipedia.org/wiki/%EC%9C%84%ED%82%A4%EB%B0%B1%EA%B3%BC:%EC%A0%95%EC%B1%85%EA%B3%BC_%EC%A7%80%EC%B9%A8'
loader = WebBaseLoader(url)

docs = loader.load()    # 웹페이지 텍스트 -> Documents

splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
splits = splitter.split_documents(docs)

vs = Chroma.from_documents(documents=splits,
                           embedding=OpenAIEmbeddings())

template = '''Answer the question based only on the following context:
{context}
Question: {question}
'''

prom = ChatPromptTemplate.from_template(template)
model = ChatOpenAI(model='gpt-3.5-turbo-0125', temperature=0)
retriever = vs.as_retriever()   # 검색

rag_chain = (
    {'context': retriever | format_docs,
     'question': RunnablePassthrough()}
    | prom
    | model
    | StrOutputParser()
)

rag_chain.invoke("격하 과정에 대해 설명해주세요.")
격하 과정은 특정 정책이나 지침이 더 이상 필요하지 않거나 개선이 필요한 경우에 해당 정책이나 지침을 수정하거나 중단하는 과정을 말합니다. 이를 위해 편집자들은 해당 정책이나 지침을 다른 형태로 변형하거나 중단할 것을 제안하고, 이에 대한 토론을 거친 후 결정이 내려집니다. 격하 과정은 채택 과정과 유사하며, 토론을 통해 공동체의 참여를 유도하고, 결정이 내려진 후에는 해당 정책이나 지침이 중단되었음을 알리는 틀을 붙여줍니다.

 

 

cf)

https://wikidocs.net/231364

https://aws.amazon.com/ko/what-is/langchain/

https://www.samsungsds.com/kr/insights/what-is-langchain.html