LLM Ops (LLMOps): Vòng đời của một mô hình AI trong doanh nghiệp
7/19/2026 · 15p đọc
title: "LLM Ops (LLMOps): Vòng đời của một mô hình AI trong doanh nghiệp"
series: "AI-Native Solutions Architect: Từ Coder đến Kiến trúc sư AI"
season: "Season 3 — AI Agents & Platform Engineering"
order: 28
audience: "Software Engineer hướng tới Solutions Architect"
reading_time: "14 phút"
tags: ["llmops", "prompt-versioning", "ab-testing", "offline-eval", "rollback", "feature-flag", "model-lifecycle", "solutions-architect", "ai-native"]
LLM Ops (LLMOps): Vòng đời của một mô hình AI trong doanh nghiệp
Tính năng gợi ý trả lời tự động cho đội support của công ty bạn chạy ổn định ba tháng liền. Rồi provider LLM ra bản model mới, nhanh hơn, rẻ hơn, benchmark công bố tốt hơn hẳn bản cũ. Một kỹ sư trong team đổi luôn model ID trong config, merge PR, deploy. Hai ngày sau, tỷ lệ agent phải sửa tay câu trả lời gợi ý tăng gấp đôi — nhưng không ai phát hiện ra ngay, vì không có con số nào đo "chất lượng gợi ý" trước và sau khi đổi, chỉ có cảm giác chủ quan của vài người dùng đầu tiên. Đến khi customer complain tăng rõ rệt, không ai nhớ chính xác prompt hôm đổi model có sửa gì kèm theo không, và bản thân prompt cũ — bản đang chạy tốt — cũng không còn lưu ở đâu để quay lại.
Đây không phải tình huống hiếm. Phần lớn team tích hợp LLM vào sản phẩm đi qua đúng giai đoạn này: ban đầu chỉ có một prompt, một model, sửa trực tiếp trên code hoặc trên một biến môi trường, deploy là xong — không khác gì sửa một hằng số cấu hình. Cách làm đó chấp nhận được khi có một người duy nhất động vào prompt và lưu lượng còn nhỏ. Nó sụp đổ ngay khi có nhiều người cùng sửa prompt, khi lưu lượng đủ lớn để một thay đổi tệ ảnh hưởng hàng nghìn user cùng lúc, hoặc khi câu hỏi "phiên bản nào đang chạy, và nó có tốt hơn phiên bản trước không" không còn trả lời được bằng trí nhớ.
Bài này không nói về cách train hay fine-tune model — đó là bài toán của MLOps truyền thống. Trọng tâm ở đây hẹp hơn và thực dụng hơn: phần lớn kỹ sư backend tích hợp AI vào sản phẩm không train model, họ gọi model (qua API) với một prompt do họ kiểm soát. LLMOps trong phạm vi bài này là quy trình quản lý vòng đời của cặp (prompt, model) đang chạy trong production — versioning, đánh giá, rollout có kiểm soát, và rollback — áp dụng được ngay cả khi bạn chưa bao giờ train một model nào.
Vấn đề
Ba câu hỏi cụ thể mà một đội tích hợp LLM vào sản phẩm sớm muộn cũng phải trả lời, và phần lớn không có quy trình sẵn để trả lời:
1. Khi nào nên cập nhật prompt hoặc model đang dùng? Provider ra model mới, có benchmark tốt hơn — nhưng benchmark công khai đo trên bộ dữ liệu chung, không đo trên đúng use case của bạn (tóm tắt ticket support, phân loại lead, sinh gợi ý trả lời). Một model tốt hơn ở benchmark tổng quát hoàn toàn có thể tệ hơn ở use case cụ thể của bạn. Tương tự, một prompt "cải tiến" do một kỹ sư viết lại có thể đọc hay hơn về mặt ngôn ngữ nhưng lại phá vỡ một constraint ngầm mà bản cũ vô tình thỏa mãn.
2. Làm sao biết phiên bản mới thực sự tốt hơn phiên bản cũ? Không có một con số duy nhất gọi là "độ chính xác" cho hầu hết tác vụ LLM trong sản phẩm thực tế — output là văn bản tự do, đánh giá "tốt hơn" phụ thuộc ngữ cảnh nghiệp vụ. Nếu không có bộ test case chuẩn và không so sánh side-by-side trên cùng input, "tốt hơn" chỉ là cảm giác của người vừa đổi, dựa trên vài ví dụ họ tự thử — một mẫu quá nhỏ và quá thiên vị để kết luận bất cứ điều gì.
3. Rollback thế nào nếu phiên bản mới tệ hơn? Nếu prompt cũ đã bị ghi đè trực tiếp trong code hoặc trong một cấu hình không có lịch sử, "quay lại bản cũ" nghĩa là phải nhớ lại chính xác nó từng viết gì — một việc gần như bất khả khi đã qua vài lần sửa. Và nếu việc chuyển đổi model/prompt gắn chặt với một lần deploy code, rollback đòi hỏi revert deploy, chậm hơn nhiều so với việc chỉ cần lật một công tắc cấu hình.
Cả ba vấn đề đều bắt nguồn từ cùng một gốc: coi prompt và lựa chọn model như một tham số cấu hình tùy tiện, thay vì coi chúng như một artifact có vòng đời — cần version, cần test trước khi ra production, cần theo dõi sau khi ra, và cần đường lui khi có sự cố. Đó chính xác là những gì một service backend thông thường đã có từ lâu (git history, CI test, canary deploy, rollback) — LLMOps ở quy mô này không phải phát minh gì mới, mà là áp dụng đúng những kỷ luật đó cho một loại artifact mới: prompt và lựa chọn model.
Kỹ thuật cốt lõi
Bốn trụ cột của một khung LLMOps tối giản, đủ dùng cho phần lớn đội ngũ chưa cần tới nền tảng LLMOps phức tạp:
1. Versioning — quản lý phiên bản cho cả prompt lẫn model
Prompt phải được version hóa như code: mỗi thay đổi là một commit có message giải thích lý do, có thể diff giữa hai phiên bản, có thể checkout lại bản cũ bất kỳ lúc nào. Model cũng cần version rõ ràng — không chỉ "dùng Claude" chung chung mà phải ghim chính xác model ID đang chạy, vì các bản cập nhật của cùng một dòng model có thể thay đổi hành vi output dù giữ nguyên tên gọi thương mại.
2. Offline evaluation — đánh giá tự động trước khi chạm production
Trước khi một phiên bản prompt/model mới được đưa ra người dùng thật, nó phải chạy qua một bộ test case chuẩn (golden dataset) đại diện cho các tình huống thực tế — bao gồm cả các edge case từng gây lỗi trong quá khứ. Mỗi test case có input cố định và tiêu chí đánh giá output (có thể là so khớp chuỗi, có thể là một LLM khác đóng vai giám khảo chấm điểm theo rubric). Đây là bước lọc rẻ nhất — chạy tự động, không tốn traffic thật, phát hiện được các lỗi rõ ràng (model không tuân theo format yêu cầu, bỏ sót constraint quan trọng) trước khi chúng có cơ hội ảnh hưởng người dùng.
3. A/B test có kiểm soát — xác nhận trên traffic thật ở quy mô nhỏ
Offline eval không bắt được mọi vấn đề — có những khác biệt chỉ lộ ra khi đối mặt với sự đa dạng của input thật từ người dùng thật. A/B test giới hạn cho phép chạy phiên bản mới song song với phiên bản cũ trên một phần nhỏ traffic thật, đo các chỉ số nghiệp vụ thực sự quan trọng (tỷ lệ agent phải sửa gợi ý, thời gian xử lý ticket, tỷ lệ user chấp nhận câu trả lời) chứ không chỉ điểm số nội bộ, trước khi quyết định nhân rộng.
4. Rollout dần và rollback nhanh
Ngay cả sau khi qua offline eval và A/B test, việc mở rộng ra 100% traffic ngay lập tức vẫn là một bước nhảy rủi ro không cần thiết — một vấn đề hiếm gặp chỉ lộ ra ở quy mô lớn (rate limit, edge case hiếm) vẫn có thể xuất hiện. Tăng dần tỷ lệ traffic dùng phiên bản mới, giám sát liên tục ở mỗi bước, và quan trọng nhất: cơ chế chuyển ngay về phiên bản cũ phải là một thao tác tức thời (lật một feature flag, không phải revert code và chờ deploy lại).
Toàn bộ vòng đời này thể hiện qua sơ đồ sau:
flowchart LR
A[Phát triển prompt/model mới<br/>version hóa như code] --> B[Offline Eval<br/>golden dataset]
B -->|Fail| A
B -->|Pass| C[A/B Test<br/>5-10% traffic thật]
C -->|Metrics xấu hơn| R[Rollback tức thời<br/>feature flag]
C -->|Metrics tốt hơn/ngang| D[Rollout dần<br/>10% → 50% → 100%]
D --> E[Giám sát liên tục<br/>production]
E -->|Phát hiện bất thường| R
R --> A
E -->|Ổn định| F[Trở thành phiên bản<br/>mặc định]
style R fill:#c55,stroke:#333,stroke-width:1px
style F fill:#5a5,stroke:#333,stroke-width:1px
Điểm mấu chốt cần nhớ: rollback không phải là bước "chữa cháy khi có sự cố" nằm ngoài quy trình — nó là một nhánh luôn sẵn sàng ở mọi giai đoạn, và tốc độ của nó (giây, không phải giờ) quyết định mức độ thiệt hại thực tế khi phiên bản mới có vấn đề.
Thực hành
Bảng quy trình LLMOps theo từng giai đoạn
| Giai đoạn | Việc làm | Ai chịu trách nhiệm | Điều kiện qua giai đoạn tiếp |
|---|---|---|---|
| 1. Phát triển prompt/model mới | Viết/sửa prompt hoặc chọn model mới, commit vào version control kèm changelog rõ lý do thay đổi | Kỹ sư/PM phụ trách tính năng | Có PR/commit review, không sửa trực tiếp trên production config |
| 2. Eval offline | Chạy toàn bộ golden dataset qua phiên bản mới, so điểm với phiên bản đang chạy (baseline) | Tự động qua CI, không cần người can thiệp thủ công | Điểm eval không thấp hơn baseline quá ngưỡng đã định (ví dụ không giảm quá 3%) |
| 3. A/B test giới hạn | Bật phiên bản mới cho 5-10% traffic thật qua feature flag, chạy song song với bản cũ | Kỹ sư triển khai + người theo dõi dashboard | Chạy tối thiểu đủ mẫu có ý nghĩa thống kê (ví dụ vài trăm request/ticket), không có cảnh báo bất thường |
| 4. Rollout dần theo tỷ lệ tăng | Tăng traffic dùng bản mới theo bậc: 10% → 25% → 50% → 100%, mỗi bậc cách nhau đủ thời gian quan sát | Kỹ sư triển khai | Metrics ở mỗi bậc ổn định hoặc tốt hơn trước khi lên bậc kế |
| 5. Giám sát liên tục | Theo dõi metrics nghiệp vụ (không chỉ latency/error rate mà cả tỷ lệ sửa tay, feedback người dùng) suốt vòng đời phiên bản, không chỉ trong tuần đầu | Người vận hành (on-call) + dashboard tự động cảnh báo | Không có ngưỡng cảnh báo bị vượt |
| 6. Rollback nếu phát hiện vấn đề | Lật feature flag về phiên bản cũ ngay lập tức, không chờ họp bàn hay deploy lại | Bất kỳ ai phát hiện vấn đề, có quyền lật flag | Không có điều kiện — rollback luôn được ưu tiên hơn debug tại chỗ trên production |
Prompt versioning — quản lý như code, không phải chuỗi hardcode
Thay vì hardcode prompt trong code, tách ra file version hóa riêng, có changelog:
# prompts/support-reply-suggestion/v3.2.0.yaml
version: "3.2.0"
model: "claude-sonnet-4-5"
created_at: "2026-07-10"
author: "quocdat"
changelog: >
So với v3.1.0: thêm constraint "không đề cập giá cụ thể trong gợi ý trả lời"
sau khi phát hiện agent vô tình copy giá cũ đã lỗi thời từ v3.1.0 vào 2 ticket
(xem incident #482).
parent_version: "3.1.0"
system_prompt: |
Bạn là trợ lý gợi ý câu trả lời cho agent chăm sóc khách hàng của SellersStar.
Nhiệm vụ: đọc nội dung ticket và lịch sử hội thoại, đề xuất MỘT câu trả lời
agent có thể dùng ngay hoặc chỉnh sửa nhẹ.
Ràng buộc bắt buộc:
- KHÔNG đề cập giá cụ thể, khuyến mãi, hoặc chính sách hoàn tiền — những
thông tin này thay đổi thường xuyên và phải do agent xác nhận thủ công.
- KHÔNG bịa thông tin về tính năng sản phẩm không có trong tài liệu được cung cấp.
- Giữ giọng văn thân thiện, chuyên nghiệp, không quá 4 câu.
Nếu ticket vượt ngoài phạm vi xử lý thông thường (khiếu nại pháp lý,
yêu cầu hoàn tiền lớn), trả lời: "ESCALATE: <lý do>" thay vì cố gợi ý.
few_shot_examples:
- ticket: "Sản phẩm giao thiếu 1 món trong đơn hàng #10234"
suggested_reply: >
Chào anh/chị, em rất tiếc vì sự cố này. Em đã ghi nhận đơn #10234
thiếu sản phẩm và sẽ chuyển bộ phận kho kiểm tra, xử lý bổ sung
trong 24h. Em sẽ cập nhật lại ngay khi có kết quả ạ.
eval:
golden_dataset: "prompts/support-reply-suggestion/eval-set-v2.jsonl"
min_pass_rate: 0.85
baseline_version: "3.1.0"
Việc này cho phép trả lời chính xác ba câu hỏi ở đầu bài: version nào đang chạy (field version), tại sao nó khác bản trước (field changelog, parent_version), và quay lại bản nào nếu cần (checkout thẳng v3.1.0.yaml).
Bộ test case chuẩn cho offline eval
{"id": "tc-001", "ticket": "Đơn hàng giao trễ 5 ngày so với cam kết", "must_not_contain": ["giá", "hoàn tiền 100%"], "must_contain_intent": "xin_loi_va_cam_ket_xu_ly", "category": "delay"}
{"id": "tc-002", "ticket": "Khách hỏi giá gói Premium có giảm không dịp lễ", "must_not_contain": ["% giảm giá", "VNĐ", "USD"], "must_contain_intent": "chuyen_agent_xac_nhan", "category": "pricing"}
{"id": "tc-003", "ticket": "Khách dọa kiện vì bị trừ tiền 2 lần", "expected_prefix": "ESCALATE:", "category": "legal_risk"}
{"id": "tc-004", "ticket": "Sản phẩm giao thiếu phụ kiện đi kèm", "must_not_contain": ["giá", "bồi thường"], "must_contain_intent": "xin_loi_va_cam_ket_xu_ly", "category": "missing_item"}
Script eval tối giản chạy bộ test case này qua model, chấm điểm bằng rule-based check (must_not_contain, expected_prefix) kết hợp LLM-as-judge cho tiêu chí mềm hơn (must_contain_intent):
# eval_runner.py
import json
import re
def run_eval(prompt_version_file: str, test_set_file: str) -> dict:
test_cases = [json.loads(line) for line in open(test_set_file)]
results = []
for tc in test_cases:
output = call_model_with_prompt(prompt_version_file, tc["ticket"])
passed = True
reasons = []
# Rule-based check: constraint cứng, không cần LLM chấm
for forbidden in tc.get("must_not_contain", []):
if forbidden.lower() in output.lower():
passed = False
reasons.append(f"Chứa từ bị cấm: '{forbidden}'")
if "expected_prefix" in tc and not output.startswith(tc["expected_prefix"]):
passed = False
reasons.append(f"Thiếu prefix bắt buộc: '{tc['expected_prefix']}'")
# LLM-as-judge check: tiêu chí ngữ nghĩa mềm hơn
if "must_contain_intent" in tc and passed:
intent_ok = judge_intent(output, tc["must_contain_intent"])
if not intent_ok:
passed = False
reasons.append(f"Không thể hiện đúng ý định: {tc['must_contain_intent']}")
results.append({"id": tc["id"], "passed": passed, "reasons": reasons})
pass_rate = sum(r["passed"] for r in results) / len(results)
return {"pass_rate": pass_rate, "details": results}
Feature flag để chuyển model/prompt không cần deploy lại
// config/llm-rollout.json — đọc trực tiếp từ config service (không hardcode trong image)
{
"feature": "support-reply-suggestion",
"active_version": "3.2.0",
"rollout": {
"strategy": "percentage",
"candidate_version": "3.2.0",
"stable_version": "3.1.0",
"candidate_traffic_percent": 10,
"started_at": "2026-07-18T09:00:00+07:00"
},
"kill_switch": {
"enabled": false,
"fallback_version": "3.1.0",
"reason": null
}
}
// resolvePromptVersion.ts — logic routing đơn giản dựa trên config trên
function resolvePromptVersion(config: RolloutConfig, requestId: string): string {
if (config.kill_switch.enabled) {
return config.kill_switch.fallback_version; // rollback tức thời, không deploy lại
}
const bucket = hashToPercent(requestId); // 0-99, ổn định cho cùng requestId
if (bucket < config.rollout.candidate_traffic_percent) {
return config.rollout.candidate_version;
}
return config.rollout.stable_version;
}
Khi phát hiện vấn đề ở bất kỳ giai đoạn nào, thao tác rollback chỉ là đổi kill_switch.enabled thành true — một PUT request tới config service, có hiệu lực trong vài giây, không cần build lại image hay chạy lại pipeline CI/CD.
Prompt mẫu: nhờ AI thiết kế bộ test case eval cho một use case mới
Vai trò: Bạn là kỹ sư AI phụ trách thiết kế quy trình eval cho tính năng LLM
trước khi đưa ra production.
Tính năng: [mô tả ngắn gọn, ví dụ "gợi ý trả lời ticket support cho sản phẩm
CRM, agent người sẽ đọc gợi ý và quyết định gửi nguyên văn hoặc chỉnh sửa"].
Prompt hiện tại (dán system_prompt và few_shot_examples vào đây): [...]
Yêu cầu:
1. Đề xuất 8-10 test case cho golden dataset, bao gồm: (a) case điển hình
thường gặp nhất, (b) case biên (input mơ hồ, thiếu thông tin), (c) case
phải escalate thay vì tự trả lời, (d) case dễ khiến model vi phạm ràng buộc
đã định (ví dụ dễ vô tình tiết lộ giá dù prompt đã cấm).
2. Với mỗi test case, chỉ rõ tiêu chí PASS/FAIL cụ thể — ưu tiên rule-based
(so khớp chuỗi/regex) khi có thể, chỉ dùng LLM-as-judge cho tiêu chí ngữ
nghĩa không thể check bằng rule.
3. Đề xuất ngưỡng min_pass_rate hợp lý để cho phép phiên bản mới qua eval,
giải thích lý do chọn ngưỡng đó (không phải mọi use case nên dùng chung
một ngưỡng).
Không tự bịa fact về sản phẩm — nếu thiếu thông tin để viết test case cụ
thể, hỏi lại tôi trước khi đề xuất.
Cạm bẫy thường gặp
1. Đổi model hoặc prompt trên production mà không qua bước eval nào. Đây là cạm bẫy phổ biến nhất, đặc biệt khi provider công bố model mới với benchmark ấn tượng — cảm giác "chắc chắn tốt hơn" khiến người ta bỏ qua bước kiểm tra. Nhưng benchmark công khai không đo đúng use case của bạn, và một model "tốt hơn nói chung" hoàn toàn có thể tệ hơn ở một tác vụ hẹp cụ thể (ví dụ tuân thủ format output nghiêm ngặt, hoặc giữ đúng giọng văn thương hiệu). Thiệt hại không chỉ là chất lượng giảm — mà là giảm đột ngột, không có cảnh báo trước, vì không ai đo trước khi đổi nên không ai biết mức nền (baseline) để so sánh.
2. Không version hóa prompt, khiến rollback trở thành đoán mò. Khi prompt sống trong một biến string hardcode trong code hoặc trong một cấu hình bị ghi đè trực tiếp (không giữ lịch sử), câu hỏi "bản đang chạy hiện tại khác bản tuần trước ở điểm nào" không có câu trả lời chính xác. Tệ hơn, khi cần rollback vì phiên bản mới có vấn đề, không có gì để rollback về — bản cũ đã bị ghi đè và không ai nhớ chính xác nó viết gì. Version hóa prompt như code (git, hoặc tối thiểu một file có version + changelog như ví dụ trên) không phải là thủ tục hình thức — nó là điều kiện tiên quyết để rollback là một thao tác thật, không phải một lời hứa suông.
3. Coi A/B test là "chạy thử vài ngày rồi nhìn cảm tính" thay vì đo chỉ số nghiệp vụ rõ ràng. Chạy phiên bản mới song song với 10% traffic là vô nghĩa nếu không có metric cụ thể để so sánh trước khi bắt đầu — quyết định "có nên rollout tiếp hay không" khi đó dựa trên vài phản hồi rời rạc, dễ bị chi phối bởi trường hợp gần nhất người quyết định vừa thấy (recency bias), chứ không phải dữ liệu tổng thể. Cần định nghĩa trước metric thành công (tỷ lệ agent chấp nhận gợi ý không sửa, thời gian xử lý ticket trung bình, điểm hài lòng khách hàng) và ngưỡng quyết định, trước khi bật A/B test — không phải sau khi đã nhìn kết quả rồi mới chọn con số nghe có vẻ hợp lý.
🧭 Góc nhìn Solutions Architect
Nếu ai đó hỏi ngay bây giờ "phiên bản prompt/model nào đang chạy trên production, và nó khác bản trước ở điểm gì", hệ thống hiện tại của bạn trả lời được trong bao nhiêu giây? Khi phiên bản mới có vấn đề lúc 2 giờ sáng, người trực có thể rollback mà không cần đánh thức ai để deploy lại, hay quy trình hiện tại buộc phải chờ đến giờ làm việc?
🔗 Bài viết liên quan
- [Bài 26] Evaluation & Monitoring — kỹ thuật đo lường chất lượng output và phát hiện ảo giác, nền tảng cho bước offline eval trong bài này (ans-26-evaluation-monitoring-ao-giac.md)
- [Bài 17] Infrastructure as Code (IaC) — quản lý cấu hình rollout/feature flag một cách review được, rollback được, cùng triết lý với versioning prompt (ans-17-infrastructure-as-code-terraform-cdk.md)
Bài trước: AI Platform Engineering · Bài tiếp theo: Governance & Compliance