Implementación de gráficos RAG mediante gráficos de conocimiento

El gráfico generación aumentada por recuperación (Graph RAG) es una técnica potente para las aplicaciones de IA generativa para utilizar conocimientos específicos del dominio e información relevante. Graph RAG es una alternativa a los métodos de búsqueda vectorial que utilizan una base de datos vectorial

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

Un enfoque Graph RAG aprovecha la naturaleza estructurada de las bases de datos de gráficos para dar mayor profundidad y contexto a la información recuperada sobre redes o relaciones complejas.  una base de datos de gráficos se empareja con un modelo de lenguaje de gran tamaño (LLM), un desarrollador puede automatizar partes significativas del proceso de creación de gráficos 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 gráfica.

Hay muchas formas de crear una aplicación Graph RAG, por ejemplo, GraphRAG de Microsoft, o emparejar GPT4 con LlamaIndex. En este tutorial, utilizará Memgraph, una solución de base de datos de gráficos de código abierto para crear un sistema rag utilizando 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 rellenará su base de datos de gráficos a partir de texto no estructurado y consultará la información de la base de datos.

Paso 1

Aunque puede elegir entre varias herramientas, este tutorial le muestra cómo configurar una cuenta de IBM para utilizar un Jupyter Notebook.

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

Cree un proyecto watsonx.ai.

Usted obtiene su ID de proyecto desde dentro de su proyecto. Haga clic en la pestaña Administrar. A continuación, copie el ID del proyecto de la sección Detalles de la página General. Necesita este ID de proyecto para este tutorial.

A continuación, asocie su proyecto con el tiempo de ejecución de watsonx.ai

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

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

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

d.  En la pestaña izquierda, seleccione Servicios e integraciones

e.  Seleccione los servicios de IBM

f. Seleccione Servicio asociado y elija watsonx.ai Runtime.

g. Asocie el tiempo de ejecución de watsonx.ai al proyecto que ha creado 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 utilizar este comando en un terminal:

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

En un ordenador con Windows, utilice:

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

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

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

virtualenv kg_rag --python=python3.12

En el entorno de Python para su cuaderno, 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 ha configurado 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 utilizar 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.
“””

Introduzca 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 debería ser bastante baja y el número de tokens alto para animar 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 desea que genere el LLM. En su caso, el texto describe a los empleados de una empresa, los grupos en los que trabajan y los títulos de sus puestos. Restringir el LLM solo a esas entidades hace que sea más probable que obtenga una buena representación del conocimiento en un gráfico.

La llamada a convert_to_graph_documents hace que LLMGraphTransformer cree un gráfico 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 gráficos para representar el contexto relevante 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 todos los datos antiguos de la base de datos Memgraph e inserte los nuevos nodos y aristas.

# 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 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 gráficos.

graph.refresh_schema()
print(graph.get_schema)

Esto 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 gráfica 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 gráfico de conocimiento.

Paso 4

Solicitar correctamente el LLM requiere cierta Prompt Engineering. LangChain proporciona una FewShotPromptTemplate que se puede utilizar para dar ejemplos al LLM en la instrucción para garantizar que escribe la sintaxis Cypher correcta y concisa. El siguiente código ofrece varios ejemplos de preguntas y consultas que debe utilizar el LLM. También muestra la restricción del output del modelo solo a la consulta. Un LLM demasiado hablador podría añadir información adicional que daría lugar a consultas Cypher no válidas, por lo que la plantilla de instrucción pide al modelo que salga solo la consulta en sí.

Añadir un prefijo instructivo también ayuda a restringir el comportamiento del modelo y hace que sea más probable que el LLM proporcione la sintaxis Cypher correcta.

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 gráficos.

 

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 utilizar, el esquema gráfico que se utilizará e 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á:

> 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, formule 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 del grupo:

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.

Por último, haga una pregunta a la cadena con dos salidas:

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

Esto debería generar:

> 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, ha creado una aplicación Graph RAG utilizando Memgraph y watsonx para generar las estructuras de datos de gráficos y consultarlas. Usando un LLM a través de watsonx, extrajo información de nodos y Edge del texto fuente en lenguaje natural y generó la sintaxis de consulta Cypher para rellenar una base de datos de gráficos. A continuación, utilizó watsonx para convertir preguntas en lenguaje natural sobre ese texto de origen en consultas Cypher que extraían información de la base de datos de gráficos. Mediante la ingeniería de prompts, el LLM convirtió los resultados de la base de datos Memgraph en respuestas en lenguaje natural.

Soluciones relacionadas
IBM watsonx.ai

Entrene, valide, ajuste e implemente IA generativa, modelos fundacionales y capacidades de machine learning con IBM watsonx.ai, un estudio empresarial de nueva generación para desarrolladores de IA. Cree aplicaciones de IA en menos tiempo y con menos datos.

Explore watsonx.ai
Soluciones de inteligencia artificial

Ponga la IA al servicio de su negocio con la experiencia líder del sector y el portfolio de soluciones de IA de IBM.

Explore las soluciones de IA
Servicios y consultoría de inteligencia artificial (IA)

Los servicios de IA de IBM Consulting ayudan a reinventar la forma de trabajar de las empresas usando IA para la transformación.

Explore los servicios de IA
Dé el siguiente paso

Gracias a la IA, IBM Concert descubre información crucial sobre sus operaciones y ofrece recomendaciones de mejora personalizadas para cada aplicación. Descubra cómo Concert puede hacer avanzar su negocio.

Explorar el concierto Explore las soluciones de automatización de procesos empresariales