김이언
김이언
🏅 AI 마스터
🌿 뉴비 파트너
🌈 지피터스금손
🚀 SNS 챌린지 달성자

Langchain - 2차 과제

과제를 할수록 오리무중입니다.🤪 요구되는 답을 얻었으니 기쁘긴 한데, 명확히 알 수가 없어요. ㅎㅎ 원래 이런 걸까요? 점차 나아지리라 믿어봅니다.😁

  • 랭체인 2-1. 벡터 저장소를 활용한 유사도 검색

  • 랭체인 2-2. 검색-강화 생성 체인 구축하기

  • 랭체인 2-3. 에이전트와 실행기를 이용한 자동화된 작업 처리




랭체인 2-1. 벡터 저장소를 활용한 유사도 검색

이 실습을 통해 사용자 입력을 기반으로 LLM 모델을 활용하여 원하는 출력을 생성하는 방법을 배우게 됩니다. 추가로, 명령어 실행 시 필요한 인자나 파라미터의 설정 방법, 출력 포맷 변환 방법 등을 학습할 수 있습니다.

  1. 첫 번째 단계에서는 문서(state_of_the_union.txt)를 로드하고 적절한 크기로 나눠줍니다. 이후, 이를 임베딩하여 벡터 저장소에 로드하는 과정을 합니다. 두 번째 단계에서는 주어진 쿼리에 대해 유사도 검색을 수행하고, '가장 유사한' 결과를 검색하여 출력합니다.

  2. 예를 들어, "What did the president say about Ketanji Brown Jackson"이라는 쿼리에 대해 유사도 검색(similarity_search)을 수행하고, 두번째로 최대 한계 관련성 검색(MMR)으로 2개의 검색된 문서의 내용을 출력하는 과정을 실습합니다

from langchain_community.document_loaders import TextLoader
from langchain_openai import OpenAIEmbeddings
from langchain_text_splitters import CharacterTextSplitter
from langchain_chroma import Chroma

# 텍스트 파일을 인코딩(UTF-8)하여 로드
raw_documents = TextLoader('./state_of_the_union.txt', encoding='utf-8').load()

# 텍스트를 일정한 크기(1000자)로 나누고, 중복되는 부분이 없도록 설정
# 텍스트를 분할하고 저장
# 분할된 문서들을 임베딩하여 DB 구축
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
documents = text_splitter.split_documents(raw_documents)
db = Chroma.from_documents(documents, OpenAIEmbeddings(model="text-embedding-3-small"))

# 검색할 쿼리 설정
query = input("쿼리: ")

# 유사도 검색(similarity_search)
print("\n======= Similarity Search ======")

# DB에 저장된 문서 중 쿼리와 가장 유사한 문서 검색
# 검색된 문서들 중 첫번째 문서 내용 출력
docs = db.similarity_search(query)
print(docs[0].page_content)

# 최대 한계 관련성(Maximum Marginal Relevance, MMR) 검색
# 쿼리와 관련성이 높으면서도 서로 다양한 내용을 포함하는 문서들을 선택하는 검색 기법
# 1) 먼저 쿼리와 유사도가 높은 fetch_k개의 문서를 검색하고
# 2) 쿼리와 가장 유사한 문서를 하나 선택
# 3) 나머지 문서들 중 이미 선택된 문서와는 다른 내용을 가진 문서를 선택
# 4) 이 과정을 k개의 문서가 선택될 때까지 반복
print("\n======= MMR ======")

# 10개의 문서 검색 후 2개의 문서를 선택
mmr_docs = db.max_marginal_relevance_search(query, k=2, fetch_k=10)

# 검색 결과로 선택된 문서들을 순서대로 출력
for i in range(len(mmr_docs)):
    print(f"\n<{i+1}> {mmr_docs[i].page_content}")
  • ‘자신의 문서를 업로드하여 쪼갠 후 저장하고, 2가지 방법으로 검색하기’라고 이해했습니다.


랭체인 2-2. 검색-강화 생성 체인 구축하기

"검색-강화 생성" 체인을 통해 특정 질문에 대한 컨텍스트를 검색하고, 이를 기반으로 질문에 답하는 방법을 배웁니다. 이 과정에서 벡터 저장소를 활용하여 관련 컨텍스트를 검색하고, 검색된 컨텍스트를 사용하여 모델이 질문에 답하도록 합니다.

이 실습을 통해, 관련 컨텍스트를 검색하여 모델의 응답 생성을 강화하는 "검색-강화 생성" 체인을 구축하는 방법을 배우게 됩니다. 검색된 컨텍스트를 효과적으로 활용하여 모델이 더 정확하고 유용한 응답을 생성할 수 있도록 하는 전략에 대해 학습합니다.

  1. “harrison worked at kensho”라는 문장을 FAISS에 저장합니다.

  2. "where did harrison work?”라는 질문에 대한 답변을 출력합니다.

  3. 두번째 체인에서는 “where did harrison work?”이라는 질문에 대한 답변을 이탈리아어로 답변을 출력합니다.

from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain_community.vectorstores import FAISS
from langchain.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough

# FAISS(Facebook AI Similarity Search)는 Facebook AI Research에 의해 개발된 라이브러리
# 대규모 벡터 데이터셋에서 유사도 검색을 빠르고 효율적으로 수행
# 특히 벡터의 압축된 표현을 사용하여 메모리 사용량을 최소화하면서도 검색 속도를 극대화

# FAISS 라이브러리로 벡터 스토어 생성
# FAISS는 주어진 텍스트 데이터 "harrison worked at kensho"에 대해 임베딩을 생성하여 저장
vectorstore = FAISS.from_texts(
    ["harrison worked at kensho"], embedding=OpenAIEmbeddings(model="text-embedding-3-small") 
)

# 벡터 스토어를 검색기로 변환, 검색기로 쿼리 관련 문서 검색 가능
retriever = vectorstore.as_retriever()

# 대화 모델 생성
model = ChatOpenAI(model="gpt-3.5-turbo")

# 주어진 문맥(context)을 기반으로 질문(question)에 답변하는 형식의 프롬프트 템플릿 정의
# 템플릿에서 프롬프트 객체 생성
template1 = """Answer the question based only on the following context:
{context}

Question: {question}
"""
prompt1 = ChatPromptTemplate.from_template(template1)

# 체인 설정
# 질문을 받아 관련 문서를 검색하고 결과를 context로 전달
retrieval_chain = (
    {"context": retriever, "question": RunnablePassthrough()} 
    | prompt1
    | model
    | StrOutputParser()
)

# 체인을 실행하여 결과 출력
answer1 = retrieval_chain.invoke("where did harrison work?")
print(answer1)

# 첫번째 체인의 응답을 이탈리아로 번역하는 프롬프트 템플릿, 체인 설정 후 실행
prompt2 = ChatPromptTemplate.from_template("Translate {answer} into Italian.")
translation_chain = prompt2 | model | StrOutputParser()
answer2 = translation_chain.invoke({"answer": answer1})
print(answer2)
  • 이번엔 직접 입력한 내용을 저장하고 검색하기였습니다.


랭체인 2-3. 에이전트와 실행기를 이용한 자동화된 작업 처리

이 실습을 통해, 특정 요청에 대해 자동으로 정보를 검색하고 처리하여 응답을 생성하는 에이전트의 구성과 실행 방법을 배우게 됩니다. 입력 처리, 중간 단계 데이터의 처리 방법, 프롬프트의 사용, 모델 및 출력 파서의 설정에 대한 중요 개념과 기술에 대해 학습합니다.

  1. Runnable을 에이전트로 전달하여 특정 작업을 자동화하는 방법을 배웁니다. 이 과정에서는 사용자의 질문이나 요청에 따라 적절한 도구를 선택하고, 그 결과를 처리하여 최종 응답을 생성하는 에이전트의 구성과 실행 방법을 실습합니다.

  2. 다음 임의의 도구를 가정하여 질문 “"whats the weather in New york?” 라는 질문에 대해 응답을 생성하는 과정을 실습합니다.

# OpenAI와 SerpAI의 API 키를 환경변수로 등록함

from langchain import hub
from langchain.agents import AgentExecutor, create_react_agent
from langchain_openai import ChatOpenAI
from langchain_community.agent_toolkits.load_tools import load_tools 

# 검색 작업을 캡슐화하는 Runnable 클래스 정의
# 실행 가능한 작업 단위인 Runnable에 해당함
class SearchRunnable:   
   # 초기화 메소드, 검색 쿼리를 받아 저장
   def __init__(self, query): 
       """
       Initializes a new instance of the SearchRunnable class.
       Args: 
           query (str): The search query.
       """   
       self.query = query

   # 에이전트를 사용하여 검색을 수행하고 결과를 반환
   def run(self, agent):
       """
       Performs the search using the provided agent and returns the search result.
       Args:
           agent: The search agent to use for the search.
       Returns:
           str: The search result.
       """  
       result = agent.invoke({"input": self.query})
       return result["output"]

# 모델 생성
llm = ChatOpenAI(model_name="gpt-3.5-turbo", temperature=0)

# SerpAPI 도구를 로드하여 검색 기능 제공
tools = load_tools(["serpapi"], llm=llm)

# "hwchase17/react" 프롬프트 템플릿을 가져오기
prompt = hub.pull("hwchase17/react")

# 모델, 도구, 프롬프트를 사용하여 React 에이전트 생성
# 생성된 에이전트와 도구를 사용하여 AgentExecutor로 검색 에이전트 생성
agent = create_react_agent(llm, tools, prompt)
search_agent = AgentExecutor(agent=agent, tools=tools, verbose=True)

# 검색 수행 함수
def search(query: str) -> str:
   """
   Performs a search using the given query and returns the search result.
   Args:
       query (str): The query string to search for.
   Returns:
       str: The search result found by the search agent.
   """
   runnable = SearchRunnable(query) # 주어진 쿼리로 SearchRunnable 객체 생성
   return runnable.run(search_agent) # SearchRunnable의 run 메소드 호출, 검색 에이전트 검색 결과 반환

# 사용자로부터 검색 쿼리를 입력받기
user_query = input("질문 입력: ")

# search 함수로 사용자 쿼리에 대한 검색 결과 얻기, 출력
result = search(user_query)
print("검색 결과:", result)
  • SERP API를 이용해보았어요.

  • LLM과 Tool 그리고 프롬프트를 결합하여 검색 Agent를 만들고, 질문을 받아 Agent를 실행했다고 이해했습니다.

  • Runnable이란 개념은 … 알아가고 있습니다.


과제를 통해 학습한 것을 제것으로 만들어야 하는데 쉽지 않습니다. 과연 뭔가를 만들어볼 수 있을까요?😝


#11기랭체인

4
2개의 답글

👉 이 게시글도 읽어보세요