{"id":239652,"date":"2026-06-23T23:38:55","date_gmt":"2026-06-23T23:38:55","guid":{"rendered":"https:\/\/felipenespralsanchez.tech\/blog\/?p=239652"},"modified":"2026-06-15T23:43:08","modified_gmt":"2026-06-15T23:43:08","slug":"ia-embebida-en-un-producto-real-lo-que-aprendimos-en-una-escuela-de-cocina-online","status":"publish","type":"post","link":"https:\/\/felipenespralsanchez.tech\/blog\/ia-embebida-en-un-producto-real-lo-que-aprendimos-en-una-escuela-de-cocina-online\/","title":{"rendered":"IA embebida en un producto real: lo que aprendimos en una escuela de cocina online"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Ten\u00edamos una escuela de cocina online con 1.404 recetas, men\u00fas semanales y miembros activos cocinando cada d\u00eda. El problema no era falta de contenido: era que el usuario ten\u00eda el men\u00fa delante y no siempre sab\u00eda c\u00f3mo ejecutarlo. Ah\u00ed decidimos integrar IA en la plataforma web, pero con una premisa clara desde el principio: la IA ten\u00eda que vivir dentro del flujo del usuario, no ser una herramienta aparte a la que vas cuando te acuerdas.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">No lo hicimos porque la IA estuviera de moda. Lo hicimos porque hab\u00eda un hueco real entre tener la receta y saber cocinarla, y un asistente con el contexto adecuado lo tapaba mejor que cualquier FAQ o v\u00eddeo. Este art\u00edculo es qu\u00e9 construimos, las decisiones que tomamos y lo que aprendimos por el camino.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">El asistente de cocina conversacional<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">El usuario abre su men\u00fa de la semana y tiene delante las recetas, los totales nutricionales y la gu\u00eda de batch cooking. Lo que le falta no es informaci\u00f3n, es alguien a quien preguntarle \u00ab\u00bfesto lo puedo doblar para cuatro?\u00bb o \u00ab\u00bfqu\u00e9 hago si no tengo el ingrediente X?\u00bb. Ese es el hueco que llena el asistente.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">La pieza que lo hace funcionar es el contexto. Cuando el usuario abre el chat desde un men\u00fa, no arranca una conversaci\u00f3n en blanco: le inyectamos autom\u00e1ticamente el contexto de ese men\u00fa \u2014las recetas, los totales nutricionales, la gu\u00eda de batch\u2014 sin que el usuario tenga que explicarle nada al modelo. Pregunta \u00ab\u00bfcu\u00e1nto tardo en hacer esto?\u00bb y el asistente ya sabe qu\u00e9 es \u00abesto\u00bb. Sin ese contexto, el modelo es un cocinero gen\u00e9rico de internet; con \u00e9l, es el asistente de tu men\u00fa concreto.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">El historial persiste por men\u00fa, as\u00ed que la conversaci\u00f3n de esta semana no se mezcla con la de la anterior. Y las respuestas se adaptan al programa del usuario: no es lo mismo aconsejar a alguien en un plan hipocal\u00f3rico que a alguien en uno terap\u00e9utico. El mismo asistente, distinto criterio seg\u00fan qui\u00e9n pregunta.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">El perfil silencioso del usuario<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Nadie rellena formularios de onboarding. Lo sabes, yo lo s\u00e9, y nuestros usuarios tambi\u00e9n: si les pones diez campos para \u00abpersonalizar tu experiencia\u00bb, los abandonan. As\u00ed que decidimos no pedir el perfil. Que se construyera solo.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">El asistente aprende mientras conversa. Si el usuario menciona que cocina para cuatro, que es intolerante a algo o que no tiene mucha mano en la cocina, eso se guarda en su perfil sin que rellene nada. La personalizaci\u00f3n crece con cada conversaci\u00f3n, sin fricci\u00f3n y sin un formulario de por medio.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u00bfC\u00f3mo? Con lo que internamente llamamos marcadores ocultos. Es el patr\u00f3n del que m\u00e1s he aprendido en este proyecto, as\u00ed que vale la pena explicarlo de verdad.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">En el system prompt le decimos al modelo que, cuando detecte cierta informaci\u00f3n, a\u00f1ada un marcador especial al final de su respuesta, con un formato exacto. El usuario nunca lo ve. La respuesta que llega al backend es algo as\u00ed:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Claro, para 4 comensales puedes doblar las cantidades del guiso.\nRecuerda que con legumbres suele quedar mejor reposado.\nPERFIL_UPDATE:{\"comensales\": 4}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">El backend, en PHP, hace tres cosas: busca el marcador, extrae el JSON y lo fusiona con el perfil existente en la base de datos, y devuelve al frontend solo el texto limpio, sin el marcador. El usuario lee una respuesta de cocina normal; el sistema, en paralelo, ha aprendido que cocina para cuatro.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Lo interesante de este patr\u00f3n es que no usa function calling ni tool use de la API. El modelo habla en texto plano y nosotros parseamos ese texto. Y es el modelo quien decide cu\u00e1ndo activarlo: no hay l\u00f3gica de triggers en el cliente buscando palabras clave. Si el usuario menciona algo relevante, el modelo lo detecta solo, porque el system prompt se lo ense\u00f1\u00f3. La conversaci\u00f3n es asim\u00e9trica: el usuario ve charla natural, el servidor ve charla m\u00e1s comandos estructurados.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Tiene un riesgo real, y lo aprendimos a base de verlo: el modelo puede alucinar el marcador en el momento equivocado, o formatearlo mal y romperte el parse. La defensa es ser obsesivamente expl\u00edcito en el system prompt sobre el formato exacto y sobre cu\u00e1ndo usarlo. Cada ambig\u00fcedad que dejas, el modelo la rellena a su manera.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Generaci\u00f3n de contenido para producci\u00f3n<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">El asistente conversacional es la cara visible de la IA, pero buena parte del trabajo del modelo no se ve. Lo usamos tambi\u00e9n para generar contenido estructurado que alimenta la producci\u00f3n de la plataforma.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">El generador de men\u00fas semanales es interno: el modelo arma propuestas de men\u00fa que luego se revisan, no algo que el usuario toque directamente. La gu\u00eda de batch cooking se genera convirtiendo un men\u00fa en instrucciones de cocinado eficiente \u2014qu\u00e9 preparar a la vez, qu\u00e9 adelantar\u2014. Y la gu\u00eda interactiva de receta es un paso a paso que se monta din\u00e1micamente en lugar de estar escrito a mano para cada una de las 1.404 recetas.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">De ah\u00ed salen tambi\u00e9n los PDFs. Generamos un HTML en el servidor, partiendo del mismo men\u00fa, con el contenido que aporta el modelo, y ese HTML es el que se imprime. El reto no fue la IA en s\u00ed, sino el puente: montar un HTML limpio y listo para impresi\u00f3n a partir del men\u00fa y de lo que devuelve el modelo, de forma que el documento final salga consistente cada vez. La IA pone el contenido; la estructura del PDF la pone el HTML que controlamos nosotros.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Reconocimiento de im\u00e1genes: hacia d\u00f3nde vamos<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Esta parte todav\u00eda no est\u00e1 cerrada, pero la direcci\u00f3n est\u00e1 clara y la cuento porque es de lo m\u00e1s prometedor que tenemos entre manos.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">La idea: el usuario fotograf\u00eda su nevera o la etiqueta de un producto, el modelo identifica los ingredientes, y el sistema busca en nuestra base recetas compatibles con lo que hay. Es el puente entre la visi\u00f3n artificial y nuestra propia base de datos de recetas, que es justo lo que un modelo gen\u00e9rico no puede hacer solo.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">El patr\u00f3n previsto reutiliza los marcadores ocultos. Si el modelo identifica ingredientes concretos en la foto, a\u00f1ade un marcador tipo <code>BUSCAR: ingrediente1, ingrediente2<\/code> en su respuesta. El backend lo intercepta, lanza la b\u00fasqueda en la base de recetas, y devuelve al frontend el texto del modelo m\u00e1s tarjetas de receta generadas por el servidor, como si el asistente las hubiera tra\u00eddo \u00e9l mismo. El usuario vive una experiencia fluida; por debajo, es el mismo truco de antes aplicado a visi\u00f3n.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Est\u00e1 a medias. Pero el hecho de que encaje en un patr\u00f3n que ya ten\u00edamos funcionando es la mejor se\u00f1al de que la arquitectura iba bien encaminada.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Lo que aprendimos<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">El contexto lo es todo. Un modelo sin el contexto nutricional y de men\u00fa no sirve para nada en este dominio: te da consejos de cocina gen\u00e9ricos que el usuario ya encuentra en Google. Todo el valor est\u00e1 en lo que le inyectamos antes de que responda. La IA no fue la parte dif\u00edcil; decidir qu\u00e9 contexto darle y cu\u00e1ndo, s\u00ed.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Los marcadores ocultos resultaron ser un patr\u00f3n m\u00e1s general de lo que pens\u00e1bamos: una forma de que el modelo le hable al sistema sin que el usuario se entere, en texto plano y sin atarte al tool use de un proveedor concreto. Eso \u00faltimo importa m\u00e1s de lo que parece: como el modelo solo produce texto, ma\u00f1ana podemos cambiar de modelo o mezclar varios sin reescribir el mecanismo. De hecho, el chat de atenci\u00f3n al cliente que tenemos en el horizonte va a usar otro modelo distinto, y el patr\u00f3n sigue valiendo igual.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Y la lecci\u00f3n que m\u00e1s me cost\u00f3 interiorizar: la IA no reemplaza la estructura de datos. Sin las 1.404 recetas bien modeladas, sin la base de ingredientes, sin los men\u00fas estructurados, nada de esto funciona. El modelo es el que conversa y el que redacta, pero lo que tiene valor de verdad es la base de datos que hay debajo. La IA la hace accesible; no la sustituye.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">D\u00f3nde estamos y qu\u00e9 viene<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Empezamos con una plataforma llena de contenido que el usuario no siempre sab\u00eda aprovechar. Ahora tiene un asistente que conoce su men\u00fa, un perfil que se construye solo mientras cocina, y contenido generado a medida para cada semana.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Lo que viene: afinar c\u00f3mo captamos los datos del usuario para que el perfil sea a\u00fan m\u00e1s preciso, cerrar el reconocimiento de im\u00e1genes, y montar el chat de atenci\u00f3n al cliente. Tambi\u00e9n queremos mejorar el sistema de comentarios. Ninguna de esas piezas es un salto al vac\u00edo: todas se apoyan en lo que ya construimos, que era exactamente la idea \u2014una base sobre la que seguir sumando, no una demo que impresiona y luego no escala.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Integramos IA en una escuela de cocina online con 1.404 recetas: un asistente que conoce tu men\u00fa, un perfil que se construye solo mientras conversas y contenido generado para producci\u00f3n. Estas son las decisiones t\u00e9cnicas y lo que aprendimos: por qu\u00e9 el contexto lo es todo y el patr\u00f3n de marcadores ocultos para que el modelo le hable al sistema sin que el usuario lo vea.<\/p>\n","protected":false},"author":1,"featured_media":239653,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1,27],"tags":[202,206,33,204,35],"class_list":["post-239652","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog","category-desarrollo-web","tag-claude","tag-desarrollo-de-producto","tag-ia","tag-llm","tag-php"],"_links":{"self":[{"href":"https:\/\/felipenespralsanchez.tech\/blog\/wp-json\/wp\/v2\/posts\/239652","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/felipenespralsanchez.tech\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/felipenespralsanchez.tech\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/felipenespralsanchez.tech\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/felipenespralsanchez.tech\/blog\/wp-json\/wp\/v2\/comments?post=239652"}],"version-history":[{"count":1,"href":"https:\/\/felipenespralsanchez.tech\/blog\/wp-json\/wp\/v2\/posts\/239652\/revisions"}],"predecessor-version":[{"id":239654,"href":"https:\/\/felipenespralsanchez.tech\/blog\/wp-json\/wp\/v2\/posts\/239652\/revisions\/239654"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/felipenespralsanchez.tech\/blog\/wp-json\/wp\/v2\/media\/239653"}],"wp:attachment":[{"href":"https:\/\/felipenespralsanchez.tech\/blog\/wp-json\/wp\/v2\/media?parent=239652"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/felipenespralsanchez.tech\/blog\/wp-json\/wp\/v2\/categories?post=239652"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/felipenespralsanchez.tech\/blog\/wp-json\/wp\/v2\/tags?post=239652"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}