レシピデータを読み込ませてお料理したいですよね。LLMを使って簡単にボットが作れます。
今回は弊社の株主であるABCクッキングスタジオさんのレシピを読み込んで、お料理作りを簡単にしてみます。
なすと挽き肉のボロネーゼごはん
https://www.abc-cooking.co.jp/plus/recipe/detail/?id=44750
ウェブサイトを見ただけではどこに注目すればいいのかわからない場合でも、下記のようにAIと会話しながらWebサイトの情報を欲しいところだけ教えてくれます。
必要な技術は、
Langchain(一通りのAIの手順を作る)
LLM(これはChatGPTなどのサービスでもいいし、自分のローカルPCに置いておくことも可能)
ウェブクローラー(今回は直接ウェブサイトから情報をとってきます)
gradio(簡単にウェブのインターフェースが作れます)
となります。まず、基本的なLLMの応答の作り方は別の記事で確認しました。
LLM + RAG 超入門
https://blueqat.com/yuichiro_minato2/a5278948-232f-45c9-859e-4257dd5d116a
まずモデルは今回はHugging Faceから読み込みました。Mistral7Bです。最近は日本語モデルも出てるので、必ずしもこれにこだわる必要はありません。
from transformers import AutoTokenizer, pipeline
#import torch
model_id = "mistralai/Mistral-7B-Instruct-v0.2"
tokenizer = AutoTokenizer.from_pretrained(model_id)
pipe = pipeline("text-generation", model=model_id, tokenizer=tokenizer, device=0, max_new_tokens=300)
次に前回はPDFLoaderを使いましたが、今回はこの部分を変更します。
from langchain_community.document_loaders import PyPDFLoader
from langchain_community.vectorstores import FAISS
from langchain_community.embeddings.huggingface import HuggingFaceEmbeddings
from langchain_text_splitters import CharacterTextSplitter
loader = PyPDFLoader("https://arxiv.org/pdf/2312.03982.pdf")
documents = loader.load()
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
docs = text_splitter.split_documents(documents)
embeddings = HuggingFaceEmbeddings(
model_name="intfloat/multilingual-e5-large"
)
db = FAISS.from_documents(docs, embeddings)
今回はウェブからとって来るので、
from langchain_community.document_loaders import WebBaseLoader
loader = WebBaseLoader("https://www.abc-cooking.co.jp/plus/recipe/detail/?id=44750")
めちゃくちゃ簡単ですよね。これでLoaderの設定は終わりです。最後にチャット部分ですが、プロンプトを含めた応答は、
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from langchain.llms import HuggingFacePipeline
llm = HuggingFacePipeline(pipeline=pipe)
template = """Answer the question based only on the following context:
{context}
Question: {question}
"""
prompt = ChatPromptTemplate.from_template(template)
def format_docs(docs):
return "\n\n".join([d.page_content for d in docs])
chain = (
{"context": retriever | format_docs, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
answer = chain.invoke(query)
print(answer)
これが基本でした。templateのところを日本語で、「下記のコンテクストに応じて質問に日本語で答えてください。」のように変更してあげてもいいです。そして、最後にこれをインターフェイスにします。
参考文献:
自前のチャットボットを「LlamaIndex+GPT4+gradio」で爆速構築してみよう!
https://qiita.com/DeepTama/items/1a44ddf6325c2b2cd030
こちらの記事はlangchainではなく似たようなLlamaIndexを使っていますが、基本的には同じです。
まずはgradioをインストール。
!pip install gradio
そして下記のようにPythonをかくとウェブサーバーが立ち上がります。
ローカルに立ち上がりますが、.launch()内部にパラメータを設定するとウェブアドレスを外部に立ち上げてもくれます。
ポイントは中程のresponseの部分を今回のLLMで構築したRAGに置き換えればOK。
import gradio as gr
import os
def add_text(history, text):
history = history + [(text, None)]
return history, gr.Textbox(value="", interactive=False)
def bot(history):
query = history[-1][0]
response = chain.invoke(query)
history[-1][1] = ""
for character in response:
history[-1][1] += character
yield history
with gr.Blocks() as demo:
chatbot = gr.Chatbot([])
with gr.Row():
txt = gr.Textbox(
scale=4,
show_label = False,
container = False
)
clear = gr.Button("Clear")
txt\_msg = txt.submit(add\_text, \[chatbot, txt\], \[chatbot, txt\], queue = False).then(bot, chatbot, chatbot)
txt\_msg.then(lambda: gr.Textbox(interactive = True), None, \[txt\], queue = False)
clear.click(lambda: None, None, chatbot, queue=False)
demo.queue()
demo.launch()
使いやすいインターフェースつきのRAGがすぐにできました!
ハルシネーションと言ってない幻覚を話してしまうこともあります。プロンプトエンジニアリングでなんとか解決しましょうね。以上です。