资讯动态

从“智障”到“神助攻”:用Agent Skills打造可靠的销售数据分析助手

发布时间:2026/10/20 14:34:48 来源:尧图企业网站定制
如果你手头接了一个大模型接口第一反应多半是直接开聊“帮我把这周销售数据分析一下。”我去年在一个零售数据项目里也这么干过结果模型给出了一个特别正经的回答“本周销售额约为1200万元环比增长15%。”听起来还行对吧后来核账发现它把订单表里“成交金额”和“数量”两列混着读了真实数字只有98.3万。那一刻我意识到光会聊天的大模型和能稳定执行作业的助手之间差着一整套Agent Skills配置。下面这些内容就围绕Agent Skills展开。我会先用一个真实踩坑场景解释为什么大模型默认表现像“智障”然后带你从零定义一套针对销售数据分析场景的Skill再附上可以直接改用的Python代码最后聊一圈我在单位、日期和数值幻觉上踩过的坑。适合正在做智能助手、数据分析助手、自动化报表的人读也适合那些刚接触Agent、被“模型乱答”折磨得想放弃的人。需要先说明我这里说的Agent Skills不是某个平台特有的概念而是一种通用做法——把大模型中不稳定的“推理表达”降级为“调用执行”。模型只负责听懂人话、拆解任务、填参数真正算数、查表、做统计的是你写的技能函数。想清楚这一点后面所有配置都不会跑偏。1. 为什么默认模式下的大模型总像“智障”1.1 一个让我头疼的真实场景第一个让我想砸键盘的场景发生在项目上线第二周。用户提了一个很简单的问题“按区域看哪边卖得好”模型当时秒回了一段包含结论、趋势、建议的漂亮回答甚至把北部区域单列出来说“北部增长最快”。我当时心里还美滋滋。直到我用SQL把明细拉出来一比发现所谓北部增长最快是因为业务表里北部大部分记录缺失模型“补全”成了平均数。换句话说它用自然语言能力把一个残缺数据问题讲成了一篇完美故事。更离谱的是第二次。我让模型“算一下各区域客单价”它直接对着表格做起了心算给了一组精确到小数点后两位的数字。我用Python一算发现它对了一半错了一半它能把销量前三名的区域客单价说对但第四名开始就明显偏离真实值。原因不难猜——模型不是在做算术它是在模仿“算过之后应该长什么样”的文本。这两个场景的共同点是模型本身没有恶意它只是不知道自己在“表演计算”。你让它读数据它读到的其实是数据在训练语料里的影子你让它算指标它算的其实是“指标回答”的惯性模式。如果不在外面套一层可执行的技能它的表现就永远是在“猜”而不是在“干”。1.2 知识、流程、技能大模型混用了三件事为什么会出现这种情况因为大模型把三种完全不同的东西搅在一起了知识、流程、技能。知识是它训练时学会的世界常识比如“销售额单价×数量”流程是做事步骤比如“先清洗数据、再算指标、最后出报告”技能则是一个“可复用、可验证、有明确输入输出边界”的执行单元。默认情况下模型直接面对用户提问时会试图用“知识”去模拟“流程”并且假装自己具备“技能”。它在训练数据里见过太多“分析销售数据”的文章于是凭空模仿那种文风而不是真的去读表格。一个特别好用的类比你脑子里知道红烧肉怎么做和你能在30分钟内做出一道稳定好吃的红烧肉是两回事。前者是知识后者是技能。大模型的知识储备很强但让它直接上灶它很容易按“想象里的菜谱”操作烧糊了还会跟你讨论火候。这里还藏着一个更实际的问题知识和技能的边界在模型内部是模糊的。你没法通过“多问几遍”让它稳定下来因为每次回答都带有随机性。技能配置要做的事恰恰是把这条模糊边界实体化——把“模型自己来”变成“模型判断该调用哪个模块然后由模块来”。1.3 Agent Skills到底解决的是哪个痛点Agent Skills要解决的就是这个“想象式执行”的痛点。核心就一句话把不确定的表达变成确定的调用。具体来说有三个痛点幻觉导致数值错误。模型不会承认它没查到数据它会编一个看似合理的结果。同样问题每次回答不一致。上午回答销售Top3是A/B/C下午再看变成B/C/D因为采样随机。复杂流程无法复现。分析一单业务需要十步模型可能做到第三步就自己“简化”了。当我把“算销售额、算客单价、按区域透视”这些动作抽成技能函数之后模型在这些步骤里不再有“自由发挥”空间它只负责两件事判断该不该调用这个技能、把用户说的自然语言翻译成参数。这样出来的结果用户才会觉得它是“神助攻”而不是“智障助手”。当然Skill不是万能的。它最适合那些“重复发生、规则明确、结果可校验”的任务。销售指标计算就是典型反过来写一篇创意文案、总结一篇长文档的情绪观点这类开放性任务不需要硬绑技能。如果你发现某个任务每次都长不一样、没有统一口径那它大概率不适合做成Skill。2. Skills配置前的四件事模型选型、上下文边界、数据入口与观测日志2.1 模型选型不是越强越好我第一次做这个项目时选了一个对话体验特别好的模型结果发现它“工具调用”能力十分感人明明给它定义了analyze_sales它偏要输出一个叫“运行_sale”的函数名参数里定义了dimensions枚举它能编出一个“城市群”新值。对话体验好的模型不等于参数抽取稳定。所以我的第一个建议是选模型先测工具调用稳定性别只看通用知识量。怎么测拿同一个技能描述和同一个用户问题连续问10次看它返回的参数Schema是否一致。10次全对才算勉强可靠。测完如果发现模型喜欢给没填的参数脑补默认值那就得在系统提示词里压一句“未提供的参数必须输出null禁止猜测”。这句话看着简单实际能挡掉一大类传参错误。我见过太多项目模型把时间范围猜错、把维度传成不存在字段最后错误发生在函数里排查半天才发现是模型在第一步就“太贴心了”。2.2 上下文边界把背景知识和临时数据分层很多人配置技能时喜欢把所有背景一股脑塞进系统提示词甚至有人直接把整张销售表贴进去。这看起来方便实际很坑上下文一长模型注意力开始飘参数抽取错误率上升推理成本也爆炸。我一般把信息分成三层系统提示层只放角色、全局口径、安全规则比如“金额单位默认是元”技能描述层描述每个技能做什么、不做什么、参数怎么填临时数据层只有技能函数真正查询的明细数据绝不整表喂给模型。层与层之间用明确的边界隔开模型才知道什么该记、什么该问、什么该交给函数。销售分析中尤其重要因为你不会希望模型在回答时“回忆”某个它其实没读过的数字。我遇到过一种情况函数返回结果已经算好了客单价模型在总结时却额外补了一句“其中东部区客单价约为2800元”——这个数字不是函数给的是它自己脑补的。分层之后模型手里的“原材料”只剩函数返回的JSON自然没有脑补空间。2.3 数据入口销售数据的三种接入方式销售数据从哪进来直接决定技能函数长什么样。我见过三种常见方式文件上传或本地CSV适合离线分析、原型验证。技能拿到的是文件路径函数自己读取。数据库查询API适合实时场景。技能拿到的是一段查询条件函数拼SQL后返回结果。数据仓库临时分析接口适合超大数据集。技能拿到一个任务句柄函数提交异步作业再拉结果。三种方式各有取舍文件最简单但数据易过期数据库API实时性强但需要严格校验权限数据仓库灵活但延迟和费用都不低。我下面的实战代码用本地CSV因为大家最容易直接跑起来。生产环境真正上线时一般会把CSV读取那一步替换成参数化的数据库查询思路完全一致。这里有一个容易踩的坑不管数据从哪来技能函数都应该接收“查询条件”而不是接收“整份数据”。比如让函数接收一个文件路径或SQL过滤条件而不是把一万行CSV塞进内存再传给模型。数据入口设计得越窄后续做权限控制、审计和性能优化就越容易。2.4 观测日志没有调用链配置Skills就是瞎子摸象第四件事最容易被忽略。技能配好之后模型没说错但传参传错了、函数执行失败但模型假装成功这些问题如果没有日志你根本无从下手。我给每个请求记五段日志user_query用户原始输入model_action模型决定调用哪个技能以及输出的参数JSONfunction_input实际传给技能函数的参数function_output函数返回的统计结果或错误信息final_response模型基于函数结果生成的最终回复五段拼在一起就是一次完整的调用链。出现问题先按日志定位是“模型选错技能”“参数传错”还是“函数算错”不要上来就改提示词。我见过太多人一遇到结果不对就拼命调prompt结果真正的问题是函数把千元当成了元。另外提醒一句日志里可能会带销售金额等敏感信息记得做访问控制和脱敏别图方便把所有消息原样写文件。尤其是把完整调用链接进排障系统的时候字段级脱敏能省掉后面一大堆合规麻烦。3. 手把手定义一个“销售数据分析”Skill结构、参数与描述的艺术3.1 技能定义的标准结构每个Agent Skills的实现底层都离不开五个部分。不管你用什么平台骨架都是这样名称name简短、唯一、模型和人都能懂。我用的是sales_data_analyzer。描述description说明什么时候用、什么时候不用、能输出什么。参数Schema定义模型需要填写的字段及枚举值是防止模型乱传参的关键。执行逻辑真正干活的代码负责读数据、清洗、计算。输出协议返回给模型的数据结构约定模型只能基于这个结果说话。这五部分互相约束。很多人只写了“执行逻辑”就号称完成了技能结果模型根本不知道何时调用——本质上等于没配。反过来也有人把描述写得天花乱坠但参数Schema全是开放字符串模型每次都填出不同字段名函数解析时只能靠正则猜。五部分缺一个技能就会在某个环节出问题。我把输出协议单拎出来说是因为它常常被忽略。函数返回“格式化好的中文报告”和返回“结构化JSON”对模型后续行为的影响完全不同。返回JSON模型可以基于数据重新组织语言返回中文报告模型容易直接复制粘贴甚至添油加醋。我的习惯是函数永远返回结构化数据文本加工交给模型。3.2 从模糊需求到结构化参数字段设计练习“帮我看一下销售情况”是一句典型废话模型不该直接算应该先拆参数。我以这句话为例演示字段设计file_path要分析哪个文件。如果用户没说技能要能报“缺少文件路径”而不是猜。dimensions按什么维度透视产品/区域/渠道/销售员。metrics算哪些指标总销售额/订单数/客单价/同比/环比。start_date、end_date时间范围用统一的日期格式。output_style返回风格brief/report/chart_ready。字段不是想加就加每个字段都要有明确枚举。比如dimensions我限定成四个值模型就不能传“城市群”这种不存在的维度。再比如output_style给几个选项比让模型自由决定“写多长报告”要稳得多。参数化越严格技能越可靠但也不能严格到用户说“随便看看”时技能卡死所以我会配默认值默认取文件里最新一个月的数据默认只看总体指标。这个设计过程其实很像给API设计入参你要站在调用方的角度想模型拿到用户的话之后能不能把话里的信息准确映射到这些字段上。如果用户说“哪个产品卖得最好”模型应该能把dimensions填成[product]如果用户说“3月份整体怎么样”模型应该能把start_date和end_date填成2024-03-01到2024-03-31。字段设计得好模型调用技能时就等于在填一张表而不是在写一篇小作文。3.3 描述怎么写Agent才看得懂、调得准技能描述是模型的“说明书”描述质量的差距直接决定调用准确性。我最开始写的描述是“分析销售数据”结果用户问“退货率怎么样”时模型也去调用这个技能——因为它只看到“销售”两个字。后来我把描述改为“分析销售明细表计算销售额、订单数、客单价以及按产品/区域/渠道/销售员的透视汇总。仅适用于包含日期、金额、数量等列的表格数据。不处理图片、不处理聊天记录、不处理退货分析。若金额列存在单位标识请先由函数完成归一化。”这样一段话等于帮模型画了条清晰的边界哪些任务归它管哪些任务不归它管。写描述时有个小技巧在结尾加一行“何时不该调用”。大多数技能描述只写正向触发条件不写负向排除模型就容易乱用。把“不处理退货分析”写进去之后我的误调用率降了一半以上。另一个技巧是给描述里加入“结果形式”比如“返回结构化JSON字段包括total_sales、order_count”这样模型拿到结果后知道怎么转述不会自作主张换个算法再算一遍。3.4 最小可用的Skill定义示例下面这个JSON结构是我常用的最小范式你可以直接套到自己的Agent框架里{ name: sales_data_analyzer, description: 分析销售明细表计算销售额、订单数、客单价以及按产品/区域/渠道/销售员的透视汇总。仅适用于包含日期、金额、数量等列的表格数据不处理退货、不处理聊天记录、不分析图片。, parameters: { type: object, properties: { file_path: { type: string, description: 销售明细CSV文件路径 }, dimensions: { type: array, items: { type: string, enum: [product, region, channel, salesperson] }, description: 需要透视的维度默认空数组 }, metrics: { type: array, items: { type: string, enum: [total_sales, order_count, avg_order_value, yoy_growth, mom_growth] }, description: 需要计算的指标默认全部核心指标 }, start_date: { type: string, format: date, description: 开始日期格式YYYY-MM-DD }, end_date: { type: string, format: date, description: 结束日期格式YYYY-MM-DD }, output_style: { type: string, enum: [brief, report, chart_ready], description: brief为要点report为完整报告chart_ready为适合图表的数据结构 } } } }注意这里的参数Schema不是给Python用的是给模型看的“契约”。模型必须按这个契约输出参数你的代码才会收到结构一致的数据。这也是Agent配置里最容易忽略的部分很多人直接让模型自由发挥然后解析时发现字段名千奇百怪。把这个JSON结构放进系统提示词模型每次调用都会照着填后面函数的容错压力会小很多。4. 让Agent在正确时机启用技能路由规则与提示词协同4.1 两种路由方式规则路由与模型自路由技能定义好了接下来是“什么时候让模型调用它”。常用的有两种规则路由程序里写死关键词判断比如用户消息含“销售”且含“分析”就强制调用技能。它稳但分支一多就变成意大利面条每加一个技能就要改一堆if。模型自路由在系统提示词里列出技能清单和触发条件让模型先输出一个结构化的调用意图再由程序解析执行。它灵活但对模型指令遵循能力有要求。我建议技能数量在10个以内的场景直接用模型自路由。销售分析这种场景技能就那么三五个规则路由反而不划算——写规则的工夫够你把提示词打磨得稳稳当当。下面是两种方式的对比维度规则路由模型自路由稳定性高规则命中必调依赖模型指令遵循扩展成本新增技能要加规则只需追加描述灵活性差无法处理模糊表达好能理解同义改写典型场景生产环境强约束知识型助手实际项目里也可以混合对绝对不允许出错的技能用规则兜底对模糊任务交给模型判断。后面会看到示例代码采用的就是先模型自路由、再做规则校验的方式。4.2 提示词里如何“声明”技能的存在模型自路由核心是系统提示词。我常用的模板是“你是销售数据分析助手。你可以使用以下技能sales_data_analyzer分析销售明细表格计算核心指标和透视汇总。当用户询问销售额、订单量、客单价、同比环比或者需要按产品/区域/渠道分析时调用。 调用格式先输出一句话思考然后输出JSON{skill: sales_data_analyzer, arguments: {file_path: ..., dimensions: [], metrics: []}}。参数缺失时输出null禁止编造。所有数字必须来自技能函数返回结果禁止估算。”这段提示词想清楚了几件事技能清单、触发条件、输出格式、防幻觉规则。你会发现它比单纯说“你可以调用工具”要实用得多因为模型知道“什么情况下必须调用”以及“调用后怎么表达”。这里有个容易踩的坑如果技能描述里写了“分析销售数据”模型很容易把“退货分析”也识别成销售分析。所以声明技能时最好在技能名称后面附上“专属触发词”和“排除词”。比如“仅当用户提到退货、退款、拒收时才调用退货分析技能提到销售额、订单量时不要调用”。模型不是看不懂而是它需要明确的边界否则就会靠猜。4.3 协同设计让模型先问清楚再动手最后是人和模型的协同。用户说“分析一下”就甩过来文件呢日期呢如果让模型猜等于又开了一个幻觉后门。我给技能配置默认值的逻辑没有指定文件先检查对话上下文里有没有用户上传的文件路径没有就回复“请上传销售明细CSV”。没有指定时间范围默认取文件里最新月份的数据。没有指定维度默认输出总体指标但会在结果里带一句“如需分区域请告诉我”。这样模型既有规矩又不会因为参数不全而卡死。本质上这是把产品交互的容错逻辑下沉到技能层而不是靠模型临场发挥。等到这一步跑通一个销售数据分析助手才算是真正有了使用价值。5. 销售数据分析实战代码从原始表格到可直接汇报的结论5.1 造一份“足够脏”的销售数据技能函数的价值靠脏数据体现。我造了一份模拟销售明细列有date、region、product、channel、sales_amount、quantity、unit。故意安排了日期格式混用、金额单位不一致unit列标了元/千元、一行为空值。这样演示起来才有说服力。import pandas as pd import random random.seed(42) regions [东部区, 北部区, 南部区, 西部区, 中部区] products [智能手表, 蓝牙耳机, 充电宝, 桌面支架, 数据线] channels [官方商城, 线下门店, 综合电商, 小程序商城] rows [] for i in range(120): date f2024-{random.randint(1, 3):02d}-{random.randint(1, 28):02d} if i % 7 0: date date.replace(-, /) # 故意混入 / 格式 amount random.choice([99, 199, 299, 499, 899, 1299, 2999]) unit 元 if i % 11 0: amount round(amount / 10, 1) # 模拟单位不一致 unit 千元 rows.append({ date: date, region: random.choice(regions), product: random.choice(products), channel: random.choice(channels), sales_amount: amount, quantity: random.randint(1, 5), unit: unit, order_id: fSO2024{1000 i} }) # 埋一颗空值 rows[3][region] None df pd.DataFrame(rows) df.to_csv(sales_data.csv, indexFalse, encodingutf-8) print(df.head())这份数据的意义在于它不是一份规规矩矩的演示数据而是带着真实业务里最常见的三类脏点——日期格式不统一、金额单位不统一、关键字段缺失。技能函数如果连这种数据都能处理成可靠结论那它在真实场景里的表现基本不会太差。5.2 技能函数统一口径与核心指标计算接下来是真正干活的技能函数。它做的事按顺序是校验文件、清洗日期、按单位列归一化金额、处理空值、按需分组汇总最后返回一个结构化结果。核心思路是宁可明确报错也不返回一个让模型“看起来合理”的错误数字。def normalize_data(df): # 统一日期 df[date] pd.to_datetime(df[date], formatmixed, dayfirstFalse) # 统一金额单位把千元转成元 df[sales_amount_yuan] df.apply( lambda row: row[sales_amount] if row[unit] 元 else row[sales_amount] * 1000, axis1 ) # 丢弃 region 为空的行但要记数 dropped df[region].isna().sum() df df.dropna(subset[region, sales_amount_yuan]) return df, dropped def analyze_sales(file_path, dimensionsNone, metricsNone, start_dateNone, end_dateNone, output_stylebrief): df pd.read_csv(file_path) df, dropped normalize_data(df) if start_date: df df[df[date] start_date] if end_date: df df[df[date] end_date] result {total_sales: float(df[sales_amount_yuan].sum())} result[order_count] len(df) result[avg_order_value] round(result[total_sales] / result[order_count], 2) if dimensions: for dim in dimensions: group df.groupby(dim)[sales_amount_yuan].sum().sort_values(ascendingFalse) result[by_ dim] {k: float(v) for k, v in group.items()} result[warning] f清洗时丢弃空值行数{dropped} return result这段代码的核心是强调所有数值都由Python算模型只负责翻译。你可能注意到我在结果里加了总销售额、订单数、客单价之外没有做更复杂的同比环比因为这里想展示的是最小可用的骨架。真实的同比环比需要上一期数据作为参照怎么传上一期、怎么对齐日期每个业务都有自己的口径这是你接入自己业务时需要扩展的地方。还有一个细节清洗时丢弃空值行不是唯一选择。你也可以把缺失region的行归到“未知区域”然后再去汇总。到底怎么做取决于业务上能不能接受“未知区域”这个口径。我在这段代码里选择丢弃并记录warning是为了让模型在最终回答里主动暴露数据质量问题而不是假装整份数据完美无缺。5.3 组装Agent调度从用户指令到技能调用调度层负责把用户的话交给模型模型返回技能和参数程序调用函数再把函数结果交还模型。下面这段是模仿通用Chat接口的调用流程我特意不写死任何一家SDK方便你换成自己用的模型服务。import json SYSTEM_PROMPT 你是销售数据分析助手。你可以使用以下技能 1. sales_data_analyzer分析销售明细CSV文件计算销售额、订单数、客单价以及按产品/区域/渠道/销售员的透视汇总。 触发条件用户需要分析销售数据、要求计算销售指标或看透视排行时必须调用此技能。 调用格式输出JSON格式为 {skill: sales_data_analyzer, arguments: { file_path: 缺省为null, dimensions: [], metrics: [], start_date: YYYY-MM-DD或null, end_date: YYYY-MM-DD或null, output_style: brief} } 注意所有指标数字必须来自函数返回禁止自己估算参数缺失输出null。 .strip() def call_model(messages): # 这段需要替换成你实际接入的模型服务 # 输入是带 role 的消息列表返回文本内容 pass def run_agent(user_message): messages [ {role: system, content: SYSTEM_PROMPT}, {role: user, content: user_message} ] model_reply call_model(messages) # 解析模型输出的 JSON action action json.loads(model_reply) if action.get(skill) ! sales_data_analyzer: return 当前问题不在技能范围内。 fn_result analyze_sales(**action[arguments]) messages.append({ role: assistant, content: f技能返回结果{json.dumps(fn_result, ensure_asciiFalse)} }) messages.append({ role: user, content: 请基于技能返回结果给出最终回答 }) return call_model(messages)有人可能会问模型输出的那一段JSON怎么保证解析成功实战中我会用JSON Schema约束、错误重试和正则提取兜底但核心思路就是这个循环用户问题交给模型模型输出动作程序执行动作函数结果再喂回模型模型生成最终回答。把“函数返回结果”再喂回模型这一步非常关键否则模型会无视函数结果自己编。我见过很多简化版demo只让模型输出一个函数名然后程序直接执行并把结果返回给用户模型完全不参与总结。那样做不是不好而是损失了模型最大的价值——把结构化数据转换成用户能直接读的人话。真正好用的Agent应该让模型既当“调度员”又当“解说员”唯独不要再当“计算器”。5.4 一次完整的调用效果演示假设用户输入“按产品维度分析2024年第一季度整体销售情况输出一份简报。”模型自路由输出{skill: sales_data_analyzer, arguments: { file_path: sales_data.csv, dimensions: [product], metrics: [total_sales, order_count, avg_order_value], start_date: 2024-01-01, end_date: 2024-03-31, output_style: brief } }函数返回后模型最终回答“2024年第一季度共产生119笔有效订单有1笔因区域缺失被排除。总销售额约33.14万元客单价约2785元。按产品看智能手表销售额最高约11.2万元桌面支架最低。注意部分订单金额以千元为单位函数已统一为元后计算。”这个演示看起来平平无奇但它恰恰是“神助攻”该有的样子模型没有创造任何数字只是把函数返回的结构化结论翻译成了人话还顺带说明了数据清洗动作。用户不需要再自己核对口径因为模型主动暴露了“排除1笔”“千元统一为元”这些关键前提。之前那个会一本正经编造1200万元的“智障”在这套配置下根本没有机会发挥想象力。6. 从“能跑”到“能用”踩过的坑、调参心得与版本维护6.1 单位混用与日期错乱技能函数内部的兜底策略第一个坑就是单位混用。某次上线后有同事报某个区域销售额暴涨我查日志发现函数没有按unit字段归一化导致该区域几条“千元”记录被当成“元”。表面上是函数bug本质上是数据口径没有在技能边界内被统一。从那以后我强制要求所有金额类字段进入计算前必须先过归一化逻辑没有单位列时就用中位数偏差做异常标记比如某条记录的数值超过该列中位数10倍就输出一条warning让模型提醒用户。与其算出一个漂亮但错误的数字不如把异常端点出来。日期格式也一样。CSV里既有2024/1/5又有2024-01-05时很多解析库会混出NaN。用pandas的宽松解析能解决大部分但要注意个别日期漏天的情况。我的原则是宁可把这行标成“日期异常已排除”也不要让模型编一个日期出来。6.2 数值幻觉永远不要让模型心算平均数我踩过的最大坑是让模型直接读CSV文本算平均值。一开始我觉得“数据量只有120行模型应该算得过来吧”试了几次后发现它给出的客单价每次都不一样偏差在5%到15%之间晃。原因很简单大模型没有真正做算术它是在预测“平均值看起来像多少”。所以后来我在系统提示词里写死了一条规则“禁止根据上下文中的原始数据自行计算任何数值指标必须调用analyze_sales函数获取。”模型偶尔还是会想偷懒但只要函数返回值已经存在最终回答就只允许引用它。这条规则比任何提示词技巧都管用。我想强调一下这个现象值得反复检查即使你在系统提示词里写了禁止估算模型也可能在长对话中被“带偏”。比如用户先问了一个不需要函数的问题模型正常回答紧接着又问“那客单价呢”模型可能顺着上文直接算而不是重新触发技能。解决方法是把“需要调用技能”的判断条件写得非常明确并且在每次函数返回后都把结果重新注入上下文让模型每一轮都能看到“最新权威数据”。6.3 多个技能共存时的优先级设计销售数据分析跑通之后我陆续加了退货分析和库存预警两个技能。结果模型开始犯难用户说“退货率怎么又高了”它一会儿调销售分析一会儿调退货分析有时还两个一起调导致最终回答中的口径互相打架。解决思路是给每个技能描述写清专属触发词和排除词并在调度代码里做优先级排序精确参数匹配优先于关键词匹配关键词匹配优先于模型自主判断。比如退货分析技能的描述里写死“仅当用户明确提到退货、退款、拒收时调用提到销售金额时不要调用”。加上这个约束后误调率明显下降。还有一个细节多个技能同时可用时我会让模型一次只选一个主技能其他需求通过追问来拆解。比如“看看销售额和库存情况”我会让模型先完成销售分析再追问是否要查库存避免两个技能返回的时间维度不一致造成对不上。6.4 技能的版本迭代与回滚策略最后聊聊维护。技能函数和提示词不是一次写对的都是从badcase里修出来的。我会给每个技能函数加一个version字段比如“sales_data_analyzer”: {version: v2.1, handler: analyze_sales}修改后统一在日志里记录版本号一旦发现新逻辑有回归可以快速切回上一版本。提示词和函数尽量分开管理。因为很多时候模型表现变差不是函数算错了而是提示词描述被改得含糊了。把两者拆开回滚时就不用去git记录里翻半天。还有一个我特别推荐的小习惯让技能返回值里自带“口径说明”比如“金额单位为元已排除空值3条”。模型引用这段说明去生成报告用户看到的不只是答案还有背后的计算边界。这个习惯在对接业务方时尤其管用——对方问“为什么销售额和报表对不上”你直接把口径说明甩给他省掉一整轮沟通。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑