DEV Community

Cover image for Cómo usar OpenAI Decisions API con Strands Agents
Elizabeth Fuentes L for AWS Español

Posted on Originally published at dev.to

Cómo usar OpenAI Decisions API con Strands Agents

OpenAI lanzó una API de Decisiones. No es un modelo de chat al que convences para que elija: responde una pregunta acotada directamente. Le das una petición y una lista fija de opciones, y devuelve una de ellas con una confianza. Sin texto generado, sin opciones que invente, nada que parsear. La elección que devuelve siempre es una de las que le pasaste.

Un agente está lleno de preguntas acotadas, así que la conecté a un agente de Strands Agents de dos formas. Las dos están en el repo y las dos corren. Aquí están, lado a lado.

La llamada, una vez

Ambos usos comparten la misma forma de petición, a través del cliente asíncrono oficial:

from openai import AsyncOpenAI

oai = AsyncOpenAI()  # lee OPENAI_API_KEY
resp = await oai.decisions.create(
    model="gpt-6-luna",
    input="How much is a room at the Cliffside Resort?",
    questions=[{
        "type": "choice",
        "name": "pick",
        "instructions": "Which option best answers this request?",
        "choices": [            # un {value, description} por opción
            {"value": "get_hotel_room_rates", "description": "Nightly room rates for a hotel"},
            {"value": "get_weather", "description": "Current weather for a city"},
        ],
    }],
)
answer = next(a for a in resp.answers if a.name == "pick")
answer.choice        # -> "get_hotel_room_rates"
answer.confidence    # -> 0.97
Enter fullscreen mode Exit fullscreen mode

Lo único que cambia entre los dos usos es cuáles son las opciones: herramientas en uno, modelos en el otro. Los dos están abajo. Uno reduce la caja de herramientas que ve el modelo; el otro elige qué modelo se ejecuta. Usa el que tu agente necesite, o los dos.

Forma 1: elegir la herramienta, y recortar los tokens

Dale a un modelo pequeño cuarenta herramientas que se solapan y elegirá la equivocada o inventará una. Cada herramienta además son tokens que paga en cada turno: nombre, descripción, esquema. Elegir la herramienta relevante antes de que el modelo corra arregla las dos cosas, y en Strands esa elección vive en un hook (BeforeModelCallEvent), porque cambia lo que el agente ve: el hook reduce el registro de herramientas del agente a la elegida. El selector es una función; todo lo demás es el hook.

oai_choices = [{"value": t.tool_name, "description": t.tool_spec["description"]} for t in ALL_TOOLS]

async def openai_select(query):
    resp = await oai.decisions.create(
        model="gpt-6-luna", input=query,
        questions=[{"type": "choice", "name": "tool",
                    "instructions": "Which tool answers this request?", "choices": oai_choices}],
    )
    answer = next(a for a in resp.answers if a.name == "tool")
    return [BY_NAME[answer.choice]]

agent = Agent(model=AGENT_MODEL, tools=ALL_TOOLS, system_prompt=PROMPT,
              hooks=[ToolFilterHook(openai_select)], callback_handler=None)
await agent.invoke_async("How much is a room at the Cliffside Resort?")
Enter fullscreen mode Exit fullscreen mode

Sobre el pool de 40 herramientas del demo, cada elección es una decisión acotada en vez de un nombre de herramienta generado:

get_hotel_room_rates   (confidence 1.00)  <- How much is a room at the Cliffside Resort?
get_weather_forecast   (confidence 0.99)  <- What's the weather forecast for Tokyo next week?
book_hotel             (confidence 0.97)  <- Book Cliffside Resort for John Smith for 2 nights
Enter fullscreen mode Exit fullscreen mode

Forma 2: elegir el modelo, y ajustar el costo a la petición

No toda petición necesita tu modelo más capaz. Enviar las fáciles a un modelo pequeño y barato, y reservar el modelo capaz para el trabajo difícil, mantiene la calidad donde importa sin pagar precio alto por preguntas triviales.

Strands enruta cada petición a uno de varios modelos con ModelRouter, y la elección es una RoutingStrategy enchufable. Esta elección no vive en un hook: pasas el router como el modelo del agente, que es la vía de Strands para elegir el modelo (la documentación lo dice claro: pasa el router como el modelo, no a través de plugins). Conecta la API de Decisiones como el clasificador: los candidatos del router se vuelven las opciones, y el modelo de decisión elige qué modelo atiende el turno. Juzga la petición contra la descripción de cada candidato, y no sabe nada de los modelos en sí.

class OpenAIDecisionsRoutingStrategy(RoutingStrategy):
    def __init__(self):
        self._oai = AsyncOpenAI()

    async def select(self, context, **kwargs):
        if context.attempts:          # enruta solo el intento inicial
            return None
        query = _user_text(context)
        choices = [{"value": c.name, "description": c.description or c.name} for c in context.candidates]
        resp = await self._oai.decisions.create(
            model="gpt-6-luna", input=query,
            questions=[{"type": "choice", "name": "model",
                        "instructions": "Which model should handle this request?", "choices": choices}],
        )
        answer = next(a for a in resp.answers if a.name == "model")
        return next((c for c in context.candidates if c.name == answer.choice), None)

router = ModelRouter(models=[routine, advanced], strategy=OpenAIDecisionsRoutingStrategy())
agent = Agent(model=router, callback_handler=None)
Enter fullscreen mode Exit fullscreen mode

Las consultas rutinarias van al modelo pequeño, las de razonamiento al fuerte:

routine   (confidence 1.0)   <- What time zone is Tokyo in?
routine   (confidence 1.0)   <- What is the capital of Australia?
advanced  (confidence 1.0)   <- Design a rollback-safe idempotency-key migration
advanced  (confidence 0.98)  <- Compare optimistic vs pessimistic locking, recommend one
Enter fullscreen mode Exit fullscreen mode

¿Cuál de las dos?

Las dos son el mismo patrón de una sola llamada detrás de vías distintas de Strands: un hook para la herramienta, un router para el modelo. Un modelo de decisión es un elector, así que dejas de pedirle a un generador que elija y de esperar que su texto se parsee en una opción real. ¿Cómo lo apuntarías a tu agente? ¿Cuál elección de tu loop es la que no le confías a un modelo de chat?

Pruébalo tú

Las dos formas corren de principio a fin con tus propias preguntas. Configura OPENAI_API_KEY y adelante:

git clone https://github.com/elizabethfuentes12/why-agents-fail-sample-for-amazon-agentcore
cd why-agents-fail-sample-for-amazon-agentcore/02-semantic-tools-demo
uv venv && uv pip install -r requirements.txt
Enter fullscreen mode Exit fullscreen mode

Si te ahorra tiempo, dale una ⭐ al repo. Ayuda a que otros lo encuentren.

Recursos


¡Gracias!

🇻🇪🇨🇱 Dev.to Linkedin GitHub Twitter Instagram YouTube

Top comments (0)