【LangChain入門】Pythonで簡単にAIチェーンを構築する方法

LLMを単体で使うだけでなく、複数のステップを組み合わせた処理パイプラインを作りたいときにLangChainが役立つ。「複雑そう」と思って敬遠していたが、基本的な使い方を覚えたら意外と簡単だった。ハンズオン形式で紹介する。

LangChainとは

LangChainは、LLMを使ったアプリケーションを構築するためのPythonフレームワークだ。

単体のAPIコールだけでできることには限界がある。LangChainは:

  • 複数のLLM呼び出しを「チェーン」でつなぐ
  • ベクトルDBと組み合わせてRAGを実装する
  • ツール(Web検索、計算機など)をLLMに使わせる
  • という仕組みを提供している。

    インストール

    pip install langchain langchain-anthropic langchain-openai chromadb

    環境変数の設定:

    # .env
    ANTHROPIC_API_KEY=your-key
    OPENAI_API_KEY=your-key

    基本1: シンプルなチェーン

    まず最も基本的な「プロンプトテンプレート + LLM」のチェーンを作る。

    from langchain_anthropic import ChatAnthropic
    from langchain_core.prompts import ChatPromptTemplate
    from langchain_core.output_parsers import StrOutputParser
    
    # モデルの設定
    llm = ChatAnthropic(model="claude-3-7-sonnet-20250219")
    
    # プロンプトテンプレートの定義
    prompt = ChatPromptTemplate.from_messages([
        ("system", "あなたはプロの技術ライターです。"),
        ("human", "{topic}について{length}文字以内で説明してください。")
    ])
    
    # チェーンを構築(LCEL記法)
    chain = prompt | llm | StrOutputParser()
    
    # 実行
    result = chain.invoke({
        "topic": "Dockerコンテナ",
        "length": "200"
    })
    print(result)

    | 演算子でコンポーネントをつなぐのがLCEL(LangChain Expression Language)記法で、LangChain v0.2以降の標準的な書き方だ。

    基本2: 構造化出力

    JSON形式で出力を受け取りたい場合は、Pydanticモデルを使う。

    from langchain_anthropic import ChatAnthropic
    from langchain_core.prompts import ChatPromptTemplate
    from pydantic import BaseModel, Field
    
    class ArticleOutline(BaseModel):
        title: str = Field(description="記事のタイトル")
        sections: list[str] = Field(description="セクションのリスト")
        tags: list[str] = Field(description="タグのリスト(3〜5個)")
    
    llm = ChatAnthropic(model="claude-3-7-sonnet-20250219")
    structured_llm = llm.with_structured_output(ArticleOutline)
    
    prompt = ChatPromptTemplate.from_messages([
        ("human", "{topic}についての記事構成を作成してください。")
    ])
    
    chain = prompt | structured_llm
    
    result = chain.invoke({"topic": "PythonでのWebスクレイピング"})
    print(type(result))    # 
    print(result.title)    # タイトルが文字列で取れる
    print(result.tags)     # タグがリストで取れる

    Pydanticモデルを指定するだけで、型安全な構造化データが返ってくる。

    基本3: RAGパイプライン

    ドキュメントをベクトル化して質問応答するRAGを実装する。

    from langchain_openai import OpenAIEmbeddings
    from langchain_community.vectorstores import Chroma
    from langchain_core.documents import Document
    from langchain_anthropic import ChatAnthropic
    from langchain_core.prompts import ChatPromptTemplate
    from langchain_core.output_parsers import StrOutputParser
    from langchain_core.runnables import RunnablePassthrough
    
    # ドキュメントの準備
    documents = [
        Document(
            page_content="LangChainはLLMアプリ開発フレームワークです。",
            metadata={"source": "intro.md"}
        ),
        Document(
            page_content="LCELを使うとチェーンを | 演算子でつなげます。",
            metadata={"source": "lcel.md"}
        ),
    ]
    
    # ベクトルDBに保存
    embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
    vectorstore = Chroma.from_documents(documents, embeddings)
    retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
    
    # RAGチェーンの構築
    llm = ChatAnthropic(model="claude-3-7-sonnet-20250219")
    
    prompt = ChatPromptTemplate.from_messages([
        ("system", """以下のドキュメントを参考に質問に答えてください。
    ドキュメントに記載のない情報は「分かりません」と答えてください。
    
    ドキュメント:
    {context}"""),
        ("human", "{question}")
    ])
    
    def format_docs(docs):
        return "\n\n".join(doc.page_content for doc in docs)
    
    rag_chain = (
        {"context": retriever | format_docs, "question": RunnablePassthrough()}
        | prompt
        | llm
        | StrOutputParser()
    )
    
    # 実行
    answer = rag_chain.invoke("LangChainとは何ですか?")
    print(answer)

    基本4: チェーンをつなぐ

    複数の処理を順番に実行するマルチステップチェーン。

    from langchain_anthropic import ChatAnthropic
    from langchain_core.prompts import ChatPromptTemplate
    from langchain_core.output_parsers import StrOutputParser
    
    llm = ChatAnthropic(model="claude-3-7-sonnet-20250219")
    
    # ステップ1: 記事のタイトルを生成
    title_prompt = ChatPromptTemplate.from_messages([
        ("human", "{topic}についての魅力的な記事タイトルを1つ生成してください。タイトルのみ返してください。")
    ])
    
    # ステップ2: タイトルを元に記事を生成
    article_prompt = ChatPromptTemplate.from_messages([
        ("human", "以下のタイトルで技術記事の本文を書いてください。\nタイトル: {title}")
    ])
    
    # チェーンを結合
    title_chain = title_prompt | llm | StrOutputParser()
    article_chain = article_prompt | llm | StrOutputParser()
    
    # タイトル生成 → 記事生成の順に実行
    full_chain = title_chain | (lambda title: {"title": title}) | article_chain
    
    result = full_chain.invoke({"topic": "Pythonの型ヒント"})
    print(result)

    LangChainを使うべきか?

    正直なところ、シンプルな用途ならLangChainを使わず直接APIを呼んだほうが良い場合もある。

    LangChainが向いている場面:

  • RAGパイプラインを実装したい
  • 複数のLLMをステップとして組み合わせたい
  • チェーンの途中でツールを呼び出したい
  • 直接APIで十分な場面:

  • 単一のプロンプトでLLMを呼ぶだけ
  • シンプルな会話履歴の管理
  • コストを細かくコントロールしたい
  • LangChainは抽象化レイヤーが厚いため、デバッグが難しくなることがある。まずAnthropicやOpenAIの直接APIで試してから、「もっと複雑な処理が必要」と感じたときに導入するのが良い。

    まとめ

    LangChainの基本的な使い方を4つ紹介した:

    1. シンプルなチェーン – プロンプトテンプレート + LLMのパイプライン

    2. 構造化出力 – Pydanticモデルで型安全なJSON取得

    3. RAGパイプライン – ベクトルDB連携で独自ドキュメントへの質問応答

    4. マルチステップチェーン – 複数のLLM呼び出しを順番に実行

    LangChainのドキュメントは日々更新されているので、バージョンに注意しながら公式ドキュメントも参照してほしい。まずは1つのチェーンを動かしてみるのが一番の近道。