Skip to main content

การตอบกลับอัตโนมัติตามคีย์เวิร์ด

ภาพรวม

เมื่อผู้ใช้พิมพ์ข้อความเข้ามา ระบบจะนำข้อความนั้นไปเทียบกับคีย์เวิร์ดที่แอดมินตั้งไว้ หากตรงกัน จะตอบกลับด้วย rich message ที่ผูกไว้ทันที

ฟีเจอร์นี้เป็นหนึ่งในงานที่ต้องเร็วที่สุดของระบบ เพราะผู้ใช้กำลังรอคำตอบอยู่หน้าจอ จึงออกแบบให้ การเทียบคีย์เวิร์ดอ่านจาก Redis hash เท่านั้น โดยไม่แตะฐานข้อมูล พร้อมมี cron sync คีย์เวิร์ด จาก DB ลง Redis ทุก 5 นาที และมีกลไก lazy-warm เมื่อ cache เย็น เพื่อแก้ปัญหาคลาสสิกที่ "ข้อความแรกหลัง restart ไม่ได้รับการตอบกลับ"

Business Flow

  1. รับ payload ที่ประกอบด้วย keyword, lineOaId, organizationId, lineUserId, replyToken, payload และฟิลด์ทางเลือก fallbackToAi, messageText, timestamp
  2. เทียบคีย์เวิร์ดด้วยคำสั่ง HGET บน Redis hash ของ OA นั้น
  3. Lazy warm — ถ้าไม่พบคีย์เวิร์ด ระบบจะตรวจต่อว่า key ทั้งก้อนหายไปเลยหรือไม่ (HGETALL แล้วว่าง)
    • ถ้า key หายทั้งก้อน แปลว่า cache เย็น จะ sync คีย์เวิร์ดของ OA นั้นจาก DB ทันทีแล้วลองใหม่
    • ถ้า key มีอยู่แต่ไม่มีคีย์เวิร์ดนี้ แปลว่าแอดมินไม่ได้ตั้งไว้ จึงไม่ต้อง warm ซ้ำทุกข้อความ
  4. กรณีไม่พบคีย์เวิร์ด
    • ถ้า fallbackToAi = true (โหมด auto_response_first) จะ publish เข้า queue message_received_trigger เพื่อให้ AI classifier รับช่วงต่อ
    • ถ้าไม่ใช่ ก็จบงานและ ack
  5. กรณีพบคีย์เวิร์ด — ค่าที่เก็บใน 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
  6. กลยุทธ์การส่ง ซึ่งปรับปรุงจากระบบเดิมที่ใช้ reply อย่างเดียว
    • เมื่อมี replyToken จะใช้ replyMessage ก่อน หาก reply ล้มเหลว เช่น token หมดอายุเพราะ ประมวลผลช้า จะ fallback ไปใช้ pushMessage เพื่อให้ผู้ใช้ได้รับคำตอบอยู่ดี
    • เมื่อไม่มี replyToken ซึ่งเกิดกับ standby event ที่ LINE ไม่ออก token ให้ จะใช้ pushMessage เฉพาะเมื่อ OA เปิด flag pushOnStandby ใน message_handling_config
  7. บันทึก 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.go
    • Service.ProcessAutoResponse(ctx, payload) — flow ทั้งหมดของฟีเจอร์
    • getRedisKey() ที่สร้าง key รูปแบบ AUTO_RESPONSE:LINE_OA_ID: ตามด้วย id, buildTrackingPayload(), attachQuickReplyAny(), standbyPushEnabled()
    • interface แคบสำหรับ dependency: RichMessageFinder, LineOaFinder, LineUserFinder, QuickReplyLoader
  • internal/autoresponse/transform.gotransformMessageObjects(), resolveMergeTags(), hasMergeTags()
  • internal/autoresponse/consumer.goConsumer.OnProcessAutoResponse
  • internal/cronscheduler/auto_response_sync.goAutoResponseSyncService.Run(), SyncKeywordsForLineOa() และ prefix LINE_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 (profile main)

จุดเชื่อมต่อกับ 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