見出し画像

Notion DBを参照するQAボットをLangChainで作成

はじめに

以前書いたこちらの記事を一部変更してNotion DBを参照するQAボットを作成しました。データソースをテキストからNotion DBとするとともにVectorDBもオンメモリのchromaからPineconeに変更しました。

Google Colabで実行

環境変数にOpenAIとGoogle Search APIのトークンを設定

# OpneAIとGoogle Search APIキー
%env OPENAI_API_KEY = sk-
# https://note.com/npaka/n/nd9a4a26a8932
%env GOOGLE_CSE_ID = 
%env GOOGLE_API_KEY = 

パッケージのインストール

!pip install langchain
!pip install openai
!pip install gradio
!pip install -U pinecone-client
!pip install tiktoken
!pip install gradio

Notion DBをロード

Notion DBのロードは、LangChainのドキュメントを参照しました。
Notion DBはLangChainのデモリポジトリに含まれるBlendle Employee Handbookを使用しました。

from langchain.document_loaders import NotionDirectoryLoader
loader = NotionDirectoryLoader("Notion_DB")
documents = loader.load()

Pineconeのindexを作成

アカウントを作成してapi_keyとenvironmentを取得します。
https://dev.classmethod.jp/articles/dive-deep-into-modern-data-saas-about-pinecone/

import pinecone
from langchain.vectorstores import Pinecone

pinecone.init(
    api_key="xxxxxxxxxxxxxxxxxx",
    environment="xxxxxxxxxx"
)

index = 'sample'

if index not in pinecone.list_indexes():
    pinecone.create_index(index, dimension=1536)

Notion DBをEmbeddingしてPineconeに格納

# Embedding用
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.text_splitter import RecursiveCharacterTextSplitter

text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
docs = text_splitter.split_documents(documents)

embeddings = OpenAIEmbeddings()
db = Pinecone.from_documents(docs, embeddings, index_name=index)

Tool、Agent、GUIのパッケージをインポート

# Google Search API
from langchain.utilities import GoogleSearchAPIWrapper
# Memory
from langchain.memory import ConversationBufferMemory
# ChatOpenAI
from langchain.chat_models import ChatOpenAI
# VectorDB
from langchain.chains import RetrievalQA
# agentとtool
from langchain.agents import Tool, initialize_agent
# prompt
from langchain.agents import ZeroShotAgent, Tool, AgentExecutor
from langchain import LLMChain
# UI
import gradio as gr

AI に使用させるツール (Google検索とNotion DB) を定義

# GoogleSearchAPIとvectorDB
search = GoogleSearchAPIWrapper()

notion = RetrievalQA.from_chain_type(llm=ChatOpenAI(), chain_type="map_reduce", retriever=db.as_retriever())
tools = [
    Tool(
        name = "Search",
        func=search.run,
        description="useful for when you need to answer questions about current events"
    ),
    Tool(
        name = "Notion DB",
        func=notion.run,
        description="useful for when you need to answer question about Blendle's Employee Handbook."
    )
]
# agent が使用する memory の作成
memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)

Promptを定義

どのツールを使用したか、回答の末尾に追加してもらいます。

prefix = """Answer the following questions as best you can. You have access to the following tools and indicate which tool you used:"""
suffix = """Begin! Use lots of tools, and please answer finally in Japanese. Please indicate which tool you used in parentheses at the end of your answer.
     {chat_history}
        Question: {input}
        {agent_scratchpad}"""
prompt = ZeroShotAgent.create_prompt(
    tools,
    prefix=prefix,
    suffix=suffix,
    input_variables=["chat_history","input", "agent_scratchpad"]
)

Agentを定義

promptとLLMをLLMChainで組み合わせる

llm_chain = LLMChain(llm=ChatOpenAI(model_name="gpt-3.5-turbo", temperature=0.75), prompt=prompt)

# エージェントの準備
agent = ZeroShotAgent(llm_chain=llm_chain, tools=tools, memory=memory)

# AgentExecuterで実行
agent_executor = AgentExecutor.from_agent_and_tools(agent=agent, tools=tools, verbose=True, memory=memory)

GUIの定義

responseでagent_executorを使用することを指定

def chat(message, history):
  history  = history or []

  try:
    response = agent_executor.run(input = message)
  
  except Exception as e:
    response = f"予期しないエラーが発生しました: {e}"

  history.append((message, response))
  return history, history

chatbot = gr.Chatbot()

demo = gr.Interface(
    chat,
    ['text',  'state'],
    [chatbot, 'state'],
    allow_flagging = 'never',
)

会話の開始

demo.launch(share=False, debug=True)

feedback processについて聞いてみる

feedback processについての回答

同じ質問に対して使うツールが変わったり、回答に掛かる時間も数十秒とまだ実用には及ばないように思いました。LLMにgpt-3.5-turboを使用していますが、gpt-4が利用できればもう少し精度は上がるかもですね。


本日GPT-4 APIの招待が届いたので、以下はGPT-4で試しました。

フィードバックプロセスの中身について、問い合わせてみます。
フィードバックプロセスの中に360度評価に関する記述があるので、チャットボットに360度が評価が含まれるのかを問い合わせてみます。

Blendleのfeedback中の360度評価に関する記述

ちゃんと360度評価が含まれることを教えてくれました。gpt-4にした方が、suffixで指定した通り日本語で回答してくれるようになった気がします(英語で聞いても)。

360度評価の有無ついての回答

Gradioのタイムアウト

gradioのデフォルトのtimeout時間は60秒で、それまでに回答が生成できないことがたまにあります。その時はキューイングが可能のようです。
https://gradio.app/key-features/#queuing

demo = gr.Interface(
    chat,
    ['text',  'state'],
    [chatbot, 'state'],
    allow_flagging = 'never',
).queue()

実行するときは、Share=Trueとする必要があるようです。

demo.launch(share=True, debug=True)

2分以上回答に時間を要しましたが、タイムアウトにならずに答えが返ってきました。

フィードバック方法全体に関する質問

GPT-4とGPT-3.5-turboの比較

GPT-4にしても、回答が返ってくるまでに少し時間は掛かりますが、精度的にはGPT-3.5-turboより改善しているように思いました(個人の感想です)。

gpt-4
gpt-3.5-turbo

この記事が気に入ったらサポートをしてみませんか?