OllamaをLangChainと連携させる方法|PythonフレームワークでローカルLLMに会話履歴・チェーン処理・ツール統合を組み込む手順

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOMELinux技術 リナックスマスター.JP(Linuxマスター.JP)ローカルLLM > OllamaをLangChainと連携させる方法|PythonフレームワークでローカルLLMに会話履歴・チェーン処理・ツール統合を組み込む手順
「OllamaのREST APIを直接叩いていたら、会話履歴の管理がコードで煩雑になってきた」
「Function CallingやRAGをもっとシンプルな構成で実装できるPythonフレームワークを探している」

そんな悩みを抱えるLinuxエンジニアは多いはずです。この記事では、PythonのAIフレームワーク「LangChain」をOllamaと連携させる手順を解説します。ChatOllamaによるチャット実装、RunnableWithMessageHistoryを使った会話履歴管理、OllamaEmbeddingsとFAISSを組み合わせたローカルベクトル検索、さらにカスタムツール統合エージェントまで一通り動かせる構成をUbuntu Server上で構築します。OpenAI APIから乗り換える場合のコード差分も示すので、既存コードのローカルLLM化にも役立ちます。

この記事のポイント

・pip install langchain-ollama でChatOllama/OllamaEmbeddingsが使えるようになる
・ChatOllama(model="llama3.3:70b-instruct-q4_0") でOpenAI互換の会話実装が数十行で可能
・RunnableWithMessageHistoryで複数セッションの会話履歴をLangChainが自動管理する
・OllamaEmbeddings+FAISSでクラウド不要のローカルベクトル検索が完成する


OllamaをLangChainと連携させる方法|PythonフレームワークでローカルLLMに会話履歴・チェーン処理・ツール統合を組み込む手順

「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
図解60P/登録10秒/解除も3秒 / 詳細はこちら

LangChainがOllamaに必要な理由 — 生APIとの使い分け

OllamaにはREST APIとPython公式ライブラリ(ollamaパッケージ)が用意されており、基本的なチャットや構造化出力はこれで十分に実装できます。では、なぜLangChainを使うのか。答えは「アプリケーションの複雑さが増したとき」です。

Ollama公式APIで自前実装すると、会話履歴の管理(messages配列のメンテナンス)、プロンプトテンプレートの切り替え、複数ステップのチェーン処理、ベクトルDBとの連携など、それぞれのロジックを自分で書くことになります。コードが増えるにつれて管理が難しくなり、テストや再利用も困難になりがちです。

LangChainはこの「LLMアプリの配管工事」を抽象化したフレームワークです。ChatOllama・OllamaEmbeddingsのクラスを使えば、OpenAIとほぼ同じコードでOllamaが動きます。既存のOpenAI前提コードをローカルLLMへ乗り換えるときも、importパスとモデル名を変えるだけで済む場合が多いです。

一方、LangChainはバージョンごとの破壊的変更が多く、ドキュメントが追いつかない面もあります。シンプルなチャットやREST API連携だけなら、Ollama公式ライブラリの方が依存関係が少なくシンプルです。Ollamaの基本的なセットアップとREST APIの実装手順は「Ubuntu ServerでローカルLLMを構築する方法」で解説しています。LangChainは、RAGやエージェント、マルチステップのチェーン処理を実装するときに選択する——というのが現場での使い分けの目安です。

環境構築: langchain-ollamaとlangchain-communityのインストール手順

LangChainのOllama連携には、公式推奨の専用パッケージ langchain-ollama を使います。インストール前にOllamaが起動していることを確認しておきます。

1. Ollamaの起動確認

# Ollamaサービスの稼働状態を確認する $ systemctl status ollama * ollama.service - Ollama Service Loaded: loaded (/etc/systemd/system/ollama.service; enabled) Active: active (running) since Thu 2026-07-10 09:00:00 JST; 2h 20min ago Main PID: 12345 (ollama) # REST APIが応答しているかテストする $ curl -s http://localhost:11434/api/tags | python3 -m json.tool | head -10 { "models": [ { "name": "llama3.3:70b-instruct-q4_0", "size": 42000000000 } ] }

2. Python仮想環境の作成とパッケージのインストール

# Python仮想環境を作成する(Python 3.10以上を推奨) $ python3 -m venv ~/ollama-langchain-env $ source ~/ollama-langchain-env/bin/activate # LangChainのOllamaサポートパッケージをインストールする (ollama-langchain-env) $ pip install langchain-ollama langchain-community # FAISSとNumPyも合わせてインストールする(ベクトル検索で使用) (ollama-langchain-env) $ pip install faiss-cpu numpy # インストール確認 (ollama-langchain-env) $ python3 -c "from langchain_ollama import ChatOllama; print('OK')" OK

2026年7月時点の推奨バージョンは langchain-ollama 0.3.x、langchain-community 0.3.x です。langchain-ollamaはlangchain-communityのOllamaクラスを置き換える公式推奨パッケージです。`from langchain_community.chat_models import ChatOllama` のような旧インポートパスは非推奨になっているため、`from langchain_ollama import ChatOllama` の形に統一してください。両者を混在させるとAttributeErrorが発生することがあります。

ChatOllamaで会話を実装する — メッセージ型・ストリーミング・温度設定

ChatOllamaのインターフェースはChatOpenAIとほぼ同じです。HumanMessage・SystemMessage・AIMessageのメッセージ型を使うため、OpenAIからの乗り換えコードの変更量が少なくて済みます。

1. 基本的なチャット応答

# basic_chat.py from langchain_ollama import ChatOllama from langchain_core.messages import HumanMessage, SystemMessage llm = ChatOllama( model="llama3.3:70b-instruct-q4_0", base_url="http://localhost:11434", temperature=0.1, ) messages = [ SystemMessage(content="あなたはLinuxサーバー管理の専門家です。日本語で回答してください。"), HumanMessage(content="cronで毎日午前2時にシェルスクリプトを実行するにはどう書きますか?"), ] response = llm.invoke(messages) print(response.content)

# 実行結果の例 cronで毎日午前2時にスクリプトを実行するには、crontabに以下の行を追加します。 0 2 * * * /path/to/script.sh 各フィールドの意味は次の通りです。 ・0 — 分(0分) ・2 — 時(午前2時) ・* * * — 日・月・曜日(毎日)

2. ストリーミングレスポンスの受け取り

応答が長い場合はストリーミングで受け取ると、ユーザーへの表示が速くなります。

# streaming_chat.py from langchain_ollama import ChatOllama from langchain_core.messages import HumanMessage llm = ChatOllama( model="llama3.3:70b-instruct-q4_0", temperature=0.1, ) # stream()メソッドでチャンクごとに受け取る for chunk in llm.stream([HumanMessage(content="journalctlでエラーログのみ抽出する方法を教えてください")]): print(chunk.content, end="", flush=True) print() # 改行

temperature=0に近いほど決定論的な回答になり、技術系のHow-to回答に向きます。temperature=0.7~1.0はクリエイティブな文章生成向きです。コマンドや手順を扱う実務用途では0.1~0.3に絞るのが安定します。

会話履歴を持つチャットボットを作る — LCELとRunnableWithMessageHistory

1. LCELパイプ記法でプロンプトテンプレートとモデルをつなぐ

LCEL(LangChain Expression Language)は `|` 演算子でコンポーネントをチェーンする記法です。プロンプトテンプレート → LLM → 出力パーサーの流れを1行で書けます。

# lcel_chain.py from langchain_ollama import ChatOllama from langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser llm = ChatOllama(model="llama3.3:70b-instruct-q4_0", temperature=0.1) prompt = ChatPromptTemplate.from_messages([ ("system", "あなたはLinuxサーバー管理の専門家です。コマンドは正確に書いてください。"), ("human", "{question}"), ]) # プロンプトテンプレート → LLM → 文字列に変換 のチェーンを組み立てる chain = prompt | llm | StrOutputParser() result = chain.invoke({"question": "Nginxのアクセスログをリアルタイムで監視するコマンドを教えてください"}) print(result)

2. 複数セッションの会話履歴を管理するチャットボット

RunnableWithMessageHistoryを使うと、以前のやり取りをメモリに保持しながら複数ユーザーの会話を並行して管理できます。

# conversation_bot.py from langchain_ollama import ChatOllama from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain_core.output_parsers import StrOutputParser from langchain_community.chat_message_histories import ChatMessageHistory from langchain_core.runnables.history import RunnableWithMessageHistory llm = ChatOllama(model="llama3.3:70b-instruct-q4_0", temperature=0.1) prompt = ChatPromptTemplate.from_messages([ ("system", "あなたはLinuxサーバー管理の専門家です。"), MessagesPlaceholder(variable_name="history"), ("human", "{question}"), ]) chain = prompt | llm | StrOutputParser() # セッションIDごとに会話履歴をメモリ上で管理する store = {} def get_session_history(session_id: str) -> ChatMessageHistory: if session_id not in store: store[session_id] = ChatMessageHistory() return store[session_id] chain_with_history = RunnableWithMessageHistory( chain, get_session_history, input_messages_key="question", history_messages_key="history", ) config = {"configurable": {"session_id": "user_001"}} # 1回目の質問 answer1 = chain_with_history.invoke({"question": "cronの基本的な書き方を教えてください"}, config=config) print("1回目:", answer1[:80], "...") # 2回目(前の会話の文脈を引き継いでいる) answer2 = chain_with_history.invoke({"question": "では、毎週月曜の午前3時に実行するにはどう書きますか?"}, config=config) print("2回目:", answer2[:80], "...")

社内でChatGPTの代替としてローカルLLMを使う場面では、セッションIDをユーザーIDやチケット番号と紐付けることで、部門別・案件別の会話履歴管理が実現できます。社内導入の判断材料については「社内でChatGPTが使えないときの代替手段」でも整理しています。

OllamaEmbeddingsでローカルベクトル検索を実装する — FAISSとの組み合わせ

テキストをベクトルに変換してFAISSで類似検索する構成は、社内ドキュメントへの質問応答(RAG)の基盤になります。LangChainを使うとベクトルDB、エンベディングモデル、検索ロジックがクラスとして抽象化されているため、数十行で動く構成を書けます。

1. エンベディングモデルの取得と確認

# nomic-embed-textモデルを取得する(日本語テキストにも対応) $ ollama pull nomic-embed-text:latest pulling manifest pulling 970aa74c0a90... 100% ▕████████████████▏ 274 MB success # モデルの動作確認(Embeddingのベクトル次元数を確認) $ curl -s http://localhost:11434/api/embed \ -d '{"model":"nomic-embed-text","input":"Linuxのcronを設定する方法"}' \ | python3 -c "import sys,json; d=json.load(sys.stdin); print('次元数:', len(d['embeddings'][0]))" 次元数: 768

2. FAISSとOllamaEmbeddingsで類似検索を実装する

# faiss_search.py from langchain_ollama import OllamaEmbeddings from langchain_community.vectorstores import FAISS from langchain_core.documents import Document # エンベディングモデルの設定 embeddings = OllamaEmbeddings( model="nomic-embed-text", base_url="http://localhost:11434", ) # 社内マニュアルを想定したドキュメントを用意する docs = [ Document(page_content="cronジョブのログは /var/log/cron(RHEL系)または journalctl -u cron(Ubuntu)で確認できる"), Document(page_content="Nginxのアクセスログは /var/log/nginx/access.log に出力される。tail -f で監視できる"), Document(page_content="sudoの設定は /etc/sudoers を visudo コマンドで編集する。直接編集すると文法エラーでsudoが使えなくなる"), Document(page_content="SSHポートのデフォルトは22番。/etc/ssh/sshd_config の Port 行で変更できる"), Document(page_content="systemctlでサービスを再起動するには systemctl restart サービス名 を実行する"), ] # FAISSにドキュメントを登録してベクトルインデックスを作成する vectorstore = FAISS.from_documents(docs, embeddings) # 類似ドキュメントを検索する query = "cronの実行ログを確認したい" results = vectorstore.similarity_search(query, k=2) for i, doc in enumerate(results): print(f"--- 検索結果 {i+1} ---") print(doc.page_content) # インデックスをディスクに保存する(次回起動時に再利用できる) vectorstore.save_local("/tmp/faiss_index") # 保存したインデックスを読み込む場合 # loaded_vs = FAISS.load_local("/tmp/faiss_index", embeddings, allow_dangerous_deserialization=True)

# 実行結果の例 --- 検索結果 1 --- cronジョブのログは /var/log/cron(RHEL系)または journalctl -u cron(Ubuntu)で確認できる --- 検索結果 2 --- systemctlでサービスを再起動するには systemctl restart サービス名 を実行する

FAISSのインデックスはsave_local()とload_local()で永続化できます。大量のドキュメントを扱う場合はChromaやQdrantへの切り替えも検討してください。エンベディングモデルの性能差やVRAM要件については「ローカルLLMのモデルを比較する方法」で詳しく解説しています。

LangChainのツール統合でOllamaにコマンド実行・ファイル操作を組み込む

LangChainの@toolデコレータでカスタムツールを定義し、create_tool_calling_agentでエージェントを作ると、OllamaがPythonの関数を自律的に呼び出せる構成になります。ツール実行の可否判断をPythonコード側のホワイトリストで制御できるため、社内環境への導入時にセキュリティ上の制約を維持しやすいのが特徴です。

1. カスタムツールを定義してエージェントに渡す

# tool_agent.py import subprocess from langchain_ollama import ChatOllama from langchain_core.tools import tool from langchain.agents import AgentExecutor, create_tool_calling_agent from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder # ホワイトリスト形式のシェルコマンド実行ツールを定義する @tool def run_safe_command(command: str) -> str: """ 安全なLinuxコマンドを実行してその出力を返す。 使用可能なコマンド: df, free, uptime, systemctl status のみ。 """ ALLOWED_CMDS = ["df", "free", "uptime", "systemctl status"] allowed = any(command.strip().startswith(cmd) for cmd in ALLOWED_CMDS) if not allowed: return "エラー: このコマンドは実行が許可されていません" result = subprocess.run( command, shell=True, capture_output=True, text=True, timeout=10 ) return result.stdout or result.stderr tools = [run_safe_command] llm = ChatOllama(model="llama3.3:70b-instruct-q4_0", temperature=0) prompt = ChatPromptTemplate.from_messages([ ("system", "あなたはLinuxサーバー管理AIです。利用可能なツールを使ってサーバーの状態を調べて回答してください。"), MessagesPlaceholder(variable_name="chat_history", optional=True), ("human", "{input}"), MessagesPlaceholder(variable_name="agent_scratchpad"), ]) agent = create_tool_calling_agent(llm, tools, prompt) agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True) result = agent_executor.invoke({"input": "現在のメモリ使用状況とディスクの空き容量を確認して教えてください"}) print(result["output"])

ツール実行の権限制御はLLM側ではなくPythonコード側で行うことが基本です。LLMに「危険なコマンドは実行しないように」とシステムプロンプトで指示するだけでは不十分で、ホワイトリスト方式でPythonコードが実行可否を判断する設計にします。create_tool_calling_agentはFunction Callingに対応したモデル(llama3.3:70b-instruct-q4_0、mistral:7b-instruct-v0.3-q8_0等)が必要です。

よくあるエラーと対処 — タイムアウト・接続エラー・モデル非対応

1. model not found — モデル名の不一致

ChatOllamaに指定したモデルがOllamaにダウンロードされていない場合に発生します。

# 取得済みモデルを確認する $ ollama list NAME ID SIZE MODIFIED llama3.3:70b-instruct-q4_0 2df51abc23f4 42 GB 2 days ago # モデルを取得する(量子化タグも含めて正確に指定する) $ ollama pull llama3.3:70b-instruct-q4_0

量子化タグは `-q4_0` のサフィックス形式で指定します。`llama3.3:q4_0` のような単独サフィックス形式は実在しないため、ChatOllamaのmodelパラメータにも `ollama list` で表示されるモデル名をそのまま使うのが確実です。

2. httpx.ConnectError — OllamaのAPI接続失敗

# Ollamaサービスの状態を確認する $ systemctl status ollama # 停止していれば起動する $ sudo systemctl start ollama # APIの待受ポートを確認する(デフォルトは11434) $ ss -tlnp | grep 11434 LISTEN 0 4096 0.0.0.0:11434 0.0.0.0:* users:(("ollama",pid=12345,fd=3))

ChatOllamaのbase_url引数のデフォルトは `http://localhost:11434` です。実際の運用でリモートサーバーのOllamaに接続する場合は `base_url="http://192.168.1.100:11434"` のように明示的に指定してください。

3. FAISSのインストールエラー(ARM64環境)

Raspberry Pi等のARM64環境では `pip install faiss-cpu` がビルドエラーになることがあります。

# ARM64でfaiss-cpuのビルドに必要なライブラリを先に入れる $ sudo apt-get install -y libopenblas-dev $ pip install faiss-cpu --no-binary :all: # 代替としてChromaを使う方法もある $ pip install chromadb # コード側: from langchain_community.vectorstores import Chroma # vectorstore = Chroma.from_documents(docs, embeddings)

4. create_tool_calling_agentでツール呼び出しが機能しない

Function Calling非対応のモデルを使うとエージェントのツール呼び出しが失敗し、LLMが直接回答を返すだけになります。`ollama show モデル名 --modelfile | grep -i tools` でModelfileに `{{ .Tools }}` の記述があるモデルを選択してください。現時点で確実に対応しているのは llama3.3:70b-instruct-q4_0、mistral:7b-instruct-v0.3-q8_0、phi4:14b-instruct-q4_0 です。

本記事のまとめ

OllamaとLangChainを組み合わせると、会話履歴管理・プロンプトテンプレート・ベクトル検索・ツール統合がPythonのクラスとして扱えるようになります。Ollama公式ライブラリで直接REST APIを叩く構成と比べると抽象度が上がり、チームでのコード共有や機能拡張が容易になります。
やりたいこと クラス/コマンド
基本的なチャット ChatOllama(model="llama3.3:70b-instruct-q4_0").invoke(messages)
ストリーミング応答 ChatOllama(...).stream([HumanMessage(content="...")])
プロンプトチェーン ChatPromptTemplate.from_messages([...]) | ChatOllama(...) | StrOutputParser()
会話履歴管理 RunnableWithMessageHistory(chain, get_session_history, ...)
テキストのベクトル化 OllamaEmbeddings(model="nomic-embed-text").embed_query("...")
FAISSによる類似検索 FAISS.from_documents(docs, embeddings).similarity_search(query, k=2)
ツール統合エージェント AgentExecutor(agent=create_tool_calling_agent(llm, tools, prompt), tools=tools).invoke(...)

LangChainとOllamaの連携を2日間のハンズオンで習得する

RAG・エージェント・チェーン処理を実機GPU環境で手を動かしながら習得したい方向けに、「ローカルAIマスターセミナー」を開催しています。
少人数(最大8名)ZOOMハンズオン形式で実施しています。

>> ローカルAIマスターセミナーの詳細を確認する
ローカルLLMの構築・運用に関する関連記事もあわせて参考にしてください。

Ubuntu ServerでローカルLLMを構築する方法|Ollamaで機密データを外に出さず業務AIを動かす完全ガイド
社内でChatGPTが使えないときの代替手段|機密データを守るローカルLLMという選択肢
ローカルLLMのモデルを比較する方法|Llama3.3・Mistral・Gemma・Phi-4をUbuntuで使い分けるポイント

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は1分、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

登録10秒/合わなければ解除3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。