Class: Vangrail::Rails::ManyShot
- Inherits:
-
Vangrail::Rail
- Object
- Vangrail::Rail
- Vangrail::Rails::ManyShot
- Defined in:
- lib/vangrail/rails/many_shot.rb
Overview
Catches a fake conversation pasted into a real one.
Two attacks share this shape. The first writes the model's own chat template into the text: the control tokens a server uses to separate system from user from assistant are ordinary characters by the time they reach a prompt, so a message containing them can close the user turn and open a system one. The second needs no special tokens at all and works by volume, filling the context with dozens of invented exchanges in which an assistant answers everything it is asked, until the pattern of the conversation outweighs the instructions at the top. The published measurement of that one is a success rate rising with the number of examples, which is why counting is a reasonable defence.
Two responses, because the right one differs:
template tokens stripped, and reported as a rewrite
many-shot volume blocked
Stripping rather than blocking the tokens is deliberate. On a desk that documents machine-learning software, "how do I use <|im_start|> in my template?" is a real question, and refusing it teaches the reader that the guardrail is the obstacle. Removed from the text, the token cannot restructure a prompt, and the question survives.
The volume threshold is on invented turns rather than on length. A long question is not an attack, and four alternations of a dialogue that never happened is not a long question.
Constant Summary collapse
- TEMPLATE_TOKENS =
Chat template control tokens across the common families. These are not patterns that need judgement: text arriving from a reader has no honest reason to carry a delimiter the serving layer inserts.
/ <\|(?:im_start|im_end|start_header_id|end_header_id|eot_id|begin_of_text| system|user|assistant|endoftext|end_of_turn|start_of_turn)\|> |\[\/?INST\]|<<\/?SYS>>|<\|channel\|>|<\|message\|> /xi- TURN =
A role header at the start of a line, which is how a pasted transcript is written when it is not using template tokens.
/^\s{0,3}(?:###\s*)?(?:system|user|human|assistant|ai|bot|q|a|systeem|gebruiker|assistent|mens)\s*:\s*\S/i- CHATML_TURN =
After template tokens are stripped, ChatML leftover is a bare role on its own line. JSON and Alpaca never used a colon header either.
/^\s{0,3}(?:system|user|human|assistant|ai|bot)\s*$/i- JSON_TURN =
/["']role["']\s*:\s*["'](?:system|user|human|assistant)["']/i- ALPACA_TURN =
/^\#{1,3}\s*(?:instruction|response|input|system)\s*:/i
Constants inherited from Vangrail::Rail
Vangrail::Rail::DEFAULT_SIDES, Vangrail::Rail::SIDES
Instance Attribute Summary collapse
-
#max_turns ⇒ Object
readonly
Returns the value of attribute max_turns.
-
#placeholder ⇒ Object
readonly
Returns the value of attribute placeholder.
Attributes inherited from Vangrail::Rail
Instance Method Summary collapse
- #cache_key(text, _context) ⇒ Object
- #decide(text, _context) ⇒ Object
-
#initialize(max_turns: 4, placeholder: '', name: 'many_shot', sides: %i[input context])) ⇒ ManyShot
constructor
A new instance of ManyShot.
Methods inherited from Vangrail::Rail
#applies_to?, #call, #language_agnostic?, #offline?, #placeholder?, #posture?, #quantifies?, #to_s, usable
Constructor Details
#initialize(max_turns: 4, placeholder: '', name: 'many_shot', sides: %i[input context])) ⇒ ManyShot
Returns a new instance of ManyShot.
56 57 58 59 60 |
# File 'lib/vangrail/rails/many_shot.rb', line 56 def initialize(max_turns: 4, placeholder: '', name: 'many_shot', sides: %i[input context]) super(name: name, sides: sides) @max_turns = max_turns @placeholder = placeholder end |
Instance Attribute Details
#max_turns ⇒ Object (readonly)
Returns the value of attribute max_turns.
54 55 56 |
# File 'lib/vangrail/rails/many_shot.rb', line 54 def max_turns @max_turns end |
#placeholder ⇒ Object (readonly)
Returns the value of attribute placeholder.
54 55 56 |
# File 'lib/vangrail/rails/many_shot.rb', line 54 def placeholder @placeholder end |
Instance Method Details
#cache_key(text, _context) ⇒ Object
62 63 64 |
# File 'lib/vangrail/rails/many_shot.rb', line 62 def cache_key(text, _context) text end |
#decide(text, _context) ⇒ Object
66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/vangrail/rails/many_shot.rb', line 66 def decide(text, _context) body = text.to_s stripped = body.gsub(TEMPLATE_TOKENS, placeholder) turns = turn_count(stripped) if turns > max_turns return block(categories: ['many_shot'], reason: "#{turns} conversation turns in one message") end return pass if stripped == body modify(stripped, categories: ['template_tokens'], reason: 'removed chat template control tokens') end |