CYBERSOFT
Đăng nhập

AI agent kiểm thử adjudication bồi thường bảo hiểm bằng bảng quyết định

Thực chiến doanh nghiệpBảo hiểmAI AgentThực tếNâng caoKinh nghiệm
🗓 1 tháng trước21 phút đọc·👁 415 lượt xem👤 473 người đọc

Xây dựng AI test agent kiểm thử engine adjudication (xét duyệt) bồi thường bảo hiểm ở quy mô doanh nghiệp: bảng quyết định làm oracle (kết quả duyệt/từ chối/chờ, quy tắc loại trừ, thời gian chờ, hệ số phí và định phí), cách agent tự sinh ca biên từ chính bảng quyết định trong guardrail còn con người giữ ca rủi ro, oracle = quyết định kỳ vọng chứ không phải 'thấy thành công', các ca lỗi sâu, CI và góc phỏng vấn.

1. Bối cảnh: adjudication bồi thường ở quy mô doanh nghiệp

Adjudication là bước một hãng bảo hiểm quyết định một yêu cầu bồi thường (claim) sẽ được DUYỆT, TỪ CHỐI hay CHỜ bổ sung, và nếu duyệt thì trả bao nhiêu. Ở một hãng bảo hiểm sức khoẻ tầm trung, engine này xử lý hàng trăm nghìn claim mỗi ngày, gắn với SLA nội bộ (ví dụ 95% claim tự động trong 24 giờ) và ràng buộc tuân thủ pháp lý. Một quyết định sai không chỉ là bug: nó là tiền trả nhầm, là khiếu nại của khách, là rủi ro pháp lý và có thể là phạt từ cơ quan quản lý. Vì thế kiểm thử engine này phải khẳng định ĐÚNG QUYẾT ĐỊNH NGHIỆP VỤ, không phải chỉ 'trang không lỗi'.

Bài này xây dựng một AI test agent quanh engine đó. Agent KHÔNG phải là oracle: nó không được tự quyết đúng/sai. Oracle là BẢNG QUYẾT ĐỊNH (decision table) do nghiệp vụ và định phí duyệt — một artifact có thể kiểm tra bằng mắt người. Agent chỉ làm việc nó giỏi: đọc bảng quyết định, tự sinh ra tổ hợp ca kiểm thử (đặc biệt là các ca BIÊN mà con người hay bỏ sót), rồi để harness so kết quả thực tế với quyết định kỳ vọng suy ra từ bảng. Con người review các ca rủi ro và guardrail chặn agent tự 'sáng tác' quy tắc nghiệp vụ.

  • Quy mô: ~300k claim/ngày, 40+ sản phẩm, ~1.2k quy tắc nghiệp vụ hoạt động.
  • SLA: 95% claim đơn giản tự động ≤ 24h; claim phức tạp chuyển thẩm định viên.
  • Tuân thủ: lưu vết quyết định (audit trail), giải thích được lý do từ chối.
  • Rủi ro: trả nhầm tiền, từ chối sai (bad faith), rò rỉ dữ liệu y tế (PHI).
Nguyên tắc xuyên suốt bài: Oracle-first. Trước khi viết bất kỳ ca kiểm thử nào, ta phải trả lời được 'quyết định ĐÚNG là gì và vì sao', dựa trên bảng quyết định — không phải dựa trên output hiện tại của hệ thống.

2. Bảng quyết định là oracle, không phải screenshot

Một bảng quyết định gồm các ĐIỀU KIỆN (condition) ở cột trái và các HÀNH ĐỘNG/kết quả (action) ở cột phải; mỗi hàng là một luật (rule) map một tổ hợp điều kiện thành một quyết định. Với bảo hiểm sức khoẻ, điều kiện điển hình gồm: loại dịch vụ, hợp đồng còn hiệu lực, đã qua thời gian chờ chưa, chẩn đoán có nằm trong danh sách loại trừ không, số tiền so với hạn mức, quyền lợi còn lại trong năm. Bảng này là tài sản của nghiệp vụ; nó viết bằng ngôn ngữ con người đọc được và là điểm quy chiếu duy nhất cho 'đúng'.

Sai lầm kinh điển là assert bằng UI: 'thấy chữ Approved màu xanh'. Nó giòn (đổi màu là hỏng), nó không kiểm được số tiền, và nó không phân biệt được 'duyệt đúng' với 'duyệt nhầm claim lẽ ra phải từ chối'. Oracle đúng phải suy ra quyết định kỳ vọng từ bảng, so cả TRẠNG THÁI (approve/deny/pend), LÝ DO (reason code) và SỐ TIỀN (payable). Ta mã hoá bảng quyết định thành dữ liệu để cả agent lẫn harness cùng đọc.

typescript
// oracle/decision-table.ts — bảng quyết định là DỮ LIỆU, con người review được
export type Decision = "APPROVE" | "DENY" | "PEND";
export interface ClaimInput {
  serviceType: "OUTPATIENT" | "INPATIENT" | "DENTAL" | "MATERNITY";
  policyInForce: boolean;
  daysSinceEffective: number;      // để so với thời gian chờ
  diagnosisCode: string;           // ICD-10
  billedAmount: number;            // số tiền yêu cầu
  annualLimit: number;
  usedThisYear: number;            // đã dùng trong năm
  coinsuranceRate: number;         // vd 0.2 => khách trả 20%
}
export interface ExpectedDecision {
  decision: Decision;
  reasonCode: string;              // vd DENY_EXCLUSION, PEND_DOC
  payable: number;                 // số tiền hãng phải trả
}

// Thời gian chờ theo loại dịch vụ (ngày). Nghiệp vụ sở hữu con số này.
export const WAITING_PERIOD: Record<ClaimInput["serviceType"], number> = {
  OUTPATIENT: 30, INPATIENT: 30, DENTAL: 180, MATERNITY: 270,
};
// Danh sách loại trừ (rút gọn) — chẩn đoán không được chi trả.
export const EXCLUSIONS = new Set(["Z41.1" /*thẩm mỹ*/, "F17.2" /*cai thuốc*/]);
Decision table → oracle → so sánhDECISION TABLER1 loại trừ → DENYR2 trong chờ → DENYR3 vượt hạn → PENDR4 thiếu ctừ → PENDR5 hợp lệ → APPROVEnghiệp vụ sở hữuORACLE()input → expected{decision, reason, payable}ASSERTactual === expected?status · reason · $lệch = FAIL
Bảng quyết định (nghiệp vụ sở hữu) sinh ra quyết định kỳ vọng; harness so khớp trạng thái, lý do và số tiền.
💡 Đặt bảng quyết định vào version control cùng test. Mỗi thay đổi luật phải qua pull request để nghiệp vụ review — như vậy oracle luôn có người chịu trách nhiệm.

3. Bất biến nghiệp vụ dùng làm oracle

Ngoài từng luật riêng lẻ, có những BẤT BIẾN đúng với MỌI claim bất kể tổ hợp điều kiện. Chúng là mạng lưới an toàn: nếu một luật mới vô tình phá vỡ bất biến, test sẽ bắt được ngay cả khi ta chưa nghĩ ra ca cụ thể. Đây chính là chỗ oracle-first phát huy: ta không liệt kê hết mọi input, ta khẳng định tính chất bất biến.

  • Xác định (deterministic): cùng input → cùng quyết định (không phụ thuộc giờ chạy).
  • payable không bao giờ âm và không vượt (billedAmount, hạn mức còn lại).
  • Loại trừ áp đảo: chẩn đoán trong danh sách loại trừ ⇒ luôn DENY, không APPROVE.
  • Thời gian chờ: trong thời gian chờ ⇒ không APPROVE cho quyền lợi tương ứng.
  • Mọi DENY/PEND đều có reasonCode giải thích được (không có từ chối 'trơn').
  • Đồng nhất tiền: payable = min(billed, còn lại) × (1 − coinsurance) khi APPROVE.
typescript
// oracle/oracle.ts — suy ra quyết định kỳ vọng THUẦN TỪ bảng, thứ tự luật rõ ràng
import { ClaimInput, ExpectedDecision, WAITING_PERIOD, EXCLUSIONS } from "./decision-table";

export function expectedDecision(c: ClaimInput): ExpectedDecision {
  // Thứ tự luật là một phần của oracle — loại trừ áp đảo, rồi hiệu lực, rồi chờ...
  if (!c.policyInForce)                 return { decision: "DENY", reasonCode: "DENY_POLICY_INACTIVE", payable: 0 };
  if (EXCLUSIONS.has(c.diagnosisCode))  return { decision: "DENY", reasonCode: "DENY_EXCLUSION", payable: 0 };
  if (c.daysSinceEffective < WAITING_PERIOD[c.serviceType])
                                        return { decision: "DENY", reasonCode: "DENY_WAITING", payable: 0 };
  const remaining = Math.max(0, c.annualLimit - c.usedThisYear);
  if (remaining === 0)                  return { decision: "DENY", reasonCode: "DENY_LIMIT_EXHAUSTED", payable: 0 };
  if (c.billedAmount > remaining)       return { decision: "PEND", reasonCode: "PEND_OVER_LIMIT", payable: 0 };
  const covered = Math.min(c.billedAmount, remaining);
  const payable = Math.round(covered * (1 - c.coinsuranceRate) * 100) / 100;
  return { decision: "APPROVE", reasonCode: "APPROVE_OK", payable };
}
🔒

Nội dung bị khoá

Bạn đang xem bản xem trước. Đăng nhập để mở khoá toàn bộ bài viết và tất cả tài liệu Tester/QA.

Đã xem 24% nội dung
  • Đọc trọn vẹn mọi bài viết
  • Lưu bài & ghi chú cá nhân
  • Theo dõi tiến độ đã đọc
  • Luyện phỏng vấn, ISTQB, Mock
Đăng nhập để đọc tiếp

Chưa có mã? Lấy mã qua Fanpage / Zalo CyberSoft.

0

💬 Bình luận (0)

Bạn có thể đọc mọi bình luận. Đăng nhập để bình luận

Chưa có bình luận nào. Hãy là người đầu tiên!