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

366 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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`):
```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
```json
{
"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)
```json
"llm": {
"provider": "lmstudio",
"model": "bielik-11b-v3.0-instruct-gptq-marlin@q8_0",
"base_url": "http://localhost:1234"
}
```
#### OpenRouter (API)
```json
"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
```bash
# 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:
```bash
curl -X POST https://hub.ag3nts.org/verify \
-H "Content-Type: application/json" \
-d @output/final_answer.json
```
Lub z formatowaniem odpowiedzi:
```bash
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`):
```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:**
```json
{
"reference_lat": 50.3086,
"reference_lon": 18.7864,
"points": [
[52.2297, 21.0122],
[51.1079, 17.0385],
[50.0647, 19.9450]
]
}
```
**Zwraca:**
```json
{
"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)