「Node.jsで社内向けWebアプリを作っている。バックエンドにOllamaを組み込む具体的な手順が知りたい」
そんな悩みを抱えるLinuxサーバー管理者・Webエンジニアは多いはずです。この記事では、Node.js 18以降で標準搭載されたfetchAPIを使ってOllamaのREST APIを呼び出し、TypeScriptで型安全なクライアントを実装する手順を解説します。
さらにExpress.jsのルートハンドラへの組み込み方と、ストリーミングレスポンスのリアルタイム受信まで、Ubuntu Server上で動作するコードとともに確認します。
この記事のポイント
・Node.js 18以降の標準fetchでOllamaのREST APIを追加パッケージなしで呼び出せる
・TypeScriptの型定義でOllamaのリクエスト・レスポンスを型安全に扱う実装手順
・stream: trueとReadableStreamを組み合わせてLLMのリアルタイム出力を受け取る方法
・Express.jsのPOSTルートにOllamaを組み込み、WebアプリのAPIエンドポイントとして公開する
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
JavaScriptからOllamaのAPIを呼び出す全体像
OllamaはHTTP REST APIを提供しています。GETリクエストで動作中のモデル一覧を取得でき、POSTリクエストでテキスト生成を呼び出せます。
JavaScriptでOllamaを呼び出すアプローチは2種類あります。
・Node.js 18以降に標準搭載の `fetch` を直接使う(追加パッケージ不要)
・npmパッケージ `ollama` をインストールしてSDKとして使う
この記事では `fetch` を直接使う方法を中心に解説します。標準APIを使うと動作原理が理解でき、後でSDKに切り替える際も迷いません。
既存のTypeScriptプロジェクトへの組み込みにもそのまま応用できます。
OllamaのUbuntu Serverへの導入はすでに完了している前提で進めます。まだの場合は「Ubuntu ServerでローカルLLMを構築する方法|Ollamaで機密データを外に出さず業務AIを動かす完全ガイド」を先に確認してください。
Node.js 18とTypeScriptの開発環境をUbuntu Serverに用意する
Ubuntu 24.04 LTSではNode.js 20以上が標準リポジトリから導入できます。Node.js 18以上であれば標準fetchが使えるため、今回の手順はどちらでも動作します。
1. Node.jsとnpmをインストールする
# sudo apt update && sudo apt install -y nodejs npm # node --version v20.18.0 # npm --version 10.8.2
2. プロジェクトディレクトリとTypeScript環境をセットアップする
# mkdir ollama-ts && cd ollama-ts # npm init -y # npm install --save-dev typescript tsx @types/node # npx tsc --version Version 5.6.3
開発中の動作確認に使います。
3. TypeScriptの設定ファイルを作成する
`tsconfig.json` を以下の内容で作成します。{ "compilerOptions": { "target": "ES2022", "module": "NodeNext", "moduleResolution": "NodeNext", "strict": true, "outDir": "dist" }, "include": ["src/**/*"] }
`mkdir -p src` でソースディレクトリを作成してから次のステップに進みます。
fetchAPIを使ってOllamaに基本リクエストを送る
fetchAPIの基本的な使い方をGETとPOSTの2種類で確認します。Ollamaが `localhost:11434` で動いていることをあらかじめ確認してから進めます。
1. GETリクエストでモデル一覧を取得する
`src/list-models.ts` を作成します。const res = await fetch('http://localhost:11434/api/tags'); const data = await res.json() as { models: Array<{ name: string }> }; for (const model of data.models) { console.log(model.name); }
# npx tsx src/list-models.ts llama3.3:70b-instruct-q4_0 phi4:14b-q4_0
2. POSTリクエストでテキスト生成を呼び出す
`src/basic-generate.ts` を作成します。const res = await fetch('http://localhost:11434/api/generate', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ model: 'llama3.3:70b-instruct-q4_0', prompt: 'Linuxのパーミッション設定を3行で教えてください', stream: false, }), }); const data = await res.json() as { response: string; done: boolean }; console.log(data.response);
# npx tsx src/basic-generate.ts Linuxのパーミッションは読み取り(r)・書き込み(w)・実行(x)の3種類で...
短いプロンプトでは数秒で返りますが、長い文章の生成では10秒以上かかることがあります。
3. chat APIを使って会話形式のリクエストを送る
テキスト生成APIとは別に、チャット形式のAPIも使えます。const res = await fetch('http://localhost:11434/api/chat', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ model: 'llama3.3:70b-instruct-q4_0', messages: [ { role: 'user', content: 'crontabの書き方を教えてください' }, ], stream: false, }), }); const data = await res.json() as { message: { content: string }; done: boolean }; console.log(data.message.content);
複数ターンの会話を扱う場合は `/api/chat` が適しています。
TypeScriptで型安全なOllamaクライアントを実装する
フェッチの呼び出しをそのまま使い続けると、`as` による型アサーションが各所に散らばります。型定義と関数を整理して、安全に再利用できる形にします。
社内でローカルLLMを導入する背景については「社内でChatGPTが使えないときの代替手段|機密データを守るローカルLLMという選択肢」が参考になります。
1. APIリクエスト・レスポンスの型を定義する
`src/ollama-types.ts` を作成します。export interface OllamaChatMessage { role: 'system' | 'user' | 'assistant'; content: string; } export interface OllamaChatRequest { model: string; messages: OllamaChatMessage[]; stream?: boolean; options?: { temperature?: number; num_ctx?: number; }; } export interface OllamaChatResponse { model: string; message: OllamaChatMessage; done: boolean; total_duration?: number; eval_count?: number; }
2. 再利用可能なclient関数を作る
`src/ollama-client.ts` を作成します。import type { OllamaChatRequest, OllamaChatResponse } from './ollama-types.js'; const BASE_URL = process.env.OLLAMA_HOST ?? 'http://localhost:11434'; export async function chat(request: OllamaChatRequest): Promise
{ const res = await fetch(`${BASE_URL}/api/chat`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ ...request, stream: false }), signal: AbortSignal.timeout(120_000), }); if (!res.ok) { throw new Error(`Ollama API error: ${res.status} ${res.statusText}`); } return res.json() as Promise ; }
LLMのモデルサイズによっては生成に時間がかかるため、適切な値に調整します。
`process.env.OLLAMA_HOST` を参照することで、後から環境変数で向き先を変更できます。
3. 型エラーなしで呼び出せることを確認する
# npx tsc --noEmit # echo "型エラーなし" 型エラーなし
エラーが出なければ型定義は正しく機能しています。
ストリーミングレスポンスをリアルタイムで受け取る
`stream: false` ではLLMの生成が完了してから全文が返ります。長文の生成では応答が来るまで画面が固まったように見えます。
`stream: true` にするとトークンが生成されるたびに少量のJSONが返り、リアルタイムに表示できます。
1. stream: trueでリクエストを送る
`src/streaming.ts` を作成します。const res = await fetch('http://localhost:11434/api/chat', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ model: 'llama3.3:70b-instruct-q4_0', messages: [{ role: 'user', content: 'Linuxのcronを3行で説明してください' }], stream: true, }), });
2. ReadableStreamとTextDecoderで分割受信する
Ollamaのストリーミングレスポンスは改行区切りのJSONを順番に送ってきます。if (!res.body) throw new Error('Response body is null'); const reader = res.body.getReader(); const decoder = new TextDecoder('utf-8'); while (true) { const { done, value } = await reader.read(); if (done) break; const lines = decoder.decode(value, { stream: true }).split('\n'); for (const line of lines) { if (!line.trim()) continue; const chunk = JSON.parse(line) as { message?: { content: string }; done: boolean }; if (chunk.message?.content) { process.stdout.write(chunk.message.content); } } } process.stdout.write('\n');
3. ターミナルにリアルタイム出力する
# npx tsx src/streaming.ts Linuxのcronはタスクスケジューラです。 設定ファイルはcrontabコマンドで編集し...
モデルによってトークンの速度は異なりますが、生成の開始は `stream: false` と比べて体感的に速く感じます。
量子化によって速度と精度のバランスが変わるため、モデル選定に迷う場合は「ローカルLLMのモデルを比較する方法|Llama3.3・Mistral・Gemma・Phi-4をUbuntuで使い分けるポイント」が参考になります。
Express.jsのAPIルートにOllamaを組み込む
ここまでで実装したTypeScriptクライアントを、Express.jsのWebアプリのバックエンドとして動かします。社内チャットツールやドキュメント検索ツールのAPIとして利用できます。
1. expressとその型定義をインストールする
# npm install express # npm install --save-dev @types/express
2. /api/chatルートを実装する
`src/server.ts` を作成します。import express from 'express'; import { chat } from './ollama-client.js'; const app = express(); app.use(express.json()); app.post('/api/chat', async (req, res) => { const { prompt, model } = req.body as { prompt: string; model?: string }; if (!prompt) { res.status(400).json({ error: 'prompt is required' }); return; } try { const result = await chat({ model: model ?? 'llama3.3:70b-instruct-q4_0', messages: [{ role: 'user', content: prompt }], }); res.json({ answer: result.message.content }); } catch (err) { const message = err instanceof Error ? err.message : 'Unknown error'; res.status(500).json({ error: message }); } }); const PORT = Number(process.env.PORT ?? 3000); app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
3. curlでエンドポイントを確認する
別のターミナルでサーバーを起動して確認します。# npx tsx src/server.ts & Server running on port 3000 # curl -s -X POST http://localhost:3000/api/chat \ -H "Content-Type: application/json" \ -d '{"prompt":"Linuxのcronを1行で説明して"}' | python3 -m json.tool { "answer": "Linux の cron は、指定した時刻にコマンドを自動実行するスケジューラです。" }
このエンドポイントをフロントエンドから呼び出すことで、チャットUIのバックエンドとして機能します。
環境変数とエラー処理を整備する
開発中は `localhost:11434` で動作しますが、本番では別サーバーのOllamaに向けることがあります。接続先を環境変数で管理し、fetchの失敗を適切にハンドルします。
1. OllamaのURLを環境変数で管理する
`.env` ファイルを作成します(このファイルは `.gitignore` に追加します)。# cat .env OLLAMA_HOST=http://10.0.0.100:11434 PORT=3000
`ollama-client.ts` の `process.env.OLLAMA_HOST ?? 'http://localhost:11434'` がそのまま参照します。
2. fetchの失敗とネットワークエラーを区別する
fetchは次の2種類の失敗を区別して処理する必要があります。・`fetch()` 自体が例外をスローする(Ollamaに到達できない場合)
・`res.ok` が false になる(Ollamaが4xx/5xxを返す場合)
`ollama-client.ts` の `chat` 関数は両方を `throw new Error(...)` で統一していますが、エラーの種類を分けたい場合は以下のように判別できます。
try { const result = await chat({ model: 'llama3.3:70b-instruct-q4_0', messages }); return result; } catch (err) { if (err instanceof TypeError) { // ネットワーク到達不能(Ollamaがダウンしているなどのケースをここで処理する) console.error('Ollama に接続できません:', err.message); } else { // HTTPエラー(401, 404, 500 など) console.error('Ollama APIエラー:', err instanceof Error ? err.message : err); } throw err; }
Ollamaが応答しているが4xxや5xxを返した場合は `Error` がスローされます。
よくあるエラーと対処法
「TypeError: fetch failed」になる
Ollamaが起動していないか、指定したURLに到達できない場合に発生します。# systemctl status ollama # curl http://localhost:11434/api/tags
別サーバーのOllamaに向けている場合は、Ollamaのバインドアドレスがデフォルトのループバックのままになっていないか確認します。
「JSON.parse: Unexpected token」になる
ストリーミング処理で、1回の `reader.read()` に複数のJSON行が含まれることがあります。`.split('\n')` で行ごとに分割してから `JSON.parse` するようにします。空行はスキップします。
TypeScriptのimport文で「.js拡張子が必要」というエラーが出る
`"module": "NodeNext"` を設定したプロジェクトでは、TypeScriptファイル間のimportでも `.js` 拡張子が必要です。// 誤り import { chat } from './ollama-client'; // 正しい import { chat } from './ollama-client.js';
生成が途中でタイムアウトする
70bクラスのモデルは1回の生成に数十秒かかることがあります。`ollama-client.ts` の `AbortSignal.timeout(120_000)` を `300_000`(5分)程度に延ばして試します。
Expressの `res.timeout` も合わせて延ばします。
まとめ
この記事ではNode.js標準のfetchAPIを使ってOllamaのREST APIをTypeScriptから呼び出し、Express.jsのWebアプリに組み込む手順を解説しました。Pythonが使えない環境や、既存のNode.jsプロジェクトにローカルLLMを追加したい場面でそのまま応用できます。
20年以上サーバー管理に携わった経験からも、言語やフレームワークに依存しないHTTP REST APIの理解が、どのスタックへの組み込みにも共通する基礎になります。
| 実装ステップ | 主なコマンド・ファイル | 目的 |
|---|---|---|
| 環境構築 | npm install --save-dev typescript tsx @types/node | TypeScriptをビルドなしで実行できる環境を整える |
| 基本リクエスト | fetch('http://localhost:11434/api/chat', { method: 'POST', ... }) | 依存ゼロでOllamaのREST APIを呼び出す |
| 型安全化 | npx tsc --noEmit | TypeScriptの型チェックでリクエスト・レスポンスを守る |
| ストリーミング | res.body.getReader() + TextDecoder | 生成されるトークンをリアルタイムに受け取る |
| Webアプリ組み込み | npm install express && npx tsx src/server.ts | OllamaをExpress.jsのPOSTルートとして公開する |
OllamaのAPI活用からWebアプリ連携まで2日間のハンズオンで体験する
ローカルLLMの導入からREST API・チームWebアプリへの組み込みまで、実機GPU環境で手を動かして学びたい方向けに、「ローカルAIマスターセミナー」を開催しています。
少人数(最大8名)ZOOMハンズオン形式で実施しています。
・Ubuntu ServerでローカルLLMを構築する方法|Ollamaで機密データを外に出さず業務AIを動かす完全ガイド
・社内でChatGPTが使えないときの代替手段|機密データを守るローカルLLMという選択肢
・ローカルLLMのモデルを比較する方法|Llama3.3・Mistral・Gemma・Phi-4をUbuntuで使い分けるポイント
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら
- 前のページへ:OllamaをWatchdogスクリプトで自動復旧させる方法|bashとcronで異常検知・自動再起動・アラート通知を実装する手順
- この記事の属するカテゴリ:ローカルLLMへ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。
登録無料・いつでも解除できます