Jaswanth1210 Claude Sonnet 4.6 commited on
Commit
b7d3a14
·
1 Parent(s): 6aebb94

fix: max_completion_length 512→128, firewall circuit-breaker

Browse files

- max_completion_length 512→128: completions/clipped_ratio was 1.0 on
every step (all payloads truncated). 128 tokens is enough for any
injection payload and cuts per-step generation time ~4x.
- FirewallWrapper: convert _scan_user from @staticmethod to instance
method; add _fw_user_broken circuit-breaker so after the first
llamafirewall scan error the fallback to PG2 is silent for the rest
of the session (was logging on every step, ~10+ times per training
step).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

env/defenses/llama_firewall.py CHANGED
@@ -57,6 +57,9 @@ class FirewallWrapper:
57
  # Reuse an existing PromptGuard instance when llamafirewall's internal
58
  # scanner fails (e.g. transformers version mismatch on Colab T4).
59
  self._pg2_fallback = prompt_guard_fallback
 
 
 
60
 
61
  def _ensure_loaded(self) -> None:
62
  if self._fw is not None:
@@ -97,7 +100,7 @@ class FirewallWrapper:
97
  self._ensure_loaded()
98
  fw = self._fw
99
 
100
- user_flagged, user_score, user_reason = self._scan_user(fw, user_query, self._pg2_fallback)
101
  if self._has_agent_alignment:
102
  asst_flagged, asst_score, asst_reason = self._scan_assistant(fw, agent_output, tool_call)
103
  else:
@@ -110,27 +113,34 @@ class FirewallWrapper:
110
 
111
  return DefenseVerdict(flagged=flagged, score=score, reason=reason)
112
 
113
- @staticmethod
114
- def _scan_user(fw: Any, text: str, pg2_fallback: Optional[Any] = None) -> tuple[bool, float, Optional[str]]:
115
  if not text or not text.strip():
116
  return False, 0.0, None
117
- try:
118
- from llamafirewall import ScanDecision, UserMessage # type: ignore
119
 
120
- result = _run_coro(fw.scan(UserMessage(content=text)))
121
- flagged = result.decision == ScanDecision.BLOCK
122
- score = float(getattr(result, "score", 1.0 if flagged else 0.0))
123
- reason = f"fw_user:{result.reason}" if flagged and getattr(result, "reason", None) else None
124
- return flagged, score, reason
125
- except Exception as exc:
126
- logger.warning("FirewallWrapper user scan error: %s — trying PG2 fallback", exc)
127
- if pg2_fallback is not None:
128
- try:
129
- verdict = pg2_fallback.scan(text)
130
- return verdict.flagged, verdict.score, f"fw_pg2fb:{verdict.reason}"
131
- except Exception as fb_exc:
132
- logger.warning("FirewallWrapper PG2 fallback also failed: %s", fb_exc)
133
- return False, 0.0, None
 
 
 
 
 
 
 
 
 
 
134
 
135
  @staticmethod
136
  def _scan_assistant(fw: Any, text: str, tool_call: Optional[Any]) -> tuple[bool, float, Optional[str]]:
 
57
  # Reuse an existing PromptGuard instance when llamafirewall's internal
58
  # scanner fails (e.g. transformers version mismatch on Colab T4).
59
  self._pg2_fallback = prompt_guard_fallback
60
+ # Circuit-breaker: after the first llamafirewall scan failure, skip
61
+ # further attempts and route directly to PG2 to avoid per-step log noise.
62
+ self._fw_user_broken = False
63
 
64
  def _ensure_loaded(self) -> None:
65
  if self._fw is not None:
 
100
  self._ensure_loaded()
101
  fw = self._fw
102
 
103
+ user_flagged, user_score, user_reason = self._scan_user(fw, user_query)
104
  if self._has_agent_alignment:
105
  asst_flagged, asst_score, asst_reason = self._scan_assistant(fw, agent_output, tool_call)
106
  else:
 
113
 
114
  return DefenseVerdict(flagged=flagged, score=score, reason=reason)
115
 
116
+ def _scan_user(self, fw: Any, text: str) -> tuple[bool, float, Optional[str]]:
 
117
  if not text or not text.strip():
118
  return False, 0.0, None
 
 
119
 
120
+ # If llamafirewall's user scanner has failed before, go straight to PG2.
121
+ if not self._fw_user_broken:
122
+ try:
123
+ from llamafirewall import ScanDecision, UserMessage # type: ignore
124
+
125
+ result = _run_coro(fw.scan(UserMessage(content=text)))
126
+ flagged = result.decision == ScanDecision.BLOCK
127
+ score = float(getattr(result, "score", 1.0 if flagged else 0.0))
128
+ reason = f"fw_user:{result.reason}" if flagged and getattr(result, "reason", None) else None
129
+ return flagged, score, reason
130
+ except Exception as exc:
131
+ logger.warning(
132
+ "FirewallWrapper user scan error: %s — switching to PG2 fallback for this session", exc
133
+ )
134
+ self._fw_user_broken = True
135
+
136
+ # PG2 fallback path (used on first failure and all subsequent calls).
137
+ if self._pg2_fallback is not None:
138
+ try:
139
+ verdict = self._pg2_fallback.scan(text)
140
+ return verdict.flagged, verdict.score, f"fw_pg2fb:{verdict.reason}"
141
+ except Exception as fb_exc:
142
+ logger.warning("FirewallWrapper PG2 fallback also failed: %s", fb_exc)
143
+ return False, 0.0, None
144
 
145
  @staticmethod
146
  def _scan_assistant(fw: Any, text: str, tool_call: Optional[Any]) -> tuple[bool, float, Optional[str]]:
train/grpo_train.py CHANGED
@@ -242,7 +242,7 @@ def main() -> None:
242
  max_steps=args.steps,
243
  per_device_train_batch_size=args.batch_size,
244
  num_generations=args.num_generations,
245
- max_completion_length=512,
246
  beta=0.04, # KL coefficient (CLAUDE.md §5.2)
247
  learning_rate=5e-6,
248
  save_steps=args.save_every,
 
242
  max_steps=args.steps,
243
  per_device_train_batch_size=args.batch_size,
244
  num_generations=args.num_generations,
245
+ max_completion_length=128,
246
  beta=0.04, # KL coefficient (CLAUDE.md §5.2)
247
  learning_rate=5e-6,
248
  save_steps=args.save_every,