AI Engineering Academy · leksjon

Parallell funksjonskalling

Håndter svar der modellen kaller flere funksjoner samtidig, kjør dem parallelt med asyncio, og samle resultatene i ett enkelt oppfølgende API-kall.

Leksjon 3 av 413 trinn

Parallell funksjonskalling er en gratis leksjon i AI Engineering Academy på CoddyKit. Dette er leksjon 3 av 4. Du kan lese hele leksjonen gratis nedenfor – og deretter øve praktisk i nettleseren med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i AI Engineering Academy, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i AI Engineering Academy inneholder totalt 4 leksjoner.

Hva er parallell funksjonskalling?

OpenAIs modeller kan kalle flere funksjoner samtidig i ett enkelt svar når svaret krever informasjon fra flere uavhengige kilder. I stedet for å lenke verktøykall sekvensielt – der hvert kall venter på det forrige – sender modellen ut flere verktøykall samtidig. Applikasjonen utfører dem parallelt og sender alle resultatene tilbake samlet, noe som reduserer ventetiden betydelig.

Gjenkjenne parallelle verktøykall

Når modellen utfører parallelle verktøykall, inneholder svarmeldingen en tool_calls-liste med mer enn ett element. Hvert element har en unik id, et funksjonsnavn og argumenter. Du må behandle alle før du gjør det neste API-kallet – modellen forventer resultater for hvert verktøykall den utførte.

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"})

Utføre verktøykall med asyncio

Kjør flere verktøykall samtidig ved hjelp av asyncio.gather(). Hver verktøyfunksjon kjører i en separat coroutine, og alle resultatene samles inn når alle coroutine-ene er fullført. Dette er langt raskere enn sekvensiell utføring når hvert verktøykall sender en nettverksforespørsel.

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

Sende alle resultater tilbake samlet

Etter at alle parallelle verktøykall er utført, legger du hvert resultat til som en separat role='tool'-melding i samtalen. Hver melding må inneholde den samsvarende tool_call_id. Send alle i ett enkelt oppfølgende API-kall, slik at modellen kan sammenfatte alle resultatene til ett helhetlig svar.

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

Bruke ThreadPoolExecutor for synkrone verktøy

Hvis verktøyfunksjonene dine er synkrone (og bruker requests i stedet for asynkrone httpx), kan du likevel kjøre dem parallelt med concurrent.futures.ThreadPoolExecutor. Dette er enklere å sette opp, men litt mindre effektivt enn ren asynkron kode.

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

Håndtere individuelle verktøyfeil

Når verktøykall utføres parallelt, kan ett mislykkes mens andre lykkes. La aldri én feil blokkere de andre. Bruk return_exceptions=True i asyncio.gather() for å samle inn alle resultater selv om noen kaster unntak. Konverter unntak til feilmeldinger, slik at modellen mottar alle resultatene og kan håndtere delvise feil.

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

Når modeller bruker parallelle kall

Modellen utfører parallelle verktøykall når den avgjør at den nødvendige informasjonen kan hentes inn uavhengig – det ene resultatet avhenger ikke av det andre. Eksempler er å hente aksjekurser for flere tickere, hente værdata for flere byer eller spørre flere databasetabeller. Sekvensielle kall brukes når resultatene avhenger av hverandre – først slår man opp en bruker-ID, og deretter henter man bestillinger for denne ID-en.

Begrense antallet parallelle kall

Hvis du kjører mange verktøykall parallelt, kan du overbelaste eksterne API-er med samtidige forespørsler. Bruk en semaphore til å begrense det maksimale antallet samtidige verktøykall. Dette overholder API-ets hastighetsbegrensninger, samtidig som utføringen blir mer effektiv enn ved ren sekvensiell behandling.

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)
    ]

Kombinere sekvensielle og parallelle kall

Virkelige agentbaserte arbeidsflyter kombinerer ofte sekvensielle og parallelle kall. Modellen kan først kalle lookup_user(email) og deretter – ved hjelp av den returnerte user_id-en – kalle get_orders(user_id) og get_preferences(user_id) parallelt. Implementer den ytre løkken slik at den oppdager hvilke kall som kan kjøres parallelt (uavhengige), og hvilke som må kjøres sekvensielt (avhengige).

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.'

Måle forbedring i ventetid

Parallelle verktøykall kan redusere ventetiden betydelig. Hvis hvert av tre verktøykall tar 500 ms sekvensielt, blir totalen 1500 ms. Hvis de kjøres parallelt, reduseres tiden til omtrent 500 ms – en tredobling av hastigheten. Mål og sammenlign alltid sekvensiell og parallell utføring i den konkrete situasjonen, og ta hensyn til kostnadene ved samtidighet og begrensninger i hastigheten.

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')

Feilsøke parallelle verktøykall

Når du feilsøker problemer med parallelle verktøykall, bør du loggføre hele forespørsels- og svarforløpet: modellens melding med alle tool_calls, hvert resultat som legges til i samtalen, og modellens endelige svar. Hvis et verktøyresultat mangler eller kommer i feil rekkefølge, kan modellen produsere inkonsistente svar. Strukturert logging med tool_call_id som korrelasjonsnøkkel gjør det mye enklere å spore problemer.

Rask kontroll

Test forståelsen din av parallell funksjonskalling med OpenAI.

Oppsummering av leksjonen

I denne leksjonen lærte De: parallelle verktøykall vises som flere oppføringer i listen tool_calls, asyncio.gather kjører dem samtidig for maksimal hastighet, og hvert resultat må ha sin samsvarende tool_call_id når det sendes tilbake til modellen. Deretter bygger vi et naturlig språkgrensesnitt for databaser som bruker funksjonskall til å oversette spørsmål i vanlig engelsk til SQL.

Gratis å komme i gang

Lær deg Python med en AI-veileder – gratis

Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.

Kurs
30
Leksjoner
120

Ofte stilte spørsmål

Er leksjonen «Parallell funksjonskalling» gratis?

Ja – hele teksten i «Parallell funksjonskalling» er gratis å lese her på nettet. For å øve interaktivt med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt, og for å låse opp resten av AI Engineering Academy-kurset, kan du oppgradere til CoddyKit PRO. Kurset i AI Engineering Academy inneholder totalt 4 leksjoner.

Hva lærer jeg i «Parallell funksjonskalling»?

Håndter svar der modellen kaller flere funksjoner samtidig, kjør dem parallelt med asyncio, og samle resultatene i ett enkelt oppfølgende API-kall. Du øver på AI Engineering Academy med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.

Trenger jeg erfaring for å begynne med AI Engineering Academy?

Ingen tidligere erfaring er nødvendig. AI Engineering Academy på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 3 av 4.

Hvor lang tid tar leksjonen «Parallell funksjonskalling»?

De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.

Kan jeg skrive og kjøre kode i denne AI Engineering Academy-leksjonen?

Ja. Alle AI Engineering Academy-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.

Alle leksjonene i dette kurset

  1. Definere funksjonsskjemaer for API-et
  2. Behandle verktøykall i applikasjonen
  3. Parallell funksjonskalling
  4. Bygge et naturlig språkgrensesnitt for databaser
← Tilbake til AI Engineering Academy