Integracja OpenAI Function Calling z własnym API: kompletny przewodnik
Naucz się integrować OpenAI Function Calling z własnym API: definicje funkcji, tool_choice, obsługa odpowiedzi tool_calls i obsługa błędów. Praktyczne przykłady JSON i kodu.
Function Calling to jedna z najważniejszych możliwości API OpenAI, jeśli chcesz zbudować asystenta, który realnie działa – nie tylko gada. Model dostaje definicje funkcji, które Twoja aplikacja potrafi wykonać, i zamiast zgadywać odpowiedź, zwraca ustrukturyzowaną prośbę o wywołanie konkretnej funkcji z argumentami. Ty wykonujesz kod, zwracasz wynik, a model na jego podstawie formułuje odpowiedź dla użytkownika.
W tym artykule pokażę kompletny przepływ: definicje funkcji, sterowanie trybem tool_choice, obsługę odpowiedzi tool_calls, łączenie kroków w pętlę oraz typowe błędy i sposoby ich rozwiązania.
Jak działa Function Calling krok po kroku
Przepływ zawsze wygląda tak samo i warto go zapamiętać, bo każda iteracja to ta sama sekwencja:
- Wysyłasz wiadomości użytkownika oraz listę definicji funkcji (
tools). - Model odpowiada albo normalną treścią, albo żądaniem wywołania funkcji (
tool_calls). - Jeśli są
tool_calls, Twój kod wykonuje każdą z funkcji i dołącza wyniki jako wiadomościrole: "tool". - Wysyłasz całą historię ponownie – model formułuje odpowiedź lub żąda kolejnych wywołań.
- Powtarzasz, aż model zwróci zwykłą odpowiedź tekstową.
Kluczowa zasada: każdy krok to nowe wywołanie API z pełną historią. Model nie pamięta niczego poza tym, co wyślesz, więc historia musi zawierać wszystkie wcześniejsze wiadomości, w tym wyniki funkcji.
Definicje funkcji – pierwszy i najważniejszy krok
Jakość całej integracji stoi na jakości definicji. Model nigdy nie uruchamia Twojego kodu – tylko opisuje, co chcesz wywołać. Dlatego opis funkcji musi mówić, kiedy jej użyć i czego oczekujesz w argumentach.
Przykład definicji funkcji sprawdzającej status zamówienia w Twoim API:
{ "tools": [ { "type": "function", "function": { "name": "sprawdz_status_zamowienia", "description": "Sprawdza status zamówienia po numerze zamówienia. Użyj, gdy użytkownik pyta o status, śledzenie przesyłki lub szczegóły zamówienia.", "parameters": { "type": "object", "properties": { "order_id": { "type": "string", "description": "Numer zamówienia w formacie ORD-XXXXXX, podany przez użytkownika." } }, "required": ["order_id"], "additionalProperties": false } } }, { "type": "function", "function": { "name": "anuluj_zamowienie", "description": "Anuluje zamówienie, jeśli jest w statusie 'oczekujace'. NIE używaj bez potwierdzenia od użytkownika.", "parameters": { "type": "object", "properties": { "order_id": { "type": "string" }, "reason": { "type": "string", "enum": ["zmiana_zdania", "bledne_zamowienie", "inne"] } }, "required": ["order_id", "reason"], "additionalProperties": false } } } ]}Zwróć uwagę na detale, które realnie zmieniają zachowanie modelu:
- Opis zawiera warunek użycia (“Użyj, gdy użytkownik pyta o status”). Model lepiej klasyfikuje intencję, gdy opis przypomina instrukcję.
additionalProperties: falsewymusza ścisłe argumenty – model nie dopisze pól, których nie zdefiniowałeś.- Ograniczenia zapisuj w opisie (“NIE używaj bez potwierdzenia”). To jedyny sposób, by model wiedział o zasadach Twojej firmy.
enumprzyreasonogranicza wartości do znanych Ci przypadków – później łatwiej mapować je na logikę biznesową.
Sterowanie wywołaniem przez tool_choice
Pole tool_choice decyduje, czy i jaką funkcję model może wywołać:
{ "tool_choice": "auto" },{ "tool_choice": "none" },{ "tool_choice": "required" },{ "tool_choice": { "type": "function", "function": { "name": "sprawdz_status_zamowienia" } }}"auto"– domyślny. Model sam decyduje, czy potrzebuje funkcji."none"– zakaz wywołań. Przydatne w pierwszym kroku rozmowy, gdy chcesz najpierw zebrać intencję."required"– wymusza wywołanie dokładnie jednej funkcji. Świetne do testów i przepływów, w których funkcja jest niezbędna (np. weryfikacja dostępności terminu).- Wartość z nazwą funkcji – wymusza konkretną funkcję. Użyj jej, gdy kontekst rozmowy jednoznacznie wskazuje potrzebny krok.
Praktyczna zasada: zaczynaj od "auto". Wymuszanie trybów zbyt wcześnie produkuje wywołania, których użytkownik nie potrzebował.
Obsługa odpowiedzi – pętla tool_calls
Model zwraca prośbę o wywołanie w polu tool_calls wiadomości asystenta. Twój kod musi:
- Sprawdzić, czy odpowiedź zawiera
tool_calls. - Dla każdego wywołania wykonać funkcję o nazwie z
function.namez argumentami zfunction.arguments(JSON string!). - Dodać wiadomości
role: "tool"z wynikiem i tym samymtool_call_id.
{ "role": "assistant", "tool_calls": [ { "id": "call_abc123", "type": "function", "function": { "name": "sprawdz_status_zamowienia", "arguments": "{\"order_id\":\"ORD-123456\"}" } } ]}Uwaga na pułapkę: arguments to string z JSON-em, nie obiekt. Przed użyciem musisz go sparsować (JSON.parse), a wynik wykonania funkcji zwrócić jako string:
{ "role": "tool", "tool_call_id": "call_abc123", "content": "{\"status\":\"w_drodze\",\"przewidywana_dostawa\":\"2026-07-15\"}"}Po dodaniu tej wiadomości wysyłasz pełną historię ponownie. Model zobaczy wynik i sformułuje odpowiedź dla użytkownika – albo zażąda kolejnego wywołania, np. anulowania zamówienia po sprawdzeniu statusu. Tak powstają łańcuchy wywołań: model sam decyduje, że potrzebuje kilku kroków, żeby odpowiedzieć.
Obsługa błędów – błędy Twojego API to też treść
Błędy w integracji Function Calling dzielą się na dwie grupy: błędy po stronie Twojego API i błędy po stronie modelu.
Błąd w Twoim API (np. zamówienie nie istnieje, usługa nie odpowiada): nie przerywaj rozmowy błędem HTTP. Zwróć modelowi komunikat błędu jako wynik funkcji:
{ "role": "tool", "tool_call_id": "call_abc123", "content": "{\"error\":\"Zamowienie ORD-999999 nie istnieje w systemie.\"}"}Model przeczyta błąd, przeprosi użytkownika i zaproponuje poprawę – np. poprosi o inny numer. To duża przewaga nad klasycznymi API, gdzie błąd kończył rozmowę. Dodatkowo zawsze waliduj argumenty po swojej stronie (JSON.parse w trybie z błędem) – zanim trafią do Twojej logiki.
Błąd po stronie modelu – nieprawidłowy JSON w arguments, brak tool_call_id, nagłe zakończenie odpowiedzi. Obsłuż je tak:
- Nieudany parse: wyślij modelowi wiadomość
role: "tool"z treścią"Invalid JSON: <raw>"i poproś o poprawne argumenty. - Przekroczony limit kroków: wprowadź twardy limit iteracji (np. 5) i zakończ rozmowę komunikatorem, że potrzebujesz pomocy człowieka.
- Cięcie odpowiedzi (
finish_reason: "length"): powiększmax_tokenslub podziel zadanie na mniejsze funkcje. - Wszystkie wywołania zwracają błąd: przełącz
tool_choicena"none"i poproś model o wyjaśnienie użytkownikowi.
Warto też logować każde wywołanie: tool_call_id, nazwę funkcji, argumenty, wynik, czas trwania. Bez logów debugowanie pętli wielokrokowych jest drogie.
Kiedy w ogóle używać Function Calling?
Function Calling ma sens, gdy model potrzebuje danych, których nie ma w prompcie: statusów z Twojej bazy, operacji zapisu, wywołań zewnętrznych API. Jeśli pytanie jest statyczne (cennik, FAQ), zwykły prompt wystarczy i będzie tańszy.
Zaczynaj od jednej, dobrze opisanej funkcji, przetestuj pętlę na 10-20 rozmowach, a dopiero potem dodawaj kolejne. Więcej funkcji w jednym wywołaniu = większe ryzyko błędnych wyborów, szczególnie gdy ich opisy są do siebie podobne.
Function Calling to fundament agentów działających na Twoich danych – jeśli planujesz budowę bardziej złożonych systemów, przeczytaj o wieloagentowych systemach AI i o architekturach RAG z API OpenAI.
Najczęściej zadawane pytania
Czym jest Function Calling w OpenAI?
Czy muszę używać tool_choice w każdym wywołaniu?
Jak obsłużyć błąd po stronie mojego API podczas wywołania funkcji?
Powiązane posty
- aiAI
OpenAI API w praktyce: function calling, embeddings i RAG
Kod produkcyjny dla OpenAI API: function calling, embeddings, vector database, RAG pipeline. Konkretne przykłady, realne pułapki, koszty. Dla developerów, nie marketerów.
6 min - aiAI
Multi-agent systemy AI w 2025: architektura, narzędzia, pułapki
Jak budować produkcyjne systemy multi-agent w 2025: Hermes-style orkiestracja, LangChain, autogen, evaluacja. Praktyczny przewodnik z kodem i realnymi pułapkami.
5 min