尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

LLM购物车集成:从葡萄牙语指令到购物车状态变更的工程实践

LLM购物车集成:从葡萄牙语指令到购物车状态变更的工程实践 From LLM to shopping cart (Portugal)这个标题看起来像一条技术路线的缩写其实它背后是一个非常具体的工程问题。我在整理一个面向葡萄牙市场的电商项目复盘时最深的感受是把大模型接进购物车难点从来不是让模型开口说话而是让它说的每句话都能变成购物车状态的一次真实变化。用户用葡萄牙语说一句adiciona duas garrafas de vinho tinto ao carrinho系统要能识别出动作是加购对象是红葡萄酒数量是两瓶然后查询商品库、校验库存、调用购物车接口最后告诉用户已经加好了。到这一步LLM 和购物车才真正接上。这个项目最有价值的部分不是模型本身选得多新而是怎么把一条从自然语言到购物车状态的链路做得足够稳。这个判断我想先从为什么不能直接让 LLM 操作购物车讲起。1. 不是让 LLM 替用户按按钮而是让它听懂按钮背后的话1.1 一句放进购物车背后至少隔了五道门很多人第一次做 LLM 购物车功能时会觉得这事很简单用户说一句话模型理解了就去调购物车接口不就完了吗实际拆开看一句话到状态变更之间至少有五道门意图识别用户到底是想加购、删除、改数量、看购物车还是想询问商品信息。实体抽取对象是什么商品、数量是多少、有没有规格要求。商品匹配口语化的描述能不能在商品库里找到一个确定 SKU。业务校验库存够不够、商品是否下架、金额是否有变化。执行与回执调用购物车接口后需要根据结果生成一句用户能看懂的话。购物车是一个有状态的系统。用户之前已经加了几样商品、目前购物车里有没有同类商品、优惠是否已经失效这些信息模型都不可能凭空知道。要让模型正确工作就必须把状态数据喂给它或者在执行前由系统去查询。1.2 为什么直接让 LLM 操作购物车会表面成功、实际翻车有一种偷懒做法是把整个购物车系统暴露成一个大工具让 LLM 自己生成代码或选择函数然后直接改数据。看起来模型很智能但实际落地时通常会在三个地方翻车。第一模型容易把意图当成事实。用户说帮我加两瓶红酒模型可能会生成一个已经加购成功的回执但购物车接口可能因为库存不足没有调用或者调用后失败。如果系统没有把执行结果反馈给模型用户看到的就是假成功。第二模型对购物车状态的维护能力很弱。它可以在一次回答里记住上下文但购物车是随时可能被其他端更新的。用户可能在电脑上加购又在手机上删掉一件。模型如果没有先读取最新状态就会用一个过期状态去推断。第三商品检索不是模型擅长的精确匹配。用户说那款便宜一点的红酒模型如果自己猜一个商品十次里可能有三次猜错。正确做法是先让系统在商品库里召回候选商品再把候选交给模型或用户确认。1.3 先记住一句话LLM 是翻译层不是状态机这个判断贯穿整个项目LLM 不负责修改购物车状态它只负责把用户的自然语言翻译成结构化操作或者把系统返回的状态翻译回自然语言。真正决定购物车能不能加购成功的是商品库、库存服务、价格服务和购物车接口不是模型。模型翻译得再好也不能绕过业务校验。所以在总体架构上我把产品分成了三层意图翻译层LLM 负责理解、抽取、生成结构化指令。领域校验层商品查询、库存校验、价格计算、购物车操作。响应生成层把执行结果用用户的语言表达出来。这个边界一旦划清楚后面所有工程问题都变得可处理。2. 架构分界把购物车规则留在系统里2.1 三个层次意图翻译、领域校验、执行回执我在项目里给团队的约束是购物车领域的规则一行都不要写进提示词里让它自由发挥全部放在后端代码里。具体分工是这样的意图翻译层输入用户文本和当前购物车快照输出一个结构化动作比如add_item(product_id123, quantity2)。领域校验层系统拿着这个结构化动作去查商品、查库存、算金额。所有规则都用代码写死。执行回执层调用购物车 API 后把结果状态传给模型让模型生成一句自然语言回复。这样做的原因是购物车规则的每一次变化比如会员满 50 欧包邮某商品限购 1 件都应该由代码来保证。如果让模型在提示词里理解这些规则模型一旦更新或提示词被压缩规则就会出现漂移。在项目初期可以把规则写在提示词里做 demo。但要进真实环境规则必须下沉到代码里。这是稳定性的分水岭。2.2 用函数调用而不是自由文本来约束 LLM 的行为要让 LLM 输出结构化动作比较好的方式是给模型定义一组函数或工具而不是让它直接写一段自由文本。我当时定义的最小动作集就四个get_cart()获取当前购物车内容。add_item(product_id, quantity)加购商品。update_item(item_id, quantity)修改购物车中某一行商品的数量。remove_item(item_id)移除购物车中某一行商品。为什么定义得这么窄因为动作集越宽模型选错的可能性越高。购物车场景里用户绝大部分需求都落在这四类里。如果用户还有其他需求比如查询订单、使用优惠券那就再加对应的函数但不要给模型一个万能操作对象。所谓LLM 只负责翻译落到工程上就是模型只能在这组函数里选择并填充参数。参数还需要再做一次类型校验比如quantity必须是正整数超过可购买上限要拦截。如果环境里已经用了类似 MCP 这样的工具协议含义也一样只是把函数描述标准化成模型可读的 schema。重点不是协议选哪个而是保持动作集合小、参数校验严、执行结果可回传模型。2.3 葡萄牙语不是小到可以忽略但真正的坑在数据规范化项目需要处理葡萄牙语一开始我以为这是 LLM 的强项毕竟翻译模型对葡语的理解能力还不错。真正跑起来才发现模型理解语言不难难的是商品库数据本身不够规范。葡萄牙语的重音字符是第一个问题。比如 Vinho Tinto 如果商品库里带重音写成 Vinho Tínto用户输入时不带重音或者相反直接精确匹配就会找不到商品。常见解决办法是做字符归一化把带重音的字符转成无重音形式再作为商品检索的候选条件之一。第二个问题是数量单位。用户说 uma garrafa一瓶和 uma caixa一箱对应的数量可能完全不同。如果商品是按箱卖的算法里必须有单位换算表不能只让模型填 1。第三个问题是礼貌用语和自然表达的冗余。葡萄牙语用户很习惯说 Por favor、poderia、queria这些都不会改变意图但会影响实体抽取需要在结构化输出时让模型忽略跟动作无关的部分。这些问题看起来小但在真实语料里出现频率很高。解决方案不是让 LLM 更智能而是在输入阶段做一次文本预处理在输出阶段做一次候选归一化。模型的职责是抽取意图和参数系统的职责是处理真实数据。3. 最小可运行链路从一句葡语到加购成功3.1 一条完整链路拆成七步从用户输入到购物车状态变化的完整链路我在项目里拆成七步。每次排查问题也是按这七步逐层往下找。接收用户输入。做文本预处理去重音、修空格、统一标点。连同当前购物车快照一起发给 LLM让它返回结构化动作。解析并校验结构化动作。根据动作去商品服务查询商品、库存、价格。调用购物车服务执行变更。把执行结果交给 LLM 生成自然语言回执。这个顺序里有两个容易漏掉的地方第 3 步要带上当前购物车快照第 7 步必须拿到执行结果再生成回复。如果跳过这两步整个链路就是盲人摸象。3.2 一个能跑通最小流程的伪代码结构下面这段是简化伪代码重点展示边界不绑定具体大模型 SDKfrom typing import Literal from pydantic import BaseModel class CartAction(BaseModel): action: Literal[add_item, update_item, remove_item, get_cart] product_id: str | None None item_id: str | None None quantity: int | None None def llm_extract_action(user_text: str, cart_state: dict) - CartAction: # 调用大模型接口要求输出符合 CartAction 的 JSON # 如果没有现成 function call就让模型返回 JSON schema CartAction.model_json_schema() raw call_llm( system你只负责把购物车相关的用户指令转成结构化动作不要执行任何操作。, useruser_text, cart_statecart_state, output_schemaschema, temperature0.2, ) return CartAction.model_validate_json(raw) def handle_cart_command(user_id: str, user_text: str): cart get_cart_from_service(user_id) try: action llm_extract_action(user_text, cart) except ValidationError: return {status: failure, reason: can_not_parse_action} if action.action add_item: product get_product(action.product_id) if product is None: return {status: failure, reason: product_not_found} if product.stock action.quantity: return {status: failure, reason: insufficient_stock} cart.add_item(product.id, action.quantity) elif action.action update_item: cart.update_item(action.item_id, action.quantity) elif action.action remove_item: cart.remove_item(action.item_id) result cart.save() reply llm_generate_reply(user_text, result) return {status: success, cart: cart, reply: reply}这个结构最关键的是CartAction这个 schema。只要模型输出能被解析成合法动作后面的领域校验和购物车执行就有机会把关。如果解析失败也不要让模型自己修直接返回一个我没听懂的兜底话术。3.3 参数里有四个位置值得反复检查我用过不少大模型接口在购物车场景里最值得检查的是下面四个参数参数位置常见建议原因temperature0 到 0.3意图抽取需要稳定温度太高会随机改参数max_tokens800 到 1500结构化输出 回执生成太短容易截断response_format / function_call开启强制模型按照 schema 输出减少自由发挥timeout / retry超时 5 到 10 秒重试 1 次购物车操作有强交互属性等待太久用户会反复提交这里要特别提醒一个误区不要把 temperature 设为 0 当成完全确定。有些模型在 temperature 为 0 时仍然会有随机性尤其是在长输出或生僻词上。所以温度低可以但该做的参数校验不能省。另外版本兼容是一个隐性坑。如果你用的模型更新了版本函数调用格式或者 JSON 输出格式可能变化。落地前先确认依赖版本然后跑一遍同样的样例确认结构化输出没有变异。4. 真正难的是多轮、反悔和状态同步4.1 把购物车当前状态放进上下文而不是只靠聊天记录购物车场景里用户经常会说把刚才那瓶酒去掉。这个来两份。那个便宜一点的还在吗这些刚才这个那个背后指的商品可能在对话历史里也可能不在。如果只把聊天记录发给 LLM模型可能记住也可能忘记。更可靠的做法是每次执行前先把当前购物车内容拿出来作为一部分上下文发送给模型。在这个项目里我固定送进上下文的购物车字段包括购物车行 ID、商品名、数量、单价、总价。这样当用户指着那瓶酒的时候模型至少能结合真实购物车状态去理解而不是凭空猜。这和 RAG 的思路类似不是让模型把整个商品目录背下来而是在需要的时候把最相关的部分作为上下文检索出来喂给它。商品信息应该按需检索购物车状态应该每次快照。4.2 每样加两件当候选不是一个时宁可追问用户表达有时会带歧义。比如用户说来两瓶便宜的红酒商品库里可能同时有 5 款红葡萄酒满足条件。这时候最稳的做法不是让 LLM 挑一个而是让系统先召回候选再向用户追问确认。具体流程是LLM 抽取动作意图是加购但商品实体是模糊的。系统在商品库搜索候选返回候选列表。如果候选列表长度为 1直接加购。如果候选多于 1 个生成一句追问您指的是 A、B、C 中的哪一个有些用户会觉得追问多了一步很烦但它的价值是避免加错商品。购物车加错商品再取消成本比多问一句高得多。这里要特别克制给 LLM 的自由裁量权。不要告诉模型选一个最合适的而要让系统决定是否需要进行澄清。因为最合适的定义涉及价格、偏好、历史订单系统还没有足够数据时模型的猜测不值得信任。4.3 库存不足、价格变化、用户反悔错误码比对话更可靠在一次真实购物车操作里LLM 生成的自然语言回执应该是最后的收尾。真正决定用户看到什么逻辑的是后端返回的错误码。我们当时定义了几个基础状态success操作成功。product_not_found找不到对应商品。insufficient_stock库存不足。quantity_invalid数量不合法比如 0 或负数。cart_conflict购物车在其他端被修改需要刷新。need_confirmation候选商品不止一个需要用户确认。每个错误码都有一套固定的话术模板LLM 只需要根据模板微调语气不需要自己发挥。比如库存不足时回复是这款红葡萄酒目前只剩 1 瓶您还需要加购吗 这句话可能由 LLM 润色但核心信息来自错误码和库存值。用户反悔的情况也要专门处理。用户说取消刚才加的红酒系统需要知道刚才加的红酒是哪一笔操作。所以每一步购物车变更都应该记录操作日志至少包含时间、商品 ID、数量、操作类型。这样才能支持撤销刚才那次操作这种能力。5. 从小样到生产不是调通一次就够了5.1 生产前需要补的工程能力很多项目在做 LLM 购物车时demo 跑得很顺一上线就出问题。问题往往不在模型而在工程化能力不足。我建议至少补四件事日志链路记录原始用户输入、LLM 结构化输出、领域校验结果、购物车执行结果。没有完整日志多轮问题根本无法排查。权限校验LLM 生成的操作必须绑定当前登录用户。购物车 API 要校验user_id不能让一个用户操作另一个用户的购物车。幂等处理用户如果网络卡顿可能连续点两次提交。后端需要有一个幂等键避免同一指令执行两次。限流与资源控制LLM 调用有成本和延迟。要给用户维度的限流不能一个用户刷 1000 次请求就把预算耗尽。这些能力不亮眼但没有它们整个功能就是玩具。5.2 小语种评价集50 条真实话术比 500 条模型生成的更有用做葡萄牙语购物车助手时最容易踩的坑是用模型生成测试数据去评估模型。比如让 ChatGPT 生成 500 句葡萄牙语购物车指令然后拿去测另一个模型。这样看起来准确率很高但真实用户不会按这种话术说话。更靠谱的做法是在一开始就收集真实用户语句。哪怕只有 50 条这 50 条里包含的口语表达、重音缺失、词汇变体往往比模型生成的 500 条更有价值。这个评价集应该持续更新。每次用户反馈没听懂时就去确认是意图识别失败、商品匹配失败还是校验逻辑失败然后把这条语句加入回归集。以后每换一次模型版本、改一次提示词都要跑一遍这批回归集确保没有回退。5.3 适用边界和落地前置条件这套LLM 做翻译层系统做规则层的方案并不是所有购物车场景都适用。我的判断是这样的适合的场景SKU 数量可控、商品属性结构化清晰、用户购物车操作类型有限加购、改数量、删、查看、询问、业务规则以代码形式能明确表达。不适合的场景购物车逻辑极其复杂、每个商品都有不同的定制流程、规则经常变动且无法标准化、用户要求完全确定性和零误操作比如部分医疗或金融相关电商场景。也就是说如果购物车系统的规则边界还不够清晰先不要说上 LLM而应该先梳理业务。LLM 只会把已有的业务混乱放大不会自动理清规则。5.4 一条可以直接复用的五步落地框架最后把这个项目里沉淀下来的方法归纳成一个五步框架。它不限于葡萄牙语购物车其他类似从自然语言到业务操作的场景也可以参考限定动作集合只定义 4 到 6 个核心操作不允许模型自由发挥。定义结构化输出协议用 JSON Schema 或函数定义把模型的输出约束成可校验的格式。领域校验前置商品查询、库存校验、金额计算全部由系统完成模型不参与。执行结果回传用错误码和状态驱动话术不要让模型自己编造执行结果。建立回归集持续收集真实语句用固定测试集保护每次迭代。这个框架的核心思想是LLM 负责降低用户表达的成本系统负责守住业务事实。两者分工明确购物车才能真正稳定运行。从 LLM 到购物车中间隔的不是一句 prompt而是一整套输入校验、状态管理、领域规则和执行链路。真正值得投入时间的永远不是让模型更聪明而是把模型和系统之间的边界控制得更清楚。
返回列表