ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

DeepSeek模型选型与提示语工程:从路由表到API落地

DeepSeek模型选型与提示语工程:从路由表到API落地

简介:这份《DeepSeek:从入门到精通》PDF讲义面向希望系统掌握国产开源通用人工智能推理模型的技术人员、开发者与研究者,围绕DeepSeek的能力边界、使用路径与提示语设计展开,帮助读者从“会用”走向“用得好”。内容先厘清DeepSeek-R1作为开源推理模型擅长复杂任务且可免费商用的定位,再梳理智能对话、文本生成、语义理解、计算推理、代码生成与补全等应用场景。重点对比推理模型与通用模型在优势领域、性能本质上的差异,说明“快思慢想”两类模型如何按任务类型选择,并给出指令驱动、需求导向、混合模式、启发式提问等提示语策略,以及数学证明、创意写作、代码生成等场景的有效示例与常见误区。压缩包仅含1个PDF文件,约4.83MB,结构紧凑便于通读检索。已有219人学习,适合希望降低试错成本、提升复杂问题拆解与提示语设计能力的读者参考。

1. 拿到这份 DeepSeek 资料后,我先翻的是它的边界章节

很多人拿到一份讲 DeepSeek 的文档,习惯从第一页顺着读到最后一页,读完记住的是“国产、开源、免费商用”几个标签,回到工位还是把推理模型当聊天框用,问一句答一句。这份资料真正值钱的地方不在名词解释,而在两件事:它把推理模型和通用模型的任务分流讲清楚了,也把提示语设计拆成了能照着填的结构。DeepSeek-R1 这类开源推理模型擅长逻辑密度高的活,网页端对话、文件上传、联网检索只是入口,决定输出质量的还是你会不会选模型、会不会写提示语。适合已经能把模型跑起来、但输出总差一口气的开发者。

2. 先分流再提问:推理模型与通用模型的选型逻辑

选型错配是成本最低也最容易被忽视的一类浪费。同一句“帮我写个排序函数”,丢给推理模型,它会先在心里把递归边界、复杂度、异常分支推一遍再落笔,多花几倍 token;丢给通用模型,它可能直接给你一段看起来对、边界条件全漏的代码。第 2 章要解决的,就是把“任务长什么样”和“该调哪个模型”之间建立一条可执行的判断链,而不是凭手感。

2.1 快思与慢想:两类模型的差别不在“谁更强”

通用大模型的训练目标本质是下一个 token 的概率预测,靠海量语料把语言规律压进参数里,擅长的是多样性高的任务:创意写作、多轮闲聊、开放式问答、文本改写。它对上下文的理解是统计意义上的,遇到需要严格逻辑链的证明题,容易在中途“抄近路”,给出一个结论正确但推导断裂的答案。

推理模型在语言建模之外额外引入了强化学习、链式推理这类训练手段,输出前会先生成一段中间推理过程,再收敛到结论。它的强项是数学推导、逻辑分析、代码生成、复杂问题拆解;弱项恰好是发散性任务——让它写一首诗,它可能给你一首结构工整但毫无意外的诗。资料里反复强调的一句话值得抄下来:推理模型并非全面更强,仅在其训练目标领域显著优于通用模型。

维度通用大模型推理模型(如 DeepSeek-R1)
优势领域文本生成、创意写作、多轮对话、开放性问答数学推导、逻辑分析、代码生成、复杂问题拆解
劣势领域需要严格逻辑链的任务,如数学证明发散性任务,如诗歌创作、头脑风暴
性能本质擅长多样性高的任务专精于逻辑密度高的任务
响应特征快,首 token 延迟低慢,需要先产出推理链再出结论
算力成本低高,推理链本身也计费
提示语依赖需要显式引导步骤,补偿能力短板无需逐步指导,强行拆解反而可能限制能力

用“快思慢想”来记这张表最省事:通用模型是快速反应,靠概率预测直接给答案;推理模型是慢速思考,一步步推。两者不是升级关系,是分工关系。真正需要警惕的是“模型热度选型”——看到推理模型刷屏就拿它做所有事,和看到通用模型便宜就拿它做数学题,是同一种错误的两面。

2.2 把任务清单映射成一张路由表

知道区别没用,要用起来得把它变成一张能贴在工位上的表。做法是按你手头实际的任务类型列清单,逐条标出首选模型、提示语写法和典型反例。常见的一版长这样:

任务类型首选模型提示语侧重点要避免的写法
数学证明、算法推导推理模型直接抛出问题,不拆步骤“先画图,再列公式,最后……”
代码生成与调试推理模型说清输入输出与运行环境手把手教它先写递归函数
长文摘要、翻译通用模型明确长度、角度、保留项一次性要求十个维度
营销文案、社交媒体内容通用模型给风格、给受众、给禁忌词完全开放式“自由创作”
结构化抽取(表格、字段)通用模型给字段定义与缺失值规则只说“帮我整理成表格”
多轮客服对话通用模型自然交互,给对话目标强制它“分三点回答”
复杂方案的因果分析推理模型给数据、给分析框架只给一句结论让它验证

这张表落到代码里,就是一个极简的路由函数。它不需要多复杂,关键是把“凭感觉选”变成“按类型查”。

# 任务路由:把任务类型映射到模型与提示语模板 import os ROUTING = { # 逻辑密度高的任务走推理模型,提示语保持简洁 "math_proof": {"model": "reasoner", "style": "direct"}, "code_gen": {"model": "reasoner", "style": "direct"}, "root_cause": {"model": "reasoner", "style": "direct"}, # 多样性与生成类任务走通用模型,提示语需要结构化补偿 "summary": {"model": "chat", "style": "structured"}, "copywriting": {"model": "chat", "style": "structured"}, "extraction": {"model": "chat", "style": "structured"}, } def pick(task_type: str) -> dict: """根据任务类型返回模型代号与提示语风格,未登记的任务给保守默认值""" default = {"model": os.environ.get("DS_MODEL_DEFAULT", "chat"), "style": "structured"} return ROUTING.get(task_type, default) print(pick("math_proof")) # {'model': 'reasoner', 'style': 'direct'} print(pick("unknown")) # 走默认分支,不会抛异常

ROUTING里的model只是内部代号,实际调用时映射到控制台当前可用的模型名,别把模型名硬编码在业务逻辑里——模型迭代时你只需要改映射层。style字段决定后面拼接哪套提示语模板,direct对应“只说要什么”,structured对应“缺什么补什么”。这个函数最大的价值不是省几行代码,是让团队里每个人调模型时走同一条判断路径。

2.3 用同一道题做交叉验证

路由表定完,别急着全量上线,先拿三到五道典型题做交叉验证:同一提示语分别打给两类模型,看四项指标——结论正确性、三次重问的一致性、token 消耗、端到端延迟。这四项目前没有现成工具帮你一次跑完,写个二十行的脚本最省事。

# 交叉验证:同一提示语对比两类模型的输出与消耗 import time from openai import OpenAI client = OpenAI( api_key=os.environ["DS_API_KEY"], base_url=os.environ.get("DS_BASE_URL", "https://api.deepseek.com"), ) def probe(prompt: str, model_name: str, runs: int = 3) -> dict: """重复调用同一提示语,记录耗时、输出长度与结果指纹""" outs, cost_ms, tokens = [], 0, 0 for _ in range(runs): t0 = time.time() resp = client.chat.completions.create( model=model_name, messages=[{"role": "user", "content": prompt}], ) cost_ms += (time.time() - t0) * 1000 content = resp.choices[0].message.content outs.append(content.strip()) tokens += resp.usage.total_tokens # 用输出前 80 字符做粗略指纹,判断多次调用是否收敛 return { "model": model_name, "avg_ms": round(cost_ms / runs, 1), "avg_tokens": round(tokens / runs, 1), "fingerprints": [o[:80] for o in outs], "stable": len(set(outs)) == 1, # True 表示三次输出完全一致 } for m in (os.environ["DS_MODEL_CHAT"], os.environ["DS_MODEL_REASONER"]): print(probe("证明:任意三个连续整数之积能被 6 整除。", m))

stable字段是这套验证里最容易被低估的指标。推理模型在同一道数学题上通常高度收敛,通用模型则可能出现三次三个说法的“玄学”现象。如果你的业务场景要求结果可复现(比如自动生成报表结论),stable=False就是一个红灯,哪怕某一次答案看起来是对的。avg_tokens超过通用模型两到三倍是正常范围,推理链越长差距越大,拿这个数去反推你的预算表,比拍脑袋估算靠谱。

2.4 成本、延迟与降级策略

推理模型的算力成本高,这个成本不只是钱,还包括等待。一个需要三十秒才吐出第一个字的接口,放在客服场景里基本不可用。常见做法是做两级降级:先用通用模型跑一遍,同时给一个置信度自评字段;自评不确定或者抽检不通过的任务,再升级给推理模型。这样八成以上的请求走便宜路径,复杂请求才付溢价。

降级策略有两个细节值得注意。一是别在推理模型上强行调低采样温度去“让它稳定”,这类模型对采样参数往往不敏感或者干脆忽略,真正影响稳定性的是任务本身有没有明确答案。二是max_tokens要留足,推理链被截断时模型可能返回半截推导,比不给答案更危险。我一般会按“预期答案长度 × 4”去设上限,宁可贵一点,也别要一个断头的结果。

3. 提示语设计:三段骨架、六种类型与五类需求公式

提示语设计是这份资料里最像“方法”也最容易被跳过的一章。跳过的人通常有两种结局:要么在通用模型上得不到想要的结果,归因于“模型不行”;要么在推理模型上写了一大段角色扮演,发现输出逻辑断裂,归因于“模型不稳定”。两种归因都不对,问题出在提示语结构和模型类型没对上。

3.1 指令、上下文、期望:缺哪段就补哪段

提示语的基本结构是三段:指令、上下文、期望。指令是核心,明确告诉模型要执行什么任务;上下文提供背景信息,帮它更准确地理解;期望明确或隐含地表达你对输出的要求和预期。三段齐全的提示语,输出质量通常不会太差;缺哪一段,就会出现对应的症状。

缺指令,模型不知道你要干什么,只能顺着你的话往下接,输出一段正确但无用的废话。缺上下文,模型会用自己的默认假设填空,比如你让它“优化登录流程”,它不知道你现在的技术栈和用户量级,只能给一份通用清单。缺期望,最常见的是输出长度和格式失控——你问一句,它给你三千字,还是 Markdown 加粗排版。

补的方法不复杂,遇到输出不对先做一次归因:是它不知道任务(补指令)、不知道背景(补上下文),还是不知道验收标准(补期望)。这个三步排查比反复改措辞有效得多。举个对照:

症状缺失段补法
回答泛泛而谈,像百科条目指令把“介绍一下”改成“对比 A 和 B 在 X 场景下的三点差异”
输出假设与你的环境不符上下文补技术栈、数据规模、已有约束
长度、格式不受控期望明确字数、结构、是否允许表格,是否只输出 JSON

3.2 六种提示语类型与各自的失效场景

资料把提示语分成六类:指令型、问答型、角色扮演型、创意型、分析型、多模态型。这六类不是并列的六个选项,而是六种语气,用错语气比用错词更致命。

指令型直接告诉模型要做什么,适合任务边界清晰、结果可验收的活,比如格式转换、字段抽取。问答型抛问题等答案,适合知识查询。角色扮演型要求模型模拟特定身份,在创意写作和风格模仿上很有效。创意型引导内容生成,分析型要求对给定信息做推理,多模态型结合文本与图像输入。

失效场景集中在角色扮演型上。给通用模型加一句“你是一位资深文案”,输出风格会明显变化,这是有效的;给推理模型加同样一句,你可能得到一段逻辑上自相矛盾的文字——它的推理主线被角色设定干扰了。资料里的原话是“不要对推理模型使用启发式提示(如角色扮演),可能干扰其逻辑主线”。我的经验是:角色扮演只给通用模型,推理模型直接说任务目标和交付物,别绕。

多模态型的边界也要说清楚。文件上传、图片文字扫描这类能力适合“读进来”而不是“理解透”——扫描出来的表格结构经常错位,关键数字建议人工复核一遍再入库。

3.3 五类需求的表达公式

需求类型决定提示语该长什么样。资料给了五类需求的表达公式,这是全篇最可直接抄作业的部分:

需求类型特点表达公式推理模型适配通用模型适配
决策需求权衡选项、评估风险、选最优解目标 + 选项 + 评估标准要求逻辑推演和量化分析直接建议,依赖经验归纳
分析需求深度理解数据、发现模式或因果问题 + 数据/信息 + 分析方法触发因果链推导与假设验证表层总结或分类
创造性需求生成新颖内容或方案主题 + 风格/约束 + 创新方向结合逻辑框架生成结构化创意自由发散,依赖示例引导
验证需求检查逻辑自洽、数据可靠结论/方案 + 验证方法 + 风险点自主设计验证路径并排查矛盾简单确认,缺乏深度推演
执行需求完成具体操作任务 + 步骤约束 + 输出格式自主优化步骤,兼顾效率与正确性严格按指令执行,无自主优化

看公式可能还抽象,落到具体句子上就清楚了。决策需求写成“为降低物流成本,现有两种方案:自建区域仓(初期投入高、长期成本低)与第三方合作(按需付费、灵活性高),请按五年总成本模型对比并给出推荐”;分析需求写成“附上近三年销量 CSV,说明增长趋势与政策节点的关联性,并预测下一年的市占率,说明你用的方法和参数依据”;验证需求写成“以下结论声称模型 A 优于方法 B,请检查实验数据是否支持、对照组设置是否有偏差,并说明你会如何重算显著性”。

公式的价值在于它逼你把“评估标准”和“验证方法”写出来。绝大多数提示语失败,不是因为模型笨,是因为提问的人自己没想清楚验收标准是什么。

3.4 把提示语做成模板:变量、版本与回归用例

提示语写到能用的程度就该存起来,别散落在聊天记录里。常见做法是做成带占位符的模板文件,版本化管理,每改一次留一条回归用例。最简单的形态是一个 JSON 模板加一个渲染函数:

# 提示语模板:占位符 + 版本号 + 回归用例,避免改一次崩一次 import json TEMPLATE = { "id": "decision_roi_v2", "style": "structured", # 走通用模型的结构化路径 "system": "你是一名成本分析助手,只基于用户给的数据推理,缺失信息要明确指出,不得编造。", "user": ( "目标:{goal}\n" "可选方案:{options}\n" "评估标准:{criteria}\n" "输出要求:先用 3 行以内的表格对比,再给一段不超过 150 字的推荐理由。" ), "cases": [ {"goal": "降低仓配成本", "options": "自建仓/第三方合作", "criteria": "五年总成本"} ], } def render(tpl: dict, **kw) -> list: """渲染成 messages 列表;缺少占位符时直接抛错,避免半截提示语上线""" for key in ("goal", "options", "criteria"): if key not in kw: raise KeyError(f"缺少必填占位符: {key}") return [ {"role": "system", "content": tpl["system"]}, {"role": "user", "content": tpl["user"].format(**kw)}, ] print(json.dumps(render(TEMPLATE, **TEMPLATE["cases"][0]), ensure_ascii=False, indent=2))

id里的版本号别省,改模板时递增,出问题能回滚到上一版。cases放一条最小可复现的输入,每次改完模板先跑这条,看输出结构有没有塌。render里那个KeyError是故意的——宁可上线前报错,也别让一个少填了评估标准的提示语悄悄跑起来,那种输出看着没问题,实际上全是模型的默认假设。

4. 从对话框到流水线:把 DeepSeek 接进日常工程

会写提示语只是第一步,真正拉开差距的是把它接进日常流水线:批量跑文档、按字段抽数据、给代码做自动补全和自查。这一章讲三个落地场景的写法,每个都能直接改成你的脚本。

4.1 三个入口的取舍:网页端、文件上传与 API

网页端对话入口适合探索性任务,改提示语、试风格、看效果最快,缺点是没法批量、没法进版本库。文件上传适合单份文档的一次性处理,扫描件和图片里的文字也能读,但对表格结构的还原经常错位。API 适合一切需要重复、需要和业务系统对接的任务。

选择标准很简单:同一件事你会做第二次,就该写脚本。网页端试出来的提示语,复制进模板文件,接 API 跑批量,这是标准路径。反过来,只做一次的长文档摘要,硬写脚本反而是浪费。

4.2 结构化输出:JSON 约束、解析与重试

字段抽取是最高频的落地场景,也是最容易在解析环节翻车的地方。约束要写在系统提示里,解析要写兜底,重试要有次数上限。

# 结构化抽取:强约束 + 容错解析 + 有限重试 import json, re from openai import OpenAI client = OpenAI(api_key=os.environ["DS_API_KEY"], base_url=os.environ.get("DS_BASE_URL", "https://api.deepseek.com")) SYSTEM = """你是信息抽取器。只输出一个 JSON 对象,不要解释、不要用代码块包裹。 字段定义: - topic: 字符串,文章主题,不超过 20 字 - entities: 字符串数组,最多 8 个,按重要性排序 - sentiment: 枚举,只能是 positive / neutral / negative - confidence: 0 到 1 的浮点数,表示你对抽取结果的把握 缺失的信息填 null,禁止编造。""" def extract(text: str, model: str, retries: int = 3) -> dict: for attempt in range(retries): resp = client.chat.completions.create( model=model, messages=[{"role": "system", "content": SYSTEM}, {"role": "user", "content": text[:6000]}], # 截断保护 response_format={"type": "json_object"}, # 部分模型支持,不支持就删掉这行 ) raw = resp.choices[0].message.content.strip() # 兜底:剥掉可能残留的 ```json 围栏 raw = re.sub(r"^```(?:json)?|```$", "", raw, flags=re.M).strip() try: data = json.loads(raw) assert data.get("sentiment") in {"positive", "neutral", "negative"} return data except Exception: if attempt == retries - 1: return {"error": "parse_failed", "raw": raw[:200]} return {}

三个地方值得说明。text[:6000]是截断保护,长文档必须先分段,靠模型自己“看完”是不可靠的。response_format参数在部分模型或版本上不生效,代码里要留一行注释说明删掉也能跑,别让读者以为缺了它就一定失败。assert那行是业务校验,枚举值跑偏是结构化输出里最常见的隐性错误——JSON 语法没问题,语义已经错了,不校验就会一路污染到下游报表。

4.3 长文本摘要:分段、锚点与合并

整篇长文直接塞进去,最典型的表现是开头结尾摘要得很准,中间章节的信息整段丢失。原因是上下文窗口内注意力分布不均,跟模型“偷懒”无关。稳妥做法是分段摘要再合并,每段摘要强制保留锚点信息。

# 分段摘要:带重叠切分 + 锚点保留 + 二次合并 def chunk(text: str, size: int = 2000, overlap: int = 200) -> list: """按字符切分,overlap 保证跨段句子不被切断""" step = size - overlap return [text[i:i + size] for i in range(0, len(text), step)] def summarize(text: str, model: str) -> str: anchors = [] for seg in chunk(text): resp = client.chat.completions.create( model=model, messages=[{"role": "user", "content": "以下是长文档的一个片段,请输出 5 条要点。\n" "硬性要求:所有数字、专有名词、结论句必须原样保留,不得改写。\n" f"片段:\n{seg}"}], ) anchors.append(resp.choices[0].message.content) # 二次合并:把要点列表压成连贯段落 merged = client.chat.completions.create( model=model, messages=[{"role": "user", "content": "把以下要点合并成一段不超过 400 字的摘要,保留全部数字与专有名词:\n" + "\n".join(anchors)}], ) return merged.choices[0].message.content

size和overlap这两个参数按文档类型调:政策类、财报类文档数字密集,overlap给到 300 以上更安全;口语化的会议记录 200 足够。合并阶段那条提示语里“保留全部数字与专有名词”不能省,省了就会在压缩环节丢掉最不该丢的东西。

4.4 代码生成与补全:把“能跑”当验收线

代码生成是推理模型的主场,但“生成了一段看起来对的代码”和“代码能跑”之间隔着一条河。提示语里要把函数签名、依赖限制、异常处理写死,生成后本地跑测试用例,跑不过就带着报错回喂一次。

# 代码生成:固定签名 + 禁第三方依赖 + 本地用例验收 SPEC = """实现 solve(data),data 是字符串列表。 要求: 1. 返回出现次数最多的前 3 个字符串及其计数,按计数降序; 2. 计数相同按字典序升序; 3. 空列表返回空列表,不得抛异常; 4. 只允许标准库,不得引入第三方依赖。 只输出代码,不要解释。""" def gen_and_check(spec: str, model: str) -> str: resp = client.chat.completions.create( model=model, messages=[{"role": "user", "content": spec}]) code = resp.choices[0].message.content.strip() code = code.replace("```python", "").replace("```", "").strip() ns = {} exec(code, ns) # 仅在受控环境使用 assert ns["solve"]([]) == [] # 空输入用例 assert ns["solve"](["a", "b", "a"])[0][0] == "a" return code

exec只适合本地受控环境,生产环境要换沙箱。三个assert是最小验收集:空输入、正常输入、排序规则。带报错回喂时把 traceback 原样贴进去,比你说“这段代码有 bug”有效得多。

5. 踩坑排查:七个高频翻车现场与解药

前面几章讲的是“怎么用对”,这一章讲“用错了会看到什么”。下面七条都是我反复见过的现场,每条按现象、原因、解决写,对号入座比读理论快。

5.1 模型选择与提示语上的四个坑

坑一:用推理模型写营销文案,输出干瘪。现象是用理由模型(此处为推理模型)生成的产品文案结构工整、逻辑通顺,但读起来像说明书,毫无节奏感。原因是推理模型训练目标偏逻辑密度,发散性任务正是它的劣势领域。解决办法是把这类任务路由回通用模型,同时补足风格约束——“面向 25 至 35 岁用户的短文案,三句以内,允许口语,禁用形容词堆砌”,比一句“写得有感染力”有用得多。

坑二:给推理模型套角色扮演,逻辑链断了。现象是加上“你是一位从业二十年的资深分析师”之后,输出的推导步骤开始前后矛盾,中途还冒出与设定身份无关的套话。原因是启发式提示干扰了模型内化的推理主线。解决办法是把角色设定删掉,直接写任务目标和交付格式——“分析这三个方案的五年成本,输出一张对比表加一段推荐理由”,效果通常立刻回来。

坑三:拿通用模型直接问复杂数学题。现象是模型给出一个特别自信的答案,推导过程看起来像那么回事,验算一遍结果是错的。原因是通用模型缺乏严格逻辑链能力,会用语言规律“补”出一个合理形状的推导。解决办法是换推理模型,或者至少把问题拆成可逐步验证的子问题,每步要求它给出中间结果。别指望靠“请仔细思考”这类话术补齐能力差距。

坑四:一条提示语塞七八个约束,模型只满足前三。现象是输出里格式对了、字数超了、该保留的数字丢了。原因是约束越多,注意力越分散,越靠后的要求越容易被丢。解决办法是做优先级分层:把必须满足的两到三条放进系统提示,把“最好满足”的放用户提示,剩下的挪到后处理脚本里用正则或校验代码兜底。能用代码检查的事情,别指望模型自觉。

5.2 工程接入与输出稳定上的三个坑

坑五:JSON 输出偶发带代码块围栏,解析直接崩。现象是批量跑了几百条,突然json.loads抛异常,日志里一看输出被 ```json 包住了。原因是模型在某些输入下会退回到“示例格式”的习惯。解决办法是解析前先做一次正则剥离,再套 try/except 做有限重试,同时保留原始输出到日志,别让脏数据悄悄进库。

坑六:长文档整篇塞进去,中段信息凭空消失。现象是摘要的开头和结尾都对,中间两章的结论完全没提。原因是长上下文里的注意力分布不均,不是模型“没读到”。解决办法是分段摘要加锚点保留,再二次合并;关键数字和专有名词在每一段提示语里都要求原样保留。

坑七:流式输出下思维链和正文混在一起,前端展示错位。现象是推理模型的流式返回里,前面的推理片段和最终答案混在一个字段里往外吐,前端把推导过程当成正文显示出来了。原因是推理模型的部分返回体会额外带一段思维链字段,字段名通常是reasoning_content,具体以你所用的接口文档为准。解决办法是在渲染层把两个字段分开,思维链折叠展示,只把最终答案作为正文;同时给思维链加一个开关,别默认全量展示给终端用户。

6. 进阶:用 30 条自建用例把精通量成数字

“会用”和“精通”之间差的是一个可重复的度量。凭感觉判断“这次输出不错”,换个提示语就不知道是变好了还是变差了。我的做法是维护一个三十条左右的自建用例集,覆盖五类需求,每条带输入、期望要点、以及一个可自动判定的检查项。用例不用多,关键是每次改提示语或换模型都能五分钟跑完。

用例类别条数检查方式关注指标
执行类(格式转换、字段抽取)8精确匹配 / JSON schema 校验通过率、解析失败率
验证类(数据核对、结论反驳)6是否指出预设的错误点命中率
分析类(趋势、因果)6是否引用了给定数据中的具体数字引用率
决策类(方案对比)5是否给出明确推荐且理由含评估标准结构完整率
创造类(文案、命名)5长度、禁忌词、风格词命中规则通过率

执行类和分析类能全自动判定,验证类和创造类需要人工看一眼,但三十条里只有十一条需要人眼,跑一轮十分钟以内。下面这个脚本是骨架,把判定函数换掉就能用:

# 自建评测:跑用例集,输出通过率与失败明细 import json def run_suite(cases: list, model: str, checker) -> dict: passed, fails = 0, [] for c in cases: out = call_model(c["input"], model) # 封装好的调用函数 ok, reason = checker(c, out) if ok: passed += 1 else: fails.append({"id": c["id"], "reason": reason, "output": out[:200]}) return {"model": model, "pass_rate": round(passed / len(cases), 3), "fails": fails} # 示例检查器:要求输出包含给定数字,且不含禁用词 def numeric_checker(case, out): if not all(n in out for n in case["must_contain"]): return False, "缺少关键数字" if any(w in out for w in case.get("forbidden", [])): return False, "命中禁用词" return True, "ok" if __name__ == "__main__": cases = json.load(open("cases.json", encoding="utf-8")) print(run_suite(cases, "chat", numeric_checker))

must_contain字段是整个用例集的灵魂,它逼你在写用例时就想清楚“这条输出好在哪”。forbidden字段用来卡那些模型特别爱写但业务上不能出现的词,比如绝对化表述、未授权的品牌名。跑完拿到pass_rate,改一版提示语再跑,涨了两个点就是真的涨了,跌了也能在fails里看到具体是哪条、为什么。

一个我踩过的坑:用例集里的输入别用太干净的样例。最早我那三十条用的全是排版规整的文本,跑出来通过率 0.95,接真实数据当天掉到 0.6——真实输入里有全角空格、有断行、有表格转文本后的错位。从那以后我每次建用例集,都强制掺三分之一“脏数据”,宁可一开始通过率难看,也别等上线才发现。

希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进