LlamaIndex와 Mistral AI로 여러 문서에 걸친 복잡한 질의 처리하기
LlamaIndex와 Mistral AI로 여러 문서에 걸친 복잡한 질의 처리하기
LlamaIndex를 Mistral API와 함께 사용해 여러 문서에 걸친 복잡한 질의를 수행하는 방법을 보여주는 노트북이에요. Lyft의 3개 연례 보고서(2020–2022)를 인덱싱하고, 도구를 사용할 수 있는 자율 LLM 에이전트인 ReAct 에이전트로 여러 문서를 동시에 질의합니다.
출처: 문서
본문
먼저 의존성을 설치합니다. LlamaIndex, Mistral, 그리고 나중에 쓸 PDF 파서가 필요해요.
!pip install llama-index-core
!pip install llama-index-embeddings-mistralai
!pip install llama-index-llms-mistralai
!pip install llama-index-readers-file
!pip install mistralai pypdf
Mistral 연결을 설정합니다. 두 가지가 필요해요.
- 질문에 답할 LLM
- 데이터를 인덱스 검색용 벡터로 변환할 임베딩 모델
Mistral이 둘 다 제공합니다! 이 둘을 얻으면 LlamaIndex가 설정을 전달하는 데 쓰는 객체인 Settings에 넣습니다.
from llama_index.llms.mistralai import MistralAI
from llama_index.embeddings.mistralai import MistralAIEmbedding
from llama_index.core.settings import Settings
api_key = ""
llm = MistralAI(api_key=api_key, model="mistral-large-latest")
embed_model = MistralAIEmbedding(model_name='mistral-embed', api_key=api_key)
Settings.llm = llm
Settings.embed_model = embed_model
이제 데이터셋을 내려받습니다. Lyft의 2020–2022 연례 보고서를 담은 아주 큰 PDF 3개예요.
!wget "https://www.dropbox.com/scl/fi/ywc29qvt66s8i97h1taci/lyft-10k-2020.pdf?rlkey=d7bru2jno7398imeirn09fey5&dl=0" -q -O ./lyft_10k_2020.pdf
!wget "https://www.dropbox.com/scl/fi/lpmmki7a9a14s1l5ef7ep/lyft-10k-2021.pdf?rlkey=ud5cwlfotrii6r5jjag1o3hvm&dl=0" -q -O ./lyft_10k_2021.pdf
!wget "https://www.dropbox.com/scl/fi/iffbbnbw9h7shqnnot5es/lyft-10k-2022.pdf?rlkey=grkdgxcrib60oegtp4jn8hpl8&dl=0" -q -O ./lyft_10k_2022.pdf
데이터가 준비됐으니 세 가지를 합니다.
- PDF 데이터를 메모리에 로드 — 이 과정에서 텍스트로 파싱됩니다. (
load_data()) - 데이터 인덱싱 — 각 문서의 벡터 표현이 만들어집니다. (
from_documents()) 벡터를 메모리에 저장합니다. - 쿼리 엔진 설정 — 벡터 스토어에서 정보를 검색해 LLM에 전달합니다. (
as_query_engine())
이 과정을 세 문서 각각에 대해 수행합니다. 3개보다 많았다면 루프로 프로그래밍적으로 처리했겠지만, 이렇게 하면 약간 반복적이어도 코드가 매우 단순해집니다. 마지막에 인덱스 하나에 질의를 넣어 테스트해 봤습니다.
from llama_index.core import SimpleDirectoryReader, VectorStoreIndex
lyft_2020_docs = SimpleDirectoryReader(input_files=["./lyft_10k_2020.pdf"]).load_data()
lyft_2020_index = VectorStoreIndex.from_documents(lyft_2020_docs)
lyft_2020_engine = lyft_2020_index.as_query_engine()
lyft_2021_docs = SimpleDirectoryReader(input_files=["./lyft_10k_2021.pdf"]).load_data()
lyft_2021_index = VectorStoreIndex.from_documents(lyft_2021_docs)
lyft_2021_engine = lyft_2021_index.as_query_engine()
lyft_2022_docs = SimpleDirectoryReader(input_files=["./lyft_10k_2022.pdf"]).load_data()
lyft_2022_index = VectorStoreIndex.from_documents(lyft_2022_docs)
lyft_2022_engine = lyft_2022_index.as_query_engine()
response = lyft_2022_engine.query("What was Lyft's profit in 2022?")
print(response)
성공! 2022 인덱스는 2022에 관한 사실을 알고 있네요. 이제 에이전트를 만들 준비가 거의 됐습니다. 그 전에 에이전트가 사용할 도구 배열을 설정합니다. 이렇게 하면 위에서 만든 각 쿼리 엔진이 도구로 바뀌고, 각 엔진이 어떤 질문에 가장 잘 답하는지도 나타냅니다. LLM은 어떤 도구를 쓸지 결정할 때 이 설명을 읽어요.
from llama_index.core.tools import QueryEngineTool, ToolMetadata
query_engine_tools = [
QueryEngineTool(
query_engine=lyft_2020_engine,
metadata=ToolMetadata(
name="lyft_2020_10k_form",
description="Annual report of Lyft's financial activities in 2020",
),
),
QueryEngineTool(
query_engine=lyft_2021_engine,
metadata=ToolMetadata(
name="lyft_2021_10k_form",
description="Annual report of Lyft's financial activities in 2021",
),
),
QueryEngineTool(
query_engine=lyft_2022_engine,
metadata=ToolMetadata(
name="lyft_2022_10k_form",
description="Annual report of Lyft's financial activities in 2022",
),
),
]
준비한 도구로 에이전트를 만들고 복잡한 질문을 할 수 있어요. 에이전트는 과정을 단계별로 추론하며 더 단순한 질문을 만들고, 각각을 다른 도구로 답합니다. 그런 다음 각 도구에서 얻은 정보를 취합해 더 복잡한 질문에 대한 단일 답변을 만듭니다.
from llama_index.core.agent import ReActAgent
lyft_agent = ReActAgent.from_tools(query_engine_tools, llm=llm, verbose=True)
response = lyft_agent.chat("What are the risk factors in 2022?")
print(response)
from llama_index.core.agent import ReActAgent
lyft_agent = ReActAgent.from_tools(query_engine_tools, llm=llm, verbose=True)
response = lyft_agent.chat("What is Lyft's profit in 2022 vs 2020? Generate only one step at a time. Use existing tools.")
print(response)
멋지죠! 2022 이익은 2022 10-K 양식에서, 2020 데이터는 2020 보고서에서 가져온 걸 볼 수 있습니다. 두 답을 취합해 우리가 요청한 차이를 만들어냈어요. 이번에는 숫자가 아닌 텍스트 답변을 물어봅니다.
from llama_index.core.agent import ReActAgent
lyft_agent = ReActAgent.from_tools(query_engine_tools, llm=llm, verbose=True)
response = lyft_agent.chat("What did Lyft do in R&D in 2022 versus 2021? Generate only one step at a time. Use existing tools.")
print(response)
훌륭해요! 위험 요소를 정확히 항목화하고 차이를 발견해 요약했습니다. 이 방식은 원하는 만큼 많은 문서와 쿼리 엔진으로 적용할 수 있어 정말 복잡한 질문에 답할 수 있어요. 심지어 쿼리 엔진 자체가 에이전트가 되도록 할 수도 있습니다.
더 알아보기 (Learn more)
- LlamaIndex Agents 문서 — 에이전트 워크플로 가이드
ReActAgent— 도구를 사용하는 자율 에이전트 (Reason+Act 패턴)QueryEngineTool/ToolMetadata— 쿼리 엔진을 도구로 감싸는 구성 요소- 모델:
mistral-large-latest,mistral-embed