How to Integrate llama.cpp with Python Applications Using llama-cpp-python

You can integrate llama.cpp with Python applications by installing the llama-cpp-python package, which uses pybind11 to expose the native C API from include/llama-cpp.h directly to Python, allowing you to load GGUF models and run inference with identical performance to the C++ CLI.

The llama-cpp-python library provides a zero-copy bridge between Python and the ggml-org/llama.cpp inference engine. By binding to the same libllama shared library used by the native llama-cli tool, it ensures that any optimization—whether Metal on macOS, CUDA on Linux, or Vulkan on Windows—works identically from Python without rewriting model loading or sampling logic.

Architecture Overview: How llama-cpp-python Bridges C++ and Python

The integration relies on a thin pybind11 wrapper that maps Python objects directly to the C structs defined in include/llama-cpp.h.


+-------------------+          +-----------------------+          +-------------------+
|   Python code     |  pybind11|  llama-cpp-python     |   C API  |   llama.cpp core  |
| (llama_cpp.*)     | <------> | (C++ wrapper)         | <------> | (src/llama-*.cpp) |
+-------------------+          +-----------------------+          +-------------------+

When you instantiate Llama(model_path=...) in Python, the binding invokes llama_init_from_file (defined in src/llama-model.h and implemented in src/llama.cpp). Subsequent calls to llm(prompt, ...) trigger llama_new_context (from src/llama-context.h) and the generation loop in src/llama.cpp, which handles KV cache management and token sampling via src/llama-sampler.cpp.

Installation and Backend Configuration

Install the package via pip. The wheel bundles a pre-compiled libllama for your platform, but you can also build from source to enable specific backends.


# CPU-only installation

pip install llama-cpp-python

# Installation with CUDA support (Linux/Windows)

CMAKE_ARGS="-DLLAMA_CUDA=on" pip install llama-cpp-python --force-reinstall --no-cache-dir

# Installation with Metal support (macOS)

CMAKE_ARGS="-DLLAMA_METAL=on" pip install llama-cpp-python --force-reinstall --no-cache-dir

The CMAKE_ARGS mirror the flags in the root CMakeLists.txt of llama.cpp, ensuring the Python package links against the same GPU-accelerated backends as the native CLI.

Loading and Running Models: Core Integration Patterns

Basic Text Completion

Load a GGUF model and generate text using the high-level Llama class. This maps to llama_init_from_file and the llama_decode loop in src/llama.cpp.

from llama_cpp import Llama

# Initialize model (CPU example)

llm = Llama(
    model_path="models/gemma-2b-it-q4_0.gguf",
    n_threads=8,
    n_gpu_layers=0,  # Increase to offload layers to GPU

)

prompt = "Write a haiku about sunrise."
output = llm(
    prompt,
    max_tokens=64,
    temperature=0.7,
    top_k=40,
    stop=["\n\n"]
)

print(output["choices"][0]["text"])

The n_gpu_layers parameter controls how many transformer layers are offloaded to the GPU via the backend-specific code in src/llama.cpp (CUDA, Metal, or Vulkan).

Real-Time Streaming Generation

For interactive applications, enable streaming to receive tokens as they are generated. The Python generator wraps the incremental decoding logic found in src/llama-context.h.

from llama_cpp import Llama

llm = Llama("models/phi-2.gguf", n_gpu_layers=1)

# Stream tokens one by one

for token in llm("Explain quantum entanglement in simple terms.", stream=True):
    print(token["choices"][0]["text"], end="", flush=True)

Each iteration calls llama_decode with the new token ID and updates the KV cache, allowing the Python loop to yield results without waiting for the full sequence to complete.

Chat-Formatted Conversations

Use the chat completion API to handle system prompts and message formatting. The chat_format parameter applies templates defined in src/llama-chat.cpp.

from llama_cpp import Llama

chat = Llama(
    model_path="models/llama3-8b-q4_0.gguf",
    chat_format="chatml",  # Applies <|system|>, <|user|> tokens

    n_gpu_layers=2,
)

response = chat.create_chat_completion(
    messages=[
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "What is the capital of France?"},
    ],
    temperature=0.2,
)

print(response["choices"][0]["message"]["content"])

The chat_format string maps to internal templates that prepend the appropriate control tokens before the text reaches the llama_decode function.

Embedding Extraction

Extract vector embeddings by enabling embedding mode. This sets llama_context_params.embeddings = true in src/llama-context.h and calls llama_encode instead of the autoregressive llama_decode.

from llama_cpp import Llama

embedder = Llama(
    "models/mistral-embed-q8_0.gguf",
    n_gpu_layers=1,
    embedding=True,  # Critical: enables encoding mode

)

emb = embedder.embed("The quick brown fox jumps over the lazy dog")
print("Embedding shape:", len(emb["embedding"]))

In this mode, the model processes the prompt in a single forward pass without sampling, returning the hidden state from the final layer as defined in src/llama.cpp.

Advanced Configuration: Backend Selection and Low-Level Controls

The Python wrapper exposes the same parameters used by the native CLI, defined in llama_context_params and llama_model_params from include/llama-cpp.h.

  • GPU Offloading: n_gpu_layers maps to the C++ backend logic in src/llama.cpp that splits computation between CPU and GPU (CUDA, Metal, or Vulkan).
  • Threading: n_threads controls the number of BLAS/CPU threads used by GGML operations in src/llama.cpp.
  • Grammar Constraints: Pass a GBNF grammar string to constrain output format; the parser is implemented in src/llama-grammar.h and invoked during sampling in src/llama-sampler.cpp.
  • Custom Sampling: Access logits directly via Llama.eval() and implement custom sampling strategies using the token ID arrays returned from src/llama-context.h.

Key Source Files and API Contracts

Understanding these files helps debug integration issues or extend the Python API with new C-level features.

File Purpose
include/llama-cpp.h Public C API header exposing llama_init, llama_new_context, llama_decode, and parameter structs.
src/llama.cpp Core inference implementation including the generation loop, KV cache management, and backend dispatch (CPU/GPU).
src/llama-context.h Context creation, parameter validation (llama_context_params), and streaming state management.
src/llama-model.h Model loading, GGUF parsing, and quantization handling.
src/llama-sampler.cpp Sampling algorithms (greedy, top-k, nucleus) exposed via the C API.
src/llama-grammar.h Grammar-constrained decoding for structured output.
src/llama-chat.cpp Chat template formatting logic used when chat_format is specified.
CMakeLists.txt Build configuration defining backend options (CUDA, Metal, Vulkan) that must match between the native library and Python wheel.

Summary

  • llama-cpp-python provides a zero-copy Python binding to llama.cpp via pybind11, exposing the C API from include/llama-cpp.h directly to Python.
  • You can load GGUF models, configure GPU/CPU backends, and run inference using the same parameters as the native llama-cli tool.
  • The wrapper supports streaming generation, chat-formatted conversations (via templates in src/llama-chat.cpp), and embedding extraction by setting embedding=True.
  • Advanced features like grammar constraints and custom sampling map directly to src/llama-grammar.h and src/llama-sampler.cpp.

Frequently Asked Questions

How do I enable GPU acceleration when using llama-cpp-python?

Set the n_gpu_layers parameter when instantiating the Llama class to offload transformer layers to your GPU. For CUDA or Metal support, install the package with the appropriate CMAKE_ARGS environment variable (e.g., CMAKE_ARGS="-DLLAMA_CUDA=on" for CUDA) to ensure the underlying libllama binary includes the backend code from src/llama.cpp.

What is the difference between the standard completion API and the chat completion API in llama-cpp-python?

The standard completion API (Llama.__call__ or Llama.create_completion) feeds raw text directly to the model's llama_decode function. The chat completion API (Llama.create_chat_completion) formats messages using templates defined in src/llama-chat.cpp (such as ChatML or Llama-2 chat formats) before tokenization, ensuring the model receives properly structured conversational input.

Can I use llama-cpp-python to extract embeddings instead of generating text?

Yes. Set embedding=True when initializing the Llama instance. This configures the underlying context parameters (llama_context_params.embeddings = true in src/llama-context.h) and uses llama_encode instead of the autoregressive llama_decode to return hidden state vectors from the final layer without sampling tokens.

How does llama-cpp-python handle streaming generation?

When you pass stream=True to the generation methods, the Python wrapper returns a generator that yields tokens incrementally. Internally, this calls llama_decode for each new token and updates the KV cache (managed in src/llama-context.h), allowing Python to receive and display output in real-time without waiting for the full sequence to complete.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →