0Pricing
AI Engineering Academy · Aula

Chamadas de funções em paralelo

Lide com respostas nas quais o modelo chama várias funções simultaneamente, execute-as em paralelo com asyncio e reúna os resultados em uma única chamada subsequente à API.

Chamadas de funções em paralelo é uma aula grátis de AI Engineering Academy no CoddyKit. Esta é a aula 3 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de AI Engineering Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de AI Engineering Academy inclui 4 aulas no total.

O que são chamadas de funções em paralelo?

Os modelos da OpenAI podem chamar várias funções simultaneamente em uma única resposta quando a resposta exige informações de várias fontes independentes. Em vez de encadear chamadas de ferramentas sequencialmente — cada uma aguardando a anterior — o modelo emite várias chamadas de uma só vez. Sua aplicação as executa em paralelo e envia todos os resultados juntos, reduzindo drasticamente a latência.

Reconhecendo chamadas de ferramentas em paralelo

Quando o modelo emite chamadas de ferramentas em paralelo, a mensagem de resposta contém uma lista tool_calls com mais de uma entrada. Cada entrada tem um id exclusivo, o nome da função e os argumentos. Você precisa processar todas elas antes de fazer a chamada subsequente à API — o modelo espera resultados para cada chamada de ferramenta emitida.

from openai import OpenAI
import json

client = OpenAI()

# A question that naturally requires two independent lookups
response = client.chat.completions.create(
    model='gpt-4o',
    messages=[{'role': 'user', 'content': 'Compare the weather in London and Tokyo right now.'}],
    tools=tools
)

message = response.choices[0].message
print('Number of tool calls:', len(message.tool_calls))
# Might print: Number of tool calls: 2

for tc in message.tool_calls:
    print(f'  {tc.function.name}({tc.function.arguments})')
# get_current_weather({"location": "London"})
# get_current_weather({"location": "Tokyo"})

Executando chamadas de ferramentas com asyncio

Execute várias chamadas de ferramentas simultaneamente usando asyncio.gather(). Cada função de ferramenta é executada em uma corrotina separada, e todos os resultados são coletados quando todas as corrotinas terminam. Isso é muito mais rápido do que a execução sequencial quando cada chamada de ferramenta faz uma solicitação de rede.

import asyncio
import json

async def execute_tool_call_async(tool_call) -> tuple:
    '''Execute a single tool call and return (tool_call_id, result).'''
    name = tool_call.function.name
    args = json.loads(tool_call.function.arguments)

    # Async version of your tool (uses httpx, aiohttp, etc.)
    if name == 'get_current_weather':
        result = await async_get_weather(**args)
    elif name == 'get_stock_price':
        result = await async_get_stock(**args)
    else:
        result = f'Unknown tool: {name}'

    return tool_call.id, str(result)

async def execute_all_parallel(tool_calls) -> list:
    '''Execute all tool calls concurrently.'''
    tasks = [execute_tool_call_async(tc) for tc in tool_calls]
    results = await asyncio.gather(*tasks, return_exceptions=True)
    return results

Enviando todos os resultados juntos

Depois de executar todas as chamadas de ferramentas em paralelo, adicione cada resultado como uma mensagem role='tool' separada à conversa. Cada mensagem deve incluir o tool_call_id correspondente. Envie todas em uma única chamada subsequente à API para que o modelo possa sintetizar todos os resultados em uma resposta coerente.

async def run_parallel_tool_calls(user_message: str) -> str:
    messages = [{'role': 'user', 'content': user_message}]

    response = client.chat.completions.create(
        model='gpt-4o', messages=messages, tools=tools
    )
    assistant_message = response.choices[0].message
    messages.append(assistant_message)  # Add assistant's tool_calls

    if response.choices[0].finish_reason == 'tool_calls':
        # Execute all tool calls in parallel
        results = await execute_all_parallel(assistant_message.tool_calls)

        # Add all results to conversation
        for tool_call_id, result in results:
            messages.append({
                'role': 'tool',
                'tool_call_id': tool_call_id,
                'content': result
            })

        # One more API call to synthesize results
        final = client.chat.completions.create(model='gpt-4o', messages=messages)
        return final.choices[0].message.content

    return assistant_message.content

Usando ThreadPoolExecutor para ferramentas síncronas

Se suas funções de ferramenta forem síncronas (usando requests em vez de httpx assíncrono), você ainda poderá executá-las em paralelo usando concurrent.futures.ThreadPoolExecutor. A configuração é mais simples, mas ligeiramente menos eficiente do que usar código totalmente assíncrono.

from concurrent.futures import ThreadPoolExecutor, as_completed
import json

def execute_all_with_threads(tool_calls) -> list:
    results = []
    with ThreadPoolExecutor(max_workers=len(tool_calls)) as executor:
        future_to_id = {
            executor.submit(execute_tool_call, tc): tc.id
            for tc in tool_calls
        }
        for future in as_completed(future_to_id):
            tool_call_id = future_to_id[future]
            try:
                result = future.result(timeout=15)
            except Exception as e:
                result = f'Tool failed: {str(e)}'
            results.append((tool_call_id, str(result)))
    return results

Lidando com falhas individuais de ferramentas

Ao executar chamadas de ferramentas em paralelo, uma pode falhar enquanto outras são bem-sucedidas. Nunca permita que uma falha bloqueie as outras. Use return_exceptions=True em asyncio.gather() para coletar todos os resultados, mesmo que algumas chamadas gerem exceções. Converta as exceções em strings de erro para que o modelo receba todos os resultados e possa raciocinar sobre falhas parciais.

async def safe_execute_all(tool_calls) -> list:
    tasks = [execute_tool_call_async(tc) for tc in tool_calls]
    raw_results = await asyncio.gather(*tasks, return_exceptions=True)

    results = []
    for tc, result in zip(tool_calls, raw_results):
        if isinstance(result, Exception):
            results.append((tc.id, f'Tool error: {str(result)}'))
        else:
            tool_call_id, output = result
            results.append((tool_call_id, output))
    return results

Quando os modelos usam chamadas em paralelo

O modelo emite chamadas de ferramentas em paralelo quando determina que as informações necessárias podem ser obtidas de forma independente — um resultado não depende de outro. Exemplos: obter preços de ações para vários códigos, consultar o clima em várias cidades ou consultar várias tabelas de banco de dados. As chamadas sequenciais ocorrem quando os resultados são dependentes — primeiro consultar o ID de um usuário e depois obter os pedidos desse ID.

Limitando a taxa de chamadas em paralelo

Executar muitas chamadas de ferramentas em paralelo pode sobrecarregar APIs externas com solicitações simultâneas. Use um semáforo para limitar o número máximo de chamadas de ferramentas simultâneas. Isso respeita os limites de taxa da API e ainda executa as chamadas com mais eficiência do que o processamento totalmente sequencial.

import asyncio

async def rate_limited_execute_all(tool_calls, max_concurrent: int = 5) -> list:
    semaphore = asyncio.Semaphore(max_concurrent)

    async def limited_call(tc):
        async with semaphore:
            return await execute_tool_call_async(tc)

    tasks = [limited_call(tc) for tc in tool_calls]
    results = await asyncio.gather(*tasks, return_exceptions=True)

    return [
        (tc.id, str(r) if not isinstance(r, Exception) else f'Error: {r}')
        for tc, r in zip(tool_calls, results)
    ]

Encadeando chamadas sequenciais e em paralelo

Fluxos de trabalho reais de agentes frequentemente combinam chamadas sequenciais e em paralelo. O modelo pode primeiro chamar lookup_user(email) e, usando o user_id retornado, chamar get_orders(user_id) e get_preferences(user_id) em paralelo. Implemente o loop externo para detectar quais chamadas podem ser paralelizadas (independentes) e quais precisam ser sequenciais (dependentes).

async def multi_round_agent(user_message: str) -> str:
    messages = [{'role': 'user', 'content': user_message}]
    MAX_ROUNDS = 5

    for _ in range(MAX_ROUNDS):
        response = client.chat.completions.create(
            model='gpt-4o', messages=messages, tools=tools
        )
        choice = response.choices[0]
        messages.append(choice.message)

        if choice.finish_reason == 'stop':
            return choice.message.content  # Done

        if choice.finish_reason == 'tool_calls':
            # Execute all tool calls in parallel (may be 1 or many)
            results = await safe_execute_all(choice.message.tool_calls)
            for tc_id, result in results:
                messages.append({'role': 'tool', 'tool_call_id': tc_id, 'content': result})
            # Loop continues for potentially sequential next call

    return 'Max rounds reached.'

Medindo a melhoria da latência

As chamadas de ferramentas em paralelo podem reduzir drasticamente a latência. Se cada uma de três chamadas de ferramentas levar 500 ms sequencialmente, o total será de 1500 ms. Executá-las em paralelo reduz o tempo para aproximadamente 500 ms — uma aceleração de 3 vezes. Sempre meça e compare a execução sequencial e em paralelo no seu cenário específico, levando em conta a sobrecarga da simultaneidade e as restrições de limite de taxa.

import time
import asyncio

async def benchmark_parallel_vs_sequential():
    tool_calls = [...]  # 5 independent tool calls

    # Sequential
    start = time.time()
    for tc in tool_calls:
        await execute_tool_call_async(tc)
    sequential_time = time.time() - start

    # Parallel
    start = time.time()
    await asyncio.gather(*[execute_tool_call_async(tc) for tc in tool_calls])
    parallel_time = time.time() - start

    print(f'Sequential: {sequential_time:.2f}s')
    print(f'Parallel:   {parallel_time:.2f}s')
    print(f'Speedup:    {sequential_time/parallel_time:.1f}x')

Depurando chamadas de ferramentas em paralelo

Ao depurar problemas em chamadas de ferramentas em paralelo, registre todo o ciclo de solicitação e resposta: a mensagem do modelo com todos os tool_calls, cada resultado adicionado à conversa e a resposta final do modelo. Se um resultado de ferramenta estiver ausente ou fora de ordem, o modelo poderá produzir respostas inconsistentes. O registro estruturado usando tool_call_id como chave de correlação facilita muito o rastreamento dos problemas.

Verificação rápida

Teste sua compreensão sobre chamadas de funções em paralelo com a OpenAI.

Recapitulação da lição

Nesta lição, você aprendeu: as chamadas paralelas de ferramentas aparecem como várias entradas na lista tool_calls, asyncio.gather as executa simultaneamente para obter a máxima velocidade e cada resultado precisa do tool_call_id correspondente ao ser enviado de volta ao modelo. A seguir, vamos criar uma interface de banco de dados em linguagem natural usando chamadas de função para traduzir consultas em linguagem comum para SQL.

Perguntas Frequentes

A aula “Chamadas de funções em paralelo” é grátis?

Sim — o texto completo de “Chamadas de funções em paralelo” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de AI Engineering Academy, atualize para CoddyKit PRO. O curso de AI Engineering Academy inclui 4 aulas no total.

O que vou aprender em “Chamadas de funções em paralelo”?

Lide com respostas nas quais o modelo chama várias funções simultaneamente, execute-as em paralelo com asyncio e reúna os resultados em uma única chamada subsequente à API. Você pratica AI Engineering Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar AI Engineering Academy?

Nenhuma experiência prévia é necessária. AI Engineering Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 3 de 4.

Quanto tempo leva a aula “Chamadas de funções em paralelo”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de AI Engineering Academy?

Sim. Cada aula de AI Engineering Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Definindo esquemas de funções para a API
  2. Processando chamadas de ferramentas na sua aplicação
  3. Chamadas de funções em paralelo
  4. Criando uma interface de banco de dados em linguagem natural
← Voltar para AI Engineering Academy