{"product_id":"tạo-test-data-tự-dộng-với-claude-synthetic-test-generation","title":"Tạo test data tự động với Claude — Synthetic Test Generation","description":"\n\u003cp\u003eXây dựng eval system cần test data đa dạng và chất lượng cao. Viết tay hàng trăm test cases tốn nhiều thời gian và thường thiếu đa dạng. \u003cstrong\u003eSynthetic data generation\u003c\/strong\u003e dùng chính Claude để tạo test data — nhanh hơn 10x và đa dạng hơn khi được hướng dẫn đúng cách.\u003c\/p\u003e\n\n\u003ch2\u003eBài toán: Khi nào cần synthetic test data?\u003c\/h2\u003e\n\n\u003cul\u003e\n  \u003cli\u003eMới bắt đầu dự án, chưa có real-world data\u003c\/li\u003e\n  \u003cli\u003eCần test edge cases khó kiếm trong thực tế (tiếng địa phương, lỗi chính tả cố ý, v.v.)\u003c\/li\u003e\n  \u003cli\u003eCần nhanh chóng mở rộng từ 20 lên 200 test cases\u003c\/li\u003e\n  \u003cli\u003eCần data với golden answers sẵn có để đánh giá tự động\u003c\/li\u003e\n\u003c\/ul\u003e\n\n\u003ch2\u003eBước 1: Phân tích prompt template để extract variables\u003c\/h2\u003e\n\n\u003cp\u003eĐầu tiên, ta phân tích prompt template để hiểu cần generate data gì:\u003c\/p\u003e\n\n\u003cpre\u003e\u003ccode\u003eimport anthropic\nimport json\nimport re\n\nclient = anthropic.Anthropic()\n\ndef extract_template_variables(prompt_template: str) -\u0026gt; list:\n    \"\"\"Extract các biến từ prompt template.\"\"\"\n    # Tìm các placeholder dạng {variable_name}\n    variables = re.findall(r\"{(w+)}\", prompt_template)\n    return list(set(variables))\n\n# Ví dụ prompt template\nSENTIMENT_PROMPT = \"\"\"Phân loại cảm xúc của review sản phẩm sau:\n\nReview: {review_text}\n\nPhân loại: POSITIVE, NEGATIVE, hay NEUTRAL?\nChỉ trả lời một từ.\"\"\"\n\nvariables = extract_template_variables(SENTIMENT_PROMPT)\nprint(f\"Variables cần generate: {variables}\")\n# Output: ['review_text']\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch2\u003eBước 2: Tạo synthetic examples với Claude\u003c\/h2\u003e\n\n\u003cpre\u003e\u003ccode\u003eGENERATOR_PROMPT = \"\"\"Tạo {n} ví dụ test đa dạng cho bài toán: {task_description}\n\nYêu cầu:\n- Đa dạng về độ dài (ngắn, trung bình, dài)\n- Đa dạng về style (formal, informal, mixed)\n- Bao gồm edge cases: tiếng lóng, lỗi chính tả, câu mơ hồ\n- Mỗi ví dụ phải có golden answer chính xác\n- Phân bổ đều: ~40% POSITIVE, ~35% NEGATIVE, ~25% NEUTRAL\n\nTrả về JSON array với format:\n[\n  {{\n    \"id\": \"ex_001\",\n    \"input\": \"{{review_text}}\",\n    \"golden\": \"POSITIVE|NEGATIVE|NEUTRAL\",\n    \"difficulty\": \"easy|medium|hard\",\n    \"notes\": \"mô tả ngắn tại sao đây là ví dụ thú vị\"\n  }}\n]\n\nChỉ trả về JSON, không có text khác.\"\"\"\n\ndef generate_synthetic_data(task_description: str, n: int = 20) -\u0026gt; list:\n    prompt = GENERATOR_PROMPT.format(\n        n=n,\n        task_description=task_description\n    )\n\n    response = client.messages.create(\n        model=\"claude-sonnet-4-5\",  # Dùng model mạnh để tạo data chất lượng\n        max_tokens=4000,\n        messages=[{\"role\": \"user\", \"content\": prompt}],\n        temperature=0.8,  # Cao hơn để tăng độ đa dạng\n    )\n\n    text = response.content[0].text.strip()\n\n    # Parse JSON\n    # Xử lý trường hợp Claude wrap trong code block\n    if text.startswith(\"'''\"):\n        text = re.sub(r\"^'''(?:json)?\n?\", \"\", text)\n        text = re.sub(r\"\n?'''$\", \"\", text)\n\n    examples = json.loads(text)\n    return examples\n\n# Tạo test data cho sentiment analysis\nexamples = generate_synthetic_data(\n    task_description=\"Phân loại cảm xúc review sản phẩm e-commerce Việt Nam (POSITIVE\/NEGATIVE\/NEUTRAL)\",\n    n=30\n)\n\nprint(f\"Đã tạo {len(examples)} examples\")\nfor ex in examples[:3]:\n    print(f\"\n[{ex['golden']}] ({ex['difficulty']}) {ex['input'][:80]}...\")\n    print(f\"  Notes: {ex['notes']}\")\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch2\u003eBước 3: Validate và filter synthetic data\u003c\/h2\u003e\n\n\u003cp\u003eSynthetic data đôi khi có lỗi — Claude tạo golden answer sai, hoặc example không tự nhiên. Cần validate:\u003c\/p\u003e\n\n\u003cpre\u003e\u003ccode\u003edef validate_example(example: dict, original_prompt: str) -\u0026gt; dict:\n    \"\"\"\n    Validate một synthetic example bằng cách:\n    1. Chạy qua actual model\n    2. So sánh output với golden answer\n    3. Flag nếu model không đồng ý với golden answer\n    \"\"\"\n    # Inject input vào template\n    full_prompt = original_prompt.replace(\n        \"{review_text}\",\n        example[\"input\"]\n    )\n\n    response = client.messages.create(\n        model=\"claude-haiku-4-5\",\n        max_tokens=20,\n        messages=[{\"role\": \"user\", \"content\": full_prompt}],\n        temperature=0.0,\n    )\n\n    model_output = response.content[0].text.strip().upper()\n    golden = example[\"golden\"].upper()\n\n    # Model đồng ý với golden?\n    agreement = golden in model_output\n\n    return {\n        **example,\n        \"model_output\": model_output,\n        \"model_agrees\": agreement,\n        \"validation_status\": \"valid\" if agreement else \"check_needed\",\n    }\n\ndef validate_dataset(examples: list, prompt_template: str) -\u0026gt; dict:\n    \"\"\"Validate toàn bộ dataset.\"\"\"\n    validated = []\n    for ex in examples:\n        result = validate_example(ex, prompt_template)\n        validated.append(result)\n\n    agreed = sum(1 for ex in validated if ex[\"model_agrees\"])\n    print(f\"Model đồng ý với golden answer: {agreed}\/{len(validated)} ({agreed\/len(validated):.1%})\")\n\n    # Tách ra hai nhóm\n    clean = [ex for ex in validated if ex[\"model_agrees\"]]\n    needs_review = [ex for ex in validated if not ex[\"model_agrees\"]]\n\n    print(f\"Clean examples: {len(clean)}\")\n    print(f\"Cần review: {len(needs_review)}\")\n\n    for ex in needs_review[:5]:\n        print(f\"\n  MISMATCH: '{ex['input'][:60]}...'\")\n        print(f\"  Golden: {ex['golden']} | Model: {ex['model_output']}\")\n\n    return {\"clean\": clean, \"needs_review\": needs_review}\n\nresults = validate_dataset(examples, SENTIMENT_PROMPT)\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch2\u003eBước 4: Iterative refinement\u003c\/h2\u003e\n\n\u003cp\u003eSau validation, ta có thể cải thiện dataset bằng cách phân tích failures:\u003c\/p\u003e\n\n\u003cpre\u003e\u003ccode\u003edef analyze_failures_and_regenerate(needs_review: list, n_new: int = 10) -\u0026gt; list:\n    \"\"\"\n    Phân tích các cases model không đồng ý, sau đó tạo thêm examples\n    tương tự nhưng rõ ràng hơn.\n    \"\"\"\n    if not needs_review:\n        print(\"Không có failures để phân tích!\")\n        return []\n\n    # Tạo summary của failures\n    failure_summary = \"\n\".join([\n        f\"- Input: '{ex['input'][:50]}...' | Golden: {ex['golden']} | Model nói: {ex['model_output']}\"\n        for ex in needs_review[:10]\n    ])\n\n    analysis_prompt = f\"\"\"Phân tích các ví dụ test data sau mà model AI phân loại sai:\n\n{failure_summary}\n\nTại sao những ví dụ này gây nhầm lẫn? Sau đó tạo {n_new} ví dụ MỚI tương tự nhưng rõ ràng hơn,\nvới golden answer dứt khoát không mơ hồ.\n\nTrả về JSON array với cùng format như trước. Chỉ JSON.\"\"\"\n\n    response = client.messages.create(\n        model=\"claude-sonnet-4-5\",\n        max_tokens=3000,\n        messages=[{\"role\": \"user\", \"content\": analysis_prompt}],\n        temperature=0.5,\n    )\n\n    text = response.content[0].text.strip()\n    if text.startswith(\"'''\"):\n        text = re.sub(r\"^'''(?:json)?\n?\", \"\", text)\n        text = re.sub(r\"\n?'''$\", \"\", text)\n\n    new_examples = json.loads(text)\n    print(f\"Đã tạo thêm {len(new_examples)} examples từ failure analysis\")\n    return new_examples\n\nnew_examples = analyze_failures_and_regenerate(results[\"needs_review\"])\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch2\u003eBước 5: Tạo few-shot examples từ synthetic data\u003c\/h2\u003e\n\n\u003cp\u003eSynthetic data không chỉ dùng cho eval — ta còn dùng để tạo few-shot examples cải thiện prompt:\u003c\/p\u003e\n\n\u003cpre\u003e\u003ccode\u003edef create_few_shot_examples(clean_examples: list, n_per_class: int = 3) -\u0026gt; str:\n    \"\"\"Chọn best examples để làm few-shot examples trong prompt.\"\"\"\n    by_class = {}\n    for ex in clean_examples:\n        label = ex[\"golden\"]\n        if label not in by_class:\n            by_class[label] = []\n        by_class[label].append(ex)\n\n    selected = []\n    for label, exs in by_class.items():\n        # Ưu tiên các examples dễ (clear signal) và đa dạng\n        easy_ones = [ex for ex in exs if ex.get(\"difficulty\") == \"easy\"]\n        chosen = (easy_ones[:n_per_class] if len(easy_ones) \u0026gt;= n_per_class\n                  else exs[:n_per_class])\n        selected.extend(chosen)\n\n    # Format thành few-shot text\n    few_shot_text = \"Dưới đây là một số ví dụ:\n\n\"\n    for ex in selected:\n        few_shot_text += f\"Review: {ex['input']}\nPhân loại: {ex['golden']}\n\n\"\n\n    return few_shot_text\n\nfew_shots = create_few_shot_examples(results[\"clean\"])\nprint(few_shots[:500])\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch2\u003eTemplate Generator cho nhiều loại task\u003c\/h2\u003e\n\n\u003cpre\u003e\u003ccode\u003eTASK_TEMPLATES = {\n    \"sentiment\": {\n        \"description\": \"Phân loại cảm xúc text (POSITIVE\/NEGATIVE\/NEUTRAL)\",\n        \"classes\": [\"POSITIVE\", \"NEGATIVE\", \"NEUTRAL\"],\n        \"distribution\": {\"POSITIVE\": 0.4, \"NEGATIVE\": 0.35, \"NEUTRAL\": 0.25},\n    },\n    \"spam_detection\": {\n        \"description\": \"Phát hiện spam email\/comment (SPAM\/HAM)\",\n        \"classes\": [\"SPAM\", \"HAM\"],\n        \"distribution\": {\"SPAM\": 0.3, \"HAM\": 0.7},\n    },\n    \"intent_classification\": {\n        \"description\": \"Phân loại intent người dùng chatbot (BUY\/SUPPORT\/INFO\/COMPLAINT)\",\n        \"classes\": [\"BUY\", \"SUPPORT\", \"INFO\", \"COMPLAINT\"],\n        \"distribution\": {\"BUY\": 0.25, \"SUPPORT\": 0.3, \"INFO\": 0.3, \"COMPLAINT\": 0.15},\n    },\n}\n\ndef generate_for_task(task_type: str, n: int = 50) -\u0026gt; list:\n    if task_type not in TASK_TEMPLATES:\n        raise ValueError(f\"Unknown task: {task_type}\")\n\n    template = TASK_TEMPLATES[task_type]\n    dist_str = \", \".join(\n        f\"~{int(v*100)}% {k}\"\n        for k, v in template[\"distribution\"].items()\n    )\n\n    return generate_synthetic_data(\n        task_description=f\"{template['description']}. Phân bổ: {dist_str}\",\n        n=n\n    )\n\n# Tạo data cho spam detection\nspam_data = generate_for_task(\"spam_detection\", n=40)\nprint(f\"Generated {len(spam_data)} spam detection examples\")\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003ch2\u003eLưu và tái sử dụng dataset\u003c\/h2\u003e\n\n\u003cpre\u003e\u003ccode\u003eimport json\nfrom datetime import datetime\n\ndef save_dataset(examples: list, task_name: str):\n    filename = f\"synthetic_data_{task_name}_{datetime.now().strftime('%Y%m%d')}.json\"\n    with open(filename, \"w\", encoding=\"utf-8\") as f:\n        json.dump({\n            \"task\": task_name,\n            \"created_at\": datetime.now().isoformat(),\n            \"n_examples\": len(examples),\n            \"examples\": examples\n        }, f, ensure_ascii=False, indent=2)\n    print(f\"Saved {len(examples)} examples to {filename}\")\n\ndef load_dataset(filename: str) -\u0026gt; list:\n    with open(filename, \"r\", encoding=\"utf-8\") as f:\n        data = json.load(f)\n    return data[\"examples\"]\n\nsave_dataset(results[\"clean\"], \"sentiment_vi\")\u003c\/code\u003e\u003c\/pre\u003e\n\n\u003cp\u003eSynthetic test generation thay đổi hoàn toàn quy trình phát triển AI: thay vì chờ đủ real data mới bắt đầu evaluate, bạn có thể tạo dataset chất lượng cao trong vài phút và bắt đầu iterate ngay. Kết hợp với \u003ca href=\"\/en\/collections\/nang-cao\"\u003eBuilding Evals\u003c\/a\u003e để tạo vòng lặp cải thiện liên tục.\u003c\/p\u003e\n","brand":"Minh Tuấn","offers":[{"title":"Default Title","offer_id":47721829728468,"sku":null,"price":0.0,"currency_code":"VND","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/0821\/0264\/9044\/files\/t_o-test-data-t_-d_ng-v_i-claude-synthetic-test-generation.jpg?v=1774507547","url":"https:\/\/claude.vn\/en\/products\/t%e1%ba%a1o-test-data-t%e1%bb%b1-d%e1%bb%99ng-v%e1%bb%9bi-claude-synthetic-test-generation","provider":"CLAUDE.VN","version":"1.0","type":"link"}