FEATURED · 精选文章

如何用Function Calling构建一个会劝你别买的AI购物Agent

发布时间 / 2026/8/29 8:25:02
来源 / 创域科博编辑部
栏目 / 资讯中心
如何用Function Calling构建一个会劝你别买的AI购物Agent TickClip一个会劝你别买的 AI 购物 Agent 是如何设计出来的最近在 Hacker News 上看到一个很有意思的项目叫 TickClip它的定位是“AI shopping agent that can recommend not buying”——也就是说这个 AI 购物助手会反过来劝你不要下单。在如今“AI 带货”“AI 一键成片营销系统”被反复炒作的环境下这种反方向的产品设计反而让人眼前一亮。作为开发者比起“它为什么会火”我更关注的是它背后的技术实现一个 shopping agent 要完成从理解用户需求、检索商品、对比参数到最后输出“买”或“不买”结论中间要经过哪些环节为什么 Agent 技术适合做这件事如果我们要自己实现一个简化版的 TickClip核心代码应该怎么写这篇文章会围绕这些问题展开尽量把概念、思路、代码和工程坑都讲清楚。适合对 AI Agent 开发感兴趣的开发者阅读也适合想用 LLM 做垂直应用的产品经理和技术负责人参考。1. 背景与核心概念1.1 什么是 shopping agentShopping agent 是 AI Agent 在电商消费场景下的一种具体形态。它不是一个简单的聊天机器人而是一套能够完成“理解需求 → 检索信息 → 对比分析 → 给出建议”的自动化系统。传统购物助手通常做的是“帮用户找到更便宜的商品”“推荐销量最高的产品”。这类系统的逻辑是用户只要输入商品关键词系统就返回一堆商品列表然后用户自己再做对比。而 shopping agent 的逻辑不同它具备更强的自主性和推理能力。Agent 可以理解用户模糊的需求描述比如“想买一双通勤穿的跑鞋预算 500 以内不要太重”。调用外部工具获取实时商品信息包括价格、评价、参数、库存。根据用户的预算、使用场景、历史偏好做综合推理。最终输出一个可解释的推荐结论比如“可以买哪款”“不建议买哪款”“现在不建议买原因是 618 大促马上开始”。从这个角度看shopping agent 本质上是“大语言模型 工具调用 决策引擎”的组合产品。1.2 TickClip 的差异化定位TickClip 最有意思的地方是它把“推荐不买”做成了一个核心能力而不是一个例外处理。这样做的好处非常明显第一它天然增加了用户信任。如果一个 AI 只会说“买买买”那它本质上跟广告投放系统没有区别。但当 AI 在某些场景下真诚地告诉用户“这个东西不适合你别买”用户会更容易相信它在其他场景下的推荐。第二它规避了利益冲突。很多购物推荐应用背后都有佣金分成所以推荐的可信度存疑。TickClip 把“不推荐购买”作为产品主张等于在用户心智中建立了一个“中立第三方”的角色。第三它引导用户进入更理性的消费决策。这对减少冲动消费、提升消费质量有实际帮助也是这个方向最容易被用户感知的价值点。1.3 开发 TickClip 这类 Agent 的关键技术点从技术角度拆解TickClip 至少要覆盖以下关键环节用户意图理解判断用户是“确定了要买”还是“在犹豫要不要买”。上下文管理在多轮对话中维护预算、品牌偏好、使用场景等信息。工具调用通过搜索 API、商品 API 获取实时数据。商品分析对商品价格、评分、功能参数做结构化处理。决策推理综合所有信息生成“买/不买/等一等”的结论并给出理由。风险控制避免模型幻觉、避免推荐过期或虚假商品信息、保护用户隐私。接下来我们用一个简化版项目来演示这些能力是怎么落地的。2. 环境准备与基础架构设计2.1 环境与依赖版本说明本文的示例使用 Python 开发建议环境如下Python 3.10 及以上版本。操作系统Windows / macOS / Linux 均可。LLM 接口使用支持 OpenAI Function Calling 格式的 API 服务。环境变量管理使用python-dotenv。建议先创建一个独立的虚拟环境python -m venv venv source venv/bin/activate # Windows 下使用 venv\Scripts\activate安装依赖pip install openai python-dotenv需要注意OpenAI SDK 更新非常频繁不同版本的接口参数可能略有差异。本文示例以常见写法为主实际使用时请根据你安装的 SDK 版本查阅对应文档。2.2 系统整体架构我们先不追求做一个生产级系统而是聚焦在 Agent 的最小可运行闭环上。简化版 TickClip 的架构可以拆成这几个模块用户输入 ↓ 意图识别模块LLM Prompt ↓ 商品检索模块模拟数据或真实 API ↓ 商品分析模块结构化打分 ↓ 决策推理模块LLM 评分 规则 ↓ 输出建议买 / 不买 / 观望这种分层设计的好处是即使 LLM 判断失误规则和评分模块还能兜底即使 API 数据延迟系统也能做降级处理。2.3 数据层设计实战示例中我们使用模拟商品数据便于演示核心逻辑。真实项目中这里可以对接淘宝开放平台、京东联盟、亚马逊 Product Advertising API 等商品数据源。模拟商品数据结构如下{ id: P001, name: 某品牌轻量跑鞋, price: 459.0, category: 跑鞋, rating: 4.6, review_count: 12340, features: [重量210g, 缓震, 透气], cons: [鞋码偏小, 不耐脏] }这里增加cons字段是一个很重要的设计。很多商品数据源只提供正向卖点但 Agent 要做出“不推荐买”的判断就必须能获取商品的负面信息。真实系统中cons可以通过解析低分评论得到。3. 核心模块原理与实现3.1 工具定义让 LLM 具备商品检索能力在 Function Calling 模式下我们先定义两个工具search_products(query)根据关键词检索商品。get_product_detail(product_id)获取商品详细信息。这是 Agent 与外部世界交互的接口你可以理解为 Agent 的“手”和“眼睛”。import json tools [ { type: function, function: { name: search_products, description: 根据用户描述的关键词检索符合条件的商品列表, parameters: { type: object, properties: { query: { type: string, description: 商品搜索关键词例如通勤跑鞋 500元以内 }, max_price: { type: number, description: 价格上限单位为元 } }, required: [query] } } }, { type: function, function: { name: get_product_detail, description: 获取指定商品的详细参数、用户评价和优缺点, parameters: { type: object, properties: { product_id: { type: string, description: 商品 ID } }, required: [product_id] } } } ]这里的关键点是每个工具函数的description要写得足够清楚LLM 才能准确判断什么时候调用哪个工具。很多 Agent 项目效果不好问题往往不是模型不行而是工具描述写得含糊。3.2 商品检索与模拟数据为了演示完整流程我们准备一个简单的商品数据库。在实际项目中这里的逻辑可以替换成调用真实电商 API。import json import random from typing import Dict, List PRODUCT_DB [ { id: P001, name: 轻量缓震跑鞋, price: 459.0, category: 跑鞋, rating: 4.6, review_count: 12340, features: [重量210g, 缓震, 透气网面], cons: [鞋码偏小, 浅色不耐脏] }, { id: P002, name: 经典全能跑鞋, price: 899.0, category: 跑鞋, rating: 4.8, review_count: 8670, features: [碳板, 回弹好, 适合马拉松], cons: [价格偏高, 不适合日常通勤] }, { id: P003, name: 轻便通勤鞋, price: 329.0, category: 通勤鞋, rating: 4.3, review_count: 2300, features: [轻量, 防滑, 易穿脱], cons: [鞋底偏薄, 减震一般] }, { id: P004, name: 高端全掌缓震鞋, price: 1299.0, category: 跑鞋, rating: 4.7, review_count: 5600, features: [全掌缓震, 透气, 支撑好], cons: [价格高, 重量偏重] } ] def search_products(query: str, max_price: float None) - List[Dict]: 模拟商品检索。真实项目中这里会调用电商搜索 API。 query_lower query.lower() result [] for product in PRODUCT_DB: if query_lower and query_lower not in product[name].lower() and query_lower not in product[category].lower(): continue if max_price is not None and product[price] max_price: continue result.append(product) return result def get_product_detail(product_id: str) - Dict: 模拟获取商品详情。真实项目中这里会调用商品详情 API。 for product in PRODUCT_DB: if product[id] product_id: return product return {}这里有一个值得注意的地方模拟检索函数内部通过query_lower not in product[name].lower()判断关键词是否匹配。这种简单匹配方式在真实场景中是不够用的生产系统应当使用搜索引擎或向量检索。但在最小示例中它能让我们把精力集中在 Agent 调用链路上。3.3 商品评分模型为了让“不买”的决策更有依据我们设计一个简单的评分函数。它的作用是把商品的结构化信息转化为一个可比较的分数。def score_product(product: Dict, budget: float) - float: 对商品进行综合评分分数越高表示越值得购买。 评分规则是基础规则真实项目中可以替换为更复杂的模型。 score 50.0 # 价格合理性预算内加分超预算大幅减分 if product[price] budget: score 20 else: score - 40 # 评分4.5 以上加分 if product[rating] 4.5: score 10 elif product[rating] 4.0: score 5 else: score - 5 # 评价数量超过 3000 说明是热门商品 if product[review_count] 3000: score 5 # 负面信息每条明显负面信息扣分 cons_count len(product.get(cons, [])) score - cons_count * 5 return round(min(100, max(0, score)), 1)这个评分函数的逻辑并不复杂但它体现了 Agent 决策中一个很重要的原则把 LLM 的“推理”和规则引擎的“计算”结合起来。LLM 负责理解语义和生成解释评分函数负责提供稳定的量化依据。如果只依赖 LLM 做决策同样的商品在不同 Prompt 下可能得到完全不同的结论。但如果只依赖规则引擎系统又无法理解用户“通勤穿”“不想太招摇”这类复杂语义。两者结合才是合理的工程方案。3.4 决策与回复生成拿到商品评分后我们设计一个规则明显超预算、评分低、负面信息多、没有明显优势的商品会被判定为“不建议购买”。def make_recommendation(product: Dict, budget: float) - Dict: 根据商品数据和评分生成推荐结论。 结论分为三个类型buy / not_buy / wait score score_product(product, budget) if product[price] budget * 1.2: decision not_buy reason 价格超出预算较多从理性消费角度不建议购买 elif score 70: decision buy reason 商品在预算范围内评分和口碑较好整体表现均衡 elif score 55: decision wait reason 商品有亮点但存在明显短板建议继续观望或对比其他商品 else: decision not_buy reason 商品综合表现一般负面评价较多不建议购买 return { product_id: product[id], product_name: product[name], price: product[price], score: score, decision: decision, reason: reason }这里把决策分为三种类型buy推荐购买。not_buy明确不推荐。wait建议观望。引入wait是很有必要的。很多时候商品本身不差但当前不是最佳购买时机。例如临近大促、价格波动大、新品马上发布这些都属于“等待”理由。4. 完整实战实现一个简化版 TickClip4.1 项目结构我们按下面的结构组织代码tickclip-demo/ ├── main.py # 入口程序负责与 LLM 交互 ├── tools.py # 工具定义、商品数据库、评分逻辑 ├── prompt.py # Prompt 模板 └── .env # 环境变量配置4.2 工具模块tools.py我们把工具、商品数据和评分逻辑放在tools.py中方便入口程序调用。完整代码如下# 文件路径tickclip-demo/tools.py from typing import Dict, List # 模拟商品数据库 PRODUCT_DB [ { id: P001, name: 轻量缓震跑鞋, price: 459.0, category: 跑鞋, rating: 4.6, review_count: 12340, features: [重量210g, 缓震, 透气网面], cons: [鞋码偏小, 浅色不耐脏] }, { id: P002, name: 经典全能跑鞋, price: 899.0, category: 跑鞋, rating: 4.8, review_count: 8670, features: [碳板, 回弹好, 适合马拉松], cons: [价格偏高, 不适合日常通勤] }, { id: P003, name: 轻便通勤鞋, price: 329.0, category: 通勤鞋, rating: 4.3, review_count: 2300, features: [轻量, 防滑, 易穿脱], cons: [鞋底偏薄, 减震一般] }, { id: P004, name: 高端全掌缓震鞋, price: 1299.0, category: 跑鞋, rating: 4.7, review_count: 5600, features: [全掌缓震, 透气, 支撑好], cons: [价格高, 重量偏重] } ] # 工具定义用于 Function Calling TOOLS [...] def search_products(query: str, max_price: float None) - List[Dict]: query_lower query.lower() result [] for product in PRODUCT_DB: name_match query_lower in product[name].lower() category_match query_lower in product[category].lower() if query_lower and not name_match and not category_match: continue if max_price is not None and product[price] max_price: continue result.append(product) return result def get_product_detail(product_id: str) - Dict: for product in PRODUCT_DB: if product[id] product_id: return product return {} def score_product(product: Dict, budget: float) - float: score 50.0 if product[price] budget: score 20 else: score - 40 if product[rating] 4.5: score 10 elif product[rating] 4.0: score 5 else: score - 5 if product[review_count] 3000: score 5 cons_count len(product.get(cons, [])) score - cons_count * 5 return round(min(100, max(0, score)), 1) def make_recommendation(product: Dict, budget: float) - Dict: score score_product(product, budget) if product[price] budget * 1.2: decision not_buy reason 价格超出预算较多从理性消费角度不建议购买 elif score 70: decision buy reason 商品在预算范围内评分和口碑较好整体表现均衡 elif score 55: decision wait reason 商品有亮点但存在明显短板建议继续观望或对比其他商品 else: decision not_buy reason 商品综合表现一般负面评价较多不建议购买 return { product_id: product[id], product_name: product[name], price: product[price], score: score, decision: decision, reason: reason }注意上面的TOOLS列表内容与第 3.1 节一致在开发中你需要把完整的tools定义复制进去。这里不再重复占用篇幅。4.3 Prompt 模板prompt.pyPrompt 是 Agent 行为风格的关键。为了让 LLM 输出更贴近 TickClip 的中立理性风格我们设计如下系统提示词。# 文件路径tickclip-demo/prompt.py SYSTEM_PROMPT 你是一个理性、中立的 AI 购物助手。你的目标不是诱导用户消费而是帮助用户做出最合适的购买决策。 你在回答时必须遵循以下原则 1. 当商品不适合用户需求、价格不合理、存在明显缺陷时要明确告诉用户不要购买。 2. 你很擅长给出“观望一段时间”的建议尤其是商品价格波动大、新品即将发布时。 3. 你的回复必须基于工具返回的真实商品数据不能编造商品参数或评价。 4. 你的回复要给出明确的结论并附上简短的决策理由。 5. 如果用户需求不够明确先追问用户的使用场景和预算不要急着推荐。 请记住用户信任你是因为你敢说“这不值得买”而不是因为你总是说“买它”。 这个 Prompt 看似简单实际上定义了 Agent 的“人设”和“边界”是区分 Agent 与普通聊天机器人的关键。4.4 入口程序main.py入口程序负责与 LLM API 交互执行tool_calls并组装最终回复。# 文件路径tickclip-demo/main.py import json import os from dotenv import load_dotenv from openai import OpenAI from prompt import SYSTEM_PROMPT from tools import ( TOOLS, make_recommendation, search_products, get_product_detail, ) load_dotenv() client OpenAI( api_keyos.getenv(OPENAI_API_KEY), base_urlos.getenv(OPENAI_BASE_URL), ) def run_agent(user_input: str): messages [ {role: system, content: SYSTEM_PROMPT}, {role: user, content: user_input}, ] # 第一轮调用让模型判断是否需要调用工具 response client.chat.completions.create( modelos.getenv(OPENAI_MODEL, gpt-4o-mini), messagesmessages, toolsTOOLS, tool_choiceauto, ) message response.choices[0].message # 追加模型响应到消息历史 messages.append(message) # 如果模型调用了工具执行工具并返回结果 if message.tool_calls: for tool_call in message.tool_calls: function_name tool_call.function.name arguments json.loads(tool_call.function.arguments) if function_name search_products: products search_products( queryarguments.get(query, ), max_pricearguments.get(max_price), ) # 生成可读结果返回给模型 result_text json.dumps(products, ensure_asciiFalse, indent2) elif function_name get_product_detail: product get_product_detail(arguments.get(product_id, )) result_text json.dumps(product, ensure_asciiFalse, indent2) else: result_text json.dumps({error: 未知工具}) messages.append({ role: tool, tool_call_id: tool_call.id, content: result_text, }) # 第二轮调用模型基于工具结果生成最终回复 second_response client.chat.completions.create( modelos.getenv(OPENAI_MODEL, gpt-4o-mini), messagesmessages, toolsTOOLS, ) return second_response.choices[0].message.content # 如果模型没有调用工具直接返回回复内容 return message.content if __name__ __main__: test_input 想买一双通勤跑鞋预算 500 左右平时走路比较多偶尔跑步 result run_agent(test_input) print(result)4.5 运行与预期结果在.env文件中配置 API Key 和模型参数OPENAI_API_KEY你的_API_Key OPENAI_BASE_URLhttps://api.openai.com/v1 OPENAI_MODELgpt-4o-mini运行程序python main.py预期结果是模型先调用search_products检索商品再根据返回的商品数据生成推荐结论。例如模型可能输出这样一段回复根据你的需求我筛选了预算 500 元以内的通勤跑鞋。比较符合条件的是「轻量缓震跑鞋」459 元它重量轻、透气性好适合日常走路和偶尔跑步。 但我也要提醒你几个问题 1. 这款鞋的尺码偏小建议买大半码。 2. 浅色款不耐脏日常通勤可能需要更频繁打理。 3. 目前没有明显的价格优惠可以观望一下近期是否有活动。 综合来看如果你不着急穿可以再等等如果急需可以选择这款但注意尺码问题。如果模型能生成这样的回复说明完整链路已经跑通。接下来需要做的就是围绕产品化做更细的打磨。5. 常见问题与排查思路5.1 模型没有触发工具调用问题现象常见原因解决思路模型直接回答没有调用search_productsPrompt 没有明确告知模型具备工具能力在系统 Prompt 中加入“你可以调用商品检索工具获取实时数据”的说明工具描述过于模糊LLM 无法判断何时调用工具重写工具描述补充触发条件和参数说明模型版本不支持 Function Calling使用的是老版本模型或不支持工具调用的模型更换支持工具调用的模型例如 GPT-4o、Claude 等5.2 工具返回数据被模型编造这是 Agent 开发中最常见也最危险的问题。具体表现是模型没有等待工具返回就直接编造商品价格和参数。解决方案在 Prompt 中强调“禁止编造商品数据所有数据必须来自工具返回结果”。在后端做数据校验如果回复中出现了数据库中不存在的价格或评分拦截并重新生成。设计“先工具、后回答”的强制流程通过代码控制不让模型在没有工具结果时有最终发言权。5.3 多轮对话上下文丢失在简单实现中每一轮用户输入都是独立处理的模型不记得用户之前说过“预算 500”或“不要黑色的”。要解决这个问题需要引入会话记忆session_messages [] def run_agent_with_memory(user_input: str): global session_messages if not session_messages: session_messages.append({role: system, content: SYSTEM_PROMPT}) session_messages.append({role: user, content: user_input}) # 后续逻辑与 run_agent 类似只是使用 session_messages ...建议在项目中引入 Redis 或数据库保存会话状态并使用向量数据库实现长短期记忆这样 Agent 才能记住用户的偏好和历史行为。5.4 Function Calling 参数格式错误有时候模型生成的工具参数是一个 JSON 字符串但缺少某个必填字段。代码中需要做防御性解析arguments json.loads(tool_call.function.arguments) query arguments.get(query, ) max_price arguments.get(max_price)如果arguments本身不是合法 JSON程序会直接报错。建议加一个异常处理try: arguments json.loads(tool_call.function.arguments) except json.JSONDecodeError: arguments {}6. 最佳实践与工程建议6.1 从“工具调用”逐步进化到完整 Agent本文演示的是 Function Calling 模式这是 Agent 的初级形态。生产级 shopping agent 通常还需要Plan-and-Execute 架构先制定整体计划再按步骤调用工具。ReAct 模式让模型在“思考”和“行动”之间循环直到得出可靠结论。人工介入选项当 Agent 判断存在高风险决策时转交人工客服确认。6.2 数据真实性与及时性作为一个推荐“不买”的 Agent数据可信度是产品生命线。如果 Agent 推荐说“现在价格偏高建议等待”但实际价格已经降到历史最低用户就会失去信任。工程上建议缓存策略商品价格和库存数据设置合理的 TTL不能长期使用过期数据。数据来源标注在回复中明确标注“数据更新于 xx 分钟前”增强透明度。多数据源交叉验证对于高客单价商品建议同时拉取多个数据源交叉对比价格和库存。6.3 决策可解释性TickClip 这类产品的核心竞争力是“让用户理解 AI 为什么给出这个建议”。可解释性设计包括输出评分体系让用户看到综合评估过程和权重。用列表展示优点和缺点而不是只给一个结论。在用户追问时允许 Agent 解释“不推荐购买”的具体判断依据。实现方式很简单在工具返回中增加一个explain字段让模型基于结构化信息生成解释而不是凭空发挥。6.4 避免偏见与虚假说服购物 Agent 最需要注意的是不能为了“显示理性”而故意不推荐用户真正需要的商品。这本质上是一种新形式的偏见。工程干预手段在评分函数中加入“需求匹配度”指标如果商品与用户需求高度匹配即使有瑕疵也应该推荐购买。定期回测用历史数据验证 Agent 的推荐是否与用户真实满意度一致。用户反馈闭环在推荐结果上增加“有帮助/没有帮助”按钮采集反馈数据来优化 Prompt 和评分函数。6.5 部署与成本控制生产环境部署 shopping agent 时需要重点考虑Token 成本Function Calling 会重复发送工具定义增加 Token 消耗建议用缓存或减少工具数量来控制。响应延迟一次 Agent 调用链可能包含 2 到 3 次 LLM 请求耗时可能超过 5 秒建议使用流式输出提升体验。限流与降级当外部商品 API 不可用时应返回缓存数据或提示用户稍后再试而不是让模型编造结果。7. 总结与学习路线通过这个简化版 TickClip我们完整走了一遍 AI shopping agent 的最小闭环用 Function Calling 让 LLM 调用商品检索工具获取真实数据。用规则评分模型对商品的价格、评分、口碑做量化分析。用决策规则生成“买 / 不买 / 观望”三种结论。用系统 Prompt 约束 Agent 的行为边界让“不推荐购买”成为产品能力而非模型随机行为。这里面最核心的工程经验是不要把决策完全交给 LLM而是让 LLM 负责语义理解和回复生成用规则引擎和结构化数据负责稳定决策。这样才能构建用户可信赖的 Agent 应用。如果你想在这个方向上继续深入建议按下面路线学习第一步熟悉 Function Calling 和 Tool Use掌握工具定义、参数解析、结果回传。第二步学习 ReAct 和 Plan-and-Execute 模式理解 Agent 的多轮决策循环。第三步研究 GraphRAG 与向量检索让 Agent 能够基于用户历史行为做个性化推荐。第四步把系统接入真实电商平台 API处理鉴权、限频、数据清洗和异常降级。第五步建立评测集对 Agent 的推荐准确率、回复质量和安全性做自动化测评。AI shopping agent 这个方向最近热度很高但真正能打的产品一定是在“可靠数据”和“可解释决策”这些基础设施层面下足功夫。希望这篇文章能帮你把思路理清动手写出自己的第一个 Agent 应用。如果后面打算落地到生产环境建议先从细分品类和垂直场景做起比如只做“跑鞋推荐”或“数码产品价值判断”再逐步扩大覆盖面。
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻