08-langchain-retrieval-agent

2024. 1. 18. 19:03langchain

검색 에이전트

이전 장에서 검색 증대 및 대화 에이전트가 얼마나 강력한지 살펴보았습니다. 대화형 에이전트는 데이터 최신성, 특정 도메인에 대한 지식 또는 내부 문서에 액세스하는 데 어려움을 겪을 수 있습니다. 에이전트를 검색 확대 도구와 결합하면 더 이상 이러한 문제가 발생하지 않습니다. 에이전트를 사용하지 않는 검색 확대는 모든 쿼리로 컨텍스트를 검색한다는 의미입니다. 다시 말하지만, 모든 쿼리에 외부 지식에 대한 액세스가 필요한 것은 아니기 때문에 이것이 항상 이상적인 것은 아닙니다.

이 두가지 방법을 병합하면 두 가지 장점을 모두 얻을 수 있습니다.

In [ ]:
!python3 -m venv langchain
!source langchain/bin/activate
In [ ]:
!pip3 install --upgrade pip --user
In [ ]:
!pip uninstall datasets  # shell에서 실행해 주세요.
In [ ]:
!pip install -qU \
    openai==0.27.7 \
    "pinecone-client[grpc]"==2.2.1 \
    langchain==0.0.162 \
    tiktoken==0.4.0 \
    datasets==2.12.0
In [ ]:
만약 위 코드를 실행하였을 때 dependency conflicts 에러가 나오면 pip install --upgrade pip --user를 실행 or venv 폴더의 pyvenv.cfg에서
include-system-site-packages의 값을 true로 해 주면 해결이 됩니다.(my case) 

기술 자료 구축

우리는 Hugging Face Datasets에 호스팅된 Stanford Question-Answering Dataset (SQuAD)라는 거의 준비된 데이터 세트를 사용합니다. 다음과 같이 다운로드합니다.

In [ ]:
!pip install -U datasets
In [ ]:
from datasets import load_dataset

data = load_dataset('squad', split='train')
data

데이터세트에는 중복된 컨텍스트가 포함되어 있으며 다음과 같이 제거할 수 있습니다.

In [ ]:
data = data.to_pandas()
data.head()
In [ ]:
data.drop_duplicates(subset='context', keep='first', inplace=True)
data.head()

임베딩 모델 및 벡터 DB 초기화

우리는 OpenAI의 text-embedding-ada-002 모델을 사용하여 LangChain과 Pinecone 벡터 DB를 통해 초기화할 것입니다. 임베딩 모델을 초기화하는 것부터 시작합니다. 이를 위해서는 OpenAI API 키가 필요합니다.

In [ ]:
from getpass import getpass
from langchain.embeddings.openai import OpenAIEmbeddings

OPENAI_API_KEY = getpass("OpenAI API Key: ")  # platform.openai.com
In [ ]:
model_name = 'text-embedding-ada-002'

embed = OpenAIEmbeddings(
    model=model_name,
    openai_api_key=OPENAI_API_KEY
)

다음으로 벡터 데이터베이스를 초기화합니다. 이를 위해서는 무료 API 키가 필요하며 색인을 생성합니다.

In [ ]:
import pinecone

# find API key in console at app.pinecone.io
YOUR_API_KEY = getpass("Pinecone API Key: ")
# find ENV (cloud region) next to API key in console
YOUR_ENV = input("Pinecone environment: ")

index_name = 'langchain-retrieval-agent'
pinecone.init(
    api_key=YOUR_API_KEY,
    environment=YOUR_ENV
)

if index_name not in pinecone.list_indexes():
    # we create a new index
    pinecone.create_index(
        name=index_name,
        metric='dotproduct',
        dimension=1536  # 1536 dim of text-embedding-ada-002
    )

그런 다음 인덱스에 연결합니다.

In [ ]:
index = pinecone.GRPCIndex(index_name)
index.describe_index_stats()

아직 벡터를 추가하지 않았으므로 새 Pinecone 인덱스에 0의 total_vector_count가 있는지 확인해야 합니다.

인덱싱

LangChain 벡터 저장소 개체를 사용하여 색인 작업을 수행할 수 있습니다. 하지만 지금은 Pinecone Python 클라이언트를 통해 직접 수행하는 것이 훨씬 더 빠릅니다. 이 작업은 100 이상 일괄적으로 수행됩니다.

In [ ]:
from tqdm.auto import tqdm
from uuid import uuid4

batch_size = 100

texts = []
metadatas = []

for i in tqdm(range(0, len(data), batch_size)):
    # get end of batch
    i_end = min(len(data), i+batch_size)
    batch = data.iloc[i:i_end]
    # first get metadata fields for this record
    metadatas = [{
        'title': record['title'],
        'text': record['context']
    } for j, record in batch.iterrows()]
    # get the list of contexts / documents
    documents = batch['context']
    # create document embeddings
    embeds = embed.embed_documents(documents)
    # get IDs
    ids = batch['id']
    # add everything to pinecone
    index.upsert(vectors=zip(ids, embeds, metadatas))

모든 것을 색인화했으므로 이제 다음과 같이 색인의 벡터 수를 확인할 수 있습니다.

In [ ]:
index.describe_index_stats()

벡터 저장소 생성 및 쿼리

이제 인덱스를 구축했으므로 LangChain으로 다시 전환할 수 있습니다. 방금 구축한 것과 동일한 인덱스를 사용하여 벡터 저장소를 초기화하는 것부터 시작합니다.

In [ ]:
from langchain.vectorstores import Pinecone

text_field = "text"

# switch back to normal index for langchain
index = pinecone.Index(index_name)

vectorstore = Pinecone(
    index, embed.embed_query, text_field
)

이전 예와 마찬가지로 similarity_search 메소드를 사용하여 (생성 구성 요소 없이) 순수한 의미 검색을 수행할 수 있습니다.

In [ ]:
query = "when was the college of engineering in the University of Notre Dame established?"

vectorstore.similarity_search(
    query,  # our search query
    k=3  # return 3 most relevant docs
)

좋은 결과를 얻고 있는 것 같습니다. 이것을 대화형 에이전트에 통합하는 방법을 살펴보겠습니다.

대화형 에이전트 초기화

저희 대화 에이전트를 초기화하려면 Chat LLM, 대화 메모리 및 RetrievalQA 체인이 필요합니다.

In [ ]:
from langchain.chat_models import ChatOpenAI
from langchain.chains.conversation.memory import ConversationBufferWindowMemory
from langchain.chains import RetrievalQA

# chat completion llm
llm = ChatOpenAI(
    openai_api_key=OPENAI_API_KEY,
    model_name='gpt-3.5-turbo',
    temperature=0.0
)
# conversational memory
conversational_memory = ConversationBufferWindowMemory(
    memory_key='chat_history',
    k=5,
    return_messages=True
)
# retrieval qa chain
qa = RetrievalQA.from_chain_type(
    llm=llm,
    chain_type="stuff",
    retriever=vectorstore.as_retriever()
)

이를 사용하여 run 방법으로 답변을 생성할 수 있습니다.

In [ ]:
qa.run(query)

하지만 아직 대화 에이전트에는 준비가 되어 있지 않습니다. 이를 위해서는 이 검색 체인을 도구로 변환해야 합니다.

In [ ]:
from langchain.agents import Tool

tools = [
    Tool(
        name='Knowledge Base',
        func=qa.run,
        description=(
            'use this tool when answering general knowledge queries to get '
            'more information about the topic'
        )
    )
]

이제 다음과 같이 에이전트를 초기화할 수 있습니다.

In [ ]:
from langchain.agents import initialize_agent

agent = initialize_agent(
    agent='chat-conversational-react-description',
    tools=tools,
    llm=llm,
    verbose=True,
    max_iterations=3,
    early_stopping_method='generate',
    memory=conversational_memory
)

이로써 검색 증강 대화 에이전트가 준비되었으며 사용을 시작할 수 있습니다.

대화형 에이전트 사용

쿼리를 하려면 agent 직접 호출하면 됩니다.m

In [ ]:
agent(query)

멋지네요. 이제 일반 지식이 아닌 질문을 하면 어떨까요?

In [ ]:
agent("what is 2 * 7?")

완벽합니다. 에이전트는 해당 질문에 대해 일반 지식 도구를 참조할 필요가 없다는 것을 인식할 수 있습니다. 몇 가지 질문을 더 시도해 보겠습니다.

In [ ]:
agent("can you tell me some facts about the University of Notre Dame?")

멋지네요! 또한 대화에서 이전 상호 작용을 참조하는 질문을 할 수 있으며 에이전트는 대화 기록을 정보 소스로 참조할 수 있습니다.

OpenAI, Pinecone(OP 스택) 및 LangChain을 사용하여 검색 증강 대화 에이전트를 구축하는 예는 이것이 전부입니다.

완료되면 Pinecone 인덱스를 삭제하여 리소스를 절약합니다.

In [ ]:
pinecone.delete_index(index_name)
출처 : https://github.com/pinecone-io/examples/blob/master/learn/generation/langchain/handbook/08-langchain-retrieval-agent.ipynb

'langchain' 카테고리의 다른 글

10-langchain-multi-query  (0) 2024.01.19
07-langchain-tools  (0) 2024.01.17
03-1-langchain-conversational-memory  (1) 2024.01.16
09-langchain-streaming  (0) 2024.01.15
06-langchain-agents  (1) 2024.01.14