ДокументацияПримитивы (Вопросы)Расширенная структура JSON

Расширенная структура JSON

Instructions, Choice options, Score levels, and Noul criteria all accept JSON structure.

Инструкции, варианты Choice, уровни Score и критерии Noul поддерживают JSON-структуру.

export function TypesafeExample({example, display, title}) {
const keyStrUriSafe = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-$";
function compressToEncodedURIComponent(input) {
if (input == null) return "";
return _compress(input, 6, function (a) {
return keyStrUriSafe.charAt(a);
});
}
function _compress(uncompressed, bitsPerChar, getCharFromInt) {
var i, value, context_dictionary = {}, context_dictionaryToCreate = {}, context_c = "", context_wc = "", context_w = "", context_enlargeIn = 2, context_dictSize = 3, context_numBits = 2, context_data = [], context_data_val = 0, context_data_position = 0, ii;
for (ii = 0; ii < uncompressed.length; ii += 1) {
context_c = uncompressed.charAt(ii);
if (!Object.prototype.hasOwnProperty.call(context_dictionary, context_c)) {
context_dictionary[context_c] = context_dictSize++;
context_dictionaryToCreate[context_c] = true;
}
context_wc = context_w + context_c;
if (Object.prototype.hasOwnProperty.call(context_dictionary, context_wc)) {
context_w = context_wc;
} else {
if (Object.prototype.hasOwnProperty.call(context_dictionaryToCreate, context_w)) {
if (context_w.charCodeAt(0) < 256) {
for (i = 0; i < context_numBits; i++) {
context_data_val = context_data_val << 1;
if (context_data_position == bitsPerChar - 1) {
context_data_position = 0;
context_data.push(getCharFromInt(context_data_val));
context_data_val = 0;
} else {
context_data_position++;
}
}
value = context_w.charCodeAt(0);
for (i = 0; i < 8; i++) {
context_data_val = context_data_val << 1 | value & 1;
if (context_data_position == bitsPerChar - 1) {
context_data_position = 0;
context_data.push(getCharFromInt(context_data_val));
context_data_val = 0;
} else {
context_data_position++;
}
value = value >> 1;
}
} else {
value = 1;
for (i = 0; i < context_numBits; i++) {
context_data_val = context_data_val << 1 | value;
if (context_data_position == bitsPerChar - 1) {
context_data_position = 0;
context_data.push(getCharFromInt(context_data_val));
context_data_val = 0;
} else {
context_data_position++;
}
value = 0;
}
value = context_w.charCodeAt(0);
for (i = 0; i < 16; i++) {
context_data_val = context_data_val << 1 | value & 1;
if (context_data_position == bitsPerChar - 1) {
context_data_position = 0;
context_data.push(getCharFromInt(context_data_val));
context_data_val = 0;
} else {
context_data_position++;
}
value = value >> 1;
}
}
context_enlargeIn--;
if (context_enlargeIn == 0) {
context_enlargeIn = Math.pow(2, context_numBits);
context_numBits++;
}
delete context_dictionaryToCreate[context_w];
} else {
value = context_dictionary[context_w];
for (i = 0; i < context_numBits; i++) {
context_data_val = context_data_val << 1 | value & 1;
if (context_data_position == bitsPerChar - 1) {
context_data_position = 0;
context_data.push(getCharFromInt(context_data_val));
context_data_val = 0;
} else {
context_data_position++;
}
value = value >> 1;
}
}
context_enlargeIn--;
if (context_enlargeIn == 0) {
context_enlargeIn = Math.pow(2, context_numBits);
context_numBits++;
}
context_dictionary[context_wc] = context_dictSize++;
context_w = String(context_c);
}
}
if (context_w !== "") {
if (Object.prototype.hasOwnProperty.call(context_dictionaryToCreate, context_w)) {
if (context_w.charCodeAt(0) < 256) {
for (i = 0; i < context_numBits; i++) {
context_data_val = context_data_val << 1;
if (context_data_position == bitsPerChar - 1) {
context_data_position = 0;
context_data.push(getCharFromInt(context_data_val));
context_data_val = 0;
} else {
context_data_position++;
}
}
value = context_w.charCodeAt(0);
for (i = 0; i < 8; i++) {
context_data_val = context_data_val << 1 | value & 1;
if (context_data_position == bitsPerChar - 1) {
context_data_position = 0;
context_data.push(getCharFromInt(context_data_val));
context_data_val = 0;
} else {
context_data_position++;
}
value = value >> 1;
}
} else {
value = 1;
for (i = 0; i < context_numBits; i++) {
context_data_val = context_data_val << 1 | value;
if (context_data_position == bitsPerChar - 1) {
context_data_position = 0;
context_data.push(getCharFromInt(context_data_val));
context_data_val = 0;
} else {
context_data_position++;
}
value = 0;
}
value = context_w.charCodeAt(0);
for (i = 0; i < 16; i++) {
context_data_val = context_data_val << 1 | value & 1;
if (context_data_position == bitsPerChar - 1) {
context_data_position = 0;
context_data.push(getCharFromInt(context_data_val));
context_data_val = 0;
} else {
context_data_position++;
}
value = value >> 1;
}
}
context_enlargeIn--;
if (context_enlargeIn == 0) {
context_enlargeIn = Math.pow(2, context_numBits);
context_numBits++;
}
delete context_dictionaryToCreate[context_w];
} else {
value = context_dictionary[context_w];
for (i = 0; i < context_numBits; i++) {
context_data_val = context_data_val << 1 | value & 1;
if (context_data_position == bitsPerChar - 1) {
context_data_position = 0;
context_data.push(getCharFromInt(context_data_val));
context_data_val = 0;
} else {
context_data_position++;
}
value = value >> 1;
}
}
context_enlargeIn--;
if (context_enlargeIn == 0) {
context_enlargeIn = Math.pow(2, context_numBits);
context_numBits++;
}
}
value = 2;
for (i = 0; i < context_numBits; i++) {
context_data_val = context_data_val << 1 | value & 1;
if (context_data_position == bitsPerChar - 1) {
context_data_position = 0;
context_data.push(getCharFromInt(context_data_val));
context_data_val = 0;
} else {
context_data_position++;
}
value = value >> 1;
}
while (true) {
context_data_val = context_data_val << 1;
if (context_data_position == bitsPerChar - 1) {
context_data.push(getCharFromInt(context_data_val));
break;
} else context_data_position++;
}
return context_data.join("");
}
function buildHref(ex) {
const documentText = ex.state === undefined ? "" : typeof ex.state === "string" ? ex.state : JSON.stringify(ex.state, null, 2);
return "https://console.typesafe.ai/decode#share/" + compressToEncodedURIComponent(JSON.stringify({
apiVersion: "v1",
documentText,
promptsText: JSON.stringify(ex.questions, null, 2),
selectedModels: ex.selectedModels
}));
}
const displayedExample = display === "questions" ? example.questions : example.state === undefined ? {
questions: example.questions
} : {
state: example.state,
questions: example.questions
};
const code = JSON.stringify(displayedExample, null, 2);
const href = buildHref(example);
return <div style={{
margin: "1.25rem 0"
}}>
<CodeBlock language="json" filename={title ?? "request"}>
{code}


;
}

Модели System One обучены понимать структуру.

Где разрешена структура

Каждое из этих полей имеет тип EntryType.

Поле Применяется к Допустимая форма
instructions Choice, Score, Noul string, object, array или null
значения criteria (описания вариантов) Choice string, object, array или null
элементы criteria (описания уровней) Score string, object, array или null
criteria.true и criteria.false Noul string, object, array или null

Когда структурировать вопрос

  • Когда это помогает достичь ясности. Когда вопрос состоит из нескольких частей, оформление их в виде JSON повышает ясность, поскольку каждый элемент снабжен понятным ключом.
  • Когда вопросу требуются вспомогательные данные. Схема, таксономия или строка базы данных уже представлены в формате JSON. Используйте этот JSON целиком или передавайте соответствующие подполя вместо сериализации их в строковый шаблон.

Структурированные инструкции

Один объект field описывает проверяемое поле, и каждый вопрос ссылается на него по ключу. Одна и та же структура обеспечивает работу вопроса Noul (проверяющего значение), Choice (выбирающего значение из кандидатов) и двух вопросов Score (размещающих значение на шкале).

<TypesafeExample
display="request"
example={{
state: {
source_text:
'Invoice #4471 issued March 3, 2026 to Beaver Dam Logistics for $12,840.00, net 30.',
},
selectedModels: ['jev-latest'],
questions: {
invoice_number_is_correct: {
type: 'noul',
instructions: {
field: {
name: 'invoice_number',
type: 'string',
description: 'The identifier printed on the invoice.',
},
extracted_value: '4471',
question: 'Does extracted_value match the field as it appears in source_text?',
},
},
customer_name: {
type: 'choice',
instructions: {
field: {
name: 'customer_name',
type: 'string',
description: 'The organization the invoice was issued to.',
},
question: 'Which option is the value of field in source_text?',
},
criteria: {
'Beaver Logistics': null,
'Dam Logistics': null,
'Beaver Dam Logistics': null,
'Beaver': null,
'Dam': null,
},
},
amount_due: {
type: 'score',
instructions: {
field: {
name: 'amount_due',
type: 'number',
unit: 'USD',
description: 'The total the invoice asks to be paid.',
},
question: 'How large is the field value in source_text?',
},
criteria: [
'Under $1,000',
'$1,000 to $10,000',
'$10,000 to $100,000',
'$100,000 to $1,000,000',
'Over $1,000,000',
],
},
payment_terms: {
type: 'score',
instructions: {
field: {
name: 'payment_terms',
type: 'integer',
unit: 'days',
description: 'Days allowed for payment, from terms such as "net 30".',
},
question: 'How many days does the field in source_text allow for payment?',
},
criteria: [
'Due on receipt',
'Net 10',
'Net 30',
'Net 60',
'Net 90',
],
},
},
}}
/>

В коде вы можете обойти в цикле потенциальные записи и сформировать по одному такому вопросу на каждое поле, отправив их все в едином вызове. В кукбуке по каскадному извлечению данных (SDE cascade) применяется аналогичный подход.

Массивы также поддерживаются. Используйте массив, когда инструкция представляет собой список объектов для проверки или сравнения:

JSON THEME={NULL} api.wedstack.ru/v1
"instructions": {
  "question": "Does the claimed sender identity conflict with the sending domain?",
  "compare": ["ticket.sender.display_name", "ticket.sender.email"],
  "focus": "Compare the named organization with the email domain."
}

Структурированные варианты Choice

Описание варианта Choice также может быть структурированным объектом.

Рубрика JSON для уточнения границ

<TypesafeExample
display="request"
example={{
state:
'I ordered the standing desk two weeks ago and tracking still says label created. Was I even charged?',
selectedModels: ['jev-latest'],
questions: {
department: {
type: 'choice',
instructions: {
question: 'Which team should handle this message?',
focus: "Classify the customer's primary request, not every topic mentioned.",
},
criteria: {
billing: {
what: 'Charges, invoices, refunds, or subscriptions',
not_for: 'Order tracking or account access',
examples: ['I was charged twice', 'Where is my refund?'],
},
orders: {
what: 'Order status, delivery, cancellation, or returns',
not_for: 'Charges or account access',
examples: ['Where is my package?', 'Cancel my order'],
},
account: {
what: 'Login, password, profile, or security',
not_for: 'Charges or delivery',
examples: ["I can't log in", 'Change my email'],
},
},
},
},
}}
/>

Пример сообщает модели, что охватывает каждый вариант, и что к нему не относится. Это делает границу между вариантами предельно четкой.

Обход таксономии

Для классификации по глубокой таксономии задавайте по одному вопросу Choice на каждый уровень и обходите дерево в коде. На каждом шаге вариантами являются дочерние узлы текущего узла, а значениями каждого варианта — поддерево этого потомка. Это позволяет модели видеть содержимое ветки до принятия окончательного решения, что особенно важно, когда товар относится к листовой категории, чье назначение неочевидно из одного лишь названия ветки.

Здесь состояние — это карточка товара, а первый вопрос выбирает отдел верхнего уровня.

<TypesafeExample
display="request"
example={{
state:
"32oz plastic bottle with a flip straw lid. Fits most bike cages.",
selectedModels: ['jev-latest'],
questions: {
department: {
type: 'choice',
instructions: 'Which top-level department does this product belong to?',
criteria: {
'Sporting Goods': {
Cycling: ['Bike Bottles & Cages', 'Bike Lights', 'Helmets'],
Fitness: ['Yoga Mats', 'Resistance Bands'],
Outdoor: ['Tents', 'Sleeping Bags', 'Hydration Packs'],
},
'Home & Kitchen': {
Drinkware: ['Water Bottles', 'Travel Mugs', 'Tumblers'],
Cookware: ['Pots & Pans', 'Bakeware'],
},
'Baby & Toddler': ['Sippy Cups', 'Bottle Warmers', 'Bibs'],
},
},
},
}}
/>

Бутылка правдоподобно подходит под два отдела. Демонстрация поддеревьев позволяет модели увидеть, что существуют и Sporting Goods > Cycling > Bike Bottles & Cages, и Home & Kitchen > Drinkware > Water Bottles, и сопоставить акцент в описании на велосипедных креплениях с обычной посудой для питья. Значения probabilities в ответе подскажут, насколько близки вероятности и стоит ли исследовать обе ветки.

После выбора отдела задайте следующий вопрос Choice с дочерними элементами этого отдела в качестве вариантов и их поддеревьями в качестве значений, повторяя процесс до достижения листа. В коде это может быть цикл по вложенному словарю, где criteria каждого вопроса — это просто текущий узел. В кукбуке по иерархической классификации показан пример аналогичного обхода дерева, включая лучевой поиск (beam search), сохраняющий несколько перспективных путей-кандидатов при близких вероятностях.

Поддеревья могут разрастаться. Если ветка слишком велика, сократите значение до прямых потомков и выборки листовых категорий.

Структурированные уровни Score

Каждый элемент массива criteria для Score может быть объектом.

<TypesafeExample
display="request"
example={{
state:
'Fixed the null check in the payment handler. Also refactored the retry loop while I was in there, and bumped the SDK version since the old one had that timeout bug.',
selectedModels: ['jev-latest'],
questions: {
pr_scope: {
type: 'score',
instructions: {
question: 'How focused is this pull request description on a single change?',
note: 'Judge the number of independent changes, not the size of any one change.',
},
criteria: [
{
summary: 'One change, clearly stated',
signals: ['A single fix or feature', 'Nothing described as "also" or "while I was in there"'],
},
{
summary: 'One main change plus a small related tweak',
signals: ['A primary change and one minor adjacent edit', 'The tweak supports the main change'],
},
{
summary: 'Several independent changes bundled together',
signals: ['Two or more unrelated fixes or features', 'Changes that could each be their own PR'],
},
],
},
},
}}
/>

Структурированные критерии Noul

Поле criteria для Noul опционально. Когда граница между «да» и «нет» тонка, структурированные описания true и false позволяют четко зафиксировать ее с помощью определений и примеров для каждого исхода.

<TypesafeExample
display="request"
example={{
state: {
sender: { display_name: 'Beaver Dam Builders Ltd.', email: 'donotreply@payroll.example' },
message:
'Your Q3 bonus is ready. Reply with your login password so we can verify your identity and release the funds.',
},
selectedModels: ['jev-latest'],
questions: {
requests_credentials: {
type: 'noul',
instructions: {
question: 'Does the message ask the recipient to disclose a sensitive credential?',
inspect: 'message',
focus: 'Look for a request to send the credential itself, not a request to change or reset it.',
},
criteria: {
true: {
what: 'Asks the recipient to reply with, type, or send a password, PIN, one-time code, or other security sensitive answer',
examples: ['Reply with your password', 'Send us the 6-digit code you just received'],
},
false: {
what: 'No sensitive credential is requested',
examples: ['Reset your password from the settings page', 'Your statement is ready'],
},
},
},
},
}}
/>