CODING WITH AI · LECTURE 06

已保存可复算的 CPU 教学输出。ICL fixture 为合成评分测试,所有 Lab 均未调用真实模型。

LAB 04 · 固定参数的 ICL 对照:192 请求离线链路

这项研究设计问:固定模型时,本轮提示里的示例与规则怎样影响关系判断与任意标签约定?我们先把数据、请求与评分做成可检查的完整链路,再决定是否投入真实模型运行。

现有结果仅来自离线 dry-run。所有带 SYNTHETIC 的输出都是人工合成评分 fixture,不是模型实测,不能用于判断 ICL 效果。没有调用 API、下载模型或发起 192 次真实推理。

你会获得 6 个示例、24 条留出记录、3 种全局循环映射、192 个完整请求、严格评分及逐请求存档格式。

1. 任务与评价先于模型

读“对照 12,处理 9”应先判断减少;当前任意标签映射若是增加→K、减少→M、相同→R,才输出 M。数字关系与本轮约定是两个不同问题。

留出集固定处理值 9、12、15、18、21、24、27、30。每个处理值配对照 t−3、t、t+3,因此同一处理值包含三种答案。部分文字把处理写在前面,部分把对照写在前面;同组措辞与对象对三类保持平衡。这样不能只看处理数值、词汇或数字位置作答。示例对照/处理数值对与留出完全分离。

查看与修改计算代码
import json, hashlib, collections, pathlib, datetime
LABELS=['增加','减少','相同']
MAPS=[dict(zip(LABELS,labels)) for labels in [('K','M','R'),('M','R','K'),('R','K','M')]]
DEMO_PAIRS=[(10,14),(10,6),(10,10),(8,11),(8,5),(8,8)]
SYSTEM='你根据本次输入完成记录比较任务。仅输出要求的单个标签,不补充解释。'

def relation(control,treatment):
    return '增加' if treatment>control else ('减少' if treatment<control else '相同')

def make_data():
    demos=[]
    for i,(c,t) in enumerate(DEMO_PAIRS):
        demos.append({'id':f'E{i+1:02d}','control':c,'treatment':t,'text':f'样本标记值:对照组 {c},处理组 {t}。','semantic':relation(c,t)})
    test=[]
    objects=['菌落计数','荧光读数','叶片数量','吸光读数','分子数量','信号强度','斑点数量','颗粒数量']
    # Every treatment value has one row from each class; wording/object stay identical within each triple.
    for j,t in enumerate(range(9,31,3)):
        for c in (t-3,t,t+3):
            wording=(f'{objects[j]}记录中,对照为 {c},处理为 {t}。' if j%2==0 else f'{objects[j]}记录中,处理为 {t},对照为 {c}。')
            test.append({'id':f'T{len(test)+1:02d}','control':c,'treatment':t,'object':objects[j],'text':wording,'semantic':relation(c,t)})
    return demos,test

def build_prompt(condition,row,demos,mapping=None):
    intro='请比较记录中的处理读数相对于对照读数的方向。'
    if condition in ('A','B'): intro+='只输出增加、减少或相同之一。'
    else: intro+='按本轮约定只输出 K、M 或 R 之一。'
    if condition=='C': intro+='本轮规则:'+';'.join(f'{x}→{mapping[x]}' for x in LABELS)+'。'
    lines=[intro]
    if condition in ('B','D'):
        lines.append('示例:')
        for ex in demos:
            label=ex['semantic'] if condition=='B' else mapping[ex['semantic']]
            lines.append(ex['text']+' 输出:'+label)
    lines+=['当前记录:'+row['text'],'输出:']
    return '\n'.join(lines)

def make_requests():
    demos,test=make_data(); requests=[]
    for condition in ('A','B','C','D'):
        maps=[(None,None)] if condition in ('A','B') else list(enumerate(MAPS))
        for mapping_id,mapping in maps:
            for row in test:
                expected=row['semantic'] if mapping is None else mapping[row['semantic']]
                prompt=build_prompt(condition,row,demos,mapping)
                identity=f"{condition}-m{mapping_id if mapping_id is not None else 'na'}-{row['id']}"
                requests.append({'request_id':identity,'condition':condition,'record_id':row['id'],
                    'mapping_id':mapping_id,'semantic':row['semantic'],'expected':expected,
                    'system':SYSTEM,'prompt':prompt,'messages':[{'role':'system','content':SYSTEM},{'role':'user','content':prompt}],
                    'input_sha256':hashlib.sha256((SYSTEM+'\n'+prompt).encode()).hexdigest(),
                    'max_visible_output_tokens':8})
    return requests

def grade(raw,request):
    normalized=raw.strip()
    allowed=LABELS if request['condition'] in ('A','B') else ['K','M','R']
    return {'normalized':normalized,'correct':normalized==request['expected'],
            'format_error':normalized not in allowed,'expected':request['expected']}

def synthetic_fixture(requests):
    # This is an intentionally mixed synthetic grading fixture, never a model.
    records=[]
    for i,r in enumerate(requests):
        allowed=LABELS if r['condition'] in ('A','B') else ['K','M','R']
        if i%13==0: raw='答案是 '+r['expected'] # format error
        elif i%17==0: raw=''                   # empty error
        elif i%11==0: raw=next(x for x in allowed if x!=r['expected']) # valid wrong label
        else: raw=' '+r['expected']+'\n'       # only outer whitespace may be removed
        records.append({**r,'raw_output':raw,'score':grade(raw,r),
                        'evidence_type':'SYNTHETIC_FIXTURE_NOT_MODEL_OUTPUT','model_id':None,
                        'model_revision':None,'tokenizer_revision':None,'decoding':None,
                        'request_started_at':None,'request_finished_at':None})
    return records

def aggregate(records):
    groups={}
    for r in records:
        group=(r['condition'],r['mapping_id'],r['semantic'])
        a=groups.setdefault(group,{'n':0,'correct':0,'format_errors':0})
        a['n']+=1; a['correct']+=int(r['score']['correct']); a['format_errors']+=int(r['score']['format_error'])
    return [{'condition':k[0],'mapping_id':k[1],'semantic':k[2],**v} for k,v in groups.items()]

def check_design():
    demos,test=make_data(); requests=make_requests()
    assert len(demos)==6 and len(test)==24 and len(requests)==192
    assert collections.Counter(x['semantic'] for x in demos)==dict.fromkeys(LABELS,2)
    assert collections.Counter(x['semantic'] for x in test)==dict.fromkeys(LABELS,8)
    assert not ({(r['control'],r['treatment']) for r in demos}&{(r['control'],r['treatment']) for r in test})
    assert collections.Counter(r['condition'] for r in requests)=={'A':24,'B':24,'C':72,'D':72}
    for t in range(9,31,3):
        rows=[r for r in test if r['treatment']==t]
        assert set(r['semantic'] for r in rows)==set(LABELS)
    assert {(9,12),(12,9)}.issubset({(r['control'],r['treatment']) for r in test})
    assert len({r['request_id'] for r in requests})==192
    assert all(not any(label in r['text'] for label in LABELS) for r in test)
    return {'demos':len(demos),'heldout':len(test),'independent_requests':len(requests),'requests_per_condition':dict(collections.Counter(r['condition'] for r in requests))}

def run_with_generator(generate,model_manifest,out_dir,max_requests=3):
    # Future extension: explicit model adapter; never called in R1 dry-run.
    required=['model_id','model_revision','tokenizer_revision','software_versions','decoding','system_prompt']
    if any(not model_manifest.get(k) for k in required): raise ValueError('先冻结完整模型与解码身份')
    if model_manifest['system_prompt']!=SYSTEM: raise ValueError('system prompt 与冻结设计不一致')
    if not 1<=max_requests<=192: raise ValueError('max_requests 须明确设为1..192')
    out=pathlib.Path(out_dir); out.mkdir(parents=True,exist_ok=True)
    path=out/'model-responses.jsonl'
    if path.exists(): raise FileExistsError('为保护教师基线,请选新输出目录')
    records=[]
    with path.open('x') as f:
        for request in make_requests()[:max_requests]:
            started=datetime.datetime.now(datetime.timezone.utc).isoformat()
            # Adapter must perform one stateless call with exactly these messages and fixed settings.
            raw=generate(request['messages'],dict(model_manifest['decoding']),request['max_visible_output_tokens'])
            if not isinstance(raw,str): raise TypeError('模型适配器必须返回原始字符串')
            record={**request,'raw_output':raw,'score':grade(raw,request),'model_manifest':model_manifest,
                    'evidence_type':'MODEL_ADAPTER_OUTPUT','request_started_at':started,
                    'request_finished_at':datetime.datetime.now(datetime.timezone.utc).isoformat()}
            f.write(json.dumps(record,ensure_ascii=False)+'\n'); f.flush(); records.append(record)
    return records

def write_artifacts(out_dir,records=None):
    out=pathlib.Path(out_dir); out.mkdir(parents=True,exist_ok=True)
    demos,test=make_data(); requests=make_requests()
    for name,data in [('demonstrations.json',demos),('heldout24.json',test),('mappings.json',MAPS),('requests192.json',requests)]:
        (out/name).write_text(json.dumps(data,ensure_ascii=False,indent=2))
    if records is not None:
        (out/'SYNTHETIC-fixture192.jsonl').write_text(''.join(json.dumps(r,ensure_ascii=False)+'\n' for r in records))
        (out/'SYNTHETIC-grading-summary.json').write_text(json.dumps(aggregate(records),ensure_ascii=False,indent=2))
    return out

def evaluate_responses(requests,responses,model_manifest):
    required=['model_id','model_revision','tokenizer_revision','software_versions','decoding','system_prompt']
    missing=[k for k in required if not model_manifest.get(k)]
    if missing: raise ValueError('缺少真实运行身份字段: '+','.join(missing))
    by_id={r['request_id']:r for r in responses}
    if len(by_id)!=len(responses): raise ValueError('重复request_id')
    if set(by_id)!=set(r['request_id'] for r in requests): raise ValueError('响应必须恰好覆盖这192个request_id')
    result=[]
    for r in requests:
        answer=by_id[r['request_id']]
        if answer.get('input_sha256')!=r['input_sha256']: raise ValueError('请求哈希不符: '+r['request_id'])
        if not isinstance(answer.get('raw_output'),str): raise ValueError('raw_output必须是字符串')
        result.append({**r,**answer,'score':grade(answer['raw_output'],r),'evidence_type':'USER_SUPPLIED_MODEL_OUTPUT_NOT_EXECUTED_BY_THIS_SCRIPT','model_manifest':model_manifest})
    return result
查看与修改计算代码
print(check_design())
demos,test=make_data()
print('完整示例:')
for row in demos: print(row['id'],row['text'],'→',row['semantic'])
print('完整留出:')
for row in test: print(row['id'],row['text'],'参考答案=',row['semantic'])
print('三轮映射:',MAPS)

保存的本地 CPU 输出 · icl192-03

{'demos': 6, 'heldout': 24, 'independent_requests': 192, 'requests_per_condition': {'A': 24, 'B': 24, 'C': 72, 'D': 72}}
完整示例:
E01 样本标记值:对照组 10,处理组 14。 → 增加
E02 样本标记值:对照组 10,处理组 6。 → 减少
E03 样本标记值:对照组 10,处理组 10。 → 相同
E04 样本标记值:对照组 8,处理组 11。 → 增加
E05 样本标记值:对照组 8,处理组 5。 → 减少
E06 样本标记值:对照组 8,处理组 8。 → 相同
完整留出:
T01 菌落计数记录中,对照为 6,处理为 9。 参考答案= 增加
T02 菌落计数记录中,对照为 9,处理为 9。 参考答案= 相同
T03 菌落计数记录中,对照为 12,处理为 9。 参考答案= 减少
T04 荧光读数记录中,处理为 12,对照为 9。 参考答案= 增加
T05 荧光读数记录中,处理为 12,对照为 12。 参考答案= 相同
T06 荧光读数记录中,处理为 12,对照为 15。 参考答案= 减少
T07 叶片数量记录中,对照为 12,处理为 15。 参考答案= 增加
T08 叶片数量记录中,对照为 15,处理为 15。 参考答案= 相同
T09 叶片数量记录中,对照为 18,处理为 15。 参考答案= 减少
T10 吸光读数记录中,处理为 18,对照为 15。 参考答案= 增加
T11 吸光读数记录中,处理为 18,对照为 18。 参考答案= 相同
T12 吸光读数记录中,处理为 18,对照为 21。 参考答案= 减少
T13 分子数量记录中,对照为 18,处理为 21。 参考答案= 增加
T14 分子数量记录中,对照为 21,处理为 21。 参考答案= 相同
T15 分子数量记录中,对照为 24,处理为 21。 参考答案= 减少
T16 信号强度记录中,处理为 24,对照为 21。 参考答案= 增加
T17 信号强度记录中,处理为 24,对照为 24。 参考答案= 相同
T18 信号强度记录中,处理为 24,对照为 27。 参考答案= 减少
T19 斑点数量记录中,对照为 24,处理为 27。 参考答案= 增加
T20 斑点数量记录中,对照为 27,处理为 27。 参考答案= 相同
T21 斑点数量记录中,对照为 30,处理为 27。 参考答案= 减少
T22 颗粒数量记录中,处理为 30,对照为 27。 参考答案= 增加
T23 颗粒数量记录中,处理为 30,对照为 30。 参考答案= 相同
T24 颗粒数量记录中,处理为 30,对照为 33。 参考答案= 减少
三轮映射: [{'增加': 'K', '减少': 'M', '相同': 'R'}, {'增加': 'M', '减少': 'R', '相同': 'K'}, {'增加': 'R', '减少': 'K', '相同': 'M'}]

2. 四个可识别条件

A:语义标签、零示例,24 次。B:语义标签、六示例,24 次。C:任意标签、显式规则、零示例,三轮共 72 次。D:任意标签、由六示例传达映射,三轮共 72 次。A/B 不随映射重复。

每个请求只含固定 system、当次任务材料和一条留出输入,单独发起。无映射任意标签条件缺少可识别答案,不进入主准确率排名。下面打印同一条 12→9 的四种完整输入;D 条件不泄露显式映射。

查看与修改计算代码
requests=make_requests()
row_id=next(x['id'] for x in test if (x['control'],x['treatment'])==(12,9))
for condition in ('A','B','C','D'):
    r=next(r for r in requests if r['condition']==condition and r['record_id']==row_id and r['mapping_id'] in (None,0))
    print('\n---',r['request_id'],'---\nSYSTEM:',r['system'],'\nUSER:\n'+r['prompt'])

保存的本地 CPU 输出 · icl192-05

--- A-mna-T03 ---
SYSTEM: 你根据本次输入完成记录比较任务。仅输出要求的单个标签,不补充解释。 
USER:
请比较记录中的处理读数相对于对照读数的方向。只输出增加、减少或相同之一。
当前记录:菌落计数记录中,对照为 12,处理为 9。
输出:

--- B-mna-T03 ---
SYSTEM: 你根据本次输入完成记录比较任务。仅输出要求的单个标签,不补充解释。 
USER:
请比较记录中的处理读数相对于对照读数的方向。只输出增加、减少或相同之一。
示例:
样本标记值:对照组 10,处理组 14。 输出:增加
样本标记值:对照组 10,处理组 6。 输出:减少
样本标记值:对照组 10,处理组 10。 输出:相同
样本标记值:对照组 8,处理组 11。 输出:增加
样本标记值:对照组 8,处理组 5。 输出:减少
样本标记值:对照组 8,处理组 8。 输出:相同
当前记录:菌落计数记录中,对照为 12,处理为 9。
输出:

--- C-m0-T03 ---
SYSTEM: 你根据本次输入完成记录比较任务。仅输出要求的单个标签,不补充解释。 
USER:
请比较记录中的处理读数相对于对照读数的方向。按本轮约定只输出 K、M 或 R 之一。本轮规则:增加→K;减少→M;相同→R。
当前记录:菌落计数记录中,对照为 12,处理为 9。
输出:

--- D-m0-T03 ---
SYSTEM: 你根据本次输入完成记录比较任务。仅输出要求的单个标签,不补充解释。 
USER:
请比较记录中的处理读数相对于对照读数的方向。按本轮约定只输出 K、M 或 R 之一。
示例:
样本标记值:对照组 10,处理组 14。 输出:K
样本标记值:对照组 10,处理组 6。 输出:M
样本标记值:对照组 10,处理组 10。 输出:R
样本标记值:对照组 8,处理组 11。 输出:K
样本标记值:对照组 8,处理组 5。 输出:M
样本标记值:对照组 8,处理组 8。 输出:R
当前记录:菌落计数记录中,对照为 12,处理为 9。
输出:

3. 评分:只去掉首尾空白

主指标是预先声明的标签精确匹配。多余解释、无效标签、空输出都计错,并单列格式错误。下面刻意混入“正确标签+解释”、有效错标签与空串,检验评分不会误把输出中出现了正确字母就算正确。

接下来所有数字是合成 fixture 的测试结果,不是模型准确率。 不会生成“某模型达到 X%”的图。

查看与修改计算代码
fixture=synthetic_fixture(requests)
for raw in [' M ','答案是 M','K','']:
    r=next(r for r in requests if r['expected']=='M')
    print('人工构造原始输出=',repr(raw),grade(raw,r))
summary=aggregate(fixture)
print('SYNTHETIC FIXTURE grading summary — NOT MODEL ACCURACY')
for row in summary: print(row)
assert len(fixture)==192
assert sum(row['n'] for row in summary)==192
assert grade(' M ',r)['correct'] and not grade('答案是 M',r)['correct']
assert grade('',r)['format_error']

保存的本地 CPU 输出 · icl192-07

人工构造原始输出= ' M ' {'normalized': 'M', 'correct': True, 'format_error': False, 'expected': 'M'}
人工构造原始输出= '答案是 M' {'normalized': '答案是 M', 'correct': False, 'format_error': True, 'expected': 'M'}
人工构造原始输出= 'K' {'normalized': 'K', 'correct': False, 'format_error': False, 'expected': 'M'}
人工构造原始输出= '' {'normalized': '', 'correct': False, 'format_error': True, 'expected': 'M'}
SYNTHETIC FIXTURE grading summary — NOT MODEL ACCURACY
{'condition': 'A', 'mapping_id': None, 'semantic': '增加', 'n': 8, 'correct': 7, 'format_errors': 1}
{'condition': 'A', 'mapping_id': None, 'semantic': '相同', 'n': 8, 'correct': 6, 'format_errors': 1}
{'condition': 'A', 'mapping_id': None, 'semantic': '减少', 'n': 8, 'correct': 6, 'format_errors': 1}
{'condition': 'B', 'mapping_id': None, 'semantic': '增加', 'n': 8, 'correct': 6, 'format_errors': 1}
{'condition': 'B', 'mapping_id': None, 'semantic': '相同', 'n': 8, 'correct': 7, 'format_errors': 1}
{'condition': 'B', 'mapping_id': None, 'semantic': '减少', 'n': 8, 'correct': 6, 'format_errors': 1}
{'condition': 'C', 'mapping_id': 0, 'semantic': '增加', 'n': 8, 'correct': 6, 'format_errors': 1}
{'condition': 'C', 'mapping_id': 0, 'semantic': '相同', 'n': 8, 'correct': 6, 'format_errors': 1}
{'condition': 'C', 'mapping_id': 0, 'semantic': '减少', 'n': 8, 'correct': 6, 'format_errors': 2}
{'condition': 'C', 'mapping_id': 1, 'semantic': '增加', 'n': 8, 'correct': 7, 'format_errors': 1}
{'condition': 'C', 'mapping_id': 1, 'semantic': '相同', 'n': 8, 'correct': 5, 'format_errors': 2}
{'condition': 'C', 'mapping_id': 1, 'semantic': '减少', 'n': 8, 'correct': 7, 'format_errors': 0}
{'condition': 'C', 'mapping_id': 2, 'semantic': '增加', 'n': 8, 'correct': 5, 'format_errors': 2}
{'condition': 'C', 'mapping_id': 2, 'semantic': '相同', 'n': 8, 'correct': 8, 'format_errors': 0}
{'condition': 'C', 'mapping_id': 2, 'semantic': '减少', 'n': 8, 'correct': 5, 'format_errors': 2}
{'condition': 'D', 'mapping_id': 0, 'semantic': '增加', 'n': 8, 'correct': 7, 'format_errors': 0}
{'condition': 'D', 'mapping_id': 0, 'semantic': '相同', 'n': 8, 'correct': 5, 'format_errors': 2}
{'condition': 'D', 'mapping_id': 0, 'semantic': '减少', 'n': 8, 'correct': 7, 'format_errors': 1}
{'condition': 'D', 'mapping_id': 1, 'semantic': '增加', 'n': 8, 'correct': 5, 'format_errors': 2}
{'condition': 'D', 'mapping_id': 1, 'semantic': '相同', 'n': 8, 'correct': 7, 'format_errors': 0}
{'condition': 'D', 'mapping_id': 1, 'semantic': '减少', 'n': 8, 'correct': 8, 'format_errors': 0}
{'condition': 'D', 'mapping_id': 2, 'semantic': '增加', 'n': 8, 'correct': 8, 'format_errors': 0}
{'condition': 'D', 'mapping_id': 2, 'semantic': '相同', 'n': 8, 'correct': 6, 'format_errors': 2}
{'condition': 'D', 'mapping_id': 2, 'semantic': '减少', 'n': 8, 'correct': 5, 'format_errors': 2}

4. 完整输出落盘,教师基线与学生重跑分开

默认写入 icl192-student-output/;可自行改目录。原始输入与输出始终保存,评分不覆盖原文。合成记录的模型身份字段为 null,证据字段明确写 SYNTHETIC_FIXTURE_NOT_MODEL_OUTPUT。这比填一个虚假的模型名更容易防止误用。

查看与修改计算代码
out=write_artifacts('icl192-student-output',fixture)
print('生成文件:')
for p in sorted(out.iterdir()): print(p.name,p.stat().st_size,'bytes')
print('首条记录证据身份:',fixture[0]['evidence_type'],'model_id=',fixture[0]['model_id'])

保存的本地 CPU 输出 · icl192-09

生成文件:
SYNTHETIC-fixture192.jsonl 319734 bytes
SYNTHETIC-grading-summary.json 3164 bytes
demonstrations.json 920 bytes
heldout24.json 4574 bytes
mappings.json 197 bytes
requests192.json 282002 bytes
首条记录证据身份: SYNTHETIC_FIXTURE_NOT_MODEL_OUTPUT model_id= None

5. 如果以后运行真实模型,哪些条件先冻结?

固定 checkpoint/revision、tokenizer revision、system、解码参数、最大输出与软件版本。每条请求独立,保留 request_id、输入 SHA、原始输出、请求起止时间、映射与评分。封闭 API 只能说未发起微调,不能声称已检查服务端权重;开放权重可在纯推理流程记录前后权重哈希。

本交付的 icl192.py 是可执行离线入口:不加参数生成全部请求和合成评分;--responses 加 --model-manifest 可评分外部运行产生的完整 JSONL。还提供 run_with_generator(generate, model_manifest, out_dir, max_requests=3):由调用者传入已选模型适配器和完整身份,明确设置请求上限,逐条保存原始输出与时间。该函数尚未调用。它不内置某个尚未选择的模型适配器,不会悄悄调用付费服务;新运行目录已存在时拒绝覆盖教师基线。

每条输入 1000 tokens、可见输出 8 tokens 时,192 请求上限估算为 192000 输入、1536 可见输出 tokens,不含重试和服务端隐藏推理。这只是预算上限,本本没有按 tokenizer 测量真实 token 数。 本轮尚未选定具体模型,成本与设备可行性未验证。

6. 结果可以支持什么?

A 很高可能是天花板;D 随映射改变且留出表现好,支持当前设置采用本轮约定;C 优于 D,支持当前显式规则方案更有效。C/D 还在长度、冗余与形式上不同,不能据此识别唯一内部机制,也不能把 D−C 称为“示例净收益”。24 条是教学诊断,不是通用能力估计。

单变量练习:先保持记录与映射固定,只打乱六示例的顺序,并另存请求清单;不要同时改模型、系统提示和评分。若破坏映射一致性,该条件不再有唯一规则,单独分析冲突偏向,不纳入主能力排名。

来源:本课已归档的 ICL 实验设计;真实模型运行另列为扩展任务;Min et al.、Wei et al. 为设计背景,不是此处结果来源。