この投稿は、セイミンが、日々、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のガイド
- 最新のモデルを使用する。
- 指示をプロンプトの冒頭に置き、### または “”” で指示とコンテキストを分ける。
- 望ましいコンテキスト、結果、長さ、形式、スタイルなどについて、できるだけ具体的、説明的、詳細にする。
- 例を通じて望ましい出力形式を明確にする。
- ゼロショットから始め、次にフューショット(いくつかの例を示す)を試し、どちらもうまくいかなければファインチューニングする。←これ結構大事かも
- 「ふわっとした」不正確な説明を減らす。
- してはいけないことを言うだけでなく、代わりに何をすべきかを言う。
- コード生成向け – 「先導語」を使ってモデルを特定のパターンへ誘導する。
- 「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”に対応。
PromptTemplate と ChatPromptTemplate の違いは、かなりシンプル。
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
- 塩: 適量
- 胡椒: 適量
- お好みでガーリックパウダーや生姜: 適量
作り方
- 材料の下ごしらえ:
- 鶏肉は一口大に切り、塩と胡椒をふっておきます。
*以下略
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に使用するためのさまざまなコンポーネントが提供されている。以下が、主なコンポーネント。
- Document loder: データソースからドキュメントを読み込む
- Document transformer: ドキュメントに何らかの変換をかける
- Embedding model: ドキュメントをベクトル化する。ベクトル化=文章の「意味」を、複数の数値の並びに変換すること
- 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’}


コメント