Flujo de preguntas y estrategia de recuperación
Cómo la ruta de preguntas expande consultas, reordena evidencia, expone diagnósticos y aplica límites de seguridad.
El endpoint de preguntas delega recuperación y generación de respuesta
app.MapPost("/api/ask", async (AskRequest request, IChatAnswerService chatAnswerService, CancellationToken cancellationToken) =>
{
var response = await chatAnswerService.AskAsync(request, cancellationToken);
return Results.Ok(response);
});Cómo la ruta de preguntas expande consultas, reordena evidencia, expone diagnósticos y aplica límites de seguridad.
POST /api/ask
Acepta:
{
"question": "Can you compare Calpurnia and Hermione?",
"documentIds": null,
"includeDiagnostics": false
}
RAG.Core/Services/ChatAnswerService.cs maneja el workflow:
- validar la pregunta;
- construir múltiples consultas de recuperación;
- crear embeddings para cada consulta;
- buscar en Qdrant;
- detectar preguntas de tipo comparación;
- extraer sujetos nombrados;
- agregar perfiles literarios coincidentes;
- agregar chunks con nombres exactos;
- ordenar y filtrar candidatos;
- enviar chunks seleccionados al proveedor de chat;
- devolver respuesta y citas.
La ruta de preguntas ahora aplica límites configurados antes de que empiece la recuperación: la pregunta debe existir, su longitud debe caber en MaxQuestionCharacters, los IDs de documentos seleccionados deben caber en MaxSelectedDocuments, las consultas de recuperación generadas están limitadas por MaxRetrievalQueries y las llamadas a proveedores corren con un timeout enlazado desde ProviderTimeoutSeconds.
Nota de producción: estos límites no reemplazan autenticación, autorización, rate limiting ni controles de facturación. Son controles locales que evitan que una app de tutorial acepte trabajo sin límites antes de crear embeddings o llamar a un proveedor de modelos.
Las preguntas literarias amplias generan consultas expandidas:
literary book club profile protagonists major characters themes...
main characters protagonists central people important names...
who are the key people and what roles do they have...
La recuperación es un problema de ranking
El servicio de preguntas ahora separa tres ideas que suelen mezclarse en demos simples de RAG: generación de candidatos, reranking y selección de contexto. La búsqueda semántica crea candidatos, IRetrievalReranker asigna ranks finales con razones, y la selección de contexto deduplica y recorta la evidencia final enviada al modelo de chat.
El HeuristicRetrievalReranker predeterminado empieza con el score vectorial y luego suma boosts explícitos para perfiles generados, coincidencias de consultas con sujetos nombrados y coincidencias de sujetos nombrados en comparaciones. Devuelve registros RankedChunk con razones de ranking, que luego aparecen en diagnósticos.
Las preguntas comparativas reciben manejo adicional:
- términos como
similarities,compare,between,both,contrastydifferencesactivan el modo comparación; - nombres con mayúscula se tratan como sujetos nombrados;
- documentos no relacionados de bajo ranking se filtran;
- se devuelven citas para todo el contexto enviado al LLM.
Este diseño sigue siendo genérico. No está hardcodeado a Calpurnia, Hermione, Harry Potter ni Eisenhorn. Usa la forma de la pregunta y los nombres para recuperar mejor evidencia.
Diagnósticos de recuperación
Para depuración local, quien llama puede activar includeDiagnostics en POST /api/ask o llamar al endpoint dedicado de debug:
POST /api/ask/debug
Los diagnósticos incluyen texto de consultas expandidas, extracción de sujetos nombrados, detección de modo comparación, scores vectoriales crudos, ranks finales, razones de ranking, contexto seleccionado y si los candidatos fueron filtrados por umbral de comparación, deduplicación o límites de contexto.
Esta es una de las adiciones profesionales más importantes. Cuando una respuesta es mala, un ingeniero puede inspeccionar si la recuperación encontró chunks incorrectos, si el ranking prefirió evidencia equivocada, si el presupuesto de contexto descartó material útil o si el modelo ignoró buena evidencia.