Prompt 方法论
**Prompt 场景三原则**:一个业务一个场景、一个模型版本一个场景、一个模板一个场景——场景变了就换模板,别凑合。 默认模型什么都不知道,所以要先背景后要求: ```text 1. 人物/地点/时间/事件 背景交代 2. 角色定义(你是一个...) 3. 任务步骤(先做什么再做什么) 4. 输入说明 5. 输出格式约定 ```
**结构化**:自然文本 → 结构化文本的过渡。结构化减少歧义、便于程序交互(JSON 化)。 精准输出用 JSON 逐字段定义格式: ```text 输出格式: { "name": "套餐名称,string", "price": {"operator": ">=|<=|==", "value": "数字"} } ``` 配合 API 的 `response_format={"type":"json_object"}` 双保险。
**核心是思维链 = 伪算法**:分几步做成一件事。 - 像人一样思考:步骤化、一段文本一个意思、多举例 - 不熟的领域先问 LLM 要步骤(让它先给方法清单,再逐步执行) - 有时一字之差对生成概率影响很大,也可能毫无影响——迭代试错是常态 简易调用(供下文案例复用): ```python from tpf.llm.ollama import chat_ollama from tpf.llm import chat def ask(prompt, model="gpt-4o-mini"): return get_completion(prompt, model=model) # 本地小模型 res = chat_ollama(prompt, model='deepseek-r1:1.5b', base_url='http://localhost:11434/v1/') ```
案例实战:流量套餐条件识别(完整迭代链)
任务:把用户对手机流量套餐的自然语言需求,转成机器可处理的选择条件。 第一步只做**任务描述+实体关系**——先讲清实体(套餐的三个属性),模型才理解语义: ```python instruction = """你的任务是识别用户对手机流量套餐产品的选择条件。 每种流量套餐产品包含三个属性:名称(name),月费价格(price),月流量(data)。 用户输入会包含选择条件,请提取并以 JSON 格式输出。""" input_text = "办个100块以下的套餐,流量要多" prompt = f"{instruction}\n用户输入:\n{input_text}" response = ask(prompt) ```
加输出格式约束 + API 层 json_object: ```python prompt = f"""{instruction} 以 JSON 格式输出,字段:name(string)、price(number)、data(number)""" response = client.chat.completions.create( model="gpt-4o-mini", messages=[{"role":"user","content":prompt}], response_format={"type":"json_object"} # 双保险 ) ```
**表达式化**:中文条件 → 可执行查询结构(operator + value + sort): ```json { "data": {"operator": ">=", "value": 100}, "price": {"operator": "<=", "value": 100}, "sort": {"ordering": "asc", "key": "data"} } ``` 把"流量要多"翻译成 `data>=100 + sort(data desc)`——prompt 里定义 operator 取值集合(>= / <= / ==)与 sort 结构即可。
**增加示例(few-shot)**——用 `query()` 模板函数批量挂示例: ```python examples = [ {"input":"便宜的套餐","output":{"sort":{"ordering":"asc","key":"price"}}}, {"input":"100块以内的月租","output":{"price":{"operator":"<=","value":100}}}, {"input":"流量大于50G","output":{"data":{"operator":">=","value":50}}}, # ... 共 9 例 ] def query(user_input): ex = "\n".join( f"输入:{e['input']}\n输出:{json.dumps(e['output'],ensure_ascii=False)}" for e in examples) return f"{instruction}\n\n示例:\n{ex}\n\n用户输入:\n{user_input}" ```
**针对不足补充**:实测发现"50元左右"被判成 `==` 不合理 → 增加 `fluctuation`(波动)字段并在规则与示例中显式声明: ```json {"price": {"operator": "==", "value": 50, "fluctuation": "20%"}} ``` 这就是 prompt 迭代的范式:跑 badcase → 定位规则缺失 → 补规则 + 补对应示例 → 回归。
**多轮对话**:把对话历史连同"每轮对应的 JSON"一起作为示例,再拼 context: ```python examples_chat = [ {"messages":[{"role":"user","content":"便宜点的"}, {"role":"assistant","content":"{\"sort\":...}"}, {"role":"user","content":"流量再多点"}], "output": {"sort":{"ordering":"asc","key":"price"}, "data":{"operator":">=","value":80}}}, ] # context = 已有对话历史 + 当前问题,一并进 prompt ``` 效果:模型能基于上一轮的条件叠加修改,而不是每次从零理解。
小模型适配(deepseek-r1 本地版)
同一套模板换本地 `deepseek-r1:1.5b`(chat_ollama 封装,base_url 指向 ollama): - 1.5b:多数输入理解尚可,但**丢 fluctuation 字段**、偶尔返回空 `{}` - 8b:仍有不稳定输出 - 14b:稳定但慢(一次约 11s vs 1.5b 的 1s)
针对性优化策略: 1. **按运行结果补示例**:把 badcase 加为近似示例——加到 4 个相似示例后 1.5b 输出才稳定 2. **降级链**:1.5b 返回空/缺字段 → 重试 3 次(字段有值即停)→ 仍失败换 14b 3. 成本视角:1.5b 快而糙适合第一道,14b 稳而慢做兜底——组合优于单选 ```python def ask_robust(prompt): for _ in range(3): out = chat_ollama(prompt, model='deepseek-r1:1.5b') d = parse(out) if d and d.get("price") or d.get("data"): return d return parse(chat_ollama(prompt, model='deepseek-r1:14b')) ```
代码场景 Prompt
实用 prompt:让 LLM 把重依赖代码改成"可选依赖"(torch 可选、延迟导入): ```text 请优化以下代码,要求: 1. torch 为可选依赖:模块导入时不强制 import torch 2. 使用处再延迟导入,并用 try/except ImportError 给出友好提示 3. 不改变已有函数的外部行为 代码如下:... ``` 同类套路适用于"去 pandas 依赖/加超时重试/统一日志"等机械改造——描述约束比描述实现更有效。
- OpenAI 官方 prompt 教程与示例:platform.openai.com/docs/guides/prompt-engineering - microsoft/promptbase:提示词工程资产库(市场/购买/案例) - 自建 GPTs 案例库:github.com/73xuetu/GPTs - 提示词市场(图像类 prompt 如"自拍"模板)可直接复用后微调
参考
     OpenAI Prompt Engineering 
     microsoft/promptbase