こんにちは! 逆瀬川
前回はOpenAIが公開しているChat APIとWhisper APIを用いて議事録文字起こしアプリケーションを作ってみました。今回は、Chat APIを便利に使うためのライブラリであるLangChainとguidanceを紹介していきます。
なぜ便利に使うためのライブラリが必要なのか?
単純にChat APIにリクエストを送るだけであれば、各言語に用意されたライブラリを使うだけで良いでしょう。たとえば、Pythonにおいてはopenai-pythonが用意されています。前回紹介したとおり、Chat APIを使うだけなら以下のようなリクエストを作るだけで済みます。
import openai
openai.api_key = "sk-..." # APIキー
completion = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": "こんにちは!"}]
)
print(completion.choices[0].message.content)
しかし、
こうした課題を解決するために作られたものが、LangChainおよびguidanceとなります。
LangChainとは
LangChainとは、大規模言語モデルを使った様々なアプリケーションの開発を支援するためにつくられたライブラリです。非常に汎用的な目的のもと作られていますが、大別して
Chatbot
Chatbotは、ChatGPTのようなアプリケーションを作成するための機能です。OpenAIのライブラリに不足していた、会話の履歴を保持する能力を持ちます。LangChainでは、この履歴のことをMemoryと呼称しています。
Agent
Agentは、大規模言語モデルの判断能力を活かして、ユーザーの代わりに様々なツールを組み合わせてタスクを実行するための機能です。これは、汎用的な人工知能を目指したものであるとも言えます。
汎用人工知能には任意のタスクを任意のツールから自動で実行することが求められます。Agentでは、ツールの選択や入力の決定を言語モデルの能力を用いて行います。たとえば、
LangChainの使い方
それではLangChainの使い方を見ておきましょう。
以下を実行し、langchainおよびopenai-pythonをインストールします。
pip install langchain pip install openai
Chatbotを用いた履歴を保持した会話
LangChainのChatbotにおいて主に使うのは、OpenAI
、LLMChain
、PromptTemplate
、ConversationBufferWindowMemory
の各モジュールです。OpenAI
はOpenAIのAPIを呼び出すために使われ、LLMChain
はプロンプトやメモリ等を統括するために用いられます。PromptTemplate
はプロンプトの管理役で、ConversationBufferWindowMemory
がチャット履歴の保持部分にあたります。
ここでは通常の会話をしてみましょう。
from langchain import OpenAI, LLMChain, PromptTemplate
from langchain.memory import ConversationBufferWindowMemory
template = """あなたは優秀なアシスタントです。
{history}
Human: {human_input}
Assistant:"""
prompt = PromptTemplate(
input_variables=["history", "human_input"],
template=template
)
chatgpt_chain = LLMChain(
llm=OpenAI(temperature=0),
prompt=prompt,
verbose=True,
memory=ConversationBufferWindowMemory(k=2),
)
output = chatgpt_chain.predict(human_input="こんにちは")
print(output)
PromptTemplate
のhistory
は会話履歴を参照するための変数であり、ConversationBufferWindowMemory
の引数のk=2
は、過去2件の会話履歴を保持することを意味します。
このプログラムを実行すると、以下のような結果になります。
> Entering new LLMChain chain... Prompt after formatting: あなたは優秀なアシスタントです。 Human: こんにちは Assistant: > Finished chain. こんにちは!どうしましたか?
また続けて以下を実行すると、会話履歴を明示的に与えずに会話が引き継がれることが分かります。
output = chatgpt_chain.predict(human_input="今日はいい天気ですね")
print(output)
> Entering new LLMChain chain... Prompt after formatting: あなたは優秀なアシスタントです。 Human: こんにちは AI: こんにちは!どうしましたか? Human: 今日はいい天気ですね Assistant: > Finished chain. はい、今日はとてもいい天気ですね!
Agentを用いたWikipediaの参照
Agentではload_
でツールをロードし、initialize_
でツールやAgentを設定します。ここではWikipediaを参照して、
pip install wikipedia
このライブラリではwikipediaのページをリクエストしますが、残念ながら英語版しか対応していないため、英語でプロンプトを構築することにします。
from langchain.agents import load_tools
from langchain.agents import initialize_agent
from langchain.llms import OpenAI
llm = OpenAI(temperature=0)
tools = load_tools(["wikipedia"], llm=llm)
agent = initialize_agent(tools, llm, agent="zero-shot-react-description", verbose=True)
agent.run("Please tell me about the characters in Bocchi the Rock?")
このプログラムを実行すると、以下のような出力が得られます。
> Entering new AgentExecutor chain... I should look up information about the characters in Bocchi the Rock. Action: Wikipedia Action Input: Bocchi the Rock characters Observation: Page: Bocchi the Rock! Summary: Bocchi the Rock! (ぼっち・ざ・ろっく!, Botchi Za Rokku!) is a Japanese four-panel manga series written and illustrated by Aki Hamaji. It has been serialized in Houbunsha's seinen manga magazine Manga Time Kirara Max since December 2017. Its chapters have been collected in five tankōbon volumes as of November 2022. An anime television series adaptation produced by CloverWorks aired from October to December 2022. The series has been praised for its writing, comedy, characters, and depiction of social anxiety, with the anime's visual creativity receiving acclaim. Page: Hitori Bocchi no Marumaru Seikatsu Summary: Hitori Bocchi no Marumaru Seikatsu (Japanese: ひとりぼっちの○○生活, lit. "Bocchi Hitori's ____ Life" or "The ____ Life of Being Alone") is a Japanese yonkoma manga series written and illustrated by Katsuwo. It was serialized in ASCII Media Works' Comic Dengeki Daioh "g" magazine from September 2013 to April 2021. Eight tankōbon volumes have been released. An anime television series adaptation by C2C aired from April to June 2019. Page: Yoshino Aoyama Summary: Yoshino Aoyama (Japanese: 青山吉能, Hepburn: Aoyama Yoshino, born May 15, 1996) is a Japanese voice actress and singer affiliated with 81 Produce. Some of her noteworthy roles include Yoshino Nanase in Wake Up, Girls!, Guri in Love Tyrant, Makoto in Shachibato! President, It's Time for Battle!, and Hitori Gotō in Bocchi the Rock!. Thought: I now know the final answer. Final Answer: Yoshino Aoyama is a Japanese voice actress and singer affiliated with 81 Produce who is known for her role as Hitori Gotō in Bocchi the Rock!. > Finished chain. Yoshino Aoyama is a Japanese voice actress and singer affiliated with 81 Produce who is known for her role as Hitori Gotō in Bocchi the Rock!.
ぼっち・
guidanceとは
guidanceとは、Microsoftが開発した、大規模言語モデルのプロンプトエンジニアリングを効率的に行うことを補助するためのライブラリです。先ほどのLangChainのAgentは複雑な機能の開発を視野に入れたライブラリでしたが、guidanceはより言語モデル自体を使いやすくすることに焦点を当てています。
guidanceの使い方
それではguidanceを使ってみましょう。以下を実行し、guidanceをインストールします。
pip install guidance
基本的な使い方
もっともシンプルなサンプルは以下のようになります。
import guidance
guidance.llm = guidance.llms.OpenAI("gpt-4")
create_plan = guidance('''{{#system~}}
あなたは素晴らしいアシスタントです。
{{~/system}}
{{#user~}}
{{user_input}}
{{~/user}}
{{#assistant~}}
{{gen 'answer' temperature=1.0 max_tokens=600}}
{{~/assistant}}''')
out = create_plan(user_input='こんにちは', parse_best=parse_best)
out
llm
の部分で言語モデルを設定しています。次のguidance
に渡すプロンプトの部分で、システム設定、ユーザー入力、アシスタント
guidance
内のプロンプトでは以下の事柄を記述しています。
{{#system~}}
と{{~/system}}
で囲まれた部分:システム設定{{#user~}}
と{{~/user}}
で囲まれた部分:ユーザー入力{{#assistant~}}
と{{~/assistant}}
で囲まれた部分:言語モデルからの返答- 生成部分は
{{gen 'answer' temperature=1.
のように表現します。0 max_ tokens=600}}
- 生成部分は
応用的な使い方
より複雑なプロンプトの組み合わせを考えてみましょう。今回は、冷蔵庫にある食材から晩ごはんのメニューを検討し、どのように調理するかスケジュール立てをするAIを作ってみます。フローとしては、以下のようになります。
- 食材からメニュー候補を考える
- メニュー候補と現在の体調からもっとも良いと思われるものを選択する
- 調理方法を提案する
これを実装すると以下のようになります。
import guidance
import re
guidance.llm = guidance.llms.OpenAI("gpt-4")
def parse_best(prosandcons, options):
best = re.search(r'Best=(\d+)', prosandcons)
if not best:
best = re.search(r'Best.*?(\d+)', 'Best= option is 3')
if best:
best = int(best.group(1))
else:
best = 0
return options[best]
create_plan = guidance('''{{#system~}}
あなたは素晴らしい料理研究家です。
{{~/system}}
{{#user~}}
私は以下の食材から料理を行いたいと思っています。
{{shokuzai}}
{{~! 食材からメニュー候補を考える ~}}
この食材群から作れる料理について 1 つの教えてください。
料理名は非常に短く、最大でも 1 行にしてください。
{{~/user}}
{{#assistant~}}
{{gen 'foods' n=5 temperature=1.0 max_tokens=600}}
{{~/assistant}}
{{~! 体調を考慮し、メニュー候補からもっとも良いと思われるものを選択する ~}}
{{#user~}}
私は今晩の晩ごはんを決めたいです。
なお、今のわたしの体調は{{condition}}です。
体調を考慮しつつ、次の各メニューから長所と短所についてコメントして、最適なメニューを選択していただけますか?
---{{#each foods}}
Menu {{@index}}: {{this}}{{/each}}
---
各メニューについて非常に簡潔に説明し (長所を1行、短所を1行)、最後に Best=X (X が最良のオプション) と言って終了してください。
{{~/user}}
{{#assistant~}}
{{gen 'prosandcons' temperature=0.0 max_tokens=600}}
{{~/assistant}}
{{#user~}}
{{~! 調理方法の提案 }}
私は今晩の晩ごはんを作りたいです。
私が作る予定の料理は以下です:
{{parse_best prosandcons foods}}
また材料は以下です:
{{shokuzai}}
この料理の作り方を詳しく説明してください。
{{~/user}}
{{#assistant~}}
{{gen 'plan' max_tokens=1024}}
{{~/assistant}}''')
out = create_plan(shokuzai='納豆、ピーマン、レタス、レッドブル、生姜、味噌、きゅうり、メロン、ハム、卵', condition='胃が重い', parse_best=parse_best)
out
最終的に以下のような胃に優しいどんぶりが提案されました。
納豆きゅうり卵の丼の作り方: 材料: - 納豆 1パック - きゅうり 1本 - 卵 2個 - ごはん 1膳分 - 醤油 小さじ1 - みりん 小さじ1 - 生姜 1かけ(すりおろす) 手順: 1. きゅうりを洗って、薄い輪切りにする。 2. 生姜をすりおろし、醤油とみりんと混ぜてタレを作る。 3. 納豆に付属のたれとからしを加えて、よくかき混ぜる。 4. 卵を割り入れ、納豆と一緒にさらによくかき混ぜる。 5. ごはんを丼に盛り、きゅうりを敷き詰める。 6. 納豆卵をごはんの上にかけ、作ったタレをかける。 7. お好みで、刻んだ海苔や白ごまをトッピングして完成。 注意: 今回の材料リストに含まれるピーマン、レタス、レッドブル、味噌、メロン、ハムは、納豆きゅうり卵の丼には使用していません。別の料理やサイドメニューとして活用してください。
プロンプト部分を詳しく見ていきましょう。
{{#system~}}
あなたは素晴らしい料理研究家です。
{{~/system}}
{{#user~}}
私は以下の食材から料理を行いたいと思っています。
{{shokuzai}}
{{~! 食材からメニュー候補を考える ~}}
この食材群から作れる料理について 1 つの教えてください。
料理名は非常に短く、最大でも 1 行にしてください。
{{~/user}}
{{#assistant~}}
{{gen 'foods' n=5 temperature=1.0 max_tokens=600}}
{{~/assistant}}
まず、この部分でメニュー候補を5つ生成しています。生成したメニューはfoods
という変数でアクセス可能になっています。
{{~! 体調を考慮し、メニュー候補からもっとも良いと思われるものを選択する ~}}
{{#user~}}
私は今晩の晩ごはんを決めたいです。
なお、今のわたしの体調は{{condition}}です。
体調を考慮しつつ、次の各メニューから長所と短所についてコメントして、最適なメニューを選択していただけますか?
---{{#each foods}}
Menu {{@index}}: {{this}}{{/each}}
---
各メニューについて非常に簡潔に説明し (長所を1行、短所を1行)、最後に Best=X (X が最良のオプション) と言って終了してください。
{{~/user}}
{{#assistant~}}
{{gen 'prosandcons' temperature=0.0 max_tokens=600}}
{{~/assistant}}
次にこちらで体調とメニュー候補群をもとにメニューを決めています。新しく登場した {{#each foods}}
と {{/each}}
ですが、これはプログラミングにおけるForeach文であり、foods
変数にアクセスして、メニュー候補を取得しています。これらのメニュー候補を展開後、{{gen 'prosandcons' temperature=0.
で長所と短所をコメントさせ、もっとも良いメニューを選択させています。
{{~! 調理方法の提案 }}
私は今晩の晩ごはんを作りたいです。
私が作る予定の料理は以下です:
{{parse_best prosandcons foods}}
また材料は以下です:
{{shokuzai}}
この料理の作り方を詳しく説明してください。
{{~/user}}
{{#assistant~}}
{{gen 'plan' max_tokens=1024}}
{{~/assistant}}
最後に選択されたメニューをもとに作り方を提案しています。prosandcons
の生成時には最終行にBest=X
と出力させるようにしていましたが、parse_
関数ではこの情報をもとに何番目のメニューがもっとも良かったかという情報を抽出し、そのメニュー名を求める処理をしています。このように、外部で定義された関数も使用できます。
まとめ
今回はLangChainおよびguidanceというライブラリを紹介し、Chat APIをより簡単で便利に活用するための方法についてまとめました。これらを用いることで、より発展的なアプリケーションが作れるでしょう。