
1. 从一场直播演示说起AI购物到底在演示什么Gemini那场直播我反复看了三遍。第一遍看热闹第二遍看交互细节第三遍专门盯着它调用工具时的参数传递和状态流转。很多人看完的第一反应是这不就是个语音助手加购物车吗但如果你真的动手搭过类似的Agent就会知道这场演示里藏着的技术密度远比表面看起来高得多。所谓用AI购物拆开来看其实是三件事的串联意图理解、工具调用、多轮状态维护。用户说一句帮我找一双适合雨天跑步的鞋预算800以内系统要做的不是关键词匹配而是先把这句话翻译成结构化的查询条件——场景是雨天跑步、品类是跑鞋、价格上限800、隐含需求是防滑和防水。然后它需要调用商品检索接口拿到候选集再根据用户后续的反馈太丑了有没有轻一点的动态调整查询参数而不是重新开始一轮对话。这场演示真正让我感兴趣的点在于Gemini在购物场景里展示的是一种**边聊边操作的混合模式**。它不是先问完所有问题再给结果而是在对话过程中就把筛选、比价、加购这些动作穿插进去。这背后依赖的是函数调用Function Calling机制和会话状态的持久化。我在自己的项目里复现过类似流程踩过的坑后面会细说。这篇文章适合三类人看一是想搞清楚AI Agent在电商场景怎么落地的开发者二是正在做AI应用、想知道工具调用链路怎么设计的同学三是对Gemini能力边界好奇、想自己动手试一把的爱好者。我会从演示拆解讲到技术原理再给出一套可以跑通的实操方案最后把我在实际搭建中遇到的坑和解决思路完整摊开。2. 拆解直播里的购物链路意图、检索、决策三段式2.1 意图理解不是听懂话而是翻译成结构化查询大多数人以为AI购物的第一步是语音识别其实语音转文字只是最外层。真正的核心是把自然语言翻译成可执行的查询对象。直播里用户说我想买一个送给刚搬新家的朋友的礼物不要太贵Gemini没有直接搜礼物而是先追问了朋友的兴趣、预算范围、是否需要包装。这个追问行为本身就是意图理解的一部分——它识别出当前信息不足以构成有效查询于是主动补全槽位Slot Filling。我在自己的实现里用的是槽位意图的双层结构。意图层判断用户是要搜索、比价、加购还是售后槽位层负责收集品类、价格区间、场景标签、偏好属性这些字段。Gemini的演示里没有暴露它的内部结构但从交互节奏能看出来它至少维护了五到六个槽位并且支持槽位的动态增删。比如用户后来说对了朋友对气味敏感系统立刻新增了一个无香型的筛选条件而不是把这个信息丢掉。这里有个容易忽略的细节槽位不是越多越好。我一开始设计了十几个槽位结果用户每说一句话系统都要追问三四个问题体验极差。后来改成核心槽位必填、扩展槽位按需触发核心槽位只有品类和预算其他槽位在检索结果不理想时才主动询问。这个策略调整之后平均对话轮次从7.2轮降到了3.8轮。2.2 商品检索接口的调用时机与参数构造直播里Gemini调用检索的时机很有意思。它不是等所有信息收集完才调用而是在信息足够构成一次有效查询时就先调一次拿到结果后再根据用户反馈细化。这个策略的好处是用户能快速看到反馈不会觉得系统在审问自己。参数构造这块我实测下来最关键的是查询条件的优先级排序。假设用户说了五个条件但商品库里有三个条件同时满足的结果为零系统需要知道先放宽哪个。我的做法是给每个槽位设一个权重品类和价格是硬约束场景标签是软约束品牌偏好是弱约束。检索时先按硬约束过滤软约束用于排序弱约束只在结果充足时作为加分项。Gemini的演示里有一个细节当用户说有没有便宜点的时系统没有重新检索而是在已有结果集里按价格升序重排。这说明它维护了一个会话级的结果缓存而不是每次都打接口。这个设计在真实场景里非常重要因为电商接口的延迟通常在200到500毫秒如果每轮对话都重新请求用户体验会明显卡顿。2.3 决策环节AI怎么替用户做选择购物场景里最难的不是找到商品而是帮用户做决策。直播里Gemini展示了一个能力当用户面对三个候选商品犹豫时它会主动对比关键差异比如第一款防水等级更高但重了80克第二款轻但只有两个配色第三款价格最低但评价里提到尺码偏小。这种对比不是简单的参数罗列而是基于用户已表达的偏好做加权。我在实现这个功能时用了一个简单的评分模型每个商品在用户关注的维度上打分然后加权求和。权重来自用户在对话中提到的偏好词频比如用户三次提到轻那重量维度的权重就调高。这个方法很粗糙但实测效果比让大模型直接凭感觉推荐要稳定得多因为大模型的推荐理由经常前后矛盾。提示决策环节一定要保留用户否决的出口。直播里用户说都不太满意Gemini立刻回到检索环节并询问是否放宽某个条件。如果系统只会推荐不会回退用户很快就会失去耐心。3. 工具调用背后的技术骨架Function Calling怎么串起来3.1 函数定义的设计原则少而精参数要扁平Gemini的Function Calling机制允许你注册一组函数模型根据对话内容决定调用哪个、传什么参数。我在项目里注册了六个函数search_products、get_product_detail、compare_products、add_to_cart、get_cart、apply_coupon。听起来不多但每个函数的参数设计花了我最多时间。核心原则是参数扁平化。我一开始把搜索参数设计成嵌套对象比如{filters: {price: {max: 800}, category: shoes}}结果模型经常传错层级。改成扁平结构{category: shoes, price_max: 800, price_min: 0}之后参数准确率从七成提升到了九成五以上。大模型对嵌套结构的处理能力确实弱一些这是实测结论。另一个原则是给参数设默认值。比如price_min默认0sort_by默认relevance。这样即使用户没说模型也不会因为缺参数而调用失败。我在函数描述里明确写了如果用户未指定使用默认值模型基本能遵守。3.2 多轮对话中的状态管理别把历史全塞进上下文直播里Gemini能记住用户三轮前说的预算800这说明它做了状态管理。但状态管理不等于把全部对话历史塞进上下文。我试过把最近十轮对话原封不动传给模型结果token消耗暴涨而且模型经常被早期信息干扰比如用户一开始说随便看看后来明确说要买模型还在纠结随便看看这个表述。我的方案是维护一个结构化的会话状态对象只把关键槽位和最近两轮对话传给模型。状态对象长这样{ intent: search, slots: { category: running_shoes, price_max: 800, scene: rainy_running, preferences: [lightweight, non_slip] }, last_results: [sku_001, sku_002, sku_003], turn_count: 4 }每次模型返回后我用一个轻量的解析逻辑更新这个对象而不是让模型自己维护。这样做的原因是模型对结构化状态的读写不如代码可靠让它专注于理解和决策状态维护交给程序。3.3 错误处理工具调用失败时AI该怎么接话这是直播里没展示但实际开发中最头疼的部分。商品接口超时、库存查询返回空、优惠券校验失败这些情况在真实环境里天天发生。如果工具调用失败后模型直接说抱歉我做不到用户体验就断了。我的做法是给每个函数定义降级返回。比如search_products超时后返回一个空结果加错误码同时在函数描述里告诉模型如果返回错误码TIMEOUT告知用户稍后重试并建议放宽条件。实测下来模型能根据错误码生成合理的回复比如刚才查询有点慢要不我们把价格范围放宽一点再试试还有一个坑是模型会编造工具返回结果。我遇到过模型在接口返回空列表时自己虚构了三个商品推荐给用户。解决办法是在系统提示里明确写只能使用工具返回的数据不得自行生成商品信息并且在代码层做校验如果模型输出的商品ID不在返回结果里直接拦截重试。4. 自己动手复现一套可跑通的AI购物Agent方案4.1 环境准备与依赖选择要复现这套流程你需要三样东西一个支持Function Calling的大模型接口、一个商品数据源、一个会话管理层。商品数据源我用的是本地SQLite建了一张商品表包含品类、价格、场景标签、重量、防水等级等字段大概两千条模拟数据。真实场景接电商平台的开放接口也行但调试阶段本地数据更可控。模型接口这块Gemini的API支持函数调用文档里有完整示例。如果你用其他模型逻辑是相通的关键是确认它支持并行函数调用和多轮函数调用。并行调用是指模型一次返回多个函数调用请求比如同时查商品和查库存多轮调用是指模型拿到函数结果后继续发起新的调用。这两个能力决定了你的Agent能不能处理复杂购物流程。会话管理我用的是Redis存状态对象key是会话ID过期时间设30分钟。如果你只是本地测试用内存字典也够但要注意进程重启后状态会丢。4.2 核心代码结构从用户输入到商品推荐整个流程分四步接收用户输入、更新会话状态、调用模型、执行函数并回传。我用Python写了一个简化版核心逻辑大概长这样def handle_user_input(session_id, user_text): state load_state(session_id) messages build_messages(state, user_text) response model.generate( messagesmessages, toolsTOOL_DEFINITIONS, tool_config{mode: AUTO} ) if response.has_tool_calls: results [] for call in response.tool_calls: result execute_tool(call.name, call.args) results.append(format_tool_result(call.id, result)) state update_state(state, response, results) save_state(session_id, state) return handle_user_input(session_id, None) # 带着工具结果再问模型 state update_state(state, response) save_state(session_id, state) return response.text这段代码里最关键的是递归调用那一步。模型返回工具调用请求后程序执行工具把结果作为新的消息追加到对话里再让模型生成最终回复。Gemini的API里这个流程有标准写法注意工具结果的格式要严格符合接口要求否则模型会解析失败。4.3 提示词设计让模型知道什么时候该问什么时候该做系统提示词我改了十几版最后稳定下来的版本核心是三条规则第一信息不足时优先追问但一次最多问两个问题第二能通过工具获取的信息不要问用户第三推荐商品时必须给出至少一个具体理由理由必须来自工具返回的数据。第三条规则特别重要。我一开始没加这条模型推荐商品时说这款很适合你完全是空话。加上规则后它会说这款防水等级IPX6重量240克符合你提到的雨天和轻量需求可信度完全不一样。还有一个小技巧在提示词里给几个少样本示例Few-shot展示一轮完整的用户说→模型调用工具→模型回复流程。我放了两个示例一个简单查询一个多轮筛选模型的表现明显更稳定。示例不用长每个控制在五行以内。5. 实测中暴露的问题与我的处理方式5.1 模型过度热情不该加购的时候加购测试初期遇到一个典型问题用户只是问这个多少钱模型就自动调用了add_to_cart。原因是我的函数描述里写了当用户对商品表达兴趣时可加入购物车模型把问价格理解成了表达兴趣。修复方式是把触发条件写得更严格仅当用户明确说出加入购物车我要买下单等指令时才调用此函数。同时我在代码层加了一道校验如果用户输入里没有购买意图关键词即使模型请求加购也拦截。这个双重保险很有必要因为模型对模糊表述的判断确实不稳定。5.2 价格计算的精度问题别让AI做算术直播里有个环节是计算优惠后的价格我特意留意了Gemini的表现。它算对了但我在自己项目里用其他模型测试时遇到过算错的情况比如满减和折扣叠加时顺序搞反。后来我把价格计算全部放到代码里模型只负责决定用哪张优惠券具体金额由程序算好再告诉模型。这个原则可以推广到所有涉及数值计算的场景模型做决策代码做计算。折扣、税费、运费、分期这些统统不要让模型碰。我在函数里加了一个calculate_final_price输入商品ID和优惠券ID返回精确到分的价格模型直接引用这个结果。5.3 会话超时后的状态恢复用户聊到一半去干别的事二十分钟后回来说就刚才那个吧这时候会话状态可能已经过期了。我的处理是保留最近一次的结果快照即使主状态过期也能从快照里恢复出用户上次看的商品列表。快照存的是商品ID和关键属性不存完整对话存储成本很低。如果快照也过期了系统会礼貌地请用户重新描述需求同时尽量从用户这句话里提取线索。比如就刚才那个提取不出有效信息但如果用户说就刚才那双跑鞋系统能提取出跑鞋这个品类重新检索后大概率能找到同一批商品。注意会话恢复功能一定要做但不要做得太聪明。我试过让模型根据过期会话的残留信息猜测用户意图结果经常猜错反而让用户困惑。老老实实说抱歉刚才的会话已结束您说的是哪类商品比自作聪明要好。6. 从演示到产品还差哪些关键能力直播演示和真实产品之间有巨大的鸿沟我踩过之后总结出三个必须补齐的能力。第一个是商品数据的实时性。演示里商品信息是静态的真实场景里价格会变、库存会变、促销会变。我的方案是在检索函数里加一层缓存缓存时间设60秒同时给每个商品返回一个数据更新时间字段模型在推荐时可以提及当前价格而不是标价。第二个是多模态输入。用户可能发一张图片说我想要类似的这时候纯文本的Function Calling就不够了。Gemini支持图片输入但要把图片特征转成检索条件需要额外的处理。我的做法是用图片描述模型先生成文字描述再把描述作为搜索关键词实测召回率大概七成够用但不算理想。第三个是个性化记忆。演示里每次对话都是独立的真实产品需要记住用户的历史偏好。我在会话状态之外加了一个用户画像层记录用户常买的品类、价格带、品牌偏好。这个画像不直接传给模型而是在检索时作为排序权重使用避免模型被历史信息带偏。最后分享一个我在调试中总结的小技巧每次修改提示词或函数定义后用同一组测试用例跑一遍回归。我准备了二十条典型用户输入覆盖简单查询、多轮筛选、模糊表达、错误恢复等场景每次改动后跑一遍看通过率有没有下降。这个习惯帮我避免了好几次改了一个问题引入两个新问题的情况。