はじめに
こんにちは、システム開発部のNです。
先日、Anthropic社からClaude 3が発表されました。Claude 3は、一部のベンチマークテストにおいてOpenAIのGPT-4を上回る性能を発揮したと報告されており、大きな期待が寄せられています。
Claude 3には、Haiku、Sonnet、Opusの3つのバリエーションがあり、いずれのモデルも画像入力に対応しています。
本記事では、Node.jsを使ってClaude 3のAPIを呼び出し、画像入力機能を実際に検証します。サンプルコードも載せているので、参考にしてください。
準備
https://claude.ai こちらからアカウントを登録し、APIキーを発行して下さい。
APIキーはSettingsのAPI Keysから発行できます。

作成後はAPIキーを参照する画面がない為、作成時にAPIキーをコピーし忘れると参照できなくなるので注意してください。
また、SMS認証をすることで5ドル分チャージされるので活用してください。
スクリーンショットを撮り忘れましたが、こんな感じで$5追加されます。

Messages APIについて
今回使う「Messages API」について簡単に説明します。(もう一つのText Completions APIは非推奨になっており、Claude3のモデルが利用できません。)
公式リファレンスはこちら https://docs.anthropic.com/claude/reference/messages_post
現在(2024/3/6)利用できるモデルは下記のOpusとSonnetの二つです。HaikuはComingSoonとのことでした。
- claude-3-opus-20240229
- claude-3-sonnet-20240229
リクエストパラメータのmax_tokensを必須で設定する必要があります。
最大で4096を設定できますが、1024あたりが標準的なようです。
また、1Mトークンあたりのコストは以下になっています。(2024/3/6時点)
| Model | Input | Output |
| Opus | $15.00 | $75.00 |
| Sonnet | $3.00 | $15.00 |
| Haiku | $0.25 | $1.25 |
サンプルコード
サンプルコードは以下になります。
コード上部に変更すべき箇所を集約したので。コメントを参照して下さい。
// 実行前に下記ライブラリをインストール
// $ npm i fs mime-types request
// 実行方法
// $ node claude3demo.js [ここにプロンプト] [画像ファイル名]
// 例
// $ node claude3demo.js これはなんですか? 1pxcabi.png
const IMAGES_PATH = "input_images/"; // TODO: 画像ファイルのパスを置き換える
const ANTHROPIC_KEY = "hoge"; // TODO: APIキーを置き換える
const MODEL = "claude-3-sonnet-20240229"; // TODO: 使えるモデル claude-3-opus-20240229 claude-3-sonnet-20240229
const SYSTEM_PROMPT = "日本語で答えて"; // TODO: 適宜変更する
const request = require("request");
const fs = require("fs").promises;
const mime = require("mime-types");
const excutePrompt = async function (message, imageFileName) {
try {
const endpoint = `https://api.anthropic.com/v1/messages`; // Anthropic社エンドポイント
const content = [
{
type: "text",
text: message,
},
]; // プロンプト
if (imageFileName) {
// 画像がある場合、contentの先頭につける
const imgBase64 = await imageToBase64(imageFileName);
const imageContent = {
type: "image",
source: {
type: "base64",
media_type: imageMimeType(imageFileName),
data: imgBase64,
},
};
content.unshift(imageContent);
}
const data = {
model: MODEL,
max_tokens: 1024,
temperature: 0.7,
system: SYSTEM_PROMPT,
messages: [
{
role: "user",
content: content,
},
],
};
console.log(content);
const parameter = {
url: endpoint,
method: "POST",
headers: {
"content-Type": "application/json",
"anthropic-version": "2023-06-01",
"x-api-key": `${ANTHROPIC_KEY}`,
},
json: data,
};
// API実行
const response = await excuteRequest(parameter);
const input_tokens = response.body.usage.input_tokens;
const output_tokens = response.body.usage.output_tokens;
console.log(`USER: ${message}`);
response.body.content.forEach(async (c) => {
console.log(`ASSISTANT: ${c.text}`);
console.log(`TOKEN: input ${input_tokens} output ${output_tokens}`);
});
} catch (error) {
console.log(error.message);
Promise.reject();
}
};
const excuteRequest = async function (parameter) {
return new Promise(function (resolve, reject) {
try {
const callback = function (error, response) {
try {
if (error || response.statusCode != 200) {
// エラーが返ってきた場合
console.log(`${response.statusCode} 失敗`);
console.log(response.body);
reject();
} else {
// 正常の場合
// console.log(`${response.statusCode} 完了`);
// console.log(response.body);
resolve(response);
}
} catch (error) {
console.log(error);
reject();
}
};
// API実行
request(parameter, callback);
} catch (error) {
console.log(error.message);
reject();
}
});
};
const imageToBase64 = async function (fileName) {
try {
const file = await fs.readFile(`${IMAGES_PATH}${fileName}`);
let base64 = file.toString("base64");
// console.log(base64);
return base64;
} catch (error) {
console.error(error.message);
throw new Error("base64変換失敗");
}
};
const imageMimeType = function (fileName) {
try {
const mimeType = mime.lookup(`${IMAGES_PATH}${fileName}`);
// console.log(mimeType);
return mimeType;
} catch (error) {
console.error(error.message);
throw new Error("mime変換失敗");
}
};
async function main() {
// console.log(`start ${new Date()}`);
try {
const value = process.argv[2];
const imageFileName = process.argv[3];
await excutePrompt(value, imageFileName);
} catch (error) {
console.log(error);
console.log(`${new Date()}`);
}
}
main();
Opus、Sonnet、GPT-4Vのレスポンスを比較してみる
上記コードでOpus、Sonnet。GPT-4VはWebUIからそれぞれどのようなレスポンスになるか検証してみました。
入力と画像は牡蠣です。手元にあった写真を使ってみました。

Prompt: この画像について説明してください
結果
Claude 3 Opus
この画像は、バーベキューをしている様子を写したものです。金属製の網の上には、いくらかの牡蠣が焼かれています。手前には赤い丼に白米とイクラが盛られており、牡蠣とイクラの海鮮バーベキューを楽しんでいるようです。背景には人の腰から下の部分が写っており、屋外でバーベキューをしているのがわかります。全体的に美味しそうな雰囲気が伝わってくる一枚です。
Claude 3 Sonnet
この画像は、牡蠣の直火焼きとイクラ(すじこ)の料理を捉えたものです。手前には赤い器に盛られた白いご飯の上にオレンジ色のイクラがのっています。奥には網の上で牡蠣が焼かれており、一部は既に開いた状態です。周りには調理の際に使われたと思われる箱やアンプなどの器具が置かれています。おそらく屋外での簡易的な調理風景を撮影したものと推測されます。料理の具材や作業環境から、活気のある料理現場の一コマを切り取った印象的な一枚です。
GPT-4
画像には、白いご飯の上にイクラ(鮭の卵)がたっぷりとのせられた丼が手に持たれています。背景には、炭火で焼かれている牡蠣が見えます。これは屋外か、屋外に似た環境で行われている食事の様子を捉えているようです。持っている人の手と、背後に座っている人が一部写っていますが、その人の顔は見えません。牡蠣は開いた状態で、焼き加減を見ながら調理されている様子が伺えます。焼き牡蠣とイクラ丼は、日本料理における海の幸を楽しむ典型的な食べ合わせで、とても美味しそうです。
まとめ(Opusで生成しました)
今回、Anthropic社のClaude 3 APIを利用し、画像入力機能を実際に検証してみました。検証の結果、中位モデルであるSonnetでも、入力された画像の内容を正確に認識し、適切な応答を返すことができることが確認できました。このことから、Claude 3の画像認識能力の高さが実証されたと言えるでしょう。
さらに、今後リリースが予定されているHaikuモデルでも画像入力機能が利用可能となる予定です。Haikuはよりコストが安いモデルであるため、多くのユーザーにとって利用しやすいものになると期待されます。
以上のように、Anthropic社のClaude 3 APIは、高い画像認識能力を持ち、様々なユースケースに適用可能な強力なツールであると言えます。今後のモデルの進化にも注目が集まります。








