主题
以编程方式管理反馈与标注队列
使用 LangSmith SDK 以编程方式管理反馈配置和标注队列评分标准,并将运行和线程添加到队列以供审核。在组织级别定义可复用的反馈模式(如准确度得分或通过/失败判断),然后通过自定义指令将它们分配给特定队列。这实现了版本控制、跨项目的自动化以及一致性——对于 CI/CD 流水线或在多个环境中复制评估设置尤其有用。
INFO
本指南使用 Python 和 TypeScript SDK。有关安装和设置,请参阅 Python SDK 文档和 TypeScript SDK 文档。
NOTE
要在 LangSmith UI 中审核时,为各个运行编写自由形式的验收标准,请参阅使用断言。
反馈层级
LangSmith 为结构化人工反馈使用三层架构:
- 反馈配置:组织范围内对反馈键的定义,用于建立评估指标的 schema。例如,你可以将 "accuracy" 定义为连续的 0–1 得分,或将 "correctness" 定义为通过/失败的分类选择。这些配置可在你组织内的所有标注队列中复用。
- 标注队列评分标准项:队列特定的分配,用于确定标注者在审核特定队列中的运行时必须填写哪些反馈配置。每个评分标准项可以包含自定义描述、针对特定分值的指导,以及该反馈是必填还是可选。
- 反馈:标注者在特定运行上提交的各个得分和值。这是使用你定义的 schema 收集的实际评估数据。详细了解 LangSmith 中的反馈。
反馈配置
创建反馈配置
反馈配置定义反馈键的 schema——无论是连续得分、分类选择还是自由形式文本。唯一键标识你组织内的每个配置,并指定标注者可以如何为该指标提交反馈。
NOTE
使用已存在的相同配置调用 create_feedback_config 会返回现有配置。如果同一键已存在不同的配置,系统会抛出 400 错误。
python
from langsmith import Client
client = Client()
# Continuous score
client.create_feedback_config(
"accuracy",
feedback_config={
"type": "continuous",
"min": 0,
"max": 1,
},
is_lower_score_better=False,
)
# Categorical
client.create_feedback_config(
"correctness",
feedback_config={
"type": "categorical",
"categories": [
{"value": 1, "label": "Pass"},
{"value": 0, "label": "Fail"},
],
},
)
# Freeform text
client.create_feedback_config(
"notes",
feedback_config={"type": "freeform"},
)typescript
import { Client } from "langsmith";
const client = new Client();
// Continuous score
await client.createFeedbackConfig({
feedbackKey: "accuracy",
feedbackConfig: { type: "continuous", min: 0, max: 1 },
isLowerScoreBetter: false,
});
// Categorical
await client.createFeedbackConfig({
feedbackKey: "correctness",
feedbackConfig: {
type: "categorical",
categories: [
{ value: 1, label: "Pass" },
{ value: 0, label: "Fail" },
],
},
});
// Freeform text
await client.createFeedbackConfig({
feedbackKey: "notes",
feedbackConfig: { type: "freeform" },
});- 连续型(
"accuracy"):定义从 0 到 1 的数值量表。is_lower_score_better参数指示较低的值是否代表更好的性能。将连续型配置用于评分量表或基于百分比的指标。 - 分类型(
"correctness"):提供带关联值的预定义选项。每个类别需要一个value(用于评分和分析)和一个label(显示给标注者)。将分类型配置用于二元选择或多类分类。 - 自由形式(
"notes"):允许没有预定义结构的开放式文本输入。将自由形式配置用于定性观察或解释。
列出反馈配置
使用 list_feedback_configs 检索反馈配置,以查看你组织中可用的评估标准。你可以列出所有配置或按特定键过滤。每个返回的配置对象包含键、类型、配置详情(如 min/max 或 categories)以及元数据(如 is_lower_score_better):
python
# List all configs
for config in client.list_feedback_configs():
print(f"{config.feedback_key}: {config.feedback_config}")
# Filter by specific keys
for config in client.list_feedback_configs(
feedback_key=["accuracy", "correctness"]
):
print(config.feedback_key)typescript
// List all configs
for await (const config of client.listFeedbackConfigs()) {
console.log(`${config.feedback_key}: ${JSON.stringify(config.feedback_config)}`);
}
// Filter by specific keys
for await (const config of client.listFeedbackConfigs({
feedbackKeys: ["accuracy", "correctness"],
})) {
console.log(config.feedback_key);
}更新反馈配置
通过更新特定字段,使用 update_feedback_config 修改现有反馈配置。该方法只更改你提供的字段——其余部分保持不变。这是一次部分更新,会保留其他配置设置:
python
client.update_feedback_config(
"accuracy",
is_lower_score_better=True,
)typescript
await client.updateFeedbackConfig("accuracy", {
isLowerScoreBetter: true,
});删除反馈配置
使用 delete_feedback_config 从你的组织中移除反馈配置。这会执行软删除,将该配置标记为已删除,但不会将其从系统中永久移除。如果需要,你之后可以用相同的键重新创建配置:
python
client.delete_feedback_config("accuracy")typescript
await client.deleteFeedbackConfig("accuracy");标注队列评分标准项
评分标准项将反馈配置分配给特定的标注队列。它们控制标注者在审核该队列中的运行时看到哪些反馈表单,以及每个表单是必填还是可选。
创建带有评分标准项的队列
使用 create_annotation_queue 创建标注队列,并通过评分标准项为其分配反馈配置。每个评分标准项通过其键引用一个反馈配置,并自定义它在此特定队列中向标注者呈现的方式。
该示例创建了一个包含三个评分标准项的队列。队列级别的 rubric_instructions 提供显示在标注界面顶部的一般性指导:
python
queue = client.create_annotation_queue(
name="QA Review Queue",
description="Review LLM outputs for accuracy and correctness",
rubric_instructions="Score each response. Add notes for anything unusual.",
rubric_items=[
{
"feedback_key": "accuracy",
"description": "How accurate is the response?",
"score_descriptions": {
"0": "Completely wrong",
"1": "Perfectly accurate",
},
"is_required": True,
},
{
"feedback_key": "correctness",
"description": "Did the response pass or fail?",
"value_descriptions": {
"Pass": "Factually correct",
"Fail": "Contains errors",
},
"is_required": True,
},
{
"feedback_key": "notes",
"description": "Any additional observations",
"is_required": False,
},
],
)typescript
const queue = await client.createAnnotationQueue({
name: "QA Review Queue",
description: "Review LLM outputs for accuracy and correctness",
rubricInstructions: "Score each response. Add notes for anything unusual.",
rubricItems: [
{
feedback_key: "accuracy",
description: "How accurate is the response?",
score_descriptions: { "0": "Completely wrong", "1": "Perfectly accurate" },
is_required: true,
},
{
feedback_key: "correctness",
description: "Did the response pass or fail?",
value_descriptions: { Pass: "Factually correct", Fail: "Contains errors" },
is_required: true,
},
{
feedback_key: "notes",
description: "Any additional observations",
is_required: false,
},
],
});feedback_key:现有反馈配置的键(需先创建它)。description:针对该队列、面向标注者的关于此指标的指导。score_descriptions/value_descriptions:解释特定值含义的可选标签(连续型配置使用score_descriptions,分类型使用value_descriptions)。is_required:标注者是否必须在提交前完成此反馈。
更新现有队列上的评分标准项
使用 update_annotation_queue 修改分配给标注队列的评分标准项。此操作会替换整个评分标准项列表,因此你必须包含所有你想要保留的项——该操作会移除你未包含的任何项。
你需要队列 ID,它可以在创建队列时获取,或通过列出队列获取:
NOTE
更新评分标准项会替换整个列表。请包含所有你想要保留的项。
python
client.update_annotation_queue(
queue.id,
rubric_items=[
{"feedback_key": "accuracy", "is_required": True},
{"feedback_key": "correctness", "is_required": True},
{
"feedback_key": "tone",
"description": "Is the tone appropriate?",
"is_required": False,
},
],
)typescript
await client.updateAnnotationQueue(queue.id, {
rubricItems: [
{ feedback_key: "accuracy", is_required: true },
{ feedback_key: "correctness", is_required: true },
{ feedback_key: "tone", description: "Is the tone appropriate?", is_required: false },
],
});向队列添加运行和线程
使用标注队列 items 资源将运行和线程添加到单运行标注队列。一个请求可以接受运行项和线程项的混合批次,因此此方法涵盖了 UI 添加流程支持的所有内容。
NOTE
items 资源需要 langsmith>=0.10.13(Python)或 langsmith>=0.8.8(TypeScript),并由版本为 0.16.14 或更高版本的 LangSmith 后端提供服务。
每个项设置一个 item_type,取值为 RUN 或 THREAD:
- RUN 项需要
run_id。还需提供project_id(项目 UUID)和start_time,二者一起可直接定位该运行。 - THREAD 项需要
thread_id和project_id。
使用 SDK 解析这些 ID:
project_id:使用read_project按名称查找项目并读取其id,例如client.read_project(project_name="my-project").id。run_id:使用client.runs.query()查询运行。每个运行都会暴露id、project_id和start_time,这些是 RUN 项所需的字段。thread_id:使用client.threads.query()查询线程。每个结果都会暴露其thread_id。
你也可以在 LangSmith UI 中找到这些 ID:
project_id:在追踪项目中,点击项目名称旁的 ID 徽章以复制项目 UUID。run_id:在详情视图中打开一个运行,然后点击运行名称旁的 ID 徽章以复制运行 ID。thread_id:在追踪项目的 线程 视图中,从 Thread ID 列复制该值。
要为添加的运行项延长追踪保留期,请传入 extend_trace_retention=True。响应是一个带有 items 数组的信封,每个添加的项对应一个条目。
NOTE
在 Python 中,annotation_queues.items.create 是异步的,因此请在事件循环中 await 它。
python
import asyncio
async def main():
queue_name = "<queue_name>"
project_id = "<project_id>"
run_id = "<run_id>"
thread_id = "<thread_id>"
# Look up the annotation queue by name to get its ID.
queue = next(client.list_annotation_queues(name=queue_name), None)
if queue is None:
raise SystemExit(f"No annotation queue named {queue_name!r}")
# Fetch the run to add by id + project_id. runs.retrieve() requires
# `selects` (uppercase RunSelectField names) to return fields like
# start_time.
run = await client.runs.retrieve(
run_id=run_id,
project_id=project_id,
selects=["ID", "PROJECT_ID", "START_TIME"],
)
response = await client.annotation_queues.items.create(
str(queue.id),
items=[
{
"item_type": "RUN",
"run_id": run_id,
"project_id": project_id,
"start_time": run.start_time,
},
{
"item_type": "THREAD",
"thread_id": thread_id,
"project_id": project_id,
},
],
)
# response.items contains one entry per added item.
for item in response.items or []:
print(item.id, item.item_type)
asyncio.run(main())typescript
const queueName = "<queue_name>";
const projectId = "<project_id>";
const runId = "<run_id>";
const threadId = "<thread_id>";
// Look up the annotation queue by name to get its ID.
let queue;
for await (const q of client.listAnnotationQueues({ name: queueName })) {
queue = q;
break;
}
if (!queue) {
throw new Error(`No annotation queue named ${queueName}`);
}
// Fetch the run to add by id + project_id. retrieve() requires `selects`
// (uppercase RunSelectField names) to return fields like start_time.
const run = await client.runs.retrieve(runId, {
project_id: projectId,
selects: ["ID", "PROJECT_ID", "START_TIME"],
});
const response = await client.annotationQueues.items.create(queue.id, {
items: [
{
item_type: "RUN",
run_id: runId,
project_id: projectId,
start_time: run.start_time,
},
{
item_type: "THREAD",
thread_id: threadId,
project_id: projectId,
},
],
});
// response.items contains one entry per added item.
for (const item of response.items ?? []) {
console.log(item.id, item.item_type);
}NOTE
对于仅添加运行的情况,add_runs_to_annotation_queue 仍然可用,并且在你不需要添加线程时仍是最简单的选择。添加线程或运行与线程混合批次的新代码应使用 items 资源。
反馈配置类型(详细)
连续型
连续型配置定义带有最小值和最大值的数值评分量表。标注者可以选择该范围内的任意值,这使其非常适合在数值量表上对准确度、质量或相关性等维度进行评分:
python
# Simple continuous score
client.create_feedback_config(
"accuracy",
feedback_config={
"type": "continuous",
"min": 0,
"max": 1,
},
)
# Continuous with labeled points on the scale
client.create_feedback_config(
"quality",
feedback_config={
"type": "continuous",
"min": 1,
"max": 5,
"categories": [
{"value": 1, "label": "Poor"},
{"value": 3, "label": "Average"},
{"value": 5, "label": "Excellent"},
],
},
)typescript
await client.createFeedbackConfig({
feedbackKey: "accuracy",
feedbackConfig: { type: "continuous", min: 0, max: 1 },
});
await client.createFeedbackConfig({
feedbackKey: "quality",
feedbackConfig: {
type: "continuous",
min: 1,
max: 5,
categories: [
{ value: 1, label: "Poor" },
{ value: 3, label: "Average" },
{ value: 5, label: "Excellent" },
],
},
});第一个示例展示了一个不带标签的 0–1 量表。第二个示例演示了在量表上添加带标签的锚点的 categories(如 "Poor"、"Average"、"Excellent"),以帮助标注者理解不同值代表什么。这些标签是可选的,但可以提高标注者解读量表时的一致性。
分类型
分类型配置提供一组供标注者选择的离散预定义选项。每个类别必须有一个 value(用于评分和分析的数值标识符)和一个 label(显示给标注者的文本)。你必须至少定义 2 个类别。
将分类型配置用于二元决策(通过/失败、正确/不正确)、多类分类(情感、主题类别)或任何具有固定离散选项集的评估。不要为分类型配置设置 min 或 max:
python
# Binary pass/fail
client.create_feedback_config(
"correctness",
feedback_config={
"type": "categorical",
"categories": [
{"value": 1, "label": "Pass"},
{"value": 0, "label": "Fail"},
],
},
)
# Multi-class
client.create_feedback_config(
"sentiment",
feedback_config={
"type": "categorical",
"categories": [
{"value": 0, "label": "Negative"},
{"value": 1, "label": "Neutral"},
{"value": 2, "label": "Positive"},
],
},
)typescript
await client.createFeedbackConfig({
feedbackKey: "correctness",
feedbackConfig: {
type: "categorical",
categories: [
{ value: 1, label: "Pass" },
{ value: 0, label: "Fail" },
],
},
});
await client.createFeedbackConfig({
feedbackKey: "sentiment",
feedbackConfig: {
type: "categorical",
categories: [
{ value: 0, label: "Negative" },
{ value: 1, label: "Neutral" },
{ value: 2, label: "Positive" },
],
},
});第一个示例展示了一个二元通过/失败配置。第二个示例演示了一个带三个选项的情感多类配置。即使对于分类型反馈,数值也允许你计算聚合得分。
自由形式
自由形式配置允许标注者提供没有预定义结构或约束的开放式文本反馈。此类型没有 min、max 或 categories 字段——标注者可以输入他们想要的任何文本。
自由形式反馈对于捕获细微的见解很有价值,但与结构化反馈类型相比更难聚合并分析:
python
client.create_feedback_config(
"notes",
feedback_config={"type": "freeform"},
)typescript
await client.createFeedbackConfig({
feedbackKey: "notes",
feedbackConfig: { type: "freeform" },
});验证规则
| 类型 | min/max | categories | 约束 |
|---|---|---|---|
continuous | 可选 | 可选(带标签的量表点) | min < max;category 值位于 [min, max] 范围内 |
categorical | 不可设置 | 必填,至少 2 个 | 值和标签唯一 |
freeform | 不可设置 | 不可设置 | 不适用 |
参考
反馈配置类型
| 类型 | 字段 | 描述 |
|---|---|---|
continuous | min、max | 某一范围内的数值得分 |
categorical | categories({value, label} 的列表) | 从预定义选项中选择 |
freeform | 无 | 自由文本输入 |
评分标准项字段
| 字段 | 类型 | 描述 |
|---|---|---|
feedback_key | string | 必填。必须与现有反馈配置键匹配。 |
description | string | 向标注者显示此项的指导。 |
score_descriptions | Record<string, string> | 特定分值的标签(连续型)。 |
value_descriptions | Record<string, string> | 特定类别值的标签(分类型)。 |
is_required | boolean | 标注者是否必须在提交前完成此项。默认为 false。 |