AI Hunter
Member
Nếu Gemini chỉ trả lời bằng chữ, nó chỉ là Chatbot.
Nếu Gemini biết trả về JSON để kích hoạt code Python, nó là Trợ lý ảo (Agent).
Hôm nay, chúng ta sẽ dạy Gemini cách sử dụng "công cụ" (Tools) để điều khiển hệ thống MQTT mà ta đã xây dựng trước đó.
Đây là phần code quan trọng nhất. Hãy backup file `server.py` cũ và cập nhật logic mới này.
*Lưu ý:* Thư viện `google-generativeai` bản mới nhất hỗ trợ `enable_automatic_function_calling=True`, giúp code gọn đi rất nhiều (không cần parse JSON thủ công).
Khởi động lại Server và mở Swagger UI (hoặc Postman) để test.
Trường hợp 1: Điều khiển thiết bị
Trường hợp 2: Hỏi thông tin cảm biến
Trường hợp 3: Chat linh tinh
Bạn thấy sự khác biệt chưa?
Từ một cái máy chỉ biết làm theo lệnh cố định, Jarvis giờ đây đã biết **"Hiểu -> Suy luận -> Hành động"**.
Bạn có thể nói: *"Tối om thế này mà không bật đèn à?"* -> Jarvis vẫn hiểu là phải bật đèn, dù bạn không dùng từ "Bật". Đó là sức mạnh của LLM.
Tuy nhiên, nãy giờ chúng ta vẫn đang chat bằng... Swagger UI/Postman. Rất thiếu chuyên nghiệp.
Tony Stark cần một giao diện Chat xịn xò trên điện thoại.
Nếu Gemini biết trả về JSON để kích hoạt code Python, nó là Trợ lý ảo (Agent).
Hôm nay, chúng ta sẽ dạy Gemini cách sử dụng "công cụ" (Tools) để điều khiển hệ thống MQTT mà ta đã xây dựng trước đó.
1. Nguyên lý hoạt động
- Bước 1 (Khai báo): Chúng ta nói với Gemini: *"Này, tao có một cái hàm tên là `control_home_device`, dùng để bật tắt thiết bị. Nếu cần thì cứ gọi nhé."*
- Bước 2 (Phán đoán): Bạn chat *"Bật quạt lên"*. Gemini phân tích và thấy cần dùng hàm trên.
- Bước 3 (Ra lệnh): Gemini không trả lời text, mà trả về lệnh:
call: control_home_device(device="fan", status="on"). - Bước 4 (Thực thi): Server Python nhận lệnh -> Gửi MQTT -> Relay nhảy "Tạch".
- Bước 5 (Phản hồi): Server báo lại Gemini: *"Xong rồi"*. Gemini trả lời bạn: *"Đã bật quạt, mát chưa sir?"*
2. Cập nhật Server (server.py)
Đây là phần code quan trọng nhất. Hãy backup file `server.py` cũ và cập nhật logic mới này.
Python:
# ... (Các import cũ giữ nguyên) ...
from google.generativeai.types import FunctionDeclaration, Tool
# --- 1. ĐỊNH NGHĨA HÀM PYTHON THỰC TẾ ---
# Đây là hàm sẽ chạy khi AI yêu cầu
def control_home_device(device_name: str, action: str):
"""
Hàm điều khiển thiết bị trong nhà (Đèn, Quạt, v.v.).
device_name: Tên thiết bị (ví dụ: "light", "fan", "living_room_light").
action: Hành động ("on" là bật, "off" là tắt).
"""
global home_state
print(f"⚡ AI đang cố gắng điều khiển: {device_name} -> {action}")
# Mapping tên thiết bị từ ngôn ngữ tự nhiên sang ID kỹ thuật
# AI có thể gọi "cái đèn", "đèn phòng khách" -> ta map về "light_living_room"
target_id = None
if "đèn" in device_name.lower() or "light" in device_name.lower():
target_id = "light_living_room"
if target_id:
# Thực thi logic MQTT (Copy từ code cũ Season 4)
status_bool = True if action.lower() == "on" else False
home_state[target_id] = status_bool
mqtt_cmd = "ON" if status_bool else "OFF"
mqtt_client.publish(MQTT_TOPIC_LIGHT, mqtt_cmd)
return f"Đã thực hiện lệnh: {action} thiết bị {target_id} thành công."
else:
return f"Xin lỗi, không tìm thấy thiết bị tên là {device_name} trong hệ thống."
# Hàm lấy dữ liệu cảm biến
def get_sensor_data():
"""
Hàm lấy thông tin nhiệt độ và độ ẩm hiện tại trong phòng.
"""
global sensor_state
return f"Nhiệt độ hiện tại là {sensor_state['temp']} độ C, độ ẩm là {sensor_state['hum']}%."
# --- 2. KHAI BÁO TOOL CHO GEMINI ---
# Gom các hàm lại thành một bộ công cụ
my_iot_tools = [control_home_device, get_sensor_data]
# --- 3. CẤU HÌNH MODEL VỚI TOOLS ---
model = genai.GenerativeModel(
'gemini-1.5-flash',
tools=my_iot_tools, # <--- Nạp tool vào đây
system_instruction="""
Bạn là Jarvis, quản gia thông minh.
Bạn có quyền điều khiển các thiết bị trong nhà thông qua các công cụ (tools) được cung cấp.
- Nếu người dùng yêu cầu bật/tắt, hãy gọi hàm control_home_device.
- Nếu người dùng hỏi nóng/lạnh/thời tiết trong nhà, hãy gọi hàm get_sensor_data.
- Nếu không cần dùng tool, hãy trả lời bình thường.
"""
)
# Bật chế độ tự động gọi hàm (Auto Function Calling)
# AI sẽ tự động chạy hàm và sinh ra câu trả lời cuối cùng
chat_session = model.start_chat(enable_automatic_function_calling=True)
# --- API CHAT (GIỮ NGUYÊN) ---
@app.post("/chat")
async def chat_with_jarvis(req: ChatRequest):
try:
print(f"🗣️ User: {req.message}")
# Gửi tin nhắn (AI sẽ tự xử lý tool ở background)
response = chat_session.send_message(req.message)
print(f"🤖 Jarvis: {response.text}")
return {"reply": response.text}
except Exception as e:
print(f"⚠️ Lỗi AI: {e}")
return {"reply": f"Lỗi hệ thống: {str(e)}"}
*Lưu ý:* Thư viện `google-generativeai` bản mới nhất hỗ trợ `enable_automatic_function_calling=True`, giúp code gọn đi rất nhiều (không cần parse JSON thủ công).
3. Kiểm chứng thực tế (Test Case)
Khởi động lại Server và mở Swagger UI (hoặc Postman) để test.
Trường hợp 1: Điều khiển thiết bị
- Input: *"Jarvis, bật đèn phòng khách lên cho tao."*
- Quy trình ngầm:
1. Gemini hiểu ý định -> Gọi `control_home_device("đèn phòng khách", "on")`.
2. Hàm Python chạy -> Gửi MQTT "ON" -> Đèn sáng "Tạch".
3. Hàm Python trả về chuỗi "Đã thực hiện...".
4. Gemini nhận kết quả -> Sinh câu trả lời cuối. - Output (AI trả lời): *"Đã bật đèn phòng khách rồi ạ, thưa ngài."*
Trường hợp 2: Hỏi thông tin cảm biến
- Input: *"Phòng đang nóng bao nhiêu độ?"*
- Quy trình ngầm: Gemini gọi `get_sensor_data()` -> Lấy giá trị từ biến `sensor_state`.
- Output: *"Nhiệt độ hiện tại đang là 30.5 độ C, khá nóng đấy ạ."*
Trường hợp 3: Chat linh tinh
- Input: *"Kể một câu chuyện cười đi."*
- Quy trình ngầm: Không gọi hàm nào cả.
- Output: *"Tại sao máy tính không bao giờ đói? Vì nó ăn RAM. Ha ha."*
4. Troubleshooting (Gỡ lỗi)
- Lỗi: AI trả lời "Tôi không thể làm điều đó" hoặc "Tôi là mô hình ngôn ngữ...".
- Lý do: Có thể do System Instruction chưa đủ rõ, hoặc bạn chưa truyền `tools` vào lúc khởi tạo Model.
- Khắc phục: Kiểm tra lại phần `tools=my_iot_tools` và đảm bảo tên hàm/mô tả hàm (Docstring) rõ ràng. Gemini đọc Docstring để hiểu chức năng của hàm.
Tổng kết
Bạn thấy sự khác biệt chưa?
Từ một cái máy chỉ biết làm theo lệnh cố định, Jarvis giờ đây đã biết **"Hiểu -> Suy luận -> Hành động"**.
Bạn có thể nói: *"Tối om thế này mà không bật đèn à?"* -> Jarvis vẫn hiểu là phải bật đèn, dù bạn không dùng từ "Bật". Đó là sức mạnh của LLM.
Tuy nhiên, nãy giờ chúng ta vẫn đang chat bằng... Swagger UI/Postman. Rất thiếu chuyên nghiệp.
Tony Stark cần một giao diện Chat xịn xò trên điện thoại.
Bài viết liên quan