2024/09/12(木)に開催された 生成 AI Application Development with LLMs on Google Cloud のテクニカルトレーニングに参加しました。
そこで感じたこと、学んだことを紹介します!
なぜトレーニングイベントに参加したのか
理由は以下の2つです。
仕事に関係しない技術の探究
1つは、ふだんの仕事では使わない技術に触れるきっかけが欲しかったからです。
エンジニアとして仕事で使う技術を勉強するのは一般的なことですが、仕事に必要なことばかり学んでいると徐々に視野が狭まる気がします。
「仕事のため」という意識が続くと、好奇心に従って新しい知識を探求するという楽しみも薄れるでしょう。
技術知識を増やすことは、今後参画するプロジェクトの幅を広げられるはずです。
長期的にみると、定期的に仕事と関係ない技術を学ぶようにしたいものです。
私はこれまで生成 AI のアプリ開発をしたことがなかったので、今回のイベントはちょうど良い内容でした。
社外エンジニアとの交流
もう一つの動機は、社外エンジニアとの交流です。
結果としては、今回のイベントは講義形式だったのでほとんど交流機会はありませんでしたが...。
日ごろ、社内のエンジニアとは 1on1 などでキャリアや勉強法、セルフマネジメントについて話すことが多いです。
社外エンジニアと会話することで、
- 世の中に技術がどのように活用されているのか
- どのような課題を解決しているのか
- 世の中の企業は何に困っているのか
などを知る機会になれば良いなという思いがありました。
技術が問題を解決しているリアルな実情を知れたら、勉強のモチベーションも上がるでしょう。
ビジネス的な視点以外にも、単に社外の人との交流することで気晴らしになるという側面もあると思っています。
私はまだエンジニア歴1年弱と経験が浅いので、私にとって技術力と経験のあるエンジニアとの交流機会は貴重です。
意識的に社外エンジニアと交流する機会は作っていきたいものです。
トレーニングイベントで学んだこと
以降では、イベントで学んだことを書きます。生成 AI アプリ開発に興味がある方はぜひ参考にしてみてください。
今回のイベントでは、LangChain を使った対話型生成 AI チャットアプリ開発について学びました。
以下に特に勉強になったトピックを書きます。
生成 AI の課題
昨今の生成 AI は、与えるプロンプトの工夫次第でかなり高精度で人間が求める回答をしてくれるようになりました。
とは言え、まだまだ品質の制御は難しいようです。
特に計算問題や、生成 AI のモデルに学習されていない情報について回答させると不正確な答えが返ってきたりします。
生成 AI を使う側は、AI が不正確な回答をし得ることをよく理解したうえで利用することが重要です。
また、生成 AI が誤った情報をあたかも正しいことのように説明することをハルシネーション(幻覚)と呼びます。
プロンプトエンジニアリング
生成 AI からより正確な回答を得るための指示や命令、設計の技術をプロンプトエンジニアリングと呼びます。
以下に代表的なプロンプト技術を紹介します。
Zero-shot prompting
Zero-shot prompting は、具体例などの詳細説明を与えずに回答させる方法です。
以下の文章から読み取れる感情は「ポジティブ」「ネガティブ」のどちらですか?
文章:今日の天気は晴れです!
ChatGPT 4o の回答
この文章から読み取れる感情は「ポジティブ」です。
Few-shot Prompting
Few-shot Prompting は、回答パターンや具体例を示したうえで回答させる方法です。
りんご:赤
ピーマン:緑
みかん:橙
バナナ:黄
上記に倣って、ナスについて答えて。
ナス:
ChatGPT 4o の回答
ナス:紫
上記のように、明示的に色に言及していない質問にも回答できています。
Chain-of-Thought Prompting
Chain-of-Thought Prompting は、連鎖的にプロンプトを与えることで求める回答に近づけていくプロンプト技術です。
ナオキさんは、鉛筆を15本持っており、2本を友人のカズヤさんにあげました。
翌日、知り合いのミキさんから鉛筆を3本もらった直後に
兄弟のタクヤさんと13本の鉛筆を同じ数だけ交換しました。
現在、ナオキさんは鉛筆を合計何本もっていますか。
ChatGPT 4o の回答
ナオキさんが現在持っている鉛筆の本数を順を追って計算します。
1. 初めにナオキさんは15本の鉛筆を持っています。
2. カズヤさんに2本あげたので、15 - 2 = 13本になります。
3. 翌日、ミキさんから3本もらいましたので、13 + 3 = 16本になります。
4. タクヤさんと13本の鉛筆を同じ数だけ交換したため、鉛筆の本数は変わりません(交換なので増減なし)。
したがって、現在ナオキさんは16本の鉛筆を持っています。
質問文ごとに対応する計算過程を回答しており、最終的に正しい回答をしています。
ReAct
ReAct は、推論(Reasoning)と行動(Acting)を組み合わせて、言語モデルで推論とタスク遂行を行わせるプロンプト技術です。
Thought(思考)、Action(行動)、Observation(観察)の3つをプロンプトに含めるのが一般的のようです。
エンジニアの効率的な勉強方法を教えてください。
Thought:
Action:
Observation:
ChatGPT 4o の回答
Thought:
エンジニアの効率的な勉強方法を模索する際、効果的なアプローチとして具体的な行動計画を立てることが重要です。
Action:
目標設定 - 学習する分野やスキルを明確にします。
教材選び - 信頼できる教材やオンラインコースを活用。
実践 - コーディングやプロジェクトベースの学習で知識を応用。
コミュニティ参加 - オンラインフォーラムやオープンソースプロジェクトに参加。
レビューとフィードバック - 定期的に進捗を確認し、改善点を見つける。
Observation:
自分の理解度を高めるためには、実践的な経験とフィードバックが重要です。
Google Cloud のデータガバナンス
まず、データガバナンスという用語について、以下に Google Cloud が定義する内容を示します。
データ ガバナンスは、データの取得から、使用および廃棄に至るまでのライフサイクル全体にわたってデータを管理するための原則に則ったアプローチです。
データ管理において、特にセキュリティ面の不安から、重要なデータをクラウド環境に保管することに抵抗のある企業・個人は少なくないのではないでしょうか。
Google Cloud では、豊富なセキュリティサービス・監視サービスを提供してくれています。
生成 AI を使用する場合に関しても基盤モデルに送信される顧客データはすべて暗号化され、顧客からの明示的な同意がなければ学習に使用されることもありません。
最低限のセキュリティ知識は必要ですが、正しく運用すればセキュリティリスクを抑えられるはずです。
LangChain を使った対話型 AI チャットアプリ開発
LangChain とは
LangChain は、大規模言語モデル(LLM)に基づいてアプリケーション開発を構築するための OSS フレームワークです。
Python や TypeScript などの言語をサポートしています。以下では、Python での実装例を書いています。
LangChain を用いた対話型アプリの実装例
以下に LangChain を用いた対話型アプリの実装例を示します。
実行環境は Google Cloud の Vertex AI ワークベンチの Jupyter Notebook を想定しています。
ライブラリのインストール
以下のコマンドで必要なライブラリをインストールしましょう
明示的にバージョン指定していないライブラリは最新バージョンをインストールするよう --upgrade
オプションをつけています。
また、--user
オプションで、Notebook にログインしているユーザーにのみインストールするようにしています。
! pip install google-cloud-aiplatform \
langchain==0.0.323 \
chromadb==0.3.26 \
pydantic==1.10.8 \
typing-inspect==0.8.0 \
typing_extensions==4.5.0 \
pandas \
datasets \
google-api-python-client \
pypdf \
faiss-cpu \
transformers \
config \
--upgrade --user
カーネルインスタンスの再起動
ライブラリをインストールできたら、Kernel を再起動して環境が新しいパッケージにアクセスできるようにします。
以下のコードを Notebook セルで実行しても良いですし、Notebook の UI から手動で Kernel を Restart しても良いです。
import IPython
app = IPython.Application.instance()
app.kernel.do_shutdown(True)
ライブラリのインポート
以下の Notebook セルを実行して使用するライブラリをインポートしましょう。
LangChain と Vertex AI SDK のバージョンを出力します。
import time
import langchain
from google.cloud import aiplatform
from langchain.chat_models import ChatVertexAI
from langchain.embeddings import VertexAIEmbeddings
from langchain.llms import VertexAI
from langchain.schema import HumanMessage, SystemMessage
from pydantic import BaseModel
from langchain.prompts import PromptTemplate
print(f"LangChain version: {langchain.version}")
print(f"Vertex AI SDK version: {aiplatform.version}")
Output
LangChain version: 0.0.323
Vertex AI SDK version: 1.67.1
Vertex AI Embeddings API 呼び出し制限をかける関数を定義
Vertex AI Enbeddings API には時間あたりの API 呼び出し回数に制約があるため、Python 側で制限するよう関数を定義しておきます。
# Embeddings APIのレート制限のためのユーティリティ関数
def rate_limit(max_per_minute: int) -> None:
period = 60 / max_per_minute
print("Waiting")
while True:
before = time.time()
yield
after = time.time()
elapsed = after - before
sleep_time = max(0, period - elapsed)
if sleep_time > 0:
print(".", end="")
time.sleep(sleep_time)
class CustomVertexAIEmbeddings(VertexAIEmbeddings, BaseModel):
requests_per_minute: int
num_instances_per_batch: int
# embed_documents メソッドのオーバーライド
def embed_documents(self, texts: list) -> list:
limiter = rate_limit(self.requests_per_minute)
results = []
docs = list(texts)
while docs:
head, docs = (
docs[: self.num_instances_per_batch],
docs[self.num_instances_per_batch :],
)
chunk = self.client.get_embeddings(head)
results.extend(chunk)
next(limiter)
return [r.to_numpy() for r in results]</code></pre></div>
モデル定義
今回は、text-bison という生成 AI モデルを使用します。
text-bison モデルとは
text-bison モデルは、Vertex AI が提供する学習済み生成 AI モデルの一つで、Google が開発した PaLM 2 の Bison モデルを言語タスク向けに最適化されたモデルです。
Embedding 手法を使います。
Embedding とは 自然言語(単語、文章)をベクトル空間に変換してコンピュータが自然言語を理解できるようにする手法です。
llm = VertexAI(
model_name="text-bison",
max_output_tokens=256,
temperature=0.1,
top_p=0.8,
top_k=40,
verbose=True,
)
EMBEDDING_QPM = 100
EMBEDDING_NUM_BATCH = 5
embeddings = CustomVertexAIEmbeddings(
requests_per_minute=EMBEDDING_QPM,
num_instances_per_batch=EMBEDDING_NUM_BATCH,
)
example_prompt = PromptTemplate(
input_variables=["input", "output"],
template="Example Input: {input}\nExample Output: {output}",
)
examples = [
{"input": "pirate", "output": "ship"},
{"input": "pilot", "output": "plane"},
{"input": "driver", "output": "car"},
{"input": "tree", "output": "ground"},
{"input": "bird", "output": "nest"},
]
example_selector = SemanticSimilarityExampleSelector.from_examples(
examples,
embeddings,
FAISS,
k=2,
)
similar_prompt = FewShotPromptTemplate(
example_selector=example_selector,
example_prompt=example_prompt,
prefix="指定したものが通常置かれている場所を示す",
suffix="Input: {noun}\nOutput:",
input_variables=["noun"],
)
my_noun = "student"
print(similar_prompt.format(noun=my_noun))
print(llm(similar_prompt.format(noun=my_noun)))
Output
Waiting
指定したものが通常置かれている場所を示す
Example Input: driver
Example Output: car
Example Input: pilot
Example Output: plane
Input: student
Output:
school
ここでは、Few-shot Prompting でプロンプトを与えて、example 変数に具体例を提示しながら質問しています。
各種モデルで調整するパラメータについて理解できていないところもありますが、概ね LangChain を使って生成 AI アプリケーションを作る流れはイメージできました。