Рубрика: Productivity

  • Как быстро исправить повреждённые JSON-файлы: полевое руководство разработчика

    Как быстро исправить повреждённые JSON-файлы: полевое руководство разработчика

    Ваш вызов API только что упал с ошибкой JSONDecodeError: Expecting property name enclosed in double quotes. Время идёт. Данные пришли от LLM, и где-то в этом ответе на 2000 токенов одна-единственная висячая запятая убила весь ваш конвейер.

    По состоянию на май 2026 года самый быстрый способ исправить повреждённые JSON-файлы — использовать автоматизированные библиотеки вроде json_repair (Python) или jsonrepair (npm). Эти инструменты созданы специально для мгновенного исправления синтаксических ошибок, порождаемых LLM. При ручном исправлении обычные подозреваемые — это висячие запятые, одинарные кавычки или ключи без кавычек — три самых частых нарушения стандарта RFC 8259.

    Самое быстрое решение: json_repair для выводов LLM

    Стандартные парсеры, такие как json.loads() в Python, строгие по замыслу. Один символ не на своём месте вызывает JSONDecodeError, и всё останавливается. В 2026 году это повседневная проблема, потому что LLM регулярно оборачивают JSON в разговорный текст, обрывают ответы на полуслове или раскидывают комментарии, нарушающие спецификацию.

    Библиотека json_repair — это решение по умолчанию. Согласно GitHub, по состоянию на 2026 год проект набрал более 4700 звёзд. Он работает, «угадывая» намерение строки: закрывает недостающие скобки, расставляет кавычки и удаляет лишний текст вокруг блока JSON.

    Простой трёхэтапный процесс json_repair: ввод (повреждено) -> угадывание намерения -> вывод (корректно)

    Python: до и после

    Установка: pip install json-repair

    Повреждённый ввод:

    import json_repair
    
    bad_json = '{"user": "Alice", "status": tru'
    decoded_object = json_repair.loads(bad_json)
    

    Что произошло за кулисами: json_repair понял, что tru, скорее всего, было true, добавил недостающую закрывающую скобку и вернул корректный словарь Python. Никакого ручного вмешательства.

    Режим Salvage: когда данные совсем плохи

    Для более сложных случаев в json_repair (v0.59.5+) есть режим Salvage. Как указано в документации проекта, этот режим создан специально для обрезанных ответов ИИ или повреждённых логов. Он может принудительно превращать массивы в объекты или отбрасывать элементы, которые уже не спасти, гарантируя, что вывод соответствует вашей схеме.

    import json_repair
    
    # Salvage mode for severely truncated data
    result = json_repair.loads(
        '{"items": [{"id": 1, "name": "Widget"}, {"id": 2, "na',
        salvage_mode=True
    )
    # Result: {'items': [{'id': 1, 'name': 'Widget'}, {'id': 2}]}
    # Dropped the incomplete 'na' but saved everything else
    

    Альтернатива для npm

    В проектах на Node.js ту же задачу решает CLI-утилита jsonrepair:

    # Fix a file in place
    npx jsonrepair broken.json > fixed.json
    
    # Fix a string in a script
    const { jsonrepair } = require('jsonrepair');
    const fixed = jsonrepair('{"name": "test",}');
    

    Ручная отладка: находим, что нарушило спецификацию

    Когда автоматизация не справляется, нужно точно найти, в каком месте файл нарушает RFC 8259. JSON гораздо менее снисходителен, чем YAML или JavaScript. Как объясняет команда диагностики JSONParser: «Парсер падает на первом символе, который не может осмыслить, и это часто лишь downstream-симптом проблемы, возникшей несколькими строками выше».

    Три главных убийцы JSON

    Убийца 1: висячие запятые

    По данным DEV Community, висячие запятые — причина №1 сбоев парсинга. В JavaScript они допустимы, но запрещены после последнего элемента в массиве или объекте JSON.

    // BROKEN - trailing comma after "active"
    {
      "name": "Alice",
      "status": "active",
    }
    
    // FIXED - no comma before closing brace
    {
      "name": "Alice",
      "status": "active"
    }
    

    Убийца 2: одинарные кавычки

    JSON требует двойных кавычек (") как для ключей, так и для строковых значений. Многие Python- и JavaScript-разработчики случайно используют одинарные кавычки ('). Как отмечает TidyCode, это обязательное исправление.

    // BROKEN - single quotes
    {'name': 'Alice'}
    
    // FIXED - double quotes
    {"name": "Alice"}
    

    Убийца 3: ключи без кавычек

    В JavaScript можно написать { name: "Alice" }. В JSON каждый ключ требует двойных кавычек.

    // BROKEN - unquoted key
    {name: "Alice"}
    
    // FIXED - quoted key
    {"name": "Alice"}
    

    Сравнение синтаксиса некорректного и корректного JSON бок о бок

    Ошибка «Unexpected Token»

    Когда валидатор выдаёт «Unexpected Token», это значит, что парсер наткнулся на NaN, Infinity или undefined — константы JavaScript, которые JSON не поддерживает. JSON допускает только null, true, false и числа.

    // BROKEN - NaN is not valid JSON
    {"score": NaN, "result": Infinity}
    
    // FIXED - replace with null or valid values
    {"score": null, "result": null}
    

    Строгий парсинг против парсинга с восстановлением: когда что использовать

    Правильный подход зависит от того, откуда поступают ваши данные. Файлы конфигурации, редактируемые человеком, заслуживают строгого парсинга, чтобы заставить автора исправлять ошибки. Машинные данные от LLM или логов API нуждаются в парсинге с восстановлением.

    Возможность Строгий (json.loads) Восстановление (json_repair)
    Висячие запятые Возбуждает JSONDecodeError Автоматически удаляются
    Одинарные кавычки Сбой Преобразуются в двойные
    Усечённые данные Сбой Закрывает открытые скобки/кавычки
    Комментарии Сбой Автоматически удаляются
    Лучший сценарий Конфиги, редактируемые человеком Вывод LLM, логи API

    Восстановление по схеме с Pydantic

    Процессом восстановления можно управлять с помощью Pydantic v2 или JSON Schema. Передав json_repair схему, инструмент делает больше, чем просто исправляет синтаксис: он может корректировать типы (превращая строку "1" в число 1) и заполнять недостающие обязательные поля значениями по умолчанию.

    from pydantic import BaseModel
    import json_repair
    
    class User(BaseModel):
        id: int
        name: str
        active: bool = True
    
    # Broken JSON with wrong types
    raw = '{"id": "42", "name": "Alice"}'
    repaired = json_repair.loads(raw)
    
    # Validate against schema
    user = User(**repaired)
    # user.id is now int(42), user.active defaults to True
    

    Как отметил Stefano Baccianella в описании проекта 2025 года, этот подход оптимизирован под «в основном корректный, но технически недействительный» JSON, который обычно порождают языковые модели.

    Обработка мультигигабайтных файлов без падений

    Восстановить фрагмент в 10 КБ легко. Починить файл в 2 ГБ требует стратегии, которая не сожрёт всю вашу оперативную память. Загрузка всего файла в память вызывает ошибки нехватки памяти (OOM).

    Стратегия 1: потоковая обработка с ijson

    Для огромных наборов данных используйте ijson, обрабатывая данные по частям. Как упоминает Scrapfly, ijson обрабатывает данные инкрементально. Сочетайте его со скриптом очистки, который исправляет проблемы построчно ещё до парсинга.

    import ijson
    
    # Stream through a large JSON file
    with open('huge_broken.json', 'r') as f:
        for item in ijson.items(f, 'records.item'):
            # Process each item individually
            process(item)
    

    Стратегия 2: CLI-конвейер для максимальной эффективности

    Самый экономный по памяти подход для больших файлов — использовать CLI jsonrepair и направлять вывод напрямую в новый файл:

    # Streams repair, never loads full file into memory
    jsonrepair large_broken.json > fixed.json
    

    Это значительно экономнее по памяти, чем загрузка файла в Python или браузер.

    Заключение

    Исправление повреждённого JSON больше не ручная рутина благодаря учитывающим AI библиотекам вроде json_repair. Вам по-прежнему нужно знать основы RFC 8259 — никаких висячих запятых, никаких одинарных кавычек, никаких ключей без кавычек — но в 2026 году при работе с данными в масштабе автоматизация остаётся единственным практически применимым подходом.

    Рабочий процесс прост: сначала попробуйте библиотеку восстановления. Если не получилось — используйте валидатор, чтобы точно указать синтаксическую ошибку. Так ваши приложения продолжат работать, даже когда входящие данные далеки от идеала.

    Часто задаваемые вопросы

    Официально ли JSON поддерживает комментарии или одинарные кавычки?

    Нет. Стандарт RFC 8259 строго запрещает комментарии. Одинарные кавычки также недействительны — для ключей и строк допускаются только двойные кавычки. Однако такие инструменты, как json_repair, могут автоматически удалять комментарии и преобразовывать кавычки, делая файлы доступными для разбора стандартными библиотеками.

    Как обрабатывать очень большие повреждённые JSON-файлы без падений?

    Используйте потоковый парсер вроде ijson, чтобы обрабатывать данные порциями. Избегайте загрузки всей повреждённой строки в одну переменную. Для максимальной скорости применяйте CLI-инструменты восстановления, которые направляют вывод напрямую в новый файл на диске, не удерживая всё в памяти.

    В чём разница между повреждённым (malformed) и недействительным (invalid) JSON?

    Повреждённый JSON нарушает синтаксические правила — не хватает скобок, ключи без кавычек, висячие запятые — из-за чего его невозможно разобрать. Недействительный JSON соблюдает все синтаксические правила, но не соответствует конкретной JSON Schema (например, поле является строкой, тогда как схема ожидает целое число). Исправление повреждённого JSON — это структурное восстановление; исправление недействительного JSON — вопрос целостности данных.

    Можно ли использовать json_repair вместе с валидацией Pydantic?

    Да. Сначала выполните json_repair.loads(), чтобы исправить синтаксические ошибки, затем передайте восстановленный словарь в вашу модель Pydantic для проверки типов и соблюдения схемы. Этот двухэтапный подход решает как структурные, так и семантические проблемы.

    Что насчёт JSON с комментариями в стиле JavaScript?

    Стандартный JSON не поддерживает комментарии, но json_repair может автоматически удалять комментарии // и /* */. Если вам нужны комментарии в конфигурационных файлах, рассмотрите формат JSONC (JSON с комментариями) и совместимый парсер, например json5 для Python.

  • Как писать AI-промпты с форматтером: структурированная инженерия для разработчиков

    Как писать AI-промпты с форматтером: структурированная инженерия для разработчиков

    Знакомо то тягучее чувство, когда вывод AI совершенно не похож на то, что вы просили? JSON malformed, тон не тот, а половина инструкций проигнорирована. Проблема не в модели — а в том, как вы форматируете промпт.

    Чтобы освоить как писать AI-промпты с форматтером, внедрите фреймворк RTCCO (Role, Task, Context, Constraints, Output) с использованием структурированных разделителей вроде XML или JSON. Такой подход превращает промпты в модульные программные активы, что к маю 2026 года позволяет снизить галлюцинации модели до 60% и сократить время ручной обработки на 75%.

    Почему параграфные промпты продолжают падать

    К 2026 году профессиональная работа с AI ушла от «болтовни» к парадигме Prompt-as-Code (PaC). Проблема параграфных промптов — тех длинных неструктурированных блоков текста — в том, что модели с трудом отделяют ваши реальные инструкции от фоновых данных или требований к выводу, смешанных с ними.

    Данные PromptOT показывают, что переход к структурированной инженерии снижает количество ошибок на 60% и ускоряет ручную обработку на 75%. Alex Ostrovskyy называет хардкод-промпты «современным эквивалентом магических чисел в исходном коде» — хрупкими системами, которые практически невозможно обновить, ничего не сломав.

    До и после: разница в форматировании

    До (без структуры):

    You are a helpful coding assistant. Please write a Python function that validates
    email addresses. Make sure it handles edge cases like plus signs and subdomains.
    The output should be in JSON format with a valid boolean and the cleaned email.
    Also make sure you add proper error handling and don't forget logging.
    

    После (RTCCO + XML-разделители):

    <system_instructions>
      <role>Senior Python engineer specializing in input validation</role>
      <primary_objective>Write a production-grade email validator</primary_objective>
    </system_instructions>
    
    <context>
      Must handle: plus addressing ([email protected]), subdomains,
      internationalized domains. Target: Python 3.11+.
    </context>
    
    <task_requirements>
      <rules>
        - Use only stdlib (no regex shortcuts)
        - Return structured JSON
        - Include type hints
      </rules>
      <steps>
        1. Parse the input string
        2. Validate format per RFC 5322
        3. Return JSON with "valid" boolean and "cleaned_email"
      </steps>
    </task_requirements>
    
    <output_format>
      {"valid": bool, "cleaned_email": str, "error": str | null}
    </output_format>
    

    Цель та же, результат — кардинально иной. Отформатированная версия не оставляет модели ни малейшего пространства для двоякого толкования.

    Фреймворк RTCCO: скелет вашего промпта

    Индустрия сошлась на RTCCO как на стандартной архитектуре промптов. Каждый промпт раскладывается на пять частей:

    Элемент Назначение Пример
    R оль (Role) Кто такой AI? «Senior backend engineer»
    T аска (Task) Какое конкретное действие? «Написать rate limiter middleware»
    C фон (Context) Какие фоновые данные? RAG-выборка, фрагменты кодовой базы
    C ограничения (Constraints) Каковы правила? «Без внешних зависимостей»
    O вывод (Output) Как он должен выглядеть? «Корректный Python 3.11 с type hints»

    Пять компонентов фреймворка RTCCO

    XML-скелет шаблона, который можно скопировать прямо сейчас

    Вот production-ready шаблон. Скопируйте, адаптируйте, выкатывайте.

    <system_instructions>
      <role> [Expert Persona] </role>
      <primary_objective> [Main Goal] </primary_objective>
    </system_instructions>
    
    <context>
      [Background Data or RAG Retrieval]
    </context>
    
    <task_requirements>
      <rules> [Non-negotiable Constraints] </rules>
      <steps> [Specific Workflow] </steps>
    </task_requirements>
    
    <output_format>
      [JSON/XML/Markdown Specification]
    </output_format>
    
    <recency_recap>
      [Reminder of Critical Constraints]
    </recency_recap>
    

    Почему Recency Recap имеет значение

    У LLM есть известный bias «Primacy and Recency» — они лучше запоминают начало и конец промпта, чем середину. Тесты, цитируемые PromptOT, показали, что перенос критичных правил из середины в блок Recency Recap внизу поднимает точность в продакшене с 78% до 96%. Держите Role наверху, а самые важные правила — внизу.

    Визуализация эффекта первичности и недавности в длинных промптах

    Разделители как защитный барьер

    Разделители — это не просто про организацию, это механизм безопасности. Оборачивание пользовательского ввода в теги вроде <user_input> говорит модели: «Это данные для обработки, а не новые инструкции к исполнению». Это ваша основная защита от атак prompt injection, при которых пользователи пытаются переопределить ваши системные инструкции.

    Частая ошибка: если вы вставляете пользовательские данные напрямую в промпт без разделителей, пользователь может написать «Ignore all previous instructions and…» — и модель подчинится. Всегда оборачивайте внешние данные в тегированные блоки.

    Модульная архитектура: перестаньте писать мега-промпты

    Вместо одного хрупкого промпта на 2000 токенов разбейте систему на независимые модули. Это предотвращает коллизию инструкций — когда изменение тона промпта случайно ломает его формат вывода JSON.

    Ключевой принцип — Context Engineering: отделяйте статические инструкции от динамических данных. В production RAG-системе ваш промпт — это шаблон, в котором блок <context> заполняется свежими данными в момент запроса. Как объясняет Jono Farrington из OptizenApp, такой модульный подход делает крупные AI-развёртки куда более консистентными.

    Prompt Chaining: соединение модулей

    Для сложных воркфлоуов используйте Prompt Chaining — когда вывод одного модуля становится вводом для следующего:

    [Planner Module] --> outline --> [Executor Module] --> draft --> [Reviewer Module] --> final
    

    Такой пошаговый подход улучшает качество вывода примерно на 35%, потому что модель каждый раз фокусируется только на одной подзадаче.

    Простой трёхшаговый workflow prompt chaining

    Пример chaining, готовый к использованию:

    planner_prompt = """
    <system_instructions>
      <role>Technical architect</role>
      <task>Create a step-by-step plan for: {user_request}</task>
    </system_instructions>
    <output_format>JSON array of steps</output_format>
    """
    
    executor_prompt = """
    <system_instructions>
      <role>Senior developer</role>
      <task>Implement step: {step_from_planner}</task>
    </system_instructions>
    <context>{previous_outputs}</context>
    <output_format>Code block with inline comments</output_format>
    """
    

    Добавляем Chain-of-Thought для сложных задач

    Когда задача требует сложной логики, добавьте блок <thought_process>. Это заставляет модель рассуждать пошагово, прежде чем выдать ответ, что заметно снижает ошибки в математике, кодинге и многошаговых рассуждениях.

    <task_requirements>
      <rules>Reason inside <thought> tags before answering</rules>
    </task_requirements>
    
    <output_format>
      <thought> [Your step-by-step reasoning here] </thought>
      <answer> [Final JSON output here] </answer>
    </output_format>
    

    По данным Zencoder, такие техники, как Tree-of-Thoughts (ToT), идут дальше: они требуют, чтобы модель одновременно оценивала несколько путей решения и выбирала лучший. Это особенно ценно для архитектурных решений, где нет единственно верного ответа.

    Предупреждение о стоимости токенов

    Структурированные рассуждения расходуют больше токенов. Типичный блок <thought_process> добавляет 200–500 токенов на запрос. В масштабе это означает более высокие расходы на API. Компромисс — в точности: вы платите больше за запрос, но нужно меньше ретраев и меньше ручных правок.

    Production readiness: версионирование, тестирование и CI/CD

    Финальный шаг — относиться к промптам как к софту. Используйте Semantic Versioning (например, v1.0.0), чтобы команда могла отслеживать изменения и мгновенно откатываться, когда новая версия промпта деградирует.

    PromptOT сообщает, что компании, управляющие 50+ промптами, могут экономить до $400 000 в год за счёт централизации управления и сокращения времени, которое инженеры тратят на ручную подгонку.

    Настройка CI/CD-пайплайна для промптов

    # .github/workflows/prompt-tests.yml
    name: Prompt Quality Gate
    on: [push]
    jobs:
      test-prompts:
        runs-on: ubuntu-latest
        steps:
          - name: Run Golden Dataset Tests
            run: |
              # Test against 50-200 curated cases
              python scripts/eval_prompts.py \
                --dataset golden_dataset.json \
                --judge-model gpt-4 \
                --min-score 0.85
    
          - name: Regression Check
            run: |
              # Compare new version vs. production
              python scripts/compare_versions.py \
                --staging v2.1.0 \
                --production v2.0.3 \
                --threshold 0.05
    

    Промпт переходит из Staging в Production, только когда проходит эти quality-гейты, оцениваемые «LLM-as-a-judge».

    Заключение

    Структурированная промпт-инженерия с форматтерами больше не опциональна — это baseline для каждого, кто строит надёжные AI-инструменты. Фреймворк RTCCO, XML-разделители и модульная архитектура — ваш стек для превращения непредсказуемых LLM-выводов в стабильные, production-grade результаты.

    Начните с самых часто используемых промптов и отрефакторите их в фреймворк RTCCO с помощью XML-шаблона выше. Заведите их в систему контроля версий, настройте базовую оценку — и у вас появится масштабируемая промпт-инфраструктура.

    FAQ

    Как конвертировать мои текущие параграфные промпты в формат RTCCO-блоков?

    Сначала выделите ядро — Task — и отделите его от Context. Оберните инструкции в теги <rules> и приведите 3–5 примеров в тегах <examples>. Можно даже привлечь LLM: дайте ей промпт «re-parse this unstructured text into the RTCCO framework using XML delimiters» — и она возьмёт тяжёлую работу на себя.

    Что использовать — XML, JSON или Markdown-разделители?

    XML — текущий золотой стандарт для отделения инструкций от длинного контента в таких моделях, как Claude и GPT-5, благодаря строгой иерархии. JSON лучше подходит, когда нужны программные input/output для API-интеграций. Markdown годится для простых, читаемых человеком промптов, но ему не хватает строгого определения границ, нужного для сложных, многослойных production-промптов.

    Как внедрить автоматическое CI/CD-тестирование промптов?

    Настройте тестовый набор с «Golden Dataset» (50–200 кураторских кейсов) и «LLM-as-a-judge», который оценивает вывод по рубрикатору. Интегрируйте эти тесты в ваш GitHub Actions или Jenkins-пайплайн, чтобы любое изменение промпта проверялось на точность и тон ещё до деплоя.

    Какая самая частая ошибка при переходе на структурированные промпты?

    Перегрузка блока <context>. Разработчики часто сваливают в контекст целые кодовые базы или документы, что распыляет внимание модели. Держите контент сфокусированным только на том, что напрямую относится к задаче. Если нужно ссылаться на большие документы, используйте RAG-выборку, чтобы подтягивать лишь релевантные разделы.