De niño, mis dibujos animados favoritos eran “Oliver y Benji”. Llamarlos “Campeones”, que era el título oficial en español era de pringao; llamarlos “Captain Tsubasa”, cuando descubrimos el original japonés, ya de adolescentes, demasiado friki. Dibujos y fútbol, lo tenía todo.
Pero hubo otra serie con los mismos elementos y mucho menos éxito, “Supergol”. Para mi es especial porque me hizo vivir la primera aparición cruzada que recuerdo, mi primer crossover. En su primer capítulo, Rafael, “el Oliver Atom de Supergol”, llegaba a una nueva ciudad y les decía a sus nuevos amigos que él había jugado con el famoso Benji Price en la academia “St. Francis”.
Hay algo de complicidad, de sentimiento de pertenencia, de chiste interno, de lenguaje de código en estos crossovers que hace sentir al espectador que está en el sitio adecuado. La industria ha aprovechado estos crossovers de mil maneras (¿quizá incluso demasiado, Marvel?); el de Rafael no fue un gran invento, ni fue el mejor ni el último crossover, pero fue mi primero.
Ese recuerdo es la semilla de un proyecto paralelo en el que he estado metido las últimas semanas: Literature Meet Up. La idea es simple: ¿y si pudiera encontrar el equivalente literario de ese saludo entre Campeones y Supergol? Personajes de novelas, de libros totalmente distintos, cuyas líneas temporales y ubicaciones se solapan de verdad. Sherlock Holmes y el Dr. Jekyll, los dos deambulando por Londres en la década de 1880.
Puedes cotillear el código, está todo aquí, y hay una app en vivo (en el plan gratuito, así que ten paciencia con el arranque) aquí. Sólo incluye 13 novelas como MVP y tiene algunos errores conocidos y muchas áreas de mejora, puede que lo ampliemos, pero como no tenía otro objetivo que aprender y compartirlo, aquí está:
La idea
Project Gutenberg tiene decenas de miles de novelas de dominio público ahí sentadas, totalmente digitalizadas y gratis. En algún lugar de todo ese texto hay un mapa enorme e implícito de dónde y cuándo estuvo cada personaje ficticio. Sherlock Holmes está en Baker Street en la década de 1880. Jean Valjean, de Los Miserables, estaba en París unas décadas antes. El capitán Nemo está... en todas partes y en ninguna, en un submarino, lo cual acabó siendo su propio caso límite.
Si pudiéramos extraer esa información de “quién estuvo dónde y cuándo” de forma fiable, podríamos construir una consulta que encuentre pares de personajes, de libros distintos, cuyos eventos se solapan en tiempo y lugar. No fanfiction, simplemente: ¿podrían estas dos personas, en los mundos que escribieron sus autores, haberse cruzado de forma plausible?
Cómo funciona
Leer un libro de Gutenberg vía la API de Gutendex, dividirlo en capítulos.
Pasárselo a un LLM capítulo a capítulo, extrayendo personajes, ubicaciones y eventos. Con una pequeña memoria, es decir, cada llamada de extracción de un capítulo ve el registro acumulado de todos los personajes y lugares vistos hasta el momento, para que no reinvente a “el Sr. Darcy” como un personaje nuevo cada vez que aparece y para que entienda que significa “diez años después…”.
Ejecutar tres pasadas más sobre la información extraída: una para reconstruir una cronología coherente, otra para estimar el marco temporal general del libro (útil cuando no tenemos fechas explícitas) y otra para limpiar personajes que se extrajeron dos veces de forma ligeramente distinta entre capítulos.
Rellenar la geocodificación de lugares reales con Nominatim, para que “Londres” y “el West End” se resuelvan en una jerarquía de lugares de verdad.
Escribir todo en Postgres en una única transacción de todo-o-nada: nada toca la base de datos hasta que un libro ha tenido éxito de principio a fin.
Servirlo a través de una pequeña app en FastAPI que te deja elegir una granularidad de solapamiento temporal (día/mes/año/década/siglo) y una de solapamiento de ubicación (barrio/ciudad/región/país), y te devuelve un “encuentro” aleatorio entre libros distintos, con la evidencia detrás.
Escribir esta lista hace que suene ordenado y lineal. Pero sólo es ordenado y lineal después de aprender varias cosas útiles.
Qué aprendimos
No todas las etapas del pipeline necesitan el mismo modelo. El paso de extracción por capítulo se ejecuta una vez por capítulo —así que para una novela de 40 capítulos, son 40 llamadas, y escala con la longitud del libro. Este paso es, a la vez, el que tiene más peso en el coste y el que impacta más en la calidad de los resultados. Otros pasos se ejecutan sólo una vez y tienen menos impacto en la calidad final. Encontrar el balance entre precio y calidad es la clave.
Acabamos haciendo que el modelo utilizado para cada paso fuera configurable por variables de entorno específicamente para poder ajustar esto sin tocar código, con tres complejidades de modelo diferentes. Esto es clave para hacer pruebas con diferentes modelos más adelante.
No todos los tokens cuestan lo mismo. Los tokens de salida suelen ser bastante más caros que los de entrada en casi cualquier proveedor, así que un prompt de extracción larguísimo (con todo el esquema, ejemplos y el registro acumulado de personajes) sale más barato de lo que parece si la respuesta del modelo es compacta y estructurada. Y ahí entra otro truco que usamos: en vez de dejar que el modelo “escriba” su respuesta con sus palabras, le obligamos a rellenar una plantilla fija —una especie de formulario con campos concretos— y nada más. Esto no solo evita que se ponga a redactar de más (menos tokens de salida, menos coste), sino que también hace que la respuesta sea mucho más fácil de procesar automáticamente después, porque siempre llega con la misma forma.
Y luego está la caché de prompt: la parte que no cambia entre capítulos —el esquema, las instrucciones fijas— se puede cachear, así que solo pagas el precio completo la primera vez y, a partir de ahí, una fracción por reutilizarla. En un pipeline donde el mismo prompt base se repite capítulo tras capítulo, eso no es un detalle menor: es la diferencia entre que procesar un libro cueste céntimos o cueste bastante más.
También usamos Open Router para probar rápido combinaciones de modelos de proveedores distintos sin tocar el código cada vez: cambiar de Claude a OpenAI o DeepSeek es, literalmente, cambiar una variable de entorno. Esto fue muy útil para comparar calidad y precio en paralelo sin comprometerse a nada: pudimos ver cómo se comportaba un modelo más barato de otro proveedor en la etapa de deduplicación de personajes, o si de verdad merecía la pena pagar más en la extracción por capítulo. Esta capa de abstracción hace que decidir los modelos adecuados sea un experimento de unas horas, no una refactorización.
Eso sí, no fue gratis del todo: al pasar todas las llamadas por Open Router en vez de ir directas a Anthropic, por ejemplo, perdimos el ahorro de la caché de prompt que mencionamos antes. Open Router tiene forma de recuperarlo, pero exige montar la petición de una manera algo distinta a la que usábamos, y no es algo que puedas activar sin más. Es el típico peaje de meter una capa intermedia entre tu código y el modelo: ganas flexibilidad para cambiar de proveedor con una línea, pero puedes perder, sin enterarte, alguna optimización fina que sí tenías yendo directo.
¡Me engañaste, Telecinco!
Hace poco descubrí que mi querido primer crossover era falso. Rafael y Benji Price nunca jugaron juntos y la anécdota nunca se menciona en la serie original japonesa. La televisión que emitía ambas series quería enganchar a los fans de “Oliver y Benji” y probaron dos cosas: primero la intentaron titular “Campeones 2” como si fuera una continuación aunque era completamente independiente y, además, modificaron el doblaje en español para incluir el crossover en el primer capítulo. Y viendo que aquí estoy, recordándolo con más de cuarenta años, no sé si honrándolo o vengándome, ¡vaya si lo consiguieron!
Si quieres curiosear, recuerda que el código está aquí y la app en vivo está aquí. Ve a averiguar si Drácula y Elizabeth Bennet, de Orgullo y Prejuicio, estuvieron alguna vez en la misma ciudad al mismo tiempo. ¿Qué se podrían haber dicho? Ése no te lo destripo.
Para escribir este post he hecho uso de algunas herramientas de IA para asistirme durante el proceso. Entre otras, he usado D-X-OPUS de Tinta Artificial y Spiral de Every. El gusto por Oliver y Benji es mío, el interés por los encuentros literarios también es mío, y además el engaño de Telecinco lo sufrí yo.





