llm-cpp

#include "llm_*.hpp" · C++17 · MIT

C++ に LLM 機能を、.hpp ひとつずつ。

ストリーミング、リトライ、キャッシュ、コスト見積もり、RAG、リランキング、トレーシング、構造化出力、エージェントのための 26 個のシングルヘッダーライブラリ。必要なファイルをプロジェクトにコピーするだけです。SDK もパッケージマネージャーもフレームワークも要りません。

26
ヘッダー
14
標準ライブラリ
だけで動く
12
libcurl
だけ必要
210-572
ヘッダー ひとつ
あたりの行数
llm_stream.hppllm_cost.hppllm_guard.hpp
llm_cache.hppC++17全 210 行
x64 Native Tools
C:\demo> curl -fsSLO https://gitlab.com/mattbusel/llm-cache/-/raw/main/include/llm_cache.hpp
C:\demo> cl /nologo /std:c++17 /EHsc cache.cpp && cache.exe
cache.cpp
What is RAII?            -> answer #1
what is raii?            -> answer #1
Explain move semantics   -> answer #2
What is SFINAE?          -> answer #3
What is RAII?            -> answer #4

api calls 4 | hits 1 | misses 4 | evictions 2
01

インストールはファイル ひとつで完了。

各ライブラリは個別のリポジトリにありますが、プロジェクトに必要なのは include/llm_<name>.hpp だけです。宣言はどこでインクルードしても使えます。実装をコンパイルするには、ちょうど ひとつの .cpp で LLM_<NAME>_IMPLEMENTATION を定義します。

gitlab.com/mattbusel/llm-cacheリポジトリ

  • examples/
  • └─ include/
  •    └─ llm_cache.hppライブラリ本体
  • CMakeLists.txt
  • README.md
  • LICENSE

your-project/あなたのプロジェクト

  • src/
  • ├─ main.cpp
  • └─ llm_impl_cache.cpp // #define ..._IMPLEMENTATION
  • third_party/
  • └─ llm_cache.hpp
  • CMakeLists.txt // 変更なし

全ヘッダーを行数どおりの縮尺で描いています。最大でも 572 行、26 個すべて合わせても 8,948 行なので、何かおかしいときは一度で読み切れるファイルを ひとつ開くだけです。

標準ライブラリのみlibcurl を使用
  1. 572format
  2. 537parse
  3. 481stream
  4. 469finetune
  5. 441json
  6. 388audio
  7. 385agent
  8. 379embed
  9. 362rag
  10. 362batch
  11. 357cost
  12. 351chat
  13. 337vision
  14. 334ab
  15. 315eval
  16. 313guard
  17. 309pool
  18. 302rank
  19. 290compress
  20. 267retry
  21. 261log
  22. 248trace
  23. 248mock
  24. 219router
  25. 211template
  26. 210cache
02

カタログ。

「なし」は完全オフラインで、標準ライブラリだけを使うという意味です。「libcurl」は実装が OpenAI や Anthropic に HTTPS でリクエストすることを示します。欲しいものにチェックを入れると、インストール欄がコマンドを書いてくれます。

// やりたいこと

llm_stream.hpp481 行

llm-stream

OpenAI と Anthropic のチャット応答を SSE でトークンごとにストリーミング

依存
libcurl
グループ
コア
#define LLM_STREAM_IMPLEMENTATION
llm_retry.hpp267 行

llm-retry

ジッター付き指数バックオフ、プロバイダーのフェイルオーバー、サーキットブレーカー

依存
なし
グループ
コア
#define LLM_RETRY_IMPLEMENTATION
llm_cost.hpp357 行

llm-cost

組み込みの OpenAI・Anthropic モデル向けのおおよそのトークン数とコスト見積もり、予算チェック

依存
なし
グループ
コア
#define LLM_COST_IMPLEMENTATION
実行結果
llm_cache.hpp210 行

llm-cache

TTL とヒット/ミス統計付きの LRU レスポンスキャッシュ。同じプロンプトでは API を呼びません

依存
なし
グループ
コア
#define LLM_CACHE_IMPLEMENTATION
実行結果
llm_format.hpp572 行

llm-format

スキーマを定義し、モデルの JSON を検証して、出力が合うまで再プロンプト

依存
なし
グループ
コア
#define LLM_FORMAT_IMPLEMENTATION
実行結果
llm_json.hpp441 行

llm-json

リクエストボディとモデル出力のための小さな JSON パーサー兼ビルダー

依存
なし
グループ
コア
#define LLM_JSON_IMPLEMENTATION
実行結果
llm_parse.hpp537 行

llm-parse

HTML と Markdown を除去し、タイトル、リンク、見出し、コードブロックを抽出、テキストをチャンク分割

依存
なし
グループ
データ
#define LLM_PARSE_IMPLEMENTATION
llm_embed.hpp379 行

llm-embed

OpenAI の埋め込み、コサイン/内積/ユークリッド類似度、小さなディスク上のベクトルストア

依存
libcurl
グループ
データ
#define LLM_EMBED_IMPLEMENTATION
llm_rag.hpp362 行

llm-rag

エンドツーエンドの RAG:チャンク分割、埋め込み、インデックスの永続化、top-k の検索と回答

依存
libcurl
グループ
データ
#define LLM_RAG_IMPLEMENTATION
llm_rank.hpp302 行

llm-rank

オフラインの BM25、LLM による関連度スコア、またはその両方のハイブリッドでパッセージをリランキング

libcurl(リンクは必要。BM25 自体はオフライン)

依存
libcurl
グループ
データ
#define LLM_RANK_IMPLEMENTATION
llm_compress.hpp290 行

llm-compress

会話履歴を縮める:先頭/末尾/スマート切り詰め、スライディングウィンドウ、LLM による要約

なし(LLM_COMPRESS_SUMMARIZE を使うときだけ libcurl が必要)

依存
なし
グループ
データ
#define LLM_COMPRESS_IMPLEMENTATION
実行結果
llm_batch.hpp362 行

llm-batch

JSONL ファイルのプロンプトをスレッドプールで処理。レート制限と再開可能なチェックポイント付き

依存
libcurl
グループ
データ
#define LLM_BATCH_IMPLEMENTATION
llm_log.hpp261 行

llm-log

すべての呼び出しをレイテンシ、トークン数、コスト付きの構造化 JSONL ログに記録。検索と集計も可能

依存
なし
グループ
運用
#define LLM_LOG_IMPLEMENTATION
llm_trace.hpp248 行

llm-trace

親子のネストができる RAII スパン、トークンとコストの属性、OTLP 形式の JSON エクスポート

依存
なし
グループ
運用
#define LLM_TRACE_IMPLEMENTATION
llm_pool.hpp309 行

llm-pool

優先度付きキューと、毎分のリクエスト数・トークン数の上限を備えたワーカープール

依存
なし
グループ
運用
#define LLM_POOL_IMPLEMENTATION
llm_mock.hpp248 行

llm-mock

台本どおり、パターン、ランダム、エコーで応答する偽の LLM。レイテンシとストリーミングも再現

依存
なし
グループ
運用
#define LLM_MOCK_IMPLEMENTATION
llm_eval.hpp315 行

llm-eval

プロンプトを N 回実行して一貫性を測り、モデルやプロンプトを比較し、応答を採点

依存
libcurl
グループ
運用
#define LLM_EVAL_IMPLEMENTATION
llm_ab.hpp334 行

llm-ab

Welch's t 検定、Cohen's d、カスタム採点器でプロンプトやモデルを A/B テスト

依存
libcurl
グループ
運用
#define LLM_AB_IMPLEMENTATION
llm_chat.hpp351 行

llm-chat

トークン予算に合わせた削り込み、固定のシステムプロンプト、保存と復元に対応したマルチターン会話

依存
libcurl
グループ
アプリ
#define LLM_CHAT_IMPLEMENTATION
llm_agent.hpp385 行

llm-agent

ツール呼び出しエージェントのループ:C++ のラムダをツールとして登録し、モデルに呼ばせる

依存
libcurl
グループ
アプリ
#define LLM_AGENT_IMPLEMENTATION
llm_vision.hpp337 行

llm-vision

画像(ファイルまたは URL)とプロンプトを OpenAI や Anthropic のビジョンモデルに送信

依存
libcurl
グループ
アプリ
#define LLM_VISION_IMPLEMENTATION
llm_template.hpp211 行

llm-template

ループ、条件分岐、トークン予算による切り詰めに対応した Mustache 風プロンプトテンプレート

依存
なし
グループ
アプリ
#define LLM_TEMPLATE_IMPLEMENTATION
llm_router.hpp219 行

llm-router

複雑さのスコアと、コスト・レイテンシ・品質・予算のいずれかの戦略から、プロンプトごとにモデルを選択

依存
なし
グループ
アプリ
#define LLM_ROUTER_IMPLEMENTATION
llm_guard.hpp313 行

llm-guard

個人情報(メール、電話番号、SSN、カード番号、API キー)を検出して除去し、プロンプトインジェクションの危険度を採点

依存
なし
グループ
アプリ
#define LLM_GUARD_IMPLEMENTATION
実行結果
llm_audio.hpp388 行

llm-audio

OpenAI API による Whisper の文字起こしと翻訳、そしてテキスト読み上げ

依存
libcurl
グループ
アプリ
#define LLM_AUDIO_IMPLEMENTATION
llm_finetune.hpp469 行

llm-finetune

OpenAI ファインチューニングの全工程:JSONL の作成、アップロード、作成、ポーリング、キャンセル、モデル一覧

依存
libcurl
グループ
アプリ
#define LLM_FINETUNE_IMPLEMENTATION

条件に合うヘッダーはありません。

03

本物のコード、本物の出力。

オフラインのライブラリから 6 つ。どれも実装マクロを同じファイルに書いた完全なプログラムです。横の出力は実際に表示されたそのままで、コメントで断っている箇所以外は何もモックしていません。

llm-cache (210 行、依存なし)。同じプロンプトでは API を呼びません。キーはデフォルトで大文字と小文字を区別せず、容量に達すると最も長く使われていないエントリを追い出します。

cache.cpp
#define LLM_CACHE_IMPLEMENTATION
#include "llm_cache.hpp"
#include <cstdio>

int main() {
    llm::CacheConfig cfg;
    cfg.max_entries = 2;                  // tiny, to show LRU eviction
    llm::ResponseCache cache(cfg);

    int api_calls = 0;
    auto ask = [&](const std::string& prompt) {
        return cache.get_or_compute(prompt, [&] {
            ++api_calls;                  // your real model call goes here
            return "answer #" + std::to_string(api_calls);
        });
    };

    for (const char* p : {"What is RAII?", "what is raii?",
                          "Explain move semantics", "What is SFINAE?",
                          "What is RAII?"})
        std::printf("%-24s -> %s\n", p, ask(p).c_str());

    auto s = cache.stats();
    std::printf("\napi calls %d | hits %zu | misses %zu | evictions %zu\n",
                api_calls, s.hits, s.misses, s.evictions);
}
x64 Native Tools
C:\demo> cl /nologo /std:c++17 /EHsc /O2 cache.cpp
cache.cpp
C:\demo> cache.exe
What is RAII?            -> answer #1
what is raii?            -> answer #1
Explain move semantics   -> answer #2
What is SFINAE?          -> answer #3
What is RAII?            -> answer #4

api calls 4 | hits 1 | misses 4 | evictions 2
C:\demo> 

MSVC 19.44 x64(/std:c++17 /EHsc /O2)で各ライブラリの最新ヘッダーに対してコンパイルし、2026-09-28 に実行。ソース:examples/offline(CI の実行ごとに g++ で再ビルド)。料金は llm-cost の組み込みテーブルによるものです。

04

複数を組み合わせて使う。

ヘッダーはどこで並べてインクルードしてもかまいません。分けておくべきなのは実装だけです。

.cpp ひとつに実装 ひとつ。

いくつかのヘッダーは内部ヘルパーに同じ名前を使っています(たとえば llm::detail::json_escape)。そのため、ひとつの翻訳単位で ふたつの *_IMPLEMENTATION マクロを定義するとコンパイルに失敗することがあります。llm-log と llm-stream がその一例です。

llm_impl.cppLOG + STREAM をひとつのファイルに:失敗する場合あり
llm_impl_log.cpp#define LLM_LOG_IMPLEMENTATION
llm_impl_retry.cpp#define LLM_RETRY_IMPLEMENTATION
llm_impl_stream.cpp#define LLM_STREAM_IMPLEMENTATION
2026-09-25 に確認済み:26 個すべての実装をそれぞれ専用の .cpp に置くと、ひとつのバイナリにコンパイル・リンクできます(MSVC 19.44 x64、libcurl は vcpkg から)。CI はプッシュのたびに g++ で同じ確認を繰り返します。
main.cpp:ストリーミング、失敗時はリトライ、呼び出しをログ
#include "llm_log.hpp"
#include "llm_retry.hpp"
#include "llm_stream.hpp"
#include <cstdlib>
#include <iostream>

int main() {
    const char* key = std::getenv("OPENAI_API_KEY");
    if (!key) { std::cerr << "set OPENAI_API_KEY\n"; return 1; }

    llm::Config cfg;
    cfg.api_key = key;
    cfg.model   = "gpt-4o-mini";
    const std::string prompt = "Explain backpressure in one paragraph.";

    llm::Logger logger(llm::LogConfig{"calls.jsonl"});
    llm::Logger::ScopedCall call(logger, cfg.model, prompt);   // written on scope exit

    auto result = llm::with_retry<std::string>([&]() -> std::string {
        std::string text, error;
        llm::stream(prompt, cfg,
            [&](std::string_view tok) { std::cout << tok << std::flush; text += tok; },
            nullptr,
            [&](std::string_view err) { error = err; });
        if (!error.empty()) throw llm::LLMError{0, error, true};   // retry
        return text;
    });

    call.set_response(result.value);
    std::cout << "\n(" << result.attempts_used << " attempt(s))\n";
}
05

インストール手順を自動で用意。

カタログでヘッダーを選んでください。ここに出るコマンドはそれらを third_party/ に取得し、実装ごとに専用の .cpp を用意し、選んだものが必要とする場合にだけ -lcurl を追加します。