Inżynier wyścigowy AI działający na żywo w iRacing
Głosowy inżynier wyścigowy AI dla iRacing: kierowca pyta przez push-to-talk i dostaje odpowiedź w stylu radia F1 w niecałe dwie sekundy, opartą na telemetrii na żywo czytanej przez 19 narzędzi MCP.
- Stack
- Python · asyncio · OpenAI · FastMCP · SQLite · Whisper
- Latencja
- odpowiada w niecałe 2 s
- Skala
- 19 narzędzi MCP · 64 auta · polling co 100 ms
LLM, który odpowiada jadącemu autu w niecałe dwie sekundy
Zbudowaliśmy produkcyjnego agenta AI, który pełni rolę inżyniera wyścigowego w czasie rzeczywistym podczas sesji na żywo. Kierowca mówi do niego przez push-to-talk: głos jest transkrybowany przez Whisper, przetwarzany przez agenta OpenAI z dostępem do 19 narzędzi telemetrii na żywo i odczytywany z powrotem przez TTS w stylu radia F1.
Agent widzi czasy okrążeń, zużycie opon, poziom paliwa, przewagi rywali, flagi na torze i status obsługi w alei serwisowej — wszystko aktualizowane na bieżąco z SDK iRacing. Kluczowe ograniczenie inżynierskie wyznacza cały projekt: LLM, który musi odpowiedzieć w niecałe dwie sekundy, pracując na danych z definicji nieaktualnych, bez zmyślania liczb, których faktycznie nie ma.

Telemetria jako warstwa narzędzi, które agent wywołuje
Warstwa telemetrii jest udostępniona agentowi przez FastMCP — serwer implementujący Model Context Protocol z 19 ustrukturyzowanymi narzędziami w sześciu kategoriach: surowe wartości telemetrii, informacje o sesji, tabela wyników, flagi, komendy pit-stopu i statystyki okrążeń. Klient MCP automatycznie konwertuje schematy narzędzi z JSON Schema MCP na definicje function-calling OpenAI, więc nie ma ręcznego mapowania do utrzymania w synchronizacji.
To agent decyduje, które narzędzia wywołać i w jakiej kolejności, na podstawie pytania kierowcy. „Czy wjeżdżać do serwisu na tym okrążeniu?” uruchamia get_current_pit_service_status, get_car_average_lap_time, get_leaderboard i get_my_car_damage_report w jednej pętli rozumowania, zanim padnie odpowiedź. MCP działa jako osobny proces po stdio — czysta izolacja procesów, bez wyścigów na współdzielonej pamięci między agentem a strumieniem danych na żywo. To samo okablowanie działa dla CRM, ERP czy systemu zgłoszeń: opisaliśmy podłączenie AI do danych firmy bez oddawania modelowi ich kopii.

Czas okrążenia sprzed 30 sekund jest już błędny
Oczywiste podejście — trzymanie całego łańcucha wywołań narzędzi w historii rozmowy — zatruwa kolejne pytanie: agent rozumuje na czasie okrążenia sprzed 30 sekund, który jest już błędny. Nieaktualne dane niesione dalej są gorsze niż brak danych.
Rozwiązaniem jest sliding window. Utrwalane są tylko pytanie kierowcy i finalna odpowiedź tekstowa agenta (MAX_HISTORY = 4); każde pośrednie wywołanie narzędzia uruchamia się na świeżo w każdej turze i jest potem odrzucane, a prompt systemowy jest przypięty jako pierwsza wiadomość. Stan sesji żyje osobno: TelemetryWorker odpytuje iRacing co 100 ms i zapisuje ukończone okrążenia wszystkich 64 aut do SQLite — historia okrążeń bez zapychania kontekstu LLM.
RAG na danych strukturalnych na żywo, z bramką na komendach pit-stopu
Zamiast bazy wektorowej system robi ustrukturyzowany retrieval w czasie rzeczywistym przez narzędzia MCP. Przed każdą odpowiedzią pobiera potrzebne dane na świeżo: historię okrążeń z SQLite, snapshot telemetrii na żywo z SDK iRacing i klasyfikację sesji z tabeli wyników trzymanej w pamięci. ExtendedTelemetryFacade pełni rolę warstwy pośredniej retrievalu — chowa źródła danych za jednym interfejsem i decyduje, czy czytać z SDK na żywo, z bazy okrążeń, czy ze snapshotu. To ten sam wzorzec co RAG na dokumentach — pobierz w momencie zapytania, wstrzyknij, odrzuć — zastosowany do strukturalnych danych na żywo zamiast fragmentów tekstu.
Odczyt jest autonomiczny, działanie już nie. Komendy pit-stopu wysokiego ryzyka przechodzą przez bramkę human-in-the-loop przed wykonaniem — agent może zarekomendować i przygotować zjazd, ale kierowca zatwierdza go, zanim cokolwiek trafi do auta.
Zobacz, jak wyglądałoby to w Twoich procesach.
30 minut · wskazujemy 3 najlepsze obszary do automatyzacji · bez zobowiązań