Skip to content

OpenAI APIでRAGのやり方

AIとかにIDやファイルパスを教えて以下のコードに当てはめて的な指示すれば一発だと思います。


この手順では 各自の環境に合わせて値を設定してください。

角括弧 <> のプレースホルダは必ず自分の値に置き換えること。

置換ルール(必読)

  • <VECTOR_STORE_ID>:自分のベクターストアID(例:vs_xxx...
  • <LOCAL_DIR>:分割したPDFを格納しているローカルフォルダの絶対パス
  • <BASE_FILENAME_PATTERN>:分割ファイルの共通パターン。{0} が連番に置換されます(例:MyDoc_Part{0}.pdf
  • <FIRST_INDEX> / <LAST_INDEX>:連番の開始・終了(例:1〜9)
  • OPENAI_API_KEY各自の環境変数に設定しておく(キー自体はこのドキュメントに記載しない)

実行前チェック

  • PowerShell 5.1 以上
  • curl.exeInvoke-RestMethod が使えること
  • echo $env:OPENAI_API_KEY でキーが見えること(キーは貼らない

スクリプト(テンプレート)

powershell
# ========= 設定(各自で置き換え)=========
$vsId   = "<VECTOR_STORE_ID>"          # 例: vs_********************************
$apiKey = $env:OPENAI_API_KEY          # 事前に環境変数に設定しておく
$dir    = "<LOCAL_DIR>"                # 例: C:\path\to\split_pdfs
$base   = "<BASE_FILENAME_PATTERN>"    # 例: MyDoc_Part{0}.pdf
$start  = <FIRST_INDEX>                # 例: 1
$end    = <LAST_INDEX>                 # 例: 9

# ========= 共通ヘッダー =========
$headersJson = @{ "Authorization"="Bearer $apiKey"; "Content-Type"="application/json" }
$headersGet  = @{ "Authorization"="Bearer $apiKey" }

# ========= HTTPエラー本文取得(見やすいログ用)=========
function Get-HttpErrorBody([System.Management.Automation.ErrorRecord]$err) {
  try {
    $resp = $err.Exception.Response
    if ($resp -and $resp.GetResponseStream) {
      $sr = New-Object System.IO.StreamReader($resp.GetResponseStream())
      return $sr.ReadToEnd()
    }
  } catch { }
  return $err.Exception.Message
}

# ========= 1ファイル処理 =========
function Invoke-UploadAndAttach {
  param(
    [Parameter(Mandatory=$true)][string]$FilePath,
    [Parameter(Mandatory=$true)][string]$VectorStoreId
  )

  $partName = [System.IO.Path]::GetFileName($FilePath)
  if (!(Test-Path -LiteralPath $FilePath)) {
    return [PSCustomObject]@{ Part=$partName; FileId=$null; Status="missing";  Error="File not found" }
  }

  Write-Host "`n=== Uploading: $partName ==="

  # 1) アップロード(purpose=assistants)
  $upload = curl.exe -s -X POST "https://api.openai.com/v1/files" `
    -H "Authorization: Bearer $apiKey" `
    -F "purpose=assistants" `
    -F "file=@$FilePath"

  try { $uobj = $upload | ConvertFrom-Json } catch {
    return [PSCustomObject]@{ Part=$partName; FileId=$null; Status="upload_failed"; Error="Invalid upload JSON: $upload" }
  }

  if ($uobj.error) {
    $msg = if ($uobj.error.message) { $uobj.error.message } else { "Upload error" }
    return [PSCustomObject]@{ Part=$partName; FileId=$null; Status="upload_failed"; Error=$msg }
  }

  $fileId = $uobj.id
  if (-not $fileId) {
    return [PSCustomObject]@{ Part=$partName; FileId=$null; Status="upload_failed"; Error="No file id in upload response" }
  }
  Write-Host "uploaded file_id: $fileId"

  # 2) ベクターストアへアタッチ(指数バックオフ)
  $payload = @{ file_id = $fileId } | ConvertTo-Json -Compress
  $maxAttempts = 5
  $attached = $false
  for ($a=1; $a -le $maxAttempts; $a++) {
    try {
      $attach = Invoke-RestMethod -Method Post `
        -Uri "https://api.openai.com/v1/vector_stores/$VectorStoreId/files" `
        -Headers $headersJson -Body $payload
      Write-Host "attached: $($attach.id) -> status: $($attach.status)"
      $attached = $true
      break
    } catch {
      $body = Get-HttpErrorBody $_
      Write-Warning "[Attempt $a/$maxAttempts] attach failed: $body"
      if ($a -lt $maxAttempts) { Start-Sleep -Seconds ([Math]::Min(10, [Math]::Pow(2, $a))) }
    }
  }
  if (-not $attached) {
    return [PSCustomObject]@{ Part=$partName; FileId=$fileId; Status="attach_failed"; Error="Attach failed after retries" }
  }

  # 3) ステータス監視(最大 8 分)
  $deadline = (Get-Date).AddMinutes(8)
  do {
    Start-Sleep -Seconds 3
    try {
      $status = Invoke-RestMethod -Method Get `
        -Uri "https://api.openai.com/v1/vector_stores/$VectorStoreId/files/$fileId" `
        -Headers $headersGet
      Write-Host "status: $($status.status)"
      if ($status.status -in @("completed","failed")) {
        if ($status.status -eq "failed") {
          $err = if ($status.last_error) { ($status.last_error | Out-String).Trim() } else { "Unknown ingestion error" }
          return [PSCustomObject]@{ Part=$partName; FileId=$fileId; Status="failed"; Error=$err }
        } else {
          return [PSCustomObject]@{ Part=$partName; FileId=$fileId; Status="completed"; Error=$null }
        }
      }
    } catch {
      $body = Get-HttpErrorBody $_
      Write-Warning "status check error: $body"
    }
  } while ((Get-Date) -lt $deadline)

  return [PSCustomObject]@{ Part=$partName; FileId=$fileId; Status="timeout"; Error="Ingestion did not finish in 8 minutes" }
}

# ========= メイン(連番ファイルを処理)=========
$results = @()
$start..$end | ForEach-Object {
  $path = Join-Path -Path $dir -ChildPath ($base -f $_)
  $results += Invoke-UploadAndAttach -FilePath $path -VectorStoreId $vsId
}

# ========= サマリー =========
"`n===== SUMMARY ====="
$results | Format-Table -AutoSize

$failed = $results | Where-Object { $_.Status -ne "completed" }
if ($failed) {
  "`nSome items did not complete:"
  $failed | ForEach-Object { " - $($_.Part): $($_.Status)  $($_.Error)" }
} else {
  "`n✅ All parts completed"
}

Author: 村井 | Source: 村井\uPano×MetaQuest3でパノラマビューアプリデモ開発\OpenAI APIでRAGのやり方 287aba435ee780bab388d2ac0d2ea573.md