從大模型應用開始:用 LLM API 打造會聊天的前端應用實戰指南

如果你是正在寫 Vue3 / React 後台的前端工程師,最近大概會發現:老闆或產品經理開始問「我們的系統能不能加一個 AI 助手?」。上一篇我們聊過「用 AI 工具輔助你寫程式」,這一篇要講的是另一件事——把大模型(LLM)接進你的應用裡,讓產品自己會說話。別被「AI 應用」四個字嚇到,它的核心其實就是:發一個 HTTP 請求、把使用者的話送過去、把模型的回答渲染出來。今天我們就從零開始,一步步做出一個會聊天的前端。

一、先搞懂:大模型應用到底在呼叫什麼?

打個比方:大模型 API 就像一家「翻譯社」,你把需求(prompt)寄過去,它把成品(回答)寄回來。所有主流大模型都遵循一套幾乎相同的呼叫格式——OpenAI 相容格式。先記住四個名詞:

  • Token:模型計算文字的基本單位,一個中文字大約 1~2 個 token,也是計費單位。
  • 上下文視窗(Context Window):模型一次能「記住」的對話長度上限,超出就要自己裁剪歷史。
  • Temperature:隨機度,0 最嚴謹穩定,越高越有創意但越容易胡說。
  • System Prompt:給模型的「人設與規則」,決定它用什麼身份、什麼口吻回答。

重點:呼叫大模型的本質就是一個 HTTP POST,body 裡帶一個 messages 陣列——這對前端工程師來說,沒有任何新知識門檻。

二、步驟 1:用 fetch 發出第一次對話請求

假設要接一個 OpenAI 相容的接口,最小可用代碼長這樣:

async function askLLM(userText: string) {
  const res = await fetch('/api/chat', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      model: 'gpt-4o-mini',
      messages: [
        { role: 'system', content: '你是一個嚴謹的客服助理,只回答與產品相關的問題。' },
        { role: 'user', content: userText },
      ],
      temperature: 0.3,
    }),
  });
  const data = await res.json();
  return data.choices[0].message.content;
}

你可能注意到請求是發到 /api/chat 而不是模型官網——因為金鑰絕對不能放在前端代碼裡。正確做法是由自己的後端(或 BFF / Serverless 函數)持有 API Key,前端只呼叫自家接口做代理。

重點:前端直連模型官方 API 等於把你的錢包公諸於世——API Key 一旦被扒走,帳單會教你看懂什麼叫「惡意刷量」。

三、步驟 2:管理對話上下文,讓它真的「會聊天」

大模型是沒有記憶的——它每次都只看你這次傳過去的內容。所謂「多輪對話」,就是前端每次把歷史訊息整包帶回去。用 Vue3 管理一個訊息列表:

const messages = ref<{ role: 'user' | 'assistant'; content: string }[]>([]);

async function sendMessage(text: string) {
  messages.value.push({ role: 'user', content: text });
  const history = messages.value.map(({ role, content }) => ({ role, content }));
  const reply = await askLLM(history);
  messages.value.push({ role: 'assistant', content: reply });
}

當對話越來越長,就要注意上下文視窗:常見策略是保留 system prompt + 最近 N 輪對話,更早的歷史可以摘要成一則壓縮訊息再帶回去,省 token 又不丟重點。

四、步驟 3:用 SSE 串流輸出,打造「打字機」體驗

等模型把整段話寫完才回應,使用者會盯著空白畫面等到懷疑人生。所以主流應用都是串流輸出——伺服器用 SSE(Server-Sent Events)一個 token 一個 token 地推,前端邊收邊渲染:

async function askLLMStream(history: Message[], onChunk: (t: string) => void) {
  const res = await fetch('/api/chat', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ model: 'gpt-4o-mini', messages: history, stream: true }),
  });
  const reader = res.body!.pipeThrough(new TextDecoderStream()).getReader();
  let buffer = '';
  while (true) {
    const { value, done } = await reader.read();
    if (done) break;
    buffer += value;
    const lines = buffer.split('\n');
    buffer = lines.pop() ?? '';
    for (const line of lines) {
      if (!line.startsWith('data:')) continue;
      const payload = line.slice(5).trim();
      if (payload === '[DONE]') return;
      const json = JSON.parse(payload);
      onChunk(json.choices[0]?.delta?.content ?? '');
    }
  }
}

重點:串流一定要處理「半包」問題——一個 SSE 訊息可能被網路拆成兩次收到,所以要用 buffer 攢齊完整行再解析,拿到片段就暴衝 JSON.parse 遲早出鬼。

五、進階:Function Calling,讓模型幫你「查資料」

模型的知識是死的,但你的系統資料是活的。Function Calling 的思路是:你告訴模型「有哪些函數可用」,模型判斷需要時回傳一個「函數名 + 參數」的 JSON,前端(或後端)真正執行後把結果再餵回去。例如使用者問「我今天有幾條待處理告警?」,模型不會瞎猜,而是回傳:

{ "name": "getAlarmCount", "arguments": { "status": "unhandled", "date": "today" } }

你呼叫自家 API 查到「23 條」,再把結果交還模型,它就會用人話回答「您今天有 23 條待處理告警」。這就是現在所有「AI Agent」的地基——模型負責理解與決策,你的程式負責真正幹活。

六、上線前的三個工程細節

  • 金鑰與代理:API Key 只存在後端,前端走自家接口,順便做鑑權與用量配額。
  • 失敗與降級:模型接口會超時、會限流,要有重試(指數退避)與「AI 功能暫不可用」的降級 UI。
  • 輸出不可全信:模型會一本正經地胡說(幻覺),涉及金額、數量的展示務必以自家資料為準,模型只負責「組織語言」。

總結一下:大模型應用 = HTTP 請求 + 上下文管理 + 串流渲染 三件套,再加 Function Calling 就能從「會聊天」升級到「會辦事」。對前端工程師來說,這是離 AI 最近的一次機會——門檻沒有想像中高,值得親手做一個玩玩。

互動話題:你的專案裡有沒有正在規劃或已經上線的 AI 功能?你在接入大模型時踩過最深的坑是什麼——串流半包、上下文爆掉、還是帳單爆炸?歡迎留言聊聊!