RAG (Retrieval-augmented Generation)
Mejorar y personalizar las respuestas de los
modelos de lenguaje natural generativos
con datos específicos de la empresa
RAG: Retrieval-augmented Generation
Generación con recuperación aumentada, o mejor,
Generación aumentada por recuperación
• El usuario quiere hacer una consulta y se invoca un
servicio de AI generativa (generalmente en Python
chainlang)
• El servicio AI primero debe establecer qué
información se está preguntando para extraer de
una base de datos de conocimiento propia la
información pertinente de la empresa (ahora se
usa búsqueda semántica = bases de datos
vectoriales)
• Con la información obtenida se arma la consulta
que se envía al modelo de lenguaje generativo:
• Prompt o instrucciones específicas
• Contexto con la información obtenida
• Pregunta del usuario
• El modelo de lenguaje LLM genera la respuesta
con base en el prompt+context+pregunta
Componentes en RAG
• Plataforma del Servicio o Agente de AI generative
– Es la solución que se construye para implementar un modelo RAG
– Normalmente en python con la biblioteca langchain, que va a orquestar la solución
• Base de datos de conocimiento:
– Documentos o datos empresariales que van a enriquecer la respuesta generada (se requiere extraer sólo el
texto relevante, o sea, quitar basura)
• Podría incluir texto, imágenes, audio y video
– Base de datos vectorial o semántica (* ver siguiente filmina)
– Base de datos para el contenido (de documentos o relacional)
• Estrategia de fragmentación (chunks):
– Los modelos de vectorización tienen límites de tamaño para conversión
– Equilibrio entre costo y coherencia.
• Modelo de conversión semántica o vectorización o embedder:
– Convierte de texto a vector semántico
• Local: intfloat/multilingual-e5-base o jinaai/jina-embeddings-v2-base-es (para español)
• Nube: OpenAI text-embedding-3-small
• Modelo de lenguage natural generativo (LLM)
– Comprende y genera texto en lenguaje humano.
• Local: no son viables porque requieren mucho procesamiento y GPUs
• Nube: OpenAI (ChatGPT), Cohere, Azure, OCI
(requieren pagar servicio)
Búsqueda Semántica
• Estrategia de recuperación de datos
– Se puede usar clasificación o full text search o búsqueda semántica
• RAG se popularizó con las técnicas de búsqueda semántica
– La búsqueda semántica requiere:
• Conversión de texto a vector semántico (vector = embedding = incrustación), a través de un modelo de conversión semántica o embedder
• Una base de datos de conocimiento: base de datos vectorial (para búsqueda semántica) + base de datos para texto o documentos
• Preparación de datos:
– Convertir toda la documentación de texto a vector semántico y almacenarlo en
una base de datos vectorial y el texto en una base de datos para texto
» Primero se divide la documentación en fragmentos o chunks
» Luego se convierte cada chunk a vector
» Por último se almacena el vector (índice) y el texto (datos) con el mismo
identificador
• Búsqueda semántica (obtener el contexto):
– Convertir la pregunta de texto a vector semántico
– Se consulta la base de datos vectorial (índice):
» La consulta semántica encuentra los ids almacenados en la base de
datos vectorial correspondientes a los vecinos más cercanos de la
pregunta vectorizada ordenados por su cercanía (los más parecidos a la
pregunta)
– Con los Ids se recupera el texto en una base de datos de documentos o
relacional (datos) (Hay bases de datos vectoriales que almacenan texto)
– El texto obtenido se convierte en el contexto que se va a enviar al modelo LLM
para enriquecer la respuesta
Base de datos semánticas (1)
Base de datos semánticas (1)
Las que realmente se usan en el Mercado
Bases de datos semánticas (2)
Base de Datos Vectorial Ventajas Desventajas Casos de Uso
- Sólo es índice en memoria, biblioteca embeddida en
programa
- Muy rápido y eficiente - No es una base de datos (no persistente por sí solo)
- Prototipos rápidos
FAISS - Altamente optimizable (usa GPU) - No tiene consultas complejas
- Sistemas embebidos con búsquedas locales
- Open Source - Escalable solo verticalmente (RAM) - Velocidad extrema y/o datasets masivos
Volúmenes de vectores depende de RAM (312.5K/1GB)
- Indice y datos, biblioteca embeddida en programa
- Ligero, simple con API facil de usar - Escalable solo verticalmente
Proyectos personales o de investigación en notebooks
Chroma - Persistente y Autocontenida - Nueva con poca Documentación
para pruebas, demos, prototipos. Más fácil que FAISS
- Open source - Sin clustering o particionado
Volúmenes medianos de vectores (<5M)
- SaaS completamente gestionado - Base de datos empresarial, autogestionada, pago
- Cerrado (no OSS)
Pinecone - Altamente escalable
- Costoso para grandes volúmenes
Empresas que necesitan escalabilidad sin administrar
- Multi-tenancy infraestructura
- Altamente escalable
- Base de datos empresarial, multinodo
- Soporte para millones de vectores - Complejo de desplegar sin Zilliz Cloud
Milvus / Zilliz Cloud - GPU/CPU - Requiere infraestructura adicional
Grandes volúmenes de vectores (>50M), búsqueda en
tiempo real
- Open Source
- Alto rendimiento - Curva de aprendizaje - Base de datos empresarial, single-node y multinodo
- API sencilla con Filtros avanzados - Menos funcionalidades de grafo Búsqueda vectorial rápida con filtros complejos
Qdrant /Qdrant Cloud - Escalable - No multimodal por defecto Grandes volúmenes de vectores (<50M)
- Open source - Requiere infraestructura
- Soporte nativo de vectores - Base de datos empresarial, multinodo
- GraphQL - Más pesado que otros PYMEs o empresas con múltiples tipos de datos
Weaviate - Escalable y fácil de usar - Curva de aprendizaje inicial semánticos y necesidades de búsqueda híbrida
- Open Source Grandes volúmenes de vectores (<50M)
- BD NoSQL clave/valor
- Rápido, en memoria
- Escalabilidad limitada (a RAM)
Redis / Valkey (fork) + Search - Soporte con módulo Search (nuevo)
- Indexación más limitada comparado con FAISS/Milvus
Casos ligeros con latencia mínima y vectores <100k
- Compatible con SaaS
- Valkey es Open Source
- Plugin de vectorización y KNN nativo (faiss/HNSW) - No tan optimizado como bases vectoriales puras - Sistemas empresariales que ya usan Elasticsearch
- Integración con modelos de lenguaje - Configuración más compleja - Documentos con metadatos estructurados
ElasticSeach / OpenSearch (fork) - Escalable y distribuido - No tiene funciones de clasificación o reranking - Sistemas híbridos
- Opensearch: Ecosistema de visualización semántico - Sistemas legales, salud, soporte técnico
- Integración SQL
Agregar vector search a sistemas relacionales
- Soporte vectorial creciente - Indexación más lenta
pgvector (PostgreSQL) - Open Source - No ideal para grandes volúmenes sin ajustes
Volúmenes medianos de vectores (<10M)
- SQL + vector
- Alta disponibilidad y escalabilidad - Costoso
Agregar vector search a sistemas relacionales
Oracle 23c y 23ai (Autonomous) - Integración con AI de Oracle - Cerrado
Volúmenes medianos de vectores (<10M)
- SQL + vector - Dependencia de ecosistema Oracle
- Vector search nativo (nuevo)
- Licenciamiento cerrado Agregar vector search a sistemas relacionales
MS SQL Server 2025 - Integración con .NET y Power BI
- Funcionalidades vectoriales aún en evolución Volúmenes medianos de vectores (<10M)
- SQL + vector
Bases de datos semánticas (3)
Base de Datos Vectorial Estrategia SOIN
Base de datos relacional con soporte vectorial, open source
Ya tenemos gran experiencia en desarrollar y gestionar bases de datos relaciones, específicamente postgresql
pgvector (PostgreSQL) Permite manejar hasta 10 millones de vectores
Se puede mejorar con nuevas extensiones: vectorScale, Lantern o vectorChord
Base de datos vectorial, open source
Qdrant Permite manejar hasta 50 millones de vectores
Fácil administración en ambientes single-node. También permite ambientes multi-node
Base de datos vectorial, open source
Permite manejar más de 50 millones de vectores (cientos y miles de millones de vectores)
Milvus Logra consultas en tiempo real con grandes volúmenes de vectores en ambientes multi-node
Más complejo de administrar
Estrategias de Fragmentación (1)
• La fragmentación (o chunking) en la búsqueda semántica tiene un propósito fundamental: dividir textos largos en
unidades manejables y significativas para que los modelos de lenguaje y los motores de búsqueda vectorial puedan
entender, indexar y recuperar información de forma más precisa y eficiente.
• Los modelos de búsqueda semántica tienen límites de entrada, tanto en tokens como en capacidad semántica. Un
documento completo podría:
– Exceder el límite del modelo.
– Contener múltiples temas (difícil de representar en un solo vector).
– Perder precisión si se resume en un solo embedding.
Beneficio Explicación
Mejora la relevancia Al dividir el texto, cada fragmento puede enfocarse en un tema específico, lo que permite encontrar
partes más relevantes del contenido.
Evita pérdida de información Fragmentar asegura que se conserven detalles que podrían perderse al vectorizar documentos
completos.
Permite matching granular Puedes encontrar el fragmento exacto que responde a una pregunta del usuario.
Facilita el RAG Proporciona chunks relevantes al modelo generativo para dar mejores respuestas.
Reduce el ruido Un chunk más pequeño tiene menos información irrelevante, aumentando la precisión semántica.
• Se busca un equilibrio entre maximizar la relevancia semántica y preservar el contexto suficiente, sin exceder los
límites del modelo ni diluir la información útil.
– Fragmentos muy pequeños pueden perder significado o resultar ambiguos.
– Fragmentos muy grandes pueden mezclar varios temas, lo que reduce la relevancia del resultado y requieren mayor consumo de recursos.
Estrategias de Fragmentación (2)
Tipo de Fragmentación Descripción Ventajas Desventajas
Divide el texto en fragmentos - Fácil de implementar - Puede cortar oraciones o
Fragmentación de uniformes basados en una cantidad - Procesamiento rápido párrafos
Tamaño Fijo predefinida de caracteres o tokens. - Consistencia en tamaño - No respeta la estructura del
contenido
Fragmentación Basada Divide el texto según una cantidad - Optimiza el uso de modelos - Puede interrumpir oraciones
en Tokens específica de tokens, adaptado a los - Control preciso del tamaño - No considera la semántica
límites del modelo.
Fragmentación Usa separadores jerárquicos - Mantiene estructura semántica - Configuración compleja
Recursiva (párrafos, oraciones) para dividir el - Adaptable a distintos tipos de - Mayor carga computacional
texto preservando estructura lógica. contenido
Trata el documento como un - Preserva contexto completo - Escalabilidad limitada en
Fragmentación Basada fragmento o lo divide mínimamente. - Ideal para contratos, informes documentos largos
en Documentos Ideal para textos donde cortar afecta médicos - Menor eficiencia en
el significado. procesamiento
Fragmentación Divide el texto según cambios en el - Mantiene coherencia semántica - Requiere análisis semántico
Semántica significado, usando embeddings. - Mejora recuperación de avanzado
información - Ajuste fino de umbrales
- Preserva significado de las - Tamaño variable según la
Fragmentación Basada Divide el texto en bloques de oraciones longitud de oraciones
en Oraciones oraciones completas. - Buena legibilidad - Menor control sobre tamaño
exacto
Fragmenta el contenido según tareas - Configuración compleja por
Fragmentación específicas que realiza un agente de - Optimiza IA para tareas específicas definición de roles
Agéntica IA. - Foco en datos relevantes - Posible pérdida de contexto
global
Overlapping o Incluir en el siguiente chunk la última - Preservar contexto - Aumento volumen de datos
solapamiento parte del chunk anterior - Mejorar comprensión semántica - Redundancia en embeddings
- Mejorar precisión búsquedas RAG - Más tiempo y recursos
Estrategias de Fragmentación (3)
• Idea propia: Sin Fragmentación (o minimizando la fragmentación), más bien comprimir el contenido de
cada documento en un nuevo texto que elimine toda la información superflua, pero que a la vez sea
completo, relevante y rico en conceptos clave para búsquedas semánticas.
• La idea es que sea el mismo modelo LLM que genere un resumen optimizado para RAG
Ventajas Desventajas (se deben resolver con indicaciones detalladas al LLM)
• Preserva el contexto de tema completo sin fragmentarlo • Riesgo de pérdida de detalles clave: Si el resumen no incluye ciertos
artificialmente. términos o conceptos importantes (aunque parezcan menores),
• Reduce el ruido semántico: eliminar tablas y detalles redundantes podría no ser recuperado en la búsqueda.
que no ayudan a la búsqueda. • Alta dependencia del resumen: La calidad del RAG dependerá
• Genera chunks con alto “embedding value”: textos condensados críticamente de cómo se generen esos resúmenes. Si no son
que son semánticamente ricos y representativos. buenos, no habrá forma de encontrar el contenido correcto.
• Mejora el recall semántico: cuando se busca, el resultado es más • Falta de granularidad: No permite hacer referencias internas
probable que sea el documento correcto. precisas (ej. "¿qué dice el campo ‘TipoProveedor’ en la tabla X?”) si
• Facilita la recuperación de documentos completos: dado un ese detalle no está en el resumen.
embedding resumido, puedes recuperar el texto completo original. • No apto para casos con múltiples temas por documento: Si un
documento contiene varios temas, un solo resumen podría ser
• Maneja menor número de entradas en FAISS o vectores, ya que se insuficiente para representar adecuadamente el contenido.
tiene 1 resumen por documento, no docenas de chunks. • Curva de ajuste inicial: Requiere definir prompts, pruebas y ajustes
• Disminuye el costo de almacenamiento y recuperación. hasta obtener resúmenes consistentes y de buena calidad.
• Pero no es una idea nueva, ya hay trabajos sobre esta tecnología :
1. Semantic Compression for Retrieval-Augmented Generation: [Link]
2. Rewriter‑based RAG / Compression‑based Indexing: [Link]
3. Dense Passage Summary (DPS): [Link]
4. Hybrid Representations (Dual Memory): [Link]
[Link]/llm-chunking-stratagies/
5. Agentic Chunking:
[Link]
Estrategias de Recuperación
• Proceso genérico
– Obtener la pregunta del usuario
– Vectorizar la pregunta del usuario
– Búsqueda semántica de la pregunta del usuario: k-top vecinos más cercanos
– Obtener los textos asociados a los resultados de la búsqueda semántica
– El texto se convierte en el “Contexto” para el LLM
• Alternativas de implementación
– Obtener la pregunta del usuario
• Opción 1: Utilizar la pregunta exacta que hace el usuario
• Opción 2: Compresión semántica, pedirle al LLM que nos optimice la pregunta para la búsqueda semántica
– Vectorizar la pregunta del usuario (mismo modelo utilizado en la base de datos vectorial)
• Vectorización local
• Vectorización OpenAI
– Búsqueda semántica de la pregunta del usuario: k-top vecinos más cercanos
• Depende de la base de datos vectorial utilizada
– Obtener los textos asociados a los resultados de la búsqueda semántica
• Textos de los chunks obtenidos
• Texto completo del tema relacionado
– El texto se convierte en el “Contexto” para el LLM
Pruebas
Implementaciones realizadas
(150 combinaciones)
Tipo Implementación Nomencaltura Modelo Relacionado
- FF: Fragmentación de tamaño fijo (muy simple)
Tipo de Fragmentación - FR: Fragmentación Recursiva
- FCS: Fragmentación por Compresión Semántica
sentence_Transformers:
- VL: Vectorización Local - jinaai/jina-embeddings-v2-base-es (español)
- intfloat/multilingual-e5-base
Modelo de Embedding - VO: Vectorización en OpenAI sentence_Transformers:
- text-embedding-3-small
- Sólo Oracle tiene forma de configurar un embedding: cargar
- VB: Vectorización por Base de Datos (N/A) modelos ONNX pero muy básicos, no pude cargan ninguno de los 2
locales; o definir un servicio REST (no le veo valor agregado)
- BL: Base de datos local - BD Vectorial: FAISS
- BD Textos: SQLite
- BQ: Qdrant - Base de datos vectorial que maneja textos como BD NoSQL
Tipo Base de datos
-BS: Microsoft SQL Server 2025
-BP: Postgresql pgvector Bases de datos relacionales que manejan vectores
-BO: Oracle Autonomous en OCI
- RCH: Recuperar sólo texto de chunks seleccionados
Estrategia Recuperación - RTC: Recuperar el texto completo del tema
- RCS: Compresión Semántica de la pregunta + RTC
[Link]:
- LL: Modelo de Lenguaje Local - Meta-Llama-3.1-8B-Instruct.Q5_K_M.gguf
- Mistral-7B-Instruct-v0.2-GGUF
Modelo de Lenguaje LLM - TinyLlama-1.1B-Chat-v1.0-GGUF
- LO: Modelos de Lenguaje en OpenAI OpenAI:
- gpt-4o-mini (mas barato)
Resultados de la Prueba
• Se realizaron 150 pruebas:
– LO - LLM OpenAI: 75 casos OK
– LL - LLM local Llama-mini: 7 OK, 68 con error, y duraron de 23 a 34 segundos (uno duró 103 segundos)
Tiempos de Vectorización (solo 75 casos de LO)
Método Casos Tiempos Comentarios
VL (Vectorización Local) 30 42-53 ms (67 ms) VL la más rápida
VO (OpenAI) 20 316-1264 ms VO sólo si mejora la calidad
RCS (Compresión Semántica) 25 2076-5280 ms RCS sólo si mejora la calidad
Tiempos de Búsqueda Semántica (solo 52 casos de VL)
Tipo Casos Tiempos Comentarios
BL+BQ (FAISS, Qdrant) 16 47-81 ms Qdrant comparable a FAISS+SQLite
SQL server sin índices con buen
BS+BL (SQL Server 2025, FAISS) 16 90-146 ms rendimiento. FAISS no estable
BP (pgvector) 10 133-551 ms pgvector estable, pero más lento
BO (Oracle 23c) 10 1176-3772 ms Oracle muy lento, sin índice
Tiempos de Generación LLM (82 casos sin error)
Método Casos Tiempos Comentarios
OpenAI no es tan lento y no
LO (OpenAI) 75 4-15segs (27s) genera mucho costo $1/1M
LL (Llama-mini) 7 23-34 segs (103s) LLM local dio muchos
problemas y requiere muchos
recursos. Contesta hasta en
LL (Llama-mini) con Error 68 N/A minutos, y respuestas muy
pobres
Resultados de la Prueba (2)
Distribución de la Calificación de las Respuestas
Calificación LLM Vectorización Fragmentación Recuperación Casos
8 LO VO FCS RCH 5
8 LO VO FCS RCS 5
8 LO VO FCS RTC 5
8 LO VO FR RCH 5
8 LO VO FR RTC 5
6 LO VL FF RCS 1
5 LO VL N/A N/A 44
4 LL VL N/A N/A 4
1 LL VL N/A N/A 3
(*) La vectorización por OpenAI obtuvo los únicos buenos resultados
(*) La vectorización Local sólo dio un resultado regular
Conclusiones
• Se recomienda el Modelo de Lenguaje OpenAI (LO)
– El LLM local da muchos problemas y requiere muchísimos recursos y dura hasta minutos en contestar
– El de OpenAI no es tan lento (entre 4 y 15 segundos) y no genera mucho costo.
• Se recomienda el Modelo de vectorización de OpenAI (VO)
– El modelo de vectorización local (VL) es el más rápido pero no dio ningún buen resultado
– El modelo de vectorización en OpenAI (VO) dio todos los buenos resultados aunque dure más.
• Se recomienda la Estrategia de Fragmentación Recursiva (FR):
– La fragmentación fija (FF) es muy simple y no generó ningún buen resultado
– Las estrategias recursivas (FR) y por Compresión Semántica (FCS) ambos dieron buenos resultados, pero el FCS dura más
preparando datos, no vale la pena
• Se recomienda la Base de datos vectorial Qdrant (BQ):
– Tanto la base de datos local (BL=FAISS+SQLite) como Qdrant (BQ) dieron los mejores tiempos de búsqueda.
– FAISS tiene la desventaja que no crece horizontalmente, tiene como límite la RAM y se debe administrar la RAM con cuidado. No
almacena texto, requiere SQLite
– Qdrant es simple, crece horizontalmente y es un servidor independiente. Además, puede almacenar texto en una misma
estructura.
– Qdrant tenía la desventaja de no aprovechar GPU (FAISS si aprovecha GPU), pero ya se lo incluyeron en las últimas versiones
– Las bases de datos relacionales están incursionando en los VECTORES, pero van a tener problemas con grandes volúmenes de
vectores.
– OJO: Oracle es bastante lerdo y no se aprovechó el índice (una de las tablas tenía índice vectorial y no hubo diferencia)
• Se recomienda la Estrategia de Recuperación de Texto Completo del Tema (RTC):
– La Compresión Semántica de la Pregunta RCS no logró mejorar la calidad de las respuestas y duró mucho más
– La recuperación de los textos de chunks (RCH) y del texto completo del tema (RTC) no dieron resultados diferentes
– Se prefiere RTC para no perder chunks de información
Implementación
Preparación de Datos
• Instalar Qdrant o Docker con Imagen de Qdrant (docker run qdrant/qdrant)
• Preparación de datos en python:
# Biblitocas
from qdrant_client import QdrantClient
from qdrant_client.[Link] import VectorParams, Distance, PointStruct
# Conectarse a la base de datos Qdrant
LvarQdrantClient = QdrantClient("[Link] port=6333)
# Crear o recrear colección destino en Qdrant
def sbRecrearTablaDestino(pTablaDestino, pVectorDim):
if LvarQdrantClient.collection_exists(pTablaDestino):
return
LvarQdrantClient.create_collection(collection_name=pTablaDestino, vectors_config=VectorParams(
size=pVectorDim, distance=[Link]))
# Insertar un vector en Qdrant (uno por chunk)
def Inserta_Vector(pTablaDestino, pId, pTema, pChunkId, pTextoChunk, pVectorChunk, pTextoCompleto=None):
LvarVector_np = [Link](pVectorChunk, dtype=np.float32) # Convertir a float32 y asegurar [Link]
LvarPoint = PointStruct (
id = pId, vector = LvarVector_np,
payload = {"tema":pTema,"chunk_id":pChunkId, "texto":pTextoChunk, "texto_completo":pTextoCompleto}
)
# Inserta un solo vector:
[Link](collection_name=LvarTablaDestino, points=[LvarPoint], wait=True)
# O bien, guarda en memoria los vectores y luego los inserta en bloque
[Link] (LvarPoint)
...
[Link](collection_name=LvarTablaDestino, points=LvarQdrantPoints, wait=True)
LvarQdrantPoints=[]
Generar respuesta Aumentada
• Incluir en un fastAPI
import tiktoken #FR: Tokenizer para VO
from langchain_openai import OpenAIEmbeddings #VO: Vectorización OpenAI con text-embedding-3-small
from qdrant_client import QdrantClient #BQ: Base de datos vectorial Qdrant
from openai import OpenAI #LO: Modelo LLM en
OpenAI
# Abrir cliente Qdrant
LvarQdrantClient=QdrantClient("[Link] port=6333)
# Abrir modelo de vectorización (embedding)
LvarOpenAIKey = “……..llave de acceso a OpenAI……."
LvarEmbeddingModel = "text-embedding-3-small"
LvarEmbedder = OpenAIEmbeddings(model=LvarEmbeddingModel, api_key=LvarOpenAIKey)
LvarTokenizer = tiktoken.encoding_for_model(LvarEmbeddingModel), # Tokenizer para contar tokens con OpenAIEmbeddings
LvarVector = LvarEmbedder.embed_query("Esto es un ejemplo") # Vectorizar para Obtener la dimensión del modelo
LvarDim = len(LvarVector) # Obtener la dimensión del modelo
# Abrir modelo de Lenguaje (LLM)
LvarOpenAIModel = "gpt-4o-mini"
LvarOpenAIClient = OpenAI(api_key=LvarOpenAIKey)
LvarUserPrompt = " Pregunta que se quiera hacer sobre el ERP de SOIN“
# Busqueda semántica para obtener el contexto
LvarContext = fnGetContext(LvarUserPrompt, 10)
# Invocar el LLM para obtener la respuesta aumentada
LvarResponse = fnInvokeLLM(LvarUserPrompt, LvarContext)
# Realiza la búsqueda semántica en la base de datos Qdrant y obtiene los textos correspondientes
def fnGetContext(pTabla, pPrompt, pTop_k: int = 25):
LvarTabla = f"ayuda_chunks_{LvarTipo_F_V}"
LvarVector = LvarEmbedder.embed_query(pPrompt) # Vectorizar el prompt a buscar
LvarVector = [Link](LvarVector, dtype="float32") # Estandardizar vector a numpy tipo float32
#Busqueda semántica
LvarResultados = LvarQdrantClient.query_points(collection_name=pTabla, query=LvarVector, limit=pTop_k).points
# Obtiene los textos completos del tema (no repite tema): [TEMA: Nombre_tema] Texto_completo_tema
LvarTexts = []
LvarTemas = []
for LvarResultado in LvarResultados:
LvarTema = [Link]("tema", "")
if LvarTema in LvarTemas:
continue
[Link](LvarTema)
LvarTextoCompleto = [Link]("texto_completo", "")
[Link](f'[TEMA: {LvarTema}] {LvarTextoCompleto}')
# Arma instrucciones + contexto + pregunta lo envía al LLM y devuelve la respuesta generada
def fnInvokeLLM(pUserPrompt: str, pContext: str):
if not [Link]():
return "Lo siento, no se encontró información relevante en la base de conocimiento. Pero te puedo ayudar con cualquier otra duda sobre el EPR de SOIN."
LvarSysPrompt = "Eres un asistente digital especializado en temas del sistema ERP de SOIN. Responde con claridad y precisión como un
profesional técnico en administración de empresas o contador. "
LvarUserPrompt = f"\n---\n[Contexto relevante]\n{pContext}\n---\n[Pregunta del usuario]\n{pUserPrompt}\n"
LvarResponse = [Link](
model = LvarOpenAIModel,
messages =[
{"role": "system", "content": LvarSysPrompt},
{"role": "user", "content": LvarUserPrompt},
],
temperature = 0.7,
max_tokens = 5000
)
return [Link][0].[Link]