Module: RubyLLM::Text::Answer
- Defined in:
- lib/ruby_llm/text/answer.rb
Class Method Summary collapse
- .build_confidence_schema(question) ⇒ Object
- .build_prompt(text, question, include_confidence:) ⇒ Object
- .call(text, question, include_confidence: false, model: nil, **options) ⇒ Object
- .is_boolean_answer?(answer) ⇒ Boolean
- .is_boolean_question?(question) ⇒ Boolean
- .parse_boolean(answer) ⇒ Object
Class Method Details
.build_confidence_schema(question) ⇒ Object
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/ruby_llm/text/answer.rb', line 80 def self.build_confidence_schema(question) # For boolean questions, allow both boolean and string types # to handle "information not available" fallback answer_type = if is_boolean_question?(question) { oneOf: [ { type: "boolean" }, { type: "string" } ] } else { type: "string" } end { type: "object", properties: { answer: answer_type, confidence: { type: "number", minimum: 0, maximum: 1 } }, required: [ "answer", "confidence" ] } end |
.build_prompt(text, question, include_confidence:) ⇒ Object
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/ruby_llm/text/answer.rb', line 52 def self.build_prompt(text, question, include_confidence:) if include_confidence output_instruction = " Return a JSON object with:\n - \"answer\": the answer to the question (use true/false for yes/no questions)\n - \"confidence\": a confidence score between 0 and 1\n\n If the answer cannot be found in the text, return \"information not available\" as the answer with low confidence.\n OUTPUT\n else\n output_instruction = <<~OUTPUT\n Answer the question based only on the information provided in the text.\n For yes/no questions, respond with true or false.\n If the answer cannot be found in the text, respond with \"information not available\".\n Return only the answer, no explanation.\n OUTPUT\n end\n\n <<~PROMPT\n Based on the following text, answer this question: \"\#{question}\"\n\n \#{output_instruction}\n\n Text:\n \#{text}\n PROMPT\nend\n" |
.call(text, question, include_confidence: false, model: nil, **options) ⇒ Object
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/ruby_llm/text/answer.rb', line 4 def self.call(text, question, include_confidence: false, model: nil, **) raise ArgumentError, "question is required" if question.nil? || question.strip.empty? model ||= RubyLLM::Text.config.model_for(:answer) prompt = build_prompt(text, question, include_confidence: include_confidence) if include_confidence # For structured output with confidence score schema = build_confidence_schema(question) response = Base.call_llm(prompt, model: model, schema: schema, **) begin result = JSON.parse(Base.clean_json_response(response)) rescue JSON::ParserError # Fallback: if JSON parsing fails, return best-effort structured response cleaned_response = Base.clean_json_response(response) result = { "answer" => cleaned_response, "confidence" => nil } end # Convert confidence to float when present (preserve nil as "unknown") if result.key?("confidence") && !result["confidence"].nil? result["confidence"] = result["confidence"].to_f end # Handle boolean answers if is_boolean_answer?(result["answer"]) result["answer"] = parse_boolean(result["answer"]) end result else response = Base.call_llm(prompt, model: model, **) # Handle boolean answers for simple responses if is_boolean_question?(question) parse_boolean(response) else response end end end |
.is_boolean_answer?(answer) ⇒ Boolean
112 113 114 115 116 117 118 |
# File 'lib/ruby_llm/text/answer.rb', line 112 def self.is_boolean_answer?(answer) return true if answer.is_a?(TrueClass) || answer.is_a?(FalseClass) return false unless answer.is_a?(String) answer_lower = answer.downcase.strip [ "true", "false", "yes", "no" ].include?(answer_lower) end |
.is_boolean_question?(question) ⇒ Boolean
104 105 106 107 108 109 110 |
# File 'lib/ruby_llm/text/answer.rb', line 104 def self.is_boolean_question?(question) question_lower = question.downcase.strip question_lower.start_with?("is ", "are ", "was ", "were ", "do ", "does ", "did ", "can ", "could ", "will ", "would ", "should ") || question_lower.start_with?("has ", "have ", "had ") || question_lower.include?(" or not") || (question_lower.end_with?("?") && question_lower.include?("yes or no")) end |
.parse_boolean(answer) ⇒ Object
120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/ruby_llm/text/answer.rb', line 120 def self.parse_boolean(answer) return answer if answer.is_a?(TrueClass) || answer.is_a?(FalseClass) return answer unless answer.is_a?(String) answer_lower = answer.downcase.strip case answer_lower when "true", "yes" true when "false", "no" false else answer # Return as-is if not clearly boolean end end |