🦔

[LangChain] Webページを構造化する60行スクリプト

2024/04/27に公開

この記事はLangChainに興味がある人が手っ取り早く動かしてみることを目標にした記事です。

この記事を見てできること

  • 渡されたWebページのURLのコンテンツを取得する
  • LLMにその情報を渡して、指定した構造に変換させる

今回はPydanticで定義したこのような形式でWebの情報を変換します。

class SummarizeOutput(BaseModel):
    Who: str = Field(description="who")
    When: str = Field(description="when")
    What: str = Field(description="what")
    Where: str = Field(description="where")
    Why: str = Field(description="why")
    How: str = Field(description="how")
    URL: str = Field(description="url")

まずはセットアップ

poetry init
poetry add langchain@0.1.14 langchain-anthropic@0.23.1 trafilature

プログラムと解説

# 利用するライブラリをインポート
# langchainではなくlangchain_coreを利用しましょう
import argparse
import trafilatura
from langchain_anthropic import ChatAnthropic
from langchain_core.globals import set_llm_cache
from langchain_core.prompts import PromptTemplate
from langchain_core.pydantic_v1 import BaseModel, Field


# URLからコンテンツを取得する関数
def fetch_content(url: str) -> str:
    downloaded = trafilatura.fetch_url(url)
    content = trafilatura.extract(downloaded, include_links=True, output_format="json")
    return content


# 出力したい形式を定義
class SummarizeOutput(BaseModel):
    Who: str = Field(description="who")
    When: str = Field(description="when")
    What: str = Field(description="what")
    Where: str = Field(description="where")
    Why: str = Field(description="why")
    How: str = Field(description="how")
    URL: str = Field(description="url")


# ここでLangChainを用います
def summarize(content: str) -> SummarizeOutput:
    # llm = OpenAI(model_name="gpt-3.5-turbo", temperature=0) とかでもOK
    llm = ChatAnthropic(model_name="claude-3-haiku-20240307", temperature=0)
    structured_llm = llm.with_structured_output(SummarizeOutput)
    prompt = PromptTemplate(
        template="""
        ----task
        日本語でまとめなさい。
        ----content
        {content}
        """,
        input_variables=["content"],
    )
    # prompt | llm | parserの順でchainを定義(今回はstructured_llmを使うのでparserは利用しない)
    chain = prompt | structured_llm
    # chainはステートレスにして、ここで変数を渡す
    result = chain.invoke({"content": content})
    return result

# CLIの引数を定義
parser = argparse.ArgumentParser(description="Webページを要約します")
parser.add_argument("url", type=str, help="要約するWebページのURL", nargs="?")
arg = parser.parse_args()

# 実行
content = fetch_content(arg.url)
summary = summarize(content)
print(summary.json(indent=4, ensure_ascii=False))

実行結果

$ export ANTHROPIC_API_KEY=sk-xxxxxx  # 環境変数を設定
$ python summarize-web.py -h
usage: summarize-web.py [-h] [url]

Webページを要約します

positional arguments:
  url         要約するWebページのURL

options:
  -h, --help  show this help message and exit

$ python summarize-web.py "https://trafilatura.readthedocs.io/en/latest/"
{
    "Who": "Trafilatura",
    "When": "2024-01-01",
    "What": "Webからテキストを収集するためのPythonパッケージとコマンドラインツール",
    "Where": "readthedocs.io",
    "Why": "Webクロール、ダウンロード、スクレイピング、本文・メタデータ・コメントの抽出などが主な用途。言語処理、テキストマイニング、SEO、ビジネス分析などの研究に役立つ。",
    "How": "Webサイトマップ、フィード、オフラインのHTML、パースされたHTML木などを入力として、本文、メタデータ、構造化情報を抽出し、テキスト、CSV、JSON、XML形式で出力する。",
    "URL": "https://trafilatura.readthedocs.io/index.html"
}

参考

今回作ったソースコードのフルバージョン(エラーハンドリングやCacheを追加)
https://github.com/HikaruEgashira/python-workspaces/blob/main/langchain/summarize-web.py

ここまで見た方へ

LangGraphについても書きました

https://zenn.dev/sqer/articles/03b03a53f0847c

Discussion