# Как заставить нейросеть писать не как нейросеть: промпты, примеры и правки стиля

> AI Release · @ai_release1 · https://ai-release.org/guides/kak-zastavit-neyroset-pisat-ne-kak-neyroset-prompty-pri.html

## TL;DR
- Время выполнения: 40–60 минут
- Уровень сложности: Intermediate
- Понадобится: Python 3 (версию сверьте с документацией SDK вашего провайдера), `curl`, терминал, API-ключ провайдера LLM, 3–5 своих текстов-образцов на 1–2 абзаца, файл с исходным «ИИ-текстом»
- Результат: файл `output.txt`, в котором 0 совпадений с вашим стоп-листом клише, и повторяемый скрипт для следующих правок

## Требования и подготовка
![Иллюстрация к разделу «Требования и подготовка»](https://ai-release.org/guides/img/kak-zastavit-neyroset-pisat-ne-kak-neyroset-prompty-pri-ru-1.jpg)

- ОС: Linux/macOS или Windows с WSL — команды ниже даны для bash; в PowerShell замените `export` на `$env:ИМЯ="значение"`.
- Python и `pip`: проверьте `python3 --version`. Если команда не найдена — установите Python из пакетного менеджера вашей ОС.
- `curl`: проверьте `curl --version`. Ожидаемый результат — строка вида `curl 8.x.x` (номер будет вашим).
- API-ключ и URL эндпоинта вашего провайдера LLM. Формат эндпоинта, имя модели и поддерживаемые параметры (например, `temperature`) **сверьте с документацией** провайдера — они отличаются.
- Права на запись в домашний каталог (создадим папку `~/style-fix`).
- 3–5 собственных текстов, написанных вами без нейросети — это база для few-shot (показ модели примеров прямо в промпте).
- Чек-лист готовности:
- [ ] `python3 --version` отвечает версией
- [ ] `curl --version` отвечает версией
- [ ] переменные `LLM_API_URL`, `LLM_API_KEY`, `LLM_MODEL` заданы в текущей сессии
- [ ] есть папка `~/style-fix` и в ней лежит `input.txt`

```bash
mkdir -p ~/style-fix/examples && cd ~/style-fix
export LLM_API_URL="https://<ваш-провайдер>/v1/chat/completions"
export LLM_API_KEY="<ваш-ключ>"
export LLM_MODEL="<имя-модели-из-документации>"
printenv LLM_API_URL LLM_MODEL
```

**Почему это работает:** стиль модели определяется системным промптом (инструкция роли, которую модель держит весь диалог) и примерами, а не вежливостью просьбы. Переменные окружения держат ключ вне кода — вы не попадёте ключом в git.

## Шаг 1. Соберите профиль голоса и стоп-лист клише

**Что сделать:** создайте три файла: `style_guide.md` (как писать), `banned.md` (что запрещено, по одному пункту на строку) и `input.txt` (текст на переписывание). Скопируйте 3–5 своих образцов в `examples/`.

**Зачем:** «пиши естественно» — неизмеримая инструкция. Модель выполняет только измеримые: длина предложения, запрещённые слова, порядок абзацев. Стоп-лист потом проверит скрипт, и вы получите объективный результат, а не ощущение.

**Пример:** `style_guide.md`

```markdown
Ты — редактор технических текстов. Правила:
1. Одно утверждение — одно предложение. Средняя длина — до 20 слов.
2. Каждый абзац начинается с факта, команды или числа. Не с обобщения.
3. Не объясняй, что такое очевидное; объясняй только термины.
4. Активный залог: «скрипт печатает», а не «скриптом печатается».
5. Никаких выводов в конце раздела. Закончил мысль — переходи к следующей.
```

`banned.md` — по одному клише на строку:

```text
в современном мире
не секрет, что
играет важную роль
давайте разберёмся
в заключение
стоит отметить
```

Типовые соответствия для стоп-листа:

| Признак ИИ-текста | Что писать в `banned.md` | Чем заменить |
|---|---|---|
| Обобщённое вступление | `в современном мире` | конкретный факт, дата или команда |
| Оценка без данных | `играет важную роль` | что именно делает объект и с каким параметром |
| Затяжка перед темой | `давайте разберёмся` | сразу шаг или команда |
| Финальная вода | `в заключение` | удалить абзац целиком |

**Как проверить:** `wc -l style_guide.md banned.md examples/*.txt` — в выводе по каждому файлу число строк. В `banned.md` их должно быть не меньше 5, в каждом образце — хотя бы 1 (то есть файл не пустой). Числа будут вашими — важен порядок, а не конкретное значение.

## Шаг 2. Соберите промпт и перепишите текст через API
![Иллюстрация к разделу «Шаг 2. Соберите промпт и перепишите текст через API»](https://ai-release.org/guides/img/kak-zastavit-neyroset-pisat-ne-kak-neyroset-prompty-pri-ru-2.jpg)


**Что сделать:** создайте `rewrite.py`, который читает `style_guide.md` и `banned.md`, отправляет их в системном сообщении вместе с `input.txt` и сохраняет ответ в `output.txt`.

**Зачем:** правила в системном сообщении весят больше, чем просьба в пользовательском. Запреты в конце пользовательского текста модель часто «съедает» — проверено на длинных промптах.

```python
import os, json, urllib.request

API_URL = os.environ["LLM_API_URL"]
API_KEY = os.environ["LLM_API_KEY"]
MODEL   = os.environ["LLM_MODEL"]

system = open("style_guide.md", encoding="utf-8").read()
banned = open("banned.md", encoding="utf-8").read()
src    = open("input.txt", encoding="utf-8").read()
samples = ""
for name in sorted(os.listdir("examples")):
    samples += "\n--- Пример моего стиля ---\n" + open(f"examples/{name}", encoding="utf-8").read()

payload = {
    "model": MODEL,
    "messages": [
        {"role": "system", "content": system + samples},
        {"role": "user", "content":
            "Перепиши текст, сохранив все факты и числа. Запрещённые формулировки:\n"
            + banned + "\n\nТЕКСТ:\n" + src},
    ],
    "temperature": 0.4,
}

req = urllib.request.Request(
    API_URL,
    data=json.dumps(payload).encode("utf-8"),
    headers={"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"},
)
with urllib.request.urlopen(req) as r:
    data = json.load(r)

open("output.txt", "w", encoding="utf-8").write(data["choices"][0]["message"]["content"])
print("OK -> output.txt")
```

**Пример запуска:**

```bash
cd ~/style-fix && python3 rewrite.py
```

Ожидаемый вывод на экране: `OK -> output.txt`.

**Почему это работает:** `temperature` управляет случайностью выбора слов — чем ниже значение, тем предсказуемее формулировки; точный диапазон и допустимые значения **сверьте с документацией** провайдера, у части моделей параметр не поддерживается. Примеры в системном сообщении задают ритм фразы, а не только список запретов — модель копирует длину предложений и порядок «факт → пояснение». Если строите ассистента с характером и памятью, пригодятся приёмы из гайда [«Как настроить эмпатичного ИИ-ассистента: системные промпты, RAG и TTS»](https://ai-release.org/guides/kak-nastroit-empatichnogo-ii-assistenta-sistemnye-promp.html?utm_source=tg&utm_medium=channel&utm_campaign=guide_inline&utm_content=guide_to_guide) — там разобрана та же логика «роль + правила + примеры».

**Как проверить:** `test -s output.txt && echo OK` — печатает `OK`, значит файл создан и не пуст. Затем `head -n 3 output.txt` — вы видите начало переписанного текста, а не JSON и не пустую строку.

## Шаг 3. Прогоните автопроверку и примите результат
![Иллюстрация к разделу «Шаг 3. Прогоните автопроверку и примите результат»](https://ai-release.org/guides/img/kak-zastavit-neyroset-pisat-ne-kak-neyroset-prompty-pri-ru-3.jpg)


**Что сделать:** создайте `check_style.py` — он ищет в `output.txt` каждую строку из `banned.md` без учёта регистра и печатает число совпадений.

**Зачем:** глазами вы пропустите половину клише, особенно на втором абзаце. Скрипт даёт одно число, по которому видно, помог промпт или нет.

```python
import pathlib

banned = [w.strip().lower() for w in
          pathlib.Path("banned.md").read_text(encoding="utf-8").splitlines() if w.strip()]
text = pathlib.Path("output.txt").read_text(encoding="utf-8").lower()
hits = [w for w in banned if w in text]
print(f"совпадений: {len(hits)}", hits if hits else "")
```

**Пример запуска:**

```bash
cd ~/style-fix && python3 check_style.py
```

Успех выглядит так: `совпадений: 0`. Если видите `совпадений: 2 ['в современном мире', 'стоит отметить']` — вернитесь в Шаг 2 и перенесите эти два пункта в начало `style_guide.md`, а не в конец `banned.md`.

**Как проверить:** сравните число слов: `wc -w input.txt output.txt`. Переписанный текст обычно короче исходного — если он вырос вдвое, модель добавила пояснений, которых не просили. Затем прочитайте вслух один абзац: спотыкаетесь на конструкции — правьте `style_guide.md`, а не текст руками.

Финальный чек-лист приёмки:
- [ ] `совпадений: 0`
- [ ] ни одно число и название из `input.txt` не потеряно
- [ ] нет абзацев, начинающихся с обобщения
- [ ] текст читается вслух без запинок

Если переписанный текст пойдёт в публичный ассистент, прогоните его через методику [«Как проверить LLM-приложение на джейлбрейки»](https://ai-release.org/guides/kak-proverit-llm-prilozhenie-na-dzheylbreyki-metodika-t.html?utm_source=tg&utm_medium=channel&utm_campaign=guide_inline&utm_content=guide_to_guide) — пользовательский ввод может перебить ваши стилевые правила.

## Возможные проблемы и решения

**Проблема. Стиль не изменился, хотя стоп-лист отправлен**

- Ошибка: `совпадений: 3 ['в современном мире', 'играет важную роль', 'в заключение']`
- Причина: запреты стоят в пользовательском сообщении после длинного текста — модель дочитывает их как «пожелание», а не как правило. Либо в `style_guide.md` больше 10 пунктов и правила конфликтуют.
- Решение: перенесите 2–3 самых частых клише в первые строки `style_guide.md` в виде «Никогда не начинай абзац со слов …», сократите список правил до 5, повторите `python3 rewrite.py && python3 check_style.py`.

**Проблема. Скрипт падает сразу после запуска**

- Ошибка: `KeyError: 'LLM_API_KEY'`
- Причина: переменная задана в другом окне терминала или в `.env`, который никто не читает. `export` действует только в текущей сессии.
- Решение: проверьте `printenv LLM_API_KEY | wc -c` — число должно быть больше 1 (сам ключ не печатайте). Если `0`, снова выполните `export LLM_API_KEY="<ваш-ключ>"` или добавьте строку в `~/.bashrc` и откройте новый терминал.

**Проблема. Ответ не разбирается как JSON**

- Ошибка: `json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)`
- Причина: вместо JSON пришёл HTML или пустое тело — обычно из-за неверного `LLM_API_URL`, редиректа или ошибки авторизации на стороне прокси.
- Решение: добавьте перед `json.load` вывод `print(r.status, data[:300])` и запустите снова. Код `200` — проблема в формате ответа, сверьте путь эндпоинта с документацией; код `401` — ключ, `404` — URL.

## Резюме и следующие шаги
Рабочая схема — три файла (`style_guide.md`, `banned.md`, `examples/`) плюс два скрипта: один переписывает, второй считает совпадения с стоп-листом. Дальше расширяйте `banned.md` по мере того, как замечаете новые клише, и держите число правил в промпте в пределах пяти.

## FAQ

**Как заставить нейросеть писать проще и без воды?**
Задать измеримые правила в системном промпте (длина предложения, активный залог) и список запрещённых формулировок, а результат проверять скриптом по стоп-листу, а не на глаз.

**Почему нейросеть пишет одинаково при каждом запросе?**
Потому что стиль задан только общей формулировкой вроде «пиши естественно». Добавьте 3–5 своих текстов как примеры в системное сообщение — модель начнёт копировать их ритм и длину фраз.

**Сколько примеров текста нужно для few-shot?**
Начните с трёх: два коротких абзаца и один длинный. Если стиль всё ещё «плывёт», добавьте четвёртый — но следите, чтобы примеры были однородными по жанру, иначе модель смешает стили.

**Можно ли убрать канцелярит постобработкой, без повторного запроса?**
Частично: замена по словарю из `banned.md` убирает штампы, но не меняет структуру фраз. Для структуры нужен повторный запрос с исправленным `style_guide.md`.
