Skip to main content

การจำแนกเจตนาข้อความด้วย AI

ภาพรวม

นอกจากการตอบกลับตามคีย์เวิร์ดแบบตรงตัว ระบบยังรองรับ chatbot ที่เข้าใจ เจตนา (intent) ของผู้ใช้ งานนี้ทำหน้าที่รับข้อความจากผู้ใช้แล้วจำแนกว่าเป็น intent ใด ผ่านการประมวลผล 3 เฟส (คีย์เวิร์ด → vector → LLM) จากนั้นส่งต่อให้ response sender ตอบกลับตาม intent ที่จับได้

งานนี้ทำงานเป็นส่วนหนึ่งของ workflow โดย trigger rule ที่มี source_type = 'message_received' จะถูกจัดกลุ่มตาม workflow_id และทำการจำแนก 1 ครั้งต่อ 1 workflow

Business Flow

  1. รับ payload ที่ประกอบด้วย lineUserId, lineOaId, organizationId, messageText, messageType, replyToken และ timestamp
  2. โหลด trigger_rule ของคู่ (lineOaId, organizationId) ที่มี source_type='message_received', enabled=true และยังไม่ถูกลบ หากไม่พบเลยก็จบงาน
  3. จัดกลุ่ม rule ตาม workflow_id โดยรักษาลำดับ insertion ให้ตรงกับพฤติกรรมของ JS Map แล้ววนเรียก classifyAndRoute
  4. อ่าน config ของ classifier จาก sourceConfig ของ rule ตัวแรก ได้แก่ intents, fallbackIntentId, confidenceThreshold (ค่า default 0.3) และ conversationMemory
  5. แยก intent ออกเป็น 2 ชนิดคือ keyword และ ai
  6. โหลดประวัติการสนทนา หากเปิดใช้ memory จะดึงจาก Redis list ของคู่ line OA และ line user สูงสุดตาม maxMessages (default 10) แล้วกลับลำดับให้เรียงจากเก่าไปใหม่
  7. จำแนก intent 3 เฟส
    • เฟสที่ 1 — Keyword: matchKeyword เทียบข้อความกับคีย์เวิร์ดของแต่ละ intent หากตรงจะได้ confidence เท่ากับ 1.0 และจบทันที เป็นเส้นทางที่ถูกและเร็วที่สุด
    • เฟสที่ 2 — Vector: เทียบ embedding ของข้อความกับ intentVectors ที่เก็บไว้ใน config ด้วย cosine similarity หากผ่าน threshold ก็ใช้ผลนั้นเลย
    • เฟสที่ 3 — AI: เรียก LLM ผ่าน aix ซึ่งอ่านค่า ai_config แยกตาม OA และ provider ให้จำแนก intent พร้อมค่า confidence หากได้ค่าต่ำกว่า threshold จะใช้ fallbackIntentId แทน
  8. เมื่อได้ intent แล้วจะ route ไปยัง ResponseSenderService.SendResponse ซึ่งรองรับหลายโหมด
    • ตอบด้วยข้อความธรรมดา, rich message หรือ flex message ตามที่กำหนดไว้
    • โหมด ai_knowledge จะค้น knowledge base ด้วย Meilisearch ร่วมกับ vector โดยใช้พารามิเตอร์ topK, semanticRatio, directAnswer และ directAnswerThreshold แล้วให้ LLM สรุปคำตอบ
    • แนบ quick reply chip, resolve merge tag กลุ่ม custom และห่อ URL ในคำตอบด้วย tracking redirect เมื่อเปิด tracking.enabled
    • เก็บคำตอบของ assistant กลับลง memory ผ่าน storeAssistantMemory
  9. บันทึกผลการทำงานลง trigger_log ผ่าน TriggerLogger
note

queue message_received_trigger เป็น queue เดียวในระบบที่ ไม่ถูก monitor DLQ กล่าวคือมีการ assert topology ไว้แต่ไม่ได้ subscribe queue .dlq ของมัน

ไฟล์และฟังก์ชันหลัก

  • internal/messagetrigger/service.go
    • MessageTriggerService.ProcessMessage(ctx, payload) — entry point
    • fetchMessageReceivedRules(), classifyAndRoute(), matchKeyword(), parseClassificationResult(), cosineSimilarity(), decodeIntents()
    • struct MessageReceivedPayload, classificationResult, IntentDefinition, ConversationEntry
  • internal/messagetrigger/response_sender.go
    • ResponseSenderService.SendResponse(ctx, params)
    • applyTracking(), loadMergeUser(), storeAssistantMemory(), appendQuickReply()
    • IntentResponseConfig ซึ่งมีฟิลด์ Extra เก็บ knowledgeBaseId, retrievalConfig และ tracking
  • internal/messagetrigger/prompts.go — prompt template ของ classifier และของการตอบคำถาม
  • internal/messagetrigger/transform.go — การแปลง message object
  • internal/messagetrigger/consumer.goConsumer.HandleMessageReceived
  • internal/aix/aix.go — LLM client โดยมี ConfigResolver อ่าน config จากตาราง ai_config
  • internal/embedx/embedx.go — เรียก embedding API และ internal/meilix/meilix.go — Meilisearch client
  • Queue: message_received_trigger (profile main)

จุดเชื่อมต่อกับ Service อื่น

  • รับ job จาก: handler ของ line_webhook เมื่อ priority เป็น ai_classifier_only หรือจาก การตอบกลับอัตโนมัติตามคีย์เวิร์ด เมื่อ fallbackToAi = true
  • ตารางที่เกี่ยวข้อง: trigger_rule (config ของ classifier), ai_config (provider, model และ api key แยกตาม OA), knowledge_chunk และ knowledge_document (สำหรับตอบจาก knowledge base), trigger_log, line_user
  • Redis: list เก็บ conversation memory แยกตามคู่ line OA และ line user
  • บริการภายนอก: LLM provider ตามที่ตั้งใน ai_config, Embedding API (EMBEDDING_API_URL) และ Meilisearch (MEILISEARCH_HOST)
  • LINE API: reply และ push ข้อความคำตอบกลับผู้ใช้
  • เชื่อมกับ: การทำดัชนีฐานความรู้ ในฐานะแหล่งข้อมูลที่ใช้ตอบ และ action executor ซึ่งใช้ response sender ตัวเดียวกันซ้ำในบริบทของ action send_message