Publicado el
OpenAI Agents SDK

Dominando el SDK de OpenAI Agents para Python: Construye flujos de trabajo inteligentes de IA con herramientas, guardarraíles y coordinación multiagente

Post image

SDK de OpenAI Agents para Python – Tutorial Completo

Introducción

El SDK de OpenAI Agents es un framework en Python para construir sistemas de IA basados en agentes que combinan grandes modelos de lenguaje (LLMs) con herramientas y flujos de trabajo estructurados. Proporciona un conjunto ligero de primitivasAgentes, Transferencias y Guardarraíles – que pueden componerse para crear aplicaciones de IA complejas y orientadas a objetivos (OpenAI Agents SDK). Un Agente en este SDK es esencialmente un LLM (como GPT-4 o GPT-3.5) configurado con instrucciones y equipado con herramientas que puede usar (OpenAI Agents SDK) (Orquestando múltiples agentes - OpenAI Agents SDK). Estos agentes operan en un bucle de agente: reciben una entrada (por ejemplo, una pregunta del usuario), deciden acciones (como llamar a una herramienta o delegar a otro agente), y continúan el bucle hasta que se produce una respuesta final (Ejecutando agentes - OpenAI Agents SDK) (Ejecutando agentes - OpenAI Agents SDK).

Conceptos arquitectónicos clave incluyen:

  • Agentes: Los actores principales de tu aplicación. Un agente consiste en un LLM más un conjunto de instrucciones (a menudo proporcionadas como un prompt de sistema) y herramientas opcionales que puede invocar. Dada una tarea, un agente puede planificar autónomamente cómo resolverla razonando sobre el problema, llamando a herramientas para asistencia y generando respuestas (Orquestando múltiples agentes - OpenAI Agents SDK). Por ejemplo, podrías tener un agente configurado como un “Asistente de Investigación” que usa una herramienta de búsqueda web para encontrar información y luego responde la consulta.

  • Herramientas: Funciones o capacidades que un agente puede usar para realizar acciones más allá del conocimiento incorporado del LLM (OpenAI Agents SDK). Las herramientas pueden ser funciones simples de Python (entrada/salida de archivos, cálculos matemáticos), llamadas a APIs externas (consulta del clima), o incluso otros agentes (permitiendo que un agente delegue subtareas). El SDK de Agents facilita convertir cualquier función Python en una herramienta y manejar entradas/salidas de herramientas mediante llamadas a funciones (Herramientas - OpenAI Agents SDK). Las herramientas permiten a los agentes interactuar con el mundo (por ejemplo, buscar en la web, consultar bases de datos, ejecutar código) en lugar de solo generar texto.

  • Transferencias: Un mecanismo para que un agente delegue o transfiera el control a otro agente a mitad de tarea (OpenAI Agents SDK). Usando transferencias, puedes componer múltiples agentes especializados en un flujo de trabajo – por ejemplo, un agente de triaje que transfiere a un agente de facturación o reembolso según la solicitud del usuario (OpenAI Agents SDK — Primeros pasos). Las transferencias permiten sistemas multiagente modulares donde cada agente se enfoca en un dominio o habilidad específica.

  • Guardarraíles: Comprobaciones integradas de validación y seguridad que se ejecutan junto a los agentes (OpenAI Agents SDK). Los guardarraíles pueden filtrar entradas (para prevenir consultas maliciosas o irrelevantes) y validar salidas (para asegurar corrección o cumplimiento de políticas) (OpenAI Agents SDK — Primeros pasos). Si una comprobación de guardarraíl falla (llamada tripwire), el SDK puede detener la ejecución del agente o lanzar una excepción antes de que se tome cualquier acción no deseada (Guardrails - OpenAI Agents SDK) (Guardrails - OpenAI Agents SDK). Esto ayuda a mantener la fiabilidad y seguridad en aplicaciones de producción.

  • Trazabilidad: El SDK tiene soporte integrado para trazabilidad para depuración y análisis (OpenAI Agents SDK — Primeros pasos). Cada paso del razonamiento de un agente – uso de herramientas, decisiones y mensajes del LLM – puede registrarse como una traza. Los desarrolladores pueden inspeccionar estas trazas (por ejemplo, vía el panel de OpenAI) para entender el comportamiento del agente, medir rendimiento y mejorar iterativamente los prompts o el código (OpenAI Agents SDK — Primeros pasos). La trazabilidad está habilitada por defecto, dándote visibilidad del proceso de pensamiento y acciones del agente.

Estos componentes trabajan juntos para formar una arquitectura de sistema basada en agentes. Un agente recibe un objetivo o consulta, usa su columna vertebral LLM para razonar sobre la tarea, llama a herramientas o delega a otros agentes según sea necesario, y eventualmente produce un resultado. Gracias al diseño del SDK, gran parte de esta complejidad es manejada por el bucle del agente y el runtime del SDK. Puedes empezar simple (un solo agente respondiendo preguntas) y gradualmente añadir herramientas, múltiples agentes, guardarraíles y controles personalizados a medida que tu aplicación crece en sofisticación. El SDK enfatiza la flexibilidad con mínima abstracción – “funciona muy bien desde el primer momento” pero te permite personalizar cada parte del flujo si es necesario (OpenAI Agents SDK) (OpenAI Agents SDK).

En el resto de este tutorial, exploraremos todas las características principales del SDK de OpenAI Agents para Python y demostraremos cómo usarlas efectivamente. Comenzaremos instalando el SDK y creando un agente simple. Luego profundizaremos en configurar agentes personalizados, añadir y construir herramientas, gestionar el contexto y estado del agente (memoria), manejar la orquestación multiagente con transferencias, integrar guardarraíles para seguridad, y más. Se proporcionan ejemplos de código a lo largo del texto, y al final combinaremos estos conceptos en un proyecto de ejemplo completo. ¡Comencemos!

Instalacion y Configuracion

Antes de usar el SDK de Agents, necesitas instalarlo. El nombre del paquete es openai-agents. Instálalo vía pip:

pip install openai-agents
``` ([OpenAI Agents SDK](https://openai.github.io/openai-agents-python/#installation))

Esto instalará el SDK principal y sus dependencias. Por defecto, el SDK usará la API de OpenAI para llamadas LLM, así que debes tener una clave API de OpenAI lista. Configura la variable de entorno `OPENAI_API_KEY` con tu clave API (o usa el método programático del SDK para configurarla, mostrado abajo) antes de ejecutar agentes:

```bash
export OPENAI_API_KEY="sk-YourOpenAIAPIKey"

Dependencias opcionales: Si planeas usar LiteLLM (un sistema de plugins para integrar otros proveedores de modelos o modelos open-source) o funciones de voz, hay dependencias extra. Por ejemplo, para habilitar soporte LiteLLM (permitiendo usar modelos no OpenAI), instala con el extra litellm:

pip install "openai-agents[litellm]"

Cubrirémos el uso de modelos personalizados vía LiteLLM en una sección posterior. Por ahora, con el SDK instalado y tu clave API configurada, podemos empezar a crear agentes.

Creando y Configurando un Agente

Crear un agente básico es sencillo. El SDK provee una clase Agent, que puedes instanciar con un nombre y parámetros opcionales como instrucciones, herramientas, transferencias y guardarraíles. Como mínimo, un agente necesita un nombre (usado para identificación y registro) y opcionalmente puede tener un prompt de instrucciones que guíe su comportamiento.

Creemos un agente simple:

from agents import Agent, Runner

# Crear un agente básico con un nombre e instrucciones de rol
agent = Agent(
    name="Assistant",
    instructions="Eres un asistente útil."
)

En este ejemplo, configuramos el agente para que se comporte como un asistente útil proporcionando una instrucción breve (que actúa como un prompt de sistema). Si ejecutamos este agente con una consulta de usuario, usará un modelo OpenAI GPT bajo el capó para generar una respuesta siguiendo esa instrucción.

Ejecutando el agente: El Runner del SDK se usa para ejecutar agentes. Puedes llamar a Runner.run_sync(agent, input) para una llamada síncrona rápida, o usar await Runner.run(agent, input) en un contexto asíncrono. Por ejemplo:

result = Runner.run_sync(agent, "Escribe un haiku sobre recursión en programación.")
print(result.final_output)

Esto pedirá al agente que responda la consulta. Bajo el capó, se llama al LLM del agente con las instrucciones del sistema y la pregunta del usuario, luego el bucle del agente maneja la respuesta. Dada nuestra configuración simple, el agente responderá directamente. El objeto result (de tipo RunResult) contiene la salida final en result.final_output. En este caso, podría imprimir un haiku como:

# Código dentro del código,
# Funciones llamándose a sí mismas,
# Danza del bucle infinito.

(Este ejemplo es el “hola mundo” de la documentación (OpenAI Agents SDK).)

Por defecto, Agent() sin especificar modelo usará el modelo de chat de OpenAI (gpt-3.5-turbo o gpt-4 vía la API Responses) como LLM. Asegúrate de que tu clave API de OpenAI esté configurada para que el agente pueda llamar al modelo. Puedes cambiar qué modelo o API se usa – hablaremos de eso pronto.

Opciones de configuración del agente: La clase Agent provee varios parámetros para personalizar su comportamiento:

  • name (str): Un nombre descriptivo para el agente (por ejemplo, "ResearchAgent"). Este nombre también se usa cuando el agente es usado como herramienta o en registros/trazas.

  • instructions (str o callable): El prompt o mensaje de sistema que establece el rol del agente. Puede ser una cadena fija o una función que genere una cadena (potencialmente usando contexto dinámico). Las instrucciones se colocan al inicio del contexto del LLM (como rol de sistema) (Gestión de contexto - OpenAI Agents SDK). Buenas instrucciones son cruciales para guiar el comportamiento del agente e informarle sobre herramientas disponibles o restricciones.

  • tools (lista): Una lista de herramientas que el agente puede usar. Las herramientas pueden añadirse aquí como referencias a funciones (para herramientas de función) o instancias de herramientas (para ciertas herramientas integradas). Discutiremos herramientas en profundidad en la siguiente sección. Si no se proveen herramientas, el agente solo puede confiar en el conocimiento y razonamiento propio del LLM.

  • handoffs (lista): Una lista de otros agentes o configuraciones de transferencia a los que este agente puede delegar. Al especificar transferencias, permites que tu agente transfiera control a otro agente en ciertas situaciones. Exploraremos transferencias en la sección Orquestacion Multi-Agente y Transferencias.

  • guardrails (lista): Una lista de funciones guardarraíl (de entrada o salida) para aplicar a este agente. Los guardarraíles se usan para hacer validaciones en entradas o salidas – por ejemplo, evitar que el agente resuelva la tarea de matemáticas de un usuario o asegurar que la salida tenga cierto formato. Los guardarraíles se cubren en Guardarrailes y Validacion de Salida más adelante.

  • model: Por defecto, cada agente usa el modelo global por defecto (GPT de OpenAI vía la API Responses). Puedes sobrescribir esto por agente pasando un parámetro model. El SDK incluye clases de modelo como OpenAIChatCompletions y OpenAIResponsesModel, y con LiteLLM puedes usar modelos de Anthropic, etc. Por ejemplo, puedes hacer Agent(model=OpenAIChatCompletionsModel()) para forzar el uso de la API de Chat Completions, o Agent(model=LitellmModel(...)) para usar un modelo de otro proveedor. Si estás conforme con el valor por defecto, puedes omitir este parámetro.

  • output_type: (Opcional) Un modelo Pydantic o tipo de dato que especifica la estructura esperada de la salida final. Si se provee, el SDK intentará parsear la respuesta final del agente a este tipo (y el LLM será instruido para formatear su respuesta en consecuencia). Esto es útil para imponer salidas estructuradas (como respuestas JSON con campos específicos). Es una característica avanzada – para la mayoría de casos básicos, la salida final será solo una cadena.

  • Otras configuraciones: El agente también puede aceptar cosas como max_turns (para limitar cuántas iteraciones del bucle puede hacer antes de detenerse), o max_tokens, etc., vía la configuración del modelo. Muchas de estas pueden controlarse globalmente al ejecutar el agente (vía opciones de Runner.run). Tocaremos estos temas en contexto.

Con un agente básico definido, pasemos a darle más capacidades con herramientas.

Anadiendo y Usando Herramientas

Una de las características más poderosas de los sistemas agenticos es la capacidad de que los agentes usen herramientas. Las herramientas extienden lo que un agente LLM puede hacer – permiten que el agente tome acciones como navegar por la web, hacer cálculos, recuperar información de bases de datos o incluso ejecutar código. En el SDK de OpenAI Agents, las herramientas se implementan como funciones (callables de Python) que el agente puede invocar mediante una interfaz estandarizada (piensa en el mecanismo de llamadas a funciones de OpenAI).

Hay dos tipos principales de herramientas en este SDK:

  1. Herramientas alojadas (integradas) – Herramientas proporcionadas por OpenAI vía la API, como búsqueda web, recuperación de archivos o control de computadora. Estas se ejecutan en el lado de OpenAI en el entorno de la “API Responses” (Herramientas - OpenAI Agents SDK).
  2. Herramientas de función (personalizadas) – Herramientas que implementas en Python. El SDK facilita exponer una función Python (o coroutine) como una herramienta que un agente puede llamar (Herramientas - OpenAI Agents SDK).

Exploremos cada tipo y cómo usarlos.

Herramientas alojadas integradas

La API Responses de OpenAI ofrece algunas herramientas integradas que los agentes pueden usar sin que escribas código para esas capacidades. Actualmente, las herramientas integradas incluyen:

  • Búsqueda web – Permite a un agente buscar en la web y recuperar información en vivo (Herramientas - OpenAI Agents SDK).
  • Búsqueda de archivos (Recuperación) – Permite consultar una base vectorial de documentos (útil para generación aumentada con recuperación con tus propios datos) (Herramientas - OpenAI Agents SDK).
  • Computadora (Operación) – Permite a un agente simular el uso de una computadora (acciones de mouse, teclado) para realizar tareas en un entorno virtual (Herramientas - OpenAI Agents SDK).

Para usar herramientas alojadas, el modelo del agente debe ser el modelo de la API Responses de OpenAI (que es el valor por defecto). Por ejemplo, para habilitar búsqueda web y recuperación de archivos en un agente:

from agents import Agent, Runner, WebSearchTool, FileSearchTool

# Agente que puede usar herramientas de búsqueda web y búsqueda de archivos
agent = Agent(
    name="ResearchAgent",
    instructions="Eres un asistente de investigación que encuentra información en línea y en documentos.",
    tools=[
        WebSearchTool(),  # habilita búsquedas web
        FileSearchTool(
            max_num_results=3,
            vector_store_ids=["<TU_ID_VECTOR_STORE>"]  # especifica tu(s) vector store(s)
        )
    ]
)

result = Runner.run_sync(
    agent,
    "¿A qué cafetería debería ir, considerando mis preferencias y el clima hoy en SF?"
)
print(result.final_output)

En este código, creamos un ResearchAgent que tiene acceso a dos herramientas: una búsqueda web y una búsqueda de archivos. Las instrucciones del agente sugieren que debe usar estas herramientas según sea necesario. Cuando lo ejecutamos con una consulta, el agente puede elegir llamar a WebSearchTool para buscar cafeterías y consultar el clima, o usar FileSearchTool si hay datos relevantes almacenados en una base vectorial. La salida final será la respuesta del agente a la pregunta, presumiblemente usando la información recopilada.

Nota: Las herramientas alojadas como WebSearchTool y FileSearchTool son ejecutadas por los sistemas de OpenAI (el modelo “se conecta” a ellas) en lugar de ejecutarse localmente. Pueden generar costos adicionales o límites de uso (por ejemplo, OpenAI cobra el uso de la herramienta File Search por separado (Nuevas herramientas para construir agentes | OpenAI)). Asegúrate de consultar la documentación de herramientas de OpenAI y tener acceso apropiado si las usas. Si tu caso de uso no requiere estas herramientas específicas o prefieres control total local, puedes implementar funcionalidades similares como herramientas de función personalizadas (por ejemplo, usando la librería requests para búsqueda web o una librería local de base vectorial).

Herramientas de función personalizadas

Para la mayoría de casos, crearás tus propias herramientas escribiendo funciones Python. El SDK de Agents puede convertir automáticamente una función Python en una interfaz de herramienta que el LLM puede llamar. Usa introspección de Python y Pydantic para generar un esquema JSON para los argumentos de la función, e incluso usa el docstring de la función como descripción de la herramienta (Herramientas - OpenAI Agents SDK) (Herramientas - OpenAI Agents SDK). Esto es similar a la llamada a funciones de OpenAI – el LLM recibe el nombre de la función, descripción y esquema de parámetros, y si decide llamar a la función, produce un payload JSON que el SDK parsea y luego llama a tu función Python con esos argumentos.

Para declarar una función como herramienta, simplemente decórala con @function_tool (importado de agents). Por ejemplo:

from typing_extensions import TypedDict
from agents import Agent, Runner, function_tool

# Definir un TypedDict para entrada estructurada (si se necesita)
class Location(TypedDict):
    lat: float
    long: float

@function_tool
async def fetch_weather(location: Location) -> str:
    """Obtiene el clima para una ubicación dada.

    Args:
        location: La ubicación para obtener el clima (con 'lat' y 'long').
    """
    # En una implementación real, llamarías a una API de clima usando las coordenadas.
    # Aquí solo devolvemos una respuesta dummy.
    return "Actualmente está soleado en la ubicación dada."

@function_tool(name_override="fetch_data")
def read_file(path: str, directory: str | None = None) -> str:
    """Lee el contenido de un archivo.

    Args:
        path: La ruta al archivo a leer.
        directory: El directorio desde donde leer el archivo (opcional).
    """
    # En una implementación real, abrirías y leerías el archivo del disco o almacenamiento.
    return "<contenido del archivo>"

Desglosemos lo que sucede:

  • Importamos function_tool y lo usamos como decorador en nuestras funciones fetch_weather y read_file. Esto indica al SDK que trate estas funciones como herramientas.

  • La función fetch_weather es async y toma un Location TypedDict con floats lat y long, retornando una cadena. Le dimos un docstring describiendo qué hace. El SDK creará automáticamente una herramienta llamada "fetch_weather" (por defecto igual al nombre de la función) con una descripción tomada del docstring, y un esquema JSON para un argumento location (con lat y long como propiedades requeridas) (Herramientas - OpenAI Agents SDK) (Herramientas - OpenAI Agents SDK). Cuando el agente llame a esta herramienta, el SDK proveerá el parámetro location como un dict Python según el esquema.

  • La función read_file es síncrona (puede ser sync o async, ambos funcionan) y demuestra el uso de name_override en el decorador. Sobrescribimos el nombre de la herramienta a "fetch_data" para presentar un nombre más semántico al LLM, en lugar del nombre de función read_file. Esta herramienta lee un archivo desde una ruta dada (con un directorio opcional). Su docstring será usada como descripción a menos que deshabilitemos esa función. El SDK generará un esquema para dos parámetros: path (cadena) y directory (cadena opcional).

Después de definir las herramientas, intégralas con un agente:

agent = Agent(
    name="UtilityAgent",
    instructions="Eres un asistente útil con acceso a información de archivos y clima.",
    tools=[fetch_weather, read_file]  # pasamos los objetos función directamente
)

# Ejecutar el agente para probar las herramientas
result = Runner.run_sync(agent, "¿Cuál es el clima en latitud 37.77, longitud -122.42 y muéstrame el contenido del archivo README.md?")
for tool in agent.tools:
    print(f"Herramienta cargada: {tool.name} - {tool.description}")
print("Respuesta final:", result.final_output)

Cuando el agente recibe la pregunta, podría decidir llamar a fetch_weather con las coordenadas dadas, luego llamar a fetch_data (nuestro read_file) con "README.md". El SDK maneja las llamadas a funciones: parseará las solicitudes del LLM, ejecutará fetch_weather y read_file, obtendrá sus valores de retorno y los proveerá de vuelta al LLM como resultados de función. El LLM del agente luego incorpora esos resultados en su respuesta final. La salida impresa listaría las herramientas y sus descripciones y esquemas auto-generados, y la respuesta final podría ser una combinación de clima y contenido de archivo (dependiendo de cómo se formuló el prompt y el razonamiento del agente).

Cómo funciona: El SDK usa el módulo inspect de Python y la librería griffe para extraer nombres de parámetros, tipos y docstrings de tu función para construir un esquema (Herramientas - OpenAI Agents SDK). El decorador @function_tool puede configurarse con parámetros como name_override (como se mostró) o use_docstring_info=False si no quieres usar el docstring para descripciones. Bajo el capó, cuando un agente con herramientas de función corre, el LLM recibe definiciones de funciones (nombres, descripciones, especificaciones de parámetros) y emitirá un JSON especial si decide invocar una función. El SDK captura eso, llama a tu función Python y luego alimenta el valor de retorno (o error) de vuelta al LLM. Este ciclo continúa hasta que el LLM produce una salida final que no es función (Ejecutando agentes - OpenAI Agents SDK). Todo esto está abstraído para que solo te enfoques en escribir la función Python para la lógica de la herramienta.

Manejo de errores en herramientas: Si tu función herramienta lanza una excepción o retorna datos inválidos, ¿cómo lo maneja el agente? Por defecto, el SDK informará al LLM que ocurrió un error en la llamada a la herramienta (esto se hace vía un manejador de errores por defecto que retorna un mensaje de error al LLM) (Herramientas - OpenAI Agents SDK). Puedes personalizar este comportamiento. El decorador @function_tool acepta un parámetro failure_error_function donde puedes especificar una función personalizada para manejar errores. Por ejemplo, podrías manejar ciertas excepciones y retornar un mensaje de error específico al agente, o incluso decidir no capturarlo. Si pasas failure_error_function=None, la excepción cruda se propagará (por ejemplo, un ModelBehaviorError si la llamada a función del modelo fue malformada, o UserError si tu código herramienta falló) (Herramientas - OpenAI Agents SDK). En la mayoría de casos, dejar el comportamiento por defecto está bien – el agente simplemente verá un resultado de “error” y puede decidir disculparse o intentar otra estrategia.

Agentes como Herramientas

Además de las herramientas de función regulares, también puedes tratar a un Agente mismo como una herramienta para otro agente. Esta es una forma de crear una jerarquía de agentes: un agente de nivel superior puede llamar a agentes especializados como si llamara a una función. La diferencia entre una transferencia y un agente-herramienta (agente-como-herramienta) es que con una transferencia, el sub-agente toma el control completo (nuevo contexto de conversación), mientras que con un agente-herramienta, el agente principal permanece en control y simplemente obtiene el resultado del sub-agente como resultado de función.

Caso de uso: Supongamos que quieres un agente orquestador central que pueda llamar a agentes traductores especializados para diferentes idiomas, pero no quieres transferir completamente el control (para que el agente principal pueda potencialmente llamar a varios traductores y luego combinar resultados). Puedes hacer esto añadiendo agentes como herramientas.

Ejemplo:

from agents import Agent, Runner

# Definir dos agentes especializados (que también podrían ejecutarse por separado)
spanish_agent = Agent(name="SpanishAgent", instructions="Traduce el mensaje del usuario al español.")
french_agent  = Agent(name="FrenchAgent",  instructions="Traduce el mensaje del usuario al francés.")

# Crear un agente orquestador que puede usar los agentes anteriores como herramientas
orchestrator = Agent(
    name="OrchestratorAgent",
    instructions=(
        "Eres un orquestador de traducción. Tienes herramientas para traducir a español o francés. "
        "Si el usuario pide una traducción, llama a la herramienta relevante. De lo contrario, responde."
    ),
    tools=[
        spanish_agent.as_tool(tool_name="translate_to_spanish",
                               tool_description="Traduce el mensaje del usuario al español"),
        french_agent.as_tool(tool_name="translate_to_french",
                              tool_description="Traduce el mensaje del usuario al francés")
    ]
)

result = Runner.run_sync(orchestrator, "Por favor di 'Hola, ¿cómo estás?' en francés y español.")
print(result.final_output)
# El orquestador podría usar ambas herramientas y producir algo como:
# "Español: Hola, ¿cómo estás?\nFrancés: Bonjour, comment ça va ?"

Aquí usamos agent.as_tool() para envolver cada sub-agente como una herramienta con un nombre y descripción dados (Herramientas - OpenAI Agents SDK). Internamente, cuando el agente Orquestador decide llamar a translate_to_french, el SDK ejecutará el french_agent (usando el texto de consulta como entrada) y devolverá su salida final como el “resultado de función” al Orquestador. Esto permite encadenar agentes sin una transferencia formal.

Personalizando agentes-herramientas: El método as_tool es una conveniencia para casos simples. Puede que no exponga toda la configuración del agente. Por ejemplo, podrías querer que el sub-agente corra con un límite específico de max_turns o use un modelo diferente para esa llamada. En tales casos, siempre puedes crear una función herramienta personalizada que llame a Runner.run sobre un agente. Por ejemplo:

from agents import function_tool

@function_tool
async def run_my_agent(subquery: str) -> str:
    """Ejecuta un agente personalizado con un prompt dado."""
    custom_agent = Agent(name="MathAgent", instructions="Resuelve problemas matemáticos paso a paso.")
    result = await Runner.run(custom_agent, subquery, max_turns=5)
    return str(result.final_output)

Esto define una herramienta run_my_agent que, cuando es llamada por un agente, internamente crea un nuevo MathAgent y lo ejecuta con la subquery proporcionada (Herramientas - OpenAI Agents SDK) (Herramientas - OpenAI Agents SDK). Esta técnica te da control total: puedes establecer modelo, temperatura, turnos, etc., para la llamada al sub-agente. La desventaja es que la lógica ahora está en ti para implementar (mientras que agent.as_tool lo hacía automáticamente con valores por defecto).

En resumen, las herramientas – ya sean integradas, personalizadas o basadas en agentes – son cómo das a tu agente la capacidad de tomar acciones. A continuación, veremos cómo gestionar múltiples agentes más directamente vía transferencias, y cómo mantener contexto y estado entre estas interacciones.

Gestion del Contexto y Estado del Agente

En cualquier aplicación no trivial, tendrás alguna noción de contexto o estado que el agente debe conocer o mantener entre pasos. Hay dos tipos principales de contexto a considerar en el SDK de Agents (Gestión de contexto - OpenAI Agents SDK):

  1. Contexto local (estado del entorno) – datos y dependencias en el lado Python a los que tus herramientas o callbacks necesitan acceder.
  2. Contexto LLM (estado de la conversación) – información que el LLM ve en su prompt (historial de conversación, instrucciones de sistema, etc.) que constituye la “memoria” desde la perspectiva del modelo.

El SDK provee mecanismos para manejar ambos tipos de contexto.

Contexto local (datos del entorno Python)

El contexto local es cualquier objeto o dato Python que quieras pasar a la ejecución del agente, que luego puede ser accedido dentro de funciones herramienta o hooks de ciclo de vida (como un callback on_handoff). Por ejemplo, podrías tener una conexión a base de datos, un perfil de usuario, o una bandera simple que tus herramientas necesiten. No quieres incrustar esto en el prompt del LLM, pero sí quieres que tu código lo tenga a mano.

El SDK aborda esto mediante RunContextWrapper y el paso de contexto en la llamada Runner.run (Gestión de contexto - OpenAI Agents SDK):

  • Puedes crear un objeto Python arbitrario (puede ser tan simple como un dict, o un dataclass, etc.) que contenga tus datos de contexto.
  • Al llamar a Runner.run (o run_sync), pasa este objeto vía el argumento context=.
  • Cualquier función herramienta que necesite usar este contexto puede declarar un parámetro de tipo RunContextWrapper[TuTipo]. El SDK pasará entonces un objeto wrapper a esa herramienta, a través del cual puedes acceder a tu contexto (wrapper.context da el objeto subyacente) (Gestión de contexto - OpenAI Agents SDK).

Ejemplo:

from dataclasses import dataclass
from agents import Agent, RunContextWrapper, Runner, function_tool

@dataclass
class UserInfo:
    name: str
    id: int

# Una herramienta que usa el contexto para obtener info específica del usuario
@function_tool
def fetch_user_data(ctx: RunContextWrapper[UserInfo]) -> str:
    user = ctx.context  # este es el objeto UserInfo
    # Usando datos del contexto (estos datos NO son visibles para el LLM directamente)
    return f"El usuario {user.name} (id={user.id}) tiene 42 notificaciones."

# Crear un agente que tiene esta herramienta
agent = Agent[UserInfo](
    name="PersonalAssistant",
    instructions="Eres un asistente que conoce la info del usuario.",
    tools=[fetch_user_data]
)

# Preparar un objeto contexto
user_info = UserInfo(name="Alice", id=123)

# Ejecutar el agente con el contexto
result = Runner.run_sync(agent, "¿Cuántas notificaciones tengo?", context=user_info)
print(result.final_output)
# Salida esperada usa el resultado de la herramienta: "El usuario Alice (id=123) tiene 42 notificaciones."

Puntos clave en este ejemplo:

  • Definimos un UserInfo dataclass para contener datos específicos del usuario.
  • La herramienta fetch_user_data tiene un parámetro ctx: RunContextWrapper[UserInfo]. Cuando el agente llama a esta herramienta, recibirá un RunContextWrapper que envuelve nuestro objeto UserInfo. Luego recuperamos el contexto real vía ctx.context.
  • El agente se define como Agent[UserInfo] – usando un tipo genérico Python para el agente. Esto ayuda con la verificación estática de tipos (asegura que las herramientas y contexto del agente esperan el mismo tipo UserInfo) (Gestión de contexto - OpenAI Agents SDK) (Gestión de contexto - OpenAI Agents SDK). No es estrictamente necesario usar el genérico, pero es una buena característica para evitar errores.
  • Llamamos a Runner.run_sync con context=user_info. Esto adjunta nuestro objeto UserInfo a la ejecución. Todas las llamadas a herramientas, comprobaciones de guardarraíles y callbacks de transferencia durante esta ejecución llevarán este objeto contexto vía el wrapper.

El objeto contexto local nunca se envía al LLM (Gestión de contexto - OpenAI Agents SDK). Es puramente para uso de tu código Python. Esto significa que puedes poner datos sensibles o grandes allí sin preocuparte – el LLM no los verá a menos que explícitamente los pases mediante una herramienta o prompt.

Usos comunes del contexto local:

  • Pasar una sesión de base de datos o cliente API que las herramientas puedan usar.
  • Proveer datos específicos del usuario (preferencias, perfil) que algunas herramientas puedan necesitar para personalizar respuestas.
  • Cachear datos entre llamadas a herramientas, o acumular resultados.

Recuerda que todos los componentes en una sola ejecución de agente deben compartir el mismo tipo de contexto (Gestión de contexto - OpenAI Agents SDK). Si inicias un agente con un tipo de objeto contexto, no deberías llamar a una herramienta que espere un tipo de contexto diferente en esa misma ejecución.

Contexto LLM (conversacion y memoria)

Ahora hablemos del contexto desde la perspectiva del LLM – esencialmente el historial de conversación y prompt que el modelo ve. Los LLMs no tienen memoria persistente entre ejecuciones (a menos que se la suministres), y en cualquier paso dado el modelo solo conoce lo que está en el prompt (mensaje de sistema, turnos de conversación hasta ahora, etc.) (Gestión de contexto - OpenAI Agents SDK). El SDK de Agents maneja automáticamente el contexto para bucles multi-paso de agentes y transferencias multiagente, pero tú como desarrollador debes saber cómo proveer información adicional al modelo cuando sea necesario.

Formas de proveer contexto al LLM:

  • Instrucciones de sistema: Ya vimos que puedes poner información en agent.instructions. Esto es similar a un prompt de sistema que permanece constante (o puede generarse dinámicamente por ejecución). Úsalo para contexto global que el agente siempre debe tener. Por ejemplo, si un agente siempre debe conocer el nombre del usuario o la fecha actual, podrías incluir eso en sus instrucciones (quizás templando la cadena de instrucciones con esos valores en tiempo de ejecución) (Gestión de contexto - OpenAI Agents SDK).

  • Consulta/entrada del usuario: Cuando llamas a Runner.run, provees una input – a menudo esta es la consulta del usuario. Eso se convierte en el último mensaje de usuario en el prompt. Si tienes algún contexto dinámico que solo es relevante para esta consulta, podrías anteponerlo o incluirlo en la entrada. El SDK permite que la input sea una cadena cruda o una lista de diccionarios de mensajes (cada uno con un rol y contenido) (Ejecutando agentes - OpenAI Agents SDK). En uso avanzado, podrías usar result.to_input_list() de una ejecución previa (que te da una lista de mensajes previos) y luego añadir un nuevo mensaje de usuario (como se muestra más adelante) (Ejecutando agentes - OpenAI Agents SDK). En resumen, lo que pases como input será visto por el agente como la última consulta del usuario (o conversación completa si pasas una lista).

  • Herramientas para recuperación: En lugar de meter toda la posible información relevante en el prompt (lo que podría alcanzar límites de tokens), un patrón común es proveer herramientas que obtengan información bajo demanda. Por ejemplo, si el LLM podría necesitar algunos datos, puedes exponerlos vía una herramienta (como una herramienta fetch_user_profile o search_documents). El LLM llamará a la herramienta cuando determine que necesita esa información (Gestión de contexto - OpenAI Agents SDK). Así, el contexto se recupera justo a tiempo. Por ejemplo, usando FileSearchTool (base vectorial) o una herramienta personalizada query_database permite al agente obtener conocimiento suplementario más allá de su prompt base.

  • Transferencia con datos de entrada: Si delegas a otro agente, podrías querer pasarle información. La función handoff() del SDK soporta un input_type para estructurar datos que van al siguiente agente (Transferencias - OpenAI Agents SDK) (Transferencias - OpenAI Agents SDK). Por ejemplo, un agente de triaje podría transferir con un mensaje como “razón de escalada: X” al siguiente agente especificando un modelo (como un Pydantic BaseModel) como input_type. El LLM proveerá valores para ese modelo al iniciar la transferencia. Veremos más en la siguiente sección.

En general, el historial de conversación (memoria) se rastrea automáticamente dentro de una sola llamada a Runner.run. Si el agente hace múltiples iteraciones (debido a herramientas o transferencias), los pasos intermedios son parte del contexto de conversación alimentado a llamadas LLM subsecuentes. Por ejemplo, si un agente llama a una herramienta y obtiene un resultado, la siguiente llamada LLM incluirá el resultado de la herramienta en el prompt (probablemente como un mensaje de asistente indicando el resultado de la función). El SDK maneja este ensamblaje vía el Protocolo de Contexto de Modelo (MCP), asegurando que el modelo vea una cadena de pensamiento.

Sin embargo, entre ejecuciones separadas (llamadas separadas a Runner.run), el SDK no recuerda nada automáticamente. Esta falta de estado es por diseño – depende de ti llevar el contexto relevante si quieres una conversación multi-turno con un usuario. El SDK ayuda vía el método to_input_list() del objeto RunResult, que provee la conversación de esa ejecución en un formato listo para usarse como entrada para la siguiente ejecución (Ejecutando agentes - OpenAI Agents SDK).

Ejemplo de conversación multi-turno:

from agents import Agent, Runner, trace

agent = Agent(name="Assistant", instructions="Responde muy concisamente.")

# Supongamos que thread_id es un identificador para la sesión de conversación
thread_id = "conv-12345"

# Primera pregunta del usuario
with trace(workflow_name="Conversation", group_id=thread_id):
    result1 = Runner.run_sync(agent, "¿En qué ciudad está el Golden Gate Bridge?")
print("Agente:", result1

Sigue leyendo

Posts relacionados