การตอบกลับอัตโนมัติตามคีย์เวิร์ด
ภาพรวม
เมื่อผู้ใช้พิมพ์ข้อความเข้ามา ระบบจะนำข้อความนั้นไปเทียบกับคีย์เวิร์ดที่แอดมินตั้งไว้ หากตรงกัน จะตอบกลับด้วย rich message ที่ผูกไว้ทันที
ฟีเจอร์นี้เป็นหนึ่งในงานที่ต้องเร็วที่สุดของระบบ เพราะผู้ใช้กำลังรอคำตอบอยู่หน้าจอ จึงออกแบบให้ การเทียบคีย์เวิร์ดอ่านจาก Redis hash เท่านั้น โดยไม่แตะฐานข้อมูล พร้อมมี cron sync คีย์เวิร์ด จาก DB ลง Redis ทุก 5 นาที และมีกลไก lazy-warm เมื่อ cache เย็น เพื่อแก้ปัญหาคลาสสิกที่ "ข้อความแรกหลัง restart ไม่ได้รับการตอบกลับ"
Business Flow
- รับ payload ที่ประกอบด้วย
keyword,lineOaId,organizationId,lineUserId,replyToken,payloadและฟิลด์ทางเลือกfallbackToAi,messageText,timestamp - เทียบคีย์เวิร์ดด้วยคำสั่ง
HGETบน Redis hash ของ OA นั้น - Lazy warm — ถ้าไม่พบคีย์เวิร์ด ระบบจะตรวจต่อว่า key ทั้งก้อนหายไปเลยหรือไม่ (
HGETALLแล้วว่าง)- ถ้า key หายทั้งก้อน แปลว่า cache เย็น จะ sync คีย์เวิร์ดของ OA นั้นจาก DB ทันทีแล้วลองใหม่
- ถ้า key มีอยู่แต่ไม่มีคีย์เวิร์ดนี้ แปลว่าแอดมินไม่ได้ตั้งไว้ จึงไม่ต้อง warm ซ้ำทุกข้อความ
- กรณีไม่พบคีย์เวิร์ด
- ถ้า
fallbackToAi = true(โหมดauto_response_first) จะ publish เข้า queuemessage_received_triggerเพื่อให้ AI classifier รับช่วงต่อ - ถ้าไม่ใช่ ก็จบงานและ ack
- ถ้า
- กรณีพบคีย์เวิร์ด — ค่าที่เก็บใน Redis คือ JSON ที่มีฟิลด์
richMessageIdและautoResponseId- โหลด
rich_messageตาม id โดย scope ด้วยlineOaId - ตรวจสอบว่า OA ยังมีสถานะ
activeหากไม่ใช่จะคืนmq.Permanent(จัดเป็น error กลุ่ม 400) แล้วเข้า DLQ transformMessageObjectsแปลงเนื้อหาให้เป็น LINE message object- หากพบ merge tag เช่น
{{display_name}}หรือ{{custom.xxx}}จะโหลดline_userมา resolve ค่า - แนบ quick reply หาก rich message ผูก
quick_reply_idไว้ กรณีโหลดไม่สำเร็จจะส่งข้อความต่อ โดยไม่มี chip
- โหลด
- กลยุทธ์การส่ง ซึ่งปรับปรุงจากระบบเดิมที่ใช้ reply อย่างเดียว
- เมื่อมี
replyTokenจะใช้replyMessageก่อน หาก reply ล้มเหลว เช่น token หมดอายุเพราะ ประมวลผลช้า จะ fallback ไปใช้pushMessageเพื่อให้ผู้ใช้ได้รับคำตอบอยู่ดี - เมื่อไม่มี
replyTokenซึ่งเกิดกับ standby event ที่ LINE ไม่ออก token ให้ จะใช้pushMessageเฉพาะเมื่อ OA เปิด flagpushOnStandbyในmessage_handling_config
- เมื่อมี
- บันทึก tracking โดย publish เข้า
tracking_logด้วยcontent_type = auto_response,action_type = sendและlogEventType = webhook
Cron sync คีย์เวิร์ด (profile cron-scheduler)
ทุก 5 นาที (*/5 * * * *) AutoResponseSyncService.Run จะดึง OA ที่มีสถานะ active ทั้งหมด
แล้ว rebuild Redis hash ของแต่ละ OA ใหม่ หาก OA ใด sync ไม่สำเร็จ จะ continue ไปตัวถัดไป
แทนที่จะ return เพราะ OA เดียวที่มี config ขนาดใหญ่หรือเสียหายต้องไม่ทำให้คีย์เวิร์ดของ OA
ที่เหลือเย็นทั้งระบบ
ไฟล์และฟังก์ชันหลัก
internal/autoresponse/service.goService.ProcessAutoResponse(ctx, payload)— flow ทั้งหมดของฟีเจอร์getRedisKey()ที่สร้าง key รูปแบบAUTO_RESPONSE:LINE_OA_ID:ตามด้วย id,buildTrackingPayload(),attachQuickReplyAny(),standbyPushEnabled()- interface แคบสำหรับ dependency:
RichMessageFinder,LineOaFinder,LineUserFinder,QuickReplyLoader
internal/autoresponse/transform.go—transformMessageObjects(),resolveMergeTags(),hasMergeTags()internal/autoresponse/consumer.go—Consumer.OnProcessAutoResponseinternal/cronscheduler/auto_response_sync.go—AutoResponseSyncService.Run(),SyncKeywordsForLineOa()และ prefixLINE_MANAGEMENT:AUTO_RESPONSE:LINE_OA_ID:cmd/worker/integration.go— จุด wiring ของlineOaForAutoResponse,lineUserFinder,quickReplyForAutoResponse- Queue: consume
line_auto_responseแล้ว publish ต่อไปยังmessage_received_triggerและtracking_log(profilemain)
จุดเชื่อมต่อกับ Service อื่น
- รับ job จาก: handler ของ
line_webhookภายใน worker เมื่อได้รับ message event ประเภท text - Redis (ส่วนสำคัญที่สุด): hash ชื่อ
LINE_MANAGEMENT:AUTO_RESPONSE:LINE_OA_ID:ตามด้วย line OA id โดย field คือคีย์เวิร์ด และ value คือ JSON ที่มีrichMessageIdและautoResponseId - ตารางที่เกี่ยวข้อง:
auto_response(แหล่งคีย์เวิร์ดที่ cron นำมา sync),rich_message,line_oa(สถานะ, token และmessage_handling_config.pushOnStandby),line_user(สำหรับ merge tag) และกลุ่มตาราง quick reply - LINE API:
POST /v2/bot/message/replyและPOST /v2/bot/message/push - เชื่อมต่อกับ: การจำแนกเจตนาข้อความด้วย AI ในฐานะ fallback และเส้นทาง tracking log