T5 — Thiết kế module NLP Chatbot - congsinhv/fluxion GitHub Wiki
Thiết Kế Module NLP Chatbot
Issue: #27 — Thiết kế module NLP Chatbot Tuần: 5 | 21/04 – 27/04/2026
Numbering chính thức: Mục 3.5 theo Master TOC
Định vị module: Module NLP Chatbot trong Fluxion được xây dựng như một ứng dụng LLM tăng cường công cụ (Tool-Augmented LLM Application), tập trung vào prompt engineering, tool schema design, và safety mechanisms — không phải nghiên cứu NLP cơ bản. Đóng góp chính: system prompt chuyên biệt cho domain MDM, 5 tool definitions, cơ chế xác nhận 2 bước cho lệnh nguy hiểm.
3.5 Thiết Kế Module NLP Chatbot
3.5.1 Conversation Flow Diagrams
3.5.1.1 Simple Query Flow
User: "liệt kê thiết bị đang active"
→ LLM: intent = query, entity = state:active
→ tool_call: query_devices(state="active")
→ Lambda: SELECT * FROM devices WHERE state='active'
→ result: [{id, name, serial, state}, ...]
→ LLM: format response
→ User: "Có 12 thiết bị đang active: ..."
3.5.1.2 Command Flow (with Confirmation)
User: "khóa thiết bị iPhone-001"
→ LLM: intent = lock, entity = iPhone-001
→ tool_call: send_device_command(device_id="...", command="lock", confirmed=false)
→ Lambda: confirmed=false → return {requiresConfirmation: true}
→ LLM → User: "Xác nhận khóa thiết bị iPhone-001?"
→ User: "xác nhận"
→ tool_call: send_device_command(confirmed=true)
→ Lambda: dispatch via command pipeline
→ User: "Đã gửi lệnh khóa thiết bị iPhone-001. Trạng thái: ACTION_PENDING"
3.5.1.3 Disambiguation Flow
User: "khóa thiết bị của An"
→ LLM: device_id unclear
→ tool_call: query_devices() + filter by name
→ result: 2 devices match "An": iPhone-An-001, iPad-An-002
→ LLM → User: "Tìm thấy 2 thiết bị của An:
1. iPhone-An-001 (active)
2. iPad-An-002 (locked)
Bạn muốn khóa thiết bị nào?"
→ User: "1"
→ tool_call: send_device_command(device_id="iPhone-An-001", command="lock", confirmed=false)
→ ... confirmation flow ...
3.5.2 System Prompt
You are the Fluxion MDM assistant. You help administrators manage iOS devices
via natural language commands in Vietnamese and English.
## Device States (FSM)
Available states: idle, registered, enrolled, active, locked, released
## Available Commands
- lock: Khóa thiết bị (chỉ khi active)
- unlock: Mở khóa (chỉ khi locked)
- send_message: Gửi thông báo push (chỉ khi active)
- lock_message: Gửi message lên lock screen (chỉ khi locked)
- release: Thu hồi thiết bị (từ bất kỳ state, admin hoặc operator)
## Rules
1. ALL command actions require explicit user confirmation before execution.
Always call send_device_command with confirmed=false first.
Only set confirmed=true AFTER user explicitly confirms.
2. If device_id is ambiguous or a name, call query_devices first to resolve.
3. Never guess device IDs — always verify via query.
4. Respond in the same language as the user.
5. When showing device info, include: name, serial, current state.
3.5.3 Tool Definitions (5 Tools)
3.5.3.1 query_devices
{
"name": "query_devices",
"description": "List or filter devices by FSM state.",
"parameters": {
"type": "object",
"properties": {
"state": {
"type": "string",
"enum": ["idle","registered","enrolled","active","locked","released"]
},
"search": {
"type": "string",
"description": "Search by device name or serial number"
},
"limit": { "type": "integer", "default": 20 }
}
}
}
3.5.3.2 get_device
{
"name": "get_device",
"description": "Get full info for a single device by ID or serial.",
"parameters": {
"type": "object",
"properties": {
"device_id": { "type": "string", "description": "UUID or serial number" }
},
"required": ["device_id"]
}
}
3.5.3.3 send_device_command
{
"name": "send_device_command",
"description": "Send MDM command to a device. ALL commands require confirmed=true after user confirms.",
"parameters": {
"type": "object",
"properties": {
"device_id": { "type": "string" },
"command": {
"type": "string",
"enum": ["lock", "unlock", "send_message", "lock_message", "release"]
},
"message": {
"type": "string",
"description": "Message content for send_message or lock_message commands"
},
"confirmed": {
"type": "boolean",
"description": "Must be true to execute. Always call with false first, then true after user confirms."
}
},
"required": ["device_id", "command", "confirmed"]
}
}
3.5.3.4 get_command_history
{
"name": "get_command_history",
"description": "Get command execution history for a device.",
"parameters": {
"type": "object",
"properties": {
"device_id": { "type": "string" },
"limit": { "type": "integer", "default": 10 }
},
"required": ["device_id"]
}
}
3.5.3.5 get_device_stats
{
"name": "get_device_stats",
"description": "Get aggregate device counts grouped by FSM state.",
"parameters": {
"type": "object",
"properties": {}
}
}
3.5.4 Safety & Authorization
3.5.4.1 Confirmation Gate
Mọi command action → confirmed=false (bắt buộc gọi trước)
→ Lambda: return {requiresConfirmation: true, summary: "..."}
→ LLM hiển thị confirmation prompt cho user
→ User xác nhận → confirmed=true → Lambda thực thi
→ User huỷ → không thực thi, log cancellation
Không có ngoại lệ — tất cả 5 commands (lock, unlock, send_message, lock_message, release) đều qua confirmation gate.
3.5.4.2 Role-Based Authorization
| Command | Admin | Operator |
|---|---|---|
| lock | ✅ | ✅ |
| unlock | ✅ | ✅ |
| send_message | ✅ | ✅ |
| lock_message | ✅ | ✅ |
| release | ✅ | ✅ |
Lambda kiểm tra JWT role claim trước mọi command execution. Nếu unauthorized:
- Return error:
UNAUTHORIZED — action requires appropriate role - LLM thông báo user: "Bạn không có quyền thực hiện lệnh này"
3.5.4.3 Audit Logging
Mọi command attempt ghi vào CloudWatch Logs:
{
"timestamp": "2026-04-20T10:30:00Z",
"user_id": "uuid",
"device_id": "uuid",
"command": "lock",
"confirmed": true,
"result": "dispatched",
"session_id": "chat-session-uuid"
}
3.5.5 Architecture — chat-handler Lambda
3.5.5.1 Sequence Diagram
sequenceDiagram
participant U as User (Chat UI)
participant AS as AppSync
participant CH as chat-handler Lambda
participant DB as PostgreSQL
participant LLM as GPT-4o mini
participant AR as action-resolver
U->>AS: mutation sendChatMessage(sessionId, message)
AS->>CH: invoke with JWT context
CH->>DB: SELECT last 10 messages WHERE session_id
CH->>CH: Build messages array: [system_prompt] + history + user_msg
CH->>LLM: POST /chat/completions (messages + tools)
LLM-->>CH: tool_call: query_devices(state="active")
CH->>DB: SELECT * FROM devices WHERE state='active'
CH->>CH: Append tool_result to messages
CH->>LLM: POST /chat/completions (messages + tool_result)
LLM-->>CH: text response: "Có 12 thiết bị active..."
CH->>DB: INSERT chat_messages (user_msg + assistant_msg)
CH-->>AS: return ChatResponse {message, toolCalls}
AS-->>U: response
3.5.5.2 Lambda Flow (Pseudocode)
def handler(event, context):
# 1. Auth
user = validate_jwt(event.identity)
# 2. Load history
session_id = event.arguments.sessionId
history = db.query(
"SELECT role, content FROM chat_messages "
"WHERE session_id = %s ORDER BY created_at DESC LIMIT 10",
session_id
)
# 3. Build messages
messages = [
{"role": "system", "content": SYSTEM_PROMPT},
*reversed(history),
{"role": "user", "content": event.arguments.message}
]
# 4. Call LLM with tools
response = llm_client.chat(messages=messages, tools=TOOLS)
# 5. Handle tool calls (max 1 round)
if response.has_tool_calls():
for tool_call in response.tool_calls:
result = execute_tool(tool_call, user)
messages.append(tool_call_message)
messages.append(tool_result_message(result))
# Follow-up call
response = llm_client.chat(messages=messages, tools=TOOLS)
# 6. Persist
db.insert_chat_messages(session_id, [
{"role": "user", "content": event.arguments.message},
{"role": "assistant", "content": response.text}
])
return {"message": response.text}
3.5.5.3 Tool Execution
def execute_tool(tool_call, user):
name = tool_call.function.name
args = json.loads(tool_call.function.arguments)
if name == "query_devices":
return db.query_devices(state=args.get("state"), search=args.get("search"))
if name == "get_device":
return db.get_device(args["device_id"])
if name == "send_device_command":
if not args.get("confirmed"):
return {"requiresConfirmation": True,
"summary": f"{args['command']} device {args['device_id']}"}
# Check role authorization
# Role check: all commands require admin or operator
if user.role not in ("admin", "operator"):
return {"error": "UNAUTHORIZED", "message": "requires admin or operator role"}
# Dispatch via AppSync mutation (internal)
return appsync_client.mutate(
mutation=DISPATCH_COMMAND,
variables={"deviceId": args["device_id"], "command": args["command"],
"message": args.get("message")}
)
if name == "get_command_history":
return db.get_command_history(args["device_id"], args.get("limit", 10))
if name == "get_device_stats":
return db.get_device_stats()
3.5.6 Context Management
| Aspect | Strategy | Detail |
|---|---|---|
| History | Sliding window | 10 messages gần nhất per session |
| Device context | Tool call on-demand | LLM gọi query_devices/get_device khi cần, không preload |
| Session | Per-user | Mỗi user có active session; session_id trong JWT hoặc client-managed |
| Token budget | ~2000 tokens | System prompt (~500) + history (~1200) + user msg (~300) |
3.5.7 LLM Provider Config
| Setting | Value | Lý do |
|---|---|---|
| Model | gpt-4o-mini |
Tốt nhất cost/performance cho thesis |
| Temperature | 0.1 | Deterministic tool calls; minimal creativity needed |
| Max tokens | 500 | MDM responses ngắn |
| Tool choice | auto |
LLM tự quyết định gọi tool hay trả text |
| Streaming | Off (sync) | Response ngắn; sync đủ cho admin tooling |
3.5.8 Biểu Đồ Lớp — Module NLP Chatbot (Class Diagram)

Hình: Biểu đồ lớp module NLP Chatbot. Xanh lá = handler chính (Entry point), xanh dương = bộ thực thi công cụ (Executor), tím = lớp trừu tượng (Abstract), vàng = công cụ cụ thể (Concrete Tool), đỏ = công cụ nguy hiểm yêu cầu xác nhận (Safety Gate).
Kết Luận
Module NLP Chatbot của Fluxion được định vị là một ứng dụng LLM tăng cường công cụ (Tool-Augmented LLM Application) theo mô hình ReAct (Reasoning + Acting), không phải hệ thống NLP truyền thống. Đóng góp kỹ thuật tập trung vào 3 điểm: (1) system prompt chuyên biệt cho domain MDM với FSM state constraints và ngôn ngữ tự nhiên song ngữ Việt-Anh, (2) 5 tool definitions với schema rõ ràng bao phủ toàn bộ operations (query, get, command, history, stats), và (3) cơ chế xác nhận 2 bước (confirmed=false → user confirm → confirmed=true) đảm bảo không có command nào được thực thi mà không có sự đồng ý tường minh của người dùng.
Safety gate thông qua confirmed parameter là thiết kế quan trọng nhất của module: LLM bắt buộc phải gọi send_device_command với confirmed=false trước, nhận lại requiresConfirmation: true, hiển thị summary cho user, và chỉ thực thi khi user xác nhận bằng ngôn ngữ tự nhiên. Cơ chế này được enforce tại Lambda layer (không chỉ ở prompt level), kết hợp với RBAC check tại Lambda layer tạo thành defense-in-depth cho các lệnh nguy hiểm.
Context management sử dụng sliding window 10 messages (~2000 tokens) đủ cho multi-turn conversation thông thường trong môi trường MDM. Quyết định chọn gpt-4o-mini với temperature=0.1 phản ánh ưu tiên deterministic tool calling over creativity — phù hợp cho admin tooling yêu cầu độ chính xác cao trong nhận dạng intent và gọi tool đúng tham số.
Tài Liệu Tham Khảo
[1] Vaswani, A. et al. Attention Is All You Need. NeurIPS, 2017.
[2] Schick, T. et al. Toolformer: Language Models Can Teach Themselves to Use Tools. NeurIPS, 2023.
[3] Yao, S. et al. ReAct: Synergizing Reasoning and Acting in Language Models. ICLR, 2023.
[4] OpenAI. Function Calling Documentation. 2024.
[5] Patil, S. G. et al. Gorilla: Large Language Model Connected with Massive APIs. 2023.