# 1. LangChain과 ChromaDB란 무엇인가?
## 1-1. LangChain
LangChain은 자연어 처리(NLP) 및 언어 모델을 활용하여 다양한 애플리케이션을 개발할 수 있도록 도와주는 프레임워크입니다. 이 프레임워크는 주로 다음과 같은 기능을 제공합니다:
1. 모델 통합: 다양한 언어 모델(API)을 통합하여 사용자가 원하는 방식으로 쉽게 활용할 수 있습니다. OpenAI, Hugging Face 등 다양한 모델과의 호환성을 지원합니다.
2. 체인(Chain) 구성: LangChain의 핵심 개념은 '체인'입니다. 사용자는 여러 개의 작업을 연결하여 복잡한 작업 흐름을 만들 수 있습니다. 예를 들어, 데이터 수집, 처리, 모델 예측 등의 과정을 연속적으로 구성할 수 있습니다.
3. 데이터 소스 연결: LangChain은 외부 데이터 소스(예: 데이터베이스, API)와의 연결을 지원하여, 모델이 더 많은 정보를 바탕으로 작업을 수행할 수 있게 합니다.
4. 사용자 정의: 사용자에게 맞춤형 작업 흐름을 구성할 수 있는 유연성을 제공하여, 특정 요구사항에 맞는 솔루션을 만들 수 있습니다.
LangChain은 AI 및 언어 모델을 활용하여 비즈니스 애플리케이션, 챗봇, 데이터 분석 도구 등 다양한 분야에 응용할 수 있는 매우 강력한 도구입니다.
Response by 'ChatGPT 4o mini'
## 1-2. ChromaDB
ChromaDB는 대규모 데이터셋을 효율적으로 저장하고 검색하기 위한 오픈 소스 벡터 데이터베이스입니다. 주로 다음과 같은 기능과 특성을 갖추고 있습니다:
1. 벡터 저장: ChromaDB는 고차원 벡터(예: 텍스트, 이미지, 오디오 등)의 저장과 검색을 최적화하여, 머신러닝 모델의 출력 결과를 효과적으로 관리할 수 있습니다.
2. 빠른 검색: 효율적인 검색 알고리즘을 통해 대량의 벡터 데이터에서 유사한 항목을 신속하게 찾을 수 있습니다. 이는 특히 추천 시스템이나 유사도 검색에 유용합니다.
3. 사용자 친화성: 간편한 API를 제공하여, 개발자들이 쉽게 데이터베이스를 구축하고 사용할 수 있도록 지원합니다. 이는 코드 몇 줄로 기본적인 CRUD(Create, Read, Update, Delete) 작업을 수행할 수 있게 합니다.
4. 확장성: ChromaDB는 클라우드 환경에서의 확장을 지원하여, 데이터의 양이 많아지더라도 성능을 유지할 수 있도록 설계되었습니다.
5. 다양한 데이터 형식 지원: 텍스트, 이미지, 오디오 등 다양한 데이터 유형을 처리할 수 있어, 다양한 분야에 활용할 수 있습니다.
ChromaDB는 AI 및 데이터 과학 분야에서 데이터 관리를 용이하게 하여, 다양한 머신러닝 및 딥러닝 애플리케이션에 적합한 도구입니다.
Response by 'ChatGPT 4o mini'
# 2. LangChain과 ChromaDB를 사용하여 RAG 구현하기
위에서 설명했듯이 ChromaDB는 문서 검색을 관리하는 저장소, LangChain은 LLM을 효과적으로 사용할 수 있는 프레임워크의 개념이다. LangChain 프레임워크에서 ChromaDB와 연동하는 라이브러리를 제공해서 더 쉽게 Retrieval Augmentated Generation(RAG)를 구현할 수 있다.
🔽 Requirements
pip install -qU langchain langchain-chroma langchain-community langchain-core langchain-huggingface langchain-text-splitters langdetect langsmith pydantic==2.9.2
## 2-1. ChromaDB 초기화
from langchain_chroma import Chroma
from langchain_huggingface import HuggingFaceEmbeddings
ENCODER = # 임베딩 모델. (Huggingface model id)
COLLECTION_NAME = # Chroma collection 이름
CHROMA_PATH = # Chroma vector store 저장할 경로
# Init chromadb
embedding_func = HuggingFaceEmbeddings(model_name=ENCODER, encode_kwargs={'normalize_embeddings':True},)
vectorstore = Chroma(
collection_name=COLLECTION_NAME,
embedding_function=embedding_func,
persist_directory=CHROMA_PATH,
)
- 'collection_name': collection에 접근하기 위한 키... 정도로 생각하면 될 듯
- 'embedding_function': Chroma가 문서를 벡터화 할 때 사용하는 인코딩 방식이다. Huggingface에 다양한 encoding 모델들이 있으니 찾아보고 사용에 맞게 적절한 모델을 선택하면 된다.
- 'persist_directory': Chroma가 문서를 저장할 실제적인 경로
## 2-2. 문서 임베딩
1) 파일 읽어오기
from langchain_community.document_loaders import PyPDFLoader
file_name = # 읽어오려는 파일 경로
loader = PyPDFLoader(file_name)
pages = loader.load()
text = ""
for page in pages:
sub = page.page_content
text += sub
위의 예시는 '.pdf' 파일을 읽어오는 코드인데, 'langchain_community.document_loaders' 에서 다른 형식의 파일들을 파싱해오는 코드들이 많으니 다른 사이트들을 참고해서 필요한 모듈을 쓰면 된다.
2) 문서 chunking 하고 vectorstore에 저장하기
from transformers import AutoTokenizer
from langchain_text_splitters import CharacterTextSplitter
from langchain_core.documents import Document
# token size 기준으로 contents split
tokenizer = AutoTokenizer.from_pretrained(ENCODER)
text_splitter = CharacterTextSplitter.from_huggingface_tokenizer(
tokenizer,
chunk_size=CHUNK_SIZE,
chunk_overlap=CHUNK_OVERLAP,
separator="\n" # default: "\n\n"
)
documents=[] # split 한 문서들을 담기 위한 array
split_conts = text_splitter.split_text(text)
for chunk_idx, split_cont in enumerate(split_conts):
documents.append(Document(
page_content=split_cont,
metadata={
"file_name": file_name,
},
id=chunk_idx,
))
idx+=1
vectorstore.add_documents(documents)
나는 tokenizer 기준으로 청킹을 수행했다. Tokenizer는 문서를 embedding 할 때 사용했던 encoder와 동일한 모델을 선택했다.
'langchain_text_splitter'에 다양한 splitter들이 있으니 상황에 맞게 선택해 쓰면 된다.
Splitter는 seperator를 기준으로 자르는데, chunk_size와 chunk_overlap이 어떻게 작동하는지는 더 살펴봐야 할 것 같음.
## 2-3. Retriever 설정하기
SEARCH_TYPE="similarity" # cosine similarity
TOPK = 3
# Init Retriver
retriever = vectorstore.as_retriever(
search_type=SEARCH_TYPE,
search_kwargs={
'k': TOPK,
}
)
'search_type="mrr"'로 설정하면 MRR(Maximal Marginal Relevance) 검색이 가능하다
## 2-4 Chain 만들기
from langchain_core.prompts import PromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from langchain_huggingface.llms import HuggingFacePipeline
INSTRUCT= # llm 으로 사용할 모델 id
# Create Template
template='''당신은 도움이 되는 한국어 어시스턴트입니다. 검색된 context를 이용해 question에 답변하십시오. 만약 정답을 모른다면, 모르겠다고 답변하세요. 답변은 한국어로 간결하게 온전한 문장으로 유지하세요.
Context: {context}
Question: {question}
Answer: '''
prompt = PromptTemplate.from_template(template)
# Set LLM
llm = HuggingFacePipeline.from_model_id(
model_id=INSTRUCT,
task="text-generation",
pipeline_kwargs={
"max_new_tokens": 512,
},
device=0,
)
# 검색 결과로 나온 문서를 원하는 포멧으로 만들어주기 위한 함수 (없어도 됨)
def format_docs(docs):
context = ""
for doc in docs:
context+=doc.metadata["file_name"]+"\n"
context+=doc.page_content
context+="\n\n"
return context
# Create chain
chain = (
{"context": retriever | format_docs, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
chain을 생성해서 retriever(vector db)와 프롬프트, LLM을 간단하게 연결할 수 있다.
## 2-5. Retrieval 하여 LLM에서 질의응답 받기
query=input("질문: ")
res = chain.invoke(query)
print(f"response: \n{res}")
Reference
- https://python.langchain.com/v0.1/docs/modules/data_connection/document_loaders/
- https://wikidocs.net/231429