11 KiB
AI Agent Person Processor ⚡
Zaawansowana aplikacja w Go oparta o Clean Architecture, która wykorzystuje ZOPTYMALIZOWANY proces z LLM Function Calling + równoległymi obliczeniami do inteligentnego przetwarzania danych osób i generowania raportów lokalizacyjnych.
🚀 Kluczowa optymalizacja:
- Tylko 2 wywołania LLM na osobę (poprzednio: 30-50)
- Równoległe obliczenia odległości (wszystkie elektrownie jednocześnie)
- 20x szybsze przetwarzanie
- Wielowątkowe goroutines w Go
Funkcjonalność
Zoptymalizowany proces przetwarzania:
Dla każdej osoby sekwencyjnie - TYLKO 2 WYWOŁANIA LLM:
-
[LLM Call 1/2] Pobierz lokalizacje osoby (function calling:
get_location)- Zwraca WSZYSTKIE możliwe lokalizacje osoby (np. 7, 12, 17 lokalizacji)
-
[Lokalne obliczenia RÓWNOLEGŁE] Znajdź globalnie najbliższą elektrownię
- Dla KAŻDEJ lokalizacji osoby (pętla):
- Dla KAŻDEJ elektrowni uruchamia oddzielną goroutine
- Każda goroutine pobiera współrzędne z geocoding cache
- Równolegle oblicza odległość Haversine (bez LLM!)
- Znajduje najbliższą elektrownię dla tej konkretnej lokalizacji
- Wybiera MINIMUM ze wszystkich lokalizacji×elektrowni
- Wielowątkowe przetwarzanie - wszystkie elektrownie jednocześnie
- Dla KAŻDEJ lokalizacji osoby (pętla):
-
[LLM Call 2/2] Pobierz poziom dostępu (function calling:
get_access_level)- Używa tylko roku urodzenia (integer)
-
Generuje raport dla osoby
- Zapisuje w
output/person_reports/{Name}_{Surname}.json - Zawiera: nazwę elektrowni, kod, odległość, poziom dostępu, współrzędne
- Zapisuje w
Po przetworzeniu wszystkich osób:
- Znajduje osobę z najmniejszą odległością do jej najbliższej elektrowni
- Generuje
output/final_answer.jsondo weryfikacji
Architektura
.
├── cmd/app/ # Punkt wejścia
├── internal/
│ ├── config/ # Konfiguracja
│ ├── domain/ # Modele i interfejsy
│ │ ├── person.go # Model osoby
│ │ ├── location.go # Haversine i obliczenia odległości
│ │ ├── report.go # Modele raportów
│ │ ├── llm.go # LLM z function calling
│ │ └── tools.go # Definicje narzędzi dla agenta
│ ├── infrastructure/
│ │ ├── api/ # Klient API hub.ag3nts.org
│ │ ├── json/ # Repozytoria JSON
│ │ └── llm/ # Providery LLM
│ └── usecase/
│ └── person_agent_processor.go # Logika przetwarzania osób przez agenta
├── output/
│ ├── locations/ # Dane lokalizacji osób (z API)
│ ├── accesslevel/ # Dane poziomów dostępu (z API)
│ ├── person_reports/ # Raport dla każdej osoby
│ ├── findhim_locations.json # Lista elektrowni z kodami
│ └── final_answer.json # Końcowa odpowiedź do weryfikacji
└── lista.json # Dane wejściowe
Przykładowy raport osoby
Raport dla osoby (output/person_reports/Oskar_Sieradzki.json):
{
"name": "Oskar",
"surname": "Sieradzki",
"nearest_plant": "Grudziądz",
"plant_code": "PWR7264PL",
"distance_km": 83.38,
"access_level": 7,
"primary_latitude": 53.483,
"primary_longitude": 18.754
}
Każdy raport zawiera najbliższą elektrownię dla danej osoby wraz z odległością i kodem elektrowni.
Optymalizacje
⚡ EKSTREMALNA OPTYMALIZACJA - 2 WYWOŁANIA LLM NA OSOBĘ:
Poprzednia wersja: 30-50 iteracji LLM na osobę Nowa wersja: TYLKO 2 wywołania LLM na osobę ✨
Jak to działa:
FAZA INICJALIZACJI (jednokrotnie przy starcie):
- Pobiera listę elektrowni z API
- Geocoding API (OpenStreetMap Nominatim): dla każdej elektrowni pobiera dokładne współrzędne
- Zapisuje współrzędne w pamięci cache
- Fallback do
CityCoordinatesjeśli API nie odpowiada
FAZA PRZETWARZANIA (dla każdej osoby):
- LLM Call 1:
get_location- pobiera WSZYSTKIE lokalizacje osoby (function calling) - Lokalne obliczenia (RÓWNOLEGŁE dla WSZYSTKICH lokalizacji):
- Dla KAŻDEJ lokalizacji osoby:
- Dla każdej elektrowni: osobna goroutine
- Pobiera współrzędne z cache (dokładne z geocoding API!)
- Oblicza odległość Haversine
- Znajduje najbliższą elektrownię dla tej lokalizacji
- Wybiera GLOBALNIE najmniejszą odległość ze wszystkich kombinacji
- Wszystko dzieje się jednocześnie (wielowątkowo)
- BEZ użycia LLM!
- Dla KAŻDEJ lokalizacji osoby:
- LLM Call 2:
get_access_level- pobiera poziom dostępu (function calling)
Kluczowe ulepszenia:
- Redukcja wywołań LLM z ~40 do 2 (20x szybciej! 💨)
- Równoległe przetwarzanie - wszystkie elektrownie jednocześnie
- Dokładne współrzędne - OpenStreetMap Nominatim API (geocoding)
- Geocoding przy starcie - jednokrotne pobranie współrzędnych wszystkich elektrowni
- Haversine bez LLM - lokalne obliczenia w Go
- Fallback coordinates - jeśli geocoding API zawiedzie, używamy CityCoordinates
- Temperature = 0.0 dla deterministycznych wyników
Zalety tego podejścia:
- ⚡ Dramatycznie szybsze - 20x mniej wywołań LLM
- 💰 Tańsze - minimalna konsumpcja API
- 🚀 Równoległe obliczenia - wykorzystanie wszystkich rdzeni CPU
- 🎯 Deterministyczne - te same wyniki za każdym razem
- 📊 Szczegółowe logi - każdy krok widoczny
- 🔧 Łatwe debugowanie - jasna struktura 2-fazowa
System logowania:
Aplikacja generuje bardzo szczegółowe logi pokazujące:
- Fazę ładowania danych (osoby, elektrownie)
- Dla każdej osoby:
[LLM Call 1/2]- wywołanie get_location[Local Processing]- równoległe goroutines dla każdej elektrowni- Wyniki z każdej goroutine:
Goroutine [Zabrze]: 123.45 km [LLM Call 2/2]- wywołanie get_access_level- Finalne wyniki z podsumowaniem
Total LLM calls: 2
- Fazę znajdowania minimalnej odległości
- Ostateczny wynik z instrukcją weryfikacji
Konfiguracja
{
"api_key": "your-api-key",
"input_file": "lista.json",
"output_dir": "output",
"locations_api": "https://hub.ag3nts.org/api/location",
"access_level_api": "https://hub.ag3nts.org/api/accesslevel",
"locations_url": "https://hub.ag3nts.org",
"llm": {
"provider": "lmstudio",
"model": "bielik-11b-v3.0-instruct-gptq-marlin@q8_0",
"base_url": "http://localhost:1234"
}
}
Providery LLM
LM Studio (lokalny)
"llm": {
"provider": "lmstudio",
"model": "bielik-11b-v3.0-instruct-gptq-marlin@q8_0",
"base_url": "http://localhost:1234"
}
OpenRouter (API)
"llm": {
"provider": "openrouter",
"model": "anthropic/claude-3.5-sonnet",
"api_key": "your-openrouter-api-key"
}
Uwaga: Model Bielik jest zalecany dla function calling - działa szybciej i stabilniej niż DeepSeek R1.
Budowanie i uruchomienie
# Budowanie
go build -o person-processor ./cmd/app
# Uruchomienie
./person-processor -config config.json
Weryfikacja odpowiedzi
Po zakończeniu przetwarzania, aplikacja zapisuje końcową odpowiedź w pliku output/final_answer.json.
Aby wysłać odpowiedź do weryfikacji:
curl -X POST https://hub.ag3nts.org/verify \
-H "Content-Type: application/json" \
-d @output/final_answer.json
Lub z formatowaniem odpowiedzi:
curl -X POST https://hub.ag3nts.org/verify \
-H "Content-Type: application/json" \
-d @output/final_answer.json | jq .
Format odpowiedzi (output/final_answer.json):
{
"apikey": "your-api-key",
"task": "findhim",
"answer": {
"name": "Imię",
"surname": "Nazwisko",
"accessLevel": 7,
"powerPlant": "PWR1234PL"
}
}
Wzór Haversine
Aplikacja używa wzoru Haversine do obliczania odległości między dwoma punktami na kuli ziemskiej:
a = sin²(Δlat/2) + cos(lat1) × cos(lat2) × sin²(Δlon/2)
c = 2 × atan2(√a, √(1−a))
distance = R × c
gdzie R = 6371 km (promień Ziemi)
Narzędzia agenta LLM i lokalne funkcje
🤖 LLM Function Calling (2 wywołania na osobę):
get_location
Pobiera wszystkie możliwe lokalizacje osoby z API.
Parametry:
name(string) - imię osobysurname(string) - nazwisko osoby
Zwraca: tablicę obiektów z latitude i longitude
Logi: → API call: get_location(Imię, Nazwisko)
Użycie: LLM Call 1/2
get_access_level
Pobiera poziom dostępu osoby z API.
Parametry:
name(string) - imię osobysurname(string) - nazwisko osobybirth_year(integer) - tylko rok urodzenia (np. 1987, NIE pełna data)
Zwraca: obiekt z accessLevel (integer)
Logi: → API call: get_access_level(Imię, Nazwisko, rok)
Użycie: LLM Call 2/2
find_nearest_point
Znajduje najbliższy punkt z listy do punktu referencyjnego (np. elektrownia).
Parametry:
reference_lat(float) - szerokość geograficzna punktu referencyjnegoreference_lon(float) - długość geograficzna punktu referencyjnegopoints(array) - tablica punktów do sprawdzenia, każdy punkt:[latitude, longitude]
Zwraca: obiekt z latitude, longitude, distance_km, index (indeks najbliższego punktu)
Przykład wywołania:
{
"reference_lat": 50.3086,
"reference_lon": 18.7864,
"points": [
[52.2297, 21.0122],
[51.1079, 17.0385],
[50.0647, 19.9450]
]
}
Zwraca:
{
"latitude": 50.0647,
"longitude": 19.9450,
"distance_km": 45.23,
"index": 2
}
Logi: → Tool call: find_nearest_point(ref: 50.3086,18.7864, 3 points)
Użycie: Opcjonalna - dostępna dla LLM jeśli zdecyduje się jej użyć
⚡ Lokalne funkcje (bez LLM - wielowątkowe):
GetPlantGeolocation (Geocoding API)
Pobiera dokładne współrzędne geograficzne elektrowni z OpenStreetMap Nominatim API.
API: https://nominatim.openstreetmap.org/search
Parametry:
city- nazwa miastacountry- Polandformat- jsonlimit- 1
Zwraca: Dokładne współrzędne {lat, lon} (6 miejsc po przecinku!)
Użycie: Jednokrotnie przy starcie aplikacji (cache w pamięci)
Logi:
→ Fetching accurate geolocations from geocoding API...
• Geocoding: Zabrze...
✓ Fetched: 50.308615°N, 18.786375°E
• Geocoding: Grudziądz...
✓ Fetched: 53.483624°N, 18.753536°E
CityCoordinates (baza fallback)
Hardcoded współrzędne wszystkich elektrowni w Polsce (fallback gdy API nie odpowiada).
Zawartość:
- Zabrze, Piotrków Trybunalski, Grudziądz, Tczew, Radom, Chełmno, Żarnowiec
- Każde miasto:
{Lat: float64, Lon: float64}
Użycie: Fallback gdy geocoding API zawiedzie
Haversine (wzór odległości)
Oblicza odległość między dwoma punktami na kuli ziemskiej.
Parametry:
lat1, lon1- współrzędne punktu 1lat2, lon2- współrzędne punktu 2
Zwraca: odległość w kilometrach (float64)
Użycie: Równoległe goroutines dla każdej elektrowni (bez LLM!)
Logi: • Goroutine [Nazwa]: 123.45 km
Wymagania
- Go 1.21+
- LM Studio lub klucz OpenRouter API
- Model LLM wspierający function calling (zalecany: Bielik 11B)