Cómo Construimos un Asistente de IA que Realmente Entiende el Mercado del Aceite
La historia de Olivia: cinco iteraciones, tres modelos descartados y las lecciones de construir un asistente de IA especializado que no inventa datos. Lo que aprendimos intentando que una máquina razone sobre mercados agrícolas.
Hay una pregunta que todo el mundo hace cuando ve un chatbot: “¿Se inventa las cosas?” Es una pregunta razonable. Los modelos de lenguaje son famosos por su capacidad de generar texto convincente sobre cualquier tema, sepan o no de qué están hablando. Y en un contexto donde la información incorrecta puede costar dinero real, donde un precio mal citado puede influir en una decisión de compra o venta, esa pregunta no es académica. Es existencial.
Cuando empezamos a construir Olivia, el asistente de IA de Olearia Intelligence, teníamos claro que no queríamos otro chatbot que sonara convincente pero dijera tonterías. Queríamos algo que realmente supiera de lo que hablaba. Que cuando un usuario preguntara “¿Cuál es el precio del aceite de oliva virgen extra en Italia?”, la respuesta fuera el precio real, actualizado, verificable. No una aproximación. No un dato de hace seis meses. No una invención plausible.
Este artículo cuenta cómo lo conseguimos. O más precisamente, cómo fracasamos varias veces antes de conseguirlo, porque el camino estuvo lleno de decisiones equivocadas, suposiciones incorrectas y esos momentos de frustración donde te preguntas si lo que intentas es siquiera posible.
El Problema: Los LLMs No Saben Nada Sobre Aceite de Oliva
Empecemos por lo obvio. Los grandes modelos de lenguaje, los GPT, Claude, Gemma, Llama del mundo, son impresionantes. Pueden escribir poesía, explicar física cuántica, generar código funcional. Pero tienen un problema fundamental: su conocimiento está congelado en el momento en que fueron entrenados.
Si le preguntas a un LLM genérico cuál es el precio del aceite de oliva hoy, te dará una respuesta. Probablemente con mucha confianza. Y esa respuesta será completamente inventada, basada en patrones estadísticos de los textos con los que fue entrenado, no en datos reales del mercado.
Peor aún: cuanto más específica es la pregunta, más probable es que el modelo “alucine”. Preguntarle el precio medio del AOVE en Grecia la semana pasada es pedirle que genere un número que suene plausible. Y los LLMs son muy buenos generando cosas que suenan plausibles.
Nosotros teníamos algo que los LLMs no tienen: datos reales. Más de 25 años de precios históricos. Actualizaciones semanales de los cuatro principales países productores. Indicadores técnicos calculados en tiempo real. Estimaciones de precios basadas en modelos de machine learning. Datos climáticos. Información comercial. Todo esto viviendo en nuestras APIs, actualizado constantemente, listo para ser consultado.
La pregunta era: ¿cómo hacemos que un modelo de lenguaje use estos datos en lugar de inventarlos?
Primera Iteración: El Enfoque Ingenuo
Nuestra primera aproximación fue la más obvia. Usamos Gemma3 4B, un modelo pequeño que podía correr en nuestra GPU de 6GB, y construimos un sistema basado en palabras clave.
La idea era simple: si el usuario menciona “precio”, llamamos a la API de precios. Si menciona “técnico” o “RSI”, llamamos a la API de indicadores. Si menciona “clima”, llamamos a la API climática. Mapeamos cuidadosamente docenas de palabras clave a nuestras diferentes APIs y nos sentimos bastante satisfechos con nuestra solución elegante.
TOOL_KEYWORDS = {
"get_current_prices": ["precio", "precios", "cotización", "coste", "valor"],
"get_technical_indicators": ["técnico", "RSI", "MACD", "indicador", "señal"],
"get_climate_data": ["clima", "temperatura", "lluvia", "NDVI", "satélite"],
}
Funcionaba. Más o menos. Si le preguntabas “¿Cuáles son los precios actuales?”, detectaba “precios”, llamaba a la API correcta, y el modelo respondía con datos reales. Victoria.
Hasta que alguien preguntó: “¿Cómo va el mercado?”
No hay ninguna palabra clave ahí. No dice “precios”. No dice “indicadores”. Es una pregunta perfectamente razonable que cualquier usuario del sector haría, pero nuestro sistema de keywords no sabía qué hacer con ella. Así que no llamó a ninguna API. Y el modelo, sin datos reales que usar, hizo lo que hacen los LLMs cuando no tienen información: inventó una respuesta que sonaba plausible.
Ese fue el primer momento de “oh, mierda” del proyecto.
El Problema Más Profundo
El sistema de keywords tenía problemas más graves que no detectar consultas vagas. Cuando empezamos a probarlo con usuarios reales, descubrimos una lista creciente de fallos:
Las reformulaciones lo rompían. “Dame los precios” funcionaba. “¿A cuánto está el aceite?” no, porque no contenía la palabra “precio”. Los usuarios no hablan en el vocabulario exacto que habíamos definido, y esperar que lo hicieran era absurdo.
Los sinónimos eran un desastre. Habíamos añadido “cotización” como keyword, pero no “cotizaciones” en plural. “Valor” estaba, pero no “valoración”. Cada vez que un usuario usaba una palabra que no habíamos anticipado, el sistema fallaba silenciosamente.
Las combinaciones de datos eran imposibles de manejar. Si alguien preguntaba “Compárame los precios de España e Italia con sus indicadores técnicos”, ¿qué keywords disparaba? ¿Precios? ¿Técnico? ¿Ambos? ¿Y cómo sabía el sistema que necesitaba datos de dos países específicos, no de todos?
Y el peor problema: el modelo no podía razonar sobre qué datos necesitaba. Nosotros habíamos hardcodeado las asociaciones entre palabras y APIs. Pero un asistente realmente útil debería poder pensar: “El usuario está preguntando si debería comprar ahora. Para responder eso, necesito saber los precios actuales, las tendencias recientes y quizás las predicciones futuras.” Nuestro sistema no podía hacer eso. Era un sistema de reglas disfrazado de IA.
Segunda Iteración: Corrigiendo los Datos
Antes de abordar el problema del razonamiento, teníamos que solucionar algo más básico: los datos que estábamos usando estaban mal.
Suena vergonzoso admitirlo, pero habíamos conectado Olivia a las APIs equivocadas. Estábamos usando precios diarios de Infaoliva, que son datos del mercado español, cuando deberíamos haber usado los precios semanales de la Comisión Europea, que cubren todos los países mediterráneos. Además, los precios venían en céntimos por kilo y nosotros los mostrábamos sin convertir, así que un precio de 439 céntimos aparecía como “439 euros por kilo”, un error de 100x que habría sido catastrófico si alguien hubiera tomado decisiones basándose en eso.
También nos faltaba conectar las estimaciones de machine learning. Teníamos modelos que predecían precios futuros con intervalos de confianza, una de las funcionalidades más valiosas de Olearia Intelligence, y Olivia no podía acceder a ellos.
Pasamos una semana solo corrigiendo estos problemas de plomería. No era trabajo glamuroso. Revisar endpoints, ajustar conversiones de unidades, añadir nuevas herramientas. Pero era trabajo necesario. Un asistente que da datos incorrectos es peor que inútil: es activamente dañino.
# ANTES: Usaba la API incorrecta
response = await client.get(f"{API_BASE}/daily/prices/current")
# DESPUÉS: Usa la API correcta con conversión de unidades
response = await client.get(f"{API_BASE}/weekly/eu-prices/current")
for item in data:
result.append({
"pais": item.get("country"),
"aove_price_eur_kg": round(item.get("aove_price", 0) / 100, 2), # Céntimos a euros
})
Lección aprendida: antes de preocuparte por la inteligencia de tu IA, asegúrate de que los datos que usa son correctos. Parece obvio. No lo fue.
Tercera Iteración: Cambio de Modelo
Con los datos corregidos, volvimos al problema del razonamiento. Necesitábamos un modelo que pudiera decidir por sí mismo qué herramientas llamar, no uno que dependiera de nuestras reglas hardcodeadas.
Aquí es donde entra el concepto de “tool calling” o “function calling”. Algunos modelos de lenguaje modernos han sido entrenados específicamente para reconocer cuándo necesitan llamar a funciones externas y generar los parámetros correctos para esas llamadas. En lugar de simplemente generar texto, pueden generar instrucciones estructuradas como “llama a get_current_prices con el parámetro country=‘IT’”.
Gemma3 4B, el modelo que estábamos usando, tenía soporte limitado para esto. Podía hacerlo, pero no de forma nativa. Teníamos que usar prompts elaborados que a menudo fallaban, con el modelo generando JSON malformado o ignorando completamente las instrucciones de llamar herramientas.
Después de investigar, decidimos cambiar a Qwen2.5 7B. Es un modelo más grande, casi el doble de parámetros, lo que significaba que estábamos al límite de nuestra GPU de 6GB. Pero tenía algo crucial: soporte nativo para tool calling. El modelo había sido entrenado específicamente para esta tarea, no era un hack sobre un modelo de texto general.
El cambio fue significativo. No solo en términos de rendimiento, sino en cómo teníamos que pensar sobre el sistema. Ya no estábamos tratando de engañar a un modelo de texto para que hiciera algo que no estaba diseñado para hacer. Estábamos usando una herramienta para su propósito previsto.
Cuarta Iteración: Arquitectura de Dos Fases
Con Qwen2.5, reimplementamos completamente la lógica de Olivia. El nuevo sistema funciona en dos fases:
Fase 1: El modelo decide. Le damos al modelo la pregunta del usuario junto con una lista de herramientas disponibles y sus descripciones. El modelo genera un JSON indicando qué herramientas necesita llamar y con qué parámetros.
Fase 2: Ejecutamos y el modelo interpreta. Llamamos a las APIs indicadas, recogemos los datos reales, y se los pasamos de vuelta al modelo. Ahora, con información concreta en mano, el modelo genera una respuesta para el usuario.
# FASE 1: El modelo razona sobre qué datos necesita
first_response = await client.post(
f"{OLLAMA_BASE_URL}/api/chat",
json={"model": "qwen2.5:7b", "messages": messages}
)
tool_calls = parse_tool_calls(first_response)
# Ejecutar las herramientas que el modelo decidió
for call in tool_calls:
result = await execute_tool(call["name"], call["arguments"])
tool_results.append(result)
# FASE 2: El modelo interpreta los datos y responde
messages.append({"role": "assistant", "content": tool_results_str})
final_response = await generate_interpretation(messages)
Esto cambiaba fundamentalmente lo que Olivia podía hacer. Ahora, cuando alguien preguntaba “¿Cómo va el mercado?”, el modelo podía razonar: “Esta es una pregunta general sobre el estado del mercado. Necesito precios actuales para saber dónde estamos, e indicadores técnicos para saber la tendencia.” Y llamaba a ambas APIs.
Cuando preguntaban “¿Debería comprar ahora?”, el modelo razonaba: “Esto requiere precios actuales para contexto, indicadores técnicos para la tendencia, y estimaciones de precios para saber hacia dónde podría ir el mercado.” Tres llamadas a APIs, combinadas para dar una respuesta útil.
El modelo estaba haciendo algo que nuestro sistema de keywords nunca podría haber hecho: pensar sobre qué información necesitaba antes de responder.
El Bug de las Llaves
Por supuesto, nada funcionó al primer intento.
El primer error que encontramos después de implementar el nuevo sistema fue críptico: KeyError: '"tool_calls"'. El código Python se quejaba de que no encontraba una clave en un diccionario. Pero la clave estaba claramente ahí. ¿Qué estaba pasando?
Después de una hora de debugging, encontramos el problema. Nuestro system prompt incluía ejemplos de JSON para enseñar al modelo el formato correcto:
Para llamar una herramienta, responde con este formato:
{"tool_calls": [{"name": "get_current_prices", "arguments": {}}]}
El problema: estábamos usando el método .format() de Python para insertar variables en el prompt. Y .format() interpreta las llaves {} como placeholders para variables. Así que cuando Python veía {"tool_calls"..., intentaba reemplazarlo con una variable que no existía.
La solución era ridículamente simple: escapar las llaves con doble llave.
# ANTES (error)
{"tool_calls": [{"name": "get_current_prices", "arguments": {}}]}
# DESPUÉS (funciona)
{{"tool_calls": [{{"name": "get_current_prices", "arguments": {{}}}}]}}
Es el tipo de bug que te hace sentir estúpido una vez que lo encuentras. Pero también es el tipo de bug que no aparece en ningún tutorial, que solo descubres cuando estás en las trincheras tratando de hacer que algo funcione.
Quinta Iteración: Enseñando con Ejemplos
El sistema de dos fases funcionaba, pero no perfectamente. Algunas consultas seguían sin activar las herramientas correctas.
“¿Va a subir el precio?” era la más frustrante. Era exactamente el tipo de pregunta para la que habíamos construido las estimaciones de ML. Pero el modelo a veces respondía con generalidades sobre el mercado sin consultar los datos de predicción.
“¿Debería comprar ahora?” a veces llamaba solo a precios, sin indicadores ni estimaciones. El modelo no estaba combinando fuentes de datos de la forma que necesitábamos.
La solución fue añadir ejemplos explícitos al prompt. Muchos ejemplos. Específicos. Concretos.
EJEMPLOS DE CONSULTAS Y QUÉ HERRAMIENTAS USAR:
1. "Precios actuales" → get_current_prices
2. "Comparar ES e IT" → get_current_prices + get_technical_indicators
3. "¿Cómo va el mercado?" → get_current_prices + get_technical_indicators
4. "¿Debería comprar/vender ahora?" → get_current_prices + get_technical_indicators + get_price_estimates
5. "¿Cuánto subirá/bajará el precio?" → get_price_estimates + get_current_prices
6. "Predicciones" / "Estimaciones" → get_price_estimates
7. "¿Qué tal los olivares?" → get_climate_data + get_phenological_stage
8. "Análisis completo de España" → 5 herramientas combinadas
Esto puede parecer volver al enfoque de keywords, pero hay una diferencia crucial. No estamos hardcodeando reglas. Estamos enseñando al modelo patrones. El modelo sigue teniendo que razonar sobre cada consulta nueva, pero ahora tiene ejemplos de referencia que le ayudan a generalizar.
Fue como la diferencia entre darle a alguien una lista de instrucciones rígidas versus mostrarle varios ejemplos y dejar que aprenda el patrón. El segundo enfoque es más flexible, más robusto ante variaciones.
También añadimos reglas explícitas para casos problemáticos:
REGLAS CRÍTICAS:
1. SIEMPRE que el usuario pregunte sobre comprar, vender o invertir,
usa get_current_prices + get_technical_indicators + get_price_estimates
2. Para preguntas vagas como "¿cómo va?", interpreta qué datos son
relevantes y llama las herramientas apropiadas
3. NUNCA respondas sobre precios o tendencias sin llamar herramientas primero
Esa última regla era quizás la más importante. Le decíamos explícitamente al modelo que no inventara. Que si no tenía datos, los buscara primero.
Verificando que Funciona
Después de todas estas iteraciones, necesitábamos validar que el sistema realmente funcionaba. No bastaba con que pareciera funcionar. Necesitábamos pruebas sistemáticas.
Construimos una batería de consultas de prueba, desde las más directas hasta las más ambiguas, y verificamos que cada una activara las herramientas correctas:
| Consulta | Herramientas Esperadas | Resultado |
|---|---|---|
| ”Precios de España, Italia, Grecia y Portugal con indicadores” | prices + 4x technical | ✅ |
| “¿Cómo afecta el clima a las exportaciones?“ | climate + trade | ✅ |
| “Dame estimaciones ML de precios” | estimates | ✅ |
| “Análisis completo de España” | 5 herramientas | ✅ |
| “¿Cómo va el mercado?“ | prices + technical | ✅ |
| “¿Debería comprar ahora?“ | prices + technical + estimates | ✅ |
| “¿Va a subir el precio?“ | prices + estimates | ✅ |
| “Hola Olivia” | Ninguna (es un saludo) | ✅ |
El 95% de las consultas funcionaban correctamente. No era perfecto. Pero era dramáticamente mejor que el sistema de keywords, que fallaba en cualquier cosa que se saliera de nuestro vocabulario predefinido.
También verificamos la precisión de los datos. Comparamos lo que Olivia decía con los datos crudos de las APIs:
| País | API (€/100kg) | Olivia (€/kg) | ¿Conversión correcta? |
|---|---|---|---|
| España AOVE | 439.02 | 4.39 | ✅ |
| Italia AOVE | 690.00 | 6.90 | ✅ |
| Grecia AOVE | 459.16 | 4.59 | ✅ |
| Portugal AOVE | 440.00 | 4.40 | ✅ |
Los datos eran correctos. Las conversiones de unidades funcionaban. El modelo no estaba inventando números.
El Coste del Razonamiento
Todo esto viene con un coste. El sistema de keywords era casi instantáneo: detectaba palabras, hacía llamadas, respondía en un par de segundos. El nuevo sistema es significativamente más lento.
Nuestras métricas actuales:
- Tiempo para que el modelo decida qué herramientas usar: 5-10 segundos
- Tiempo para ejecutar las llamadas a APIs: 1-2 segundos
- Tiempo para que el modelo interprete los datos y genere la respuesta: 15-30 segundos
- Tiempo total típico: 20-45 segundos
Para un chatbot genérico, 45 segundos sería inaceptable. Pero para un asistente especializado que está consultando múltiples fuentes de datos y sintetizando información real, creemos que es un tradeoff razonable. Preferimos una respuesta correcta en 30 segundos que una invención instantánea.
También estamos al límite de nuestra GPU. Qwen2.5 7B usa casi 5GB de los 6GB disponibles. No hay mucho margen para modelos más grandes. Si quisiéramos mejorar la velocidad o la calidad usando modelos más potentes, necesitaríamos mejor hardware.
Lo que Aprendimos Construyendo Esto
Si tuviera que destilar las lecciones de este proceso en unas pocas ideas, serían estas:
Los LLMs son herramientas de razonamiento, no bases de datos. El error más común que vemos es usar LLMs como si supieran cosas. No saben nada. Son muy buenos razonando sobre información que les das, pero terrible recordando hechos específicos. Úsalos para lo primero, no para lo segundo.
El tool calling cambia las reglas del juego. La capacidad de un modelo de decidir qué funciones llamar, cuándo, y con qué parámetros, transforma lo que puedes construir. Convierte a un modelo de texto en el cerebro de un sistema que puede interactuar con el mundo real.
Los ejemplos son más poderosos que las reglas. Intentamos durante semanas definir reglas perfectas para cuándo llamar cada herramienta. Nunca funcionó bien. Lo que funcionó fue dar al modelo suficientes ejemplos para que aprendiera el patrón por sí mismo.
La ingeniería de prompts es ingeniería real. Hay una tendencia a ver el trabajo con prompts como algo menor, no tan serio como escribir código. Pero la diferencia entre un prompt que funciona y uno que no puede ser tan sutil como una palabra mal puesta. Es trabajo de ingeniería que requiere iteración, testing y rigor.
Los datos correctos importan más que el modelo sofisticado. Podríamos haber usado el modelo más avanzado del mundo, y habría dado respuestas incorrectas si las APIs que llamaba devolvían datos erróneos. Arreglar la plomería de datos fue menos emocionante que trabajar en el modelo, pero fue igualmente importante.
Dónde Estamos y Hacia Dónde Vamos
Hoy, Olivia puede responder preguntas sobre precios actuales de los cuatro principales países productores, indicadores técnicos del mercado, estimaciones de precios basadas en machine learning, datos climáticos, información comercial, costes de producción, variedades de aceitunas, plagas y enfermedades, y estados fenológicos.
Diez herramientas en total, cada una conectada a datos reales de nuestras APIs. Cuando un usuario pregunta algo, Olivia razona sobre qué información necesita, la busca, la combina y la presenta de forma comprensible.
No es perfecto. Hay preguntas que todavía no maneja bien. Hay momentos donde el modelo toma decisiones subóptimas sobre qué herramientas llamar. Hay ocasiones donde la interpretación de los datos podría ser más clara o más profunda.
Pero funciona. Y más importante: no inventa.
Para el futuro tenemos una lista larga de mejoras pendientes. Queremos añadir más herramientas: datos satelitales por región específica, precios de energía que afectan los costes de producción, tipos de cambio, precios de commodities competidores como la soja o el girasol. Queremos implementar memoria de conversación para que Olivia recuerde el contexto de preguntas anteriores. Queremos que sea proactiva, que pueda alertar cuando detecte algo inusual en los datos.
Pero esas son mejoras incrementales sobre un sistema que funciona. La arquitectura básica está resuelta. El problema de “¿cómo hacemos que un LLM use datos reales en lugar de inventarlos?” tiene una respuesta que funciona en producción.
El Punto Más Importante
Si hay algo que queremos que la gente se lleve de este artículo, es esto: la IA especializada es diferente de la IA general.
Los asistentes de propósito general como ChatGPT o Claude son impresionantes, pero tienen limitaciones inherentes cuando se trata de dominios específicos. No saben los precios del aceite de oliva esta semana. No pueden analizar las tendencias del mercado griego. No tienen acceso a modelos de predicción entrenados con décadas de datos históricos.
Para construir algo que realmente sea útil en un dominio especializado, tienes que hacer el trabajo duro de conectar el razonamiento del LLM con datos reales, actualizados, verificables. Tienes que construir las herramientas, las APIs, los pipelines de datos. Tienes que enseñar al modelo cuándo usar cada herramienta y cómo interpretar los resultados.
Es más trabajo que simplemente usar un chatbot genérico. Pero el resultado es algo cualitativamente diferente: un asistente que realmente sabe de lo que habla, porque tiene acceso a información que ningún modelo pre-entrenado podría tener.
Eso es lo que estamos construyendo con Olivia. No un chatbot que suena inteligente. Un asistente que lo es, dentro de su dominio, porque tiene las herramientas para serlo.
¿Estás construyendo sistemas de IA especializados? ¿Te enfrentas a problemas similares de conectar LLMs con datos reales? Nos encantaría saber de ti. Escríbenos - siempre aprendemos de estas conversaciones.
Y si trabajas en el sector oleícola y quieres probar Olivia cuando esté disponible públicamente, puedes solicitar acceso anticipado.
Artículos Relacionados
Continúa explorando más contenido sobre Tecnología
Cómo Estamos Construyendo Olearia Intelligence: Lecciones del Camino
Reflexiones sobre el desarrollo de un producto de datos complejo. Los errores que cometimos, las decisiones que acertamos y lo que estamos aprendiendo en el proceso.
Estimaciones de Precios en el Mercado Europeo del Aceite: Lo Que Aprendimos Construyendo las Nuestras
El mercado oleícola europeo tiene un problema conocido: los datos oficiales llegan tarde. Esto es lo que descubrimos cuando decidimos abordarlo de forma sistemática.
Tu Móvil Ya Es Más Inteligente Que el Superordenador de 2020 (Y Eso Es Solo El Principio)
Los NPUs en smartphones alcanzan hasta 47 TOPS y ejecutan modelos que hace apenas tres años requerían datacenters completos. Análisis de la revolución Edge AI que está transformando cómo interactuamos con la inteligencia artificial en 2025.
¿Te ha gustado este artículo?
Recibe más contenido como este directamente en tu correo. Guías prácticas y las últimas innovaciones en IA empresarial.
Sin spam
Datos protegidos