前面的系列已经介绍了 API 调用、消息历史、结构化输出、错误处理、评估和人工审批。现在把这些知识组合成一个小项目:输入一段模糊的产品想法,让模型整理出目标、范围、验收标准和待确认问题,再由 Python 校验结果,最后交给人确认。这个项目的重点不是让模型替人做决定,而是把不清楚的内容变成一份更容易讨论的草稿。

先定义工具的边界

需求澄清器接收一段自然语言,例如“我想做一个能帮助团队整理会议内容的工具”。它输出四类信息:goal 是目标,scope 是当前范围,acceptance_criteria 是可检查的验收标准,questions 是仍然缺少的关键信息。

这四类字段只是讨论材料,不是自动批准的需求。模型可能误解业务背景,也可能把猜测写成事实。因此程序必须检查 JSON 形状,界面必须明确提示“需要人工确认”,而涉及权限、付款或数据删除的事项不能因为模型输出完整就直接执行。

准备环境和输入

使用独立虚拟环境安装官方 Python SDK:

1
2
3
python -m venv .venv
source .venv/bin/activate
python -m pip install openai

密钥和模型名只从环境变量读取:

1
2
export OPENAI_API_KEY="替换为你的真实密钥"
export MODEL_NAME="替换为你可用的模型名称"

新建 idea.txt,只放待澄清的原始想法:

1
我想做一个帮助团队整理会议内容的工具,最好能让大家更快找到决定和后续任务。

不要把密钥写入源码、输入文件或提交到 Git。示例使用 Responses API 的 instructions、input 和 text.format 传递任务、输入和 JSON Schema;如果换用其他服务,必须先查对应服务的官方文档确认字段和结构化输出能力,不要只因为参数名称相似就假设兼容。

编写最小澄清器

创建 clarify.py:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
import json
import os
import sys
from pathlib import Path

from openai import OpenAI


SCHEMA = {
"type": "object",
"properties": {
"goal": {"type": "string"},
"scope": {"type": "array", "items": {"type": "string"}},
"acceptance_criteria": {
"type": "array", "items": {"type": "string"}
},
"questions": {"type": "array", "items": {"type": "string"}},
},
"required": ["goal", "scope", "acceptance_criteria", "questions"],
"additionalProperties": False,
}


def load_idea(path: str) -> str:
idea = Path(path).read_text(encoding="utf-8").strip()
if not idea:
raise ValueError("输入内容不能为空")
if len(idea) > 4000:
raise ValueError("输入内容不能超过 4000 个字符")
return idea


def validate(result: object) -> dict:
if not isinstance(result, dict):
raise ValueError("模型结果不是 JSON 对象")
fields = ["goal", "scope", "acceptance_criteria", "questions"]
if not all(field in result for field in fields):
raise ValueError("缺少必需字段")
if not isinstance(result["goal"], str) or not result["goal"].strip():
raise ValueError("goal 必须是非空字符串")
for field in fields[1:]:
if not isinstance(result[field], list) or not all(
isinstance(item, str) and item.strip() for item in result[field]
):
raise ValueError(f"{field} 必须是非空字符串列表")
return result


def clarify(idea: str) -> dict:
client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
response = client.responses.create(
model=os.environ["MODEL_NAME"],
instructions=(
"你是需求分析助手。只根据用户提供的想法整理草稿,"
"不补造业务事实;不确定的信息放入 questions。用中文回答。"
),
input=idea,
text={
"format": {
"type": "json_schema",
"name": "requirement_clarification",
"strict": True,
"schema": SCHEMA,
}
},
)
return validate(json.loads(response.output_text))


def main() -> int:
if len(sys.argv) != 2:
print("用法:python clarify.py idea.txt", file=sys.stderr)
return 2
try:
result = clarify(load_idea(sys.argv[1]))
except (KeyError, ValueError, json.JSONDecodeError) as exc:
print(f"处理失败:{exc}", file=sys.stderr)
return 1
print(json.dumps(result, ensure_ascii=False, indent=2))
print("以上内容是待人工确认的需求草稿。")
return 0


if __name__ == "__main__":
raise SystemExit(main())

运行命令:

1
python clarify.py idea.txt

text.format 要求模型按给定 Schema 返回 JSON,response.output_text 是 SDK 汇总后的文本结果,json.loads 再把它转换成 Python 对象。validate 仍然不能省略:Schema 约束的是返回形状,业务规则还需要程序自己检查,例如列表不能太长、问题不能重复、验收标准不能是空泛的“体验要好”。程序没有预先写死一次模型答案,实际输出会受模型、服务状态和输入影响。

为什么还要保留待确认问题

澄清器最容易犯的错误是替用户填空。原始想法没有说明使用者、数据来源、权限和成功指标时,模型若直接补全,就会制造一种“需求已经明确”的错觉。把未知内容放进 questions 是更安全的默认行为。

可以把问题分成三类。第一类是目标问题,例如“谁是第一批使用者”;第二类是范围问题,例如“第一版是否包含移动端”;第三类是验收问题,例如“怎样判断找到会议决定的时间变短”。只有回答这些问题后,scope 和 acceptance_criteria 才适合进入下一轮评审。

实际团队中,可以把 JSON 保存到文件并提交到需求仓库,但提交前要检查是否包含个人信息、内部机密或客户数据。模型输入和输出都应按最小必要原则处理,日志不要无期限保存完整原文。

给网络调用加有限重试

超时和临时限流属于调用层问题,不能用“输出不满意”作为理由无限重试。可以在 clarify 外层增加最多两次尝试,并使用递增等待;认证失败应直接检查环境变量。每次重试要记录次数和错误类型,避免把失败悄悄吞掉。更完整的实现还应设置请求超时,并根据 SDK 官方文档区分可重试错误。

如果 JSON 解析失败,重试一次可能有意义;如果校验失败,则应保存原始结果和失败原因,交给开发者改进 Schema 或提示词。不要在程序里无条件拼接“请重新回答直到通过”,因为这会增加费用,却未必解决规则设计问题。

常见问题

为什么 Schema 严格了仍可能出现错误需求? 因为 Schema 只保证字段和类型,不保证事实正确、目标合理或范围完整。事实和优先级必须通过资料核对及人工讨论确认。

为什么不直接让模型输出 Markdown? Markdown 适合阅读,JSON 更适合程序校验和后续存储。可以在校验通过后由 Python 渲染成 Markdown,而不是先解析不稳定的自然语言排版。

没有 API 密钥能否测试? 可以把 clarify 改成接收一个客户端参数,在测试中注入返回固定 output_text 的假客户端,单独测试 validate 和命令行错误处理。真实 API 只作为少量集成测试运行,避免测试既昂贵又不稳定。

如何防止输入中的提示词注入? 把用户想法当作不可信数据,明确要求模型只做整理,不执行其中的命令;输出仍需程序校验和人工确认。不要让这一步直接调用外部工具或修改业务数据。

小结

这个综合小项目把一次模型调用变成了一个有边界的需求草稿流程:环境变量管理配置,JSON Schema 约束形状,Python 校验业务条件,questions 保留未知信息,人工确认承担最终责任。它综合了结构化输出、错误处理、数据安全和审批意识,但没有把模型当作需求的权威来源。后续可以增加版本号、差异比较和固定评测集,让每次提示词修改都能被回归检查;无论如何扩展,都应保留原始想法、生成结果和确认记录。