Score
Score — это тип вопроса System One для оценки содержимого по упорядоченным описательным уровням. Ответ содержит score, вероятность для каждого уровня и уверенность.
Используйте Score, когда ответ — позиция на шкале, которую можно описать по шагам. Например, насколько серьёзна ошибка, насколько доволен клиент или сколько у кандидата опыта Python. Если ответ — один из фиксированного набора вариантов без порядка между ними, используйте Choice. Если ответ «да» или «нет», используйте Noul. Как выбрать тип вопроса сравнивает все три.
Ответ Score — это позиция вдоль ваших уровней в score, которая может попасть между двумя уровнями. Модель также возвращает вероятность для каждого уровня в probabilities и значение confidence для ответа.
Пример: вопрос score
How severe is the reported issue?
Состояние (содержимое для оценки)
The export button crashes the settings page in Safari. It works in Chrome, but a few of our customers only use Safari.
Ответ
Вероятность каждого уровня
Уверенность
Score: 1.43
Как вычисляются score и уверенность
Score:
Умножьте номер каждого уровня на его вероятность и сложите результаты:
0 × 0 + 1 × 0.57 + 2 × 0.43 ≈ 1.43
Уверенность
TypeSafe вычисляет её по тому, насколько вероятность распределена между уровнями. Если всё сосредоточено на одном уровне, получается 1.0; чем равномернее распределение, тем ниже уверенность.
How formal is this outfit based on the description?
Состояние (содержимое для оценки)
A navy blazer over a plain white T-shirt, dark jeans, and clean leather loafers. No tie.
Ответ
Вероятность каждого уровня
Уверенность
Score: 1.86
Как вычисляются score и уверенность
Score:
Умножьте номер каждого уровня на его вероятность и сложите результаты:
0 × 0 + 1 × 0.14 + 2 × 0.86 + 3 × 0 + 4 × 0 ≈ 1.86
Уверенность
TypeSafe вычисляет её по тому, насколько вероятность распределена между уровнями. Если всё сосредоточено на одном уровне, получается 1.0; чем равномернее распределение, тем ниже уверенность.
How relevant is this candidate's experience to the job posting?
Состояние (содержимое для оценки)
Job posting: Senior backend engineer building Python APIs and PostgreSQL services. Candidate: Three years building Django REST APIs with PostgreSQL, preceded by two years in frontend JavaScript. Has owned small services but has not led a backend team.
Ответ
Вероятность каждого уровня
Уверенность
Score: 2.52
Как вычисляются score и уверенность
Score:
Умножьте номер каждого уровня на его вероятность и сложите результаты:
0 × 0 + 1 × 0 + 2 × 0.48 + 3 × 0.52 ≈ 2.52
Уверенность
TypeSafe вычисляет её по тому, насколько вероятность распределена между уровнями. Если всё сосредоточено на одном уровне, получается 1.0; чем равномернее распределение, тем ниже уверенность.
How frustrated is the customer?
Состояние (содержимое для оценки)
Export to PDF fails with a spinner that never finishes. Some of our team say CSV export still works for them, others say it fails too. This is the third time I'm writing in and honestly I'm done. Steps: open any report, click Export, choose PDF. Chrome 128 on macOS.
Ответ
Вероятность каждого уровня
Уверенность
Score: 1.26
Как вычисляются score и уверенность
Score:
Умножьте номер каждого уровня на его вероятность и сложите результаты:
0 × 0 + 1 × 0.74 + 2 × 0.26 ≈ 1.26
Уверенность
TypeSafe вычисляет её по тому, насколько вероятность распределена между уровнями. Если всё сосредоточено на одном уровне, получается 1.0; чем равномернее распределение, тем ниже уверенность.
How much does the report give an engineer to work with?
Состояние (содержимое для оценки)
Export to PDF fails with a spinner that never finishes. Some of our team say CSV export still works for them, others say it fails too. This is the third time I'm writing in and honestly I'm done. Steps: open any report, click Export, choose PDF. Chrome 128 on macOS.
Ответ
Вероятность каждого уровня
Уверенность
Score: 3.00
Как вычисляются score и уверенность
Score:
Умножьте номер каждого уровня на его вероятность и сложите результаты:
0 × 0 + 1 × 0 + 2 × 0 + 3 × 1 ≈ 3.00
Уверенность
TypeSafe вычисляет её по тому, насколько вероятность распределена между уровнями. Если всё сосредоточено на одном уровне, получается 1.0; чем равномернее распределение, тем ниже уверенность.
Числа перед каждым шагом — это позиции, они объясняются в разделе Уровни.
Структура запроса
Тело POST-запроса к API TypeSafe имеет те же три поля верхнего уровня, что и любой другой тип вопроса: state — содержимое для оценки; model; и questions. Каждый вопрос Score имеет следующие поля:
type: Всегда"score".instructions: Вопрос, на который отвечает модель. Что она оценивает.criteria: Упорядоченный массив описаний уровней, от нижнего конца шкалы к верхнему. Должен содержать хотя бы два уровня; API принимает до 10.
Ниже запрос, где состояние — отчёт об ошибке, а вопрос — насколько серьёзна ошибка:
{
"state": "The export button crashes the settings page in Safari. It works in Chrome, but a few of our customers only use Safari.",
"questions": {
"bug_severity": {
"type": "score",
"instructions": "How severe is the reported issue?",
"criteria": [
"Cosmetic; no impact to functionality",
"Broken or degraded feature, but workaround exists",
"Blocking issue; no workaround exists"
]
}
}
}Id вопроса выбираете вы, в этом случае bug_severity. Этот id не отправляется модели. Ответ возвращается под тем же id.
Уровни
Каждая запись в criteria — это уровень: одна точка на спектре возможных ответов, описанная словами. Номер уровня — его позиция в массиве criteria, начиная с 0, поэтому три записи выше — это уровни 0, 1 и 2. Порядок массива и есть нумерация.
Модель получает описания и больше ничего, и каждый уровень оценивается отдельно относительно состояния.
score в ответе — это позиция на спектре уровней. Для трёхуровневой шкалы он идёт от 0 до 2 и может попасть между двумя уровнями.
Наши клиентские SDK предоставляют типизированные вопросы. В Python тот же вопрос — это Score:
from typesafe_sdk import Score, TypeSafeClient
with TypeSafeClient() as client:
response = client.system_one(
state="The export button crashes the settings page in Safari. It works in Chrome, but a few of our customers only use Safari.",
questions={
"bug_severity": Score(
instructions="How severe is the reported issue?",
criteria=[
"Cosmetic; no impact to functionality",
"Broken or degraded feature, but workaround exists",
"Blocking issue; no workaround exists",
],
),
},
)
print(response.answers["bug_severity"].score)
Используйте метод system_one или endpoint https://api.typesafe.ai/v1/systemone, чтобы вызвать модель System One. Поле model выбирает, какая модель обрабатывает запрос. Как создавать с TypeSafe рассказывает, где в вашем коде её вызывать.
Используйте один из наших клиентских SDK или обратитесь напрямую к API TypeSafe. Если интеграцию за вас пишет агент программирования, сначала установите навык агента TypeSafe, чтобы он знал формы запроса и ответа.
Структура ответа
В ответе на каждый вопрос приходится одна запись в answers, под id из запроса. Это ответ на пример запроса выше:
{
"model": "jev-1.13.0",
"answers": {
"bug_severity": {
"type": "score",
"score": 1.43,
"confidence": 0.35,
"legend": {
"0": "Cosmetic; no impact to functionality",
"1": "Broken or degraded feature, but workaround exists",
"2": "Blocking issue; no workaround exists"
},
"probabilities": {
"0": 0.0,
"1": 0.57,
"2": 0.43
}
}
},
"usage": {
"input_tokens": 332,
"output_tokens": 18
}
}
Каждый ответ Score содержит пять значений:
type: Тип вопроса TypeSafe.probabilities: Вероятность каждого уровня, с номером уровня в виде строки в качестве ключа. Сумма всех значений равна 1.score: Позиция на числовой прямой уровней, от 0 до номера верхнего уровня, здесь это 2. Это сумма номеров уровней, умноженных на их вероятности: 0 x 0.0 + 1 x 0.57 + 2 x 0.43 = 1.43.legend: Каждый номер уровня, сопоставленный обратно со своим описанием.confidence: Число от 0 до 1, вычисленное из того, как распределеныprobabilities. Один пик на одном уровне означает высокую уверенность. Вероятность, размазанная по нескольким уровням, означает низкую уверенность.
Score 1.43 означает, что модель делится между уровнями 1 и 2, склоняясь к уровню 1. Это соответствует отчёту: экспорт сломан, а переход на Chrome — обходной путь для большинства клиентов, но не для тех, кто пользуется только Safari. Модель ставит 0.57 на «есть обходной путь» и 0.43 на «обходного пути нет», и уверенность равна 0.35, потому что она разделена.
При использовании Python SDK ScoreAnswer имеет score, confidence, probabilities и legend как типизированные поля. SDK индексирует probabilities и legend целым числом уровня, а не строкой.
Чтение Score
Посмотрим, как score меняется при разных входных данных. Например, используя вопрос и его уровни из запроса выше:
"How severe is the reported issue?"
→ 0: Cosmetic; no impact to functionality
→ 1: Broken or degraded feature, but workaround exists
→ 2: Blocking issue; no workaround exists
Видно, как разные отчёты об ошибках меняют score:
probabilities | |||||
|---|---|---|---|---|---|
| Состояние | score | confidence | Уровень 0 | Уровень 1 | Уровень 2 |
| Кнопка экспорта смещена на несколько пикселей на странице настроек. | 0.0 | 1.0 | 1.0 | 0.0 | 0.0 |
| Кнопка экспорта в PDF ничего не делает при нажатии. Я всё ещё могу экспортировать в CSV и преобразовать самому, но это занимает целую вечность. | 1.0 | 1.0 | 0.0 | 1.0 | 0.0 |
| Экспорт в PDF падает со спиннером, который никогда не заканчивается. Часть нашей команды говорит, что экспорт в CSV у них всё ещё работает, другие — что он тоже падает. | 1.11 | 0.84 | 0.0 | 0.89 | 0.11 |
| Кнопка экспорта обрушивает страницу настроек в Safari. В Chrome она работает, но несколько наших клиентов пользуются только Safari. | 1.43 | 0.35 | 0.0 | 0.57 | 0.43 |
| Никто из нашей команды не может войти с сегодняшнего утра. Мы получаем ошибку 500 при каждой попытке. | 2.0 | 1.0 | 0.0 | 0.0 | 1.0 |
В этих примерах уверенность 1.0 означает, что возвращённое распределение помещает всю вероятность на один уровень. Это описывает ответ модели, а не гарантирует, что ответ правильный.
Score — это средневзвешенное по вероятностям значение номеров уровней. В третьем и четвёртом примерах вероятность делится между уровнями 1 и 2. Больший вес на уровне 2 повышает score. Он не измеряет долю клиентов без обходного пути.
Разные распределения могут давать одинаковый score. Score 1.0 может означать, что вся вероятность на уровне 1, или что половина на уровне 0, а половина на уровне 2. Читайте probabilities и confidence вместе со score, чтобы различать эти случаи.
Дробный score — это позиция. Его можно использовать, чтобы ранжировать отчёты по серьёзности, или округлить до ближайшего уровня, когда коду нужен один исход. Наш cookbook по выравниванию сущностей показывает пример округления до ближайшего уровня для принятия решения.
Низкая уверенность на Score обычно означает одно из трёх. Уровни перекрываются для этого состояния, вопрос измеряет больше одной вещи, или состояние говорит недостаточно, чтобы его разместить. Наша документация Уверенность рассказывает, как использовать её в вашем коде.
Написание хороших уровней
Описывайте ситуации, а не степени. «Функция сломана или деградировала, но есть обходной путь» даёт модели то, с чем сопоставить состояние. «Умеренно серьёзно» — нет. Конкретные описания помогают модели различать уровни. Проверяйте ответы на известных примерах; более высокая уверенность сама по себе не доказывает, что описание лучше.
Каждый уровень оценивается отдельно. Модель не видит номер уровня и его соседей, поэтому «хуже предыдущего уровня» для неё ничего не значит, и числа в описаниях или в инструкциях не помогают. Вот что происходит, когда уровни — только числа, на отчёте о смещённой кнопке из таблицы выше:
instructions: "Rate severity from 0 to 2, where 2 is worst"
criteria: ["0", "1", "2"]
→ score 0.55, confidence 0.33, probabilities 0: 0.45, 1: 0.55, 2: 0.0
Тот же отчёт с тремя описательными уровнями даёт score 0.0 при уверенности 1.0. С одними числами модели не с чем сопоставлять, и она делит вероятность между 0 и 1.
Используйте столько уровней, сколько сможете описать различимо, вплоть до 10. Трёх достаточно. Не добавляйте уровни, которые не можете описать различимо.
Держите каждый вопрос Score в одном измерении. Если описание говорит «пунктуальный, умный и опытный», вопрос измеряет три вещи, и входные данные, высокие по одной и низкие по другой, нельзя разместить. Уверенность падает, и score значит меньше. Разделите его на один вопрос Score на каждую вещь и объедините их в коде, как показывает следующая секция.
Если на верхнем конце вашей шкалы есть редкий крайний случай, на который нужно реагировать иначе, дайте ему свой уровень. Шкала тональности, заканчивающаяся на «очень злой», может добавить «оскорбительный или угрожающий». Без этого уровня оба сообщения могут получить score около верхнего конца. Один score может их не различить.
Если середины нет вообще, а ответ — одна из нескольких дискретных категорий, используйте вместо этого Choice или разделите вопрос на несколько вопросов Noul. Важно проверять свои уровни на собственных данных. Две формулировки одной и той же шкалы могут вести себя на ваших данных по-разному.
Разделение сложного суждения на несколько вопросов Score
Сложное суждение, зависящее от нескольких вещей, лучше разделить на один вопрос Score на каждую вещь. Затем вы можете объединить в своём коде Scores, возвращённые TypeSafe, чтобы вынести суждение. Некоторые вопросы Score могут быть важнее других, поэтому дайте каждому вопросу Score вес по его относительной важности. Веса — ваши. Когда объединённый результат не совпадает с тем, что решила бы ваша команда, измените их в коде и запустите снова. Отправляйте вопросы Score в одном запросе. Они оцениваются параллельно. Добавление вопросов почти не меняет время ответа и стоит несколько дополнительных токенов вопроса; см. Задавайте несколько вопросов вместе.
Запрос ниже — это тикет со спиннером из таблицы выше, но с чуть большим контекстом. Он задаёт три вопроса Score: насколько серьёзна ошибка, насколько раздражён клиент и сколько отчёт даёт инженеру для работы.
{
"state": "Export to PDF fails with a spinner that never finishes. Some of our team say CSV export still works for them, others say it fails too. This is the third time I'm writing in and honestly I'm done. Steps: open any report, click Export, choose PDF. Chrome 128 on macOS.",
"questions": {
"severity": {
"type": "score",
"instructions": "How severe is the reported issue?",
"criteria": [
"Cosmetic; no impact to functionality",
"Broken or degraded feature, but workaround exists",
"Blocking issue; no workaround exists"
]
},
"frustration": {
"type": "score",
"instructions": "How frustrated is the customer?",
"criteria": [
"Calm, just stating facts",
"Frustrated but civil",
"Very angry, strong language or threatening to leave"
]
},
"report_quality": {
"type": "score",
"instructions": "How much does the report give an engineer to work with?",
"criteria": [
"No detail; just says something is broken",
"Names the feature but no steps or environment",
"Steps to reproduce or environment, but not both",
"Steps to reproduce and environment"
]
}
}
}Ответ TypeSafe:
{
"model": "jev-1.13.0",
"answers": {
"severity": {
"type": "score",
"score": 1.24,
"confidence": 0.64,
"legend": {
"0": "Cosmetic; no impact to functionality",
"1": "Broken or degraded feature, but workaround exists",
"2": "Blocking issue; no workaround exists"
},
"probabilities": {
"0": 0.0,
"1": 0.76,
"2": 0.24
}
},
"frustration": {
"type": "score",
"score": 1.28,
"confidence": 0.58,
"legend": {
"0": "Calm, just stating facts",
"1": "Frustrated but civil",
"2": "Very angry, strong language or threatening to leave"
},
"probabilities": {
"0": 0.0,
"1": 0.72,
"2": 0.28
}
},
"report_quality": {
"type": "score",
"score": 3.0,
"confidence": 1.0,
"legend": {
"0": "No detail; just says something is broken",
"1": "Names the feature but no steps or environment",
"2": "Steps to reproduce or environment, but not both",
"3": "Steps to reproduce and environment"
},
"probabilities": {
"0": 0.0,
"1": 0.0,
"2": 0.0,
"3": 1.0
}
}
},
"usage": {
"input_tokens": 468,
"output_tokens": 43
}
}
Каждый вопрос оценивается отдельно относительно тикета и получает score:
severityравен 1.24 при уверенности 0.64. Читается так же, как в начальном примере: экспорт сломан, и у некоторых есть обходной путь.frustrationравен 1.28 при уверенности 0.58. Формулировки вежливы, но «третий раз» и «с меня хватит» сдвигают часть score к верхнему уровню, поэтому модель делит 0.72 и 0.28 между «раздражён, но вежлив» и «очень зол». Для этого тикета два уровня перекрываются — вот почему уверенность умеренная.report_qualityравен 3.0 при уверенности 1.0. И шаги, и версия браузера указаны.
Три шкалы имеют разную длину, поэтому перед объединением нормализуйте каждый score. Четырёхуровневая шкала возвращает значения от 0 до 3, а трёхуровневая — от 0 до 2, поэтому верхний score на одной больше верхнего score на другой. Разделите каждый score на номер его верхнего уровня, len(criteria) - 1, чтобы привести все score к диапазону от 0 до 1. Тогда веса значат то, что говорят: 0.6 на severity и 0.3 на frustration делают вес severity вдвое большим.
Код на Python SDK для TypeSafe ниже задаёт три вопроса, нормализует каждый score и объединяет их с помощью примера расчёта приоритета:
from typesafe_sdk import Score, TypeSafeClient
TRIAGE_QUESTIONS = {
"severity": Score(
instructions="How severe is the reported issue?",
criteria=[
"Cosmetic; no impact to functionality",
"Broken or degraded feature, but workaround exists",
"Blocking issue; no workaround exists",
],
),
"frustration": Score(
instructions="How frustrated is the customer?",
criteria=[
"Calm, just stating facts",
"Frustrated but civil",
"Very angry, strong language or threatening to leave",
],
),
"report_quality": Score(
instructions="How much does the report give an engineer to work with?",
criteria=[
"No detail; just says something is broken",
"Names the feature but no steps or environment",
"Steps to reproduce or environment, but not both",
"Steps to reproduce and environment",
],
),
}
def normalized(answers, question_id: str) -> float:
"""Put a score on 0 to 1 by dividing by its top level number."""
top_level = len(TRIAGE_QUESTIONS[question_id].criteria) - 1
return answers[question_id].score / top_level
def priority(ticket: str) -> float:
with TypeSafeClient() as client:
response = client.system_one(
state=ticket,
questions=TRIAGE_QUESTIONS,
)
answers = response.answers
severity = normalized(answers, "severity")
frustration = normalized(answers, "frustration")
report_quality = normalized(answers, "report_quality")
# A detailed report helps an engineer investigate, so it raises priority a little.
return 0.6 * severity + 0.3 * frustration + 0.1 * report_quality
Для примера ответа выше нормализованные score равны 0.62 для severity, 0.64 для frustration и 1.0 для report quality. Приоритет равен 0.6 × 0.62 + 0.3 × 0.64 + 0.1 × 1.0 = 0.664, что округляется до 0.66.
Веса живут в вашем коде, поэтому вы видите, как именно получается число, и можете изменить его, когда ранжирование не совпадает с тем, что сделала бы ваша команда. Если позже понадобится больше вопросов Score, добавьте их в TRIAGE_QUESTIONS. Число запросов останется прежним — один. Этот приём — разбить сложное суждение на отдельные Scores, а затем объединить их с весами в коде — называется паттерном Составное оценивание.
Структурированные описания уровней
Начните с базового текстового описания для каждого уровня. Когда модель постоянно ставит score между двумя соседними уровнями на входных данных, которые вы считаете ясными, дайте каждому уровню объект вместо строки: поле для того, что покрывает уровень, и поле с несколькими примерами ситуаций. Используйте одни и те же имена полей на каждом уровне, чтобы модель сравнивала сравнимое.
Запрос ниже — тикет со спиннером, который мы использовали раньше, но с примерами на каждом уровне:
{
"state": "Export to PDF fails with a spinner that never finishes. Some of our team say CSV export still works for them, others say it fails too.",
"questions": {
"bug_severity": {
"type": "score",
"instructions": "How severe is the reported issue?",
"criteria": [
{
"what": "Cosmetic; no impact to functionality",
"examples": [
"typo in a label",
"misaligned icon"
]
},
{
"what": "Broken or degraded feature, but workaround exists",
"examples": [
"export fails in one browser but works in another"
]
},
{
"what": "Blocking issue; no workaround exists",
"examples": [
"cannot log in",
"data loss"
]
}
]
}
}
}Ответ:
{
"model": "jev-1.13.0",
"answers": {
"bug_severity": {
"type": "score",
"score": 1.09,
"confidence": 0.87,
"legend": {
"0": {
"what": "Cosmetic; no impact to functionality",
"examples": [
"typo in a label",
"misaligned icon"
]
},
"1": {
"what": "Broken or degraded feature, but workaround exists",
"examples": [
"export fails in one browser but works in another"
]
},
"2": {
"what": "Blocking issue; no workaround exists",
"examples": [
"cannot log in",
"data loss"
]
}
},
"probabilities": {
"0": 0.0,
"1": 0.91,
"2": 0.09
}
}
},
"usage": {
"input_tokens": 379,
"output_tokens": 18
}
}
С обычными строками этот тикет давал score 1.11 при уверенности 0.84. С примерами он даёт 1.09 при уверенности 0.87 — небольшой сдвиг, потому что обычные строки уже разместили его хорошо. Эффект больше, когда обычные строки оставляют модель в нерешительности, как показывает следующая таблица.
Примеры направляют модель, и они помогают, только когда похожи на ваши реальные входные данные. Таблица ниже — начальный отчёт про Safari с тремя разными наборами объектов уровней:
| Описание уровня | score |
confidence |
|---|---|---|
| обычная строка: без объекта с примерами | 1.43 | 0.35 |
| Добавлен массив examples с полезным примером: «экспорт падает в одном браузере, но работает в другом» | 1.03 | 0.96 |
| Добавлен массив examples с примером, не связанным с браузерами: «поиск падает, но просмотр категорий всё ещё работает» | 1.43 | 0.35 |
В этом сравнении подходящий пример концентрирует почти всю вероятность на одном уровне. Несвязанный пример возвращает тот же результат, что и обычные строки. Более высокая уверенность не устанавливает, какой ответ правильный. Выбирайте примеры с известными ожидаемыми уровнями, а затем проверьте пересмотренные описания на отдельных входных данных, прежде чем оставлять их.