paint-brush
Cómo ahorrar $70 000 creando un gráfico de conocimiento para RAG en 6 millones de páginas de Wikipediapor@datastax
824 lecturas
824 lecturas

Cómo ahorrar $70 000 creando un gráfico de conocimiento para RAG en 6 millones de páginas de Wikipedia

por DataStax4m2024/10/15
Read on Terminal Reader

Demasiado Largo; Para Leer

Hemos argumentado que los gráficos de conocimiento centrados en el contenido (un almacén de vectores que permite vínculos entre fragmentos) son un enfoque más fácil de usar y más eficiente para mejorar los resultados de RAG. Aquí, lo ponemos a prueba.
featured image - Cómo ahorrar $70 000 creando un gráfico de conocimiento para RAG en 6 millones de páginas de Wikipedia
DataStax HackerNoon profile picture
0-item



El uso de gráficos de conocimiento para mejorar los resultados de las aplicaciones de generación aumentada por recuperación (RAG) se ha convertido en un tema de actualidad. La mayoría de los ejemplos demuestran cómo crear un gráfico de conocimiento utilizando una cantidad relativamente pequeña de documentos. Esto podría deberse a que el enfoque típico (extraer información detallada centrada en las entidades) simplemente no es escalable. Ejecutar cada documento a través de un modelo para extraer las entidades (nodos) y las relaciones (bordes) lleva demasiado tiempo (y cuesta demasiado) para ejecutarse en conjuntos de datos grandes.


Hemos argumentado que gráficos de conocimiento centrados en el contenido – un almacén de vectores que permite enlaces entre fragmentos – son un enfoque más fácil de usar y más eficiente. Aquí, lo ponemos a prueba. Cargamos un subconjunto de los artículos de Wikipedia desde 2wikimultisalto conjunto de datos utilizando ambas técnicas y analizamos lo que esto significa para cargar el conjunto de datos completo. Demostramos los resultados de algunas preguntas sobre los datos cargados. También cargaremos el conjunto de datos completo (casi 6 millones de documentos) en un sistema centrado en el contenido. Tienda de vectores de gráficos .

Centrado en la entidad: LLMGraphTransformer

La carga de documentos en un almacén de gráficos centrado en entidades como Neo4j se realizó utilizando LLMGraphTransformer de LangChain. El código se basa en el LLMGraphTransformer de LangChain. "Cómo construir gráficos de conocimiento".

 from langchain_core.documents import Document from langchain_experimental.graph_transformers import LLMGraphTransformer from langchain_openai import ChatOpenAI llm = ChatOpenAI(temperature=0, model_name="gpt-4-turbo") llm_transformer = LLMGraphTransformer(llm=llm) from time import perf_counter start = perf_counter() documents_to_load = [Document(page_content=line) for line in lines_to_load] graph_documents = llm_transformer.convert_to_graph_documents(documents_to_load) end = perf_counter() print(f"Loaded (but NOT written) {NUM_LINES_TO_LOAD} in {end - start:0.2f}s")

Centrado en el contenido: GraphVectorStore

Cargar los datos en GraphVectorStore es prácticamente lo mismo que cargarlos en un almacén de vectores. El único añadido es que calculamos metadatos que indican cómo cada página se vincula con otras páginas.


 import json from langchain_core.graph_vectorstores.links import METADATA_LINKS_KEY, Link def parse_document(line: str) -> Document:    para = json.loads(line)    id = para["id"]    links = {        Link.outgoing(kind="href", tag=id)        for m in para["mentions"]        if m["ref_ids"] is not None        for id in m["ref_ids"]    }    links.add(Link.incoming(kind="href", tag=id))    return Document(        id = id,        page_content = " ".join(para["sentences"]),        metadata = {            "content_id": para["id"],            METADATA_LINKS_KEY: list(links)        },    )


Este también es un buen ejemplo de cómo puedes agregar tus propios enlaces entre nodos.


 from langchain_openai import OpenAIEmbeddings from langchain_community.graph_vectorstores.cassandra import CassandraGraphVectorStore import cassio cassio.init(auto=True) TABLE_NAME = "wiki_load" store = CassandraGraphVectorStore( embedding = OpenAIEmbeddings(), node_table=TABLE_NAME, insert_timeout = 1000.0, ) from time import perf_counter start = perf_counter() from datasets.wikimultihop.load import parse_document kg_documents = [parse_document(line) for line in lines_to_load] store.add_documents(kg_documents) end = perf_counter() print(f"Loaded (and written) {NUM_LINES_TO_LOAD} in {end - start:0.2f}s")

Cargando puntos de referencia

Al ejecutarse con 100 filas, el enfoque centrado en entidades que utiliza GPT-4o tardó 405,93 s en extraer los GraphDocuments y 10,99 s en escribirlos en Neo4j, mientras que el enfoque centrado en el contenido tardó 1,43 s. Extrapolando, se necesitarían 41 semanas para cargar las 5.989.847 páginas utilizando el enfoque centrado en entidades y aproximadamente 24 horas utilizando el enfoque centrado en el contenido. Pero gracias al paralelismo, el enfoque centrado en el contenido se ejecuta en solo 2,5 horas. Suponiendo que el paralelismo tenga los mismos beneficios, todavía se necesitarían más de cuatro semanas para cargar todo utilizando el enfoque centrado en entidades. No lo probé porque el costo estimado sería de $58.700, ¡suponiendo que todo funcionara la primera vez!



En resumen: el enfoque centrado en entidades para extraer gráficos de conocimiento del contenido mediante un LLM era prohibitivo en términos de tiempo y costo a gran escala. Por otro lado, el uso de GraphVectorStore era rápido y económico.

Ejemplos de respuestas

En esta sección se formulan algunas preguntas, extraídas del subconjunto de documentos cargados, para abordar la calidad de las respuestas.


La entidad centrada utilizó 7324 tokens de solicitud y costó $0,03 para producir respuestas básicamente inútiles, mientras que la entidad centrada en el contenido utilizó 450 tokens de solicitud y costó $0,002 para producir respuestas concisas que respondieran directamente las preguntas.


Puede resultar sorprendente que el gráfico de Neo4j de grano fino devuelva respuestas inútiles. Si observamos el registro de la cadena, vemos algunas de las razones por las que esto sucede:


 > Entering new GraphCypherQAChain chain... Generated Cypher: cypher MATCH (a:Album {id: 'The Circle'})-[:RELEASED_BY]->(r:Record_label) RETURN a.id, r.id Full Context: [{'a.id': 'The Circle', 'r.id': 'Restless'}] > Finished chain. {'query': "When was 'The Circle' released?", 'result': "I don't know the answer."}


Por lo tanto, el esquema detallado solo devolvió información sobre el sello discográfico. Tiene sentido que el LLM no haya podido responder la pregunta basándose en la información recuperada.

Conclusión

La extracción de gráficos de conocimiento específicos de entidades y de granularidad fina es prohibitiva en términos de tiempo y costo a gran escala. Cuando se formularon preguntas sobre el subconjunto de datos que se cargó, la granularidad adicional (y el costo adicional de cargar el gráfico de granularidad fina) devolvieron más tokens para incluir la solicitud, pero generaron respuestas inútiles.


GraphVectorStore adopta un enfoque de grano grueso y centrado en el contenido que permite crear un gráfico de conocimiento de forma rápida y sencilla. Puede comenzar con su código existente para completar un VectorStore mediante LangChain y agregar enlaces (bordes) entre fragmentos para mejorar el proceso de recuperación.


Graph RAG es una herramienta útil para permitir que las aplicaciones RAG de IA generativa recuperen contextos más relevantes. Sin embargo, el uso de un enfoque de grano fino centrado en la entidad no se adapta a las necesidades de producción. Si desea agregar capacidades de gráficos de conocimiento a su aplicación RAG, pruebe Tienda de vectores de gráficos .


Por Ben Chambers , DataStax