Równoległe wywoływanie funkcji
Obsługuj odpowiedzi, w których model jednocześnie wywołuje wiele funkcji, wykonuj je równolegle za pomocą asyncio i przesyłaj wyniki w jednym kolejnym wywołaniu API.
Równoległe wywoływanie funkcji to bezpłatna lekcja AI Engineering Academy na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej AI Engineering Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs AI Engineering Academy zawiera 4 lekcji w sumie.
Czym są równoległe wywołania funkcji?
Modele OpenAI mogą wywoływać wiele funkcji jednocześnie w ramach jednej odpowiedzi, gdy odpowiedź wymaga informacji z kilku niezależnych źródeł. Zamiast łączyć wywołania narzędzi sekwencyjnie — każde czekające na poprzednie — model generuje wiele wywołań naraz. Aplikacja wykonuje je równolegle i odsyła wszystkie wyniki razem, znacznie zmniejszając opóźnienie.
Rozpoznawanie równoległych wywołań narzędzi
Gdy model wydaje równoległe wywołania narzędzi, wiadomość odpowiedzi zawiera listę tool_calls z więcej niż jednym elementem. Każdy element ma unikalny id, nazwę funkcji i argumenty. Należy przetworzyć wszystkie wywołania przed wykonaniem kolejnego wywołania API — model oczekuje wyników dla każdego wywołanego narzędzia.
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"})Wykonywanie wywołań narzędzi za pomocą asyncio
Uruchamiaj wiele wywołań narzędzi współbieżnie za pomocą asyncio.gather(). Każda funkcja narzędzia działa w osobnej korutynie, a wszystkie wyniki są zbierane po zakończeniu wszystkich korutyn. Jest to znacznie szybsze niż wykonywanie sekwencyjne, gdy każde wywołanie narzędzia wysyła żądanie sieciowe.
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 resultsWspólne odsyłanie wszystkich wyników
Po wykonaniu wszystkich równoległych wywołań narzędzi dodaj każdy wynik jako osobną wiadomość role='tool' do konwersacji. Każda wiadomość musi zawierać pasujący identyfikator tool_call_id. Wyślij je wszystkie w jednym kolejnym wywołaniu API, aby model mógł połączyć wszystkie wyniki w jedną spójną odpowiedź.
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.contentUżywanie ThreadPoolExecutor dla narzędzi synchronicznych
Jeśli funkcje narzędzi są synchroniczne, czyli używają requests zamiast asynchronicznego httpx, nadal można uruchamiać je równolegle za pomocą concurrent.futures.ThreadPoolExecutor. Konfiguracja jest prostsza, ale rozwiązanie to jest nieco mniej wydajne niż kod w pełni asynchroniczny.
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 resultsObsługa pojedynczych błędów narzędzi
Podczas równoległego wykonywania wywołań narzędzi jedno z nich może się nie powieść, podczas gdy pozostałe zakończą się sukcesem. Nigdy nie pozwalaj, aby jeden błąd blokował pozostałe wywołania. Użyj return_exceptions=True w asyncio.gather(), aby zebrać wszystkie wyniki, nawet jeśli niektóre korutyny zgłoszą wyjątki. Zamień wyjątki na ciągi opisujące błąd, aby model otrzymał wszystkie wyniki i mógł rozumować na temat częściowych niepowodzeń.
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 resultsKiedy modele używają wywołań równoległych
Model wydaje równoległe wywołania narzędzi, gdy uznaje, że wymagane informacje można uzyskać niezależnie — jeden wynik nie zależy od drugiego. Przykłady to pobieranie cen akcji dla wielu tickerów, sprawdzanie pogody w wielu miastach lub wykonywanie zapytań do wielu tabel bazy danych. Wywołania sekwencyjne są stosowane, gdy wyniki są od siebie zależne — najpierw wyszukiwany jest identyfikator użytkownika, a następnie zamówienia dla tego identyfikatora.
Ograniczanie częstotliwości wywołań równoległych
Uruchamianie wielu wywołań narzędzi równolegle może przeciążyć zewnętrzne interfejsy API jednoczesnymi żądaniami. Użyj semafora, aby ograniczyć maksymalną liczbę współbieżnych wywołań narzędzi. Pozwala to przestrzegać limitów API, a jednocześnie wykonywać operacje wydajniej niż przy przetwarzaniu wyłącznie sekwencyjnym.
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)
]Łączenie wywołań sekwencyjnych i równoległych
Rzeczywiste przepływy pracy agentów często łączą wywołania sekwencyjne i równoległe. Model może najpierw wywołać lookup_user(email), a następnie — korzystając ze zwróconego user_id — równolegle wywołać get_orders(user_id) i get_preferences(user_id). Zaimplementuj zewnętrzną pętlę, która rozpoznaje, które wywołania można wykonywać równolegle (niezależne), a które muszą być sekwencyjne (zależne).
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.'Pomiar poprawy opóźnienia
Równoległe wywołania narzędzi mogą znacznie zmniejszyć opóźnienie. Jeśli każde z trzech wywołań narzędzi trwa sekwencyjnie 500 ms, łączny czas wynosi 1500 ms. Uruchomienie ich równolegle skraca go do około 500 ms, czyli zapewnia trzykrotne przyspieszenie. Zawsze mierz i porównuj wykonanie sekwencyjne z równoległym w konkretnym scenariuszu, uwzględniając narzut współbieżności i ograniczenia limitów zapytań.
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')Debugowanie równoległych wywołań narzędzi
Podczas debugowania problemów z równoległymi wywołaniami narzędzi rejestruj pełny cykl żądania i odpowiedzi: wiadomość modelu ze wszystkimi elementami tool_calls, każdy wynik dodany do konwersacji oraz końcową odpowiedź modelu. Jeśli brakuje wyniku narzędzia albo wyniki są w niewłaściwej kolejności, model może generować niespójne odpowiedzi. Rejestrowanie strukturalne z tool_call_id jako kluczem korelacji znacznie ułatwia śledzenie problemów.
Szybkie sprawdzenie
Sprawdź, czy rozumiesz równoległe wywoływanie funkcji w OpenAI.
Podsumowanie lekcji
W tej lekcji nauczyli się Państwo, że: równoległe wywołania narzędzi pojawiają się jako wiele wpisów na liście tool_calls, asyncio.gather wykonuje je współbieżnie, zapewniając maksymalną szybkość, a każdy wynik musi zawierać pasujący tool_call_id, gdy jest odsyłany do modelu. Następnie zbudujemy interfejs bazy danych w języku naturalnym, który za pomocą wywoływania funkcji tłumaczy zapytania w zwykłym języku angielskim na SQL.
Często zadawane pytania
Czy lekcja „Równoległe wywoływanie funkcji” jest bezpłatna?
Tak — pełny tekst „Równoległe wywoływanie funkcji” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu AI Engineering Academy, przejdź na CoddyKit PRO. Kurs AI Engineering Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Równoległe wywoływanie funkcji”?
Obsługuj odpowiedzi, w których model jednocześnie wywołuje wiele funkcji, wykonuj je równolegle za pomocą asyncio i przesyłaj wyniki w jednym kolejnym wywołaniu API. Ćwiczysz AI Engineering Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć AI Engineering Academy?
Nie wymagamy żadnego doświadczenia. AI Engineering Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.
Ile czasu zajmuje lekcja „Równoległe wywoływanie funkcji”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji AI Engineering Academy?
Tak. Każda lekcja AI Engineering Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Definiowanie schematów funkcji dla API
- Przetwarzanie wywołań narzędzi w aplikacji
- Równoległe wywoływanie funkcji
- Budowanie interfejsu bazy danych w języku naturalnym