IA y LLMs

Un documento STXT generado por un modelo se valida contra una plantilla:
la salida es verificable, y cada error vuelve al modelo con su línea y su código.

Un modelo de lenguaje que genera un documento, o que extrae uno de un texto libre, produce texto. Si ese texto es Markdown, no hay contra qué comprobarlo: cualquier salida pasa, con campos inventados, secciones que faltan o fechas mal escritas. Si es STXT con una plantilla, la salida se valida como cualquier otro documento, y lo que no cumple la plantilla es un error con línea y código.

Lo que el validador comprueba

  • El modelo de contenido cerrado rechaza los nombres de nodo no declarados (CHILD_NOT_DECLARED, NODE_NOT_DEFINED_IN_SCHEMA).
  • Las cardinalidades rechazan los nodos que faltan o sobran (TOO_FEW_CHILDREN, TOO_MANY_CHILDREN).
  • Los tipos (DATE, EMAIL, NUMBER...) rechazan los formatos incorrectos, y los ENUM los valores fuera de la lista (INVALID_VALUE).

La plantilla del ejemplo ejecutable de esta página, tal cual está en su .stxt/:

Template (@stxt.template): com.acme.reports
	Structure >>
		Report (com.acme.reports):
			Title: (1)
			Date: (1) DATE
			Author: (1)
			Status: (1) ENUM [Draft, Final]
			Summary: (1) TEXT
			Section: (*)
				Title: (1) @Title
				Content: (1) TEXT
			Action: (*)
				Owner: (1)
				Due: (?) DATE
				Description: (1) TEXT
	Description >>
		Report: A short internal report extracted from free text (notes, emails, minutes)
		Date: Date of the source material, YYYY-MM-DD
		Status: Draft until a person has reviewed it
		Summary: Three sentences at most
		Section: One per topic discussed
		Action: One per agreed follow-up

Una salida con cuatro errores, todos detectados:

Report (com.acme.reports): Análisis de mercado
	Title: Análisis de mercado
	# ERROR: DATE exige YYYY-MM-DD
	Date: mañana
	Author: Ana García
	# ERROR: no es un valor del ENUM
	Status: Pendiente
	# ERROR: hijo no declarado (modelo cerrado)
	Subtitle: Versión corta
	# ERROR: falta Summary, que es obligatorio

El bucle: generar, validar, corregir

  1. El modelo genera el documento STXT.
  2. El validador lo comprueba contra la plantilla.
  3. Si hay errores, se devuelven al modelo tal cual, con línea y código.
  4. El modelo corrige y se repite, hasta que el documento valida o se agotan los intentos.

El paso 2 es stxt validate -: la CLI lee el documento por la entrada estándar, lo valida contra las gramáticas del directorio actual y emite cada hallazgo como <stdin>:línea: [CÓDIGO] mensaje (error), con código de salida 1 si hay errores (La línea de comandos). Con la biblioteca, es UnifiedSchemaProvider para cargar la plantilla y Parser con SchemaValidator para obtener los mismos errores.

El bucle completo está en examples/llm/ del repositorio de la especificación: un programa de Node que convierte unas notas de reunión en texto libre en un Report (com.acme.reports) válido. Lo acompañan la plantilla de arriba, un documento de ejemplo correcto, el prompt con las reglas del lenguaje y las notas de partida. El prompt lleva las reglas de STXT, la plantilla entera, el ejemplo válido y el texto a convertir, y pide solo el documento.

$ node generate.mjs > report.stxt
--- attempt 1: 3 error(s)
    line 3: [INVALID_VALUE] Date: Invalid date (12 March 2026) (schema)
    line 5: [INVALID_VALUE] The value 'draft' is not one of the allowed values of Status (schema)
    line 1: [TOO_FEW_CHILDREN] 0 nodes of 'com.acme.reports:summary' and min is 1 (schema)
--- attempt 2: valid

El documento sale por la salida estándar y el diálogo por la de error, con código de salida 0 solo si la última versión valida. El ejemplo usa la API de Anthropic, pero nada del bucle depende del proveedor: la llamada al modelo es una función que devuelve texto. El README del directorio resume qué error del modelo produce qué código.

Lo que facilita la generación

  • Pocas formas de línea. Cada línea es Nombre: valor, Nombre:, Nombre >> o texto de un bloque, y no hay sintaxis alternativas para un mismo elemento. El documento se genera de arriba abajo, sin referencias hacia atrás.
  • Sin escapado. Un bloque >> es texto literal: el modelo solo tiene que indentarlo. En JSON, el mismo texto exige escapar comillas y saltos de línea:
{"summary": "Línea 1\nLínea 2 con \"comillas\" y más texto..."}
Summary >>
	Línea 1
	Línea 2 con "comillas" y más texto...
  • Los nombres se comparan por su forma canónica. TITLE:, Title: y title: son el mismo nodo (STXT-SPEC §4.3); los valores de un ENUM, en cambio, se comparan exactos, con mayúsculas y minúsculas.

Prácticas de prompting

  • Incluir la plantilla completa del namespace: declara qué nodos existen, sus cardinalidades y sus valores permitidos.
  • Añadir un documento de ejemplo completo y válido.
  • Pedir una indentación fija: tabuladores, o cuatro espacios por nivel.
  • Validar siempre la salida con el parser, nunca por inspección.
  • Devolver al modelo los mensajes del validador tal cual, con línea y código.

Los casos donde este flujo encaja se desarrollan en CMS y publicaciones, donde el build rechaza las páginas generadas que no validan, y en Documentos corporativos, para la extracción de datos de texto libre.