promptfoo: viết test cho prompt và chạy eval LLM trong CI
Tóm tắt
promptfoo là CLI mã nguồn mở để test prompt, agent và RAG. Viết test case bằng YAML với assertion xác định hoặc chấm bằng model, chạy trên nhiều model và chặn PR khi chất lượng tụt.
Team sửa một dòng trong system prompt để chữa một lỗi khách báo, deploy, và tuần sau phát hiện ba tính năng khác bị "lệch giọng" hoặc trả sai format. Với phần mềm thường, ta có unit test để bắt hồi quy; với ứng dụng LLM, nhiều team vẫn kiểm thử bằng cách… thử vài câu bằng tay. promptfoo (repo promptfoo/promptfoo, MIT) là công cụ CLI để viết test cho prompt, agent và RAG, so sánh nhiều model, và chạy trong CI như unit test. README cho biết dự án đã được OpenAI mua lại nhưng vẫn là mã nguồn mở MIT.
Bắt đầu trong 5 phút
npx promptfoo@latest init --example getting-started
cd getting-started
export ANTHROPIC_API_KEY=...
npx promptfoo@latest eval # chạy bộ test
npx promptfoo@latest view # mở giao diện web xem kết quả dạng bảng
Cũng cài được bằng npm install -g promptfoo, brew hoặc pip. Eval chạy cục bộ, có cache để chạy lại nhanh.
Cấu trúc file cấu hình
Mọi thứ nằm trong promptfooconfig.yaml: prompt nào, chạy trên model nào, với bộ test nào:
prompts:
- file://prompts/triage.txt
providers:
- anthropic:messages:claude-haiku-5-5
- anthropic:messages:claude-sonnet-5-5
tests:
- vars:
ticket: "Tôi bị trừ tiền 2 lần cho cùng một đơn"
assert:
- type: is-json
- type: javascript
value: JSON.parse(output).priority === 'P1'
- type: latency
threshold: 5000
- vars:
ticket: "Làm sao xuất báo cáo ra Excel?"
assert:
- type: icontains
value: how_to
- type: llm-rubric
value: Không hứa hẹn tính năng không tồn tại
weight: 2
Kết quả là một ma trận: hàng là test case, cột là model. Bạn thấy ngay model rẻ có đạt yêu cầu không, prompt mới có làm hỏng case cũ không.
Các loại assertion
| Nhóm | Ví dụ | Dùng khi |
|---|---|---|
| Chuỗi | equals, contains, icontains, regex, contains-any | Kiểm tra từ khoá, nhãn phân loại |
| Định dạng | is-json, contains-json, is-sql, is-refusal | Output phải parse được |
| Code tuỳ chỉnh | javascript, python, webhook | Logic nghiệp vụ cụ thể |
| Hiệu năng | latency, cost | Đặt trần thời gian/chi phí |
| Agent/tool | is-valid-function-call, trajectory:tool-used | Kiểm tra agent gọi đúng tool |
| Chấm bằng model | llm-rubric, factuality, context-faithfulness, similar | Tiêu chí mềm: giọng văn, đúng ngữ cảnh RAG |
Thêm tiền tố not- để phủ định (not-contains). weight đặt trọng số (mặc định 1, đặt 0 để chỉ ghi metric); threshold ở cấp test cho phép pass khi điểm trung bình có trọng số đủ ngưỡng.
Đưa vào CI
- Commit
promptfooconfig.yamlvà thư mục prompt vào repo, cạnh code. - Thêm job CI chạy
promptfoo evalkhi PR đụng tới thư mục prompt. - Fail PR nếu tỉ lệ pass dưới ngưỡng; đính kèm link báo cáo để reviewer xem diff từng case.
- Mỗi bug từ production → thêm một test case. Bộ test lớn dần như regression suite.
Ngoài eval, promptfoo có chế độ red teaming để quét lỗ hổng (prompt injection, rò rỉ dữ liệu…) và sinh báo cáo, rất hữu ích trước khi mở chatbot ra ngoài.
Rủi ro và lưu ý
- LLM chấm LLM không tuyệt đối:
llm-rubriccó thể chấm sai. Ưu tiên assertion xác định (JSON, regex, code) khi có thể; dùng rubric cho phần còn lại và thỉnh thoảng kiểm tra tay. - Chi phí eval: 200 case × 3 model × chấm bằng model = nhiều lượt gọi. Dùng model nhỏ để chấm, bật cache, chỉ chạy khi prompt đổi.
- Kết quả dao động: output LLM không cố định. Có thể chạy lặp và dùng ngưỡng tỉ lệ thay vì đòi 100%.
- Dữ liệu test: case lấy từ ticket thật phải ẩn danh trước khi commit.
Áp dụng thế nào?
- Dev: Bắt đầu với 20 case thật cho prompt quan trọng nhất, chủ yếu assertion xác định. Chạy trước mỗi lần sửa prompt.
- Tech Lead: Đưa eval vào CI như unit test; dùng ma trận đa model để chứng minh khi nào hạ được xuống model rẻ hơn.
- PM: Viết tiêu chí chất lượng thành rubric cụ thể ("không hứa hẹn tính năng", "trả lời bằng tiếng Việt"). Đó chính là acceptance criteria cho tính năng AI.
Nguồn & tham khảo
- promptfoo — GitHub repository — promptfoo
- Assertions & metrics — promptfoo docs