
Eco²
Backend · Cloud infrastructure
Îndrumări de reciclare dintr-o fotografie și o conversație.
Un asistent AI complet, care înțelege cum funcționează reciclarea în Coreea.
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
Cum se conectează de fapt cele 24 de noduri, câte un flux pe rând.
Kubernetes autogestionat, construit cu kubeadm. Harta plasează cele 24 de noduri fizice și sarcinile de lucru de pe ele în cele cinci straturi din README și le leagă prin conexiunile lor reale. Alegeți un flux și doar acel traseu este evidențiat, cu pași numerotați.
Identifică deșeurile dintr-o fotografie și explică modul de eliminare, iar în conversație apelează instrumente pentru locuri, vreme, prețuri de reciclare și căutare web și generează imagini. În acest proiect de echipă am început cu fundația de cluster și implementare și mi-am extins domeniul la backendul de domeniu, procesarea asincronă, agentul conversațional și verificare.
De la dezvoltarea pentru competiție până la consolidarea backendului și a operării
Serviciul și-a încheiat activitatea; un demo înregistrat și raportul tehnic îl arată în funcțiune.
Cerere Scan → livrare în timp real
O cerere de analiză a unei fotografii devine lucru pus în coadă, iar evenimentele ei de progres revin la același browser.
Browsercăutare DNS: Căutare DNSRoute 53
Doar numele este rezolvat din înregistrările Route 53. Cererile nu trec prin DNS.
Browserflux de date: HTTPS 443AWS ALB
TLS se încheie la ALB.
AWS ALBflux de date: HTTP · NodePortIstio ingress Envoy
k8s-ingress-gatewayTransmis către Envoy-ul de ingress Istio prin NodePort-ul țintei de tip instanță EC2.
Istio ingress Envoy
k8s-ingress-gatewayflux de date: VirtualServiceScan APIk8s-api-scanRutat către API-ul Scan, care pune lucrul în coadă și returnează imediat un job_id; interogarea rezultatului răspunde cu 202 până când jobul este gata.
Scan API
k8s-api-scanflux de date: Sarcină CeleryRabbitMQk8s-rabbitmqSarcina Scan intră în RabbitMQ.
RabbitMQ
k8s-rabbitmqflux de date: consumescan-workerk8s-worker-ai · k8s-worker-ai-2scan-worker (Celery · gevent) din pool-ul AI o preia și rulează Vision → Rule → Answer → Reward. Cele patru etape sunt sarcini Celery înlănțuite, nu noduri.
Pool AI
k8s-worker-ai · k8s-worker-ai-2flux de date: HTTPSLLM APIWorkerii scan și chat apelează API-urile OpenAI și Google.
scan-worker
k8s-worker-ai · k8s-worker-ai-2flux de date: XADD scan:eventsStreamsk8s-redis-streamsEvenimentele de progres sunt scrise într-unul dintre cele patru sharduri Streams.
Streams
k8s-redis-streamsflux de date: XREADGROUPEvent Routerk8s-event-routerEvent Router le citește ca grup de consumatori și face XACK după procesare; pending și reclaim mențin livrarea at-least-once.
Event Router
k8s-event-routerflux de date: SETEX stateState KVk8s-redis-streamsScrie starea cea mai recentă și un marcaj de procesare duplicată în State KV, pe același nod Redis.
Event Router
k8s-event-routerflux de date: PUBLISHPub/Subk8s-redis-pubsubLivrate în timp real pe canalul jobului, în Pub/Sub pe sharduri.
Pub/Sub
k8s-redis-pubsubflux de date: SUBSCRIBESSE Gatewayk8s-sse-gatewaySSE Gateway se abonează printr-un singur listener partajat per proces și le distribuie fiecărui browser conectat.
SSE Gateway
k8s-sse-gatewayflux de date: Flux SSEBrowserO conexiune deschisă pe aceeași cale ALB și ingress. Livrarea este at-least-once; duplicatele sunt tratate idempotent.
State KV
k8s-redis-streamsflux de date: Recuperare la reconectareSSE Gatewayk8s-sse-gatewayLa reconectarea cu Last-Event-ID, State KV și Streams păstrate completează evenimentele pierdute.
Chat · tokenuri și stocare
Tokenurile Chat urmează aceeași cale de evenimente ca Scan; punctele de control și mesajele sunt stocate de două sarcini de lucru diferite.
Browserflux de date: HTTPS 443AWS ALB
TLS se încheie la ALB.
AWS ALBflux de date: HTTP · NodePortIstio ingress Envoy
k8s-ingress-gatewayTransmis către Envoy-ul de ingress Istio prin NodePort-ul țintei de tip instanță EC2.
Istio ingress Envoy
k8s-ingress-gatewayflux de date: VirtualServiceChat APIk8s-api-chatRutat către API-ul Chat.
Chat API
k8s-api-chatflux de date: Sarcină TaskiqRabbitMQk8s-rabbitmqSarcina Chat intră în RabbitMQ.
RabbitMQ
k8s-rabbitmqflux de date: consumechat-workerk8s-worker-ai · k8s-worker-ai-2chat-worker (Taskiq · asyncio) clasifică intenția cu LangGraph, apoi rulează vision dacă e nevoie, instrumentele selectate, agregatorul și un rezumat dacă e nevoie, apoi răspunde. Fiecare cerere rulează doar ramurile de care are nevoie.
Pool AI
k8s-worker-ai · k8s-worker-ai-2flux de date: HTTPSLLM APIWorkerii scan și chat apelează API-urile OpenAI și Google.
chat-worker
k8s-worker-ai · k8s-worker-ai-2flux de date: XADD chat:eventsStreamsk8s-redis-streamsTokenurile și evenimentele de etapă sunt scrise în patru sharduri Streams; de acolo, calea de livrare este aceeași ca la Scan.
Streams
k8s-redis-streamsflux de date: XREADGROUPEvent Routerk8s-event-routerEvent Router le citește ca grup de consumatori și face XACK după procesare; pending și reclaim mențin livrarea at-least-once.
Event Router
k8s-event-routerflux de date: PUBLISHPub/Subk8s-redis-pubsubLivrate în timp real pe canalul jobului, în Pub/Sub pe sharduri.
Pub/Sub
k8s-redis-pubsubflux de date: SUBSCRIBESSE Gatewayk8s-sse-gatewaySSE Gateway se abonează printr-un singur listener partajat per proces și le distribuie fiecărui browser conectat.
SSE Gateway
k8s-sse-gatewayflux de date: Flux SSEBrowserO conexiune deschisă pe aceeași cale ALB și ingress. Livrarea este at-least-once; duplicatele sunt tratate idempotent.
chat-worker
k8s-worker-ai · k8s-worker-ai-2flux de date: checkpointCachek8s-redis-cachePunctul de control LangGraph este păstrat în Redis Cache.
Cache
k8s-redis-cacheflux de date: citirea punctului de controlcheckpoint-syncerk8s-worker-ai · k8s-worker-ai-2checkpoint-syncer citește punctul de control din Redis.
checkpoint-syncer
k8s-worker-ai · k8s-worker-ai-2flux de date: sincronizare cu PostgreSQLPostgreSQLk8s-postgresqlAsyncPostgresSaver îl stochează asincron în PostgreSQL.
Streams
k8s-redis-streamsflux de date: chat-persistence grouppersistence consumerk8s-api-chatpersistence consumer de pe nodul Chat citește evenimentele done ca grup de consumatori.
persistence consumer
k8s-api-chatflux de date: salvarea mesajelorPostgreSQLk8s-postgresqlMesajele Chat sunt salvate în PostgreSQL. Este o sarcină de lucru diferită de checkpoint-syncer.
Intrare · autentificare
Calea sincronă de la intrarea în cluster până la un API de domeniu. Doar căile protejate de politici verifică mai întâi autentificarea; traficul dintre pod-uri de pe noduri diferite rulează pe Calico VXLAN.
Browsercăutare DNS: Căutare DNSRoute 53
Doar numele este rezolvat din înregistrările Route 53. Cererile nu trec prin DNS.
Browserflux de date: HTTPS 443AWS ALB
TLS se încheie la ALB.
AWS ALBflux de date: HTTP · NodePortIstio ingress Envoy
k8s-ingress-gatewayTransmis către Envoy-ul de ingress Istio prin NodePort-ul țintei de tip instanță EC2.
Istio ingress Envoy
k8s-ingress-gatewayflux de date: ext-authz · gRPC 50051ext-authzk8s-api-authDoar căile aflate sub o politică CUSTOM întreabă mai întâi Go ext-authz (timeout 2 s, failOpen false). Căi precum login, health și docs sunt excluse.
ext-authz
k8s-api-authflux de date: căutare în blacklistblacklistk8s-redis-authTokenul este verificat în blacklistul Redis.
Istio ingress Envoy
k8s-ingress-gatewayflux de date: VirtualServiceChat APIk8s-api-chatRutat către API-ul Chat.
Chat API
k8s-api-chatflux de date: gRPCimages APIk8s-api-imageApelul sincron chat → images menționat în README.
auth API
k8s-api-authflux de date: gRPCusers APIk8s-api-usersApelul sincron auth → users menționat în README.
Pool de stocare · scrieri asincrone
Blacklistul de autentificare și proprietatea asupra personajelor sunt stocate de workerii din pool-ul de stocare, care își primesc lucrul din RabbitMQ.
blacklist
k8s-redis-authflux de date: outbox:blacklistauth-relayk8s-worker-storage · k8s-worker-storage-2auth-relay (auth-Bus din README) citește outboxul Redis.
auth-relay
k8s-worker-storage · k8s-worker-storage-2flux de date: blacklist.eventsRabbitMQk8s-rabbitmqRepublică în RabbitMQ, cu reîncercări și un DLQ.
RabbitMQ
k8s-rabbitmqflux de date: blacklist.eventsauth-workerk8s-worker-storage · k8s-worker-storage-2auth-worker primește evenimentele de blacklist.
auth-worker
k8s-worker-storage · k8s-worker-storage-2flux de date: stocarea blacklistuluiblacklistk8s-redis-authSunt stocate în blacklistul Redis.
RabbitMQ
k8s-rabbitmqflux de date: Celery batchusers-workerk8s-worker-storage · k8s-worker-storage-2users-worker primește în loturi lucrul privind proprietatea asupra personajelor.
users-worker
k8s-worker-storage · k8s-worker-storage-2flux de date: UPSERTPostgreSQLk8s-postgresqlEste aplicat în PostgreSQL.
Configurare · scalare · observare
Platform Layer nu este o etapă prin care trec cererile; implementează, configurează, scalează și observă celelalte straturi. Nodurile sunt instanțe EC2 create cu Terraform, cu kubeadm și Calico instalate prin Ansible; CI doar validează Terraform și nu face niciodată apply automat.
GitHub Actions · Docker Hubconfigurare · scalare: imagine · revizie manifestArgo CD image updater
k8s-masterArgo CD aliniază configurația clusterului prin App-of-Apps și Sync Waves. Plasarea pe control-plane a fost confirmată doar pentru image updater.
ALB Controller · ExternalDNS
k8s-masterconfigurare · scalare: Ingress → ALB · înregistrări DNSGestionat de AWSALB Controller și ExternalDNS configurează resursele din partea AWS. Nu este o cale pe care o urmează cererile.
Istiod
k8s-masterconfigurare · scalare: Configurație xDSIstio ingress Envoyk8s-ingress-gatewayIstiod trimite prin xDS configurația Gateway, VirtualService și EnvoyFilter către Envoy-ul de ingress și către sidecarul Envoy al fiecărui API.
KEDA
k8s-monitoringconfigurare · scalare: număr de pod-uriPool AIk8s-worker-ai · k8s-worker-ai-2KEDA ajustează numărul de pod-uri ale workerilor. Numărul de noduri nu se schimbă.
KEDA
k8s-monitoringconfigurare · scalare: număr de pod-uripool de stocarek8s-worker-storage · k8s-worker-storage-2Pod-urile workerilor din pool-ul de stocare sunt scalate la fel.
Fluent Bitobservabilitate: jurnaleElasticsearch
k8s-loggingFluent Bit este un DaemonSet pe fiecare nod și trimite jurnalele către Elasticsearch.
Pool AI
k8s-worker-ai · k8s-worker-ai-2observabilitate: urmărirea rulărilor LLMLangSmithUrmele apelurilor LLM merg la LangSmith, un SaaS extern.
Fiecare conexiune cu aceeași grosime. Alegeți un flux pentru a evidenția doar traseul lui, cu pași numerotați.
- Continuă · direcția în care circulă cererile, lucrul, evenimentele și scrierile
- Punctată · căutare DNS; cererile nu trec prin ea
- Întreruptă · configurare sau scalare; nu este o cale de date
- Linie-punct lungă · jurnale și urmărirea rulărilor
- Linie neagră groasă · fluxul selectat; numerele dau ordinea
- Casetă · un nod fizic, cu numele gazdei în antet
- Etichetă interioară · o sarcină de lucru care rulează pe acel nod
- Cadru întrerupt · un pool de planificare cu două noduri
- Casetă întreruptă · în afara clusterului, nenumărată ca nod
- Contur portocaliu · locul în care decide un model
- Control plane1 nod
- Domain API8 noduri
- Pool AI2 noduri
- pool de stocare2 noduri
- Data5 noduri
- Platform6 noduri
Cele cinci straturi din README (benzile) și grupurile fizice (nuanța antetului fiecărui nod) grupează diferit aceleași 24 de noduri. State KV împarte nodul Streams și nu este numărat separat; Route 53, ALB și serviciile din afara clusterului nu sunt noduri. Un pool este un domeniu de planificare, nu o afirmație că fiecare pod rulează pe ambele noduri.
24noduri
24 = 1 control plane + 8 API + 4 worker + 5 data + 6 platform
1Control plane
role: control-planekube-apiserver · scheduler · controller-manager · etcd, plus controlerele de platformă.
- k8s-master
8Domain API
domain: <serviciu>Un nod pentru fiecare domeniu. Apelurile interne folosesc 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
Două pool-uri de planificare, cu câte două noduri fiecare. KEDA schimbă numărul de pod-uri; numărul de noduri rămâne același.
pool de stocare
domain: worker-storage- k8s-worker-storage
- k8s-worker-storage-2
Pool AI
domain: worker-ai- k8s-worker-ai
- k8s-worker-ai-2
5Data
Redis este împărțit pe patru noduri dedicate. Stocarea PostgreSQL este EBS CSI · gp3.
- k8s-postgresql
- k8s-redis-auth
- k8s-redis-streams
- k8s-redis-cache
- k8s-redis-pubsub
6Platform
Mesageria, observabilitatea, ingress-ul și livrarea în timp real au fiecare propriul nod.
- k8s-rabbitmq
- k8s-monitoring
- k8s-logging
- k8s-ingress-gateway
- k8s-sse-gateway
- k8s-event-router
- Fiecare nod
- Fluent Bit · DaemonSet
- Calico
Modele configurate · pe furnizori
Serviciul a fost închis, așa că acestea sunt modelele configurate în depozit, nu opțiuni disponibile astăzi. Fiecare rol este listat separat; nu este o listă de rulări verificate.
OpenAI
Furnizorul implicit pentru Chat
Chat
openai/gpt-5.2implicit
Modelul implicit este gpt-5.2; un model numit în cerere este folosit în locul lui.
Scan
gpt-5.2implicitgpt-5.2-progpt-5.1gpt-5gpt-5-progpt-5-mini
Modelele din afara mapării de 13 modele sunt respinse.
Maparea imaginilor
gpt-image-1.5
Separat de gpt-5.2, modelul de orchestrare Responses. Generarea de imagini este dezactivată implicit.
Evaluare
gpt-4o-miniimplicit
Evaluatorul LLM pentru evaluarea conversațiilor, separat de modelul Chat.
Google
Când Chat alege Google
Chat
google/gemini-3-pro-previewgoogle/gemini-3-flash-preview
Cu Google selectat, gemini-3-flash-preview este implicit.
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
Maparea imaginilor
gemini-3-pro-image-preview
Sursăbackend main d8840c7Commit public 29 septembrie 2026 · verificat 8 octombrie 2026