Cuando empecé en el Grado de Informática, nos enseñaban que para procesar texto estructurado lo mejor eran las expresiones regulares (regex). Sin embargo, cuando te enfrentas a 400 PDFs de contratos de alquiler repletos de jerga legal redundante, las expresiones regulares se quedan cortas. Hace unos meses me cayó un proyecto para un cliente donde tenía que extraer variables muy específicas de informes financieros de tres años seguidos. El volumen total rondaba los 800.000 tokens.
Muchos desarrolladores novatos habrían copiado y pegado los archivos enteros en la interfaz de Anthropic o Google, confiando en sus ventanas de contexto de un millón de tokens. Yo cometí ese mismo error el primer día. ¿El resultado? El modelo sufría el clásico efecto de «pérdida en el medio» (lost in the middle), ignorando cláusulas clave situadas en la página 45 de los documentos y alucinando con datos que no existían.
Frustrado por perder créditos de la API de OpenAI tirando prompts masivos a la basura, decidí estructurar mi primer Pipeline modular con embeddings y filtrado por capas. Aquí te cuento exactamente cómo lo monté, el código exacto que usé y cómo resolví la falta de coherencia en el output final.
El problema del contexto masivo: Por qué el «copia y pega» te está costando dinero
Cuando alimentas a un modelo con demasiada información a la vez, la atención de la red de transformers se diluye. Es matemática pura. Para solucionar esto, implementé una arquitectura dividida en tres fases independientes:
- Fragmentación y vectorización (Chunking & Vectorization).
- Recuperación semántica selectiva.
- Síntesis estructurada mediante JSON Mode.
Al separar las tareas, logré que cada llamada a la API procesara únicamente el fragmento exacto donde residía la respuesta, reduciendo mi factura de OpenAI de un estimado de 45 dólares a tan solo 2,10 dólares para todo el lote de documentos.
El código base de mi pipeline de procesamiento
Para que veas que esto no es teoría vacía de manual, este es el script en Python que utilizo en mi propio entorno local para segmentar los textos y forzar al modelo a devolver únicamente lo que necesito, asegurando un formato estructurado y predecible:
Python
import os
from openai import OpenAI
client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
def procesar_fragmento_financiero(texto_chunk):
# Forzamos una temperatura baja para evitar creatividad e invenciones
response = client.chat.completions.create(
model="gpt-4o-mini",
temperature=0.0,
response_format={ "type": "json_object" },
messages=[
{
"role": "system",
"content": (
"Eres un parser de datos financieros extremadamente estricto. "
"Tu única tarea es extraer el EBITDA, el flujo de caja operativo "
"y cualquier deuda neta mencionada en el texto proporcionado. "
"Devuelve los datos exclusivamente en un objeto JSON con las llaves: "
"'ebitda', 'flujo_caja', 'deuda_neta', 'pagina_referencia'. "
"Si un dato no aparece, pon obligatoriamente null. No asumas ni calcules nada."
)
},
{
"role": "user",
"content": f"Analiza el siguiente fragmento de informe:\n\n{texto_chunk}"
}
]
)
return response.choices[0].message.content
# Ejemplo de uso con un fragmento controlado extraído previamente
fragmento_ejemplo = "El flujo de caja operativo ascendió a 450.000€ según se detalla en la página 14..."
resultado_json = procesar_fragmento_financiero(fragmento_ejemplo)
print(resultado_json)

El framework de prompt engineering avanzado que salvó el proyecto
El verdadero secreto para que el script anterior funcione sin fallos no está en el código Python, sino en el aislamiento del prompt del sistema. Descubrí que si mezclas las instrucciones de formato con las instrucciones de negocio en un solo párrafo largo, el LLM tiende a priorizar el final del texto.
Para solucionar esto, desarrollé una técnica que llamo Delimitación de Variables por Bloques. Consiste en estructurar el prompt utilizando etiquetas pseudo-HTML para que la IA entienda perfectamente la jerarquía de las órdenes. Aquí tienes la plantilla de prompt que acabé integrando en mi pipeline:
Plaintext
<CONTEXTO_SISTEMA>
Eres un analista de datos algorítmico trabajando dentro de una tubería automatizada de backend. No eres un chatbot. No saludes. No des explicaciones.
</CONTEXTO_SISTEMA>
<RESTRICCIONES_ESTRICTAS>
1. Formato de salida obligatorio: JSON válido.
2. Si rompes el esquema JSON, el sistema fallará.
3. Queda terminantemente prohibido inventar números. Si lees "pérdidas significativas" pero no hay cifra numérica, el valor en el JSON debe ser null.
</RESTRICCIONES_ESTRICTAS>
<INPUT_DATOS>
{TEXTO_DEL_FRAGMENTO}
</INPUT_DATOS>
Lecciones aprendidas en producción
Tras procesar los 400 documentos del cliente, saqué tres conclusiones que cambiaron mi forma de entender el desarrollo con Inteligencia Artificial:
- La temperatura lo es todo: En desarrollo y extracción de datos, cualquier valor por encima de
0.2destruirá la consistencia de tu base de datos a largo plazo. Yo uso siempre0.0para tareas de extracción pura. - El tamaño del fragmento importa: Si haces trozos (chunks) demasiado pequeños (ej. 500 caracteres), puedes cortar una frase importante por la mitad, perdiendo la relación entre el sujeto y la cifra. Yo encontré el punto óptimo en fragmentos de 3000 caracteres con un solapamiento (overlap) de 400 caracteres.
- El validador de esquemas es obligatorio: Aunque configures el parámetro
response_format={ "type": "json_object" }, a veces el modelo puede omitir una llave requerida si no encuentra el dato. Implementar una función de validación con Pydantic en Python antes de guardar en la base de datos es lo único que evitará que tu aplicación rompa en producción.
Si sigues aplicando el método tradicional de meter PDFs enteros en la ventana de chat y rezar para que extraiga los datos correctos, estás perdiendo el control de tu software. Construir pipelines modulares requiere más código inicial, pero es la única forma de escalar soluciones de IA que las empresas estén dispuestas a pagar de forma recurrente.