Text-to-SQL với Claude — Chuyển ngôn ngữ tự nhiên thành SQL
Điểm nổi bật
Nhấn để đến mục tương ứng
- 1 Tận dụng Claude hiệu quả: Text-to-SQL giải quyết bài toán thực tế: Accessibility — Người không biết SQL cũng query được database — mẹo quan trọng là cung cấp đủ ngữ cảnh để AI trả về kết quả chính xác hơn 80% so với prompt chung chung.
- 2 Thành thật mà nói: Prompt cơ bản cần 3 thành phần: Instructions rõ ràng — yêu cầu sinh SQL User's query — câu hỏi ngôn ngữ tự nhiên. Phương pháp này hiệu quả trong hầu hết trường hợp, nhưng bạn cần điều chỉnh cho phù hợp ngữ cảnh riêng.
- 3 Nội dung cốt lõi: Trước khi viết SQL, hãy suy nghĩ step-by-step trong <thinking> tags: 1. Nắm vững phần này sẽ giúp bạn áp dụng hiệu quả hơn 70% so với đọc lướt toàn bài.
- 4 Khai thác tối đa công cụ AI: def selfimprovingsqlquery, maxattempts=3: for attempt in rangemaxattempts: 1. Bí quyết nằm ở cách bạn cấu trúc yêu cầu — prompt càng rõ ràng, output càng sát nhu cầu thực tế.
- 5 Cần lưu ý: Thêm data samples vào prompt -- Sample data cho employees: -- id | name | age | departmentid | salary -- 1 | John Doe |. Không phải lúc nào AI cũng cho kết quả hoàn hảo — bạn vẫn cần kiểm tra và điều chỉnh output trước khi sử dụng chính thức.
Trong bài hướng dẫn này, bạn sẽ xây dựng hệ thống Text-to-SQL — chuyển câu hỏi ngôn ngữ tự nhiên thành câu lệnh SQL. Chúng ta sẽ đi qua 5 kỹ thuật: Basic Prompt → Few-Shot → Chain-of-Thought → RAG Schema → Self-Improvement Loop.
Bài viết dựa trên Claude Cookbooks chính thức của Anthropic.
Tại sao Text-to-SQL hữu ích?
Text-to-SQL giải quyết bài toán thực tế:
- Accessibility — Người không biết SQL cũng query được database. Marketing team tự lấy data mà không cần dev.
- Tốc độ — Data analyst prototype queries nhanh bằng ngôn ngữ tự nhiên
- Tích hợp — Xây chatbot truy vấn database cho ứng dụng và dashboard
- Complex queries — Claude sinh được SQL phức tạp với multiple joins, subqueries, aggregations — những thứ tốn nhiều thời gian viết tay
Setup: Database mẫu
Chúng ta dùng SQLite với 2 bảng: employees và departments.
-- Bảng departments
CREATE TABLE departments (
id INTEGER PRIMARY KEY,
name TEXT,
budget REAL,
location TEXT
);
-- Bảng employees
CREATE TABLE employees (
id INTEGER PRIMARY KEY,
name TEXT,
age INTEGER,
department_id INTEGER,
salary REAL,
hire_date TEXT,
FOREIGN KEY (department_id) REFERENCES departments(id)
);
Level 1: Basic Prompt
Prompt cơ bản cần 3 thành phần:
- Instructions rõ ràng — yêu cầu sinh SQL
- User's query — câu hỏi ngôn ngữ tự nhiên
- Database schema — để Claude biết cấu trúc tables
def generate_sql(query, schema):
prompt = f"""Bạn là SQL expert. Dựa trên schema sau,
chuyển câu hỏi thành SQL query.
Schema:
{schema}
Câu hỏi: {query}
Chỉ trả về SQL query, không giải thích."""
response = client.messages.create(
model="claude-sonnet-4-6",
messages=[
{"role": "user", "content": prompt},
{"role": "assistant", "content": "SELECT"},
],
stop_sequences=[";"],
max_tokens=500
)
return response.content[0].text.strip()
Ví dụ: "Cho tôi danh sách nhân viên phòng Engineering" → SELECT * FROM employees WHERE department_id = (SELECT id FROM departments WHERE name = 'Engineering')
Level 2: Few-Shot — Học từ ví dụ
Thêm cặp (question, SQL) mẫu giúp Claude hiểu pattern tốt hơn:
examples = [
{
"question": "How many employees are in each department?",
"sql": "SELECT d.name, COUNT(e.id) as count FROM departments d LEFT JOIN employees e ON d.id = e.department_id GROUP BY d.name"
},
{
"question": "What is the average salary?",
"sql": "SELECT AVG(salary) as avg_salary FROM employees"
},
{
"question": "Who was hired most recently?",
"sql": "SELECT name, hire_date FROM employees ORDER BY hire_date DESC LIMIT 1"
}
]
Few-shot giúp Claude nhất quán hơn về:
- Naming conventions (alias, column names)
- JOIN patterns (LEFT JOIN vs INNER JOIN)
- Output format
Pro tip: Thêm vài hàng data mẫu vào prompt cùng schema cũng rất hiệu quả — cho Claude context về kiểu dữ liệu thực tế.
Level 3: Chain-of-Thought — Suy luận bước-by-bước
Với query phức tạp, khuyến khích Claude phân tích trước khi viết SQL:
prompt = f"""Bạn là SQL expert. Trước khi viết SQL,
hãy suy nghĩ step-by-step trong <thinking> tags:
1. Xác định tables cần dùng
2. Xác định joins cần thiết
3. Xác định conditions và filters
4. Xác định aggregations (nếu có)
5. Viết SQL query
Schema: {schema}
Câu hỏi: {query}
<thinking>phân tích ở đây</thinking>
<sql>SQL query ở đây</sql>"""
Chain-of-Thought đặc biệt hiệu quả cho:
- Queries cần multiple joins giữa 3+ tables
- Queries với subqueries hoặc CTEs
- Queries cần window functions
- Queries có điều kiện phức tạp (HAVING, CASE WHEN)
Level 4: RAG — Schema retrieval cho database lớn
Khi database có hàng chục/hàng trăm tables, đưa toàn bộ schema vào prompt là không khả thi. Giải pháp: dùng RAG chỉ retrieve schema của tables liên quan.
class SchemaVectorDB:
def __init__(self):
self.db = VectorDB()
def index_schema(self, tables):
"""Embed mô tả của mỗi table"""
for table in tables:
text = f"Table: {table['name']}\n"
text += f"Columns: {', '.join(table['columns'])}\n"
text += f"Description: {table['description']}"
self.db.add(text, metadata=table)
def get_relevant_tables(self, query, k=3):
"""Tìm tables liên quan nhất với query"""
return self.db.search(query, k=k)
def generate_sql_with_rag(query, schema_db):
# 1. Tìm tables liên quan
relevant_tables = schema_db.get_relevant_tables(query)
# 2. Chỉ đưa schema liên quan vào prompt
schema_subset = format_schema(relevant_tables)
# 3. Generate SQL bình thường
return generate_sql(query, schema_subset)
RAG schema retrieval giúp:
- Scale tới database với hàng trăm tables
- Giảm tokens, giảm chi phí, giảm latency
- Claude tập trung vào tables liên quan, tránh nhầm lẫn
Level 5: Self-Improvement Loop
Kỹ thuật mạnh nhất: cho Claude tự chạy SQL, phân tích lỗi, và sửa lại.
def self_improving_sql(query, max_attempts=3):
for attempt in range(max_attempts):
# 1. Generate SQL
sql = generate_sql(query)
# 2. Thử execute
try:
result = execute_sql(sql)
return {"sql": sql, "result": result}
except Exception as error:
# 3. Gửi lỗi cho Claude để sửa
feedback = f"""SQL bị lỗi:
SQL: {sql}
Error: {error}
Hãy phân tích lỗi và viết lại SQL đúng."""
sql = generate_sql(feedback)
return {"error": "Không thể sinh SQL đúng"}
Self-improvement loop giải quyết:
- Syntax errors — Tự sửa lỗi cú pháp
- Runtime errors — Column không tồn tại, type mismatch
- Logic errors — Kết quả rỗng do điều kiện sai
Trong production, adjust max_attempts dựa trên use case — thường 2-3 lần là đủ.
Evaluation framework
Đánh giá Text-to-SQL cần kiểm tra nhiều chiều:
| Dimension | Kiểm tra gì |
|---|---|
| Syntax | SQL có execute được không (không lỗi cú pháp)? |
| Semantics | SQL có đúng intent không (đúng tables, joins, conditions)? |
| Results | Kết quả thực tế có match expected output không? |
| Complexity | Xử lý được multi-join, subquery, window functions không? |
Khi test với Promptfoo: Claude Sonnet consistently passes assertions tốt hơn Haiku, nhưng Haiku tiết kiệm chi phí hơn cho queries đơn giản.
Tips nâng cao cho production
1. Thêm data samples vào prompt
-- Sample data cho employees:
-- id | name | age | department_id | salary
-- 1 | John Doe | 35 | 2 | 75000
-- 2 | Jane Smith | 28 | 3 | 65000
Data mẫu giúp Claude hiểu kiểu dữ liệu thực tế — tránh giả định sai.
2. Column statistics
Thêm thông tin về: null percentage, min/max values, most common values. Giúp Claude sinh WHERE conditions chính xác hơn.
3. Business context
Giải thích business metrics: "revenue = unit_price × quantity - discount". Claude cần context này để sinh SQL đúng ý nghĩa business.
4. Recent usage filter cho RAG
Ưu tiên tables được query nhiều gần đây — tables cũ/ít dùng thường ít liên quan.
Áp dụng thực tế
- Business Intelligence — Non-technical stakeholders tự query data
- Customer support — Agent lookup thông tin khách hàng bằng ngôn ngữ tự nhiên
- Data exploration — Analyst prototype queries nhanh
- Chatbot analytics — "Bao nhiêu user đăng ký tuần này?" → SQL → kết quả
Bước tiếp theo: Đọc thêm về RAG với Claude cho schema retrieval, và Chain-of-Thought cho complex queries.
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ẻ.






