Когда модель GPT отклоняет запрос, нарушающий политику использования провайдера, она возвращает статус 200 с кратким отказом, без ошибки и категории. Ознакомьтесь с телом ответа и узнайте, как его обнаружить.
Когда модель GPT получает запрос, нарушающий политику использования провайдера, она не возвращает ошибку. API отвечает с кодом HTTP 200, finish_reason имеет значение stop, а содержимое представляет собой отказ, написанный самой моделью, например «Я не могу помочь с этим…».В ответе нет ни кода ошибки, ни категории или степени серьезности отказа. Он имеет точно такую же структуру, как обычный ответ, и тарифицируется точно так же. По одному лишь коду состояния и finish_reason невозможно определить, что в запросе было отказано.
Ниже приведен реальный непотоковый отказ от /v1/chat/completions (содержимое заменено нейтральным примером):
{ "model": "gpt-5.6-terra", "object": "chat.completion", "created": 1789712872, "choices": [ { "index": 0, "message": { "role": "assistant", "content": "I can't help with that request. I can, however, help with a related topic or a rewritten version that stays within the usage policy." }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 35, "completion_tokens": 54, "total_tokens": 89 }}
Поле
Как выглядит отказ
HTTP-статус
200
finish_reason
stop, как и в обычном ответе
message
Только role и content; отдельного поля refusalнет
Начальные слова
Обычно I can't… или Sorry, I can't…; на китайском — 抱歉,我不能…
Язык
Соответствует prompt: на prompt на китайском языке обычно возвращается отказ на китайском
Длина
В основном 50–120 tokens; темы, связанные с личным благополучием, сопровождаются рекомендациями по поддержке и могут достигать примерно 400 tokens
Тарификация
Тарифицируется в обычном порядке по фактическому количеству входных и выходных tokens
Для запросов, нарушающих правила, чат-API OpenAI позволяет модели принять решение не отвечать вместо возврата ошибки. Он не сообщает, какая именно категория была затронута (например, контент для взрослых, сцены насилия или причинение себе вреда), и не указывает степень серьезности.Это отличается от ошибки. При ошибке вы получаете статус, отличный от 200, и объект error. При отказе же вы получаете успешный вызов, содержимое которого просто не является тем, что вы запрашивали.
В задачах пакетного перевода и извлечения данных от модели обычно требуется фиксированный формат, например массив JSON. Когда пакет вызывает отказ, модель возвращает обычное предложение, поэтому его парсинг как JSON завершается с ошибками вроде Unrecognized token 'I' или Expecting value.Это не проблема формата API. Содержимое этого пакета было отклонено. Повторная отправка того же пакета без изменений обычно дает тот же результат.
APIYI включил автоматическое переключение при сбое для безопасности контента в запросах без потоковой передачи. Если один официальный маршрут активирует фильтр контента — для prompt или для сгенерированного вывода, — запрос автоматически повторяется через другой официальный маршрут без необходимости повторных попыток с вашей стороны. После переключения большинство запросов возвращают обычный результат; небольшая часть все еще может быть отклонена самой моделью — именно этот случай и описан на данной странице.
Если вы запрашивали JSON, парсите его как JSON; если запрашивали фиксированное количество элементов, проверьте их число. Если формат не совпадает, считайте вызов «результат отсутствует» и не используйте полученный контент в качестве вывода.
2
Затем проверьте, не является ли это отказом
Если формат не совпадает, проверьте, не представляет ли собой контент короткое предложение, начинающееся с I can't, Sorry или подобных фраз. Если это так, то это почти наверняка отказ, а не отклонение модели от формата.
3
Не повторяйте запрос без изменений
Повторная отправка того же контента без изменений, скорее всего, приведет к аналогичному отказу, при этом каждая попытка тарифицируется.
4
Разделите пакет, чтобы найти конкретные элементы
Отправьте неудавшийся пакет повторно меньшими частями, чтобы выяснить, какие именно элементы вызывают отказ; остальные обычно обрабатываются успешно. Для элементов, вызвавших отказ, скорректируйте формулировку и попробуйте снова.
5
Архивируйте неудачные случаи, затем решите, стоит ли сменить модель
Ведите внутренний архив неудачных случаев (входные данные, время запроса, ID запроса, возвращенный контент), анализируйте, на каких типах контента концентрируются отказы, и затем рассмотрите возможность повторной отправки этого контента с использованием другой модели.
Мы рекомендуем сделать цепочку «архивация неудачных случаев → анализ → повторная попытка с другой моделью» стандартным процессом. Отказы обычно группируются вокруг нескольких типов контента, поэтому архив позволяет легко увидеть закономерность. Это избавляет от повторных ручных проверок и предотвращает повторную оплату за один и тот же контент.
Вот минимальный пример: валидация JSON и запись всего, что не соответствует формату, в локальный журнал сбоев.
import jsonimport osimport timefrom openai import OpenAIclient = OpenAI(api_key=os.environ["APIYI_API_KEY"], base_url="https://api.apiyi.com/v1")REFUSAL_PREFIXES = ("I can't", "I can’t", "Sorry", "I'm sorry", "I’m sorry", "抱歉")def translate_batch(lines): prompt = "Translate each subtitle line below into English. Output a JSON array only:\n" + json.dumps(lines, ensure_ascii=False) resp = client.chat.completions.create( model="gpt-5.6-terra", messages=[{"role": "user", "content": prompt}], ) text = resp.choices[0].message.content or "" try: result = json.loads(text) if isinstance(result, list) and len(result) == len(lines): return result except json.JSONDecodeError: pass # No usable result: record it for later analysis or a retry with another model with open("failed_cases.jsonl", "a", encoding="utf-8") as f: f.write(json.dumps({ "time": time.strftime("%Y-%m-%d %H:%M:%S %z"), "request_id": resp.id, "is_refusal": text.strip().startswith(REFUSAL_PREFIXES), "input": lines, "output": text, }, ensure_ascii=False) + "\n") return None
Как только начинается ответ с потоковой передачей, его больше нельзя переключить на другой маршрут, поэтому автоматическое аварийное переключение безопасности контента применяется только к запросам без потоковой передачи. При потоковой передаче вы можете увидеть:
краткий отказ, в последнем событии которого finish_reason установлено в content_filter; или
часть уже доставленного контента, заканчивающуюся на finish_reason: "content_filter".
Для таких задач, как пакетный перевод, где не требуется отображение token за token, мы рекомендуем использовать вызовы без потоковой передачи.
Да. Отказ считается успешным вызовом и тарифицируется по фактическому объему входных и выходных tokens, поэтому избегайте повторных запросов с тем же содержимым.
Можно ли отключить отказы?
Нет. Решение об отказе принимается моделью провайдера в соответствии с ее политикой использования. APIYI не может отключить их или изменить степень их строгости.
Почему один и тот же контент иногда проходит, а иногда отклоняется?
В оценке модели присутствует элемент случайности, а разные официальные маршруты выполняют фильтрацию немного по-разному, поэтому пограничный контент может один раз пройти, а в следующий — получить отказ. Контент, явно нарушающий политику использования, отклоняется всегда.
Как получить категорию отказа?
OpenAI chat API не возвращает ее. Если для вашего рабочего процесса требуются категории, классифицируйте контент самостоятельно перед отправкой или разбирайте архивные неудачные запросы вручную.