🎁

ローカルRAG環境を非エンジニアに届ける|ダブルクリックで入る「社内知恵袋(ShineosQA)」を作って、llama.cppで書き直した話

に公開
2026/10/03

現在の製品の雰囲気は、1分のユースケースデモ動画で見られます。

https://www.youtube.com/watch?v=r5k4L6a9dEU

はじめに

前回、OllamaとOpen WebUIで作るRAG環境という記事を書きました。Docker Composeひとつで、社内文書を読み込んで答えてくれるローカルRAGが立ち上がる、という内容です。

で、この記事がそこそこ反響を呼んで、弊社に「これ、うちでも使いたいんですが」みたいな相談が来るようになりました。ただ、よく話を聞いてみると、全員が技術者じゃない。「Docker」「コマンド」「ポート番号」で会話が終わってしまう。納品物は技術記事ではなく、「ダブルクリックしたら使える何か」だったんです。

そこで作ったのが、社内知恵袋(ShineosQA) というOSSです。Ollama + Open WebUIをベースに、非エンジニアでもインストールした瞬間から使えるように、exe化してダブルクリック一発で入る形にパッケージ化しました。

この記事は、そのときに「どうすれば非エンジニアに届くか」「小さいモデルで精度を出すにはどうしたか」を考えた記録です。その後、中身をllama.cpp直接実行へ全面書き直ししたので、この記事でも初代(v1)を作った話から、なぜ・どう書き直したかまでを通しで書いています。前後で作りがガラッと変わるので、初代のパートには見出しに【初代】と付けてあります。

課題:RAG環境は作れても、届かない

前回の構成は、技術的にはよくできていると思います。セキュリティもコストもクリアしてる。 ただし、使う人の前提が「エンジニア」 でした。

実際に起きた現場の声を並べると、

  • 「Dockerって何ですか?」
  • 「コマンドプロンプト開けって言われても…」
  • 「ブラウザで localhost:3000 にアクセスして、って…localhostって何?」

技術者からすると「ちょっと触れば分かるだろ」と思ってしまうんですが、非エンジニアの皆さんにとっては、それすら高い壁です。 いくら正確な技術記事でも、対象がDockerを触れない人では意味がない 、という当たり前のことに気づきました。

そこで逆算しました。「エンジニアに届ける」から「非エンジニアに届ける」に視点を変えると、要件はこうなります。

  • インストールはダブルクリックで完了する
  • 起動もデスクトップのアイコンから
  • URLもコマンドも触らせない
  • もちろん社内文書は外に出さない

これが「社内知恵袋」の出発点です。

作ったもの:社内知恵袋(ShineosQA)【初代】

できあがったのがこちらです。

https://github.com/Shineos/shineos-qa-assistant

Windowsアプリで、インストーラ(.exe)をダブルクリックすると、Ollama本体とAIモデル(合計約6GB)まで含めて自動で入ります。インストール中にモデルを選べて、あとはデスクトップのアイコンをダブルクリックすればチャット画面が開く、という作りです。

ポイントは、内部で動いてるのは前回記事のOllama + Open WebUIと同じものだということ。技術スタックは一緒で、フタを変えただけです。ただ、この「フタ」がすごく大事で、非エンジニアに取っつきやすさはここで決まります。

インストールの流れはこんな感じです(実際の操作を3倍速で録画・初代v1のもの)。

インストールの流れ

ダブルクリック → 案内に従う → 完了、という流れだけで、コマンドもURLも出てきません。

RAG注入:ナレッジをどう登録してもらうか

RAGの肝は「ナレッジをどう登録するか」です。Open WebUIでもファイルアップロードはできますが、非エンジニアが毎回アップロードする運用は現実的じゃない。

そこで「社内知恵袋」では、インストール時にナレッジフォルダを指定するだけ、インストール後は画面からドラッグ&ドロップで追加できるようにしました。

  • フォルダを1つ指定すれば、中のPDF・Markdownが自動でナレッジ化される
  • 追加の資料はドラッグ&ドロップでいつでも登録できる
  • 検索は BM25(キーワード一致)+ベクトル検索(意味一致)のハイブリッドで、型番・規程番号・固有名詞も正確にヒットさせる

実際に質問してから、出典付きの回答が返ってくるまでの流れはこんな感じです(実際の操作を録画・初代v1のもの)。

使用例: 質問から出典付き回答まで

この「フォルダ指定だけで全部入る」が、非エンジニアにはすごく評判が良かったです。「フォルダ選ぶだけでいいんですか?」って。エンジニア的には「ベクタDBにドキュメントを入れる」だけのことですが、ユーザー視点では「フォルダを選ぶ」だけで話が完結するのが大事なんですね。

この設計は初代・v2を通じて変わっていません。初代からの記録としてもう一つ、大きかったのが次の「小さいモデルでいかに精度を出すか」という話です。

小さいモデルで精度を出す:RAGの作り込みとプロンプト【初代】

もう一つ大きかったのが、「小さなモデルでいかに精度を出すか」 です。

非エンジニア向けのPCって、GPUが載ってないことがほとんどです。会社の支給ノートPCで動かす前提なら、モデルは qwen2.5:3b あたりが現実的。でも3bって、正直そのまま使うとRAGの回答が微妙なんです。コンテキストを渡しても「それっぽいけど違う」ことを言いがち。

ここで効いたのは、システムプロンプトだけじゃなくて、RAGの側の作り込みのほうが大きかったです。具体的には、3つやりました。

  • 検索語をLLMに生成させない:Open WebUIの標準は、質問から検索キーワードをLLMに生成させるんですが、3bモデルの生成する検索語は揺らぎが大きく、関連文書を取りこぼす。そこで、ユーザーの質問文をそのまま検索に使うように固定しました。検索語生成という余計なLLM呼び出しが消えるので、回答が遅くなるのも防げます
  • チャンクとベクタDBをチューニング:文書の分割単位(チャンク)は300文字・オーバーラップ30文字、検索の上位取得は3件に固定。埋め込みは日本語・多言語対応の bge-m3 にして、BM25(キーワード一致)+ベクトル(意味一致)のハイブリッド検索にしました。このチャンクサイズと検索方式が、3bモデルにはちょうどいい塩梅でした
  • RAGの注入パッチを当てる:Open WebUI 0.11には「モデルに紐付けたナレッジがRAG処理に渡らず検索されない」という不具合があって、これを最小パッチで修正して、関連文書の断片を常に自動注入するようにしました。あわせて、根拠が無い場合は引用欄を書かず「該当する記載がありません」と答えるガードレールも入れています

その上で、システムプロンプトでもこう縛りました。

  • ナレッジに書かれていないことは、絶対に推測で答えるなと明示する
  • 該当がなければ「該当する記載がありません」と正直に言わせる。これを「失敗」ではなく「正解」として扱う
  • 回答は必ず出典(文書名・該当箇所)を添えさせる
  • ハルシネーションしやすい「一般知識っぽい話」をさせないよう、役割を「社内規程・マニュアルの回答者」に固定する
あなたは社内規定・業務マニュアルの回答者です。
ナレッジに記載されている内容のみを根拠に回答してください。
記載がない場合は「該当する記載がありません」と回答してください。
推測や一般知識で補わないこと。回答には必ず出典(文書名・該当箇所)を添えてください。

この辺は、金融編の記事で書いた 「マニュアルにないことは答えさせない」 と同じ思想です。モデルを大きくして精度を上げるんじゃなくて、検索とプロンプトで「答えさせる範囲を狭めて精度を上げる」。非エンジニア向け・ローカル環境という制約下では、こっちの方が現実解でした。

その他の工夫をざっくり【初代】

精度以外にも、非エンジニア向けにここまでやらないと、という工夫がいくつかあります。

  • GPUがあれば自動で使う:NVIDIA GPUがあるPCなら自動でGPU処理(高速)、なければCPUで動く。インストール時に自動判定
  • 応答速度の自動チューニング:モデル常駐の最適化・起動時ウォームアップで、質問から回答までの待ち時間を最小化
  • 他アプリへの配慮:AI応答中でも他のアプリを優先(CPU機のみ優先度制御・メモリ自動調整)
  • Windowsサービスとして自動起動:PC再起動後も自動で立ち上がる
  • ファイル生成:チャットからPDF・PowerPoint・Wordを作成(オプション)

「AIが遅くて他の仕事ができない」「PCを再起動したら消えた」——この手の体験が1回あるだけで、非エンジニアの導入は失敗します。地味ですが、こういうところまで面倒を見ないと「届く」にならない、というのが実感です。

ハマりどころを正直に【初代】

1つ目が、SmartScreenとの戦いです。現在はテスト証明書での署名のため、WindowsのSmartScreenが「認識されないアプリ」と出ることがあります。技術者なら「詳細情報」→「実行」で済みますが、非エンジニアに「ここをクリックしてください」と案内するのは、かなり心理的なハードルがありました。

この解決のため、現在 SignPath Foundation に署名証明書の発行を申請中です。承認されたら正式な署名でビルドし直して、SmartScreenに警告を出させない形でアップロードし直す予定です。コード署名をちゃんと取るのは、非エンジニア向けアプリの必須要件だなと痛感しています。

2つ目が、速度の体感です。完全社内処理なので、回答まで数秒〜20秒ほどかかります。クラウドのChatGPTに慣れた人には「遅い」と感じます。ここは「セキュリティとのトレードオフ」として割り切ってもらうしかなく、正直な説明を心がけました。Web検索をONにすれば最新情報も取れますが、質問が外部に出るため既定OFFにしています。

(→ この「遅さ」は、ここから先に書く全面書き直しでけっこう変わります。)

その後、llama.cppで全面書き直しました(v2)

ここまでは初代(v1)の話です。開発はその後も続いていて、あるとき思い切って中身を全部書き直しました。「ダブルクリックで入る・アイコンで開く・URLもコマンドも触らせない」という外側の約束はそのままに、内部を Ollama + Open WebUI → llama.cpp直接実行の自作軽量バックエンド に置き換えたv2です。

UIもOpen WebUIから自前のチャットUIに変わりました。デスクトップのアイコンから約2秒で開くメイン画面はこんな感じです。

メイン画面

なぜ書き直したのか:初代のつらみ

初代は「Open WebUIにフタを被せる」方式でした。作り方は速くて確実なんですが、Open WebUIとPythonが丸ごと入るぶん、こんな問題を抱えていました。

  • インストールが重い: Ollama本体+Python+venv+torch+Open WebUIで、AIモデル以外の部分だけで6GB近く。インストールは15〜40分
  • パッチ運用が脆い: Open WebUIのsite-packagesにソースパッチを5種類当てる方式なので、Open WebUIのバージョン固定(0.11.0)が必須。パッチ逸脱チェックや修復ツールまで用意する始末
  • メモリを食う: Python+torch+WebUIの常駐で推論に使えないRAMが約2GB。8GBメモリの支給PCでは、モデルは3Bクラスが上限。前の章で「qwen2.5:3bあたりが現実的」と書いたのは、精度の話であると同時に、この重さの話でもありました
  • ollama pullが不透明: 量子化やリビジョンを指定できず、ハッシュ検証もない

で、冷静に考えると気づくんです。Ollamaの中身はllama.cppなんですよね。推論を速くするためにOllamaを選んでいたわけではなく、llama.cppの前に立つ「仲介層」として使っていた。RAGの実体は「検索 → プロンプト組立 → 推論 → 出典表示」なので、仲介層がやることは自前で書けて、推論コアだけは一番軽くて速いOSSに任せればいい。

というわけで、v2の構成はこうなりました。

  • 推論エンジン: llama.cpp公式プリビルドの llama-server.exe(約15MB)をそのまま実行。ユーザーPCでもCIでも一切コンパイルしない
  • アプリ層: Open WebUI + Python + パッチ5種が全部消えて、自作の軽量バックエンド(C#・1実行ファイル)1本に。SQLite(+FTS5)を内蔵して、ナレッジもベクトルもこの1ファイルに
  • UI: Open WebUIの代わりに TypeScript + Vite製の自前チャットUI をWebView2で表示
  • モデル取得: HuggingFaceから GGUFを直接ダウンロード(SHA256検証・レジューム対応)

推論エンジンを自作する話ではありません。「エンジンは最高のOSSを借りて、自分たちはフタを作る」は初代と同じ思想のままで、変えたのは「フタの中身を、パッチの継ぎ接ぎではなく自前で持った」ことです。バックエンドをC#にしたのも同じ理由で、推論のホットパスは100% llama.cpp(C/C++)が担うので、バックエンド側には検索・プロンプト組立・プロセス管理のような数十ミリ秒の仕事しか残らない。ここをC++化しても速くはならないので、開発効率と既存資産(PDF解析など)を優先しました。

3つのllama-serverを子プロセスとして管理していて、アプリを閉じたら全部停止します(孤児プロセスも残りません)。RAG本体のハイブリッド検索(BM25+ベクトル)は初代から引き継いで、リランク(bge-reranker-v2-m3) を追加しました。ちなみにChromaDBもやめてSQLiteに丸ごと入れていますが、社内文書程度のチャンク数なら全件コサイン類似度でも20ms未満で、専用ベクタDBは不要だった、というのも学びでした。

初代からの変化(数字で)

項目 初代(Ollama + Open WebUI) v2(llama.cpp直接実行)
AIエンジン Ollama(仲介層あり) llama.cpp(llama-server)を直接実行
アプリ層 Open WebUI + Python + ソースパッチ 自作軽量バックエンド1実行ファイル
インストール 合計約6GB・15〜40分 約200MB・数分(初回起動時にモデル約1.7GBをDL)
メモリ Python等の常駐で約2GB消費 常駐ゼロ。解放した分をモデルに回せる
最初の1文字まで モデル・状態により大きく変動 クイック1.7Bで約4秒・同一質問は0.2秒未満
モデル切替 インストール時に選択(後から変えるにはやり直し) 画面上で即切替(⚡1.7B/🎯4B/🏆30B)
常駐 Windowsサービスで常駐 起動2秒・閉じたら完全停止

モデルも qwen2.5:3b固定 から、3階級(⚡クイック1.7B/🎯標準4B/🏆高品質30B)の即切替 に変わりました。メモリ16GB以上のPCなら30Bも選べるので、「サクッと確認はクイック、難しい質問は高品質」と、その日の用件で使い分けられます。未ダウンロードのモデルも、画面のボタンからその場でDLできます。

モデル選択

ナレッジ登録は初代どおり、ドラッグ&ドロップ

非エンジニア向けの要だった「フォルダを指定するだけ」「ドラッグ&ドロップで追加」のナレッジ登録は、v2でも変えていません。対応形式は初代のPDF・Markdownから PDF・Word・Excel・CSV・Markdown・テキスト に広がっていて、追加した資料は即座に検索対象になります。入力欄の📎ボタンから、その場でファイルを登録することもできます。

ナレッジ管理

遅さと重さの解決

初代の「ハマりどころ」で書いた「回答まで数秒〜20秒」は、v2でこう変わりました。開発機(Ryzen 7 5700U・GPUなし・CPUのみ)での実測です。

  • ⚡クイック(1.7B): 最初の1文字まで約4秒(🎯標準4Bで約8〜9秒、🏆高品質30Bでも約11〜14秒)
  • 同一質問の再質問: 0.2秒未満(回答キャッシュ)
  • アプリ起動から入力可能まで: 約2秒

効いたのは地味な積み重ねです。①システムプロンプト等の静的部分をプロンプトの前方に固定してキャッシュを効かせる(同一prefixの再質問でプロンプト処理が約25秒→0.9秒になった実測あり)、②起動時のモデル事前ロード+ウォームアップ、③高信頼時はリランクを省略。あとはモデルサイズを削る 軽量量子化(IQ4_XS) を、18シナリオ×4構成の検証で品質劣化なしを確認した上で採用しました。

「重さ」については、初代と真逆の方針にしました。初代はWindowsサービスで常駐させていたんですが、v2ではアプリを閉じたらAIエンジンもバックエンドも完全停止。使っていない間のメモリは自動解放され(常駐2.3GB→約0.08GB)、他アプリ優先モード(既定ON) でAI処理の優先度を下げるので、「AIが動くと他の作業が重くなる」も実測で影響ゼロまで抑えました。この解放のしやすさのおかげで、8GBメモリのPCでも標準の4Bモデルが動くようになっています。

精度はどうなったか

「検索とプロンプトで答える範囲を狭める」という初代の思想はそのままに、モデルの外側に機械的な防波堤を足しました。

  • 生成後バリデーション:回答中の数値が出典に存在しない場合(小型モデルがよくやる捏造・取り違え)を自動検出して、出典の数値だけで1回だけ答え直させる
  • 対象ガード:「〜できますか?」系の質問で、質問の対象語が取得文書のどこにも現れない場合は、生成する前に「該当する記載がありません」に倒す(別の手続きの転用回答や、規程に無い許可のでっち上げを防ぐ)
  • リランク:bge-reranker-v2-m3で検索候補を再評価。文脈が途切れるチャンクは隣接チャンクを連結して渡す

回答の下に出典(文書名・該当箇所)が付くのは、初代どおりです。

出典付き回答

自前で作ったゴールデンQA(118問)での正答率は、最小の1.7Bモデルで 108/118(91.5%)。「モデルを大きくするより、検索とガードを固める」は、v2でも正解でした。

製造業向けに、図面も読めるようにした

土台が軽くなったぶん、応用も足しています。図面を扱う製造業向けの拡張で、

  • 図面PDF・DXFの検索とQ&A:図面の表題欄(図番・品名・材質・改訂)を取り込み時に自動読取。A-1234 と A1234 のような表記ゆれも同一視して検索できます
  • キャプチャのAI読取:Win+Shift+S で図面をキャプチャして貼り付けると、視覚言語モデル(Qwen3-VL・PC内で処理)が表題欄を画像から直接読み取って検索を補助。製造業の検品にVLMを使った記事で書いた知見がそのまま活きています
  • 出典プレビュー:回答の根拠となった領域を、元PDFの図の上にハイライト表示

あたりが入っています。あと表計算(Excel・CSV)のナレッジ取り込みにも対応しました。

配布も軽くした

インストーラは 約200MB に軽量化して、AIモデルは初回起動時のウィザードからダウンロードする方式にしました(進捗表示・SHA256検証付き)。初回起動時のモデルダウンロードウィザードはこんな感じです。

初回起動時のモデルダウンロード

インストールは管理者権限不要・数分で終わります。初代で悩んだSmartScreen警告は、Microsoft Storeで公開を開始したことで、Store版では出なくなりました(Microsoftの署名付きで配布されるため)。Storeのアプリページから無料で入手できます。GitHub Releasesからの直接ダウンロード版も引き続き公開しています(こちらは前述のとおりテスト証明書での署名のため、警告が出ることがあります)。

まとめ

Ollama + Open WebUIのRAG環境を、非エンジニアに届けるために作った「社内知恵袋(ShineosQA)」。そして、その後llama.cpp直接実行へ全面書き直した、という話でした。

  • 技術的に正しいだけでは人には届かない。「ダブルクリックで入る」まで落とすのが非エンジニア向けの本質
  • ナレッジ登録はフォルダ指定・ドラッグ&ドロップに寄せる
  • 小さいモデルの精度は、 システムプロンプトで「答える範囲を狭める」 ことで出す
  • ハルシネーション対策は 「該当なし」を正解にする設計
  • 非エンジニア向けは署名・速度・再起動耐性のような「体験」が実は大事
  • そして書き直しで分かったのは、仲介層(Ollama + Open WebUI)は「楽な構成」と引き換えに「重さ」と「脆さ」を抱え込むということ。推論コアはllama.cppを直接使い、仲介層は自前で持つほうが、結果的に軽く・速く・壊れにくくなりました
  • 「パッチの継ぎ接ぎで長く育てる」より「必要な分だけ自前で持つ」ほうが、長い目で見ると楽な場合がある

前回の「RAG環境をDockerで作る」記事がエンジニア向け、初代の「社内知恵袋」はその非エンジニア向けの続編、今回はその書き直し編という位置づけです。同じ技術でも、届け方が違うとこんなに作り方が変わる。そして動かし続けるうちに、「最初に楽な構成」と「育てられる構成」は違う、というのがここまでの学びでした。

本体はMIT Licenseで無償公開していて、Microsoft Storeからも無料で入手できるようになりました。導入支援・保守サポートは有償で受け付けているので、社内Q&A・ナレッジ運用のご相談があればお気軽にどうぞ。


💡 社内Q&A・ローカルLLM導入のご相談は、以下よりお気軽にお問い合わせください。

https://shineos.com/contact/


参考

Discussion