CritICL:用小模型错误反馈增强大模型推理的上下文学习方法 📅 发布时间:2026/9/3 19:06:26 👁 浏览次数: 这次我们来看一个跟大模型推理密切相关的方法CritICL。单独看这个名字Critic 是批评者ICL 是 In-Context Learning中文一般叫上下文学习。合在一起CritICL 的核心思路可以概括成一句话先用小模型在大模型要处理的推理任务上“试错”把小模型容易犯的错误、错误类型和失败样本整理成上下文信号再把这份“错题本”喂给大模型让大模型在推理时主动避开这些坑。这类方法的价值在于它不需要修改大模型权重也不用大规模微调主要改动集中在推理阶段的输入构造上。对普通开发者来说这意味着可以保留现有大模型服务不动额外接一个小模型做“前置诊断”再让大模型做最终推理对评测和 Prompt 工程来说则可以用更低算力成本去发现大模型的薄弱环节。文章会先解释 CritICL 的技术思路和适用边界然后给出一套可以在本地搭建的实验链路环境准备、双模型服务启动、功能测试、接口调用、批量评测、资源观察和常见问题排查。先说清楚一点CritICL 的方法名和设计方向已经被不少研究者讨论但具体的工程实现往往随论文或仓库版本变化。下面给出的命令和脚本属于通用实验模板不能直接当成某个官方安装包使用。你需要按实际项目目录、模型路径、接口协议做替换。文章后面所有“预期结果”都基于方法设计推断最终数据以本机实测为准。1. 核心能力速览先把 CritICL 关注的能力点整理成一张表方便快速判断它适不适合你当前的场景。能力项说明项目类型大模型推理增强方法 / 上下文学习ICL优化思路核心机制用小模型错误反馈、错误样本、错误类型帮助大模型改进推理是否修改大模型权重否以推理阶段提示词改造为主是否需要微调不一定主要依赖上下文学习主要功能错误诊断、提示词增强、推理评测、批量结果对比推荐硬件需要同时加载小模型与大模型具体按模型规模估算显存占用不确定取决于小模型/大模型的规模、量化方式与上下文长度支持平台Linux 优先CPU 也可运行但速度会明显变慢启动方式命令行启动 / 本地 API 服务是否支持 API可按 OpenAI 兼容接口方式接入以实际实现为准是否支持批量任务可通过脚本、请求队列和并发策略实现适合场景低成本诊断大模型推理缺陷、评测集筛选、Prompt 优化从表里可以看出来CritICL 更像是一种方法论而不是一个“双击启动”的单一工具。它适合你已经有大模型服务并且想在不重训模型的前提下提升特定推理任务表现的团队。2. CritICL 的技术思路与适用场景2.1 为什么小模型的错误能帮到大模型大模型在推理任务上常常出现一种现象结果是错的但推理过程读起来很流畅。这种“一本正经地错”不容易被模型自己发现也让自动评测变得棘手。小模型虽然整体能力不如大模型但它在大模型容易出错的题目上往往能暴露出类似的问题——理解偏差、计算失误、逻辑断裂、关键条件遗漏。CritICL 做的事情就是把小模型犯过的错误转成正向提示。比如小模型在某类数学题上总是漏掉单位换算把这个错误样本放进提示词里大模型在预测时就会更关注单位换算。小模型在长文本问答里经常答非所问把这些反例给大模型大模型就会更注意“答案必须来自原文区间”。小模型在多步逻辑推理中断裂把断裂步骤标出来大模型会学习避免同类跳跃。这种方法在概念上等于给大模型配了一份“错题集”。真正有价值的不是小模型本身有多强而是它能在低算力条件下批量产生可复用的错误信号帮助大模型在推理阶段做更稳定的决策。2.2 CritICL 适合解决什么问题结合“小模型错误提升大模型推理”这个标题CritICL 最适合下面几类任务数学推理与符号推理答案可校验错误信号清晰。逻辑判断题和中长问答需要多步推理适合用反例约束。评测集筛选先用小模型快速跑一遍找出大模型可能失败的边界样本。Prompt 自动优化通过错误分析动态构造 few-shot 示例代替人工调提示词。如果你的业务已经跑在一个稳定的大模型 API 上又不想承担微调成本引入 CritICL 这种“错误提示 上下文学习”的链路是相对轻量的方案。2.3 使用边界与合规提醒CritICL 也存在局限。第一它不能凭空增加模型知识如果大模型本身没有掌握相关事实错误提示只能降低犯错概率不能替代知识注入。第二小模型的错误信号如果本身不稳定需要多次采样做聚合推理成本和延迟都会上升。第三在低延迟高并发场景下多一次小模型调用会让接口耗时变长需要提前评估。另外必须强调如果评测数据或业务数据包含用户隐私、版权文本、内部文档使用前要做脱敏和授权确认。任何数据都不能直接丢进模型服务而忽略数据边界。3. 环境准备与前置条件CritICL 没有一个固定的官方安装包所以环境准备的核心是保证“小模型服务 大模型服务 评测代码”三条链路能跑通。下面是通用检查清单。3.1 操作系统与基础环境检查项建议操作系统Ubuntu 22.04 或同类 Linux 发行版Python 版本3.9 到 3.11GPU 驱动NVIDIA 驱动已安装nvidia-smi能正常输出CUDA 环境按你使用的推理框架选择 CUDA 11.8 或 12.1磁盘空间至少预留 20GB 到 100GB取决于模型权重大小端口占用确认 8000、8001 等端口没有被占用3.2 推理框架选型CritICL 是方法不是固定软件。实际落地时建议选用一个你熟悉的本地推理框架来承载模型服务常见选择有vLLM适合高并发、OpenAI 兼容接口。Ollama适合快速部署和个人电脑测试。Xinference适合本地多模型管理。Transformers PEFT适合实验代码直接加载模型。如果你要跑批量评测最好选带 OpenAI 兼容接口的框架这样上层代码可以用统一的requests或openaiSDK 调用不用每个框架写一套客户端。3.3 环境检查命令创建虚拟环境并安装基础依赖# 创建并激活虚拟环境示例路径可替换 python -m venv criticl_env source criticl_env/bin/activate # 依赖按实际框架版本安装下面只是示例 pip install torch transformers openai requests pandas检查 GPU 和端口# 查看 GPU 状态 nvidia-smi # 查看 8000 和 8001 端口是否被占用 ss -ltnp | grep -E :8000|:8001这里的命令是通用检查模板。真正开始推理前先确保 GPU 驱动、Python 虚拟环境和端口都没有问题。4. 安装部署与启动方式CritICL 的部署可以拆成两个服务小模型服务负责生成错误信号大模型服务负责最终推理。下面以“本地推理框架 OpenAI 兼容接口”为例给出启动思路。4.1 启动小模型服务小模型的作用是批量产生错误样本。为了不占满整张卡可以限制显存利用率或只加载量化版本。# 通用模板用小模型启动 OpenAI 兼容服务 # 端口、模型路径、显存利用率都需要按实际环境修改 python -m vllm.entrypoints.openai.api_server \ --model /path/to/small-model \ --port 8001 \ --gpu-memory-utilization 0.3如果你的环境没有用 vLLM而是用 Ollama可以先通过ollama pull拉取小模型再在服务配置里指定端口。启动成功后访问/v1/models能看到模型列表。4.2 启动大模型服务大模型服务是最终推理入口。显存利用率要结合小模型占用和测试并发量来调整。# 通用模板大模型服务显存利用率按实际卡量设置 python -m vllm.entrypoints.openai.api_server \ --model /path/to/large-model \ --port 8000 \ --gpu-memory-utilization 0.6如果只有一张显卡可以把小模型和大模型都放进同一条服务链路也可以直接在小模型服务进程结束后再启动大模型服务。实际部署时建议用两张卡隔离两个模型避免显存竞争导致服务 OOM。4.3 验证服务是否启动服务启动后先用简单请求确认可用# 查询大模型服务下的模型列表 curl http://127.0.0.1:8000/v1/models如果返回 JSON说明大模型服务已经正常监听。小模型服务同理只是把端口换成 8001。如果启动失败优先看日志里的模型路径、CUDA 报错和显存不足错误。端口冲突时换一个端口重试。5. 功能测试与效果验证验证 CritICL 有没有效果核心问题是加了小模型错误提示之后大模型在特定推理任务上的准确率是否比普通 ICL 更高。下面给出一套可复现的实验流程。5.1 测试目标与设计实验建议分三组组别提示词策略说明A 组直接提问作为基准看大模型裸跑效果B 组普通 few-shot 示例给 3 到 5 个正确示例看常规 ICL 效果C 组CritICL 错误提示给出小模型错误样本 错误类型说明看提升效果这里重点关注 C 组相对于 B 组的提升幅度。如果 C 组准确率稳定高于 B 组说明小模型错误信号确实有帮助。5.2 用小模型生成错误样本在跑测试集之前先让大模型不加提示地做一遍题目同时让同一个小模型预测一遍。对比后发现小模型出错、大模型也容易出错的样本可以作为 CritICL 的错误提示素材。import requests import json # 小模型服务地址按实际环境修改 SMALL_MODEL_URL http://127.0.0.1:8001/v1/chat/completions # 大模型服务地址 LARGE_MODEL_URL http://127.0.0.1:8000/v1/chat/completions def chat(model_url, messages, max_tokens512, temperature0.7): payload { model: local-model, messages: messages, max_tokens: max_tokens, temperature: temperature, } response requests.post(model_url, jsonpayload, timeout180) response.raise_for_status() return response.json()[choices][0][message][content] question 一个农场有 12 只鸡和 8 只鸭鸡比鸭多多少只 # 先让小模型回答观察错误 small_answer chat( SMALL_MODEL_URL, [{role: user, content: question}] ) print(小模型回答:, small_answer)如果小模型输出的答案与标准答案不一致就把这道题和它的错误答案记录下来。这样的样本收集 10 到 30 条足够构造一轮 CritICL 提示。5.3 构造 CritICL 提示词CritICL 的关键是把错误样本组织成上下文提示而不是简单堆砌题目。结构可以参考三段式任务说明。小模型错误示例。当前问题。def build_criticl_prompt(question, error_examples): system_prompt 你是一个严谨的推理助手。下面给出一些参考案例这些案例包含错误答案和错误原因请注意避免犯同类错误。 icl_part for idx, ex in enumerate(error_examples, 1): icl_part f示例{idx}\n icl_part f题目{ex[question]}\n icl_part f错误答案{ex[wrong_answer]}\n icl_part f错误原因{ex[error_reason]}\n\n user_prompt f请回答下面的题目\n{question} return [ {role: system, content: system_prompt}, {role: user, content: icl_part \n user_prompt}, ]注意这里的error_reason可以人工标注也可以让小模型自己用一句话解释。后面再交给大模型做学习。5.4 批量验证与结果对比在一个小规模测试集上跑三组实验记录每组准确率import json import random def evaluate(prompts_fn, dataset, model_url): correct 0 total 0 for item in dataset: messages prompts_fn(item[question]) answer_text chat(model_url, messages, max_tokens256, temperature0.2) # 简单判断答案文本是否包含标准答案实际可按解析规则处理 if item[answer] in answer_text: correct 1 total 1 return correct / total if total else 0 dataset [ {question: 一个农场有 12 只鸡和 8 只鸭鸡比鸭多多少只, answer: 4}, # 继续增加题目 ] random.shuffle(dataset) baseline_acc evaluate(lambda q: [{role: user, content: q}], dataset, LARGE_MODEL_URL) print(零样本准确率:, baseline_acc)判断成功的标准不是单次准确率提升而是多次运行后依然稳定提升。如果 C 组相对于 B 组没有提升要检查错误样本是否与当前问题类型匹配以及提示词是否过长导致注意力分散。5.5 常见失败原因现象可能原因处理方式C 组准确率反而下降错误样本与当前题不相关按题目类型分组只使用同类错误模型输出被错误示例带偏错误示例过多或过于详细控制错误示例数量抓主要错误结果波动大采样温度太高评测时用 temperature0 或 0.1小模型错误率太低题目太简单换更困难的测试集实操时不要第一次就跑几千条数据。先用 50 到 100 条题调通链路再扩展到完整测试集。6. 接口 API 与批量任务CritICL 的工程化落地最终要落到接口和批量任务上。下面给出一个常见的最小实现方案。6.1 接口服务设计如果 CritICL 要做成一个内部服务建议提供两个接口错误分析接口接收题目调用小模型返回错误答案和错误原因。增强推理接口接收题目 错误示例调用大模型完成推理并返回结果。6.2 通用 API 调用示例在接口协议没有确定前可以先要求小模型服务和大模型服务都暴露 OpenAI 兼容接口然后用统一的 Python 回调。import requests def criticl_inference(question, error_examples): # 先调用大模型做 CritICL 推理 messages build_criticl_prompt(question, error_examples) payload { model: local-model, messages: messages, max_tokens: 512, temperature: 0.2, } response requests.post(LARGE_MODEL_URL, jsonpayload, timeout180) response.raise_for_status() return response.json()[choices][0][message][content]curl 调用示意curl http://127.0.0.1:8000/v1/chat/completions \ -H Content-Type: application/json \ -d { model: local-model, messages: [ {role: system, content: 你是严谨的推理助手。}, {role: user, content: 示例1... 当前题目...} ], max_tokens: 512, temperature: 0.2 }需要说明的是上面的请求体是常见大模型推理服务的标准格式具体字段要按实际框架提供的接口文档调整。6.3 批量任务与失败重试批量评测时可以按下面方式设计任务import time import json def batch_run(input_file, output_file, error_examples, concurrency4): tasks json.load(open(input_file, encodingutf-8)) results [] for i, item in enumerate(tasks): for attempt in range(3): try: answer criticl_inference(item[question], error_examples) results.append({ question: item[question], answer: item.get(answer), model_output: answer, success: True }) break except Exception as e: print(f第 {i} 题第 {attempt 1} 次失败: {e}) time.sleep(2 ** attempt) else: results.append({ question: item[question], answer: item.get(answer), model_output: , success: False }) json.dump(results, open(output_file, w, encodingutf-8), ensure_asciiFalse, indent2)批量任务建议注意三点超时控制单次请求超过 180 秒就标记失败避免拖垮队列。重试策略指数退避连续失败 3 次后跳过。结果落盘每处理 10 题写一次结果防止进程中断丢数据。6.4 并发与限速如果使用 vLLM 等框架并发请求数需要根据显存和 batch size 调整。压测时不要一开始就给满并发建议从并发数 1、4、8 逐步往上加观察 P99 延迟和显存变化。对于小模型错误分析接口并发可以高一些因为它只负责快速试错。7. 资源占用与性能观察7.1 显存与 GPU 观察启动两个模型服务后用下面的命令实时观察# 每秒刷新一次 GPU 显存 nvidia-smi -l 1重点看两个进程各自占用多少显存。如果大模型服务报CUDA out of memory优先调整启动参数里的gpu-memory-utilization。如果小模型和大模型都在同一张卡要保证两个进程的显存预算之和不超过显卡总容量。7.2 CPU 与 GPU 差异CritICL 并非模型训练工具而是推理链路增强方案。在 CPU 上跑也可以完成实验验证但小模型频繁调用和大模型长上下文生成都会明显变慢。如果只是验证方法有效性可以用小规模数据集加 CPU 跑一遍如果要做批量评测或接入线上服务最好还是用 GPU。7.3 影响性能的关键参数参数影响小模型错误示例数量示例越多上下文越长生成延迟越高最大生成长度 max_tokens直接影响单次推理耗时和显存占用temperature越高越耗时间不一定但会提高重试需求并发数并发上涨会提高吞吐也容易触发显存瓶颈降低显存占用最有效的手段是使用量化模型或者控制上下文长度。比如把错误示例控制在 3 到 5 条每条只保留题目、错误答案和一句话错误原因不贴完整长文本。7.4 延迟预算如果业务要求单次推理延迟在 3 秒以内CritICL 里额外的小模型调用会成为瓶颈。建议提前用小模型错误分析接口做压测记录 P50、P95 延迟。若延迟超标可以考虑把错误示例缓存到本地命中相同题型时直接复用而不是每次请求都重新跑小模型。8. 常见问题与排查方法问题现象可能原因排查方式解决方案依赖安装失败Python 版本不匹配或系统缺少编译工具查看 pip 报错日志重建虚拟环境切换 Python 版本模型文件缺失路径配置错误或权重未下载完整检查启动日志和目录结构下载完整权重检查模型路径启动后页面打不开端口被占用或服务未启动查看日志和端口监听状态更换端口或重启服务显存不足两个模型同时加载或并发过高nvidia-smi查看占用降低显存利用率降低并发使用量化模型API 调用失败接口协议不匹配或模型名错误检查请求体和返回报文按框架文档修正请求参数批量任务卡住单条请求超时未设置检查请求线程是否阻塞加超时加指数退避重试输出质量不稳定温度过高或错误样本干扰对比多次输出降低温度精简错误示例小模型和大模型结果混用端口或服务地址配置错误检查请求打到了哪个端口在代码中显式区分两个 URL排查时最有效的方式是看日志。无论是框架日志还是业务日志只要发现报错先定位是模型加载阶段、请求阶段还是解析阶段再对症处理。9. 最佳实践与使用建议9.1 从小规模开始第一次验证 CritICL 时不要追求大模型效果立竿见影。先用一个小模型、一个 50 条题的测试集跑通“小模型试错 - 错误提示构造 - 大模型推理 - 准确率对比”整条链路。链路通了再扩大数据规模能省很多调试时间。9.2 目录和日志管理实验项目建议按下面结构组织criticl_exp/ ├── data/ │ ├── raw/ # 原始测试集 │ ├── errors/ # 小模型错误样本 │ └── outputs/ # 大模型推理结果 ├── scripts/ # 评测脚本 └── logs/ # 运行日志每次实验都生成新的日志文件记录模型路径、端口、参数和数据集版本。这样后续复现结果和排查问题都更方便。9.3 错误样本质量比数量更重要错误示例不是越多越好。5 条高质量、和当前题目同类型的错误示例往往比 20 条混合错误示例更有效。错误原因也要写得清晰比如“这里把鸡和鸭的数量搞混了”而不是“这里算错了”这样模糊的表述。9.4 API 服务安全CritICL 服务如果只在内网使用建议绑定127.0.0.1或内网地址不要直接暴露公网。如果有多人需要访问用 token 或网关做认证。批量任务接口一定加限流和超时防止一次误操作把推理服务打满。9.5 数据合规涉及用户聊天记录、内部文档、未公开代码、人脸或声音素材时必须先确认数据使用范围和授权边界。评测过程中尽量不要使用真实用户隐私数据可以先用脱敏数据验证链路。10. 总结与下一步CritICL 最值得尝试的点在于它提供了一种低成本的推理增强路径不用动大模型权重就能用小模型的错误信号改善上下文学习效果。对很多团队来说这比直接微调大模型更容易接受也更适合在现有推理服务上做增量优化。如果你准备在自己环境里验证我的建议是先找一个有标准答案的评测集跑通小模型错误生成与大模型增强推理的完整链路然后对比 CritICL 和普通 few-shot 的结果。第一次跑通后不要急着加功能而是花时间分析错误样本的类型分布看看小模型错误与大模型错误的重合度有多高。这一步决定了 CritICL 在你任务上的上限。最需要留意的坑有三个一是小模型错误示例与当前题目类型不匹配导致提示词反而干扰大模型二是双服务显存竞争导致某个模型进程崩溃三是评测时温度设置不稳定导致结果波动误判方法无效。后续可以继续扩展的方向包括把错误样本按类型聚类后动态选择、将 CritICL 接入自动评测平台、根据错误分析结果自动生成优化后的 few-shot 示例。只要评测链路稳定CritICL 这类“以小促大”的思路就可以迁移到更多业务场景里。