从外卖订单到AI编程:我在成都用NLP搞Prompt工程的实战笔记
上周五晚上十点,办公室只剩下我和隔壁组那个刚入职的实习生还在对着屏幕发愣。耳机里放着《City of Stars》,手边是已经凉透的第三杯美式——没错,又是被产品经理临时加需求的日子。这次的需求听起来还挺玄乎:“能不能让系统自动理解用户在外卖备注里写的‘不要香菜,多给点辣椒’这种话?”
我心想,这不就是个典型的自然语言处理(NLP)任务嘛。但问题在于,我们后端是Java栈,团队里没人正经搞过AI。更尴尬的是,离大促上线只剩两周了。
作为一个在美团干了四年的Java老油条,平时写写高并发接口、调调JVM参数还行,突然要碰NLP,说实话有点慌。不过转念一想,现在不是有各种大模型和AI编程工具吗?比如最近火出圈的 Claude Code,还有满大街都在聊的 Prompt工程,或许能曲线救国?
于是,我决定边听歌边撸代码,用 JavaScript 写个原型试试水——毕竟前端同学说他们那边跑JS快,而且Node.js部署也轻量。没想到这一试,还真摸出点门道来。
外卖备注里的“潜规则”:业务场景驱动的技术选型
先说清楚我们要解决的问题:用户在外卖下单时,会在“备注”栏写各种非结构化指令,比如:
- “米饭少给点,减肥中”
- “汤别洒了!上次洒了一半”
- “骑手小哥辛苦了,请放门口别按门铃”
这些话看似随意,但对履约体验影响巨大。如果系统能自动提取“少米饭”、“防洒漏”、“静音配送”等意图,并打上标签,就能自动触发对应的履约策略,比如通知商家调整分量、要求包装加固、或在派单时标注特殊要求。
传统做法是写一堆正则表达式,但你懂的,用户语言千奇百怪,昨天还有人写“香菜滚粗!!!”,正则根本覆盖不过来。这时候,NLP的价值就体现出来了。
但问题是:我们不是AI公司,没GPU集群,也没数据科学家。怎么办?
答案是:站在大模型的肩膀上,用Prompt工程+轻量微调搞定。
初探Prompt工程:从“问AI”到“教AI”
一开始我天真地以为,直接把用户备注扔给Claude或者GPT-4,问它“这段话里有什么特殊要求?”,就能拿到结构化输出。结果现实狠狠打了脸。
比如输入:
“老板,上次给的酸辣粉太酸了,这次能少放醋吗?谢谢啦~”
我期望的输出是:
{ "intent": "reduce_vinegar", "dish": "酸辣粉" }
但大模型经常返回一大段礼貌的中文解释,或者干脆胡编乱造一个不存在的菜品。更气人的是,有时候它会说“根据隐私政策,我不能处理订单信息”——大哥,这是模拟数据啊!
后来我才明白,Prompt不是提问,而是编程。你得像写函数签名一样,严格约束输入输出格式。于是我开始疯狂迭代Prompt,最终稳定下来的是这个模板(以Claude为例):
你是一个外卖订单意图识别助手。请从用户备注中提取关键指令,并严格按照JSON格式输出,不要任何额外解释。
输出字段:
- intent: 意图类型(如 reduce_vinegar, no_cilantro, extra_rice 等)
- dish: 涉及的菜品名称(若无则为null)
- note: 原始相关语句(用于人工复核)
用户备注:"{user_note}"
请输出:
配合上 {"max_tokens": 150, "temperature": 0.1} 这种低随机性配置,准确率一下从60%飙到了85%以上。
但这还不够。因为线上QPS可能上千,每次调大模型API又贵又慢。于是我们想到:能不能用大模型生成训练数据,然后训练一个小模型本地跑?
AI编程实战:用Claude Code生成数据 + JS微服务落地
这里就要吹一波 Claude Code 了。Anthropic新出的这个功能,不仅能理解代码上下文,还能根据自然语言描述生成高质量代码片段。我让它干了两件事:
- 批量生成模拟用户备注
- 自动生成标注JSON
比如我给它的指令是:
“请生成100条中国用户在外卖平台写的备注,内容涉及忌口、分量调整、配送要求等,语言要真实口语化,并附带对应的结构化标签。”
它真的给我吐出了像这样的数据:
{
"note": "青菜煮软一点,老人家牙口不好",
"label": { "intent": "soft_cooked", "dish": "青菜", "note": "青菜煮软一点,老人家牙口不好" }
}
有了5000条这样的合成数据,我立刻用 JavaScript 搭了个轻量级分类器。为什么选JS?因为我们前端团队有现成的TensorFlow.js pipeline,而且Node.js服务启动快、内存占用低,适合做边缘推理。
模型结构也很简单:
- 分词用
jieba的Node封装版 - Embedding用预训练的中文BERT-mini
- 分类头就一层全连接
训练脚本不到50行:
const tf = require('@tensorflow/tfjs-node');
const jieba = require('nodejieba');
// 加载合成数据
const dataset = loadSyntheticData('./data/notes_5k.json');
// 构建模型
const model = tf.sequential({
layers: [
tf.layers.embedding({ inputDim: vocabSize, outputDim: 128 }),
tf.layers.globalAveragePooling1D(),
tf.layers.dense({ units: 64, activation: 'relu' }),
tf.layers.dense({ units: intentClasses.length, activation: 'softmax' })
]
});
model.compile({ optimizer: 'adam', loss: 'categoricalCrossentropy', metrics: ['accuracy'] });
await model.fit(xTrain, yTrain, { epochs: 10, batchSize: 32 });
训练完模型只有8MB,放在K8s里跑,P99延迟<30ms,成本几乎可以忽略不计。
从原型到上线:踩过的坑和学到的教训
当然,过程远没有上面写得那么顺利。中间至少翻了三次车:
坑1:方言和网络用语搞崩了分词器
成都用户爱写“微辣都算中辣了,求求了给个真微辣”,结果“求求了”被jieba切成“求 / 求 / 了”,embedding完全失效。后来我们手动加了词典,把“求求了”、“绝绝子”、“尊嘟假嘟”这类高频网络语标成整体。
坑2:大模型幻觉导致脏数据
Claude生成的数据里,居然有“不要放量子波动速读调料”这种鬼话……我们不得不加一道人工审核过滤,再用规则引擎兜底。
坑3:Java和JS服务怎么打通?
最后我们搞了个混合架构:
- 前端Node.js服务做实时意图识别
- 结果通过gRPC推给Java主系统
- Java这边负责落库、触发履约逻辑
虽然有点“缝合怪”,但在 deadline 压力下,能跑就行(狗头)。
效果对比:老方法 vs NLP方案
上线两周后,我们拉了数据对比:
| 指标 | 正则规则引擎 | NLP+Prompt工程 | 提升 |
|---|---|---|---|
| 意图识别准确率 | 62% | 89% | +27% |
| 覆盖用户备注比例 | 45% | 83% | +38% |
| 人工客服介入率 | 12% | 5% | -7% |
| 单次推理成本 | ¥0.0001 | ¥0.0015 (API) → ¥0.00005 (本地) | 降96% |
最惊喜的是,差评里关于“没按备注做”的投诉下降了近一半。产品经理终于露出了久违的笑容,还请我们吃了顿火锅(当然是公司报销)。
我的一些思考:NLP不是魔法,而是工程
干了四年外卖系统开发,我越来越觉得:技术没有高低贵贱,能解决问题的就是好技术。NLP听起来高大上,但落到业务里,其实就是“理解用户那几句大白话”。
而现在的 AI编程工具(比如Claude Code、GitHub Copilot)真正改变的是我们的工作流:
- 不再从零造轮子,而是用大模型生成初版代码或数据
- Prompt工程 成了新的“接口设计”——你如何描述问题,决定了AI能否正确协作
- 小模型+大模型混合部署,成了性价比最高的落地路径
另外,别迷信“端到端”。我们在项目后期还是加了规则引擎做后处理,比如把“不要葱”和“不要香菜”合并成“no_allium”标签。AI负责泛化,规则负责兜底,这才是稳如老狗的做法。
写在最后:成都的慢生活与技术的快节奏
有时候我觉得,在成都这种生活节奏舒服的城市写代码,反而更容易沉下心来做点扎实的东西。不用天天卷“颠覆式创新”,而是盯着一个具体的用户痛点,一点点打磨。
就像这次的NLP尝试,从被产品经理“逼上梁山”,到用JavaScript搭原型,再到和Java主系统融合上线,整个过程充满了糙快猛的互联网味道,但也带着工程师特有的较真劲儿。
如果你也在传统业务团队,想尝试AI但怕成本高、周期长,我的建议是:
- 先用 Prompt工程 快速验证可行性
- 借助 AI编程工具 生成数据或代码
- 用轻量语言(如JS/Python)做MVP
- 最后和现有系统集成,别追求一步到位
技术永远服务于业务。而最好的技术,往往是那些让用户感觉不到技术存在的技术——比如你点了一份酸辣粉,它真的就没那么酸了。
(完)
P.S. 本文所有代码和Prompt模板已脱敏,如有需要可私信交流。别问,问就是“还在改Bug”。

评论 0