Produce un resumen estructurado de un documento

PythonBeginner
Practicar Ahora

Introducción

Un equipo de operaciones necesita un resumen estructurado de un informe breve de incidente. Un modelo puede generar prosa plausible, pero una aplicación necesita campos predecibles y debe rechazar resultados no válidos. Solicitarás un resumen JSON con Bedrock Converse, lo analizarás en Python y probarás la ruta de rechazo con casos locales claramente identificados.

Debes conocer Python introductorio, JSON y las solicitudes Converse del laboratorio guiado anterior. Cada VM nueva proporciona su propio documento, identidad configurada y cuota de inferencia. No necesitas archivos ni credenciales de una VM anterior.

Relación con la certificación

Certificación Tarea del examen Práctica
AI Practitioner (AIF-C01) Tarea 3.2 Especificar el formato de salida y validar una respuesta antes de que la aplicación la utilice.

Esquema conceptual creado con draw.io: el documento entra en Bedrock Converse; el análisis y la validación seleccionan un resumen utilizable o un rechazo controlado.

Inspecciona el documento y los campos requeridos

En este paso inspeccionarás un informe sintético proporcionado y definirás la estructura que espera la aplicación consumidora.

Comienza en el espacio de trabajo:

cd /home/labex/project

El documento proporcionado es texto plano. Léelo con cat, que imprime el archivo:

cat incident.txt

Describe el incidente INC-204: un error de configuración del proceso de pago provocó 30 minutos de pagos fallidos. El equipo revirtió la configuración y restableció el servicio. Hay una prueba de configuración posterior planificada, todavía no completada. Estos hechos delimitan tu resumen.

La aplicación espera exactamente tres campos: incident_id, impact y next_action. Cada uno debe contener una cadena no vacía. Un esquema describe esa forma; JSON válido no basta, porque una lista, un campo ausente o un número pueden seguir siendo JSON válido. Lee la referencia de esquema proporcionada:

cat summary-schema.json

La referencia explica la salida deseada. Aplicarás sus campos con Python ordinario; no promete automáticamente que el modelo los respete. Pedir JSON y validar JSON son responsabilidades distintas.

Genera y valida un resumen estructurado

En este paso construirás un pequeño comando Python que solicita un resumen y valida el texto devuelto antes de imprimir éxito.

boto3 es el SDK de AWS para Python. Está instalado en el entorno Python proporcionado y utiliza las credenciales y el endpoint ya configurados. El código usa converse, la misma operación practicada con CLI. maxTokens limita la salida y el cliente desactiva reintentos automáticos para que un fallo ambiguo no envíe silenciosamente otra solicitud de inferencia.

Crea summary.py con el siguiente código. La función parse_response comprueba el motivo de finalización, analiza el texto con json.loads, valida las claves exactas y comprueba los tipos. ValueError representa un rechazo controlado; un ClientError o error de conexión se comunica sin mostrar credenciales ni la excepción completa. El modo opcional --response-file lee una respuesta local para probar el analizador y no envía inferencia:

cat > summary.py <<'EOF'
import argparse
import json
from pathlib import Path
import boto3
from botocore.config import Config
from botocore.exceptions import BotoCoreError, ClientError


def parse_response(response):
    if not isinstance(response, dict):
        raise ValueError("invalid_response")
    if response.get("stopReason") != "end_turn":
        raise ValueError("incomplete_response")
    try:
        text = response["output"]["message"]["content"][0]["text"]
        value = json.loads(text)
        expected = {"incident_id", "impact", "next_action"}
        if not isinstance(value, dict) or set(value) != expected:
            raise ValueError("invalid_fields")
        if any(not isinstance(v, str) or not v.strip() for v in value.values()):
            raise ValueError("invalid_field_type")
        if value["incident_id"] != "INC-204":
            raise ValueError("unexpected_incident")
        return value
    except (KeyError, IndexError, TypeError, json.JSONDecodeError) as error:
        raise ValueError("invalid_response") from error


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--response-file", type=Path)
    args = parser.parse_args()
    try:
        if args.response_file:
            response = json.loads(args.response_file.read_text())
        else:
            client = boto3.client("bedrock-runtime", config=Config(
                connect_timeout=5, read_timeout=150,
                retries={"total_max_attempts": 1}))
            response = client.converse(
                modelId="labex.text-v1:0",
                system=[{"text": "Summarize only facts supplied in the incident document. Return exactly one JSON object with string fields incident_id, impact and next_action. No Markdown fences, extra keys or surrounding prose. Do not turn planned work into completed work."}],
                messages=[{"role": "user", "content": [
                    {"text": Path("incident.txt").read_text()}]}],
                inferenceConfig={"maxTokens": 768, "temperature": 0})
            Path("response.json").write_text(json.dumps(response, indent=2))
        value = parse_response(response)
    except (ValueError, KeyError, TypeError):
        print(json.dumps({"status": "rejected", "reason": "invalid_model_output"}))
        return 2
    except (BotoCoreError, ClientError):
        print(json.dumps({"status": "unavailable", "reason": "inference_failed"}))
        return 3
    print(json.dumps({"status": "ok", "summary": value}, indent=2))
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
EOF

Ejecuta el script con el entorno Python de AWS instalado. El último > summary.json guarda el resultado impreso:

/opt/labex/aws/venv/bin/python summary.py > summary.json

Espera al prompt y después inspecciona el resultado:

cat summary.json

Una ejecución correcta contiene "status": "ok" y un objeto summary con los tres campos de cadena requeridos. Lee también la respuesta Converse sin procesar:

python3 -m json.tool response.json

response.json registra la salida real del modelo, el motivo de finalización y el uso de tokens. Expande la solicitud completada en AWS View y compara su texto. Las palabras generadas pueden variar. Comprueba que impact refleje los pagos fallidos y que next_action describa trabajo planificado. Superar el esquema no demuestra la exactitud de esas afirmaciones.

AWS View real de una VM: la solicitud completada contiene un resumen de incidente JSON, uso de tokens y cuota restante. Tu redacción, tiempo y cuota pueden variar.

Si el script informa de rechazo, lee la respuesta sin procesar antes de reintentar. El modelo puede truncar la salida o ignorar el formato solicitado; no sustituyas el resumen por un éxito fijado en el código. Una inferencia fallida puede consumir cuota.

Prueba el límite de respuestas no válidas

En este paso confirmarás que se rechazan respuestas malformadas, con tipos incorrectos y truncadas sin enviar otra solicitud al modelo.

El directorio fixtures/ contiene entradas deliberadas para probar el analizador. Son datos locales de prueba, no resultados de inferencia. Lístalos:

ls fixtures

Ejecuta el script con el caso JSON malformado:

/opt/labex/aws/venv/bin/python summary.py --response-file fixtures/malformed.json

La salida esperada es {"status": "rejected", "reason": "invalid_model_output"}. El código de salida 2 identifica este rechazo controlado. echo $? imprime el código del comando inmediatamente anterior:

echo $?

Una respuesta puede ser JSON válido y aun así incumplir el esquema. Prueba el caso con impact numérico:

/opt/labex/aws/venv/bin/python summary.py --response-file fixtures/wrong-type.json

Debe informar del mismo rechazo. Un objeto JSON que parezca completo también debe rechazarse si el modelo alcanzó el máximo de tokens. Prueba ese límite:

/opt/labex/aws/venv/bin/python summary.py --response-file fixtures/truncated.json

Debe rechazarse porque su stopReason es max_tokens. Estas pruebas no imprimen resúmenes exitosos ni añaden solicitudes a AWS View.

Por último, analiza de nuevo la respuesta real guardada:

/opt/labex/aws/venv/bin/python summary.py --response-file response.json

Debe seguir devolviendo status: ok. Has probado la respuesta real utilizable y entradas de fallo controladas. No confundas los casos del analizador con prueba de que funcionó la inferencia: la solicitud completada y su respuesta sin procesar lo demuestran por separado.

Elimina los archivos creados en el ejercicio

En este paso eliminarás tu script y sus dos archivos de resultados después de superar las comprobaciones funcionales.

El documento, esquema y casos del analizador pertenecen al entorno nuevo. Consérvalos junto con el servicio backend. rm elimina solo los tres archivos del estudiante indicados:

rm summary.py summary.json response.json

Confirma que se conservan las entradas proporcionadas:

ls

Converse no crea ningún servidor persistente que debas borrar. Eliminar archivos locales no devuelve créditos consumidos ni borra los registros reales de inferencia conservados por AWS View.

Resumen

Utilizaste una respuesta real de Bedrock Converse para generar un resumen estructurado, aplicaste nombres y tipos de campos, comprobaste el motivo de finalización y rechazaste casos no válidos controlados. También revisaste el significado factual por separado de la validez del esquema y eliminaste solo tus archivos.

Para ampliar este tema, consulta la referencia de AWS: Contenido, motivos de parada y uso de la respuesta Converse.