AI 機能について考えるとき、"必要なわけではありません" という言葉が役立つガイドです。 たとえば、Azure OpenAI の SQL に対する自然言語機能を使用すると、ユーザーはプレーンな英語でデータベース クエリを作成できます。これは、生産性を向上させる強力なツールになります。 ただし、 強力な 機能は、必ずしも 適切 または 安全という意味ではありません。 この演習では、この AI 機能を使用する方法を示しながら、実装を決定する前に留意すべき重要な考慮事項についても説明します。
データベースからデータを取得するために使用できる自然言語クエリの例を次に示します。
Get the the total revenue for all companies in London.
適切なプロンプトが表示されると、Azure OpenAI はこのクエリを SQL に変換し、データベースから結果を返すために使用できます。 その結果、ビジネス アナリスト、マーケティング担当者、エグゼクティブなどの非技術ユーザーは、複雑な SQL 構文に取り組んだり、制約付きデータグリッドやフィルターに依存したりすることなく、データベースから貴重な情報をより簡単に取得できます。 この合理化されたアプローチにより、ユーザーが技術専門家からの支援を求める必要がなくなり、生産性が向上します。
この演習では、SQL への自然言語のしくみを理解し、いくつかの重要な考慮事項を紹介し、長所と短所について考え、開始するコードを示すのに役立つ開始点を提供します。
この演習では、以下のことを行います。
- GPT プロンプトを使用して、自然言語を SQL に変換します。
- さまざまな GPT プロンプトを試します。
- 生成された SQL を使用して、先ほど開始した PostgreSQL データベースに対してクエリを実行します。
- PostgreSQL からクエリ結果を返し、ブラウザーに表示します。
まず、自然言語を SQL に変換するために使用できるさまざまな GPT プロンプトを試してみましょう。
自然言語から SQL への機能の使用
前の 演習 では、データベース、API、アプリケーションを開始しました。 また、
.envファイルも更新しました。 これらの手順を完了していない場合は、演習の最後の手順に従って続行してください。ブラウザー (http://localhost:4200) に戻り、データ グリッドの下にあるページの [カスタム クエリ ] セクションを見つけます。 サンプル クエリ値が既に含まれていることに注意してください。 すべての注文の合計収益を取得します。会社別にグループ化し、市区町村を含めます。
[ クエリの実行 ] ボタンを選択します。 これにより、ユーザーの自然言語クエリが Azure OpenAI に渡され、SQL に変換されます。 その後、SQL クエリを使用してデータベースのクエリを実行し、潜在的な結果を返します。
次の カスタム クエリを実行します。
Get the total revenue for Adventure Works Cycles. Include the contact information as well.Visual Studio Code で API サーバーを実行しているターミナル ウィンドウを表示すると、Azure OpenAI から返された SQL クエリが表示されます。 JSON データは、サーバー側 API によって PostgreSQL データベースのクエリを実行するために使用されます。 クエリに含まれる文字列値は、SQL インジェクション攻撃を防ぐためにパラメーター値として追加されます。
{ "sql": "SELECT c.company, c.city, c.email, SUM(o.total) AS revenue FROM customers c INNER JOIN orders o ON c.id = o.customer_id WHERE c.company = $1 GROUP BY c.company, c.city, c.email", "paramValues": ["Adventure Works Cycles"] }ブラウザーに戻り、[データの リセット ] を選択して、すべての顧客をデータ グリッドに再び表示します。
自然言語から SQL コードへの探索
ヒント
Visual Studio Code を使用している場合は、次を選択してファイルを直接開くことができます。
- Windows/Linux: Ctrl + P
- Mac: Cmd + P
次に、開くファイルの名前を入力します。
注
この演習の目的は、自然言語を使用して可能な機能を SQL 機能に示し、使用を開始する方法を示することです。 前述のように、実装を続行する前に、この種の AI が組織に適しているかどうかを検討することが重要です。 また、不正アクセスを防ぎ、機密データを保護するために 、適切なプロンプトルールとデータベースセキュリティ対策を計画することも不可欠 です。
これで、自然言語から SQL への機能の動作を確認したので、それがどのように実装されているかを調べてみましょう。
サーバー/apiRoutes.ts ファイルを開き、
generateSqlルートを見つけます。 この API ルートは、ブラウザーで実行されているクライアント側アプリケーションによって呼び出され、自然言語クエリから SQL を生成するために使用されます。 SQL クエリが取得されると、データベースのクエリを実行して結果を返すために使用されます。router.post('/generateSql', async (req, res) => { const userPrompt = req.body.prompt; if (!userPrompt) { return res.status(400).json({ error: 'Missing parameter "prompt".' }); } try { // Call Azure OpenAI to convert the user prompt into a SQL query const sqlCommandObject = await getSQLFromNLP(userPrompt); let result: any[] = []; // Execute the SQL query if (sqlCommandObject && !sqlCommandObject.error) { result = await queryDb(sqlCommandObject) as any[]; } else { result = [ { query_error : sqlCommandObject.error } ]; } res.json(result); } catch (e) { console.error(e); res.status(500).json({ error: 'Error generating or running SQL query.' }); } });generateSqlルートの次の機能に注意してください。-
req.body.promptからユーザー クエリ値を取得し、userPromptという名前の変数に割り当てます。 この値は、GPT プロンプトで使用されます。 - 自然言語を SQL に変換するために、
getSQLFromNLP()関数を呼び出します。 - 生成された SQL を、SQL クエリを実行する
queryDbという名前の関数に渡され、データベースから結果が返されます。
-
エディターで サーバー/openAI.ts ファイルを開き、
getSQLFromNLP()関数を見つけます。 この関数は、generatesqlルートによって呼び出され、自然言語を SQL に変換するために使用されます。async function getSQLFromNLP(userPrompt: string): Promise<QueryData> { // Get the high-level database schema summary to be used in the prompt. // The db.schema file could be generated by a background process or the // schema could be dynamically retrieved. const dbSchema = await fs.promises.readFile('db.schema', 'utf8'); const systemPrompt = ` Assistant is a natural language to SQL bot that returns a JSON object with the SQL query and the parameter values in it. The SQL will query a PostgreSQL database. PostgreSQL tables with their columns: ${dbSchema} Rules: - Convert any strings to a PostgreSQL parameterized query value to avoid SQL injection attacks. - Return a JSON object with the following structure: { "sql": "", "paramValues": [] } Examples: User: "Display all company reviews. Group by company." Assistant: { "sql": "SELECT * FROM reviews", "paramValues": [] } User: "Display all reviews for companies located in cities that start with 'L'." Assistant: { "sql": "SELECT r.* FROM reviews r INNER JOIN customers c ON r.customer_id = c.id WHERE c.city LIKE 'L%'", "paramValues": [] } User: "Display revenue for companies located in London. Include the company name and city." Assistant: { "sql": "SELECT c.company, c.city, SUM(o.total) AS revenue FROM customers c INNER JOIN orders o ON c.id = o.customer_id WHERE c.city = $1 GROUP BY c.company, c.city", "paramValues": ["London"] } User: "Get the total revenue for Adventure Works Cycles. Include the contact information as well." Assistant: { "sql": "SELECT c.company, c.city, c.email, SUM(o.total) AS revenue FROM customers c INNER JOIN orders o ON c.id = o.customer_id WHERE c.company = $1 GROUP BY c.company, c.city, c.email", "paramValues": ["Adventure Works Cycles"] } `; let queryData: QueryData = { sql: '', paramValues: [], error: '' }; let results = ''; try { results = await callOpenAI(systemPrompt, userPrompt); if (results) { console.log('results', results); const parsedResults = JSON.parse(results); queryData = { ...queryData, ...parsedResults }; if (isProhibitedQuery(queryData.sql)) { queryData.sql = ''; queryData.error = 'Prohibited query.'; } } } catch (error) { console.log(error); if (isProhibitedQuery(results)) { queryData.sql = ''; queryData.error = 'Prohibited query.'; } else { queryData.error = results; } } return queryData; }-
userPromptパラメーターが関数に渡されます。userPrompt値は、ブラウザーでユーザーが入力した自然言語クエリです。 -
systemPromptでは、使用する AI アシスタントの種類と、それに従う必要があるルールを定義します。 これにより、Azure OpenAI は、データベース構造、適用する規則、生成された SQL クエリとパラメーターを返す方法を理解するのに役立ちます。 -
callOpenAI()という名前の関数が呼び出され、systemPrompt値とuserPrompt値が渡されます。 - 生成された SQL クエリに禁止値が含まれていないことを確認するために、結果がチェックされます。 禁止された値が見つかった場合、SQL クエリは空の文字列に設定されます。
-
システム プロンプトの詳細を見てみましょう。
const systemPrompt = ` Assistant is a natural language to SQL bot that returns a JSON object with the SQL query and the parameter values in it. The SQL will query a PostgreSQL database. PostgreSQL tables with their columns: ${dbSchema} Rules: - Convert any strings to a PostgreSQL parameterized query value to avoid SQL injection attacks. - Return a JSON object with the following structure: { "sql": "", "paramValues": [] } Examples: User: "Display all company reviews. Group by company." Assistant: { "sql": "SELECT * FROM reviews", "paramValues": [] } User: "Display all reviews for companies located in cities that start with 'L'." Assistant: { "sql": "SELECT r.* FROM reviews r INNER JOIN customers c ON r.customer_id = c.id WHERE c.city LIKE 'L%'", "paramValues": [] } User: "Display revenue for companies located in London. Include the company name and city." Assistant: { "sql": "SELECT c.company, c.city, SUM(o.total) AS revenue FROM customers c INNER JOIN orders o ON c.id = o.customer_id WHERE c.city = $1 GROUP BY c.company, c.city", "paramValues": ["London"] } User: "Get the total revenue for Adventure Works Cycles. Include the contact information as well." Assistant: { "sql": "SELECT c.company, c.city, c.email, SUM(o.total) AS revenue FROM customers c INNER JOIN orders o ON c.id = o.customer_id WHERE c.company = $1 GROUP BY c.company, c.city, c.email", "paramValues": ["Adventure Works Cycles"] } `;使用する AI アシスタントの種類が定義されています。 この場合は、"SQL ボットに対する自然言語" です。
データベース内のテーブル名と列が定義されます。 プロンプトに含まれる大まかなスキーマは 、server/db.schema ファイル内にあり、次のようになります。
- customers (id, company, city, email) - orders (id, customer_id, date, total) - order_items (id, order_id, product_id, quantity, price) - reviews (id, customer_id, review, date, comment)ヒント
ユーザーが自然言語を使用して SQL に対してクエリを実行できるデータのみを含む読み取り専用ビューを作成することを検討できます。
SQL インジェクション攻撃を回避するために、任意の文字列値をパラメーター化されたクエリ値に変換するルールが定義されています。
ルールは、SQL クエリとそのパラメーター値を含む JSON オブジェクトを常に返すように定義されています。
ユーザー プロンプトの例と、想定される SQL クエリとパラメーター値が提供されます。 これは 、"少数のショット" 学習と呼ばれます。 LLM は大量のデータに対してトレーニングされますが、いくつかの例だけで新しいタスクに適応できます。 もう 1 つの方法は、例が提供されておらず、モデルが正しい SQL クエリとパラメーター値を生成することが期待される"ゼロショット" 学習です。
getSQLFromNLP()関数は、callOpenAI()ファイルにある という名前の関数にシステム プロンプトとユーザー プロンプトを送信します。callOpenAI()関数は、Foundry Models または OpenAI サービスの Azure OpenAI を環境変数をチェックして呼び出す必要があるかどうかを決定します。 キー、エンドポイント、およびモデルが環境変数で使用できる場合は、Azure OpenAI が呼び出され、それ以外の場合は OpenAI が呼び出されます。function callOpenAI(systemPrompt: string, userPrompt: string, temperature = 0, useBYOD = false) { const isAzureOpenAI = OPENAI_API_KEY && OPENAI_ENDPOINT && OPENAI_MODEL; if (isAzureOpenAI) { if (useBYOD) { return getAzureOpenAIBYODCompletion(systemPrompt, userPrompt, temperature); } return getAzureOpenAICompletion(systemPrompt, userPrompt, temperature); } return getOpenAICompletion(systemPrompt, userPrompt, temperature); }注
このチュートリアルでは Azure OpenAI に焦点を当てますが、
OPENAI_API_KEYファイルに値のみを指定した場合、アプリケーションでは代わりに OpenAI が使用されます。 Azure OpenAI の代わりに OpenAI を使用することを選択した場合、場合によっては異なる結果が表示されることがあります。getAzureOpenAICompletion()関数を見つけます。async function getAzureOpenAICompletion(systemPrompt: string, userPrompt: string, temperature: number): Promise<string> { const completion = await createAzureOpenAICompletion(systemPrompt, userPrompt, temperature); let content = completion.choices[0]?.message?.content?.trim() ?? ''; console.log('Azure OpenAI Output: \n', content); if (content && content.includes('{') && content.includes('}')) { content = extractJson(content); } return content; }この関数は、次のことを行います。
パラメーター:
-
systemPrompt、userPrompt、およびtemperatureが主なパラメーターです。-
systemPrompt: Azure OpenAI モデルにそのロールと従う規則を通知します。 -
userPrompt: 自然言語入力や出力を生成するためのルールなど、ユーザーが指定した情報が含まれます。 -
temperature: モデルの応答の創造性レベルを決定します。 値が大きいほどクリエイティブな出力が増え、値が小さい (0 など) ほど決定的な回答が得られます。
-
-
完了の生成:
- 関数は、
createAzureOpenAICompletion()、systemPrompt、およびuserPromptを使用してtemperatureを呼び出して完了を生成します。 - 入力候補の最初の選択肢からコンテンツが抽出され、余分な空白がトリミングされます。
- コンテンツに JSON に似た構造 (
{と}の存在によって示される) が含まれている場合は、JSON コンテンツが抽出されます。
- 関数は、
ログと戻り値:
- この関数は、Azure OpenAI 出力をコンソールに記録します。
- 処理されたコンテンツを文字列として返します。
createAzureOpenAICompletion()関数を見つけます。async function createAzureOpenAICompletion(systemPrompt: string, userPrompt: string, temperature: number, dataSources?: any[]): Promise<any> { const baseEnvVars = ['OPENAI_API_KEY', 'OPENAI_ENDPOINT', 'OPENAI_MODEL']; const byodEnvVars = ['AZURE_AI_SEARCH_ENDPOINT', 'AZURE_AI_SEARCH_KEY', 'AZURE_AI_SEARCH_INDEX']; const requiredEnvVars = dataSources ? [...baseEnvVars, ...byodEnvVars] : baseEnvVars; checkRequiredEnvVars(requiredEnvVars); const config = { apiKey: OPENAI_API_KEY, endpoint: OPENAI_ENDPOINT, apiVersion: OPENAI_API_VERSION, deployment: OPENAI_MODEL }; const aoai = new AzureOpenAI(config); const completion = await aoai.chat.completions.create({ model: OPENAI_MODEL, // gpt-4o, gpt-3.5-turbo, etc. Pulled from .env file max_tokens: 1024, temperature, response_format: { type: "json_object", }, messages: [ { role: 'system', content: systemPrompt }, { role: 'user', content: userPrompt } ], // @ts-expect-error data_sources is a custom property used with the "Azure Add Your Data" feature data_sources: dataSources }); return completion; } function checkRequiredEnvVars(requiredEnvVars: string[]) { for (const envVar of requiredEnvVars) { if (!process.env[envVar]) { throw new Error(`Missing ${envVar} in environment variables.`); } } }この関数は、次のことを行います。
パラメーター:
-
systemPrompt、userPrompt、およびtemperatureは、前に説明した主要なパラメーターです。 - 省略可能な
dataSourcesパラメーターでは、このチュートリアルの後半で説明する "Azure Bring Your Own Data" 機能がサポートされます。
-
環境変数チェック:
- この関数は、不可欠な環境変数が存在することを確認し、存在しない場合はエラーをスローします。
構成オブジェクト:
-
configオブジェクトは、.envファイルの値 (OPENAI_API_KEY、OPENAI_ENDPOINT、OPENAI_API_VERSION、OPENAI_MODEL) を使用して作成されます。 これらの値は、Azure OpenAI を呼び出すための URL を構築するために使用されます。
-
AzureOpenAI インスタンス:
-
AzureOpenAIのインスタンスが、configオブジェクトを使用して作成されます。AzureOpenAIシンボルはopenaiパッケージの一部であり、ファイルの先頭にインポートする必要があります。
-
完了の生成:
-
chat.completions.create()関数は、次のプロパティを使用して呼び出されます。-
model:.envファイルで定義されている GPT モデル (gpt-4o、gpt-3.5-turbo など) を指定します。 -
max_tokens: 完了のトークンの最大数を定義します。 -
temperature:サンプリング温度を設定します。 値が大きいほど (0.9 など)、クリエイティブな反応が増え、値が小さい (0 など) ほど決定的な回答が生成されます。 -
response_format: 応答形式を定義します。 ここでは、JSON オブジェクトを返すように設定されています。 JSON モードの詳細については、 Azure OpenAI リファレンス ドキュメントを参照してください。 -
messages: チャットの完了を生成するためのメッセージが含まれます。 この例には、システムからのメッセージ (動作とルールの定義) とユーザーからのメッセージ (プロンプト テキストを含む) の 2 つのメッセージが含まれています。
-
-
戻り値:
- この関数は、Azure OpenAI によって生成された完了オブジェクトを返します。
getSQLFromNLP()関数の次の行をコメント アウトします。// if (isProhibitedQuery(queryData.sql)) { // queryData.sql = ''; // }openAI.ts保存します。 API サーバーは、TypeScript コードを自動的に再構築し、サーバーを再起動します。
ブラウザーに戻り、「 データベースからすべてのテーブル名を選択」 と入力して、 カスタム クエリ 入力に入力します。 [クエリの実行] を選択します。 テーブル名は表示されますか?
getSQLFromNLP()の関数に戻り、システム プロンプトのRules:セクションに次の規則を追加して、ファイルを保存します。- Do not allow the SELECT query to return table names, function names, or procedure names.ブラウザーに戻り、次のタスクを実行します。
- [カスタム クエリ] 入力に「データベースからすべてのテーブル名を選択する」と入力します。 [クエリの実行] を選択します。 テーブル名は表示されますか?
- 「データベースからすべての関数名を選択する」と入力します。カスタム クエリ入力に入力し、[クエリの実行] をもう一度選択します。 関数名は表示されますか?
質問: モデルは、プロンプトで定義したルールに常に従いますか?
回答: いいえ。 OpenAI モデルは、定義したルールと一致しない場合に予期しない結果を返す可能性があることに注意してください。 コードで計画することが重要です。
サーバー/openAI.tsに戻り、
isProhibitedQuery()関数を見つけます。 これは、Azure OpenAI が結果を返した後に実行できる後処理コードの例です。 生成された SQL クエリで禁止キーワードが返された場合、sqlプロパティは空の文字列に設定されます。 これにより、Azure OpenAI から予期しない結果が返された場合、SQL クエリはデータベースに対して実行されなくなります。function isProhibitedQuery(query: string): boolean { if (!query) return false; const prohibitedKeywords = [ 'insert', 'update', 'delete', 'drop', 'truncate', 'alter', 'create', 'replace', 'information_schema', 'pg_catalog', 'pg_tables', 'pg_proc', 'pg_namespace', 'pg_class', 'table_schema', 'table_name', 'column_name', 'column_default', 'is_nullable', 'data_type', 'udt_name', 'character_maximum_length', 'numeric_precision', 'numeric_scale', 'datetime_precision', 'interval_type', 'collation_name', 'grant', 'revoke', 'rollback', 'commit', 'savepoint', 'vacuum', 'analyze' ]; const queryLower = query.toLowerCase(); return prohibitedKeywords.some(keyword => queryLower.includes(keyword)); }注
これはデモ コードに過ぎないことに注意してください。 自然言語を SQL に変換する場合は、特定のユース ケースに対応するために他の禁止キーワードが必要になる場合があります。 これは、有効な SQL クエリのみが返され、データベースに対して実行されるように注意して計画し、使用する必要がある機能です。 禁止されたキーワードに加えて、セキュリティも考慮する必要があります。
サーバー/openAI.tsに戻り、
getSQLFromNLP()関数で次のコードのコメントを解除します。 ファイルを保存します。if (isProhibitedQuery(queryData.sql)) { queryData.sql = ''; }systemPromptから次の規則を削除し、ファイルを保存します。- Do not allow the SELECT query to return table names, function names, or procedure names.ブラウザーに戻り、「 データベースからすべてのテーブル名を選択 する」と入力して、もう一度 カスタム クエリ 入力を選択し、[ クエリの実行 ] ボタンを選択します。
テーブルの結果は表示されますか? 規則が設定されていない場合でも、
isProhibitedQuery後処理コードでは、その種類のクエリがデータベースに対して実行されることを禁止します。前に説明したように、基幹業務アプリケーションで自然言語を SQL に統合することは、ユーザーにとって非常に有益ですが、独自の一連の考慮事項が付属しています。
長所:
使いやすさ: この機能により、技術的な専門知識がなくてもデータベースの操作にユーザーがアクセスしやすくなり、SQL の知識の必要性が減り、操作が高速化される可能性があります。
生産性の向上: ビジネス アナリスト、マーケティング担当者、エグゼクティブ、その他の非技術ユーザーは、技術専門家に頼ることなくデータベースから貴重な情報を取得できるため、効率が向上します。
広範なアプリケーション: 高度な言語モデルを使用することで、アプリケーションは幅広いユーザーやユース ケースに対応するように設計できます。
考慮事項:
セキュリティ: 最大の懸念事項の 1 つはセキュリティです。 ユーザーが自然言語を使用してデータベースを操作できる場合は、承認されていないアクセスや悪意のあるクエリを防ぐために、堅牢なセキュリティ対策が必要です。 ユーザーがデータを変更できないように、読み取り専用モードを実装することを検討できます。
データのプライバシー: 特定のデータは機密性が高く、簡単にアクセスできないようにする必要があるため、適切な保護とユーザーのアクセス許可を確保する必要があります。
精度:自然言語処理は大幅に改善されていますが、完璧ではありません。 ユーザー クエリを誤って解釈すると、不正確な結果や予期しない動作が発生する可能性があります。 予期しない結果がどのように処理されるかを計画する必要があります。
効率性: 自然言語クエリから返される SQL が効率的であるという保証はありません。 場合によっては、後処理ルールで SQL クエリの問題が検出された場合に、Azure OpenAI への追加の呼び出しが必要になる場合があります。
トレーニングとユーザー適応: クエリを正しく作成するには、ユーザーをトレーニングする必要があります。 SQL を学習するよりも簡単ですが、学習曲線が必要な場合もあります。
次の演習に進む前に、いくつかの最後の点を考慮する必要があります。
- ここで適用されるのは、"必要とは言えないからといって" という点に注意してください。 自然言語を SQL にアプリケーションに統合する前に、細心の注意と慎重な計画を使用してください。 潜在的なリスクを理解し、それらを計画することが重要です。
- この種のテクノロジを使用する前に、チーム、データベース管理者、セキュリティ チーム、利害関係者、およびその他の関係者と潜在的なシナリオについて話し合い、組織に適していることを確認します。 SQL に対する自然言語が、セキュリティ、プライバシー、および組織が持つその他の要件を満たしているかどうかを検討することが重要です。
- セキュリティは主な懸念事項であり、計画、開発、デプロイのプロセスに組み込まれている必要があります。
- SQL に対する自然言語は非常に強力ですが、プロンプトに必要なルールがあり、後処理機能が含まれていることを確認するために、慎重な計画を立てなければなりません。 この種の機能を実装してテストし、予期しない結果が返されるシナリオを考慮して、追加の時間を計画します。
- Azure OpenAI を使用すると、顧客は OpenAI と同じモデルを実行しながら、Microsoft Azure のセキュリティ機能を使用できます。 Azure OpenAI では、プライベート ネットワーク、リージョンの可用性、責任ある AI コンテンツのフィルター処理が提供されます。 Azure OpenAI のデータ、プライバシー、セキュリティの詳細について説明します。
これで、Azure OpenAI を使用して自然言語を SQL に変換する方法を確認し、この種の機能を実装することの長所と短所について学習しました。 次の演習では、Azure OpenAI を使用して電子メールメッセージと SMS メッセージを生成する方法について説明します。