
Eco²
Backend · Cloud infrastructure
Indicazioni per la raccolta differenziata da una foto e una conversazione.
Un assistente IA tutto in uno che conosce il funzionamento della raccolta differenziata in Corea.
Eco² vocabulary
- edge
- auth offload
- domain api
- task queue
- scan pipeline
- chat agent
- event bus
- cluster
- gitops
- autoscaling
- observability
- load test
- evaluation
Edge: ROUTE 53 · ALB · HTTPS 443 · internet-facing · external-dns · istio-ingressgateway · NodePort · eco2-gateway · VirtualService · x-canary · AuthorizationPolicy · ENVOY SIDECAR · kiali-serverAuth Offload: AuthorizationPolicy · action: CUSTOM · notPaths · envoyExtAuthzGrpc · failOpen: false · CheckRequest · x-user-id · BlacklistCache · BootstrapFromRedis · outbox:blacklist · blacklist.events · UsersServiceDomain API: VirtualService · x-user-id · /api/v1/scan · X-Idempotency-Key · job_id · stream_url · 202 ACCEPTED · Retry-After · ScanTask · UsersService · ImageService · ENVOY SIDECARTask Queue: outbox:blacklist · blacklist.events · RabbitmqCluster · scan.direct · reward.events · dlx · x-dead-letter-exchange · chat.process · AioPikaBroker · task_acks_late · apply_async · gevent · scan.vision · scan.rule · scan.answer · scan.reward · CELERY CHAIN · QueueLength · inspect ping · QUEUE SATURATIONScan Pipeline: ScanTask · scan.direct · reward.events · apply_async · gevent · scan.vision · scan.rule · scan.answer · scan.reward · CELERY CHAIN · RewardStep · item_class_list.yaml · situation_tags.yaml · LITE RAG · JsonRegulationRetriever · PipelineStage · waste_rag · XADD · domain: worker-ai · pipeline_duration · vision_stage_durationChat Agent: ImageService · chat.process · AioPikaBroker · create_chat_graph · route_by_intent · MULTI-INTENT FANOUT · waste_rag · recyclable_price · collection_point · image_generation · aggregator · thread_id · SyncableRedisSaver · AsyncPostgresSaver · LANGSMITH_TRACING · regenerateEvent Bus: job_id · stream_url · PipelineStage · XADD · scan:events:{shard} · XREADGROUP · XACK · XAUTOCLAIM · PendingReclaimer · STATE KV · scan:state:{job_id} · sse:events:{shard} · SSEBroadcastManager · Last-Event-ID · scan_sse_connections_active · ServiceMonitor · traceparentCluster: NodePort · kubeadm init · kubeadm join · vxlanMode · BGPConfiguration · module "vpc" · worker_ai · nodeSelector · domain: worker-ai · NoSchedule · 24-NODE CLUSTERGitOps: external-dns · x-canary · dev-root · ApplicationSet · sync-wave · selfHeal · ignoreDifferences · argocd-image-updater · update-strategy: digest · write-back-method · targetRevision · ci-services.ymlAutoscaling: ignoreDifferences · ScaledObject · QueueLength · cooldownPeriod · pollingInterval · fallback · maxReplicaCount · stabilizationWindowSeconds · HorizontalPodAutoscaler · scan_sse_connections_active · prometheus-adapterObservability: 24-NODE CLUSTER · prometheus-adapter · FLUENT BIT · Elasticsearch · Kibana · kube-prometheus-stack · AlertmanagerConfig · ServiceMonitor · JAEGER · OPENTELEMETRY · traceparent · kiali-server · LANGSMITH_TRACINGLoad Test: k6 · ramping-vus · thresholds · pipeline_duration · vision_stage_duration · poll_timeout · inspect ping · WORKER RESTART · POLLING TIMEOUT · QUEUE SATURATIONEvaluation: EvalConfig · eval_mode · eval_sample_rate · eval_cost_budget_daily_usd · EvalResult · EvalGrade · code_grader · llm_grader · CUSUM · regenerate · OpenAIBARSEvaluator
Come si collegano davvero i 24 nodi, un flusso alla volta.
Kubernetes autogestito, costruito con kubeadm. La mappa colloca i 24 nodi fisici e i workload che ospitano nei cinque livelli del README e li unisce con le connessioni reali. Scegliendo un flusso se ne evidenzia solo il percorso, con passi numerati.
Riconosce i rifiuti da una foto e spiega come smaltirli, e in conversazione chiama strumenti per luoghi, meteo, prezzi del riciclo e ricerca web, e genera immagini. In questo progetto di squadra ho iniziato dalla base di cluster e deployment e ho esteso il mio ambito al backend di dominio, all’elaborazione asincrona, all’agente conversazionale e alla verifica.
Dallo sviluppo per la competizione al consolidamento di backend e operazioni
Il servizio ha concluso la sua attività; una demo registrata e il rapporto tecnico lo mostrano in funzione.
Richiesta Scan → consegna in tempo reale
Una richiesta di analisi di una foto diventa lavoro in coda, e i suoi eventi di avanzamento tornano allo stesso browser.
Browserrisoluzione DNS: risoluzione DNSRoute 53
Dai record di Route 53 si risolve solo il nome. Le richieste non passano per il DNS.
Browserflusso di dati: HTTPS 443AWS ALB
Il TLS termina all’ALB.
AWS ALBflusso di dati: HTTP · NodePortIstio ingress Envoy
k8s-ingress-gatewayPassata all’Envoy di ingress di Istio tramite il NodePort del target di istanza EC2.
Istio ingress Envoy
k8s-ingress-gatewayflusso di dati: VirtualServiceScan APIk8s-api-scanInstradata all’API Scan, che mette il lavoro in coda e restituisce subito un job_id; un’interrogazione del risultato risponde 202 finché il job non è terminato.
Scan API
k8s-api-scanflusso di dati: task CeleryRabbitMQk8s-rabbitmqIl task Scan va su RabbitMQ.
RabbitMQ
k8s-rabbitmqflusso di dati: consumescan-workerk8s-worker-ai · k8s-worker-ai-2scan-worker (Celery · gevent) nel pool AI lo prende ed esegue Vision → Rule → Answer → Reward. Le quattro fasi sono task Celery concatenati, non nodi.
Pool AI
k8s-worker-ai · k8s-worker-ai-2flusso di dati: HTTPSLLM APII worker di scan e chat chiamano le API di OpenAI e Google.
scan-worker
k8s-worker-ai · k8s-worker-ai-2flusso di dati: XADD scan:eventsStreamsk8s-redis-streamsGli eventi di avanzamento vengono scritti in uno dei quattro shard di Streams.
Streams
k8s-redis-streamsflusso di dati: XREADGROUPEvent Routerk8s-event-routerL’Event Router li legge come consumer group ed esegue XACK dopo l’elaborazione; pending e reclaim mantengono la consegna at-least-once.
Event Router
k8s-event-routerflusso di dati: SETEX stateState KVk8s-redis-streamsScrive lo stato più recente e un marcatore contro la doppia elaborazione in State KV sullo stesso nodo Redis.
Event Router
k8s-event-routerflusso di dati: PUBLISHPub/Subk8s-redis-pubsubConsegnato in tempo reale sul canale del job nel Pub/Sub a shard.
Pub/Sub
k8s-redis-pubsubflusso di dati: SUBSCRIBESSE Gatewayk8s-sse-gatewayL’SSE Gateway si iscrive tramite un unico listener condiviso per processo e distribuisce a ogni browser connesso.
SSE Gateway
k8s-sse-gatewayflusso di dati: stream SSEBrowserUna connessione aperta sullo stesso percorso di ALB e ingress. La consegna è at-least-once; i duplicati sono gestiti in modo idempotente.
State KV
k8s-redis-streamsflusso di dati: Recupero alla riconnessioneSSE Gatewayk8s-sse-gatewayAlla riconnessione con Last-Event-ID, State KV e gli Streams conservati recuperano gli eventi persi.
Chat · token e archiviazione
I token di Chat seguono lo stesso percorso di eventi di Scan; checkpoint e messaggi sono salvati da due workload diversi.
Browserflusso di dati: HTTPS 443AWS ALB
Il TLS termina all’ALB.
AWS ALBflusso di dati: HTTP · NodePortIstio ingress Envoy
k8s-ingress-gatewayPassata all’Envoy di ingress di Istio tramite il NodePort del target di istanza EC2.
Istio ingress Envoy
k8s-ingress-gatewayflusso di dati: VirtualServiceChat APIk8s-api-chatInstradata all’API Chat.
Chat API
k8s-api-chatflusso di dati: task TaskiqRabbitMQk8s-rabbitmqIl task Chat va su RabbitMQ.
RabbitMQ
k8s-rabbitmqflusso di dati: consumechat-workerk8s-worker-ai · k8s-worker-ai-2chat-worker (Taskiq · asyncio) classifica l’intento con LangGraph, poi esegue se serve vision, gli strumenti selezionati, l’aggregator e se serve un riepilogo, e risponde. Ogni richiesta esegue solo i rami che le servono.
Pool AI
k8s-worker-ai · k8s-worker-ai-2flusso di dati: HTTPSLLM APII worker di scan e chat chiamano le API di OpenAI e Google.
chat-worker
k8s-worker-ai · k8s-worker-ai-2flusso di dati: XADD chat:eventsStreamsk8s-redis-streamsToken ed eventi di fase vengono scritti in quattro shard di Streams; da lì il percorso di consegna è lo stesso di Scan.
Streams
k8s-redis-streamsflusso di dati: XREADGROUPEvent Routerk8s-event-routerL’Event Router li legge come consumer group ed esegue XACK dopo l’elaborazione; pending e reclaim mantengono la consegna at-least-once.
Event Router
k8s-event-routerflusso di dati: PUBLISHPub/Subk8s-redis-pubsubConsegnato in tempo reale sul canale del job nel Pub/Sub a shard.
Pub/Sub
k8s-redis-pubsubflusso di dati: SUBSCRIBESSE Gatewayk8s-sse-gatewayL’SSE Gateway si iscrive tramite un unico listener condiviso per processo e distribuisce a ogni browser connesso.
SSE Gateway
k8s-sse-gatewayflusso di dati: stream SSEBrowserUna connessione aperta sullo stesso percorso di ALB e ingress. La consegna è at-least-once; i duplicati sono gestiti in modo idempotente.
chat-worker
k8s-worker-ai · k8s-worker-ai-2flusso di dati: checkpointCachek8s-redis-cacheIl checkpoint di LangGraph è conservato in Redis Cache.
Cache
k8s-redis-cacheflusso di dati: lettura del checkpointcheckpoint-syncerk8s-worker-ai · k8s-worker-ai-2checkpoint-syncer legge il checkpoint da Redis.
checkpoint-syncer
k8s-worker-ai · k8s-worker-ai-2flusso di dati: sincronizzazione su PostgreSQLPostgreSQLk8s-postgresqlAsyncPostgresSaver lo salva in PostgreSQL in modo asincrono.
Streams
k8s-redis-streamsflusso di dati: chat-persistence grouppersistence consumerk8s-api-chatIl persistence consumer sul nodo Chat legge gli eventi done come consumer group.
persistence consumer
k8s-api-chatflusso di dati: salvataggio dei messaggiPostgreSQLk8s-postgresqlI messaggi di chat vengono salvati in PostgreSQL. È un workload diverso da checkpoint-syncer.
Ingresso · autenticazione
Il percorso sincrono dall’ingresso del cluster a un’API di dominio. Solo i percorsi protetti da policy controllano prima l’autenticazione; il traffico dei Pod tra i nodi passa su Calico VXLAN.
Browserrisoluzione DNS: risoluzione DNSRoute 53
Dai record di Route 53 si risolve solo il nome. Le richieste non passano per il DNS.
Browserflusso di dati: HTTPS 443AWS ALB
Il TLS termina all’ALB.
AWS ALBflusso di dati: HTTP · NodePortIstio ingress Envoy
k8s-ingress-gatewayPassata all’Envoy di ingress di Istio tramite il NodePort del target di istanza EC2.
Istio ingress Envoy
k8s-ingress-gatewayflusso di dati: ext-authz · gRPC 50051ext-authzk8s-api-authSolo i percorsi sotto una policy CUSTOM interrogano prima l’ext-authz in Go (timeout 2 s, failOpen false). Percorsi come login, health e docs sono esclusi.
ext-authz
k8s-api-authflusso di dati: consultazione della blacklistblacklistk8s-redis-authIl token viene confrontato con la blacklist di Redis.
Istio ingress Envoy
k8s-ingress-gatewayflusso di dati: VirtualServiceChat APIk8s-api-chatInstradata all’API Chat.
Chat API
k8s-api-chatflusso di dati: gRPCimages APIk8s-api-imageLa chiamata sincrona chat → images indicata nel README.
auth API
k8s-api-authflusso di dati: gRPCusers APIk8s-api-usersLa chiamata sincrona auth → users indicata nel README.
Pool storage · scritture asincrone
La blacklist di autenticazione e la proprietà dei personaggi sono salvate dai worker del pool storage, che prendono il lavoro da RabbitMQ.
blacklist
k8s-redis-authflusso di dati: outbox:blacklistauth-relayk8s-worker-storage · k8s-worker-storage-2auth-relay (l’auth-Bus del README) legge l’outbox di Redis.
auth-relay
k8s-worker-storage · k8s-worker-storage-2flusso di dati: blacklist.eventsRabbitMQk8s-rabbitmqRipubblica su RabbitMQ, con retry e una DLQ.
RabbitMQ
k8s-rabbitmqflusso di dati: blacklist.eventsauth-workerk8s-worker-storage · k8s-worker-storage-2auth-worker riceve gli eventi della blacklist.
auth-worker
k8s-worker-storage · k8s-worker-storage-2flusso di dati: salvataggio della blacklistblacklistk8s-redis-authVengono salvati nella blacklist di Redis.
RabbitMQ
k8s-rabbitmqflusso di dati: Celery batchusers-workerk8s-worker-storage · k8s-worker-storage-2users-worker riceve in batch il lavoro sulla proprietà dei personaggi.
users-worker
k8s-worker-storage · k8s-worker-storage-2flusso di dati: UPSERTPostgreSQLk8s-postgresqlViene applicato a PostgreSQL.
Configurare · scalare · osservare
Il Platform Layer non è un passo attraversato dalle richieste; distribuisce, configura, scala e osserva gli altri livelli. I nodi sono istanze EC2 create con Terraform, con kubeadm e Calico installati da Ansible; la CI si limita a validare Terraform e non lo applica mai automaticamente.
GitHub Actions · Docker Hubconfigurare · scalare: immagine · revisione del manifestArgo CD image updater
k8s-masterArgo CD allinea la configurazione del cluster tramite App-of-Apps e Sync Waves. È stata confermata solo la collocazione sul control plane dell’image updater.
ALB Controller · ExternalDNS
k8s-masterconfigurare · scalare: Ingress → ALB · record DNSGestito da AWSALB Controller ed ExternalDNS configurano le risorse lato AWS. Non è un percorso seguito dalle richieste.
Istiod
k8s-masterconfigurare · scalare: configurazione xDSIstio ingress Envoyk8s-ingress-gatewayIstiod invia via xDS la configurazione di Gateway, VirtualService ed EnvoyFilter all’Envoy di ingress e al sidecar Envoy di ogni API.
KEDA
k8s-monitoringconfigurare · scalare: numero di PodPool AIk8s-worker-ai · k8s-worker-ai-2KEDA regola il numero di Pod dei worker. Il numero di nodi non cambia.
KEDA
k8s-monitoringconfigurare · scalare: numero di Podpool storagek8s-worker-storage · k8s-worker-storage-2I Pod dei worker del pool storage sono scalati allo stesso modo.
Fluent Bitosservabilità: logElasticsearch
k8s-loggingFluent Bit è un DaemonSet su ogni nodo e invia i log a Elasticsearch.
Pool AI
k8s-worker-ai · k8s-worker-ai-2osservabilità: tracciamento delle esecuzioni LLMLangSmithLe trace delle chiamate LLM vanno a LangSmith, un SaaS esterno.
Tutte le connessioni con lo stesso peso. Scegliendo un flusso se ne evidenzia solo il percorso, con passi numerati.
- Continua · direzione di richieste, lavoro, eventi e scritture
- Punteggiata · risoluzione DNS; le richieste non vi passano
- Tratteggiata · configurare o scalare; non è un percorso dei dati
- Tratto lungo e punto · log e tracciamento delle esecuzioni
- Linea nera spessa · il flusso scelto; i numeri danno l’ordine
- Riquadro · un nodo fisico, nome host nell’intestazione
- Chip interno · un workload in esecuzione su quel nodo
- Cornice tratteggiata · un pool di scheduling di due nodi
- Riquadro tratteggiato · fuori dal cluster, non contato come nodo
- Contorno arancione · dove decide un modello
- Control plane1 nodo
- Domain API8 nodi
- Pool AI2 nodi
- pool storage2 nodi
- Data5 nodi
- Platform6 nodi
I cinque livelli del README (le fasce) e i gruppi fisici (la tinta dell’intestazione di ogni nodo) raggruppano diversamente gli stessi 24 nodi. State KV condivide il nodo di Streams e non è contato a parte; Route 53, l’ALB e i servizi fuori dal cluster non sono nodi. Un pool è un ambito di scheduling, non l’affermazione che ogni pod giri su entrambi i nodi.
24nodi
24 = 1 control plane + 8 API + 4 worker + 5 data + 6 platform
1Control plane
role: control-planekube-apiserver · scheduler · controller-manager · etcd, più i controller della piattaforma.
- k8s-master
8Domain API
domain: <servizio>Un nodo per dominio. Le chiamate interne usano gRPC.
- k8s-api-auth
- k8s-api-users
- k8s-api-scan
- k8s-api-character
- k8s-api-location
- k8s-api-image
- k8s-api-chat
- k8s-api-info
4Execution worker
Due pool di scheduling di due nodi ciascuno. KEDA cambia il numero di pod; il numero di nodi resta lo stesso.
pool storage
domain: worker-storage- k8s-worker-storage
- k8s-worker-storage-2
Pool AI
domain: worker-ai- k8s-worker-ai
- k8s-worker-ai-2
5Data
Redis è diviso per scopo su quattro nodi. Lo storage di PostgreSQL è EBS CSI · gp3.
- k8s-postgresql
- k8s-redis-auth
- k8s-redis-streams
- k8s-redis-cache
- k8s-redis-pubsub
6Platform
Messaggistica, osservabilità, ingress e consegna in tempo reale hanno ciascuno un proprio nodo.
- k8s-rabbitmq
- k8s-monitoring
- k8s-logging
- k8s-ingress-gateway
- k8s-sse-gateway
- k8s-event-router
- Ogni nodo
- Fluent Bit · DaemonSet
- Calico
Modelli configurati · per provider
Il servizio è stato chiuso, quindi questi sono i modelli configurati nel repository, non scelte disponibili oggi. Ogni ruolo è elencato a parte; non è un elenco di esecuzioni verificate.
OpenAI
Provider predefinito di Chat
Chat
openai/gpt-5.2predefinito
Il modello predefinito è gpt-5.2; se la richiesta indica un modello, si usa quello.
Scan
gpt-5.2predefinitogpt-5.2-progpt-5.1gpt-5gpt-5-progpt-5-mini
I modelli fuori dalla mappatura dei 13 modelli vengono rifiutati.
Mappatura delle immagini
gpt-image-1.5
Separato da gpt-5.2, il modello di orchestrazione di Responses. La generazione di immagini è disattivata per impostazione predefinita.
Valutazione
gpt-4o-minipredefinito
Il grader LLM per la valutazione delle conversazioni, separato dal modello Chat.
Google
Quando Chat seleziona Google
Chat
google/gemini-3-pro-previewgoogle/gemini-3-flash-preview
Con Google selezionato, gemini-3-flash-preview è il predefinito.
Scan
gemini-3-pro-previewgemini-3-flash-previewgemini-2.5-progemini-2.5-flashgemini-2.5-flash-litegemini-2.0-flashgemini-2.0-flash-lite
Mappatura delle immagini
gemini-3-pro-image-preview
Fontebackend main d8840c7Commit pubblico September 29, 2026 · verificato October 8, 2026