Запуск языковых моделей через llama.cpp из Python: полный гайд

Раздел: Машинное обучение и ИИ -> Интеграция с библиотеками C++

Основы работы с llama.cpp в Python

Библиотека llama.cpp предоставляет эффективную реализацию инференса больших языковых моделей на C++ с биндингами для Python через пакет llama-cpp-python. Она позволяет запускать модели формата GGUF на CPU и GPU (CUDA, Metal, Vulkan) с минимальным потреблением ресурсов. Ниже рассмотрены основной способ установки и несколько альтернативных подходов.

Быстрая установка через pip и базовый пример

Самый простой способ начать работу - установить пакет из PyPI (без поддержки GPU) или с поддержкой выбранного бэкенда.

Установка основной версии:

pip install llama-cpp-python

Llama 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.

Использование llama.cpp в Python - comments

En
Llama cpp python (python)