Módulo 2: El cerebro del agente: modelo y system prompt
6. Parámetros del modelo y salida estructurada
Descripción
Al terminar esta cápsula vas a poder ajustar dos parámetros de muestreo del modelo —temperatura y límite de tokens— y, sobre todo, vas a poder forzar que tu agente devuelva un JSON con una forma fija en vez de un párrafo de prosa, para que el nodo que sigue en el flujo pueda leer los datos directamente en lugar de tener que interpretarlos.
Esto no es un capricho de prolijidad. En la lección 2 armaste, sobre el papel, un agente que recibe tickets de soporte de una tienda en línea, clasifica su urgencia y redacta un borrador de respuesta —5,000 tickets al mes, corriendo en segundo plano—. Si ese agente responde con algo como "Este ticket parece urgente, yo diría prioridad alta, aquí va un borrador de respuesta: …", ningún nodo posterior puede decidir automáticamente si el ticket entra a la cola de escalamiento o no —alguien tendría que leerlo primero—. Si en cambio responde {"urgency": 4, "category": "billing", "draft_reply": "..."}, un simple nodo IF lo rutea con una condición, sin que ninguna persona lo haya leído todavía.
Conexión con el módulo: la lección anterior fijó el contrato de comportamiento del agente —quién es, qué no debe hacer, cómo debería responder— a través del system prompt. Esa instrucción, sin embargo, es un pedido en lenguaje natural: el modelo puede seguirla la mayoría de las veces y desviarse justo cuando más te importa que no lo haga. Aquí vas a agregar la pieza que impone y valida la forma exacta de la respuesta, además de los controles que deciden qué tan predecible es esa respuesta y cuánto puede llegar a escribir.
Cuánto se arriesga el modelo y hasta dónde puede escribir
Piensa en un traductor simultáneo trabajando en vivo, palabra por palabra. Frente a una expresión ambigua, un traductor cauteloso elige siempre la traducción más obvia y más usada —nunca sorprende, pero tampoco se equivoca de forma llamativa—. Uno más arriesgado, en cambio, a veces prueba un sinónimo menos común buscando más matiz, y de vez en cuando esa apuesta sale mal y cambia el sentido de lo que se dijo.
Un modelo de lenguaje elige su próxima palabra —en rigor, su próximo token— de una manera parecida: en cada paso calcula qué tan probable es cada opción posible y después decide cuál usar. La temperatura es el parámetro que controla cuánto se apega a la opción más probable. Cerca de 0, el modelo elige casi siempre el token de mayor probabilidad —respuestas más predecibles y repetibles, aunque Anthropic aclara en su propia documentación que ni siquiera con temperatura 0 el resultado queda completamente determinista—. Conforme subes el valor, el modelo empieza a arriesgarse con tokens menos probables: respuestas más variadas, y también más chance de que se desvíen de lo que esperabas.
En n8n, este parámetro no vive en el nodo AI Agent —vive en el nodo de modelo que conectaste al puerto Chat Model (Anthropic Chat Model, OpenAI Chat Model, el que corresponda). Ábrelo y, en su sección Options (el botón "Add Option"), agrega Sampling Temperature. En el nodo Anthropic Chat Model el rango va de 0 a 1, con 0.7 como valor por defecto; en el nodo OpenAI Chat Model el rango llega hasta 2, también con 0.7 por defecto. El número en sí no es comparable de un proveedor a otro —0.7 en Anthropic y 0.7 en OpenAI no representan el mismo "nivel de riesgo", porque las escalas tienen distinto largo—, pero el criterio para elegirlo sí es el mismo: cerca de 0 para tareas donde una respuesta rara sale cara (clasificar, extraer datos, decidir un monto), más arriba para tareas donde la variedad suma (redactar, generar variantes de un mensaje).
Hay una excepción que conviene conocer antes de confiar ciegamente en este parámetro. Si conectaste uno de los tiers más nuevos de Anthropic —Claude Sonnet 5, Claude Opus 4.7 o superiores, que corren con razonamiento extendido activo por defecto—, Sampling Temperature sigue apareciendo en el panel de opciones, pero el proveedor lo ignora. El propio texto de ayuda del campo, dentro del nodo, lo advierte: "Not supported on newer Anthropic models (Claude Opus 4.7+, Claude Sonnet 5+) — ignored there". Lo mismo pasa con Top K y Top P en esa generación. El control real de cuánto "se arriesga" ese modelo pasó a ser el modo de razonamiento del modelo —un parámetro llamado Effort (bajo, medio, alto), que excede el objetivo de esta lección—, no un parámetro de muestreo clásico. Es la misma disciplina que viste en la lección 2 con los IDs de modelo retirados: antes de asumir que un campo hace algo, confirma contra la descripción vigente de ese campo para el modelo que tienes conectado.
La segunda opción en ese mismo panel es Maximum Number of Tokens —por dentro se llama maxTokensToSample en el nodo Anthropic, con 4096 como valor por defecto, y maxTokens en el nodo OpenAI, por defecto en -1, es decir, sin tope propio del lado de n8n, hasta el máximo que el modelo permita—. No confundas este límite con el tamaño de lo que el modelo puede leer, su ventana de contexto: maxTokens topea solo la respuesta, cuánto puede generar el modelo antes de que n8n lo corte a la fuerza. Si ese tope queda demasiado bajo para lo que le pides, la respuesta se corta a la mitad —literalmente en medio de una palabra o de una llave de cierre—, y si esa respuesta era un JSON, el corte la vuelve inválida antes de que llegue a ningún parser.
Un dato aparte, para que no te sorprenda: la API de Anthropic exige max_tokens en cada llamada —es un parámetro obligatorio del lado del proveedor—, por eso el nodo Anthropic Chat Model siempre manda un valor (4096 si no tocas nada) aunque tú no hayas configurado la opción. OpenAI no lo exige, y por eso n8n lo deja en -1 por defecto en ese nodo.
Del párrafo libre al formulario: forzar una salida estructurada
Pídele a alguien que te cuente sobre un producto en una hoja en blanco, y te va a escribir un párrafo —capaz que hasta bien redactado—, pero para sacar el precio y el stock vas a tener que leerlo entero. Dale, en cambio, un formulario con casillas —Precio: ___, Stock: ___, Categoría: ___— y esa persona llena exactamente esos campos: tú lees el dato, no interpretas un texto.
La salida estructurada es darle al agente ese formulario: en vez de dejarlo redactar libre, defines un esquema —un JSON con campos y tipos fijos— y n8n valida que la respuesta calce con ese esquema antes de pasarla al siguiente nodo. Esto es distinto de pedirle en el system prompt que "responda en JSON", que fue lo que viste en la lección anterior: esa instrucción es un pedido en lenguaje natural, tan fuerte como el resto del prompt y tan propenso a que el modelo lo ignore a mitad de una respuesta larga. Lo que armas acá es una pieza mecánica conectada al agente, que revisa la respuesta después de que el modelo la generó.
En el nodo AI Agent, esta pieza se activa con la opción Require Specific Output Format, un interruptor que viene apagado por defecto. Al activarlo, aparece un aviso para conectar un output parser en el lienzo: un puerto nuevo en la parte inferior del nodo, llamado Output Parser, junto a Chat Model, Memory y Tool. Ahí conectas el nodo Structured Output Parser. Con el interruptor apagado —el valor por defecto—, el agente devuelve un string plano en $json.output; con el interruptor prendido y el parser conectado, ese mismo campo deja de ser texto libre y pasa a ser el objeto que definiste.
En el Structured Output Parser eliges, en el campo Schema Type, cómo describir ese objeto: Generate From JSON Example —le das un JSON de muestra y n8n infiere el esquema solo, tratando cada campo del ejemplo como obligatorio— o Define using JSON Schema, donde escribes el esquema a mano siguiendo la especificación estándar, con una limitación real: no soporta la sintaxis $ref, así que si tu esquema referencia otro esquema externo, el tipo puede no llegar bien. Para la mayoría de los agentes que armas en n8n, "Generate From JSON Example" alcanza y es más rápido de escribir.
Ejemplo trabajado
Vamos a retomar el agente de tickets de soporte de la lección 2 —el que clasifica urgencia y redacta un borrador— y forzar que su salida sea un JSON con tres campos: urgency (número del 1 al 5), category (texto) y draft_reply (el borrador). Para el Chat Model usamos Claude Haiku 4.5: es coherente con el volumen alto y la tarea acotada que viste en la lección 2, y —a diferencia de Sonnet 5— es una generación donde Sampling Temperature todavía tiene efecto real, como acabas de ver arriba.
Paso 1 — fijar la temperatura y el límite de tokens en el modelo. Conecta un nodo Anthropic Chat Model al puerto Chat Model del agente, con el modelo claude-haiku-4-5. En Options → Add Option, agrega Sampling Temperature y ponla en 0: esta tarea clasifica y decide una prioridad, y no quieres que la misma queja, escrita casi igual dos veces, te devuelva a veces urgencia 3 y a veces urgencia 4. Deja Maximum Number of Tokens en su valor por defecto (4096): de sobra para un JSON de tres campos cortos.
Paso 2 — activar la salida estructurada en el agente. Abre el nodo AI Agent y activa Require Specific Output Format. Va a aparecer un aviso pidiéndote que conectes un output parser en el lienzo; en el puerto nuevo Output Parser, agrega un Structured Output Parser.
Paso 3 — definir el esquema. Abre el Structured Output Parser, deja Schema Type en Generate From JSON Example (el valor por defecto) y, en el campo JSON Example, escribe:
{
"urgency": 4,
"category": "billing",
"draft_reply": "Gracias por escribirnos. Ya estamos revisando el cobro duplicado y te confirmamos la devolución en menos de 24 horas."
}
n8n usa este ejemplo solo para inferir tipos —urgency como número, category y draft_reply como texto—, no para copiar estos valores literales. Los tres campos quedan obligatorios en el esquema resultante, porque así trata n8n cualquier campo generado a partir de un ejemplo.
Paso 4 — ejecutar con un ticket de prueba. Desde el Chat Trigger, envía:
Me cobraron dos veces el mismo pedido y necesito que me devuelvan el dinero cuanto antes.
Qué esperar:
{
"output": {
"urgency": 4,
"category": "billing",
"draft_reply": "Gracias por contactarnos. Detectamos el cobro duplicado en tu pedido; ya iniciamos la reversión y te confirmamos por este medio en menos de 24 horas."
}
}
El detalle que conviene marcar: la respuesta no llega en $json.urgency directamente, llega envuelta en una clave output —$json.output.urgency, $json.output.category, $json.output.draft_reply—. Es el nodo que sigue (un IF, un Set, un Postgres) el que va a leer esos tres campos por su nombre, sin que nadie tenga que interpretar una frase para saber si el ticket es urgente.
Profundización: el seguro contra un JSON que no calza
Ningún parser puede obligar al modelo a escribir bien un JSON —solo puede rechazarlo si está mal—. La opción Auto-Fix Format, dentro del mismo nodo Structured Output Parser, es el seguro para ese caso: al activarla, aparece un puerto adicional para conectar un segundo modelo de lenguaje (puede ser el mismo proveedor, o uno más económico). Si la respuesta del agente no calza con el esquema, n8n le manda ese error de vuelta a ese segundo modelo, junto con la respuesta fallida, para que la corrija —a costa de una llamada extra—. Es una capa de reintento, no una garantía absoluta: sigue siendo un modelo de lenguaje generando la corrección, así que en casos raros puede volver a fallar.
Si tu agente corre exclusivamente sobre el nodo OpenAI Chat Model con la Responses API activa —la opción por defecto en las versiones recientes del nodo—, tienes una alternativa más fuerte y específica de ese proveedor: en Options → Response Format, eliges JSON Schema (recommended) en vez de conectar un Structured Output Parser aparte. Ahí defines el esquema directamente en el nodo del modelo, con un interruptor Strict que exige que la API misma nunca entregue nada que no calce con el esquema —es una restricción a nivel de la generación del modelo, más fuerte que validar después—. La contrapartida es que solo funciona con OpenAI: si mañana cambias el Chat Model por Anthropic o por un modelo local en Ollama, esa configuración no viaja con el nodo. El Structured Output Parser conectado al puerto Output Parser del agente, en cambio, funciona igual sin importar qué modelo tengas atrás —es la opción portable, y por eso es la que usamos en el ejemplo de arriba—.
Errores comunes
Ajustar Sampling Temperature en un Claude de la generación más nueva esperando que cambie algo. Qué pasa: cambias el valor entre 0 y 1, ejecutas el mismo prompt varias veces, y no notas ninguna diferencia real en la variabilidad de las respuestas, sea cual sea el número que pongas. Por qué: como viste arriba, en Claude Sonnet 5, Claude Opus 4.7 y superiores —con razonamiento extendido activo por defecto— Anthropic ignora Sampling Temperature, Top K y Top P del lado de la API; el propio campo lo advierte en su descripción dentro de n8n. Cómo detectarlo: lee la descripción del campo (el ícono de información junto a Sampling Temperature) antes de asumir que está funcionando, o corre el mismo prompt cinco veces con el valor en 0 y luego en 1 —si las respuestas se ven igual de variables en ambos casos, el parámetro no tiene efecto—. Cómo corregirlo: para esa generación de modelos, el control real de variabilidad ya no es Sampling Temperature; si necesitas ese control fino hoy mismo, usa un modelo donde el parámetro sí aplique —Claude Haiku 4.5, o cualquier modelo de otro proveedor—.
Confundir la instrucción del prompt ("responde siempre en JSON") con la salida estructurada del parser. Qué pasa: el flujo corre bien la mayoría de las veces, pero de tanto en tanto —sobre todo en una respuesta más larga de lo normal, o con un ticket ambiguo— el modelo agrega una frase antes del JSON ("Aquí tienes la clasificación:") o lo envuelve en un bloque de código, y el nodo siguiente falla al leer un campo que nunca llegó con el formato exacto. Por qué: sin Require Specific Output Format activado y sin un Structured Output Parser conectado, esa instrucción en el system prompt es solo texto que el modelo puede seguir o no —no hay nada de tu lado validando la respuesta antes de que siga camino—. Cómo detectarlo: revisa si el AI Agent tiene Require Specific Output Format encendido y el puerto Output Parser efectivamente conectado; si está apagado o vacío, el "JSON" de tu prompt es una sugerencia, no una regla. Cómo corregirlo: activa Require Specific Output Format y conecta un Structured Output Parser con el esquema exacto que necesitas —el prompt sigue ayudando a que el modelo apunte en la dirección correcta, pero deja de ser el único control—.
Leer $json.category en vez de $json.output.category en el nodo siguiente. Qué pasa: el nodo que sigue al agente —un Set, un IF, cualquier expresión— devuelve vacío un campo que sabes que el agente sí generó bien, porque lo viste en el panel de ejecución del AI Agent. Por qué: el Structured Output Parser envuelve todo el objeto parseado dentro de una clave output —la respuesta real es { "output": { "urgency": 4, ... } }, no { "urgency": 4, ... } directamente—. Cómo detectarlo: abre el panel de salida del nodo AI Agent y mira la estructura completa del JSON, no solo los nombres de campo que definiste en el esquema; vas a ver la clave output envolviendo todo. Cómo corregirlo: referencia los campos con el prefijo completo ({{$json.output.urgency}}, {{$json.output.category}}) en cualquier nodo posterior.
Ejercicios
1. Tu system prompt ya le dice al agente "Responde siempre en el formato JSON: {urgency, category, draft_reply}". ¿Alcanza esa instrucción para garantizar que el nodo siguiente reciba siempre esos tres campos? Justifica con lo que viste en esta cápsula.
Ver solución
No alcanza. Esa instrucción es un pedido en lenguaje natural dentro del prompt —el modelo la sigue la mayoría de las veces, pero nada garantiza que no la rompa en una respuesta larga, en un caso ambiguo, o envolviendo el JSON en un bloque de código—. La garantía real viene de activar Require Specific Output Format en el AI Agent y conectar un Structured Output Parser con el esquema: eso agrega una validación mecánica después de que el modelo responde, en vez de confiar solo en que siguió la instrucción.
Por qué funciona: separar "pedirle algo al modelo" de "validar lo que devolvió" es justo la diferencia entre un prompt (lección 5) y un parser (esta lección) —el primero orienta, el segundo exige—.
2. Necesitas que el Structured Output Parser genere un esquema con estos campos: urgency (número entero del 1 al 5), category (texto) y escalate (verdadero o falso). Escribe el JSON Example que pondrías en el campo correspondiente, usando Generate From JSON Example.
Ver solución
{
"urgency": 3,
"category": "shipping",
"escalate": false
}
Por qué funciona: n8n infiere el tipo de cada campo a partir del valor de ejemplo —número para urgency, texto para category, booleano para escalate— sin que tengas que escribir un JSON Schema a mano. Los tres campos quedan obligatorios en el esquema resultante, porque así trata n8n cualquier campo generado desde un ejemplo.
3. Un colega arma el mismo agente, conecta el Structured Output Parser, y en el nodo Set que sigue escribe {{$json.category}} para leer la categoría del ticket. Al ejecutar, ese campo llega vacío, aunque en el panel de ejecución del AI Agent la categoría sí aparece bien clasificada. ¿Qué está mal?
Ver solución
Le falta el prefijo output. El Structured Output Parser envuelve el objeto que arma dentro de una clave output, así que la ruta correcta es {{$json.output.category}}, no {{$json.category}}. El dato sí llegó bien —solo que la expresión apunta a un lugar del JSON donde ese campo no existe—.
Por qué funciona: entender que el parser envuelve la respuesta evita perder tiempo revisando el prompt o el esquema cuando el problema real es solo la ruta de la expresión que lee el dato.
4 (reto). El mismo agente de tickets hace dos cosas en una sola llamada: clasifica la urgencia (una tarea donde quieres el mismo resultado cada vez) y redacta un borrador de respuesta (una tarea donde un poco de variedad no está mal). Tienes un solo control de temperatura para las dos. ¿Qué valor eliges, y qué le sacrificas a la otra tarea con esa elección?
Ver solución
Conviene priorizar la temperatura baja (cercana a 0), porque el costo de fallar en la clasificación —un ticket urgente que no escala a tiempo— es mayor que el costo de un borrador un poco más plano o repetitivo. Lo que se sacrifica es variedad en draft_reply: con temperatura baja, tickets parecidos van a recibir borradores de redacción muy similar entre sí. Si esa uniformidad se vuelve un problema real —varios clientes reciben respuestas casi idénticas y lo notan—, la solución de fondo no es subir la temperatura de todo el agente, sino separar la tarea en dos llamadas: una de clasificación a temperatura 0, y otra solo de redacción con una temperatura más alta, encadenando un segundo nodo de IA después del primero.
Por qué funciona: cuando dos objetivos distintos compiten por el mismo parámetro, casi siempre conviene priorizar el que tiene el error más caro, y considerar separar la tarea en dos llamadas independientes si el compromiso deja de ser aceptable.
Resumen y siguiente paso
Antes de avanzar deberías poder bajar la temperatura de un Chat Model para una tarea de clasificación —y saber en qué modelos ese ajuste realmente hace algo—, explicar qué controla maxTokens/maxTokensToSample y por qué no es lo mismo que la ventana de contexto, activar Require Specific Output Format en el AI Agent, y conectar un Structured Output Parser con un esquema que describa exactamente los campos que necesitas, sabiendo que la respuesta te va a llegar envuelta en output.
Ya tienes un agente que responde con datos que el resto del flujo puede leer sin interpretarlos. Lo que todavía no tienes es una forma de comparar, sin volver a disparar todo el flujo desde el Chat Trigger, qué pasa si cambias la temperatura, el modelo o el prompt: eso es exactamente para lo que sirve el motor de depuración que armas en la siguiente cápsula.
Recursos
- Structured Output Parser — los dos modos de definir el esquema (JSON Example vs. JSON Schema) y sus límites.
- AI Agent node — el nodo central del agente y sus puertos de conexión.
- Anthropic Chat Model — opciones del nodo, incluida Sampling Temperature y Maximum Number of Tokens.
- OpenAI Chat Model — incluye la opción nativa Response Format con JSON Schema bajo la Responses API.
- Anthropic Messages API — parámetros — rango y comportamiento oficiales de
temperatureymax_tokens. - JSON Schema — primeros pasos — sintaxis de referencia para cuando necesites "Define using JSON Schema" en vez de un ejemplo.