Eco² 地球角色,以最新的官方主角色為基礎、為本作品集重新調整:天藍色的地球,綠色陸地,頭頂一株新芽,棕色的笑臉
返回展廳

Eco²

Backend · Cloud infrastructure

一張照片與一段對話,就能得到資源回收指引。

一款了解韓國資源回收方式的一站式 AI 助理。

2025.10.31 — 2026.02.10

團隊專案 · 基礎設施與部署基礎 → 領域後端 → 非同步處理、對話代理、驗證

2025 새싹 해커톤 (Saessak Hackathon)優秀獎 · 2025年12月2日

  • 網頁應用程式已終止營運

Eco² vocabulary

Lens
Service Path
Request Path
Async Work
Operations
Infrastructure
Measurement
  1. edge
  2. auth offload
  3. domain api
  1. task queue
  2. scan pipeline
  3. chat agent
  4. event bus
  1. cluster
  2. gitops
  3. autoscaling
  1. observability
  2. load test
  3. 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 個節點實際上如何連接,一次看一條流程。

以 kubeadm 建置的自行管理 Kubernetes。架構圖將 24 個實體節點及其上的工作負載,放進 README 的五個層級中,並以實際連線相接。選擇一條流程,即只標示該路徑並附上步驟編號。

它從照片辨識廢棄物並說明丟棄方式,在對話中呼叫地點、天氣、回收價格與網路搜尋等工具,並生成圖片。在這個團隊專案中,我從叢集與部署基礎開始,逐步將負責範圍擴展到領域後端、非同步處理、對話代理與驗證。

從競賽開發到後端與維運強化

服務已結束營運;錄製的示範影片與技術報告呈現其運作情形。

叢集連線架構圖 · 依提交 a072127 的 manifest 與程式碼重新繪製
Eco² 叢集連線架構圖 · 24 個節點README 五個層級帶狀區內 24 個實體節點的架構圖。瀏覽器只向 Route 53 查詢名稱;TLS 在 ALB 的 443 埠終止後,NodePort 上的 Istio ingress Envoy 將請求送往領域 API。Scan API 將工作放入 RabbitMQ 佇列並立即傳回 job_id;AI 池中的 scan-worker 以 XADD 將進度事件寫入 Redis Streams。Event Router 讀取這些事件、更新 State KV 並發布到 Pub/Sub,SSE Gateway 再將其送往瀏覽器。checkpoint-syncer 儲存 Chat 的檢查點,Chat 節點上的 persistence consumer 則將訊息存入 PostgreSQL。Platform Layer 不是請求路徑;它負責設定、擴展與觀測。瀏覽器HTTPS · SSEAWS ALB443 · TLS 在此終止Route 53DNSGitHub Actions · Docker Hub映像檔 · manifest 修訂版本LLM APIOpenAI · GoogleLangSmithLLM 執行追蹤Fluent BitDaemonSet · 每個節點k8s-masterALB Controller · ExternalDNSArgo CD image updaterIstiodcontrol planek8s-ingress-gatewayIstio ingress Envoyk8s-api-scanScan APIk8s-api-chatChat APImessage consumerpersistence consumerk8s-api-authauth APIext-authzk8s-api-infoInfo APIinfo-workerk8s-api-charactercharacter APIk8s-api-imageimages APIk8s-api-usersusers APIk8s-api-locationlocation APIk8s-sse-gatewaySSE Gatewayk8s-event-routerEvent Routerk8s-rabbitmqRabbitMQk8s-worker-aik8s-worker-ai-2k8s-worker-storagek8s-worker-storage-2k8s-redis-pubsubPub/Subk8s-redis-streamsStreamsState KVk8s-redis-cacheCachek8s-postgresqlPostgreSQLk8s-redis-authblacklistk8s-monitoringKEDAPrometheusGrafanaAlertmanagerk8s-loggingElasticsearchKibanascan-workerchat-workercheckpoint-syncerauth-relayauth-workerusers-workercharacter-workercharacter-match-workerKialiJaeger · dev in-memoryKubernetes 叢集24 個節點 · kubeadmEdge Layer1 個節點Service Layer8 個節點 · Envoy sidecarIntegration Layer7 個節點Persistence Layer5 個節點Platform Layer3 個節點 · 設定 · 擴展 · 觀測AWS 託管AI 池domain: worker-ai儲存池domain: worker-storage未指定節點1DNS 查詢2 HTTPS 443 · 瀏覽器 → AWS ALB23HTTP · NodePort4VirtualService5Celery 任務6 consume · RabbitMQ → scan-worker67 HTTPS · AI 池 → LLM API78XADD scan:events9XREADGROUP10SETEX state11PUBLISH12SUBSCRIBE13SSE 串流14重新連線復原1 HTTPS 443 · 瀏覽器 → AWS ALB12HTTP · NodePort3VirtualService4Taskiq 任務5 consume · RabbitMQ → chat-worker56 HTTPS · AI 池 → LLM API67XADD chat:events8XREADGROUP9PUBLISH10SUBSCRIBE11SSE 串流12checkpoint13讀取檢查點14同步至 PostgreSQL15chat-persistence group16儲存訊息1DNS 查詢2 HTTPS 443 · 瀏覽器 → AWS ALB23HTTP · NodePort4ext-authz · gRPC 500515黑名單查詢6VirtualService7gRPC8gRPC1outbox:blacklist2blacklist.events3 blacklist.events · RabbitMQ → auth-worker34儲存黑名單5 Celery batch · RabbitMQ → users-worker56UPSERT1映像檔 · manifest 修訂版本2Ingress → ALB · DNS 記錄3xDS 設定4Pod 數量5 Pod 數量 · KEDA → 儲存池56日誌7 LLM 執行追蹤 · AI 池 → LangSmith7

Scan 請求 → 即時傳遞

照片分析請求成為排入佇列的工作,其進度事件回到同一個瀏覽器。

  1. 瀏覽器DNS 查詢: DNS 查詢Route 53

    只從 Route 53 的記錄解析名稱。請求不會經過 DNS。

  2. 瀏覽器資料流: HTTPS 443AWS ALB

    TLS 在 ALB 終止。

  3. AWS ALB資料流: HTTP · NodePortIstio ingress Envoyk8s-ingress-gateway

    經由 EC2 執行個體目標的 NodePort,交給 Istio ingress Envoy。

  4. Istio ingress Envoyk8s-ingress-gateway資料流: VirtualServiceScan APIk8s-api-scan

    路由至 Scan API,由它將工作排入佇列並立即傳回 job_id;查詢結果時,在作業完成前都回應 202。

  5. Scan APIk8s-api-scan資料流: Celery 任務RabbitMQk8s-rabbitmq

    Scan 任務放入 RabbitMQ。

  6. RabbitMQk8s-rabbitmq資料流: consumescan-workerk8s-worker-ai · k8s-worker-ai-2

    AI 池中的 scan-worker(Celery · gevent)取得任務,執行 Vision → Rule → Answer → Reward。這四個階段是以 chain 串接的 Celery 任務,不是節點。

  7. AI 池k8s-worker-ai · k8s-worker-ai-2資料流: HTTPSLLM API

    scan 與 chat worker 呼叫 OpenAI 與 Google API。

  8. scan-workerk8s-worker-ai · k8s-worker-ai-2資料流: XADD scan:eventsStreamsk8s-redis-streams

    進度事件寫入四個 Streams 分片之一。

  9. Streamsk8s-redis-streams資料流: XREADGROUPEvent Routerk8s-event-router

    Event Router 以 consumer group 讀取,處理後執行 XACK;pending 與 reclaim 確保 at-least-once 傳遞。

  10. Event Routerk8s-event-router資料流: SETEX stateState KVk8s-redis-streams

    它將最新狀態與重複處理標記,寫入同一 Redis 節點上的 State KV。

  11. Event Routerk8s-event-router資料流: PUBLISHPub/Subk8s-redis-pubsub

    透過分片 Pub/Sub 中該作業的頻道即時傳送。

  12. Pub/Subk8s-redis-pubsub資料流: SUBSCRIBESSE Gatewayk8s-sse-gateway

    SSE Gateway 在每個行程中以一個共用的 listener 訂閱,再分送給每個已連線的瀏覽器。

  13. SSE Gatewayk8s-sse-gateway資料流: SSE 串流瀏覽器

    經由相同 ALB 與 ingress 路徑開啟的連線。傳遞為 at-least-once;重複以冪等方式處理。

  14. State KVk8s-redis-streams資料流: 重新連線復原SSE Gatewayk8s-sse-gateway

    帶著 Last-Event-ID 重新連線時,由 State KV 與保留的 Streams 補上遺漏的事件。

Chat · token 與儲存

Chat 的 token 與 Scan 走相同的事件路徑;檢查點與訊息由兩個不同的工作負載儲存。

  1. 瀏覽器資料流: HTTPS 443AWS ALB

    TLS 在 ALB 終止。

  2. AWS ALB資料流: HTTP · NodePortIstio ingress Envoyk8s-ingress-gateway

    經由 EC2 執行個體目標的 NodePort,交給 Istio ingress Envoy。

  3. Istio ingress Envoyk8s-ingress-gateway資料流: VirtualServiceChat APIk8s-api-chat

    路由至 Chat API。

  4. Chat APIk8s-api-chat資料流: Taskiq 任務RabbitMQk8s-rabbitmq

    Chat 任務放入 RabbitMQ。

  5. RabbitMQk8s-rabbitmq資料流: consumechat-workerk8s-worker-ai · k8s-worker-ai-2

    chat-worker(Taskiq · asyncio)以 LangGraph 分類意圖,接著視需要執行 vision、選定的工具、aggregator,必要時再產生摘要,然後回答。每個請求只執行所需的分支。

  6. AI 池k8s-worker-ai · k8s-worker-ai-2資料流: HTTPSLLM API

    scan 與 chat worker 呼叫 OpenAI 與 Google API。

  7. chat-workerk8s-worker-ai · k8s-worker-ai-2資料流: XADD chat:eventsStreamsk8s-redis-streams

    token 與階段事件寫入四個 Streams 分片;之後的傳遞路徑與 Scan 相同。

  8. Streamsk8s-redis-streams資料流: XREADGROUPEvent Routerk8s-event-router

    Event Router 以 consumer group 讀取,處理後執行 XACK;pending 與 reclaim 確保 at-least-once 傳遞。

  9. Event Routerk8s-event-router資料流: PUBLISHPub/Subk8s-redis-pubsub

    透過分片 Pub/Sub 中該作業的頻道即時傳送。

  10. Pub/Subk8s-redis-pubsub資料流: SUBSCRIBESSE Gatewayk8s-sse-gateway

    SSE Gateway 在每個行程中以一個共用的 listener 訂閱,再分送給每個已連線的瀏覽器。

  11. SSE Gatewayk8s-sse-gateway資料流: SSE 串流瀏覽器

    經由相同 ALB 與 ingress 路徑開啟的連線。傳遞為 at-least-once;重複以冪等方式處理。

  12. chat-workerk8s-worker-ai · k8s-worker-ai-2資料流: checkpointCachek8s-redis-cache

    LangGraph 的檢查點保存在 Redis Cache 中。

  13. Cachek8s-redis-cache資料流: 讀取檢查點checkpoint-syncerk8s-worker-ai · k8s-worker-ai-2

    checkpoint-syncer 從 Redis 讀取檢查點。

  14. checkpoint-syncerk8s-worker-ai · k8s-worker-ai-2資料流: 同步至 PostgreSQLPostgreSQLk8s-postgresql

    AsyncPostgresSaver 以非同步方式將其存入 PostgreSQL。

  15. Streamsk8s-redis-streams資料流: chat-persistence grouppersistence consumerk8s-api-chat

    Chat 節點上的 persistence consumer 以 consumer group 讀取 done 事件。

  16. persistence consumerk8s-api-chat資料流: 儲存訊息PostgreSQLk8s-postgresql

    Chat 訊息存入 PostgreSQL。這與 checkpoint-syncer 是不同的工作負載。

入口 · 身分驗證

從叢集入口到達領域 API 的同步路徑。只有受策略保護的路徑會先檢查身分驗證;節點之間的 Pod 通訊使用 Calico VXLAN。

  1. 瀏覽器DNS 查詢: DNS 查詢Route 53

    只從 Route 53 的記錄解析名稱。請求不會經過 DNS。

  2. 瀏覽器資料流: HTTPS 443AWS ALB

    TLS 在 ALB 終止。

  3. AWS ALB資料流: HTTP · NodePortIstio ingress Envoyk8s-ingress-gateway

    經由 EC2 執行個體目標的 NodePort,交給 Istio ingress Envoy。

  4. Istio ingress Envoyk8s-ingress-gateway資料流: ext-authz · gRPC 50051ext-authzk8s-api-auth

    只有套用 CUSTOM 策略的路徑,才會先詢問 Go ext-authz(逾時 2 秒,failOpen false)。登入、health 與 docs 等路徑不在此列。

  5. ext-authzk8s-api-auth資料流: 黑名單查詢blacklistk8s-redis-auth

    以 Redis 黑名單檢查權杖。

  6. Istio ingress Envoyk8s-ingress-gateway資料流: VirtualServiceChat APIk8s-api-chat

    路由至 Chat API。

  7. Chat APIk8s-api-chat資料流: gRPCimages APIk8s-api-image

    README 中載明的 chat → images 同步呼叫。

  8. auth APIk8s-api-auth資料流: gRPCusers APIk8s-api-users

    README 中載明的 auth → users 同步呼叫。

儲存池 · 非同步儲存

身分驗證黑名單與角色擁有權,由儲存池的 worker 儲存,這些 worker 從 RabbitMQ 取得工作。

  1. blacklistk8s-redis-auth資料流: outbox:blacklistauth-relayk8s-worker-storage · k8s-worker-storage-2

    auth-relay(README 中的 auth-Bus)讀取 Redis outbox。

  2. auth-relayk8s-worker-storage · k8s-worker-storage-2資料流: blacklist.eventsRabbitMQk8s-rabbitmq

    它重新發布到 RabbitMQ,並具備重試與 DLQ。

  3. RabbitMQk8s-rabbitmq資料流: blacklist.eventsauth-workerk8s-worker-storage · k8s-worker-storage-2

    auth-worker 接收黑名單事件。

  4. auth-workerk8s-worker-storage · k8s-worker-storage-2資料流: 儲存黑名單blacklistk8s-redis-auth

    事件存入 Redis 黑名單。

  5. RabbitMQk8s-rabbitmq資料流: Celery batchusers-workerk8s-worker-storage · k8s-worker-storage-2

    users-worker 以批次接收角色擁有權的工作。

  6. users-workerk8s-worker-storage · k8s-worker-storage-2資料流: UPSERTPostgreSQLk8s-postgresql

    套用至 PostgreSQL。

設定 · 擴展 · 觀測

Platform Layer 不是請求經過的步驟;它部署、設定、擴展並觀測其他層級。節點是以 Terraform 建立的 EC2,並以 Ansible 安裝 kubeadm 與 Calico;CI 只驗證 Terraform,從不自動 apply。

  1. GitHub Actions · Docker Hub設定 · 擴縮: 映像檔 · manifest 修訂版本Argo CD image updaterk8s-master

    Argo CD 透過 App-of-Apps 與 Sync Waves 使叢集設定保持一致。只確認了 image updater 位於 control-plane。

  2. ALB Controller · ExternalDNSk8s-master設定 · 擴縮: Ingress → ALB · DNS 記錄AWS 託管

    ALB Controller 與 ExternalDNS 設定 AWS 端的資源。這不是請求經過的路徑。

  3. Istiodk8s-master設定 · 擴縮: xDS 設定Istio ingress Envoyk8s-ingress-gateway

    Istiod 透過 xDS,將 Gateway、VirtualService 與 EnvoyFilter 設定推送到 ingress Envoy 與各 API 的 Envoy sidecar。

  4. KEDAk8s-monitoring設定 · 擴縮: Pod 數量AI 池k8s-worker-ai · k8s-worker-ai-2

    KEDA 調整 worker Pod 的數量。節點數量不變。

  5. KEDAk8s-monitoring設定 · 擴縮: Pod 數量儲存池k8s-worker-storage · k8s-worker-storage-2

    儲存池的 worker Pod 也以相同方式調整規模。

  6. Fluent Bit觀測: 日誌Elasticsearchk8s-logging

    Fluent Bit 是每個節點上的 DaemonSet,將日誌送往 Elasticsearch。

  7. AI 池k8s-worker-ai · k8s-worker-ai-2觀測: LLM 執行追蹤LangSmith

    LLM 呼叫的追蹤送往外部 SaaS LangSmith。

所有連線以相同粗細顯示。選擇一個流程,即只突顯其路徑,並標出步驟編號。

  • 實線 · 請求、工作、事件與寫入的流向
  • 點線 · DNS 查詢;請求不經過此處
  • 虛線 · 設定或擴縮;不是資料路徑
  • 長點劃線 · 日誌與執行追蹤
  • 粗黑線 · 所選流程;數字表示順序
  • 方框 · 實體節點,標題為主機名稱
  • 內層小框 · 在該節點上執行的工作負載
  • 虛線框 · 由兩個節點組成的排程池
  • 虛線框 · 位於叢集之外,不計入節點數
  • 橘色外框 · 模型做出判斷之處
  • Control plane1 個節點
  • Domain API8 個節點
  • AI 池2 個節點
  • 儲存池2 個節點
  • Data5 個節點
  • Platform6 個節點

README 的五個層級(帶狀區)與實體群組(各節點標頭的色調),以不同方式歸組同樣的 24 個節點。State KV 與 Streams 共用節點,不另行計算;Route 53、ALB 與叢集外的服務不是節點。池是排程範圍,並不表示每個 Pod 都在兩個節點上執行。

24 節點配置 · 依 2026年1月21日儀表板的節點清單

24節點

24 = 1 control plane + 8 API + 4 worker + 5 data + 6 platform

  1. 1Control plane

    role: control-plane

    kube-apiserver · scheduler · controller-manager · etcd,以及平台控制器。

    1. k8s-master
  2. 8Domain API

    domain: <服務>

    每個領域一個節點。內部呼叫使用 gRPC。

    1. k8s-api-auth
    2. k8s-api-users
    3. k8s-api-scan
    4. k8s-api-character
    5. k8s-api-location
    6. k8s-api-image
    7. k8s-api-chat
    8. k8s-api-info
  3. 4Execution worker

    兩個排程池,各有兩個節點。KEDA 調整 Pod 數量;節點數量維持不變。

    儲存池domain: worker-storage
    1. k8s-worker-storage
    2. k8s-worker-storage-2
    AI 池domain: worker-ai
    1. k8s-worker-ai
    2. k8s-worker-ai-2
  4. 5Data

    Redis 依用途分為四個節點。PostgreSQL 的儲存使用 EBS CSI · gp3。

    1. k8s-postgresql
    2. k8s-redis-auth
    3. k8s-redis-streams
    4. k8s-redis-cache
    5. k8s-redis-pubsub
  5. 6Platform

    訊息傳遞、可觀測性、入口與即時傳遞,各自擁有節點。

    1. k8s-rabbitmq
    2. k8s-monitoring
    3. k8s-logging
    4. k8s-ingress-gateway
    5. k8s-sse-gateway
    6. k8s-event-router
每個節點
  • Fluent Bit · DaemonSet
  • Calico

設定的模型 · 依供應商

服務已終止,因此這些是儲存庫中設定的模型,而非現今可選的模型。每個角色分別列出;這不是經驗證執行的清單。

  • OpenAI

    Chat 預設供應商

    Chat

    • openai/gpt-5.2預設

    預設模型為 gpt-5.2;請求中指定模型時,改用該模型。

    Scan

    • gpt-5.2預設
    • gpt-5.2-pro
    • gpt-5.1
    • gpt-5
    • gpt-5-pro
    • gpt-5-mini

    不在 13 個模型對應表中的模型會被拒絕。

    圖片對應

    • gpt-image-1.5

    與 Responses 協調模型 gpt-5.2 分開。影像生成預設為關閉。

    評測

    • gpt-4o-mini預設

    對話評測的 LLM grader,與 Chat 模型分開。

  • Google

    Chat 選擇 Google 時

    Chat

    • google/gemini-3-pro-preview
    • google/gemini-3-flash-preview

    選擇 Google 時,預設為 gemini-3-flash-preview。

    Scan

    • gemini-3-pro-preview
    • gemini-3-flash-preview
    • gemini-2.5-pro
    • gemini-2.5-flash
    • gemini-2.5-flash-lite
    • gemini-2.0-flash
    • gemini-2.0-flash-lite

    圖片對應

    • gemini-3-pro-image-preview