반응형

 

 

LLM 개발이 상용화 되고 있는 건 알겠는데,,, 초심자가 접근하기에 정보가 너무 많다...!

 

그래서 준비했습니다

 

RAG 한판 정리..!

사실 한판에 정리한다는건 말도 안되지만, 그냥 한눈에 보기 편한(?)

 

 

[개발 진행 순서]

 

 

이렇게만 보면 아무도 이해 못하거든요.. 찾기도 귀찮고 

간단하게 예제를 만들어보았습니다.

 

저는 위키피디아를 이용해서 LCA에 대한 내용을 학습시켜 보았습니다!

 

1. 문서업로드

url1 , url2를 추가해서 여러 url을 불러올 수 있습니다.

class에 들어갈 내용은 "개발자 모드" 에서 html 파서를 적절하게 배치하면 된답니다

from langchain_community.document_loaders import WebBaseLoader  # 웹 로더 임포트
from langchain.text_splitter import RecursiveCharacterTextSplitter  # 텍스트 분할기
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_community.vectorstores import FAISS  # 벡터 저장소
import bs4

# 1. 웹페이지 로드: 문서 로드
url1 = 'https://ko.wikipedia.org/wiki/%ED%83%84%EC%86%8C_%EB%B0%9C%EC%9E%90%EA%B5%AD'
url2 = 'https://ko.wikipedia.org/wiki/%EC%A0%84_%EA%B3%BC%EC%A0%95_%ED%8F%89%EA%B0%80'
loader = WebBaseLoader(
    web_path=(url1,url2),
    bs_kwargs=dict(
        parse_only=bs4.SoupStrainer(
            class_= ("mw-page-title-main", "mw-content-ltr mw-parser-output")
        )
    ),
)
docs = loader.load()

 

 

 

2. 텍스트 분할

텍스트 분할이 참 과정이 어려운데요,

핵심은 결국 문장을 어디서 자를것인지(chunk_size)

자른 문장끼리 얼마나 연결 시킬건지(chunk_overlap) <- 앞 뒤 문맥을 알아야 하잖아요?

아래와 같이 원하는 청크를 적절하게 수정해봅니다

# 2. 텍스트 분할: 긴 문서를 검색할 수 있는 짧은 청크로 분할
text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
split_docs = text_splitter.split_documents(docs)

 

 

3. 벡터 저장소(vector DB)

벡터 저장소는 참 중요한 부분중의 하나인데요, 원리가 복잡하지만

간단하게 설명하면 임베딩(수치화) 해서 유사도(코사인,유클리디안) 등으로 검색을 하기위한

"성능 향상 작업" 이라고 보시면 됩니다.

# 3. 벡터 저장소 구축: 문서 청크를 벡터로 변환하고 인덱싱
embedding_model = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")  # 적절한 모델 이름 사용
vector_store = FAISS.from_documents(split_docs, embedding_model)

 

4. 검색기 설정

 

prompt를 지정해주고 (양식 지정)

콜백 부분은 API 통신 내용이라 필요 없습니다!

 

스트리밍 LLM과 챗봇 체인을 확인하시면 

prompt | llm | StrOutputParser()

 

prompt(미리 양식을 주고) -> llm(모델에 전달) -> StrOutputParser(대답)

이런 구조입니다.

# 4. 검색기 설정: 벡터 저장소를 사용하는 검색기 설정
retriever = vector_store.as_retriever()
# 챗봇의 기본 프롬프트 설정
prompt = ChatPromptTemplate.from_messages(
    [
        (
            "system",
            "당신은 Question-Answering 챗봇입니다. 주어진 질문에 대한 답변을 제공해주세요.",
        ),
        MessagesPlaceholder(variable_name="history"),
        ("human", "{input}"),
    ]
)

# 콜백 관리자를 생성하고, 스트리밍 핸들러를 추가
manager = AsyncCallbackManager([])
stream_manager = AsyncCallbackManager([stream_handler])

# 트레이싱 활성화 시, 트레이서를 설정하고 콜백 관리자가 이를 처리하도록 추가
if tracing:
    tracer = LangChainTracer()
    tracer.load_default_session()
    manager.add_handler(tracer)
    stream_manager.add_handler(tracer)

# 스트리밍 LLM 설정 (여기서는 Ollama 모델 사용)
llm = ChatOllama(model="ollama-bllossom",
         temperature=0,
 )

# 챗봇 체인 생성
chain = prompt | llm | StrOutputParser()

chain_with_history = RunnableWithMessageHistory(
    chain,
    lambda session_id: RedisChatMessageHistory(session_id, url=REDIS_URL),
    input_messages_key="input",
    history_messages_key="history",
)

return chain_with_history

 

 

간단하게 프론트로 보여주고 질문을 던졌더니, 아래와 같은 답변을 해주네요!

 

 

 

 

 

반응형

'머신러닝 > 자연어처리의 모든것' 카테고리의 다른 글

RAG와 Lang chain에 대하여  (0) 2024.08.01