565 lecturas
565 lecturas

Un agente de IA que interpreta los documentos para que no tengas que: Guía completa de construcción

por Superlinked18m2025/06/26
Read on Terminal Reader

Demasiado Largo; Para Leer

Construye un agente de investigación de IA en tiempo real utilizando la búsqueda vectorial de Superlinked.Supera las complejas tuberías de RAG incorporando y consultando documentos directamente, haciendo la investigación más rápida, sencilla y inteligente.
featured image - Un agente de IA que interpreta los documentos para que no tengas que: Guía completa de construcción
Superlinked HackerNoon profile picture
0-item
1-item


Aprenda a construir un agente de IA para la recuperación de documentos de investigación, búsqueda y resumen

Aprenda a construir un agente de IA para la recuperación de documentos de investigación, búsqueda y resumen

Para los investigadores, mantenerse actualizado con los últimos hallazgos es similar a encontrar una aguja en una pila de heno. Imagínese a un asistente alimentado por IA que no solo recupera los artículos más relevantes, sino que también resume las ideas clave y responde a sus preguntas específicas, todo en tiempo real.

Este artículo profundiza en la construcción de un agente de investigación de IA de este tipo utilizando las complejas capacidades de incorporación de documentos de Superlinked.Al integrar la relevancia semántica y temporal, eliminamos la necesidad de un rearrangamiento complejo, asegurando una recuperación eficiente y precisa de la información.

Este artículo profundiza en la construcción de un agente de investigación de IA de este tipo utilizando las complejas capacidades de incorporación de documentos de Superlinked.Al integrar la relevancia semántica y temporal, eliminamos la necesidad de un rearrangamiento complejo, asegurando una recuperación eficiente y precisa de la información.

TL;DR:

Construye un agente de investigación de IA en tiempo real utilizando la búsqueda vectorial de Superlinked.Supera las complejas tuberías de RAG incorporando y consultando documentos directamente, haciendo la investigación más rápida, sencilla y inteligente.

(¿Quieres saltar directamente al código? Compruebe el código abierto en GitHub aquí. Listo para probar la búsqueda semántica para su propio caso de uso de agentes?

Revisa el código abierto en GitHubAquí.AquíAquíEstamos aquí paraAyuda.AyudaAyuda

Este artículo muestra cómo construir un sistema de agentes usando un agente del núcleo para manejar consultas. Si desea seguir y ejecutar el código en el navegador,here’s the Colab.

Colab.Colab

Where to start building a research assistant system?

Tradicionalmente, la construcción de un sistema de este tipo implica complejidad e inversión considerable de recursos. Los sistemas de búsqueda suelen recuperar un amplio conjunto inicial de documentos basado en la relevancia y luego aplicar un proceso de rearrangamiento secundario para refinar y reordenar los resultados. Mientras que el rearrangamiento mejora la precisión, aumenta significativamente la complejidad computacional, la latencia y la sobrecarga debido a la extensa recuperación de datos requerida inicialmente. Superlinked aborda esta complejidad mediante la combinación de incorporaciones numéricas y categoricas estructuradas con incorporaciones de texto semántico, proporcionando vectores multimodales completos. Este método mejora significativamente la precisión de la búsqueda preservando información específica de atributos dentro de cada incorporación.

Construye un sistema de agentes con Superlinked

Este agente de IA puede hacer tres cosas principales:

  1. Buscar trabajos de investigación: Buscar los trabajos de investigación por tema (por ejemplo, “computación cuántica”) y luego ordenarlos por relevancia y reciente.
  2. Resumir los documentos: Condensar los documentos recuperados en insights de tamaño de pedazo.
  3. Preguntas de respuesta: Extraer respuestas directamente de los artículos de investigación específicos basados en consultas de usuarios dirigidas.

Superlinked elimina la necesidad de métodos de re-rango ya que mejora la relevancia de la búsqueda vectorial. Se utilizará el RecencySpace de Superlinked que codifica específicamente metadatos temporales, priorizando documentos recientes durante la búsqueda, y eliminando la necesidad de re-rango computacionalmente caro. Por ejemplo, si dos artículos tienen la misma relevancia - el que es más reciente se clasificará más alto.

Paso 1: Configurar la caja de herramientas

 %pip install superlinked

Para hacer las cosas más fáciles y más modulares, he creado una clase de herramientas abstractas.

import pandas as pd
import superlinked.framework as sl
from datetime import timedelta
from sentence_transformers import SentenceTransformer
from openai import OpenAI
import os
from abc import ABC, abstractmethod
from typing import Any, Optional, Dict
from tqdm import tqdm
from google.colab import userdata

# Abstract Tool Class
class Tool(ABC):
    @abstractmethod
    def name(self) -> str:
        pass

    @abstractmethod
    def description(self) -> str:
        pass

    @abstractmethod
    def use(self, *args, **kwargs) -> Any:
        pass


# Get API key from Google Colab secrets
try:
    api_key = userdata.get('OPENAI_API_KEY')
except KeyError:
    raise ValueError("OPENAI_API_KEY not found in user secrets. Please add it using Tools > User secrets.")

# Initialize OpenAI Client
api_key = os.environ.get("OPENAI_API_KEY", "your-openai-key")  # Replace with your OpenAI API key
if not api_key:
    raise ValueError("Please set the OPENAI_API_KEY environment variable.")

client = OpenAI(api_key=api_key)
model = "gpt-4"


Paso 2: Comprender el conjunto de datos

Este ejemplo utiliza un conjunto de datos que contiene aproximadamente 10.000 artículos de investigación de IA disponibles enKaguyaPara facilitarlo, simplemente ejecute la celda de abajo y descargará automáticamente el conjunto de datos a su directorio de trabajo. También puede utilizar sus propias fuentes de datos, como artículos de investigación u otro contenido académico. Si decide hacerlo, todo lo que necesita hacer es ajustar ligeramente el diseño del esquema y actualizar los nombres de columnas.

import pandas as pd

!wget --no-check-certificate 'https://drive.google.com/uc?export=download&id=1FCR3TW5yLjGhEmm-Uclw0_5PWVEaLk1j' -O arxiv_ai_data.csv


Por ahora, para hacer que las cosas funcionen un poco más rápido, usaremos un subconjunto más pequeño de los papeles sólo para acelerar las cosas, pero siéntate libre de probar el ejemplo usando el conjunto completo de datos. Un detalle técnico importante aquí es que los timestamps del conjunto de datos se convertirán de timestamps de cuerdas (como '1993-08-01 00:00:00+00:00') en objetos de tiempo de data pandas. Esta conversión es necesaria porque nos permite realizar operaciones de fecha/hora.

df = pd.read_csv('arxiv_ai_data.csv').head(100)

# Convert to datetime but keep it as datetime (more readable and usable)
df['published'] = pd.to_datetime(df['published'])

# Ensure summary is a string
df['summary'] = df['summary'].astype(str)

# Add 'text' column for similarity search
df['text'] = df['title'] + " " + df['summary']
Debug: Columns in original DataFrame: ['authors', 'categories', 'comment', 'doi', 'entry_id', 'journal_ref' 'pdf_url', 'primary_category', 'published', 'summary', 'title', 'updated']

Comprender las columnas de Dataset

A continuación se muestra una breve visión general de las columnas clave en nuestro conjunto de datos, que serán importantes en los próximos pasos:

  1. Publicado: La fecha de publicación del artículo de investigación.
  2. Resumen: El resumen del artículo, proporcionando una visión general concisa.
  3. entry_id: El identificador único para cada papel de arXiv.

Para esta demostración, nos centramos específicamente en cuatro columnas:entry_id, depublished, detitle, ysummaryPara optimizar la calidad de búsqueda, el título y el resumen se combinan en una única columna de texto completa, que forma el núcleo de nuestro proceso de incorporación y búsqueda.

Nota sobre el Índice In-Memory de Superlinked: La indexación in-memory de Superlinked almacena nuestro conjunto de datos directamente en la RAM, lo que hace que la recuperación sea excepcionalmente rápida, lo que es ideal para búsquedas en tiempo real y prototipos rápidos.

Paso 3: Definir el esquema superligado

Para avanzar, hay necesidad de un esquema para mapear nuestros datos.PaperSchemaCon los campos clave:

lass PaperSchema(sl.Schema):
    text: sl.String
    published: sl.Timestamp  # This will handle datetime objects properly
    entry_id: sl.IdField
    title: sl.String
    summary: sl.String

paper = PaperSchema()


Definición de espacios superligados para una recuperación efectiva

Un paso esencial en la organización y consulta efectiva de nuestro conjunto de datos implica la definición de dos espacios vectoriales especializados: TextSimilaritySpace y RecencySpace.

  1. Espacio Textil

ElTextSimilaritySpaceestá diseñado para codificar la información textual, como los títulos y los abstractos de los trabajos de investigación en vectores. Al convertir el texto en embeddings, este espacio mejora significativamente la facilidad y la precisión de las búsquedas semánticas.

text_space = sl.TextSimilaritySpace(
    text=sl.chunk(paper.text, chunk_size=200, chunk_overlap=50),
    model="sentence-transformers/all-mpnet-base-v2"
)


  1. Espacio Recente

ElRecencySpacecaptura metadatos temporales, enfatizando la actualidad de las publicaciones de investigación. Al codificar los timestamps, este espacio asigna mayor importancia a los documentos más recientes. Como resultado, los resultados de la búsqueda equilibran naturalmente la relevancia del contenido con las fechas de publicación, favoreciendo las ideas recientes.

recency_space = sl.RecencySpace(
    timestamp=paper.published,
    period_time_list=[
        sl.PeriodTime(timedelta(days=365)),      # papers within 1 year
        sl.PeriodTime(timedelta(days=2*365)),    # papers within 2 years
        sl.PeriodTime(timedelta(days=3*365)),    # papers within 3 years
    ],
    negative_filter=-0.25
)


Piense en RecencySpace como un filtro basado en el tiempo, similar a ordenar sus correos electrónicos por fecha o ver las publicaciones de Instagram con las más recientes primero.

  • Los intervalos de tiempo más pequeños (como los 365 días) permiten una clasificación más granular, basada en el tiempo anual.
  • Los intervalos de tiempo más grandes (como 1095 días) crean períodos de tiempo más amplios.

Elnegative_filterPara explicarlo más claramente, considere el siguiente ejemplo donde dos artículos tienen la misma relevancia de contenido, pero su clasificación dependerá de sus fechas de publicación.

Paper A: Published in 1996 
Paper B: Published in 1993

Scoring example:
- Text similarity score: Both papers get 0.8
- Recency score:
  - Paper A: Receives the full recency boost (1.0)
  - Paper B: Gets penalized (-0.25 due to negative_filter)

Final combined scores:
- Paper A: Higher final rank
- Paper B: Lower final rank


Estos espacios son clave para hacer el conjunto de datos más accesible y eficaz. Permiten tanto las búsquedas basadas en el contenido como en el tiempo, y son realmente útiles para comprender la relevancia y la actualidad de los trabajos de investigación. Esto proporciona una forma poderosa de organizar y buscar a través del conjunto de datos basado tanto en el contenido como en el tiempo de publicación.

Paso 4: Creación del índice

Luego, los espacios se fusionan en un índice que es el núcleo del motor de búsqueda:

paper_index = sl.Index([text_space, recency_space])

Luego, el DataFrame es mapeado al esquema y cargado en lotes (10 papeles a la vez) en un almacenamiento en memoria:

# Parser to map DataFrame columns to schema fields
parser = sl.DataFrameParser(
    paper,
    mapping={
        paper.entry_id: "entry_id",
        paper.published: "published",
        paper.text: "text",
        paper.title: "title",
        paper.summary: "summary",
    }
)

# Set up in-memory source and executor
source = sl.InMemorySource(paper, parser=parser)
executor = sl.InMemoryExecutor(sources=[source], indices=[paper_index])
app = executor.run()

# Load the DataFrame with a progress bar using batches
batch_size = 10
data_batches = [df[i:i + batch_size] for i in range(0, len(df), batch_size)]
for batch in tqdm(data_batches, total=len(data_batches), desc="Loading Data into Source"):
    source.put([batch])


El ejecutor en memoria es por lo que Superlinked brilla aquí: 1.000 papeles se encajan bien en la RAM, y las consultas vuelan sin botellas de I/O del disco.

Paso 5: Creación de la consulta

A continuación está la creación de la consulta. Aquí es donde se crea la plantilla para elaborar consultas. Para gestionar esto, necesitamos una plantilla de consulta que equilibre tanto la relevancia como la reciente.

# Define the query
knowledgebase_query = (
    sl.Query(
        paper_index,
        weights={
            text_space: sl.Param("relevance_weight"),
            recency_space: sl.Param("recency_weight"),
        }
    )
    .find(paper)
    .similar(text_space, sl.Param("search_query"))
    .select(paper.entry_id, paper.published, paper.text, paper.title, paper.summary)
    .limit(sl.Param("limit"))
)


Esto nos permite elegir si priorizar el contenido (relevance_weight) o el reciente (recency_weight) - una combinación muy útil para las necesidades de nuestro agente.

Paso 6: Creación de herramientas

Ahora viene la parte de la herramienta.

Crearemos tres herramientas...

  1. Herramienta de recuperación: Esta herramienta se crea conectando al índice de Superlinked, permitiéndole sacar los 5 primeros artículos basados en una consulta. Equilibra la relevancia (1.0 peso) y la reciente (0.5 peso) para lograr el objetivo de “encontrar documentos”.Lo que queremos es encontrar los artículos que son relevantes para la consulta. Por lo tanto, si la consulta es: “¿Qué artículos de computación cuántica se publicaron entre 1993 y 1994?”, entonces la herramienta de recuperación recuperará esos artículos, los resumirá uno por uno y devolverá los resultados.
class RetrievalTool(Tool):
    def __init__(self, df, app, knowledgebase_query, client, model):
        self.df = df
        self.app = app
        self.knowledgebase_query = knowledgebase_query
        self.client = client
        self.model = model

    def name(self) -> str:
        return "RetrievalTool"

    def description(self) -> str:
        return "Retrieves a list of relevant papers based on a query using Superlinked."

    def use(self, query: str) -> pd.DataFrame:
        result = self.app.query(
            self.knowledgebase_query,
            relevance_weight=1.0,
            recency_weight=0.5,
            search_query=query,
            limit=5
        )
        df_result = sl.PandasConverter.to_pandas(result)
        # Ensure summary is a string
        if 'summary' in df_result.columns:
            df_result['summary'] = df_result['summary'].astype(str)
        else:
            print("Warning: 'summary' column not found in retrieved DataFrame.")
        return df_result


El siguiente es elSummarization ToolEsta herramienta está diseñada para los casos en los que se necesita un resumen conciso de un documento.paper_id, que es la identificación del papel que debe ser resumido.paper_idno se proporciona, la herramienta no funcionará ya que estos identificadores son un requisito para encontrar los papeles correspondientes en el conjunto de datos.

class SummarizationTool(Tool):
    def __init__(self, df, client, model):
        self.df = df
        self.client = client
        self.model = model

    def name(self) -> str:
        return "SummarizationTool"

    def description(self) -> str:
        return "Generates a concise summary of specified papers using an LLM."

    def use(self, query: str, paper_ids: list) -> str:
        papers = self.df[self.df['entry_id'].isin(paper_ids)]
        if papers.empty:
            return "No papers found with the given IDs."
        summaries = papers['summary'].tolist()
        summary_str = "\n\n".join(summaries)
        prompt = f"""
        Summarize the following paper summaries:\n\n{summary_str}\n\nProvide a concise summary.
        """
        response = self.client.chat.completions.create(
            model=self.model,
            messages=[{"role": "user", "content": prompt}],
            temperature=0.7,
            max_tokens=500
        )
        return response.choices[0].message.content.strip()


Por último, tenemos elQuestionAnsweringToolEsta herramienta cede laRetrievalToolpara recoger los documentos pertinentes y luego usarlos para responder a las preguntas.Si no se encuentran documentos pertinentes para responder a las preguntas, proporcionará una respuesta basada en el conocimiento general

class QuestionAnsweringTool(Tool):
    def __init__(self, retrieval_tool, client, model):
        self.retrieval_tool = retrieval_tool
        self.client = client
        self.model = model

    def name(self) -> str:
        return "QuestionAnsweringTool"

    def description(self) -> str:
        return "Answers questions about research topics using retrieved paper summaries or general knowledge if no specific context is available."

    def use(self, query: str) -> str:
        df_result = self.retrieval_tool.use(query)
        if 'summary' not in df_result.columns:
            # Tag as a general question if summary is missing
            prompt = f"""
            You are a knowledgeable research assistant. This is a general question tagged as [GENERAL]. Answer based on your broad knowledge, not limited to specific paper summaries. If you don't know the answer, provide a brief explanation of why.

            User's question: {query}
            """
        else:
            # Use paper summaries for specific context
            contexts = df_result['summary'].tolist()
            context_str = "\n\n".join(contexts)
            prompt = f"""
            You are a research assistant. Use the following paper summaries to answer the user's question. If you don't know the answer based on the summaries, say 'I don't know.'

            Paper summaries:
            {context_str}

            User's question: {query}
            """
        response = self.client.chat.completions.create(
            model=self.model,
            messages=[{"role": "user", "content": prompt}],
            temperature=0.7,
            max_tokens=500
        )
        return response.choices[0].message.content.strip()


Paso 7: Construir el Agente del Núcleo

A continuación, el Agente del Núcleo. Funciona como el controlador central, asegurando un funcionamiento suave y eficiente. Actando como el componente principal del sistema, el Agente del Núcleo coordina la comunicación mediante el enrutamiento de consultas según su intención cuando varios agentes operan simultáneamente. En sistemas de agentes únicos, como este, el Agente del Núcleo utiliza directamente las herramientas pertinentes para gestionar tareas de manera efectiva.

class KernelAgent:
    def __init__(self, retrieval_tool: RetrievalTool, summarization_tool: SummarizationTool, question_answering_tool: QuestionAnsweringTool, client, model):
        self.retrieval_tool = retrieval_tool
        self.summarization_tool = summarization_tool
        self.question_answering_tool = question_answering_tool
        self.client = client
        self.model = model

    def classify_query(self, query: str) -> str:
        prompt = f"""
        Classify the following user prompt into one of the three categories:
        - retrieval: The user wants to find a list of papers based on some criteria (e.g., 'Find papers on AI ethics from 2020').
        - summarization: The user wants to summarize a list of papers (e.g., 'Summarize papers with entry_id 123, 456, 789').
        - question_answering: The user wants to ask a question about research topics and get an answer (e.g., 'What is the latest development in AI ethics?').

        User prompt: {query}

        Respond with only the category name (retrieval, summarization, question_answering).
        If unsure, respond with 'unknown'.
        """
        response = self.client.chat.completions.create(
            model=self.model,
            messages=[{"role": "user", "content": prompt}],
            temperature=0.7,
            max_tokens=10
        )
        classification = response.choices[0].message.content.strip().lower()
        print(f"Query type: {classification}")
        return classification

    def process_query(self, query: str, params: Optional[Dict] = None) -> str:
        query_type = self.classify_query(query)
        if query_type == 'retrieval':
            df_result = self.retrieval_tool.use(query)
            response = "Here are the top papers:\n"
            for i, row in df_result.iterrows():
                # Ensure summary is a string and handle empty cases
                summary = str(row['summary']) if pd.notna(row['summary']) else ""
                response += f"{i+1}. {row['title']} \nSummary: {summary[:200]}...\n\n"
            return response
        elif query_type == 'summarization':
            if not params or 'paper_ids' not in params:
                return "Error: Summarization query requires a 'paper_ids' parameter with a list of entry_ids."
            return self.summarization_tool.use(query, params['paper_ids'])
        elif query_type == 'question_answering':
            return self.question_answering_tool.use(query)
        else:
            return "Error: Unable to classify query as 'retrieval', 'summarization', or 'question_answering'."


En esta etapa, todos los componentes del Sistema de Agentes de Investigación han sido configurados.El sistema ahora puede ser inicializado proporcionando al Agente del Núcleo las herramientas adecuadas, después de lo cual el Sistema de Agentes de Investigación estará plenamente operativo.

retrieval_tool = RetrievalTool(df, app, knowledgebase_query, client, model)
summarization_tool = SummarizationTool(df, client, model)
question_answering_tool = QuestionAnsweringTool(retrieval_tool, client, model)

# Initialize KernelAgent
kernel_agent = KernelAgent(retrieval_tool, summarization_tool, question_answering_tool, client, model)


Ahora vamos a probar el sistema.

# Test query print(kernel_agent.process_query("Find papers on quantum computing in last 10 years"))

Con esta acción se activa elRetrievalToolRecogerá los documentos pertinentes basados tanto en la relevancia como en la actualidad, y devolverá las columnas pertinentes.Si el resultado devuelto incluye la columna de resumen (indicando que los documentos fueron recuperados del conjunto de datos), utilizará esos resúmenes y los devolverá a nosotros.

Query type: retrieval
Here are the top papers:
1. Quantum Computing and Phase Transitions in Combinatorial Search 
Summary: We introduce an algorithm for combinatorial search on quantum computers that
is capable of significantly concentrating amplitude into solutions for some NP
search problems, on average. This is done by...

1. The Road to Quantum Artificial Intelligence 
Summary: This paper overviews the basic principles and recent advances in the emerging
field of Quantum Computation (QC), highlighting its potential application to
Artificial Intelligence (AI). The paper provi...

1. Solving Highly Constrained Search Problems with Quantum Computers 
Summary: A previously developed quantum search algorithm for solving 1-SAT problems in
a single step is generalized to apply to a range of highly constrained k-SAT
problems. We identify a bound on the number o...

1. The model of quantum evolution 
Summary: This paper has been withdrawn by the author due to extremely unscientific
errors....

1. Artificial and Biological Intelligence 
Summary: This article considers evidence from physical and biological sciences to show
machines are deficient compared to biological systems at incorporating
intelligence. Machines fall short on two counts: fi...


Vamos a intentar otra consulta, esta vez, vamos a hacer un resumen.

print(kernel_agent.process_query("Summarize this paper", params={"paper_ids": ["http://arxiv.org/abs/cs/9311101v1"]}))

Query type: summarization
This paper discusses the challenges of learning logic programs that contain the cut predicate (!). Traditional learning methods cannot handle clauses with cut because it has a procedural meaning. The proposed approach is to first generate a candidate base program that covers positive examples, and then make it consistent by inserting cut where needed. Learning programs with cut is difficult due to the need for intensional evaluation, and current induction techniques may need to be limited to purely declarative logic languages.


Espero que este ejemplo haya sido útil para el desarrollo de agentes de IA y sistemas basados en agentes. Gran parte de la funcionalidad de recuperación demostrada aquí fue posible por Superlinked, por lo que considere protagonizar larepositoriopara futuras referencias cuando se necesiten capacidades de recuperación precisas para sus agentes de IA!

Takeaways

Código de notas

  • La combinación de la relevancia semántica y temporal elimina el complejo rearrangamiento al tiempo que se mantiene la exactitud de la búsqueda para los artículos de investigación.
  • Las penas basadas en el tiempo (negative_filter=-0.25) priorizan la investigación reciente cuando los artículos tienen relevancia de contenido similar.
  • La arquitectura modular basada en herramientas permite a los componentes especializados manejar tareas distintas (recuperación, resumen, respuesta a preguntas) mientras se mantiene la cohesión del sistema.
  • Cargar datos en lotes pequeños (batch_size=10) con seguimiento del progreso mejora la estabilidad del sistema al procesar grandes conjuntos de datos de investigación.
  • Los pesos de consulta ajustables permiten a los usuarios equilibrar la relevancia (1.0) y la reciente (0.5) en función de las necesidades de investigación específicas.
  • El componente de respuesta a preguntas se degrada graciosamente a conocimientos generales cuando el contexto específico del papel no está disponible, lo que evita experiencias de usuario sin fin.

Mantener actualizado con el gran número de artículos de investigación publicados regularmente puede ser desafiante y demorado.Un flujo de trabajo de asistente de IA capaz de localizar de manera eficiente la investigación relevante, resumir las ideas clave y responder a preguntas específicas de estos artículos podría simplificar significativamente este proceso.

Contribuyentes

  • Vipul Maheshwari, autor
  • Filip Makraduli, crítico


Trending Topics

blockchaincryptocurrencyhackernoon-top-storyprogrammingsoftware-developmenttechnologystartuphackernoon-booksBitcoinbooks