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

SYSTEMATIC LEARNING / 分层专题

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

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

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

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

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

本层学习目录

先补齐必要概念

适合:准备写提示、JSON Schema 和可执行验收程序。

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

原理怎样一步步成立?

  1. 写清输入与任务

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

  2. 定义候选结构

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

  3. 检查证据与标签

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

  4. 比较并回归

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

初级 · 完成实现

实现结构与证据分开的验收

本层目标:对照代码把 Schema、引用、政策标签与自由文本复核分别实现。

运行候选验收

在解压目录执行:

python3 prompt_iteration.py

三道教学问题中,作者编写的 v1 候选有一份通过契约,v2 候选有三份通过。候选集合是专门构造的示例,用来观察 grader 的检查行为。要比较真实提示效果,需要对相同任务实际调用模型、保存候选,再交给同一套验收。

build_prompt 只传用户问题和上下文证据;grade 先检查字段与类型,再检查引用是否出现在当前上下文、是否属于允许租户和当前版本,之后对照决定与期限标签。true 在 Python 中可表现为整数,代码使用严格类型检查,避免把它当作一天。

结构化输出的请求形状

对于支持该能力的 Responses 模型,可把以下格式配置放进请求的 text.format。完整支持范围与拒绝处理按官方文档核对:

{
  "type": "json_schema",
  "name": "policy_answer",
  "strict": true,
  "schema": {
    "type": "object",
    "properties": {
      "decision": {"type":"string","enum":["eligible","manual_review","unknown"]},
      "returnWindowDays": {"type":["integer","null"]},
      "answer": {"type":"string"},
      "citations": {"type":"array","items":{"type":"string"}}
    },
    "required": ["decision","returnWindowDays","answer","citations"],
    "additionalProperties": false
  }
}

先使用模型响应课的分类路径处理拒绝与不完整,再解析完整文本。给定拒答类型和 null 分支,可以让模型在材料不足时交付合法对象。下游验证器仍要检查数值范围、引用与业务政策。

用一份真实候选复用 grader

准备自己的 candidate.json 后,在本地运行:

python3 - <<'PY'
import json
from application_data import read_cases, load_chunks
from prompt_iteration import grade
case = next(c for c in read_cases() if c['id'] == 'battery')
context = [c for c in load_chunks() if c['tenant']=='shop-a' and c['current']]
print(grade(case, json.load(open('candidate.json')), context))
PY

文件可来自作者样本或脱敏的真实生成,交付时标明来源、模型和提示版本。测试未知引用、少一条例外、期限写成 true 和正确拒答,观察错误归到哪一段。

最后一项需要单独复核

程序可以发现结构、来源身份和已标注政策字段的问题,自由解释文本显示 semanticQuality=not_scored。比如对象标签正确,却写“已经执行现金退款”,此 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。
查看运行环境、输出和校验记录 →

本层验收任务

交付四份候选:正确例外、未知引用、缺失例外和带错误自由文本的合法对象;分别运行 grader,并写出还需人工核对的主张。

完成后逐条核对

  • 正确对象能通过现有字段与标签检查。
  • 引用缺失或越权有独立失败类别。
  • 期限 true 被归为 schema 错误。
  • 机械通过与自由文本支持分别记录。
  • 真实候选保留模型、提示、数据和响应来源。

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

收起答案,检查理解

引用 ID 存在,是否已经证明解释中的每个事实都成立?

延伸原理与知识练习

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

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

依据与验证范围

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