☰
电商AI营销助手落地实践:函数调用让大模型从聊天到办事
2026/10/20 5:01:29 网站建设 项目流程

最近在帮一家电商团队落地“AI营销助手”项目,前后折腾了两个月。回顾整个过程,最值得记录的并不是Prompt调优,而是把函数调用(Function Calling)真正塞进电商营销链路的那段经历。AI原生应用看起来很美,但一落到“查实时价格、发优惠券、核对库存”这种要求不能出错的场景,函数调用几乎成了唯一靠谱的解法。这篇文章就把这段实践从头到尾拆开,讲清楚函数调用解决什么问题、函数怎么设计、调用链路怎么搭、上线后踩了哪些坑。

1. 从一次促销活动说起:为什么电商营销需要函数调用

1.1 传统电商营销系统的一个典型断点

想象一下大促期间的客服场景:用户问“我这张券能买什么?”,传统客服机器人先做意图识别,再匹配FAQ,回答往往是“请点击链接查看”。用户追问“那帮我领一张满200减100的券”,机器人又回到固定脚本,判断不出当前用户是否已领过、券是否还有库存。

问题不在自然语言理解,而在于对话系统无法安全地操作业务系统。查询优惠券、发券、核销、查询库存这些动作,传统方案要么写成硬编码规则,要么让人工介入。规则写多了,意图分支爆炸;人工介入多了,成本压不住。

这时候AI原生应用给出一个新思路:让大模型负责理解用户意图、生成回答,但所有关键动作都通过“函数调用”交还给业务系统执行。模型只负责说“该调用什么函数、传什么参数”,真正的事务操作由后端代码完成。

1.2 函数调用让大模型从“聊天”变成“办事”

一句话理解函数调用:把后端能力包装成一个个函数,告诉大模型这些函数的存在、参数和功能描述;当用户表达的需求命中某个函数时,模型不直接给出最终答案,而是返回一段结构化结果,声明“我想调用 get_coupon_list,参数是 userId=12345”。程序拿到这个结果后真正去执行函数,再把执行结果回填给模型,让模型基于真实数据继续回答。

这个机制的微妙之处在于,模型不再“编造”优惠券、库存、价格,而变成了一个会安排工作的调度员。业务数据、事务操作、权限控制都留在可控的后端系统里,模型只做选择与组织语言。

在电商营销场景里,这个特性尤其重要。价格、库存、券状态是强事实数据,让模型凭训练知识回答必然出错。函数调用把“事实”的获取方式从“记忆”切换成了“查询”,这是整个应用能落地的最核心原因。

2. 函数调用的核心机制:模型、工具、上下文的三角配合

2.1 什么是函数调用,它解决了什么问题

函数调用是模型接口提供的一种工具调用能力。从表面看,它只是把函数的名称、参数结构发给模型,由模型决定是否调用、传什么参数。

更深一层看,它把“对话系统”拆成了三个角色:

  • 模型:负责理解意图、选择工具、组织语言。
  • 函数:负责访问数据、执行操作、返回事实。
  • 上下文:负责在模型与函数之间传递结果,让模型“看到”执行后的真实状态。

举个例子,用户说“还有哪些商品在打折?”如果只靠模型,它可能凭记忆说出几个品牌名,这在电商场景里是不可接受的。接入函数调用后,模型会先调用“查询促销商品列表”,拿到真实活动数据,再基于这些数据做筛选和总结。

函数调用解决的并不是“让模型更聪明”,而是“让模型在需要事实和操作时不自作主张”。它划定了模型的权限边界:可以自由措辞,但不能随意决定库存和券数量。

2.2 一套完整调用链路的四个关键要素

实际落地一个函数调用项目,至少要拆出四个环节:

第一个是函数定义。每个函数需要给模型提供名称、描述、参数结构(JSON Schema)、是否必须等元信息。描述写得越接近用户口语,模型选对函数的概率越高。

第二个是模型决策。请求里带上用户消息和函数列表,模型内部经过推理后,要么返回普通文本,要么返回函数调用请求(包括函数名和参数)。

第三个是运行时执行。程序识别到函数调用请求后,负责解析参数、鉴权、执行后端函数、捕获异常,并把结果封装成一条“工具消息”。

第四个是上下文回填。把工具消息追加到历史对话里,再次调用模型,让模型基于函数结果生成最终回复。这一步不能省,否则模型不知道函数执行成功还是失败。

四个要素缺一个,函数调用都不成立。尤其第四个,很多人第一次做时拿到函数调用结果就直接拼字符串返回,导致上下文里没有工具消息,模型对后续追问完全断片。

2.3 选型考量:什么时候用函数调用,什么时候别硬上

函数调用有很强的适用边界。只做静态知识问答时,比如“这个商品怎么退换货”,如果政策稳定,用普通RAG(检索增强生成)或者FAQ效果更好,没必要让模型去调函数。

只有满足下面任一条件时,函数调用才值得上:

  • 需要实时数据(价格、库存、券数量)
  • 需要执行操作(发券、核销、创建订单)
  • 需要严格权限控制(用户只能操作自己的订单)
  • 需要外部系统联动(CRM、营销中台、物流系统)

我在项目里定过一条原则:凡是“查了再答”的需求优先函数调用;凡是“背下来回答”的需求走知识库;凡是需要人工确认的复杂操作,函数只负责发起流程,不负责直接完成。

这个边界想清楚之后,整个系统不会变成一个大杂烩。AI原生应用最容易犯的错,就是什么能力都堆给模型,结果模型既当裁判又当运动员,出了问题都难排查。

3. 电商营销场景下的函数设计实战

3.1 场景一:优惠券发放与核销

优惠券是电商营销里最典型、也最容易出错的功能。用户可能问“我有哪些优惠券”“能领什么券”“帮我用掉这张券”,每个问题都涉及不同函数。

我实际设计的函数组是这样的:

获取用户优惠券列表:查询当前用户已领取的优惠券及状态。 获取可领取优惠券列表:查询当前面向用户的运营位,包含券面额、门槛、使用范围。 领取优惠券:给指定用户领取指定券,返回领取结果和剩余库存。 核销优惠券:提交订单时核销券,返回抵扣金额。

函数 Schema 要有明确的参数约束,比如券状态用枚举值限定为“可用、已用、过期”,金额统一用整数分存储。模型最怕含糊的参数说明,给它一个字符串枚举,它能少出很多错。

这里有一个关键点:营销活动有大量时效性规则,比如“仅限会员领取”“每人限领一张”“满200减100”。这些规则不应该靠模型理解,而应该写在后端领取函数的业务校验里。模型只负责识别用户要领券、传正确的券ID,能不能领、是否超限由后端代码决定。前端可以友好提示,但最终判定权必须在业务系统。

3.2 场景二:商品推荐与价格查询

商品查询类函数的难点不在参数,而在返回结果的表达。

我见过很多团队直接把数据库行返回给模型,一长串字段名和时间戳。模型虽然能读,但容易把原始字段误解成面向用户的文案。

更稳妥的做法是:后端函数先完成数据聚合,筛选出商品名、营销标签、价格、优惠价、剩余库存、唯一商品ID,再做一次字段映射。模型拿到的工具消息是一段干净的结构化JSON,生成自然语言时就不容易走样。

价格查询最容易出幻觉的地方是“到手价”。到手价 = 原价 - 满减 - 优惠券 + 运费,要经过实时试算。函数返回之前,后端必须完成这套计算,不能只把原价扔给模型。我在这类函数里加了“价格说明”字段,专门解释当前到手价是由哪些权益叠加的。这样模型回答“到手价是79元”时,能顺带说明“包含一张10元优惠券”,用户信任度完全不一样。

3.3 场景三:营销文案生成后的投放参数联动

这个场景比较进阶,适合把函数调用用在营销人员内部系统。

运营写一条活动文案时,经常要根据选择的商品自动带入投放参数,比如投放渠道、定向人群、预算、排期。传统做法是运营自己从商品库里复制参数,容易错。

我们用函数调用做了一个“文案与投放参数联动”能力:运营先描述活动对象和目标,模型识别商品ID后,调用“查询商品投放配置函数”,返回该商品的历史转化率、建议出价、可投放渠道等真实数据;模型再基于这些数据生成文案和投放建议。

这里的函数设计侧重“读”,不直接写投放系统。运营确认后,再由前端表单提交,避免模型在一次调用里误操作预算。这个“建议-确认-执行”的漏斗,在B端营销工具里特别重要,模型永远不能直接把钱花出去。

3.4 函数设计避坑清单

总结一下函数设计时的实操教训:

  • 函数粒度宁细勿粗:一个函数只做一件事。把发券和查券拆开,模型选错的概率低,后端也容易复用。
  • 参数描述要“面向语义”:不能只写“商品ID”,要写“用户请求中的商品唯一标识,来自商品搜索结果”,模型才不容易传错。
  • 返回结构要做“预格式化”:后端直接把适合生成的JSON给模型,别让模型读原始表结构。
  • 枚举值务必约束:状态、类型、渠道全部用枚举,模型一旦想自由发挥,参数校验直接拦。
  • 每个函数都要有失败返回:不要执行出错时空返回,必须告诉模型“失败原因”,否则模型会编造成功结果。

这些清单看上去琐碎,但每一个都是从真实事故里捞出来的。函数调用在Demo阶段怎么跑都对,一上生产,参数一乱、返回一空,用户立刻觉得机器人不可信。

4. 从原型到生产:一个可复用的调用流程实现

4.1 整体架构和模块划分

我们最终落地的模块大致分四层:

入口层负责接收用户消息和会话上下文。 编排层负责调用模型、解析函数调用请求、维护消息历史。 执行层负责执行具体业务函数,做权限校验、幂等控制、限流。 数据层负责访问优惠券、商品、订单等业务表。

各层之间只通过结构化消息通信。编排层不直接写业务代码,执行层不接触模型。这样的好处是,业务函数出了问题,不需要动模型链路;模型参数变了,也不影响后端函数。

4.2 关键代码:函数定义与结构化参数

以“领取优惠券”为例,函数定义通常是这样(通用伪代码,平台无关):

tools = [ { "type": "function", "function": { "name": "receive_coupon", "description": "给当前登录用户领取一张指定优惠券,只有用户明确表示要领取时才调用。", "parameters": { "type": "object", "properties": { "coupon_id": { "type": "string", "description": "优惠券唯一ID,来自可领取优惠券列表" } }, "required": ["coupon_id"] } } }, { "type": "function", "function": { "name": "get_coupon_list", "description": "查询当前用户已领取的优惠券及其状态。用户询问我的券、优惠券时调用。", "parameters": { "type": "object", "properties": { "status": { "type": "string", "enum": ["AVAILABLE", "USED", "EXPIRED", "ALL"], "description": "优惠券状态筛选,默认ALL" } } } } } ]

这里最关键的是description。前半句写动作,后半句写触发条件。很多函数被模型误调用,都是因为description写得太抽象,比如只写“领取优惠券”,没限定“只有明确表示要领取时才调用”。

函数定义里不要放业务规则。哪些用户能领、限领次数,这些放后端校验。模型只看得到参数结构,不感知规则,反而更安全。

4.3 关键代码:模型调用与结果回填

一次完整调用流程大约分四步。

第一步,把用户消息连同tools一起发给模型:

messages = [{"role": "user", "content": "帮我领一张满200减100的券"}] response = call_model(messages=messages, tools=tools)

第二步,检查模型的返回。如果返回里有tool_calls,就解析出函数名和参数:

tool_calls = response.get("tool_calls") if not tool_calls: # 模型直接回答了,没有调用函数 return response["content"] # 把模型的工具调用请求加入历史 messages.append({ "role": "assistant", "content": None, "tool_calls": tool_calls })

第三步,逐个执行函数,并把结果作为tool消息追加到历史:

for tc in tool_calls: fn_name = tc["function"]["name"] fn_args = json.loads(tc["function"]["arguments"]) result = execute_business_function(fn_name, fn_args) messages.append({ "role": "tool", "tool_call_id": tc["id"], "content": json.dumps(result, ensure_ascii=False) })

第四步,带着追加后的完整消息再次调用模型,让模型基于工具结果生成最终回复:

second_response = call_model(messages=messages, tools=tools)

这四步不能乱。tool消息必须关联到对应的tool_call_id,顺序也不能调换。如果多个函数并行调用,执行完成后仍然要按原始顺序回填,否则模型会困惑。

4.4 幂等、限流、审计:营销场景的三个硬要求

代码能跑通只是第一步。电商营销场景下,函数调用直接从“搜索式对话”变成了“事务式操作”,这时候三个工程问题必须处理。

第一个是幂等。用户说“领券”,模型发起两次调用,用户手抖重试一次,后端如果没做防重,同一个用户同一张券可能被领两次。我们的做法是增加业务唯一键,比如“用户ID + 券批次ID + 会话ID”作为幂等键,重复请求只返回第一次的结果。

第二个是限流。营销活动上线时,瞬时流量可能很高,模型调用和业务函数都要限流。模型侧限制每秒请求数,函数侧按用户维度限制操作频率,比如一分钟内最多领5次券。限流触发时不返回成功,反而要明确告诉模型“当前操作太频繁,请告知用户稍后再试”。

第三个是审计。所有函数调用都要记录完整的入参、出参、响应耗时和调用来源。营销活动出问题时,运营第一时间要能查到“谁在几点几分调用了什么函数,拿到了什么结果”。没有审计,出了问题就只能靠猜。

生产环境里我还建议加一个“人工确认”开关:对高影响函数(核销、退款、改价),先进入待确认状态,运营或用户在界面里点确认后真正执行。这个开关可以被函数调用的参数控制,比如require_confirmation=true,模型会生成确认文案,等用户回复“确认”后再调用执行函数。

5. 上线后踩过的坑:常见问题与排查实录

5.1 模型“乱选函数”怎么办

上线第一周最头疼的问题,是用户明明在问“我的订单到哪了”,模型却调用了“领取优惠券”函数。后来定位到原因,优惠券函数的description里写了“用户提到优惠、券、福利时可能触发”,这个“可能”给了模型太大自由。

解决办法是重写函数描述,收敛触发条件。描述要精确到“只有明确表示要领取时才调用”。另外,一个请求里如果模型选错了函数,可以在二次校验时把函数名与候选白名单做比对,不在名单内就强制拦截,返回给模型重新选择。

还有一个技巧:函数数量不是越多越好。当初我们为了覆盖各种营销玩法,一口气传了12个函数,模型选择负担很大,误选率直线上升。压缩到5个以内,误选率明显下降。低频函数可以折叠成一个“了解更多活动”入口,等用户点进去再展开具体函数。

5.2 参数幻觉怎么治理

AI原生应用里,参数幻觉(模型生成了业务系统不存在的参数)是必须零容忍的问题。

我们遇到过一次严重事故:用户问“我能领新人券吗”,模型调用领券函数时,传入了一个不存在的coupon_id,后端一查无此券,返回“券不存在”,模型居然顺着用户的话说“抱歉,您不符合领券条件”。

问题出在两层。第一层,后端函数没有做参数预校验,也没提供友好错误提示;第二层,模型面对失败结果时没有足够上下文说明“这个ID本身无效”。

治理办法有两个:

一是所有查询类函数先于操作类函数调用。用户想领券时,编排层优先确保“可领取优惠券列表”已经查询过,领券函数只接受来自列表的券ID。这相当于在流程上堵住幻觉入口。

二是后端函数返回错误时,要给模型足够判断信息。返回内容不能只有{"error": true},而要写成{"error_code": "COUPON_NOT_FOUND", "message": "未找到ID为xxx的优惠券,请先调用查询可领取列表"}。模型看得懂原因,才能向用户解释清楚,而不是瞎编。

5.3 延迟与成本:函数调用不是免费的

函数调用最容易被低估的,是它至少需要两次模型请求。第一次模型决定调用哪个函数,第二次模型基于函数结果生成回复。这导致单轮对话耗时翻倍,成本也翻倍。

我们实测下来,一次简单的领券操作,首轮请求0.8秒,函数执行0.1秒,回填后第二轮请求1.2秒,整体接近2.1秒。用户感知明显偏慢。

几个优化方向:

  • 对时效性不敏感的信息做缓存,比如商品基础信息,缓存5分钟都够用。
  • 多个独立函数并行调用,让模型一次返回多个tool_calls,前端并行执行后再回填,能省一次整体往返。
  • 对固定问答场景,直接跳过函数调用,用普通意图规则响应。
  • 参数化Prompt能压多少就压多少,函数描述写得精炼些,减少模型推理负担。

成本和延迟不能到了生产才考虑。我在设计期就定过目标,单轮耗时控制在2秒内,成本增幅不超过原纯对话方案的30%。有了指标,优化才有方向。

5.4 常见问题速查表

表现常见原因处理思路
模型答非所问,不调函数函数描述不清晰、参数必填不明确重写描述,加入触发条件示例,减少函数数量
调用了错误函数description范围过宽收缩触发条件,启用函数名白名单校验
函数参数传错ID未先做前置查询强制先查后传,操作类函数只接受查询结果中的ID
执行失败后模型乱解释错误返回信息不足返回结构化错误码和可选纠偏方案
同一操作重复执行缺少幂等控制增加用户+业务ID幂等键
页面响应太慢两次模型调用串行耗时并行工具调用、缓存、减少函数数量
成本超标每次请求携带过多函数精简函数描述,使用更短模型处理简单意图

这张表应该贴在每个参与项目的开发工位旁边。很多问题不是模型能力问题,而是工程侧没把函数调用的基础设施做好。

6. 复盘:函数调用落地的几条真实体会

第一,函数调用不是“给模型加几个工具”那么简单,它本质上是把对话系统从一个文本生成器,改造成了一个“意图-动作”编排框架。做这个改造,最花时间的是函数边界划分和参数约束,不是写调用代码。

第二,描述质量直接影响调用准确率,值得用半天时间反复打磨。我的习惯是,每个函数的description都要用真实用户话术验证一遍:把用户常问的句子套进去,看看模型是否会选中这个函数。选不中就改描述,直到命中为止。

第三,测试集必须包含“不该调用”的情况。只测试“应该调函数”的场景,模型永远不会知道该收敛的时候要收敛。我们专门造了50条不该调函数的语料,比如闲聊、问政策、表达不满,保证模型在那些场景下不擅自触发营销操作。

第四,日志可视化非常重要。函数调用的链路比普通问答长,出问题时不看链路根本定位不了。我们在日志里记录了每次tool_call的入参出参,用单独看板展示函数命中率、失败率和平均延迟。上线前一个月,我每天都盯这三个数字,调整函数描述和校验逻辑。

最后再分享一个小技巧:上线初期给所有高影响函数加一个“沙盒模式”,函数执行时只返回模拟数据,不真正发券、不改库存。先让模型在模拟环境里跑上一周,看函数命中率、参数准确率和用户满意度,一切稳定后再切换到真实执行模式。这个模式帮我避开了很多上线初期的惊险时刻,也给了运营团队足够的培训缓冲期。AI原生应用的函数调用,真正拼的不是花哨的代码,而是对业务边界的克制和对工程细节的较真。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询