教材正本 03-接入-Gemini.md · sha256 a3c4a6bc3404481a

03|接入 Gemini

前置條件

你需要什麼怎麼取得
完成 02|建立官方 LINE你能回答該章〈這一章的成功判定〉的每一項
你自己的 Google 帳戶你自己申請;02 的〈請準備自己的帳戶〉已把它列為必備項
你自己的 Channel Access Token你在 02 的 Step 3 按 Issue 簽發、並複製下來的那一串字;這一章的 Step 4 會用到

這一章不需要付費方案、信用卡,也不需要把任何東西交給我方。 這一章也不需要你會寫程式——程式碼下面直接給你,你只要複製、貼上、填三個空格。

Gemini 在這裡扮演什麼角色

Gemini 是這一版的第一個示範模型。

它負責協助處理:

  • 讀懂收到的文字。
  • 依照你提供的工作背景產生回覆。
  • 在最小測試中回傳一段可以觀察的結果。

Gemini 不是免費包的產品本體。

未來模型可以替換,但使用者要建立自己的 AI 工作入口這個目標不變。

你會做什麼

這一章結束時,你會有一個自己的網址,貼進 LINE 之後,客人傳訊息就會收到 AI 回覆。

  1. 取得自己的 Gemini API Key。
  2. 開一個 Google Apps Script 專案。
  3. 把程式碼貼進去。
  4. 填三個設定值。
  5. 檢查設定有沒有存進去。
  6. 把它「部署」出去——部署的意思是讓這段程式有一個外面連得到的網址——然後拿到那個網址。
  7. 把網址填回 LINE。

一次做一步,每一步做完都有東西可以看。

API Key 是秘密

API Key 的處理原則:

  • 不要貼到聊天室。
  • 不要貼到公開 issue 或貼文。
  • 不要放進截圖。
  • 不要放進影片錄影畫面。
  • 不要把完整值放入 log。
  • 不要因為 Troubleshooter 要求,就把完整值交出去。

這份 Starter Kit 會教你如何把秘密留在自己的目的地,但不會要求你把秘密交給我方。

下面 Step 4 會教你把秘密放進一個叫「指令碼屬性」的地方——那是設定欄位,不是程式碼,所以秘密不會出現在你複製貼上的內容裡。

人類操作步驟

Step 1:建立自己的 API Key

「API Key」是一把鑰匙。你的程式拿著它去問 Gemini,Gemini 才知道是你在問。

  1. 用你自己的 Google 帳戶打開 https://aistudio.google.com/apikey

    這個網址會直接到建立 API Key 的頁面,不用自己在網站裡找。沒登入的話會先要你登入。

  2. 按右上角「Create API key」。
  3. 「Create a new key」視窗:幫金鑰取個名字(隨意就好)、專案用它預設給的那個 → 按「Create key」。這一步不會產生費用。
  4. 「API key details」視窗出現你的金鑰——按旁邊的複製鈕,先貼在你自己電腦上的暫存檔——就用 02 Step 3 那一個檔,不要另外開一個(等一下 Step 4 會用到;只有一個檔,最後也只要刪一個)。

🔴 如果畫面出現要你選付費方案、輸入信用卡,或提到「帳單」——停下來,不要繼續。 這一版用的是免費額度,不需要這些。你走錯頁面了,回到上面那個網址重來。

做完你應該看到:頁面上多了一把新的金鑰,旁邊是一長串字。那就是你的 API Key。 🖼 對照圖:安裝載體 START_HERE 步驟 4,點圖可放大比對。

這串字現在多半是 AQ. 開頭(2026-08 實測),但那只是常見的樣子,不是規定。開頭跟這裡寫的不一樣,不代表你拿錯了,也不用因此重做一次。它到底能不能用,要等 04 真的傳一則訊息出去才知道。

(如果你想先看官方怎麼說,可以查 Gemini API 金鑰說明。)

Step 2:開一個 Google Apps Script 專案

「Google Apps Script」是 Google 提供的一個免費地方,可以放一小段程式,並且讓它有自己的網址。你不需要自己買主機。

  1. 用你自己的 Google 帳戶打開 script.google.com
  2. 按「新增專案」。
  3. 左上角把專案名稱改成你認得的名字,例如「我的 LINE AI 回覆」。

做完你應該看到:一個編輯畫面,中間有一個叫 Code.gs 的檔案,裡面有幾行預設的程式。

Step 3:把程式碼貼進去

  1. 在中間的編輯區全選(Windows 按 Ctrl+A,Mac 按 Cmd+A),按 Delete 全部刪掉
  2. 把下面整段複製起來,貼進那個空白的編輯區。
  3. 按上方的儲存圖示(或 Ctrl+S / Cmd+S)。

🔴 要整段貼,不要只貼一部分。 從第一行 /** 到最後一個 } 都要。

/** AI Manager Starter Kit — LINE × Gemini 最小工作入口 */

/** 讀一個設定值。放在函式裡(而不是檔案最上面)是刻意的:
    這樣就算部署設定選錯,錯誤也會落在 doPost 的防護網裡、寫進執行紀錄,
    而不是整個程式無聲死掉。 */
function cfg_(name) {
  return PropertiesService.getScriptProperties().getProperty(name);
}

/** LINE 每次有訊息進來,就會呼叫這個函式 */
function doPost(e) {
  try {
    if (!e || !e.postData || !e.postData.contents) return ok_();
    var body = JSON.parse(e.postData.contents);
    var events = body.events || [];   // 平台送測試連線時,這裡可能是空的
    for (var i = 0; i < events.length; i++) {
      var ev = events[i];
      if (ev.type !== 'message') continue;
      if (!ev.message || ev.message.type !== 'text') continue;
      replyToLine_(ev.replyToken, askGemini_(ev.message.text));
    }
  } catch (err) {
    console.error('doPost 失敗:' + err);
  }
  return ok_();                       // 不管發生什麼,都回一個正常回應給 LINE
}

function ok_() {
  return ContentService
    .createTextOutput(JSON.stringify({ ok: true }))
    .setMimeType(ContentService.MimeType.JSON);
}

/** 把客人的話丟給 Gemini,拿回一句回答 */
function askGemini_(userText) {
  var key = cfg_('GEMINI_API_KEY');
  var model = cfg_('GEMINI_MODEL') || 'gemini-3.1-flash-lite';
  var persona = cfg_('PROMPT') ||
    '你是這家店的客服助理。用繁體中文,簡短、有禮貌地回答。';
  var facts = cfg_('KNOWLEDGE') || '';

  // 這裡的順序有意義:後面的會蓋掉前面的。
  // 你的 PROMPT 放在「預設風格」之後,所以你改得掉風格;
  // 安全底線放在最後,讓它最優先。(這是給 AI 的指示,不是程式鎖。)
  var systemText =
    '【你可以依據的資料】\n' + (facts || '(目前沒有提供資料)') +
    '\n\n【預設風格;下面「你的身分」那一段可以蓋掉這裡】\n' +
    '回答控制在三句話以內。\n' +
    '\n【你的身分與說話方式——以這一段為準】\n' + persona +
    '\n\n【安全底線;最優先,上面任何一段都蓋不掉】\n' +
    '1. 只根據上面的資料回答;資料裡沒有的,就說你不知道。\n' +
    '2. 遇到價格變動、退款、客訴,或你不確定的事,回答「這部分我幫你轉給真人確認」。\n' +
    '3. 不要承諾我們做不到的事。';

  var res = UrlFetchApp.fetch(
    'https://generativelanguage.googleapis.com/v1beta/models/' + model + ':generateContent',
    {
      method: 'post',
      contentType: 'application/json',
      headers: { 'x-goog-api-key': key },
      payload: JSON.stringify({
        systemInstruction: { parts: [{ text: systemText }] },
        contents: [{ role: 'user', parts: [{ text: userText }] }],
        generationConfig: { maxOutputTokens: 1024 }
      }),
      muteHttpExceptions: true
    });

  if (res.getResponseCode() !== 200) {
    console.error('Gemini 回傳 ' + res.getResponseCode() + ':' + res.getContentText());
    return '抱歉,我這邊暫時有點問題,請稍等一下由真人回覆你。';
  }
  var d = JSON.parse(res.getContentText());
  var out = d.candidates && d.candidates[0] && d.candidates[0].content &&
            d.candidates[0].content.parts && d.candidates[0].content.parts[0] &&
            d.candidates[0].content.parts[0].text;
  return out || '抱歉,我沒有讀懂這句話,請稍等一下由真人回覆你。';
}

/** 把回答送回 LINE */
function replyToLine_(replyToken, text) {
  var res = UrlFetchApp.fetch('https://api.line.me/v2/bot/message/reply', {
    method: 'post',
    contentType: 'application/json',
    headers: { Authorization: 'Bearer ' + cfg_('LINE_ACCESS_TOKEN') },
    payload: JSON.stringify({
      replyToken: replyToken,
      messages: [{ type: 'text', text: String(text).slice(0, 4900) }]
    }),
    muteHttpExceptions: true
  });
  if (res.getResponseCode() !== 200) {
    console.error('LINE 回覆失敗 ' + res.getResponseCode() + ':' + res.getContentText());
  }
}

/** 部署前先執行這個,檢查設定有沒有填好 */
function checkSetup() {
  console.log('LINE_ACCESS_TOKEN:' + (cfg_('LINE_ACCESS_TOKEN') ? '已填' : '❌ 沒有填'));
  console.log('GEMINI_API_KEY:'   + (cfg_('GEMINI_API_KEY')   ? '已填' : '❌ 沒有填'));
  console.log('GEMINI_MODEL:'     + (cfg_('GEMINI_MODEL')     || '(沒填,會用預設 gemini-3.1-flash-lite)'));
  console.log('PROMPT:'           + (cfg_('PROMPT')           ? '已填' : '(沒填,會用預設語氣)'));
  console.log('KNOWLEDGE:'        + (cfg_('KNOWLEDGE')        ? '已填' : '(沒填,AI 大部分問題都會說不知道)'));
}

做完你應該看到:編輯區裡是上面這段內容,而且上方出現「已儲存」之類的提示。 🖼 對照圖:安裝載體 START_HERE 步驟 5。

Step 4:填三個設定值

「指令碼屬性」是這個專案的設定欄位。你的秘密放在這裡,不會出現在程式碼裡。

  1. 左邊選「專案設定」(齒輪圖示)。
  2. 拉到最下面「指令碼屬性」,按「新增指令碼屬性」。
  3. 一個一個加,屬性名稱要一字不差
屬性名稱值要填什麼一定要填嗎
LINE_ACCESS_TOKEN你在 02 Step 3 按 Issue 簽發、複製下來的那一串字
GEMINI_API_KEYStep 1 拿到的那一整串金鑰
KNOWLEDGE你希望 AI 知道的事,用白話寫,換行分開
PROMPT你希望 AI 用什麼身分、什麼語氣回答;想讓它回答長一點,也寫在這裡可不填
GEMINI_MODEL想換模型時才填;預設模型塞車時的換法見〈如果卡住〉可不填

KNOWLEDGE 可以直接這樣寫:

營業時間:週一到週六 11:00–20:00,週日公休。
地址:(填你的地址)
可以先回答的事:營業時間、地址、有沒有停車位、大概多久能做好。
一定要轉真人的事:報價、改期、退款、客訴。
  1. 按「儲存指令碼屬性」。

做完你應該看到:屬性列表裡有你剛剛加的那幾列。 🖼 對照圖:安裝載體 START_HERE 步驟 6。

🔴 這一格就是你的 AI 懂多少的來源。 KNOWLEDGE 空著,AI 幾乎每題都會說不知道——那不是壞掉,是你還沒告訴它。

Step 5:檢查設定有沒有存進去

  1. 回到編輯畫面。
  2. 編輯區上方有一個下拉選單,裡面列著程式裡每一段功能的名字。把它拉開,選 checkSetup
  3. 按「執行」。
  4. 第一次執行會跳出授權視窗,按「審查權限」→ 選你自己的 Google 帳戶 → 如果出現「這個應用程式未經驗證」,點「進階」→「前往(你的專案名稱)」→「允許」。

這個授權是你允許你自己的程式,用你自己的帳戶去連外網。你沒有把任何東西交給我方。

做完你應該看到:畫面下方的「執行紀錄」出現五行,LINE_ACCESS_TOKENGEMINI_API_KEYKNOWLEDGE 三行都寫「已填」。 🖼 對照圖:安裝載體 START_HERE 步驟 7。

如果看到 ❌,回 Step 4 檢查屬性名稱有沒有打錯字。

Step 6:部署,拿到自己的網址

「部署」的意思是:讓這段程式有一個外面連得到的網址。

  1. 右上角按「部署」→「新增部署」。
  2. 視窗打開後,按「選取類型」旁邊的齒輪圖示,選「網頁應用程式」。
  3. 「執行身分」選(你自己的帳戶)。
  4. 「誰可以存取」選所有人
  5. 按「部署」。

🔴 第 3、4 兩點是兩格設定,一格都不能錯。 第 3 點「執行身分」要選的「」,那格會顯示你自己的 email(例:我(xxxx@gmail.com))。絕對不要選「存取網頁應用程式的使用者」——選了它,後面每一關檢查都會過(checkSetup 全綠、手動執行全成功),但客人真的傳訊息進來時程式半秒內就失敗、而且不留任何錯誤訊息,你會完全查不出原因(2026-08 實測案例:改回「我」立刻就通)。 第 4 點一定要選「所有人」。這不是把你的資料公開——是讓 LINE 的伺服器連得到你這個網址。選錯的話 LINE 會連不上。 🖼 兩格正確時的對照圖:安裝載體 START_HERE 步驟 8。

做完你應該看到:一個以 https://script.google.com/macros/s/ 開頭、/exec 結尾的網址。按「複製」。

🔴 部署畫面上可能同時出現兩個網址,只有一個是對的:「網頁應用程式」底下、/exec 結尾的才是要用的;「資料庫」底下、網址裡有 library 字樣的不要拿——貼給 LINE 會直接連不通。口訣:給 LINE 的網址一定是 /exec 結尾;看到 library=拿錯張了。 🖼 兩個網址並列的對照圖:安裝載體 START_HERE 步驟 8。

這就是 Step 7 要交給 LINE 的網址(自檢清單 對應步驟 8)。

🔴 以後每次改程式碼,都要再部署一次:「部署」→「管理部署作業」→ 按編輯(鉛筆)圖示 → 版本選「新版本」→ 按「部署」。只按儲存不會生效,網址不變,但內容不會更新。

Step 7:把網址交給 LINE,打開 Webhook

「Webhook」是一個約定:有人傳訊息給你的官方 LINE 時,LINE 就自動把訊息送到你指定的網址。你要告訴 LINE 的,就是 Step 6 那個網址。這一步全程在中文介面的 LINE Official Account Manager 完成,不需要回英文的 Console

  1. LINE Official Account Manager,選你的帳號 → 右上「設定」→ 左邊「Messaging API」(啟用 Messaging API 時用過的那一頁)。
  2. 把 Step 6 的網址貼進「Webhook網址」那格,按「儲存」。
  3. 左邊「回應設定」→ 把「Webhook」開關打開成綠色

做完你應該看到:「回應設定」頁的 Webhook 開關是綠的。 🖼 對照圖:安裝載體 START_HERE 步驟 9。

同一頁的「自動回應訊息」「加入好友的歡迎訊息」「聊天」開不開由你決定——它們跟 AI 回覆不衝突(2026-08 實測)。只有一件事要注意:自動回應開著時,你測試收到的可能是它的罐頭回應、而不是 AI——測試時以回覆內容判斷;想讓客人只收到 AI 的回答,就把自動回應關掉。

這一章的成功判定

只要你確認:

  • API Key 是你自己的,而且留在你自己的環境。
  • checkSetup 執行後,三個必填屬性都顯示「已填」。
  • 你有一個 /exec 結尾的網址。
  • Manager 的「Webhook網址」填了那個網址,而且按過「儲存」。
  • 「回應設定」的「Webhook」開關是綠色。

🔴 這幾項的意思是「動作都做完了」,不是「設定都是對的」。 每一項都只證明它自己:

  • checkSetup 顯示「已填」,只代表那一格不是空的——貼錯的、過期的值一樣顯示「已填」。
  • 「Webhook」開關是綠的,只代表開關開了——不代表對面接得住。

這幾件事互相推不出對方。 唯一能證明整條路真的通的,是 04你自己傳一則訊息,收到回覆。 在那之前,這一章都只是「做完了」,還不是「成功了」。

你不需要把 API Key 貼出來。

留下非秘密的設定紀錄

你可以記錄以下資料,但不要記錄 API Key 原文:

使用的模型供應商:Gemini
使用的執行環境:自己的 Google Apps Script
秘密保存位置:指令碼屬性
Webhook 開關狀態:
建立日期:
最後一次驗證日期:

這一版做到哪裡,沒做到哪裡

誠實說明這段程式的邊界:

  • 看不到是誰傳的訊息,也不記得上一句話。每一則訊息都是獨立回答。
  • 它只回文字。貼圖、照片、語音一律不回應。
  • 你的網址是公開可連的。Google Apps Script 不讓程式讀取請求的標頭,所以這一版無法驗證訊息是不是真的來自 LINE。實際影響:別人若猜到你的網址,可以讓你多用一點 Gemini 額度,但沒辦法讓你的帳號去回覆你的客人——因為回覆需要 LINE 當下才會發出的一次性代碼。
  • 免費額度有上限。用量大的時候會回不出來,這是額度問題不是設定問題。另一種回不出來是模型本身當下全球過載——不是你的用量造成的,處理方式見〈如果卡住〉。
  • 它是一步一步做完才回覆:先問 Gemini,等它回答,再送回 LINE。所以回覆通常慢個一兩秒。LINE 官方建議這類程式改成「先答應、再處理」,那需要多一層設定,這一版刻意不做——多那一層會讓安裝變難,而這一版的目標是先讓你跑通一次。
  • 你的官方帳號後台可能會出現 request_timeout 之類的統計。只要你手機收得到回覆,那是統計數字,不是壞掉。
  • 有兩個上限是程式寫死的,改 PROMPT 沒有用:①每一則回覆的長度上限(程式碼裡的 maxOutputTokens)②送去 LINE 的訊息太長會被截短(這是 LINE 平台自己的上限,不是我們加的)。
  • 還有一條安全規則:「只根據 KNOWLEDGE 裡的內容回答,沒寫的就說不知道」——這是為了不讓它自己編出價格和規則,我們刻意把它放在最後、要它最優先。🔴 但要跟你說實話:這一條是寫給 AI 的指示,不是程式鎖。你如果在 PROMPT 裡下一個正好相反的命令,它有可能就不照這條走了。所以請不要那樣寫。
  • 「回答控制在三句話以內」只是預設,不是規定——你在 PROMPT 裡叫它回答詳細一點,它通常就會照你的。

這些不是缺陷,是這一版刻意的範圍。

如果卡住

常見原因可能包括:

  • 登入了不同的 Google 帳戶。
  • API Key 建立在另一個專案。
  • 指令碼屬性的名稱打錯字(大小寫也要一樣)。
  • 改完程式碼只按了儲存,沒有重新部署。
  • 「誰可以存取」沒有選「所有人」。
  • 「執行身分」選成「存取網頁應用程式的使用者」——特徵:手動執行都成功,但真訊息進來時執行紀錄半秒內失敗、點進去沒有任何內容。改回「我」+新版本重新部署。
  • 權限、配額或模型設定不一致。
  • 模型當下全球過載:執行紀錄出現「Gemini 回傳 503」加上「high demand」字樣,每則訊息拖到一分鐘以上——這不是你裝錯

不要先重建整套 LINE。

「503/high demand」有現成解法:到 AI Studio 的模型選單挑另一顆 flash 系列模型,把它顯示的確切名稱填進指令碼屬性 GEMINI_MODEL(就是 Step 4 那張表的可選欄位;存了立刻生效,不用重新部署)。這一版的預設 gemini-3.1-flash-lite,就是在前一代預設塞車時這樣實測換出來的(2026-08)。

請進入 05|AI Troubleshooter,從最後一個確定成功的步驟開始。

下一步

進入 04|看到第一個 AI 回覆

安裝卡住 → 加 LINE 直接講。

進 LINE 體驗