最近不少开发者在讨论 Agent 任务时都会遇到一个尴尬局面模型生成的回答看起来有模有样一到真实环境执行就频繁出错你让模型“再检查一遍”它往往只是把原答案换个说法又交上来。问题出在哪里出路又在哪里这正是 LLM-as-a-Verifier 这类思路开始被广泛关注的原因。它把“生成答案”和“验证答案”拆成两个环节让大模型在推理阶段做验证、纠错和筛选而不是只靠一次生成直接定结果。斯坦福等团队陆续放出的相关工作把这套思路推到更多开发者面前其中一个被反复讨论的判断是Verification 也能 Scaling——验证本身可以随着算力和模型能力的增长持续提升而不是一个可有可无的附加步骤。这篇文章会解释 LLM-as-a-Verifier 的核心原理说明为什么“验证”能成为可扩展的关键能力然后以 DeepSeek 的开放 API 为例给你一个可以直接运行的“生成—验证—修正”最小工程。读完你可以自己搭一个自验证流水线同时避开我在实测中最常踩的坑。1. 这篇文章真正要解决的问题先看一类真实场景你正在开发一个 Agent它负责调用工具、写代码、查文档最终返回一个结果给用户。传统做法是让大模型直接输出答案但 Agent 任务有一个天然问题——生成路径不可控。同一个问题换个说法、换个上下文模型可能给出完全不同的执行方案其中不少方案是错的。很多团队的第一反应是换更大的模型、加更多 few-shot 示例或者让用户手动确认。但这些方案各有成本。更大的模型意味着更高的推理成本加示例只能覆盖部分场景用户确认等于把问题推给用户。LLM-as-a-Verifier 提供了一个不同的改进方向保留原来的生成模型但额外增加一个“验证器”角色。生成器负责提出候选方案验证器负责检查这些方案是否正确、是否完整、是否满足约束。如果验证不通过生成器根据验证反馈重新生成。这个过程本质上是把“一次生成”变成“生成—验证—迭代”。这篇文章想让三类读者受益正在做 Agent 或 RAG 应用的开发者希望通过自验证减少错误输出。使用大模型 API 做业务集成的工程师想理解怎么在不换模型的前提下提升回答稳定性。对推理时计算inference-time compute和大模型评测感兴趣的研究型开发者。读完你应该能回答三个问题LLM-as-a-Verifier 到底在验证什么为什么它能 Scaling用 DeepSeek API 怎么落地一个最小验证工程2. LLM-as-a-Verifier 的核心概念与适用场景2.1 从生成器—验证器范式说起LLM-as-a-Verifier 并不是一个全新的概念它借鉴了机器学习里经典的 generator-verifier生成器—验证器范式。传统做法是训练一个生成模型输出候选结果再训练一个判别模型判断结果好坏。两者分离各司其职。在 LLM 时代生成器是大语言模型本身。验证器同样可以是一个大语言模型由它阅读生成器的输出然后回答“这个结果是否正确”或“这个结果哪里有问题”。这就是“LLM-as-a-Verifier”的直观含义用大模型来验证大模型。这里有个容易混淆的地方。很多开发者会把“让模型自己检查答案”等同于 LLM-as-a-Verifier。实际上如果只是在同一轮对话里追加一句“你再检查一下”模型依旧处于同一个生成模式很难跳出原有的错误路径。LLM-as-a-Verifier 强调的是一种结构上的分离生成器负责发散给出候选结果。验证器负责收敛判断候选结果是否可靠。控制逻辑决定验证失败后是重新生成、换一个候选还是终止流程。2.2 与自一致性、奖励模型的区别要真正理解 LLM-as-a-Verifier需要和两个相关概念做区分。Self-Consistency自一致性是另一种提升可靠性的方法。它让模型对同一个问题多次采样得到多个答案然后通过投票选出出现频率最高的答案。它的核心假设是“正确答案往往被重复出现”。LLM-as-a-Verifier 走的是另一条路不重复采样取多数而是让一个独立的验证器对候选结果进行判别。投票适合答案形式固定的任务比如选择题、数学题验证器更适合答案形式开放、需要动态判断的任务。Reward Model奖励模型是在 RLHF 阶段训练的目标是给一个答案打一个分数用来指导强化学习。LLM-as-a-Verifier 的验证器则在推理阶段工作一次性判断一个答案是否正确或者指出错误位置。两者目的一致但应用阶段不同。2.3 适用场景结合我的经验LLM-as-a-Verifier 在这些场景收益最明显代码生成与执行验证生成代码后让验证器阅读代码逻辑或者直接看单元测试结果。数学与逻辑推理生成解题步骤后验证器逐步检查推理链条是否有跳跃或错误。Agent 工具调用模型决定调用哪个工具、传什么参数验证器检查工具名和参数是否合法。结构化输出模型输出 JSON验证器检查字段完整性、类型和取值范围。RAG 答案校验模型基于检索结果生成答案验证器判断答案是否忠于检索资料避免幻觉。不适合的场景也很清楚实时对话要求首字延迟极低多次验证会明显增加延迟超高吞吐的批处理任务验证器带来的额外成本可能超过收益如果任务本身答案开放且没有客观标准验证器也需要人工定义标准复杂度会转移到 prompt 设计上。3. Verification 为什么也能 Scaling“Verification 也能 Scaling”是这个题目里最值得琢磨的一句话也是最近相关论文被反复讨论的关键点。3.1 生成侧 scaling 的瓶颈过去几年Scaling Law 主要落在训练阶段模型参数变大、训练数据变多、算力变强模型能力持续提升。这套逻辑在生成侧遇到了两个现实问题。第一推理成本是刚性的。生成一次响应需要一次完整的前向计算生成 10 次就是 10 份成本。如果只是通过多次采样来“碰运气”成本线性增长收益却不一定线性增长。第二生成难题的搜索空间很大。对大模型来说从输入到输出是一条很长的路径路径上任何一步出错最终结果都会出错。而模型并不具备天然的“知道自己哪里错了”的能力它只是在按概率生成下一个 token。3.2 验证侧 scaling 的优势验证任务和生成任务在本质上不同。生成任务是从巨大的可能空间中找一个可接受的序列验证任务则是在给定候选结果的情况下判断它是否满足一组条件。搜索空间小了判断路径短了模型的正确率通常也更高。这意味着你可以用验证器对多个候选结果做筛选和排序候选结果越多最终选中的答案质量越有保障。这就是“验证侧也能扩展”的核心逻辑——不是靠生成更多内容来提升质量而是靠验证更多候选来提升选择质量。用一个工程上的类比来说生成器像是面试者验证器像是面试官。面试者再多如果面试官不会判断招来的还是不合格的人一旦面试官的判断能力足够好扩大候选人池子就能稳健地提高录取质量。3.3 验证扩展的具体形态Verification Scaling 在实际工程中大致有三种形态多候选重排生成 N 个候选答案验证器对每个答案评分或排序选择最优。迭代修正验证器给出具体的错误反馈生成器根据反馈重新生成形成闭环。搜索式扩展借助 Best-of-N、树搜索等算法把验证器当作节点评估函数在解空间里做更系统的搜索。这三种形态的共同点是模型能力不是唯一变量验证策略和计算量成为新的杠杆。这也是“Verification 也能 Scaling”在工程上的真实含义。4. DeepSeek 自验证环境准备与前置条件理解原理之后自然要动手跑一遍。下面我用 DeepSeek 的开放 API 来演示一个最简自验证流水线。选择 DeepSeek 的原因有三个API 兼容 OpenAI 格式接入成本低对中文任务友好社区讨论活跃定价相对透明适合个人开发者做实验。4.1 准备 DeepSeek API Key首先在 DeepSeek 开放平台注册账号并创建一个 API Key。创建后请立即妥善保存它只会在创建页面显示一次之后无法再次查看完整 Key。安全提醒不要把 API Key 硬编码到代码里更不要提交到公开仓库。建议通过环境变量注入。export DEEPSEEK_API_KEYsk-xxxxxxxxxxxxxxxxxxxxxxxx4.2 安装依赖本文示例使用 Python 3.10 及以上版本依赖 openai 库作为 HTTP 客户端。你也可以使用 requests 直接调用但 openai 库更省事。pip install openai1.30.0之所以指定版本是我在实际使用时发现部分高版本 openai 库对自定义 base_url 的处理有变化。如果你本地已经安装了更高版本也可以先跑通再调整。4.3 确认基础连通性先写一个最小脚本确认 API 可用。新建文件test_connection.pyimport os from openai import OpenAI client OpenAI( api_keyos.environ.get(DEEPSEEK_API_KEY), base_urlhttps://api.deepseek.com ) resp client.chat.completions.create( modeldeepseek-chat, messages[ {role: user, content: 请回复连接成功} ], temperature0.0 ) print(resp.choices[0].message.content)运行方式python test_connection.py如果输出包含“连接成功”说明 API Key 和网络链路正常。这一步是后面所有实验的基础不要跳过。5. DeepSeek 自验证代码实现这一节是实现重点。我会从简单到完整提供三份代码示例让你看到同一个思路在不同复杂度的工程里如何落地。5.1 示例一单轮生成 结构验证第一个示例解决一个高频问题模型输出的 JSON 格式不稳定。很多业务系统需要大模型返回结构化数据但模型偶尔会多输出一个逗号、丢掉一个字段导致下游解析直接失败。这个示例里生成器负责产出 JSON验证器负责两件事检查能否被解析成合法 JSON检查必需字段是否存在。import json import os from openai import OpenAI client OpenAI( api_keyos.environ.get(DEEPSEEK_API_KEY), base_urlhttps://api.deepseek.com ) REQUIRED_FIELDS [action, args, reason] def generate_response(user_query: str) - str: 生成器输出一个 JSON 结构的动作规划 prompt f 你是一个 Agent 规划器。请根据用户问题输出一个 JSON 对象。 JSON 必须包含三个字段 - action: 字符串要采取的动作 - args: 对象动作参数 - reason: 字符串说明理由 用户问题{user_query} 只输出 JSON不要输出其他文字。 resp client.chat.completions.create( modeldeepseek-chat, messages[{role: user, content: prompt}], temperature0.2 ) return resp.choices[0].message.content.strip() def validate_json(text: str) - dict: 验证器检查 JSON 合法性及字段完整性返回错误信息 errors [] try: data json.loads(text) except json.JSONDecodeError as e: return {valid: False, errors: [fJSON 解析失败: {e}], data: None} for field in REQUIRED_FIELDS: if field not in data: errors.append(f缺少必需字段: {field}) if errors: return {valid: False, errors: errors, data: data} return {valid: True, errors: [], data: data} if __name__ __main__: query 查询北京今天的天气 raw generate_response(query) print(生成器原始输出:, raw) result validate_json(raw) print(验证器判断:, result)这个示例虽然简单但已经体现了生成器与验证器分离的思想。当验证器返回valid: False时你可以把errors反馈给生成器让它重新生成。这就是下一个示例要做的。5.2 示例二生成—验证—修正闭环第二个示例加入修正循环。生成器第一次输出往往有格式问题但这不重要重要的是验证器能指出问题生成器能根据反馈修正。循环最多执行 3 次避免无限迭代。import json import os from openai import OpenAI client OpenAI( api_keyos.environ.get(DEEPSEEK_API_KEY), base_urlhttps://api.deepseek.com ) REQUIRED_FIELDS [action, args, reason] MAX_ITERATIONS 3 def generate_response(user_query: str, feedback: str ) - str: 生成器根据用户问题和历史反馈生成 JSON if feedback: prompt f 你是一个 Agent 规划器。你上一次的输出存在以下问题 {feedback} 请修正后重新输出一个 JSON 对象必须包含字段action, args, reason。 JSON 必须合法不要包含注释和额外文字。 用户原问题{user_query} else: prompt f 你是一个 Agent 规划器。请根据用户问题输出一个 JSON 对象字段 - action: 字符串 - args: 对象 - reason: 字符串 用户问题{user_query} 只输出 JSON不要添加其他文字。 resp client.chat.completions.create( modeldeepseek-chat, messages[{role: user, content: prompt}], temperature0.2 ) return resp.choices[0].message.content.strip() def validate_json(text: str) - dict: 验证器检查 JSON 与字段完整性 errors [] try: data json.loads(text) except json.JSONDecodeError as e: return {valid: False, errors: [fJSON 解析失败: {e}], data: None} for field in REQUIRED_FIELDS: if field not in data: errors.append(f缺少必需字段: {field}) if errors: return {valid: False, errors: errors, data: data} return {valid: True, errors: [], data: data} def generate_with_validation(user_query: str): 控制逻辑连接生成器和验证器允许修正 for i in range(1, MAX_ITERATIONS 1): print(f--- 第 {i} 轮 ---) raw generate_response(user_query, feedback) result validate_json(raw) print(生成结果:, raw) print(验证结果:, result[valid]) if result[valid]: return result[data], i feedback ; .join(result[errors]) print(反馈给生成器:, feedback) return None, MAX_ITERATIONS if __name__ __main__: data, rounds generate_with_validation(给张三发送一封邮件提醒他明天下午三点开会) if data: print(最终成功占用轮次:, rounds) print(最终 action:, data[action]) print(最终 args:, data[args]) print(最终 reason:, data[reason]) else: print(经过多轮修正仍未通过验证)这段代码的关键设计是feedback变量的闭环传递。验证器不直接修改生成器的输出而是把错误信息作为新的上下文输入给生成器。这个模式非常通用后续可以扩展到更复杂的业务验证规则。5.3 示例三多候选答案 验证器重排第三个示例对应前面提到的“验证侧 Scaling”的典型形态Best-of-N 重排。生成器一次生成 N 个候选答案验证器对每个答案做质量评分选择得分最高的结果。这种方案适合正确答案不唯一、但质量有高低的开放任务。import os from openai import OpenAI client OpenAI( api_keyos.environ.get(DEEPSEEK_API_KEY), base_urlhttps://api.deepseek.com ) def generate_candidates(question: str, n: int 3) - list[str]: 生成器采样生成 N 个候选回答 candidates [] for i in range(n): resp client.chat.completions.create( modeldeepseek-chat, messages[{role: user, content: question}], temperature0.8, max_tokens300 ) candidates.append(resp.choices[0].message.content.strip()) return candidates def verify_candidate(question: str, answer: str) - float: 验证器对单个候选回答打分返回 0 到 10 的分数 prompt f 你是一个回答质量评估器。请根据“准确性、完整性、清晰度”三个维度 对下面的回答打分0 到 10 分并说明理由。 用户问题{question} 候选回答{answer} 请按如下格式输出 分数数字 理由简要说明 resp client.chat.completions.create( modeldeepseek-chat, messages[{role: user, content: prompt}], temperature0.0 ) text resp.choices[0].message.content.strip() # 从输出中解析分数 score 0.0 for line in text.splitlines(): if line.startswith(分数): try: score float(line.split()[1].strip() or line.split(:)[1].strip()) except (IndexError, ValueError): score 0.0 break return score def best_of_n(question: str, n: int 3): 控制逻辑生成 N 个候选验证器重排 candidates generate_candidates(question, nn) scored [] for i, cand in enumerate(candidates): score verify_candidate(question, cand) scored.append((score, i, cand)) print(f候选 {i1} 得分: {score}) scored.sort(reverseTrue) return scored[0][2], scored[0][0] if __name__ __main__: question 如何用 Python 判断一个字符串是否是回文请给出三种方法并对比复杂度。 best_answer, best_score best_of_n(question, n3) print( * 50) print(最终选中的最佳回答:) print(best_answer) print(验证器评分:, best_score)这个示例解释了为什么“验证能缩放”当 N 从 3 增加到 10、20你不需要提升生成器的能力只需增加验证器的工作量就能持续扩大候选池的覆盖度最终选择质量通常会更高。这在工程上非常实用因为你可以在不同算力预算之间灵活切换 N 的大小。6. 运行结果与效果验证三个示例的运行方式和预期结果可以这样判断。示例一运行后会输出一行生成器的原始 JSON 文本紧接着打印验证器判断结果。如果输出类似于生成器原始输出: {action: query_weather, args: {city: 北京, date: 今天}, reason: 用户需要查询北京今日天气} 验证器判断: {valid: True, errors: [], data: {...}}说明单轮验证已通过。如果出现valid: False一般是因为模型输出了多余文字、使用了中文引号或字段名拼写不一致。示例二运行后你会看到每一轮的生成结果、验证结果和反馈内容。成功的标志是最终能在一个合理轮次内输出合法的 JSON 对象。如果连续 3 轮都失败优先检查REQUIRED_FIELDS是否与生成器 prompt 中要求的字段完全一致。示例三运行后每个候选回答都会获得一个分数最终程序会输出得分最高的回答。判断成功有两个指标分数能被正确解析排序结果符合你对回答质量的主观判断。如果每个候选分数都恒定不变通常是 LLM 验证器的评分 prompt 区分度不够可以调整验证器 prompt要求它先列出优缺点再打总分。这里需要特别提醒LLM-as-a-Verifier 的验证器并不是绝对可靠的。验证器本身也可能出现误判尤其是当验证器模型和生成器模型能力差距较大时。更稳妥的做法是在验证器 prompt 中加入可验证的检查点比如“如果候选回答中出现了术语 A必须明确给出出处”。让验证器有可执行的检查项而不是空泛地打一个感情分。7. DeepSeek 自验证常见问题与排查我在实际跑这些示例时遇到过几类问题。整理成表格供你排查时参考。问题现象可能原因排查方式解决方案请求返回 401 UnauthorizedAPI Key 错误或环境变量未生效检查echo $DEEPSEEK_API_KEY是否输出正确的 Key重新 export 环境变量或者检查代码中os.environ.get的拼写请求返回 400 Bad Request请求参数不合法或把推理模型的reasoning_content传回了 API打印发送给 API 的 messages检查是否包含多余字段删除 messages 中的reasoning_content字段只保留role和content返回超时或连接失败网络代理配置异常或 base_url 填写错误先执行 curl 测试 API 连通性确认使用https://api.deepseek.com检查系统代理设置JSON 解析失败模型输出了自然语言描述而非纯 JSON打印生成器原始输出定位多余内容在生成 prompt 中强调“只输出 JSON”或使用 json.loads 前先做前后括号截取验证器评分区分度低验证 prompt 没有定义清晰的评分维度查看完整评分输出确认模型是否有推理过程重写评分 prompt要求先输出评分理由再输出分数多轮循环不收敛验证规则与生成 prompt 不一致对比 REQUIRED_FIELDS 与 prompt 中的字段名统一字段名尽量使用英文键名避免中文键名导致编码问题其中reasoning_content的问题值得单独说明。DeepSeek 的推理模型deepseek-reasoner在响应中会附带reasoning_content字段用于记录推理过程。当你把一段包含reasoning_content的历史消息作为上下文传给下一次请求时API 会拒绝请求因为它不是合法的输入消息字段。解决方法是在拼接历史消息时只复制role和content丢弃reasoning_content。另一个常见误解是有了验证器之后是不是每次都要把生成器和验证器都调用一遍不一定。如果任务是高并发低延迟的可以让验证器抽样运行例如对 10% 的流量做实时验证其余流量靠规则校验兜底。验证器的价值是质量监控和风险拦截不必在所有流量上都承担额外延迟。8. 最佳实践与工程建议写到这里我想把真正重要的工程建议集中起来。这些经验来自实际的 API 接入和 Agent 项目不是空泛的原则。8.1 生成器和验证器的 prompt 要分开设计很多人会复用同一个 prompt 给生成器和验证器这是一个误区。生成器需要的是自由度和明确目标验证器需要的是检查点和判断标准。正确做法是维护两套独立 prompt。验证器 prompt 应尽量使用可验证的清单式描述例如“检查输出是否包含至少 3 个字段”“检查引用的数字是否与上文的计算结果一致”这比“请判断回答是否准确”可靠得多。8.2 把验证规则从 prompt 中剥离验证逻辑不一定要全部交给 LLM 判断。如果字段是否存在、格式是否合法、类型是否正确这些可以用代码写死就不要让 LLM 再判断一次。代码验证快速、零成本、绝对一致。LLM 验证器主要承担的是语义层面的判断答案是否忠实于检索资料、推理过程是否有跳跃、候选回答哪个更符合用户意图。我在项目里推荐的策略是“规则验证先行语义验证兜底”。先让 JSON Schema、正则表达式、字段检查跑一遍只有通过规则验证的结果才送给 LLM 验证器。这样可以显著减少 LLM 调用次数降低成本也能避免让模型处理它不擅长的格式问题。8.3 控制迭代成本自验证循环虽然能提升质量但也会成倍增加 token 消耗。建议在进入循环前设定最大迭代次数并且每次修正时把前一轮的“验证错误”一并传给生成器而不是只让它重新生成。没有反馈的重复生成本质上和多次采样区别不大。工程上还可以对每次调用做 token 预算控制。比如生成器调用允许最大输出 512 token验证器调用允许最大输出 128 token。验证器不需要输出很长的推理过程你只需要它给出结论或少量理由所以限制输出长度能明显降低延迟。8.4 安全与合规底线凡是涉及用户敏感数据的验证流程都要考虑数据边界。如果你使用外部 API 做验证务必确认服务协议允许传输这类数据如果不行应选择本地部署模型作为验证器。对于有明确回答任务的场景可以加入“验证器只负责判断不把用户原始提问原样转发给其他第三方服务”这类工程约束。权限方面遵循最小授权原则API Key 使用独立账号不与其他业务服务共享。8.5 可观测性比追求准确率更重要生产环境中验证器的每一次判断都应该是可追踪的。建议至少记录以下字段请求 ID生成器的原始输出验证器的判断结果和评分迭代轮次最终是否通过验证有了这些日志你才能在下游出现问题时快速回溯。不要等到线上结果出错才去排查一份完整的验证日志本身就是一张安全网。8.6 评估一次推广到全流程LLM-as-a-Verifier 是否真正提升了质量需要用一个稳定的评测集来回答。不要只凭几个例子就得出结论。建议采样 100 到 200 条代表性任务对比“无验证”和“有验证”两组结果按你需要的人工规则或 LLM 评分来统计通过率变化。评测通过后再逐步把验证逻辑接入更多业务流程。接入时先用影子模式即验证器照常运行但它的结果不立即影响线上返回只写入日志连续观察几天确认效果稳定后再切换为强校验模式。9. 总结与后续学习方向这篇文章从问题切入讲了 LLM-as-a-Verifier 为什么值得关注。核心判断是验证环节正在从一个辅助工具变成一个可扩展的核心能力。生成侧的能力提升依赖模型参数和训练数据验证侧的能力提升则可以通过多候选重排、迭代修正和搜索扩展来实现。后者尤其适合在不更换底层模型的情况下通过工程手段提高系统输出的可靠性。配套的三个示例演示了最小可落地的路径单轮格式验证、生成-验证-修正闭环、多候选重排。它们都是可以直接改造成业务代码的模板而不只是概念演示。下一步你可以做的事是选一个你当前最头疼的任务整理出它最容易出错的地方把这些错误类型写成验证器的检查清单。然后跑通一个最小验证循环用真实业务数据评估它到底提升了多少通过率。如果你沿着这个方向继续深入建议关注几个方向如何把验证结果和历史反馈组织成更有效的记忆如何同时使用代码验证和 LLM 语义验证做双层校验以及如何在 Agent 的工具调用链路中引入验证节点而不是只在最终回答处验证。每一次验证节点的加入都是在为你的系统增加一道可扩展的安全边界。