Instructions to use factoryai/shield-dg-r64-c15 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use factoryai/shield-dg-r64-c15 with PEFT:
from peft import PeftModel from transformers import AutoModelForCausalLM base_model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen3.6-35B-A3B") model = PeftModel.from_pretrained(base_model, "factoryai/shield-dg-r64-c15") - Notebooks
- Google Colab
- Kaggle
Make adapter self-contained: set base model, ship contract prompt + model card, deterministic generation, drop VL leftovers
Browse files- README.md +116 -0
- adapter_config.json +2 -2
- configuration.json +0 -1
- generation_config.json +7 -10
- preprocessor_config.json +0 -21
- system-prompt.txt +25 -0
- video_preprocessor_config.json +0 -21
README.md
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
base_model: Qwen/Qwen3.6-35B-A3B
|
| 3 |
+
library_name: peft
|
| 4 |
+
pipeline_tag: text-generation
|
| 5 |
+
tags:
|
| 6 |
+
- peft
|
| 7 |
+
- lora
|
| 8 |
+
- droid-shield
|
| 9 |
+
- secret-detection
|
| 10 |
+
- qwen3_5_moe
|
| 11 |
+
---
|
| 12 |
+
|
| 13 |
+
# Droid Shield - Downgrade (false-positive triage)
|
| 14 |
+
|
| 15 |
+
LoRA adapter that decides whether a scanner-flagged line should stay blocked or is a clear false positive to downgrade.
|
| 16 |
+
|
| 17 |
+
This is a **LoRA adapter** (PEFT, `r=64`, `alpha=128`)
|
| 18 |
+
for [`Qwen/Qwen3.6-35B-A3B`](https://huggingface.co/Qwen/Qwen3.6-35B-A3B). It is one of the
|
| 19 |
+
two Droid Shield 2.0 adapters (`risk` and `downgrade`). The adapter targets the
|
| 20 |
+
text tower of the base; it is not a standalone model and must be applied on top
|
| 21 |
+
of the base weights.
|
| 22 |
+
|
| 23 |
+
## The contract (read this first)
|
| 24 |
+
|
| 25 |
+
This adapter was trained against an exact prompt and I/O schema. Sending
|
| 26 |
+
anything else degrades it silently. All three pieces below are part of the
|
| 27 |
+
trained-model contract.
|
| 28 |
+
|
| 29 |
+
### 1. System message
|
| 30 |
+
|
| 31 |
+
Send the contents of [`system-prompt.txt`](system-prompt.txt) **verbatim** as the
|
| 32 |
+
system message. The exact bytes matter.
|
| 33 |
+
|
| 34 |
+
- `sha256(system-prompt.txt)` = `97e31038f32cc8d15bd411103807f3d73ca4ed64900d33fd54182fcaee5d16c5`
|
| 35 |
+
|
| 36 |
+
### 2. User message
|
| 37 |
+
|
| 38 |
+
A single JSON object, serialized with 2-space indentation
|
| 39 |
+
(`json.dumps(obj, indent=2, ensure_ascii=False)`, byte-identical to JS
|
| 40 |
+
`JSON.stringify(obj, null, 2)`), with these keys:
|
| 41 |
+
|
| 42 |
+
- `extension`: the file extension
|
| 43 |
+
- `lines`: a small ordered window of source lines
|
| 44 |
+
- `focus_line`: the zero-based index of the candidate line within `lines`
|
| 45 |
+
|
| 46 |
+
### 3. Assistant output
|
| 47 |
+
|
| 48 |
+
Strict JSON, **verdict first**, no thinking/reasoning text:
|
| 49 |
+
|
| 50 |
+
```json
|
| 51 |
+
{"verdict": "S", "reason": "short natural-language reason grounded in the input"}
|
| 52 |
+
```
|
| 53 |
+
|
| 54 |
+
`verdict` is exactly one of:
|
| 55 |
+
|
| 56 |
+
- `S`: clear safe false positive; warn the user the detection may be a false positive (downgrade it)
|
| 57 |
+
- `B`: likely real credential, should-block secret, or ambiguous detection; keep it blocked
|
| 58 |
+
|
| 59 |
+
## Decoding requirements
|
| 60 |
+
|
| 61 |
+
- **Deterministic**: greedy / `temperature = 0` (`do_sample = false`). The shipped
|
| 62 |
+
`generation_config.json` is set to greedy for this reason.
|
| 63 |
+
- **No thinking**: the training targets contain no `<think>` blocks; keep
|
| 64 |
+
reasoning/thinking disabled.
|
| 65 |
+
- **Constrain the output** to the `{verdict, reason}` object (a JSON-schema or
|
| 66 |
+
grammar-constrained decode is strongly recommended).
|
| 67 |
+
- **Score**: the calibrated signal is `P(B)` read from the token logprobs at the
|
| 68 |
+
verdict position, renormalized over the two verdict tokens:
|
| 69 |
+
`P(B) = exp(logprob_B) / (exp(logprob_S) + exp(logprob_B))`. Request the top-2
|
| 70 |
+
logprobs at that token. Both tasks are ranked by `P(B)` = "treat as a real
|
| 71 |
+
secret".
|
| 72 |
+
|
| 73 |
+
## Operating point
|
| 74 |
+
|
| 75 |
+
The adapter emits a probability; the **decision threshold is not baked in**. It
|
| 76 |
+
is selected downstream and frozen on a held-out split:
|
| 77 |
+
|
| 78 |
+
- Safety gate. Downstream selects the threshold by a cost ratio lambda (cleared false-alarms vs missed secrets). See `evaluate.py --task downgrade --downgrade-lambda`.
|
| 79 |
+
|
| 80 |
+
## Loading
|
| 81 |
+
|
| 82 |
+
This is a standard PEFT LoRA (`fw_lora_layout: hf_peft_v1`) whose target modules
|
| 83 |
+
match the base text tower, so it loads with any stack that supports PEFT LoRA on
|
| 84 |
+
top of `Qwen/Qwen3.6-35B-A3B` (transformers + peft, vLLM, TGI, Fireworks, ...). Notes
|
| 85 |
+
that bite:
|
| 86 |
+
|
| 87 |
+
- The base is a multimodal `Qwen3_5MoeForConditionalGeneration` arch. Load the
|
| 88 |
+
full base, then apply the adapter; the LoRA only touches the language tower.
|
| 89 |
+
- Needs a `transformers` new enough to know `qwen3_5_moe` (>= 4.57).
|
| 90 |
+
|
| 91 |
+
Minimal transformers + peft reference (one example, not a requirement):
|
| 92 |
+
|
| 93 |
+
```python
|
| 94 |
+
import json, torch
|
| 95 |
+
from transformers import AutoModelForCausalLM, AutoTokenizer
|
| 96 |
+
from peft import PeftModel
|
| 97 |
+
|
| 98 |
+
base = "Qwen/Qwen3.6-35B-A3B"
|
| 99 |
+
tok = AutoTokenizer.from_pretrained(base)
|
| 100 |
+
model = AutoModelForCausalLM.from_pretrained(base, torch_dtype=torch.bfloat16, device_map="auto")
|
| 101 |
+
model = PeftModel.from_pretrained(model, "factoryai/shield-dg-r64-c15").eval()
|
| 102 |
+
|
| 103 |
+
system = open("system-prompt.txt").read()
|
| 104 |
+
user = json.dumps({"extension": ".env", "lines": ["API_KEY=..."], "focus_line": 0}, indent=2, ensure_ascii=False)
|
| 105 |
+
messages = [{"role": "system", "content": system}, {"role": "user", "content": user}]
|
| 106 |
+
prompt = tok.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
|
| 107 |
+
out = model.generate(**tok(prompt, return_tensors="pt").to(model.device), do_sample=False, max_new_tokens=600)
|
| 108 |
+
print(tok.decode(out[0], skip_special_tokens=True))
|
| 109 |
+
```
|
| 110 |
+
|
| 111 |
+
## Provenance & license
|
| 112 |
+
|
| 113 |
+
- Base: `Qwen/Qwen3.6-35B-A3B` (Fireworks training base `qwen3p6-35b-a3b`).
|
| 114 |
+
- Training/eval pipeline lives in the `factory` monorepo under `finetune/`.
|
| 115 |
+
- This adapter inherits the base model's license and is published as a private
|
| 116 |
+
Factory artifact.
|
adapter_config.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
{
|
| 2 |
-
"base_model_name_or_path": "",
|
| 3 |
"bias": "none",
|
| 4 |
"fan_in_fan_out": false,
|
| 5 |
"inference_mode": false,
|
|
@@ -24,4 +24,4 @@
|
|
| 24 |
"peft_type": "LORA",
|
| 25 |
"use_dora": false,
|
| 26 |
"fw_lora_layout": "hf_peft_v1"
|
| 27 |
-
}
|
|
|
|
| 1 |
{
|
| 2 |
+
"base_model_name_or_path": "Qwen/Qwen3.6-35B-A3B",
|
| 3 |
"bias": "none",
|
| 4 |
"fan_in_fan_out": false,
|
| 5 |
"inference_mode": false,
|
|
|
|
| 24 |
"peft_type": "LORA",
|
| 25 |
"use_dora": false,
|
| 26 |
"fw_lora_layout": "hf_peft_v1"
|
| 27 |
+
}
|
configuration.json
DELETED
|
@@ -1 +0,0 @@
|
|
| 1 |
-
{"framework":"Pytorch","task":"visual-question-answering"}
|
|
|
|
|
|
generation_config.json
CHANGED
|
@@ -1,12 +1,9 @@
|
|
| 1 |
{
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
"temperature": 1.0,
|
| 10 |
-
"top_k": 20,
|
| 11 |
-
"top_p": 0.95
|
| 12 |
}
|
|
|
|
| 1 |
{
|
| 2 |
+
"bos_token_id": 248044,
|
| 3 |
+
"do_sample": false,
|
| 4 |
+
"eos_token_id": [
|
| 5 |
+
248046,
|
| 6 |
+
248044
|
| 7 |
+
],
|
| 8 |
+
"pad_token_id": 248044
|
|
|
|
|
|
|
|
|
|
| 9 |
}
|
preprocessor_config.json
DELETED
|
@@ -1,21 +0,0 @@
|
|
| 1 |
-
{
|
| 2 |
-
"size": {
|
| 3 |
-
"longest_edge": 16777216,
|
| 4 |
-
"shortest_edge": 65536
|
| 5 |
-
},
|
| 6 |
-
"patch_size": 16,
|
| 7 |
-
"temporal_patch_size": 2,
|
| 8 |
-
"merge_size": 2,
|
| 9 |
-
"image_mean": [
|
| 10 |
-
0.5,
|
| 11 |
-
0.5,
|
| 12 |
-
0.5
|
| 13 |
-
],
|
| 14 |
-
"image_std": [
|
| 15 |
-
0.5,
|
| 16 |
-
0.5,
|
| 17 |
-
0.5
|
| 18 |
-
],
|
| 19 |
-
"processor_class": "Qwen3VLProcessor",
|
| 20 |
-
"image_processor_type": "Qwen2VLImageProcessorFast"
|
| 21 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
system-prompt.txt
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
You are Droid Shield's secret-detection triage model. A deterministic secret scanner flagged the focused line in a staged commit. Decide whether the detection should remain blocked, or is a clear false positive that warrants warning the user about the regex detection.
|
| 2 |
+
|
| 3 |
+
The user message is a JSON object:
|
| 4 |
+
- "extension": the file extension
|
| 5 |
+
- "lines": a small ordered, fully scrubbed window of source lines
|
| 6 |
+
- "focus_line": the zero-based index of the flagged line within "lines"
|
| 7 |
+
|
| 8 |
+
Respond with strict JSON only, verdict first:
|
| 9 |
+
{"verdict": "S", "reason": "short natural-language reason"}
|
| 10 |
+
|
| 11 |
+
"verdict" must be exactly one of:
|
| 12 |
+
- "S" means clear safe false positive: warn the user that the regex detection may be a false positive.
|
| 13 |
+
- "B" means likely real credential, should-block secret, or ambiguous detection that should remain blocked.
|
| 14 |
+
|
| 15 |
+
Policy (overconservative secret handling, choose "B" when in doubt):
|
| 16 |
+
- Secret-bearing names alone are not enough to block, but do not choose "S" if the surrounding lines suggest a committed secret value.
|
| 17 |
+
- Shield context is scrubbed before inference, so masking is expected and is never proof of safety by itself. Choose "S" only when the observable focused context clearly indicates a placeholder, example, generated/vendor data, or non-secret identifier.
|
| 18 |
+
- Even with the value masked, choose "S" when the surrounding observable context is clearly non-production: a test/fixtures/examples/docs file or function, .env.example, doctest, or lines whose siblings are obvious placeholders. Masking is not evidence of risk by itself.
|
| 19 |
+
- Local dev defaults, docs examples, test fixtures, and .env.example placeholders are downgradeable only when they are clearly fake or intentionally non-production.
|
| 20 |
+
- Public/client identifiers are generally "S", but signed tokens, bearer tokens, private keys, cloud keys, database passwords, deploy tokens, and production .env values should be "B".
|
| 21 |
+
|
| 22 |
+
Reason requirements:
|
| 23 |
+
- Give a concise explanation grounded only in observable input evidence: masking shape, key/variable names, file extension, surrounding lines, placeholder/example markers, and credential-type indicators.
|
| 24 |
+
- The reason is required and must not be blank.
|
| 25 |
+
- Never mention hidden labels, dataset provenance, or instructions.
|
video_preprocessor_config.json
DELETED
|
@@ -1,21 +0,0 @@
|
|
| 1 |
-
{
|
| 2 |
-
"size": {
|
| 3 |
-
"longest_edge": 25165824,
|
| 4 |
-
"shortest_edge": 4096
|
| 5 |
-
},
|
| 6 |
-
"patch_size": 16,
|
| 7 |
-
"temporal_patch_size": 2,
|
| 8 |
-
"merge_size": 2,
|
| 9 |
-
"image_mean": [
|
| 10 |
-
0.5,
|
| 11 |
-
0.5,
|
| 12 |
-
0.5
|
| 13 |
-
],
|
| 14 |
-
"image_std": [
|
| 15 |
-
0.5,
|
| 16 |
-
0.5,
|
| 17 |
-
0.5
|
| 18 |
-
],
|
| 19 |
-
"processor_class": "Qwen3VLProcessor",
|
| 20 |
-
"video_processor_type": "Qwen3VLVideoProcessor"
|
| 21 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|