Chamada de ferramenta programática com a API de Respostas do OpenAI do Azure

A chamada de ferramenta programática permite que um modelo use código para orquestrar ferramentas durante uma solicitação da Responses API. Em vez de exigir uma interação do modelo separada para cada invocação de ferramenta, o modelo pode gerar um programa que chama ferramentas e processa seus resultados. O programa pode executar operações como ramificação ou iteração.

Este artigo explica quando a chamada de ferramenta programática é útil e como ela difere da chamada de função, da chamada de ferramenta paralela e da pesquisa de ferramentas.

Considerações sobre disponibilidade

Antes de implementar a chamada programática de ferramenta, confirme se sua implantação de modelo do Azure OpenAI e a versão do SDK dão suporte ao recurso. Não suponha que o suporte para a Responses API também estabeleça suporte para chamada programática de ferramentas.

Para obter o endpoint e a configuração de autenticação, consulte Usar a API Responses do Azure OpenAI.

Chamada de ferramenta programática e chamada de função

Com a chamada de função padrão, seu aplicativo normalmente participa de cada etapa de chamada de ferramenta:

Modelo –> chamada de ferramenta –> aplicativo executa a ferramenta –> modelo –> próxima chamada de ferramenta –> aplicativo executa a ferramenta –> modelo

Com a chamada de ferramenta programática, o modelo pode gerar código que orquestra várias operações de ferramenta:

Modelo –> programa gerado –> operações de ferramenta –> resultado do programa –> modelo

Essa abordagem pode reduzir o número de interações do modelo necessárias para fluxos de trabalho que envolvem várias ferramentas.

Esses fluxos ilustram a diferença conceitual na orquestração. Eles não especificam quais operações seu aplicativo ou o serviço executam.

Exemplo: comparar inventário com demanda

Este Python exemplo expõe duas funções definidas pelo aplicativo que retornam dados de inventário e demanda de exemplo. O modelo usa a chamada de ferramenta programática para comparar os resultados. Seu aplicativo executa as funções e retorna seus resultados para que o runtime possa retomar o programa gerado.

Os blocos de código formam um script. Combine-os na ordem mostrada.

cliente do Azure OpenAI

Use uma implantação do Azure OpenAI que dê suporte à chamada programática de ferramentas e a uma versão do SDK da OpenAI que inclua output_schema, allowed_callers e informações do chamador. Instale os pacotes azure-identity e openai em seu ambiente de Python:

pip install --upgrade openai azure-identity

Configure a autenticação do Microsoft Entra ID, conforme descrito em Usar a API de Respostas do Azure OpenAI. Sua identidade precisa de permissão para chamar sua implantação do Azure OpenAI.

Substitua YOUR-RESOURCE-NAME pelo nome do recurso. O model valor mais adiante no exemplo é seu nome de implantação Azure, não um identificador de catálogo de modelos.

import json

from azure.identity import DefaultAzureCredential, get_bearer_token_provider
from openai import OpenAI

# Use the Azure OpenAI v1 endpoint and Microsoft Entra ID authentication.
endpoint = "https://YOUR-RESOURCE-NAME.openai.azure.com/openai/v1/"
credential = DefaultAzureCredential()
token_provider = get_bearer_token_provider(
    credential, "https://cognitiveservices.azure.com/.default"
)
openai = OpenAI(base_url=endpoint, api_key=token_provider)

Funções definidas pelo aplicativo

As funções retornam dados de exemplo fixos: 42 unidades disponíveis e 31 unidades solicitadas para o SKU especificado. Substitua as implementações deles por suas fontes de dados de inventário e demanda em seu aplicativo.

def get_inventory(sku):
    return {"sku": sku, "available_units": 42}


def get_demand(sku):
    return {"sku": sku, "requested_units": 31}


implementations = {
    "get_inventory": get_inventory,
    "get_demand": get_demand,
}

Definições de ferramenta

Cada função declara um esquema de entrada e um output_schema descrevendo o resultado JSON. Definir allowed_callers como ["programmatic"] disponibiliza a função para programas gerados em vez de chamadas diretas ao modelo.

tools = [
    {
        "type": "function",
        "name": "get_inventory",
        "description": "Return the SKU and available inventory units.",
        "strict": True,
        "parameters": {
            "type": "object",
            "properties": {"sku": {"type": "string"}},
            "required": ["sku"],
            "additionalProperties": False,
        },
        "output_schema": {
            "type": "object",
            "properties": {
                "sku": {"type": "string"},
                "available_units": {"type": "number"},
            },
            "required": ["sku", "available_units"],
            "additionalProperties": False,
        },
        "allowed_callers": ["programmatic"],
    }
]

Adicione a função de demanda e o recurso de chamada de ferramenta programática à mesma lista:

tools.extend([
    {
        "type": "function",
        "name": "get_demand",
        "description": "Return the SKU and requested demand units.",
        "strict": True,
        "parameters": {
            "type": "object",
            "properties": {"sku": {"type": "string"}},
            "required": ["sku"],
            "additionalProperties": False,
        },
        "output_schema": {
            "type": "object",
            "properties": {
                "sku": {"type": "string"},
                "requested_units": {"type": "number"},
            },
            "required": ["sku", "requested_units"],
            "additionalProperties": False,
        },
        "allowed_callers": ["programmatic"],
    },
    {"type": "programmatic_tool_calling"},
])

Resultados da ferramenta e informações de chamador

O aplicativo despacha chamadas de função por nome e serializa cada resultado. Preserve as informações da chamada caller para que o runtime possa retomar o programa correto. Nomes de ferramentas desconhecidos e argumentos inválidos geram erros em vez de retornar resultados fabricados.

def run_tool(call):
    run = implementations.get(call.name)
    if run is None:
        raise ValueError(f"Unknown tool: {call.name}")

    arguments = json.loads(call.arguments)
    if (
        not isinstance(arguments, dict)
        or set(arguments) != {"sku"}
        or not isinstance(arguments["sku"], str)
    ):
        raise ValueError(f"Invalid arguments for tool: {call.name}")

    result = run(**arguments)
    output = {
        "type": "function_call_output",
        "call_id": call.call_id,
        "output": json.dumps(result),
    }
    if call.caller is not None:
        output["caller"] = call.caller.model_dump(exclude_none=True)
    return output

Continuação da resposta

Substitua YOUR-MODEL-DEPLOYMENT pelo nome da implantação do Azure OpenAI com suporte.

Com store=False, o aplicativo leva a conversa adiante. Preservar cada item de saída, incluindo itens de programa e de raciocínio, antes de adicionar resultados da ferramenta. O loop para em uma resposta final ou recusa e gera um erro se uma resposta falhar ou o limite de solicitação for atingido.

input_items = [
    {"role": "user", "content": "Compare inventory with demand for sku_123."}
]
MAX_REQUESTS = 10
for _ in range(MAX_REQUESTS):
    response = openai.responses.create(
        model="YOUR-MODEL-DEPLOYMENT",
        store=False, input=input_items, tools=tools,
    )
    if response.status != "completed":
        raise RuntimeError(f"Response ended with status {response.status}")
    input_items.extend(
        item.model_dump(exclude_none=True) for item in response.output
    )
    calls = [item for item in response.output if item.type == "function_call"]
    if calls:
        input_items.extend(run_tool(call) for call in calls)
        continue
    if response.output_text:
        print(response.output_text)
        break
    refusals = [
        part.refusal for item in response.output if item.type == "message"
        for part in item.content if part.type == "refusal"
    ]
    if refusals:
        print("\n".join(refusals))
        break
else:
    raise RuntimeError("Programmatic tool calling exceeded the request limit")

A resposta final deve explicar que o inventário abrange a demanda: 42 unidades disponíveis menos 31 unidades solicitadas deixam 11 unidades. A redação pode variar. Uma recusa será impressa se o modelo recusar a solicitação.

O aplicativo executa as funções de inventário e demanda, enquanto o programa gerado coordena seu uso e processa os resultados.

Quando usar a chamada de ferramenta programática

Considere a chamada de ferramenta programática quando uma tarefa:

  • Requer várias chamadas de ferramenta relacionadas.
  • Contém lógica condicional.
  • Precisa de iteração sobre os resultados da ferramenta.
  • Executa o processamento de dados intermediários antes de produzir uma resposta.
  • Caso contrário, exigiria interações repetidas do modelo para coordenar ferramentas.

Para fluxos de trabalho simples que envolvem uma ou duas funções independentes, a chamada de função padrão pode ser mais fácil de implementar.

Chamada de ferramenta programática e chamada de ferramenta paralela

Chamada de ferramenta paralela e chamada de ferramenta programática abordam diferentes necessidades de orquestração.

Use chamadas paralelas de ferramentas quando várias operações independentes puderem ser executadas ao mesmo tempo. Por exemplo, recupere a previsão do tempo para cinco locais independentes.

Use a chamada de ferramenta programática quando as operações de ferramenta exigirem coordenação, computação intermediária, ramificação ou iteração. Por exemplo, recupere os pedidos de um cliente, selecione pedidos que correspondam a uma condição e consulte as informações de envio desses pedidos.

A pesquisa de ferramentas controla quais definições de ferramenta são carregadas no contexto do modelo.

A chamada de ferramenta programática controla como o modelo orquestra as ferramentas depois que elas estão disponíveis.

A distinção é entre a descoberta de ferramentas e a orquestração de ferramentas. A relação conceitual deles não estabelece se a implantação dá suporte ao uso de ambos os recursos na mesma solicitação.

Considerações de segurança

Trate os programas gerados como código não confiável.

Ao expor ferramentas:

  • Siga os princípios do menor privilégio.
  • Validar argumentos da ferramenta.
  • Restringir o acesso a operações confidenciais.
  • Autenticar e autorizar operações independentemente da saída do modelo.
  • Registre a execução da ferramenta para auditoria e diagnóstico sem registrar segredos ou dados confidenciais desnecessários.
  • Evite expor dados ou ferramentas desnecessárias.

Não confie no código gerado pelo modelo como um limite de autorização.