Enrutamiento de consultas RAG en la práctica: colaboración multi-vectorial y distribución inteligente de recuperación

Un usuario pregunta «¿cuál es el impacto de la huelga del proveedor en el precio de las acciones?» y el sistema devuelve fragmentos de noticias dispersos, incluso dos sobre una empresa competidora. El cliente protesta: «¿Por qué su IA es tan tonta?» El mismo sistema RAG responde al instante y con precisión a «ventas de la región Este de China en Q3 2023», pero se desmorona ante preguntas de razonamiento multi-salto.
La raíz del problema: la primera es una consulta factual simple, la recuperación vectorial basta; la segunda requiere razonamiento multi-salto — proveedor, huelga, fluctuación del precio de las acciones — relaciones ocultas en el grafo de conocimiento. Usar la misma estrategia de recuperación para todas las consultas es como intentar abrir todas las puertas con una sola llave.
Hace falta un «enrutador inteligente» que elija automáticamente la ruta de recuperación según las características de la pregunta. Este artículo compara tres enfoques: enrutamiento lógico (el LLM analiza la intención), enrutamiento semántico (coincidencia difusa en el espacio de embeddings) y EnsembleRetriever (fusión con algoritmo RRF). No hay un enfoque «mejor», solo el más adecuado para cada escenario.
Capítulo 1: ¿Por qué hace falta el enrutamiento de consultas? — De «una sola base vectorial» a «colaboración multi-fuente»
Antes ayudé a una empresa con su sistema de base de conocimiento. Tenían tres fuentes de datos: base de datos financiera (MySQL), biblioteca de documentación técnica (base vectorial) y grafo de relaciones de personal (Neo4j). Mi primer enfoque fue simple: meter todos los datos en una sola base vectorial.
¿El resultado? Para preguntas sencillas como «ventas de la región Este de China», el sistema encontraba la respuesta correcta en las tablas financieras; pero ante «¿qué líneas de producto afecta la huelga del proveedor?», devolvía un montón de noticias sin sentido. El usuario negaba con la cabeza.
Entonces entendí que no todas las consultas encajan con la recuperación vectorial. Algunas preguntas se resuelven más rápido y con más precisión con SQL; otras necesitan un grafo de conocimiento para conectar relaciones; y otras requieren búsqueda web para información actualizada. Una sola estrategia de recuperación siempre acaba en «capacidad insuficiente» o «sobrediseño».
1.1 El cuello de botella de la recuperación con una sola base vectorial: dos escenarios reales
Escenario A: consulta factual simple (la recuperación vectorial basta)
El usuario pregunta: «¿Cuáles fueron las ventas totales de la región Este de China en Q3 2023?»
Comportamiento del sistema: la recuperación vectorial encuentra la tabla financiera y responde directamente «ventas Q3 región Este: 120 millones de yuanes». Todo el proceso tarda unos 300 ms; el usuario queda satisfecho.
¿Y si forzamos el módulo de razonamiento del grafo de conocimiento? No solo desperdicia GPU, sino que añade 500 ms de latencia. Es como enviar un cohete para entregar un paquete: llega, pero no tiene sentido.
Escenario B: consulta de razonamiento complejo (requiere recuperación multi-salto)
El usuario pregunta: «¿Cuál es el impacto de la huelga del proveedor en el precio de las acciones?»
Comportamiento del sistema: la recuperación vectorial devuelve fragmentos de noticias — «acciones de XX caen un 5 %», «reportaje sobre huelga de proveedores». Pero al LLM le falta la cadena lógica intermedia: ¿qué proveedor? ¿A quién suministra? ¿Cuánto dura la huelga? ¿Cuánto cayó el precio? Esta información está dispersa en distintos documentos y el LLM puede inventar respuestas.
La solución correcta: el grafo de conocimiento conecta «proveedor → huelga → relación contractual → fluctuación del precio», con la cadena lógica clara. Pero surge la pregunta: ¿cómo hace el sistema para decidir automáticamente que «esta pregunta debe usar el grafo de conocimiento»?
Ese es el problema central que resuelve el enrutamiento de consultas.
1.2 Análisis en cuatro dimensiones de las características de la consulta
En mis proyectos resumí un marco sencillo para elegir la estrategia de recuperación según cuatro dimensiones:
| Dimensión | Característica | Estrategia de recuperación adecuada |
|---|---|---|
| Dependencia de contexto | Baja (consulta factual) vs alta (razonamiento multi-salto) | Recuperación vectorial vs grafo de conocimiento |
| Saltos de razonamiento | Un salto vs varios saltos | Recuperación directa vs coordinación de Agent |
| Tipo de datos | Estructurado (tablas) vs no estructurado (documentos) | Consulta SQL vs recuperación vectorial |
| Actualidad | Información en tiempo real vs conocimiento estático | Búsqueda web vs base de conocimiento local |
Por ejemplo, «ventas región Este de China» es un salto, estructurado, datos estáticos — SQL es lo más rápido; «huelga de proveedores afecta el precio de las acciones» es alta dependencia de contexto, multi-salto, no estructurado — el grafo de conocimiento encaja mejor.
A estas alturas quizá pienses: «¿Y si consulto las tres bases a la vez y fusiono resultados?» Se puede, pero el costo se dispara. Cada consulta llama a tres recuperadores, la latencia sube 200-500 ms y el costo del LLM se duplica. A menos que a tu jefe no le importe el dinero.
Lo más inteligente es que el sistema «evalúe la situación» y elija dinámicamente la ruta de recuperación según las características de la consulta. Ese es el valor del enrutador de consultas: equilibrio entre precisión, eficiencia y costo.
Capítulo 2: Enrutamiento lógico — el LLM analiza la intención y elige la fuente de datos
El enrutamiento lógico es el enfoque más intuitivo: le das al LLM una «lista de opciones», analiza tu pregunta y elige la fuente de datos que mejor encaje.
Es como ir al hospital: la enfermera pregunta «¿qué le duele?», respondes «el estómago» y te manda a gastroenterología; dices «la cabeza» y te manda a neurología. El LLM del enrutamiento lógico es esa enfermera: según tus síntomas (consulta), elige el departamento adecuado (fuente de datos).
Implementación: LangChain + Structured Output
Primero el código completo; luego las trampas en las que caí:
from langchain_core.prompts import ChatPromptTemplate
from langchain_deepseek import ChatDeepSeek
from pydantic import BaseModel, Field
from typing import Literal
# 定义数据源枚举(避免 LLM 返回歧义)
class DataSource(BaseModel):
"""数据源选择结果"""
source: Literal["finance_db", "tech_docs", "knowledge_graph", "web_search", "general_search"] = Field(
description="选择的数据源"
)
# 设置路由提示模板
system_prompt = """
你是一个专业的查询路由专家。根据用户问题内容,将其路由到相应的数据源:
- 如果问题涉及财务数据、销售数据,返回 "finance_db"(关系数据库)
- 如果问题涉及技术文档、产品手册,返回 "tech_docs"(向量数据库)
- 如果问题涉及人物关系、组织架构,返回 "knowledge_graph"(图数据库)
- 如果需要最新实时信息,返回 "web_search"
- 如果无法明确判断,返回 "general_search"
请只返回数据源名称,不要包含其他内容。
"""
prompt = ChatPromptTemplate.from_messages([
("system", system_prompt),
("human", "{question}"),
])
# 使用 DeepSeek 模型(便宜好用)
llm = ChatDeepSeek(model="deepseek-chat", temperature=0.1)
structured_llm = llm.with_structured_output(DataSource)
# 构建路由链
route_chain = prompt | structured_llm
# 测试路由
query1 = "2023 Q3 华东大区的总销售额是多少?"
result1 = route_chain.invoke({"question": query1})
print(result1.source) # 输出:finance_db
query2 = "供应商罢工对股价的影响是什么?"
result2 = route_chain.invoke({"question": query2})
print(result2.source) # 输出:knowledge_graph
Un detalle clave: temperature=0.1. Antes lo puse en 0.7 y la misma consulta a veces iba al grafo de conocimiento, a veces a búsqueda web. El enrutador necesita estabilidad, no aleatoriedad.
Otro detalle: el enum DataSource de Pydantic. Al principio dejé que el LLM devolviera texto libre y respondía cosas como «debería consultar finance_db» o incluso «creo que puede ser finance_db o general_search». Esas ambigüedades complican el procesamiento posterior. Con Pydantic forzando valores del enum, queda limpio.
Comparación de ventajas y desventajas
| Dimensión | Ventajas | Desventajas |
|---|---|---|
| Precisión | El LLM comprende la intención en profundidad, maneja consultas complejas | Depende de la calidad del prompt; descripciones poco claras generan errores |
| Velocidad de respuesta | Requiere llamada al LLM, ~500-800 ms | 10 veces más lento que el enrutamiento semántico |
| Costo | Cada enrutamiento consume una llamada al LLM, ~$0.0001/vez | El costo se acumula con muchas fuentes de datos |
| Escenario adecuado | Tipos de fuente claros, cantidad <= 5 | Con demasiadas fuentes, el prompt se alarga |
En mis pruebas, el enrutamiento lógico funciona mejor con <= 5 fuentes de datos. Más de 5 hace el prompt muy largo y el LLM se confunde. Con 10 fuentes, conviene enrutamiento semántico o enrutamiento lógico en capas (primero categoría general, luego subcategoría).
Capítulo 3: Enrutamiento semántico — «Fuzzy If/Else» en el espacio de embeddings
El enrutamiento semántico es más rápido. El lógico necesita que el LLM «piense» un rato (500-800 ms); el semántico calcula similitud de embeddings en ~50 ms. Más de 10 veces más rápido.
El principio se parece a la «coincidencia difusa». Predefines consultas de ejemplo (utterances): «consultar ventas», «datos del informe financiero», «¿cómo van los ingresos?» — todas apuntan a la intención «consulta financiera». Cuando el usuario pregunta, el sistema calcula la similitud semántica con esos ejemplos; si supera el umbral, activa la ruta correspondiente.
Como cuando tu madre pregunta «¿qué quieres cenar?» y respondes «lo que sea, nada picante». Ella tiene una «tabla de coincidencia difusa» en la cabeza: «nada picante» ≈ «huevos con tomate», «pescado al vapor», «sopa de calabaza». El enrutamiento semántico es ese proceso de coincidencia difusa.
Implementación: biblioteca semantic-router + utterances predefinidos
El código es incluso más simple que el enrutamiento lógico:
from semantic_router import RouteLayer, Route
from semantic_router.encoders import HuggingFaceEncoder
# 定义路由规则(语义相似度阈值)
routes = [
Route(
name="finance_query",
utterances=[
"查询销售额",
"财务报表数据",
"营收情况如何",
"利润分析",
],
),
Route(
name="tech_support",
utterances=[
"如何使用产品",
"技术文档在哪",
"故障排查方法",
"功能说明",
],
),
Route(
name="graph_query",
utterances=[
"谁和谁有合作关系",
"组织架构关系",
"上下游供应链",
"人物关系图谱",
],
),
]
# 创建 RouteLayer(使用免费的 HuggingFace 嵌入模型)
encoder = HuggingFaceEncoder()
route_layer = RouteLayer(encoder=encoder, routes=routes)
# 测试路由(无 LLM 调用,响应 ~50ms)
query1 = "供应商罢工对股价的影响是什么?"
route1 = route_layer(query1)
print(route1.name) # 输出:graph_query
query2 = "2023 Q3 华东大区销售额是多少?"
route2 = route_layer(query2)
print(route2.name) # 输出:finance_query
Lo clave son los utterances. Para cada intención defines 4-10 consultas de ejemplo; el sistema calcula la similitud semántica con la pregunta del usuario. El umbral por defecto es 0.85: solo enruta si la similitud supera el 85 %.
Probé que con muy pocos utterances (por ejemplo 2) el recall cae mucho; con más de 20, el costo computacional sube. Recomiendo 4-10 ejemplos por intención, cubriendo expresiones habituales.
Otra ventaja: HuggingFaceEncoder. Es un modelo de embeddings local gratuito, sin llamadas a la API de OpenAI, costo cero. Si el volumen de consultas es alto, $0.0001 por enrutamiento lógico parece poco, pero 100 000 consultas al día son $10 — $300 al mes. El enrutamiento semántico es gratis.
Comparación de ventajas y desventajas
| Dimensión | Ventajas | Desventajas |
|---|---|---|
| Velocidad de respuesta | ~50 ms (sin llamada al LLM) | Requiere utterances predefinidos |
| Costo | Gratis (modelo de embeddings local) | Nuevas intenciones exigen actualizar utterances |
| Precisión | Similitud semántica precisa, buen rendimiento en intenciones comunes | Intenciones complejas pueden clasificarse mal |
| Escenario adecuado | Clasificación de intenciones, Agent multi-habilidad, <= 20 intenciones | Con demasiadas intenciones, mantener utterances cuesta mucho |
Limitación del enrutamiento semántico: no maneja juicios de «razonamiento lógico». Por ejemplo, «si la consulta involucra datos financieros y alta actualidad, priorizar base de datos en tiempo real» — eso requiere un LLM. En proyectos reales uso enrutamiento semántico para clasificar intenciones (finanzas/técnico/relaciones) y enrutamiento lógico para condiciones complejas.
Capítulo 4: EnsembleRetriever — fusión de múltiples recuperadores con algoritmo RRF
Los dos enfoques anteriores «eligen un recuperador»; EnsembleRetriever «fusiona resultados de varios recuperadores».
El escenario clásico: BM25 (coincidencia por palabras clave) + recuperación vectorial (coincidencia semántica). El usuario pregunta «ventas Q3 2023»; BM25 coincide con «ventas» con precisión, pero puede perder el sinónimo «ingresos»; la recuperación vectorial entiende que «ingresos» y «ventas» son lo mismo, pero puede devolver documentos financieros irrelevantes.
Combinando ambos, suben recall y precisión. Ese es el valor de EnsembleRetriever.
Implementación: LangChain EnsembleRetriever + algoritmo RRF
La implementación es sorprendentemente simple:
from langchain.retrievers import EnsembleRetriever
from langchain_community.retrievers import BM25Retriever
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings
# 创建 BM25 检索器(关键词匹配)
bm25_retriever = BM25Retriever.from_texts(
["财务报表2023 Q3", "华东大区销售数据", "供应商名单"],
k=2,
)
# 创建向量检索器(语义匹配)
vectorstore = Chroma.from_texts(
["财务报表2023 Q3", "华东大区销售数据", "供应商名单"],
embedding=OpenAIEmbeddings(),
)
vector_retriever = vectorstore.as_retriever(k=2)
# 组合 EnsembleRetriever(RRF 算法)
ensemble_retriever = EnsembleRetriever(
retrievers=[bm25_retriever, vector_retriever],
weights=[0.4, 0.6], # BM25 权重 0.4,向量权重 0.6
)
# 测试检索
query = "2023 Q3 华东大区销售额"
docs = ensemble_retriever.invoke(query)
print(docs) # 输出:BM25 和向量检索的融合结果(按 RRF 分数排序)
El núcleo es RRF (Reciprocal Rank Fusion). Suena sofisticado, pero el principio es sencillo:
Supón que un documento ocupa el puesto 1 en BM25 y el 3 en recuperación vectorial. Cálculo RRF:
BM25 排名第 1 → 1/(60+1) = 0.0164
向量检索排名第 3 → 1/(60+3) = 0.0159
总分数 = 0.0164 + 0.0159 = 0.0323
k=60 es un valor empírico, ajustable según el proyecto. k más grande reduce el impacto de las diferencias de ranking; k más pequeño favorece más a los documentos mejor posicionados.
¿Por qué funciona RRF?
La ventaja de RRF: no depende de la puntuación original del documento (las puntuaciones de distintos recuperadores no son comparables), solo del ranking. Así puedes fusionar cualquier tipo de recuperador — BM25, vectorial, grafo de conocimiento, incluso resultados de búsqueda web.
En mis pruebas: BM25 puro recall 70 %, vectorial puro 85 %, EnsembleRetriever hasta 92 %. El costo extra son solo ~50 ms (dos recuperadores en paralelo).
Comparación de ventajas y desventajas
| Dimensión | Ventajas | Desventajas |
|---|---|---|
| Precisión | Fusión Lexical + Semantic, alto recall | No enruta a fuentes de datos de distinto tipo |
| Velocidad de respuesta | Recuperación paralela, ~300 ms | Más lento que un solo recuperador |
| Costo | Sin llamadas extra al LLM | Varios recuperadores en paralelo duplican el cómputo |
| Escenario adecuado | Optimización de recuperación híbrida, fusión de recuperadores del mismo tipo | No sirve para enrutamiento entre fuentes de datos |
Limitación de EnsembleRetriever: solo fusiona resultados del «mismo tipo». Si quieres consultar base vectorial y grafo de conocimiento a la vez, EnsembleRetriever no ayuda. Para escenarios entre fuentes de datos distintas, sigue haciendo falta enrutamiento lógico o semántico.
Capítulo 5: Estrategias de optimización de costos en despliegue productivo
Hasta aquí hablamos de «cómo hacer el sistema más inteligente»; este capítulo trata de «cómo hacerlo más barato». Mi mayor trampa fue la explosión de costos — la primera semana en producción, $500 en llamadas al LLM; el jefe casi me despide.
Luego aprendí tres estrategias: Semantic Caching (caché semántica), Tiered Retrieval (recuperación por capas) y Parallel Processing (procesamiento paralelo). El costo bajó a $50/semana y la precisión mejoró.
5.1 Semantic Caching (caché semántica)
La estrategia más simple y efectiva. Principio: cachear embeddings de consultas frecuentes; si la similitud > 0.95, devolver la respuesta en caché sin llamar al LLM.
En producción, la tasa de aciertos de caché llega al 30-50 %. El tiempo de respuesta baja de ~500 ms a ~50 ms (con acierto de caché); la experiencia del usuario mejora notablemente.
from langchain.cache import InMemoryCache
from langchain.embeddings import CacheBackedEmbeddings
from langchain_openai import OpenAIEmbeddings
# 缓存常见查询的嵌入
underlying_embeddings = OpenAIEmbeddings()
cached_embeddings = CacheBackedEmbeddings.from_bytes_store(
underlying_embeddings,
InMemoryCache(), # 生产环境建议用 Redis
)
# 使用缓存嵌入进行路由
# 相似度 > 0.95 直接返回缓存答案
En producción conviene Redis o Memcached, no InMemoryCache (se pierde al reiniciar). También limpio la caché periódicamente: consultas sin acceso en más de 30 días expiran automáticamente.
5.2 Tiered Retrieval (recuperación por capas)
Consultas simples con modelos baratos, complejas con modelos caros. La optimización de costos más directa.
from langchain_openai import ChatOpenAI
from langchain_anthropic import ChatAnthropic
# 简单查询用便宜模型
simple_llm = ChatOpenAI(model="gpt-4o-mini", temperature=0.1)
# 复杂查询用昂贵模型
complex_llm = ChatAnthropic(model="claude-opus-4-20250514", temperature=0.2)
# 路由逻辑
if route_layer(query).name in ["finance_query", "tech_support"]:
# 简单意图用 GPT-4o-mini
response = simple_llm.invoke(query)
elif route_layer(query).name == "graph_query":
# 复杂推理用 Claude Opus
response = complex_llm.invoke(query)
La diferencia de costo es clara:
| Modelo | Costo por llamada | Escenario adecuado |
|---|---|---|
| GPT-4o-mini | $0.00015/1K tokens | Consultas factuales simples |
| Claude Opus 4 | $0.015/1K tokens | Consultas de razonamiento complejo |
100 veces de diferencia. Si el 80 % de las consultas son simples, el costo puede bajar al 20 % del original.
5.3 Parallel Processing (procesamiento paralelo)
El enrutamiento híbrido (lógico + EnsembleRetriever) añade 200-500 ms de latencia. Pero varios recuperadores pueden llamarse en paralelo; la latencia extra es mínima.
import asyncio
from langchain_community.retrievers import BM25Retriever
# 并行调用 BM25 + Vector 检索器
async def parallel_retrieval(query):
bm25_task = asyncio.create_task(bm25_retriever.invoke(query))
vector_task = asyncio.create_task(vector_retriever.invoke(query))
bm25_docs, vector_docs = await asyncio.gather(bm25_task, vector_task)
# RRF 融合
return ensemble_docs
Resultados medidos: llamada en serie 600 ms, en paralelo 320 ms. Casi compensa la latencia del enrutamiento híbrido.
Combinando las tres estrategias, el costo de mi sistema pasó de $500/semana a $50/semana, con respuestas más rápidas. Optimizar costos no es «recortar calidad», sino «asignar recursos con inteligencia».
Capítulo 6: Comparación de enfoques y guía de selección
Después de tanto, quizá quieras saber: «¿qué enfoque usar en mi proyecto?» Aquí va una tabla comparativa y un árbol de decisión.
Comparación central de los tres enfoques
| Dimensión | Enrutamiento lógico | Enrutamiento semántico | EnsembleRetriever |
|---|---|---|---|
| Principio central | El LLM analiza la intención | Coincidencia por similitud semántica | Fusión con algoritmo RRF |
| Velocidad de respuesta | ~500 ms (llamada al LLM) | ~50 ms (cálculo de embeddings) | ~300 ms (recuperación paralela) |
| Costo | Medio (LLM en cada enrutamiento) | Bajo (embeddings gratuitos) | Bajo (sin LLM) |
| Precisión | Alta (comprensión profunda) | Media (umbral de similitud) | Alta (Lexical + Semantic) |
| Escenario adecuado | Tipos de fuente claros (<=5) | Clasificación de intenciones (<=20) | Fusión de recuperadores del mismo tipo |
| Stack técnico | LangChain + Structured Output | biblioteca semantic-router | LangChain EnsembleRetriever |
Árbol de decisión para la selección
Un flujo sencillo para decidir rápido:
Paso 1: ¿Necesitas enrutar a distintos tipos de fuentes de datos?
├─ Sí → Paso 2: ¿Número de fuentes <= 5?
│ ├─ Sí → Elige [enrutamiento lógico] (el LLM analiza la intención)
│ └─ No → Paso 2b: ¿Número de fuentes <= 20?
│ ├─ Sí → Elige [enrutamiento semántico] (utterances predefinidos)
│ └─ No → Requiere coordinador Multi-Agent (fuera del alcance de este artículo)
└─ No → Paso 3: ¿Necesitas fusionar recuperadores del mismo tipo?
├─ Sí → Elige [EnsembleRetriever] (fusión RRF)
└─ No → Recuperación con una sola base vectorial basta
Recomendaciones de la práctica
Si tu proyecto es un «sistema de base de conocimiento empresarial» con base de datos financiera, documentación técnica y grafo de conocimiento, sugiero:
- Primero enrutamiento semántico para clasificar intenciones (finanzas/técnico/relaciones): rápido y gratis.
- Luego enrutamiento lógico para escenarios especiales (por ejemplo, consultas con alta actualidad van a búsqueda web).
- Dentro de cada fuente, EnsembleRetriever (BM25 + vectorial) para subir el recall.
- Finalmente optimización de costos (Semantic Caching, Tiered Retrieval) para ahorrar y acelerar.
Esta arquitectura de «enrutamiento en tres capas» la validé en 3 proyectos con resultados estables. Costo ~$50/semana, tiempo de respuesta < 800 ms, satisfacción del usuario por encima del 85 %.
Si tu proyecto tiene una sola fuente de datos (solo base vectorial), no te apresures a introducir enrutamiento. Primero prueba EnsembleRetriever con BM25 + vectorial y mira si el recall basta. Muchas veces el cuello de botella de una sola base vectorial es solo la estrategia de recuperación, no hace falta enrutamiento.
Resumen y recomendaciones de acción
Resumiendo los puntos centrales.
Esencia del enrutamiento de consultas: elegir dinámicamente la ruta de recuperación según las características de la consulta (dependencia de contexto, saltos de razonamiento, tipo de datos, actualidad). Como un GPS que elige la ruta óptima según el tráfico, no un camino fijo a ciegas.
Escenarios adecuados de los tres enfoques:
- Enrutamiento lógico: tipos de fuente claros (<=5), necesidad de comprensión profunda de la intención.
- Enrutamiento semántico: clasificación de intenciones (<=20), respuesta rápida, sensible al costo.
- EnsembleRetriever: fusión de recuperadores del mismo tipo (BM25 + vectorial), mejora del recall.
Optimización de costos en producción: Semantic Caching, Tiered Retrieval y Parallel Processing combinados pueden reducir el costo al 10 % del original, con respuestas más rápidas.
Mis recomendaciones de acción
Si estás construyendo un sistema RAG, itera en este orden:
Paso 1: diagnosticar el cuello de botella
Analiza los casos de fallo del sistema actual y clasifícalos en «baja dependencia de contexto» (recuperación vectorial basta) vs «alta dependencia de contexto» (requiere razonamiento multi-salto). No saltes este paso o acabarás sobrediseñando.
Paso 2: elegir el enfoque
Según número de fuentes de datos, número de intenciones y presupuesto, elige lógico/semántico/EnsembleRetriever. No combines los tres desde el inicio; valida primero un enfoque único.
Paso 3: superponer optimización de costos
Primero Semantic Caching (lo más simple y efectivo), luego Tiered Retrieval y Parallel Processing. La optimización de costos es iteración continua, no un paso único.
Si tienes dudas concretas sobre tu proyecto, deja un comentario. Los errores que yo cometí quizá te ayuden a evitarlos.
FAQ
¿Cómo elegir entre enrutamiento lógico, semántico y EnsembleRetriever?
• Enrutamiento lógico: adecuado cuando el tipo de fuente de datos es claro (<=5), requiere comprensión profunda de la intención, tiempo de respuesta ~500 ms
• Enrutamiento semántico: adecuado para clasificación de intenciones (<=20), necesita respuesta rápida (~50 ms), sensible al costo
• EnsembleRetriever: adecuado para fusionar recuperadores del mismo tipo (BM25 + vectorial), mejora el recall
En proyectos reales puedes combinarlos: enrutamiento semántico para clasificar intenciones, enrutamiento lógico para escenarios especiales, EnsembleRetriever para recuperación híbrida.
¿Cómo reducir el costo de llamadas al LLM en sistemas RAG?
• Semantic Caching: cachea los embeddings de consultas frecuentes; si la similitud > 0.95, devuelve la respuesta en caché directamente, reduciendo un 30-50 % las llamadas al LLM
• Tiered Retrieval: consultas simples con modelos baratos (GPT-4o-mini), consultas complejas con modelos caros (Claude Opus), costo reducido un 80 %
• Parallel Processing: llamadas paralelas a múltiples recuperadores, compensando la latencia; el tiempo de respuesta baja de 600 ms a 320 ms
Combinando las tres estrategias, el costo puede pasar de $500/semana a $50/semana.
¿Cuál es el principio del algoritmo RRF en EnsembleRetriever?
• Fórmula: RRF(d) = Σ 1/(k + rank(d)), típicamente k=60
• Ventaja: no depende de la puntuación original del documento, puede fusionar cualquier tipo de recuperador (BM25, vectorial, grafo de conocimiento)
• Efecto: BM25 puro recall 70 %, vectorial puro 85 %, EnsembleRetriever puede alcanzar 92 %
Adecuado para recuperación híbrida Lexical + Semantic, pero no para enrutamiento entre fuentes de datos distintas.
¿Qué fuentes de datos necesita el enrutamiento de consultas? ¿Cómo juzgar las características de una consulta?
• Dependencia de contexto: baja (consultas factuales) usa recuperación vectorial, alta (razonamiento multi-salto) usa grafo de conocimiento
• Saltos de razonamiento: un salto recuperación directa, varios saltos requiere coordinación de Agent
• Tipo de datos: estructurados usa SQL, no estructurados usa recuperación vectorial
• Actualidad: información en tiempo real usa búsqueda web, conocimiento estático usa base de conocimiento local
Por ejemplo, «ventas de la región Este de China» es un salto, estructurado, datos estáticos — SQL es lo más rápido; «huelga de proveedores afecta el precio de las acciones» es alta dependencia de contexto, multi-salto, no estructurado — el grafo de conocimiento es más adecuado.
¿Cómo definir utterances para enrutamiento semántico? ¿Cómo configurar umbrales?
• 4-10 consultas de ejemplo por intención, cubriendo expresiones comunes
• Muy pocas (<4) baja el recall, demasiadas (>20) aumenta el costo computacional
• HuggingFaceEncoder permite embeddings locales gratuitos, sin costo de API
Configuración de umbrales:
• Umbral de similitud por defecto 0.85 (85 %), ajustable según el proyecto
• Umbral más alto = mayor precisión, pero menor recall
• Recomendación: empezar en 0.85 y afinar según datos de prueba
17 min de lectura · Publicado el: 5 may 2026 · Actualizado el: 21 ago 2026
Guía de ingeniería RAG
Si llegaste desde búsqueda, lo más rápido es ir al artículo anterior o siguiente de esta misma serie.
Anterior
Optimización de sistemas RAG: equilibrio entre precisión de recuperación y calidad de generación
¿RAG recupera mal? Cinco ejes: Query, búsqueda híbrida, rerank, chunking y evaluación. Marco de decisión precisión vs latencia.
Parte 3 de 5
Siguiente
Enrutamiento de consultas RAG en la práctica: colaboración entre múltiples bases vectoriales y recuperación inteligente
Guía práctica de enrutamiento de consultas RAG: cómo usar EnsembleRetriever y Semantic Router para recuperación colaborativa entre múltiples bases vectoriales. Desde enrutamiento lógico hasta semántico, pasando por la fusión con RRF: ejemplos de código completos y comparativa de rendimiento.
Parte 5 de 5



Comentarios
Inicia sesión con GitHub para dejar un comentario