Implementação do gráfico da RAG usando gráficos de conhecimento

geração aumentada de recuperação de gráficos (Graph RAG) está emergindo como uma técnica poderosa para aplicações de IA generativa para usar conhecimento específico de domínio e informações relevantes. A Graph RAG é uma alternativa aos métodos de pesquisa vetorial que usam um banco de dados de vetores

Os gráficos de conhecimento são sistemas de conhecimento em que bancos de dados gráficos, como Neo4j ou Amazon Neptune, podem representar dados estruturados. Em um gráfico de conhecimento, as relações entre pontos de dados, chamados de edges, são tão significativas quanto as conexões entre os pontos de dados, chamados de nós. Um gráfico de conhecimento facilita a travessia de uma rede e o processamento de consultas complexas sobre dados conectados. Os gráficos de conhecimento são especialmente adequados para casos de uso envolvendo chatbots, resolução de identidade, análise de rede, mecanismos de recomendação, customer 360 e detecção de fraude.

A abordagem da Graph RAG aproveita a natureza estruturada dos bancos de dados gráficos para dar maior profundidade e contexto às informações recuperadas sobre redes ou relacionamentos complexos.  Quando um banco de dados gráfico é emparelhado com um grande modelo de linguagem (LLM), um desenvolvedor pode automatizar partes significativas do processo de criação do gráfico a partir de dados não estruturados, como texto. Um LLM pode processar dados de texto e identificar entidades, entender seus relacionamentos e representá-los em uma estrutura gráfica.

Há muitas maneiras de criar uma aplicação Graph RAG, por exemplo, o GraphRAG da Microsoft, ou emparelhar o GPT4 com o LlamaIndex. Para este tutorial, você usará o Memgraph, uma solução de banco de dados gráfico de código aberto para criar um sistema rag usando o Llama-3 da Meta no watsonx. O Memgraph usa Cypher, uma linguagem de consulta declarativa. Ele compartilha algumas semelhanças com o SQL mas concentra-se em nós e relacionamentos em vez de tabelas e linhas. Você fará com que o Llama 3 crie e preencha seu banco de dados gráfico a partir de texto não estruturado e informações de consultas no banco de dados.

Etapa 1

Embora você possa escolher entre várias ferramentas, este tutorial explica como configurar uma conta da IBM para usar um Jupyter Notebook.

Faça login no watsonx.ai usando sua conta do IBM Cloud.

Crie um projeto do watsonx.ai.

Você obtém a ID do projeto no seu projeto. Clique na guia Gerenciar. Em seguida, copie a ID do projeto da seção Detalhes da página Geral. Você precisa dessa ID do projeto para este tutorial.

Em seguida, associe seu projeto ao watsonx.ai Runtime

a.  Crie uma instância do serviço watsonx.ai Runtime (escolha o plano Lite, que é uma instância gratuita).

b.  Gere uma chave de API no watsonx.ai® tempo de execução. Salve esta chave de API para uso neste tutorial.

c.  Acesse seu projeto e selecione a guia Gerenciar

d.  Na guia esquerda, selecione Serviços e integrações

e.  Selecione os serviços da IBM

f. Selecione Associar serviço e escolha watsonx.ai Runtime.

g. Associe o watsonx.ai Runtime. ao projeto que você criou no watsonx.ai

Etapa 2

Agora, você precisará instalar o Docker.

Depois de instalar o Docker, instale o Memgraph usando o contêiner do Docker. No OSX ou no Linux, você pode usar este comando em um terminal:

curl https://install.memgraph.com | sh

Em um computador Windows, use:

iwr https://windows.memgraph.com | iex

Siga as etapas de instalação para colocar o mecanismo Memgraph e o laboratório Memgraph em funcionamento.

Em seu computador, crie um novo virtualenv para este projeto:

virtualenv kg_rag --python=python3.12

No ambiente do Python para seu notebook, instale as seguintes bibliotecas do Python:

./kg_rag/bin/pip install langchain langchain-openai langchain_experimental langchain-community==0.3.15 neo4j langchain_ibm jupyterlab json-repair getpass4

Agora você está pronto para se conectar ao Memgraph.

Etapa 3

Se você configurou o Memgraph para usar um nome de usuário e senha, defina-os aqui, caso contrário, poderá usar o padrão de não ter nenhum dos dois. Não é uma boa prática para um banco de dados de produção, mas para um ambiente de desenvolvimento local que não armazena dados confidenciais, não é um problema.

import os
from langchain_community.chains.graph_qa.memgraph import MemgraphQAChain
from langchain_community.graphs import MemgraphGraph

url = os.environ.get("MEMGRAPH_URI", "bolt://localhost:7687")
username = os.environ.get("MEMGRAPH_USERNAME", "")
password = os.environ.get("MEMGRAPH_PASSWORD", "")

#initialize memgraph connection
graph = MemgraphGraph(
    url=url, username=username, password=password, refresh_schema=True
)

Agora, crie uma string de amostra que descreva um conjunto de dados de relacionamentos que você pode usar para testar os recursos de geração de gráficos do seu sistema LLM. Você pode usar fontes de dados mais complexas, mas esse exemplo simples nos ajuda a demonstrar o algoritmo.

graph_text = “””
John’s title is Director of the Digital Marketing Group.
John works with Jane whose title is Chief Marketing Officer.
Jane works in the Executive Group.
Jane works with Sharon whose title is the Director of Client Outreach.
Sharon works in the Sales Group.
“””

Insira a chave de API do watsonx que você criou na primeira etapa:

from getpass import getpass

watsonx_api_key = getpass()
os.environ[“WATSONX_APIKEY”] = watsonx_api_key
watsonx_project_id = getpass()
os.environ[“WATSONX_PROJECT_ID”] = watsonx_project_id

Agora, configure uma instância do WatsonxLLM para gerar texto. A temperatura deve ser bastante baixa, e o número de tokens alto para incentivar o modelo a gerar o máximo de detalhes possível sem alucinar entidades ou relacionamentos que não estejam presentes.

from langchain_ibm import WatsonxLLM
from ibm_watsonx_ai.metanames import GenTextParamsMetaNames

graph_gen_parameters = {   
    GenTextParamsMetaNames.DECODING_METHOD: “sample”,
    GenTextParamsMetaNames.MAX_NEW_TOKENS: 1000,
    GenTextParamsMetaNames.MIN_NEW_TOKENS: 1,
    GenTextParamsMetaNames.TEMPERATURE: 0.3,
    GenTextParamsMetaNames.TOP_K: 10,
    GenTextParamsMetaNames.TOP_P: 0.8
}
watsonx_llm = WatsonxLLM(
    model_id=”meta-llama/llama-3-3-70b-instruct”,
    url=”https://us-south.ml.cloud.ibm.com”,
    project_id=os.getenv(“WATSONX_PROJECT_ID”),
    params=graph_gen_parameters,
)

O LLMGraphTransformer permite que você defina quais tipos de nós e relacionamentos você gostaria que o LLM gerasse. No seu caso, o texto descreve os funcionários de uma empresa, os grupos em que trabalham e os cargos que ocupam. Restringir o LLM a apenas essas entidades aumenta a probabilidade de obter uma boa representação do conhecimento em um gráfico.

A chamada para convert_to_graph_documents faz com que o LLMGraphTransformer crie um gráfico de conhecimento a partir do texto. Essa etapa gera a sintaxe correta do Neo4j para inserir as informações no banco de dados gráfico para representar o contexto relevante e as entidades relevantes.

from langchain_experimental.graph_transformers.llm import LLMGraphTransformer
from langchain_core.documents import Document

llm_transformer = LLMGraphTransformer(
    llm=watsonx_llm,
    allowed_nodes=[“Person”, “Title”, “Group”],
    allowed_relationships=[“TITLE”, “COLLABORATES”, “GROUP”]
)
documents = [Document(page_content=graph_text)]
graph_documents = llm_transformer.convert_to_graph_documents(documents)

Agora, limpe todos os dados antigos do banco de dados do Memgraph e insira os novos nós e edges.

# make sure the database is empty
graph.query(“STORAGE MODE IN_MEMORY_ANALYTICAL”)
graph.query(“DROP GRAPH”)
graph.query(“STORAGE MODE IN_MEMORY_TRANSACTIONAL”)

# create knowledge graph
graph.add_graph_documents(graph_documents)

A sintaxe do Cypher gerada é armazenada nos objetos graph_documents . Você pode inspecioná-lo simplesmente exibindo-o como uma string.

print(f”{graph_documents}”)

O esquema e os tipos de dados criados pelo Cypher podem ser vistos na propriedade "get_schema" dos gráficos.

graph.refresh_schema()
print(graph.get_schema)

Isso imprime:

Node labels and properties (name and type) are:
- labels: (:Title)
properties:
- id: string
- labels: (:Group)
properties:
- id: string
- labels: (:Person)
properties:
- id: string

Nodes are connected with the following relationships:
(:Person)-[:COLLABORATES]->(:Person)
(:Person)-[:GROUP]->(:Group)
(:Person)-[:TITLE]->(:Title)

Você também pode ver a estrutura do gráfico no visualizador do Memgraph labs:

 

Uma imagem de rede gráfica mostrando nós e edges A rede Memgraph gerada a partir do texto de entrada

O LLM fez um trabalho razoável na criação dos nós e das relações corretas. Chegou a hora de consultar o gráfico de conhecimento.

Etapa 4

Solicitar o LLM corretamente requer alguma engenharia de prompts. O LangChain fornece um FewShotPromptTemplate que pode ser usado para dar exemplos ao LLM no prompt para garantir que ele grave a sintaxe do Cypher correta e sucinta. O código a seguir fornece vários exemplos de perguntas e consultas que o LLM deve usar. Elas também mostram como restringir a saída do modelo apenas à consulta. Um LLM excessivamente conversacional pode adicionar informações extras que levariam a consultas inválidas do Cypher, de modo que o prompt pede ao modelo que produza apenas a própria consulta.

Adicionar um prefixo instrutivo também ajuda a restringir o comportamento do modelo e torna mais provável que o LLM produza a sintaxe correta do Cypher.

from langchain_core.prompts import PromptTemplate, FewShotPromptTemplate

examples = [
{
“question”: “<|begin_of_text|>What group is Charles in?<|eot_id|>“,
“query”: “<|begin_of_text|>MATCH (p:Person {{id: ‘Charles’}})-[:GROUP]->(g:Group) RETURN g.id<|eot_id|>“,
},
{
“question”: “<|begin_of_text|>Who does Paul work with?<|eot_id|>“,
“query”: “<|begin_of_text|>MATCH (a:Person {{id: ‘Paul’}})-[:COLLABORATES]->(p:Person) RETURN p.id<|eot_id|>“,
},
{
“question”: “What title does Rico have?<|eot_id|>“,
“query”: “<|begin_of_text|>MATCH (p:Person {{id: ‘Rico’}})-[:TITLE]->(t:Title) RETURN t.id<|eot_id|>“,
}
]

example_prompt = PromptTemplate.from_template(
“<|begin_of_text|>{query}<|eot_id|>“
)

prefix = “””
Instructions:
- Respond with ONE and ONLY ONE query.
- Use provided node and relationship labels and property names from the
schema which describes the database’s structure. Upon receiving a user
question, synthesize the schema to craft a precise Cypher query that
directly corresponds to the user’s intent.
- Generate valid executable Cypher queries on top of Memgraph database.
Any explanation, context, or additional information that is not a part
of the Cypher query syntax should be omitted entirely.
- Use Memgraph MAGE procedures instead of Neo4j APOC procedures.
- Do not include any explanations or apologies in your responses. Only answer the question asked.
- Do not include additional questions. Only the original user question.
- Do not include any text except the generated Cypher statement.
- For queries that ask for information or functionalities outside the direct
generation of Cypher queries, use the Cypher query format to communicate
limitations or capabilities. For example: RETURN “I am designed to generate Cypher queries based on the provided schema only.”

Here is the schema information

{schema}

With all the above information and instructions, generate Cypher query for the
user question.

The question is:

{question}

Below are a number of examples of questions and their corresponding Cypher queries.”””

cypher_prompt = FewShotPromptTemplate(
    examples=examples,
    example_prompt=example_prompt,
    prefix=prefix,
    suffix=”User input: {question}\nCypher query: “,
    input_variables=[“question”, “schema”],
)

Em seguida, você criará um prompt para controlar como o LLM responde à pergunta com as informações retornadas do Memgraph. Daremos ao LLM vários exemplos e instruções sobre como responder assim que ele receber as informações de contexto do banco de dados do gráfico.

 

qa_examples = [
    {
        “question”: “<|begin_of_text|>What group is Charles in?<|eot_id|>“,
        “context”: “[{{‘g.id’: ‘Executive Group’}}]”,
        “response”: “Charles is in the Executive Group<|eot_id|>“
    },
    {
        “question”: “<|begin_of_text|>Who does Paul work with?<|eot_id|>“,
        “context”: “[{{‘p.id’: ‘Greg’}}, {{‘p2.id’: ‘Norma’}}]”,
        “response”: “Paul works with Greg and Norma<|eot_id|>“
    },
    {
        “question”: “What title does Rico have?<|eot_id|>“,
        “context”: “[{{‘t.id’: ‘Vice President of Sales’}}]”,
        “response”: “Vice President of Sales<|eot_id|>“
    }
]

qa_template = “””
Use the provided question and context to create an answer.Question: {question}

Context: {context}
Use only names departments or titles contained within {question} and {context}.
“””
qa_example_prompt = PromptTemplate.from_template(“”)

qa_prompt = FewShotPromptTemplate(
    examples=qa_examples,
    prefix=qa_template,
    input_variables=[“question”, “context”],
    example_prompt=qa_example_prompt,
    suffix=” “
)

Agora é hora de criar a cadeia de resposta à pergunta. O MemgraphQACChain permite que você defina qual LLM você gostaria de usar, o esquema do gráfico a ser usado e informações sobre depuração. Usar uma temperatura de 0 e uma penalidade de comprimento incentiva o LLM a manter o prompt do Cypher curto e direto.

query_gen_parameters = {
    GenTextParamsMetaNames.DECODING_METHOD: “sample”,
    GenTextParamsMetaNames.MAX_NEW_TOKENS: 100,
    GenTextParamsMetaNames.MIN_NEW_TOKENS: 1,
    GenTextParamsMetaNames.TEMPERATURE: 0.0,
    GenTextParamsMetaNames.TOP_K: 1,
    GenTextParamsMetaNames.TOP_P: 0.9,
    GenTextParamsMetaNames.LENGTH_PENALTY: {‘decay_factor’: 1.2, ‘start_index’: 20}
}

chain = MemgraphQAChain.from_llm(
        llm = WatsonxLLM(
        model_id=”meta-llama/llama-3-3-70b-instruct”,
        url=”https://us-south.ml.cloud.ibm.com”,
        project_id=”dfe8787b-1f6f-4e18-b36a-e22c00f141d1”,
        params=query_gen_parameters
    ),
    graph = graph,
    allow_dangerous_requests = True,
    verbose = True,
    return_intermediate_steps = True, # for debugging
    cypher_prompt=cypher_prompt,
    qa_prompt=qa_prompt
)

Agora, você pode invocar a cadeia com uma pergunta em linguagem natural (observe que suas respostas podem ser ligeiramente diferentes, porque LLMs não são puramente determinísticos).

chain.invoke(“What is Johns title?”)

Isso gerará:

> Entering new MemgraphQAChain chain...
Generated Cypher:
 MATCH (p:Person {id: 'John'})-[:TITLE]->(t:Title) RETURN t.id
Full Context:
[{'t.id': 'Director of the Digital Marketing Group'}]

> Finished chain.
{'query': 'What is Johns title?',
 'result': ' \nAnswer: Director of the Digital Marketing Group.',
 'intermediate_steps': [{'query': " MATCH (p:Person {id: 'John'})-[:TITLE]->(t:Title) RETURN t.id"},
  {'context': [{'t.id': 'Director of the Digital Marketing Group'}]}]}

Na próxima pergunta, faça à cadeia uma pergunta um pouco mais complexa:

chain.invoke(“Who does John collaborate with?”)

Isso deve retornar:

> Entering new MemgraphQAChain chain...
Generated Cypher:
MATCH (p:Person {id: ‘John’})-[:COLLABORATES]->(c:Person) RETURN c
Full Context:
[{‘c’: {‘id’: ‘Jane’}}]

> Finished chain.
{‘query’: ‘Who does John collaborate with?’,
‘result’: ‘ \nAnswer: John collaborates with Jane.’,
‘intermediate_steps’: [{‘query’: “ MATCH (p:Person {id: ‘John’})-[:COLLABORATES]->(c:Person) RETURN c”},
{‘context’: [{‘c’: {‘id’: ‘Jane’}}]}]}

A resposta correta está contida na resposta. Em alguns casos, pode haver texto extra que você gostaria de remover antes de devolver a resposta ao usuário final.

Você pode perguntar à cadeia do Memgraph sobre os relacionamentos com o grupo:

chain.invoke(“What group is Jane in?”)

Isso retornará:

> Entering new MemgraphQAChain chain...
Generated Cypher:
MATCH (p:Person {id: ‘Jane’})-[:GROUP]->(g:Group) RETURN g.id
Full Context:
[{‘g.id’: ‘Executive Group’}]

> Finished chain.
{‘query’: ‘What group is Jane in?’,
‘result’: ‘Jane is in Executive Group.’,
‘intermediate_steps’: [{‘query’: “ MATCH (p:Person {id: ‘Jane’})-[:GROUP]->(g:Group) RETURN g.id”},
{‘context’: [{‘g.id’: ‘Executive Group’}]}]}

Essa é a resposta correta.

Finalmente, faça uma pergunta à cadeia com duas saídas:

chain.invoke(“Who does Jane collaborate with?”)

Isso deve produzir:

> Entering new MemgraphQAChain chain...
Generated Cypher:
MATCH (p:Person {id: ‘Jane’})-[:COLLABORATES]->(c:Person) RETURN c
Full Context:
[{‘c’: {‘id’: ‘Sharon’}}]

> Finished chain.
{‘query’: ‘Who does Jane collaborate with?’,
‘result’: ‘ Jane collaborates with Sharon.’,
‘intermediate_steps’: [{‘query’: “ MATCH (p:Person {id: ‘Jane’})-[:COLLABORATES]->(c:Person) RETURN c”},
{‘context’: [{‘c’: {‘id’: ‘Sharon’}}]}]}

A cadeia identifica corretamente ambos os colaboradores.

Conclusão

Neste tutorial, você criou uma aplicação da Graph RAG usando o Memgraph e o watsonx para gerar as estruturas de dados gráficas e consultá-las. Usando um LLM por meio do watsonx, você extraiu informações de nós e edge do texto de origem em linguagem natural e gerou a sintaxe de consulta do Cypher para preencher um banco de dados gráfico. Em seguida, você usou o watsonx para transformar perguntas de linguagem natural sobre esse texto de origem em consultas do Cypher que extraíram informações do banco de dados gráfico. Usando engenharia de prompts, o LLM transformou os resultados do banco de dados Memgraph em respostas de linguagem natural.

Soluções relacionadas
IBM® watsonx.ai

Treine, valide, ajuste e implemente recursos de IA generativa, modelos de base e recursos de aprendizado de máquina com o IBM watsonx.ai, um estúdio empresarial de última geração para construtores de IA. Crie aplicações de IA em menos tempo com menos dados.

Explore o watsonx.ai
Soluções de inteligência artificial

Coloque a IA em ação na sua empresa com a experiência em IA líder do setor e com o portfólio de soluções da IBM.

Explore as soluções de IA
Consultoria e serviços em inteligência artificial (IA)

Os serviços de IA da IBM Consulting ajudam a reinventar a forma como as empresas trabalham com IA para gerar transformação.

Explore os serviços de IA
Dê o próximo passo

Ao utilizar a IA, o IBM Concert revela insights cruciais sobre suas operações e fornece recomendações específicas para cada aplicação com foco em melhorias. Descubra como o Concert pode impulsionar sua empresa.

Explorar Concert Explore as soluções de automação de processos de negócios