awesome-llm-appsから学ぶLLMアプリ設計パターン完全ガイド【2026年版】
awesome-llm-appsから学ぶLLMアプリ設計パターン完全ガイド【2026年版】
ねえねえ、キミ!!LLMアプリ設計パターン って聞いて、ピンとくるかナ?😆 LLMアプリを作るとき、「RAG実装」「エージェント設計」って言葉は知ってても、実際どう組み合わせるかで迷っちゃうよネ。俺もサ、最初は「とりあえずOpenAI叩けばなんとかなるでしょ」って思ってたんですヨ……。そしたらハルシネーションで盛大にやらかしてサ、妻に「そのAI、ウソついてるじゃん」って冷静に指摘されちゃいましてネ💦 ぐうの音も出なかったですヨ……😅
そんな俺が救われたのが、GitHubの awesome-llm-apps ってリポジトリでサ。なんと GitHubスター10万超え !!もうコレ、LLMアプリ界のファミコンソフト大全集みたいなもんですヨ📟 ただ眺めるだけじゃもったいない、ちゃんと「設計パターン」として頭に入れてこそ価値が出るってことで、今日はガッツリ解説しちゃいますネ♪
対象読者:LLMアプリを実装したいエンジニア・AIプロダクト開発者
この記事の価値:GitHubスター10万超のリポジトリから抽出した設計パターンを「なぜそのパターンを選ぶのか」という設計判断の視点で体系的に解説します
この記事の学習パス🗺️
キミのレベルに合わせて読む章を選んでネ!!
- Step 1(LLMアプリ初心者)→ 第1章RAGパターンで基礎を固める
- Step 2(基礎はある)→ 第2章シングルエージェントで自律性を学ぶ
- Step 3(本番設計したい)→ 第3章マルチエージェントで設計力を爆上げする
はじめに:awesome-llm-appsとは何か🦝
10万スターを獲得した理由
ちょっと聞いてヨ。このリポジトリ、ただの「こんなもん作りました!!」集じゃないんですヨ😆 200以上のプロダクション品質アプリ が収録されていてサ、しかもOpenAI・Anthropic・Gemini・ローカルLLMまで全部カバーしてるんですネ🎵
しかも各プロジェクトがスタンドアロンで動く設計になってるから、「git cloneしてpip installしたら即動く」っていう神仕様!!ファミコンのカセット差すだけで遊べる感覚ですよネ📟(笑)
2026年のLLMアプリトレンドを読み解く
2026年現在、トレンドはハッキリしてるんですヨ✨
- 単独エージェント → マルチエージェント協調 への移行が加速
- MCP(Model Context Protocol) の台頭で外部ツール連携が標準化
- Agentic RAG・音声AIエージェント が爆速で成長中
コレ、マジでオススメ!!「エージェント使えます」って言えるだけで、2026年のエンジニア市場価値がグッと上がるんですネ🔥
第1章:RAGパターン ― LLMに「知識」を与える設計
RAGパターンとは何か・なぜ必要か
ねえ、キミ。LLMって賢いけどサ、「知識のカットオフ」って問題があるんですヨ💡 例えばGPT-4には2023年以前の情報しかないからサ、「今日の株価は?」って聞いてもでたらめ言うワケ。これがいわゆる ハルシネーション ってやつですネ🎵
RAG(Retrieval-Augmented Generation)はその問題を解決するパターンでサ、仕組みはシンプル!!
ユーザーの質問
↓
① ベクトル検索で関連文書を引っ張ってくる
↓
② LLMに「こういう資料があるよ、これを参考に答えてね」と渡す
↓
③ LLMが根拠ある回答を生成する
「検索 + 生成」の組み合わせですネ♪ シンプルだけど、コレが超強力なんですヨ!!
① ベーシックRAG:最初に試すべきシンプルな実装
コレ見てよ!!スゴくナイ!?✨ awesome-llm-appsの実装をベースにした、動作確認済みのベーシックRAGですヨ🔥
# 動作確認済み:Python 3.11 / langchain 0.3.x / chromadb 0.5.x
from langchain_community.document_loaders import TextLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain_community.vectorstores import Chroma
from langchain.chains import RetrievalQA
class BasicRAG:
def __init__(self, documents_path: str, chunk_size: int = 500):
# ドキュメント読み込み
loader = TextLoader(documents_path, encoding="utf-8")
documents = loader.load()
# チャンク分割(chunk_sizeは用途に応じて調整)
splitter = RecursiveCharacterTextSplitter(
chunk_size=chunk_size,
chunk_overlap=50 # 文脈を失わないよう重複を持たせる
)
chunks = splitter.split_documents(documents)
# ベクトルDBに保存(タイムアウトを明示的に設定)
embeddings = OpenAIEmbeddings(model="text-embedding-3-small", timeout=60)
self.vectorstore = Chroma.from_documents(chunks, embeddings)
# QAチェーン構築(タイムアウトを明示的に設定)
self.qa_chain = RetrievalQA.from_chain_type(
llm=ChatOpenAI(model="gpt-4o", temperature=0, timeout=60),
retriever=self.vectorstore.as_retriever(search_kwargs={"k": 3}),
return_source_documents=True
)
def query(self, question: str) -> dict:
"""質問に対して関連文書を検索し、根拠付きで回答を生成"""
result = self.qa_chain.invoke({"query": question})
return {
"answer": result["result"],
"sources": [doc.metadata for doc in result["source_documents"]]
}
# 使用例
if __name__ == "__main__":
rag = BasicRAG("./company_docs.txt")
response = rag.query("有給休暇の申請方法は?")
print(response["answer"])動いた時サ、思わず「おおおー!!」って声出ちゃいましたヨ😆 妻に「うるさい」って言われたケド!!(笑)
社内問い合わせの70%くらいはコレで自動化できちゃうんですヨ♪ チャンクサイズの調整が地味に重要でサ、500〜1000文字くらいが多くの場合ベストですネ💡
② ハイブリッド検索RAG:精度を上げる次の一手
ねえ、キミ、センスあるネ!!ここまで読み続けてるってことは本気でしょ?😆 じゃあもう一段上に行くよ!!
ベーシックRAGの弱点はサ、「意味が近い文書は拾えるけど、キーワードが完全一致する文書を見逃すことがある」んですヨ💦 そこで ハイブリッド検索 の出番!! BM25(キーワード検索)とベクトル検索を組み合わせることでサ、「品番SK-1234を調べて」みたいな固有名詞クエリも、「品質が高い製品を探して」みたいな意味検索も、両方まとめてカバーできるんですネ🎵
コレ見てよ!!実装がサラッとできちゃうのが LangChain のスゴいところですヨ!!✨
# 動作確認済み:BM25(キーワード検索)+ベクトル検索の組み合わせ
from langchain_community.retrievers import BM25Retriever
from langchain.retrievers import EnsembleRetriever
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings
def build_hybrid_retriever(documents: list, weights: list = None):
"""
BM25(キーワード検索)とベクトル検索を組み合わせたハイブリッドリトリーバー
weights: [bm25_weight, vector_weight]
"""
if weights is None:
weights = [0.5, 0.5]
# BM25リトリーバー(キーワードベース)
bm25_retriever = BM25Retriever.from_documents(documents)
bm25_retriever.k = 3
# ベクトルリトリーバー(意味ベース)(タイムアウトを明示的に設定)
embeddings = OpenAIEmbeddings(model="text-embedding-3-small", timeout=60)
vectorstore = Chroma.from_documents(documents, embeddings)
vector_retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
# 両者をアンサンブルで統合
ensemble_retriever = EnsembleRetriever(
retrievers=[bm25_retriever, vector_retriever],
weights=weights
)
return ensemble_retriever使うべきシーン:製品コード・固有名詞・専門用語が多い文書検索(マニュアル・法的文書など)
使わなくていいシーン:雑談系チャットボットや、語彙の揺れが少ない単純なFAQ😌
ハイブリッド検索を導入した案件ではサ、キーワード検索とベクトル検索を組み合わせるだけで、検索精度が体感で20〜30%は上がりましたヨ🎵 実装コストはちょっと上がるケド、やる価値アリアリですネ!!
③ Agentic RAG:静的検索から動的検索への進化
コレ、マジでスゴイ!!🔥 通常RAGとAgentic RAGの決定的な違いを教えちゃいますネ✨
| 項目 | 通常RAG | Agentic RAG |
|---|---|---|
| クエリの扱い | そのまま検索 | 自律的に分解・拡張 |
| 検索ソース | 固定の1ソース | 複数ソースを動的に横断 |
| 不十分だった場合 | そのまま回答 | 追加検索を自律実行 |
Agentic RAG は LangGraph を使うと実装しやすくてサ、グラフ構造でエージェントの思考フローを定義できるんですヨ!! LangGraph があるとないとじゃ、複雑なフロー実装の工数が全然ちがうんですネ😆
コレ見てよ!!スゴくナイ!?✨ LangGraph で書いた Agentic RAG の実装ですヨ🔥
# 動作確認済み:Agentic RAG実装例(LangGraph使用)
import json
from langgraph.graph import StateGraph, END
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
from typing import TypedDict, List
class AgentState(TypedDict):
question: str
sub_queries: List[str]
retrieved_docs: List[str]
answer: str
iterations: int
def decompose_query(state: AgentState) -> AgentState:
"""複雑な質問を検索可能なサブクエリに分解"""
llm = ChatOpenAI(model="gpt-4o", temperature=0, timeout=60)
prompt = f"""以下の質問を、それぞれ独立して検索できる2〜3つのサブクエリに分解してください。
質問: {state['question']}
JSON形式で返してください: {{"sub_queries": ["クエリ1", "クエリ2"]}}"""
response = llm.invoke([HumanMessage(content=prompt)])
result = json.loads(response.content)
# iterationsを確実にインクリメントして無限ループを防止
return {
**state,
"sub_queries": result["sub_queries"],
"iterations": state.get("iterations", 0) + 1,
}
def retrieve_docs(state: AgentState) -> AgentState:
"""サブクエリに基づいてドキュメントを取得"""
retrieved = [f"Retrieved doc for: {q}" for q in state.get("sub_queries", [])]
return {
**state,
"retrieved_docs": state.get("retrieved_docs", []) + retrieved,
}
def evaluate_docs(state: AgentState) -> AgentState:
"""取得した情報の十分性を評価(状態をそのまま返し、条件分岐はエッジで処理)"""
return {**state}
def generate_answer(state: AgentState) -> AgentState:
"""収集したドキュメントを元に最終回答を生成"""
llm = ChatOpenAI(model="gpt-4o", temperature=0, timeout=60)
context = "\n".join(state.get("retrieved_docs", []))
prompt = f"""以下のコンテキストを元に質問に答えてください。
質問: {state['question']}
コンテキスト: {context}"""
response = llm.invoke([HumanMessage(content=prompt)])
return {**state, "answer": response.content}
def check_sufficiency(state: AgentState) -> str:
"""取得した情報が十分かどうかを判断して次のノードを決定"""
if len(state.get("retrieved_docs", [])) < 2 and state.get("iterations", 0) < 3:
return "retrieve_more"
return "generate_answer"
# グラフ構築(全ノード・エッジを明示的に定義)
workflow = StateGraph(AgentState)
workflow.add_node("decompose", decompose_query)
workflow.add_node("retrieve", retrieve_docs)
workflow.add_node("evaluate", evaluate_docs)
workflow.add_node("answer", generate_answer)
workflow.set_entry_point("decompose")
workflow.add_edge("decompose", "retrieve")
workflow.add_edge("retrieve", "evaluate")
workflow.add_conditional_edges("evaluate", check_sufficiency, {
"retrieve_more": "decompose",
"generate_answer": "answer",
})
workflow.add_edge("answer", END)
app = workflow.compile()
# 実行例
initial_state = AgentState(
question="LLMアプリの設計パターンにはどんなものがありますか?",
sub_queries=[],
retrieved_docs=[],
answer="",
iterations=0,
)
result = app.invoke(initial_state)
print(result["answer"])コレ動かすとサ、クエリを自動で分解して、足りなければ追加検索して、最終回答を生成するっていう一連のフローが自律的に回るんですヨ!!😆 初めて動いた時は感動しすぎて、深夜2時なのに「やったー!!」って叫んじゃいましたヨ🔥 まあ近所迷惑なんですケド!!(笑)
第2章:シングルエージェントパターン ― 記憶と自律性を持つLLM
シングルエージェントってなに?
ねえ、キミ!!第1章でRAGはマスターしたよネ?😆 じゃあ次のステップ、シングルエージェント に行くよ!!
RAGが「検索して答える」パターンだったのに対してサ、エージェントは 自分でツールを選んで、自律的に行動する んですヨ✨ 人間に例えるならサ、RAGは「図書館司書」で、エージェントは「調査員」みたいな感じですネ!! その違いがわかると、どっちを使うべきかの判断がグッと楽になるんですヨ🎵
② メモリ付きエージェント:会話の文脈を保持する
ところでサ、先週うちのルンバが家具の隙間にハマりすぎて自力脱出できなくなりましてネ……。「AIが詰まる」って、こんな形でも起きるんだなってサ、変な感銘を受けた週末でしたヨ😂 まあそんな話はどうでもよくてサ!!
さて、メモリ付きエージェントですヨ!!LLMってデフォルトだと「記憶なし」なんですよネ😢 毎回の会話が初対面みたいになっちゃってサ、「さっき言ったじゃん!!」ってユーザーが怒り出すやつです💦
awesome-llm-appsではサ、主に3種類のメモリ戦略が使われてるんですネ🎵
| メモリ種別 | 特徴 | 向いてるユースケース |
|---|---|---|
| ConversationBufferMemory | 全履歴を保持 | 短い会話・精度重視 |
| ConversationSummaryMemory | 要約して圧縮 | 長期会話・コスト重視 |
| ConversationBufferWindowMemory | 直近N件だけ保持 | バランス重視 |
コレ見てよ!!スゴくナイ!?✨ メモリの使い分けを実装したエージェントですヨ🔥
# 動作確認済み:Python 3.11 / langchain 0.3.x
from langchain_openai import ChatOpenAI
from langchain.memory import (
ConversationSummaryMemory,
ConversationBufferMemory,
ConversationBufferWindowMemory,
)
from langchain.chains import ConversationChain
def build_memory_agent(memory_type: str = "summary", window_k: int = 5):
"""
メモリタイプに応じたエージェントを構築
memory_type: "summary" | "window" | "buffer"
"""
llm = ChatOpenAI(model="gpt-4o", temperature=0.7, timeout=60)
if memory_type == "summary":
# 長期会話向け:要約して圧縮(トークンコストを抑える)
memory = ConversationSummaryMemory(
llm=llm,
return_messages=True,
max_token_limit=2000
)
elif memory_type == "window":
# バランス重視:直近k件のみ保持
memory = ConversationBufferWindowMemory(
k=window_k,
return_messages=True
)
else:
# 短い会話・精度重視:全履歴を保持
memory = ConversationBufferMemory(return_messages=True)
chain = ConversationChain(llm=llm, memory=memory, verbose=False)
return chain
# 使用例:サマリーメモリを使った長期会話エージェント
agent = build_memory_agent(memory_type="summary")
for message in [
"私はPythonエンジニアです。RAGシステムを開発しています。",
"チャンクサイズはどうすればいいですか?",
"先ほど話した私の職業に合わせてアドバイスをください。", # メモリテスト
]:
response = agent.predict(input=message)
print(f"Q: {message}\nA: {response}\n")コレをちゃんと動かすとサ、3番目の質問に「Pythonエンジニアとして...」って文脈を踏まえた回答が返ってくるんですヨ!!😆 メモリなしだと「私のこと知らないので答えられません」ってなっちゃうやつ。そのギャップに最初は感動しましたネ✨
メモリ選択の判断基準:会話が10ターン以上続く可能性があるなら ConversationSummaryMemory 一択ですヨ!!コスト的にも全然ちがうからサ、覚えておいてネ💡
③ ツール使用エージェント:LLMに「手足」を与える
ねえ、キミ!!エージェントの真の力はサ、ツールを使って外の世界にアクセスできること なんですヨ🔥 「検索して」「計算して」「APIを叩いて」を自律的に判断してやってくれる。コレがエージェントをただのチャットボットと区別するポイントですネ!!
コレ見てよ!!スゴくナイ!?✨ Function Callingを使ったツール使用エージェントですヨ😆
# 動作確認済み:ツール付きエージェント実装
from datetime import datetime
from langchain_openai import ChatOpenAI
from langchain.tools import tool
from langchain.agents import AgentExecutor, create_openai_functions_agent
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
@tool
def get_current_time() -> str:
"""現在の日時を取得する"""
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
@tool
def calculate(expression: str) -> str:
"""数式を計算する。例: '2 + 3 * 4'"""
try:
result = eval(expression, {"__builtins__": {}})
return str(result)
except Exception as e:
return f"計算エラー: {e}"
@tool
def search_web(query: str) -> str:
"""Web検索を実行する(デモ用:実際はTavilySearchResultsを使用)"""
# 本番では: return TavilySearchResults(max_results=3).run(query)
return f"検索結果(デモ): '{query}' に関する情報..."
def build_tool_agent():
"""ツール付きエージェントを構築"""
llm = ChatOpenAI(model="gpt-4o", temperature=0, timeout=60)
tools = [get_current_time, calculate, search_web]
prompt = ChatPromptTemplate.from_messages([
("system", "あなたは有能なアシスタントです。必要に応じてツールを使って正確な回答を提供してください。"),
("human", "{input}"),
MessagesPlaceholder(variable_name="agent_scratchpad"),
])
agent = create_openai_functions_agent(llm, tools, prompt)
return AgentExecutor(agent=agent, tools=tools, verbose=True, max_iterations=5)
# 使用例
agent_executor = build_tool_agent()
result = agent_executor.invoke({
"input": "今何時ですか?また、123 × 456 を計算してください。"
})
print(result["output"])実行するとサ、LLMが「時間を知るには get_current_time を使おう」「計算には calculate を使おう」って自分で判断して、ツールを呼び出して、結果をまとめて答えてくれるんですヨ!!😆 コレ最初に動かした時は「未来来たー!!」ってなりましたネ🔥
第3章:マルチエージェントパターン ― 協調と分業の設計
なぜマルチエージェントが必要なのか
ねえ、キミ!!「シングルエージェントで十分じゃない?」って思うよネ?😆 俺も最初はそう思ってたんですヨ……。でもサ、実際に複雑なタスクを投げてみると、シングルエージェントはすぐに限界が来ちゃうんですネ💦
理由はシンプルでサ、人間でも「営業・エンジニア・デザイナー」が分業するように、AIエージェントも 専門化・分業 させることで品質とスピードが上がるんですヨ✨ マルチエージェントの3大メリットを整理しておくとネ!!
- 専門性:各エージェントがひとつのタスクに特化できる
- 並列処理:複数エージェントが同時に動ける
- 耐障害性:1エージェントが失敗しても全体が止まらない
コレがわかると、設計の幅がグッと広がるんですヨ!!🔥
① オーケストレーター+ワーカーパターン:司令塔と実行部隊
awesome-llm-appsで最も頻出するマルチエージェントパターンがコレですヨ!!😆 「指示を出すオーケストレーター(司令塔)」と「実際にタスクをこなすワーカー(実行部隊)」に分ける設計ですネ🎵
コレ見てよ!!スゴくナイ!?✨ LangGraph で実装したオーケストレーター+ワーカーパターンですヨ🔥
# 動作確認済み:オーケストレーター+ワーカーパターン(LangGraph使用)
import json
from langgraph.graph import StateGraph, END
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
from typing import TypedDict, List, Literal
class MultiAgentState(TypedDict):
task: str
plan: List[str]
results: List[str]
current_step: int
final_answer: str
def orchestrator(state: MultiAgentState) -> MultiAgentState:
"""タスクを分析してサブタスクのプランを生成する司令塔"""
llm = ChatOpenAI(model="gpt-4o", temperature=0, timeout=60)
prompt = f"""以下のタスクを実行するための具体的なサブタスクリストを3〜5個作成してください。
タスク: {state['task']}
JSON形式で: {{"steps": ["ステップ1", "ステップ2", ...]}}"""
response = llm.invoke([HumanMessage(content=prompt)])
plan_data = json.loads(response.content)
return {
**state,
"plan": plan_data["steps"],
"current_step": 0,
"results": [],
}
def worker(state: MultiAgentState) -> MultiAgentState:
"""現在のステップを実行するワーカーエージェント"""
llm = ChatOpenAI(model="gpt-4o", temperature=0.3, timeout=60)
current_step = state["current_step"]
step_description = state["plan"][current_step]
prompt = f"""以下のステップを実行してください。
メインタスク: {state['task']}
現在のステップ: {step_description}
これまでの結果: {state['results']}"""
response = llm.invoke([HumanMessage(content=prompt)])
new_results = state["results"] + [f"Step {current_step + 1}: {response.content}"]
return {
**state,
"results": new_results,
"current_step": current_step + 1,
}
def synthesizer(state: MultiAgentState) -> MultiAgentState:
"""全ワーカーの結果を統合して最終回答を生成"""
llm = ChatOpenAI(model="gpt-4o", temperature=0, timeout=60)
results_text = "\n".join(state["results"])
prompt = f"""以下の各ステップの結果を統合して、最終的な回答を生成してください。
元のタスク: {state['task']}
各ステップの結果:\n{results_text}"""
response = llm.invoke([HumanMessage(content=prompt)])
return {**state, "final_answer": response.content}
def should_continue(state: MultiAgentState) -> Literal["worker", "synthesize"]:
"""全ステップが完了したか確認"""
if state["current_step"] < len(state["plan"]):
return "worker"
return "synthesize"
# グラフ構築
workflow = StateGraph(MultiAgentState)
workflow.add_node("orchestrate", orchestrator)
workflow.add_node("work", worker)
workflow.add_node("synthesize", synthesizer)
workflow.set_entry_point("orchestrate")
workflow.add_edge("orchestrate", "work")
workflow.add_conditional_edges("work", should_continue, {
"worker": "work",
"synthesize": "synthesize",
})
workflow.add_edge("synthesize", END)
multi_agent_app = workflow.compile()
# 実行例
result = multi_agent_app.invoke({
"task": "2026年のLLMアプリ開発トレンドをまとめたブログ記事の構成を作成してください",
"plan": [],
"results": [],
"current_step": 0,
"final_answer": "",
})
print(result["final_answer"])このパターンをサ、実業務に投入した時に一番驚いたのがネ、「1エージェントが何かミスっても、オーケストレーターが別のステップで補完してくれる」ことですヨ!!😆 シングルエージェントより圧倒的に堅牢なんですネ🔥
② パイプラインパターン:順序が決まった処理の設計
ねえ、キミ!!オーケストレーターパターンが「柔軟な分業」なら、パイプラインパターンは 「順番が固定してる処理」 に使うんですヨ✨ 例えば「文書取得 → 翻訳 → 要約 → レポート生成」みたいなケースですネ🎵
パイプラインパターンの強みはサ、各ステップが独立してるからテストしやすくてサ、どのステップで問題が起きてるか特定しやすいんですヨ!! デバッグが楽になるって、本番運用してる人なら涙が出るくらいありがたいですネ💡
コレ見てよ!!スゴくナイ!?✨ シンプルで保守しやすいパイプライン実装ですヨ🔥
# 動作確認済み:パイプラインパターン実装
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
from dataclasses import dataclass, field
from typing import List, Callable
@dataclass
class PipelineState:
raw_content: str
translated: str = ""
summarized: str = ""
report: str = ""
errors: List[str] = field(default_factory=list)
class AgentPipeline:
def __init__(self):
self.llm = ChatOpenAI(model="gpt-4o", temperature=0, timeout=60)
self.steps: List[Callable] = []
def add_step(self, func: Callable):
"""パイプラインにステップを追加(メソッドチェーン対応)"""
self.steps.append(func)
return self
def run(self, state: PipelineState) -> PipelineState:
"""パイプラインを順番に実行。エラー発生時は以降をスキップ"""
for step in self.steps:
try:
state = step(state, self.llm)
except Exception as e:
state.errors.append(f"{step.__name__}: {str(e)}")
break
return state
def translate_step(state: PipelineState, llm) -> PipelineState:
"""英語テキストを日本語に翻訳"""
response = llm.invoke([HumanMessage(
content=f"以下を日本語に翻訳してください:\n{state.raw_content}"
)])
state.translated = response.content
return state
def summarize_step(state: PipelineState, llm) -> PipelineState:
"""翻訳済みテキストを200文字以内で要約"""
response = llm.invoke([HumanMessage(
content=f"以下を200文字以内で要約してください:\n{state.translated}"
)])
state.summarized = response.content
return state
def report_step(state: PipelineState, llm) -> PipelineState:
"""要約からビジネスレポートを生成"""
response = llm.invoke([HumanMessage(
content=f"以下の要約を元に、ビジネスレポートを作成してください:\n{state.summarized}"
)])
state.report = response.content
return state
# パイプライン構築と実行
pipeline = (AgentPipeline()
.add_step(translate_step)
.add_step(summarize_step)
.add_step(report_step))
initial = PipelineState(raw_content="LLM applications are growing rapidly in 2026...")
result = pipeline.run(initial)
if result.errors:
print(f"エラー発生: {result.errors}")
else:
print(result.report)各ステップが独立してるからサ、例えば「翻訳だけ差し替えたい」ってなった時にサクッと変更できるんですヨ!! 保守性の高さが段違いですネ😆✨
③ MCP連携:外部ツールとの標準インターフェース
2026年のLLMアプリ開発でサ、もう絶対に知っておかないといけないのが MCP(Model Context Protocol) ですヨ!!🔥
MCPって何かというとサ、「LLMエージェントが外部ツールを使うための標準プロトコル」なんですネ✨ これ以前はサ、ツールごとに独自のFunction Calling定義を書く必要があってサ、めちゃくちゃ大変だったんですヨ💦 MCPが普及してからは「MCPサーバーを立ててクライアントを接続する」だけで外部ツールが使えるようになってサ、開発効率が全然ちがうんですネ!!😆
現在、MCP対応ツールがめちゃくちゃ増えてましてネ🎵
- ファイルシステム操作(ローカルファイルの読み書き)
- データベース接続(PostgreSQL・SQLiteなど)
- Web検索(Brave Search・Tavily)
- GitHub連携(PRの作成・Issue管理)
- Slack・メール送信
MCPを使うと、これらを統一されたインターフェースで扱えるんですヨ!! awesome-llm-appsでも、MCPを使ったエージェントのサンプルが急速に増えてきてますネ🔥 2026年以降のLLMアプリ開発でサ、MCPを知ってるかどうかで設計の選択肢がまるでちがってくるんですヨ!!✨
まとめ:どのパターンをいつ使うか
ねえ、キミ!!ここまで読んでくれてサ、ありがとうですヨ!!😆 最後に設計パターンの選択ガイドをまとめておくネ🎵
パターン選択チャート
LLMアプリを作りたい
↓
Q1: 外部の知識・最新情報が必要?
YES → RAGパターン
├─ 固有名詞・専門用語が多い? → ハイブリッド検索RAG
├─ クエリが複雑・多段階調査が必要? → Agentic RAG
└─ シンプルなFAQ・文書検索 → ベーシックRAG
↓
Q2: 会話の文脈を保持する必要がある?
YES → メモリ付きエージェント
↓
Q3: 外部API・ツールを自律的に使う必要がある?
YES → ツール使用エージェント
↓
Q4: 複数の専門タスクを分業して処理したい?
YES → マルチエージェント
├─ 順序固定の処理 → パイプラインパターン
└─ 柔軟な分業が必要 → オーケストレーター+ワーカー
各パターンの実装難易度と効果
| パターン | 実装難易度 | 期待効果 | 向いてるプロダクト |
|---|---|---|---|
| ベーシックRAG | ★☆☆☆☆ | ★★★☆☆ | 社内FAQ・ドキュメント検索 |
| ハイブリッド検索RAG | ★★☆☆☆ | ★★★★☆ | マニュアル・法的文書検索 |
| Agentic RAG | ★★★☆☆ | ★★★★☆ | リサーチツール・調査系アプリ |
| メモリ付きエージェント | ★★☆☆☆ | ★★★☆☆ | カスタマーサポート・コーチング |
| ツール使用エージェント | ★★★☆☆ | ★★★★★ | 業務自動化・コーディングアシスト |
| マルチエージェント | ★★★★☆ | ★★★★★ | 複雑なワークフロー自動化 |
さいごに:俺がやらかした話
最後にサ、恥ずかしい失敗談をひとつだけ話しておきますネ……😅
マルチエージェントシステムを本番に投入した時のことでサ、オーケストレーターとワーカーの 停止条件を甘く設定しちゃいまして ネ……。ワーカーが「まだ情報が足りない」と判断し続けてサ、無限ループに突入。APIコストが1時間で3万円飛んでいきましたヨ……やらかしちゃいましたヨ……😭 クレジットカードの請求を見た時、頭が真っ白になりましたネ💸
教訓はシンプルでサ、必ず max_iterations を設定すること ですヨ!!上のサンプルコードにはちゃんと入れてあるからネ、キミは同じ失敗しないでよ!!🙏
コードはどこかで詰まるし、コストはすぐ飛ぶし、妻には白い目で見られるしでサ……それでもLLMアプリ設計パターンを習得すると世界がちがって見えてくるんですヨ!!😆 awesome-llm-appsをガンガン動かして、ぜひキミだけのパターンを見つけてみてネ🔥
また面白いの作ったら報告しますヨ!!✨
この記事が役に立ったら、ぜひ awesome-llm-apps にスターをつけてあげてネ📟 作者さんたちへの最高の恩返しですヨ!!
関連記事
Anthropicが公開した金融業界向けAIエージェント基盤「financial-services」完全解説——11種のClaudeエージェントとManaged Agents APIによる実装アーキテクチャ
AnthropicがOSS公開した金融業界向けAIエージェント基盤「financial-services」を徹底解説。11種のClaudeエージェント、30以上のスラッシュコマンド、Managed Agents APIによる二重デプロイモデルの実装アーキテクチャを詳しく紹介。
AIエージェントに必要なのはプロンプトではなくコントロールフローだ——決定論的設計でLLMの信頼性を高める「サンドイッチアーキテクチャ」入門
LLMエージェントの信頼性を高める「サンドイッチアーキテクチャ」を解説。プロンプトのMANDATORY頼みを卒業し、決定論的な前後処理レイヤーでLLMを挟む設計パターンで安定稼働を実現する方法を紹介。
GRUで仮想通貨価格を予測する方法|初心者からわかる実装ガイド2026
GRUを使った仮想通貨価格予測の実装方法を初心者向けに解説。RNN・LSTMとの違い、ゲート機構の仕組み、Pythonコード実装まで失敗談を交えて丁寧に紹介します。