> For the complete documentation index, see [llms.txt](https://docs.neuron-ai.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.neuron-ai.dev/neuron-v3-es/rag/pre-post-processor.md).

# Preprocesador/Posprocesador

Como con la mayoría de los sistemas de software, RAG es fácil de usar pero difícil de dominar. La verdad es que hay más en RAG que poner documentos en una BD vectorial y añadir un LLM encima. Eso *puede funcionar*, pero no siempre.

Con RAG, estás realizando una *búsqueda semántica* a través de muchos documentos de texto — estos podrían ser desde decenas de miles hasta decenas de miles de millones de documentos.

Para garantizar tiempos de búsqueda rápidos a escala, normalmente usamos búsqueda vectorial — es decir, transformamos nuestro texto en vectores, los colocamos todos en una base de datos vectorial y comparamos su proximidad con una consulta mediante un algoritmo de similitud (como la similitud del coseno).

Para lograr respuestas de alta calidad del agente RAG puedes trabajar en dos partes del proceso de recuperación:

1. Optimiza el prompt del usuario (*Preprocesadores*)
2. Refina los resultados de búsqueda obtenidos del almacén vectorial (*Posprocesadores*)

## Preprocesadores

En lugar de tratar la consulta original del usuario como la última palabra, el preprocesador la ve como el punto de partida para una interacción más sofisticada con el sistema de conocimiento subyacente. No se trata de cuestionar la intención del usuario, sino de reconocer que su expresión en lenguaje natural a menudo contiene múltiples preguntas incrustadas, restricciones implícitas y supuestos contextuales que deben desglosarse y reformularse para maximizar la eficacia de la recuperación.

Considera la complejidad oculta dentro de consultas aparentemente simples. Cuando alguien pregunta "¿Por qué cayeron nuestras ventas el último trimestre?", en realidad está expresando una necesidad de información multifacética que podría requerir comprender tendencias estacionales, actividades de la competencia, la eficacia de las campañas de marketing, métricas de rendimiento del producto e indicadores económicos. Un sistema RAG ingenuo podría recuperar información general sobre el análisis de ventas, perdiendo la oportunidad de ofrecer perspectivas completas y contextualmente relevantes que aborden todo el alcance de la pregunta subyacente.

### Transformación de consultas

La esencia de este patrón es usar un LLM para transformar la pregunta original en un prompt más estructurado que el agente RAG principal pueda usar para realizar una recuperación de documentos más precisa y eficaz desde el almacén vectorial.

Con Neuron puedes pasar la instancia del proveedor de IA ya adjunta a tu agente:

```php
namespace App\Neuron;

use NeuronAI\RAG\RAG;
use NeuronAI\RAG\PreProcessor\QueryTransformationPreProcessor;
use NeuronAI\RAG\PreProcessor\QueryTransformationType;

class MyChatBot extends RAG
{
    ...

    protected function preProcessors(): array
    {
        return [
            new QueryTransformationPreProcessor(
                provider: $this->resolveProvider(),
                transformation: QueryTransformationType::REWRITING,
            ),
        ];
    }
}
```

O bien usa un proveedor diferente entre los proveedores de IA compatibles como Gemini, Ollama, OpenAI, HuggingFace, etc.

```php
namespace App\Neuron;

use NeuronAI\RAG\RAG;
use NeuronAI\RAG\PreProcessor\QueryTransformationPreProcessor;
use NeuronAI\RAG\PreProcessor\QueryTransformationType;

class MyChatBot extends RAG
{
    ...

    protected function preProcessors(): array
    {
        return [
            new QueryTransformationPreProcessor(
                // Usa uno de los proveedores de IA compatibles
                provider: new Anthropic(
                    key: 'ANTHROPIC_API_KEY',
                    model: 'ANTHROPIC_MODEL',
                ),
                transformation: QueryTransformationType::REWRITING,
            ),
        ];
    }
}
```

Las tres estrategias principales implementadas en el preprocesador de Neuron son: reescritura, descomposición y HyDE (Hypothetical Document Embeddings), y cada una aborda distintos aspectos de este desafío de transformación de consultas.

**Reescritura de consultas** aborda el desajuste fundamental entre el lenguaje conversacional y las formulaciones optimizadas para la búsqueda. Cuando los usuarios expresan sus necesidades en un lenguaje informal y dependiente del contexto, el proceso de reescritura traduce estas expresiones a formulaciones más precisas y fáciles de buscar, que encajan mejor con la forma en que la información suele organizarse e indexarse.

**Descomposición** maneja la realidad de que las preguntas complejas a menudo contienen múltiples necesidades de información distintas que se servirían mejor mediante operaciones de recuperación separadas. En lugar de forzar una sola búsqueda para satisfacer múltiples aspectos diferentes de una consulta, la descomposición divide las preguntas complejas en sus partes constituyentes, permitiendo que cada componente se aborde con precisión enfocada antes de sintetizar los resultados en una respuesta completa.

T**el enfoque HyDE** representa quizá la estrategia más sofisticada, trabajando hacia atrás a partir de la suposición de que la mejor manera de encontrar información relevante es imaginar primero cómo podría verse esa información. En lugar de buscar directamente con la pregunta del usuario, HyDE genera documentos hipotéticos que idealmente responderían a la consulta, y luego usa esos documentos generados como base para búsquedas de similitud. Este enfoque es particularmente poderoso cuando se trata de conceptos abstractos o cuando la terminología del usuario no coincide estrechamente con el vocabulario usado en los documentos de origen.

## Posprocesadores

Para que la búsqueda vectorial funcione en su lugar, necesitamos vectores. Estos vectores son esencialmente compresiones del "significado" detrás de algún texto en vectores de (normalmente) 768 o 1536 dimensiones. Hay cierta pérdida de información porque estamos comprimiendo esta información en un solo vector.

Debido a esta pérdida de información, a menudo vemos que los tres primeros documentos recuperados mediante búsqueda vectorial, por ejemplo, no incluirán información relevante. Desafortunadamente, la recuperación puede devolver información relevante por debajo de nuestro `top_k` umbral.

¿Qué hacemos si la información relevante en una posición más baja ayudaría a nuestro LLM a formular una mejor respuesta? El enfoque más sencillo es aumentar el número de documentos que devolvemos (aumentar `top_k`) y pasarlos todos al LLM.

Desafortunadamente, no podemos pasar todo al LLM porque esto reduce drásticamente el rendimiento del LLM para encontrar información relevante en el texto colocado dentro de su ventana de contexto.

La solución a este problema es recuperar muchos documentos del almacén vectorial y luego *minimizando* el número de documentos que llegan al LLM. Para hacerlo, puedes reordenar y filtrar los documentos recuperados para conservar solo los más relevantes para nuestro LLM.

Neuron te permite definir una lista de componentes de posprocesamiento para encadenar tantas transformaciones como necesites para optimizar la salida del agente.

### Reclasificadores

La reclasificación es una de las operaciones de posprocesamiento más populares que puedes aplicar a los documentos recuperados. Un servicio de reclasificación calcula una puntuación de similitud de cada documento recuperado del almacén vectorial con la consulta de entrada.

Usamos esta puntuación para reordenar los documentos por relevancia y quedarnos solo con los más útiles.

### Reclasificador Jina

```php
namespace App\Neuron;

use NeuronAI\RAG\RAG;
use NeuronAI\RAG\PostProcessor\JinaRerankerPostProcessor;
use NeuronAI\RAG\VectorStore\FileVectoreStore;
use NeuronAI\RAG\VectorStore\VectorStoreInterface;

class MyChatBot extends RAG
{
    ...
    
    protected function vectorStore(): VectorStoreInterface
    {
        return new FileVectoreStore(
            directory: storage_path(),
            topK: 50
        );
    }

    protected function postProcessors(): array
    {
        return [
            new JinaRerankerPostProcessor(
                key: 'JINA_API_KEY',
                model: 'JINA_MODEL',
                topN: 5
            ),
        ];
    }
}
```

En el ejemplo anterior puedes ver cómo se le indica al almacén vectorial que obtenga 50 documentos, y el reclasificador básicamente tomará solo los 5 más relevantes.

### Reclasificador Cohere

```php
namespace App\Neuron;

use NeuronAI\RAG\RAG;
use NeuronAI\RAG\PostProcessor\CohereRerankerPostProcessor;
use NeuronAI\RAG\VectorStore\FileVectoreStore;
use NeuronAI\RAG\VectorStore\VectorStoreInterface;

class MyChatBot extends RAG
{
    ...
    
    protected function vectorStore(): VectorStoreInterface
    {
        return new FileVectoreStore(
            directory: storage_path(),
            topK: 50
        );
    }

    protected function postProcessors(): array
    {
        return [
            new CohereRerankerPostProcessor(
                key: 'COHERE_API_KEY',
                model: 'COHERE_MODEL',
                topN: 3
            ),
        ];
    }
}
```

### Umbral fijo

Usa un umbral fijo simple y configurable para filtrar documentos. Los documentos con puntuaciones por debajo del umbral se eliminan de los resultados.

Es ideal para escenarios que requieren un punto de corte explícito de puntuación para requisitos de calidad fijos.

```php
namespace App\Neuron;

use NeuronAI\RAG\PostProcessor\FixedThresholdPostProcessor;

class MyChatBot extends RAG
{
    ...

    protected function postProcessors(): array
    {
        return [
            new FixedThresholdPostProcessor(
                threshold: 0.5
            ),
        ];
    }
}
```

### Umbral adaptativo

Implementa un algoritmo de umbralización dinámica usando la mediana y la MAD (Desviación Absoluta Mediana). Se ajusta automáticamente a las distribuciones de puntuación, haciéndolo robusto frente a valores atípicos.

Puedes configurar un parámetro multiplicador que controla la agresividad del filtrado.

Valores recomendados del multiplicador:

* \[0.2 a 0.4] Modo de alta precisión. Para resultados más específicos con menos documentos pero más relevantes.
* \[0.5 a 0.7] Modo equilibrado. Configuración recomendada para casos de uso generales.
* \[0.8 a 1.0] Modo de alto recall. Para resultados más inclusivos que priorizan la cobertura.
* \>1.0 No recomendado, ya que tiende a incluir casi todos los documentos.

Este componente es ideal para depurar los resultados de RAG con un filtrado dinámico que se adapta a la distribución de puntuaciones del conjunto de resultados actual.

```php
namespace App\Neuron;

use NeuronAI\RAG\PostProcessor\AdaptiveThresholdPostProcessor;

class MyChatBot extends RAG
{
    ...

    protected function postProcessors(): array
    {
        return [
            new AdaptiveThresholdPostProcessor(
                multiplicador: 0.6
            ),
        ];
    }
}
```

### Reclasificador LocalAI

[LocalAI](https://localai.io/) es una pila completa de IA todo en uno. Puedes ejecutar modelos de lenguaje grandes localmente en tu hardware. Proporciona una API compatible con OpenAI para LLM, así que puedes usarla con el [OpenAILike](/neuron-v3-es/proveedores/ai-provider.md#openailike) proveedor.

```php
namespace App\Neuron;

use NeuronAI\RAG\PostProcessor\LocalAIPostProcessor;

class MyChatBot extends RAG
{
    ...

    protected function postProcessors(): array
    {
        return [
            new LocalAIPostProcessor(
                key: 'LOCALAI_KEY',
                model: 'LOCALAI_MODEL',
                topN: 3,
                host: 'LOCALAI_HOST' // "https://localhost:8080" por defecto
            ),
        ];
    }
}
```

## Monitoreo

Las funciones integradas de observabilidad de Neuron rastrean automáticamente la ejecución de cada posprocesador, por lo que podrás supervisar las interacciones con servicios externos en tu [Inspector](https://inspector.dev/) cuenta. Obtén más información en la [sección de monitoreo](/neuron-v3-es/agente/observability.md).

<figure><img src="/files/6ae85d5799bfc0f7b7f7d4399e9e70f78caff083" alt=""><figcaption></figcaption></figure>

## Extender el framework

Con Neuron puedes crear fácilmente tus componentes personalizados de posprocesamiento simplemente extendiendo el `\NeuronAI\PostProcessor\PostProcessorInterface`:

```php
namespace NeuronAI\RAG\PostProcessor;

use NeuronAI\Chat\Messages\Message;
use NeuronAI\RAG\Document;

interface PostProcessorInterface
{
    /**
     * Procesa un array de documentos y devuelve los documentos procesados.
     *
     * @param Message $question La pregunta para la que se procesarán los documentos.
     * @param array<Document> $documents Los documentos que se van a procesar.
     * @return array<Document> Los documentos procesados.
     */
    public function process(Message $question, array $documents): array;
}
```

Implementando el `método` process puedes realizar acciones sobre la lista de documentos y devolver la nueva lista. Neuron ejecutará los posprocesadores en el mismo orden en que aparecen en `postProcessors()` método.

Aquí tienes un ejemplo práctico:

```php
namespace App\Neuron\PostProcessors;

use NeuronAI\Chat\Messages\Message;
use NeuronAI\RAG\PostProcessor\PostProcessorInterface;

// Implementa tu componente personalizado
class CutOffPostProcessor implements PostProcessorInterface
{
    public function __constructor(protected int $level) {}

    public function process(Message $question, array $documents): array
    {
        /*
         * Aplica un punto de corte en la puntuación devuelta por el almacén vectorial
         */
         
        return $documents;
    }
}
```
