Skip to main content

原语(问题)

机器翻译译自英文(docs.typesafe.ai)本页 51 段已全部译完

文档索引

在以下地址获取完整的文档索引:https://docs.typesafe.ai/llms.txt 使用此文件可以在进一步探索之前发现所有可用页面。

原语(问题)

三种 TypeSafe 问题类型(Choice、Score、Noul)、它们返回的类型化答案、如何在它们之间进行选择以及如何一次性提问。

TypeSafe 的原语是你在代码中组合的小型、类型化构建块。它们成对出现:一个问题定义 System One 模型 对 状态 所做的一个判断,而其答案则是返回的类型化值。你在代码中组合这些答案以做出决策。有三种问题类型,每种返回不同形态的答案。

类型回答什么返回
Choice这些选项中哪个?choice, probabilities, confidence
Score哪个级别?score, legend, probabilities, confidence
Noul这是真的吗?noul (0 到 1)

你可以提出一个问题或将几个问题一起发送。请求中的每个问题查看相同的状态,独立评估,并返回你在你选择的 ID 下的类型化答案。

每个问题只请求一个瞬间判断

System One 模型专为快速、集中的判断而构建。询问一个拥有知识的人在给定正确上下文时在一秒内做出的判断。“此消息是否传达出紧迫感?”是一个好问题。“分析此消息并确定最佳行动方案”则不是。这需要缓慢的推理,这是一个信号,提示你应将该任务分解为小问题,并在代码中组合答案。

如果你想要的判断取决于几个独立因素,请分别询问每个因素,并使用你自己的逻辑组合答案。与其“评估这个创业计划”,不如分别询问市场规模、技术可行性和差异化程度,然后在代码中根据它们的相对重要性进行加权。当优先级变化时,更改权重的值而不是重写提示。同时询问多个问题 展示了如何做到这一点。

定义问题

每个问题都有一个 ID、type 和 instructions。Choice 和 Score 问题还包含 criteria,用于定义 Choice 问题的选项或 Score 的级别。Noul 问题可以接受 criteria 作为对是和否含义的可选澄清。

  • ID。你选择的键,例如 refund_requested。它在响应中标识答案。
  • type。choice、score 或 noul 之一。
  • instructions。你针对状态提出的问题。这是放入评估逻辑的地方。将其写成一个清晰、具体的问题,或一个供模型判断的陈述。对于大多数问题,字符串就足够了。它也可以是对象或数组,将问题放在一个字段中,将其引用的数据放在其他字段中;参见 在问题中使用结构。
  • criteria。可能的答案:Choice 问题的选项映射,Score 的有序级别列表,以及 Noul 对是和否的可选描述。每种问题类型的页面都介绍其结构。

这个问题询问客户是否申请了退款:

from typesafe_sdk import Noul

questions = {
    "refund_requested": Noul(
        instructions="Does the customer request a refund?",
    ),
}

Tip

问题 ID 是供你的代码使用的。它们不会发送给模型。在 instructions 中编写完整的问题,即使 ID 看似不言自明。

选择问题类型

选择与你所需答案形状匹配的类型。

  • Choice 适用于答案是从一组无顺序的选项中选择的情况:将工单路由到部门、对文档类型进行分类、检测编程语言。提供完整的选项列表,并在列表可能无法覆盖所有输入时添加 other(其他)或 none of the above(以上都不是)选项。

  • Score 适用于答案落在频谱上,且你可以描述该频谱上每个点含义的情况:错误严重程度、客户挫败感、技能水平。级别由你定义,模型返回在这些级别上的位置。

  • Noul 适用于清晰的 是/否 问题,其中概率本身就是有用的信号:此消息是否包含个人身份信息、客户是否请求退款、简历是否提及分布式系统。

Note

使用 Noul 进行是/否判断,使用 Score 来衡量光谱上的位置。“这位候选人 Python 能力强吗?”需要明确定义“强”。Noul 值为 0.5 意味着模型对于是和否给出相等的概率。这并不意味着候选人的技能水平中等。模糊的定义会使该概率难以解释。

如果你想测量技能水平,请使用带有定义级别的 Score,例如:无经验、稍有熟悉、日常使用、深度专业知识。如果你需要一个 是/否 决策,请明确定义条件,例如“简历是否陈述候选人在工作中使用过 Python?”

如果两种类型似乎都合适,请优先选择其答案你的代码可直接操作的那种。refund、rebook 和 information 之间的 Choice 直接映射到三条代码路径。客户挫折感的 Score 映射到一个阈值。Noul 映射到一个 if。

返回什么

答案也是原语。每种问题类型返回一个类型化值,你的代码可以对其进行比较、阈值处理、排序、传入进一步逻辑,或放入后续请求的状态中(参见 当一个问题依赖于另一个问题时)。

类型答案字段如何解读
Choicechoice, probabilities, confidencechoice 是选定的选项。probabilities 是跨越每个选项的分布。confidence 总结了该分布的峰值程度。
Scorescore, legend, probabilities, confidencescore 是你级别上的一个位置,可以介于两个级别之间。legend 按数字重复这些级别。probabilities 是跨越级别的分布。
Noulnoul答案为是的概率。接近 1 表示强烈的肯定,接近 0 表示强烈的否定,接近 0.5 表示不确定。Noul 没有单独的 confidence。

这些答案的两个属性使它们可组合:

  • 每个答案都限制在你提供的选项范围内。 模型返回你选项或级别上的概率分布,绝不会返回它们之外的值。你的代码无需从生成的文本中恢复值。
  • 每个答案都是独立的。 一个问题答案不是另一个问题的隐藏上下文。你可以添加或删除问题,而不会更改其他问题的结果。

置信度 解释了 confidence 如何从 probabilities 派生,以及如何使用它来决定何时自动执行操作,何时升级到人工处理。

引用特定字段

被评估的内容,即 状态,通常是包含多个部分的 JSON 对象:对话、记录、政策。当问题涉及其中某一部分时,在 instructions 中使用点号和索引路径引用其键,并包含反引号。模型随后知道应评估状态的哪一部分。

取状态页面中的支持对话示例:

{
  "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`?"
        ),
    },
}

明确的路径可以清晰指示结构化状态的哪些部分应作为每次判断的依据。请参阅 状态 了解如何结构化输入数据。

同时询问多个问题

在一次请求中发送所有使用相同状态的问题。你可以自由混合问题类型。System One 模型并行评估请求中的每个问题。增加问题几乎不会改变响应时间,且只增加额外问题的 token 成本(非常便宜)。询问你可能不需要的问题几乎零成本。

此请求同时分类客户消息、检查紧急程度并对挫败感进行评分:

{
  "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 中,将 questions 字典(包含 Choice、Noul 和 Score 对象)传递给 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 了解你所用语言的安装和使用方法。

提出推测性问题

询问你的代码可能需要的所有问题,包括那些仅与某些输入相关的问题,并让代码决定使用哪些答案。如果工单结果不是 bug 报告,请忽略严重性答案。我们称此为 推测性扇出 模式。并行问题 cookbook 展示了如何将 13 个问题批量处理为一次调用,其成本是 13 个单独调用的 1/11.5 倍,速度快 9.6 倍,且答案不变。

Tip

编码 agent 比人类更容易养成每次调用只问一个问题的习惯。TypeSafe agent skill 会指示你的 agent 在每次调用中包含多个问题,包括那些仅与某些输入相关的问题。

将复杂的判断拆分为多个问题

依赖多个因素的判断最好拆分为每个因素一个问题。在你的代码中组合答案,给每个答案赋予反映其相对重要性的权重。权重由你决定。当组合结果与你团队的决策不符时,在代码中更改权重并重新运行。增加问题几乎不会改变响应时间,因为它们在一次请求中并行运行。拆分仅增加少量额外的问题 token。

例如,工单优先级可能由三个 Score 问题构建:bug 有多严重、客户有多沮丧,以及报告为工程师提供了多少工作依据。Score 页面逐步介绍了此请求以及规范化并加权答案的代码,见 将复杂判断拆分为多个 Score。此技术称为 复合评分 模式。

当一个问题依赖于另一个问题时

同一请求中的问题是独立的:一个答案不会成为另一个问题的上下文。如果后续的判断取决于先前的答案,请在代码中发出第二个请求。只有当你的代码在获得第一个答案之前无法构建第二个请求时(例如,需要答案来获取状态的更多数据、决定状态的组成或选择下一个问题的选项),这种依赖关系才是真实的。否则,请将问题一起提出,并在代码中组合它们的答案。

两次请求是例外,而非规则。如果第二次请求的问题本可以针对原始状态提出,请在第一次请求中提出它们,并让代码忽略不需要的答案。三个 cookbook 因实际原因进行第二次请求。Skill 建议 在一次请求中对 182 个 skill 进行排名,然后获取前三个 skill 的完整文本并基于更好的证据再次评估它们。结构恢复 询问每个换行符是否分割了句子,根据这些答案将行合并为块,然后对块进行分类,这些块在第一次请求回答之前并不存在。层次分类 使用每个 Choice 答案来决定下一个请求提供哪些选项。

请参阅 如何使用 TypeSafe 构建 以获取关于将工作流分解为专注判断的指导。

下一步

Choice

从固定列表中选择一个选项。

Score

沿有序级别对状态进行评级。

Noul

获取陈述为真的概率。

要了解这些如何组合成系统架构,请前往 模式。