Inicio / Artículos / De la ingeniería de prompts a los flujos de trabajo agentes: construyendo sistemas inteligentes sobre

De la ingeniería de prompts a los flujos de trabajo agentes: construyendo sistemas inteligentes sobre

Guía práctica paso a paso desde la ingeniería de prompts hasta el flujo de trabajo agente: creación de sistemas inteligentes basados en contratos, verificaciones y espacios para código listo para usar, dirigida a los equipos que implementan este patrón.

2274 palabras

Las notas siguientes reconstruyen un camino práctico relacionado con “De la ingeniería de prompts a flujos de trabajo agentes: Construyendo sistemas inteligentes en Dataproc Serverless, Parte 1”. Se da énfasis a los contratos, las verificaciones y los marcadores de posición para código, en lugar de a un enfoque motivacional. Al trabajar en la etapa de descripción general, anote primero el contrato: las entradas requeridas, la señal de éxito y qué ocurre en caso de un fallo parcial. Esa lista de verificación ayuda a mantener honestas las futuras modificaciones del código. Prefiera unidades pequeñas y verificables en lugar de scripts extensos. Cuando un paso falla, el fallo debe apuntar a una sola responsabilidad y no a un proceso complicado.

Resumen de la serie

La etapa de Resumen de la Serie funciona mejor cuando se trata como una superficie medible. Capture un transcripte ideal, un caso de fallo y la nota de reversión antes de ampliar el alcance. Considere esta etapa como un contrato entre las entradas y las salidas validadas. Asigne nombres a los artefactos, defina verificaciones de éxito y rechace completaciones parciales silenciosas. Asigne un presupuesto de tokens por turno y por sesión. Las herramientas agentes amplían el contexto de forma excesiva; los límites máximos evitan que las demostraciones se conviertan en facturas inesperadas.

Parte 1: Eliminando las fricciones para desarrolladores de Spark — Automatizando el ciclo de vida de Git, SBT y almacenamiento en la nube

La etapa 1 de eliminación de chispas funciona mejor cuando se trata como una superficie medible. Capture un registro exitoso, un caso de fallo y la nota de reversión antes de ampliar el alcance. Registre los tiempos y el costo de tokens o consultas junto con los resultados funcionales. Tener visibilidad del costo desde el principio evita facturas inesperadas cuando el proceso pasa de la fase de demostración a entornos compartidos. Asigne un presupuesto de tokens por turno y por sesión. Las herramientas agenciales amplían el contexto de manera intensiva; los límites estrictos impiden que las demostraciones se conviertan en facturas inesperadas.

Introducción: La agonía del bucle interno en la ingeniería de Spark

La introducción: “The Agony of stage” funciona mejor cuando se trata como una superficie medible. Capture un registro ideal, un caso de fallo y la nota de reversión antes de ampliar el alcance. Mantenga la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de datos secretos y las banderas de funcionalidad deben estar en un lugar donde los operadores puedan auditarlos sin tener que leer todo el sistema. Asigne un límite de tokens por turno y por sesión; las herramientas agentes amplían el contexto de forma excesiva, por lo que los límites estrictos evitan que las demostraciones se conviertan en facturas inesperadas. La introducción: “The Agony of stage” funciona mejor cuando se trata como una superficie medible. Capture un registro ideal, un caso de fallo y la nota de reversión antes de ampliar el alcance. Prefiera unidades pequeñas y verificables en lugar de scripts extensos. Cuando un paso falla, el fallo debe referirse a una sola responsabilidad y no a un proceso complicado.

Arquitectura: Desacoplamiento de la compilación y la carga para un consumo agente

En la etapa de desacoplamiento arquitectónico entre compilación y carga, se deben definir las entradas, el responsable de cada paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido, sin tener que adivinar el estado oculto. Considere esta etapa como un contrato entre las entradas y los resultados validados. Asigne nombres a los artefactos, defina verificaciones de éxito y rechace las completaciones parciales silenciosas. Prefiera resultados estructurados con validación de esquema sobre textos en formato libre cuando el siguiente paso sea la generación de código o una llamada a una herramienta.

Implementación paso a paso

En la fase de implementación paso a paso, defina las entradas, el responsable de cada paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido sin tener que adivinar el estado oculto. Registre los tiempos de ejecución y el costo de tokens o consultas junto con los resultados funcionales. La visibilidad temprana del costo evita facturas inesperadas cuando el proceso pasa de entornos de demostración a entornos compartidos. Prefiera salidas estructuradas con validación de esquema sobre texto en formato libre cuando el siguiente paso sea escribir código o realizar una llamada a una herramienta.

1. Aplicación de Java 11 y detección de compilaciones (artifact_builder.py)

En la fase 1 de implementación de Java 11, defina las entradas, el responsable del paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido sin tener que adivinar el estado oculto. Mantenga la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de datos confidenciales y las banderas de funcionalidad deben estar en un lugar donde los operadores puedan auditarlos sin necesidad de leer todo el sistema. Prefiera salidas estructuradas con validación de esquema sobre textos en formato libre cuando el siguiente paso sea código o una llamada a una herramienta. En la fase 1 de implementación de Java 11, defina las entradas, el responsable del paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido sin tener que adivinar el estado oculto. Prefiera unidades pequeñas y verificables sobre scripts extensos. Cuando un paso falla, el error debe indicar una única responsabilidad y no un proceso complicado.

import os
import subprocess
import logging

class ArtifactBuilder:
    """Builds Scala JAR artifacts from Git repositories using SBT."""

    def __init__(self, repo_url: str, branch: str = "main"):
        self.repo_url = repo_url
        self.branch = branch

    def clone_repo(self, dest_dir: str):
        """Clone the given Git repository to the destination directory."""
        logging.info(f"Cloning {self.repo_url} (branch={self.branch}) into {dest_dir}")
        subprocess.run(["git", "clone", "-b", self.branch, self.repo_url, dest_dir], check=True)

    def find_build_dir(self, root_dir: str) -> str:
        """Recursively search for SBT build file."""
        for dirpath, _, filenames in os.walk(root_dir):
            if "build.sbt" in filenames:
                logging.info(f"Detected SBT build file in {dirpath}")
                return dirpath
        raise FileNotFoundError(f"No build.sbt file found in {root_dir}")

    def check_java_installed(self):
        """Ensure Java 11 is available and active in environment."""
        env = os.environ.copy()
        env["JAVA_HOME"] = "/opt/homebrew/opt/openjdk@11/libexec/openjdk.jdk/Contents/Home"
        env["PATH"] = f"/opt/homebrew/opt/openjdk@11/bin:{env.get('PATH', '')}"

        result = subprocess.run(
            ["java", "-version"],
            check=True,
            env=env,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True
        )
        output = result.stdout + result.stderr
        if "version" in output:
            version_str = output.split("version")[1].split()[0].strip('"')
            major_version = int(version_str.split(".")[0])
            if major_version != 11:
                raise EnvironmentError(f"Java 11 required, but detected Java {major_version}")
        logging.info("Java 11 verified successfully.")

    def build_artifact(self, repo_dir: str) -> str:
        """Compile and assemble fat JAR."""
        build_dir = self.find_build_dir(repo_dir)
        self.check_java_installed()

        env = os.environ.copy()
        env["JAVA_HOME"] = "/opt/homebrew/opt/openjdk@11/libexec/openjdk.jdk/Contents/Home"
        env["PATH"] = f"/opt/homebrew/opt/openjdk@11/bin:{env.get('PATH', '')}"

        logging.info("Running: sbt clean compile assembly...")
        subprocess.run(["sbt", "clean", "compile", "assembly"], cwd=build_dir, env=env, check=True)

        target_dir = os.path.join(build_dir, "target")
        return self._find_file(target_dir, ".jar")

    def _find_file(self, directory: str, extension: str) -> str:
        for root, _, files in os.walk(directory):
            for f in files:
                if f.endswith(extension):
                    return os.path.join(root, f)
        raise FileNotFoundError(f"No {extension} file found in {directory}")

2. Publicación fiable en almacenamiento en la nube (uploader.py)

Al trabajar en la fase 2 de almacenamiento en la nube fiable, anote primero el contrato: entradas requeridas, señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación mantiene honestas las futuras modificaciones del código. Trate esta fase como un contrato entre las entradas y los resultados validados. Asigne nombres a los artefactos, defina comprobaciones de éxito y evite completaciones parciales silenciosas. Almacene en caché las instrucciones del sistema estables y los esquemas de las herramientas. Reenviar un preámbulo idéntico es una causa común de problemas.

from google.cloud import storage
import logging
import os

class ArtifactUploader:
    """Handles secure upload of artifacts to Google Cloud Storage."""

    def __init__(self):
        self.client = storage.Client()

    def upload_to_gcs(self, bucket_name: str, artifact_path: str, dest_path: str):
        if not os.path.exists(artifact_path):
            raise FileNotFoundError(f"Artifact not found: {artifact_path}")

        logging.info(f"Uploading {artifact_path} → gs://{bucket_name}/{dest_path}")
        bucket = self.client.bucket(bucket_name)
        blob = bucket.blob(dest_path)
        blob.upload_from_filename(artifact_path)
        logging.info("Upload to GCS completed successfully.")

3. Orquestación del backend y envoltorio CLI (run_build_and_upload.py)

Al trabajar en la etapa 3 de Orquestación de Backend mediante CLI, anote primero el contrato: las entradas requeridas, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación mantiene honestas las futuras modificaciones del código. Registre los tiempos y el costo de tokens o consultas junto con los resultados funcionales. Tener visibilidad del costo desde el principio evita facturas inesperadas cuando el proceso pasa de entornos de demostración a entornos compartidos. Almacene en caché las instrucciones del sistema estables y los esquemas de herramientas. Reenviar un preámbulo idéntico es una causa común de gastos innecesarios.

# Executed autonomously in the background by the Agent's backend tool:
python3 artifact_pipeline/run_build_and_upload.py \
  --repo "https://github.com/<username>/demo-pipeline.git" \
  --branch main \
  --bucket "demo-spark-sandbox-bucket" \
  --dest "spark-jobs/spark-serverless-job_test.jar" \
  --cleanup

Visualización del pipeline de construcción en acción

Al trabajar en la etapa de Visualización de la tubería de construcción, anote primero el contrato: entradas requeridas, señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación mantiene honestas las futuras modificaciones del código. Guarde la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de secretos y las banderas de funcionalidad deben estar en un lugar donde los operadores puedan auditarlos sin tener que leer todo el diagrama. Almacene en caché las instrucciones del sistema estables y los esquemas de las herramientas. Reenviar un preámbulo idéntico es una causa común de consumo excesivo.

1. Verificación del almacenamiento en la nube

Al trabajar en la etapa 1 de Verificación de Almacenamiento en la Nube, anote primero el contrato: los datos requeridos, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación ayuda a mantener la integridad de los cambios en el código posteriormente. Documente tanto el camino óptimo como el camino de recuperación. Las reintentos, los controles humanos y el manejo de mensajes no entregados forman parte del producto, no son mejoras realizadas después. Almacene en caché las instrucciones del sistema estables y los esquemas de las herramientas. Reenviar un preámbulo idéntico es una causa común de problemas.

2. Ciclo de vida de ejecución del agente en Streamlit

Al trabajar en la etapa del ciclo de vida de ejecución de 2 agentes, anote primero el contrato: los datos de entrada requeridos, la señal de éxito y qué ocurre en caso de un fallo parcial. Esa lista de verificación ayuda a mantener honestos los cambios posteriores en el código. Prefiera unidades pequeñas y probables sobre scripts extensos. Cuando un paso falla, el fallo debe apuntar a una única responsabilidad y no a un proceso complicado. Almacene en caché las instrucciones del sistema estables y los esquemas de las herramientas. Reenviar un preámbulo idéntico es una causa común de desperdicio de recursos.

Manejo robusto de errores y diagnóstico en la práctica

Al trabajar en la etapa de Diagnóstico de Manejo Robusto de Errores, anote primero el contrato: las entradas requeridas, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación mantiene honestas las futuras modificaciones del código. Trate esta etapa como un contrato entre las entradas y las salidas validadas. Asigne nombres a los artefactos, defina comprobaciones de éxito y rechace las completaciones parciales silenciosas. Almacene en caché las instrucciones del sistema estables y los esquemas de las herramientas. Reenviar un preámbulo idéntico es una causa común de problemas.

Escenario 1: Errores de Autenticación y Clonado en Git

Al trabajar en la etapa de Autenticación con Git del Escenario 1, anote primero el contrato: los datos requeridos, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación mantiene honestas las futuras modificaciones del código. Registre los tiempos y el costo de los tokens o consultas junto con los resultados funcionales. Tener visibilidad del costo desde el principio evita facturas inesperadas cuando se pasa de entornos de demostración a entornos compartidos. Almacene en caché las instrucciones del sistema estables y los esquemas de las herramientas. Reenviar un preámbulo idéntico es una causa común de gastos innecesarios.

Escenario 2: Tiempo de ejecución del pipeline y errores en el entorno

Al trabajar en la etapa de tiempo de ejecución del pipeline del Escenario 2, anote primero el contrato: las entradas requeridas, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación mantiene honestas las futuras modificaciones del código. Guarde la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de secretos y las banderas de funcionalidad deben estar en un lugar donde los operadores puedan auditarlos sin tener que leer todo el sistema. Almacene en caché las instrucciones del sistema estables y los esquemas de las herramientas. Reenviar un preámbulo idéntico es una causa común de desperdicio de recursos. Al trabajar en la etapa de tiempo de ejecución del pipeline del Escenario 2, anote primero el contrato: las entradas requeridas, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación mantiene honestas las futuras modificaciones del código. Prefiera unidades pequeñas y probables sobre scripts extensos. Cuando una etapa falla, el fallo debe apuntar a una única responsabilidad y no a un pipeline complicado.

Puntos clave de la Parte 1

Los puntos clave de esta etapa funcionan mejor cuando se considera como una superficie medible. Capture un registro ejemplar, un caso de fallo y la nota de reversión antes de ampliar el alcance. Trate esta etapa como un contrato entre las entradas y las salidas validadas. Asigne nombres a los artefactos, defina verificaciones de éxito y rechace las completaciones parciales silenciosas. Asigne un presupuesto de tokens por turno y por sesión; las herramientas agentes amplían el contexto de forma excesiva; los límites máximos evitan que las demostraciones se conviertan en facturas inesperadas.

Conclusión

La etapa de Conclusión funciona mejor cuando se trata como una superficie medible. Capture un registro ideal, un caso de fallo y la nota de reversión antes de ampliar el alcance. Registre los tiempos y el costo de tokens o consultas junto con los resultados funcionales. Tener visibilidad del costo desde el principio evita facturas inesperadas cuando el proceso pasa de la demostración a entornos compartidos. Asigne un presupuesto de tokens por turno y por sesión. Las herramientas agenciales amplían el contexto de manera intensiva; los límites estrictos impiden que las demostraciones se conviertan en facturas inesperadas.

Referencias y lectura adicional (Parte 1)

La etapa de Referencias y Lecturas Adicionales funciona mejor cuando se trata como una superficie medible. Capture un registro ideal, un caso de fallo y la nota de reversión antes de ampliar el alcance. Mantenga la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de secretos y las banderas de funcionalidad deben estar en un lugar donde los operadores puedan auditarlos sin tener que leer todo el sistema. Establezca un límite de tokens por turno y por sesión. Las herramientas agentes amplían el contexto de manera excesiva; los límites estrictos evitan que las demostraciones se conviertan en facturas inesperadas. La etapa de Referencias y Lecturas Adicionales funciona mejor cuando se trata como una superficie medible. Capture un registro ideal, un caso de fallo y la nota de reversión antes de ampliar el alcance. Prefiera unidades pequeñas y verificables en lugar de scripts extensos. Cuando un paso falla, el fallo debe apuntar a una única responsabilidad y no a un proceso complicado.

Lista de verificación operativa

En la fase de lista de verificación operativa, defina las entradas, el responsable de cada paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido sin tener que adivinar el estado oculto.

Documente tanto la ruta óptima como la ruta de recuperación. Las intentonas, los controles humanos y el manejo de mensajes no entregados forman parte del producto, no son algo que se añada posteriormente.

Prefiera salidas estructuradas con validación de esquema en lugar de texto libre cuando el siguiente paso sea escribir código o realizar una llamada a una herramienta.

Establezca puntos de control después de los pasos costosos. La función de reanudación no debe volver a facturar la misma llamada al LLM cuando un operador intente nuevamente un nodo posterior.

Fije las versiones de las dependencias y registre el resumen de la imagen que ejecutó la demostración. La reproducibilidad es mejor que el conocimiento basado en prácticas internas.

Registra los tiempos y el costo de tokens o consultas junto con los resultados funcionales. Ver la información sobre costos desde el principio evita facturas inesperadas cuando se pasa de entornos de demostración a entornos compartidos.

Antes de promocionar la solución, congela las versiones, guarda una transcripción de referencia para el camino crítico y confirma los pasos para revertir cambios. Los entornos compartidos requieren límites de uso, verificaciones de tenencia y un responsable claro para la rotación de credenciales secretas. Prefiere una fiabilidad sencilla a demostraciones ingeniosas pero puntuales.

Nota para el lote 671e92168610: mantén las claves del proveedor fuera del repositorio, establece un límite para tokens por sesión y almacena las transcripciones junto a los archivos de prueba para que los cambios en el modelo posterior sigan siendo comparables.