
Overview
Amazon Bedrock: Mistral AI: チャット
この工程は、Amazon Bedrock 上で動作する Mistral AI のモデルにメッセージを送信し、回答をデータ項目に保存します。
Configs for this Auto Step
- conf_AccessKey
- C1: アクセスキー *
- conf_SecretKey
- C2: シークレットアクセスキー *
- conf_Region
- C3: リージョンコード *
- conf_Model
- C4: モデル *
- conf_MaxTokens
- C5: 回答の生成に使用するトークン数の上限
- conf_Temperature
- C6: 温度(0.0 〜 1.0)
- conf_SystemPrompt
- C7: システムプロンプト#{EL}
- conf_Message1
- U1: ユーザメッセージ *#{EL}
- conf_Images1
- I1: ユーザメッセージに添付する画像
- conf_Answer1
- A1: 回答を保存するデータ項目 *
Script (click to open)
const SERVICE = 'bedrock';
const main = () => {
////// == 工程コンフィグ・ワークフローデータの参照 / Config & Data Retrieving ==
const awsKey = configs.getObject('conf_AccessKey').getToken();
const awsSecret = configs.getObject('conf_SecretKey').getToken();
const region = retrieveRegion();
const model = retrieveModel();
const maxTokens = retrieveMaxTokens();
const temperature = retrieveTemperature();
const systemPrompt = configs.get('conf_SystemPrompt');
const userMessage = retrieveUserMessage(); // 添付画像の取得も含む
////// == 演算 / Calculating ==
const answer = converse(
awsKey,
awsSecret,
region,
model,
maxTokens,
temperature,
systemPrompt,
userMessage
);
////// == ワークフローデータへの代入 / Data Updating ==
saveData('conf_Answer1', answer);
}
/**
* config からリージョンコードを読み出す
* リージョンコードの形式として不正な場合はエラー
* @return {String}
*/
const retrieveRegion = () => {
const region = configs.get('conf_Region');
// 今後リージョンが増えることも考えて、中央の最大文字数には余裕をみている
const reg = new RegExp('^[a-z]{2}-[a-z]{4,16}-[1-9]$');
if (!reg.test(region)) {
throw new Error('Region Code is invalid.');
}
return region;
}
/**
* config からモデル ID を読み出す
* モデル ID として不正な場合はエラー
* @return {String}
*/
const retrieveModel = () => {
const model = configs.get('conf_Model');
const reg = new RegExp('^[a-z0-9.:-]+$');
if (!reg.test(model)) {
throw new Error('Model is invalid. It contains an invalid character.');
}
const MODEL_PREFIX = 'mistral.';
if (!model.startsWith(MODEL_PREFIX)){
throw new Error(`Model is invalid. It must start with "${MODEL_PREFIX}".`);
}
return model;
}
/**
* config から最大トークン数を読み出す
* 正の整数でない場合、エラー
* 未定義の場合、null を返す
* @returns {Number}
*/
const retrieveMaxTokens = () => {
const maxTokens = configs.get('conf_MaxTokens');
if (maxTokens === '') {
return null;
}
const regExp = new RegExp(/^[1-9][0-9]*$/);
if (!regExp.test(maxTokens)) {
throw new Error('Maximum number of tokens for generating output must be a positive integer.');
}
return parseInt(maxTokens, 10);
};
/**
* config から温度を読み出す
* 未定義の場合、null を返す
* @returns {Number}
*/
const retrieveTemperature = () => {
const temperature = configs.get('conf_Temperature');
if (temperature === '') {
return null;
}
const regExp = /^(0(\.\d+)?|1(\.0+)?)$/;
if (!regExp.test(temperature)) {
throw new Error('Temperature must be a number from 0 to 1.');
}
return parseFloat(temperature);
};
// https://docs.mistral.ai/studio-api/conversations/vision#faq
const MAX_IMAGE_NUM = 8; // Mistral AI の制限。1 リクエストにつき添付画像 8 個まで
const MAX_IMAGE_SIZE = 10000000; // Mistral AI の制限。1 ファイルにつき 10 Mb まで
const ALLOWED_MEDIA_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
/**
* config からユーザメッセージ(添付画像を含む)を読み出す
* ユーザメッセージが空の場合、添付画像が不正な場合はエラー
* @returns {Object} ユーザメッセージオブジェクト
*/
const retrieveUserMessage = () => {
const message = configs.get('conf_Message1');
if (message === '') {
throw new Error('User Message is empty.');
}
const imageFiles = retrieveImageFiles();
validateFiles(imageFiles, 'image', MAX_IMAGE_NUM, MAX_IMAGE_SIZE);
const inlineImages = imageFiles.map(file => ({
image: fileToObj(file)
}));
const userMessage = {
role: 'user',
content: [
{
text: message
},
...inlineImages
]
};
return userMessage;
};
/**
* config から画像ファイルを読み出す
* 以下の場合はエラー
* - Content-Type が許可されていない場合
* @returns {Array<Qfile>} ファイルオブジェクトの配列
*/
const retrieveImageFiles = () => {
const imageFiles = [];
const filesDef = configs.getObject('conf_Images1');
if (filesDef === null) {
return imageFiles;
}
const files = engine.findData(filesDef);
if (files === null) {
return imageFiles;
}
files.forEach(file => {
const contentType = file.getContentType().split(';')[0];
if (ALLOWED_MEDIA_TYPES.includes(contentType)){
imageFiles.push(file);
} else {
throw new Error(`Content-Type of the attached file "${file.getName()}" is not allowed.`);
}
});
return imageFiles;
};
/**
* ファイルの総数、サイズをチェックする
* 以下の場合はエラー
* - 添付ファイルの総数が多すぎる場合
* - ファイルサイズが大きすぎる場合
* @param {Array<Qfile>} ファイルオブジェクトの配列
* @param errorLabel
* @param maxNum
* @param maxSize
*/
const validateFiles = (files, errorLabel, maxNum, maxSize) => {
if (files.length > maxNum) {
throw new Error(`Too many ${errorLabel}s attached. The maximum number is ${maxNum}.`);
}
files.forEach(file => {
if (file.getLength() > maxSize) {
throw new Error(`Attached ${errorLabel} file "${file.getName()}" is too large. The maximum size is ${maxSize} bytes.`);
}
});
}
/**
* ファイルから inline コンテンツに必要な source, format を読み出し、ファイルオブジェクトを返す
* @param {Qfile} file ファイルオブジェクト
*/
const fileToObj = file => ({
format : file.getContentType().split(';')[0].split('/')[1],
source: {
bytes: base64.encodeToString(fileRepository.readFile(file))
}
});
/**
* モデルの実行
* @param awsKey
* @param awsSecret
* @param region
* @param model
* @param maxTokens
* @param temperature
* @param systemPrompt
* @param userMessage
* @returns {String} answer
*/
const converse = (
awsKey,
awsSecret,
region,
model,
maxTokens,
temperature,
systemPrompt,
userMessage
) => {
const URL = `https://bedrock-runtime.${region}.amazonaws.com/model/${model}/converse`;
const inferenceConfig = {};
if (maxTokens !== null) {
inferenceConfig.maxTokens = maxTokens;
}
if (temperature !== null) {
inferenceConfig.temperature = temperature;
}
const payload = {
inferenceConfig,
messages: [userMessage]
};
if (systemPrompt !== '') {
Object.assign(payload, {
system: [
{text :`${systemPrompt}`}
]
});
}
const response = httpClient.begin()
.awsSignV4(awsKey, awsSecret, region, SERVICE)
.body(JSON.stringify(payload), 'application/json')
.post(URL);
const status = response.getStatusCode();
const respTxt = response.getResponseAsString();
if (status !== 200) {
engine.log(respTxt);
throw new Error(`Failed to converse. status: ${status}`);
}
const {output, stopReason, usage} = JSON.parse(respTxt);
// 推論の要約 reasoningContent を返すモデルは今のところなし
engine.log(`Stop Reason: ${stopReason}`);
engine.log(`Input Tokens: ${usage.inputTokens}`);
engine.log(`Output Tokens: ${usage.outputTokens}`);
// text プロパティを持つ content をすべて連結して回答とする
const answer1 = output.message.content
.filter(content => content.text !== undefined)
.map(content => content.text)
.join('');
if (answer1 === null || answer1.trim() === '') {
throw new Error(`No response content generated. Stop Reason: ${stopReason}`);
}
return answer1;
};
/**
* データ項目への保存
* @param configName
* @param data
*/
const saveData = (configName, data) => {
const def = configs.getObject(configName);
if (def === null) {
return;
}
engine.setData(def, data);
};
Download
- aws-bedrock-mistral-ai-chat.xml
- 2026-11-02 (C) Questetra, Inc. (MIT License)
自由改変可能な JavaScript (ECMAScript) コードです。いかなる保証もありません。
(アドオン自動工程のインストールは Professional editionでのみ可能です)
(アドオン自動工程のインストールは Professional editionでのみ可能です)
Notes
- アクセスキー、シークレットアクセスキーの作成方法については、Amazon Web Services のドキュメントを参照してください
- モデルによっては、日本語の応答が不自然になる場合があります



