Chatbotのお勉強

この投稿は、セイミンが、日々、AIのお勉強のノートです。

目次

APIの基本コード

import os

from google.colab import userdata

os.environ[“OPENAI_API_KEY”] = userdata.get(“OPENAI_API_KEY”)

APIキーを呼び出す基本コード。

roleの基本コード

from openai import OpenAI

client = OpenAI()

response = client.chat.completions.create(

model=”gpt-4o-mini”,

messages=[

{“role”: “system“, “content”: “You are a helpful assistant.”},

{“role”:”user“, “content”: “こんにちは!私はジョンと言います!”},

{“role”:”assistant“,”content”: “こんにちは!ジョンサン!お会いできて嬉しいです。今日はどんなことをお話ししましょうか?”},

{“role”:”user”, “content”: “私の名前が分かりますか?”},

],

)

print(response.to_json(indent=2))

  • system → AIへの指示書
  • user → 人間の発言
  • assistant → AIの発言

JSONとは?

一言でいうと、データを整理して書くための共通フォーマット

たとえば普通に書けば、

名前:ジョン年齢:30趣味:登山

これをJSONで書くと、

{ “name”: “John”, “age”: 30, “hobby”: “登山”}

となる。

パラメーターとは

パラメータ(parameter)は、一言でいうと 「動作を調整するために渡す設定値」

response = client.chat.completions.create(
model=”gpt-4o-mini”,
messages=[
{“role”: “user”, “content”: “こんにちは”}
],
)

 ここでは、

model=”gpt-4o-mini”

messages=[…]

がパラメータ。

つまり、

「どのモデルを使う?」→ model
「何をAIに伝える?」→ messages

という設定をAPIに渡してる。

プロンプトエンジニアリング

OpenAIのガイド

OpenAIプロンプトエンジニアリングガイド

  1. 最新のモデルを使用する。
  2. 指示をプロンプトの冒頭に置き、### または “”” で指示とコンテキストを分ける。
  3. 望ましいコンテキスト、結果、長さ、形式、スタイルなどについて、できるだけ具体的、説明的、詳細にする。
  4. 例を通じて望ましい出力形式を明確にする。
  5. ゼロショットから始め、次にフューショット(いくつかの例を示す)を試し、どちらもうまくいかなければファインチューニングする。←これ結構大事かも
  6. 「ふわっとした」不正確な説明を減らす。
  7. してはいけないことを言うだけでなく、代わりに何をすべきかを言う。
  8. コード生成向け – 「先導語」を使ってモデルを特定のパターンへ誘導する。
  9. 「Generate Anything(何でも生成)」機能の使用。

LangChain

できること

  • ChatGPTのように会話できるチャットボット
  • 文章の要約ツール
  • 社内文書やPDFファイルへのQ&Aアプリ
  • AIエージェント

Chat model

チャット形式の言語モデルをLangChainで扱うためのコンポーネント。

from langchain_core.messages import AIMessage, HumanMessage, SystemMessage
from langchain_openai import ChatOpenAI

model = ChatOpenAI(model="gpt-4o-mini", temperature=0)

messages = [
    SystemMessage("You are a helpful assistant"),
    HumanMessage("こんにちは!私はセイミンと言います!"),
    AIMessage(content="こんにてゃ、セイミンさん!どのようにお手伝いしましょうか?"),
    HumanMessage(content="私の名前が分かりますか?")
]

ai_message = model.invoke(messages)
print(ai_message.content)
  • SystemMessageは、”role”: “system”に対応。
  • HumanMessageは、”role”: “user”に対応。
  • AIMessageは、”role”: “assistant”に対応。
  • temperatureは、大きいほど出力がランダムになり、小さいほど決定的になるパラメータ。

LLMとChat modelの継承関係

Prompt template

プロンプトをテンプレート化できる。

from langchain_core.prompts import PromptTemplate

prompt = PromptTemplate.from_template("""以下の料理のレシピを考えて下さい。

料理名: {dish}""")

prompt_value = prompt.invoke({"dish": "カレー"})
print(prompt_value.text)

dishをカレーに置き換えているだけで、LLMは動かしていない。

ChatPromptTemplate

from langchain_core.prompts import ChatPromptTemplate

prompt = ChatPromptTemplate.from_messages(
    [
    ("system", "ユーザーが入力した料理のレシピを考えて下さい。"),
    ("human", "{dish}"),
    ]
                                          )
                                          
prompt_value = prompt.invoke({"dish": "カレー"})
print(prompt_value)
messages=[SystemMessage(content='ユーザーが入力した料理のレシピを考えて下さい。', additional_kwargs={}, response_metadata={}), HumanMessage(content='カレー', additional_kwargs={}, response_metadata={})]
  • “human” = “role”: “user”に対応
  • “ai” = “role””assistant”に対応。

PromptTemplateChatPromptTemplate の違いは、かなりシンプル。

PromptTemplate → 1枚の文章を作る
ChatPromptTemplate → 会話形式のメッセージを作る

Chain-LangChain Expression Language(LCEL)の概要ーつまりchain(連鎖)のはなし

LLMアプリケーションで、処理を連鎖的につなぎたいことが多い。

  • Prompt templateを穴埋めして、その結果をChat model(4o-miniとか)に与え、GPTが返した回答を、Pythonが扱えるデータとして受け取る。
  • Zero-shot CoTポロンプティングでステップバイステップで考えさせて、その結果を要約したい。
  • LLMの出力を得た後で、その内容がサービスのポリシーに違反していないか(たとえば差別的な表現でないか)チェックしたい。
  • LLMの出力結果をもとに、SQLを実行してデータを分析させてみたい。

LCELとは

Chain-LangChain Expression Language(LCEL)は、LangChainでのChainの記述方法です。
LCELではプロンプトやLLMを「|」でつなげて書き、処理の連鎖(Chain)を実装します。

promptとmodelの連鎖

はじめに、prompt(ChatPromptTemplate)とmodel(ChatOpenAI)を準備する。

from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI

prompt = ChatPromptTemplate.from_messages(
    [
        ("system", "ユーザーが入力した料理のレシピを考えて下さい。"),
        ("human", "{dish}"),
    ]
)

model = ChatOpenAI(model_name="gpt-4o-mini", temperature=0)

そして、これらをつないだchainを作成する。

chain = prompt | model

このchainを実行する。

ai_message = chain.invoke({"dish": "カレー"})
print(ai_message.content)

LLMの生成した応答が表示される。

カレーのレシピをご紹介します。シンプルで美味しい基本のカレーを作りましょう。

材料(4人分)

  • 鶏肉(もも肉または胸肉): 400g
  • 玉ねぎ: 2個
  • にんじん: 1本
  • じゃがいも: 2個
  • カレールー: 1箱(約200g)
  • サラダ油: 大さじ2
  • 水: 800ml
  • 塩: 適量
  • 胡椒: 適量
  • お好みでガーリックパウダーや生姜: 適量

作り方

  1. 材料の下ごしらえ:
  • 鶏肉は一口大に切り、塩と胡椒をふっておきます。
    *以下略

StrOutputParserを連鎖に追加

str(string)とは文字列

from langchain_core.output_parsers import StrOutputParser

chain = prompt | model | StrOutputParser()
output = chain.invoke({"dish": "カレー"})
print(output)

RAG(Retrieval-Augmented Generation)

RAGとは、プロンプトに文脈(context)を入れる方法。

R = Retrieval(検索)
A = Augmented(情報を追加)
G = Generation(生成)

大量の文書

質問に関係する部分を検索 ← Retrieval

見つかった文章

contextとしてプロンプトに追加 ← Augmented

LLMが回答を生成 ← Generation

入力をもとに文書を検索して、検索結果をcontextに含めて、LLMに回答させる手法

LangchainのRAGに関するコンポーネントの概要

LangChainでは、RAGに使用するためのさまざまなコンポーネントが提供されている。以下が、主なコンポーネント。

  1. Document loder: データソースからドキュメントを読み込む
  2. Document transformer: ドキュメントに何らかの変換をかける
  3. Embedding model: ドキュメントをベクトル化する。ベクトル化=文章の「意味」を、複数の数値の並びに変換すること
  4. Retriver: 入力のテキストと関連するドキュメントを検索する

これらは、データソースから、Retriverによる検索まで、つながる行程。

1. Document loder(読み込む)

例えば、LangChainの公式ドキュメントの一部を読み込んでみる。

パッケージ(最新バージョンを確認する必要がある。GPTに聞け)

!pip install langchain-community==0.3.0 GitPython==3.1.43

続いて、Document loderの一種であるGitLoaderを使い、LangChainのリポジトリから、.mdxのファイルを読み込む。

from langchain_community.document_loaders import GitLoader

def file_filter(file_path: str) -> bool:
    return file_path.endswith(".mdx")

loader = GitLoader(
    clone_url="https://github.com/langchain-ai/docs",
    repo_path="./langchain-docs",
    branch="main",
    file_filter=file_filter,
)

raw_docs = loader.load()

print(len(raw_docs))

読み込んだデータの件数が表示される。

2. Document transformer(変換する)

Document loaderで読み込んだデータは「ドキュメント」と呼ぶ。

ドキュメントに変換をかける。

適切な大きさのチャンクに分割することで、LLMに入力するトークン数を削除したり、より正確な回答が得やすくなる。

ドキュメントをチャンク化する機能はText splintterという。

langchain-text-splittersをインストール

!pip install langchain-text-splitters==0.3.0

ドクメントをチャンクに分割

from langchain_community.document_loaders import GitLoader

def file_filter(file_path: str) -> bool:
    return file_path.endswith(".mdx")

loader = GitLoader(
    clone_url="https://github.com/langchain-ai/docs",
    repo_path="./langchain-docs",
    branch="main",
    file_filter=file_filter,
)

raw_docs = loader.load()

print(len(raw_docs))

chunk_size=1000: 1つの文章を約1000文字単位のかたまり(chunk)に分ける。
chunk_overlap=0: 前後のチャンクをどれくらい重複させるか。0なので、重複無し。RAGでは、文章がちょうど境界で切れて意味が分からなくなるのを防ぐため、少し重複させることも多い

3. Embedding model(ベクトル化)

テキストの変換処理を終えたら、テキストをベクトル化する。

OpenAIEmbeddingsのように、テキストのベクトル化に使えるのが、Embedding modelである。

まず、OpenAIEmbeddingsのインスタンスを作成します。

from langchain_openai import OpenAIEmbeddings

embeddings = OpenAIEmbeddings(model="text-embedding-3-small")

例えば、こんな感じ。

query  ="AWSのS3からデータを読み込むためのDocument loaderがありますか?"

vector = embeddings.embed_query(query)
print(len(vector))
print(vector)

1536
[0.017791748046875, -0.006954193115234375, 0.03387451171875, -0.0262298583984375, …

Vector store

ドキュメントをベクトル化して保存する。

例えば、Chromerというローカル使用可能なVectorを使う。

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

!pip install -U langchain-chroma

-Uは最新版という意味。

チャンクに分割したドキュメントと、Embedding modelをもとに、Vector storeを初期化する。つまり、細かく切った文章をEmbeddingモデルで数字に変換して、検索できるデータベース(Vector Store)を作る

from langchain_chroma import Chroma

db = Chroma.from_documents(docs, embeddings)

Vector storeに対しては、ユーザーの入力に関連するドキュメントを得る操作を行います。

LangChainにおいて、テキストに関連するドキュメントを得るインターフェイスをRetrieverと呼ぶ。

Retriever(リトリーバー)=質問に関係する文章をVector Storeから探して取ってくる係

Vector storeのインスタンスから、Retrieverを作成する。

retriever = db.as_retriever()

次に、Retrieverを使って、試しに「AWSのS3からデータを読み込むためのDocument loaderがありますか?」という質問に近いドキュメントを検索してみる。

query = "AWSのS3からデータを読み込むためのDocument loaderがありますか?"

context_docs = retriever.invoke(query)
print(f"len = {len(context_docs)}")

first_doc = context_docs[0]
print(f"metadata = {first_doc.metadata}")
print(first_doc.page_content)

4件ヒット。

len = 4
metadata = {‘file_path’: ‘src/oss/python/integrations/document_loaders/index.mdx’, ‘file_type’: ‘.mdx’, ‘source’: ‘src/oss/python/integrations/document_loaders/index.mdx’, ‘file_name’: ‘index.mdx’}

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

はじめまして。木村整民です。
天台宗の僧侶・仏教学研究者として、インド仏教や日本仏教を研究しています。
Buddha AIでは、仏教を分かりやすく伝える記事や、AIを活用した仏教学習・翻訳・チャットボットの開発について発信しています。

コメント

コメントする

目次