Cómo construir una base de conocimientos RAG a partir de cualquier sitio web 2026
TL;DR
Una base de conocimientos RAG útil comienza con documentos fuente limpios y trazables—no con un modelo de incrustación. Preserve la URL canónica, el título, el tiempo de rastreo, los encabezados y el hash de contenido con cada fragmento.
El pipeline es rastreo → normalizar → desduplicar → fragmentar → incrustar → almacenar → recuperar → responder con citas. Evalúe cada límite de manera independiente para que los errores de recuperación no se confundan con errores de modelo.
Markdown es un formato de intercambio práctico para la ingestión de sitios web. Elimina gran parte del ruido de navegación mientras mantiene una estructura de encabezados que puede guiar la fragmentación semántica.
Use Nstproxy Crawl cuando necesite contenido de sitio web renderizado sin mantener navegadores y orquestación de proxy. El ejemplo a continuación utiliza su ruta de raspado actual, y luego demuestra una línea base de recuperación local sin dependencias.
Convierte Páginas Web en Datos Utilizables
Usa Nstproxy Crawl para convertir una URL en salidas limpias para AI, RAG y flujos de trabajo de datos.
Un sistema de generación aumentada por recuperación es tan confiable como la evidencia que puede recuperar. Si la ingesta de sitios web almacena banners de cookies, navegación repetida, copias obsoletas y fragmentos sin metadatos de origen, un modelo de lenguaje más potente no puede reparar la falta de procedencia.
Este tutorial construye una pequeña canalización inspeccionable y muestra dónde los sistemas de producción necesitan componentes más fuertes. Utiliza una línea base de vector hash local para que la lógica de recuperación pueda ejecutarse con la biblioteca estándar de Python. Reemplace esa línea base con un modelo de incrustación de producción y un índice vectorial después de que los contratos de datos estén funcionando.
¿Qué necesita una canalización Crawl-for-RAG?
Una canalización Crawl-for-RAG necesita seis propiedades: cobertura, contenido limpio, identidad estable, segmentación útil, vectores recuperables y respuestas basadas en fuentes. La velocidad importa, pero la completitud y la trazabilidad importan más.
El registro mínimo para cada página recuperada debe contener:
Campo
Por qué es importante
source_url
Permite que una respuesta cite evidencia
canonical_url
Previene duplicados de parámetros de URL
title y encabezados
Mejora la visualización y los límites semánticos
crawled_at
Soporta políticas de frescura
content_hash
Detecta contenido sin cambios o duplicado
markdown
Proporciona texto normalizado con estructura
http_status
Separa páginas no disponibles de extracciones vacías
contexto de localidad/acceso
Explica diferencias regionales o de idioma
Nstproxy Crawl puede convertir URLs en formatos como Markdown y JSON mientras maneja la infraestructura de renderizado. No reemplaza tu política de base de conocimiento: tu aplicación aún debe decidir qué caminos están permitidos, con qué frecuencia se actualizan y qué califica como un documento aceptado.
Antes de rastrear, inspecciona las reglas del sitio y tu autorización. El Protocolo de Exclusión de Robots define cómo los rastreadores descubren instrucciones en robots.txt, pero el cumplimiento de robots es solo una parte de la revisión legal y contractual. Consulta la guía legal de raspado web de Nstproxy para una lista de verificación más amplia.
Paso 1: Definir el Alcance y Rastrear el Sitio Web
Comienza con un mapa del sitio, una raíz de documentación conocida o una semilla de URL curada. Agrega reglas explícitas de permitir y denegar. Para un sitio de documentación, puedes permitir /docs/ y excluir inicio de sesión, búsqueda, paginación de registros de cambios, parámetros de consulta y binarios descargables.
La API en vivo de Nstproxy acepta actualmente solicitudes de raspado autenticadas en la ruta de abajo. La ruta fue verificada para llegar a la autenticación el 3 de septiembre de 2026; una respuesta exitosa no pudo ser probada sin una clave de cuenta. Confirma los campos de solicitud en la documentación actual de Crawl antes de su uso en producción.
Almacena la respuesta sin procesar antes de la normalización. La retención sin procesar hace que las actualizaciones del analizador sean reproducibles y te brinda evidencia cuando una regla de extracción cambia. Nunca registres claves de API, cookies o datos personales de páginas autenticadas.
Si estás decidiendo entre métodos de descubrimiento, lee raspado vs rastreo. Raspar una URL conocida es apropiado para actualizaciones dirigidas; el rastreo es apropiado cuando el descubrimiento de enlaces es parte del trabajo.
Paso 2: Normalizar y Deduplicar Antes de Incrustar
La normalización debe eliminar la navegación repetida, el texto del pie de página, los avisos de cookies, los controles invisibles y los encabezados vacíos sin aplanar la estructura de documento significativa. Markdown ayuda porque los encabezados, listas, código y enlaces sobreviven en una forma compacta. CommonMark proporciona una línea base útil para un análisis consistente de Markdown.
Usa dos identidades:
Identidad de URL: normaliza el caso de esquema/anfitrión, elimina parámetros de seguimiento, resuelve redirecciones y prefiere una URL canónica autoritativa.
Identidad de contenido: hash de texto del cuerpo normalizado para detectar duplicados espejados o parametrizados.
No descartes cada casi duplicado ciegamente. La documentación del producto puede repetir una advertencia compartida pero contener diferentes procedimientos. Los hash exactos son seguros para duplicación exacta; la similitud difusa debe producir candidatos revisables.
La frescura pertenece al mismo contrato. Almacene crawled_at, pistas de modificación de fuente cuando estén disponibles, y la versión del extractor. Al actualizar, vuelva a incrustar solo los fragmentos cambiados y elimine los vectores de páginas eliminadas.
Paso 3: Fragmentar Basado en el Significado, No en Conteos Arbitrarios de Caracteres
Un fragmento debe ser lo suficientemente grande como para responder una pregunta probable y lo suficientemente pequeño como para recuperar con precisión. Comience con segmentos conscientes de los encabezados, luego divida secciones largas por párrafos o oraciones. Adjunte encabezados de migas de pan a cada fragmento hijo.
Una política de inicio práctico es:
dividir en límites de H2/H3;
apuntar aproximadamente a 300–700 tokens por fragmento;
mantener bloques de código y tablas intactos siempre que sea posible;
agregar una pequeña superposición solo a través de prosa verdaderamente continua;
anteponer el título de la página y la ruta del encabezado al texto incrustado;
almacenar el texto de visualización sin modificaciones por separado.
No hay un tamaño de fragmento universalmente mejor. Evalúe con preguntas reales. Si las respuestas necesitan hechos dispersos a lo largo de un procedimiento largo, recupere fragmentos vecinos o use recuperación padre-hijo en lugar de hacer cada fragmento enorme.
Paso 4: Incrustar, Almacenar y Recuperar una Línea Base Local Ejecutable
El siguiente script implementa la mecánica local completa con solo la biblioteca estándar de Python. Utiliza un vector de bolsa de palabras hasheado determinístico—no una incrustación de producción semántica. Esa limitación es deliberada: puede ejecutar el flujo de datos localmente, inspeccionar registros de SQLite y más tarde reemplazar solo embed().
import hashlib
import json
import math
import re
import sqlite3
from datetime import datetime, timezone
DIMENSIONS =256defnormalize(text:str)->str: text = re.sub(r"\r\n?","\n", text) text = re.sub(r"[ \t]+"," ", text) text = re.sub(r"\n{3,}","\n\n", text)return text.strip()defchunk_markdown(markdown:str, max_words:int=90): chunks, heading,buffer=[],"",[]for line in normalize(markdown).splitlines():if line.startswith("#"):ifbuffer: chunks.append((heading,"\n".join(buffer)))buffer=[] heading = line.lstrip("# ")else:buffer.append(line)iflen(" ".join(buffer).split())>= max_words: chunks.append((heading,"\n".join(buffer)))buffer=[]ifbuffer: chunks.append((heading,"\n".join(buffer)))return[(h, t.strip())for h, t in chunks if t.strip()]defembed(text:str): vector =[0.0]* DIMENSIONS
for token in re.findall(r"[a-z0-9]+", text.lower()): slot =int(hashlib.sha256(token.encode()).hexdigest()[:8],16)% DIMENSIONS
vector[slot]+=1.0 length = math.sqrt(sum(x * x for x in vector))or1.0return[x / length for x in vector]defcosine(a, b):returnsum(x * y for x, y inzip(a, b))defingest(db, url, title, markdown): cleaned = normalize(markdown) page_hash = hashlib.sha256(cleaned.encode()).hexdigest() crawled_at = datetime.now(timezone.utc).isoformat() db.execute("DELETE FROM chunks WHERE source_url = ?",(url,))for index,(heading, text)inenumerate(chunk_markdown(cleaned)): embedding_text =f"{title}\n{heading}\n{text}" db.execute("INSERT INTO chunks VALUES (?, ?, ?, ?, ?, ?, ?)",(url, title, heading, index, text, json.dumps(embed(embedding_text)),f"{page_hash}:{crawled_at}"),) db.commit()defsearch(db, question, limit=3): query_vector = embed(question) rows = db.execute("SELECT source_url, title, heading, body, vector FROM chunks").fetchall() ranked =[(cosine(query_vector, json.loads(vector)), url, title, heading, body)for url, title, heading, body, vector in rows
]returnsorted(ranked, reverse=True)[:limit]db = sqlite3.connect(":memory:")db.execute("""CREATE TABLE chunks (
source_url TEXT, title TEXT, heading TEXT, chunk_index INTEGER,
body TEXT, vector TEXT, version TEXT
)""")sample ="""# Acme Docs
## Authentication
Send an API key in the Authorization header. Never expose the key in client code.
## Retries
Retry rate limits with exponential backoff and jitter. Do not retry invalid credentials.
"""ingest(db,"https://example.com/docs","Acme Docs", sample)for score, url, title, heading, body in search(db,"How should I handle rate limits?"):print(f"{score:.3f}\t{heading}\t{url}\t{body}")
El script se ejecutó localmente con Python 3 utilizando el documento ilustrativo incluido. Clasificó la sección “Retries” primero para la pregunta sobre límites de tasa. Esto confirma la conexión de almacenamiento y recuperación de fragmentos; no valida la calidad semántica en un corpus real.
Para producción, intercambie la función de vector local por una API de incrustación y reemplace el escaneo lineal con un índice vectorial. pgvector añade búsqueda de vectores exacta y aproximada a PostgreSQL; las bases de datos vectoriales gestionadas son otra opción. Preserve los mismos metadatos independientemente del motor de almacenamiento.
Paso 5: Generar Respuestas Solo a Partir de la Evidencia Recuperada
Pase los mejores fragmentos al modelo de respuestas con URLs de origen y una instrucción estricta: responda a partir del contexto suministrado, cite reclamaciones y diga cuándo la evidencia es insuficiente. No permita que el modelo sustituya en silencio el conocimiento general por el contenido faltante del sitio.
Una etapa de respuesta robusta debería:
aplicar un umbral de relevancia absoluto, no solo “los tres mejores”;
diversificar los resultados para que una página duplicada no ocupe cada espacio;
incluir fragmentos vecinos para los procedimientos;
filtrar por inquilino, localidad, versión del producto y control de acceso;
citar la URL de origen canónica junto a cada reclamación soportada;
registrar los IDs de los fragmentos recuperados para su evaluación posterior.
La reordenación puede mejorar la precisión después de la recuperación inicial de vectores. La recuperación híbrida—vectores semánticos más puntuación de palabras clave—es particularmente útil para códigos de error, nombres de productos y parámetros exactos de API.
La guía del servidor MCP de búsqueda web de Nstproxy ofrece contexto relacionado para conectar evidence web en vivo con agentes de IA. Una base de conocimientos fija y una búsqueda en vivo resuelven diferentes problemas: la primera es controlable y rápida, mientras que la segunda puede descubrir páginas más nuevas.
Paso 6: Evaluar el Pipeline de Extremo a Extremo
Construya un conjunto de preguntas a partir de tickets de soporte reales, encabezados de documentación y casos de fallos conocidos. Para cada pregunta, etiquete la página de origen esperada y si el corpus contiene una respuesta.
Mida al menos:
cobertura de rastreo: páginas esperadas aceptadas con éxito;
retraso de frescura: tiempo desde el cambio de origen hasta la actualización buscable;
recall de recuperación: evidencia esperada aparece en el conjunto candidato;
precisión de citación: las páginas citadas realmente respaldan la respuesta;
fidelidad de la respuesta: las reclamaciones están implicadas por el texto recuperado;
calidad de abstención: el sistema se niega cuando la evidencia está ausente.
Depure en ese orden. Si la página correcta nunca fue rastreada, sintonizar las incrustaciones es un esfuerzo desperdiciado. Si el fragmento correcto fue recuperado pero la respuesta lo ignoró, cambie el aviso o la etapa del modelo.
Errores Comunes en la Ingesta de RAG
El error más común es incrustar HTML en bruto. Llena el índice con menús, texto de script y contenido de plantilla repetido. Otros errores costosos incluyen fragmentar antes de la eliminación de duplicados, perder rutas de encabezados, omitir URLs canónicas, refrescar todo el corpus en lugar de las páginas cambiadas, y permitir que el contenido eliminado permanezca buscable.
La seguridad es igualmente importante. No rastree páginas privadas en un índice compartido a menos que la recuperación haga cumplir el modelo de autorización de origen. Trate el texto raspado como entrada no confiable: puede contener inyección de aviso destinada a agentes posteriores. Mantenga las instrucciones del sistema separadas y restrinja lo que las herramientas de tiempo de respuesta pueden hacer.
Antes del lanzamiento, confirme que cada fragmento tenga una fuente canónica, ruta de encabezado, marca de tiempo de rastreo, versión y hash de contenido. Verifique la propagación de eliminación, filtros de acceso, límites de reintento, observabilidad y una política de actualización documentada. Mantenga un pequeño conjunto de preguntas doradas en CI para que los cambios en el analizador o el modelo no puedan reducir silenciosamente la calidad de recuperación.
El rastreador es el primer componente, pero establece el techo para todo lo que viene después. Markdown limpio, versionado más puertas de calidad explícitas le da a las etapas de incrustación y respuesta evidencia que pueden utilizar realmente.