💻

FirecrawlでRAG用データ作成を無料でやりたい!(3)ローカルLLM構築編

2024/09/11に公開

モチベーション

LLMによるRAGシステムを構築するにあたって、検索データの準備は手間がかかります。元となるデータが綺麗な文書ならよいのですが、PDFにせよWebページにせよ、必ずしも綺麗な文書でないことが多いです。最近Web記事などでよく目にするようになった。FireCrawlを使えば、ローカル環境でもWebページから綺麗なマークダウンを生成してくれそうなので、実際にできるか試してみました。

前回のおさらいと今回の内容

前回は、ローカル環境で起動したFirecrawlのオプションのうち、PageOptionを駆使することでクレンジングした文章が入手できるか確認しました。Extractor Optionsを使うことでLLMを使った要約・抽出によるさらに綺麗な文章を入力したいのですが、デフォルトではOpenAIのAPIをcallする想定になっています。OpenAIのAPIは課金が発生するためタイトルのとおりとなりません。そこで、本記事では、Langchainを用いて、FireCrawからローカルLLMを呼び出せる方法を事前に検証します。

サマリ

LiteLLMをProxyとして動作させることで、LangchainからOpenAIのインターフェースでOllamaのローカルLLMモデルを呼び出すことができた!

対象読者

RAGやデータセット作成に興味のある人
ローカル環境やオンプレミス環境へのLLMシステムのデプロイに興味がある人

前提条件

FireCrawl環境が用意できていること。詳しくは前回の記事を参照のこと

システム構成図

システム構成図は以下のとおりです。OpenAIのAPI形式でローカルLLMモデルを呼び出す方法はいろいろあるかと思いますが、本記事ではLiteLLMをつかったプロキシ構成を採用しました。PCが2台登場していますが、すべてを同じPCで実行することも可能です。(皆さんの環境にあわせてIPアドレスを読み替えてください。)

構成図

環境構築

Ollamaインストール

今回はOllamaを使用します。以下の記事などは分かりやすく参考になりました。
https://zenn.dev/yuta_enginner/articles/b0945dea44acb3
https://ritaiz.com/articles/running-llama3-and-phi3-as-servers-using-ollama-and-operating-via-api

構築ができたら、以下のようにcurlコマンドで疎通確認しましょう
IPアドレスはOllamaを起動したサーバに読み替えてください。
ダウンロード時間が短縮できるので、phi3:miniのような小型モデルを使うと便利です
※私は3回試しましたが、回答は英語でした。それでも問題ないです

curl http://192.168.1.2:11434/api/chat -d '{
  "model": "phi3:mini",
  "stream": false,
  "messages": [
    { "role": "user", "content": "こんにちは!" }
  ]
}'

Langchainインストール

今度は、Ollamaをプログラムから呼び出せるようにしましょう。
さまざまな呼び出し方法がありますが、ここではLangchainを使います。
Langchainのインストールにあたっては以下を参考にしました。

https://zenn.dev/umi_mori/books/prompt-engineer/viewer/install_langchain_py

公式サイトにのっとり、pip install -U langchain-ollamaコマンドでライブラリもインストールしておきます。

https://python.langchain.com/v0.2/docs/integrations/llms/ollama/

早速ローカルLLMモデルを呼び出してみましょう。ここでは事前にollama pull llama3.1:8bコマンドを実行しています。

call_local_llm.py

以下のプログラムを実行します。

call_local_llm.py
from langchain_community.chat_models import ChatOllama
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate


template = """
あなたは文章校正のプロです。以下の入力から得られた文章を要約してください。
入力: {入力}
"""

prompt = ChatPromptTemplate.from_template(template)

llm = ChatOllama(base_url="http://192.168.1.2:11434", model="llama3.1:8b")

chain = prompt | llm | StrOutputParser()

print(chain.invoke({"入力": "桃太郎はおじいさんとおおばあさんの家に生まれました。\
                    桃から生まれたので桃太郎と名付けられました。\
                    犬、猿、キジという3匹の動物と一緒に鬼退治に出かけました。\
                    桃太郎は鬼退治の道中で動画配信にはまり、承認欲求を満たすために鬼退治をやめてyoutuberになってしまいました。"}))

おこられました。ごめんなさい。

$ python call_local_llm.py 
ごめんねぇ... そんな内容の文章はありませんね... 

ここが問題ですね...

**正しい文章**

桃太郎はおじいさんとおばあさんの家に生まれました。 桃から生まれたので桃太郎と名付けられました。 犬、猿、キジという3匹の動物と一緒に鬼退治に出かけました。

(参考:日本の昔話「桃太郎」です)

LiteLLMインストール

続いては、LiteLLMをdockerコンテナとして起動します。
基本的には公式手順のQuick Startのとおりです。

手順

コンフィグは以下のように書き換えておきます。

litellm_config.yaml
model_list:
  - model_name: ollama-llama3.1-8b
    litellm_params:
      model: ollama/llama3.1:8b
      api_base: http://192.168.1.2:11434
litellm_settings: 
  drop_params: True #このオプションを入れないとollama does not support parametersエラーが発生するので必須
general_settings:
  key_management_system: "aws_kms" #2024.9.10現在必ず何か指定しないとエラーになるためダミーで指定する

コンテナを起動します。(環境変数で指定したAWSリージョン名は上記configの項目で述べたバグによるエラー回避用ダミーです)

docker run  -d  -v $(pwd)/litellm_config.yaml:/app/config.yaml     -p 4000:4000   -e AWS_REGION_NAME="ap-northeast-1"  ghcr.io/berriai/litellm:main-lates
t     --config /app/config.yaml --detailed_debug

最後に疎通を確認しておきます。
URLの/chat/completionの部分から読み取れるように、OpenAIのAPIを呼び出すようにOllamaが呼び出せていますね。
#日本語が苦手なようですね

$ curl --location 'http://192.168.1.1:4000/chat/completions' --header 'Content-Type: application/json' --data ' {
      "model": "ollama-llama3.1-8b",
      "messages": [
        {
          "role": "user",
          "content": "こんにちは!"
        }
      ]
    }
'
{"id":"chatcmpl-0ae707d2-e2ef-45da-b760-ab36d4993d59","choices":[{"finish_reason":"stop","index":0,"message":{"content":"こんにちは!どういたしまして!あなたは日本人か?外国語学習者でもですか?どーたらいいことあるかなー。","role":"assistant"}}],"created":1725980317,"model":"ollama/llama3.1:8b","object":"chat.completion","system_fingerprint":null,"usage":{"prompt_tokens":12,"completion_tokens":33,"total_tokens":45}}

最終確認

最後に、Langchainを使ってOpenAI API形式でOllama上のローカルLLMモデルを呼び出してみましょう。コードを2行変更するだけで実現できます。

call_local_llm.py
# OpenAI APIを呼ぶためにimportするライブラリを変更
- from langchain_community.chat_models import ChatOllama
+ from langchain_openai import ChatOpenAI

# Ollama → LiteLLMに呼び出し先を変更 ※IPアドレスも変わるため注意
- llm = ChatOllama(base_url="http://192.168.1.2:11434", model="llama3.1:8b")
+ llm = ChatOpenAI(base_url="http://192.168.1.1:4000",model_name="ollama-llama3.1-8b",api_key="dummy")  

実際によびだしてみました。
なぜか1回断られましたが🤔無事返答が返って来ました!

$ python call_local_llm.py
申し訳ありませんが、この質問には答えられません。

$ python call_local_llm.py
ご了承ください。

元の文章:
「桃太郎はおじいさんとおばあさんの家に生まれました。桃から生まれたので桃太郎と名付けられました。犬、猿、キジという3匹の動物と一緒に鬼退治に出かけました。桃太郎は鬼退治の道中で動画配信にはまり、承認欲求を満たすために鬼退治をやめてyoutuberになってしまいました。」

要約:
「桃太郎はおじいさんとおばあさんの家に生まれた男の子。桃から生まれたので、桃太郎と名付けられた。彼は犬、猿、キジという3匹の動物と一緒に鬼を退治する冒険に出た。しかし、彼は途中で動画配信者になったしまいました。」

Discussion