Машинный перевод
Эта страница была автоматически переведена ИИ и может содержать ошибки. Если что-то неясно, обращайтесь к английскому источнику.
Структура ответа API и семантика ошибок¶
Часть справочника веб-API Perplexity — полная карта в индексе API.
1. Основы структуры ответа (дисциплина парсинга)¶
- Необработанные данные сохраняются в успешных архивах:
raw_entries.json(простой) иraw_blocks.json(схематизированный, при получении) хранятся вместе с отрисованными артефактами; парсинг/рендеринг можно повторно запустить офлайн (pplx-export re-render) без повторной загрузки. - Извлечение полей централизовано в
sites/perplexity/parsers.py(при изменении схемы нужно изменить только одно место). - Определение режима (
normalize.detect_mode; дерево решений в export-pipeline.md): сигнал наивысшего приоритета — это полеsearch_modeлюбой записи (сопоставление в конце §3.9); когда все сигналы не срабатывают, запасной вариант — computer = URL/computer/tasks/или metadata.mode=="4" или индекс mode ∈ {ASI,COMPUTER}; council = существует шаг COUNCIL_RESEARCH; deep-research = существует шаг RESEARCH_ANSWER (на основе содержимого, а не китайских меток); в противном случае search. - Пользовательский интерфейс computer сворачивает всё — всегда ориентируйтесь на записи/блоки API; никогда не используйте текст интерфейса как границу содержимого.
- Двойной канал субагента (обнаружено 2026-07-19): подсказка в схематизированном
workflow_payload.objective_chunks; шаги/заключение в простомbackground_entries; связаны черезworkflow_payload.id(toolu_X). - Элементы
WORKFLOW_ITEM_SOURCESчасто содержатtext_payload(текст извлечения страницы субагентом / таблицы сравнения; 450 вхождений по всей библиотеке, 408 внутри вложенных полезных нагрузок background) в дополнение кsources_payload.sources(список ссылок); одно и то же содержимое появляется как в простой записи background вtextвстроенном JSON шага, так и в схематизированной вложенной полезной нагрузке — закреплённые субагенты, отрисованные через простой путь, уже сохраняют текст (проверка по всей библиотеке 2026-07-22: 408/408 присутствуют, ни одного отсутствующего). related_queries/related_query_items(установлено 2026-07-23): каждая запись содержит рекомендации по следующему вопросу — предложения продолжения, которые платформа генерирует для завершённого ответа;related_queries— массив текстов рекомендаций,related_query_items— структурированные элементы (uuid/upsell_type и т.д.). Криминалистический вывод: uuid элемента не является uuid потока (0/988 совпадений с uuid потоков библиотеки), а тексты рекомендаций не пересекаются с запросами других потоков — пока не разрешимо в межпотоковые отношения; гипотеза о «предварительно выделенных uuid потоков (материализуемых по клику)» остаётся непроверенной. Данные естественным образом сохраняются в архивеraw_entries.json(попадания более чем в половине потоков одной библиотеки архива); никаких дополнительных действий по сбору не требуется; граф отношений не строит рёбер на их основе.
2. Семантика ошибок и контроля рисков¶
| Симптом | Значение / обработка |
|---|---|
| 403 (со страницей вызова cf) | Блокировка Cloudflare (отпечаток TLS / контроль скорости) — отступить; urllib + куки браузера обычно не вызывают её |
| 401 / 403 на уровне API (без страницы вызова cf) | Кука сеанса истекла/недействительна — инструмент вызывает ошибку немедленно, без отступления; пакетный режим быстро завершается ошибкой после 3 последовательных сбоев аутентификации (обновите куку) |
| 429 | Ограничение скорости — экспоненциальное отступление (реализовано в инструменте) |
| 5xx (500/502/503/504) | Временные ошибки сервера (504 часто является тайм-аутом Cloudflare) — отступить и повторить (реализовано в инструменте) |
| ENTRY_EXPIRED | Удалено платформой (~3 месяца) — окончательно, не повторять |
| ENTRY_DELETED | Удалено пользователем/удалённо (также HTTP 400, другой код) — окончательно deleted, не повторять |
_response_type: VIEW_COLLECTION_NOT_ALLOWED (HTTP 200) |
Текущая учётная запись не может просмотреть пространство — повторить с учётной записью, которая может |
error_code: VIEW_THREAD_NOT_ALLOWED (HTTP 403) |
Текущая учётная запись не может просмотреть поток (проверено 2026-07-23: зондирование uuid родственного варианта; объект существует, но недоступен, а не «не существует») |
status:"failed" пустые данные |
Тот же класс (форма отказа get_collection) |
Дисциплина ограничения скорости (антибан, явное требование пользователя): случайные 10–20 с между пакетными потоками, без параллелизма, отступление при 429/403, отступление-повтор при 5xx; пагинация ≥3 с; повторная загрузка схематизированных данных ≥4 с; загрузка метаданных пространства ≥3 с. Экспорт одного потока = 1–2 запроса ≈ открытие страницы один раз.
2.1 Семантика прерываний — наблюдаемые значения (2026-07-22; источник истины классификации: parsers.classify_wf_status)¶
Поле locked_reason: появляется в thread_metadata / entries[] / background_entries[]
(как на простой, так и на схематизированной стороне). Единственное наблюдаемое значение:
| locked_reason | Значение | Наблюдаемое распределение |
|---|---|---|
spending_limit_exceeded |
прерывание из-за лимита расходов (квота исчерпана; рабочий процесс останавливается в точке прерывания) | ровно один поток по всей библиотеке (маркеры как в raw_entries, так и в raw_blocks) |
Поле статуса рабочего процесса (workflow_block.status и вложенное workflow_payload.status используют одно и то же перечисление) наблюдаемые значения:
| status | Семантика | Аннотация рендеринга (COMPLETED не получает) |
|---|---|---|
WORKFLOW_COMPLETED |
нормальное завершение | — |
WORKFLOW_AWAITING_NEXT_STEPS |
ожидание следующих шагов; с locked_reason=spending_limit_exceeded это прерывание из-за лимита расходов (содержимое останавливается в точке прерывания); без locked_reason, прервано в ожидании продолжения |
⏸ 限额中断(内容截至中断点) (⏸ прервано лимитом — содержимое останавливается в точке прерывания) / ⏸ 中断待续 (⏸ прервано, ожидание продолжения) |
WORKFLOW_CANCELED |
отменено (прерывание пользователем/платформой) | ⛔ 已取消 (⛔ отменено) |
WORKFLOW_CANCELEDнаблюдалось 19 раз (16 основных + 3 вложенных) в 7 потоках computer (a5e8f481/cfca382d/f2e5957d/8417b02a/2dc5716d/356f833e/ed3714ff).- Примечание: статус основной полезной нагрузки anchor может отставать (наблюдался anchor COMPLETED, в то время как background фактически был CANCELED) —
истинный статус субагента — это
workflow_block.statusна стороне background. - Прерванные фоновые задачи не генерируют уведомление о завершении subagent_result; непотреблённые фоновые полезные нагрузки возвращаются в приложение потока (см. «водопад атрибуции» в subagents-interruptions.md).
- Пустые ответы в режиме computer (дважды проверено 2026-07, невосстановимо): в режиме computer некоторые витки имеют пустой
ответ, потому что сервер просто не имеет его — повторная загрузка API возвращает данные, идентичные архиву, и
разворачивание панели «N шагов выполнено» в интерфейсе не вызывает запросов данных (чисто клиентский рендеринг; интерфейс и
API используют один источник), поэтому API не может их восстановить. Только часть таких витков связана с
locked_reason=spending_limit_exceeded; остальные не имеют маркера на стороне сервера.
2.2 side_by_side_metadata: сигнал варианта перезаписи ответа (установлено 2026-07-23)¶
Путь к полю: entries[].side_by_side_metadata (простой ответ /rest/thread/<uuid>).
Когда платформа генерирует несколько версий ответа на один и тот же запрос (A/B-эксперимент или перезапись), это
единственный след, остающийся в текущей активной записи — тело заменённого варианта (текст/шаги/цитаты) отсутствует в ответе API потока (реальный случай
b2d2632b: ответ содержит только 1 запись, 1 FINAL; вариант 2 полностью невидим).
Наблюдаемые ключи и значения (доказательства: b2d2632b raw; сканирование 2442 записей по всей библиотеке):
{
"experiment_role": "override-default-model-class:qwen3_instruct-01f7f",
"sibling_uuid": "00000000-0000-5000-8000-000000000000",
"experiment_override": {"override-default-model-class": "qwen3_instruct"},
"selection_status": "SELECTED",
"execution_log": {}
}
| Ключ | Семантика (наблюдаемая/гипотетическая) |
|---|---|
sibling_uuid |
Указывает на родственный вариант ответа того же запроса (другой идентификатор записи/контекста). 7 потоков по всей библиотеке; онлайн-криминалистика (2026-07-23) подтверждает мёртвую ссылку: GET /rest/thread/<sibling_uuid> обеих учётных записей возвращают 403 VIEW_THREAD_NOT_ALLOWED (не 404/ENTRY_EXPIRED — сервер распознаёт его как существующий, но не просматриваемый объект), и открытие /search/<sibling_uuid> в браузере (учётная запись владельца) перенаправляется SPA на домашнюю страницу — заменённые варианты невозможно восстановить через sibling_uuid |
selection_status |
SELECTED = ответ этой записи является версией, выбранной для отображения; все экземпляры контрольной группы имеют SELECTION_STATUS_UNSPECIFIED |
experiment_role |
Роль в эксперименте. Контрольная группа имеет префикс [control] (6 случаев по всей библиотеке: [control]default-model-class:gpt41 и т.д.); реальный случай не имеет префикса (override-default-model-class:qwen3_instruct-01f7f, т.е. экспериментальная группа эксперимента с переопределением модели) |
experiment_override |
Параметры переопределения эксперимента (например, override-default-model-class: qwen3_instruct); наблюдаются только в экземплярах экспериментальной группы |
execution_log |
Наблюдается как пустой объект; семантика неизвестна |
Критерии сужения (отличие «подлинной перезаписи с сохранением обеих версий» от «рутинного A/B-контроля»):
sibling_uuid не пустое И (selection_status не пустое и не равно SELECTION_STATUS_UNSPECIFIED,
ИЛИ experiment_role без префикса [control]) → только b2d2632b попадает среди 2442 записей по всей библиотеке
(единственный подтверждённый реальный случай; точность и полнота равны 1 в этой библиотеке, но n=1 нельзя экстраполировать).
Поведение инструмента: parsers.collect_answer_variants извлекает попадания; adapter.get_thread
записывает предупреждение + записывает thread.json.answer_variants (ключ отсутствует, когда нет попаданий);
re-render --thread-json добавляет/удаляет на месте (идемпотентно). Временное доказательство: дельта created→updated записи реального случая
составляет 53,66 с (сгенерирована в 17:13, затем перезаписана/выбрана), и перезапись продвинула lastUpdated на уровне потока (повторный экспорт
может вызвать повторную загрузку, но повторно загруженный ответ всё равно содержит только активный ответ; старые варианты невосстановимы).
Журнал обнаружения и порядок обработки (2026-07-23, sites/perplexity/variant_log.py):
- Маркер журнала: каждое попадание генерирует одну строку WARNING с единым маркером для поиска
ANSWER_VARIANT_DETECTED, включая все поля для локализации и руководство по обработке, в формате:ANSWER_VARIANT_DETECTED thread=<full uuid> uuid8=<8 chars> title="…" entry=<entry_uuid> sibling=<sibling_uuid> selection_status=SELECTED experiment_role=… | action: …Онлайн-путь (adapter.get_thread) выводит при каждом фактическом попадании при загрузке; офлайнre-renderвыводит только при добавлении/изменении зарегистрированного содержимого (идемпотентные повторные запуски не засоряют);batchтакже передаёт однострочное напоминание о количестве попаданий в итоговом резюме (не нарушая существующий формат резюме). - Центральный реестр:
<out>/index/answer_variants_log.jsonl(файл, отслеживаемый в репозитории, не под gitignoredlogs/) — один JSON на строку (detected_at / source=online|offline / web_uuid / uuid8 / title / entry_uuid / sibling_uuid / selection_status / experiment_role), дедуплицирован по (web_uuid, entry_uuid); повторные экспорты/рендеринги не добавляют бесконечно; detected_at сохраняет время первого обнаружения. - Рекомендуемое действие при попадании: родственные варианты эмпирически являются мёртвыми ссылками (см. таблицу выше); альтернативный ответ обычно
невозможно восстановить через API — оперативно проверьте вручную, доступен ли альтернативный ответ (беседа на платформе / память пользователя / скриншоты); если доступен,
запишите его вручную как файл
rewritten_answer_variant.mdв каталоге потока; если нет,thread.json.answer_variants+ реестр jsonl служат окончательной отслеживаемой записью.