AI Engine & Prompt Engineering
Phần này giải thích cách module src/analyzer.py sử dụng AI để biến ảnh chụp màn hình thành hướng dẫn chi tiết.
1. Multimodal AI Models
Hệ thống hỗ trợ 2 provider chính với cơ chế auto-detection và fallback thông minh:
| Provider | Models mặc định | Thư viện Python | Đặc điểm |
|---|---|---|---|
gemma-3-27b, gemini-2.5-flash, gemini-1.5-flash | google-generativeai | RPD cao (14.4K), Free tier tốt | |
| OpenAI | gpt-4o-mini, gpt-4o, gpt-4-turbo | openai | Chi phí thấp, hiệu năng ổn định |
1.1. Cơ chế Auto-Detection Model
Thay vì hardcode model, hệ thống tự động:
- Lấy danh sách models khả dụng từ API (
get_available_gemini_models) - Lọc models hỗ trợ vision (loại bỏ TTS, embedding, audio...)
- Chọn model tốt nhất theo thứ tự ưu tiên đã định nghĩa
# Thứ tự ưu tiên trong code thực tế
GEMINI_DEFAULT_MODELS = [
"gemma-3-27b", # RPD cao (14.4K)
"gemma-3-12b", # Backup
"gemini-2.5-flash", # RPD=20
"gemini-1.5-flash", # Ổn định
]1.2. Cơ chế Fallback khi hết Quota
Khi gặp lỗi 429 (quota exceeded), hệ thống tự động:
- Đánh dấu model hiện tại vào
_failed_gemini_models - Tìm model thay thế từ danh sách còn lại
- Retry tối đa 2 lần mỗi request
- Nếu tất cả models đều fail → fallback về code-based description
# Logic trong _analyze_with_gemini()
if "429" in error_str or "quota" in error_str.lower():
_failed_gemini_models.append(current_model)
new_model = select_best_model(None, remaining, GEMINI_DEFAULT_MODELS, _failed_gemini_models)
if new_model:
_switch_gemini_model(api_key, new_model)
return _analyze_with_gemini(..., retry_count + 1)Ưu điểm của cơ chế này
- ✅ Tự động thích ứng: Không cần sửa code khi Google thay đổi models
- ✅ Resilient: Hệ thống không bị gián đoạn khi 1 model hết quota
- ✅ Transparent: User thấy rõ model nào đang được sử dụng
Nhược điểm
- ❌ Latency: Mất thời gian gọi API lấy danh sách models
- ❌ Inconsistent output: Các models khác nhau có thể cho kết quả khác nhau
2. Quy trình xử lý ảnh
Trước khi gửi cho AI, ảnh được xử lý trong hàm _encode_image_base64:
- Read: Đọc file ảnh từ đĩa (
rbmode). - Encode: Chuyển đổi sang chuỗi Base64 (
base64.standard_b64encode). - Context: Nếu có ảnh của bước trước đó (
previous_screenshot), hệ thống sẽ gửi cả 2 ảnh (Trước/Sau) để AI so sánh sự thay đổi.
3. Prompt Engineering (Thực tế)
Dưới đây là Prompt thực tế được sử dụng trong code (src/analyzer.py), được tối ưu qua nhiều lần iteration.
3.1. System Prompt (Code thực tế)
prompt = f"""Bạn là chuyên gia viết tài liệu hướng dẫn sử dụng phần mềm.
NHIỆM VỤ: Viết MỘT câu tiếng Việt mô tả hành động người dùng cần làm.
GỢI Ý HÀNH ĐỘNG: {action_hint if action_hint else 'Không có'}
YÊU CẦU:
- Viết câu HOÀN CHỈNH bằng tiếng Việt (có chủ ngữ, vị ngữ)
- Mô tả hành động cụ thể (nhấn, nhập, chọn, điền...)
- Độ dài: 8-20 từ
- Kết thúc bằng dấu chấm (.)
VÍ DỤ TỐT:
- "Nhấn nút Đăng nhập để vào hệ thống."
- "Nhập địa chỉ email vào ô Email đăng nhập."
- "Chọn menu Cloud Server từ thanh điều hướng bên trái."
CHỈ TRẢ VỀ MỘT CÂU MÔ TẢ, KHÔNG GIẢI THÍCH THÊM."""3.2. Generation Config
generation_config={
"temperature": 0.2, # Giảm để output ổn định
"max_output_tokens": 256, # Đủ cho câu hoàn chỉnh
"top_p": 0.8,
"top_k": 40,
}3.3. Validation Output
Sau khi nhận response từ AI, hệ thống validate:
# Đảm bảo câu hoàn chỉnh (ít nhất 3 từ)
if result and len(result.split()) >= 3:
if not result.endswith(('.', '!', '?')):
result += '.'
return result
# Nếu câu quá ngắn, dùng action_hint
return action_hintƯu điểm của Prompt này
- ✅ Structured: Yêu cầu rõ ràng, có ví dụ cụ thể
- ✅ Constrained: Giới hạn độ dài (8-20 từ) tránh output quá dài/ngắn
- ✅ Vietnamese-first: Tối ưu cho tiếng Việt
Nhược điểm
- ❌ Rigid: Khó customize cho các ngôn ngữ khác
- ❌ Context-limited: Không có thông tin về các bước trước đó
4. Fallback Mechanism (3 tầng)
Hệ thống có 3 tầng fallback để đảm bảo không bao giờ gián đoạn:
Tầng 1: Model Fallback
Khi model hiện tại hết quota → tự động chuyển sang model khác.
Tầng 2: Provider Fallback
Khi tất cả Gemini models đều fail → có thể chuyển sang OpenAI (nếu có key).
Tầng 3: Code-based Fallback
Khi AI hoàn toàn không khả dụng → dùng get_action_hint() từ Parser.
def analyze_screenshot(screenshot, provider, previous_screenshot=None):
global _all_models_exhausted
action_hint = get_action_hint(screenshot.action)
# Skip AI nếu đã biết tất cả models đều fail
if provider == "gemini" and _all_models_exhausted:
return action_hint
try:
if provider == "gemini":
return _analyze_with_gemini(...)
elif provider == "openai":
return _analyze_with_openai(...)
except Exception as e:
print(f"⚠️ AI analysis failed: {e}")
print(f"↪️ Falling back to code-based description")
return action_hint5. So sánh AI vs Code-based Description
| Tiêu chí | AI Description | Code-based |
|---|---|---|
| Chất lượng | Tự nhiên, dễ đọc | Kỹ thuật, khô khan |
| Tốc độ | 1-3s/step | Instant |
| Chi phí | ~$0.001/step | Free |
| Độ tin cậy | Phụ thuộc API | 100% |
Ví dụ output:
- AI: "Nhấn nút Đăng nhập để vào hệ thống."
- Code-based: "Nhấn nút 'Đăng nhập'"