メタデータではなく意味による検索:4D.Vectorによるセマンティック画像フィルタリング

Deeplからの自動翻訳

ユーザーはファイル名やフォルダ階層で物事を考えません。アイデアで考えるのです。

  • “水彩画で描かれたロボット”
  • “色でいっぱいの晴れたビーチ”
  • “モナリザのような何か…でも未来から来たもの”

そのアイデアが画像から来るのか、顧客からの注文から来るのか、Eメールから来るのか、4D Write Proのドキュメントから来るのかは関係ありません。

4D.Vectorと 4D AI Kitを使えば、アプリケーションは最終的に意味を理解することができます。この記事では、セマンティック画像類似検索で説明します。ここで重要なのは、私たちは生画像を扱っているのではなく、その説明文を扱っているということです。全く同じアプローチが、アプリケーション内のあらゆる種類のテキストデータにも有効です。

DEMO_AI_Vector_ImageSearch

ベクター+AIがすべてを変える理由

従来の検索には、正確な用語にマッチさせるという1つの仕事があります。しかし、ユーザーは常に正確な用語を知っているとは限らない。ユーザーは物事を説明します。彼らは意図を表現する。彼らは雑然とした、美しい、人間の言葉で考える。

ユーザーが考えるように検索を機能させるには、文字列のマッチング以上のものが必要です。理解することが必要であり、それがベクター埋め込みの出番なのです。

エンベッディングとは何か?

エンベッディングとは、乱雑で構造化されていない入力(文章、プロンプト、画像など)を、構造化された数値のベクトルに変える方法です。単なるトークンやキーワードのリストではありません。意味の数学的スナップショットなのだ。

水彩画で描かれたロボット」というフレーズをOpenAIのtext-embedding-ada-002モデルに送ると、数百の浮動小数点値が返される。トピック、ムード、スタイル、そのプロンプトに組み込まれた意味的関係性など、それぞれが何かを捉えている。似たようなフレーズは似たようなベクトルを生成する。似ていないものは?それらは離れて着地する。

地図上に意味を配置するようなものだ。2つのフレーズがその高次元空間で近ければ近いほど、言い回しに関係なく、似ていることになる。これが、意味に基づいて検索、レコメンデーション、クラスタリング、分類を構築する基礎となる。

実際の使用例:意味による画像検索

私たちのデモページでは 、ユーザーに意味的に検索させることができる。ユーザーがプロンプトを入力するか、リストから1つを選ぶと、アプリはそのアイデアにどれだけマッチするかによってランク付けされた画像を返します。

UIはあえて最小限にしています:

  • カスタムプロンプト用のテキストフィールド
  • 定義済みのプロンプトのドロップダウン
  • プロンプトとの類似性でソートされた画像を表示するマトリックス

ここで重要なのは、生の画像をベクトル化していないことだ。代わりに、各画像はAIKitの OpenAIVisionによって分析され、自然言語でキャプションと説明を生成します。その説明が4D.Vectorに埋め込まれて保存される。

このようにして、すべてがピクセルではなく、意味のレベルで比較されます。

注:この例では4D Qodly Proを使用していますが、同じロジックは標準的な4Dフォームにも完全に当てはまります。実際、すべてのコードは4Dのメソッドや関数の中で実行されます。唯一の違いは、結果をどのように表示させるか、つまりクラシックな4DフォームかQodlyページかの選択です。

ベクターの生成方法

誰かがプロンプトを入力し、“Use Custom Prompt“をクリックすると、4DはVectorManagementクラスのcalculate() 関数を実行します:

exposed shared Function calculate($prompt : Text) : cs.PicturesSelection

これは、OpenAIのAPIキーをメモリから取得することから始まります (Storage.OpenAI.key) –情報タブの最初の入力フィールドから送信されるはずです。これをスキップしてUse Custom Prompt をクリックすると、続行する前にキーを入力するようモーダルが表示されます:

If (Storage.OpenAI.key#"")
	$apiKey:=Storage.OpenAI.key
Else 
	$apiModal:=Web Form.setApiKeyModal
	$apiModal.show()
End if 

注:この例では、AI操作にOpenAIを使用していますが、OpenAI互換のプロバイダであれば、Ollamaのローカルモデルでも使用できます。OpenAIはセットアップが簡単で、ローカルにインストールする必要がないからです。OpenAIを使いたい場合は、 からOpenAIのキーをリクエストしてください。

次に、AIManagementクラス内のgenerateVector() 関数を呼び出します:

var $vector := cs.AIManagement.new($apiKey).generateVector($prompt)

ここで何が起こっているのでしょうか?

短いテキストに最適化されたOpenAIのtext-embedding-ada-002モデルを使って、プロンプトを高次元ベクトルに変換しています。.create() メソッドを使って、OpenAI にプロンプトとtext-embedding-ada-002 モデルをリクエストとして送信し、ベクトルを含む JSON 構造体を返します。このベクトルは4D.Vector オブジェクトにラップされ、4Dでネイティブに比較したりソートしたりできるようになります。

property clientAI : Object

Class constructor($openAIKey : Text)
  This.clientAI := cs.AIKit.OpenAI.new($openAIKey)

Function generateVector($text : Text) : 4D.Vector
  var $model := "text-embedding-ada-002"
  var $result := This.clientAI.embeddings.create($text; $model)
  return $result.vector

この時点で、ユーザーのプロンプトを、4Dがセマンティック比較に使用できる構造化されたフォーマットに変換したことになります。

プロンプトからランキング結果へ

ベクターが手に入ったら、今度はデータベースに保存されているすべての画像説明ベクターと比較します:

var $pictureList := This._calculateVectors($vector)

そして、_calculateVectors 、次のことが起こります:

For each ($picture; $pictureList)
  $picture.cosineSimilarity := $vector.cosineSimilarity($picture.vector)
  $picture.dotSimilarity := $vector.dotSimilarity($picture.vector)
  $picture.euclideanDistance := $vector.euclideanDistance($picture.vector)
  $picture.save()
End for each 

各類似度測定は、異なるレンズを提供します:

  • コサイン類似度は、2つのベクトルがどれだけ同じ方向を向いているかを測定します。意味的類似度のランキングに最適です。
  • ドット積は方向と大きさの両方を考慮する。2つのベクトルがどれだけ “強く “整列しているかを考慮したい場合に便利です。
  • ユークリッド距離は、空間内の2点間の生の距離です。距離が小さければ小さいほど、両者は似ていることになります。

4Dでのベクトル計算が初めての方は、このシリーズの最初のブログ記事で、これらの方法を使ったベクトルの作成方法と比較方法、そしてそれぞれを使うタイミングについて解説しています。

すべての類似度スコアが計算され、画像エンティティに保存されたら、余弦類似度でソートして結果を返します:

return $pictureList.orderBy("cosineSimilarity desc")

つまり、ファイル名や説明文、メタデータに関係なく、概念的に最も関連性の高い画像が最初に表示されます。

ユーザーが定義済みのプロンプトを選択した場合はどうなりますか?

ユーザがドロップダウンからプロンプトを選択し、[ 選択されたプロンプトを使用] をクリックした場合 、埋め込みステップは完全にスキップされます:

exposed shared Function calculateWithSelectedPrompt($prompt : cs.PromptsEntity) : cs.PicturesSelection
  var $pictureList:=This._calculateVectors($prompt.Vector)
  return $pictureList.orderBy("cosineSimilarity desc")

プロンプトのベクターはすでにデータベースに保存されています。プロンプトのベクトルはすでにデータベースに保存されているため、プロンプトが最初に作成されたときにPromptsデータクラスに保存された4D.Vector を再利用するだけです。

画像の説明と同じように、各プロンプトは一度ベクトル化され、再利用のために保存されます。これにより

  • API呼び出しなし →即時の結果、ネットワーク遅延なし

  • トークンのコストなし →予算に優しい、特に規模が大きい場合

  • オフラインで動作 →外部サービスに依存せず、すべてローカルで動作

画像のアップロードからベクトル化された説明文まで

誰かが画像をアップロードしても、ピクセルを埋め込むことはありません。代わりに、OpenAI Visionで画像を説明し、その説明を埋め込みます。

vectorizeImageDescription関数では、2つのプロンプトが定義されています:1つは短いキャプション、もう1つは詳細な説明です。どちらも、埋め込み用に最適化された、流暢な文章を返すように作られています:

// --- Prompts (single, fluent, embedding-friendly) ---
$captionPrompt:="You are a precise visual captioner. "+\
	"Write one short, clear English sentence (12–20 words) that summarizes the main subject of the image. "+\
	"Keep it straightforward and descriptive, not poetic. Output only the sentence."

$descriptionPrompt:="You are a detailed scene describer. "+\
	"Write a longer English paragraph (80–150 words) that expands on the caption. "+\
	"Include context, secondary elements (icons, arrows, checklists, text, logos), and atmosphere so nothing important is missed. "+\
	"Avoid repeating the caption verbatim. Output only the description."

これらのプロンプトを使用して、OpenAI Visionは画像を分析します。これは2つのステップで行われる:

  • .create()は、アップロードされた画像に関連付けられたVisionHelperをインスタンス化します。
  • .prompt()は 、その画像とともに自然言語の指示をOpenAI Chat APIに送信し、キャプションまたは説明を返します。
// --- Get caption ---
$caption:=$client.chat.vision.create($imageData).prompt($captionPrompt).choice.message.text
	
// --- Get description ---
$description:=$client.chat.vision.create($imageData).prompt($descriptionPrompt).choice.message.text

この時点で、キャプションと説明文の両方があります。これらは画像そのものと一緒に保存され、最も重要なのは、説明文がセマンティック検索のためにベクトル化されることです:

// --- Save entity ---
$pictureEntity:=ds.Pictures.new()
$pictureEntity.picture:=$imageToUpload.picture
$pictureEntity.prompt:=$caption
$pictureEntity.description:=$description
$pictureEntity.vector:=cs.AIManagement.new($apiKey).generateVector($description+$caption)
$status:=$pictureEntity.save()

uiに表示されるもの

比較が終わると、マトリックスは即座に更新されます。画像は類似度スコアに基づいてランク付けされます。

  • 検索すると「ロボットの水彩画” – 柔らかいテクスチャとロボットの形をした画像が表示されます:

Visual results of a semantic AI image search using the prompt 'a watercolor painting of a robot,' showing six top-matching artworks with cosine similarity scores in a futuristic 4D interface.

  • あなたは次のように切り替えます:「カラフルな要素で活気に満ちた晴れたビーチシーン“に切り替えると、まったく異なる、しかし同様に関連性の高い結果セットが表示されます:

Semantic image search results for the prompt 'a vibrant and sunny beach scene with colorful elements,' ranked by AI using vector comparisons in a real-time 4D interface.

タイプしてもアップロードしても、ピクセルやファイル名ではなく、常にアイデアを比較することになる。

開発者として得られるもの

AIでベクターを使用することで、4Dアプリケーションの真の価値を即座に引き出します:

  • よりスマートな検索:ユーザーがキーワードではなく、意味によって検索できるようにします。タグもフィルターもなく、関連性のある結果だけが表示されます。

  • ネイティブなロジック:すべてが4D内部で実行されます。外部の検索エンジンやサードパーティのツールは必要ありません。

  • 再利用可能なパターン:画像、文書、商品、チケットなど、コンセプトで比較したいものなら何でも使えます。

  • 少ないセットアップ、高いインパクト:数行のコードで、AIによるランキング、フィルタリング、レコメンデーションが可能です。

  • より安く、より速く:一度埋め込めば、ベクトルを保存し、永久に再利用できます。何度もAPIを呼び出したり、トークンにコストをかける必要はありません。

  • AI対応基盤:単に検索機能を追加するだけでなく、チャットボット、レコメンデーション、よりスマートなワークフローを実現するための基盤を構築します。

4D.Vectorと4D AI Kitがあれば、インテリジェンスを構築する必要はありません。

最終的な感想

AIをアプリに追加するのではなく、コアロジックにインテリジェンスを組み込むのです。

4D.Vector と4D AI Kitを使えば、アプリに単なる入力ではなく、意図を理解する能力を与えることができます。単なる一致ではなく、意味を浮かび上がらせる。

ツールは準備万端。コードは軽い。価値は本物です。今必要なのは…プロンプトだけです。

Avatar
プロダクトマーケティングマネージャー – Basmaは2019年に4Dに入社し、開発、ドキュメント作成、コンテンツ戦略に携わる中で現在の役割にステップアップしました。彼女は製品、エンジニアリング、マーケティング、サポート、マネジメントチームと密接に連携し、各リリースや機能の「なぜ」「どのように」「何を」を明確にしています。 これまでの幅広い経験を活かして、現在は4Dのブログやウェブサイト向けに、明確なメッセージ設計と深みのある技術記事を作成しています。ソフトウェア工学の修士号を持つ彼女は、技術的な理解と鋭い編集スキルの両方を兼ね備えています。開発、マイグレーション、技術監査、ウェビナー、トレーニングといった分野での経験が、プロダクトマーケティングにおける強みとなり、複雑な内容をわかりやすく伝える力となっています。