Запуск языковых моделей через llama.cpp из Python: полный гайд
Основы работы с llama.cpp в Python
Библиотека llama.cpp предоставляет эффективную реализацию инференса больших языковых моделей на C++ с биндингами для Python через пакет llama-cpp-python. Она позволяет запускать модели формата GGUF на CPU и GPU (CUDA, Metal, Vulkan) с минимальным потреблением ресурсов. Ниже рассмотрены основной способ установки и несколько альтернативных подходов.
Быстрая установка через pip и базовый пример
Самый простой способ начать работу - установить пакет из PyPI (без поддержки GPU) или с поддержкой выбранного бэкенда.
Установка основной версии:
pip install llama-cpp-pythonLlama cpp python (использование llama.cpp в python)
Для поддержки CUDA (Linux):
CMAKE_ARGS="-DLLAMA_CUBLAS=on" pip install llama-cpp-python
Пример загрузки модели и генерации текста:
from llama_cpp import Llama
# Укажите путь к файлу GGUF модели
llm = Llama(model_path="./models/llama-2-7b.Q4_K_M.gguf", n_ctx=2048)
output = llm(
"Какой язык программирования лучше всего подходит для анализа данных?",
max_tokens=100,
temperature=0.7,
echo=False
)
print(output["choices"][0]["text"])
Результат:
Для анализа данных часто используют Python благодаря библиотекам Pandas, NumPy и SciPy. Также популярен R для статистической обработки.
Типичные ошибки:
- ImportError: libllama.so - не найдена динамическая библиотека. Решение: переустановить пакет с соответствующими флагами сборки или установить llama.cpp отдельно.
- ValueError: Model file not found - неверный путь к модели. Проверьте, что файл существует.
- При запуске на ARM Mac без Metal может быть медленная работа. Используйте CMAKE_ARGS="-DLLAMA_METAL=on".
Как собрать llama.cpp из исходников с оптимизациями под конкретное железо?
Иногда требуется максимальная производительность или поддержка нестандартных инструкций (AVX512, AMX). Сборка из исходников даёт полный контроль.
git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp
mkdir build && cd build
cmake .. -DLLAMA_CUDA=ON -DLLAMA_AVX2=ON -DCMAKE_BUILD_TYPE=Release
make -j4
# После сборки установите переменную окружения или скопируйте библиотеку
# Далее установка биндингов из исходников:
pip install --force-reinstall --no-deps llama-cpp-python --no-binary llama-cpp-python
Возможные проблемы:
- Ошибка компиляции из-за отсутствия CMake или компилятора C++17. Установите build-essential.
- Конфликт с ранее установленной версией - используйте виртуальное окружение.
Как загрузить квантованную модель в формате GGUF из локального файла или Hugging Face?
Модели можно загружать напрямую с Hugging Face Hub с помощью llama-cpp-python и huggingface_hub.
from llama_cpp import Llama
from huggingface_hub import hf_hub_download
# Скачать модель TheBloke/Mistral-7B-Instruct-v0.2-GGUF
model_path = hf_hub_download(
repo_id="TheBloke/Mistral-7B-Instruct-v0.2-GGUF",
filename="mistral-7b-instruct-v0.2.Q4_K_M.gguf",
local_dir="./models"
)
llm = Llama(model_path=model_path, n_ctx=4096)
print("Модель загружена:", llm.model_path)
Ошибки:
- OSError: Download failed - проверьте интернет-соединение или укажите правильный repo_id.
- Модель может весить несколько гигабайт, убедитесь, что есть свободное место.
Как управлять параметрами генерации: температура, top_k, top_p, повторные штрафы?
Все параметры передаются в метод __call__ или generate.
output = llm(
"Напиши короткое стихотворение о программировании.",
max_tokens=150,
temperature=0.9, # креативность (0.0 - детерминированно)
top_p=0.85, # nucleus sampling
top_k=40, # количество рассматриваемых токенов
repeat_penalty=1.1, # штраф за повтор
stop=["\n", "."] # стоп-токены
)
Замечания:
- Слишком высокая температура может привести к бессвязному тексту.
- Параметр stop ожидает список строк, а не токенов.
Как обрабатывать несколько запросов последовательно или в пакетном режиме?
Можно передать список промптов в метод create_completion с параметром stream=False.
prompts = ["Расскажи о Python.", "Что такое нейронная сеть?", "Как работает attention?"]
for p in prompts:
response = llm(p, max_tokens=50)
print(f"Промпт: {p}")
print(f"Ответ: {response['choices'][0]['text']}\n")
Пакетная обработка (если модель поддерживает):
# llama-cpp-python поддерживает пакетную обработку через batch_size
responses = llm.create_completion(prompts, max_tokens=50, batch_size=8)
for i, r in enumerate(responses):
print(f"Промпт {i}: {r['choices'][0]['text']}")
Важно: Пакетная обработка доступна только в сборках с поддержкой batching (например, с LLAMA_BATCHING). В стандартной установке может не работать.
Как увеличить контекстное окно модели (n_ctx) и избежать ошибок памяти?
Параметр n_ctx задаётся при создании объекта Llama. Он не может превышать максимальную длину, на которую обучена модель (например, для LLaMA 2 это 4096 токенов).
# Увеличение контекста до 4096 (если модель поддерживает)
llm = Llama(model_path="model.gguf", n_ctx=4096, n_batch=512)
При превышении лимита появится ошибка IndexError: sequence length too long. Для моделей с RoPE можно использовать экстраполяцию, но это не поддерживается напрямую в llama.cpp (требуется пересчёт позиционных кодировок).
Советы по памяти:
- Уменьшите n_batch (по умолчанию 512) - снизит пиковое потребление RAM.
- Используйте квантованные модели (Q4_K_M, Q5_K_M).
- Для GPU следите за VRAM; n_gpu_layers позволяет выгружать часть слоёв на GPU.
Как выполнять инференс с потоковой передачей токенов (streaming)?
Потоковый режим полезен для чат-интерфейсов - каждый токен выводится по мере генерации.
stream = llm(
"Напиши рассказ о роботе.",
max_tokens=200,
stream=True
)
for chunk in stream:
token = chunk["choices"][0]["text"]
print(token, end="", flush=True)
Примечание: В старых версиях stream мог возвращать полные ответы, обновляйте пакет до последней версии.
Расширенные примеры использования llama.cpp в Python
Ниже представлены продвинутые сценарии: работа с токенами, кастомные callback-функции, генерация с фиксированным seed, сравнение скорости разных квантований и использование с многопоточностью.
1. Получение логарифмов вероятностей (logprobs)
from llama_cpp import Llama
llm = Llama(model_path="model.gguf", n_ctx=2048, n_gpu_layers=-1)
output = llm(
"Столица Франции - ",
max_tokens=5,
logprobs=True,
top_logprobs=3
)
choice = output["choices"][0]
print("Текст:", choice["text"])
print("Лог-вероятности:")
for token_logprobs in choice.get("logprobs", {}).get("top_logprobs", []):
print(token_logprobs)
Результат (фрагмент):
Текст: Париж.
Лог-вероятности:
{' Париж': -0.045, ' Лондон': -4.23, ' Берлин': -5.10}
2. Использование callback для отслеживания прогресса
import sys
from llama_cpp import Llama
def progress_callback(progress: float) -> bool:
"""Вызывается на каждом шаге генерации."""
sys.stdout.write(f"\rСгенерировано: {progress*100:.1f}%")
sys.stdout.flush()
return True # верните False, чтобы прервать
llm = Llama(model_path="model.gguf", n_ctx=2048, progress_callback=progress_callback)
response = llm("Расскажи о квантовых вычислениях.", max_tokens=50)
print("\nРезультат:", response["choices"][0]["text"])
3. Генерация с фиксированным seed для воспроизводимости
from llama_cpp import Llama
llm = Llama(model_path="model.gguf", seed=42, n_ctx=1024)
prompt = "2 + 2 = "
output1 = llm(prompt, max_tokens=2, temperature=0.0)
output2 = llm(prompt, max_tokens=2, temperature=0.0)
print("Первый ответ:", output1["choices"][0]["text"])
print("Второй ответ:", output2["choices"][0]["text"])
# Оба вывода будут "4" при seed=42 и temperature=0
4. Извлечение и анализ токенов
llm = Llama(model_path="model.gguf")
tokens = llm.tokenize("Привет, мир!")
print("Токены (ID):", tokens)
print("Декодировано:", llm.detokenize(tokens))
Вывод:
Токены (ID): [1, 20304, 11, 837, 0] Декодировано: b'Привет, мир!'
5. Сравнение скорости генерации для разных квантований
import time
from llama_cpp import Llama
models = {
"Q4_K_M": "llama-2-7b.Q4_K_M.gguf",
"Q8_0": "llama-2-7b.Q8_0.gguf",
"FP16": "llama-2-7b.gguf" # если есть
}
prompt = "Что такое машинное обучение? " * 50 # ~500 токенов
for name, path in models.items():
start = time.time()
llm = Llama(model_path=path, n_ctx=512, n_threads=8)
llm(prompt, max_tokens=50)
elapsed = time.time() - start
print(f"{name}: {elapsed:.2f} сек")
Примечание: Для точного сравнения следует усреднить несколько запусков. Результаты сильно зависят от аппаратного обеспечения.
6. Использование нескольких потоков (threading) для параллельной генерации
import threading
from llama_cpp import Llama
llm = Llama(model_path="model.gguf", n_ctx=1024)
def generate(prompt):
result = llm(prompt, max_tokens=20)
print(f"[{threading.current_thread().name}] {result['choices'][0]['text']}")
t1 = threading.Thread(target=generate, args=("Расскажи о Python",))
t2 = threading.Thread(target=generate, args=("Расскажи о C++",))
t1.start()
t2.start()
t1.join()
t2.join()
Важно: Объект Llama не является потокобезопасным для параллельных вызовов. Для параллельной работы создавайте отдельные экземпляры модели.
7. Интеграция с фреймворком LangChain
from langchain.llms import LlamaCpp
from langchain.prompts import PromptTemplate
from langchain.chains import LLMChain
llm = LlamaCpp(
model_path="model.gguf",
n_ctx=2048,
temperature=0.7,
verbose=True
)
prompt = PromptTemplate(
input_variables=["topic"],
template="Напиши короткое эссе на тему: {topic}."
)
chain = LLMChain(llm=llm, prompt=prompt)
print(chain.run("Будущее нейросетей"))
8. Настройка количества слоёв на GPU (n_gpu_layers) для баланса скорости и памяти
# Поместить 40 слоёв на GPU (если модель имеет 32, то все 32)
llm = Llama(model_path="model.gguf", n_gpu_layers=40, n_ctx=4096)
result = llm("Пример.", max_tokens=10)
print(result["choices"][0]["text"])
Типичная ошибка: CUDA out of memory. Уменьшите n_gpu_layers или n_ctx.