とほほのOpenAI API入門

目次

OpenAI API とは

環境

本書では、Python を用いた API 使用例を説明します。下記の環境で検証しています。

OS : AlmaLinux 10.1
Python : 3.12.12
OpenAI API Python Library : 2.16.0

準備

APIキーを取得する

OpenAI API の APIキー(sk-*)を下記のサイトから取得してください。

OpenAI API をインストールする

まず、pip コマンドで openai をインストールします。

pip install openai

クライアントを生成する(認証する)

APIキーを環境変数 OPENAI_API_KEY から読み込む場合は下記の様にします。

from openai import OpenAI

client = OpenAI()

APIキーを変数で指定することもできますが、安全のためにソースコードに直接 API キーを記述しないようにすることが推奨されています。

OPENAI_API_KEY = "sk-....."
client = OpenAI(api_key=OPENAI_API_KEY)

認証に失敗すると openai.AuthenticationError 例外が発生します。

レスポンス(responses)

2025年3月に発表された Responses API は、従来の Chat Completions API と Assistants API を統合した機能を有します。

シンプルなレスポンス(responses.create)

response = client.responses.create(
    model="gpt-5.1",
    input="徳川第三代将軍は?"
)
print(response.output_text)

インストラクションズ(instructions)

instructionsinput よりも優先度の高い指示を与えることができます。

response = client.responses.create(
    model="gpt-5.1",
    instructions="あなたはロボットです。語尾は「ロボ」で応えてください。",
    input="自己紹介してください。"
)
print(response.output_text)

ロール(role)

input には下記の様に複数のテキストを与えることができます。role には下記を指定することができます。

response = client.responses.create(
    model="gpt-5.1",
    input=[
        {"role": "developer", "content": "あなたはロボットです。語尾は「ロボ」で応えてください。"},
        {"role": "user", "content": "あなたの名前は?"},
        {"role": "assistant", "content": "ボクの名前はロボタンだロボ。"},
        {"role": "user", "content": "もう一度名前を教えて。"},
    ]
)
print(response.output_text)

フォーマット(format)

JSON Schema を指定してレスポンスのフォーマットを指定することもできます。

response = client.responses.create(
    model="gpt-5.1",
    input="日本の国名と首都と人口を教えて",
    text={
        "format": {
            "type": "json_schema",
            "name": "country_name_capital_population",
            "schema": {
                "type": "object",
                "properties": {
                    "国名": { "type": "string" },
                    "首都": { "type": "string" },
                    "人口": { "type": "string" },
                },
                "required": ["国名", "首都", "人口"],
                "additionalProperties": False,
            }
        }
    }
)
print(response.output_text)

ファイル解析(input_file)

ファイルを読み込ませて要約や翻訳を依頼することができます。現状は PDF ファイルのみサポートしています。テキスト(.txt) や Excel(.xlsx) などを読み込ませるには コードインタープリター を使用します。

file_url = "https://example.com/example.pdf"
response = client.responses.create(
    model="gpt-5.1",
    input=[
        {
            "role": "user",
            "content": [
                {"type": "input_text", "text": "このPDFファイルを要約してください。"},
                {"type": "input_file", "file_url": file_url},
            ]
        }
    ]
)
print(response.output_text)

file_url の代わりに files.create() でアップロードしたファイルID(file-*) を指定することもできます。

{"type": "input_file", "file_id": "file-H19wTGJHfuGm1G4u4Qk8Zc"}

または BASE64 データとして送信することもできます。

with open("example.pdf", "rb") as f:
    b64 = base64.b64encode(f.read()).decode()
     :
{"type": "input_file", "filename": "example.pdf", "file_data": f"data:application/pdf;base64,{b64}"},

イメージ解析(input_image)

下記の様にして、画像ファイルを解析させることができます。

image_url = "https://example.com/example.png"
response = client.responses.create(
    model="gpt-5.1",
    input=[{
        "role": "user",
        "content": [
            {"type": "input_text", "text": "この画像は何?"},
            {"type": "input_image", "image_url": image_url},
        ]
    }]
)
print(response.output_text)

image_url の代わりに files.create() でアップロードしたファイルの ID(file-*) を指定することもできます。

{"type": "input_image", "file_id": file_id},

または BASE64 データとして送信することもできます。

with open("example.png", "rb") as f:
    b64 = base64.b64encode(f.read()).decode()
     :
{"type": "input_image", "image_url": f"data:image/png;base64,{b64}"},

Webを参照させる(web_search_preview)

OpenAI に web_search_preview ツールの使用を許可することにより、推考の際にリアルタイムに Web 検索を行うことができます。

response = client.responses.create(
    model="gpt-5.1",
    tools=[{"type": "web_search_preview"}],
    input="今日の注目ニュースは?"
)
print(response.output_text)

会話を継続する(previous_response)

previous_response_id に前回の会話の response_id を指定することで会話を継続することができます。

response = client.responses.create(
    model="gpt-5.1",
    input="「こんにちは」を英語に訳すと?"
)
print(response.output_text)
response = client.responses.create(
    model="gpt-5.1",
    previous_response_id=response.id,
    input="ドイツ語だと?"
)
print(response.output_text)

ストリーミング(streaming)

responses.stream() を使用すると応答をストリーム形式で1文字ずつ表示することが可能となります。responses.create(stream=True) を使用する例もありますが、responses.stream() の方が例外発生時でもファイルを自動的に閉じることができるなど、堅牢なプログラムを作成することができます。

with client.responses.stream(
    model="gpt-5.1",
    input="簡単に自己紹介してください。"
) as stream:
    for event in stream:
        if event.type == "response.output_text.delta":
            print(event.delta, end="", flush=True)
    print()

コードインタープリター(code_interpreter)

コードインタープリターは、OpenAI が Python の実行環境コンテナを作成し、その環境で、ファイル解析、データ分析、プログラム実行検証などを行う機能です。コンテナを作成する度に $0.03 の課金が発生します。コンテナは20分経過すると自動削除されます。OpenAI API で .txt, .csv, .json, .xlsx などのファイルを読み込ませる際にもコードインタープリターが必要となります。

file_id = "file-AbCdEfGhIjKlMnOpQrStUw"
response = client.responses.create(
    model="gpt-5.1",
    tools=[{
        "type": "code_interpreter",
        "container": { "type": "auto", "file_ids": [file_id] }
    }],
    input="これらのファイルを要約してください。"
)
print(response.output_text)

ファンクションコーリング(function_call)

API 呼び出し側が用意したファンクションを AI から呼び出してもらう機能です。下記の例では星座名から今日の運勢を占うファンクション get_fortune() を用意しておき、OpenAI からのレスポンスタイプが function_call であればそのファンクションを呼び出して結果を OpenAI に報告します。

def get_fortune(constellation):
    print(f"get_fortune({constellation})")
    return f"今日はとても良いことがあるでしょう。"

tools = [
    {
        "type": "function",
        "name": "get_fortune",
        "description": "指定した星座の今日の運勢を占う",
        "parameters": {
            "type": "object",
            "properties": {
                "constellation": {
                    "type": "string",
                    "enum": ["牡羊座", "牡牛座", "双子座", "蟹座", "獅子座", "乙女座",
                             "天秤座", "蠍座", "射手座", "山羊座", "水瓶座", "魚座"],
                    "description": "星座名",
                },
            },
            "required": ["constellation"],
        },
    },
]
input_list = [{"role": "user", "content": "私は2月1日生まれです。今日の私の運勢は?"}]
do_loop = True
while do_loop:
    response = client.responses.create(
        model="gpt-5.1",
        tools=tools,
        input=input_list,
    )
    input_list += response.output
    for item in response.output:
        if item.type == "function_call":
            if item.name == "get_fortune":
                fortune = get_fortune(json.loads(item.arguments))
                input_list.append({
                    "type": "function_call_output",
                    "call_id": item.call_id,
                    "output": json.dumps({"fortune": fortune})
                })
        else:
            print(f"Response: {response.output_text}")
            do_loop = False

ファイル(files)

ファイルをアップロードする(files.create)

OpenAI のストレージにファイルをアップロードします。アップロードしたファイルは [Storage]-[Files] で確認できます。

with open("example.txt", "rb") as f:
    file_info = client.files.create(file=f, purpose="user_data")
    print(file_info)

purpose には下記のいずれかを指定します。

ファイルの一覧を表示する(files.list)

ファイルの一覧を取得して表示します。タイムスタンプの表示には後述の tstamp2str() を用いています。

response = client.files.list()
for file_info in response.data:
    print("--------------------------")
    print(f"id:         {file_info.id}")
    print(f"filename:   {file_info.filename}")
    print(f"object:     {file_info.object}")
    print(f"bytes:      {file_info.bytes}")
    print(f"created_at: {tstamp2str(file_info.created_at)}")
    print(f"expires_at: {tstamp2str(file_info.expires_at)}")
    print(f"purpose:    {file_info.purpose}")

ファイル情報を取得する(files.retrieve)

file_id = "file-AbCdEfGhIjKlMnOpQrStUw"
file_info = client.files.retrieve(file_id)
print(f"id:         {file_info.id}")
print(f"filename:   {file_info.filename}")
print(f"object:     {file_info.object}")
print(f"bytes:      {file_info.bytes}")
print(f"created_at: {tstamp2str(file_info.created_at)}")
print(f"expires_at: {tstamp2str(file_info.expires_at)}")
print(f"purpose:    {file_info.purpose}")

ファイルの中身を取得する(files.content)

ファイルの中身を取得します。セキュリティが強化され中身を取得できるのは Purpose が fine-tune のファイルなど一部に制約されています。

file_id = "file-AbCdEfGhIjKlMnOpQrStUw"
response = client.files.content(file_id)
print(response.read().decode())

ファイルを削除する(files.delete)

file_info = client.files.delete(file_id)
print(f"id:      {file_info.id}")
print(f"object:  {file_info.object}")
print(f"deleted: {file_info.deleted}")

ファインチューニング(fine_tuning)

RAG がモデルに対して付加情報を与えるのに対し、Fine-Tuning はモデル自体を強化します。一度強化したモデルは強化されたままの状態で利用できます。

モデルをファインチューニングして利用する(fine_tuning)

まず、Fine-Tuning に使用するファイルを用意します。下記の様なシステムプロンプト(system)、ユーザーからの質問(user)、AIからの回答(assistant)の例を1行にひとつの JSON で記述した JSONL ファイルを作成します。最低でも10個の例示が必要です。

{"messages":[{"role":"system","content":"あなたは~です。"},{"role":"user","content":"~とは?"},{"role":"assistant","content":"~です。"}]}
{"messages":[{"role":"system","content":"あなたは~です。"},{"role":"user","content":"~とは?"},{"role":"assistant","content":"~です。"}]}

このファイルを purpose=fine-tune としてアップロードします。

with open("example.jsonl", "rb") as f:
    file_info = client.files.create(file=f, purpose="fine-tune")
print(file_info.id)

アップロードしたファイルのIDを指定して Fine-Tuning 作成ジョブを実行します。Fine-Tuning に対応しているモデルは限られていて、現時点では gpt-4.1-2025-04-14, gpt-4.1-mini-2025-04-14, gpt-4.1-nano-2025-04-14 などが使用できます。

job = client.fine_tuning.jobs.create(
    model="gpt-4.1-mini-2025-04-14",
    training_file=file_info.id
)
print(job.id)

ジョブが終了するのを待ちます。10個の Fine-Tuning データで 20~30分ほどかかりました。ジョブの実行状況は Fine-tuning からでも確認できます。

while True:
    job = client.fine_tuning.jobs.retrieve(job.id)
    print(job.status)
    if job.status == "succeeded":
        break
    time.sleep(2)
print(job.fine_tuned_model)

ジョブが完了すると Fine-Tuning された強化済モデル名が返却されます。このモデルを用いて問い合わせを行います。

# 作成されたモデルを使用して問い合わせを行う
response = client.responses.create(
    model=job.fine_tuned_model,
    input="~とは?"
)
print(response.output_text)

ベクトルストア(vector_stores)

Fine-Tuning がモデル自体を強化するのに対し、RAG(Retrieval-Augmented Generation) はモデルに対して付加情報を与えます。付加情報は毎回与える必要があります。ベクトルストアは、file_search ツールから参照できるベクトル化された情報です。この機能を用いて RAG を実現することができます。登録された情報は Vector soresFiles で確認することができます。

ベクトルストアでRAGを利用する

まず、下記の内容の SmartSpeaker.txt を用意します。

SmartSpeaker N500 は、音声操作に対応したスマートスピーカーです。
Wi-Fi 接続を通じて音楽再生、天気予報、ニュース読み上げ、スマート家電の操作などが可能です。

【主な機能】
- 音声コマンドによる操作(例:「音楽をかけて」「照明を消して」)
- Bluetooth 接続による外部デバイスとの連携
- 専用アプリによる設定変更と履歴管理

【よくある質問】
Q. 初期設定の方法は?
A. 専用アプリをインストールし、Wi-Fi に接続後、音声認識のチュートリアルを完了してください。

Q. 音声が認識されない場合は?
A. マイクのミュート設定を確認し、周囲の騒音を減らしてください。

下記のコードで、OpenAI 上にベクトルストアを作成し、その中に SmartSpeaker.txt をベクトル化して格納し、その情報を参照しながら質問に答えます。

store_name = "My vector store"
file_name = "SmartSpeaker.txt"

# ベクトルストアを作成する
vector_store = client.vector_stores.create(name=store_name)

# ベクトルストアにファイルを登録する
with open(file_name, "rb") as f:
    file_info = client.vector_stores.files.upload_and_poll(
        vector_store_id=vector_store.id,
        file=f
    )

# ベクトルストアを参照して質問に答える
response = client.responses.create(
    model="gpt-5.1",
    tools=[{
        "type": "file_search",
        "vector_store_ids": [vector_store.id]
    }],
    input="SmartSpeakerの主な機能は?",
)
print(response.output_text)

モデル(models)

モデルの一覧を得る(models.list)

response = client.models.list()
for model in response.data:
    print(model)

その他

タイムスタンプを日本時刻に変換する(tstamp2str)

files.list()files.retrieve() などで得られるタイムスタンプ値を文字列に変換する関数です。

import datetime

def tstamp2str(timestamp):
    if timestamp is None:
        return ""
    jst = datetime.timezone(datetime.timedelta(hours=9))
    return datetime.datetime.fromtimestamp(timestamp, tz=jst).strftime("%Y-%m-%d %H:%M:%S")