はい、承知いたしました。llama-cpp-python
の内部構造や開発に関心のある方向けに、開発者ドキュメントを作成します。
llama-cpp-python
は、C++ で実装された高性能な LLM 推論ライブラリ llama.cpp
の Python バインディングです。主な目的は、llama.cpp
の持つ高速な CPU/GPU 推論能力、メモリ効率(特に量子化モデル)、そして豊富な機能を、Python 開発者が容易に利用できるようにすることです。
主な設計目標:
- Pythonic なインターフェース: C++ API をラップし、直感的で使いやすい Python クラスとメソッドを提供します。
- パフォーマンス:
llama.cpp
のパフォーマンスを可能な限り引き出せるように、ctypes
を介した効率的な連携を目指します。 - 機能網羅: テキスト生成(補完、チャット)、埋め込み、トークナイズ、KV キャッシュ管理、グラマー制約、マルチモーダル (LLaVA)、LoRA 適用など、
llama.cpp
の主要機能をサポートします。 - OpenAI 互換性: 特にサーバー機能において、OpenAI API と互換性のあるインターフェースを提供し、既存のエコシステムとの連携を容易にします。
- 拡張性: 新しいチャットフォーマットやカスタムトークナイザなどを追加しやすい構造を目指します。
llama-cpp-python
は、いくつかのレイヤーで構成されています。
graph TD
A[User Python Code: examples/high_level_api] --> B[Llama class: llama.py]
B --> C[Llama Internals: LlamaModel, LlamaContext, LlamaBatch, LlamaSampler _internals.py]
C --> D[ctypes Bindings: llama_cpp.py]
D --> E[libllama Compiled C++ Library]
F[User Python Code: FastAPI Client] --> G[FastAPI Endpoints: server/app.py]
G --> H[LlamaProxy: server/model.py]
H --> B
I[Chat Formatting Logic] --> J[llama_chat_format.py]
B --> J
G --> J
K[Tokenizer Logic] --> L[llama_tokenizer.py]
B --> L
M[Grammar Logic] --> N[llama_grammar.py]
B --> N
J --> N
O[LLaVA Logic] --> P[ctypes Bindings: llava_cpp.py]
P --> Q[libllava Compiled C++ Library]
J --> Pz
libllama
/libllava
(C++ Core):llama.cpp
(およびllava.cpp
) をコンパイルして生成される共有ライブラリ (.so
,.dylib
,.dll
)。- 実際のモデル読み込み、推論計算 (Transformer レイヤー、KV キャッシュ管理)、トークナイズ、サンプリングなどの低レベルな処理を担当します。
- ハードウェアアクセラレーション (BLAS, Metal, CUDA, ROCm) を活用します。
llama_cpp.py
/llava_cpp.py
(CTypes Bindings):- Python の標準ライブラリ
ctypes
を使用して、libllama
/libllava
が公開している C API (関数、構造体、定数) を Python から呼び出せるようにします。 - C のデータ型と Python のデータ型間の変換を行います。
- 共有ライブラリのロード (
_ctypes_extensions.py
) も担当します。
- Python の標準ライブラリ
_internals.py
(Low-level Python Wrapper):- C API を直接呼び出すよりも少し扱いやすい Python クラス (
LlamaModel
,LlamaContext
,LlamaBatch
,LlamaSampler
など) を提供します。 - C ポインタや構造体のライフサイクル管理(例:
contextlib.closing
を使ったリソース解放)を部分的に行います。 - 主に
Llama
クラスの内部実装で使用されますが、より低レベルな制御が必要な場合に直接利用することも可能です。
- C API を直接呼び出すよりも少し扱いやすい Python クラス (
llama.py
(High-level API -Llama
class):- ユーザーが主に直接利用するクラスです。
- モデルのロード、コンテキストの作成、トークナイズ/デトークナイズ、テキスト生成 (
__call__
,create_completion
,create_chat_completion
)、埋め込み生成 (create_embedding
)、状態管理 (save_state
,load_state
) などを抽象化されたメソッドとして提供します。 - 内部で
_internals.py
のクラスやllama_cpp.py
の関数を呼び出します。 - KV キャッシュの管理(プレフィックスマッチングなど)も行います。
- Supporting Modules (
llama_chat_format.py
,llama_tokenizer.py
,llama_grammar.py
など):llama_chat_format.py
: 様々なチャットテンプレートを処理し、OpenAI 形式のチャット補完を実現します (Jinja2 使用)。llama_tokenizer.py
: トークナイザの抽象インターフェースと、llama.cpp
組み込みトークナイザや Hugging Face Tokenizers を使うための実装を提供します。llama_grammar.py
: GBNF (GGML BNF) 形式のグラマーをパースし、制約付き生成を可能にします。JSON スキーマからの変換機能も含まれます。
server/
(FastAPI Server Layer):- FastAPI を使用して Web サーバーを構築し、OpenAI 互換の API エンドポイントを提供します。
model.py
: 複数のモデル設定を管理し、リクエストに応じてLlama
インスタンスをロード/アンロードするLlamaProxy
を提供します。settings.py
: Pydantic を使ってサーバーとモデルの設定を管理します。app.py
: FastAPI アプリケーションのセットアップ、ルーティング、非同期処理 (AnyIO + Threadpool)、SSE ストリーミングなどを担当します。errors.py
: エラーハンドリングを行い、OpenAI 形式のエラーレスポンスを返します。
-
llama_cpp.py
:ctypes
の関数 (ctypes_function
) と構造体定義が中心です。libllama
の C ヘッダーファイル (llama.h
) に対応します。- 定数 (例:
LLAMA_SPLIT_MODE_LAYER
,LLAMA_FTYPE_MOSTLY_Q4_0
) もここで定義されます。 - ライブラリのロード処理は
_ctypes_extensions.py
のload_shared_library
で行われ、環境変数 (LLAMA_CPP_LIB_PATH
) によるオーバーライドもサポートされます。
-
_internals.py
:LlamaModel
: GGUF ファイルをロードし、モデル構造 (レイヤー数、埋め込み次元など) やメタデータへのアクセスを提供します。LlamaContext
: 推論コンテキスト (KV キャッシュなど) を保持します。llama_decode
の呼び出しを担当します。LlamaBatch
:llama_decode
に渡すためのトークン、位置、シーケンス ID などの情報をまとめたバッチ構造を管理します。LlamaSampler
: Top-K, Top-P, Temperature, Mirostat, Repetition Penalty などのサンプリングパイプラインを構築・実行します。
-
llama.py
(Llama
class):__init__
: パラメータを解釈し、LlamaModel
,LlamaContext
,LlamaBatch
を初期化します。チャットハンドラやトークナイザもここで設定されます。eval()
: トークンを受け取り、バッチに分割してLlamaContext.decode()
を呼び出し、KV キャッシュを更新します。sample()
: 現在の logits に対してLlamaSampler.sample()
を呼び出し、次のトークンを取得します。generate()
:eval()
とsample()
を組み合わせたコアな生成ループを提供するジェネレータです。KV キャッシュの管理 (プレフィックスマッチ、シフト) もここで行われます。create_completion()
/create_chat_completion()
:generate()
をラップし、OpenAI 互換のインターフェースとレスポンスを提供します。チャットの場合はllama_chat_format
を利用します。
-
server/
ディレクトリ:- FastAPI の標準的な構造に従います。
app.py
がエントリーポイントで、ルーティング、ミドルウェア、依存性注入 (DI) を設定します。 LlamaProxy
が DI を通じて各エンドポイントに提供され、モデルへのアクセスを抽象化します。- 非同期 (
async def
) エンドポイント内で、同期的なllama-cpp-python
のメソッド (Llama.__call__
など) をrun_in_threadpool
を使って呼び出すことで、イベントループのブロッキングを防いでいます。 - ストリーミングは
EventSourceResponse
とanyio
のメモリチャネルを使って実現されています。get_event_publisher
関数がバックグラウンドで生成結果をチャネルに送り、FastAPI がそれをクライアントに SSE として送信します。 llama_outer_lock
とllama_inner_lock
: サーバーが複数のリクエストを処理する際、同時にllama_decode
を呼び出さないようにするための排他制御です。また、ストリーミング中に新しいリクエストが来た場合に既存のストリームを中断する (interrupt_requests
) 機能にも関連しています。
- FastAPI の標準的な構造に従います。
pip install llama-cpp-python
を実行すると、setup.py
(またはpyproject.toml
のビルドバックエンド設定) がCMake
を呼び出します。- CMake は
vendor/llama.cpp
ディレクトリ内のソースコードをコンパイルし、共有ライブラリ (libllama
) を生成します。 - 生成された
libllama
は Python パッケージ内に配置されます。 - カスタマイズ:
- GPU サポート: 環境変数
CMAKE_ARGS
またはpip install --config-settings="cmake.args=..."
を使って CMake にフラグ (例:-DLLAMA_CUBLAS=ON
,-DLLAMA_METAL=ON
) を渡すことで、GPU サポートを有効にしてビルドできます。 - 外部ライブラリ: 環境変数
LLAMA_CPP_LIB_PATH
を設定すると、実行時に指定されたディレクトリ内のlibllama
がロードされます(ビルド済みのライブラリを使用する場合)。 - ソース変更: リポジトリをクローンし、
CMakeLists.txt
やvendor/llama.cpp
のコードを直接変更してpip install .
でビルドすることも可能です(上級者向け)。
- GPU サポート: 環境変数
- チャットフォーマット:
llama_chat_format.py
の@register_chat_completion_handler
デコレータを使うか、LlamaChatCompletionHandlerRegistry
を直接操作して、新しいチャットフォーマットハンドラを登録できます。- 多くの場合は
Jinja2ChatFormatter
を使ってテンプレートと特殊トークンを指定するだけで対応可能です。
- トークナイザ:
llama_tokenizer.py
のBaseLlamaTokenizer
を継承し、tokenize
とdetokenize
メソッドを実装することで、カスタムトークナイザを作成できます。Llama
の__init__
でtokenizer
引数にカスタムトークナイザインスタンスを渡します。
- Verbose 出力:
Llama(..., verbose=True)
やサーバー設定でverbose: true
を指定すると、llama.cpp
からの詳細なログ (モデルロード、推論タイミングなど) が標準エラー出力に表示されます。 - CTypes エラー: ライブラリのロード失敗 (
FileNotFoundError
,OSError
) は、共有ライブラリが見つからないか、依存関係が満たされていない場合に発生します。ビルドログやldd
(Linux),otool -L
(macOS), Dependency Walker (Windows) などで確認します。関数が見つからない (AttributeError
) 場合は、libllama
とllama-cpp-python
の C API バージョン間の不整合が考えられます。 - 推論結果の問題: プロンプトのフォーマット、トークナイズ、サンプリングパラメータ、KV キャッシュの状態などを確認します。低レベル API (
_internals
) を使ってステップごとにデバッグすることも有効です。 - サーバー関連: FastAPI や Uvicorn のログ、リクエスト/レスポンスの内容、非同期/同期処理の境界、ロックの状態などを確認します。
- コーディングスタイルに従ってください (主に
black
,flake8
)。 - 新しい機能にはテストを追加してください (
tests/
)。 - ドキュメント (README, docstrings) を更新してください。
- GitHub リポジトリで Issue を立てて議論し、Pull Request を送ってください。
このドキュメントが llama-cpp-python
の内部構造の理解や開発に役立つことを願っています。