負責任地經營成人聊天機器人產品:開發者檢查清單
成人聊天機器人是一個真正的產品,而真正的產品承擔著責任。API 提供一個不會拒絕合法成人內容的模型,這意味著年齡檢查、內部規則、舉報和濫用控制都位於你的應用程式中,而非模型中。這份檢查清單將透過實際程式碼逐步說明每一層,讓你能夠自信地上線。
已更新
重點
- 平台僅限成人;在你的入口處驗證年齡,並將檢查保留在伺服器端。
- 撰寫你自己的內容政策和舉報路徑,因為模型的開放性並不能取代你的規則。
- 涉及未成年人的性內容一律遭封鎖(403);為此設計清晰、平靜的使用體驗。
- 限制每位使用者的用量,並將 API 金鑰保留在你的伺服器上;單一金鑰處理所有流量。
誰負責什麼
將堆疊視為兩層。API 為 18 歲以上使用者提供合法成人內容、小說與爭議性主題,且不會拒絕。模型周邊的一切——誰能存取、他們同意的規則以及出錯時發生什麼事——都由你負責。這種分工令人感到自由,但前提是你必須認真對待自己的那部分。
這裡有一個簡短的責任表格供你張貼在牆上。
| 關注事項 | 平台 | 你的應用程式 |
|---|---|---|
| 涉及未成年人的性內容 | 一律遭封鎖(403) | 解釋、結束場景、防止繞過 |
| 使用者的年齡 | 依條款僅限成人 | 在入口處進行把關與驗證 |
| 法律之外的內部規則 | 未套用 | 撰寫、發布並執行 |
| 每位使用者的濫用行為 | 每個金鑰每分鐘 300 次請求 | 每位使用者和每日限制 |
| 金鑰 | 簽發 | 保留在你的伺服器上 |
這是工程指導,並非法律建議;規則因地區而異,請檢查使用者所在地的要求。
真正有效的年齡限制
"我年滿 18 歲"按鈕的橫幅是最低要求,而意志堅定的未成年人仍可以點擊它。這仍然很重要,因為它記錄了肯定的聲明,並讓你的政策保持誠實。關鍵在於你執行規則的地方。如果檢查僅在瀏覽器中隱藏聊天,任何人都可以直接呼叫你的端點。讓伺服器在存在已簽署的標記之前拒絕回應。
import crypto from "node:crypto";
// Minimal 18+ gate: the user must confirm before the chat routes work.
// Replace the confirmation with a real verification step when your market requires it.
const SECRET = process.env.GATE_SECRET; // random string kept on the server
function sign(value) {
return crypto.createHmac("sha256", SECRET).update(value).digest("hex");
}
export function issueAdultCookie(res, userId) {
const stamp = String(Date.now());
const payload = `${userId}.${stamp}`;
res.cookie("adult_ok", `${payload}.${sign(payload)}`, {
httpOnly: true, sameSite: "strict", secure: true, maxAge: 30 * 24 * 3600 * 1000,
});
}
export function requireAdult(req, res, next) {
const raw = req.cookies?.adult_ok || "";
const [userId, stamp, sig] = raw.split(".");
if (!sig || sign(`${userId}.${stamp}`) !== sig) {
return res.status(403).json({ state: "age_required" });
}
req.userId = userId;
next();
}在每個聊天路由前方加入 requireAdult。根據你的市場或風險等級加入更嚴格的驗證機制,例如第三方年齡驗證,並確保標記的有效期足夠短,以便你重新提示。在行銷中不要鎖定學生或學校,並將檢查機制放在任何成人內容顯示之前,包括預覽和範例對話。
撰寫你自己的內容政策
模型不會拒絕合法的成人內容,因此由你決定產品允許什麼。一份單頁政策就足夠了。涵蓋歡迎的內容、在你的社群中即使合法也不允許的內容(例如騷擾真實人物或人肉搜尋)、使用者如何舉報問題,以及你會採取的行動:警告、暫時禁言、封鎖。
- 在用戶註冊時以淺顯易懂的語言發布。
- 將其複製到你的系統提示詞中。 例如「所有角色均為成年人;若場景變得非自願或涉及真實具名人士,請結束該場景」,這樣可讓機器人符合你的規則。
- 讓執行機制變得無趣。 事先決定閾值,讓審核人員不必臨場發揮。
- 每季檢視一次政策,隨著產品演進進行調整。
讓使用者能找到的舉報路徑
為每則訊息提供小型回報控制項,並使其在無需登入繞道的情况下運作。當有人回報回覆時,擷取執行動作所需的最小資訊:使用者 ID、訊息 ID、簡短原因和時間戳記。將其路由到你審核人員監控的佇列中。
app.post("/api/report", requireAdult, express.json(), (req, res) => {
const { messageId, reason } = req.body;
// Store only what you need to act on: who, which message, why, when.
queueForModerator({ userId: req.userId, messageId, reason: String(reason).slice(0, 500), at: Date.now() });
res.json({ ok: true });
});保持你的承諾範圍狹窄。告訴使用者舉報會觸發什麼,並且只儲存你的政策和適用規則所要求的資料。檢視你保留舉報的時間,並按計畫刪除它們。確認每份舉報給提交者,即使只有一行感謝,因為當似乎沒有任何事情發生時,使用者就會停止舉報。追蹤審核人員關閉項目的速度,並設定一個你實際能達成的目標。
為 403 未成年人區塊進行設計
涉及未成年人的性內容一律會被封鎖,小說和角色扮演也不例外,API 會回傳 403 狀態碼與程式碼 content_blocked。不要重試,也不要替使用者重新措辭。相反地,應將其視為一個值得清晰設計的產品時機。
- 在伺服器上將其翻譯為你 UI 能識別的狀態,這樣原始上游文字就不會顯示在螢幕上。
- 用一句平靜的話說明發生了什麼事並點出規則。
- 結束或重置場景。 提供「繼續」選項會破壞其要點。
- 記錄事件並附上使用者 ID,以便重複嘗試時觸發你自己的執行機制。
- 不要猜測意圖。某些封鎖來自含糊的措辭;中性訊息可同時適用於兩種情況。
// server: translate upstream outcomes into states your UI understands
if (upstream.status === 403) {
return res.status(403).json({
state: "content_blocked",
message: "That request breaks our rules, so we can't continue this scene.",
});
}
if (upstream.status === 402) return res.status(503).json({ state: "paused" });
if (upstream.status === 503) return res.status(503).json({ state: "busy" });// browser: show a calm, specific message for each state
const MESSAGES = {
content_blocked: "This scene can't continue. Sexual content involving minors is never allowed. Start a new chat any time.",
age_required: "Please confirm you are 18 or older to use the chat.",
slow_down: "You're sending messages quickly. Give it a few seconds.",
daily_limit: "You've reached today's message allowance. Come back tomorrow.",
paused: "Chat is briefly unavailable. We're on it.",
busy: "The service is busy. Try again in a moment.",
};
async function send(messages) {
const res = await fetch("/api/chat", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ messages }),
});
if (!res.ok) {
const info = await res.json().catch(() => ({}));
showBanner(MESSAGES[info.state] || "Something went wrong.");
if (info.state === "content_blocked") endCurrentScene();
return null;
}
return res;
}
每個使用者的濫用與速率控制
你的單一 API 金鑰總共允許每分鐘 300 次請求,由所有使用者共用。一個腳本帳戶可能會導致其他使用者資源匱乏,因此你必須自行執行公平使用限制,且遠低於該上限。此範例將每個使用者限制為每分鐘 12 則訊息,並根據最終串流區塊中的 usage 數字,為每個使用者提供每日 token 預算。
const WINDOW_MS = 60_000;
const PER_USER_PER_MIN = 12; // your product rule, far below the key's 300
const DAILY_TOKEN_BUDGET = 60_000; // per user, tracked from the usage chunk
const hits = new Map(); // userId -> array of timestamps
const spent = new Map(); // userId -> tokens used today
export function userLimit(req, res, next) {
const now = Date.now();
const recent = (hits.get(req.userId) || []).filter((t) => now - t < WINDOW_MS);
if (recent.length >= PER_USER_PER_MIN) {
return res.status(429).json({ state: "slow_down" });
}
if ((spent.get(req.userId) || 0) >= DAILY_TOKEN_BUDGET) {
return res.status(429).json({ state: "daily_limit" });
}
recent.push(now);
hits.set(req.userId, recent);
next();
}
export function recordUsage(userId, totalTokens) {
spent.set(userId, (spent.get(userId) || 0) + totalTokens);
}對於生產環境,請將計數器儲存在共用儲存區而非程序記憶體中,以便在重新啟動後維持限制,並在多個伺服器之間運作。在每個請求中加入適度的 max_tokens 以限制最壞情況,並留意自己帳戶餘額的 402 錯誤。7 天 $0.50 的免費試用額度是測試這些控制機制的好方法,之後再導入真實流量。
將金鑰保留在伺服器上
不要將金鑰發布在前端套件、行動應用程式或公開儲存庫中。將其儲存為環境變數或存放在機密管理器中,僅在你的後端載入,並將其排除在日誌和錯誤報告之外。如果你懷疑金鑰已洩露,請從你的帳戶重新產生它;舊金鑰會立即失效,因此請準備好部署。記住每個帳戶只有一個金鑰,這使得乾淨的代理層變得更具價值。網頁聊天教學展示了端到端的模式,文件列出了你的包裝程式應對應的錯誤代碼。
上線前檢查清單
在開放營運的前一天,逐一檢查此清單。每個項目只需幾分鐘,即可防止一類在用戶到達後難以修復的問題。
- 嘗試破壞把關機制。 使用 curl 呼叫你的聊天路由且不带 cookie。它必須以
age_required回應 403,而不是模型回覆。 - 觸發每個狀態。 模擬上游依序返回 402、403、429 和 503,並確認每個狀態都顯示正確的橫幅,且從未洩露原始錯誤文字。
- 大聲朗讀你自己的政策。 如果審核人員無法在一分鐘內根據它決定案例,請收緊措辭。
- 從手機螢幕測試回報按鈕。難以觸及的控制項不算作回報路徑。
- 在你的儲存庫中搜尋金鑰。 查看前端資料夾、建置輸出、範例設定和提交歷史記錄。如果在任何公開位置找到它,請重新產生它。
- 設定警示。當出現 402 錯誤、單一使用者的 403 封鎖激增或每日 token 使用量跳升時,請自行通知自己。
- 準備暫停開關。 一個能優雅關閉聊天的單一旗標在事故期間非常有價值。
安全永遠沒有完成的一天,清單也是;每次事故教會你新事物時,就新增項目,並與接下來加入團隊的任何人分享。當你新增功能(例如在你自己的 UI 中上傳圖片、團體房間或公開角色分享)時,請重新檢視清單,因為每個功能都會為濫用開啟新的路徑。若要協助塑造角色本身,請閱讀 角色設計指南,並隨著團隊成長,將 文件中的整合筆記基礎保持在手邊。
問答
勾選方塊足以作為年齡驗證嗎?
這是最低要求,僅記錄聲明,但很容易被繞過。請在伺服器端執行,並根據你的風險或當地法規要求,加入更強化的驗證機制。
當出現 403 content_blocked 時,我的應用程式該怎麼辦?
不要重試。將其翻譯為應用程式內的平靜訊息,結束或重置場景,並記錄事件以供你自己的執行機制使用。
我可以讓使用者公平地共用我的 API 金鑰容量嗎?
可以,透過在你的伺服器上設定每使用者速率和每日 token 限制來達成。金鑰本身的總請求限制為每分鐘 300 次。
模型會執行我的內部規則嗎?
不會。它不會拒絕合法的成人內容,因此你的政策、系統提示詞和審核流程必須完成這項工作。