
Eco²
Backend · Cloud infrastructure
Vägledning för källsortering utifrån ett foto och ett samtal.
En allt-i-ett-AI-assistent som förstår hur källsortering fungerar i Korea.
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
Hur de 24 noderna faktiskt hänger ihop, ett flöde i taget.
Självförvaltad Kubernetes byggd med kubeadm. Kartan placerar de 24 fysiska noderna och arbetslasterna på dem inom README:s fem lager och ritar de faktiska förbindelserna mellan dem. När ett flöde väljs markeras bara den vägen, med numrerade steg.
Den identifierar avfall utifrån ett foto och förklarar hur det ska sorteras, och i samtalet anropar den verktyg för platser, väder, återvinningspriser och webbsökning och genererar bilder. I det här teamprojektet började jag med grunden för kluster och driftsättning och breddade mitt ansvar till domänbackend, asynkron bearbetning, konversationsagenten och verifiering.
Från utvecklingen under tävlingen till förstärkning av backend och drift
Tjänsten har avslutats; en inspelad demo och den tekniska rapporten visar den i drift.
Scan-förfrågan → leverans i realtid
En förfrågan om fotoanalys blir köat arbete, och dess förloppshändelser kommer tillbaka till samma webbläsare.
WebbläsareDNS-uppslag: DNS-uppslagRoute 53
Bara namnet slås upp i Route 53-poster. Förfrågningar passerar inte genom DNS.
Webbläsaredataflöde: HTTPS 443AWS ALB
TLS avslutas vid ALB:n.
AWS ALBdataflöde: HTTP · NodePortIstio ingress Envoy
k8s-ingress-gatewayLämnas till Istio ingress Envoy via EC2-instansmålets NodePort.
Istio ingress Envoy
k8s-ingress-gatewaydataflöde: VirtualServiceScan APIk8s-api-scanRoutas till Scan API, som köar arbetet och genast returnerar ett job_id; en pollning efter resultatet besvaras med 202 tills jobbet är klart.
Scan API
k8s-api-scandataflöde: Celery-uppgiftRabbitMQk8s-rabbitmqScan-uppgiften läggs på RabbitMQ.
RabbitMQ
k8s-rabbitmqdataflöde: consumescan-workerk8s-worker-ai · k8s-worker-ai-2scan-worker (Celery · gevent) i AI-poolen tar den och kör Vision → Rule → Answer → Reward. De fyra stadierna är kedjade Celery-tasks, inte noder.
AI-pool
k8s-worker-ai · k8s-worker-ai-2dataflöde: HTTPSLLM APIScan- och chat-workerna anropar OpenAI:s och Googles API:er.
scan-worker
k8s-worker-ai · k8s-worker-ai-2dataflöde: XADD scan:eventsStreamsk8s-redis-streamsFörloppshändelser skrivs till en av fyra Streams-shards.
Streams
k8s-redis-streamsdataflöde: XREADGROUPEvent Routerk8s-event-routerEvent Router läser dem som consumer group och gör XACK efter bearbetningen; pending och reclaim håller leveransen at-least-once.
Event Router
k8s-event-routerdataflöde: SETEX stateState KVk8s-redis-streamsDen skriver det senaste tillståndet och en markering mot dubbelbearbetning till State KV på samma Redis-nod.
Event Router
k8s-event-routerdataflöde: PUBLISHPub/Subk8s-redis-pubsubLevereras i realtid på jobbets kanal i shard Pub/Sub.
Pub/Sub
k8s-redis-pubsubdataflöde: SUBSCRIBESSE Gatewayk8s-sse-gatewaySSE Gateway prenumererar via en delad listener per process och fördelar till varje ansluten webbläsare.
SSE Gateway
k8s-sse-gatewaydataflöde: SSE-streamWebbläsareEn anslutning öppnad över samma ALB- och ingress-väg. Leveransen är at-least-once; dubbletter hanteras idempotent.
State KV
k8s-redis-streamsdataflöde: Återställning vid återanslutningSSE Gatewayk8s-sse-gatewayVid återanslutning med Last-Event-ID fyller State KV och de bevarade Streams i missade händelser.
Chat · tokens och lagring
Chat-tokens tar samma händelseväg som Scan; checkpoints och meddelanden sparas av två olika arbetslaster.
Webbläsaredataflöde: HTTPS 443AWS ALB
TLS avslutas vid ALB:n.
AWS ALBdataflöde: HTTP · NodePortIstio ingress Envoy
k8s-ingress-gatewayLämnas till Istio ingress Envoy via EC2-instansmålets NodePort.
Istio ingress Envoy
k8s-ingress-gatewaydataflöde: VirtualServiceChat APIk8s-api-chatRoutas till Chat API.
Chat API
k8s-api-chatdataflöde: Taskiq-uppgiftRabbitMQk8s-rabbitmqChat-uppgiften läggs på RabbitMQ.
RabbitMQ
k8s-rabbitmqdataflöde: consumechat-workerk8s-worker-ai · k8s-worker-ai-2chat-worker (Taskiq · asyncio) klassificerar avsikten med LangGraph, kör sedan vision vid behov, de valda verktygen, aggregatorn och en sammanfattning vid behov och svarar. Varje förfrågan kör bara de grenar den behöver.
AI-pool
k8s-worker-ai · k8s-worker-ai-2dataflöde: HTTPSLLM APIScan- och chat-workerna anropar OpenAI:s och Googles API:er.
chat-worker
k8s-worker-ai · k8s-worker-ai-2dataflöde: XADD chat:eventsStreamsk8s-redis-streamsTokens och stage-händelser skrivs till fyra Streams-shards; därifrån är leveransvägen densamma som för Scan.
Streams
k8s-redis-streamsdataflöde: XREADGROUPEvent Routerk8s-event-routerEvent Router läser dem som consumer group och gör XACK efter bearbetningen; pending och reclaim håller leveransen at-least-once.
Event Router
k8s-event-routerdataflöde: PUBLISHPub/Subk8s-redis-pubsubLevereras i realtid på jobbets kanal i shard Pub/Sub.
Pub/Sub
k8s-redis-pubsubdataflöde: SUBSCRIBESSE Gatewayk8s-sse-gatewaySSE Gateway prenumererar via en delad listener per process och fördelar till varje ansluten webbläsare.
SSE Gateway
k8s-sse-gatewaydataflöde: SSE-streamWebbläsareEn anslutning öppnad över samma ALB- och ingress-väg. Leveransen är at-least-once; dubbletter hanteras idempotent.
chat-worker
k8s-worker-ai · k8s-worker-ai-2dataflöde: checkpointCachek8s-redis-cacheLangGraph-checkpointen hålls i Redis Cache.
Cache
k8s-redis-cachedataflöde: läs checkpointcheckpoint-syncerk8s-worker-ai · k8s-worker-ai-2checkpoint-syncer läser checkpointen från Redis.
checkpoint-syncer
k8s-worker-ai · k8s-worker-ai-2dataflöde: synka till PostgreSQLPostgreSQLk8s-postgresqlAsyncPostgresSaver sparar den asynkront i PostgreSQL.
Streams
k8s-redis-streamsdataflöde: chat-persistence grouppersistence consumerk8s-api-chatpersistence consumer på Chat-noden läser done-händelser som consumer group.
persistence consumer
k8s-api-chatdataflöde: spara meddelandenPostgreSQLk8s-postgresqlChattmeddelanden sparas i PostgreSQL. Det är en annan arbetslast än checkpoint-syncer.
Ingång · autentisering
Den synkrona vägen från klustrets ingång till ett domän-API. Bara policyskyddade vägar kontrollerar autentisering först; podtrafik mellan noder går över Calico VXLAN.
WebbläsareDNS-uppslag: DNS-uppslagRoute 53
Bara namnet slås upp i Route 53-poster. Förfrågningar passerar inte genom DNS.
Webbläsaredataflöde: HTTPS 443AWS ALB
TLS avslutas vid ALB:n.
AWS ALBdataflöde: HTTP · NodePortIstio ingress Envoy
k8s-ingress-gatewayLämnas till Istio ingress Envoy via EC2-instansmålets NodePort.
Istio ingress Envoy
k8s-ingress-gatewaydataflöde: ext-authz · gRPC 50051ext-authzk8s-api-authBara vägar under en CUSTOM-policy frågar först Go ext-authz (timeout 2 s, failOpen false). Vägar som login, health och docs är undantagna.
ext-authz
k8s-api-authdataflöde: blacklist-uppslagblacklistk8s-redis-authToken kontrolleras mot Redis-blacklistan.
Istio ingress Envoy
k8s-ingress-gatewaydataflöde: VirtualServiceChat APIk8s-api-chatRoutas till Chat API.
Chat API
k8s-api-chatdataflöde: gRPCimages APIk8s-api-imageDet synkrona anropet chat → images som nämns i README.
auth API
k8s-api-authdataflöde: gRPCusers APIk8s-api-usersDet synkrona anropet auth → users som nämns i README.
Storage-pool · asynkrona skrivningar
Blacklistan för autentisering och ägarskap av figurer sparas av workers i storage-poolen, som hämtar sitt arbete från RabbitMQ.
blacklist
k8s-redis-authdataflöde: outbox:blacklistauth-relayk8s-worker-storage · k8s-worker-storage-2auth-relay (README:s auth-Bus) läser Redis-outboxen.
auth-relay
k8s-worker-storage · k8s-worker-storage-2dataflöde: blacklist.eventsRabbitMQk8s-rabbitmqDen publicerar om till RabbitMQ, med omförsök och en DLQ.
RabbitMQ
k8s-rabbitmqdataflöde: blacklist.eventsauth-workerk8s-worker-storage · k8s-worker-storage-2auth-worker tar emot blacklist-händelserna.
auth-worker
k8s-worker-storage · k8s-worker-storage-2dataflöde: spara blacklistblacklistk8s-redis-authDe sparas i Redis-blacklistan.
RabbitMQ
k8s-rabbitmqdataflöde: Celery batchusers-workerk8s-worker-storage · k8s-worker-storage-2users-worker tar emot arbete om ägarskap av figurer i batchar.
users-worker
k8s-worker-storage · k8s-worker-storage-2dataflöde: UPSERTPostgreSQLk8s-postgresqlDet skrivs till PostgreSQL.
Konfigurera · skala · observera
Platform Layer är inget steg som förfrågningar passerar; det driftsätter, konfigurerar, skalar och observerar de andra lagren. Noderna är EC2-instanser skapade med Terraform, med kubeadm och Calico installerade av Ansible; CI validerar bara Terraform och kör aldrig apply automatiskt.
GitHub Actions · Docker Hubkonfiguration · skalning: image · manifestrevisionArgo CD image updater
k8s-masterArgo CD synkroniserar klustrets konfiguration via App-of-Apps och Sync Waves. Bara image updaterns placering på control plane bekräftades.
ALB Controller · ExternalDNS
k8s-masterkonfiguration · skalning: Ingress → ALB · DNS-posterAWS-hanteratALB Controller och ExternalDNS konfigurerar resurser på AWS-sidan. Det är ingen väg som förfrågningar tar.
Istiod
k8s-masterkonfiguration · skalning: xDS-konfigurationIstio ingress Envoyk8s-ingress-gatewayIstiod skickar Gateway-, VirtualService- och EnvoyFilter-konfigurationen via xDS till ingress Envoy och till varje API:s Envoy-sidecar.
KEDA
k8s-monitoringkonfiguration · skalning: antal podsAI-poolk8s-worker-ai · k8s-worker-ai-2KEDA justerar antalet worker-pods. Antalet noder ändras inte.
KEDA
k8s-monitoringkonfiguration · skalning: antal podsstorage-poolk8s-worker-storage · k8s-worker-storage-2Worker-pods i storage-poolen skalas på samma sätt.
Fluent Bitobserverbarhet: loggarElasticsearch
k8s-loggingFluent Bit är ett DaemonSet på alla noder och skickar loggar till Elasticsearch.
AI-pool
k8s-worker-ai · k8s-worker-ai-2observerbarhet: spårning av LLM-körningarLangSmithTraces av LLM-anrop skickas till LangSmith, en extern SaaS.
Alla kopplingar med samma tjocklek. Välj ett flöde för att bara markera dess väg, med numrerade steg.
- Heldragen · riktningen som förfrågningar, arbete, händelser och skrivningar flödar i
- Prickad · DNS-uppslag; förfrågningar passerar inte genom det
- Streckad · konfiguration eller skalning; inte en dataväg
- Lång streck-punkt · loggar och spårning av körningar
- Kraftig svart linje · det valda flödet; siffrorna anger ordningen
- Ruta · en fysisk nod, värdnamn i rubriken
- Inre chip · en arbetslast som körs på noden
- Streckad ram · en schemaläggningspool med två noder
- Streckad ruta · utanför klustret, räknas inte som nod
- Orange kontur · där en modell fattar beslut
- Control plane1 nod
- Domain API8 noder
- AI-pool2 noder
- storage-pool2 noder
- Data5 noder
- Platform6 noder
README:s fem lager (banden) och de fysiska grupperna (färgen i varje nods rubrik) grupperar samma 24 noder olika. State KV delar Streams-noden och räknas inte separat; Route 53, ALB:n och tjänster utanför klustret är inte noder. En pool är ett schemaläggningsområde, inget påstående om att varje pod körs på båda noderna.
24noder
24 = 1 control plane + 8 API + 4 worker + 5 data + 6 platform
1Control plane
role: control-planekube-apiserver · scheduler · controller-manager · etcd samt plattformens controllrar.
- k8s-master
8Domain API
domain: <tjänst>En nod per domän. Interna anrop använder 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
Två schemaläggningspooler med två noder vardera. KEDA ändrar antalet pods; antalet noder förblir detsamma.
storage-pool
domain: worker-storage- k8s-worker-storage
- k8s-worker-storage-2
AI-pool
domain: worker-ai- k8s-worker-ai
- k8s-worker-ai-2
5Data
Redis är uppdelat på fyra noder efter användning. PostgreSQL-lagringen är EBS CSI · gp3.
- k8s-postgresql
- k8s-redis-auth
- k8s-redis-streams
- k8s-redis-cache
- k8s-redis-pubsub
6Platform
Meddelanden, observerbarhet, ingress och leverans i realtid har var sin nod.
- k8s-rabbitmq
- k8s-monitoring
- k8s-logging
- k8s-ingress-gateway
- k8s-sse-gateway
- k8s-event-router
- Alla noder
- Fluent Bit · DaemonSet
- Calico
Konfigurerade modeller · per leverantör
Tjänsten har lagts ned, så detta är de modeller som är konfigurerade i repositoryt, inte val som finns i dag. Varje roll anges separat; detta är ingen lista över verifierade körningar.
OpenAI
Standardleverantör för Chat
Chat
openai/gpt-5.2standard
Standardmodellen är gpt-5.2; en modell som anges i förfrågan används i stället.
Scan
gpt-5.2standardgpt-5.2-progpt-5.1gpt-5gpt-5-progpt-5-mini
Modeller utanför mappningen med 13 modeller avvisas.
Bildmappning
gpt-image-1.5
Skild från gpt-5.2, som är orkestreringsmodellen för Responses. Bildgenerering är avstängd som standard.
Utvärdering
gpt-4o-ministandard
LLM-gradern för utvärdering av samtal, skild från Chat-modellen.
Google
När Chat väljer Google
Chat
google/gemini-3-pro-previewgoogle/gemini-3-flash-preview
När Google är valt är gemini-3-flash-preview standard.
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
Bildmappning
gemini-3-pro-image-preview
Källabackend main d8840c7Offentlig commit 29 september 2026 · kontrollerad 8 oktober 2026