Class: Vangrail::Rails::GuardModel
- Inherits:
-
Vangrail::Rail
- Object
- Vangrail::Rail
- Vangrail::Rails::GuardModel
- Defined in:
- lib/vangrail/rails/guard_model.rb
Overview
A safety classifier as a rail: one chat call, the model's own template does the framing, and the label it answers becomes the decision.
:llama_guard "safe" | "unsafe\nS1,S10"
:apriel_guard "safe\nnon_adversarial" | "unsafe-O14,O12\nadversarial"
Classifiers only ever pass or block. They cannot rewrite text, so this rail never returns :modified; a redaction or policy rail does that.
- Needs a provider that actually hosts one. Where none exists, Rails
SelfCheck puts a written policy in front of an instruct model instead, which is the same job done differently rather than the same job skipped.
Constant Summary collapse
- PRESETS =
%i[llama_guard apriel_guard].freeze
- REASONING_KWARGS =
Chat-template switch that turns on an assessment before the verdict. Gateways forward these to the serving engine's template, so a written rationale costs tokens and latency and nothing else.
{ 'chat_template_kwargs' => { 'reasoning_mode' => 'on' } }.freeze
- REASONING_MAX_TOKENS =
900
Instance Attribute Summary collapse
-
#chat ⇒ Object
readonly
Returns the value of attribute chat.
-
#model ⇒ Object
readonly
Returns the value of attribute model.
-
#preset ⇒ Object
readonly
Returns the value of attribute preset.
-
#reasoning ⇒ Object
readonly
Returns the value of attribute reasoning.
Instance Method Summary collapse
-
#cache_key(text, context) ⇒ Object
The verdict depends on the text and, on the output side, on the user turn sent with it.
- #call(text, context) ⇒ Object
-
#initialize(provider: nil, model: nil, preset: nil, chat: nil, reasoning: false, name: nil, sides: Rail::SIDES, max_tokens: nil, **chat_options) ⇒ GuardModel
constructor
A new instance of GuardModel.
Constructor Details
#initialize(provider: nil, model: nil, preset: nil, chat: nil, reasoning: false, name: nil, sides: Rail::SIDES, max_tokens: nil, **chat_options) ⇒ GuardModel
Returns a new instance of GuardModel.
32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/vangrail/rails/guard_model.rb', line 32 def initialize(provider: nil, model: nil, preset: nil, chat: nil, reasoning: false, name: nil, sides: Rail::SIDES, max_tokens: nil, **) @model = model || provider&.model(:guard) @preset = (preset || provider&.guard_preset)&.to_sym raise ArgumentError, 'a guard rail needs a model' if @model.nil? unless PRESETS.include?(@preset) raise ArgumentError, "preset must be one of #{PRESETS.join(', ')}; " \ 'a model answering a written policy belongs in Rails::SelfCheck' end @reasoning = reasoning && @preset == :apriel_guard super(name: name || @preset.to_s, sides: sides) @chat = chat || build_chat(provider, max_tokens, ) end |
Instance Attribute Details
#chat ⇒ Object (readonly)
Returns the value of attribute chat.
30 31 32 |
# File 'lib/vangrail/rails/guard_model.rb', line 30 def chat @chat end |
#model ⇒ Object (readonly)
Returns the value of attribute model.
30 31 32 |
# File 'lib/vangrail/rails/guard_model.rb', line 30 def model @model end |
#preset ⇒ Object (readonly)
Returns the value of attribute preset.
30 31 32 |
# File 'lib/vangrail/rails/guard_model.rb', line 30 def preset @preset end |
#reasoning ⇒ Object (readonly)
Returns the value of attribute reasoning.
30 31 32 |
# File 'lib/vangrail/rails/guard_model.rb', line 30 def reasoning @reasoning end |
Instance Method Details
#cache_key(text, context) ⇒ Object
The verdict depends on the text and, on the output side, on the user turn sent with it.
49 50 51 52 53 |
# File 'lib/vangrail/rails/guard_model.rb', line 49 def cache_key(text, context) return text if context[:side] == :input "#{context[:user_input]} #{text}" end |
#call(text, context) ⇒ Object
55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/vangrail/rails/guard_model.rb', line 55 def call(text, context) answer = chat.ask((text, context)) parsed = preset == :apriel_guard ? Parsers.apriel_guard(answer.text) : Parsers.llama_guard(answer.text) unless parsed[:decided] return Result.new(status: :passed, rail: name, certain: false, model: model, latency_ms: answer.latency_ms, raw: answer.raw, reason: "unparsed guard response: #{parsed[:reason]}") end return pass(model: model, latency_ms: answer.latency_ms, raw: answer.raw) unless parsed[:violated] block(reason: parsed[:reason], categories: parsed[:categories], model: model, latency_ms: answer.latency_ms, raw: answer.raw) end |