iT邦幫忙

2025 iThome 鐵人賽

DAY 2
0

前言

歡迎回來!如果你正在讀這篇,代表你昨天成功建立了專案,恭喜你已經打敗了 50%在 Day 1 就放棄的參賽者(我瞎掰的數據,但應該差不多,健身房也是過年假期結束第二天後就少一堆人了)。今天我們要做一件更刺激的事:讓 AI 真的開始跟你對話。

還記得昨天那個按了沒反應的「提交答案」按鈕嗎?今天它就要活過來了,我們會一路從 goolge 雲端專案建立、API key 的申請、google AI 套件安裝一路到整合到我們的專案中,讓我們的 AI 面試官能至少開始與你對話而不是在那邊當薪水小偷,過程中也會帶到一點提示詞工程(Prompt Engineering)最最基本的概念,讓你了解一個最基本的有效提示詞會是怎麼樣的結構,廢話不多說,馬上開始吧!

今日目標

今天結束時,你將能:

  • 取得 Google AI Studio 的 API Key(完全免費)
  • 成功呼叫你的第一個 AI API
  • 理解什麼是「角色設定」以及為什麼它如此重要
  • 讓你的面試官開始回應問題

聽起來很多?別擔心,我們一步步來。

Step0: 建立一個新的Google cloud platform專案

首先,我們要做一件看起來完全不相干的事情,我們要建立一個gcp專案!我不是離題或是腦袋錯亂,單純是為了後續的流程鋪路。請你前往Google Cloud的頁面,並點選左上角Logo旁的「選取專案」按鈕,理論上你會看到彈出的視窗,在那個視窗中點選「新增專案」按鈕,如下圖1所示:

圖1
圖1 :GCP專案建立視窗-1

接著跳到專案新增細節的頁面,輸入你想做的任何專案名稱,我這邊以AI-Interviewer當作例子,位置的部分採用預設的無組織即可,如下圖2所示:

圖2
圖2 :GCP專案建立視窗-2

專案建立需要一點點時間,稍稍等候一下後你應該會在右上角看到專案建立成功的訊息通知,看到該訊息後你就可以把這個玩意先拋在一邊了!

Step 1: 取得你的 AI 通行證

我們剛剛做的前置作業就是為了這一步而做的,誰叫Google更改了建立Api Key的方案導致我們需要多跑一步,不過拿人手短,我們照新規則做就沒事了。請你接著前往Google AI Studio的頁面,你會看到一個相當簡潔的介面,用你的 Google 帳號登入即可,在這個頁面中你可以免費的嘗試各種Google最新的AI模型與新功能,像是圖片生成、Story Book當時都是先在這邊開放試用的,之後有事沒事都可以過來看一下有沒有什麼新玩意可以玩!不過這些暫時不是我們的目標,請你先把眼光放在頁面左下角的「Get API Key」按鈕,如下圖3所示:

圖3
圖3 :Google AI Studio畫面

接著會跳到你的API key的管理畫面,往右上角尋找「Create API Key」的按鈕,點擊後會跳出另一個彈出視窗,這邊你就會發現它需要選擇一個GCP專案才能創立API Key,但若你剛剛沒有照步驟走,在這邊也可以藉由下方的按鈕去跑一次一模一樣的流程後再建立自己的Key,選擇專案後點選「Create API Key in existing project」按鈕就行了!

圖4
圖4 :選擇專案建立API Key

按下按鈕後就替你產生一個獨一無二的API Key,請務必複製下來並存在你電腦的某個地方,跟絕大多數的第三方服務API key一樣,一旦你關閉這個視窗,你就再也看不到這個完整的值了!

辛苦了!到這邊我們一行Code都還沒寫,就已經感覺跑了很多地方,但至少我們取得可以用的API Key囉!

💡 為什麼選 Google AI Studio?

  • 完全免費(截至我寫文章的當下,目前的免費額度是每分鐘 5 - 30 個請求,每天 100 - 1000 個請求,具體的數字因你使用的模型而異)
  • 不需要信用卡
  • Gemini 模型的中文理解相當不錯
  • 設定簡單快速,適合新手
  • 有著相對其他模型較大的 context window,講白話點就是一次可以餵更多內容給它

⚠️ 安全提醒: 這個 API key 就像你家鑰匙,別隨便給人看。絕對不要把它直接寫在程式碼裡推上 GitHub(我知道你會想這麼做,但請忍住),你這麼做的話Google會森氣氣然後讓那個key失效,你之後就得重新申請一個囉。

Step 2: 讓 Next.js 認識你的 API Key

回到程式碼的部分吧!先打開我們昨天建立的專案。首先,在專案根目錄建立一個 .env.local 檔案:

在專案根目錄

touch .env.local  # Mac/Linux

echo. > .env.local  # Windows

打開 .env.local,加入:

GEMINI_API_KEY=你剛剛複製的API_KEY

📝 小知識: .env.local 檔案會被 Git 自動忽略(Next.js 已經幫你設定好了),所以你的 API key 不會不小心被推上去。這就是為什麼我們要用環境變數而不是直接寫在程式碼裡。

Step 3: 安裝 Google AI SDK

打開終端機,確保你在專案目錄內,然後執行:

npm install @google/genai

這個套件是 Google 官方提供的,讓我們可以輕鬆呼叫 Gemini API,且會替我們整理回應後的結果以及支援一些其他功能讓使用上更為方便!

📝 小知識: 你也許會看到有些教學在與Gemini API溝通時會要求你用@google/generative-ai這個套件,不過這個套件已經在2025年年初宣告不再維護,官方的文件現在推薦使用更新的@google/genai進行串接。

Step 4: 建立我們的第一個 API 路由

這個步驟也牽扯到為什麼我們當時會選用Next這樣的全端框架(或是你用Nuxt, Remix之類的),主要是這類的框架都已經有很成熟的路由系統,許多都有包含API路由的支援,讓你的應用程式可以輕鬆的建立前後端溝通的管道而不用費神管理兩個專案。
至於為什麼我們會需要這樣的API路由系統呢?主要是因為像我們取得的Google API Key是屬於隱私需求極高的東西,放在前端中不管怎麼樣都會洩漏出去(不要以為環境變數可以保護它,這點我們以後有足夠篇幅時可以談談),因此我們肯定需要一個後端去儲存這個Key提供我們使用!理解這些後我們就可以繼續我們的操作了,請你先在以下的路徑建立以下的檔案。

// app/api/gemini/route.ts:

import { GoogleGenAI } from '@google/genai';
import { NextResponse } from 'next/server';
const GEMINI_API_KEY = process.env.GEMINI_API_KEY;

const ai = new GoogleGenAI({ apiKey: GEMINI_API_KEY });

export async function POST(request: Request) {
  try {
    const { question, answer } = await request.json();

    // 設計提示詞,讓 AI 扮演前端面試官
    const prompt = `
      你是一位經驗豐富的前端技術面試官,正在進行技術面試。

      你的特點是:

      1. 專業但友善,會給予建設性的回饋

      2. 不只是說對或錯,會解釋為什麼

      3. 會提供改進建議和學習資源

      4. 偶爾會分享業界實務經驗

      現在考生回答了一個問題:

      問題:${question}

      考生的答案:${answer}

      請給予專業的評價和建議。如果答案有誤,請溫和地指出並解釋正確的概念。

      如果答案正確,請肯定並補充一些進階的知識點。

      `;

    // 使用Gemini提供的AI模型去取得回應
    const response = await ai.models.generateContent({
      model: 'gemini-2.5-flash',
      contents: prompt,
    });
    const text = response.text;

    // 回傳回應
    return NextResponse.json({ result: text });
  } catch (error) {
    console.error('Gemini API error:', error);
    return NextResponse.json(
      { error: '無法生成回饋,請稍後再試' },
      { status: 500 }
    );
  }
}

這段程式碼做了什麼?

1. 接收前端傳來的問題和答案
2. 組合成一個 prompt(提示詞)
3. 送給 Gemini API(你可以在這個頁面去看有哪些模型可用且收費標準怎麼算的,尤其當你打算要用比較大量的token時)
4. 把回應傳回前端

最關鍵的是那段 prompt。這就像是給演員的劇本,決定了AI會如何回應,也是決定你的AI服務成敗的基礎,當然,具體來說該怎麼寫prompt才能100%適用於所有的情況、得到你想要的結果,暫時還沒有足夠的文獻去佐證,不過在經過幾年的AI使用後,慢慢的社群以及一些AI工具的官方頁面都有分享一些他們認為有用的手段,這個部分我們會在Day 6時再做詳細的說明,暫時你可以先以這份基本版將就一下,給它最基礎的角色設定以及回覆方式就好了!

Step 5: 讓前端按鈕真的能用

現在後端服務已經弄好了,馬上做個串接讓前端頁面不再是個死人骨頭吧!請修改 app/page.tsx,加入互動功能,嫌懶的人就直接整份複製貼上就能使用了,主要修改的部分有在下方做條列式基本說明,如果你覺得這些有一點點點難懂的話,你可能會需要回頭複習一下React,目前為止應該還沒有太高深的知識或是Next.js的玄學:D

'use client'; // 重要!告訴 Next.js 這是客戶端元件, 這樣才能使用 client-side 的 hooks

import { useState } from 'react';
export default function Home() {
  const [answer, setAnswer] = useState('');
  const [feedback, setFeedback] = useState('');
  const [isLoading, setIsLoading] = useState(false);
  const question = '請解釋 JavaScript 中的 hoisting 是什麼?';

  const handleSubmit = async () => {
    if (!answer) return;
    try {
      setIsLoading(true);

      // 發送請求到我們剛剛在後端app/api/gemini/route.ts建立的API
      const response = await fetch('/api/gemini', {
        method: 'POST',
        body: JSON.stringify({
          question,
          answer,
        }),
      });
      const data = await response.json();

      setFeedback(data.result);
    } catch (error) {
      console.error('錯誤:', error);
    } finally {
      setIsLoading(false);
    }
  };
  return (
    <main className="min-h-screen bg-gray-900 text-white">
      <div className="container mx-auto px-4 py-16">
        <h1 className="text-4xl font-bold text-center mb-8">
          AI 前端面試官 🤖
        </h1>

        <div className="max-w-2xl mx-auto">
          {/* 題目區 */}
          <div className="bg-gray-800 rounded-lg p-6 mb-6">
            <div className="text-sm text-blue-400 mb-2">題目 #1</div>
            <p className="text-lg">{question}</p>
          </div>

          {/* 作答區 */}
          <div className="bg-gray-800 rounded-lg p-6 mb-6">
            <textarea
              value={answer}
              onChange={(e) => setAnswer(e.target.value)}
              className="w-full h-32 bg-gray-700 rounded p-3 text-white"
              placeholder="在這裡輸入你的答案..."
              disabled={isLoading}
            />
          </div>

          {/* 按鈕 */}
          <button
            onClick={handleSubmit}
            disabled={isLoading || !answer}
            className="w-full bg-blue-600 hover:bg-blue-700 disabled:bg-gray-600 text-white font-bold py-3 px-6 rounded-lg transition-colors"
          >
            {isLoading ? '🤔 AI 思考中...' : '提交答案'}
          </button>

          {/* AI 回饋區 */}
          <div className="bg-gray-800 rounded-lg p-6 mt-6">
            <div className="text-sm text-green-400 mb-2">AI 回饋</div>

            {feedback ? (
              <div className="text-gray-300 whitespace-pre-wrap">
                {feedback}
              </div>
            ) : (
              <p className="text-gray-400 italic">
                提交答案後,AI 將在這裡提供回饋...
              </p>
            )}
          </div>
        </div>
      </div>
    </main>
  );
}

主要改動:

  • 加入 'use client'
    因為我們需要使用 useState,這也是Next.js一開始容易比較不習慣的地方,自從正式引入了Server side component之後就多了一些條條框框。
  • 加入狀態管理(answer, feedback, isLoading)
  • 實作 handleSubmit 函數呼叫我們的 API,並將回應的內容渲染到畫面上

Step 6: 測試你的 AI 面試官

Moment of truth! 請打開你的終端機輸入

npm run dev

打開 http://localhost:3000,試著回答問題後按下提交按鈕,比方說我今天簡單的在輸入框輸入「一個仿佛將所有程式碼的函數與變數宣告都移到該作用域最上方的行為」並按下提交按鈕,理論上你會看到畫面進入讀取,送出的請求正在被Gemini解析並試著回覆。

圖5
圖5 :輸入回覆後的讀取畫面

經過超長一段時間後,你應該會發現他真的回覆你東西了!

圖6
圖6 :輸入回覆後的回應畫面

大致上內容都是正確的,有AI該有的樣子,能回應得比大部分的junior工程師都來得出色,恭喜!到此為止就已經完成AI的串接,大家可以回家啦!

今日回顧

辛苦了,今天花了不少篇幅在詳細的說明一些設置,雖然大致上都精簡的帶過一些流程,但想必還是挺累人的吧? 回顧一下今天的進度,我們大致上推進了以下的項目:

✅ 取得了 Google AI Studio API Key
✅ 建立了第一個 API 路由
✅ 成功呼叫 Gemini API
✅ 讓介面真的可以互動

經過這麼一連串的折騰,你是否覺得「阿靠杯喔,這樣我不如直接去用chatgpt, gemini, claude之類的網站不就好了?」,如果你心裡有冒出任何一點這樣的想法,那你該好好誇獎你自己,因為你是完全正確的!目前我們做出的東西完全比不上你剛說的那些成熟頁面,不但介面陽春、回覆慢且使用麻煩,看起來一點都不值得我們這樣費工,不過這也只是開始而已,是任何類似的軟體都需要走過的步驟,因此不要給自己太大的壓力,慢慢、一步步地跟我一起達成目標就好!

明天預告

明天(Day 3)我們要來好好規劃架構了,在開發前先做好一定程度的計畫遠比你之後在那邊修修補補來得有效率,雖然我們不見得會100%照著開發計畫執行,尤其在我們對於這些技術不是這麼熟悉的情況下,設計或架構上的變更都是家常便飯,但至少要有個基本的起步,讓整個過程稍微有條理一點!我們明天見吧!🚀

今日程式碼: GitHub Day-02 Branch


上一篇
我不是AI專家,但我能打造AI應用:環境設置
下一篇
設計我們的面試系統:提出基本架構設計
系列文
前端工程師的AI應用開發實戰:30天從Prompt到Production - 以打造AI前端面試官為例3
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言