From 4c6a45e2e8a03a37d933323cbeea9ad31801f7a7 Mon Sep 17 00:00:00 2001 From: roman Date: Thu, 24 Sep 2026 13:22:17 +0500 Subject: [PATCH] =?UTF-8?q?=D0=97=D0=B0=D0=B3=D1=80=D1=83=D0=B7=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D1=84=D0=B0=D0=B9=D0=BB=D1=8B=20=D0=B2=20=C2=AB?= =?UTF-8?q?/=C2=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Поиск и удаление старых файлов в Linux.md | 33 + Тесто (балиш, курник).md | 7 + 🤖 ЛОКАЛЬНЫЙ ИИ-ЭКСПЕРТ ПО БАНКОМАТНОМУ ПО.md | 608 ++++++++++++++++++ 🤖ЛОКАЛЬНЫЙ ИИ-ЭКСПЕРТ ПО БАНКОМАТНОМУ ПО.md | 370 +++++++++++ 4 files changed, 1018 insertions(+) create mode 100644 Поиск и удаление старых файлов в Linux.md create mode 100644 Тесто (балиш, курник).md create mode 100644 🤖 ЛОКАЛЬНЫЙ ИИ-ЭКСПЕРТ ПО БАНКОМАТНОМУ ПО.md create mode 100644 🤖ЛОКАЛЬНЫЙ ИИ-ЭКСПЕРТ ПО БАНКОМАТНОМУ ПО.md diff --git a/Поиск и удаление старых файлов в Linux.md b/Поиск и удаление старых файлов в Linux.md new file mode 100644 index 0000000..d3314d5 --- /dev/null +++ b/Поиск и удаление старых файлов в Linux.md @@ -0,0 +1,33 @@ +#linux + +🔍 Поиск файлов старше 30 дней: + +```sh +find /path/to/directory -type f -mtime +30 +``` + +- -type f — ищем только файлы; +- -mtime +30 — файлы старше 30 дней. + +🗑️ Удаление этих файлов: + +```sh + find /path/to/directory -type f -mtime +30 -delete +``` + +⚠️ Осторожно! Удаление без подтверждения. + +✅ Безопасный вариант с подтверждением: + +```sh +find /path/to/directory -type f -mtime +30 -exec rm -i {} \; +``` + +Будет запрашиваться подтверждение перед удалением. + +🔥 Автоматизация через cron: +Добавляем в crontab -e: + +0 3 * * * find /var/log -type f -mtime +30 -delete + +Очистка логов каждую ночь в 03:00. diff --git a/Тесто (балиш, курник).md b/Тесто (балиш, курник).md new file mode 100644 index 0000000..20b794f --- /dev/null +++ b/Тесто (балиш, курник).md @@ -0,0 +1,7 @@ +- [?] Масло 100 грамм +- [?] Кефир или ряженка 1 стакан +- [?] 2-3 столовые ложки сметаны или майонеза +- [?] 1 яйцо +- [?] Пол чайной ложки соли +- [?] Пол чайной ложки соды +- [?] Мука \ No newline at end of file diff --git a/🤖 ЛОКАЛЬНЫЙ ИИ-ЭКСПЕРТ ПО БАНКОМАТНОМУ ПО.md b/🤖 ЛОКАЛЬНЫЙ ИИ-ЭКСПЕРТ ПО БАНКОМАТНОМУ ПО.md new file mode 100644 index 0000000..e79aae8 --- /dev/null +++ b/🤖 ЛОКАЛЬНЫЙ ИИ-ЭКСПЕРТ ПО БАНКОМАТНОМУ ПО.md @@ -0,0 +1,608 @@ +- **Платформа:** Windows 10/11 + WSL2 (Ubuntu 22.04 / 24.04) +- **Железо:** NVIDIA RTX 3060 Ti (8 ГБ VRAM) +- **Базовая модель для обучения:** Meta Llama 3.1 8B (`unsloth/llama-3.1-8b-Instruct-bnb-4bit`) +- **Рабочая директория:** `C:\ST\aandc\` (внутри WSL2: `/mnt/c/ST/aandc/`) + +--- + +ЧАСТЬ 1. Развертывание среды и проброс GPU в WSL2 + +Шаг 1.1. Базовая установка подсистемы + +Откройте **PowerShell от имени Администратора** на хостовой Windows: + +powershell + +``` +wsl --install +wsl --set-default-version 2 +``` + +Используйте код с осторожностью. + +_Перезагрузите компьютер. При первом запуске терминала Ubuntu задайте логин и пароль._ + +Шаг 1.2. Защита от Out Of Memory (Выделение ресурсов) + +1. В Windows нажмите `Win + R`, введите `%USERPROFILE%` и нажмите Enter. +2. Создайте в этой папке текстовый файл `.wslconfig` (без расширения `.txt`) и вставьте: + +ini + +``` +[wsl2] +memory=16GB # Выделяем минимум 16 ГБ оперативной памяти (или 75% от системной RAM) +swap=8GB # Обязательный файл подкачки для подстраховки при компиляции моделей +localhostForwarding=true +``` + +Используйте код с осторожностью. + +3. Перезапустите WSL в PowerShell: `wsl --shutdown` + +Шаг 1.3. Настройка NVIDIA Container Toolkit + +Запустите терминал **Ubuntu в WSL2** и выполните цепочку команд для чистой настройки проброса видеокарты: + +bash + +``` +sudo apt-get update && sudo apt-get install -y ca-certificates curl gnupg2 + +# Удаляем старые битые кэши и ключи, если они создались +sudo rm -f /etc/apt/sources.list.d/nvidia-container-toolkit.list +sudo rm -f /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg + +# Скачивание официального валидного GPG-ключа NVIDIA +curl -fsSL https://github.io | sudo gpg --dearmor --yes -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg + +# Добавление стабильного репозитория пакетов +curl -s -L https://github.io | \ + sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \ + sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list + +# Обновление списков и установка утилиты сопряжения +sudo apt-get update +sudo apt-get install -y nvidia-container-toolkit +``` + +Используйте код с осторожностью. + +_Для проверки введите `nvidia-smi`. На экране должна появиться таблица вашей видеокарты RTX 3060 Ti._ + +--- + +ЧАСТЬ 2. Установка Ollama и Запуск Базовой Модели + +Шаг 2.1. Установка движка и скачивание Llama 3.1 + +Выполните в терминале WSL2: + +bash + +``` +curl -fsSL https://ollama.com | sh +ollama pull llama3.1 +``` + +Используйте код с осторожностью. + +Шаг 2.2. Фоновый запуск сервера Ollama + +Поскольку менеджер служб `systemd` в WSL часто ограничен, запускайте Ollama напрямую встроенным фоновым процессом Linux: + +bash + +``` +ollama serve > /dev/null 2>&1 & +``` + +Используйте код с осторожностью. + +_(Нажмите Enter, если терминал временно застынет. Проверить статус можно командой `ollama list`)._ + +--- + +ЧАСТЬ 3. Автоматизированная генерация ShareGPT-датасета + +Шаг 3.1. Подготовка файлов в Windows и WSL2 + +1. В Windows создайте папку `C:\ST\aandc\manuals\`. +2. Скопируйте в неё все ваши **71 исходный технический PDF-мануал**. Внутри WSL2 они мгновенно станут доступны по пути `/mnt/c/ST/aandc/manuals/`. +3. В терминале WSL2 установите библиотеки обработки данных (обходя ограничения `PEP 668` системы Ubuntu): + +bash + +``` +pip3 install pypdf requests --break-system-packages +``` + +Используйте код с осторожностью. + +Шаг 3.2. Развертывание отказоустойчивого скрипта `generate_qa.py` + +Создайте файл `/mnt/c/ST/aandc/generate_qa.py` и скопируйте в него этот код. Он очищает текст регулярными выражениями и корректно парсит ответы Ollama, даже если она возвращает одиночный словарь вместо списка: + +python + +``` +import os +import re +import json +import pypdf +import requests + +# === КОНФИГУРАЦИЯ === +MODEL_NAME = "llama3.1:latest" +OLLAMA_URL = "http://localhost:11434/api/generate" +MANUALS_DIR = "/mnt/c/ST/aandc/manuals" +OUTPUT_FILE = "/mnt/c/ST/aandc/aandc_dataset.jsonl" +WINDOW_SIZE = 3 # Размер окна чтения документа (в страницах) + +SYSTEM_PROMPT = ( + "Вы — опытный technical writer и эксперт по банкоматному ПО.\n" + "Изучите предоставленный фрагмент технической документации.\n" + "Создайте от 2 до 4 высококачественных пар 'Вопрос-Ответ' на основе ТОЛЬКО этого текста.\n" + "Вопросы должны быть конкретными (коды ошибок, процедуры калибровки, настройка систем).\n" + "Ответы должны быть глубокими, технически точными, структурированными и без упоминания номеров страниц.\n" + "Формат ответа строго JSON списка ShareGPT:\n" + '[{"conversations": [{"from": "human", "value": "Вопрос"}, {"from": "gpt", "value": "Ответ"}]}]' +) + +def clean_text(text): + """Очистка текста от мусора, номеров страниц и колонтитулов""" + text = re.sub(r'Page \d+ of \d+', '', text, flags=re.IGNORECASE) + text = re.sub(r'^\d+\s*$', '', text, flags=re.MULTILINE) + text = re.sub(r'\n+', '\n', text) + text = re.sub(r' +', ' ', text) + return text.strip() + +def extract_pdf_chunks(pdf_path, window_size=3): + """Динамическое чтение любого PDF файла порциями страниц""" + try: + with open(pdf_path, 'rb') as f: + reader = pypdf.PdfReader(f) + total_pages = len(reader.pages) + + for i in range(0, total_pages, window_size): + chunk_text = "" + for j in range(i, min(i + window_size, total_pages)): + page_text = reader.pages[j].extract_text() + if page_text: + chunk_text += page_text + "\n" + + cleaned = clean_text(chunk_text) + if len(cleaned) > 100: + yield cleaned + except Exception as e: + print(f"Ошибка при чтении файла {os.path.basename(pdf_path)}: {e}") + +def ask_ollama(context): + """Запрос к локальному серверу Ollama за строгим JSON-форматом""" + prompt = f"ДОКУМЕНТАЦИЯ:\n{context}\n\nСгенерируй JSON по инструкции." + payload = { + "model": MODEL_NAME, + "prompt": prompt, + "system": SYSTEM_PROMPT, + "stream": False, + "format": "json" + } + try: + response = requests.post(OLLAMA_URL, json=payload) + if response.status_code == 200: + return response.json().get("response", "") + except Exception as e: + print(f"Ошибка связи с Ollama: {e}") + return None + +def main(): + if not os.path.exists(MANUALS_DIR): + print(f"Ошибка: Папка {MANUALS_DIR} не найдена!") + return + + pdf_files = [f for f in os.listdir(MANUALS_DIR) if f.lower().endswith('.pdf')] + total_files = len(pdf_files) + + if total_files == 0: + print(f"В папке {MANUALS_DIR} не найдено ни одного PDF файла.") + return + + print(f"Найдено файлов для обработки: {total_files}") + print("Старт генерации профессионального датасета...") + + # Файл затирает старую сырую базу 'w' и наполняется построчно (JSON Lines) + with open(OUTPUT_FILE, 'w', encoding='utf-8') as outfile: + for idx, pdf_name in enumerate(pdf_files, 1): + pdf_path = os.path.join(MANUALS_DIR, pdf_name) + print(f"[{idx}/{total_files}] Обработка: {pdf_name}") + + for chunk in extract_pdf_chunks(pdf_path, WINDOW_SIZE): + raw_json = ask_ollama(chunk) + if not raw_json: + continue + + try: + data = json.loads(raw_json) + + # Сценарий 1: Модель вернула список объектов [ {...}, {...} ] + if isinstance(data, list): + for item in data: + if isinstance(item, dict) and "conversations" in item: + outfile.write(json.dumps(item, ensure_ascii=False) + "\n") + outfile.flush() + print(" ✅ Записана карточка (из списка)") + + # Сценарий 2: Модель вернула один одиночный объект { "conversations": [...] } + elif isinstance(data, dict): + if "conversations" in data: + outfile.write(json.dumps(data, ensure_ascii=False) + "\n") + outfile.flush() + print(" ✅ Записана карточка (прямой словарь)") + else: + for key, val in data.items(): + if isinstance(val, list): + for sub_item in val: + if isinstance(sub_item, dict) and "conversations" in sub_item: + outfile.write(json.dumps(sub_item, ensure_ascii=False) + "\n") + outfile.flush() + print(" ✅ Записана карточка (из вложенного ключа)") + except json.JSONDecodeError: + continue + + print(f"\nУспешно! Все файлы обработаны. Новый датасет сохранен в: {OUTPUT_FILE}") + +if __name__ == "__main__": + main() +``` + +Используйте код с осторожностью. + +_Запуск: `python3 /mnt/c/ST/aandc/generate_qa.py`. На выходе сформируется файл на 756 качественных диалогов._ + +--- + +ЧАСТЬ 4. Стабильный Fine-Tuning LoRA на 8 ГБ VRAM + +Для того чтобы обучение гарантированно шло без вылетов по памяти (`RuntimeError по fused cross entropy`), мы используем чистый, промышленный стек **Hugging Face (`transformers` + `peft` + `bitsandbytes`)**. Мы полностью убрали капризные компиляторы Unsloth, исключив любые пики выделения памяти на карте хоста. + +Шаг 4.1. Установка стабильных зависимостей + +Выполните в терминале WSL2: + +bash + +``` +pip install torch torchvision torchaudio --index-url https://pytorch.org --break-system-packages +pip install transformers datasets peft bitsandbytes --break-system-packages +``` + +Используйте код с осторожностью. + +Шаг 4.2. Развертывание «железного» скрипта обучения `train.py` + +Создайте файл `/mnt/c/ST/aandc/train.py` и скопируйте в него этот код: + +python + +``` +import os +import json +import torch +from datasets import Dataset +from transformers import ( + AutoModelForCausalLM, + AutoTokenizer, + BitsAndBytesConfig, + TrainingArguments, + Trainer, + DataCollatorForLanguageModeling +) +from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training + +# === КОНФИГУРАЦИЯ ДЛЯ ГАРАНТИРОВАННОГО СТАРТА НА 8 ГБ VRAM === +MODEL_NAME = "unsloth/llama-3.1-8b-Instruct-bnb-4bit" # Весовая база +max_seq_length = 512 # Идеальный размер контекста для защиты памяти от пиков +DATASET_PATH = "/mnt/c/ST/aandc/aandc_dataset.jsonl" + +# Принудительная очистка видеопамяти +torch.cuda.empty_cache() + +print("--- 1. Конфигурация 4-битного квантования bitsandbytes ---") +bnb_config = BitsAndBytesConfig( + load_in_4bit=True, + bnb_4bit_quant_type="nf4", + bnb_4bit_compute_dtype=torch.float16, + bnb_4bit_use_double_quant=True +) + +print("--- 2. Загрузка модели и токенизатора напрямую через HF ---") +tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME) +tokenizer.pad_token = tokenizer.eos_token + +model = AutoModelForCausalLM.from_pretrained( + MODEL_NAME, + quantization_config=bnb_config, + device_map="auto" +) + +# Подготовка модели к PEFT обучению (стабилизация градиентов k-bit) +model = prepare_model_for_kbit_training(model) + +print("--- 3. Конфигурация LoRA (Чистый PEFT) ---") +peft_config = LoraConfig( + r=16, + lora_alpha=16, + target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"], + lora_dropout=0.05, + bias="none", + task_type="CAUSAL_LM" +) +model = get_peft_model(model, peft_config) + +print("--- 4. Отказоустойчивая валидация и загрузка датасета ---") +valid_dialogues = [] +with open(DATASET_PATH, "r", encoding="utf-8") as f: + for idx, line in enumerate(f, 1): + if not line.strip(): + continue + try: + item = json.loads(line) + if "conversations" not in item or not isinstance(item["conversations"], list): + continue + clean_conv = [] + is_corrupted = False + for msg in item["conversations"]: + # Защита от изменения типов (строка вместо словаря на row 9) + if not isinstance(msg, dict) or "from" not in msg or "value" not in msg: + is_corrupted = True + break + clean_conv.append({ + "from": str(msg["from"]).strip(), + "value": str(msg["value"]).strip() + }) + if not is_corrupted and len(clean_conv) > 0: + valid_dialogues.append({"conversations": clean_conv}) + except json.JSONDecodeError: + continue + +print(f"Успешно загружено чистых диалогов: {len(valid_dialogues)}") +dataset = Dataset.from_list(valid_dialogues) + +# Форматирование и ЯВНАЯ ТОКЕНИЗАЦИЯ строк под формат ролей Llama 3.1 +def tokenize_prompts_func(examples): + conversations = examples["conversations"] + tokenized_inputs = {"input_ids": [], "attention_mask": []} + + for con in conversations: + mapped_conversation = [] + for msg in con: + # Превращаем "human" в "user", "gpt" в "assistant" для шаблона Llama 3.1 + role = "user" if msg["from"] == "human" else "assistant" + mapped_conversation.append({"role": role, "content": msg["value"]}) + + # Применяем Jinja-шаблон чата + text = tokenizer.apply_chat_template(mapped_conversation, tokenize=False, add_generation_prompt=False) + + # Токенизируем текст напрямую с жесткой обрезкой до max_seq_length + tokenized = tokenizer(text, truncation=True, max_length=max_seq_length, padding=False) + tokenized_inputs["input_ids"].append(tokenized["input_ids"]) + tokenized_inputs["attention_mask"].append(tokenized["attention_mask"]) + + return tokenized_inputs + +# Пересобираем датасет в готовые числовые тензоры +dataset = dataset.map(tokenize_prompts_func, batched=True, remove_columns=["conversations"]) + +print("--- 5. Инициализация индустриального Trainer ---") +trainer = Trainer( + model=model, + train_dataset=dataset, + data_collator=DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False), # Сборщик батчей + args=TrainingArguments( + per_device_train_batch_size=1, # Размер батча 1 исключает переполнение VRAM + gradient_accumulation_steps=8, # Накопление шагов (1 * 8 эмулирует реальный батч размера 8) + warmup_steps=5, + max_steps=60, # Обучение на 60 шагах. Для финала: num_train_epochs = 3 + learning_rate=2e-4, + fp16=True, + logging_steps=1, + optim="adamw_8bit", # 8-битный оптимизатор экономит драгоценную VRAM + weight_decay=0.01, + lr_scheduler_type="linear", + seed=3407, + output_dir="outputs", + remove_unused_columns=False + ), +) + +print("--- 6. СТАРТ ТРЕНИРОВКИ (Чистый стек Hugging Face) ---") +trainer.train() +print("--- ТРЕНИРОВКА УСПЕШНО ЗАВЕРШЕНА ---") + +print("--- 7. Сохранение LoRA адаптеров ---") +model.save_pretrained("/mnt/c/ST/aandc/aandc_lora_model") +tokenizer.save_pretrained("/mnt/c/ST/aandc/aandc_lora_model") +print("Обученные адаптеры сохранены в папку aandc_lora_model!") +``` + +Используйте код с осторожностью. + +Шаг 4.3. Выполнение тренировки + +Перед запуском обязательно **выгрузите Ollama из памяти**, чтобы освободить видеокарту хоста: + +bash + +``` +pkill -f ollama +``` + +Используйте код с осторожностью. + +Запустите скрипт: + +bash + +``` +python3 /mnt/c/ST/aandc/train.py +``` + +Используйте код с осторожностью. + +_Процесс займет около 2 часов. Значение `loss` будет плавно падать, фиксируя технические знания в весах LoRA._ + +--- + +ЧАСТЬ 5. Слияние Модели в Совместимый Монолит + +Поскольку базовая модель `bnb-4bit` аппаратно заблокирована от обратной распаковки на CPU через `llama.cpp`, мы используем официальный индустриальный метод: **накатим ваши адаптеры на открытую, чистую базовую модель Llama 3.1 8B в формате `float16`** и запишем один полноценный монолитный файл. + +Шаг 5.1. Запуск скрипта слияния (Merge & Unload) + +Запустите интерактивный Python в терминале WSL2: + +bash + +``` +python3 +``` + +Используйте код с осторожностью. + +Вставьте этот код (он скачает чистую базу от Unsloth и объединит её с вашими адаптерами): + +python + +``` +import torch +from transformers import AutoModelForCausalLM, AutoTokenizer +from peft import PeftModel + +base_model_path = "unsloth/llama-3.1-8b-Instruct" +lora_path = "/mnt/c/ST/aandc/aandc_lora_model" +output_path = "/mnt/c/ST/aandc/atm_expert_fused_clean" + +print("1. Загрузка открытой базовой модели Llama 3.1 (float16)...") +base_model = AutoModelForCausalLM.from_pretrained(base_model_path, torch_dtype=torch.bfloat16, device_map="cpu") +tokenizer = AutoTokenizer.from_pretrained(base_model_path) + +print("2. Наложение обученных LoRA весов...") +model = PeftModel.from_pretrained(base_model, lora_path) + +print("3. Слияние матриц в единый монолит...") +model = model.merge_and_unload() + +print("4. Сохранение финальной совместимой модели...") +model.save_pretrained(output_path, safe_serialization=True) +tokenizer.save_pretrained(output_path) + +print("--- СЛИЯНИЕ УСПЕШНО ЗАВЕРШЕНО ---") +exit() +``` + +Используйте код с осторожностью. + +_После завершения в директории `C:\ST\aandc\atm_expert_fused_clean\` появится полноценная, совместимая с Ollama модель._ + +--- + +ЧАСТЬ 6. Сборка и Запуск Финального ИИ-Эксперта + +Шаг 6.1. Настройка конфигурационного файла `Modelfile` + +Перепишите ваш `Modelfile`, чтобы Ollama прочитала готовую монолитную папку, выполнив в консоли команду: + +bash + +``` +cat << 'EOF' > /mnt/c/ST/aandc/Modelfile +# Ссылка на созданную монолитную папку +FROM /mnt/c/ST/aandc/atm_expert_fused_clean + +TEMPLATE """{{ if .System }}<|start_header_id|>system<|end_header_id|> +{{ .System }}<|eot_id|>{{ end }}{{ if .Prompt }}<|start_header_id|>user<|end_header_id|> +{{ .Prompt }}<|eot_id|>{{ end }}<|start_header_id|>assistant<|end_header_id|> +{{ .Response }}<|eot_id|>""" + +SYSTEM "Вы — специализированный локальный ИИ-эксперт по банкоматному ПО. Вы отвечаете строго на основе технической документации, четко, структурированно, используя точные инженерные термины и коды ошибок." +EOF +``` + +Используйте код с осторожностью. + +Шаг 6.2. Компиляция модели внутри Ollama + +Запустите сервер Ollama обратно в фоне и выполните сборку: + +bash + +``` +ollama serve > /dev/null 2>&1 & +cd /mnt/c/ST/aandc/ +ollama create atm_expert -f ./Modelfile +``` + +Используйте код с осторожностью. + +_Ollama за секунды скопирует компоненты, переварит типы данных и напишет долгожданное `success`._ + +Шаг 6.3. Интерактивный запуск + +Входите в чат с готовым экспертом: + +bash + +``` +ollama run atm_expert +``` + +Используйте код с осторожностью. + +_Модель будет отвечать глубоко, инженерно точно, без колонтитулов и «каши». Выход из чата — команда `/exit`._ + +--- + +ЧАСТЬ 7. Автономный Перенос Эксперта на Другой ПК + +Поскольку модель собрана в монолит, перенос на любой другой компьютер (даже полностью отключенный от интернета) занимает ровно 1 минуту. + +1. **Экспорт в GGUF-файл на текущем ПК:** + Выполните в терминале WSL2 команду экспорта: + + bash + + ``` + ollama show atm_expert --modelfile > /mnt/c/ST/aandc/atm_expert_final.gguf + ``` + + Используйте код с осторожностью. + + _Заберите получившийся файл `atm_expert_final.gguf` (размером около 4.7 ГБ) на флешку._ +2. **Подготовка целевого ПК:** + Установите чистую Ollama на новый компьютер (скачав десктопный установщик для Windows или Mac с официального сайта ollama.com). +3. **Импорт модели на новом месте:** + Положите файл `atm_expert_final.gguf` в любую папку на новом ПК (например, `C:\ATM_AI\`). Создайте рядом текстовый файл `Modelfile` со следующим содержимым: + + dockerfile + + ``` + FROM ./atm_expert_final.gguf + SYSTEM "Вы — специализированный локальный ИИ-эксперт по банкоматному ПО. Вы отвечаете строго на основе технической документации, четко, структурированно, используя точные инженерные термины и коды ошибок." + ``` + + Используйте код с осторожностью. + + Откройте обычную командную строку Windows (cmd или PowerShell) в этой папке и зарегистрируйте модель: + + powershell + + ``` + cd C:\ATM_AI\ + ollama create atm_expert -f ./Modelfile + ``` + + Используйте код с осторожностью. + +4. **Запуск:** Модель готова отвечать на новом ПК по стандартной команде: `ollama run atm_expert`. Если на целевом ПК нет видеокарты, обеспечьте ему минимум **16 ГБ оперативной памяти (RAM)** — Ollama автоматически и без сбоев переключит вычисления на процессор. + +--- \ No newline at end of file diff --git a/🤖ЛОКАЛЬНЫЙ ИИ-ЭКСПЕРТ ПО БАНКОМАТНОМУ ПО.md b/🤖ЛОКАЛЬНЫЙ ИИ-ЭКСПЕРТ ПО БАНКОМАТНОМУ ПО.md new file mode 100644 index 0000000..e45190f --- /dev/null +++ b/🤖ЛОКАЛЬНЫЙ ИИ-ЭКСПЕРТ ПО БАНКОМАТНОМУ ПО.md @@ -0,0 +1,370 @@ +Обновленная версия, Не проверена +- **Платформа:** Windows 10/11 + WSL2 (Ubuntu 22.04 / 24.04) +- **Железо:** NVIDIA RTX 3060 Ti (8 ГБ VRAM) +- **Базовая модель:** Meta Llama 3.1 8B +- **Рабочая директория:** `C:\ST\aandc\` (в WSL2: `/mnt/c/ST/aandc/`) + + +ЧАСТЬ 1. Развертывание среды и проброс GPU в WSL2 + +1.1. Базовая установка подсистемы + +Откройте **PowerShell от имени Администратора** на Windows: + +powershell + +``` +wsl --install +wsl --set-default-version 2 +``` + +Используйте код с осторожностью. + +_Перезагрузите ПК. В терминале Ubuntu задайте логин и пароль._ + +1.2. Выделение системных ресурсов (Защита от Out Of Memory) + +1. В Windows нажмите `Win + R`, введите `%USERPROFILE%` и нажмите Enter. +2. Создайте файл `.wslconfig` и вставьте параметры: + +ini + +``` +[wsl2] +memory=16GB +swap=8GB +localhostForwarding=true +``` + +Используйте код с осторожностью. + +3. Перезапустите WSL в PowerShell: `wsl --shutdown` + +1.3. Инсталляция NVIDIA Container Toolkit (Проброс графического ядра) + +Запустите терминал **Ubuntu в WSL2**: + +bash + +``` +sudo apt-get update && sudo apt-get install -y ca-certificates curl gnupg2 + +# Скачивание официального GPG-ключа +curl -fsSL https://github.io | sudo gpg --dearmor --yes -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg + +# Добавление официального репозитория пакетов +curl -s -L https://github.io | \ + sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \ + sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list + +sudo apt-get update && sudo apt-get install -y nvidia-container-toolkit +``` + +Используйте код с осторожностью. + +_Проверить сопряжение: команда `nvidia-smi` должна вывести таблицу с вашей RTX 3060 Ti._ + +--- + +ЧАСТЬ 2. Установка Ollama и Локальный Запуск + +2.1. Установка движка и скачивание модели (в терминале WSL2) + +bash + +``` +curl -fsSL https://ollama.com | sh +ollama pull llama3.1 +``` + +Используйте код с осторожностью. + +2.2. Фоновый запуск сервера Ollama в WSL2 + +bash + +``` +ollama serve > /dev/null 2>&1 & +``` + +Используйте код с осторожностью. + +_(Нажмите Enter, если терминал временно застынет. Проверить доступность: `ollama list`)._ + +--- + +ЧАСТЬ 3. Автоматизированная генерация ShareGPT-датасета + +3.1. Подготовка папок и Python + +В Windows скопируйте все **71 технический PDF-мануал** в папку `C:\ST\aandc\manuals\`. +В терминале WSL2 установите библиотеки (обход защиты `PEP 668`): + +bash + +``` +pip3 install pypdf requests --break-system-packages +``` + +Используйте код с осторожностью. + +3.2. Создание интеллектуального генератора `generate_qa.py` + +Создайте файл `/mnt/c/ST/aandc/generate_qa.py`: + +python + +``` +import os, re, json, pypdf, requests + +MODEL_NAME = "llama3.1:latest" +OLLAMA_URL = "http://localhost:11434/api/generate" +MANUALS_DIR = "/mnt/c/ST/aandc/manuals" +OUTPUT_FILE = "/mnt/c/ST/aandc/aandc_dataset.jsonl" +WINDOW_SIZE = 3 + +SYSTEM_PROMPT = ( + "Вы — опытный technical writer и эксперт по банкоматному ПО.\n" + "Изучите предоставленный текст. Создайте от 2 до 4 высококачественных пар 'Вопрос-Ответ'.\n" + "Ответы должны быть глубокими, технически точными, без упоминания номеров страниц.\n" + "Формат ответа строго JSON: [{\"conversations\": [{\"from\": \"human\", \"value\": \"Вопрос\"}, {\"from\": \"gpt\", \"value\": \"Ответ\"}]}]" +) + +def clean_text(text): + text = re.sub(r'Page \d+ of \d+', '', text, flags=re.IGNORECASE) + text = re.sub(r'^\d+\s*$', '', text, flags=re.MULTILINE) + return re.sub(r'\n+', '\n', text).strip() + +def extract_pdf_chunks(pdf_path, window_size=3): + try: + with open(pdf_path, 'rb') as f: + reader = pypdf.PdfReader(f) + for i in range(0, len(reader.pages), window_size): + chunk_text = "".join([reader.pages[j].extract_text() or "" for j in range(i, min(i + window_size, len(reader.pages)))]) + cleaned = clean_text(chunk_text) + if len(cleaned) > 100: yield cleaned + except Exception as e: print(f"Ошибка чтения {os.path.basename(pdf_path)}: {e}") + +def ask_ollama(context): + payload = {"model": MODEL_NAME, "prompt": f"ДОКУМЕНТАЦИЯ:\n{context}\n\nСгенерируй JSON.", "system": SYSTEM_PROMPT, "stream": False, "format": "json"} + try: + response = requests.post(OLLAMA_URL, json=payload) + if response.status_code == 200: return response.json().get("response", "") + except: pass + return None + +def main(): + pdf_files = [f for f in os.listdir(MANUALS_DIR) if f.lower().endswith('.pdf')] + print(f"Найдено файлов: {len(pdf_files)}. Старт генерации...") + + with open(OUTPUT_FILE, 'w', encoding='utf-8') as outfile: + for idx, pdf_name in enumerate(pdf_files, 1): + print(f"[{idx}/{len(pdf_files)}] Обработка: {pdf_name}") + for chunk in extract_pdf_chunks(os.path.join(MANUALS_DIR, pdf_name), WINDOW_SIZE): + raw_json = ask_ollama(chunk) + if not raw_json: continue + try: + data = json.loads(raw_json) + # Всеядный парсер: обрабатывает и массивы, и прямые словари + items = data if isinstance(data, list) else [data] if isinstance(data, dict) and "conversations" in data else data.values() if isinstance(data, dict) else [] + for item in items: + if isinstance(item, dict) and "conversations" in item: + outfile.write(json.dumps(item, ensure_ascii=False) + "\n") + outfile.flush() + except: continue + print("Датасет успешно сохранен!") + +if __name__ == "__main__": main() +``` + +Используйте код с осторожностью. + +_Запуск: `python3 /mnt/c/ST/aandc/generate_qa.py`. Сформируется чистый файл `aandc_dataset.jsonl` на 756 диалогов._ + +--- + +ЧАСТЬ 4. Индустриальный Fine-Tuning на 8 ГБ VRAM + +Для обхода аппаратных ограничений памяти Triton-ядер мы используем чистый, надежный стек **Hugging Face (`peft` + `bitsandbytes` + `transformers`)** в режиме 4-битного квантования. + +4.1. Установка стабильного окружения + +bash + +``` +pip install torch torchvision torchaudio --index-url https://pytorch.org --break-system-packages +pip install transformers datasets peft bitsandbytes trl --break-system-packages +``` + +Используйте код с осторожностью. + +4.2. Развертывание «железного» скрипта обучения `train.py` + +Создайте файл `/mnt/c/ST/aandc/train.py` (выполняется прямо сейчас): + +python + +``` +import os, json, torch +from datasets import Dataset +from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig, TrainingArguments, Trainer, DataCollatorForLanguageModeling +from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training + +MODEL_NAME = "unsloth/llama-3.1-8b-Instruct-bnb-4bit" +max_seq_length = 512 # Идеальный размер контекста для защиты 8 ГБ VRAM от пиков +DATASET_PATH = "/mnt/c/ST/aandc/aandc_dataset.jsonl" + +torch.cuda.empty_cache() + +print("--- 1. Конфигурация 4-бит NF4 ---") +bnb_config = BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_quant_type="nf4", bnb_4bit_compute_dtype=torch.float16, bnb_4bit_use_double_quant=True) + +print("--- 2. Загрузка модели через HF ---") +tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME) +tokenizer.pad_token = tokenizer.eos_token +model = AutoModelForCausalLM.from_pretrained(MODEL_NAME, quantization_config=bnb_config, device_map="auto") +model = prepare_model_for_kbit_training(model) + +print("--- 3. Настройка LoRA параметров ---") +peft_config = LoraConfig(r=16, lora_alpha=16, target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"], lora_dropout=0.05, bias="none", task_type="CAUSAL_LM") +model = get_peft_model(model, peft_config) + +print("--- 4. Валидация и Токенизация датасета ---") +valid_dialogues = [] +with open(DATASET_PATH, "r", encoding="utf-8") as f: + for line in f: + if not line.strip(): continue + try: + item = json.loads(line) + if "conversations" in item and isinstance(item["conversations"], list): + valid_dialogues.append({"conversations": item["conversations"]}) + except: continue + +dataset = Dataset.from_list(valid_dialogues) + +def tokenize_prompts_func(examples): + tokenized_inputs = {"input_ids": [], "attention_mask": []} + for con in examples["conversations"]: + mapped = [{"role": "user" if m["from"] == "human" else "assistant", "content": m["value"]} for m in con] + text = tokenizer.apply_chat_template(mapped, tokenize=False, add_generation_prompt=False) + tokenized = tokenizer(text, truncation=True, max_length=max_seq_length, padding=False) + tokenized_inputs["input_ids"].append(tokenized["input_ids"]) + tokenized_inputs["attention_mask"].append(tokenized["attention_mask"]) + return tokenized_inputs + +dataset = dataset.map(tokenize_prompts_func, batched=True, remove_columns=["conversations"]) + +print("--- 5. Запуск неубиваемого Trainer ---") +trainer = Trainer( + model=model, train_dataset=dataset, + data_collator=DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False), + args=TrainingArguments( + per_device_train_batch_size=1, gradient_accumulation_steps=8, + warmup_steps=5, max_steps=60, learning_rate=2e-4, fp16=True, logging_steps=1, + optim="adamw_8bit", weight_decay=0.01, lr_scheduler_type="linear", + seed=3407, output_dir="outputs", remove_unused_columns=False + ), +) +trainer.train() +print("--- ТРЕНИРОВКА УСПЕШНО ЗАВЕРШЕНА ---") + +model.save_pretrained("/mnt/c/ST/aandc/aandc_lora_model") +tokenizer.save_pretrained("/mnt/c/ST/aandc/aandc_lora_model") +print("Адаптеры сохранены!") +``` + +Используйте код с осторожностью. + +_Запуск: выгрузите Ollama (`pkill -f ollama`) для очистки VRAM и введите `python3 /mnt/c/ST/aandc/train.py`._ + +--- + +ЧАСТЬ 5. Экспорт адаптеров и Сборка модели для Ollama + +После завершения обучения у вас есть базовая модель и папка обученных LoRA-адаптеров `aandc_lora_model`. Переведём их в единый формат `.gguf`. + +5.1. Скачивание утилиты конвертации `llama.cpp` + +bash + +``` +cd /mnt/c/ST/aandc/ +git clone https://github.com +pip3 install -r llama.cpp/requirements.txt --break-system-packages +``` + +Используйте код с осторожностью. + +5.2. Слияние и Квантование (Merge & Quantize) + +Мы берем обученные веса LoRA и упаковываем их в единый 4-битный файл, который мгновенно зачитает любая система: + +bash + +``` +# Конвертируем веса адаптеров LoRA в формат GGUF +python3 llama.cpp/convert_hf_to_gguf.py /mnt/c/ST/aandc/aandc_lora_model/ --outfile atm_expert_q4.gguf +``` + +Используйте код с осторожностью. + +5.3. Настройка `Modelfile` + +Создайте текстовый файл `/mnt/c/ST/aandc/Modelfile`: + +dockerfile + +``` +FROM ./atm_expert_q4.gguf + +TEMPLATE """{{ if .System }}<|start_header_id|>system<|end_header_id|> + +{{ .System }}<|eot_id|>{{ end }}{{ if .Prompt }}<|start_header_id|>user<|end_header_id|> + +{{ .Prompt }}<|eot_id|>{{ end }}<|start_header_id|>assistant<|end_header_id|> + +{{ .Response }}<|eot_id|>""" + +SYSTEM "Вы — специализированный локальный ИИ-эксперт по банкоматному ПО. Вы отвечаете строго на основе технической документации, без «каши», четко, структурированно, используя инженерные термины." +``` + +Используйте код с осторожностью. + +5.4. Регистрация Эксперта + +bash + +``` +# Поднимаем сервер заново +ollama serve > /dev/null 2>&1 & + +# Регистрируем финальную модель +ollama create atm_expert -f /mnt/c/ST/aandc/Modelfile +``` + +Используйте код с осторожностью. + +_Проверка работоспособности: `ollama run atm_expert`_. + +--- + +ЧАСТЬ 6. Автономный перенос модели на другой ПК + +Благодаря архитектуре `.gguf`, готовый эксперт полностью автономен и не требует CUDA, Python или Linux на целевом ПК. + +1. **Копирование:** Заберите с флешки два файла: `atm_expert_q4.gguf` и `Modelfile`. +2. **Установка Ollama:** На целевом ПК (Windows, Mac или Linux) поставьте чистую Ollama с официального сайта ollama.com. +3. **Импорт:** Положите файлы в любую папку (например, `C:\ATM_AI\`), откройте командную строку Windows (cmd/PowerShell) в этой папке и выполните: + +bash + +``` +cd C:\ATM_AI\ +ollama create atm_expert -f Modelfile +``` + +Используйте код с осторожностью. + +4. **Работа:** Модель готова к эксплуатации без интернета по команде `ollama run atm_expert`. + +--- \ No newline at end of file