Eco² 地球角色,依据最新的官方主角色为本作品集修整:天蓝色的地球、绿色陆地、头顶一株新芽,以及棕色的笑脸
返回展厅

Eco²

Backend · Cloud infrastructure

一张照片、一段对话,得到分类回收指引。

一款理解韩国分类回收规则的一体化 AI 助手。

2025.10.31 — 2026.02.10

团队项目 · 基础设施与部署基础 → 领域后端 → 异步处理、对话智能体、验证

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

  • Web 应用已停止运营

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 revisionLLM 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-aistorage 池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 revision2Ingress → ALB · DNS 记录3xDS 配置4Pod 数量5 Pod 数量 · KEDA → storage 池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 instance target 的 NodePort 交给 Istio ingress Envoy。

  4. Istio ingress Envoyk8s-ingress-gateway数据流: VirtualServiceScan APIk8s-api-scan

    路由到 Scan API,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 以消费者组读取,处理后 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 instance target 的 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 以消费者组读取,处理后 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 以消费者组读取 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 instance target 的 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 黑名单检查 token。

  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 同步调用。

storage 池 · 异步存储

认证黑名单与角色归属由 storage 池的 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 revisionArgo 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 数量storage 池k8s-worker-storage · k8s-worker-storage-2

    storage 池的 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 个节点
  • storage 池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 数量;节点数量保持不变。

    storage 池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 评分器,与 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