Vision + Tool Use — Trích xuất dữ liệu từ hình ảnh
Điểm nổi bật
Nhấn để đến mục tương ứng
- 1 Công cụ AI sẽ thay đổi cách bạn làm việc: Vision alone chỉ gửi ảnh và hỏi cho output dạng text tự nhiên: Chi dung Vision - output khong nhat quan response =. Điểm mấu chốt là biết cách đặt prompt đúng để nhận kết quả có thể sử dụng ngay.
- 2 Một điều ít người đề cập: import anthropic import base64 import json from pathlib import Path client = anthropic.Anthropic nutritiontool = {. Hiểu rõ bối cảnh áp dụng sẽ quyết định 80% thành công khi triển khai.
- 3 Điểm nhấn quan trọng: def displaynutritiondata: """In thong tin dinh duong dep mat""" print"=" 50 if data.get"productname": printf"SAN PHAM:. Đây là phần mang lại giá trị thực tiễn cao nhất trong toàn bài viết.
- 4 Bước đầu tiên bạn nên làm: import asyncio from concurrent.futures import ThreadPoolExecutor def batchextractnutritionimageurls, maxworkers=5: """. Áp dụng đúng cách sẽ thấy kết quả rõ rệt từ tuần đầu tiên.
- 5 Một điều ít người đề cập: Tình huống Cách xử lý Ảnh mờ, khuất Field confidence: "low" + notes mô tả vấn đề Nhãn tiếng nước ngoài Claude đọc được. Hiểu rõ bối cảnh áp dụng sẽ quyết định 80% thành công khi triển khai.
Một trong những ứng dụng thú vị nhất của Claude API là kết hợp Vision (phân tích hình ảnh) với Tool Use (output có cấu trúc). Kết quả: bạn có thể gửi một bức ảnh và nhận về JSON data — không cần OCR riêng, không cần computer vision model chuyên biệt.
Bài này xây dựng pipeline trích xuất thông tin dinh dưỡng từ ảnh nhãn thực phẩm — bài toán thực tế cho app theo dõi sức khỏe, hệ thống quản lý kho thực phẩm, hoặc ứng dụng đọc nhãn cho người khiếm thị.
Tại sao kết hợp Vision + Tool Use?
Vision alone (chỉ gửi ảnh và hỏi) cho output dạng text tự nhiên:
# Chi dung Vision - output khong nhat quan
response = client.messages.create(
model="claude-opus-4-5",
max_tokens=512,
messages=[{
"role": "user",
"content": [
{"type": "image", "source": {"type": "url", "url": image_url}},
{"type": "text", "text": "Bao nhieu calories trong san pham nay?"}
]
}]
)
# Output co the la:
# "San pham nay chua khoang 250 calories moi khau phan."
# "Calories: 250 kcal"
# "250 Cal (dua tren khau phan 30g)"
# Moi lan chay khac nhau!
Vision + Tool Use cho output JSON có cấu trúc, nhất quán 100%:
# Vision + Tool Use - output co cau truc bao dam
# {
# "calories": 250,
# "serving_size": "30g",
# "fat_total_g": 12.5,
# "cholesterol_mg": 0,
# "sodium_mg": 180,
# "carbohydrates_g": 31,
# "protein_g": 3,
# ...
# }
Định nghĩa Nutrition Tool
import anthropic
import base64
import json
from pathlib import Path
client = anthropic.Anthropic()
nutrition_tool = {
"name": "print_nutrition_info",
"description": "Hien thi thong tin dinh duong tu nhan thuc pham da duoc doc tu hinh anh",
"input_schema": {
"type": "object",
"properties": {
"product_name": {
"type": "string",
"description": "Ten san pham (neu doc duoc tu nhan)"
},
"serving_size": {
"type": "string",
"description": "Khau phan an, VD: '30g', '1 cup (240ml)'"
},
"servings_per_container": {
"type": "number",
"description": "So khau phan trong bao bi, null neu khong co"
},
"calories": {
"type": "number",
"description": "Calories moi khau phan (kcal)"
},
"calories_from_fat": {
"type": "number",
"description": "Calories tu chat beo, null neu khong co"
},
"fat_total_g": {
"type": "number",
"description": "Tong chat beo (gram)"
},
"fat_saturated_g": {
"type": "number",
"description": "Chat beo bao hoa (gram), null neu khong co"
},
"fat_trans_g": {
"type": "number",
"description": "Chat beo trans (gram), null neu khong co"
},
"cholesterol_mg": {
"type": "number",
"description": "Cholesterol (miligram)"
},
"sodium_mg": {
"type": "number",
"description": "Natri/Muoi (miligram)"
},
"carbohydrates_g": {
"type": "number",
"description": "Tong carbohydrate (gram)"
},
"fiber_g": {
"type": "number",
"description": "Chat xo (gram), null neu khong co"
},
"sugar_g": {
"type": "number",
"description": "Duong (gram), null neu khong co"
},
"protein_g": {
"type": "number",
"description": "Protein (gram)"
},
"vitamins_minerals": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {"type": "string"},
"amount": {"type": "string"},
"daily_value_percent": {"type": "number"}
}
},
"description": "Danh sach vitamins va khoang chat (neu co)"
},
"confidence": {
"type": "string",
"enum": ["high", "medium", "low"],
"description": "Do tin cay cua viec doc nhan - high: nhan ro net, low: nhan mo/bi che"
},
"notes": {
"type": "string",
"description": "Ghi chu them (nhan bi che mot phan, don vi khac thuong, v.v.)"
}
},
"required": ["serving_size", "calories", "fat_total_g", "cholesterol_mg",
"sodium_mg", "carbohydrates_g", "protein_g", "confidence"]
}
}
Gửi Ảnh đến Claude
Claude hỗ trợ hai cách gửi ảnh: URL trực tiếp hoặc base64 encoded.
Cách 1: Gửi qua URL
def extract_nutrition_from_url(image_url):
response = client.messages.create(
model="claude-opus-4-5",
max_tokens=1024,
tools=[nutrition_tool],
tool_choice={"type": "tool", "name": "print_nutrition_info"},
messages=[{
"role": "user",
"content": [
{
"type": "image",
"source": {
"type": "url",
"url": image_url
}
},
{
"type": "text",
"text": "Doc va trich xuat thong tin dinh duong day du tu nhan thuc pham trong hinh."
}
]
}]
)
if response.content[0].type == "tool_use":
return response.content[0].input
return None
Cách 2: Gửi file local qua base64
def extract_nutrition_from_file(image_path):
# Doc file va chuyen sang base64
with open(image_path, "rb") as f:
image_data = base64.standard_b64encode(f.read()).decode("utf-8")
# Xac dinh media type tu extension
ext = Path(image_path).suffix.lower()
media_types = {
".jpg": "image/jpeg",
".jpeg": "image/jpeg",
".png": "image/png",
".gif": "image/gif",
".webp": "image/webp"
}
media_type = media_types.get(ext, "image/jpeg")
response = client.messages.create(
model="claude-opus-4-5",
max_tokens=1024,
tools=[nutrition_tool],
tool_choice={"type": "tool", "name": "print_nutrition_info"},
messages=[{
"role": "user",
"content": [
{
"type": "image",
"source": {
"type": "base64",
"media_type": media_type,
"data": image_data
}
},
{
"type": "text",
"text": "Doc va trich xuat thong tin dinh duong day du tu nhan thuc pham trong hinh."
}
]
}]
)
if response.content[0].type == "tool_use":
return response.content[0].input
return None
Hiển thị Kết quả
def display_nutrition(data):
"""In thong tin dinh duong dep mat"""
print("=" * 50)
if data.get("product_name"):
print(f"SAN PHAM: {data['product_name']}")
print(f"Khau phan: {data['serving_size']}")
if data.get("servings_per_container"):
print(f"So khau phan: {data['servings_per_container']}")
print("=" * 50)
print(f"{'Calories':<30} {data['calories']} kcal")
if data.get("calories_from_fat"):
print(f" Tu chat beo: {data['calories_from_fat']} kcal")
print("-" * 50)
print(f"{'Tong chat beo':<30} {data['fat_total_g']}g")
if data.get("fat_saturated_g") is not None:
print(f" Chat beo bao hoa: {data['fat_saturated_g']}g")
if data.get("fat_trans_g") is not None:
print(f" Chat beo trans: {data['fat_trans_g']}g")
print(f"{'Cholesterol':<30} {data['cholesterol_mg']}mg")
print(f"{'Natri':<30} {data['sodium_mg']}mg")
print(f"{'Tong Carbohydrate':<30} {data['carbohydrates_g']}g")
if data.get("fiber_g") is not None:
print(f" Chat xo: {data['fiber_g']}g")
if data.get("sugar_g") is not None:
print(f" Duong: {data['sugar_g']}g")
print(f"{'Protein':<30} {data['protein_g']}g")
if data.get("vitamins_minerals"):
print("-" * 50)
print("Vitamins va Khoang chat:")
for vm in data["vitamins_minerals"]:
dv = f"({vm['daily_value_percent']}% DV)" if vm.get("daily_value_percent") else ""
print(f" {vm['name']}: {vm['amount']} {dv}")
print("=" * 50)
print(f"Do tin cay: {data['confidence'].upper()}")
if data.get("notes"):
print(f"Ghi chu: {data['notes']}")
# Test voi anh nutrition label tu web
test_url = "https://upload.wikimedia.org/wikipedia/commons/thumb/a/a4/Nutricion.jpg/400px-Nutricion.jpg"
result = extract_nutrition_from_url(test_url)
if result:
display_nutrition(result)
Xử lý nhiều ảnh cùng lúc
import asyncio
from concurrent.futures import ThreadPoolExecutor
def batch_extract_nutrition(image_urls, max_workers=5):
"""
Trich xuat thong tin dinh duong tu nhieu anh song song.
Tra ve list ket qua theo thu tu input.
"""
results = []
errors = []
with ThreadPoolExecutor(max_workers=max_workers) as executor:
futures = {
executor.submit(extract_nutrition_from_url, url): i
for i, url in enumerate(image_urls)
}
indexed_results = [None] * len(image_urls)
for future in futures:
idx = futures[future]
try:
indexed_results[idx] = {
"url": image_urls[idx],
"data": future.result(),
"success": True
}
except Exception as e:
indexed_results[idx] = {
"url": image_urls[idx],
"error": str(e),
"success": False
}
return indexed_results
# Test voi nhieu anh
urls = [
"https://example.com/product1-label.jpg",
"https://example.com/product2-label.jpg",
"https://example.com/product3-label.jpg",
]
results = batch_extract_nutrition(urls)
for r in results:
if r["success"]:
print(f"OK: {r['url']}")
print(f" Calories: {r['data']['calories']}")
else:
print(f"LOI: {r['url']} - {r['error']}")
Ứng dụng thực tế
1. App theo dõi dinh dưỡng
User chụp ảnh thức ăn, app trích xuất thông tin và tự động cộng vào nhật ký dinh dưỡng hàng ngày. Với Claude Vision + Tool Use, chỉ cần vài trăm dòng code để có feature này.
2. Hệ thống so sánh sản phẩm
Scan nhiều nhãn sản phẩm, so sánh nutritional profile, gợi ý lựa chọn lành mạnh hơn. Kết hợp với database sản phẩm để build recommendation engine.
3. Accessibility tool
Người dùng khiếm thị chụp ảnh nhãn sản phẩm, hệ thống đọc to thông tin dinh dưỡng quan trọng. Confidence field giúp cảnh báo khi ảnh không rõ.
4. Quality control trong sản xuất
Kiểm tra tự động xem nhãn in trên sản phẩm có đúng format, đủ thông tin bắt buộc theo quy định hay không.
Giới hạn và Xử lý Edge Cases
| Tình huống | Cách xử lý |
|---|---|
| Ảnh mờ, khuất | Field confidence: "low" + notes mô tả vấn đề |
| Nhãn tiếng nước ngoài | Claude đọc được nhiều ngôn ngữ — thêm instruction "dịch sang tiếng Việt" |
| Đơn vị khác thường | Field notes để Claude ghi rõ đơn vị gốc |
| Không phải nhãn dinh dưỡng | Claude trả về confidence: "low" và notes giải thích |
| Ảnh quá lớn | Resize xuống 1024x1024 trước khi gửi — Claude không cần resolution cao để đọc text |
Tối ưu Chi phí
Vision requests tốn nhiều token hơn text-only. Một số tips:
- Resize ảnh trước khi gửi — 800x800 thường đủ để đọc text rõ
- Crop vùng nhãn thay vì gửi cả ảnh sản phẩm — giảm 50-70% image tokens
- Dùng claude-haiku cho batch processing lớn — rẻ hơn nhiều, vẫn đọc text tốt
- Cache kết quả theo image hash — tránh phân tích lại ảnh đã xử lý
import hashlib
# Cache don gian dung in-memory dict
_nutrition_cache = {}
def extract_with_cache(image_url):
# Tao cache key tu URL
cache_key = hashlib.md5(image_url.encode()).hexdigest()
if cache_key in _nutrition_cache:
print(f"[Cache hit] {cache_key}")
return _nutrition_cache[cache_key]
result = extract_nutrition_from_url(image_url)
_nutrition_cache[cache_key] = result
return result
Tổng kết: Vision + Tool Use Pattern
Pattern Vision + Tool Use hoạt động tốt cho bất kỳ bài toán nào cần trích xuất structured data từ visual content:
- Đọc hóa đơn, receipt — extract line items, total, date
- Phân tích business card — extract tên, email, phone, company
- Đọc bảng trong ảnh — convert sang JSON/CSV
- Trích xuất thông số từ ảnh sản phẩm kỹ thuật
- Phân tích chart/biểu đồ — extract data points
Chỉ cần định nghĩa tool schema phù hợp với cấu trúc data bạn cần, gửi ảnh kèm tool, và đọc tool.input — Claude làm phần còn lại.
Đây là điểm kết thúc của series Tool Use cơ bản. Bước tiếp theo trong hành trình Claude API: tìm hiểu về Prompt Caching để giảm chi phí khi làm việc với system prompts dài và Streaming để cải thiện UX trong ứng dụng chat thời gian thực.
Bai viet co huu ich khong?
Bản quyền thuộc về tác giả. Vui lòng dẫn nguồn khi chia sẻ.



