Введение
Команде эксплуатации нужна структурированная сводка короткого отчёта об инциденте. Модель может создавать убедительный текст, но приложению нужны предсказуемые поля и отклонение недопустимого вывода. Вы запросите сводку JSON через Bedrock Converse, разберёте её в Python и проверите отказ на явно обозначенных локальных примерах.
Вы должны знать основы Python, JSON и запросы Converse предыдущей работы. Каждая новая VM предоставляет документ, настроенную идентификацию и лимит вывода. Файлы и учётные данные предыдущих VM не нужны.
Связь с сертификацией
| Сертификация | Задача экзамена | Практика |
|---|---|---|
| AI Practitioner (AIF-C01) | Задача 3.2 | Задать формат и проверить ответ до использования приложением. |

Изучите документ и обязательные поля
На этом шаге вы изучите предоставленный синтетический отчёт и определите структуру для использующего сводку приложения.
Начните в рабочем каталоге:
cd /home/labex/project
Документ — обычный текст. Прочитайте его командой cat, выводящей файл:
cat incident.txt
Он описывает INC-204: ошибка настройки оформления заказа вызвала 30 минут неудачных оформлений. Команда вернула предыдущую настройку и восстановила сервис. Дополнительный тест настройки запланирован, но не завершён. Эти факты ограничивают сводку.
Приложение ожидает ровно три поля: incident_id, impact и next_action, каждое с непустой строкой. Схема описывает эту форму; корректного JSON недостаточно, поскольку список, пропущенное поле или число также могут быть корректным JSON. Прочитайте предоставленную схему:
cat summary-schema.json
Справка объясняет желаемый результат. Вы обеспечите поля обычным Python; сама справка не гарантирует соблюдения моделью. Запросить JSON и проверить JSON — разные обязанности.
Создайте и проверьте структурированную сводку
На этом шаге вы создадите небольшой Python-командный скрипт, который запрашивает сводку и проверяет текст до сообщения об успехе.
boto3 — AWS SDK для Python. Он установлен в предоставленной среде и использует настроенные учётные данные и endpoint. Код вызывает converse, уже изученную операцию CLI. maxTokens ограничивает вывод; клиент отключает автоматические повторы, чтобы неоднозначный сбой незаметно не отправил ещё один запрос модели.
Создайте summary.py с этим кодом. parse_response проверяет причину завершения, разбирает текст через json.loads, проверяет точные ключи и типы. ValueError обозначает контролируемое отклонение; ClientError или ошибка соединения сообщаются без раскрытия учётных данных и полной ошибки сервиса. Необязательный --response-file читает локальный ответ для теста парсера и не отправляет запрос модели:
cat > summary.py <<'EOF'
import argparse
import json
from pathlib import Path
import boto3
from botocore.config import Config
from botocore.exceptions import BotoCoreError, ClientError
def parse_response(response):
if not isinstance(response, dict):
raise ValueError("invalid_response")
if response.get("stopReason") != "end_turn":
raise ValueError("incomplete_response")
try:
text = response["output"]["message"]["content"][0]["text"]
value = json.loads(text)
expected = {"incident_id", "impact", "next_action"}
if not isinstance(value, dict) or set(value) != expected:
raise ValueError("invalid_fields")
if any(not isinstance(v, str) or not v.strip() for v in value.values()):
raise ValueError("invalid_field_type")
if value["incident_id"] != "INC-204":
raise ValueError("unexpected_incident")
return value
except (KeyError, IndexError, TypeError, json.JSONDecodeError) as error:
raise ValueError("invalid_response") from error
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--response-file", type=Path)
args = parser.parse_args()
try:
if args.response_file:
response = json.loads(args.response_file.read_text())
else:
client = boto3.client("bedrock-runtime", config=Config(
connect_timeout=5, read_timeout=150,
retries={"total_max_attempts": 1}))
response = client.converse(
modelId="labex.text-v1:0",
system=[{"text": "Summarize only facts supplied in the incident document. Return exactly one JSON object with string fields incident_id, impact and next_action. No Markdown fences, extra keys or surrounding prose. Do not turn planned work into completed work."}],
messages=[{"role": "user", "content": [
{"text": Path("incident.txt").read_text()}]}],
inferenceConfig={"maxTokens": 768, "temperature": 0})
Path("response.json").write_text(json.dumps(response, indent=2))
value = parse_response(response)
except (ValueError, KeyError, TypeError):
print(json.dumps({"status": "rejected", "reason": "invalid_model_output"}))
return 2
except (BotoCoreError, ClientError):
print(json.dumps({"status": "unavailable", "reason": "inference_failed"}))
return 3
print(json.dumps({"status": "ok", "summary": value}, indent=2))
return 0
if __name__ == "__main__":
raise SystemExit(main())
EOF
Запустите скрипт установленной Python-средой AWS. Заключительное > summary.json сохраняет напечатанный результат:
/opt/labex/aws/venv/bin/python summary.py > summary.json
Дождитесь приглашения и изучите результат:
cat summary.json
Успешный запуск содержит "status": "ok" и объект summary с тремя строковыми полями. Прочитайте также исходный ответ Converse:
python3 -m json.tool response.json
response.json сохраняет реальный вывод, причину завершения и токены. Разверните завершённый запрос в AWS View и сравните текст. Формулировки могут отличаться. Проверьте, что impact отражает неудачные оформления, а next_action — запланированную работу. Соответствие схеме не доказывает точность этих утверждений.

Если скрипт отклонил результат, прочитайте исходный ответ перед повтором. Модель может обрезать текст или игнорировать формат; не подменяйте сводку успехом, зашитым в код. Неудачный запрос может расходовать лимит.
Проверьте границу недопустимых ответов
На этом шаге вы подтвердите отказ для ошибочного JSON, неверных типов и обрезанных ответов без нового запроса модели.
В fixtures/ находятся намеренно подготовленные входы для тестирования парсера. Это локальные данные, не результаты вывода. Выведите их список:
ls fixtures
Запустите скрипт на примере ошибочного JSON:
/opt/labex/aws/venv/bin/python summary.py --response-file fixtures/malformed.json
Ожидается {"status": "rejected", "reason": "invalid_model_output"}. Код выхода 2 обозначает контролируемое отклонение. echo $? выводит код непосредственно предыдущей команды:
echo $?
Ответ может быть корректным JSON и нарушать схему. Проверьте пример с числовым impact:
/opt/labex/aws/venv/bin/python summary.py --response-file fixtures/wrong-type.json
Он должен дать такое же отклонение. Даже полный на вид объект нужно отклонить, если модель достигла предела токенов. Проверьте эту границу:
/opt/labex/aws/venv/bin/python summary.py --response-file fixtures/truncated.json
Пример отклоняется, потому что его stopReason — max_tokens. Тесты не печатают успешных сводок и не добавляют запросы в AWS View.
Наконец, снова разберите реальный сохранённый ответ:
/opt/labex/aws/venv/bin/python summary.py --response-file response.json
Он должен вернуть status: ok. Вы проверили пригодный реальный ответ и контролируемые ошибочные входы. Примеры парсера не являются доказательством работы модели: завершённый запрос и исходный ответ доказывают это отдельно.
Удалите созданные файлы упражнения
На этом шаге после функциональных проверок вы удалите свой скрипт и два файла результата.
Документ, схема и примеры парсера относятся к новой среде. Сохраните их и backend-сервис. rm удаляет только три названных файла учащегося:
rm summary.py summary.json response.json
Убедитесь, что предоставленные входы остались:
ls
Converse не создаёт постоянный сервер для удаления. Удаление локальных файлов не возвращает credits и не стирает реальные записи AWS View.
Заключение
Вы получили структурированную сводку из реального ответа Bedrock Converse, обеспечили имена и типы полей, проверили завершение и отклонили контролируемые недопустимые ответы. Вы также отделили проверку фактов от схемы и удалили только свои файлы.
Подробнее см. в документации AWS: Содержимое ответа, причины остановки и использование Converse.



