1. はじめに
「社内データを外に出さずにチャットを試したい」「オフラインで動く LLM アプリが欲しい」——そんなときに便利なのが Foundry Local です。Foundry Local は Microsoft が提供するオンデバイス AI ソリューションで、モデルの取得・ハードウェア高速化・推論をアプリのプロセス内で完結させます。
本記事では、Foundry Local を使って 端末内だけで動くマルチターン・チャットアプリを作ります。OpenAI 互換 API に対応しているため、普段 OpenAI SDK を使っている方ならほぼ同じ書き方で実装できます。
2. Foundry Local とは
Foundry Local は、ONNX Runtime を基盤とする軽量ランタイムで、次の特徴があります。
- オンデバイス完結: プロンプトも応答も端末内で処理され、初回のモデル取得以外はネットワーク不要です。
- ハードウェア自動選択: GPU・NPU・CPU を検出し、最適な実行プロバイダーを自動で選びます。
- OpenAI 互換 API: OpenAI SDK や REST クライアントからそのまま呼び出せます。
- Azure サブスクリプション不要: ローカルのハードウェアだけで動きます。
カタログには Phi・Qwen・DeepSeek・Mistral・GPT OSS などのチャットモデルが収録されています。他のランタイム(Ollama・LM Studio・llama.cpp・vLLM)との位置づけは 2026年版 ローカル LLM 実行環境の比較:Foundry Local・Ollama・LM Studio・llama.cpp・vLLM を参照してください。
3. 事前準備:Foundry Local のインストール
まず Foundry Local 本体をインストールします。OS に合わせて次のコマンドを実行してください。
# Windows
winget install Microsoft.FoundryLocal
# macOS(Apple Silicon)
brew tap microsoft/foundrylocal
brew install foundrylocal
インストールできたらバージョンとサービス状態を確認します。
foundry --version
foundry service status
サービス接続エラー(
Request to local service failedなど)が出た場合は、foundry service restartで復旧することが多いです。
4. CLI でチャットを動作確認する
アプリを書く前に、CLI だけでチャットを試して動作を確認しましょう。まず利用可能なモデルの一覧を表示します(初回はハードウェアに合う実行プロバイダーが自動ダウンロードされます)。
foundry model list
一覧からエイリアスを選び、対話セッションを開始します。ここでは軽量で扱いやすい Phi の小型モデルを使います。
foundry model run phi-4-mini
初回はモデルがダウンロードされ、その後プロンプトを入力すると応答が返ります。foundry model run はエイリアスを指定すると、端末のハードウェアに最適なモデルの変種(CUDA 版・NPU 版など)を自動で選択します。
phi-4-miniが見つからない場合は、foundry model listに表示されるエイリアスへ読み替えてください。とにかく軽く試すならqwen2.5-0.5bでも動きます。
5. アプリの全体像
これから作るアプリの処理経路は次のとおりです。アプリは OpenAI SDK 経由で、Foundry Local が起動する OpenAI 互換のローカル REST サーバーに接続します。その先は Core API → ONNX Runtime → 実行プロバイダーと、すべて端末内で処理されます。
6. Python プロジェクトの準備
仮想環境を作り、必要な 2 つのパッケージをインストールします。
python -m venv .venv
# Windows: .venv\Scripts\activate / macOS・Linux: source .venv/bin/activate
pip install -U pip
pip install foundry-local-sdk openai
Windows でより広いハードウェアアクセラレーション(Windows ML 連携)を使う場合は、
foundry-local-sdkの代わりにfoundry-local-sdk-winmlをインストールします。
7. チャットアプリの実装
app.py を作成します。処理は「Foundry Local を初期化してモデルをロードする準備部分」と「会話を繰り返すチャットループ」に分かれます。
会話履歴を messages リストに積み上げることでマルチターンの対話になり、stream=True でトークンを逐次表示します。
# app.py
import openai
from foundry_local_sdk import Configuration, FoundryLocalManager
ALIAS = "phi-4-mini" # foundry model list で確認。軽量に試すなら "qwen2.5-0.5b"
def setup_chat_client():
"""Foundry Local を初期化し、モデルをロードして OpenAI 互換クライアントを返す。"""
# 1. SDK を初期化
config = Configuration(app_name="local-chat-app")
FoundryLocalManager.initialize(config)
manager = FoundryLocalManager.instance
# 2. 端末に最適な実行プロバイダー(EP)を取得・登録(初回のみ時間がかかる)
manager.download_and_register_eps(
progress_callback=lambda ep, pct: print(
f"\rEP 準備中 {ep}: {pct:5.1f}%", end="", flush=True
)
)
print()
# 3. モデルを取得・ダウンロード・ロード
model = manager.catalog.get_model(ALIAS)
model.download(lambda pct: print(f"\rモデル取得中: {pct:5.1f}%", end="", flush=True))
print()
model.load()
print(f"モデル {model.id} をロードしました。")
# 4. OpenAI 互換のローカル REST サーバーを起動して接続
manager.start_web_service()
client = openai.OpenAI(base_url=f"{manager.urls[0]}/v1", api_key="none")
return manager, model, client
def main():
manager, model, client = setup_chat_client()
messages = [
{"role": "system", "content": "あなたは親切で簡潔に答える日本語アシスタントです。"}
]
print("\nチャットを開始します('exit' で終了)\n")
try:
while True:
user_input = input("You: ").strip()
if user_input.lower() in {"exit", "quit"}:
break
if not user_input:
continue
messages.append({"role": "user", "content": user_input})
# ストリーミングで応答を受け取りつつ表示
print("AI: ", end="", flush=True)
reply = ""
stream = client.chat.completions.create(
model=model.id,
messages=messages,
stream=True,
)
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
piece = chunk.choices[0].delta.content
print(piece, end="", flush=True)
reply += piece
print("\n")
# 応答を履歴に追加して次のターンの文脈にする
messages.append({"role": "assistant", "content": reply})
finally:
# 後片付け:モデルをアンロードし、サーバーを停止
model.unload()
manager.stop_web_service()
print("モデルをアンロードしました。")
if __name__ == "__main__":
main()
チャットループの中で messages がどう育つかを図にすると、マルチターンの仕組みがつかめます。毎ターン、ユーザー発話と AI 応答の両方を履歴へ積み上げ、その全体を毎回モデルへ送ることで文脈が保たれます。
8. 実行する
仮想環境を有効にした状態で実行します。
python app.py
初回は実行プロバイダーとモデルのダウンロードに数分かかることがあります。準備が終わると対話できます。
モデル Phi-4-mini-instruct-... をロードしました。
チャットを開始します('exit' で終了)
You: 自己紹介して
AI: こんにちは。ローカルで動く AI アシスタントです。…
You: いまの説明を一言で
AI: 端末内で動く、あなた専用のアシスタントです。
You: exit
モデルをアンロードしました。
2 つ目の質問で「いまの説明を」と指示しても文脈が通じるのは、会話履歴を messages に積み上げているためです。
9. (任意)Gradio で Web UI にする
ターミナルの代わりにブラウザの UI で使いたい場合は、Gradio を使うと数行で Web チャットにできます。pip install gradio を追加し、先ほどの setup_chat_client() を再利用します。
# web.py
import gradio as gr
from app import setup_chat_client # 7 章のセットアップ関数を再利用
manager, model, client = setup_chat_client()
def chat(message, history):
# history は {"role", "content"} の辞書リスト(Gradio 5 の messages 形式)
messages = [{"role": "system", "content": "あなたは親切な日本語アシスタントです。"}]
messages.extend(history)
messages.append({"role": "user", "content": message})
reply = ""
stream = client.chat.completions.create(
model=model.id, messages=messages, stream=True
)
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
reply += chunk.choices[0].delta.content
yield reply # 部分応答を逐次返してストリーミング表示
gr.ChatInterface(chat, type="messages", title="ローカルチャット (Foundry Local)").launch()
python web.py を実行すると、http://127.0.0.1:7860 でブラウザチャットが開きます。モデルは起動時に一度だけロードし、リクエストごとに再読込しないのがポイントです。
ノーコードでブラウザ UI を使いたいだけなら、CLI で
foundry model run <model>を起動したまま、Open WebUI を Foundry Local のローカルエンドポイントに接続する方法もあります。
10. つまずきポイント
- モデルのエイリアスが見つからない:
foundry model listで実際に利用可能なエイリアス/モデル ID を確認し、ALIASを読み替えます。 - 初回が遅い: 実行プロバイダーとモデルのダウンロードが走るためです。2 回目以降はキャッシュから即座に起動します。
- サービスに接続できない:
foundry service restartでサービスを再起動します。状態はfoundry service statusで確認できます。 - 応答品質が物足りない: 小型モデルは複雑な推論が苦手です。
foundry model listでより大きめのモデルを選ぶか、用途に合うモデルへ切り替えます。 - リソースを解放したい: 終了時に
model.unload()とmanager.stop_web_service()を必ず呼びます(本記事のコードはfinallyで実行します)。
11. まとめ
- Foundry Local なら、
foundry-local-sdkとopenaiの 2 パッケージで端末内完結のチャットアプリを作れます。 - 会話履歴を
messagesに積み上げればマルチターン、stream=Trueでトークンの逐次表示が実現できます。 - モデルは初回だけダウンロードされ、以降はオフラインで動作。プロンプトも応答も端末の外に出ません。
- Gradio を足せば、同じロジックのままブラウザ UI に拡張できます。
- 次のアクション: 軽い処理はローカル、重い処理はクラウドへ振り分ける構成は ローカル LLM × Azure エージェント:Phi-4 と Azure を組み合わせたコスト削減構成 が参考になります。
12. 参考リンク
- Foundry Local をはじめる — モデルの取得・ロード・推論までのクイックスタート
- 推論 SDK と Foundry Local の連携 — OpenAI 互換 SDK でローカルモデルを呼び出す方法
- Foundry Local CLI リファレンス —
foundryコマンドの一覧とインストール手順 - Foundry Local アーキテクチャ概要 — Core API・ONNX Runtime・実行プロバイダーの仕組み
この記事の執筆にあたり、AI の支援を受けています。






