文档目录
题型总览
TypeSafe 的题型、它们返回的带类型答案、如何在它们之间选择,以及如何一次性提出多个问题。
非官方中文翻译 · 内容以 英文原文 ↗ 为准 · 同步于 2026-10-15
TypeSafe 的题型是你在代码中组合使用的小型、带类型的积木。它们成对出现:一个**问题(question)**定义了一个由 System One 模型针对某个 **state(上下文状态)做出的判断,而它的答案(answer)**就是返回的那个带类型的值。你在代码中组合这些答案来做出决策。每种题型返回不同形态的答案。
| 类型 | 它回答的问题 | 返回值 |
|---|---|---|
| Choice(选择题) | 这些选项中哪一个? | choice、probabilities、confidence |
| Score(打分题) | 处于哪一档? | score、legend、probabilities、confidence |
| Noul(是非题) | 这是真的吗? | noul(取值 0 到 1) |
你可以一次提一个问题,也可以一次性发送多个。同一请求中的每个问题看到的 state 相同,互相独立地评估,并按你选择的 ID 返回带类型的答案。
一次提问一个问题,获得单一快速判断
System One 模型专为快速、聚焦的判断而设计。请让它做出的判断,应当是「具备合适上下文的内行人花一秒钟就能给出」的那种。「这条消息是否传达了紧迫感?」是一个好问题。「分析这条消息并确定最佳行动方案」就不是。那需要慢速推理,这也是一个把任务拆分成小问题并在代码中组合答案的信号。
如果你想要的判断依赖于若干独立因素,那就分别针对每个因素提问,然后用你自己的逻辑组合答案。不要问「给这个创业路演打分」,而是分别就市场规模、技术可行性和差异化提问,然后根据它们的相对重要性在代码中加权。当优先级变化时,调整权重值,而不是重写提示词。一次性提出多个问题 展示了如何做到这一点。
定义一个问题
每个问题都有一个 ID、一个 type 和 instructions。Choice 和 Score 类型的问题还需要 criteria,它定义了 Choice 问题的选项或 Score 问题的档位。Noul 类型的问题接受 criteria 作为对 yes 与 no 含义的可选澄清。
- ID。 你选择的键,比如
refund_requested。它在响应中标识该答案。 type。choice、score或noul之一。instructions。 你就 state 提出的问题。这是放置你的评估逻辑的地方。把它写成一个清晰、具体的问题,或者写成一个供模型判断的陈述。对于大多数问题来说,一个字符串就够了。它也可以是一个对象或数组,把问题放在一个字段中,把它所引用的数据放在其他字段中;参见在问题中使用结构。criteria。 可能的答案:Choice 问题的选项 map,Score 问题的有序档位列表,以及 Noul 问题的 yes 和 no 的可选描述。每个题型的页面都会介绍其形态。
这个问题询问客户是否请求了退款:
from typesafe_sdk import Noul
questions = {
"refund_requested": Noul(
instructions="Does the customer request a refund?",
),
}选择问题类型
选择与所需答案形态匹配的类型。
Choice(选择题) 适合答案是一组已知选项、且彼此之间没有顺序关系的情况:把工单路由到一个部门、对文档类型进行分类、检测编程语言。给出完整的选项列表,并在列表可能无法覆盖所有输入时添加一个
other或none of the above选项。Score(打分题) 适合答案落在一个连续谱上、并且你能描述该连续谱上每个点含义的情况:缺陷严重度、客户挫败感、技能水平。档位由你定义,模型返回沿档位的一个位置。
Noul(是非题) 适合一个干净的 yes/no 问题,并且概率本身就是有用的信号:这条消息是否包含个人可识别信息,客户是否在请求退款,这份简历是否提到分布式系统。
如果两种类型看起来都合适,选择你的代码可以直接采取行动的那一种。refund、rebook、information 之间的 Choice 直接对应三条代码路径。客户挫败感的 Score 对应一个阈值。Noul 对应一个 if。
返回结果
答案也是题型。每个问题类型返回一个带类型的值,你的代码可以比较、设置阈值、排序、传入进一步的逻辑,或放入后续请求的 state 中(参见一个问题依赖于另一个问题时)。
| 类型 | 答案字段 | 如何解读 |
|---|---|---|
| Choice | choice、probabilities、confidence |
choice 是所选选项。probabilities 是跨所有选项的分布。confidence 概括了该分布的尖锐程度。 |
| Score | score、legend、probabilities、confidence |
score 是沿你的档位上的一个位置,可以落在两档之间。legend 按编号重复档位。probabilities 是跨档位的分布。 |
| Noul | noul |
答案为 yes 的概率。接近 1 是强烈的 yes,接近 0 是强烈的 no,接近 0.5 表示不确定。Noul 没有独立的 confidence。 |
这些答案有两个使其可组合的特性:
- 每个答案都被约束在你提供的选项内。 模型返回的是你的选项或档位上的概率分布,绝不会返回超出它们的值。你的代码永远不需要从生成的散文中恢复一个值。
- 每个答案都是独立的。 一个问题的答案不会成为另一个问题的隐藏上下文。你可以添加或删除问题,而不会改变其他问题的结果。
某些题型还会返回 confidence;每个题型的页面会说明其答案是否包含它。置信度 一节解释了如何用它来决定何时自动执行、何时升级到人工处理。
引用具体字段
被评估的内容——也就是 state ——通常是一个包含多个部分的 JSON 对象:一次对话、一条记录、一份策略。当问题针对的是其中某一部分时,用点-索引路径在 instructions 中指明它的键,包括反引号。模型于是就知道要判断 state 的哪一部分。
拿 State 页面中的支持对话为例:
{
"ticket": {
"subject": "Duplicate charge",
"messages": [
{"from": "customer", "text": "I was charged twice for order A-104. Please refund the duplicate."},
{"from": "support", "text": "We are checking the charges."}
]
},
"order": {
"id": "A-104",
"charges": [
{"amount_usd": 49, "status": "captured"},
{"amount_usd": 49, "status": "captured"}
]
},
"refund_policy": "Duplicate charges are eligible for a refund."
}下面这两个问题按路径指向客户的消息、策略以及收费记录:
questions = {
"refund_requested": {
"type": "noul",
"instructions": "Does `ticket.messages[0].text` request a refund?",
},
"policy_supports_refund": {
"type": "noul",
"instructions": (
"Does `refund_policy` support the refund requested "
"in `ticket.messages[0].text`, given `order.charges`?"
),
},
}显式的路径能清楚地表明结构化 state 中的哪些部分应当影响每次判断。参见 State 以了解如何组织输入。
一次性提出多个问题
把所有使用同一个 state 的问题放在一个请求中发送。你可以自由地混合题型。System One 模型并行评估同一请求中的所有问题。增加问题几乎不会改变响应时间,也只会增加少量额外问题的 token 成本,而这些成本是很低的。问一个你可能不需要的问题几乎是不花钱的。
这个请求一次性完成了客户消息的分类、紧迫性的判断以及挫败感的打分:
{
"model": "jev-latest",
"state": "Our API integration started returning 500 errors on every request about 20 minutes ago, and we can't process any customer orders until this is fixed.",
"questions": {
"department": {
"type": "choice",
"instructions": "Which team should handle this",
"criteria": {
"billing": "Payment or subscription issues",
"technical": "Bugs or integration problems",
"sales": "Pricing or account questions"
}
},
"is_urgent": {
"type": "noul",
"instructions": "The message conveys urgency or time-sensitivity"
},
"frustration": {
"type": "score",
"instructions": "How frustrated the customer appears",
"criteria": [
"Calm, just stating facts",
"Frustrated but civil",
"Very angry, strong language"
]
}
}
}我们的客户端 SDK 提供了带类型的问题和答案。在 Python 中,把 Choice、Noul 和 Score 对象的 questions 字典传递给 client.system_one(...)。下面的请求发送一张工单和一条退款策略一次,并为每个问题获得一个带类型的答案:
from typesafe_sdk import Choice, Noul, Score, TypeSafeClient
state = {
"ticket_message": "My flight was cancelled. Can I get a refund?",
"refund_policy": "Cancelled flights are eligible for a full refund.",
}
with TypeSafeClient() as client:
response = client.system_one(
state=state,
questions={
"refund_requested": Noul(
instructions="Does `ticket_message` request a refund?",
),
"request_type": Choice(
instructions="What is the main request in `ticket_message`?",
criteria={
"refund": "The customer wants money returned.",
"rebooking": "The customer wants a replacement flight.",
"information": "The customer is asking for information only.",
},
),
"frustration": Score(
instructions="How frustrated does the customer appear in `ticket_message`?",
criteria=[
"Calm and neutral.",
"Concerned but civil.",
"Very angry or using strong language.",
],
),
},
)
print(response.answers["refund_requested"].noul)
print(response.answers["request_type"].choice)
print(response.answers["frustration"].score)参见客户端 SDK 以获取你所使用语言的安装和使用方法。
提出推测式问题
把所有你的代码可能需要的问题都问出来,包括那些答案只对部分输入才有意义的问题,然后让代码决定使用哪些答案。如果一张工单最终不是缺陷报告,那就忽略严重度答案。我们称其为推测式扇出(speculative fan-out) 设计模式。并行问题实战示例 展示了把 13 个问题批量放入一次调用比 13 次单独调用便宜 11.5 倍、快 9.6 倍,而答案没有任何变化。
你可以问多少个问题
请求中的问题数量没有限制。真正限制请求的是其大小:它必须适配模型的单次请求上下文和单题上下文。
与 state 相比,问题通常较短,因此 state 占据了这两者的大部分。如果你的问题无法全部放进一个请求,一种做法是把它们拆分到几个共享同一个 state 的请求中。
把一个复杂判断拆成多个问题
依赖于多件事的判断最好按「一件事一个问题」的方式拆开。在你的代码中组合这些答案,按相对重要性给每个加权。这些权重由你决定。当组合结果与你团队的判断不一致时,在代码中调整它们并重新运行。由于问题在同一个请求内并行运行,增加问题几乎不会改变响应时间。这种拆分只会多花少量问题的 token。
例如,工单优先级可以由三个 Score 问题构建:缺陷有多严重、客户有多挫败、以及这份报告为工程师提供了多少可操作的信息。Score 页面通过把一个复杂判断拆成多个 Score 问题 一节详细介绍了这个请求及其对答案进行归一化和加权的代码。这种技巧被称为组合打分 设计模式。
一个问题依赖于另一个问题时
同一请求中的问题是相互独立的:一个问题的答案不会成为另一个问题的上下文。如果后续的判断依赖于前面的答案,就在代码中发起第二次请求。只有当你的代码在拿到第一个答案之前无法构建第二次请求时,这种依赖才是真实的:它需要该答案来为 state 获取更多数据、决定 state 由什么组成,或者挑选下一个问题的选项。否则,就把这些问题一起提出,并在代码中组合它们的答案。
两次请求是例外,而非通则。如果第二次请求中的问题原本就可以针对原始 state 提出,就把它们放进第一次请求中,让代码忽略它不需要的部分。三个实战示例出于真实的原因发出了第二次请求。技能推荐 在一次请求中排序 182 个技能,然后获取前三名的完整内容,并针对这些更好的证据再次进行判断。结构恢复 询问每个换行是否分隔了句子,根据这些答案把行合并成块,然后对这些块进行分类——而这些块直到第一次请求回答后才存在。层次化分类 用每个 Choice 答案来决定下一次请求提供哪些选项。
参见如何使用 TypeSafe 构建 以获取关于把工作流拆解为聚焦判断的指导。
下一步
- Choice(选择题):从固定列表中选择一个选项。
- Score(打分题):按有序档位对 state(上下文状态)进行打分。
- Noul(是非题):获取某条陈述为真的概率。
要看这些题型如何组合成系统架构,可以前往 设计模式(Patterns)。
本文档由 Mintlify 构建和托管,Mintlify 是一个面向开发者的文档平台。