本文最后更新于 2026-05-18,文章内容可能已经过时。

一个周末,我们用AI把制造业报价从40分钟压到5分钟——踩了五个坑才跑通

周五下午四点,客户催报价。

业务员小李盯着三张Excel表,计算器按了第五遍,还是算错了。

原材料单价、损耗率、加工费、运费、利润率……每一项都要手动查、手动算、手动填。一份报价单平均要花40分钟,出错了还得重来。客户那边已经在问"怎么还没发过来",小李额头上的汗比窗外的太阳还烫。

这不是某一家工厂的故事。这是中国几十万家制造业中小厂的日常。

我们花了一个周末,把这个流程改掉了。不是买什么系统,不是私有化部署大模型,就是调API、写逻辑、踩坑、修坑。这篇文章把整个过程原原本本写出来——包括那些让我们头疼了好几个小时的坑。

---

一、报价地狱:这家五金厂的真实现状

我们合作的这家厂在广东,做五金配件,SKU大概有两三百个,客户以外贸订单为主。

报价流程是这样的:

1. 客户发来需求(有时是邮件,有时是微信,有时是一张手机拍的图纸)

2. 业务员翻出物料价格Excel,找到对应品类

3. 手动计算损耗率(不同材料损耗不一样,铝件和铜件差很多)

4. 加上加工费、包装费、运费估算

5. 乘以利润率(还要看客户级别,老客户和新客户不一样)

6. 填进报价单模板,排版,发出去

平均一份报价40分钟。旺季一天要出七八份报价,业务员基本没时间干别的。出错率也不低——价格表更新了但业务员手上还是旧版,或者损耗率搞混了,这种事每个月都会发生几次。

老板的原话是:"我不是不想做数字化,但那些ERP系统动辄几十万,我们这种规模根本用不起。"

这句话让我们找到了切入点:不需要ERP,只需要一条能跑通的流水线。

---

二、我们设计的方案:五步流水线

整条流水线的逻辑并不复杂:

客户需求输入(自然语言)

AI解析意图(提取品类、规格、数量、交期)

查询物料数据库(结构化Excel/数据库)

调用价格计算逻辑(损耗率、加工费、利润率)

生成格式化报价单(Word/PDF输出)

为什么用API而不是本地模型?

中小厂没有GPU服务器,本地部署成本和维护门槛都太高。调API按量付费,测试期成本极低,跑通之后再考虑优化。

为什么用Function Calling而不是简单Prompt?

这是关键决策。如果只用Prompt让模型"输出报价",模型会把计算逻辑和输出混在一起,既不可控也不可审计。Function Calling的思路是:让模型只做它擅长的事——理解意图、提取结构化信息,计算和查询交给确定性代码来做。

这个分工非常重要,后面踩的坑很多都跟这个边界有关。

---

三、落地时踩过的五个真实坑

坑1:Prompt写得"太聪明",模型反而乱发挥

最开始我们写了一个很详细的Prompt,把损耗率计算规则、利润率档位、各种特殊情况都塞进去,大概有800个token。

结果模型开始自己"算价格"。它会说"根据铝材当前市场价大约每吨18000元……"——问题是,它根本不知道这家厂的实际采购价,它在用训练数据里的"常识"瞎估。

错误版Prompt(节选):
你是一个专业的五金报价助手,请根据客户需求计算报价。

铝材损耗率约8-12%,铜材损耗率约5-8%,

利润率一般在15-25%之间,请综合考虑后给出合理报价。

修正版Prompt:
你是一个信息提取助手。你的唯一任务是从客户需求中提取以下字段:
  • 产品品类(必填)
  • 材质(如有)
  • 规格尺寸(如有)
  • 数量(必填)
  • 交货期要求(如有)

不要计算价格,不要做任何估算,只提取信息并调用query_material函数。

如果信息不足,返回missing_fields列表。

核心教训:给模型划定边界,比给它更多信息更重要。

---

坑2:客户输入是模糊的人话,解析失败率超30%

客户不会按照你的格式说话。真实输入长这样:

"要一批铝的,圆的那种,大概手掌这么大,要500个,下个月要用"

"圆的那种"是什么规格?"手掌这么大"是直径多少?"下个月"是几号?

我们统计了前两周的测试数据,模糊输入导致解析不完整的比例超过30%。

解决方案是加一层澄清对话

# Function Calling定义示例

functions = [

{

"name": "query_material",

"description": "查询物料价格数据库",

"parameters": {

"type": "object",

"properties": {

"category": {"type": "string", "description": "产品品类"},

"material": {"type": "string", "description": "材质"},

"diameter_mm": {"type": "number", "description": "直径(毫米)"},

"quantity": {"type": "integer", "description": "数量"},

"missing_fields": {

"type": "array",

"items": {"type": "string"},

"description": "信息不足时填写缺失字段列表"

}

},

"required": ["category", "quantity"]

}

}

]

missing_fields不为空时,系统自动回复客户追问缺失信息,而不是强行生成一个错误报价。

这个设计让解析失败率从30%+降到了不到8%。

---

坑3:价格数据在Excel里,结构混乱,AI读不准

这家厂的价格表是一个历史悠久的Excel,合并单元格、颜色标注、备注写在角落里……这种文件,直接让AI读会出各种幺蛾子。

我们做了一件重要的前置工作:把Excel"压平"成结构化的SQLite数据库,同时写了一个简单的数据清洗脚本,把合并单元格展开,把颜色标注转成字段,把备注里的特殊规则提取出来。

import pandas as pd

import sqlite3

读取Excel并清洗

df = pd.read_excel('price_table.xlsx', header=2) # 跳过合并的表头行

df = df.dropna(subset=['品类', '单价'])

df.columns = ['category', 'material', 'spec', 'unit_price', 'loss_rate', 'note']

写入SQLite

conn = sqlite3.connect('materials.db')

df.to_sql('materials', conn, if_exists='replace', index=False)

这一步花了将近半天,但值得。数据质量是整个流水线的地基,地基不稳,上面盖什么都会塌。

---

坑4:生成的报价单格式老板不认

第一版自动生成的报价单,内容是对的,但格式和老板用了十几年的模板差太多——字体、表头位置、盖章区域……老板看了摇头:"这发给客户客户会觉得我们不专业。"

这个坑的解决方案很简单,但费时间:不要让AI生成最终格式,而是用Python操作一个固定的Word模板,把AI提取的数据填进去。

from docx import Document

from docx.shared import Pt

def fill_quotation_template(data: dict) -> str:

doc = Document('quotation_template.docx') # 用老板认可的模板

# 填写客户信息

for para in doc.paragraphs:

if '{{client_name}}' in para.text:

para.text = para.text.replace('{{client_name}}', data['client_name'])

# 填写报价明细表格

table = doc.tables[0]

for i, item in enumerate(data['items']):

row = table.rows[i + 1]

row.cells[0].text = item['description']

row.cells[1].text = str(item['quantity'])

row.cells[2].text = f"¥{item['unit_price']:.2f}"

row.cells[3].text = f"¥{item['total_price']:.2f}"

output_path = f"quotations/QT_{data['order_id']}.docx"

doc.save(output_path)

return output_path

AI负责理解,代码负责格式。这个分工不能乱。

---

坑5:Token成本没算好,第一周账单吓了一跳

第一周测试,我们没有做任何Token优化,每次请求都把完整的价格表背景信息塞进去,加上对话历史,单次请求轻松超过3000 token。

一周下来,账单比预期高了将近四倍。

排查之后发现两个主要问题:

1. System Prompt太长:把所有规则都写进去了,其实很多规则是用不到的

2. 对话历史没有截断:多轮对话把所有历史都带上了,越聊越贵

优化方案:

  • System Prompt精简到300 token以内,只保留角色定义和核心约束
  • 对话历史只保留最近3轮,更早的轮次丢弃
  • 物料数据不放进Prompt,通过Function Calling查询返回

优化后,单次报价的Token消耗降到了优化前的约1/5,成本回到了可接受范围。

⚠️ 重要提示:上线前一定要先估算Token用量,用小批量测试数据跑一遍,别等账单来了才发现。

---

四、最终效果——数字说话,但也说局限

改造前后的对比:

| 指标 | 改造前 | 改造后 | | 单份报价耗时 | 约40分钟 | 约5分钟 | | 价格计算出错率 | 每月数次 | 接近零(计算逻辑确定性执行) | | 业务员同时处理报价数 | 1份 | 可并行处理多份 | | 旺季加班频率 | 几乎每天 | 明显减少 |

业务员小李的原话:"现在客户发过来,我看一眼确认一下,点一下就出去了。以前我最怕周五下午客户催报价,现在不怕了。"

老板的态度变化更有意思。一开始他是持怀疑态度的,觉得"AI能算准吗"。第一周跑下来,他开始主动问:"这个能不能也接到我们的微信群里,客户在群里说要报价直接就出?"

但我们也要诚实交代局限性:
  • 复杂定制件还是要人工介入:如果客户的需求涉及特殊工艺、非标尺寸或者需要工程师评估,AI流水线只能做到"初步整理信息",最终报价还是要人来拍板
  • 价格表需要人工维护:原材料价格波动,数据库要定期更新,这个环节没有自动化
  • 异常输入需要兜底机制:极端模糊或者完全跑偏的需求,系统要能识别并转人工,不能强行输出一个错误报价

AI不是万能的,边界在哪里要说清楚。这套方案解决的是"标准化报价"这个最高频、最痛的场景,不是解决所有问题。

---

五、你也能复刻——最小可行方案

如果你也想在自己的厂或者客户那里跑通这套逻辑,这里是最低成本的启动路径:

前置条件检查:
  • [ ] 有一份相对规范的价格Excel(哪怕有点乱,能清洗就行)
  • [ ] 有一个固定的报价单模板(Word格式最好)
  • [ ] 有一个懂基础Python的人(或者愿意学)
  • [ ] 有API调用权限
技术门槛评估:
  • 会Python基础:可以自己跑通
  • 不会编程但有IT支持:找一个外包或者内部技术同事,一个周末够了
  • 完全没有技术资源:先把价格表整理干净,这一步无论如何都要做
推进建议:

不要一上来就想做完整系统。先跑通最小闭环:只处理最高频的5-10个SKU,只支持最标准的需求格式,先让老板和业务员看到效果,再逐步扩展。

整套方案的API调用核心用的是标准OpenAI兼容接口。我们实际跑通用的是 [api.884819.xyz](https://api.884819.xyz)——支持多个主流模型切换,对这类结构化任务的Function Calling支持稳定,小厂测试期成本压得很低。新用户注册即送体验token,注册只需要用户名和密码,不需要邮箱验证,国产模型(Deepseek/千问等)完全免费,没有月租没有订阅。如果你想复刻这个方案,从这里开一个key是最快的起点。

---

结语

这不是什么颠覆性的革命。

它就是一个周末的工程:理清流程、整理数据、写几百行代码、踩几个坑、再修几个坑。

但它让一个业务员从此不用在周五下午盯着计算器发愁,让一个老板第一次觉得"数字化"不是遥不可及的事。

可复制、有边界、值得试。

---

这次做的是报价单,相对结构化,是AI落地制造业最容易切入的场口。

但我们在做这个项目时发现了一个更难、也更值钱的问题——

客户的历史订单数据里,藏着定价策略的秘密,但没有人整理过。

哪些客户在涨价时最不敏感?哪些品类的利润率其实被低估了十几年?这些答案就在那堆积灰的订单Excel里,但没有人有时间去看。

下一篇,我们来聊聊怎么用RAG让老板第一次"看懂"自己十年的生意。

---

本文由8848AI原创,转载请注明出处。关注8848AI,带你从零开始学AI。

#AI落地 #制造业数字化 #Function Calling #API开发 #AI教程 #Python #8848AI #中小企业数字化