聊天對話
AI 提示訊息
「你是一位專業的旅遊助手。你需要分三個不同的階段進行操作,並且必須遵循每個階段的嚴格格式規則。
請根據使用者的請求與其進行對話、問候,並顯示相應的按鈕。
階段 1:目的地探索
觸發條件:初始問候。
操作:呼叫 get_destinations。
格式:以 [TYPE:DESTINATION] 開頭,接著是問候語,然後是原始 JSON […]。
階段 2:城市探索
觸發條件:使用者選擇一個國家。
操作:呼叫 get_cities。
格式:以 [TYPE:CITY] 開頭,接著是簡短的選擇提示,然後是原始 JSON […]。
階段 3:套餐探索
觸發條件:使用者選擇一個城市。
操作:使用承載值呼叫 tour_packages。
取得城市 ID 的說明:當使用者選擇一個城市時,你將收到一條包含承載值的訊息。此承載值是該城市的 term_id。在呼叫 tour_packages 工具時,你必須使用此特定值。如果你沒有 term_id,請要求使用者澄清他們的城市選擇
格式:以 [TYPE:PACKAGES] 開頭,接著是簡短的確認訊息,然後是原始 JSON […]。
關鍵協議:
路由標題:每條訊息必須以 [TYPE:DESTINATION]、[TYPE:CITY] 或 [TYPE:PACKAGES] 開頭。
無摘要:永遠不要寫成對話式列表或計數。僅提供標籤、簡短問候語和原始 JSON。
機器可讀:JSON […] 必須是每條訊息的最後部分。
工具使用:始終使用提供的工具來擷取資料。永遠不要虛構套餐或城市。」
重要事項:
- 僅返回有效的 JSON
- 不包含解釋
- 不轉義引號
- 不在 JSON 中包含 [TYPE:…]
- 輸出必須能直接被 JSON.parse 解析
工作流
全域解析器
const rawOutput = $input.first().json.output || “”;
// =========================
// 幫助函式:標準返回
// =========================
function formatResponse(data) {
return [{ json: data }];
}
// =========================
// 偵測 TYPE
// =========================
function detectType(text) {
if (text.includes(“[TYPE:DESTINATION]”)) return “DESTINATION”;
if (text.includes(“[TYPE:CITY]”)) return “CITY”;
if (text.includes(“[TYPE:PACKAGES]”)) return “PACKAGES”;
return null;
}
// =========================
// 提取清潔 JSON
// =========================
function extractJSONArray(text) {
if (!text) return null;
// 移除 TYPE 標籤
let cleaned = text.replace(/\[TYPE:[A-Z]+\]/g, "").trim();
// 移除佔位符
if (cleaned.includes("[...]")) return null;
// 取得 JSON 邊界
const start = cleaned.indexOf('[');
const end = cleaned.lastIndexOf(']');
if (start === -1 || end === -1) return null;
let jsonString = cleaned.substring(start, end + 1);
// 🔥 修正常見的 AI 問題
jsonString = jsonString
.replace(/\\\//g, "/") // 修正轉義斜線
.replace(/;\s*$/, "") // 移除尾部分號
.trim();
try {
let parsed = JSON.parse(jsonString);
// 處理雙重編碼的 JSON
if (typeof parsed === "string") {
parsed = JSON.parse(parsed);
}
return parsed;
} catch (e) {
throw new Error("JSON 解析失敗:\n" + jsonString);
}
}
// =========================
// 主程式
// =========================
const type = detectType(rawOutput);
const parsed = extractJSONArray(rawOutput);
// =========================
// 目的地
// =========================
if (type === “DESTINATION” && parsed) {
return formatResponse({
recipient: { id: “123456” },
message: {
text: “選擇一個國家:”,
quick_replies: parsed[0].data.map(i => ({
content_type: “text”,
title: i.destination,
payload: i.id
}))
}
});
}
// =========================
// 城市
// =========================
if (type === “CITY” && parsed) {
return formatResponse({
recipient: { id: “123456” },
message: {
text: “選擇一個城市:”,
quick_replies: parsed[0].data.map(i => ({
content_type: “text”,
title: i.city || i.name,
payload: i.id
}))
}
});
}
// =========================
// 套餐
// =========================
if (type === “PACKAGES” && parsed) {
const packages = parsed[0].data;
const elements = packages.map(pkg => ({
title: pkg.title,
subtitle: pkg.subtitle || "最佳旅遊套餐",
image_url: pkg.image_url,
buttons: (pkg.buttons || []).map(btn => ({
type: btn.type === "web_url" ? "web_url" : "postback",
title: btn.title,
url: btn.url,
payload: btn.payload
}))
}));
return formatResponse({
recipient: { id: "123456" },
message: {
attachment: {
type: "template",
payload: {
template_type: "generic",
elements: elements
}
}
}
});
}
// =========================
// 備用方案
// =========================
return formatResponse({
message: {
text: rawOutput || “沒有可用的回應。”
}
});
我的問題
- 我想要讓對話進行,並讓 AI 代理自行搜尋並提供結果。
- 目前它只能根據按鈕點擊和承載值來運作。
- 在使用者點擊程式詳細資訊後,AI 將只為該套餐擷取資料並進行對話。
為了讓所有功能都能運作,請建議我如何制定工作流程、如何設計系統,我需要使用多少個 AI 代理,以及如何告訴工作流程在何時使用哪個工具?
請幫助我進行腦力激盪或提供指引,非常感謝。



