【技術解説】LangChainとLangGraphでAIエージェント開発に入門してみた【初心者】
最初に結論: LangChainとLangGraphを活用すると、AIエージェント構築・拡張がしやすいっぽい!
↑そんなの知っとるわいと言う人はこの記事をスルーしてください!
LLMアプリやAIエージェント・RAGに興味があって、LangChainって結局なんだ?と思っている人はもしかしたら役立つかも!
今回は、LangChainとLangGraphによるRAG・AIエージェント[実践]入門を最後まで読んだので、結局LangChainって何だったんだ?ってのを軽くまとめようと思って備忘録的に書いてみました。
LLM・AIエージェント実装初心者の方向けにLangChainとLangGraphの基本的な内容を理解し、活用イメージを持てることを目標に書いてみます!
- 本当に簡単な技術説明:
- LangChain: LLMアプリケーション開発を簡単にするフレームワーク
- LangGraph: LangChainを拡張。マルチステップ・並列処理を効率的に構築できるワークフロー管理ツール
なぜLangChainが必要なのか
1. LangChainが必要になる瞬間って?
- LLM APIを直接叩くのは簡単ですが、LLMを「アプリ」として動かすには課題があります。
- 毎回プロンプトを作るのが面倒(テンプレート化したい)
- 会話の流れが記憶されない(履歴を管理したい)
- 外部データ(DB・API・検索エンジン)を参照できない(ナレッジ活用したい)
- ユーザーの質問に応じて柔軟に処理を変えたい(動的フロー制御したい)
- 例えば
- ユーザーが何度も問い合わせてくるサポートチャットボットを作りたいが、API直叩きでは会話履歴が保持できない
- こういう時に LangChain が役立ちます!
2. LangChainの概要
- LangChainとは?
それではひとまず簡単な例を見てもらいます。
from langchain.schema import HumanMessage, SystemMessage
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4", openai_api_key="your_api_key")
messages = [
SystemMessage(content="あなたは親切なアシスタントです")
HumanMessage(content="こんにちは!")
]
response = llm.invoke(messages)
print(response.content)
"こんにちは!今日はどんなことをお手伝いできますか?"
…APIを叩くのと変わらないと思いましたか?まぁシンプルな実装例だとそうなります。
では続きましてMemoryモジュールを使ってみましょうか
# 会話を保持してくれるMemoryを使った実装例
from langchain.chains import ConversationChain
from langchain.chat_models import ChatOpenAI
from langchain.memory import ConversationBufferMemory
memory = ConversationBufferMemory()
llm = ChatOpenAI(model="gpt-4", openai_api_key="your_api_key")
chain = ConversationChain(llm=llm, memory=memory)
print(chain.invoke("おすすめの本を教えて"))
print("\n\n")
print(chain.invoke("前におすすめされた本は?"))
関数を書けばもちろん何も使わなくても実装はできますが、行数が桁違いですね(参考: [Azure] OpenAI Service で AI チャットボットを作ってみよう)。
3. LangChainの「Chain」とLCEL(LangChain Expression Language)
- LangChainのChainが分かりやすく実装されているLCEL
- LCELは、パイプ | を使って処理をシンプルに連結できる記法[1]
- 複数の処理を直感的につなげる仕組み→Chain(チェーン)
- これなら「データ取得 → 変換 → LLMで解釈」 を簡潔に記述可能!
- LCEL(LangChain Expression Language)を使ったデモ
- 例えば以下のコードでは、以下の 3ステップの処理 を | を使ってつなげています。
- retriever → TavilySearchResults[2]
- 「今日の東京の天気」の検索結果を取得
- データ変換 → lambda x: f"今日の東京の天気の情報: {x}"
- 検索結果を LLM が理解しやすいフォーマットに変換
- LLM に渡す → llm
- ChatGPT (AzureOpenAPI)に渡して解釈させる
# デモ
from langchain.chat_models import ChatOpenAI
from langchain.schema import HumanMessage, SystemMessage
from langchain_community.tools.tavily_search import TavilySearchResults
# LLM & 検索ツールの準備
# llm = ChatOpenAI(model_name="gpt-4")
llm = azureai
retriever = TavilySearchResults()
# LCEL (LangChain Expression Language) を使ってシンプルに処理を定義
workflow = retriever | (lambda x: f"今日の東京の天気の情報: {x}") | llm
# 実行
result = workflow.invoke("今日の東京の天気")
print(result.content)
今日の東京の天気は以下の通りです。
- **日付**: 2025年2月8日(土)
- **天気**: 晴れ時々曇り
- **最高気温**: 9℃
- **最低気温**: 1℃
- **降水確率**: 10%(昼間は降水なし)
- **風**: 北西の風、日中はやや強く吹く
- **湿度**: 約58%
明日、2月9日(日)の予報は以下の通りです。
- **天気**: 晴れ
- **最高気温**: 11℃
- **最低気温**: 2℃
- **降水確率**: 0%(降水の可能性は低い)
注意点として、強い冬型の気圧配置が続いており、寒気の影響を受ける見込みです。特に、山沿いでは雪が降る可能性があるため、交通機関への影響に注意が必要です。
詳しい情報は以下のリンクから確認できます:
- [東進の天気情報](https://www.toshin.com/weather/detail?id=66124)
- [Yahoo!天気](https://weather.yahoo.co.jp/weather/jp/13/4410.html)
- [tenki.jp](https://tenki.jp/live/3/16/)
- [NHK天気情報](https://www.nhk.or.jp/kishou-saigai/pref/weather/tokyo/)
4.LangChainを使うメリットを比較
API直叩き | LangChain | |
---|---|---|
プロンプト管理 | 手動で書く必要あり | PromptTemplateで再利用可能 |
会話履歴の保持 | なし | Memoryで文脈を理解 |
外部データの参照 | APIを個別に呼ぶ必要あり | RetrievalQAで簡単に実装 |
動的な意思決定 | if 文だらけの処理 | Agentsで自動的に適切なツールを選択 |
- 例えば、「カスタマーサポートの問い合わせAIを作る」場合
- ユーザー:「注文履歴を教えて!」
- LangChain:「外部データベースにアクセス」
- LangChain:「あなたの注文履歴はこちらです!」
- → API直叩きではできない「データ検索+履歴保持+動的応答」が可能になります!
ではLangGraphとは?
LangGraphの概要
-
LangGraphとは?
- LangChainを拡張し、複雑なワークフローを「グラフ構造」で直感的に管理・構築するフレームワーク
- 特徴:
- グラフベースのノード処理
- 並列処理・条件分岐が可能
- LLMの推論ステップを整理しやすい
-
LangGraphを使うメリット
-
例えば、「FAQの問い合わせ対応AI」を作る場合
- LangChain だけ → if 文だらけで管理が大変[4]
- LangGraph → 「質問の種類」に応じて適切なノードへ分岐
-
参考になりそうなサイト
-
以下デモ
ここでは、基本的なチャットボットのワークフローをLangChainとLangGraphで構築してみます!
LangGraphのサンプルコードをAnthropicからAzure OpenAIモデルにしたものです。
以下の構成で実装します:
from typing import Annotated
- from langchain_anthropic import ChatAnthropic
+ from langchain_openai import AzureChatOpenAI
from langchain_community.tools.tavily_search import TavilySearchResults
from langchain_core.messages import BaseMessage
from typing_extensions import TypedDict
from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph import StateGraph
from langgraph.graph.message import add_messages
from langgraph.prebuilt import ToolNode, tools_condition
class State(TypedDict):
messages: Annotated[list, add_messages]
graph_builder = StateGraph(State)
tool = TavilySearchResults(max_results=2)
tools = [tool]
- llm = ChatAnthropic(model="claude-3-5-sonnet-20240620")
+ llm = AzureChatOpenAI(api_key="your_api_key", azure_endpoint="your_endpoint", azure_deployment="gpt-4")
llm_with_tools = llm.bind_tools(tools)
def chatbot(state: State):
return {"messages": [llm_with_tools.invoke(state["messages"])]}
graph_builder.add_node("chatbot", chatbot)
tool_node = ToolNode(tools=[tool])
graph_builder.add_node("tools", tool_node)
graph_builder.add_conditional_edges(
"chatbot",
tools_condition,
)
graph_builder.add_edge("tools", "chatbot")
graph_builder.set_entry_point("chatbot")
memory = MemorySaver()
graph = graph_builder.compile(checkpointer=memory)
こちらでコンパイルしたグラフ構成を見るには以下のコードで確認できます!
from IPython.display import Image, display
try:
display(Image(graph.get_graph().draw_mermaid_png()))
except Exception:
# This requires some extra dependencies and is optional
pass
ワークフローがどうなっているのか、とても理解しやすいと思います。
こちらを実行すると、記憶機能のあるチャットボットが確認できます!
config = {"configurable": {"thread_id": "1"}}
user_input = "こんにちは、元気ですか?私はジョンです。"
events = graph.stream(
{"messages": [{"role": "user", "content": user_input}]},
config,
stream_mode="values",
)
for event in events:
event["messages"][-1].pretty_print()
================================ Human Message =================================
こんにちは、元気ですか?私はジョンです。
================================== Ai Message ==================================
こんにちは、ジョンさん!お会いできて嬉しいです。元気ですか?何かお話ししたいことや質問があれば、どうぞお気軽にお知らせください。
user_input = "私の名前を覚えていますか?"
# The config is the **second positional argument** to stream() or invoke()!
events = graph.stream(
{"messages": [{"role": "user", "content": user_input}]},
config,
stream_mode="values",
)
for event in events:
event["messages"][-1].pretty_print()
================================ Human Message =================================
私の名前を覚えていますか?
================================== Ai Message ==================================
はい、ジョンさんという名前を覚えています。何か特別なことについてお話ししたいですか?
しっかりと動作することが確認できました!
公式のチュートリアルでは基本のチャットノードからノード・機能を追加していく体験ができます。
ここからさらに、Human in the roopの実装も解説されていました!
ぜひ皆さんも触ってみてはいかがでしょうか?
まとめ: LangChainとLangGraphを活用すると、AIエージェント構築・拡張がしやすい!
-
今回の目標:
- LangChainとLangGraphの基本的な内容を理解し、活用イメージを持つ
-
簡単な技術説明:
- LangChain: LLMアプリケーション開発を簡単にするフレームワーク
- LangGraph: LangChainを拡張。マルチステップ・並列処理を効率的に構築できるワークフロー管理ツール
-
個人の感想
LangChain | LangGraph | |
---|---|---|
シンプルな処理 | 得意 | 可能 |
分岐処理 | if 文で実装が大変 | グラフで簡単に整理 |
並列処理 | できなくはない | ネイティブサポート |
複雑なワークフロー | 状態管理が大変 | グラフで自然に設計可能 |
※こちらのサイトのLangGraphとLangChainを比較する図がわかりやすかったのでもしよければ参考にどうぞ!
最後に
なかなかLLMアプリ開発よく分からないと思っていましたが、LangChainとLangGraphの本やチュートリアルを見ていると、なんだか自分でも実装できそうとイメージがついてきて妄想が膨らみました!
今後はもう少し凝ったものの開発に挑戦したいです。
本当に初めて記事掲載ですが、良かったよって方・少しでも参考になったという方は「いいね/like」、また「ここ違うんじゃない?」とかありましたら気軽にコメントをいただけると励みになります!
最後までお読みいただきありがとうございました!!
-
通常のコードだと、関数を定義して順番に呼び出す必要がありますが、LCELを使うと「|(パイプ)」を使って直感的に記述できますね!他にも追加の処理を挟むのが簡単というメリットもあります。 ↩︎
-
「Tavily」は、AIエージェント専用に構築された検索エンジンです。クレジットカードの登録なしで、毎月最大1,000回まで無料利用が可能みたいなので使いやすいですね! ↩︎
-
ここでの解説は省きますが、エージェントの中でどのような処理が行われているかトレースできる便利なサイト・機能です! ↩︎
-
この表現は語弊を生むかもしれないですね。LangChainでもRunnableParallelという関数が標準でありますが、複雑なフローを管理するにはLangGraphがオススメというお話です! ↩︎
Discussion