醫智匯

faq-bot

faq-bot

怎麼用

打開你的 AI 助手,把下面這句話貼給它。下面那一大段是寫給它看的,你不必讀。

請照平台的 faq-bot 這個 skill 幫我做

適用:使用者想要「客服機器人」「問答機器人」,而問題其實是一群固定的常見問題——

檢查前要空腹多久、探病時間、某個表單去哪裡拿、單位內的作業規定。

做法是事先寫好的問答+選單+關鍵字比對,不用 AI,所以:

  • 可以設成公開(病人、家屬掃 QR 就能用),也可以只給院內同仁。
  • 答案每一句都是負責的科別審過的,不會「自己編」。

先講清楚

  • 平台目前沒有 AI 服務(llms.txt §4.6)。使用者說「機器人」時,先用白話確認:

「平台現在不能用 AI。我可以做一個用選單和關鍵字找答案的問答頁,答案是你們事先寫好的。這樣可以嗎?」

  • 給病人用的 AI 機器人,平台開放 AI 之後也不行:公開的應用不能用 AI(llms.txt §4.55)。不要承諾「之後換成 AI」。
  • 不能記錄大家問了什麼:公開的應用不能存資料。想知道哪些問題常被問,請同仁在現場記下,再來更新題庫。
  • 找不到答案時,畫面要給真人管道(單位、分機、服務台位置)。聯絡資料問使用者,不要自己用帳號資料填(llms.txt §2)。

做法

  • archetype: A,data.collects: [],skills_used: [faq-bot];開放程度照使用者的回答(病人家屬要用就 public)。
  • 題庫是資料,不是程式:放在頁面裡的一個陣列(或同資料夾的 faq.json,用 fetch('faq.json') 讀)。每一題:

```js

{ id: 'fasting', category: '檢查前準備', q: '抽血前要空腹多久?',

keywords: ['空腹', '禁食', '吃東西', '喝水', '抽血'], a: '一般抽血不用空腹;…', source: '檢驗科', reviewed: '2026-10-01' }

```

  • 答案的內容由使用者提供,你只排版。要上網找資料當參考,照 llms.txt §2 先問他、查到的先唸給他確認。
  • 每題都要有 source(哪個單位審的)與 reviewed(審閱日期),顯示在答案下面。
  • 畫面:
  • 最上面一句說明:「這是常見問題查詢,答案由○○科整理;不是真人、也不是 AI。」
  • 先給分類按鈕(多數人用點的,不用打字),點進去列出題目,點題目看答案。
  • 再給一個搜尋框:把使用者打的字和每題的 q、keywords 比對,列出最相關的 3–5 題(骨架的 search())。
  • 找不到時顯示真人管道。緊急狀況(胸痛、呼吸困難…)在頁面最上面寫「請立即就醫或撥 119」。
  • 比對的小技巧(骨架已含):全形轉半形、去掉空白與標點、英文轉小寫;同義詞放進 keywords(「禁食」「空腹」「不能吃」)。

不用裝搜尋套件;題目上百題、需要錯字容忍時,用平台提供的 Fuse.js(ES module,llms.txt §4.9):

```html

<script type="module">

import Fuse from 'https://platform.wanfangai.tw/lib/fuse.js@7.5.0/fuse.min.mjs';

const fuse = new Fuse(FAQ, { keys: ['q', 'keywords'], threshold: 0.4 });

const hits = fuse.search('要空腹嗎').slice(0, 5).map((r) => r.item);

</script>

```

  • 使用者打的字只用來比對,不要用 innerHTML 放回畫面;顯示答案也用 textContent。答案要分段就把文字切成多個 <p>。

骨架

<!doctype html>
<html lang="zh-Hant">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>檢查前準備常見問題</title>
  <style>
    body { font-family: system-ui, sans-serif; margin: 0; padding: 16px; line-height: 1.7; max-width: 720px; }
    button, input { min-height: 44px; font-size: 16px; }
    .cats button { margin: 4px; }
    .answer { border-left: 4px solid #2a7; padding: 8px 12px; background: #f5fbf8; }
    .meta { color: #666; font-size: 14px; }
  </style>
</head>
<body>
  <p><strong>緊急狀況請立即就醫或撥 119。</strong></p>
  <h1>檢查前準備常見問題</h1>
  <p>這是常見問題查詢,答案由檢驗科整理;不是真人,也不是 AI。</p>
  <div class="cats" id="cats"></div>
  <label>找問題 <input id="q" type="search" placeholder="例如:要空腹嗎"></label>
  <ul id="hits"></ul>
  <div id="answer"></div>
  <p class="meta">找不到答案?請洽檢驗科櫃台,分機 0000。</p>
  <script>
    const FAQ = [
      { id: 'fasting', category: '抽血', q: '抽血前要空腹多久?', keywords: ['空腹', '禁食', '吃東西', '喝水'],
        a: '(由檢驗科提供的答案)', source: '檢驗科', reviewed: '2026-10-01' },
    ];
    const norm = (s) => s.normalize('NFKC').toLowerCase().replace(/[\s\p{P}]/gu, '');
    function search(text) {
      const t = norm(text);
      if (!t) return [];
      return FAQ.map((f) => {
        let score = norm(f.q).includes(t) ? 3 : 0;
        for (const k of f.keywords) if (t.includes(norm(k)) || norm(k).includes(t)) score += 2;
        return { f, score };
      }).filter((x) => x.score > 0).sort((a, b) => b.score - a.score).slice(0, 5).map((x) => x.f);
    }
    function show(f) {
      const box = document.getElementById('answer');
      box.replaceChildren();
      box.className = 'answer';
      const h = document.createElement('h2');
      h.textContent = f.q;
      box.append(h);
      for (const para of f.a.split('\n')) {
        const p = document.createElement('p');
        p.textContent = para;
        box.append(p);
      }
      const meta = document.createElement('p');
      meta.className = 'meta';
      meta.textContent = `資料來源:${f.source}|最後審閱:${f.reviewed}`;
      box.append(meta);
    }
    function list(items) {
      const ul = document.getElementById('hits');
      ul.replaceChildren();
      for (const f of items) {
        const li = document.createElement('li');
        const b = document.createElement('button');
        b.textContent = f.q;
        b.addEventListener('click', () => show(f));
        li.append(b);
        ul.append(li);
      }
    }
    for (const cat of [...new Set(FAQ.map((f) => f.category))]) {
      const b = document.createElement('button');
      b.textContent = cat;
      b.addEventListener('click', () => list(FAQ.filter((f) => f.category === cat)));
      document.getElementById('cats').append(b);
    }
    document.getElementById('q').addEventListener('input', (e) => list(search(e.target.value)));
  </script>
</body>
</html>

發佈前檢查

  • 每一題都有 source 與 reviewed;答案是使用者給的或他確認過的。
  • 頁面寫清楚「不是真人、也不是 AI」,有緊急狀況提示與真人管道。
  • data.collects 是空的;開放程度照他的回答(公開的話,正式版會被搜尋引擎收錄)。
  • 告訴他:題庫要更新時,跟你說「新增一題/改一題」,再發佈一次就好。

用到的平台套件

照這份做法做的工具,會從平台載入這些: