Agent 应用开发会员账号
知识目录选择核心方向与细分内容

SYSTEMATIC LEARNING / 分层专题

提示、结构化输出与迭代验收

用普通退货、商品例外和缺失政策三个问题,连接任务指令、结构约束、证据引用及版本比较。

学习目标:能设计有证据与拒答边界的提示和输出 Schema,并用独立标签与失败样本解释一次修改的收益和限制。

内容核对 2026-10-04 · 每层有独立讲解、任务与检查

按这个知识点的熟悉程度选择起点。当前层:资深 · 解释取舍。完成任务后可以继续下一层;阅读与自检不自动代表掌握。

本层学习目录

先补齐必要概念

适合:需要持续改提示、检索策略或模型,并向团队说明效果。

任务契约
输入、允许使用的事实、输出要求及验收条件共同定义任务。
结构约束
约束字段、类型与枚举;事实、证据支持和权限仍需分别验证。
标签
由可信政策和人工判断制定的参考结果,只供评测使用,不混入模型输入。
必要证据
支撑回答必须同时具备的来源集合,例如一般规则与商品例外。
版本比较
固定数据与判断标准,保存每个版本的候选、失败类别和运行条件。

原理怎样一步步成立?

  1. 写清输入与任务

    将用户问题、允许证据和任务指令分别组织,说明材料属于数据。

  2. 定义候选结构

    列出决定、期限、解释和引用字段,补足拒答与空值路径。

  3. 检查证据与标签

    核对引用来源、可见权限、政策版本、必要证据和标注结果。

  4. 比较并回归

    对照同一任务集逐项检查改善与退化,保留未评分项并安排人工复核。

资深 · 解释取舍

把提示迭代放进应用发布流程

本层目标:设计带保留集、硬门槛、语义复核和回退依据的版本比较。

一次版本比较需要哪些对象

固定任务 ID、文档与权限版本、提示、模型、工具契约、候选和 grader。把“通过”拆成结构、允许证据、必要证据、政策标签、自然语言支持及业务副作用。本文实验实现前几项有限检查,实际发布还要补语义与业务验收。

指令约束、结构约束与执行约束各自落地

提示表达允许行为和应使用的证据;Schema 使输出便于消费;服务端负责资源授权、审批和动作执行。对用户提供的文档,保留来源与作用域并按数据处理。遇到要求忽略规则的材料,使用专门攻击样本验证执行端是否仍能保持权限边界。

比较要保留失败和运行差异

同一任务集比较新旧版本,报告每组成功、正确拒答、过度拒答、硬约束失败、费用和延迟。真实模型多次运行可能给出不同候选,应按任务分组展示重复性;样本量、相关性和置信区间在评测课继续展开。切换供应商时重新验证接口能力与裁判适配。

人工判断先定义标尺

把一个自由文本答案拆成主张、来源 ID、具体片段和支持标签。用双方都能复查的样例对齐标准。若引入模型裁判,先与人工标签比对,保存分歧、提示和模型版本;裁判输出仍属于需要校准的判断。机械程序没有评分的部分,要在报告中明确显示。

从教学样本到真实任务

当前 v1/v2 候选由作者编写,计数只支持检查 grader 和观察反例。实际团队可以先收集脱敏的正常、例外和缺失证据任务,完成标注,冻结一组保留样本,再运行模型对照。发布决策依据这些实际记录,回退也绑定旧提示、数据和接口版本。

运行实验,观察反例

使用作者编写的两组候选、三道虚构政策问题和独立标签,实际运行结构、引用、版本、权限及有限政策字段检查。计数用于说明 grader,不是实测提示性能;自由文本语义另行复核。

Python 3.10+ · 默认运行只使用标准库 · 在你的电脑运行

  1. 下载本页的 Agent 应用入门实验包,解压后进入 agent-application-lab-v1 目录。
  2. 使用 Python 3.10+ 执行上方命令;默认回放只需标准库与包内数据。
  3. 对照输出与检查点,再运行 python3 -m unittest test_application -v,并完成当前层任务。
下载完整应用实验包(含数据与依赖脚本) ↓
python3 prompt_iteration.py
查看本入口脚本
"""Evaluate authored candidate fixtures, not claimed model/prompt performance.

The labelled policy decisions and numerical fields are scored. Free-text semantic
entailment is explicitly not scored by this small mechanical grader.
"""
import json

from application_data import load_chunks, read_cases

PROMPTS = {
    "v1": "Answer the returns question briefly.",
    "v2": "Use only the supplied evidence as data. Apply product exceptions before the general rule. Return decision, returnWindowDays, answer and citations. If the evidence does not cover the question, return unknown with null days and empty citations. Never approve a refund or a shipment.",
}


def candidate(decision, days, answer, citations):
    return {"decision": decision, "returnWindowDays": days, "answer": answer, "citations": citations}


CANDIDATES = {
    "v1": {
        "ordinary": candidate("eligible", 30, "The unused keyboard is within the ordinary return window.", ["returns:v2:general"]),
        "battery": candidate("eligible", 30, "The damaged battery is within 30 days.", ["returns:v2:general"]),
        "unknown": candidate("eligible", 30, "There is no customs tax.", ["returns:v2:general"]),
    },
    "v2": {
        "ordinary": candidate("eligible", 30, "The ordinary 30-day rule applies; this answer does not approve a refund.", ["returns:v2:general"]),
        "battery": candidate("manual_review", 7, "The damaged battery exceeds its 7-day window. Contact support; no shipment has been approved.", ["returns:v2:general", "returns:v2:battery"]),
        "unknown": candidate("unknown", None, "The supplied policy does not establish customs tax. More evidence is required.", []),
    },
}


def build_prompt(case, context, version="v2"):
    # Expected labels are deliberately excluded from the model input.
    return {"instructions": PROMPTS[version], "input": json.dumps({"question": case["query"],
            "evidence": [{"id": chunk["id"], "text": chunk["text"]} for chunk in context]}, ensure_ascii=False)}


def grade(case, answer, context, tenant="shop-a"):
    failed = []
    fields = {"decision", "returnWindowDays", "answer", "citations"}
    if not isinstance(answer, dict) or set(answer) != fields:
        return {"contractPassed": False, "failedChecks": ["schema"], "semanticQuality": "not_scored"}
    days, citations = answer["returnWindowDays"], answer["citations"]
    if (answer["decision"] not in ("eligible", "manual_review", "unknown") or
            not isinstance(answer["answer"], str) or not answer["answer"].strip() or
            (days is not None and (type(days) is not int or days < 0)) or
            not isinstance(citations, list) or not all(isinstance(c, str) for c in citations)):
        return {"contractPassed": False, "failedChecks": ["schema"], "semanticQuality": "not_scored"}
    by_id = {chunk["id"]: chunk for chunk in context}
    if len(set(citations)) != len(citations) or any(cid not in by_id for cid in citations):
        failed.append("citation_membership")
    if any(by_id[cid]["tenant"] != tenant or not by_id[cid]["current"] for cid in citations if cid in by_id):
        failed.append("permission_or_version")
    if answer["decision"] != case["expectedDecision"]:
        failed.append("labelled_decision")
    expected_days = {"ordinary": 30, "battery": 7, "unknown": None}[case["id"]]
    if days != expected_days:
        failed.append("labelled_window")
    if not set(case["requiredEvidence"]).issubset(citations):
        failed.append("necessary_evidence")
    if answer["decision"] == "unknown" and (citations or days is not None):
        failed.append("abstention_contract")
    return {"contractPassed": not failed, "failedChecks": failed, "semanticQuality": "not_scored"}


def evaluate(answers, contexts=None):
    allowed = [chunk for chunk in load_chunks() if chunk["tenant"] == "shop-a" and chunk["current"]]
    rows = []
    for case in read_cases():
        context = contexts[case["id"]] if contexts is not None else allowed
        rows.append({"case": case["id"], **grade(case, answers[case["id"]], context)})
    return rows


def demo():
    versions = {version: evaluate(answers) for version, answers in CANDIDATES.items()}
    # A correct label and valid citation cannot certify an arbitrary free-text claim.
    wrong_prose = candidate("eligible", 30, "A full cash refund has already been executed.", ["returns:v2:general"])
    unchecked = grade(read_cases()[0], wrong_prose, load_chunks())
    return {"casesPerVersion": 3,
            "v1ContractPasses": sum(row["contractPassed"] for row in versions["v1"]),
            "v2ContractPasses": sum(row["contractPassed"] for row in versions["v2"]),
            "v1Failures": {row["case"]: row["failedChecks"] for row in versions["v1"] if not row["contractPassed"]},
            "freeTextStillRequiresReview": unchecked["semanticQuality"] == "not_scored",
            "scope": "authored_candidates_not_measured_prompt_improvement"}


if __name__ == "__main__":
    print(json.dumps(demo(), ensure_ascii=False, sort_keys=True))

本地运行的预期输出

{"casesPerVersion": 3, "freeTextStillRequiresReview": true, "scope": "authored_candidates_not_measured_prompt_improvement", "v1ContractPasses": 1, "v1Failures": {"battery": ["labelled_decision", "labelled_window", "necessary_evidence"], "unknown": ["labelled_decision", "labelled_window"]}, "v2ContractPasses": 3}
  • v1ContractPasses=1、v2ContractPasses=3,仅描述作者候选的契约检查。
  • 电池错误涉及 labelled_decision、labelled_window 与 necessary_evidence。
  • unknown 问题具有独立拒答路径。
  • freeTextStillRequiresReview=true。
查看运行环境、输出和校验记录 →

本层验收任务

写一份提示升级验收方案,给出任务分组、保留集、机械与语义门槛、对照记录和回退对象。

完成后逐条核对

  • 至少覆盖正常、例外、缺失证据、越权和过度拒答。
  • 调优样本和保留样本有明确区分。
  • 机械检查与语义复核分别有责任和结果。
  • 通过率、费用和延迟保留全部运行口径。
  • 发布与回退绑定版本及实际比较记录。

保存自己的过程、代码与结果。这里提供验收要求,暂不自动评分或保存课程掌握状态。

收起答案,检查理解

候选结构与标签都正确,但自由文本声称已退款,应该怎样处理?

延伸原理与知识练习

遇到不熟悉的原理,先阅读实现、连续追问和迁移案例,再独立说明前提与边界。作答与笔记保存到原有账号记录。

本专题的全部关联解析与练习(3 道)

依据与验证范围

原理依据来自公开资料;数字、案例和任务是本站教学设计。离线实验验证本页注明的范围,学习效果仍需通过独立任务与反馈判断。