LangChain RAG
RAG (Retrieval-Augmented Generation, generación aumentada por recuperación) permite que la IA responda preguntas basándose en tus documentos privados. No es necesario ajustar el modelo; basta con vectorizar y almacenar los documentos, y el agente podrá recuperar el contenido relevante para responder.
¿Qué es RAG?
Los grandes modelos de lenguaje comunes solo pueden responder contenido que está en sus datos de entrenamiento. Si tus documentos son privados (documentos internos de la empresa, notas personales), el modelo "no los conoce". RAG resuelve este problema:
- Fase offline: dividir los documentos en fragmentos pequeños → usar el modelo Embedding para convertirlos en vectores → almacenarlos en la base de datos vectorial
- Fase online: el usuario pregunta → convertir la pregunta en vector → buscar el contenido más similar en la base de datos vectorial → enviar el contenido recuperado al modelo como contexto → el modelo responde basándose en el contenido recuperado
Flujo de trabajo de RAG
┌──────────────────────────────────────────────────────┐ │ 离线阶段(索引) │ │ │ │ 文档 → DocumentLoader → TextSplitter → Embedding │ │ ↓ │ │ VectorStore │ └──────────────────────────────────────────────────────┘ ┌──────────────────────────────────────────────────────┐ │ 在线阶段(检索) │ │ │ │ 用户提问 → Embedding → 相似度搜索 → 检索结果 │ │ ↓ │ │ 检索结果 + 用户问题 → 模型 → 回答 │ └──────────────────────────────────────────────────────┘

Preparación del entorno
Instalar las dependencias relacionadas con RAG:
$ pip install langchain-deepseek langchain-chroma chromadb
| Paquete | Propósito |
|---|---|
| langchain-deepseek | Proporciona el modelo de embeddings de OpenAI |
| langchain-chroma | Integración de LangChain con la base de datos vectorial Chroma |
| chromadb | Base de datos vectorial Chroma (ligera, adecuada para principiantes) |
Inicialización del modelo Embedding
Ejemplo
load_dotenv()
from langchain_openai import OpenAIEmbeddings
# Modelo de embeddings de texto de OpenAI
# Convierte texto en vectores (un conjunto de números de punto flotante)
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
# Prueba: convierte un texto en vector
text = "Ejemplo es una plataforma de aprendizaje de programación"
vector = embeddings.embed_query(text)
print(f"Texto: {text}")
print(f"Dimensión del vector: {len(vector)}") # text-embedding-3-small tiene 1536 dimensiones
print(f"Primeros 5 valores del vector: {vector[:5]}")
Resultado de la ejecución:
Texto: Ejemplo 是一个编程学习平台 Dimensión del vector: 1536 Primeros 5 valores del vector: [0.0123, -0.0045, 0.0234, -0.0012, 0.0089]
Además, si no tienes la clave de OpenAI, puedes usar el servicio de embeddings de Alibaba Bailian,.envEl archivo de configuración debe incluir la clave de Alibaba Bailian:
DASHSCOPE_API_KEY="sk-xxx"
Código después de la configuración:
Ejemplo
from dotenv import load_dotenv
load_dotenv()
from langchain_openai import OpenAIEmbeddings
# Modelo de embeddings de texto de OpenAI
# Convierte texto en vectores (un conjunto de números de punto flotante)
# Usa el servicio de embeddings Qwen de Alibaba Cloud Bailian (DashScope)
# La interfaz de embeddings de Bailian es compatible con la especificación de la API de OpenAI, por lo que se usa directamente langchain-openai
# de OpenAIEmbeddings; solo hay que apuntar base_url al endpoint compatible de Bailian,
# No es necesario instalar langchain-community / dashscope (ese paquete ya no recibe mantenimiento).
# text-embedding-v4 es el modelo vectorial general recomendado actualmente; por defecto genera vectores de 1024 dimensiones.
#
# Dos parámetros clave son imprescindibles:
# - check_embedding_ctx_length=False: OpenAIEmbeddings por defecto usa tiktoken para
# codificar previamente el texto en una matriz de IDs de token antes de enviarlo (la API oficial de OpenAI reconoce este formato),
# pero la interfaz compatible de Bailian solo acepta cadenas de texto sin procesar; si no se desactiva esta opción, se producirá
# el error "contents is neither str nor list of str".
# - chunk_size=10: la interfaz de embeddings de Bailian acepta como máximo 10 textos por solicitud,
# OpenAIEmbeddings agrupa 1000 por defecto; si la base de conocimiento es un poco grande, superará el límite y dará error.
embeddings = OpenAIEmbeddings(
model="text-embedding-v4",
api_key=os.getenv("DASHSCOPE_API_KEY"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
check_embedding_ctx_length=False,
chunk_size=10,
)
# Prueba: convierte un texto en vector
text = "Ejemplo es una plataforma de aprendizaje de programación"
vector = embeddings.embed_query(text)
print(f"Texto: {text}")
print(f"Dimensión del vector: {len(vector)}") # text-embedding-3-small tiene 1536 dimensiones
print(f"Primeros 5 valores del vector: {vector[:5]}")
Crear el almacenamiento vectorial
Ejemplo
from langchain_chroma import Chroma
# Inicializar el modelo Embedding
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
# Crear el almacenamiento vectorial Chroma (los datos se guardan en el directorio local)
vector_store = Chroma(
collection_name="ejemplo_docs",
embedding_function=embeddings,
persist_directory="./chroma_db", # Directorio de persistencia
)
# Agregar documentos (la forma más simple: una lista de textos)
texts = [
"Ejemplo es un sitio web gratuito de aprendizaje de programación que ofrece tutoriales de HTML, CSS, JavaScript, Python, etc.",
"El tutorial básico de Python3 consta de 30 capítulos, es adecuado para principiantes sin conocimientos previos e incluye configuración del entorno, conceptos básicos de sintaxis, programación orientada a objetos, etc.",
"El tutorial básico de HTML consta de 25 capítulos y cubre conocimientos básicos como etiquetas HTML, formularios, multimedia, etc.",
]
# add_texts convierte automáticamente los textos en vectores y los almacena
vector_store.add_texts(texts)
print(f"Se agregaron {len(texts)} documentos al almacenamiento vectorial")
Búsqueda semántica
Ejemplo
results = vector_store.similarity_search(
"Quiero aprender Python, ¿qué tutorial recomiendas?",
k=2, # Devuelve los 2 resultados más similares
)
print("Resultados de la búsqueda:")
for i, doc in enumerate(results):
print(f"\nResultado {i+1}:")
print(f" Contenido: {doc.page_content}")
print(f" Metadatos: {doc.metadata}")
Resultado de la ejecución:
搜索结果:
Resultado 1:
Contenido: Python3 基础教程共 30 章,适合零基础入门...
Metadatos: {}
Resultado 2:
Contenido: Ejemplo是一个免费的编程学习网站...
Metadatos: {}
Observa que el primer resultado de búsqueda es más relevante que el segundo; aunque el primero contiene la palabra clave "Python", se ordena porsimilitud semánticaen lugar de por coincidencia de palabras clave. Esta es la ventaja de la búsqueda vectorial.
Crear el retriever (recuperador)
Retriever es la interfaz estandarizada de Vector Store:
Ejemplo
retriever = vector_store.as_retriever(
search_type="similarity", # Búsqueda por similitud
search_kwargs={"k": 3}, # Devuelve los primeros 3 resultados
)
# Usar el retriever
docs = retriever.invoke("Ruta de aprendizaje de Python")
for doc in docs:
print(f"- {doc.page_content[:60]}...")