Implementación de RAG de grados mediante grafos de conocimiento

La generación aumentada por recuperación de grafos (RAG de grafos) es una técnica emergente y poderosa para las aplicaciones de IA generativa para utilizar los conocimientos específicos del dominio y la información relevante. El RAG de grafos es una alternativa a los métodos de búsqueda vectorial que utilizan una base de datos vectorial

Los grafos de conocimiento son sistemas de conocimiento en los que las bases de datos de grafos, como Neo4j o Amazon Neptune, pueden representar datos estructurados. En un grafo de conocimiento, las relaciones entre los puntos de datos, llamadas aristas, son tan significativas como las conexiones entre los puntos de datos, llamados vértices o, a veces, nodos. Un grafo de conocimiento facilita atravesar una red y procesar consultas complejas sobre datos conectados. Los grafos de conocimiento son especialmente adecuados para casos de uso que involucran chatbots, resolución de identidades, análisis de redes, motores de recomendación, Customer 360 y detección de fraude.

Un enfoque de RAG de grafos aprovecha la naturaleza estructurada de las bases de datos de grafos para dar mayor profundidad y contexto a la información recuperada sobre redes o relaciones complejas.  Una base de datos de grafos se combina con un modelo de lenguaje grande (LLM) y un desarrollador puede automatizar partes significativas del proceso de creación de grafos a partir de datos no estructurados, como texto. Un LLM puede procesar datos de texto e identificar entidades, comprender sus relaciones y representarlas en una estructura de grafos.

Hay muchas formas de crear una aplicación de RAG de grafos, por ejemplo, GraphRAG de Microsoft, o emparejar GPT4 con LlamaIndex. En este tutorial, utilizará Memgraph, una solución de base de datos de grafos de código abierto para crear un sistema RAG mediante Llama-3 de Meta en watsonx. Memgraph utiliza Cypher, un lenguaje de consulta declarativo. Comparte algunas similitudes con SQL, pero se centra en nodos y relaciones en lugar de tablas y filas. Llama 3 creará y completará su base de datos de grafos a partir de texto no estructurado e información de consulta en la base de datos.

Paso 1

Si bien puede elegir entre varias herramientas, este tutorial lo guiará a través de cómo configurar una cuenta de IBM para usar un Jupyter Notebook.

Inicie sesión en watsonx.ai con su cuenta de IBM Cloud.

Cree un proyecto watsonx.ai.

Obtiene su ID de proyecto desde dentro de su proyecto. Haga clic en la pestaña Manage. Luego, copie el ID del proyecto de la sección Details de la página General. Necesita este ID de proyecto para este tutorial.

A continuación, asocie su proyecto con watsonx.ai Runtime.

a.  Cree una instancia de servicio watsonx.ai Runtime (elija el plan Lite, que es una instancia gratuita).

b. Genere una clave de API en watsonx.ai Runtime. Guarde esta clave de API para usarla en este tutorial.

c. Vaya a su proyecto y seleccione la pestaña Manage.

d.  En la pestaña izquierda, seleccione Services and Integrations.

e. Seleccione los servicios de IBM.

f. Seleccione Associate service y elija watsonx.ai® Runtime.

g. Asocie watsonx.ai Runtime al proyecto que creó en watsonx.ai.

Paso 2

Ahora, deberá instalar Docker.

Una vez que haya instalado Docker, instale Memgraph utilizando su contenedor Docker. En OSX o Linux, puede usar este comando en una terminal:

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

En una computadora con Windows, use:

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

Siga los pasos de instalación para poner en marcha el motor Memgraph y el Memgraph lab.

En su computadora, cree un virtualenv nuevo para este proyecto:

virtualenv kg_rag --python=python3.12

En el entorno de Python para su notebook, instale las siguientes bibliotecas de Python:

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

Ahora está listo para conectarse a Memgraph.

Paso 3

Si configuró Memgraph para usar un nombre de usuario y una contraseña, configúrelos aquí; de lo contrario, puede usar los valores predeterminados de no tener ninguno. No es una buena práctica para una base de datos de producción, pero para un entorno de desarrollo local que no almacena datos confidenciales, no es un 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
)

Ahora cree una cadena de muestra que describa un conjunto de datos de relaciones que pueda usar para probar las capacidades de generación de gráficos de su sistema LLM. Puede utilizar fuentes de datos más complejas, pero este sencillo ejemplo nos ayuda a demostrar el 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.
“””

Ingrese la clave de API de watsonx que creó en el primer paso:

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

Ahora configure una instancia de watsonxLLM para generar texto. La temperatura debe ser bastante baja y la cantidad de tokens alta para alentar al modelo a generar tantos detalles como sea posible sin alucinar entidades o relaciones que no están 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,
)

El LLMGraphTransformer le permite establecer qué tipos de nodos y relaciones le gustaría que genere el LLM. En su caso, el texto describe a los empleados de una empresa, los grupos en los que trabajan y sus puestos. Restringir el LLM a solo esas entidades hace que sea más probable que obtenga una buena representación del conocimiento en un grafo.

La llamada a convert_to_graph_documents hace que LLMGraphTransformer cree un grafo de conocimiento a partir del texto. Este paso genera la sintaxis correcta de Neo4j para insertar la información en la base de datos de grafos para representar el contexto y las 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)

Ahora borre cualquier dato antiguo de la base de datos de Memgraph e inserte los nuevos nodos y bordes.

# 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)

La sintaxis de Cypher generada se almacena en los objetos graph_documents. Puede inspeccionarlo simplemente imprimiéndolo como una cadena.

print(f”{graph_documents}”)

El esquema y los tipos de datos creados por Cypher se pueden ver en la propiedad 'get_schema' de los grafos.

graph.refresh_schema()
print(graph.get_schema)

Esto se 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)

También puede ver la estructura del gráfico en el visor de Memgraph labs:

 

Una imagen de red de grafos que muestra nodos y aristas La red Memgraph generada a partir del texto de entrada

El LLM ha hecho un trabajo razonable al crear los nodos y las relaciones correctos. Ahora es el momento de consultar el grafo de conocimiento.

Paso 4

Solicitar correctamente el LLM requiere cierta ingeniería rápida. LangChain proporciona una FewShotPromptTemplate que se puede usar para dar ejemplos al LLM en la instrucción para garantizar que escriba la sintaxis de Cypher correcta y concisa. El siguiente código ofrece varios ejemplos de preguntas y consultas que debe utilizar el LLM. También muestra cómo restringir la salida del modelo solo a la consulta. Un LLM que habla demasiado podría agregar información adicional que daría lugar a consultas Cypher no válidas, por lo que la instrucción le pide al modelo que genere solo el resultado en sí.

Agregar un prefijo instructivo también ayuda a restringir el comportamiento del modelo y hace que sea más probable que el LLM proporcione resultados correctos de sintaxis 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”],
)

A continuación, creará una instrucción para controlar cómo el LLM responde a la pregunta con la información devuelta por Memgraph. Le daremos al LLM varios ejemplos e instrucciones sobre cómo responder una vez que tenga información de contexto de la base de datos de grafos.

 

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=” “
)

Ahora es el momento de crear la cadena de preguntas y respuestas. MemgraphQACain le permite establecer qué LLM le gustaría usar, el esquema gráfico que se usará y la información sobre la depuración. El uso de una temperatura de 0 y una penalización de longitud anima al LLM a mantener la instrucción de Cypher breve y directa.

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
)

Ahora puede invocar la cadena con una pregunta en lenguaje natural (tenga en cuenta que sus respuestas pueden ser ligeramente diferentes porque los LLM no son puramente deterministas).

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

Esto generará el siguiente resultado:

> 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'}]}]}

En la siguiente pregunta, haga a la cadena una pregunta un poco más compleja:

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

Esto debería devolver:

> 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’}}]}]}

La respuesta correcta está contenida en la respuesta. En algunos casos, puede haber texto adicional que desee eliminar antes de devolver la respuesta a un usuario final.

Puede preguntar a la cadena Memgraph sobre las relaciones grupales:

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

Esto devolverá:

> 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’}]}]}

Esta es la respuesta correcta.

Finalmente, haga una pregunta a la cadena con dos resultados:

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

Esto debería generar el siguiente resultado:

> 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’}}]}]}

La cadena identifica correctamente a ambos colaboradores.

Conclusión

En este tutorial, creó una aplicación de RAG de grafos utilizando Memgraph y watsonx para generar las estructuras de datos de gráficos y consultarlas. Con un LLM a través de watsonx, extrajo información de nodos y aristas del texto fuente del lenguaje natural y generó sintaxis de consulta Cypher para completar una base de datos de grafos. Luego utilizó watsonx para convertir preguntas de lenguaje natural sobre ese texto de origen en consultas Cypher que extraían información de la base de datos de gráficos. Mediante ingeniería rápida, el LLM convirtió los resultados de la base de datos Memgraph en respuestas de lenguaje natural.

Soluciones relacionadas
IBM® watsonx.ai

Entrene, valide, ajuste y despliegue IA generativa, modelos fundacionales y capacidades de machine learning con IBM watsonx.ai, un estudio empresarial de próxima generación para creadores de IA. Diseñe aplicaciones de IA en menos tiempo y con menos datos.

Explore watsonx.ai
Soluciones de inteligencia artificial

Ponga a trabajar la IA en su negocio con la experiencia en IA líder del sector y la cartera de soluciones de IBM a su lado.

Explore las soluciones de IA
Consultoría y servicios de inteligencia artificial (IA)

Los servicios de IA de IBM Consulting ayudan a reinventar la forma en que las empresas trabajan con IA para la transformación.

Explore los servicios de IA
Dé el siguiente paso

Con la IA, IBM Concert muestra insights cruciales sobre operaciones y proporciona recomendaciones de mejora específicas de las aplicaciones. Descubra cómo Concert puede hacer avanzar su negocio.

Explore Concert Explore las soluciones de automatización de procesos de negocio