Перейти к содержанию

Машинный перевод

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

Английский источник · Сообщить о проблеме перевода

Структура ответа 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 (файл, отслеживаемый в репозитории, не под gitignored logs/) — один 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 служат окончательной отслеживаемой записью.