방카@Dev
[AI/Langchain][인프런]모두를 위한 대규모 언어 모델 LLM Part 2 - 랭체인(LangChain)으로 나만의 ChatGPT 만들기 본문
[AI/Langchain][인프런]모두를 위한 대규모 언어 모델 LLM Part 2 - 랭체인(LangChain)으로 나만의 ChatGPT 만들기
방카킴 2024. 7. 13. 15:01
나는 유데미에서 이 강의를 들었는데 유데미에는 섹션 15부터 업데이트가 되어 있지 않다. 인프런 강의에는 업데이트되어 있으니 인프런으로 수강하면 된다.
1. RAG(Retrieval-Augmented Generation ; 검색증강생성)이란?
- RAG는 LLM의 '사실 관계 오류 가능성'과 '맥락 이해의 한계'를 개선하는데 초점을 맞춘 방법으로, LLM에 외부 지식 베이스를 연결하여 모델의 생성 능력과 사실 관계 파악능력을 향상시키는 기술(https://modulabs.co.kr/blog/retrieval-augmented-generation/)
- 새로운 지식에 관한 텍스트 데이터 소스를 embedding해서 vector stores에 저장하고, 프롬프트 구성을 진행할 때 외부 데이터 소스로부터 가져온 텍스트 데이터를 함꼐 이용해서 프롬프트를 구성한 뒤 LLM 으로 부터 답변을 얻어냄.
- 전체적인 코드 구현방식은 외부 텍스트 데이터 소스를 document_loader로 불러오고, textSplitter를 이용해 부분 청크로 분리한 다음, embedding 모델로 임베딩으로 바꿔서 vectorstore 에 저장한 후, query String과 유사한 임베딩 벡터를 찾아 유사한 텍스트들을 반환하게 됨
- source→load : document-loader module
- Load → transform : 더 작은 단위로 나눔(청크분할)
- Transform →Embed : embeddings 모듈 사용
- embed → rstore : embedding한 모델 벡터스토어에 유사값 찾을 수 있게 저장
- store → retriever : 검색도구, 벡터 저장소에서 문서를 검색하는 도구
- retreiver는 llm과 연동하여 query string으로 질문을 주면 retriever가 벡터스토어에서 유사한 청크를 찾아주고 청크텍스트를 토대로 최종적으로 llm이 리턴된 텍스트와 질문을 조합해서 최종답변을 만들어주는 역할 수행
2. DocumentLoaders(from langchain.document_loaders)
1) WebBaseLoader : 웹페이지 스크래핑
2) CSV : CSVLoader(file_path='./mlb_teams_2012.csv', source_column="Team")
3) File Directory : DirectoryLoader('./sample_data', glob="**/*.md")
4) HTML : UnstructuredHTMLLoader("./sample_html.html"), BSHTMLLoader("./sample_html.html")
5) JSON
!pip install jq
from langchain.document_loaders import JSONLoader
from pprint import pprint
loader = JSONLoader(
file_path='./sample_data/anscombe.json',
jq_schema='.', // jq_schema='.[]', jq_schema='.[].Series'
text_content=False)
data = loader.load()
pprint(data)
6) Markdown : UnstructuredMarkdownLoader(markdown_path)
7) PDF : PyPDFLoader("./llama1_paper.pdf")
8) XML
from langchain_community.document_loaders import UnstructuredXMLLoader
loader = UnstructuredXMLLoader(
"./example_data/factbook.xml",
)
docs = loader.load()
docs[0]
3. transformer(RecursiveCharacterTextSplitter)
기본으로 추천하는 Text splitter는 RecursiveCharacterTextSplitter
- 기본적으로 사용하는 구분 기호 ["\n\n", "\n", " ", ""]
- length_function : chunk의 길이를 계산하는 방법을 지정 (문자의 길이 or 토큰의 개수)
- chunk_size : (length_function에서 정의한 기준에 따른) chunk의 최대 크기
- chunk_overlap : chunk 간에 최대 중복 크기, 자연스러운 연결을 위해서 적절한 길이의 중복이 있는 것이 좋습니다.
- add_start_index : 원본 문서내에서 chunk의 시작위치를 metadata에 포함할지 말지를 결정
from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
chunk_size = 100, //청크 크기
chunk_overlap = 20, //중복
length_function = len,
add_start_index = True,
)
texts = text_splitter.create_documents([llm_example_text])
print(texts[0])
- 토큰으로 구분하기
tiktoken은 OpenAI에서 개발된 BPE 알고리즘을 사용하는 tokenizer
!pip install tiktoken
text_splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder(
chunk_size=100, chunk_overlap=0
)
texts = text_splitter.split_text(llm_example_text)
4. Embedding
- OpenAI 임베딩 모델 사용하는 법
from langchain.embeddings import OpenAIEmbeddings
embeddings_model = OpenAIEmbeddings(openai_api_key=OPENAI_KEY) # text-embedding-ada-002
embeddings = embeddings_model.embed_documents(
[
"안녕!",
"빨간색 공",
"파란색 공",
"붉은색 공",
"푸른색 공"
]
)
- HuggingFace 오픈소스 임베딩 모델 사용하는 법
from langchain.embeddings import HuggingFaceEmbeddings
model_name = "sentence-transformers/all-mpnet-base-v2"
#model_name = "BAAI/bge-large-en-v1.5" # (2023.11.16 기준 공개모델 중 LeaderBoard 1위 모델)
#model_name = "jhgan/ko-sroberta-multitask" # (KorNLU 데이터셋에 학습시킨 한국어 임베딩 모델)
model_kwargs = {'device': 'cpu'}
encode_kwargs = {'normalize_embeddings': False}
hf = HuggingFaceEmbeddings(
model_name=model_name,
model_kwargs=model_kwargs,
encode_kwargs=encode_kwargs
)
5. Vector Store
from langchain.vectorstores import Chroma
db = Chroma.from_documents(documents, embeddings_model) //임베딩과 임베딩 저장을 수행
6. Retriever
retriever = vectorstore.as_retriever()
retrieved_docs = retriever.invoke(
"저출산을 극복한 나라들은 어디가 있어?"
)
print(retrieved_docs[0].page_content)
7. Memory
이전대화내용을 저장하기 위해 memory 기능 제공
prompt에 vector store, retriever result와 함께 memory에 저장된 내용으로 프롬프트 생성
- ConversationChain : 유저의 입력과 모델의 출력값을 history로 가지고 있는 built-in memory chain 모듈
from langchain.chains import ConversationChain
conversation = ConversationChain(llm=chat)
conversation.run("이 문장을 영어에서 한국어로 번역하세요 : I love programming.")
8. LangChain을 이용하여 요약 실습하기
- 핵심 이슈는 문서들을 어떻게 LLM의 Context Window에 전달할 것인가
1) 스터프(Stuff) : 모든 문서를 단일 프롬프트에 넣는 가장 간단한 방식
(https://python.langchain.com/v0.1/docs/modules/chains/#lcel-chains)
from langchain.chains.combine_documents.stuff import StuffDocumentsChain
from langchain.chains.llm import LLMChain
from langchain.prompts import PromptTemplate
# Define prompt
prompt_template = """아래 내용을 간략히 요약해줘.:
"{text}"
요약된 내용:"""
prompt = PromptTemplate.from_template(prompt_template)
# Define LLM chain
llm = ChatOpenAI(temperature=0, model_name="gpt-3.5-turbo-16k", openai_api_key=OPENAI_KEY)
llm_chain = LLMChain(llm=llm, prompt=prompt)
# Define StuffDocumentsChain
stuff_chain = StuffDocumentsChain(llm_chain=llm_chain, document_variable_name="text")
docs = loader.load()
print(stuff_chain.run(docs))
2) 맵-리듀스(Map-reduce) : 각 문서를 “맵(map)” 단계에서 개별적으로 요약한 다음, 요약본을 최종 요약으로 “리듀스(reduce)”하는 방식
-우선 각 문서를 개별 요약으로 매핑하는 LLMChain을 사용한 후 ReduceDocumentsChain을 사용하여 그 요약들을 하나의 전체 요약으로 결합
from langchain.chains import MapReduceDocumentsChain, ReduceDocumentsChain
from langchain.text_splitter import CharacterTextSplitter
# Map
map_template = """다음은 일련의 문서들입니다.
{docs}
이 문서 목록을 바탕으로, 주요 주제들을 파악해주세요.
도움이 되는 답변:"""
map_prompt = PromptTemplate.from_template(map_template)
map_chain = LLMChain(llm=llm, prompt=map_prompt)
- ReduceDocumentsChain은 문서 매핑 결과를 취해 단일 출력으로 줄이는 역할
- 일반적인 CombineDocumentsChain(예: StuffDocumentsChain)을 래핑하지만, 그들의 누적 크기가 token_max를 초과하는 경우 문서를 결합하기 전에 축소할 수 있는 능력을 추가
- 이 예제에서는 문서를 결합하기 위해 사용한 체인을 문서를 축소하기 위해서도 재사용할 수 있음
- 따라서, 매핑된 문서들의 누적 토큰 수가 4000 토큰을 초과하는 경우, < 4000 토큰의 배치로 문서들을 재귀적으로 StuffDocumentsChain에 전달하여 배치 요약 생성
- 그리고 그 배치 요약들의 누적 토큰 수가 4000 토큰 미만이 되면, 모든 것을 마지막으로 StuffDocumentsChain에 한 번 더 전달하여 최종 요약을 생성
# Reduce
reduce_template = """다음은 요약들의 집합입니다:
{docs}
이것들을 가져다가 최종적으로 통합된 주요 주제들의 요약으로 정리해주세요.
도움이 되는 답변:
"""
reduce_prompt = PromptTemplate.from_template(reduce_template)
# Run chain
reduce_chain = LLMChain(llm=llm, prompt=reduce_prompt)
# Takes a list of documents, combines them into a single string, and passes this to an LLMChain
combine_documents_chain = StuffDocumentsChain(
llm_chain=reduce_chain, document_variable_name="docs"
)
# Combines and iteravely reduces the mapped documents
reduce_documents_chain = ReduceDocumentsChain(
# This is final chain that is called.
combine_documents_chain=combine_documents_chain,
# If documents exceed context for `StuffDocumentsChain`
collapse_documents_chain=combine_documents_chain,
# The maximum number of tokens to group documents into.
token_max=4000,
)
- 맵과 리듀스 체인을 하나로 결합함
# Combining documents by mapping a chain over them, then combining results
map_reduce_chain = MapReduceDocumentsChain(
# Map chain
llm_chain=map_chain,
# Reduce chain
reduce_documents_chain=reduce_documents_chain,
# The variable name in the llm_chain to put the documents in
document_variable_name="docs",
# Return the results of the map steps in the output
return_intermediate_steps=False,
)
text_splitter = CharacterTextSplitter.from_tiktoken_encoder(
chunk_size=1000, chunk_overlap=0
)
split_docs = text_splitter.split_documents(docs)
9. 엔티티 추출하기(Entity Extraction)
reference: https://python.langchain.com/v0.1/docs/use_cases/extraction/
#Schema
schema = {
"properties": {
"aggressiveness": {
"type": "integer",
"enum": [1, 2, 3, 4, 5],
"description": "describes how aggressive the statement is, the higher the number the more aggressive",
},
"language": {
"type": "string",
"enum": ["spanish", "english", "french", "german", "italian", "korean"],
},
"sentiment": {
"type": "string",
"enum": ["positive", "negative"],
},
},
"required": ["language", "sentiment", "aggressiveness"],
}
#LLM
llm = ChatOpenAI(temperature=0, model="gpt-3.5-turbo", openai_api_key=OPENAI_KEY)
chain = create_tagging_chain(schema, llm)
inp = "너에게 정말 화가 났어! 너에게 마땅한 대가를 치르게 할거야!"
chain.run(inp)
'AI' 카테고리의 다른 글
[24.12.11]서강대학교 AI•SW대학원 데싸•인공지능전공 합격 (1) | 2024.12.13 |
---|---|
[AI]LLM을 활용한 실전 AI 애플리케이션 개발_2장.트랜스포머 아키텍쳐 (1) | 2024.10.04 |
AI관련 참고자료 (1) | 2024.10.02 |
[GenCon]생성형AI 컨퍼런스_Gencon AI Conference for Dev 후기 (1) | 2024.10.01 |