iT邦幫忙

2025 iThome 鐵人賽

DAY 4
0
生成式 AI

用 Node.js 打造生成式 AI 應用:從 Prompt 到 Agent 開發實戰系列 第 4

Day 04 - 提示工程與角色設計:打造回應清楚的 AI 助理

  • 分享至 

  • xImage
  •  

在前一篇文章中,我們已經學會如何透過 OpenAI API 建立一個基本的 CLI 聊天機器人,並進一步支援串流輸出與多輪對話。不過,實際使用時你可能會發現,AI 的回應有時過於簡短,有時又顯得冗長,甚至語氣或表達方式不符合期待。

這正是 提示工程(Prompt Engineering) 發揮作用的地方。我們可以透過精心設計的提示,讓 AI 扮演特定角色,同時控制回應的內容與風格,打造出更符合需求的智慧助理。

什麼是提示工程?

提示工程 指的是透過精心設計的輸入文字,來引導語言模型產生符合需求的回應。這些提示可能包含任務說明、語氣要求、角色設定、輸出格式限制,甚至是範例資料。其核心目的,就是讓模型能夠按照我們指定的方式思考並表達。

雖然 GPT 模型本身非常強大,能回答問題、生成文章、甚至轉換格式,但它並不會自動理解我們的偏好或期待。這時候,你就必須在提示中清楚告訴它:

  • 你希望它扮演什麼角色(例如客服專員、教學助理、行銷企劃)。
  • 回答應採用的語氣與用詞(親切、專業、簡單白話、條列式)。
  • 輸出的內容格式(純文字、JSON、Markdown 等)。
  • 任務的完成方式或回答的結構。

舉個例子,如果我們只是單純問:

什麼是 API?

模型大多會給出一個通用的、較為中規中矩的解釋。但若你改寫成:

你是一位資深工程師,請用條列方式解釋 API 是什麼,並舉出實務應用的例子。

模型的回應就會更貼近工程師的角度,並依照條列格式,提供結構化且實用的答案。

換句話說,提示工程的本質就是「給模型下明確的指令」。當我們的 Prompt 設計得清楚,回應就能準確、專業、符合預期;反之,若提示模糊不明,AI 可能會偏題、冗長,甚至出現格式錯亂。

因此,學會設計 Prompt,不僅是我們開發任何 AI 應用的基礎功,也是讓模型真正成為你得力助手的關鍵技術。

提示的基本結構:組合角色、任務與上下文

在 OpenAI 的 Chat Completions API 中,一次對話請求是由一個 messages 陣列組成。這個陣列會按照時間順序依序列出所有訊息,而每則訊息都需要標註一個 role,用來表明「說話者是誰」以及「這段話的用途」。

透過角色的區分,模型才能理解對話脈絡,並依據上下文生成最合適的回應。一般來說,最常見的角色包括:

  • system系統提示。用來定義模型的行為,例如應該扮演什麼角色、採取什麼語氣、遵循哪些規則。這是整段對話的基礎,對模型的回應風格影響很大。
  • user使用者輸入。也就是我們真正要問的問題、下達的指令或任務描述。
  • assistant模型的回應。我們也可以在這裡提供「範例回答」,幫助模型學習特定語氣或邏輯,讓後續回應更一致。

以下是一個簡單範例,模擬我們希望模型用白話方式解釋 Node.js 的 Event Loop:

const messages = [
  { role: 'system', content: '你是一位幽默但專業的軟體工程師,擅長用生活化比喻解釋技術觀念。' },
  { role: 'user', content: 'Node.js 的 Event Loop 是什麼?' }
];

在這個例子中,我們先透過 system 設定模型的角色與語氣,再讓 user 提出問題。這樣的設計會讓模型以「軟體工程師」的身份回答,並遵循我們要求的幽默、生活化風格。當我們繼續輸入其他問題時,它也能根據上下文延續相同的角色設定。

這種多段訊息組合,就是提示工程的核心基礎。我們可以依需求自由調整 system 提示、加入上下文、補充範例問答,進一步打造出更貼近應用場景的 AI 助理。

常見的提示設計技巧

設計 Prompt 的核心目標,是讓模型能更精準理解我們的需求,並生成格式清晰、語氣一致且內容正確的回應。以下介紹幾種常用且實用的設計技巧,它們可以單獨應用,也能彼此搭配,依照實際情境靈活組合。

設定角色與語氣

在提示設計裡,最常見也有效的方法,就是利用 system 訊息替模型設定「角色」和「語氣」。透過這個方式,我們能明確告訴模型它是誰、要面對誰,以及該用什麼程度的專業度來回答,讓整段對話的風格自然一致。

以下是一個例子:

{ role: 'system', content: '你是一位資深前端工程師,擅長用簡潔明瞭的方式解釋 JavaScript 概念。' }

有了這段設定,模型會以「前端工程師」的身份回應,並傾向用結構化、邏輯清楚的方式解釋問題。

明確描述任務與格式

除了角色設定之外,在 user 的提示中也應該明確說明任務與輸出格式。

例如:

{ role: 'user', content: '請用條列方式說明 async/await 的優點,並搭配簡單的範例程式碼。' }

這樣能有效提升回應的結構性,避免模型生成過於冗長或鬆散的答案。

加入範例問答

若希望模型模仿特定語氣或回答風格,可以提供一到兩組範例問答,這種方式稱為 Few-shot Prompting

範例如下:

{ role: 'user', content: '什麼是 API?' },
{ role: 'assistant', content: 'Q: 什麼是 API?\nA: API 是應用程式之間溝通的標準介面。' },
{ role: 'user', content: '什麼是 HTTP?' }

透過範例,模型在回答最後一個問題時,就會自動模仿相同的格式與語氣。這種技巧特別適合需要保持輸出一致性的應用,例如問答系統、客服助理、學習平台等。

給出輸出格式範本

當你需要特定格式(例如 JSON、Markdown、CSV)時,可以直接在提示中提供樣板,模型通常會自動依照範本輸出。

以下是要求模型回傳 JSON 格式摘要的範例:

{ role: 'user', content: '請用以下格式回應:\n{\n  "topic": "",\n  "explanation": "",\n  "example": ""\n}' }

這種方式特別適合應用程式開發情境,因為輸出結構穩定、容易解析,有助於系統自動化處理模型的回傳資料。

以上這些技巧,就是提示工程的基礎工具。透過角色設定、格式約束、範例引導,我們可以讓 AI 助理的回應更準確,風格更一致,也更容易整合進各種應用場景。

實作:讓 CLI Chatbot 擁有角色意識

理解了提示工程的基本概念後,現在我們要將這些知識應用到 CLI 聊天機器人中。

這次的實作會在你昨天完成的 CLI Chatbot 基礎上,加入角色設定,讓使用者在啟動程式時就能決定 AI 助理要採取什麼樣的語氣與風格。

建立角色提示模板

首先,我們需要為不同的角色設計提示語(prompt),並封裝成可重複使用的模板。

請在 src/ 資料夾中新增一個名為 prompts.ts 的檔案,內容如下:

// src/prompts.ts
import type { ChatCompletionMessageParam } from 'openai/resources';

export const roles: Record<string, ChatCompletionMessageParam[]> = {
  default: [
    { role: 'system', content: '你是一個樂於助人的 AI 助理。' }
  ],
  software: [
    { role: 'system', content: '你是一位專業的軟體工程講師,擅長用條列方式解釋技術術語,語氣清楚、簡潔且具邏輯性。' },
    { role: 'user', content: '什麼是 API?' },
    { role: 'assistant', content: 'Q: 什麼是 API?\nA: API(應用程式介面)是讓不同系統交換資料的標準方式。' },
    { role: 'user', content: '什麼是 HTTP?' },
    { role: 'assistant', content: 'Q: 什麼是 HTTP?\nA: HTTP 是一種用於網頁資料傳輸的通訊協定,支援請求與回應的交換流程。' },
  ],
};

在這裡我們定義了兩種助理角色:

  • default:中性通用型助理,風格友善但不偏特定任務。
  • software:技術導向助理,具備固定問答格式、偏好條列說明的軟體工程講師。

修改主程式支援角色參數

接下來要讓 CLI 程式能透過參數指定角色。我們會使用 yargs 來處理命令列參數。

先安裝依賴:

npm install yargs
npm install --save-dev @types/yargs

然後修改 src/index.ts

// src/index.ts
import 'dotenv/config';
import readline from 'readline';
import yargs, { Arguments } from 'yargs';
import { hideBin } from 'yargs/helpers';
import { OpenAI } from 'openai';
import { roles } from './prompts';

interface Argv {
  role: keyof typeof roles;
}

const argv = yargs(hideBin(process.argv))
  .option('role', {
    alias: 'r',
    type: 'string',
    choices: Object.keys(roles) as (keyof typeof roles)[],
    default: 'default',
    description: '指定助理角色',
  })
  .help()
  .parseSync();

async function main(argv: Arguments<Argv>) {
  const openai = new OpenAI();
  const messages = [...roles[argv.role]];

  const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
  });

  console.log('GPT Chatbot 已啟動,輸入訊息開始對話(按 Ctrl+C 離開)。\n');
  rl.setPrompt('> ');
  rl.prompt();

  rl.on('line', async (input) => {
    messages.push({ role: 'user', content: input });

    try {
      const stream = await openai.chat.completions.create({
        model: 'gpt-4o-mini',
        messages,
        stream: true,
      });

      let reply = '';

      process.stdout.write('\n');
      for await (const chunk of stream) {
        const content = chunk.choices[0]?.delta?.content || '';
        process.stdout.write(content);
        reply += content;
      }
      process.stdout.write('\n\n');

      messages.push({ role: 'assistant', content: reply });
    } catch (err) {
      console.error(err);
    }

    rl.prompt();
  });
}

main(argv);

這段程式碼的重點調整如下:

  • 使用者現在可以透過 --role 或簡寫的 -r 參數來指定要使用的助理角色。
  • 程式會根據選擇的角色,從 prompts.ts 中定義的 roles 物件中載入對應的提示訊息,作為對話的起始內容。
  • 使用者的每一次輸入與模型的回應,依然會被依序加入 messages 陣列中,持續維持對話上下文,實現多輪互動的效果。

執行與測試角色風格

現在,你可以在執行時切換不同角色。

預設模式:

npm run dev

軟體工程師模式:

npm run dev -- --role software

輸入問題測試:

> 什麼是 RESTful?

可能輸出:

Q: 什麼是 RESTful?
A: RESTful 是一種基於 REST(Representational State Transfer)的架構風格,用於設計網路應用程式的 API,具有以下特點:

1. **無狀態性**:每個請求都包含所有必要的信息,伺服器不會存儲客戶端的狀態。
2. **資源導向**:主要透過 URL 定義資源,每個資源都有其唯一的標識符。
3. **統一介面**:使用標準的 HTTP 方法(如 GET、POST、PUT、DELETE)操作資源。
4. **可擴展性**:設計上易於擴展,支援多種資料格式(如 JSON、XML)。
5. **緩存能力**:可以對響應進行緩存,提升性能。

可以看到,software 角色的回答更有結構、風格一致,這就是透過 Prompt 模板設計出的效果。

你可以持續在 src/prompts.ts 中擴充角色設定,只要透過 --role 參數切換,就能快速測試不同風格的 AI 助理。

小結

今天我們認識了 提示工程(Prompt Engineering) 技巧,並將其應用在 CLI 聊天機器人中,讓 AI 回應更符合需求與場景:

  • 提示工程的核心,就是透過精心設計的 Prompt,引導模型產生符合期待的回應。
  • Prompt 可以包含角色設定、語氣要求、輸出格式與範例問答,讓回應更有結構與一致性。
  • 在 Chat Completions API 中,訊息透過 systemuserassistant 三種角色組成,能夠清楚定義模型的行為與對話上下文。
  • 常見技巧包括:設定角色與語氣、明確描述任務與格式、提供範例問答(Few-shot Prompting)、指定輸出樣板。

提示工程是開發生成式 AI 應用的基本功,學會善用角色與格式設計,才能讓模型的回應真正貼近需求並具備一致性。


上一篇
Day 03 - OpenAI API 快速上手:實作 CLI 聊天機器人
下一篇
Day 05 - 回應風格調控:掌握 Temperature 與 Top-P 設定
系列文
用 Node.js 打造生成式 AI 應用:從 Prompt 到 Agent 開發實戰5
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言