Conectando LLM a sua base de dados usando LlamaIndex

José Henrique Luckmann
Senior Sistemas
Published in
4 min readApr 19, 2024

É inegável que os Modelos de Linguagem de Grande Escala (LLMs) tem puxado a fila na corrida pela inovação e um dos grandes desafios para extrair valor desta tecnologia tem sido comunicar os modelos generalistas com os seus dados dentro do seu contexto. Neste tutorial vamos mergulhar no LlamaIndex, um framework que facilita a integração de dados privados ou específicos de domínio com LLMs, como sistemas de Geração Aumentada por Recuperação (RAG), potencializando assim a criação de textos mais acurados e relevantes.

Este artigo servirá como seu guia para explorar as riquezas que essa ferramenta tem a oferecer, além de um passeio pelos conceitos fundamentais que fazem do LlamaIndex uma peça chave no desenvolvimento de aplicações baseadas em LLM.

🦙 Por que Escolher LlamaIndex para a Sua Contextualização de Dados?

LlamaIndex não impõe limitações no uso de LLMs, ampliando as possibilidades de uso em auto-completation, chatbots, agentes semiautônomos, entre outros. Oferece ferramentas que vão desde conectores de dados, que ingerem seus dados em seus formatos nativos, até integrações de aplicativos que recolocam o LlamaIndex no centro do seu ecossistema digital.

⚙️ Como o LlamaIndex funciona?

Este desenho traz uma boa ideia sobre qual é a funcionalidade do LlamaIndex, ele atua como um centralizador para todos os recursos de RAG do seu modelo. Ele concentra os dados estruturados, não estruturados, acessos programáticos e etc. Tudo isso é agregado em um conceito de index que pode ser persistido e acessado no momento que for necessário. Então ao conversar com um LLM ele consegue acessar esse index da maneira mais otimizada possivel para otimizar a qualidade das respostas e também o custo.

Ele divide suas ações nas seguintes etapas:

  • Loading: Carrega os dados, seja acessando uma pasta de documentos, um banco de dados, ou qualquer outro recurso.
  • Indexing: Transforma estes dados em um conceito de index que deixa os dados em um formato muito mais fácil de acessar pelo LLM posteriormente
  • Storing: Armazena este index seja em uma estrutura de pastas, um banco de dados de vetores, ou um banco não relacional. Varia de acordo com a abordagem escolhida
  • Querying: Etapa de consulta, onde busca dados do index e envia para o LLM
  • Evaluating: Definição da qualidade da resposta para entender se atende a pergunta inicial

🐍Criando um agente com acesso aos seus dados

Vamos criar um e exemplo onde o modelo vai acessar uma base de dados fictícia simulando dados de RH de uma empresa, você pode acessar o notebook na integra aqui

Começamos realizando todos os imports necessários

from llama_index.core.tools import QueryEngineTool, ToolMetadata
from llama_index.core.query_engine import SubQuestionQueryEngine
from llama_index.core.query_engine import NLSQLTableQueryEngine
from llama_index.agent.openai import OpenAIAgent
from llama_index.llms.openai import OpenAI
from llama_index.core import SQLDatabase
from llama_index.core import Settings
from sqlalchemy import create_engine
import os
from IPython.display import Markdown, display

Configurando parâmetros com relação ao modelo LLM utilizado

os.environ["OPENAI_API_KEY"] = "sk-SUA+CHAVE"
model = "gpt-3.5-turbo"
chunk_size = 2048
Settings.llm = OpenAI(model="gpt-3.5-turbo", temperature=0)
Settings.chunk_size = chunk_size

Conectamos ao nosso banco de dados, para fins de estudos usaremos o SQLite mas esta conexão pode ser substituída por qualquer conexão usando o SQLAlchemy

!wget https://github.com/JoseLuckmann/tutorial-llama-index/raw/main/rh.db
connection_string = "sqlite:///rh.db"
engine = create_engine(connection_string)

Agora conectamos o nosso banco de dados ao Index aqui surgem alguns objetos novos que é importante entendermos?

  • SQLDatabase: Uma abstração simples para permitir a conexão entre o SQLAlchemy e o LLamaIndex
  • NLSQLTableQueryEngine: Motor de consulta de tabelas SQL em linguagem natural
  • QueryEngineTool: Uma ferramenta que utiliza um motor de pesquisa (no nosso caso a NLSQLTable)
  • SubQuestionQueryEngine: Divide uma consulta complexa em muitas sub-perguntas e no seu motor de consulta de destino para execução. Após a execução de todas as sub-perguntas, todas as respostas são reunidas e enviadas para o sintetizador de respostas para produzir a resposta final.
sql_database = SQLDatabase(engine)
sql_query_engine = NLSQLTableQueryEngine(sql_database=sql_database, verbose=True)
sql_tool = QueryEngineTool.from_defaults(
query_engine=sql_query_engine,
description="""Utilizado para traduzir a linguagem natural em linguagem SQL para executar as querys
Base de dados de recursos humanos com informações de funcionarios, salarios, vagas e etc""",
)
query_engine = SubQuestionQueryEngine.from_defaults(
query_engine_tools=[sql_tool], #No nosso caso temos apenas uma conexão, mas aqui é possivel informar varias conexões
)
query_engine_tool = QueryEngineTool(
query_engine=query_engine,
metadata=ToolMetadata(
name="sub_question_query_engine",
description="Util para responder perguntas sobre as bases de dados que você tem acesso.",
),
)
tools = [query_engine_tool] + [sql_tool]

Iniciamos um agente da OpenAI com acesso as nossas ferramentas

agent = OpenAIAgent.from_tools(tools, verbose=False)

Vamos testar algumas perguntas agora

response = agent.chat("Quantos funcionários eu tenho?")
display(Markdown(str(response)))
Você tem um total de 1000 funcionários.
response = agent.chat("Quem é o funcionário com maior salário?")
display(Markdown(str(response)))
O funcionário com o maior salário é Emily Lewis, com um salário de $9986.00.
response = agent.chat("Crie uma tabela com a soma da minha folha salarial mes a mes dos ultimos 6 meses")
display(Markdown(str(response)))
Aqui está a tabela com a soma da folha salarial mês a mês dos últimos 6 meses:
Janeiro: $498,353.00
Fevereiro: $570,587.00
Março: $507,059.00
Abril: $422,937.00
Maio: $464,552.00
Junho: $560,706.00

Conclusão

Seguindo os passos deste tutorial conseguimos conectar de maneira simples um modelo de LLM a uma base de dados que contenha dados personalizados. Este é um exemplo simples, dentro da ferramenta LlamaIndex existem diversos recursos para acessar diferentes tipos de dados estruturados e não estruturados.

Dentro da ferramenta existem formas de aplicar e customizar utilizando técnicas de Langchain, prompts personalizados, agentes especiais e muitos outros recursos. Além de ser possivel utilizar outroi fornecedors que não sejam a OpenAI garantindo assium que seja uma ferramenta com um amplo arsenal para resolver diversos tipos de problemas

Referências

LlamaIndex. “LlamaIndex Documentation.” , https://docs.llamaindex.ai/en/stable/

LlamaIndex. “LlamaIndex Github Repository”, https://github.com/run-llama/llama_index

Tutorial. “Repositório com o tutorial”, https://github.com/JoseLuckmann/tutorial-llama-index/tree/main

--

--