ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

AI购物代理如何劝你不买:反向推荐Agent的设计与实现

AI购物代理如何劝你不买:反向推荐Agent的设计与实现 现在的大模型购物助手几乎都活成同一个样子你给它一个商品链接它帮你拉参数、比价格、说优点最后补一句综合考虑建议入手。用久了你会发现这类 agent 给人的帮助其实非常有限。它把帮你买东西简化成了帮你把东西加入购物车而真正难的问题——这个东西你到底该不该买它反而避开了。所以当我在 Show HN 上看到 TickClip 这个项目时第一反应是终于有人把产品锚点放在recommend not buying上了。一个 AI shopping agent 不把成交当目标而是主动劝用户别买。这不是营销噱头它背后其实是一个完全不同的 agent 设计思路目标函数从平台转化率变成了用户长期效用。这篇文章我不打算只评价 TickClip 的理念有多好而是想把它作为一个技术案例来拆解一个能诚实说不要买的购物代理需要哪些模块支撑它的 prompt 和普通购物助手有什么本质区别如果我们要自己做一个最小实现代码应该怎么组织文章最后会给出一个可以直接运行的参考实现并把我认为这类 agent 最容易踩的坑和工程化建议一并说清楚。1. 为什么建议不买的 AI 购物代理值得关注先看一个现象现在几乎所有购物类 agent优化目标都是让用户下单。品牌方看 GMV平台看转化率推荐系统看点击率。整个链路里的每一个环节都在往成交方向推用户。当我们把一个 LLM Agent 接到这个链路里时它也会无意识地继承这种立场因为它的 prompt、工具、评分标准全都围绕如何完成购买来设计。这带来一个结构性问题agent 的立场天然偏向卖家而它服务的却是买家。用户在冲动消费、买错型号、忽略替代品的时候agent 通常会顺着用户的高预期给出一个看起来合理的推荐。你问它这个耳机值不值得买它会拼命找好评、参数亮点、品牌背书然后把结论导向值得买。TickClip 的价值恰恰在于反着做。从标题看它的核心卖点不是帮你买得更快而是帮你判断要不要买。这个差异如果落到技术实现上会产生一系列连锁变化检索方向变了。普通购物 agent 检索的是为什么这个商品好TickClip 这类 agent 需要检索为什么这个商品不该现在买。信息权重变了。差评、历史价格、替代品、需求匹配度这些劝退信号在普通 agent 里是次要信息在这种 agent 里是核心证据。输出形式变了。不再是一个买它的结论而是一个 BUY / WAIT / DONT_BUY 的三分决策并且要求给出可验证的理由。也就是说这事真正值得技术人关注的点不是推荐不买这个产品概念多新鲜而是它代表了购物类 agent 里一种很少见的评估标准这个 agent 不是以成交率衡量好坏而是以用户是否做出了理性决策来衡量好坏。指标一变整个系统设计都会跟着变。2. TickClip 这类 AI 购物代理的核心概念与设计差异2.1 什么是 AI shopping agentAI shopping agent 可以理解为一个能自主完成购物任务的智能体。它通常具备以下能力理解用户模糊的自然语言需求、调用搜索或商品 API 获取信息、做多商品对比、给出购买建议有些还会自动完成下单流程。核心是把逛、找、比、买这个链路尽量自动化。市面上多数实现是把 agent 当高级搜索引擎用用户给需求agent 搜出一堆商品按评分和价格排序推荐一个最高分。这个过程最大的问题是推荐系统的评分依赖的是历史用户行为它不会理解你这个具体的人到底需不需要。一个 4.8 分的商品对你可能毫无价值因为你压根不需要这项功能。2.2 反向推荐与传统购物助手的差异TickClip 式的 agent它的差异不在某个单一功能上而在整条决策链路的立场上。我整理了一个对比表格维度传统购物 agentTickClip 这类反向推荐 agent核心目标完成成交提升转化率帮用户做出理性购买决策检索方向找出商品优点、卖点、促销信息找出负面评价、价格风险、替代品、需求错配信息权重好评与官方参数优先差评、长期评价、实际体验反馈优先结论倾向偏向 BUY给出放心买的话术允许 WAIT 和 DONT_BUY并且不为此道歉成功指标下单率、GMV决策准确率、用户后悔率下降、退货率下降输出设计商品卡片 推荐理由决策动作 置信度 证据链 下单前自查清单可以看到推荐不买不是简单地给商品打个低分而是把 agent 的整个信息处理逻辑反转了。它要求模型主动去寻找不买的理由并且让这些理由足够具体、可验证才能支撑一个反对结论。2.3 为什么普通 LLM 做不到反向推荐有人会说那我在 prompt 里加一句如果商品不好就告诉用户别买不就行了事实上没有那么简单。原因在于大型语言模型的训练语料里购物推荐类内容绝大多数是种草内容模型天然倾向于顺着用户表达输出积极结论。你只加一句可以说不买模型通常会给你一个很别扭的如果……那么不建议但总体来说还是可以尝试的中庸答案。真正需要的是通过 prompt 结构和工具链强迫模型先收集反向证据再基于证据下判断而不是直接让它生成一个不买的理由。这一点我会在第 5 章的代码里演示。3. 反向推荐 agent 的核心模块拆解要做成一个 TickClip 思路的购物 agent光靠一个 LLM 的 prompt 是不够的。从工程上看至少有五个模块需要认真设计。3.1 需求理解模块这个模块负责把用户的模糊需求变成可判断的约束条件。比如我想买个好一点的降噪耳机它要进一步拆解为预算区间是多少、主要使用场景通勤/办公/运动、是否在乎便携性、对降噪强度的要求有多高、是否接受二手、多久之内必须用上。更重要的是它还应该识别伪需求。比如用户说最近心情不好想买个耳机这类需求背后可能是情绪驱动而非功能驱动。反向推荐的 agent 在这种情况下应当给出 WAIT 而非 BUY这是普通购物 agent 完全不会考虑的。3.2 商品信息采集模块这个模块负责获取候选商品的完整信息。至少包括价格、历史价格曲线、评分、评论数量、差评摘要、官方参数、优惠活动。目前公开可用的电商 API 有限很多项目会通过爬虫或第三方比价服务获取数据这块也是合规风险最高的部分。建议优先使用平台官方开放接口或者商用比价 API。3.3 反向证据收集模块这是整个系统最核心的模块。它要做的事情是主动寻找不利于立刻下单的证据。具体包括差评分析从大量中差评里提取重复出现的问题比如品控、售后、发热、噪音。价格风险对比历史价格判断当前是否处于高位。替代品挖掘查找同品牌上一代、竞品同价位产品判断是否有更好的选择。需求匹配度对照用户需求约束检查商品是否存在明显错配。长期成本耗材、维护、生态绑定带来的后续支出。这个模块在技术上可以用一次独立的 LLM 调用来完成也可以做成一个多工具并行的检索流程。关键是它和推荐模块解耦先收集反面证据再让决策模块基于正反两面信息做判断而不是让模型一次性生成又找优点又找缺点的混杂结果。3.4 决策与输出模块决策模块接收正反两面信息输出一个结构化决策。我建议采用三分法BUY现在买是理性的。WAIT需求真实存在但可以等促销、换渠道、等下一代。DONT_BUY不应该买原因是需求不成立或商品质量不值得。输出不能只是一个动作还应该包含置信度、理由列表、下单前自查清单。这个自查清单很重要它把一部分判断责任交还给用户避免 agent 给出错误建议时用户完全没有复核机会。3.5 记录与复盘模块一个负责任的购物 agent 应该记住自己给过的建议。用户三个月前听你的买了某产品后来发现不好用这个反馈如果无法回流agent 就永远学不会。工程上可以用一个简单的历史记录表记录每次建议和后续用户反馈定期重算建议准确率。这也是构建评测集的第一步。4. 环境准备与前置条件下面开始搭建一个最小可运行的参考实现。这个 demo 借鉴 TickClip 的产品思路但代码是我为演示写的并非 TickClip 官方实现。它只解决一个核心问题让读者看到反向证据收集 决策输出这个链路在代码里长什么样。4.1 运行环境操作系统Windows / macOS / Linux 均可Python 版本3.9 及以上依赖openai仅当使用真实模型时需要GPU不需要LLM 调用走 API 或本地 mock4.2 安装步骤建议先创建虚拟环境mkdir tickclip_demo cd tickclip_demo python3 -m venv venv source venv/bin/activate # 如果使用真实模型需要安装 openai SDK pip install openai如果只想先跑通演示流程不需要安装任何第三方依赖因为默认的 mock 模式只用 Python 标准库。4.3 目录结构tickclip_demo/ ├── agent.py # 购物决策 agent 核心逻辑 ├── prompts.py # prompt 模板 ├── mock_llm.py # 无网络 mock 实现 └── run_demo.py # 演示入口5. 完整示例一个 TickClip 思路的购物代理参考实现5.1 Prompt 设计先说结论反向推荐的关键在 prompt 结构不在模型多聪明。如果让模型一次性输出该不该买它很容易打太极。正确做法是拆成两次调用第一次只收集反面证据第二次基于证据做决策。 文件路径: tickclip_demo/prompts.py 这里把找不买的理由拆成了两个独立步骤 1. 反向证据收集让模型主动搜索不利于购买的信号。 2. 决策判断结合正反两面证据输出最终结论。 EVIDENCE_SYSTEM_PROMPT 你是一个购物决策分析助手你的目标不是说服用户购买而是帮助用户避免冲动消费和错误购买。 请基于给定的用户需求与候选商品信息完成两项任务 1. 找出所有不应该立刻购买的证据包括价格风险、质量问题、需求匹配度不足、替代品优势等。 2. 指出当前信息中缺少哪些关键信息例如售后政策、真实评测、长期使用反馈。 要求 - 输出必须是 JSON 对象字段为 negative_evidence 和 missing_info。 - negative_evidence 是字符串数组每一项都必须有依据。 - 不要编造商品页面中不存在的评价如果信息不足请写入 missing_info。 DECISION_SYSTEM_PROMPT 你是一个克制、理性、以用户长期利益为目标的购物决策助手。 你会拿到用户需求、候选商品信息、反向证据。 请从用户角度判断对当前这个商品给出一个动作 - BUY可以购买 - WAIT暂时不要买等待更好的时机、渠道或价格 - DONT_BUY不建议购买 输出必须是 JSON 对象字段 - action: 以上三个字符串之一 - confidence: 0 到 1 之间的浮点数 - reasons: 字符串数组说明判断理由 - checks: 字符串数组列出用户下单前应该自己再确认的事项 注意 - 当反向证据充分时不要为了避免冲突而转向 BUY。 - 优先给出可执行的建议不要只说看情况。 这里有个容易被忽略的设计点第二次决策的输入里不但要有商品信息还必须把第一次收集到的negative_evidence原样传进去。如果省掉这一步模型会退回种草模式因为它的直觉是在帮用户完成购买。5.2 无网络 mock 实现为了让没有 API key 的读者也能立刻跑通流程我写了一个 mock 类。它根据system_prompt判断当前阶段返回一个符合预期格式的 JSON。注意mock 里的证据和理由都是固定写死的目的只是演示链路不代表真实模型输出。 文件路径: tickclip_demo/mock_llm.py 默认的 LLM 实现不依赖外网也可以跑通演示流程。 import json def call_llm_mock(system_prompt: str, user_prompt: str) - str: if 反向证据收集 in system_prompt: return json.dumps( { negative_evidence: [ 该商品在近 3 个月出现过多次价格下调当前价格处于相对高位, 差评区提到品控不稳定存在一定比例一星反馈, 存在同品牌上一代型号功能差异很小而价格低 30%, 用户需求是降噪耳机但该商品主打音质降噪表现一般, ], missing_info: [ 官方保修时长与退换政策, 用户对佩戴舒适度的长期反馈, ], }, ensure_asciiFalse, ) if 决策判断 in system_prompt: return json.dumps( { action: DONT_BUY, confidence: 0.85, reasons: [ 价格处于历史高位且上一代产品可以满足核心需求, 降噪能力与用户核心需求不匹配, 短期内容易出现同价位新款或降价, ], checks: [ 确认是否真的需要降噪耳机还是只是情绪化购物, 对比上一代型号的实际售价与保修政策, 等待一次大促或渠道促销再决策, ], }, ensure_asciiFalse, ) return {}5.3 Agent 核心逻辑Agent 类的核心方法是analyze()它完成了完整的两阶段调用。先收集反面证据再基于证据做决策。为了展示真实场景的接入方式我也写了一个_call_real()方法用 OpenAI 兼容接口调用真实模型。 文件路径: tickclip_demo/agent.py import json import os from typing import List, TypedDict from prompts import EVIDENCE_SYSTEM_PROMPT, DECISION_SYSTEM_PROMPT from mock_llm import call_llm_mock class Product(TypedDict): id: str title: str price: float rating: float review_count: int bad_review_snippets: List[str] alternatives: List[str] class Decision(TypedDict): action: str confidence: float reasons: List[str] checks: List[str] class TickClipLikeAgent: def __init__(self, use_mock: bool True, model: str gpt-4o-mini): self.use_mock use_mock self.model model def analyze(self, user_need: str, product: Product) - Decision: # 第一步收集反向证据 evidence self._collect_negative_evidence(user_need, product) # 第二步生成决策 user_prompt self._build_decision_prompt(user_need, product, evidence) raw self._call(DECISION_SYSTEM_PROMPT, user_prompt) return json.loads(raw) def _collect_negative_evidence(self, user_need: str, product: Product) - dict: product_text json.dumps(product, ensure_asciiFalse, indent2) user_prompt f用户需求{user_need}\n\n候选商品信息\n{product_text} raw self._call(EVIDENCE_SYSTEM_PROMPT, user_prompt) return json.loads(raw) def _build_decision_prompt( self, user_need: str, product: Product, evidence: dict ) - str: return ( f用户需求{user_need}\n\n f候选商品信息\n{json.dumps(product, ensure_asciiFalse, indent2)}\n\n f反向证据必须认真对待\n{json.dumps(evidence, ensure_asciiFalse, indent2)} ) def _call(self, system_prompt: str, user_prompt: str) - str: if self.use_mock: return call_llm_mock(system_prompt, user_prompt) return self._call_real(system_prompt, user_prompt) def _call_real(self, system_prompt: str, user_prompt: str) - str: from openai import OpenAI client OpenAI(api_keyos.environ.get(OPENAI_API_KEY)) resp client.chat.completions.create( modelself.model, messages[ {role: system, content: system_prompt}, {role: user, content: user_prompt}, ], temperature0.2, ) return resp.choices[0].message.content这里值得注意的设计是_build_decision_prompt()这个方法。它把商品信息和反向证据放进同一个 user prompt 里但没有把正面的商品优点单独包装成一段很长的说服性文本。这样可以避免模型被商品厂商的描述带偏。如果你在真实项目里接入商品详情页的 HTML也应该先抽取出关键字段再传给模型而不是把整页内容都塞进去。5.4 运行入口 文件路径: tickclip_demo/run_demo.py import json from agent import TickClipLikeAgent def main(): user_need 我每天通勤两小时想买一款降噪耳机预算 1500 到 2500 元 product: Product { id: P001, title: 某品牌旗舰款头戴式降噪耳机 HX-2000, price: 2399, rating: 4.6, review_count: 12800, bad_review_snippets: [ 用了一个月出现右耳电流声, 降噪开满之后有轻微底噪, 戴久了夹头, ], alternatives: [ 上一代 HX-1000价格 1699降噪能力接近, 竞品 QC-Ultra价格 1899佩戴更舒适, ], } agent TickClipLikeAgent(use_mockTrue, modelgpt-4o-mini) decision agent.analyze(user_need, product) print( * 60) print(TickClip 思路的购物决策结果) print( * 60) print(json.dumps(decision, ensure_asciiFalse, indent2)) if __name__ __main__: main()在run_demo.py里我把用户需求和商品信息都写死成了演示数据。真实项目中用户需求应该由对话模块产生商品信息应该来自比价 API 或商品数据库。这里的重点是让你看清调用关系。6. 运行结果与效果验证运行演示cd tickclip_demo # 有虚拟环境时先激活 source venv/bin/activate python run_demo.py预期输出如下{ action: DONT_BUY, confidence: 0.85, reasons: [ 价格处于历史高位且上一代产品可以满足核心需求, 降噪能力与用户核心需求不匹配, 短期内容易出现同价位新款或降价 ], checks: [ 确认是否真的需要降噪耳机还是只是情绪化购物, 对比上一代型号的实际售价与保修政策, 等待一次大促或渠道促销再决策 ] }怎么判断这个结果是否有效我建议从三个角度观察输出格式是否合法。action是否在三个枚举值内confidence是否为 0 到 1 的浮点数reasons和checks是否都是字符串数组。证据是否支撑结论。如果 action 是 DONT_BUY给定的 reasons 是否引用到了具体信息比如价格、差评、替代品。如果理由全是感觉一般不太推荐这种空话说明 prompt 结构需要加强。是否提供了可执行的下一步。好的反向推荐不应该只说No它还要告诉用户怎么做是等促销、换型号还是彻底放弃。运行失败时第一步要看的是json.loads()是否报错。真实模型经常输出非 JSON 内容比如代码块标记、前后多出的文字这在第 7 章会详细说。Mock 模式基本不会失败如果 mock 都报错先检查 Python 版本和文件目录结构。7. 常见问题与排查思路问题现象可能原因排查方式解决方案json.loads()报错LLM 返回的内容无法解析模型输出了多余文字或代码块标记打印原始raw内容观察前后缀在 prompt 中要求只输出 JSON增加输出清理函数去除 json 和前后空白真实模型几乎永远不会给出 DONT_BUY模型的推荐立场仍然偏向成交检查是否把negative_evidence真正传入了决策 prompt将反向证据作为决策 prompt 的强制输入降低 temperature必要时用 few-shot 示例展示 DONT_BUY 样本结论过于保守全部输出 WAIT模型为了安全倾向不表态查看每个 WAIT 的理由是否具体评估评测集里 WAIT 占比在 prompt 中说明当证据充分时应给出明确 BUY 或 DONT_BUY增加置信度阈值判断mock 模式正常切到真实模型后效果差很多mock 的固定输出掩盖了 prompt 缺陷单独测试证据收集阶段的输出质量先跑 10 个真实商品样本人工检查negative_evidence的覆盖率再调决策 prompt商品信息过多API 成本高商品详情页全文被直接塞入 prompt检查传入内容是否包含无关字段只保留商品标题、价格、评分、差评摘要、替代品等结构化字段做截断或向量检索无法判断模型给出的理由是否真实模型幻觉编造降价 30%这类事实将理由中的事实性陈述与商品数据做字符串匹配或人工抽检要求模型引用输入中的具体字段对没把握的信息允许写入missing_info这里我想重点强调最后一个问题幻觉。购物决策 agent 一旦编造理由危害比普通聊天助手大得多。用户可能因为一个虚构的历史低价放弃购买也可能因为一个虚构的差评错过好商品。工程上最有效的缓解手段是让模型只基于输入信息做判断并明确允许它说信息不足。不要在 prompt 里要求模型自行判断市场行情。如果你想让模型参考历史价格就把历史价格数据喂给它而不是让它凭记忆编。8. 工程化的最佳实践与建议8.1 建立自己的评测集购物决策是个开放问题别指望靠感觉调优。建议你从第一天开始就积累评测集。每个评测样本包含用户需求描述、候选商品结构化信息、标准答案BUY/WAIT/DONT_BUY以及理由里的关键事实点。最少先做 30 条覆盖三类动作、不同商品类目和不同价格区间。后续所有 prompt 改动都跑一遍评测看三类动作的准确率变化而不是只看几个手工案例。8.2 对真实 LLM 输出做防御式解析真实模型的输出不可控所以解析层一定要做加固。建议你封装一个safe_parse_json()函数去除输出中的 json 代码块标记。找到第一个{和最后一个}截取 JSON 子串。解析失败时自动把异常信息和原始输出返回方便排查。对action字段做枚举校验不符合时降级为WAIT并记录日志。这类防御代码看起来不起眼但在生产环境里能避免大量线上故障。8.3 数据源与合规边界构建这类 agent最大的工程风险不在模型而在商品数据。直接爬取电商平台页面可能违反平台条款也存在封号风险。更稳妥的做法是使用平台官方开放 API或接入有授权的比价服务。即便拿到数据也要注意价格历史数据要标注统计口径比如近 90 天自营渠道价格区间。用户购物数据属于敏感信息不要长期保存超过必要的范围。agent 如果具备自动下单能力务必设置最低人工确认门槛比如金额超过 500 元必须用户二次确认。8.4 输出可解释性优先TickClip 这类产品想要建立用户信任可解释性比准确性更早暴露问题。我给用户的每个决策都包含reasons和checks这不是为了好看而是为了让用户可以反驳 agent。如果用户发现理由中有任何一条与事实不符他要么撤销决策要么对 agent 失去信任。所以在 prompt 里尽量减少宏大判断比如市场趋势下滑竞品全面碾压这种没有数据支撑的表述而要多输出该商品近 3 个月的公开降价记录显示用户需求与商品主打功能不匹配这种可验证的内容。8.5 用缓存降低 API 成本购物数据相对稳定同一个商品短时间内不会频繁变化。可以对同一商品 ID 的决策结果做缓存比如 12 小时有效。只有当价格、评分等重要字段发生变化时才重新调用模型。搜索结果的缓存也要考虑避免用户每次问同一个问题都产生多次 LLM 调用。9. 总结与后续实践方向TickClip 这个项目的出现给 AI 购物 agent 提供了一个稀缺的视角购物助手不一定只能帮用户买它还可以帮用户不买。从技术实现上看这件事并不复杂核心就是两段式 prompt 结构加一个反向证据优先的决策逻辑但它背后代表的产品立场会直接影响 agent 的目标函数、数据采集方式和评测体系。如果你打算自己动手做一个类似的东西我建议按下面的顺序推进先跑通本文的参考实现把 mock 换成真实模型观察输出差异。然后找一个你熟悉的商品类目手动构造 10 条评测数据单独测证据收集阶段的质量。接着把商品数据从写死字典改为接一个真实的比价 API处理字段缺失和价格波动。最后再考虑加缓存、历史记录和用户反馈回流。对于 TickClip 这类产品它最终能走多远取决于一个问题当用户真的因为 agent 的劝阻而省下一笔钱时这个 agent 如何证明自己的价值。这比任何推荐算法都更难量化但也正是这个方向最值得做的原因。建议收藏这篇文章后面搭建自己的购物决策 agent 时可以直接复用其中的 prompt 和代码结构。
返回列表