Skip to content

Instantly share code, notes, and snippets.

@laksjdjf
Created April 10, 2025 11:05
Show Gist options
  • Save laksjdjf/9795b43ed64224547fc234d3cda57fd4 to your computer and use it in GitHub Desktop.
Save laksjdjf/9795b43ed64224547fc234d3cda57fd4 to your computer and use it in GitHub Desktop.
docs

はい、承知いたしました。llama-cpp-python の内部構造や開発に関心のある方向けに、開発者ドキュメントを作成します。


llama-cpp-python 開発者向けドキュメント

1. 概要 (Overview)

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 と互換性のあるインターフェースを提供し、既存のエコシステムとの連携を容易にします。
  • 拡張性: 新しいチャットフォーマットやカスタムトークナイザなどを追加しやすい構造を目指します。

2. アーキテクチャ (Architecture)

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
Loading
  • 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) も担当します。
  • _internals.py (Low-level Python Wrapper):
    • C API を直接呼び出すよりも少し扱いやすい Python クラス (LlamaModel, LlamaContext, LlamaBatch, LlamaSampler など) を提供します。
    • C ポインタや構造体のライフサイクル管理(例: contextlib.closing を使ったリソース解放)を部分的に行います。
    • 主に Llama クラスの内部実装で使用されますが、より低レベルな制御が必要な場合に直接利用することも可能です。
  • 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 形式のエラーレスポンスを返します。

3. 主要コンポーネントの詳細

  • llama_cpp.py:

    • ctypes の関数 (ctypes_function) と構造体定義が中心です。libllama の C ヘッダーファイル (llama.h) に対応します。
    • 定数 (例: LLAMA_SPLIT_MODE_LAYER, LLAMA_FTYPE_MOSTLY_Q4_0) もここで定義されます。
    • ライブラリのロード処理は _ctypes_extensions.pyload_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 を使って呼び出すことで、イベントループのブロッキングを防いでいます。
    • ストリーミングは EventSourceResponseanyio のメモリチャネルを使って実現されています。get_event_publisher 関数がバックグラウンドで生成結果をチャネルに送り、FastAPI がそれをクライアントに SSE として送信します。
    • llama_outer_lockllama_inner_lock: サーバーが複数のリクエストを処理する際、同時に llama_decode を呼び出さないようにするための排他制御です。また、ストリーミング中に新しいリクエストが来た場合に既存のストリームを中断する (interrupt_requests) 機能にも関連しています。

4. ビルドプロセス

  • 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.txtvendor/llama.cpp のコードを直接変更して pip install . でビルドすることも可能です(上級者向け)。

5. 拡張性

  • チャットフォーマット:
    • llama_chat_format.py@register_chat_completion_handler デコレータを使うか、LlamaChatCompletionHandlerRegistry を直接操作して、新しいチャットフォーマットハンドラを登録できます。
    • 多くの場合は Jinja2ChatFormatter を使ってテンプレートと特殊トークンを指定するだけで対応可能です。
  • トークナイザ:
    • llama_tokenizer.pyBaseLlamaTokenizer を継承し、tokenizedetokenize メソッドを実装することで、カスタムトークナイザを作成できます。
    • Llama__init__tokenizer 引数にカスタムトークナイザインスタンスを渡します。

6. デバッグのヒント

  • Verbose 出力: Llama(..., verbose=True) やサーバー設定で verbose: true を指定すると、llama.cpp からの詳細なログ (モデルロード、推論タイミングなど) が標準エラー出力に表示されます。
  • CTypes エラー: ライブラリのロード失敗 (FileNotFoundError, OSError) は、共有ライブラリが見つからないか、依存関係が満たされていない場合に発生します。ビルドログや ldd (Linux), otool -L (macOS), Dependency Walker (Windows) などで確認します。関数が見つからない (AttributeError) 場合は、libllamallama-cpp-python の C API バージョン間の不整合が考えられます。
  • 推論結果の問題: プロンプトのフォーマット、トークナイズ、サンプリングパラメータ、KV キャッシュの状態などを確認します。低レベル API (_internals) を使ってステップごとにデバッグすることも有効です。
  • サーバー関連: FastAPI や Uvicorn のログ、リクエスト/レスポンスの内容、非同期/同期処理の境界、ロックの状態などを確認します。

7. 貢献 (Contributing)

  • コーディングスタイルに従ってください (主に black, flake8)。
  • 新しい機能にはテストを追加してください (tests/)。
  • ドキュメント (README, docstrings) を更新してください。
  • GitHub リポジトリで Issue を立てて議論し、Pull Request を送ってください。

このドキュメントが llama-cpp-python の内部構造の理解や開発に役立つことを願っています。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment