Class: Assistant::TechnicalSupport::ResponseGroundingAnalyzer

Inherits:
Object
  • Object
show all
Defined in:
app/services/assistant/technical_support/response_grounding_analyzer.rb

Overview

Performs the schema-constrained claim extraction pass used by the live
Technical Support response gate.

Defined Under Namespace

Classes: InvalidResponse, Result

Constant Summary collapse

TIMEOUT_SECONDS =

Caps provider latency so a queued shadow audit cannot occupy its
background worker indefinitely.

60
SCHEMA =
{
  type: 'object',
  properties: {
    has_material_technical_claims: { type: 'boolean' },
    claims: {
      type: 'array',
      maxItems: ResponseGroundingAssessmentBuilder::MAX_CLAIMS,
      items: {
        type: 'object',
        properties: {
          text: { type: 'string' },
          category: {
            type: 'string',
            enum: %w[measurement compatibility diagnosis procedure safety part_number other]
          },
          verdict: {
            type: 'string',
            enum: %w[supported unsupported contradicted]
          },
          evidence_ids: {
            type: 'array',
            items: { type: 'string' }
          },
          answer_segment_id: { type: 'string' }
        },
        required: %w[text category verdict evidence_ids answer_segment_id],
        additionalProperties: false
      }
    },
    non_material_segment_ids: {
      type: 'array',
      items: { type: 'string' },
      maxItems: ResponseGroundingAnswerSegments::MAX_SEGMENTS
    },
    safe: { type: 'boolean' },
    safety_concerns: { type: 'array', items: { type: 'string' }, maxItems: 10 },
    notes: { type: %w[string null] }
  },
  required: %w[has_material_technical_claims claims non_material_segment_ids safe safety_concerns notes],
  additionalProperties: false
}.freeze

Instance Method Summary collapse

Constructor Details

#initialize(chat_factory: nil) ⇒ ResponseGroundingAnalyzer

Builds an analyzer with an optional test chat factory.

Parameters:

  • chat_factory (Proc, nil) (defaults to: nil)

    factory receiving a model ID



70
71
72
# File 'app/services/assistant/technical_support/response_grounding_analyzer.rb', line 70

def initialize(chat_factory: nil)
  @chat_factory = chat_factory || method(:build_chat)
end

Instance Method Details

#call(answer:, evidence:, conversation:, answer_segments: nil) ⇒ Result

Returns structured claims and the model that produced them.

Parameters:

  • answer (String)

    bounded Sunny answer

  • evidence (Array<Hash>)

    bounded reported-context and successful-tool entries

  • conversation (AssistantConversation)

    conversation being audited

Returns:

  • (Result)

    structured claims and the model that produced them



78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'app/services/assistant/technical_support/response_grounding_analyzer.rb', line 78

def call(answer:, evidence:, conversation:, answer_segments: nil)
  answer_segments ||= ResponseGroundingAnswerSegments.call(answer:)
  model_used = nil
  content = Timeout.timeout(TIMEOUT_SECONDS) do
    AiModelConstants.with_fallback(:gemini_flash) do |model_id|
      model_used = model_id
      chat = configured_chat(model_id, evidence:, answer_segments:)
      ask(chat, answer_segments:, evidence:, conversation:)
    end
  end

  Result.new(data: coerce_hash(content), model: model_used)
end