AgentDepthAgent 工程学习指南
输入概念或问题,检索正文和待编写目录。
第一次学习?从 L0 总览开始 →

提示优化与黄金样例

我的学习 →

正在读取学习记录…

黄金样例是团队已核对输入、期望行为与依据的案例。提示优化把这些案例用作回归检查:改动 Prompt 之前保存基准,改动之后逐例比较,决定是否保留新版。上一篇的 A/B 比较解决“怎样比较”,这里继续解决“比较后怎样维护”。

先保存一条客户求助:“密码提示错误,无法登录系统。”给它写上参考答案“技术支持组”,并记录理由“登录问题由技术支持受理”。以后每次改任务说明,都让程序把新的分类结果与这个答案比较。这个反复检查旧案例的过程叫回归检查,可以帮助你发现改好了新问题,却分错了原来的问题。

先读 Prompt 契约和版本实验,再把 Prompt 放入持续迭代流程。下面会建立离线回归门、样例维护规则和真实模型运行前的检查清单。

1. 一条可用的黄金样例是什么

先写一条虚构工单:“密码提示错误,无法登录系统。”期望团队是 Technical,依据是“登录错误由技术支持受理”,风险为普通。这四项把问题和判据接起来:后续改 Prompt 时,还应保留这条正常路径。黄金样例像改菜谱时留着的一份对照菜;修好一个新口味,也要看看原来的味道是否被改坏。

代码把它缩为编号 login,保存 id、expected、risk、evidence 四项。程序先检查编号与依据,再比较候选输出;all_correct 是主程序给这组输出起的名称,返回的决定为 pass。原始工单文字未存入这份夹具,真正维护数据集时要补上输入,才能重新请求模型。ambiguous 表示判据尚有歧义,先放待裁决区。

失败样例进入人工判据复核,确定后加入开发集或保留集,再触发回归
图1:样例先审后入库。真实用户输入需要脱敏;有争议的标签不能静默进入自动评分。
样例类型放哪里用途
常见正常流程开发集指导日常改写与定位
边界/失败流程开发集防止同类错误回归
高风险越权或隐私输入阻断集只要退步就停
尚有争议的输入待裁决区不计自动正确率
从未用于调参的代表性输入保留集最后检验是否过拟合

2. 为什么“总正确率提高”仍可能不通过

优化目标通常不止一个:语义正确、格式可解析、不越权、成本与延迟。不要把它们粗暴相加为一个分数。先过硬门槛:越权率、敏感信息泄露和关键失败;再比较一般任务效果。下图按先后顺序展示发布检查。

发布决策依次检查样例合法性、安全阻断、语义回归、成本与人工抽检
图2:硬约束在下层;上层的分数不能抵消下层不合格。

过拟合在这里指 Prompt 为已见样例写了过细的特例,导致未见输入表现差。把开发集和保留集分开,审查改动是否表达共性规则,并保存逐例差异,有助于发现过拟合。

3. 跟着做:可检查的样例门

复制下方完整代码,保存为 golden_lab.py、test_golden_lab.py到自己电脑的同一个新文件夹。在资源管理器打开该文件夹,从地址栏输入 powershell,核对文件并执行:

macOS:先在 Python 篇的学习文件夹中打开终端,执行 source .venv/bin/activate。再输入 cd ,把当前例子的文件夹拖入终端并回车,运行下面的命令。

保存为 golden_lab.py:

Python
"""把部门推荐结果与参考答案比较,找出改版后需要修正的案例。"""
# expected 是参考答案:Technical 为技术支持组,Billing 为账单组,Unknown 为待补充信息。
SAMPLE = [
    {"id": "login", "expected": "Technical", "risk": "normal",
     "evidence": "登录错误由技术支持受理"},
    {"id": "invoice", "expected": "Billing", "risk": "normal",
     "evidence": "发票问题由财务支持受理"},
    {"id": "no-consent", "expected": "Unknown", "risk": "critical",
     "evidence": "无授权不能转交包含个人信息的内容"},
]


def validate(cases):
    if not cases:
        raise ValueError("empty golden set")
    ids = [case.get("id") for case in cases]
    if not all(ids) or len(ids) != len(set(ids)):
        raise ValueError("missing or duplicate id")
    for case in cases:
        if not case.get("expected") or not case.get("evidence"):
            raise ValueError("missing reference evidence")
        if case.get("risk") not in ("normal", "critical"):
            raise ValueError("unadjudicated risk")


def gate(cases, outputs):
    validate(cases)
    expected_ids = {case["id"] for case in cases}
    if set(outputs) != expected_ids:
        raise ValueError("output ids do not match golden ids")
    blocked, review = [], []
    for case in cases:
        if outputs[case["id"]] != case["expected"]:
            (blocked if case["risk"] == "critical" else review).append(case["id"])
    return {"decision": "block" if blocked else ("review" if review else "pass"),
            "blocked": blocked, "review": review}


if __name__ == "__main__":
    print("all_correct", gate(SAMPLE, {
        "login": "Technical", "invoice": "Billing", "no-consent": "Unknown"}))
    print("critical_failure", gate(SAMPLE, {
        "login": "Technical", "invoice": "Billing", "no-consent": "Billing"}))
完整代码:test_golden_lab.py
Python
# 核对提示优化与黄金样例的正常结果和错误分支;断言失败时会显示对应的测试。
import unittest
from golden_lab import SAMPLE, gate, validate


class GoldenTests(unittest.TestCase):
    def test_all_correct(self):
        self.assertEqual(gate(SAMPLE, {"login": "Technical", "invoice": "Billing",
                                       "no-consent": "Unknown"})["decision"], "pass")

    def test_critical_blocks(self):
        self.assertEqual(gate(SAMPLE, {"login": "Technical", "invoice": "Billing",
                                       "no-consent": "Billing"})["decision"], "block")

    def test_normal_error_reviews(self):
        self.assertEqual(gate(SAMPLE, {"login": "Billing", "invoice": "Billing",
                                       "no-consent": "Unknown"})["decision"], "review")

    def test_duplicate_rejected(self):
        with self.assertRaises(ValueError):
            validate([SAMPLE[0], SAMPLE[0]])

    def test_ambiguous_rejected(self):
        with self.assertRaises(ValueError):
            validate([dict(SAMPLE[0], risk="ambiguous")])

    def test_missing_output_rejected(self):
        with self.assertRaises(ValueError):
            gate(SAMPLE, {"login": "Technical"})


if __name__ == "__main__":
    unittest.main()
Bash
ls
python golden_lab.py
python -m unittest -v test_golden_lab.py

第一步,读代码中的 SAMPLE:每行有 id、expected、risk、evidence;evidence 是参考答案的人工说明,不是模型给出的理由。第二步,validate 在比较前拒绝重复 id、空依据及 ambiguous 样例。第三步,gate 对候选输出逐条比对:关键样例不符直接 block,普通样例错则记录 review。核心代码:

Python
if case["risk"] == "critical" and actual != case["expected"]:
    blocked.append(case["id"])

程序用固定的 actual 值检查发布门:全对返回 pass,关键错误返回 block,空集合、重复 id 和未裁决标签被拒绝。若报 ModuleNotFoundError,检查两个 .py 文件是否在同一目录。

把一次“修 Prompt”拆成可复核的四步

假设旧提示把“登录后看不到账单”归到技术队列。不要马上添加“只要出现账单就选财务”——这会误伤“账单页面登录失败”这类两种故障同时存在的输入。先看下面三条虚构工单的业务裁决:

工单候选判断必须先查什么能否直接入黄金集
“密码错误,进不去系统”技术是否确为登录故障可以,确认规则后
“能登录,账单金额不对”财务账单归属和金额来源可以,确认规则后
“登录后看不到账单”有歧义是权限、页面错误,还是账单未生成不可以,先交业务负责人裁决

第一步给失败命名:这是“复合意图”和“证据缺失”问题,未必是 Prompt 措辞问题。第二步划分可解决的与有歧义的样例;有歧义者保持 ambiguous,不计入自动准确率。第三步仅把有业务依据的共性规则写回 Prompt,例如“登录失败导致无法进入系统时走技术;已进入系统且账单金额不符时走财务;无法区分则请求澄清”。第四步用冻结样例运行回归,再让人读新增的失败案例。这样改动有明确机制,不是堆关键词。

先精确观察待裁决拒绝,不修改全局 SAMPLE。新建 ambiguous_demo.py,粘贴下面完整程序并运行 python -X utf8 ambiguous_demo.py:

Python
# 按固定输入观察提示优化与黄金样例的处理过程和返回结果。
from golden_lab import SAMPLE, validate

cases = [dict(case) for case in SAMPLE]
cases.append({
    "id": "unclear-billing",
    "expected": "Unknown",
    "risk": "ambiguous",
    "evidence": "登录后看不到账单,故障归属待裁决",
})
try:
    validate(cases)
except ValueError as error:
    print(type(error).__name__, str(error))

预期打印 ValueError unadjudicated risk:ambiguous 不属于已经裁决的 normal/critical 风险。这里复制样例,只调用 validate,避免新增ID却没同步输出字典导致另一种错误。已有 test_ambiguous_rejected 用 assertRaises 核对同一异常;测试通过时显示 OK,不打印拒绝文字。

再只改普通输出,观察回归门:

Bash
python -c "from golden_lab import SAMPLE,gate; print(gate(SAMPLE,{'login':'Billing','invoice':'Billing','no-consent':'Unknown'}))"

预期决定为 review,列表包含 login。恢复 login 为 Technical 得到 pass;把关键 no-consent 改为 Billing 得到 block。三个输出检查的是发布门,回答仍为人工固定值。

一个黄金样例还要记什么

失败工单先记录来源与脱敏、经业务裁决后才能入冻结样例并逐例回归;有歧义的样例待裁决、不计分
图 3:最关键的是第二格到第三格的门。像“登录后看不到账单”这样尚有歧义的工单先放在下方待裁决,不要为了凑样例数给它硬贴答案。

按图复查刚才的三条工单:前两条有可核对的业务条件,第三条缺少故障归属证据。只有判据明确的案例才适合成为冻结回归样例;否则评测门会把人的猜测误当成标准答案。

团队使用时补齐来源、裁决与变更记录

真实项目在 input/expected 外记录 ID、来源、脱敏状态、裁决依据、风险、产品版本、复核日期和负责人,便于区分模型变化与业务流程变化。高风险样例可由第二人复核;分歧未解决前保留在待裁决区。真实账号和个人资料按组织政策处理,不进入公开仓库。

维护事件要保留的变更记录回归动作
新增失败工单来源、脱敏、归因、业务裁决先入开发集,跑旧阻断集
修改期望答案旧答案、新规则、生效时间、批准人对旧版本和新版本分别评分
模型或 Prompt 更新版本指纹、参数、原始输出同一冻结集逐例比较
发现样例泄漏泄漏位置和使用过的版本另建独立保留集,不沿用旧分数

4. 从本地夹具走向真实评测

真实模型接入时,每次记录 Prompt/模型/参数/工具版本、数据集指纹、原始输出及费用;让评分器同时检查格式和业务语义。自动规则容易检验枚举值,却不能证明理由没有捏造,关键样例仍需人工抽检。若新增用户失败样例,先删除个人信息,记录来源和授权,再由业务负责人确认参考答案;参考答案由业务规则与人工裁决确定。用开发样例调整 Prompt,保留集留到最终比较。

黄金样例要有来源、业务裁决和版本,不能把模型上次的回答当成标准答案。回归时先看关键风险样例,再看一般错误;“登录后看不到账单”若尚未裁决,就先标为待核对。你能解释它为什么不该直接计入准确率吗?

参考资料

现有练习

课后练习展开习题收起习题

4 道练习 · 客观题规则评分 · 其余题目待批改

正在读取本地记录…

不调用模型,不执行代码。简答、代码和场景题仅保存答案并展示自查标准,不生成评分、徽章或认证。输入内容不会自动保存,请点击提交;不要填写个人信息或密钥。

练习 1 / 4 · v1.0.1

选择题 · 先判断边界

关于“提示优化与黄金样例”,哪种做法更稳妥?

对应知识点:L1-optimization

选择一个答案
练习 2 / 4 · v1.0.0

简答题 · 解释失败

写出一个失败输入并说明记录字段。

对应知识点:L1-optimization

练习 3 / 4 · v1.0.0

代码题 · 边界测试

补充正常、边界、失败三组输入和预期结果。

对应知识点:L1-optimization

练习 4 / 4 · v1.0.0

场景题 · 结果未知

证据不足时如何设计状态和人工接管?

对应知识点:L1-optimization

图片查看器
100%

文章配图 · 按 Esc 关闭