Files
s01e02/README.md
2026-03-12 02:10:57 +01:00

11 KiB
Raw Blame History

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:

  1. [LLM Call 1/2] Pobierz lokalizacje osoby (function calling: get_location)

    • Zwraca WSZYSTKIE możliwe lokalizacje osoby (np. 7, 12, 17 lokalizacji)
  2. [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
  3. [LLM Call 2/2] Pobierz poziom dostępu (function calling: get_access_level)

    • Używa tylko roku urodzenia (integer)
  4. Generuje raport dla osoby

    • Zapisuje w output/person_reports/{Name}_{Surname}.json
    • Zawiera: nazwę elektrowni, kod, odległość, poziom dostępu, współrzędne

Po przetworzeniu wszystkich osób:

  • Znajduje osobę z najmniejszą odległością do jej najbliższej elektrowni
  • Generuje output/final_answer.json do 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 CityCoordinates jeśli API nie odpowiada

FAZA PRZETWARZANIA (dla każdej osoby):

  1. LLM Call 1: get_location - pobiera WSZYSTKIE lokalizacje osoby (function calling)
  2. 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!
  3. 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, √(1a))
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ę osoby
  • surname (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ę osoby
  • surname (string) - nazwisko osoby
  • birth_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 referencyjnego
  • reference_lon (float) - długość geograficzna punktu referencyjnego
  • points (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 miasta
  • country - Poland
  • format - json
  • limit - 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 1
  • lat2, 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)