☰
工厂报价 Agent 实战:AI 出初版报价单,人只审异常(附规则引擎与提示词)
2026/10/14 14:27:16 网站建设 项目流程

一、报价慢的账,其实很好算

先说一组行业基准:制造业与分销业的 B2B 报价响应时间,平均值在 24 到 72 小时之间(2026 年制造业基准数据);而买方在发出询价后的4 小时内就基本形成了供应商偏好。Proposify 对近 200 万份销售提案的分析显示:4 小时内给出回应的,成交率比超过 24 小时才回应的高出约 35%。

在制造业里,这个差距还要更直接一点:客户通常同时向三到五家供应商发同一份询价,往往是第一个给出可用报价的赢。

那 24 到 72 小时都花在哪了?把手工报价拆开看,大概是这样:

步骤耗时干的事
1. 查客户价目10~20 分钟翻 ERP、找客户等级、核对专属价、对阶梯表
2. 查库存与交期10~15 分钟多仓库存、在制品、外协件回货时间
3. 算阶梯折扣与毛利10~20 分钟数量阶梯、折扣、毛利复核
4. 排版与发送10~20 分钟报价单文档、付款与交付条款

单份 40 到 75 分钟,复杂件更久。其中第 1 到第 3 步占了大约 80% 的时间,而这三步是纯确定性的查表和算术——恰恰是最不该由人来做、也最适合交给程序的部分。

所以这篇文章不讲「AI 能不能报价」,只讲一件工程上的事:怎么让 AI 把报价的 80% 做成一份可审核的初稿,同时保证它一毛钱都不能自己说了算。


二、先划边界:AI 算到哪一步,哪一步必须人签

这一步比写提示词重要十倍。报价 Agent 翻车从来不是因为算不出来,而是因为算出来了,还没人看过就发出去了。报价在法律上是要约,说错价要么亏钱,要么丢信用。

把「能自动」和「必须人工」先切干净:

报价环节处理方式理由
需求参数识别(材质/规格/数量/表面处理)✅ AI 抽取把图纸说明和聊天记录变成结构化字段
标准件单价、阶梯价查询✅ AI 按规则算纯查表,规则可复现、可验证
材料成本、损耗率、加工费✅ AI 算,并标注依据有费率表就能倒推出每一步
交期承诺⚠️ AI 只给区间,不给绝对日期排产是动态的,写死日期就是埋雷
折扣、账期、付款条件⚠️ AI 出建议值,必须人批商务策略,让错一次就很被动
非标件、开模、大额项目❌ 直接转人工规则覆盖不到,AI 只能添乱
报价单最终发出❌ 人点发送要约行为,责任在人

一句话:AI 负责把报价变成「一稿」,人负责那一签。


三、整体架构

缺料

齐全

低风险
老客户/标准件

高风险
低于毛利底线/偏离历史价

客户询价
阿里/邮箱/微信/官网表单

参数抽取
LLM + JSON Schema

参数是否齐全

自动追问
材质/数量/表面处理

规则引擎计算
材料+工艺+阶梯价

风险分级

生成初版报价单

挂起 + 推送业务复核

人工改价/确认

落库 + 留痕

推送销售与客户
标注为初版

对应的节点配置:

顺序节点类型关键配置
1接收询价触发器入参:raw_text、客户 ID、渠道、附件
2参数抽取LLM(JSON 模式)输出材质、规格、数量、工艺、表面处理
3参数校验代码节点必填字段判空,缺失走追问分支
4规则计算代码节点全部算术在这里做,LLM 不碰数字
5风险分级条件分支金额 / 毛利率 / 价格偏离度三个条件
6生成初版模板节点填入报价单模板,加「初版」水印
7落库HTTP / 数据库写报价记录 + 改价留痕表
8通知插件推送飞书/钉钉,高风险带复核链接

第 4 步是全套设计的核心:把所有算术从模型里拿出来,放进确定性代码。下面第五节会展开。


四、把报价规则变成「可计算的东西」

这一步是纯体力活,但做完就一劳永逸。你需要的其实是四张表,把老师傅脑子里的经验搬到纸上:

① 材料费率表(材料 → 单价、密度、损耗率)

材料单价(元/kg)密度(g/cm³)常规损耗率
Q235 钢板4.207.858%
304 不锈钢16.507.9312%
6061 铝板19.802.7010%
ABS 塑料12.301.055%

② 工艺费率表(工序 → 费率、基准工时)

工序费率(元/小时)基准工时(分钟/件)
激光切割1201.5
数控折弯952.0
焊接1106.0
喷涂804.0

③ 数量阶梯表(数量 → 折扣系数)

数量区间系数
1 ~ 991.00
100 ~ 4990.94
500 ~ 19990.88
2000 以上0.82

④ 客户价格等级表(等级 → 折扣、毛利底线)

客户等级额外折扣毛利底线
A 类(年采购 500 万+)0.9618%
B 类(年采购 100 万+)0.9822%
C 类(新客户/散单)1.0028%

有了这四张表,单价公式就可以写死了:

材料成本 = 单件净重(kg) × 材料单价 × (1 + 损耗率) 加工费 = Σ(工序基准工时 × 工艺费率 / 60) × 数量 直接成本 = 材料成本 + 加工费 + 固定摊销 基准报价 = 直接成本 ÷ (1 − 目标毛利率) 最终单价 = 基准报价 × 数量阶梯系数 × 客户等级折扣

这里有个必须坚持的点:报价随数量变化,不是因为「量大便宜」这种模糊感觉,而是因为物料损耗和换型摊销被数量摊薄了。规则写成公式,才能被复核、被测试、被版本管理。


五、提示词:只抽参数,不做计算

这是整套方案里最容易写错的地方。千万不要让大模型去算钱。LLM 做多位数乘除时的错误率不低,而报价单上错一位数就是真金白银。

所以提示词只让它干一件事:把非结构化的需求,翻译成结构化字段。算钱交给代码。

系统提示词(可直接复制):

你是制造业报价助理,唯一职责是把客户的询价信息抽取成结构化参数。 你不负责计算价格,不负责判断是否接单,不负责承诺交期。 【输出规则】 1. 只输出 JSON,不要任何解释、不要 Markdown 代码块标记。 2. 未提及的字段一律填 null,禁止猜测、禁止编造。 3. 数量单位统一换算为「件」;重量统一为「kg」;长度统一为「mm」。 4. 材质只允许取以下枚举值:Q235、304、6061、ABS、其他。 若不在这四类里,material 填「其他」,并在 material_raw 写客户原话。 5. 工艺从以下枚举中多选:激光切割、数控折弯、焊接、喷涂、机加工、组装。 6. 客户原话里出现「大概」「类似」「差不多」等模糊表述时, 对应字段照实填写,并在 ambiguous_fields 里列出字段名。 7. 如果数量、材质、工艺三项中有任意一项为 null, 在 need_clarify 里列出需要追问的问题,每个问题不超过 20 字。 【输出格式】 { "material": "Q235", "material_raw": null, "quantity": 500, "unit": "件", "part_name": "支架", "processes": ["激光切割", "数控折弯", "焊接"], "surface_treatment": "镀锌", "unit_weight_kg": 1.85, "deadline_days": 15, "ambiguous_fields": [], "need_clarify": [] }

实测经验:加了ambiguous_fields和need_clarify之后,追问质量提升最明显。以前它会把「差不多五百件」直接写成500,现在会照实记并且标记歧义,让业务决定要不要追问。


六、计算节点:规则引擎代码

抽完参数,交给一段纯函数。核心是三件事:算成本、查阶梯价、校验毛利底线。

fromdecimalimportDecimal,ROUND_HALF_UP MATERIAL={"Q235":{"price":Decimal("4.20"),"loss":Decimal("0.08")},"304":{"price":Decimal("16.50"),"loss":Decimal("0.12")},"6061":{"price":Decimal("19.80"),"loss":Decimal("0.10")},"ABS":{"price":Decimal("12.30"),"loss":Decimal("0.05")},}PROCESS={"激光切割":{"rate":Decimal("120"),"base_min":Decimal("1.5")},"数控折弯":{"rate":Decimal("95"),"base_min":Decimal("2.0")},"焊接":{"rate":Decimal("110"),"base_min":Decimal("6.0")},"喷涂":{"rate":Decimal("80"),"base_min":Decimal("4.0")},}# 数量阶梯系数(按区间下界,倒序匹配)TIER=[(2000,Decimal("0.82")),(500,Decimal("0.88")),(100,Decimal("0.94")),(0,Decimal("1.00"))]CUSTOMER={"A":{"discount":Decimal("0.96"),"floor_margin":Decimal("0.18")},"B":{"discount":Decimal("0.98"),"floor_margin":Decimal("0.22")},"C":{"discount":Decimal("1.00"),"floor_margin":Decimal("0.28")},}FIXED_OVERHEAD=Decimal("3.00")# 固定摊销,元/件deftier_factor(qty:int)->Decimal:forlow,finTIER:ifqty>=low:returnfreturnDecimal("1.00")defcalc_quote(params:dict,customer_level:str="C")->dict:"""纯函数:不调用任何模型,输入参数出价格,可单元测试。"""mat=MATERIAL.get(params["material"])ifmatisNone:raiseValueError(f"材质不在费率表内:{params['material']}")qty=int(params["quantity"])weight=Decimal(str(params["unit_weight_kg"]))# 1) 材料成本:单件净重 × 单价 × (1 + 损耗)material_cost=weight*mat["price"]*(Decimal("1")+mat["loss"])# 2) 加工费:Σ(工时 × 费率 / 60)labor=Decimal("0")forpinparams["processes"]:cfg=PROCESS.get(p)ifcfgisNone:raiseValueError(f"工艺不在费率表内:{p}")labor+=cfg["base_min"]*cfg["rate"]/Decimal("60")unit_cost=material_cost+labor+FIXED_OVERHEAD# 3) 按目标毛利率反推基准报价cust=CUSTOMER[customer_level]target_margin=cust["floor_margin"]+Decimal("0.10")# 常规留 10 个点空间base_price=unit_cost/(Decimal("1")-target_margin)# 4) 套阶梯系数与客户折扣unit_price=base_price*tier_factor(qty)*cust["discount"]total=unit_price*qty real_margin=(unit_price-unit_cost)/unit_price# 5) 高风险标记(不是拒绝,是挂起给人看)flags=[]ifreal_margin<cust["floor_margin"]:flags.append("低于毛利底线")ifqty<100andlen(params["processes"])>=3:flags.append("小批量多工序,建议人工核价")ifparams.get("ambiguous_fields"):flags.append("需求存在歧义:"+",".join(params["ambiguous_fields"]))q=lambdax:Decimal(x).quantize(Decimal("0.01"),rounding=ROUND_HALF_UP)return{"unit_cost":q(unit_cost),"unit_price":q(unit_price),"total_price":q(total),"margin":q(real_margin*100),"risk_flags":flags,"need_review":len(flags)>0,}

这段代码有三个工程上必须守住的点:

  1. 金额一律用Decimal,不用float。浮点数在累加和除法的场景下会出现0.1 + 0.2 != 0.3这类误差,报价单上很尴尬。
  2. 它是纯函数。同一份输入永远出同一个价,可以写单元测试——这是 LLM 做不到的。
  3. 费率表出错时抛异常,不猜。遇到不在表里的材质,宁可挂起,也不要模型凑一个数。

把三段串起来的主流程,其实就是二十行:

defhandle_inquiry(raw_text:str,customer_id:int)->dict:"""询价进 → 初稿出。LLM 只出现在第一步。"""# 1. LLM 抽参数(唯一调用模型的地方)params=llm_extract(raw_text)# 返回第五节定义的 JSON# 2. 缺参数就追问,不硬算ifparams["need_clarify"]:return{"status":"need_clarify","questions":params["need_clarify"]}# 3. 确定性计算level=get_customer_level(customer_id)# A / B / Cresult=calc_quote(params,level)# 4. 分级:低风险出初稿,高风险挂起status="reviewing"if(result["need_review"]orresult["total_price"]>REVIEW_THRESHOLD)else"draft"# 5. 落库 + 留痕 + 通知quote_id=save_quote(customer_id,params,result,status)notify_sales(quote_id,result,status)return{"status":status,"quote_id":quote_id,**result}

注意REVIEW_THRESHOLD这个常量的位置:它在代码里,不在提示词里。审批阈值是管理决策,不该由模型来「理解」。


七、人在环:三道闸门

自动化程度的高低,不是看它能不能全自动,而是看你把「什么时候必须停下来」定义得多清楚。我建议至少三道闸门,任何一道触发就走人工:

闸门触发条件动作
金额闸单笔总价 > 设定阈值(如 5 万)强制人工审批后才生成正式报价单
异常闸毛利率低于底线 / 单价偏离该客户历史价 ±15%挂起,推送异常原因给复核人
白名单闸老客户 + 标准件 + 价格在历史区间内允许生成初版直接给到业务

第三道闸门是提效的关键:让高频、低风险的场景全速通过,让低频、高风险的场景强制刹车。实测里,能走白名单的报价请求通常占六到七成,这部分从「等半天」变成「几分钟出一稿」,而真正需要人盯的只剩三成。


八、落库与留痕:报价单必须可追溯

报价 Agent 上线后,最先被问的问题一定是:「这个价谁定的?」所以留痕要一开始就做。最小可用的两张表:

CREATETABLEquote(id BIGSERIALPRIMARYKEY,customer_idBIGINTNOTNULL,part_nameVARCHAR(128),params_json JSONBNOTNULL,-- 抽取出的一稿参数,原样存档unit_priceNUMERIC(12,2)NOTNULL,total_priceNUMERIC(14,2)NOTNULL,margin_pctNUMERIC(5,2),risk_flags JSONB,-- 触发的闸门statusVARCHAR(16)NOTNULL,-- draft / reviewing / approved / sentvalid_untilDATE,-- 报价有效期,默认 7 天created_at TIMESTAMPTZDEFAULTnow());CREATETABLEquote_revision(id BIGSERIALPRIMARYKEY,quote_idBIGINTNOTNULLREFERENCESquote(id),fieldVARCHAR(64)NOTNULL,-- 改了哪个字段old_valueTEXT,new_valueTEXT,operatorVARCHAR(64)NOTNULL,-- 人工复核者reasonTEXT,-- 为什么改created_at TIMESTAMPTZDEFAULTnow());

quote_revision这张表看着多余,实际上是把老师傅的改价经验沉淀成训练数据的地方。跑三个月,你就能看到「AI 出的价,人平均往上调还是往下调、调在哪个字段上」——这就是下一次优化规则表的依据。

初版报价单给到业务时,建议就长这样(模板可直接抄):

【初版待确认】报价单 No. Q-20261013-018 客户:成都 XX 精密机械(B 类) 产品:不锈钢支架 304 / 500 件 ────────────────────────────── 材料成本 4.92 元/件 (304,1.85kg,损耗 12%) 加工费 13.20 元/件 (切割+折弯+焊接) 成本合计 21.12 元/件 建议单价 29.80 元/件 毛利率 29.1% 整单金额 14,900.00 元 报价有效期 7 天(至 2026-10-20) ────────────────────────────── ⚠️ 风险提示:无 📌 本单为初版,正式报价以业务确认后的报价单为准。

三个细节别省:逐项列出成本构成(业务一眼能看出哪项不对)、写出毛利率(便于快速判断该不该批)、固定标注「初版」(这是后面所有商务谈判的安全垫)。


九、必踩的五个坑

坑后果修法
让 LLM 直接算钱幻觉价,错一位数就是真金白银算术全部移到代码节点,模型只抽参数
单位不统一元/kg 和元/件混用,差出十倍提示词里强制单位归一,代码里再校验一次
交期随口承诺排产跟不上,客户投诉提示词明确禁止给绝对日期,只给区间
报价没有有效期原材料一涨,按老价交付就亏报价单固定写「有效期 7 天」
客户拿初稿来谈价把初版当正式报价,很难往回谈初稿明确标注「初版,以正式报价单为准」

第五条特别值得展开说一句。AI 出的报价如果能直接发到客户手上,那它就已经是一份对外承诺了。所以流程设计上,初版只发给内部业务,客户那一侧的正式报价单始终由人发出——这不是保守,这是把风险留在你能控制的那一侧。


十、怎么衡量有没有用

上线两周后别看「省了多少人」,看这四个数:

指标定义观察方向
报价响应中位时长询价到初稿的时长中位数从 24 小时级压到分钟级
初稿一次通过率未被人改价直接采用的占比反映规则表准不准,低于 60% 说明费率表要重做
改价方向分布人工改价是普遍上调还是下调普遍上调说明毛利率设低了
报价→订单转化报价后成交比例与响应时长做交叉对比

第一个和第二个是过程指标,用来调规则;第三个和第四个是结果指标,用来向老板说明价值。如果初稿一次通过率长期低于 60%,问题不在模型,在你的费率表——很多工厂的报价规则其实从来没被写下来过,这是这件事最难、也最有价值的部分。


写在最后

报价 Agent 的技术难度,其实比询盘接待 Agent 低:它不涉及多轮对话,也不涉及知识库检索,本质上就是「抽取 + 运算 + 分级」。

但它暴露的问题更大——它会把「你们厂的报价规则到底是什么」这件事,逼到你面前。很多工厂的报价依赖老师傅的经验,规则在他脑子里,不在纸上。做这件事的过程,就是把它变成四张表、一段可测试的代码。

三步起步:

  1. 先把最近 30 份标准件的实际报价单翻出来,倒推费率表(这一步比搭工作流重要得多);
  2. 把计算逻辑写成纯函数,用历史报价做回归测试,误差超过 5% 的先把规则改对;
  3. 再上工作流和人在环的闸门,先只让初稿发给内部业务,跑稳两周再考虑提效范围。

顺序别反。先让规则可计算、可复核,再谈自动化。

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

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

立即咨询