一个购物助手能说出流畅的话,并不等于它能把商品选对、库存查准、购物车改对。DoorDash 介绍的 Ask DoorDash 把大模型放在系统的一部分,而不是让它独自承担整个购物流程:LLM 负责理解与表达,专用 AI Agent 负责拆解任务,MCP 工具连接业务能力,智能层则结合持久化消费者记忆和实时后端数据作出决策。
这种设计带来的价值最终落在业务指标上。早期结果显示,结账转化率最高提升 24%,购物篮金额提升 17%;带记忆的会话也改善了意图识别准确性。不过,这些数字更适合被视为特定产品阶段的实验结果,而不是所有电商助手都能直接复制的收益。
把 LLM 从“业务系统”降级为“推理组件”
如果让 LLM 直接根据提示词回答“帮我买一份低糖早餐”,它可能生成合理建议,但无法天然回答几个关键问题:
- 用户所在区域现在有哪些门店营业?
- 推荐商品是否仍有库存,价格是否已经变化?
- “低糖”是本次要求,还是用户长期偏好?
- 替换商品能否满足过敏原、预算和配送时间约束?
- 修改购物车后,后端是否真的接受了操作?
Ask DoorDash 的架构思路,是把这些问题分给不同层次处理。可以将其抽象成四部分:
- 对话与推理层:LLM 理解自然语言,提取目标、约束和缺失信息,并组织最终回复。
- 专用 Agent 层:搜索、推荐、购物车操作等 Agent 各自处理边界明确的任务。
- MCP 工具层:通过标准化工具接口访问商品目录、库存、价格、门店和购物车服务。
- 智能与记忆层:保存稳定偏好和历史上下文,同时读取实时后端状态,帮助系统判断当前意图。
这里最重要的工程变化是:LLM 的输出不再直接等于业务事实。价格、库存、配送范围和购物车状态必须由后端工具返回;模型只能决定调用什么工具、如何使用结果,以及是否需要继续询问用户。
记忆和实时数据解决的是两类不同问题
持久记忆适合保存跨会话仍然有价值的信息,例如用户经常选择无乳糖牛奶、对花生过敏,或通常将晚餐预算控制在某个范围。实时数据则回答此刻才成立的问题,例如某个商品是否售罄、门店是否营业以及当前配送费是多少。
两者不能混为一谈。把库存结果写成长期记忆,会让过期状态污染后续推荐;把过敏信息只留在当前会话,又会让下一次购物失去关键约束。
一个实用的分类方式如下:
| 数据 | 建议存储位置 | 典型有效期 |
|---|---|---|
| 过敏原、饮食限制 | 持久记忆 | 长期,但允许用户修改 |
| 品牌偏好 | 持久记忆 | 中长期,可逐步衰减 |
| 本次预算和用餐人数 | 会话状态 | 当前任务 |
| 商品价格与库存 | 实时后端 | 秒到分钟 |
| 购物车内容 | 交易后端 | 以服务端状态为准 |
记忆也不应等同于完整聊天记录。更稳妥的做法是保存结构化事实,并记录来源、更新时间和置信度。涉及健康、宗教或其他敏感偏好时,还需要明确的授权、删除入口和数据保留策略。
可以这样实践:实现一个不让模型虚构库存的最小编排器
下面的示例不是 DoorDash 的实际实现,而是根据上述架构做的最小可运行版本。它使用 SQLite 保存消费者偏好,用函数注册表模拟 MCP 风格的工具边界,并始终从实时目录读取价格和库存。
将代码保存为 shopping_assistant.py,使用 Python 3.10 或更高版本运行:
import json
import sqlite3
from dataclasses import dataclass
from typing import Any, Callable
CATALOG = [
{"id": "oat-1", "name": "无糖燕麦奶", "price": 18.0, "stock": 8, "tags": ["低糖", "无乳糖"]},
{"id": "yogurt-1", "name": "原味酸奶", "price": 12.0, "stock": 0, "tags": ["低糖"]},
{"id": "bread-1", "name": "全麦面包", "price": 15.0, "stock": 5, "tags": ["低糖"]},
]
@dataclass
class Tool:
name: str
handler: Callable[..., Any]
class MemoryStore:
def __init__(self, path: str = "assistant.db") -> None:
self.db = sqlite3.connect(path)
self.db.execute(
"CREATE TABLE IF NOT EXISTS memory "
"(user_id TEXT, key TEXT, value TEXT, PRIMARY KEY(user_id, key))"
)
def put(self, user_id: str, key: str, value: str) -> None:
self.db.execute(
"INSERT OR REPLACE INTO memory(user_id, key, value) VALUES (?, ?, ?)",
(user_id, key, value),
)
self.db.commit()
def get_all(self, user_id: str) -> dict[str, str]:
rows = self.db.execute(
"SELECT key, value FROM memory WHERE user_id = ?", (user_id,)
).fetchall()
return dict(rows)
def search_catalog(required_tag: str, max_price: float) -> list[dict[str, Any]]:
return [
item for item in CATALOG
if item["stock"] > 0
and item["price"] <= max_price
and required_tag in item["tags"]
]
def build_tools() -> dict[str, Tool]:
return {
"search_catalog": Tool("search_catalog", search_catalog),
}
def handle_request(user_id: str, request: str, memory: MemoryStore) -> dict[str, Any]:
# 实际系统可让 LLM 提取这些参数,但后端仍需校验其类型和范围。
preferences = memory.get_all(user_id)
required_tag = "低糖" if "低糖" in request else preferences.get("diet", "")
max_price = float(preferences.get("item_budget", "20"))
tools = build_tools()
matches = tools["search_catalog"].handler(required_tag, max_price)
return {
"interpreted_intent": {"tag": required_tag, "max_price": max_price},
"recommendations": matches,
"message": "找到可购买商品" if matches else "没有满足条件且有库存的商品",
}
if __name__ == "__main__":
store = MemoryStore()
store.put("user-42", "diet", "低糖")
store.put("user-42", "item_budget", "20")
result = handle_request("user-42", "帮我准备早餐", store)
print(json.dumps(result, ensure_ascii=False, indent=2))
运行命令:
python shopping_assistant.py
这个例子刻意保留了三条边界:偏好来自持久记忆,库存和价格来自目录工具,最终推荐只能包含工具实际返回的商品。接入真实 LLM 时,可以让模型输出结构化工具调用参数,但需要在服务端增加 JSON Schema 校验、超时、重试、权限控制和幂等键。
如果采用 MCP,可以把 search_catalog、get_store_status、read_cart 和 update_cart 暴露为独立工具。读操作与写操作应采用不同权限:搜索可以自动执行,而提交订单、替换商品或提高预算等操作应要求显式确认。
评估时不要只看回答是否“像人”
购物助手的离线评测至少应覆盖意图识别、约束保留、工具选择和参数正确率。上线后还要观察工具失败率、无结果率、购物车变更成功率、结账转化率和购物篮金额。
记忆功能需要单独做对照实验:同一个请求分别在无记忆、仅会话记忆和持久记忆条件下运行,检查模型是否更准确,同时确认它没有错误继承过期偏好。对于转化率和购物篮提升,应控制用户群、门店覆盖、库存和促销等变量,避免把推荐质量之外的变化归因于助手。
落地前的检查清单
- 将价格、库存、配送范围和购物车状态定义为后端事实,不允许 LLM 自行补全。
- 为每个 Agent 划定任务边界,并限制其可调用的工具与数据。
- 区分持久偏好、会话约束和实时状态,分别设置更新及过期规则。
- 对写入购物车、替换商品和下单等操作增加确认、审计和幂等控制。
- 同时评测对话质量、工具调用正确率和业务结果,不用单一指标代替整体质量。
- 为记忆提供查看、纠正和删除机制,并谨慎处理敏感偏好。
Ask DoorDash 展示的关键并不是给购物页面增加一个聊天框,而是把对话模型嵌入一套受约束的业务执行系统。LLM 擅长理解含糊需求,Agent 擅长拆分任务,MCP 工具提供可控的执行入口,记忆和实时数据则让建议既贴近用户,又不脱离当前事实。真正可靠的购物助手,需要这几部分共同工作。