黄金主线(6 分钟):演示 1 → 2/3 → 6 → 7 → 多模态压轴(演示 19 语音深度 + 演示 8 跨模态拍照找货)→ 后台(演示 18 Dashboard + 演示 20 对话模型)。
后端 必须用 Python 3.11(≥3.10)。系统 / Xcode 自带的 python3 常是 3.9,直接建 venv 会在启动时报 unsupported operand type(s) for |(代码用了 3.10+ 的 str | None 注解):
cd "/Users/xuwenyao/字节AI全栈挑战赛" # 项目根
python3.11 -m venv server/.venv # 一次性:务必用 3.11,别用默认 python3
source server/.venv/bin/activate
python --version # 确认 Python 3.11.x(≥3.10),不是 3.9
pip install -r server/requirements.txt
# 启动(路径已 CWD 无关,从项目根或 server/ 目录启动都不会找错库)
PYTHONPATH=server python -m uvicorn app.main:app --host 127.0.0.1 --port 8000.env 里的对话 / embedding / 图像理解三把 key 会自动加载,商品向量已预热,秒开。自检:
curl -s http://127.0.0.1:8000/api/health # 期望 llm_configured=true、embedding configured=true、商品数 321iOS(工程已提交,直接打开即可,无需 xcodegen):
cd client-ios
open ShopGuide.xcodeproj选 iPhone 模拟器运行「智购罗盘」(默认连 http://127.0.0.1:8000)。演示间想要干净上下文,点侧栏顶部「新对话」即可换新 session。
只有改了
project.yml才需要xcodegen generate。若 Run 报Multiple commands produce '….app':git checkout -- client-ios/ShopGuide.xcodeproj/project.pbxproj还原已提交工程,删~/Library/Developer/Xcode/DerivedData/ShopGuide-*后重开 Xcode。
用户输入:
推荐手机
预期:
- Agent 不直接乱推。
- 先追问拍照、续航、游戏性能、性价比和预算。
继续输入:
游戏,预算9999
预期:
- 返回手机商品卡。
- 商品卡可点进详情页。
用户输入:
苹果手机不要小米
预期:
- 返回 Apple 相关手机。
- 不出现小米商品。
用户输入:
推荐适合油皮的防晒,200元以内,不要含酒精
预期:
- 返回防晒商品。
- 不受上一轮手机上下文影响。
- 推荐商品符合 200 元以内和不含酒精约束。
用户输入:
推荐适合油皮的防晒,200元以内,不要含酒精
预期:
- 商品卡右上角显示匹配分。
- 商品卡底部显示首条命中依据。
- 点进详情页后,“推荐决策”区块展示命中依据和注意点,例如预算、偏好、评论、来源、SKU、价格是否接近预算上限等。
用户输入:
推荐去三亚要带的东西
预期:
- 返回防晒、轻量衣物、补能食品、充电类商品组合。
- 不再沿用上一轮手机偏好。
- 输入
17pm。 - 点击 iPhone 商品卡的规格按钮。
- 在详情页切换“宇宙橙 / 冰川蓝 / 银色”和存储容量。
预期:
- 价格随容量变化。
- 图片随颜色变化。
- 图片来自 Apple 官方公开 CDN,本地只缓存,不使用伪造图片。
先输入:
推荐适合油皮的防晒,200元以内,不要含酒精
继续追问:
第一款差评主要说什么
这款适合敏感肌吗,有没有酒精
预期:
- Agent 不重新随机推荐,而是围绕上一轮第一款商品回答。
- 回答引用商品库里的 FAQ、评论和详情证据。
- 差评问题会归纳 3 星及以下评论,成分问题会说明不含酒精并提醒敏感肌先测试。
再输入:
17pm
继续追问:
第一款不同规格怎么选
预期:
- Agent 汇总可选存储、颜色、价格区间。
- 明确说明该商品有独立真实规格图。
- 在详情页选一个 SKU 加入购物车。
- 返回聊天页,确认右上角购物车徽标。
- 输入:
我要下单
- Agent 汇总订单并要求地址,继续输入:
北京市朝阳区 Demo 路 1 号
- Agent 再次汇总商品、地址和金额,继续输入:
确认下单
预期:
- 同商品不同 SKU 是独立购物车行项目。
- 总价按 SKU 单价计算。
- 加购、改数量和下单前会校验 mock 库存。
- 模拟下单后聊天页出现独立订单卡,包含
SG...订单号、地址、金额和商品数量;购物车清空。 - 订单后推荐商品自动出现,例如配件、补充购买或复购候选。
- 点击聊天输入框左侧图片按钮(相机或相册)。
- 上传一张商品图,例如一副耳机或一台手机的图片。
稳定样例见 server/evaluation/cases/multimodal_demo_samples.json,可优先使用:
server/static/product_images/p_digital_016.jpg:手机。server/static/product_images/p_anker_001_fc881685.jpg:Anker 充电设备。server/static/product_images/p_beauty_001.jpg:防晒。server/static/product_images/p_clothes_014.jpg:防水徒步鞋。
预期(讲解词):
- 跨模态语义匹配:上传图用豆包多模态向量
doubao-embedding-vision编码,与商品的文本向量落在同一图文共享空间比对——所以一张耳机图会召回耳机、一张防晒图会召回防晒,靠语义而不是关键词或颜色直方图。 - 商品卡推荐理由里会出现
语义图文匹配 X%(多模态向量,拍照找货),这是主导信号(权重最高),再融合 VLM 图像理解、轻量视觉特征和文本意图做重排。 - 相似度呈梯度,不会全部 100%。
继续演示图文融合(图片 + 文字一起):
- 先在输入框输入
油皮防晒或降噪耳机。 - 不点击发送,直接上传一张商品图片。
预期:
- Agent 会提示正在融合图片和文字需求。
- 推荐理由同时包含:多模态向量语义匹配、VLM 图像理解词(品类/子类目/关键词/外观属性)、文本筛选词和融合排序依据。
- 优雅降级:未配置 embedding key 时回退到轻量视觉特征,未配置 VLM 时明确显示 VLM fallback——服务不中断。
运行:
python3 server/scripts/stress_test_retrieval.py --sample 1000 --concurrency 16 --p95-ms 800预期:
- 脚本优先下载 Kaggle
olistbr/brazilian-ecommerce数据集生成压力查询。 - 输出 QPS、p50/p95/p99/max 延迟和错误数。
- 错误数为 0 且 p95 未超过阈值。
输入:
记住我以后护肤品不要含酒精,我是油皮,预算200
预期:
- Agent 回复已记住肤质、预算和排除成分。
- iOS 左上角“我的偏好”入口显示已保存状态。
- 打开“我的偏好”页能看到肤质、预算偏好、排除成分,并支持清除。
继续输入:
推荐防晒
预期:
- Agent 不再反复追问肤质,而是自动带上油皮、200 元预算和酒精排除条件。
- 推荐结果仍然展示匹配原因和风险提示。
输入:
我1000元预算,下周去三亚,帮我配一套防晒和出行用品
预期:
- 返回结构化 Shopping Plan 卡片。
- 卡片包含必需项、可升级项、总价、剩余预算和每个商品的选择理由。
- 每个方案项可点进商品详情,或直接按 SKU 逻辑加入购物车。
先输入:
推荐适合油皮的防晒,200元以内,不要含酒精
然后继续输入:
第一款太贵了,有没有平替
预期:
- Agent 记录
too_expensive反馈。 - 返回更低价候选,并解释“平替”逻辑。
继续尝试:
换个品牌
预期:
- Agent 避开上一款品牌,返回同类替代商品。
- 用户画像里的
last_feedback会记录反馈链路。
输入:
推荐 Anker 100W 快充
预期:
- 商品推荐理由中出现
混合检索:BM25 / 语义向量或本地向量 / 结构化 / 可信度。 - 未配置
TEXT_EMBEDDING_*时,打开/api/traces/{trace_id}可看到retrieval_stack为structured_filter + BM25 + hashing_vector + trust_reranker。 - 配置文本 embedding 并运行
server/scripts/build_text_embeddings.py后,Trace 会显示text_embedding(...)。 - 同时启用
VECTOR_STORE_BACKEND=chroma且已预计算真实向量时,Trace 会显示Chroma text_embedding(...),商品理由会出现Chroma语义向量,用于演示标准向量数据库承载真实商品 embedding。
先输入:
我要看17pm
继续追问:
第一款售后和保修怎么说
预期:
- Agent 不编造真实平台七天无理由、库存、保修期限或运费险。
- 回答会说明这是导购 Demo,不产生真实支付、物流和售后承诺。
- 回答会提示真实退换货规则以公开来源页面和下单平台为准。
- 点击聊天页左上角
info.circle。 - 查看“隐私与合规”页。
预期:
- 页面说明商品数据来源、图片处理方式、偏好记忆内容和 API 使用边界。
- 明确说明上传图片只用于当前检索,不作为伪造商品图保存。
- 明确说明项目不模拟真实支付、物流、库存或平台售后承诺。
- 发送任意问题,观察 assistant 思考态。
- 等待商品卡片出现。
- 点击麦克风按钮,用语音说出一个导购需求,再打开扬声器按钮让回复朗读。
- 重复打开同一批商品卡图片,观察二次加载速度。
- 切换模拟器深色模式。
预期:
- Assistant 空消息显示三点思考动画。
- 商品卡图片加载时有 skeleton,占位不会导致布局跳动。
- 图片走内存缓存和
URLCache磁盘缓存,重复展示不会反复拉取同一张图。 - 发送、加购、切换语音开关时有轻量触觉反馈;TTS 只朗读简短导购回答,不朗读商品卡 JSON。
- 商品卡进入有轻量 scale/opacity 动效。
- 深色模式下背景、卡片、徽标描边和文字对比保持清晰。
运行:
PYTHONPATH=server python3 server/evaluation/run_eval.py预期:
- 输出意图、约束、反选、多轮、购物车、图片找货和来源 grounding 的通过率。
- 生成
server/evaluation/output/evaluation_report.html,可直接打开作为答辩材料。 - 报告中展示 Top-3 命中率、反选过滤准确率、主动澄清准确率、购物车成功率、图片 Top-K 命中率、预算套装成功率、订单后推荐成功率和 p95 延迟。
- 启动后端并完成一次聊天推荐,例如
推荐适合油皮的防晒,200元以内,不要含酒精。 - 打开
http://127.0.0.1:8000/admin/metrics。
预期:
- Dashboard 显示商品总数、公开来源覆盖、评论覆盖、SKU 覆盖和规格图覆盖。
- 能看到 Agent 调用次数、Grounding Guard 通过/拦截次数、图片检索延迟、SSE 首 token 延迟和最近 Trace。
- 第二次发送完全相同的推荐问题时,
retrieval_cache_hit_rate或recommendation_cache_hit_rate应上升,可现场展示缓存命中带来的延迟下降。 - 点击 Trace ID 或访问
/api/traces/{trace_id},可以看到意图识别、约束解析、候选过滤、检索 Top 商品、Grounding Guard 和 SSE 输出链路。
- 点击聊天页底部的麦克风按钮,对着说一句导购需求,例如“推荐拍照好的手机四千以内”。
- 观察输入区上方弹出的聆听浮层:波形动效 + 实时转写文字随说随出。 3.(可选)开启语音连续对话后再说一句。
- 长按顶部喇叭按钮,打开语音设置面板,拖动语速滑杆、切换中文音色,点“试听”。
预期:
- 流式 ASR:
SFSpeechRecognizer(zh-CN)开启 partial results,聆听浮层实时展示转写,不是说完才出。 - 语音连续对话:开启后,识别一停顿就自动发送并把回复朗读出来,全程免手动——可演示一问一答的语音闭环。
- 可调 TTS:语速(0.5×–1.5×)和中文音色可调并本地持久化(
@AppStorage);只朗读简短导购回答,不朗读商品卡 JSON。 - 讲解点:语音输入用系统级 ASR,语音播报用系统 TTS,商品事实仍只来自后端工具——多模态入口扩展但不破坏 grounding。
- 打开侧栏 →「对话模型」,可见当前状态(默认就用后端
.env的 key,演示时无需手填)。 - 讲解:这里只切换最外层对话/规划模型;商品检索、跨模态图搜、RAG 工具调用、Grounding Guard 都由后端统一控制,不受影响。 3.(进阶演示)切换到另一个 OpenAI-compatible 模型并保存,或直接清空配置退回本地确定性逻辑。
预期:
- 可插拔:换对话模型后,商品、价格、SKU 依然准确,Guard 依然拦截编造的促销/库存/价格——证明“事实来自工具,不来自模型”。
- 保存有护栏:保存前先做连通性校验,校验失败不写入会话覆盖、自动回退到后端默认 key,现场不会因填错 Key 把会话弄挂。
- 优雅降级:把 key 清空 / 用错模型时,Agent 退回本地确定性文案,服务不中断,仍能出商品卡。