ローカル言語モデルで私が試した5 つの面白いこと
この記事は、クラウド依存からの脱却としてローカル LLM の実用性を示し、Ollama と AnythingLLM を活用したプライバシー保護型ドキュメント管理の実装方法を具体的に解説している。
キーポイント
ローカルモデルの利点と環境要件
API キー不要・データ流出リスクゼロ・オフライン動作が可能であり、8GB-16GB の RAM や Apple Silicon Mac でも実用的に動作する。
プライバシー保護型ドキュメント管理の実装
Ollama で Llama 3.2 を実行し、AnythingLLM と連携させることで、機密文書や研究論文をローカル環境で検索・分析できるシステムを構築可能。
クラウド依存からの脱却と所有権の確立
外部サーバーへのデータ送信やトークン課金が発生せず、ユーザーが会話とデータを完全に所有・管理できる環境を提供する。
ローカル環境での機密データ処理
AnythingLLM と Ollama を組み合わせてローカルで動作させることで、契約書や研究論文などの機密情報をクラウドにアップロードせずに検索・分析できる。
RAG パイプラインの完全なオンプレミス化
ドキュメントの取り込み、チャンキング、埋め込み、ベクトル保存、検索に至るまでの全工程をクラウド依存なしで完結させるオープンソースツールである。
Docker による簡易なセットアップ
単一の Docker コマンドで AnythingLLM を起動し、Ollama と接続するだけで数分で検索可能な文書脳を構築できる。
機密データ保護によるローカルRAGの優位性
文書データを外部に転送せず、推論と要約をローカルで行うことで、クラウドAIが抱えるデータ転送やサードパーティ依存のリスクを排除できる。
影響分析・編集コメントを表示
影響分析
この記事は、AI ツールの利用において「クラウド依存」から「エッジ/オンプレミス」へのシフトを促す重要な示唆を含んでいます。特にデータプライバシーが重視される法務・医療・研究分野において、ローカル LLM がクラウドサービスに代わる実用的な代替案として確立されつつある現状を浮き彫りにしています。
編集コメント
クラウド AI の台頭の中で、ローカル実行の価値を再評価する貴重な実例記事です。特に機密データを扱う現場では、このアプローチが標準的なワークフローの一つとなりつつあります。
image**
# イントロダクション
ターミナルで ollama run llama3.2 を実行し、70 億パラメータのモデルが自分のマシンに読み込まれるのを眺めた最初の瞬間 — API キーも請求管理画面もなく、データもコンピューターから外へ出ない — 何かが変わります。技術的に印象的だからという理由だけではありません(もちろんそれは事実ですが)。なぜなら、それが速く、能力があり、そして完全にあなた自身のものだからです。会話の所有権はあなたにあります。誰かがそれを記録しているわけではありません。トークン数に応じて課金されることもありません。モデルはあなたがオフラインであることを知りませんし、気にもしません。
私はしばらくの間、ローカルモデルを日常業務の一部として実行してきましたが、私が最も驚いたのは、ローカルの方が妥協点ではなく、むしろより良い選択肢であるケースが非常に多いということです。以下に、クラウドツールでは行わなかった(あるいは行うことができなかった)ローカル言語モデルで実際にやった 5 つのことを紹介します。必要な箇所には動作するコードも含まれています。
「ローカル」とは、モデルがあなたのマシン上で実行されることを意味します。セットアップには Ollama というツールを使用します。これは、オープンソースのモデルをダウンロードして実行することを、他のアプリケーションをインストールするほど複雑ではないものにするツールです。以下の内容の多くは、小規模なモデルであれば 8GB の RAM を備えたマシンで、快適に動作させるには 16GB で十分です。Apple Silicon Mac(M1 以降)はユニファイドメモリのおかげで、このタスクを驚くほどよく処理します。専用 NVIDIA GPU は処理速度を大幅に向上させますが、始めるために必須というわけではありません。
# プロジェクト 1:プライベートドキュメント脳(Brain)の構築
**
私は研究論文、契約書、プロジェクトノートといった多様な資料を扱っており、それらが適切にインデックスされる速度よりも速く蓄積していきます。ある時点で、ディスク上には3年分の PDF ファイル、数枚の Word ドキュメント、そしてプレーンテキストのノートフォルダが放置されていました。理論的には有用なはずなのに、実質的に検索可能な状態ではありませんでした。
明白な解決策は、これらを AI に投げつけて質問することです。しかし、明白な問題は、契約書や個人的な研究ノートをクラウドサービスにアップロードすると、それらが他人のサーバー上に置かれ、他人のインフラによって処理され、他人の保持ポリシーの下で保存されることになります。法的文書、医療記録、社内ビジネスファイル、個人日記といった機密性の高い情報においては、このトレードオフを正当化するのは困難です。
そこで私は、Ollama を介して Llama 3.2 に接続し、AnythingLLM をローカル環境でセットアップしました。AnythingLLM は、ドキュメントの取り込み、チャンク化(分割)、埋め込み(embedding)、ベクトルストレージ、検索といった、フルな検索拡張生成(RAG: Retrieval-Augmented Generation)パイプラインをクラウド依存なしで処理するオープンソースアプリケーションです。GitHub でのスター数は 54,000+ に達しており、完全にあなたのマシン上で動作します。ドキュメントをドラッグ&ドロップするだけでローカルで処理され、すぐに質問を始められます。
これを稼働させるには、たった 1 つのコマンドを実行するだけです:
Docker を経由して AnythingLLM をプルして実行
すべての処理はあなたのマシン上で行われる -- データは一切外部に送信されない
docker run -d \
--name anythingllm \
-p 3001:3001 \
-v anythingllm_storage:/app/server/storage \
mintplexlabs/anythingllm
次に、ブラウザで http://localhost:3001 を開く
Ollama(すでに localhost:11434 で動作中)に接続し
ドキュメントチャットに使用したいモデルをプルする
ollama pull llama3.2:3b
研究論文のフォルダを読み込み、複数の文書にまたがって読む必要がある質問に対して尋ねてみました:
私が使用したプロンプトは以下の通りです:
**
"2023 年と 2025 年の論文における検索拡張(retrieval augmentation)のアプローチにはどのような主要な違いがありますか?チャンキング戦略については合意していますか、それとも意見が対立していますか?"
**
モデルは各論文から適切なセクションを抽出し、各ポイントの出典となる文書を引用し、個別に読んでいた時には気づかなかった本質的な方法論上の相違点を特定しました。これらの論文のすべてのバイトデータは私のマシン上に留まりました。
このタスクで最もよく機能したモデル:軽量なハードウェアでは速度を重視して Llama 3.2 3B、8 GB の VRAM を持ち、より長い文書にわたる強力な要約合成を求める場合は Mistral 7B です。16 GB の RAM を持つマシンでの単純なドキュメント Q&A では違いは明確です。Mistral はより注意深く読み込みます。
なぜこれが重要なのか**: これが、クラウド AI と単に同等ではなく、ローカル RAG が本質的に優れている理由となるユースケースです。ドキュメントは移動しません。AI が移動します。クラウド AI を素晴らしいものにするすべての要素——推論、統合、複数のソースにわたる質問への回答能力——はすべて存在しています。一方で、機密資料に対して不安を感じさせるすべての要素——データ転送、サーバーサイドでのログ記録、サードパーティへの依存関係——は消え去ります。
# プロジェクト 2: あなたを裁かないコードレビューラーの実行
**
多くの開発者が共感する特定の種類のコードレビューにおける不安があります:動作するコードを書いたが、それに対して誇りを持てない状態です。未来の自分が後悔するような、少し巧妙な方法で書かれているのかもしれません。処理しきれていないエッジケースがあるのではないかと疑っています。他の人間が確認する前に、正直なフィードバックが欲しいのです。
クラウド AI を利用する方法には明白な落とし穴があります。プロダクションコードを ChatGPT や Claude に貼り付けることは、会社の知的財産をサードパーティのサーバーに送信することを意味します。多くの雇用主との秘密保持契約(NDA)は、誰かがそれを執行しているかどうかにかかわらず、この行為をカバーしています。これは特に独自アルゴリズムや内部ビジネスロジック、あるいは顧客データに関わるあらゆるものにとって、現実的な懸念事項です。
私は、Ollama を通じて Qwen2.5-Coder 7B** をローカル環境にセットアップしました。このモデルはコードの生成のために特別にトレーニングされたものであり、同じパラメータ規模を持つ汎用モデルと比較して、コーディングベンチマークにおいて一貫して優れたパフォーマンスを発揮します。7B パラメータというサイズでありながら、8 GB の VRAM で快適に動作します。私は、実際のプロジェクトから生きた関数を与え、以下の 3 つの点を求めました:セキュリティ上の脆弱性、私が処理し忘れたエッジケース、そして不必要に巧妙になっている箇所です。
モデルをプルする
ollama pull qwen2.5-coder:7b
インタラクティブセッションを実行する
ollama run qwen2.5-coder:7b
私がすべてのレビューセッションで使用したシステムプロンプトは以下の通りです:
あなたはコードレビューを行うシニアソフトウェアエンジニアです。
あなたの仕事は、問題を発見することであり、励ますことではありません。
レビュー対象:
- セキュリティ上の脆弱性(インジェクション、認証の問題、データ露出)
- 処理されていないエッジケース
- 必要以上に複雑になっているコードの箇所
- 実際の条件下で破綻する可能性のある仮定
率直に述べてください。コードが何をしているかの要約は不要です。
見つけたことからすぐに始めてください。
私はこの関数を入力しました:
def get_user_data(user_id):
query = f"SELECT * FROM users WHERE id = {user_id}"
result = db.execute(query)
return result.fetchone()
必ず JSON 形式で返してください。translation フィールドのみ。他のフィールド (technical_terms 等) は一切追加しないこと — 余計なフィールドを書こうとして本文翻訳がトークン上限で打ち切られる事故を防ぐため:
{"translation": "翻訳全文"}
モデルは SQL インジェクションを即座に検知し、ワイルドカード SELECT * がデータ露出のリスクであることを指摘しました。さらに、ユーザーが存在しない場合に関数が静かに None を返すため、結果が使用される 3 つの呼び出し先で混乱を招くエラーが発生する可能性があると指摘しました。これら 3 つはすべて実際の課題でした。そのうち 2 つについては私が把握しており、「後で」修正する予定でしたが、1 つは本当に見落としていたものでした。
エディタにこの機能を統合したい開発者のために、VS Code および JetBrains 向けの Continue プラグインは、ローカルの Ollama インスタンスに直接接続します:
// .continue/config.json -- Continue をローカルモデルに指すためにこれを追加する
{
"models": [
{
"title": "Qwen2.5-Coder Local",
"provider": "ollama",
"model": "qwen2.5-coder:7b",
"apiBase": "http://localhost:11434"
}
]
}
これにより、インライン補完とチャットサイドバーが利用可能になります。すべてローカルで動作し、プライバシーは守られ、サブスクリプションも不要です。
# プロジェクト 3:完全オフラインの AI アシスタントの実行
**
これは一見シンプルに思えますが、AI ツールが実際に何のためにあるのかという私の考え方を大きく変えました。私は Wi-Fi が不安定な 10 時間のフライト中に、先延ばしにしてきた思考を要する作業の backlog を抱えていました。飛行中ずっと使える AI アシスタントが必要でした。接続が安定している間だけ断続的に使うのではなく、機内インターネットに料金を支払うことなく、航空会社のネットワークを通じて何を送信しているかを気にすることなく、一貫して利用できるものでした。
搭乗前にモデルを呼び出しました:
飛行前にダウンロードする -- これは Q4 量子化で 4.1 GB のファイルです
ollama pull mistral:7b
ローカルにキャッシュされていることを確認する
ollama list
mistral:7b がサイズと最終更新日付とともに表示されるはずです
これがセットアップのすべてです。ダウンロードが完了すると、Ollama はモデルをローカルファイルから完全に実行します。ラップトップを飛行機モードに切り替え、ターミナルを開きます。「ollama run mistral:7b」と入力するだけです。M2 MacBook Pro では約 8 秒でモデルが読み込まれ、即座に応答を開始します。ping は不要です。モデルはあなたが 35,000 フィートの高度にいることを知りませんし、気にもしません。
その飛行中に私がこれを使った用途:
- 後で編集するためのメールのドラフト作成。状況と望む結果を説明すると、モデルがドラフトを作成しました。私はそれを編集しました。ゼロから書くよりも速く、サーバーに何も送信する必要もありません。
- 技術的なアーキテクチャに関する質問への取り組み。私がずっと悩んでいたシステム設計の問題について説明しました。自分のアイデアに反論するもの(私のコードベースを完全に理解していなくても)があることは役立ちます。モデルは明確化のための質問を投げかけ、私はそれに応えました。最終的に、出発時よりも明確な立場を持つことができました。
- この記事の構成案作成。本当にそうでした。カバーしたい 5 つの使用事例を説明し、それらを構造化するよう助けを求め、降下中に順序と強調点を整理しました。
速度に関する正直なメモ: M2 MacBook Pro(統合メモリ16GB)では、Q4_K_M 量子化された Mistral 7B は、秒間約 25〜35 トークンの速度で動作します。これはリアルタイムの会話のように感じるには十分な速さです。古いハードウェアや GPU オフロード機能がない場合、速度は遅くなり、チャットというよりは読書に近い状態になりますが、ドラフト作成や思考作業としては依然として使用可能です。オフラインで行えないこと:リアルタイム情報(最新のニュース、ライブ価格、最近の研究)を必要とするものはすべてです。これはローカルモデル特有の制限ではなく、単なる物理法則の問題です。
# プロジェクト 4: あなたの文脈を知るパーソナル思考パートナーの作成
Claude、ChatGPT、またはクラウド AI のいずれと新しいチャットを開始するたびに、あなたはゼロから始めます。そのモデルはあなたについて、あなたの仕事、進行中のプロジェクト、すでに試したこと、あるいはあなたが問題を考えるのを好む方法について何も知りません。実りあるセッションの最初の 5 分間は、前回のセッションでも確立する必要があった文脈を再構築するために費やされます。これはすぐに飽き飽きするものです。
ローカルモデルは「Modelfile」と呼ばれる機能でこれを解決します。これは永続的なシステムプロンプトを名前付きモデルに直接焼き付ける短い設定ファイルです。一度作成すれば、そのモデルとのすべてのセッションが完全な文脈から始まります。再説明も不要、前置きも不要。
私が構築した Modelfile は以下の通りです:
任意のディレクトリに拡張子なしで「Modelfile」として保存してください
その後、以下を実行してください: ollama create myassistant -f Modelfile
FROM llama3.2:3b
この SYSTEM ブロックは、すべての会話の冒頭に注入されます
SYSTEM """
あなたは私の個人的な思考パートナーです。あなたが常に持っているコンテキストは以下の通りです:
私について:
私は技術ライター兼開発者であり、主に AI ツールと開発者教育に取り組んでいます。私は方向性を決定する前に、問題を書き起こしたり、声に出して議論することで最もよく考えます。
現在のプロジェクト:
- エージェント型 AI と LLM ツーリングに関する一連の技術記事
- 構造化されたプロンプト管理のための Python ライブラリ
- 個人用ナレッジベース向けの検索拡張生成(Retrieval-Augmented Generation: RAG)の研究
私が最もよく機能する方法:
- 私の前提に異議を唱えてください。同意よりも反対を好みます。
- プロンプトが曖昧な場合、回答する前に明確化のための質問を一つだけしてください。
- 私が決定の理由を説明しているときは、その推論が妥当かどうかを問いかけてください。
- 私が言ったことを要約して返さないでください。実際の回答から始めてください。
あなたが知っておくべきこと:
- 私はソフトウェア業界で 8 年間働いています。基本事項を過剰に説明しないでください。
- 執筆のサポートを求める場合は、飾り気のない構造と率直さを望んでいます。
- 文章で表現できる箇条書きは苦手です。
"""
適切な生成パラメータを設定します
PARAMETER temperature 0.7
PARAMETER top_p 0.9
PARAMETER num_ctx 4096
作成と実行:
Modelfile からモデルを作成します
ollama create myassistant -f Modelfile
モデルが正常に作成されたか確認します
ollama list
モデルを実行します -- すべてのセッションは、あなたの完全なコンテキストから始まります
ollama run myassistant
実践における違いは即座に現れます。同じ質問「この記事をコード例から始めるように再構成すべきでしょうか?」に対する、文脈を考慮しないモデルとパーソナライズされたモデルの 2 つの回答を比較してください。
文脈を考慮しないモデル:
**
"それは読者次第です。読者が技術的な内容に慣れているなら、コード例から始めることで学習内容を即座に示せるため効果的です。一方で、まず文脈を作りたいのであれば…"
パーソナライズされたモデル:**
**
"現在の構成はどのようなものですか?コードが自己完結的で、背景知識なしでも読者が追跡できるほど明確であれば、コードから始めることは有効です。あなたがツールを学習中の開発者向けに執筆していると言っていたので、熟練した実践家ではないとすれば、コードから始めることには反対します。最初のセクションを見せてください。それが単独で成立するかお伝えします。"
2 つ目の回答はあなたの実際の状況から始まります。「場合による」という枠組みに時間を浪費しません。あなたが箇条書きを避けたいと思っていることを知らないわけではありませんが、それは学習データに基づいているのではなく、一度教えてくれたことを記憶しているからです。
プロジェクトが変更されたらModelfile(モデルファイル)を常に更新してください。ollama create myassistant -f Modelfile を再度実行すれば、以前のバージョンが上書きされます。
# プロジェクト 5:実際にツールを使用するローカル AI エージェントの構築
必ず JSON 形式で返してください。translation フィールドのみ。他のフィールド (technical_terms 等) は一切追加しないこと — 余計なフィールドを書こうとして本文翻訳がトークン上限で打ち切られる事故を防ぐため:
{"translation": "翻訳全文"}
**
このリストの最初の4つは印象的ですが、それらは本質的に非常に能力の高いテキスト生成モデルとしての役割に留まります。これとは異なります。これは、計画し、行動し、結果を観察し、完成した出力を届けるシステム内部の意思決定エンジンとしてのモデルです。外部 AI サービスへのアプリケーションプログラミングインターフェース(API)呼び出しは一切行われません。
クラウドでのフォールバックなしで、ローカルモデルがエージェントタスクにおいてどこまで到達できるかを確認したかったのです。私は、Ollama の OpenAI 互換 API を経由して Llama 3.2 Instruct を実行する最小限の Python エージェントを構築しました。このエージェントにはウェブ検索とファイル作成という2つのツールを与え、タスクが完了するまで ReAct ループを実行します。外部コスト合計:0 ドル。**
まず、Ollama がモデルを提供していることを確認してください。
ollama serve # Ollama API サーバーを起動
ollama pull llama3.2:3b # インストラクションモデルが既にキャッシュされていない場合はダウンロード
Ollama API は OpenAI 互換です。つまり、1行を変更するだけで、OpenAI API を対象とするあらゆるフレームワークに差し替えることができます。以下が完全なローカルエージェントのコードです。
local_agent.py
インストール:pip install openai duckduckgo-search
要件:http://localhost:11434 でローカルで実行中の Ollama
from openai import OpenAI
import json
from duckduckgo_search import DDGS
OpenAI クライアントをローカルの Ollama インスタンスに向ける
これだけで、OpenAI 互換のツールがすべてローカルで動作するようになります
client = OpenAI(
base_url="http://localhost:11434/v1",
api_key="ollama" # Ollama は実際のキーを必要としない -- この文字列は任意のものでも構いません
)
MODEL = "llama3.2:3b" # これは、Ollama でプルした任意のモデルに変更してください
エージェントが呼び出せるツールを定義する
tools = [
{
"type": "function",
"function": {
"name": "web_search",
"description": (
"トピックに関する最新の情報をウェブで検索します。"
"最近変更された可能性のある事実やデータが必要な場合に使用してください。"
"会話内ですでに存在する情報については使用しないでください。"
),
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "具体的な検索クエリ(3〜8 語程度)。"
}
},
"required": ["query"]
}
}
},
{
"type": "function",
"function": {
"name": "write_file",
"description": "テキストコンテンツをローカルファイルに保存します。タスクが完了した際に使用してください。",
"parameters": {
"type": "object",
"properties": {
"filename": {
"type": "string",
"description": "出力先のファイル名(例:'summary.md')"
},
"content": {
"type": "string",
"description": "書き込む全文コンテンツ。"
}
},
"required": ["filename", "content"]
}
}
}
]
必ず JSON 形式で返してください。translation フィールドのみ。他のフィールド (technical_terms など) は一切追加しないこと — 余計なフィールドを書こうとして本文翻訳がトークン上限で打ち切られる事故を防ぐため:
{"translation": "翻訳全文"}
def web_search(query: str) -> str:
"""DuckDuckGo を使用して実際のウェブ検索を実行します -- API キーは不要です。"""
with DDGS() as ddgs:
results = list(ddgs.text(query, max_results=4))
if not results:
return "結果が見つかりませんでした。"
# モデルが読みやすいように結果をきれいに整形
return "\n\n".join(
f"Title: {r['title']}\nURL: {r['href']}\nSnippet: {r['body']}"
for r in results
)
def write_file(filename: str, content: str) -> str:
"""現在のディレクトリにファイルを記述します。"""
with open(filename, "w") as f:
f.write(content)
return f"ファイル '{filename}' が正常に書き込まれました ({len(content)} 文字)。"
def run_tool(name: str, arguments: dict) -> str:
"""ツール呼び出しを正しい関数へルーティングします。"""
if name == "web_search":
return web_search(arguments["query"])
elif name == "write_file":
return write_file(arguments["filename"], arguments["content"])
return f"不明なツール: {name}"
必ず JSON 形式で返してください。translation フィールドのみ。他のフィールド (technical_terms 等) は一切追加しないこと — 余計なフィールドを書こうとして本文翻訳がトークン上限で打ち切られる事故を防ぐため:
{"translation": "翻訳全文"}
def run_agent(goal: str, max_turns: int = 10) -> None:
"""
エージェントループ:
- 目標と現在の会話内容をローカルモデルに送信する
- モデルがツールの呼び出しを行った場合、それを実行して結果を会話に追加する
- モデルの処理が完了した場合、最終メッセージを出力して終了する
- 完了するか max_turns に達するまで繰り返す
"""
system = """あなたは研究エージェントです。目標を与えられた場合:
- web_search を使用して正確で最新の情報を検索する -- 異なる側面について複数回検索すること
- 十分な情報が得られ次第、write_file を使用して構造化された要約を保存する
- ファイルには以下の内容を含めること:主要な発見事項、その重要性、および情報源
各アクションを実行する前に慎重に思考すること。ファイルが書き込まれたら、あなたのタスクは完了です。"""
messages = [{"role": "user", "content": goal}]
for turn in range(max_turns):
print(f"\n--- Turn {turn + 1} ---")
# 会話をローカルモデルに送信する
response = client.chat.completions.create(
model=MODEL,
messages=[{"role": "system", "content": system}] + messages,
tools=tools,
tool_choice="auto"
)
choice = response.choices[0]
message = choice.message
# モデルが完了 -- 出力して終了する
if choice.finish_reason == "stop":
print(f"\nAgent finished: {message.content}")
return
モデルが1つ以上のツールを呼び出した場合 -- それぞれを実行
if choice.finish_reason == "tool_calls" and message.tool_calls:
# ツール呼び出しを含むモデルのメッセージを会話履歴に追加
messages.append({
"role": "assistant",
"content": message.content,
"tool_calls": [
{
"id": tc.id,
"type": "function",
"function": {
"name": tc.function.name,
"arguments": tc.function.arguments
}
}
for tc in message.tool_calls
]
})
# 各ツール呼び出しを実行し、結果を会話に追加
for tool_call in message.tool_calls:
name = tool_call.function.name
args = json.loads(tool_call.function.arguments)
print(f"Tool: {name}({args})")
result = run_tool(name, args)
print(f"Result preview: {result[:120]}...")
# ツール結果は、応答対象となる tool_call_id を参照する必要がある
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": result
})
print("Max turns reached.")
if __name__ == "__main__":
goal = (
"2026 年に最も活発に議論されているオープンソースの RAG フレームワークを 3 つ特定し、それぞれが何を行うものであり、誰にとって最適かを説明する要約を rag-summary.md に記述してください。"
)
print(f"Goal: {goal}\n")
run_agent(goal)
このコードが行うこと: OpenAI クライアントは OpenAI のサーバーではなく localhost:11434 を指し示します。そのたった一つの変更が、クラウド型エージェントとローカル型の間の決定的な違いです。DuckDuckGo 検索には API キーは不要です。このエージェントは、出力ファイルを作成するまで、完全な ReAct ループ(推論、行動、観察、再度推論)を実行します。すべてのステップがあなたのマシン上で実行されます。
モデル能力に関する正直な注記: パラメータ数が 30 億〜70 億のローカルモデルは、多段階推論において最先端のクラウドモデルと比較して明らかに速度が遅く、精度も劣ります。Llama 3.2 は、目標が明確で焦点を絞った場合にこのタスクを良好に処理します。より複雑なエージェント型タスクにおいては、Qwen3.5-4B または Mistral 7B Instruct が、より信頼性の高いツール呼び出し動作を生み出します。タスクを焦点化し、ツールのセットを小さく保つことが重要です。クラウドエージェントに適用される同じルールがここでも適用されますが、その傾向はさらに顕著です。
# まとめ
これら 5 つのことは、クラウド AI では全く同じ方法では不可能です。
クラウド AI が生来のベンチマーク性能において劣っているからではありません。Claude Opus や GPT-5 といった最先端モデルは、ラップトップ上でローカルで実行される anything よりも優れたパフォーマンスを発揮します。しかし、ベンチマーク結果がそのままユースケースを意味するわけではありません。
文書脳は、文書が機密情報であるためローカル環境でよりよく機能します。コードレビューアーは、コードが proprietary であるためローカル環境でより有用です。オフラインアシスタントは、クラウドが利用できないためローカル環境でのみ可能です。パーソナライズされたモデルは、クラウドセッションが設計上ステートレスであるため、ユーザーを記憶するのはローカル環境だけです。ローカルエージェントの実行コストはゼロです。なぜなら API のメーターが刻むことはないからです。
これらは妥協ではありません。モデルを自分で実行することが、適切な理由で正しい判断となるケースにおける、真の利点です。セットアップは 1 つのコマンド で完了します。モデルは無料です。天井(上限)は、実際には多くの人が予想するよりも高いことがわかりました。
Shittu Olumide は、最先端の技術を活用して説得力のある物語を構築することに情熱を持つソフトウェアエンジニアでありテクニカルライターです。細部への鋭い眼と複雑な概念を簡素化する才能を持っています。Shittu は Twitter でも活動しています。
原文を表示

**
# Introduction
The first time you run ollama run llama3.2 in a terminal and watch a 7-billion-parameter model load onto your own machine — no API key, no billing dashboard, no data leaving your computer — something shifts. Not because it is technically impressive, though it is. But because it is fast, it is capable, and it is entirely yours. You own the conversation. Nobody is logging it. Nobody is charging you per token. The model does not know or care that you are offline.
I have been running local models as part of my daily workflow for a while now, and what surprised me most is how often local turned out to be the better choice, not a compromise. What follows are five things I actually did with local language models that I would not have done (or could not have done) with a cloud tool. There is also working code where it matters.
"Local" means the model runs on your machine. The setup is Ollama**, a tool that makes downloading and running open-source models about as complicated as installing any other application. Most of what follows works on a machine with 8 GB of RAM for smaller models, 16 GB to get comfortable. Apple Silicon Macs (M1 and later) handle this surprisingly well thanks to unified memory. A dedicated NVIDIA GPU speeds things up significantly, but it is not a requirement to get started.
# Project 1: Building a Private Document Brain
**
I work with a mix of research papers, contracts, and project notes that accumulate faster than I can properly index them. At some point, I had three years' worth of PDFs, a handful of Word documents, and a folder of plain-text notes all sitting on disk — theoretically useful, none of them searchable in any meaningful way.
The obvious solution is to throw them at an AI and ask questions. The obvious problem is that uploading contracts and personal research notes to a cloud service means they are now on someone else's server, processed by someone else's infrastructure, and stored under someone else's retention policy. For anything sensitive — legal documents, medical records, internal business files, personal journals — that trade-off is hard to justify.
So I set up AnythingLLM** running locally against Llama 3.2 via Ollama. AnythingLLM is an open-source application that handles the full retrieval-augmented generation (RAG) pipeline — document ingestion, chunking, embedding, vector storage, and retrieval — without any cloud dependency. It has 54,000+ GitHub stars and runs entirely on your machine. You drag documents in, it processes them locally, and you start asking questions.
Getting it running takes one command:
# Pull and run AnythingLLM via Docker
# Everything stays on your machine -- no data leaves
docker run -d \
--name anythingllm \
-p 3001:3001 \
-v anythingllm_storage:/app/server/storage \
mintplexlabs/anythingllm
# Then open http://localhost:3001 in your browser
# Connect it to Ollama (already running at localhost:11434)
# and pull the model you want to use for document chat
ollama pull llama3.2:3bI loaded a folder of research papers and asked it questions that required reading across multiple documents:
This is the prompt I used:
"What are the key differences in how the 2023 and 2025 papers approach retrieval augmentation? Do they agree on chunking strategy or is there disagreement?"
The model pulled the right sections from each paper, cited which document each point came from, and identified a genuine methodological disagreement I had not noticed reading them separately. Every byte of those papers stayed on my machine.
The model that worked best for this: Llama 3.2 3B for speed on lighter hardware, and Mistral 7B if you have 8 GB of VRAM and want stronger synthesis across longer documents. For straight document Q&A on a machine with 16 GB of RAM, the difference is noticeable. Mistral reads more carefully.
Why this matters: This is the use case that makes local RAG genuinely better than cloud — not just equivalent. The document does not move. The AI does. Everything that makes cloud AI great — the reasoning, the synthesis, and the ability to answer questions across multiple sources — is present. Everything that makes it uncomfortable for sensitive material — the data transfer, the server-side logging, and the third-party dependency — is gone.
# Project 2: Running a Code Reviewer That Never Judges You
**
There is a specific kind of code review anxiety that most developers will recognize: you wrote something that works, but you are not proud of it. It is a bit clever in ways that future-you will resent. You suspect there is an edge case you have not handled. You want honest feedback before another human sees it.
The cloud AI route has an obvious catch. Pasting production code into ChatGPT or Claude means sending your company's intellectual property to a third-party server. Most employer non-disclosure agreements (NDAs) cover this, whether or not anyone is enforcing them. It is a real concern, especially for proprietary algorithms, internal business logic, or anything that touches customer data.
I set up Qwen2.5-Coder 7B** locally via Ollama. This model was specifically trained on code; it consistently outperforms general-purpose models of the same size on coding benchmarks. At 7B parameters, it runs comfortably on 8 GB of VRAM. I gave it real functions from a live project and asked for three things: security vulnerabilities, edge cases I had not handled, and anywhere I was being unnecessarily clever.
# Pull the model
ollama pull qwen2.5-coder:7b
# Run an interactive session
ollama run qwen2.5-coder:7bThe system prompt I used for every review session:
You are a senior software engineer doing a code review.
Your job is to find problems, not to be encouraging.
Review for:
1. Security vulnerabilities (injection, auth issues, data exposure)
2. Edge cases that are not handled
3. Anywhere the code is more complex than it needs to be
4. Any assumptions that will break under real conditions
Be direct. Do not summarize what the code does.
Start immediately with what you found.I fed it this function:
def get_user_data(user_id):
query = f"SELECT * FROM users WHERE id = {user_id}"
result = db.execute(query)
return result.fetchone()The model caught the SQL injection immediately, flagged the wildcard SELECT * as a data exposure risk, and pointed out that the function returns None silently if the user does not exist — which would cause a confusing error three calls later wherever the result was used. All three were real issues. Two of them I knew about and was planning to fix "later." One I had genuinely missed.
For developers who want this integrated into their editor, the Continue plugin for VS Code and JetBrains connects directly to a local Ollama instance:
// .continue/config.json -- add this to point Continue at your local model
{
"models": [
{
"title": "Qwen2.5-Coder Local",
"provider": "ollama",
"model": "qwen2.5-coder:7b",
"apiBase": "http://localhost:11434"
}
]
}After that, you get inline completions and a chat sidebar — all running locally, all private, no subscription.
# Project 3: Running a Completely Offline AI Assistant
**
This one sounds simple, but it changed how I think about what AI tools are actually for. I had a 10-hour flight with patchy Wi-Fi and a real backlog of thinking work I had been deferring. I wanted an AI assistant for the whole flight — not intermittently when the connection held, but consistently, without paying for in-flight internet, without worrying about what I was sending through the airline's network.
Before boarding, I pulled a model:
# Download before you fly -- this is a 4.1 GB file at Q4 quantization
ollama pull mistral:7b
# Verify it is cached locally
ollama list
# Should show mistral:7b with size and last modified dateThat is the entire setup. Once downloaded, Ollama runs the model entirely from local files. Put the laptop in airplane mode. Open a terminal. Type ollama run mistral:7b. The model loads in about 8 seconds on an M2 MacBook Pro and starts responding immediately. No ping required. The model does not know or care that you are at 35,000 feet.
What I used it for during that flight:
- Drafting emails to edit later. I described the situation and the outcome I wanted. The model wrote a draft. I edited it. Faster than writing from scratch, workable without sending anything to a server.
- Working through a technical architecture question. I described a system design problem I had been sitting with. Having something to push back on my ideas — even something that does not fully understand my codebase — is useful. The model asked clarifying questions. I answered them. By the end, I had a clearer position than when I started.
- Outlining this article. Genuinely. I described the five use cases I wanted to cover, asked it to help me structure them, and worked through the order and emphasis during the descent.
Honest note on speed: on an M2 MacBook Pro with 16 GB unified memory, Mistral 7B at Q4_K_M quantization runs at roughly 25–35 tokens per second. That is fast enough to feel like a real conversation. On older hardware or without GPU offloading, it is slower — more like reading than chatting — but still usable for drafting and thinking work. What you cannot do offline: anything that requires real-time information (current news, live prices, recent research). That is not a limitation of local models specifically; it is just physics.
# Project 4: Creating a Personal Thinking Partner That Knows Your Context
Every time you open a new chat with Claude, ChatGPT, or any cloud AI, you start from zero. The model knows nothing about you, your work, your ongoing projects, what you have already tried, or how you prefer to think through problems. The first five minutes of any substantive session are spent re-establishing the context you had to establish in the last session too. It gets old.
Local models solve this with a feature called a Modelfile — a short configuration file that bakes a persistent system prompt directly into a named model. You create it once, and every session with that model starts with full context. No re-explaining. No preamble.
Here is the Modelfile** I built:
# Save this as Modelfile (no extension) in any directory
# Then run: ollama create myassistant -f Modelfile
FROM llama3.2:3b
# This SYSTEM block is injected at the start of every conversation
SYSTEM """
You are my personal thinking partner. Here is the context you always have:
ABOUT ME:
I am a technical writer and developer working primarily on AI tooling and
developer education. I think best by writing and talking through problems
out loud before committing to a direction.
CURRENT PROJECTS:
- A series of technical articles on agentic AI and LLM tooling
- A Python library for structured prompt management
- Researching retrieval-augmented generation for personal knowledge bases
HOW I WORK BEST:
- Push back on my assumptions. I prefer disagreement to agreement.
- Ask one clarifying question if my prompt is ambiguous before answering.
- When I am explaining a decision, challenge whether my reasoning is sound.
- Do not summarize what I said back to me. Start with your actual response.
WHAT YOU SHOULD KNOW:
- I have been working in software for 8 years. Do not over-explain fundamentals.
- When I ask for help writing, I want structure and directness, not fluff.
- I am allergic to bullet points that could have been prose.
"""
# Set reasonable generation parameters
PARAMETER temperature 0.7
PARAMETER top_p 0.9
PARAMETER num_ctx 4096Creating and running it:
# Create the model from your Modelfile
ollama create myassistant -f Modelfile
# Verify it was created
ollama list
# Run it -- every session starts with your full context
ollama run myassistantThe difference in practice is immediate. Compare these two responses to the same question — "*Should I restructure this article to lead with the code examples?*" — from a context-free model versus the personalized one:
Context-free model:
"That depends on your audience. If your readers are more technical, leading with code examples can be effective because it immediately shows them what they'll learn. On the other hand, if you want to build context first..."
Personalized model:
"What's the current structure? Leading with code only works if the code is self-explanatory enough that a reader can follow without background. Given that you said you're writing for developers who are learning the tooling, not seasoned practitioners, I'd push back on leading with code. Give me the first section, and I'll tell you if it stands on its own."
The second response starts from your actual situation. It does not waste time on the "it depends" frame. It does not know you want to avoid bullet points because it was trained on your preferences; it knows because you told it once, and it always remembers.
Update the Modelfile whenever your projects change. Run ollama create myassistant -f Modelfile again, and it overwrites the previous version.
# Project 5: Building a Local AI Agent That Actually Uses Tools
**
The first four things on this list are impressive, but they are essentially the model as a very capable text generator. This one is different. This is the model as the decision-making engine inside a system that plans, acts, observes results, and delivers a finished output — with no application programming interface (API) call to any external AI service.
I wanted to see how far a local model could go on an agentic task without a cloud fallback. I built a minimal Python agent that runs Llama 3.2 Instruct via Ollama's OpenAI-compatible API, gives it two tools — a web search and a file writer — and runs the ReAct loop until the task is done. Total external cost: $0**.
First, make sure Ollama is serving the model:
ollama serve # starts the Ollama API server
ollama pull llama3.2:3b # pulls the instruct model if not already cachedThe Ollama API is OpenAI-compatible, which means you can swap it into any framework that targets the OpenAI API by changing one line. Here is the full local agent:
# local_agent.py
# Install: pip install openai duckduckgo-search
# Requires: Ollama running locally at http://localhost:11434
from openai import OpenAI
import json
from duckduckgo_search import DDGS
# Point the OpenAI client at your local Ollama instance
# This is the one-line swap that makes any OpenAI-compatible tool work locally
client = OpenAI(
base_url="http://localhost:11434/v1",
api_key="ollama" # Ollama does not require a real key -- this can be any string
)
MODEL = "llama3.2:3b" # Change this to any model you have pulled via Ollama
# Define the tools the agent can call
tools = [
{
"type": "function",
"function": {
"name": "web_search",
"description": (
"Search the web for current information on a topic. "
"Use when you need facts or data that may have changed recently. "
"Do NOT use for information already in the conversation."
),
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Specific search query, 3-8 words."
}
},
"required": ["query"]
}
}
},
{
"type": "function",
"function": {
"name": "write_file",
"description": "Save text content to a local file. Use when the task is complete.",
"parameters": {
"type": "object",
"properties": {
"filename": {
"type": "string",
"description": "The output filename, e.g. 'summary.md'"
},
"content": {
"type": "string",
"description": "The full text content to write."
}
},
"required": ["filename", "content"]
}
}
}
]
def web_search(query: str) -> str:
"""Run a real web search using DuckDuckGo -- no API key required."""
with DDGS() as ddgs:
results = list(ddgs.text(query, max_results=4))
if not results:
return "No results found."
# Format results cleanly for the model to read
return "\n\n".join(
f"Title: {r['title']}\nURL: {r['href']}\nSnippet: {r['body']}"
for r in results
)
def write_file(filename: str, content: str) -> str:
"""Write content to a file in the current directory."""
with open(filename, "w") as f:
f.write(content)
return f"File '{filename}' written successfully ({len(content)} characters)."
def run_tool(name: str, arguments: dict) -> str:
"""Route tool calls to the correct function."""
if name == "web_search":
return web_search(arguments["query"])
elif name == "write_file":
return write_file(arguments["filename"], arguments["content"])
return f"Unknown tool: {name}"
def run_agent(goal: str, max_turns: int = 10) -> None:
"""
The agent loop:
1. Send the goal and current conversation to the local model
2. If the model calls a tool, execute it and add the result to the conversation
3. If the model is done, print the final message and exit
4. Repeat until done or max_turns reached
"""
system = """You are a research agent. When given a goal:
1. Use web_search to find accurate, current information -- search multiple times for different aspects
2. When you have enough information, use write_file to save a structured summary
3. The file should include: key findings, why they matter, and sources
Think carefully before each action. When the file is written, your task is complete."""
messages = [{"role": "user", "content": goal}]
for turn in range(max_turns):
print(f"\n--- Turn {turn + 1} ---")
# Send conversation to the local model
response = client.chat.completions.create(
model=MODEL,
messages=[{"role": "system", "content": system}] + messages,
tools=tools,
tool_choice="auto"
)
choice = response.choices[0]
message = choice.message
# Model is done -- print and exit
if choice.finish_reason == "stop":
print(f"\nAgent finished: {message.content}")
return
# Model called one or more tools -- execute each one
if choice.finish_reason == "tool_calls" and message.tool_calls:
# Add the model's message (with tool calls) to conversation history
messages.append({
"role": "assistant",
"content": message.content,
"tool_calls": [
{
"id": tc.id,
"type": "function",
"function": {
"name": tc.function.name,
"arguments": tc.function.arguments
}
}
for tc in message.tool_calls
]
})
# Execute each tool call and add results to conversation
for tool_call in message.tool_calls:
name = tool_call.function.name
args = json.loads(tool_call.function.arguments)
print(f"Tool: {name}({args})")
result = run_tool(name, args)
print(f"Result preview: {result[:120]}...")
# Tool results must reference the tool_call_id they are responding to
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": result
})
print("Max turns reached.")
if __name__ == "__main__":
goal = (
"Find the three most actively discussed open-source RAG frameworks "
"in 2026 and write a summary to rag-summary.md explaining what each "
"one does and who it is best for."
)
print(f"Goal: {goal}\n")
run_agent(goal)What this code does: The OpenAI client is pointed at localhost:11434 instead of OpenAI's servers. That one change is the entire difference between a cloud agent and a local one. DuckDuckGo search requires no API key. The agent runs the full ReAct loop — reason, act, observe, reason again — until it writes the output file. Every step runs on your machine.
Honest note on model capability: local models at 3–7B parameters are noticeably slower and less precise at multi-step reasoning than frontier cloud models. Llama 3.2 handles this task well when the goal is clear and focused. For more complex agentic tasks, Qwen3.5-4B or Mistral 7B Instruct produce more reliable tool-calling behavior. Keep the tasks focused and the tool set small. The same rule that applies to cloud agents applies here, just more so.
# Wrapping Up
**
None of these five things is possible in quite the same way with cloud AI. Not because cloud AI is less capable in raw benchmark terms — frontier models like Claude Opus and GPT-5 outperform anything running locally on a laptop. But benchmarks are not use cases.
The document brain works better locally because the documents are sensitive. The code reviewer is more useful locally because the code is proprietary. The offline assistant is only possible locally because the cloud is not available. The personalized model only remembers you locally because cloud sessions are stateless by design. The local agent costs nothing to run because there is no API meter ticking.
These are not compromises. They are genuine advantages in cases where running the model yourself is the right call for the right reasons. The setup is one command. The models are free. The ceiling, as it turns out, is higher than most people expect.
Shittu Olumide** is a software engineer and technical writer passionate about leveraging cutting-edge technologies to craft compelling narratives, with a keen eye for detail and a knack for simplifying complex concepts. You can also find Shittu on Twitter.
関連記事
今日のまとめ
AI日報で今日の重要ニュースをまとめ読み