「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でクラウド不要のローカルベクトル検索が完成する
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
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
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() # 改行
会話履歴を持つチャットボットを作る — 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], "...")
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 サービス名 を実行する
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"])
よくあるエラーと対処 — タイムアウト・接続エラー・モデル非対応
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
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))
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ハンズオン形式で実施しています。
・Ubuntu ServerでローカルLLMを構築する方法|Ollamaで機密データを外に出さず業務AIを動かす完全ガイド
・社内でChatGPTが使えないときの代替手段|機密データを守るローカルLLMという選択肢
・ローカルLLMのモデルを比較する方法|Llama3.3・Mistral・Gemma・Phi-4をUbuntuで使い分けるポイント
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
登録10秒/合わなければ解除3秒 / 詳細はこちら

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