
Eco²
Backend · Cloud infrastructure
Сортування відходів за одним фото й розмовою.
Універсальний AI-асистент, що розуміє, як влаштоване сортування відходів у Кореї.
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
Як насправді з’єднані 24 вузли, по одному потоку за раз.
Самокерований Kubernetes, зібраний за допомогою kubeadm. Карта розміщує 24 фізичні вузли й робочі навантаження на них у п’яти шарах із README і з’єднує їх фактичними зв’язками. Оберіть потік, і буде підсвічено лише цей шлях із пронумерованими кроками.
Він розпізнає відходи на фото й пояснює, як їх утилізувати, а в розмові викликає інструменти для місць, погоди, цін на вторсировину та вебпошуку й генерує зображення. У цьому командному проєкті я почав із кластера й основи розгортання, а потім розширив свою зону до доменного бекенду, асинхронної обробки, розмовного агента й верифікації.
Від розробки для конкурсу до посилення бекенду й експлуатації
Сервіс завершив роботу; записане демо й технічний звіт показують його в дії.
Запит Scan → доставка наживо
Запит на аналіз фото стає роботою в черзі, а події її поступу повертаються в той самий браузер.
БраузерDNS-запит: DNS-запитRoute 53
З записів Route 53 визначається лише ім’я. Запити через DNS не проходять.
Браузерпотік даних: HTTPS 443AWS ALB
TLS завершується на ALB.
AWS ALBпотік даних: HTTP · NodePortIstio ingress Envoy
k8s-ingress-gatewayПередається в Istio ingress Envoy через NodePort цілі-інстансу EC2.
Istio ingress Envoy
k8s-ingress-gatewayпотік даних: VirtualServiceScan APIk8s-api-scanМаршрутизується до Scan API, який ставить роботу в чергу й одразу повертає job_id; на запит результату він відповідає 202, доки завдання не завершиться.
Scan API
k8s-api-scanпотік даних: Завдання CeleryRabbitMQk8s-rabbitmqЗавдання Scan іде в RabbitMQ.
RabbitMQ
k8s-rabbitmqпотік даних: consumescan-workerk8s-worker-ai · k8s-worker-ai-2scan-worker (Celery · gevent) у пулі AI бере його й виконує Vision → Rule → Answer → Reward. Чотири етапи — це завдання Celery, з’єднані в ланцюжок, а не вузли.
Пул AI
k8s-worker-ai · k8s-worker-ai-2потік даних: HTTPSLLM APIВоркери scan і chat викликають API OpenAI і Google.
scan-worker
k8s-worker-ai · k8s-worker-ai-2потік даних: XADD scan:eventsStreamsk8s-redis-streamsПодії поступу записуються в один із чотирьох шардів Streams.
Streams
k8s-redis-streamsпотік даних: XREADGROUPEvent Routerk8s-event-routerEvent Router читає їх як consumer group і після обробки виконує XACK; pending і reclaim забезпечують доставку at-least-once.
Event Router
k8s-event-routerпотік даних: SETEX stateState KVk8s-redis-streamsВін записує останній стан і маркер повторної обробки в State KV на тому самому вузлі Redis.
Event Router
k8s-event-routerпотік даних: PUBLISHPub/Subk8s-redis-pubsubДоставляється в реальному часі каналом завдання в шардованому Pub/Sub.
Pub/Sub
k8s-redis-pubsubпотік даних: SUBSCRIBESSE Gatewayk8s-sse-gatewaySSE Gateway підписується через один спільний listener на процес і розсилає кожному підключеному браузеру.
SSE Gateway
k8s-sse-gatewayпотік даних: Потік SSEБраузерЗ’єднання, відкрите тим самим шляхом через ALB та ingress. Доставка at-least-once; дублікати обробляються ідемпотентно.
State KV
k8s-redis-streamsпотік даних: Відновлення після перепідключенняSSE Gatewayk8s-sse-gatewayПід час перепідключення з Last-Event-ID State KV і збережені Streams заповнюють пропущені події.
Chat · токени й зберігання
Токени Chat ідуть тим самим шляхом подій, що й Scan; контрольні точки й повідомлення зберігають два різні робочі навантаження.
Браузерпотік даних: HTTPS 443AWS ALB
TLS завершується на ALB.
AWS ALBпотік даних: HTTP · NodePortIstio ingress Envoy
k8s-ingress-gatewayПередається в Istio ingress Envoy через NodePort цілі-інстансу EC2.
Istio ingress Envoy
k8s-ingress-gatewayпотік даних: VirtualServiceChat APIk8s-api-chatМаршрутизується до Chat API.
Chat API
k8s-api-chatпотік даних: Завдання TaskiqRabbitMQk8s-rabbitmqЗавдання Chat іде в RabbitMQ.
RabbitMQ
k8s-rabbitmqпотік даних: consumechat-workerk8s-worker-ai · k8s-worker-ai-2chat-worker (Taskiq · asyncio) класифікує намір за допомогою LangGraph, потім за потреби виконує vision, обрані інструменти, aggregator і за потреби підсумок, після чого відповідає. Кожен запит виконує лише потрібні йому гілки.
Пул AI
k8s-worker-ai · k8s-worker-ai-2потік даних: HTTPSLLM APIВоркери scan і chat викликають API OpenAI і Google.
chat-worker
k8s-worker-ai · k8s-worker-ai-2потік даних: XADD chat:eventsStreamsk8s-redis-streamsТокени й події етапів записуються в чотири шарди Streams; далі шлях доставки такий самий, як у Scan.
Streams
k8s-redis-streamsпотік даних: XREADGROUPEvent Routerk8s-event-routerEvent Router читає їх як consumer group і після обробки виконує XACK; pending і reclaim забезпечують доставку at-least-once.
Event Router
k8s-event-routerпотік даних: PUBLISHPub/Subk8s-redis-pubsubДоставляється в реальному часі каналом завдання в шардованому Pub/Sub.
Pub/Sub
k8s-redis-pubsubпотік даних: SUBSCRIBESSE Gatewayk8s-sse-gatewaySSE Gateway підписується через один спільний listener на процес і розсилає кожному підключеному браузеру.
SSE Gateway
k8s-sse-gatewayпотік даних: Потік SSEБраузерЗ’єднання, відкрите тим самим шляхом через ALB та ingress. Доставка at-least-once; дублікати обробляються ідемпотентно.
chat-worker
k8s-worker-ai · k8s-worker-ai-2потік даних: checkpointCachek8s-redis-cacheКонтрольна точка LangGraph зберігається в Redis Cache.
Cache
k8s-redis-cacheпотік даних: читання контрольної точкиcheckpoint-syncerk8s-worker-ai · k8s-worker-ai-2checkpoint-syncer читає контрольну точку з Redis.
checkpoint-syncer
k8s-worker-ai · k8s-worker-ai-2потік даних: синхронізація з PostgreSQLPostgreSQLk8s-postgresqlAsyncPostgresSaver асинхронно зберігає її в PostgreSQL.
Streams
k8s-redis-streamsпотік даних: chat-persistence grouppersistence consumerk8s-api-chatpersistence consumer на вузлі Chat читає події done як consumer group.
persistence consumer
k8s-api-chatпотік даних: збереження повідомленьPostgreSQLk8s-postgresqlПовідомлення Chat зберігаються в PostgreSQL. Це інше робоче навантаження, ніж checkpoint-syncer.
Вхід · автентифікація
Синхронний шлях від входу в кластер до доменного API. Лише шляхи під політикою спершу перевіряють автентифікацію; трафік подів між вузлами йде через Calico VXLAN.
БраузерDNS-запит: DNS-запитRoute 53
З записів Route 53 визначається лише ім’я. Запити через DNS не проходять.
Браузерпотік даних: HTTPS 443AWS ALB
TLS завершується на ALB.
AWS ALBпотік даних: HTTP · NodePortIstio ingress Envoy
k8s-ingress-gatewayПередається в Istio ingress Envoy через NodePort цілі-інстансу EC2.
Istio ingress Envoy
k8s-ingress-gatewayпотік даних: ext-authz · gRPC 50051ext-authzk8s-api-authЛише шляхи під політикою CUSTOM спершу звертаються до Go ext-authz (тайм-аут 2 с, failOpen false). Шляхи на кшталт login, health і docs виключено.
ext-authz
k8s-api-authпотік даних: перевірка чорного спискуblacklistk8s-redis-authТокен перевіряється за чорним списком Redis.
Istio ingress Envoy
k8s-ingress-gatewayпотік даних: VirtualServiceChat APIk8s-api-chatМаршрутизується до Chat API.
Chat API
k8s-api-chatпотік даних: gRPCimages APIk8s-api-imageСинхронний виклик chat → images, зазначений у README.
auth API
k8s-api-authпотік даних: gRPCusers APIk8s-api-usersСинхронний виклик auth → users, зазначений у README.
Пул storage · асинхронний запис
Чорний список автентифікації та володіння персонажами зберігають воркери пулу storage, які беруть роботу з RabbitMQ.
blacklist
k8s-redis-authпотік даних: outbox:blacklistauth-relayk8s-worker-storage · k8s-worker-storage-2auth-relay (auth-Bus у README) читає outbox Redis.
auth-relay
k8s-worker-storage · k8s-worker-storage-2потік даних: blacklist.eventsRabbitMQk8s-rabbitmqВін повторно публікує в RabbitMQ, з повторами й DLQ.
RabbitMQ
k8s-rabbitmqпотік даних: blacklist.eventsauth-workerk8s-worker-storage · k8s-worker-storage-2auth-worker отримує події чорного списку.
auth-worker
k8s-worker-storage · k8s-worker-storage-2потік даних: збереження чорного спискуblacklistk8s-redis-authВони зберігаються в чорному списку Redis.
RabbitMQ
k8s-rabbitmqпотік даних: Celery batchusers-workerk8s-worker-storage · k8s-worker-storage-2users-worker отримує роботу з володіння персонажами пакетами.
users-worker
k8s-worker-storage · k8s-worker-storage-2потік даних: UPSERTPostgreSQLk8s-postgresqlВона застосовується до PostgreSQL.
Налаштування · масштабування · спостереження
Platform Layer — не етап, через який проходять запити; він розгортає, налаштовує, масштабує й спостерігає інші шари. Вузли — це інстанси EC2, створені Terraform, із kubeadm і Calico, встановленими через Ansible; CI лише перевіряє Terraform і ніколи не застосовує його автоматично.
GitHub Actions · Docker Hubналаштування · масштабування: образ · ревізія маніфестуArgo CD image updater
k8s-masterArgo CD узгоджує конфігурацію кластера через App-of-Apps і Sync Waves. Підтверджено лише розміщення image updater на control-plane.
ALB Controller · ExternalDNS
k8s-masterналаштування · масштабування: Ingress → ALB · DNS-записиПід керуванням AWSALB Controller і ExternalDNS налаштовують ресурси на боці AWS. Це не шлях, яким проходять запити.
Istiod
k8s-masterналаштування · масштабування: конфігурація xDSIstio ingress Envoyk8s-ingress-gatewayIstiod передає конфігурацію Gateway, VirtualService і EnvoyFilter через xDS в ingress Envoy і в Envoy sidecar кожного API.
KEDA
k8s-monitoringналаштування · масштабування: кількість подівПул AIk8s-worker-ai · k8s-worker-ai-2KEDA змінює кількість подів воркерів. Кількість вузлів не змінюється.
KEDA
k8s-monitoringналаштування · масштабування: кількість подівпул storagek8s-worker-storage · k8s-worker-storage-2Поди воркерів пулу storage масштабуються так само.
Fluent Bitспостережуваність: журналиElasticsearch
k8s-loggingFluent Bit — DaemonSet на кожному вузлі, що надсилає журнали в Elasticsearch.
Пул AI
k8s-worker-ai · k8s-worker-ai-2спостережуваність: трасування запусків LLMLangSmithТраси викликів LLM ідуть до LangSmith — зовнішнього SaaS.
Усі зв’язки однакової товщини. Оберіть потік, щоб підсвітити лише його шлях із пронумерованими кроками.
- Суцільна · напрямок, яким рухаються запити, робота, події й записи
- Пунктирна · DNS-запит; запити через нього не проходять
- Штрихова · налаштування чи масштабування; не шлях даних
- Довга штрихпунктирна · журнали й трасування запусків
- Товста чорна лінія · обраний потік; номери показують порядок
- Рамка · фізичний вузол, ім’я хоста в заголовку
- Внутрішня плашка · робоче навантаження на цьому вузлі
- Штрихова рамка · пул планування з двох вузлів
- Штрихова рамка · поза кластером, не рахується як вузол
- Помаранчевий контур · де вирішує модель
- Control plane1 вузол
- Domain API8 вузлів
- Пул AI2 вузли
- пул storage2 вузли
- Data5 вузлів
- Platform6 вузлів
П’ять шарів із README (смуги) й фізичні групи (відтінок заголовка кожного вузла) групують ті самі 24 вузли по-різному. State KV ділить вузол зі Streams і окремо не рахується; Route 53, ALB і сервіси поза кластером не є вузлами. Пул — це діапазон планування, а не твердження, що кожен под працює на обох вузлах.
24вузлів
24 = 1 control plane + 8 API + 4 worker + 5 data + 6 platform
1Control plane
role: control-planekube-apiserver · scheduler · controller-manager · etcd, а також контролери платформи.
- k8s-master
8Domain API
domain: <сервіс>Один вузол на домен. Внутрішні виклики використовують 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
Два пули планування по два вузли. KEDA змінює кількість подів; кількість вузлів лишається тією самою.
пул storage
domain: worker-storage- k8s-worker-storage
- k8s-worker-storage-2
Пул AI
domain: worker-ai- k8s-worker-ai
- k8s-worker-ai-2
5Data
Redis розділено за призначенням на чотири вузли. Сховище PostgreSQL — EBS CSI · gp3.
- k8s-postgresql
- k8s-redis-auth
- k8s-redis-streams
- k8s-redis-cache
- k8s-redis-pubsub
6Platform
Обмін повідомленнями, спостережуваність, ingress і доставка в реальному часі мають кожен свій вузол.
- k8s-rabbitmq
- k8s-monitoring
- k8s-logging
- k8s-ingress-gateway
- k8s-sse-gateway
- k8s-event-router
- Кожен вузол
- Fluent Bit · DaemonSet
- Calico
Налаштовані моделі · за провайдерами
Сервіс закрито, тож це моделі, налаштовані в репозиторії, а не варіанти, доступні сьогодні. Кожну роль наведено окремо; це не список перевірених запусків.
OpenAI
Типовий провайдер Chat
Chat
openai/gpt-5.2типово
Типова модель — gpt-5.2; якщо модель вказано в запиті, використовується вона.
Scan
gpt-5.2типовоgpt-5.2-progpt-5.1gpt-5gpt-5-progpt-5-mini
Моделі поза відображенням із 13 моделей відхиляються.
Відображення зображень
gpt-image-1.5
Окремо від gpt-5.2 — моделі оркестрації Responses. Генерацію зображень типово вимкнено.
Оцінювання
gpt-4o-miniтипово
LLM grader для оцінювання розмов, окремий від моделі Chat.
Google
Коли в Chat обрано Google
Chat
google/gemini-3-pro-previewgoogle/gemini-3-flash-preview
Якщо обрано Google, типовою є gemini-3-flash-preview.
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
Відображення зображень
gemini-3-pro-image-preview
Джерелоbackend main d8840c7Публічний коміт September 29, 2026 · перевірено October 8, 2026