1. 低效提示踩坑现场:一个“智能客服”翻车实录
去年我帮朋友搭电商客服机器人,需求很简单:用户问“我的快递到哪儿了”,机器人返回订单状态。
第一次写的提示只有一句话:
你是客服,请回答用户问题。
结果 ChatGPT 把“我的快递到哪儿了”当成开放式闲聊,开始讲物流发展史,还贴心附赠 300 字快递小哥辛苦感言—— token 烧掉 400+,答案却毫无订单号、物流单号,前端直接超时。
第二次加了一句“请用一句话”,它倒是短了,却返回:“您的快递正在路上。”——仍然没订单号。
第三次我怒了,把用户原句+订单号拼进去,它干脆把订单号当收货人名字,回复:“亲爱的 123456789,你的快递正在路上。”
那一刻我深刻体会到:提示不给骨架,模型就自由发挥;提示不给边界,输出就失控。
2. 提示设计三板斧:零样本、少样本、指令细化怎么选
先放一张“选型速查表”,后面再逐一举例。
| 场景 | 推荐套路 | 关键口诀 |
|---|---|---|
| 需求明确、输出格式固定 | 零样本+指令细化 | “角色+任务+格式+边界”四段式 |
| 需求模糊、需要模仿风格 | 少样本+思维链 | 给 2~3 组“输入→输出”示例,末尾留空让模型补 |
| 创意开放、允许发散 | 零样本+开放提问 | 只给角色+目标,让模型自由发挥 |
一句话总结:
- 零样本:快、省 token,适合格式死板或你有强后置校验。
- 少样本:贵一点,但能“照猫画虎”,适合风格/口径难描述。
- 指令细化:在零样本里把“格式、边界、反例”写全,80% 生产问题都能 cover。
3. 渐进式代码示例:从“能跑”到“能上线”
下面 3 段代码均基于 OpenAI Python SDK ≥1.0,默认model="gpt-3.5-turbo",复制即可跑通。
每段都给出“运行成本”与“可继续优化的点”,方便你直接往项目里搬。
3.1 基础提示:先让模型“说人话”
目标:用户问订单,返回“状态+下一步动作”,字数≤30。
from openai import OpenAI client = OpenAI() def ask_order_basic(order_id: str) -> str: prompt = f""" 角色:你是电商客服机器人,只回答物流问题。 任务:根据订单号{order_id}查询状态,用一句话告诉用户“当前状态+下一步动作”。 约束:30 字以内,禁止多余解释。 """ resp = client.chat.completions.create( model="gpt-3.5-turbo", messages=[{"role": "user", "content": prompt}], temperature=0 ) return resp.choices[0].message.content print(ask_order_basic("123456789")) # 示例输出:您的订单已到达深圳转运中心,预计明日派送。运行成本:约 60 token;问题:每次都要把“角色+任务”重复传,长对话浪费钱。
3.2 上下文管理:把“角色”塞进 system,少重复
目标:多轮对话里记住“我是客服”+“只答物流”,用户可追问。
def create_session(): return [ {"role": "system", "content": "你是电商客服机器人,只回答物流问题,回答≤30 字。"} ] def chat(session: list, user_q: str) -> str: session.append({"role": "user", "content": user_q}) resp = client.chat.completions.create( model="gpt-3.5-turbo", messages=session, temperature=0, max_tokens=60 # 硬上限,防止超长 ) answer = resp.choices[0].message.content session.append({"role": "assistant", "content": answer}) return answer # 模拟两轮对话 s = create_session() print(chat(s, "我的快递到哪儿了?")) # 第一轮 print(chat(s, "明天能到吗?")) # 第二轮,模型仍记得身份优化点:
- system 消息只传一次,后续轮次省 30% token。
- 把
max_tokens写死,避免偶尔抽风写出 200 字小作文。
3.3 输出格式化:让模型“按模板 JSON 返回”,前端直接解析
目标:返回结构化数据{status, next_action, eta},方便前端渲染进度条。
from datetime import datetime, timedelta import json def ask_order_json(order_id: str) -> dict: system = """ 你是物流查询API,只输出合法JSON,格式: {"status": "<当前状态>", "next_action": "<下一步>", "eta": "YYYY-MM-DD"} 禁止任何解释或markdown代码块。 """ user = f"订单号{order_id},当前状态?" resp = client.chat.completions.create( model="gpt-3.5-turbo", messages=[{"role": "system", "content": system}, {"role": "user", "content": user}], temperature=0, max_tokens=120 ) text = resp.choices[0].message.content # 简单兜底:若模型手抖写 ```json 包裹,先剥掉 text = text.strip().removeprefix("```json").removesuffix("```").strip() return json.loads(text) # 让前端直接拿到字段 print(ask_order_json("123456789")) # 示例输出:{'status': '运输中', 'next_action': '到达派送网点', 'eta': '2024-07-12'}踩坑提示:
- 一定在 system 里强调“不要 markdown 代码块”,否则 3.5 偶尔给你整 fenced code。
- 如果下游强依赖字段,建议加
Pydantic再做一层校验,模型仍可能漏 key。
4. 性能 & 安全:省钱的细节与防“嘴瓢”方案
4.1 Token 节省技巧
- 角色描述固化在 system 后,别再每轮重复“你是一个客服机器人……”。
- 列表/映射型数据让模型“只返回 key”,value 由本地字典补。
例:让模型输出“status_code: 1”,前端再映射“1→运输中”,可把输出 token 砍半。 - 用
gpt-3.5-turbo做“草稿”,复杂场景再路由到gpt-4,成本可降 70%。
4.2 内容过滤与合规
- 先过一遍免费 Moderation API,命中政治/暴力直接拒答,节省后续所有开销。
- 对可能暴露个人信息的字段(手机号、地址)做本地正则脱敏,再送模型。
- 若业务在欧盟,记得把 PII 伪化,日志保留 30 天自动清理,免 GDPR 罚款。
5. 生产环境检查清单:5 条黄金法则
- 角色+任务+格式+边界 四段式提示,缺一段就多 30% 纠错成本。
- system 消息只写一次,用户侧永远看不到,减少重复 token。
- 输出要结构化,先写“只返回 JSON/CSV”,再补字段说明,前端省心。
- 必加 max_tokens 与 temperature=0,把“自由发挥”关进笼子。
- 上线前跑 100 条自动化回归:改提示→跑脚本→diff 结果,防止手抖改崩。
6. 写在最后:把提示工程再往前一步
当你能稳定拿到结构化、低 token、高可靠的回答,其实就已经拥有了一个“对话 API”。
下一步可以给它装上真正的耳朵和嘴巴——让语音实时流进来,文本回答再秒级合成语音,用户拿起手机就能“打电话”与 AI 对话。
我上周就在 从0打造个人豆包实时通话AI 实验里,把上面这套提示直接嵌进火山引擎的豆包实时语音链路:ASR 把用户话音转文字 → 我的提示模板负责思考 → TTS 把 JSON 里的 next_action 读出来,端到端延迟 800 ms,小白也能跟着文档跑通。
如果你已经写好提示,却还没试过“能听会说”的完整体验,不妨点过去玩一圈,把提示工程真正落地到实时通话场景。