見出し画像

LangChainでChatGPTに検索とDBの機能を追加する

はじめに


人には、数時間の間保管される短期記憶と年単位で保管される長期記憶があり、短期記憶は、数秒から数時間の記憶で、リアルタイムでの対話やタスクを遂行する際に役立ちます。一方、長期記憶は、年単位で大量の情報を保管し、過去の経験や学習を現在に活かします。これをAIに当てはめるとPromptを通したAIとの会話は、短期記憶に相当するのではないでしょうか。

一方、長期記憶に相当する機能はChatGPTなどのAI単体では実現できないためベクトルデータベースを利用することが必要になります。

また、Google検索を可能とすることで、AIは最新の情報や専門知識の利用も可能になります。

Google Colabで実行

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

# OpneAIとGoogle Search APIキー
%env OPENAI_API_KEY = sk-xxxxxxxxxxxxxxxxxxx
%env GOOGLE_CSE_ID = xxxxxxxxxxxxxxxxxxxxxxx
%env GOOGLE_API_KEY = xxxxxxxxxxxxxxxxxxxxxx

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

!pip install langchain
!pip install openai
!pip install gradio
!pip install chromadb
!pip install tiktoken
!pip install gradio
!pip install unstructured

Vector DB を作るまでに必要なパッケージをインポート

# テキストファイルの読み込み
from langchain.document_loaders import UnstructuredFileLoader
# from langchain.text_splitter import CharacterTextSplitter
from langchain.text_splitter import RecursiveCharacterTextSplitter
# Embedding
from langchain.embeddings.openai import OpenAIEmbeddings
# vectorDB
from langchain.vectorstores import Chroma

テキストファイルを読み込んでVector DBを作成

今回はジョジョの奇妙な冒険 Part3 スターダストクルセイダースのwikiを利用しました。
テキストファイル以外にもより実用的なソースとして例えば、Notion DB なども利用可能です。
大規模なデータを利用する際はPineconeなど外部のVectorDBのサービスを利用することになるかと思います。

# テキストファイルの読み込みとチャンクへ分割
loader = UnstructuredFileLoader("jojo3.txt")
documents = loader.load()
# text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
docs = text_splitter.split_documents(documents)

# Embedding
embeddings = OpenAIEmbeddings()
# vectorDBの作成
db = Chroma.from_documents(docs, embeddings)

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

# Google Search API
from langchain.utilities import GoogleSearchAPIWrapper
# Memory
from langchain.memory import ConversationBufferMemory
# ChatOpenAI
from langchain.chat_models import ChatOpenAI
# Retriever
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検索とVectorDB) を定義

# GoogleSearchAPIとvectorDB
search = GoogleSearchAPIWrapper()

jojo3 = 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 = "database of jojo part3",
        func=jojo3.run,
        description="useful for when you need to answer question about jojo part3."
    )
]
# agent が使用する memory
memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)

Promptを定義

prefixではツールを使えるとことを伝え、suffixでは承太郎っぽく回答してくれるように語尾を指定

prefix = """次の質問にできる限り日本語で答えてください。次のツールにアクセスできます:"""
suffix = """始めましょう! 最終的な答えを出すときは、回答の後に"やれやれだぜ"を追加してください

Question: {input}
{agent_scratchpad}"""

prompt = ZeroShotAgent.create_prompt(
    tools,
    prefix=prefix,
    suffix=suffix,
    input_variables=["input", "agent_scratchpad"]
)

Agentを定義

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

llm_chain = LLMChain(llm=ChatOpenAI(temperature=0), prompt=prompt)

# エージェント
agent = ZeroShotAgent(llm_chain=llm_chain, tools=tools)

# 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 []
  response = agent_executor.run(input = message) 
  
  history.append((message, response))
  
  return history, history

chatbot = gr.Chatbot().style(color_map=('green', 'pink'))

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

会話の開始

demo.launch()
Vector DBを利用した回答
検索を利用した回答


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