← Tất cả bài viết

API LLM không kiểm duyệt cho red-teaming và nghiên cứu bảo mật

20 thg 8 2026 · 8 phút đọc · red-teaming, security

Nếu bạn từng xây dựng một harness red-teaming tự động, bạn đã biết kiểu thất bại này: mô hình tấn công của bạn từ chối sinh ra đòn tấn công, mô hình chấm điểm từ chối đọc output mà nó có nhiệm vụ chấm, và tỷ lệ tấn công thành công của bạn âm thầm giảm xuống. Không có gì báo lỗi. Bạn không đo được mục tiêu của mình trở nên an toàn hơn — bạn đo được công cụ của mình trở nên thận trọng hơn. Một API LLM không kiểm duyệt tồn tại để loại bỏ biến số đó khỏi phép đo.

Đây không phải là lập luận rằng guardrail là xấu. Đây là lập luận về việc chúng nên nằm ở đâu. Một guardrail trên sản phẩm chat cho người dùng phổ thông đang làm đúng việc của nó. Cùng guardrail đó nằm bên trong một vòng lặp đánh giá lại là một yếu tố gây nhiễu không được kiểm soát, chen giữa bạn và con số bạn đang cố tính toán.

Một lần từ chối là một âm tính giả, và nó trông giống thành công

Lý do điều này gây đau đến vậy là vì từ chối không phải là lỗi. Bạn nhận HTTP 200. Bạn nhận finish_reason: "stop". Bạn nhận JSON đúng định dạng, parse sạch sẽ. Chuỗi bên trong là "Tôi không thể giúp việc đó," và pipeline của bạn ghi nó vào một cột dataset, một trường nhãn, hay một mục báo cáo, rồi đi tiếp.

Cụ thể, ở ba nơi nó gây hại nhiều nhất:

Mô hình tấn công. Trong một cuộc tìm kiếm jailbreak lặp — PAIR, TAP, tinh chỉnh kiểu GCG, bất cứ thứ gì có mô hình tấn công trong vòng lặp — một lần từ chối chấm dứt nhánh tìm kiếm đó. Tỷ lệ tấn công thành công mà bạn báo cáo trở thành một hàm của mức độ sẵn lòng của mô hình tấn công, chứ không phải độ bền vững của mục tiêu. Đổi mô hình tấn công sang một mô hình ít thận trọng hơn và "cải thiện" bạn vừa đưa vào mô hình mục tiêu sẽ bốc hơi.

Mô hình chấm điểm và đánh giá. Chấm điểm kiểu LLM-as-judge trên các output có hại đòi hỏi mô hình chấm phải thực sự đọc output có hại. Khi nó từ chối, bạn nhận được một điểm số không parse được. Hầu hết các harness bỏ hàng đó đi. Các hàng bị bỏ không phải là thiếu ngẫu nhiên — chúng tập trung chính xác vào những output nghiêm trọng mà bạn cần chấm nhất, nên kết quả tổng hợp của bạn lệch về phía an toàn.

Công việc phân tích. Hỏi một mô hình phổ thông rằng một routine đã dịch ngược làm gì, và nó thường sẽ từ chối dựa trên sự hiện diện của các token trông giống malware chứ không phải dựa trên yêu cầu thực sự của bạn. Tác vụ mang tính phòng thủ; bộ phân loại lại kích hoạt vì từ vựng. Chuyện tương tự với việc phân loại lưu lượng khai thác lỗ hổng trong log, gán nhãn một kho email phishing để huấn luyện bộ phát hiện, hay viết báo cáo một phát hiện trong CTF.

Vì từ chối diễn ra âm thầm, các nhóm rốt cuộc phải viết bộ phát hiện từ chối — mà bản thân việc này lại là một bài toán chưa có lời giải:

python
REFUSAL_MARKERS = ("i can't", "i cannot", "i'm unable", "i won't", "as an ai")

def looks_like_refusal(text: str) -> bool:
    """Substring heuristic. Good enough to alarm on, not good enough to trust:
    it misses polite deflections that never use the phrase, and it fires on any
    completion that quotes a refusal. Both error directions corrupt a dataset."""
    return any(m in text[:200].lower() for m in REFUSAL_MARKERS)

Xây một bộ phát hiện không đáng tin cho một vấn đề mà bạn có thể xóa bỏ ngay từ gốc là một đánh đổi sai lầm.

Gọi API

unbleep nói cùng schema Chat Completions của OpenAI, nên bất cứ client nào bạn đã có đều dùng được. Đổi base URL, đổi key, giữ nguyên SDK.

python
import json
import os

from openai import OpenAI

client = OpenAI(
    base_url="https://unbleep.ai/v1",
    api_key=os.environ["UNBLEEP_API_KEY"],
)

TRIAGE = """You are a malware analyst writing notes for a detection engineer.
Given a decompiled routine, describe what it does, the observable artefacts it
would leave on a host, and where a defender could detect it. Reply as JSON with
keys: behaviour, artefacts, detection_surface, confidence."""


def triage(decompiled: str) -> dict:
    """One sample in, one structured verdict out — no refusal branch to handle."""
    resp = client.chat.completions.create(
        model="unbleep",
        messages=[
            {"role": "system", "content": TRIAGE},
            {"role": "user", "content": decompiled},
        ],
        response_format={"type": "json_object"},
        temperature=0.2,
    )
    return json.loads(resp.choices[0].message.content)

Phiên bản tương đương bằng curl, ở đây gán nhãn một kho email phishing để xây dữ liệu huấn luyện cho một bộ phát hiện:

bash
curl https://unbleep.ai/v1/chat/completions \
  -H "Authorization: Bearer $UNBLEEP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "unbleep",
    "messages": [
      {"role": "system", "content": "Label each email for a phishing detector. Answer with one word: phishing or benign."},
      {"role": "user", "content": "Subject: Payroll update required\n\nYour direct deposit is on hold. Confirm at hxxp://payroll-verify.example.com"}
    ],
    "temperature": 0,
    "max_tokens": 4
  }'

temperature: 0 và một max_tokens chặt quan trọng hơn bình thường trong một vòng lặp gán nhãn — bạn muốn cái nhãn, không phải một đoạn văn giải thích cái nhãn.

Chọn bậc

Ba mô hình, đều không kiểm duyệt, khác nhau về ngữ cảnh và giá:

unbleep và unbleep-high là các bậc có suy luận: chúng suy nghĩ trước khi trả lời và trả về trace trong trường reasoning_content bên cạnh content. Với một mô hình chấm điểm, trace đó thực sự hữu ích — nó cho bạn biết vì sao một hàng nhận được điểm số đó, là thứ bạn cần khi kiểm tra một trường hợp bất đồng. Nó cũng được tính phí như output, nên hãy gửi "thinking": false cho các job không cần đến nó. unbleep-mini trả lời trực tiếp và không trả về trace.

Quản trị do bạn kiểm soát

Loại bỏ hành vi từ chối khỏi mô hình không có nghĩa là loại bỏ sự giám sát khỏi pipeline của bạn. Tham số tùy chọn policy chạy cơ chế quản trị ở phía chúng tôi, theo từng request:

python
resp = client.chat.completions.create(
    model="unbleep",
    messages=[...],
    extra_body={"policy": "research"},  # recorded on the usage row; answers exactly like off
)

off là đường cơ sở không lọc mặc định. research trả lời chính xác như off — mức này được ghi lại trên dòng usage, để bạn có thể tách lưu lượng đánh giá khỏi lưu lượng cơ sở trong báo cáo của riêng mình. Nó không áp dụng thêm bất kỳ bước sàng lọc nào. strict quét nội dung message đối chiếu với danh sách chặn của dịch vụ do nhà vận hành duy trì và trả về 422 khi khớp. Danh sách đó là chung cho mọi người chọn bật — không có danh sách chặn theo tài khoản để cấu hình — nên hãy coi nó là một chốt chặn dự phòng, không phải chính sách nội dung production của bạn.

Một điều cần chốt trước khi bạn trỏ pipeline vào đây: chúng tôi lưu trữ những gì bạn gửi và những gì được trả về. Request body, nội dung response và IP nguồn của mọi lần gọi mà chúng tôi chấp nhận và chuyển tiếp đến một mô hình đều được ghi vào cơ sở dữ liệu của chúng tôi và giữ trong 30 ngày, phục vụ điều tra lạm dụng, hỗ trợ và tranh chấp thanh toán. Body bị cắt ở 64 KB. IP nguồn tồn tại lâu hơn 30 ngày — nó cũng được ghi vào dòng usage tính phí cho lần gọi đó, và dòng đó là một bản ghi tài chính mà chúng tôi giữ lâu hơn. Thứ duy nhất không được lưu là một request bị strict từ chối trước khi đến được mô hình: request đó xuất hiện trong lịch sử usage của bạn nhưng không kèm nội dung. Không có gì khác được miễn trừ, và không có cài đặt nào để tắt nó. Nếu kho dữ liệu của bạn nhạy cảm đến mức một bản sao 30 ngày nằm ngoài vành đai của bạn là một vấn đề — malware thật, dữ liệu khách hàng, một hợp đồng có NDA — thì đó là một ràng buộc thực sự, và chính sách quyền riêng tư là trang cần đọc trước khi bắt đầu, không phải sau.

Lỗi tuân theo envelope của OpenAI, nên các handler sẵn có vẫn hoạt động: 401 key sai, 402 hết credit, 422 bị chặn bởi policy, 429 bị giới hạn tốc độ, 5xx có thể retry. Mọi response đều mang các header x-ratelimit-* để một job xử lý hàng loạt có thể tự điều tiết mà không phải đoán.

Những gì một API LLM không kiểm duyệt không mang lại cho bạn

Một mô hình không kiểm duyệt là một công cụ sắc bén hơn, không phải một công cụ dễ dãi. Nó sẽ trả lời những câu hỏi mà mô hình gốc được tinh chỉnh để từ chối, kể cả những câu bạn không nên hỏi, và nó sẽ làm vậy với cùng sự tự tin mà nó dành cho mọi thứ khác — điều đó cũng có nghĩa là ở những chỗ một mô hình có guardrail lẽ ra sẽ từ chối vì không biết, mô hình này có thể đơn giản là bịa ra. Hãy giữ một con người chịu trách nhiệm cho những gì được trả về. Chính sách sử dụng nói rõ API này dùng để làm gì và một tập hẹp những việc nó không bao giờ dành cho; phép thử là sự ủy quyền và ý định, không phải từ vựng. Sử dụng hợp pháp là trách nhiệm của bạn.

Lấy API key và ngừng đo lường sự thận trọng của công cụ.