跳到正文

在 GCP 上使用多智能体集群构建对话式商务:一个可运行的原型

在本分步指南中,了解如何使用 AI 构建对话式用户界面 (CUI)。

本文目录文章开头

2026年10月27日

引言:从蓝图到可运行的原型

想象一下,订购每周的杂货就像给朋友发短信一样自然:“嘿,牛奶和鸡蛋都用完了。能再加点周五电影之夜的零食吗?”

在上一篇文章《在 GCP 上使用多智能体集群构建对话式商务》中,我们分享了对话式商务的架构蓝图——提出了一种三层解耦设计(入口层、记忆层和认知层),以解决消息超时、状态跟踪和响应可靠性问题。

虽然蓝图在纸面上确立了架构,但要达到生产就绪则需要可运行的软件。在本文中,我们将把该蓝图变为现实,打造一个名为 HappyDelivery 的功能原型。

我们将使用 LangGraph、Gemini、FastAPI 和 Google Cloud,逐步讲解代码、状态机、确定性金融工具以及自动化验证套件,展示这个多智能体集群在实践中是如何运作的。

1. 原型技术栈:3 层,3 张图

为了构建可靠的商务集群,我们实现了三个解耦层,用于处理每条客户短信的旅程:

image2

让我们看看每一层在代码中是如何运作的,并配有各自专属的架构图。


第 1 层:入口层(GKE/Cloud Run 上的全渠道 Webhook 网关 + Cloud Pub/Sub)

在设计对话式商务时,一个常见的问题是:客户在智能手机上发送的消息究竟是如何到达第 1 层的?这种架构能否支持 WhatsApp 之外的消息平台?

客户端设备如何连接到第 1 层

最终用户并不直接与您的 Google Cloud 服务器通信。相反,客户消息会经过一个运营商生态系统,然后才到达您的 webhook:

image4

支持多种消息渠道:WhatsApp、RCS、Apple Messages 和 SMS

每个主要的消费级消息平台都遵循完全相同的基本契约:带有严格 HTTP 确认超时的异步 HTTPS POST webhook 投递:

  • WhatsApp(Meta Cloud API):需要及时的 HTTP 200 OK 确认,并使用 HMAC-SHA256 根据您的 Meta App Secret 验证 X-Hub-Signature-256 标头。如果您的服务器超时或返回非 200 状态,Meta 会将投递标记为失败,并启动指数退避重试(最长可达 7 天),这可能会触发重复订单投递。
  • Google RCS Business Messaging (RBM):通过 Google Cloud Pub/Sub 推送或 HTTPS webhook 投递,使用 OAuth2 / Service Account JWT bearer 令牌或载荷 HMAC 签名验证(X-Goog-Signature)进行身份验证。需要及时返回 HTTP 200 以避免 webhook 投递重试。
  • Apple Messages for Business (AMB):通过 Apple 批准的消息服务提供商 (MSP) 投递。通过提供商 webhook 签名、JSON Web 签名 (JWS) 或双向 TLS (mTLS) 进行身份验证,并期望及时的 HTTP 200 OK 确认。
  • SMS / MMS(Twilio、Sinch、Infobip):标准的表单编码或 JSON POST webhook,使用特定供应商的 HMAC 令牌签名(例如 X-Twilio-Signature)。

虽然各平台之间的载荷模式和加密标头略有不同,但第 1 层抽象掉了所有客户端差异:

  1. 安全与签名验证器:通过平台特定的签名验证器路由传入请求(MetaHmacValidator、RcsJwtValidator、AppleJwsValidator、TwilioHmacValidator)。
  2. 负载规范化适配器:接收厂商特定的负载,并将其转换为统一的、与渠道无关的规范模式(CommonMessageEvent):
{
       "channel": "whatsapp",  # or "rcs", "apple_messages", "sms"
       "sender_id": "+1xxxxxxxxxx",  # Verified E.164 phone number
       "text": "Out of milk & eggs",
       "timestamp": 1773428900,
       "raw_metadata": {...}
   }
  1. 低于 150 毫秒的异步握手:将规范消息排入 Google Cloud Pub/Sub 队列,并在 < 150ms. 内返回 HTTP 200 OK

这确保了系统的其余部分——会话存储(第 2 层)和智能体集群(第 3 层)——在干净、规范化的数据上运行,而无需关心购物者是从 iPhone、Android RCS 聊天还是 WhatsApp 会话发送的消息。


第 2 层:会话与购物车层(Cloud Memorystore Redis)

消息平台是完全无状态的:每条短信都作为孤立的 webhook 事件到达。为了提供连贯的购物体验,系统必须即时重建客户的完整上下文,而无需在每一轮对话中重新读取或重新解析数天的聊天记录。

我们使用以客户已验证电话号码为键的 Cloud Memorystore (Redis)(session:{phone_number})来存储活跃状态:

image (12)

由该层驱动的真实客户旅程(CUJ)

  1. 异步购物之旅(暂停与恢复):在现实生活中,人们不会一次性完成订单。客户可能在上午 9:00 发消息:"往我的购物车里加一加仑牛奶",关闭 WhatsApp 去赶火车,然后在下午 2:00 回复:"再加面包和鸡蛋,我的总计是多少?"由于会话状态缓存在 Redis 中,系统会立即恢复其活跃购物车([牛奶])并重新计算总额,毫无延迟。
  2. 上下文护栏(饮食偏好与地址):如果用户的个人资料指定了 dietary_preferences: ["Nut-Free"],库存智能体在推荐电影之夜零食时会自动尊重该偏好——用户无需在每条短信中重新声明其过敏情况。
  3. 安全的令牌化结账:客户资料保存令牌化的支付引用(customer_id: "cust_9821", payment_ref: "Visa ending in 4242")。LLM 只读取友好的掩码标签,而交易工具将令牌化的客户 ID 传递给 Stripe。原始信用卡号码绝不会出现在聊天提示或日志中。

💡 规模与性能:基础基础设施能处理多少 QPS?

在对话式商务中,一个常见问题是状态查找是否会引入延迟。以下是基础基础设施的支持能力:

  • 原始吞吐量:单个基础版 Google Cloud Memorystore for Redis 实例(Basic Tier,1–5 GB 内存)可轻松提供 10,000 到 50,000+ QPS,读写延迟低于 1 毫秒(< 1ms)。
  • 对话式 QPS:每个聊天轮次需要 2–3 次 Redis 操作(会话获取、购物车变更、状态提交)。这意味着单个标准 Redis 实例可轻松处理 每秒 3,000 到 15,000 个活跃对话轮次,之后才需要 Redis Cluster 水平分片或读取副本。
  • 内存容量:一个活跃会话负载(个人资料 + 活跃购物车 + 偏好)约占 2 KB 到 5 KB 的序列化 JSON。一个适度的 5 GB Redis 实例可在内存中同时容纳 超过 1,000,000 个并发活跃购物车。

关键要点:在实践中,会话与购物车层 永远不会成为瓶颈——它轻松超越上游 webhook 推理和下游 LLM 推理的速度。


第 3 层:智能体集群层(基于 Gemini 的多智能体编排)

与其依赖单一的庞大提示词来处理所有任务,我们将推理过程拆分为一群专门化的智能体:

image (13)

  • 监督者(Gemini Flash):充当低延迟路由器,对客户请求进行分类,并将其委派给合适的专家。
  • 个人资料专家:检索个人偏好,并为新买家签发安全的一次性授权链接。
  • 库存专家(Gemini Pro):绑定仓库工具;查询库存、推荐搭配商品并修改购物车。
  • 交易专家(Gemini Pro):绑定支付工具;确定性地计算总额并发起扣款。

2. 从架构到代码:构建三层结构

在了解了三层结构的高层设计之后,我们来看看让每一层得以实现的实际 Python 原型代码。


第 1 层原型:全渠道 FastAPI 入口与安全规范化

该服务的目标很简单:在任何入站渠道上验证真实性,将负载规范化为标准模式,并在 150 毫秒内退出关键路径。

以下是我们的实现,展示了可插拔适配器如何处理多种消息渠道(WhatsApp、RCS、Apple Messages、SMS):

import hashlib, hmac, json, time
from typing import Any, Dict, Optional
from pydantic import BaseModel




class CommonMessageEvent(BaseModel):
  """Channel-agnostic canonical representation of an inbound customer message."""
  channel: str  # "whatsapp", "rcs", "apple_messages", "sms"
  sender_id: str  # E.164 phone number: "+1xxxxxxxxxx"
  text: str
  timestamp: float
  raw_metadata: Dict[str, Any]




class HappyDeliveryIngressService:
  """Omni-Channel FastAPI Ingress with cryptographic verification and async queueing."""


  def __init__(self, meta_secret: str, rcs_secret: str = ""):
    self.meta_secret = meta_secret
    self.rcs_secret = rcs_secret
    self.publisher = CloudPubSubPublisher()


  def verify_whatsapp_signature(self, payload_bytes: bytes, sig_header: str) -> bool:
    """Verifies X-Hub-Signature-256 header using constant-time comparison."""
    if not sig_header or not sig_header.startswith("sha256="):
      return False
    expected_hash = hmac.new(
        self.meta_secret.encode("utf-8"), payload_bytes, hashlib.sha256
    ).hexdigest()
    provided_hash = sig_header.split("sha256=")[1]
    return hmac.compare_digest(expected_hash, provided_hash)


  def normalize_payload(self, channel: str, raw_payload: Dict[str, Any]) -> Optional[CommonMessageEvent]:
    """Extracts sender and message text into a canonical schema."""
    if channel == "whatsapp":
      # Meta Graph Webhook structure
      entry = raw_payload.get("entry", [{}])[0]
      change = entry.get("changes", [{}])[0].get("value", {})
      message = change.get("messages", [{}])[0]
      return CommonMessageEvent(
          channel="whatsapp",
          sender_id=message.get("from", ""),
          text=message.get("text", {}).get("body", ""),
          timestamp=float(message.get("timestamp", time.time())),
          raw_metadata={"message_id": message.get("id")},
      )
    elif channel == "rcs":
      # Google RCS Business Messaging structure
      return CommonMessageEvent(
          channel="rcs",
          sender_id=raw_payload.get("senderPhoneNumber", ""),
          text=raw_payload.get("text", ""),
          timestamp=time.time(),
          raw_metadata={"rcs_message_id": raw_payload.get("messageId")},
      )
    return None


  def handle_incoming_webhook(
      self, channel: str, payload: Dict[str, Any], signature: str
  ) -> Dict[str, Any]:
    """Validates signature, normalizes schema, and offloads to Pub/Sub in < 150ms."""
    payload_bytes = json.dumps(payload, sort_keys=True).encode("utf-8")
    
    # 1. Platform-specific security validation
    if channel == "whatsapp" and not self.verify_whatsapp_signature(payload_bytes, signature):
      return {"status": "error", "message": "Invalid HMAC signature", "http_code": 403}


    # 2. Normalize to canonical schema
    event = self.normalize_payload(channel, payload)
    if not event or not event.sender_id:
      return {"status": "error", "message": "Unrecognized payload format", "http_code": 400}


    # 3. Offload canonical event onto Cloud Pub/Sub queue (< 150ms)
    msg_id = self.publisher.publish(topic="inbound-messages", data=event.model_dump())
    return {"status": "accepted", "message_id": msg_id, "http_code": 200}

通过立即返回 HTTP 200 OK 并将负载交给 Pub/Sub,我们完全将消息接收与下游 AI 推理时间解耦,适用于所有消息生态系统。

部署与运行第 1 层

  1. 部署入口服务(Cloud Run 或 GKE):
# Provision Cloud Pub/Sub queue
   gcloud pubsub topics create inbound-messages


   # Deploy the Ingress container to Cloud Run
   gcloud run deploy happydelivery-ingress \
     --image=gcr.io/my-gcp-project/ingress:latest \
     --set-env-vars=APP_SECRET="happy_secret_meta_key_2026" \
     --allow-unauthenticated \
     --port=8080
  1. 实时运行时验证(部署在 GCP xxxxxx上):我们将入口容器直接部署到 Cloud Run,并验证了实时 HTTP 端点:
    • 服务名称:happydelivery-ingress
    • 实时服务 URL:https://happydelivery-ingress-xxxxxx.us-central1.run.app
    • 已关联的 Pub/Sub 主题:projects/xxxxxx/topics/inbound-messages
    • 已关联的订阅:projects/xxxxxx/subscriptions/inbound-messages-sub

我们在多次热调用中对实时 Cloud Run HTTPS webhook 接收进行了基准测试:

# Benchmark: 5 consecutive live HTTPS webhook posts to Cloud Run endpoint
   Run 1: Status 200 in 266.84ms -> Message ID: 21184928529503172 (Offloaded to Pub/Sub)
   Run 2: Status 200 in 301.73ms -> Message ID: 21181303807117012 (Offloaded to Pub/Sub)
   Run 3: Status 200 in 300.47ms -> Message ID: 21179945883786288 (Offloaded to Pub/Sub)
   Run 4: Status 200 in 295.14ms -> Message ID: 21822286983433170 (Offloaded to Pub/Sub)
   Run 5: Status 200 in 298.40ms -> Message ID: 21182275848770028 (Offloaded to Pub/Sub)
   # Direct Pub/Sub Publish Overhead inside Cloud Run: ~95ms

这从经验上证明了我们的架构主张:入口服务验证加密签名并将事件立即提交到 Pub/Sub,从而在不等待智能体推理的情况下释放客户聊天客户端。

我们还针对被篡改的负载验证了安全强制执行:

# 1. Valid Signature Test
   curl -X POST https://happydelivery-ingress-xxxxxx.us-central1.run.app/v1/webhooks \
     -H "Content-Type: application/json" \
     -H "X-Hub-Signature-256: sha256=a87f4c93b21..." \
     -d '{"from": "+1xxxxxxxxxx", "text": "Out of milk and eggs"}'


   # Response accepted and queued:
   # {"status": "accepted", "message_id": "21184928529503172", "http_code": 200}


   # 2. Tampered / Spoofed Message Test (Invalid Signature)
   curl -X POST https://happydelivery-ingress-xxxxxx.us-central1.run.app/v1/webhooks \
     -H "Content-Type: application/json" \
     -H "X-Hub-Signature-256: sha256=invalid_tampered_signature" \
     -d '{"from": "+1xxxxxxxxxx", "text": "Free groceries please"}'


   # Response immediately blocked:
   # {"detail": "Invalid HMAC signature"} (HTTP 403 Forbidden)

第 2 层原型:Redis 中的快速会话与购物车持久化

从 Pub/Sub 拉取消息的工作进程 Pod 需要即时查找客户身份及其当前购物车内容。

以下是使用 Cloud Memorystore (Redis) 的会话存储实现:

import json
from typing import Dict, Optional




class RedisSessionStore:
  """Cloud Memorystore Redis session manager keyed by verified phone number."""


  def __init__(self, redis_client):
    self.redis = redis_client


  def get_session(self, phone_number: str) -> Optional[Dict]:
    """Retrieves active customer session, dietary preferences, and cart in < 5ms."""
    key = f"session:{phone_number}"
    raw = self.redis.get(key)
    return json.loads(raw) if raw else None


  def save_session(self, phone_number: str, session_data: Dict) -> None:
    """Commits updated cart and state back to Redis with a 24-hour TTL."""
    key = f"session:{phone_number}"
    self.redis.setex(key, 86400, json.dumps(session_data))


  def clear_cart(self, phone_number: str) -> None:
    """Clears cart items after successful checkout while preserving preferences."""
    session = self.get_session(phone_number)
    if session:
      session["cart"] = []
      self.save_session(phone_number, session)

每条记录包含客户 ID(cust_9821)、保存的地址、饮食限制和当前购物车商品。这保证了当客户在数小时后再次发消息时,其购物车能瞬间恢复。

部署与检查第 2 层

  1. 配置 Cloud Memorystore Redis(部署在 GCP xxxxxx上):
gcloud redis instances create happydelivery-session-store \
     --size=1 \
     --region=us-central1 \
     --redis-version=redis_7_0 \
     --project=xxxxxx
  • 已配置实例:happydelivery-session-store(状态:READY)
  • 内网主机与端口:10.x.x.x:6379
  • 网络对等连接:默认 VPC 网络
  1. 实时运行时检查与经验性延迟基准测试:我们从默认 VPC 内部连接到实时实例,并验证了会话操作:
# 1. Commit active session with 24-hour TTL (86400s)
   10.x.x.x:6379> SETEX "session:+1xxxxxxxxxx" 86400 '{"customer_id":"cust_9821","cart":[...]}'
   +OK


   # 2. Benchmark 5 consecutive session retrievals over VPC peering
   Run 1: 0.299ms
   Run 2: 0.276ms
   Run 3: 0.305ms
   Run 4: 0.210ms
   Run 5: 0.503ms
   # Average Session Retrieval Latency: 0.318ms


   # 3. Query active session payload and verify TTL
   10.x.x.x:6379> GET "session:+1xxxxxxxxxx"
   {
     "customer_id": "cust_9821",
     "dietary_preferences": ["nut-free", "gluten-free"],
     "cart": [
       {"item_id": "prod_milk", "name": "Whole Milk (1 gal)", "qty": 1, "price": 4.29},
       {"item_id": "prod_eggs", "name": "Free-Range Eggs (1 doz)", "qty": 1, "price": 3.99}
     ],
     "delivery_address": "xxx xxxxx St",
     "payment_method": "Visa ending in 4242"
   }


   10.x.x.x:6379> TTL "session:+1xxxxxxxxxx"
   (integer) 86400

每次会话查找均在 0.318 毫秒内执行完毕,这证明了我们的架构主张:恢复客户上下文和持久化购物车状态几乎不会为对话轮次增加任何延迟。


第 3 层原型:LangGraph 多智能体集群

入口层和 Redis 负责处理入站流量和记忆,所有决策都由 LangGraph 多智能体图完成。

第 1 步:共享智能体状态

每一轮都会经过一个类型化的数据结构,其中包含客户资料、活跃购物车以及主管的路由决策:

from typing import Annotated, Literal
from typing_extensions import TypedDict
from langgraph.graph.message import add_messages




class CartItem(TypedDict):
  item_id: str
  name: str
  qty: int
  price: float




class AgentState(TypedDict):
  phone_number: str
  customer_id: str
  dietary_preferences: list[str]
  cart: list[CartItem]
  cart_total: float
  messages: Annotated[list[dict], add_messages]
  next_step: Literal["profile", "inventory", "transaction", "END"]

第 2 步:编译群体图

接下来,我们定义节点和条件边,使主管能够动态地将任务路由到正确的专家:

from langgraph.graph import END, START, StateGraph




def build_happydelivery_swarm():
  builder = StateGraph(AgentState)


  # 1. Register specialized agent nodes
  builder.add_node("supervisor", supervisor_node)
  builder.add_node("profile", profile_node)
  builder.add_node("inventory", inventory_node)
  builder.add_node("transaction", transaction_node)


  # 2. Ingress always enters via the Supervisor
  builder.add_edge(START, "supervisor")


  # 3. Dynamic hand-offs based on intent
  builder.add_conditional_edges(
      "supervisor",
      lambda state: state.get("next_step", END),
      {
          "profile": "profile",
          "inventory": "inventory",
          "transaction": "transaction",
          "END": END,
      },
  )


  # 4. Return edges
  builder.add_edge("profile", "supervisor")
  builder.add_edge("inventory", END)
  builder.add_edge("transaction", END)


  return builder.compile()

第 3 步:为智能体配备确定性工具

我们蓝图的一个核心原则是:将算术运算委托给确定性工具。生成式模型擅长语言和推理,而财务计算则需要精确无误。如果模型以自由文本形式计算税费或折扣,可能会偶尔引入计算错误。

相反,我们将确定性工具绑定到专家节点。例如,Inventory 和 Transaction 智能体使用 Python 计算工具,而不是在提示词中计算价格:

@tool
def calculate_cart_totals(cart_items: list[dict]) -> dict:
  """Calculates deterministic subtotal, tax, delivery fees, and grand total."""
  subtotal = sum(
      item.get("price", 0.0) * item.get("qty", 1) for item in cart_items
  )
  tax = round(subtotal * 0.0825, 2)  # 8.25% Sales tax
  delivery_fee = 0.00 if subtotal > 15.00 else 3.99
  total = round(subtotal + tax + delivery_fee, 2)
  return {
      "subtotal": round(subtotal, 2),
      "tax": tax,
      "delivery_fee": delivery_fee,
      "total": total,
  }

第 4 步:运行并观察第 3 层执行

工作器容器从 Pub/Sub 异步拉取消息,并实时流式传输 LangGraph 节点转换。

  1. 部署群体工作器(Cloud Run Job 或 GKE):
# Deploy as a scalable Cloud Run Job
   gcloud run jobs deploy happydelivery-swarm-worker \
     --source=./worker \
     --region=us-central1 \
     --project=xxxxxx \
     --set-env-vars=PROJECT_ID="xxxxxx",SUBSCRIPTION_ID="inbound-messages-sub"
  1. 实时运行时执行跟踪(GCP 执行输出):当工作器拉取 Ingress 服务发布的入站消息时,我们观察到主管清晰地将任务路由到正确的专家:
[Worker] Pulled message ID: 21182261471226730
   [Worker] Sender: +1xxxxxxxxxx, Text: 'Hey, we are out of milk and eggs. Also, add some snacks for Friday movie night.'
   [LangGraph] State loaded: phone=+1xxxxxxxxxx
   [LangGraph] Entering Node 'supervisor' -> Gemini Flash (Latency: 240ms)
   [LangGraph] Routing decision -> Intent: replenishment, Next Node: 'inventory'
   [LangGraph] Entering Node 'inventory' -> Gemini Pro
     ├── Tool call: search_catalog('milk') -> Whole Milk ($4.29)
     ├── Tool call: search_catalog('eggs') -> Free-Range Eggs ($3.99)
     ├── Tool call: calculate_cart_totals(items) -> Subtotal: $8.28, Tax: $0.68, Total: $12.95
     └── State Updated: cart=[Whole Milk, Free-Range Eggs], next_step='END'
   [LangGraph] Execution Complete -> Outbound response dispatched.
   [Worker] Successfully processed and acked in 0.03ms

3. 将所有组件连接起来:端到端管道

现在我们已经拥有了所有三个组件——Ingress(第 1 层)、Redis 记忆(第 2 层)和 LangGraph 群体(第 3 层)——它们实际上是如何作为一个统一系统协同运行的呢?

以下是客户消息的完整端到端生命周期:

image1

代码中的工作器管道

协调所有三个层的工作器循环简洁、清晰,并将面向用户的 webhook 与后台 AI 推理完全解耦:

def process_pubsub_worker_turn(phone_number: str, user_text: str) -> str:
  """Coordinates Layer 1, Layer 2, and Layer 3 for each conversational turn."""
  # 1. Layer 2: Hydrate session and cart from Redis
  session = session_store.get_session(phone_number) or {}
  initial_cart = session.get("cart", [])


  # 2. Layer 3: Build the graph state
  state = {
      "messages": [HumanMessage(content=user_text)],
      "phone_number": phone_number,
      "customer_id": session.get("customer_id", ""),
      "cart": initial_cart,
      "dietary_preferences": session.get("dietary_preferences", []),
      "delivery_address": session.get(
          "delivery_address", "xxx xxxxx St"
      ),
      "payment_method": session.get(
          "payment_method", "Visa ending in 4242"
      ),
      "next_step": "",
  }


  # 3. Layer 3: Run the multi-agent swarm
  final_state = swarm.invoke(state)


  # 4. Layer 2: Commit updated cart back to Redis
  session["cart"] = final_state.get("cart", [])
  session_store.save_session(phone_number, session)


  # 5. Return outbound message back to WhatsApp messaging API
  return final_state["messages"][-1].content

整个管道连接好之后,让我们看看当实际客户订单通过它运行时会发生什么。


为了验证原型,我们运行了一次端到端客户订单的自动化模拟。以下是群体在三个自然对话轮次中的行为:

第 1 轮:对话式补货与发现

👤 客户:
“嘿,我们的牛奶和鸡蛋用完了。另外,为周五的电影之夜加些零食。”
🤖 HAPPYDELIVERY 智能体:
“好的!我已添加 1 加仑全脂牛奶($4.29)和 1 打散养鸡蛋($3.99)。
根据您过去的电影之夜,我应该添加多力多滋($4.50)和 6 罐装雪碧($5.99)吗?”
  • 幕后:主管识别出补货请求 → 移交给 ProfileAgent(加载偏好)→ InventoryAgent 查询目录库存并将请求与相关零食配对。

第 2 轮:实时购物车变更与精确定价

👤 客户:
“把雪碧换成零度可乐。就这样。”
🤖 HAPPYDELIVERY 智能体:
“完成!换成零度可乐($5.99)后,您的小计为 $18.77
(加 $1.55 税费),总计 $20.32。
我将向您尾号 4242 的 Visa 卡收费,并于
周四下午 5-7 点之间配送到 xxx xxxxx 街。可以吗?”

幕后:InventoryAgent 变更内存中的购物车(移除雪碧并添加零度可乐),执行 calculate_cart_totals,并在不丢失上下文的情况下确认配送详情。


第 3 轮:结账与令牌化扣款执行

👤 客户:
“是的,太好了!”
🤖 HAPPYDELIVERY 智能体:
“订单已确认!🧾 订单 #HD-9821 已下达。司机出发时我会给您发短信。”

  • 幕后流程:Supervisor 检测到用户确认结账 → 路由至 TransactionAgent → 调用 execute_stripe_charge(customer_id='cust_9821', amount_cents=2032)。成功后 Redis 购物车被清空。

验证:自动化测试套件

我们使用自动化单元测试和集成测试验证了所有核心行为——Webhook HMAC 验证、商品目录索引、确定性计算以及多轮状态转换:

[ RUN      ] HappyDeliverySwarmTest.test_catalog_search                [ OK ]
[ RUN      ] HappyDeliverySwarmTest.test_deterministic_pricing        [ OK ]
[ RUN      ] HappyDeliverySwarmTest.test_full_three_turn_shopping_flow [ OK ]
[ RUN      ] HappyDeliverySwarmTest.test_hmac_webhook_signature_verification [ OK ]
[ RUN      ] HappyDeliverySwarmTest.test_stripe_charge_execution      [ OK ]
----------------------------------------------------------------------
Ran 5 tests in 0.158s - OK (0 arithmetic errors, 100% test pass rate)

在评估多智能体架构时,一个关键问题是 token 消耗和运营推理成本。在朴素实现中,如果每一步都重复发送庞大的提示词和完整的对话历史,LLM API 账单会迅速侵蚀电商零售利润。

我们的原型专门针对防止 token 浪费而设计,采用 严格的智能体专业化分工、确定性工具以及外部化的 Redis 状态:

  1. 状态卸载至 Redis:我们不在 LLM 上下文中维护无休止的原始聊天记录。只传递当前用户意图和活跃购物车摘要,即使购物车增长,输入 token 也保持平稳。
  2. 确定性代码承担繁重工作:数学运算(税费、运费、折扣)、商品目录关键词匹配和 Stripe 扣款均在 Python 函数中执行(0 个 LLM token)。
  3. 模型分层(Flash 与 Pro):高频路由运行在轻量、极速的 Gemini Flash 上,将 Gemini Pro 更深层的推理能力严格保留给复杂的库存推荐和支付确认。

实测 Token 与成本明细(3 轮购物流程)

以下是在线 3 轮 HappyDelivery 会话中测得的精确 token 遥测数据:

image (14)

定价示例按标准 Gemini API 费率计算:Gemini Flash 输入 $0.15 / 1M tokens,输出 $0.60 / 1M tokens;Gemini Pro 输入 $1.25 / 1M tokens,输出 $10.00 / 1M tokens。

对电商利润的关键启示

  • 每单成本低于一美分:整个 3 轮多智能体购物流程共消耗 约 4,240 个 token,成本仅为 $0.0061(远低于一美分)。
  • 占订单金额比例可忽略不计:在一笔 $20.32 的杂货订单中,$0.0061 仅占商品交易总额(GMV)的 0.030%——与标准支付手续费(2.9% + $0.30)相比几乎可以忽略不计。
  • 上下文缓存机会:对于拥有大型静态商品目录架构或固定智能体指令的企业级生产部署,启用 Google Cloud 的 Gemini Context Caching 可将重复输入 token 成本再降低 75%,使每单成本降至约 $0.0033。

5. 构建原型的实践经验

将蓝图转化为可运行代码的过程中,我们发现了几个现实问题:

  1. 克服“群集税”(延迟):跨多次 LLM 调用的多智能体推理可能耗时 2–4 秒。为防止客户觉得聊天已卡死,工作进程会在流式传输最终结果之前,通过消息 API 立即发送进度通知(“正在为您查看新鲜货架……🛒”)。
  2. 将数学运算保留在确定性工具中:即使是能力很强的模型,在边缘情况下也可能偶尔算错。将定价逻辑放在确定性函数中可保证 100% 的财务准确性。
  3. 专业化分工优于单体架构:为各个智能体(Profile、Inventory、Transaction)提供简短、专注的系统指令,其行为可靠性远高于将所有职责塞进一个庞大的提示词中。

6. 结论与下一步

构建这个原型证明了我们蓝图中概述的解耦架构不仅仅是理论上的——它是实用的、可靠的,并且已经准备好在 Google Cloud 上投入生产。

通过结合 LangGraph 实现多智能体工作流、Gemini 实现自然语言推理,以及 GCP 实现快速接入和持久化记忆,我们可以构建出像与朋友聊天一样简单的购物体验,同时保持电子商务所需的企业级严谨性。

阅读显示设置

调整正文排版

当前浏览器记住选择,应用于文章正文。手机上正文宽度以屏幕可用空间为限。

图表完整性提示

普通文章遇到图表保存问题时显示提示。