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
PaquetePropósito
langchain-deepseekProporciona el modelo de embeddings de OpenAI
langchain-chromaIntegración de LangChain con la base de datos vectorial Chroma
chromadbBase de datos vectorial Chroma (ligera, adecuada para principiantes)

Inicialización del modelo Embedding

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)
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

import os
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_openai import OpenAIEmbeddings
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

# Búsqueda semántica: no depende de la coincidencia de palabras clave, sino de la similitud semántica
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

# Crear el retriever a partir de vector_store
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]}...")
Otras extensiones