Unknown เป็นข้อผิดพลาดหรือเป็นผลลัพธ์?
เมื่อคุณเริ่มจำแนก interaction เป็น Human, Human + AI, Agent หรือ Unknown มักจะพบว่า bucket ของ Unknown มีขนาดใหญ่กว่าที่คนคาดไว้ เป็นเรื่องน่าล่อลวงที่จะมองว่านี่คือช่องว่างที่ต้องซ่อน ไม่ว่าจะโดยรวม Unknown เข้าเป็น Human หรือมองว่ามันน่าสงสัย ทั้งสองแบบก่อปัญหา
Unknown หมายความว่าหลักฐานที่มีอยู่ยังไม่พอสำหรับการตัดสินที่เชื่อถือได้ คำขอจาก client ที่ไม่รัน JavaScript, การเรียกไปยัง endpoint ที่คุณไม่เก็บสัญญาณใดๆ, session ที่จบลงหลังเพียงหนึ่งหน้า: ทั้งหมดนี้อาจถูกต้องโดยสมบูรณ์ และไม่มีข้อใดให้ข้อมูลพอที่จะบอกได้ว่าใครหรืออะไรเป็นผู้กระทำ
การรายงาน Unknown อย่างตรงไปตรงมาคือสิ่งที่ทำให้ class อื่นๆ น่าเชื่อถือ หากระบบของคุณไม่เคยบอกว่า Unknown ผลลัพธ์ Human ทุกครั้งก็จะเป็นการเดาบางส่วน และคุณจะบอกไม่ได้ว่าส่วนไหนเป็นส่วนไหน บทความของเราที่ว่า ทำไม Unknown จึงเป็นผลลัพธ์ที่ถูกต้องเมื่อจำแนกทราฟฟิกของ AI อธิบายเหตุผลเชิงลึกไว้แล้ว
คู่มือนี้ครอบคลุมวิธีจัดการ Unknown ในทางปฏิบัติ: fallback แบบชัดเจนแยกตาม route กฎที่ป้องกันไม่ให้มันไหลไปเป็น class อื่น วิธีติดตามมัน และวิธีลดมันในจุดที่สำคัญ
ขั้นที่ 1: อย่าตั้ง Human เป็นค่าเริ่มต้น
ความผิดพลาดที่พบบ่อยที่สุดคือฟังก์ชันจำแนกที่คืนค่า Human เมื่อไม่พบสัญญาณของระบบอัตโนมัติ ดูเหมือนสมเหตุสมผล แต่ไม่ถูกต้อง การไม่มีสัญญาณของ bot ไม่ได้แปลว่ามีสัญญาณของมนุษย์
// Wrong: silence becomes Human
function classifyWrong(e: Evidence) {
if (e.signatureValid) return { actor: "agent", basis: "verified" };
if (e.declaredAgent) return { actor: "agent", basis: "declared" };
return { actor: "human", basis: "inferred" };
}
// Right: Human requires positive evidence, otherwise Unknown
function classify(e: Evidence) {
if (e.signatureValid) return { actor: "agent", basis: "verified" };
if (e.declaredAgent) return { actor: "agent", basis: "declared" };
if (e.interactiveSession) return { actor: "human", basis: "inferred" };
return { actor: "unknown", basis: "unknown" };
}ใช้กฎเดียวกันนี้ทุกที่ที่มีการสร้างผลลัพธ์: timeout, ข้อผิดพลาด, cache ที่เก่า และ telemetry ที่หายไป ล้วนต้องให้ผลเป็น Unknown เขียน test สำหรับแต่ละเส้นทางเหล่านี้เพื่อไม่ให้พฤติกรรมถดถอยแบบเงียบๆ ตัวอย่างด้านล่างใช้ Node.js test runner ที่มีมาในตัว
import { test } from "node:test";
import assert from "node:assert/strict";
test("missing evidence is unknown, not human", () => {
const r = classify({ signatureValid: false, declaredAgent: false, interactiveSession: false });
assert.equal(r.actor, "unknown");
});ขั้นที่ 2: กำหนด fallback แบบชัดเจนให้ทุก route
Unknown ต้องมีพฤติกรรมที่กำหนดไว้ และพฤติกรรมที่เหมาะสมขึ้นอยู่กับ route ตัดสินใจเป็นราย route เขียนลงไป และเก็บไว้ใน configuration สำหรับวิธีที่ fallback เหล่านี้เข้ากับโมเดล policy ที่กว้างกว่า ดูที่ การออกแบบ policy ระดับแอปสำหรับมนุษย์และเอเจนต์ AI
| ประเภท route | ตัวอย่าง | Fallback ที่เหมาะสมสำหรับ Unknown |
|---|---|---|
| เนื้อหาสาธารณะ | หน้า marketing, docs | อนุญาต, response มาตรฐาน |
| ข้อมูลแบบอ่านอย่างเดียว | catalog, search API | อนุญาตพร้อม rate limit มาตรฐาน |
| การสร้างบัญชี | signup | ใช้การตรวจสอบที่มีอยู่, มีคิวตรวจสอบเพิ่มเติมได้ |
| การเปลี่ยนแปลงที่อ่อนไหว | รหัสผ่าน, อีเมล, รายละเอียดการเรียกเก็บเงิน | ใช้การยืนยันตัวตนซ้ำตามเดิม, ไม่ผ่อนคลาย |
| การกระทำที่มีความสำคัญสูง | bulk export, การทำงานของ admin | ใช้การอนุญาตระดับเข้มที่มีอยู่เดิม |
รูปแบบนี้เรียบง่าย สำหรับ route ที่มีความเสี่ยงต่ำ Unknown จะทำงานเหมือนทราฟฟิกปกติ สำหรับ route ที่มีความเสี่ยงสูง Unknown จะได้รับการป้องกันเหมือนที่ route นั้นมีอยู่แล้ว ในทั้งสองกรณี actor result จะไม่ทำให้สถานการณ์แย่ลงสำหรับผู้ใช้ที่ยังไม่ถูกจำแนกแต่ใช้งานโดยชอบ
type Fallback = "allow" | "standard_limit" | "existing_checks" | "review";
const unknownFallback: Record<string, Fallback> = {
"GET /docs/*": "allow",
"GET /api/catalog": "standard_limit",
"POST /signup": "existing_checks",
"POST /account/password": "existing_checks",
"POST /exports": "review",
};ขั้นที่ 3: จัดการ timeout และข้อผิดพลาดด้วยวิธีเดียวกัน
การประเมิน actor อยู่บนเส้นทางของ request จึงต้องมีกรอบเวลาที่เข้มงวด เมื่อใช้เวลาเกินกรอบ ให้ส่งผลเป็น Unknown และใช้ fallback ของ route อย่าบล็อก request เพราะการประเมินช้าเกินไป
async function withBudget<T>(work: Promise<T>, ms: number, onTimeout: T): Promise<T> {
let timer: NodeJS.Timeout;
const timeout = new Promise<T>((resolve) => {
timer = setTimeout(() => resolve(onTimeout), ms);
});
try {
return await Promise.race([work, timeout]);
} finally {
clearTimeout(timer!);
}
}
const result = await withBudget(evaluateActor(req), 150, { actor: "unknown", basis: "unknown" });บันทึกเหตุผลที่ทำให้ผลลัพธ์เป็น Unknown: ไม่มีหลักฐาน, timeout, ข้อผิดพลาดในการประเมิน หรือหลักฐานที่เก่า เหตุผลเหล่านี้จะบอกคุณว่าต้องแก้ตรงไหน
ขั้นที่ 4: อย่ามอง Unknown ว่าน่าสงสัย
Unknown ไม่ใช่คะแนนความเสี่ยง client ที่ใช้งานได้ถูกต้องตามปกติหลายประเภทจะเป็น Unknown เสมอบนบาง route เช่น เครื่องมือบรรทัดคำสั่ง, integration ฝั่งเซิร์ฟเวอร์ที่ไม่มีลายเซ็น, เครื่องมือเพื่อการเข้าถึง, browser ที่เน้นความเป็นส่วนตัว และ feed reader แบบง่าย แม้แต่ผู้ให้บริการ AI ขนาดใหญ่ในปัจจุบันก็ระบุ fetcher ของตนหลักๆ ด้วย user agent และช่วง IP ที่เผยแพร่ไว้ เอกสาร crawler ของ OpenAI ตัวอย่างเช่น ระบุ user agent string และไฟล์ที่เผยแพร่ IP address สำหรับ bot แต่ละตัว ณ เดือนพฤศจิกายน 2026
ถ้าคุณต้องการตอบสนองต่อพฤติกรรมที่น่าสงสัย ให้ยึดตามพฤติกรรมที่คุณอธิบายได้ เช่น อัตราการ request, รูปแบบการเข้าสู่ระบบที่ล้มเหลว หรือรายงานการละเมิด โดยมีหลักฐานของมันเอง แยก logic นี้ออกจาก actor class เพื่อไม่ให้ทั้งสองส่วนบิดเบือนกัน
ขั้นที่ 5: จะติดตามอัตรา Unknown ของคุณอย่างไร?
อัตรา Unknown คือสัดส่วนของ interaction ที่ถูกจำแนกเป็น Unknown ติดตามแยกตาม route, ตามบริบทของ integration และตามช่วงเวลา นี่เป็นหนึ่งในตัวชี้วัดสุขภาพที่มีประโยชน์ที่สุดที่คุณมี
type Row = { route: string; actor: string };
export function unknownRate(rows: Row[]) {
const byRoute = new Map<string, { total: number; unknown: number }>();
for (const r of rows) {
const s = byRoute.get(r.route) ?? { total: 0, unknown: 0 };
s.total += 1;
if (r.actor === "unknown") s.unknown += 1;
byRoute.set(r.route, s);
}
return [...byRoute].map(([route, s]) => ({ route, rate: s.unknown / s.total, total: s.total }));
}ตัวเลขบอกอะไรกับคุณบ้าง:
- อัตราสูงที่คงที่บน route ใด route หนึ่ง มักหมายความว่าคุณขาดสัญญาณบางอย่างในจุดนั้น หน้าเว็บที่ไม่เคยโหลด browser integration ของคุณ หรือ API ที่ไม่เคยเห็นคำขอที่ลงลายเซ็น จะยังคงเป็น Unknown เป็นส่วนใหญ่
- การเพิ่มขึ้นอย่างฉับพลัน มักหมายความว่ามีบางอย่างเปลี่ยนไปใน stack ของคุณ เช่น release ที่ทำให้ header หาย, กฎของ CDN ที่ลบ signature header, หรือการเปลี่ยนแปลงฝั่ง frontend ที่หยุดส่งการประกาศจาก app ของคุณ
- การลดลงอย่างฉับพลัน ก็ควรตรวจสอบเช่นกัน ถ้า Unknown ลดลงในขณะที่ Human เพิ่มขึ้น ให้ยืนยันว่ามีหลักฐานใหม่เข้ามาจริง ไม่ใช่เพราะ fallback เปลี่ยนไปแบบเงียบๆ
ให้แจ้งเตือนเมื่อมีการเปลี่ยนแปลงรวดเร็ว ไม่ใช่ตามระดับสัมบูรณ์ ทุก application มีค่าปกติของตัวเอง
ขั้นที่ 6: จะลด Unknown ในจุดที่สำคัญได้อย่างไร?
คุณไม่จำเป็นต้องทำให้ Unknown เป็นศูนย์ คุณต้องมีหลักฐานเพียงพอบน route ที่การตัดสินมีความสำคัญ จัดการตามลำดับผลกระทบ:
- เพิ่มหลักฐานใน route ที่มีผลกระทบสูงก่อน ถ้าการเปลี่ยนแปลงบัญชีส่วนใหญ่เป็น Unknown นั่นคือจุดที่ browser integration หรือการตรวจฝั่งเซิร์ฟเวอร์ให้ผลคุ้มค่า
- เชิญให้ client อัตโนมัติระบุตัวตนของตนเอง เผยแพร่เอกสารสำหรับ API ของคุณที่อธิบายว่าเอเจนต์สามารถลงลายเซ็นคำขอด้วย HTTP Message Signatures และแนวปฏิบัติของ IETF Web Bot Auth ได้อย่างไร และมอบประสบการณ์ที่ดีกว่าให้ client ที่ยืนยันได้ เช่น ขีดจำกัดที่สูงขึ้นหรือ response แบบมีโครงสร้าง Client ที่ตรวจสอบได้จะเริ่มทำเช่นนั้น
- ใช้ความรู้ของ application เอง ถ้าผู้ใช้โต้ตอบกับ assistant ที่มีอยู่ในระบบของคุณ ให้บันทึกสิ่งนั้นเป็นการประกาศ แอปของคุณมักรู้มากกว่าเครือข่าย
- แก้ปัญหาท่อทางข้อมูล ตรวจสอบให้แน่ใจว่า proxy ส่งต่อ headers ที่คุณพึ่งพา และการประเมินมีกรอบเวลาเพียงพอที่จะทำงานเสร็จ
ถ้าต้องการดูอย่างเป็นรูปธรรมว่าสัญญาณใดช่วยให้ทราฟฟิกออกจาก Unknown ได้ อ่าน วิธีดูว่าเว็บทราฟฟิกมาจากเอเจนต์ AI หรือไม่
ขั้นที่ 7: แสดง Unknown อย่างตรงไปตรงมาใน dashboard
แสดง Unknown เป็นซีรีส์ของมันเองโดยมีน้ำหนักทางภาพเท่ากับ class อื่นๆ อย่าซ่อนมันไว้ใน bucket "อื่นๆ" และอย่าใช้สีแบบ alert เมื่อผู้มีส่วนได้ส่วนเสียเห็นสัดส่วน Unknown ที่มาก การตอบสนองที่ถูกต้องคือ "เราต้องการหลักฐานเพิ่มตรงไหน" ไม่ใช่ "บอทอยู่ตรงไหน"
ขั้นที่ 8: ทบทวน Unknown ด้วยผลลัพธ์ ไม่ใช่สมมติฐาน
ทุกๆ สองสามสัปดาห์ ให้สุ่มตัวอย่าง interaction ที่เป็น Unknown จาก route ที่สำคัญที่สุดของคุณ แล้วดูว่าจริงๆ แล้วเกิดอะไรขึ้น session นั้นทำการซื้อสินค้าสำเร็จ, สร้างโปรเจกต์, อ่านบทความสามบทความ, หรือเข้าสู่ระบบล้มเหลวซ้ำๆ? ผลลัพธ์จะบอกคุณได้ว่าทราฟฟิกประเภทใดอยู่ใน bucket โดยไม่ต้องรีบติดป้ายกำกับให้มัน
จัดกลุ่มสิ่งที่พบเป็นสามหมวดปฏิบัติได้จริง:
- ถูกต้องและมีความเสี่ยงต่ำ feed reader, link preview, เครื่องมือตรวจสอบ และผู้ใช้ที่ตั้งค่าความเป็นส่วนตัวไว้ เก็บ fallback ของ route ไว้เหมือนเดิม
- ระบบอัตโนมัติที่ถูกต้องซึ่งสามารถระบุตัวตนของตนเองได้ integration และเอเจนต์ที่ยินดีใช้เส้นทางแบบมีโครงสร้างหรือลงลายเซ็นคำขอถ้าคุณเสนอทางเลือกนั้น เผยแพร่แนวทางและติดต่อกลับเมื่อทำได้
- พฤติกรรมที่ต้องมีการควบคุมของตัวเอง รูปแบบ credential stuffing หรือ scraping ซึ่งถูกรวบรวมไว้ในโครงการ OWASP Automated Threats to Web Applications รับมือด้วยการควบคุมที่อาศัยพฤติกรรมและมีหลักฐานของตัวเอง เช่น อัตราความล้มเหลวในการเข้าสู่ระบบ และแยกออกจาก actor class
การทบทวนนี้ช่วยให้ fallback ของคุณยึดกับทราฟฟิกจริง และให้รายการที่ชัดเจนว่าต้องเพิ่มหลักฐานตรงไหนต่อไป
คำถามที่พบบ่อย
ควรให้นับ Unknown รวมใน rate limit หรือไม่? ใช้ขีดจำกัดมาตรฐานของคุณ การจำกัดตาม class ใช้ได้สำหรับ verified agents ซึ่งสามารถได้รับขีดจำกัดที่สูงกว่าได้ แต่ Unknown ควรได้ขีดจำกัดปกติ ไม่ใช่ขีดจำกัดเชิงลงโทษ
เราสามารถ challenge ผู้ใช้ Unknown ได้ไหม? เฉพาะในกรณีที่ route นั้น challenge ทุกคนอยู่แล้วในสถานการณ์นั้น การเพิ่ม challenge เพียงเพราะผลลัพธ์เป็น Unknown จะลงโทษผู้ใช้ที่ถูกต้องตามกฎหมายแต่ client ส่งสัญญาณน้อยกว่า
Unknown จะลดลงเมื่อมาตรฐานพัฒนาขึ้นหรือไม่? เมื่อ client อัตโนมัติมากขึ้นลงลายเซ็นในคำขอ ทราฟฟิกของเอเจนต์จะย้ายจาก Unknown หรือ declared ไปเป็น verified มากขึ้น การติดตามของคุณจะเห็นการเปลี่ยนแปลงนั้นแยกตาม route
Proof of Actor เข้ามาเกี่ยวข้องอย่างไร
Proof of Actor รายงาน Unknown เป็นผลลัพธ์ระดับแรก พร้อมเหตุผล และไม่แปลงมันเป็น Human แอปพลิเคชันของคุณเป็นผู้เลือก fallback สำหรับแต่ละ route และ analytics จะแสดงให้เห็นว่าการ coverage สิ้นสุดตรงไหน เพื่อให้คุณเพิ่มหลักฐานในจุดที่สำคัญ
หากต้องการตั้งค่านี้บน application จริงกับทีมของเรา สมัครขอสิทธิ์เข้าถึงล่วงหน้า หากต้องการเข้าใจอย่างแม่นยำว่าหลักฐานสามารถยืนยันอะไรได้บ้าง อ่าน Detection & Limitations
แหล่งอ้างอิง
- RFC 9421: HTTP Message Signatures: มาตรฐานที่ client อัตโนมัติสามารถใช้ลงลายเซ็นคำขอ
- draft-ietf-webbotauth-httpsig-protocol: ร่าง IETF Web Bot Auth สำหรับทราฟฟิกอัตโนมัติที่ลงลายเซ็น (กำลังดำเนินการ ณ เดือนพฤศจิกายน 2026)
- OpenAI: Overview of OpenAI Crawlers: user agent strings และไฟล์ที่เผยแพร่ IP address สำหรับ bot ของ OpenAI
- OWASP Automated Threats to Web Applications: การจัดหมวดหมู่ภัยคุกคามอัตโนมัติ เช่น credential stuffing และ scraping
- Node.js test runner: โมดูล
node:testที่ใช้ในตัวอย่าง