// RAG · MÓDULO 05/12
RAG financiero de grado institucional
Chunking consciente de estructura, hybrid search con reranking, la división texto/números y evaluación RAGAS.
El módulo 4 dejó las fuentes documentales institucionales (EDGAR, transcripts, textos regulatorios) ingestadas y normalizadas. Este módulo las convierte en un sistema de comprensión: un pipeline de Retrieval-Augmented Generation (RAG — generación aumentada por recuperación: se recuperan fragmentos documentales y se inyectan como contexto al LLM para fundamentar su respuesta) al estándar de evidencia de una mesa de research o de riesgo. La tesis central, sostenida con datos en cada sección: en finanzas la estructura es el pipeline — el chunking, el retrieval y la evaluación genéricos destruyen exactamente la señal que el analista necesita, y la diferencia entre un 19% y un 83,7% de precisión es ingeniería, no modelo. (API EvangelistAPI Evangelist)
5.1 Por qué el RAG de tutorial falla en finanzas
El RAG de tutorial — cargar PDF, RecursiveCharacterTextSplitter con 1.000 tokens, embeddings genéricos, top-k por similitud coseno — parte de tres supuestos que el documento financiero viola sistemáticamente. Primero, que el texto es prosa plana: un 10-K es un artefacto estructurado (Items, notas, tablas, tags XBRL), y los chunks de tamaño fijo "aplanan disclosures estructurados en bloques arbitrarios de texto", partiendo factores de riesgo y separando cada cifra de la sección que le da significado. (🦜️🔗 LangChain) Segundo, que la similitud semántica basta: preguntar por el inventario a cierre de ejercicio puede recuperar prosa del periodo equivocado "porque el embedding parecía suficientemente cercano" — el RAG plano "confunde periodos fiscales, enruta mal hechos del balance o cita narrativa que no soporta la cifra de la respuesta". (csdn.net) Tercero, que recuperar el texto correcto implica responder correctamente: la respuesta financiera exige razonamiento numérico multi-paso sobre tabla y texto, donde el LLM solo es estructuralmente débil. (getvocal.ai)
5.1.1 Evidencia de benchmarks: qué miden y por qué importan al buy-side
La referencia empírica es FinanceBench (Patronus AI, arXiv 2311.11944, nov-2023): 10.231 preguntas escritas por expertos sobre SEC filings de 40 empresas estadounidenses, con un subconjunto abierto de 150 preguntas y scoring binario con tolerancia de ±2,5% en respuestas numéricas. (API EvangelistAPI Evangelist) Sus resultados originales son la radiografía del RAG naive: GPT-4-Turbo a libro cerrado acierta el 9%; con un vector store compartido para todos los documentos, el 19% — es decir, "respondió incorrectamente o se negó a responder el 81% de las preguntas"; con un vector store por documento, el 50%; con el filing completo en contexto (long-context), el 76%; y con las páginas de evidencia dadas (oracle), el 85%. (API EvangelistAPI Evangelist) En 2026, una evaluación independiente sobre el mismo benchmark (media de 10 corridas con LLM-juez) sitúa el RAG agéntico exhaustivo — retrieval híbrido, rerank, navegación por estructura y herramientas — en el 83,7%, por encima del full-context con modelos de 1M de tokens (76,0%). (langchain.js) La trayectoria 19% → 83,7% es la demostración cuantificada de que la ingeniería del pipeline mueve la aguja en comprensión documental, el dominio donde el ROI institucional de los LLM está probado.
Fuente: resultados originales de FinanceBench (arXiv 2311.11944, 2023) (API EvangelistAPI Evangelist) y evaluación independiente de RAG agéntico (2026, media de 10 corridas) (langchain.js); elaboración propia, datos a julio de 2026.
El resto de benchmarks acotan el problema desde el razonamiento numérico. FinQA (arXiv 2109.00122): 8.281 pares QA anotados por once profesionales sobre earnings reports del S&P 500, con evidencia heterogénea (tabla + texto) y un programa de razonamiento numérico; GPT-4 alcanza 62,87 frente a 91,16 del experto humano. (Model Agent Platform) ConvFinQA (arXiv 2210.03849) lo extiende a 3.892 conversaciones multi-turno con anáfora sobre cifras: GPT-4 logra 76,48 frente a 89,44 humano, y los errores van en cascada — si un turno falla, "hay muy pocas posibilidades de que los turnos subsiguientes sean correctos". (🦜️🔗 LangChain) TAT-QA (ACL 2021): 16.552 preguntas híbridas tabular-textuales (42% aritméticas); el mejor modelo del paper, TAGOP, alcanza 58,0 F1 frente a 90,8 F1 humano. (博客园)
Tabla 5.1 — Benchmarks financieros de QA y razonamiento numérico: tamaño, mejor resultado documentado y brecha frente al experto humano
| Benchmark | Tamaño | Qué mide | Mejor resultado documentado | Humano experto | Brecha |
|---|---|---|---|---|---|
| FinanceBench (arXiv 2311.11944, 2023) | 10.231 preg. (150 abiertas) | QA open-book sobre SEC filings; exactitud de cifra con cita | 83,7% (RAG agéntico, 2026); 19% (RAG naive, 2023) | ~100% (respuestas gold de expertos) | El RAG naive falla el 81%; el agéntico aún deja ~16 pp |
| FinQA (arXiv 2109.00122, 2021) | 8.281 QA | Razonamiento numérico multi-paso sobre tabla + texto | GPT-4: 62,87% accuracy (arXiv 2305.05862, 2023) | 91,16% | ~28 pp |
| ConvFinQA (arXiv 2210.03849, 2022) | 14.115 preg. / 3.892 conv. | Numérico multi-turno con anáfora sobre cifras | GPT-4: 76,48% (arXiv 2305.05862, 2023) | 89,44% | ~13 pp; cascada de errores entre turnos |
| TAT-QA (ACL 2021.acl-long.254, 2021) | 16.552 QA | QA híbrido tabular + textual; 42% aritmético | TAGOP: 58,0 F1 | 90,8 F1 | ~33 pp |
5.2 Chunking consciente de estructura
El chunking es la palanca número uno del RAG financiero porque decide qué unidades de significado sobreviven a la indexación. La regla operativa: la estructura del documento marca las fronteras; el tamaño solo subdivide dentro de ellas. LangChain ofrece el patrón de doble división — primero estructural (por ejemplo, MarkdownHeaderTextSplitter, que conserva el linaje de encabezados como metadata) y luego por tamaño con RecursiveCharacterTextSplitter, heredando la metadata estructural en cada sub-chunk. (stackademic.com)
5.2.1 10-K por Items, earnings calls por turnos, textos regulatorios con jerarquía
10-K por Items regulatorios. La unidad semántica de un 10-K es el Item (1 Business, 1A Risk Factors, 7 MD&A, 8 Financial Statements): un analista lee "seleccionando filing y periodo, inspeccionando la tabla de contenidos y navegando a Item 1A, 7 u 8", y el retrieval debe imitar ese recorrido. (🦜️🔗 LangChain) Cada chunk lleva un section_path de linaje ("10-K > Item 1A > Regulatory Risk > EU Operations") que permite citar con precisión de sección y filtrar antes de buscar. (🦜️🔗 LangChain)
import re
from langchain_core.documents import Document
ITEM_RE = re.compile(r"^\s*Item\s+(\d+[A-Z]?)\.?\s+(.+)$", re.IGNORECASE | re.MULTILINE)
def chunk_10k_by_items(text: str, ticker: str, fiscal_year: int) -> list[Document]:
"""Divide un 10-K en chunks por Item regulatorio, con metadata de linaje."""
matches = list(ITEM_RE.finditer(text))
docs = []
for i, m in enumerate(matches):
start = m.end()
end = matches[i + 1].start() if i + 1 < len(matches) else len(text)
docs.append(Document(
page_content=text[start:end].strip(),
metadata={
"ticker": ticker,
"fiscal_year": fiscal_year,
"filing_type": "10-K",
"item": f"Item {m.group(1).upper()}",
"item_title": m.group(2).strip(),
"section_path": f"10-K > Item {m.group(1).upper()} > {m.group(2).strip()}",
},
))
return docs
# Después: re-dividir Items largos con RecursiveCharacterTextSplitter,
# PROPAGANDO la metadata a cada sub-chunk.Earnings calls por turnos de hablante. Los transcripts ya traen fronteras de turno y nombre del hablante (formato XML), y la literatura de NLP financiero valida el turno como unidad natural de procesamiento, eliminando turnos del operador y turnos de menos de 10 tokens (saludos sin señal). (LangChain Forum) Un practitioner del sector (FinTech Studios, feb-2026) reporta una mejora del 34% en precisión de retrieval para consultas sobre resultados con chunking por turnos frente a ventanas fijas de 512 tokens — cifra de vendor sin metodología publicada, pero cuya dirección (estructura > ventana fija) está corroborada por fuentes independientes. (🦜️🔗 LangChain)
from langchain_core.documents import Document
def chunk_earnings_call(turns: list[dict], ticker: str, quarter: str) -> list[Document]:
"""turns = [{'speaker': 'Jamie Dimon', 'role': 'CEO', 'section': 'prepared_remarks',
'text': '...'}, ...]"""
docs = []
for t in turns:
if t["role"] == "Operator" or len(t["text"].split()) < 10:
continue # ruido sin señal (cf. arXiv 1906.02868)
docs.append(Document(
page_content=f"[{t['speaker']} — {t['role']}] {t['text']}",
metadata={
"ticker": ticker, "quarter": quarter,
"speaker": t["speaker"], "role": t["role"],
"section": t["section"], # prepared_remarks | qa
},
))
return docsTextos regulatorios. Circulares, normas técnicas y rulebooks tienen jerarquía de artículos y cross-referencias ("según el artículo 12.3.b"). El chunking debe respetar la jerarquía capítulo-sección-artículo y resolver las cross-referencias materializando el texto referenciado o su identificador en metadata; de lo contrario, un chunk que dice "se aplicará lo dispuesto en el apartado anterior" llega al LLM sin el contenido que lo completa. La tabla siguiente sintetiza la técnica por tipo de documento.
Tabla 5.2 — Chunking consciente de estructura por tipo de documento financiero: unidad, metadata, técnica y riesgo del chunking genérico
| Tipo de documento | Unidad de chunking | Metadata obligatoria | Técnica / splitter | Riesgo del chunking genérico |
|---|---|---|---|---|
| 10-K / 10-Q (EDGAR) | Item regulatorio (1, 1A, 7, 8) y subsección titulada | ticker, fiscal_year, item, section_path | Parseo HTML/XBRL + regex de Items; re-split recursivo propagando metadata | Factor de riesgo partido; cifra sin sección que la contextualiza (🦜️🔗 LangChain) |
| Earnings call | Turno de hablante (≥10 tokens, sin operador) | speaker, role, section (prepared_remarks/qa), quarter | Segmentación por turnos del transcript XML | Q&A mezclado con discurso: se pierde el +34% de precisión de retrieval que aporta el chunking por turnos (🦜️🔗 LangChain) |
| Texto regulatorio | Artículo / apartado jerárquico | regulation, article_path, cross_refs resueltas | Split por encabezados (MarkdownHeaderTextSplitter) + resolución de referencias | Referencias cruzadas huérfanas; norma incompleta en el contexto (stackademic.com) |
| Tablas financieras | Fila/hecho XBRL como unidad de primera clase | concept, period, currency, scale | Docling/unstructured: filas y hechos XBRL como nodos, nunca "sopa de palabras" (csdn.net) | Números separados de cabecera y unidad; errores de escala (🦜️🔗 LangChain) |
| Research / notas de sell-side | Párrafo temático con encabezado | analyst, date, rating, sector | Doble división: headers → recursivo 400-1.000 tokens | Tesis y condiciones mezcladas entre chunks |
5.3 Retrieval avanzado
Con el corpus chunkeado por estructura, la capa de retrieval decide qué candidatos llegan al LLM. El stack de producción 2026 tiene cuatro componentes ordenados: filtro de metadata → búsqueda híbrida → reranking → expansión de contexto padre, todo ello enchufable como BaseRetriever a la cadena canónica de LangChain v1, create_retrieval_chain(retriever, create_stuff_documents_chain(llm, prompt)). (Github)
5.3.1 Hybrid search, reranking, metadata filtering y contexto padre
Metadata filtering primero. El error más común del RAG financiero es recuperar la cifra correcta del periodo equivocado; la defensa de primera línea es estrechar el subconjunto antes de la similitud vectorial con los campos de linaje del chunking. (LangChain Forum)
retriever = vectorstore.as_retriever(search_kwargs={
"k": 6,
"filter": {
"$and": [
{"ticker": {"$eq": "JPM"}},
{"fiscal_year": {"$gte": 2023}},
{"item": {"$in": ["Item 7", "Item 8"]}},
]
},
})Hybrid search BM25 + denso. La búsqueda densa falla en identificadores exactos (tickers, ISIN, nombres de instrumento, códigos de taxonomía) y BM25 falla en semántica; la combinación con Reciprocal Rank Fusion (RRF — fusión que puntúa cada documento por la suma de los inversos de sus rangos en cada lista) es el estándar de producción: cifras de vendor de 2026 reportan 91% de recall@10 frente a 78% (solo denso) y 65% (solo BM25), con ~6 ms de overhead de fusión. (LangChain) En LangChain, EnsembleRetriever implementa RRF con pesos configurables; el punto de partida típico es 0,6 semántico / 0,4 keyword, subiendo el peso BM25 cuando las consultas contienen términos exactos como tickers o códigos. (🦜️🔗 LangChain)
from langchain_classic.retrievers import EnsembleRetriever
from langchain_community.retrievers import BM25Retriever
bm25 = BM25Retriever.from_documents(chunks); bm25.k = 10
dense = vectorstore.as_retriever(search_kwargs={"k": 10})
hybrid = EnsembleRetriever(retrievers=[dense, bm25], weights=[0.6, 0.4])
# En finanzas, tickers/ISIN/nombres de instrumentos favorecen subir peso BM25.El embedding también es una decisión de dominio: en un benchmark de retrieval financiero (HR@5), los embeddings adaptados a finanzas alcanzan 88% frente a 86% de OpenAI text-embedding-3-large, 85% de Cohere embed-english-v3.0 y 84% de Google text-embedding-004, (CSDN博客) y sustituir ada-002 por embeddings financieros en FinanceBench suma +8 puntos de precisión. (Towards AI) Presupuestar un embedding de dominio (p. ej., voyage-finance-2) es de las mejoras más baratas del pipeline.
Reranking. El retrieval híbrido devuelve candidatos; el reranker los reordena leyendo query y documento completos. Cohere Rerank 3 acepta hasta 4.000 tokens de entrada, lo que permite reranquear con contexto de documento completo en lugar del chunk aislado, recuperando relevancia que el chunking destruyó. (🦜️🔗 LangChain) Se integra como compresor sobre cualquier retriever base:
from langchain_classic.retrievers import ContextualCompressionRetriever
from langchain_cohere import CohereRerank
reranker = CohereRerank(model="rerank-v3.5", top_n=5)
final_retriever = ContextualCompressionRetriever(
base_retriever=hybrid, # ensemble BM25+denso, o multi-query
base_compressor=reranker,
)Contexto padre. Queda el dilema embeddings-precisos vs contexto-amplio: ParentDocumentRetriever lo resuelve indexando chunks hijos pequeños (~400 tokens, embeddings precisos) pero devolviendo el documento padre (~2.000 tokens) al recuperar. (arXiv.org) Aplicación financiera: el hijo es el párrafo con la cifra; el padre, la subsección completa del Item (toda la nota de "Liquidity and Capital Resources"), de modo que el LLM recibe la cifra con su narrativa de gestión.
from langchain_classic.retrievers import ParentDocumentRetriever
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain.storage import InMemoryStore
retriever = ParentDocumentRetriever(
vectorstore=vectorstore,
docstore=InMemoryStore(),
child_splitter=RecursiveCharacterTextSplitter(chunk_size=400, chunk_overlap=50),
parent_splitter=RecursiveCharacterTextSplitter(chunk_size=2000, chunk_overlap=200),
)
retriever.add_documents(filing_docs) # indexa hijos en vectorstore, padres en docstoreMMR y multi-query. Cuando los top-k son casi duplicados (típico en filings anuales repetitivos), Maximal Marginal Relevance (MMR) equilibra relevancia y diversidad sobre un pool de fetch_k candidatos, con lambda_mult entre 1,0 (similitud pura) y 0,0 (diversidad pura): (🦜️🔗 LangChain)
donde es el conjunto de candidatos, el de documentos ya seleccionados, la consulta y el peso de relevancia frente a diversidad. El multi-query retrieval genera varias paráfrasis de la consulta con un LLM, recupera para cada una y fusiona, mejorando recall y robustez ante la formulación; es patrón estándar de producción junto a MMR, al coste de llamadas LLM adicionales. (🦜️🔗 LangChain) La compresión contextual con LLM mejora precisión a costa de ~duplicar la latencia: reservarla para consultas de alto valor. (🦜️🔗 LangChain)
El pipeline completo resultante se resume en el diagrama siguiente.
5.4 La división texto/números
5.4.1 Principio: el texto va al vector store, las cifras a herramientas estructuradas
El embedding de un número no preserva su valor: codifica contexto distributivo, no magnitud. De ahí la regla de primer orden del RAG financiero —la regla de oro de los datos del Módulo 4 (§4.4.1) aplicada al retrieval—: la prosa va al vector store con linaje de sección; las cifras van a bases estructuradas (hechos XBRL de la SEC, tablas SQL) accesibles por tool-calling; y toda cifra citada debe existir verbatim en la fuente. Tres evidencias la sostienen. Las tablas "son donde viven las cifras exactas", y el chunking estándar "convierte las tablas en sopa de palabras y separa los números de las secciones que les dan significado": la solución documentada (Red Hat, jul-2026) mantiene filas y hechos XBRL como nodos de primera clase con metadata de concepto, periodo y moneda. (csdn.net) XBRL-Agent cuantifica el beneficio: RAG + calculadoras simbólicas produjo +17 puntos en consultas de taxonomía y +42 en razonamiento numérico frente a LLM base, que "alucinan o malinterpretan contenido financiero" sobre XBRL. (getvocal.ai) Y los errores de escala (millones leídos como miles) son el 15% de los fallos de extracción: un campo scale explícito y la lectura desde la fuente estructurada los eliminan por construcción. (🦜️🔗 LangChain)
La arquitectura resultante divide la consulta en dos planos:
La verificación verbatim es código, no prompting: un segundo pase comprueba que cada cifra de la salida aparece literalmente en el extracto citado (el patrón de verificación en dos pasos; el modo de fallo dominante del razonamiento LLM es la aritmética, no la lógica, como demostró PAL: 16 de 25 cadenas de pensamiento eran idénticas salvo en los números; el desarrollo completo de esta evidencia está en §6.2). (Financial Wisdom TV)
import re
def cifras_en_respuesta(texto: str) -> list[str]:
"""Extrae literales numéricos de una respuesta (soporta escala y separadores)."""
return re.findall(r"\$?\d[\d,.]*\s*(?:million|billion|thousand|%)?", texto)
def verificacion_verbatim(respuesta: str, contextos: list[str]) -> dict:
"""Toda cifra citada debe existir VERBATIM en algún contexto recuperado."""
corpus = " ".join(contextos).replace(",", "")
no_soportadas = [
c for c in cifras_en_respuesta(respuesta)
if c.replace(",", "").strip() not in corpus
]
return {
"ok": not no_soportadas,
"cifras_no_soportadas": no_soportadas,
# En producción: si ok=False -> abstenerse ("NO_DISPONIBLE")
# o enrutar a cola de revisión humana, NUNCA publicar la cifra.
}5.5 Evaluación de RAG
Un pipeline RAG no evaluado es un pipeline que ya falló en silencio. La evaluación institucional se hace por separado para retrieval y generación, y luego end-to-end sobre un golden dataset: (towardsai.net) el retrieval se mide con métricas de ranking (context precision/recall), la generación con faithfulness y answer relevancy. (ActiveWizards: data science and engineering lab)
5.5.1 RAGAS, golden dataset propio y umbrales de aceptación
Las cuatro métricas de RAGAS (definiciones operativas de arXiv 2409.09046): (ActiveWizards: data science and engineering lab)
- Faithfulness (fidelidad): fracción de afirmaciones atómicas de la respuesta inferibles del contexto recuperado — el detector de alucinación. Un LLM-juez descompone la respuesta en claims y verifica cada uno contra el contexto.
- Answer Relevancy: similitud coseno media entre la pregunta original y preguntas regeneradas a partir de la respuesta; detecta respuestas que no contestan lo preguntado.
- Context Recall: fracción de afirmaciones del ground truth atribuibles al contexto recuperado — mide si el retrieval trajo la evidencia necesaria.
- Context Precision: precision@k ponderada por rango — premia que los chunks relevantes aparezcan arriba en la lista.
La métrica de retrieval subyacente a context recall es recall@k: dado el conjunto de pasajes relevantes para la consulta y los pasajes recuperados ,
Es decir, la fracción de la evidencia necesaria que aparece entre los primeros resultados; es la métrica que justifica el hybrid search (91% vs 78% de recall@10 reportado) (LangChain) y la que un golden dataset propio mide contra los pasajes de evidencia anotados.
El valor diagnóstico clave de RAGAS es la separación de fallos: faithfulness baja con context recall alta indica un problema de generación (el modelo tenía los documentos pero los distorsionó); context recall baja indica un problema de retrieval (los documentos nunca se recuperaron). Faithfulness y Answer Relevancy son reference-free (no requieren respuesta dorada), lo que las hace escalables a tráfico real. (shafiqulai.github.io)
from datasets import Dataset
from ragas import evaluate
from ragas.metrics import (
Faithfulness, AnswerRelevancy,
LLMContextPrecisionWithReference, LLMContextRecall,
)
from ragas.llms import LangchainLLMWrapper
from ragas.embeddings import LangchainEmbeddingsWrapper
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
judge_llm = LangchainLLMWrapper(ChatOpenAI(model="gpt-4o-mini", temperature=0))
judge_emb = LangchainEmbeddingsWrapper(OpenAIEmbeddings(model="text-embedding-3-small"))
rows = {"question": [], "answer": [], "contexts": [], "reference": []}
for item in EVAL_QUESTIONS: # p.ej. preguntas tipo FinanceBench
result = rag.invoke({"input": item["q"]})
rows["question"].append(item["q"])
rows["answer"].append(result["answer"])
rows["contexts"].append([d.page_content for d in result["context"]])
rows["reference"].append(item["ref"])
result = evaluate(
Dataset.from_dict(rows),
metrics=[Faithfulness(), AnswerRelevancy(),
LLMContextPrecisionWithReference(), LLMContextRecall()],
llm=judge_llm, embeddings=judge_emb,
)
print(result.to_pandas().mean(numeric_only=True))Golden dataset propio estilo FinanceBench. La plantilla: preguntas escritas por expertos sobre los filings propios de la firma, cada una con (a) respuesta dorada con la cifra exacta y tolerancia (±2,5% en numéricas, como FinanceBench), (b) pasajes de evidencia anotados (doc, sección, página) que definen para recall@k, y (c) tipo de pregunta (extractiva, comparativa entre periodos, multi-hop, con cálculo) para desglosar fallos. (API EvangelistAPI Evangelist) Unas 100-200 preguntas sobre 20-40 filings de la cartera cubren el 80% de los modos de consulta de un desk. LangSmith complementa con un grader de correctness de salida estructurada ("califica SOLO por exactitud factual respecto al ground truth; es aceptable información adicional si no contradice") y drill-down por traza. (matt-harrison.com)
Umbrales de aceptación para producción. La guía RAGAS 2026 con gating en CI propone como punto de partida: faithfulness ≥ 0,85, answer relevancy ≥ 0,80, context precision ≥ 0,75 y context recall ≥ 0,80; (shafiqulai.github.io) pipelines financieros reales sobre FinanceBench reportan faithfulness en torno a 0,86-0,87 como referencia alcanzable. (CallSphere) A estos umbrales se añaden dos gates específicos de finanzas: (1) tasa de verificación verbatim = 100% de las cifras de la muestra de evaluación (§5.4) — es determinista, no negociable; (2) tasa de abstención adecuada: en preguntas sin evidencia en el corpus, la respuesta correcta es "NO_DISPONIBLE", y una tasa de invención >0% en ese subconjunto bloquea el despliegue. El control de costes del juez se resuelve con un modelo barato (gpt-4o-mini), temperatura 0 y muestreo en PR. (shafiqulai.github.io)
Caso aplicado: mesa de research sobre filings de banca
Un equipo de research de banca despliega el pipeline del módulo sobre 10-K/10-Q y earnings calls de sus 40 bancos de cobertura: chunking por Items con section_path y turnos con rol; embedding financiero; Qdrant con filtro de metadata; EnsembleRetriever (0,6/0,4) → CohereRerank (top 5) → ParentDocumentRetriever; hechos XBRL y ratios en herramientas SQL/calculadora; verificación verbatim obligatoria. Golden dataset: 150 preguntas tipo FinanceBench escritas por los propios analistas.
La primera medición RAGAS muestra context recall 0,62 — problema de retrieval: el 40% de los fallos se concentra en consultas con tickers y códigos de instrumento exactos. Subir el peso BM25 a 0,5 y añadir el filtro de fiscal_year eleva recall a 0,84. La segunda medición muestra faithfulness 0,79 — ahora problema de generación: el LLM derivaba variaciones interanuales en texto. Se mueve todo cálculo a la herramienta de ratios y se activa la verificación verbatim: faithfulness sube a 0,88 y las cifras no soportadas caen a cero. El gate de producción (faithfulness ≥ 0,85, recall ≥ 0,80, verbatim 100%, invención 0% en preguntas sin evidencia) se supera y el sistema entra en piloto con revisión humana de toda cifra que alimenta notas a clientes. La lección transferible es el bucle diagnóstico: cada métrica señaló una capa distinta del pipeline, y ninguna mejora fue de prompting.
Ejercicios
- Chunking de un 10-K por Items. Descargue el 10-K más reciente de JPMorgan de EDGAR (Módulo 4) e implemente
chunk_10k_by_items(§5.2.1) consection_pathcompleto. Verifique que Item 1A e Item 7 quedan separados, re-divida Items >2.000 tokens propagando metadata y escriba un test: ningún chunk sinitemyfiscal_year. - Hybrid search medido. Sobre el corpus del ejercicio 1, construya un retriever denso solo y un
EnsembleRetriever0,6/0,4. Con 20 preguntas que mezclen consultas semánticas ("riesgos de liquidez") y exactas ("Common Equity Tier 1 ratio", tickers), mida recall@10 contra evidencia anotada y compare con la referencia 78% vs 91%. - Reranking y contexto padre. Añada
CohereRerank(o cross-encoder localms-marco-MiniLM-L-6-v2) yParentDocumentRetriever(hijo 400 / padre 2.000). Mida context precision de RAGAS antes y después sobre las mismas 20 preguntas y cuantifique la latencia añadida por consulta. - División texto/números. Implemente
xbrl_lookup(SEC company facts) y la calculadora de ratios; reescriba cinco preguntas con cálculo ("variación interanual del margen neto") para resolverlas por tool-calling. Apliqueverificacion_verbatimy reporte la tasa de cifras no soportadas antes y después. - Evaluación RAGAS con gate de CI. Ejecute
evaluate()(§5.5.1) con un golden dataset propio de ≥30 preguntas estilo FinanceBench (respuesta dorada + pasajes de evidencia). Diagnostique retrieval-vs-generación con la matriz faithfulness × context recall y fije los umbrales 0,85/0,80/0,75/0,80 como job de CI que bloquee el merge. - Abstención controlada. Añada 10 preguntas sin respuesta en el corpus (otro periodo u otra empresa). Mida la tasa de invención y ajuste prompt y verificador hasta 0% de cifras inventadas con abstención "NO_DISPONIBLE". Discuta por qué este gate pesa más que un punto de accuracy para un risk manager.
Módulo 5 de 15 — LangChain para Trading Cuantitativo. Datos y versiones verificados a julio de 2026; precios y cifras de mercado sujetos a cambio. LangChain 1.3.14 / langchain-core 1.5.2.
// check
Comprueba lo aprendido
Autoevaluación con respuesta inmediata. No se guarda ninguna puntuación.
Ver respuesta
B. El benchmark mantiene fijos el examen y el modelo: lo que cambia entre filas es la arquitectura de retrieval y las herramientas. Es la demostración cuantificada del módulo de que la diferencia entre 19% y 83,7% es ingeniería. Y aun así quedan ~16 puntos de brecha, lo que justifica el veto humano de §5.5.
Ver respuesta
C. El fallo es de unidad, no de tamaño: la estructura del documento marca las fronteras y el tamaño solo subdivide dentro (§5.2). Además, la metadata de linaje habilita el filtrado previo a la similitud y la citación auditable ante compliance.
Ver respuesta
B. La búsqueda densa falla precisamente en identificadores exactos; BM25 los captura y la fusión RRF eleva el recall@10 del 78% (solo denso) al 91% reportado (§5.3.1). El filtro de metadata evita además recuperar la cifra correcta del periodo equivocado. MMR y multi-query ayudan a diversidad y robustez, pero no a términos exactos.
Ver respuesta
C. El modo de fallo dominante del razonamiento LLM es la aritmética, no la lógica (evidencia de PAL citada en §5.4). La división texto/números exige que el cálculo sea determinista — los +42 puntos de XBRL-Agent miden esa decisión — y que cada cifra citada exista verbatim en la fuente.
Ver respuesta
B. Es la matriz de diagnóstico del módulo: recall alto significa que la evidencia está en el contexto, así que faithfulness bajo señala distorsión en la generación. El caso aplicado lo resolvió delegando el cálculo y verificando cifras, no con prompting.
Ver respuesta
B. La nota de riesgo de §5.1.1 distingue abstención (resultado válido) de cifra alucinada (incidente en un informe de riesgo). El pipeline debe premiar la abstención y verificar cada cifra contra la fuente, no maximizar cobertura: por eso invención >0% bloquea el despliegue aunque las demás métricas estén en verde.
Ver respuesta
B. El hijo pequeño da embeddings precisos para el matching; el padre devuelve la nota o subsección completa (p. ej. toda «Liquidity and Capital Resources») para que el LLM reciba la cifra con su contexto (§5.3.1). No sustituye ni al reranker ni al chunking estructural: se apila sobre ellos.