Garantizar implementaciones de RAG seguras y conscientes de los permisos
En el área acelerada de la inteligencia artificial, la generación aumentada por recuperación (RAG) ha surgido como un enfoque poderoso para mejorar las capacidades de los modelos generativos, como la serie GPT de OpenAI y Gemini de Google. Sin embargo, un gran potencial conlleva una responsabilidad significativa, especialmente cuando se trata de proteger datos sensibles y garantizar el cumplimiento de las regulaciones de privacidad.
A medida que las organizaciones dependen cada vez más de soluciones impulsadas por IA, comprender las implicaciones de seguridad de estas tecnologías es crucial. Implementar medidas de seguridad sólidas que no solo protejan los datos, sino que también generen confianza en los usuarios, es esencial para las aplicaciones RAG listas para producción.
En un reciente Unstructured Data Meetup organizado por Zilliz, Oz Wasserman, cofundador de Opsin, destacó consideraciones clave de seguridad para implementaciones RAG, enfatizando la importancia de la anonimización de datos, el cifrado sólido, la validación de entrada/salida y controles de acceso robustos, entre otras medidas de seguridad críticas.
En este blog, analizaremos los aspectos clave de las implementaciones RAG seguras y conscientes de los permisos. También recorreremos un notebook de ejemplo de un pipeline RAG usando la base de datos vectorial Milvus y postprocesadores de LlamaIndex diseñados para eliminar información sensible, garantizando la privacidad de los datos y el cumplimiento normativo.
Diagrama de arquitectura RAG
En su charla, Oz comenzó explicando una arquitectura RAG fundamental similar a la que se muestra en la Figura 1. Esencialmente, un sistema RAG mejora un modelo de lenguaje grande (LLM) al integrar una base de conocimiento impulsada por una base de datos vectorial que almacena documentos para recuperar contenido relevante en respuesta a la consulta de un usuario. Este enfoque mejora la precisión, garantiza una mayor relevancia contextual y minimiza las alucinaciones que a menudo se observan en las salidas de LLM independientes.
Sin embargo, este pipeline básico carece de medidas de seguridad específicas a menos que se integren en las distintas etapas. Oz destacó un diagrama de flujo de trabajo RAG (ver Figura 2) de Ken Huang de DistributedApps.ai, donde los controles de seguridad pueden implementarse a lo largo de todo el pipeline RAG:
Etapa de fuente de datos/VectorDB
Etapa de recuperación
Etapa de generación
Figura- Base de datos vectorial que facilita un chatbot RAG.png
Figura 1: Arquitectura RAG básica
Figura 2- Arquitectura RAG detallada (Autor- Ken Huang)
Figura 2: Arquitectura RAG detallada (Autor: Ken Huang)
Etapa de fuente de datos/VectorDB
Las bases de datos vectoriales, como Milvus y Zilliz Cloud (el Milvus gestionado), almacenan, indexan y recuperan embeddings vectoriales convertidos a partir de datos no estructurados. Son repositorios críticos de información valiosa. Sin embargo, también pueden convertirse en objetivos de filtraciones de datos o acceso no autorizado, lo que hace necesaria la implementación de estrategias de protección robustas como cifrado, control de acceso o anonimización de datos.
Figura 3- Fuente de datos: Controles de seguridad de VectorDB.png
Figura 3: Controles de seguridad de la fuente de datos/VectorDB
El primer hilo de seguridad se puede encontrar en la anonimización de datos. Los datos contienen información personal sensible, comúnmente denominada Información de Identificación Personal (PII). Estos datos deben anonimizarse para proteger la privacidad individual. Este paso es obligatorio antes de cualquier procesamiento de datos para garantizar que esta información no pueda rastrearse hasta individuos específicos.
Una vez que los datos se han anonimizado, pueden indexarse y se pueden generar embeddings para habilitar la búsqueda semántica para recuperar contenido relevante. En esta etapa, es importante definir quién puede almacenar y recuperar los datos en y desde la base de datos vectorial, en otras palabras, quién tiene acceso a ellos. Implementar controles de acceso estrictos es esencial para prevenir el acceso no autorizado, que podría resultar en manipulación o filtración de datos.
El control de acceso puede desglosarse en varias etapas:
Autenticación: Garantizar que el usuario verifique su identidad, normalmente mediante métodos como OAuth 2.0.
Autorización: Según la identidad verificada, se otorgan al usuario permisos específicos y derechos de acceso.
Trazabilidad: Supervisar el acceso para garantizar que cualquier intento de acceder a los datos se registre y pueda rastrearse, proporcionando una pista de auditoría para el cumplimiento de seguridad.
Estas medidas ayudan a proteger la base de datos vectorial y garantizan que solo los usuarios autorizados puedan interactuar con datos sensibles.
Se puede añadir otra capa de seguridad con cifrado para hacer que los datos sean ininteligibles en reposo (cuando se almacenan) o en tránsito (cuando se transmiten). El cifrado tradicional utiliza claves de cifrado, pero también se están adoptando cada vez más técnicas más avanzadas como la Privacidad Diferencial o la Descentralización y Sharding para mejorar la seguridad de los datos.
Zilliz Cloud es un servicio de base de datos vectorial totalmente administrado impulsado por Milvus. Ofrece todas estas medidas esenciales de seguridad de datos. Puede proporcionar otras soluciones, como Private Link, para evitar el acceso a internet público, copias de seguridad y restauración para garantizar respaldos de datos regulares y seguros, y recuperación de la base de conocimientos en caso de pérdida de datos.
Figura 6- Seguridad de nivel empresarial multicapa de Zilliz
Figura 6: Seguridad de nivel empresarial multicapa de Zilliz (Fuente)
Etapa de recuperación
La etapa de recuperación es otro paso crítico en el que deben abordarse las preocupaciones de seguridad. Al igual que en la etapa anterior, controlar el acceso a la base de conocimientos mediante consultas es esencial. Además, durante esta etapa, también deben mitigarse varios riesgos de seguridad:
Validación de consultas: Validar las consultas es crucial para prevenir ataques de inyección de prompts. Este enfoque garantiza que las entradas de los usuarios no exploten vulnerabilidades del sistema, lo que podría conducir a acceso no autorizado o manipulación de los datos.
Riesgos de la búsqueda por similitud: También es importante gestionar los riesgos asociados con las búsquedas por similitud. Deben establecerse medidas adecuadas para garantizar que la búsqueda por similitud no exponga inadvertidamente información sensible ni proporcione acceso no autorizado a datos restringidos.
Figura 7- Paso de validación de consultas
Figura 7: Paso de validación de consultas
Oz compartió un ejemplo (ver Figura 8) de inyección de prompts mientras presentaba un modelo interno. Este es un buen ejemplo de manipulación de prompts, donde el prompt se cambia para recuperar datos.
Figura 8- Ejemplo de inyección de prompts
Figura 8: Ejemplo de inyección de prompts
Además, Oz analizó varios riesgos asociados con la búsqueda por similitud, entre ellos:
Filtración de datos: Al manipular las consultas de similitud, los atacantes pueden influir en el mecanismo de búsqueda para recuperar datos confidenciales indirectamente.
Manipulación de resultados de búsqueda: Los atacantes podrían modificar el proceso de búsqueda para influir en qué resultados se recuperan, lo que podría llevar a la exposición de información restringida.
Reconocimiento y análisis de patrones: Los atacantes pueden analizar patrones en las consultas de búsqueda y las respuestas para mapear la estructura de la base de datos y obtener información sobre los datos almacenados.
Agotamiento de recursos: Las consultas continuas o excesivas podrían provocar condiciones de denegación de servicio, agotando los recursos del sistema y reduciendo la disponibilidad para otros usuarios.
Vemos que deben implementarse técnicas de seguridad similares para la etapa de recuperación, como el control de acceso o la validación de datos. Además, debe considerarse el cifrado (en tránsito) a medida que los datos se transmiten entre componentes.
Etapa de generación
La etapa final en el pipeline RAG es la etapa de generación, donde el modelo de lenguaje grande (LLM) genera respuestas basadas en el contenido recuperado de la base de datos vectorial. Aunque el LLM es el actor central en esta etapa, pueden surgir problemas de seguridad y cumplimiento normativo dependiendo de la naturaleza de los datos utilizados para entrenar el modelo. Algunos riesgos clave incluyen:
Violaciones de privacidad de datos: El LLM puede revelar inadvertidamente información sensible o privada si se entrenó con datos que incluyen información de identificación personal (PII) u otro contenido confidencial. Esto podría resultar en infracciones de regulaciones de privacidad como GDPR o HIPAA.
Manipulación de la salida: Los atacantes podrían manipular la salida del LLM influyendo en las consultas de entrada, lo que llevaría a la generación de contenido malicioso o engañoso. Esto es particularmente preocupante en entornos donde las salidas se consideran fiables sin verificación.
Sesgo y contenido ofensivo: Si los datos de entrenamiento contienen elementos sesgados u ofensivos, el LLM podría producir respuestas sesgadas u ofensivas, lo que podría llevar a responsabilidades legales, especialmente en entornos de producción.
Abordar estos riesgos requiere un cuidadoso posprocesamiento del contenido generado, incluidas técnicas como:
Filtrado de contenido: Filtrar automáticamente las salidas para detectar y bloquear contenido sensible, sesgado u ofensivo.
Validación de salida: Validar la respuesta del modelo para garantizar que cumpla con las políticas de seguridad y los estándares regulatorios antes de entregarla al usuario.
Ajuste fino del modelo: Asegurar que el modelo se ajuste finamente con datos que cumplan con la normativa y aplicar estrategias de aprendizaje por refuerzo para evitar salidas dañinas.
Al incorporar estas estrategias, la etapa de generación puede hacerse más segura y fiable, y añade una capa de seguridad.
Ahora profundicemos en un ejemplo de anonimización de datos, donde se compararán diferentes posprocesadores de LlamaIndex y se mostrará un ejemplo de violaciones de privacidad de datos.
RAG seguro usando LlamaIndex y Milvus
El siguiente notebook es un ejemplo de un pipeline RAG creado con LlamaIndex como framework LLM, Milvus como base de datos vectorial, y tres módulos diferentes especializados en enmascaramiento de PII: uno que usa un modelo NER de Hugging Face, otro que usa un LLM (OpenAI) y Presidio, una biblioteca de Microsoft.
También puedes consultar el código completo en este notebook de colab.
Paso 1: Configurar variables de entorno
Necesitamos una clave de OpenAI para probar el módulo usando modelos de OpenAI.
from google.colab import userdata
import os
os.environ["OPENAI_API_KEY"] = userdata.get('OPENAI_API_KEY')
Paso 2: Definir texto con datos privados
Primero, definimos un texto breve que contiene información privada como números de tarjetas de crédito, nombres o fechas de nacimiento.
from llama_index.core.postprocessor import NERPIINodePostprocessor
from llama_index.core.schema import TextNode, NodeWithScore
text = """
Hi, I'm Sarah Mitchell, and I just got a new credit card with the number 3714-496089-47322.
My personal email is sarah.mitchell@mailbox.com, and I'm currently based in Sydney.
By the way, I tried paying my utility bill with card number 6011-5832-9109-1726, but it didn't work.
For my bank transactions, I use this IBAN: NL91ABNA0417164300.
Also, can you help me with my Wi-Fi issues? I keep getting blocked by IP address 203.0.113.15.
I've shared a family photo on my personal blog at https://www.sarahs-lifediary.org/.
Oh, and my grandfather, George Stone, was born in 1921, while my grandmother, Emily Clarkson, was born in 1925.
Last question--what's the spending limit on my main card, the one ending in 8473?
"""
node = TextNode(text=text)
Paso 3: Modelo NER para enmascaramiento de PII: NERPIINodePostprocessor
NERPIINodePostprocessor es un módulo de Llama Index que enmascara esa información usando un modelo de Hugging Face especializado en NER (reconocimiento de entidades con nombre).
from llama_index.core.postprocessor import NERPIINodePostprocessor
from llama_index.core.schema import TextNode, NodeWithScore
processor = NERPIINodePostprocessor()
new_nodes = processor.postprocess_nodes([NodeWithScore(node=node)])
print(new_nodes[0].node.get_text())
Vemos que este modelo específico enmascara cierta información, pero los datos privados siguen siendo visibles. Usar este enfoque representaría una fuga de datos. Por lo tanto, se deberá usar otro modelo o enfoque.
"""
Output:
Hi, I'm [PER_9], and I just got a new credit card with the number 3714-496089-47322.
My personal email is sarah.mitchell@mailbox.com, and I'm currently based in [LOC_169].
By the way, I tried paying my utility bill with card number 6011-5832-9109-1726, but it didn't work.
For my bank transactions, I use this IBAN: NL91ABNA0417164300.
Also, can you help me with my Wi-[MISC_374] issues? I keep getting blocked by IP address 203.0.113.15.
I've shared a family photo on my personal blog at https://www.sarahs-lifediary.org/.
Oh, and my grandfather, [PER_545], was born in 1921, while my grandmother, [PER_599], was born in 1925.
Last question--what's the spending limit on my main card, the one ending in 8473?
"""
Paso 4: LLM para enmascaramiento de PII: PIINodePostprocessor
PIINodePostprocessor es un módulo de Llama Index que usa un modelo LLM para enmascarar información sensible. Para probar la eficiencia de este enfoque, usaremos el modelo predeterminado de OpenAI.
from llama_index.core.postprocessor import PIINodePostprocessor
from llama_index.core.schema import TextNode, NodeWithScore
from llama_index.llms.openai import OpenAI
processor = PIINodePostprocessor(llm=OpenAI())
new_nodes = processor.postprocess_nodes([NodeWithScore(node=node)])
print(new_nodes[0].node.get_text())
Siguiendo este enfoque, el modelo puede reconocer toda la información sensible y enmascararla en consecuencia.
"""
Output:
Hola, soy [NAME1] [NAME2], y acabo de recibir una nueva tarjeta de crédito con el número [CREDIT_CARD_NUMBER1].
Mi correo electrónico personal es [EMAIL], y actualmente estoy ubicado en [CITY].
Por cierto, intenté pagar mi factura de servicios públicos con el número de tarjeta [CREDIT_CARD_NUMBER2], pero no funcionó.
Para mis transacciones bancarias, uso este IBAN: [IBAN].
Además, ¿puedes ayudarme con mis problemas de Wi-Fi? Me sigue bloqueando la dirección IP [IP_ADDRESS].
He compartido una foto familiar en mi blog personal en [URL].
Ah, y mi abuelo, [NAME3] [NAME4], nació en [DATE1], mientras que mi abuela, [NAME5] [NAME6], nació en [DATE2].
Última pregunta--cuál es el límite de gasto de mi tarjeta principal, la que termina en [CREDIT_CARD_ENDING].
"""
Paso 5: Presidio para el enmascaramiento de PII
Finalmente, probamos Presidio, una biblioteca de Microsoft que enmascara información sensible usando un modelo de Spacy especializado en NER.
from llama_index.postprocessor.presidio import PresidioPIINodePostprocessor
from llama_index.core.schema import TextNode, NodeWithScore
from llama_index.llms.openai import OpenAI
processor = PresidioPIINodePostprocessor()
new_nodes = processor.postprocess_nodes([NodeWithScore(node=node)])
print(new_nodes[0].node.get_text())
Esta vez, vemos que el modelo puede enmascarar toda la información excepto el número de tarjeta de crédito, ya que se considera parte de él como una licencia de conducir. En el siguiente paso, probaremos varias consultas con este modelo y mostraremos cómo son posibles las violaciones de privacidad de datos porque parte del número de la tarjeta de crédito está disponible.
"""
Output:
Hi, I'm <PERSON_3>, and I just got a new credit card with the number 3714-<US_DRIVER_LICENSE_1>-47322.
My personal email is <EMAIL_ADDRESS_1>, and I'm currently based in <LOCATION_1>.
By the way, I tried paying my utility bill with card number <IN_PAN_1>9109-1726, but it didn't work.
For my bank transactions, I use this IBAN: <IBAN_CODE_1>.
Also, can you help me with my Wi-Fi issues? I keep getting blocked by IP address <IP_ADDRESS_1>.
I've shared a family photo on my personal blog at <URL_1>
Oh, and my grandfather, <PERSON_2>, was born in <DATE_TIME_2>, while my grandmother, <PERSON_1>, was born in <DATE_TIME_1>.
Last question--what's the spending limit on my main card, the one ending in 8473?
"""
Paso 6: Recuperación usando Milvus
Primero, creemos una base de datos vectorial Milvus para almacenar nuestro texto.
from llama_index.core import VectorStoreIndex, StorageContext
from llama_index.vector_stores.milvus import MilvusVectorStore
vector_store = MilvusVectorStore(
uri="./milvus_demo.db", dim=1536, overwrite=True
)
storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex([n.node for n in new_nodes], storage_context=storage_context)
A continuación, probemos algunas consultas.
Esta primera consulta funciona correctamente. Nos proporciona la respuesta correcta y mantiene la información enmascarada.
response = index.as_query_engine().query(
"What is the name of the person?"
)
print(str(response))
"""
Output:
The name of the person is <PERSON_3>.
"""
Ahora intentamos obtener el número de la tarjeta de crédito, y vemos que obtenemos el número completo con parte de él enmascarado como una licencia de conducir.
response = index.as_query_engine().query(
"What is the number of the credit card?"
)
print(str(response))
"""
Output:
The number of the credit card is 3714-<US_DRIVER_LICENSE_1>-47322.
"""
Pero también se sabe que todos los emisores de tarjetas de crédito tienen asignado un IIN (Issuer Identification Number). Los primeros dígitos definen el emisor. Así que, en este caso, 37 significa American Express. Si no lo sabes, podemos comprobarlo preguntándole al modelo.
response = index.as_query_engine().query(
"What is the issuer of the credit card number?"
)
print(str(response))
The issuer of the credit card number is American Express
Entonces, vemos que el modelo puede reconocer el emisor de la tarjeta, aunque esta información no se haya proporcionado en el texto. Esto significa que el modelo ha sido entrenado con información de tarjetas de crédito sobre emisores y puede proporcionar la respuesta con su conocimiento. Este es un ejemplo de violaciones de la privacidad de los datos en la etapa de generación, descrito anteriormente.
Conclusión
Oz nos guio a través de las diversas etapas de una canalización RAG y destacó dónde se pueden abordar las preocupaciones de seguridad. La primera preocupación clave implica la anonimización de datos, garantizando que los datos sensibles no puedan ser accedidos por terceros no autorizados. Sin embargo, es importante recordar que los modelos fundacionales LLM podrían haber sido entrenados con estos datos, lo que convierte a los propios modelos en posibles fuentes de filtración de datos.
Para proteger el acceso y la transmisión de datos, el control de acceso y el cifrado son fundamentales. Estas técnicas proporcionan un alto nivel de seguridad y control, pero amenazas como la inyección de prompts y la manipulación de búsqueda todavía representan riesgos para la información sensible.
Por lo tanto, añadir múltiples capas de seguridad a lo largo de la canalización es esencial para mitigar posibles amenazas. Una aplicación RAG lista para producción debe integrar medidas de seguridad robustas en cada etapa para garantizar que el sistema sea resiliente frente a ataques y cumpla con los estándares regulatorios.
Recursos adicionales
Sigue leyendo

How Zilliz Saw the Future of Vector Databases—and Built for Production
An inside look at how Zilliz built vector databases for real-world use, focusing on scalability, stability, and running them reliably at scale.

Announcing the General Availability of Single Sign-On (SSO) on Zilliz Cloud
SSO is GA on Zilliz Cloud, delivering the enterprise-grade identity management capabilities your teams need to deploy vectorDB with confidence.

OpenAI o1: What Developers Need to Know
In this article, we will talk about the o1 series from a developer's perspective, exploring how these models can be implemented for sophisticated use cases.



