การจำแนกเจตนาข้อความด้วย AI
ภาพรวม
นอกจากการตอบกลับตามคีย์เวิร์ดแบบตรงตัว ระบบยังรองรับ chatbot ที่เข้าใจ เจตนา (intent) ของผู้ใช้ งานนี้ทำหน้าที่รับข้อความจากผู้ใช้แล้วจำแนกว่าเป็น intent ใด ผ่านการประมวลผล 3 เฟส (คีย์เวิร์ด → vector → LLM) จากนั้นส่งต่อให้ response sender ตอบกลับตาม intent ที่จับได้
งานนี้ทำงานเป็นส่วนหนึ่งของ workflow โดย trigger rule ที่มี source_type = 'message_received'
จะถูกจัดกลุ่มตาม workflow_id และทำการจำแนก 1 ครั้งต่อ 1 workflow
Business Flow
- รับ payload ที่ประกอบด้วย
lineUserId,lineOaId,organizationId,messageText,messageType,replyTokenและtimestamp - โหลด
trigger_ruleของคู่ (lineOaId, organizationId) ที่มีsource_type='message_received',enabled=trueและยังไม่ถูกลบ หากไม่พบเลยก็จบงาน - จัดกลุ่ม rule ตาม
workflow_idโดยรักษาลำดับ insertion ให้ตรงกับพฤติกรรมของ JS Map แล้ววนเรียกclassifyAndRoute - อ่าน config ของ classifier จาก
sourceConfigของ rule ตัวแรก ได้แก่intents,fallbackIntentId,confidenceThreshold(ค่า default 0.3) และconversationMemory - แยก intent ออกเป็น 2 ชนิดคือ
keywordและai - โหลดประวัติการสนทนา หากเปิดใช้ memory จะดึงจาก Redis list ของคู่ line OA และ line user
สูงสุดตาม
maxMessages(default 10) แล้วกลับลำดับให้เรียงจากเก่าไปใหม่ - จำแนก 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แทน
- เฟสที่ 1 — Keyword:
- เมื่อได้ 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
- บันทึกผลการทำงานลง
trigger_logผ่านTriggerLogger
note
queue message_received_trigger เป็น queue เดียวในระบบที่ ไม่ถูก monitor DLQ กล่าวคือมีการ
assert topology ไว้แต่ไม่ได้ subscribe queue .dlq ของมัน
ไฟล์และฟังก์ชันหลัก
internal/messagetrigger/service.goMessageTriggerService.ProcessMessage(ctx, payload)— entry pointfetchMessageReceivedRules(),classifyAndRoute(),matchKeyword(),parseClassificationResult(),cosineSimilarity(),decodeIntents()- struct
MessageReceivedPayload,classificationResult,IntentDefinition,ConversationEntry
internal/messagetrigger/response_sender.goResponseSenderService.SendResponse(ctx, params)applyTracking(),loadMergeUser(),storeAssistantMemory(),appendQuickReply()IntentResponseConfigซึ่งมีฟิลด์Extraเก็บknowledgeBaseId,retrievalConfigและtracking
internal/messagetrigger/prompts.go— prompt template ของ classifier และของการตอบคำถามinternal/messagetrigger/transform.go— การแปลง message objectinternal/messagetrigger/consumer.go—Consumer.HandleMessageReceivedinternal/aix/aix.go— LLM client โดยมีConfigResolverอ่าน config จากตารางai_configinternal/embedx/embedx.go— เรียก embedding API และinternal/meilix/meilix.go— Meilisearch client- Queue:
message_received_trigger(profilemain)
จุดเชื่อมต่อกับ 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