Skip to content

Zero-shot与Few-shot的成对实验 ​

上一节定义输出校验,本篇开始设计真正发送给模型的消息。任务是判断用户请求的动作,而非出现的单词。因此“不要退款,查询配送”必须标为shipping。zero-shot只给规则;few-shot在相同规则后补边界例子。对照中模型、保留输入、调用参数不变,只改变示例。

例子不能包含测试原句,否则评估混入记忆命中。这里保留输入包含同义改写和提及但未请求的退款;分别记录JSON合法性与语义正确性。两者分开,才能区分格式修复和任务理解。

首次完整实验 ​

先按本地模型入口启动127.0.0.1:8087。代码保存为prompt_pairs.py,用Python3.12执行。标准库HTTP客户端默认调用本机真实模型;支持有凭据的云模型分支但未执行。

python
import json,os
from urllib.request import Request,urlopen

def generate(messages):
    if os.environ.get('GENERATOR_MODE','local')=='openai':
        body={'model':os.environ['OPENAI_MODEL'],'messages':messages,'response_format':{'type':'json_object'}}
        req=Request('https://api.openai.com/v1/chat/completions',data=json.dumps(body).encode(),headers={'Authorization':'Bearer '+os.environ['OPENAI_API_KEY'],'Content-Type':'application/json'})
        return json.load(urlopen(req,timeout=60))['choices'][0]['message']['content']
    prompt='\n'.join(m['role']+': '+m['content'] for m in messages)+'\nassistant:'
    req=Request('http://127.0.0.1:8087/generate',data=json.dumps({'prompt':prompt,'max_new_tokens':16}).encode(),headers={'Content-Type':'application/json'})
    return json.load(urlopen(req,timeout=60))['text']

contract='Classify requested action as refund, shipping, or other. Mention alone is not a request. Return JSON {"label":"..."}.'
examples=[{'role':'user','content':'Do not refund; track delivery.'},{'role':'assistant','content':'{"label":"shipping"}'},
          {'role':'user','content':'I want a refund.'},{'role':'assistant','content':'{"label":"refund"}'}]
tests=[('Refund policy is clear; where is my parcel?','shipping'),('Please return my payment.','refund')]
records=[]
for variant,shots in [('zero',[]),('few',examples)]:
 for text,expected in tests:
    messages=[{'role':'system','content':contract},*shots,{'role':'user','content':text}]
    raw=generate(messages)
    try:
        result=json.loads(raw)
        label=result['label']
        valid=set(result)=={'label'} and label in {'refund','shipping','other'}
    except (ValueError,KeyError,TypeError):label=None;valid=False
    records.append({'variant':variant,'input':text,'raw':raw,'valid':valid,'correct':valid and label==expected})
print(json.dumps(records,indent=2,ensure_ascii=False))
# Store failures as failures; no fabricated expected model outputs.
assert len(records)==4

本地tiny-gpt2实际四次都输出重复词,valid/correct均false。这是模型不具备任务能力的真实结果,不能把few-shot预期答案写进日志来制造提升。要测有能力模型,在已配置凭据的终端设GENERATOR_MODE=openai、OPENAI_MODEL为账户可用且支持JSON模式的模型,再执行相同脚本;会产生API费用,本节没有执行该分支。凭据只从环境读取,不写代码。网络/拒绝/截断应单独记为失败,不能计入正确。JSON模式限制格式,不保证字段或业务规则;支持strict JSON schema的模型可进一步约束形状,仍要做服务端验证。

few-shot可能增加偏置:若全是退款例子,模型可能把所有输入都选refund。示例应覆盖边界而非重复简单题。对样本顺序做置换、保留输入加否定和同义词,才知道提升是否稳定。不能根据两个测试宣称全面改进。

抽取、摘要与代码各自需要什么合同 ​

抽取提示可以是:Extract the stated refund deadline as JSON {days:number|null,quote:string|null}. Do not infer missing values. Input: opened goods cannot be returned. 此输入没有天数,预期days与quote为null;另用“Return unopened goods within 7 days”检查days=7且quote来自原句。数字类型必须在解析后校验,不能接受字符串“7 days”。

摘要提示可以是:Summarize as JSON {summary:string}. Preserve all exceptions and deadlines. Text: Goods may be returned within seven days, except opened goods. Shipping fees are not refundable. 可接受摘要必须同时保留七天、开封例外与运费限制。错误压缩“7天内可退”丢失两个限定条件;对这种短政策,完整证据通常比压缩更安全。自动关键词只能检查遗漏,不能证明否定方向正确,还需以具体“已开封第3天”和“未开封第8天”问答验证。

代码提示可以是:Return JSON {code:string} implementing refund_allowed(days:int,opened:bool)->bool. True only for 0<=days<=7 and not opened. No I/O, imports or network. 验收必须包含(-1,false)、(7,false)、(8,false)、(3,true)。先将代码作为数据保存并审查,再在无凭据、无网络、资源受限的独立执行器运行,不能在应用进程直接exec。生成代码正确与授权执行是两件事。

这三种提示可用正文generate函数替换messages中的任务和输入执行,模型输出照样记录raw;小模型失败仍应如实保留。任务各自的验证器不能复用label枚举冒充验收。

练习 ​

新增一个示例“Refunds are expensive but track shipping please”作为shipping,再保留完全不同的新输入“Do not send another parcel; pay me back”。比较zero/few,不更改保留答案;另写出摘要压缩前后的两个例外测试。

完成后查看本章答案。

下一章:上下文组织、压缩与版本演进。

用心记录每一步成长