rubric_llm 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -1
- data/README.md +36 -21
- data/lib/rubric_llm/evaluator.rb +1 -1
- data/lib/rubric_llm/judge.rb +64 -10
- data/lib/rubric_llm/metrics/base.rb +1 -4
- data/lib/rubric_llm/metrics/context_precision.rb +1 -3
- data/lib/rubric_llm/metrics/context_recall.rb +1 -3
- data/lib/rubric_llm/metrics/correctness.rb +1 -3
- data/lib/rubric_llm/metrics/factual_accuracy.rb +1 -3
- data/lib/rubric_llm/metrics/faithfulness.rb +1 -3
- data/lib/rubric_llm/metrics/relevance.rb +1 -3
- data/lib/rubric_llm/retrieval_result.rb +1 -1
- data/lib/rubric_llm/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6ed5a9f9ece0c78f86b4134211e39d8100e046046686ec296697d794cefcce15
|
|
4
|
+
data.tar.gz: 40e120b95e7d8b5711e495f909e357395fd5ffbae76cb49dd8aa6c5212488196
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e07a90dabde33a66007ce21bd2173c577ce61fb1a964ce6946f2df26d03ff29dac18bc5757d209fcf5f8d76b5e8bb72c33562f250ee2335adc9aa1c83b0aada1
|
|
7
|
+
data.tar.gz: 8fcf6d081679021ac44aa729f63e243aabe344aa93c730a5b660d4fcc981963a08f7017276416b68b7b8b2d390756c537469263cdad92772e5f23a66199f1b0e
|
data/CHANGELOG.md
CHANGED
|
@@ -5,7 +5,21 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
-
## [
|
|
8
|
+
## [0.2.0] - 2026-07-11
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- Enforce schema-backed judge responses through RubyLLM structured output when supported
|
|
13
|
+
- Raise `RubricLLM::JudgeError` for empty, malformed, missing-score, non-numeric, or out-of-range judge responses instead of returning `nil` or clamping invalid scores
|
|
14
|
+
- Require `ruby_llm ~> 1.13` for named schema payload support in structured output
|
|
15
|
+
- Record judge failures per metric in `RubricLLM.evaluate` and `RubricLLM.evaluate_batch` as a `nil` score with the error message in details and continue the run, while non-judge errors propagate
|
|
16
|
+
- Remove dead score clamping and nil-response guards from LLM metrics now that the judge validates the response contract
|
|
17
|
+
|
|
18
|
+
## [0.1.2] - 2026-04-30
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- Add standalone LLM-as-Judge examples for RAG scoring, batch reports, model comparison, custom metrics, and Minitest assertions
|
|
9
23
|
|
|
10
24
|
## [0.1.1] - 2026-03-24
|
|
11
25
|
|
data/README.md
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
# RubricLLM
|
|
2
2
|
|
|
3
|
-
Lightweight LLM evaluation framework for Ruby, inspired by [
|
|
3
|
+
Lightweight LLM evaluation framework for Ruby, inspired by [DeepEval](https://github.com/confident-ai/deepeval), powered by [RubyLLM](https://github.com/crmne/ruby_llm).
|
|
4
4
|
|
|
5
5
|
[](https://badge.fury.io/rb/rubric_llm)
|
|
6
6
|
[](https://github.com/dpaluy/rubric_llm/actions/workflows/ci.yml)
|
|
7
|
+
[](https://github.com/dpaluy/rubric_llm/wiki)
|
|
7
8
|
|
|
8
9
|
Provider-agnostic evaluation with pluggable metrics, statistical A/B comparison, and test framework integration — no Rails, no ActiveRecord, no UI. Works anywhere Ruby runs.
|
|
9
10
|
|
|
@@ -27,31 +28,34 @@ gem install rubric_llm
|
|
|
27
28
|
require "rubric_llm"
|
|
28
29
|
|
|
29
30
|
RubricLLM.configure do |c|
|
|
30
|
-
c.judge_model = "gpt-
|
|
31
|
+
c.judge_model = "gpt-5.5"
|
|
31
32
|
c.judge_provider = :openai
|
|
32
33
|
end
|
|
33
34
|
|
|
34
35
|
result = RubricLLM.evaluate(
|
|
35
|
-
question: "What is
|
|
36
|
-
answer: "
|
|
37
|
-
context: [
|
|
38
|
-
|
|
36
|
+
question: "What is Ruby's core design philosophy?",
|
|
37
|
+
answer: "Ruby was designed by Yukihiro Matsumoto to optimize for developer happiness and productivity, prioritizing the programmer's joy over machine efficiency.",
|
|
38
|
+
context: [
|
|
39
|
+
"Yukihiro Matsumoto, Ruby's creator, has stated that Ruby is designed to make programmers happy. " \
|
|
40
|
+
"He optimized the language for human readability and developer productivity rather than raw machine performance."
|
|
41
|
+
],
|
|
42
|
+
ground_truth: "Ruby is designed to maximize developer happiness and productivity."
|
|
39
43
|
)
|
|
40
44
|
|
|
41
|
-
result.
|
|
42
|
-
result.relevance # => 0.92
|
|
43
|
-
result.correctness # => 0.98
|
|
44
|
-
result.overall # => 0.94
|
|
45
|
+
result.correctness # => 0.99
|
|
45
46
|
result.pass? # => true
|
|
46
47
|
```
|
|
47
48
|
|
|
49
|
+
For runnable LLM-as-Judge examples, including RAG scoring, batch pass/fail output, model comparison, custom metrics, and live
|
|
50
|
+
Minitest assertions, see [examples/README.md](examples/README.md).
|
|
51
|
+
|
|
48
52
|
## Configuration
|
|
49
53
|
|
|
50
54
|
### Global
|
|
51
55
|
|
|
52
56
|
```ruby
|
|
53
57
|
RubricLLM.configure do |c|
|
|
54
|
-
c.judge_model = "gpt-
|
|
58
|
+
c.judge_model = "gpt-5.5" # any model RubyLLM supports
|
|
55
59
|
c.judge_provider = :openai # :openai, :anthropic, :gemini, etc.
|
|
56
60
|
c.temperature = 0.0 # deterministic scoring (default)
|
|
57
61
|
c.max_tokens = 4096 # max tokens for judge response
|
|
@@ -80,7 +84,7 @@ config = RubricLLM::Config.from_env
|
|
|
80
84
|
### Per-Evaluation Override
|
|
81
85
|
|
|
82
86
|
```ruby
|
|
83
|
-
custom = RubricLLM::Config.new(judge_model: "claude-
|
|
87
|
+
custom = RubricLLM::Config.new(judge_model: "claude-opus-4-5", judge_provider: :anthropic)
|
|
84
88
|
|
|
85
89
|
result = RubricLLM.evaluate(question: "...", answer: "...", config: custom)
|
|
86
90
|
report = RubricLLM.evaluate_batch(dataset, config: custom)
|
|
@@ -91,7 +95,7 @@ report = RubricLLM.evaluate_batch(dataset, config: custom)
|
|
|
91
95
|
```ruby
|
|
92
96
|
# config/initializers/rubric_llm.rb
|
|
93
97
|
RubricLLM.configure do |c|
|
|
94
|
-
c.judge_model = "gpt-
|
|
98
|
+
c.judge_model = "gpt-5.5"
|
|
95
99
|
c.judge_provider = :openai
|
|
96
100
|
end
|
|
97
101
|
```
|
|
@@ -104,12 +108,12 @@ These metrics use a judge LLM to evaluate quality. Each sends a structured promp
|
|
|
104
108
|
|
|
105
109
|
| Metric | Question it answers | Requires |
|
|
106
110
|
|--------|-------------------|----------|
|
|
107
|
-
| **Faithfulness** | Is every claim in the answer supported by the context? | `context` |
|
|
108
|
-
| **Relevance** | Does the answer address what was asked? | `question` |
|
|
109
111
|
| **Correctness** | Does the answer match the known correct answer? | `ground_truth` |
|
|
112
|
+
| **Relevance** | Does the answer address what was asked? | `question` |
|
|
110
113
|
| **Context Precision** | Are the retrieved context chunks actually relevant? | `question`, `context` |
|
|
111
|
-
| **Context Recall** | Do the contexts cover the information in the ground truth? | `context`, `ground_truth` |
|
|
112
114
|
| **Factual Accuracy** | Are there factual discrepancies between candidate and reference? | `ground_truth` |
|
|
115
|
+
| **Context Recall** | Do the contexts cover the information in the ground truth? | `context`, `ground_truth` |
|
|
116
|
+
| **Faithfulness** | Is every claim in the answer supported by the context? | `context` |
|
|
113
117
|
|
|
114
118
|
```ruby
|
|
115
119
|
# Only context — gets faithfulness, relevance, context_precision
|
|
@@ -160,8 +164,8 @@ result = RubricLLM.evaluate_retrieval(
|
|
|
160
164
|
)
|
|
161
165
|
|
|
162
166
|
result.precision_at_k(3) # => 0.67
|
|
163
|
-
result.recall_at_k(3) # =>
|
|
164
|
-
result.mrr # =>
|
|
167
|
+
result.recall_at_k(3) # => 0.90
|
|
168
|
+
result.mrr # => 0.90
|
|
165
169
|
result.ndcg # => 0.86
|
|
166
170
|
result.hit_rate # => 1.0
|
|
167
171
|
```
|
|
@@ -203,7 +207,7 @@ report.to_json # returns JSON string
|
|
|
203
207
|
Compare two models with statistical significance testing:
|
|
204
208
|
|
|
205
209
|
```ruby
|
|
206
|
-
config_a = RubricLLM::Config.new(judge_model: "gpt-
|
|
210
|
+
config_a = RubricLLM::Config.new(judge_model: "gpt-5.5")
|
|
207
211
|
config_b = RubricLLM::Config.new(judge_model: "claude-sonnet-4-6")
|
|
208
212
|
|
|
209
213
|
report_a = RubricLLM.evaluate_batch(dataset, config: config_a)
|
|
@@ -226,6 +230,8 @@ comparison.significant_regressions # => []
|
|
|
226
230
|
|
|
227
231
|
Significance markers: `*` (p < 0.05), `**` (p < 0.01), `***` (p < 0.001)
|
|
228
232
|
|
|
233
|
+
For the statistical reasoning behind paired t-tests and how to read these p-values, see [Understanding A/B Comparison](https://github.com/dpaluy/rubric_llm/wiki/Understanding-A-B-Comparison) on the wiki.
|
|
234
|
+
|
|
229
235
|
## Test Integration
|
|
230
236
|
|
|
231
237
|
### Minitest
|
|
@@ -315,8 +321,8 @@ RubricLLM uses LLM-as-Judge — an LLM scores another LLM's output. This is the
|
|
|
315
321
|
|
|
316
322
|
Mitigations built into the framework:
|
|
317
323
|
|
|
318
|
-
- **Cross-model judging.** Configure a different model as judge than the one being evaluated. Don't let
|
|
319
|
-
- **Retrieval metrics are pure math.** `precision_at_k`, `recall_at_k`, `mrr`, `ndcg` — no LLM involved, no judge bias.
|
|
324
|
+
- **Cross-model judging.** Configure a different model as judge than the one being evaluated. Don't let gpt-5.5 grade gpt-5.5.
|
|
325
|
+
- **Retrieval metrics are pure math.** `precision_at_k`, `recall_at_k`, `mrr`, `ndcg` — no LLM involved, no judge bias. See [Why Retrieval Metrics Are Pure Math](https://github.com/dpaluy/rubric_llm/wiki/Why-Retrieval-Metrics-Are-Pure-Math).
|
|
320
326
|
- **Custom non-LLM metrics.** Subclass `Metrics::Base` with regex checks, embedding similarity, or any deterministic logic.
|
|
321
327
|
- **Statistical comparison.** A/B testing with paired t-tests surfaces systematic judge bias across runs.
|
|
322
328
|
|
|
@@ -337,6 +343,13 @@ Ruby has two LLM evaluation options today. Neither fits most use cases:
|
|
|
337
343
|
| **Pluggable metrics** | No (fixed set) | Yes | Yes |
|
|
338
344
|
| **Retrieval metrics** | Yes | No | Yes |
|
|
339
345
|
|
|
346
|
+
## Further Reading
|
|
347
|
+
|
|
348
|
+
Deep dives live in the [project wiki](https://github.com/dpaluy/rubric_llm/wiki):
|
|
349
|
+
|
|
350
|
+
- [Understanding A/B Comparison](https://github.com/dpaluy/rubric_llm/wiki/Understanding-A-B-Comparison) — what paired t-tests and p-values mean for model comparison
|
|
351
|
+
- [Why Retrieval Metrics Are Pure Math](https://github.com/dpaluy/rubric_llm/wiki/Why-Retrieval-Metrics-Are-Pure-Math) — why `precision_at_k`, `recall_at_k`, `mrr`, `ndcg`, and `hit_rate` are deterministic and bias-free
|
|
352
|
+
|
|
340
353
|
## Requirements
|
|
341
354
|
|
|
342
355
|
- Ruby >= 3.4
|
|
@@ -350,3 +363,5 @@ Bug reports and pull requests are welcome on [GitHub](https://github.com/dpaluy/
|
|
|
350
363
|
## License
|
|
351
364
|
|
|
352
365
|
[MIT](LICENSE.txt)
|
|
366
|
+
|
|
367
|
+
Supported by [Majestic Labs](https://majesticlabs.dev/).
|
data/lib/rubric_llm/evaluator.rb
CHANGED
|
@@ -30,7 +30,7 @@ module RubricLLM
|
|
|
30
30
|
result = metric.call(question:, answer:, context:, ground_truth:)
|
|
31
31
|
scores[name] = result[:score]
|
|
32
32
|
details[name] = result[:details]
|
|
33
|
-
rescue
|
|
33
|
+
rescue JudgeError => e
|
|
34
34
|
scores[name] = nil
|
|
35
35
|
details[name] = { error: e.message }
|
|
36
36
|
end
|
data/lib/rubric_llm/judge.rb
CHANGED
|
@@ -4,6 +4,24 @@ require "json"
|
|
|
4
4
|
|
|
5
5
|
module RubricLLM
|
|
6
6
|
class Judge
|
|
7
|
+
METRIC_RESPONSE_SCHEMA = {
|
|
8
|
+
name: "rubric_llm_metric_response",
|
|
9
|
+
strict: false,
|
|
10
|
+
schema: {
|
|
11
|
+
type: "object",
|
|
12
|
+
properties: {
|
|
13
|
+
score: { type: "number", minimum: 0.0, maximum: 1.0 },
|
|
14
|
+
reasoning: { type: "string" },
|
|
15
|
+
claims: { type: "array", items: { type: "object" } },
|
|
16
|
+
context_scores: { type: "array", items: { type: "object" } },
|
|
17
|
+
covered_facts: { type: "array", items: { type: "object" } },
|
|
18
|
+
discrepancies: { type: "array", items: { type: "object" } }
|
|
19
|
+
},
|
|
20
|
+
required: ["score"],
|
|
21
|
+
additionalProperties: true
|
|
22
|
+
}
|
|
23
|
+
}.freeze
|
|
24
|
+
|
|
7
25
|
attr_reader :config
|
|
8
26
|
|
|
9
27
|
def initialize(config:)
|
|
@@ -20,13 +38,19 @@ module RubricLLM
|
|
|
20
38
|
chat = RubyLLM.chat(model: config.judge_model, provider: config.judge_provider)
|
|
21
39
|
chat.with_temperature(config.temperature)
|
|
22
40
|
chat.with_params(max_tokens: config.max_tokens)
|
|
41
|
+
apply_response_schema(chat)
|
|
23
42
|
|
|
24
43
|
full_system_prompt = build_system_prompt(system_prompt)
|
|
25
44
|
chat.with_instructions(full_system_prompt)
|
|
26
45
|
response = chat.ask(user_prompt)
|
|
27
|
-
|
|
46
|
+
content = response.content
|
|
47
|
+
validate_response!(content.is_a?(Hash) ? content : parse_json(content))
|
|
28
48
|
rescue StandardError => e
|
|
29
|
-
|
|
49
|
+
if attempts > config.max_retries
|
|
50
|
+
raise e if e.is_a?(JudgeError)
|
|
51
|
+
|
|
52
|
+
raise JudgeError, "Judge call failed: #{e.message}"
|
|
53
|
+
end
|
|
30
54
|
|
|
31
55
|
sleep(config.retry_base_delay * (2**(attempts - 1)))
|
|
32
56
|
retry
|
|
@@ -36,25 +60,55 @@ module RubricLLM
|
|
|
36
60
|
# Parse JSON from LLM output with multiple strategies:
|
|
37
61
|
# 1. Direct JSON.parse
|
|
38
62
|
# 2. Extract from markdown code fence
|
|
39
|
-
# 3.
|
|
63
|
+
# 3. Raise JudgeError for malformed output
|
|
40
64
|
def parse_json(text)
|
|
41
|
-
|
|
65
|
+
raise JudgeError, "Judge response was empty" if text.nil? || text.strip.empty?
|
|
42
66
|
|
|
43
|
-
# Try direct parse
|
|
44
67
|
JSON.parse(text)
|
|
45
|
-
rescue JSON::ParserError
|
|
46
|
-
# Try extracting from code fence
|
|
68
|
+
rescue JSON::ParserError => e
|
|
47
69
|
if (match = text.match(/```(?:json)?\s*\n?(.*?)\n?\s*```/m))
|
|
48
70
|
begin
|
|
49
|
-
JSON.parse(match[1])
|
|
50
|
-
rescue JSON::ParserError
|
|
51
|
-
|
|
71
|
+
return JSON.parse(match[1])
|
|
72
|
+
rescue JSON::ParserError => e
|
|
73
|
+
raise JudgeError, "Judge response code fence was not valid JSON: #{e.message}"
|
|
52
74
|
end
|
|
53
75
|
end
|
|
76
|
+
|
|
77
|
+
raise JudgeError, "Judge response was not valid JSON: #{e.message}"
|
|
54
78
|
end
|
|
55
79
|
|
|
56
80
|
private
|
|
57
81
|
|
|
82
|
+
def apply_response_schema(chat)
|
|
83
|
+
return chat unless chat.respond_to?(:with_schema)
|
|
84
|
+
return chat unless structured_output_supported?(chat)
|
|
85
|
+
|
|
86
|
+
chat.with_schema(METRIC_RESPONSE_SCHEMA)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def structured_output_supported?(chat)
|
|
90
|
+
return true unless chat.respond_to?(:model)
|
|
91
|
+
return true unless chat.model.respond_to?(:structured_output?)
|
|
92
|
+
|
|
93
|
+
chat.model.structured_output?
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def validate_response!(response)
|
|
97
|
+
raise JudgeError, "Judge response must be a JSON object" unless response.is_a?(Hash)
|
|
98
|
+
raise JudgeError, "Judge response missing required score" unless response.key?("score")
|
|
99
|
+
|
|
100
|
+
score = parse_score(response["score"])
|
|
101
|
+
raise JudgeError, "Judge response score must be between 0.0 and 1.0" unless score.finite? && score.between?(0.0, 1.0)
|
|
102
|
+
|
|
103
|
+
response
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def parse_score(score)
|
|
107
|
+
Float(score)
|
|
108
|
+
rescue ArgumentError, TypeError
|
|
109
|
+
raise JudgeError, "Judge response score must be numeric"
|
|
110
|
+
end
|
|
111
|
+
|
|
58
112
|
def build_system_prompt(base_prompt)
|
|
59
113
|
return base_prompt unless config.custom_prompt
|
|
60
114
|
|
|
@@ -19,10 +19,7 @@ module RubricLLM
|
|
|
19
19
|
private
|
|
20
20
|
|
|
21
21
|
def judge_eval(system_prompt:, user_prompt:)
|
|
22
|
-
|
|
23
|
-
return { score: nil, details: { error: "No response from judge" } } if result.nil?
|
|
24
|
-
|
|
25
|
-
result
|
|
22
|
+
judge.call(system_prompt:, user_prompt:)
|
|
26
23
|
end
|
|
27
24
|
end
|
|
28
25
|
end
|
|
@@ -34,10 +34,8 @@ module RubricLLM
|
|
|
34
34
|
private
|
|
35
35
|
|
|
36
36
|
def normalize(result)
|
|
37
|
-
return { score: nil, details: result } unless result.is_a?(Hash) && result["score"]
|
|
38
|
-
|
|
39
37
|
{
|
|
40
|
-
score: Float(result["score"])
|
|
38
|
+
score: Float(result["score"]),
|
|
41
39
|
details: {
|
|
42
40
|
context_scores: result["context_scores"],
|
|
43
41
|
reasoning: result["reasoning"]
|
|
@@ -35,10 +35,8 @@ module RubricLLM
|
|
|
35
35
|
private
|
|
36
36
|
|
|
37
37
|
def normalize(result)
|
|
38
|
-
return { score: nil, details: result } unless result.is_a?(Hash) && result["score"]
|
|
39
|
-
|
|
40
38
|
{
|
|
41
|
-
score: Float(result["score"])
|
|
39
|
+
score: Float(result["score"]),
|
|
42
40
|
details: {
|
|
43
41
|
covered_facts: result["covered_facts"],
|
|
44
42
|
reasoning: result["reasoning"]
|
|
@@ -34,10 +34,8 @@ module RubricLLM
|
|
|
34
34
|
private
|
|
35
35
|
|
|
36
36
|
def normalize(result)
|
|
37
|
-
return { score: nil, details: result } unless result.is_a?(Hash) && result["score"]
|
|
38
|
-
|
|
39
37
|
{
|
|
40
|
-
score: Float(result["score"])
|
|
38
|
+
score: Float(result["score"]),
|
|
41
39
|
details: { reasoning: result["reasoning"] }
|
|
42
40
|
}
|
|
43
41
|
end
|
|
@@ -33,10 +33,8 @@ module RubricLLM
|
|
|
33
33
|
private
|
|
34
34
|
|
|
35
35
|
def normalize(result)
|
|
36
|
-
return { score: nil, details: result } unless result.is_a?(Hash) && result["score"]
|
|
37
|
-
|
|
38
36
|
{
|
|
39
|
-
score: Float(result["score"])
|
|
37
|
+
score: Float(result["score"]),
|
|
40
38
|
details: {
|
|
41
39
|
discrepancies: result["discrepancies"],
|
|
42
40
|
reasoning: result["reasoning"]
|
|
@@ -36,10 +36,8 @@ module RubricLLM
|
|
|
36
36
|
private
|
|
37
37
|
|
|
38
38
|
def normalize(result)
|
|
39
|
-
return { score: nil, details: result } unless result.is_a?(Hash) && result["score"]
|
|
40
|
-
|
|
41
39
|
{
|
|
42
|
-
score: Float(result["score"])
|
|
40
|
+
score: Float(result["score"]),
|
|
43
41
|
details: {
|
|
44
42
|
claims: result["claims"],
|
|
45
43
|
reasoning: result["reasoning"]
|
|
@@ -30,10 +30,8 @@ module RubricLLM
|
|
|
30
30
|
private
|
|
31
31
|
|
|
32
32
|
def normalize(result)
|
|
33
|
-
return { score: nil, details: result } unless result.is_a?(Hash) && result["score"]
|
|
34
|
-
|
|
35
33
|
{
|
|
36
|
-
score: Float(result["score"])
|
|
34
|
+
score: Float(result["score"]),
|
|
37
35
|
details: { reasoning: result["reasoning"] }
|
|
38
36
|
}
|
|
39
37
|
end
|
data/lib/rubric_llm/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rubric_llm
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- David Paluy
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - "~>"
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: '1.
|
|
18
|
+
version: '1.13'
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - "~>"
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: '1.
|
|
25
|
+
version: '1.13'
|
|
26
26
|
description: Provider-agnostic LLM evaluation with pluggable metrics, statistical
|
|
27
27
|
A/B comparison, and test framework integration. Ragas for Ruby, powered by RubyLLM.
|
|
28
28
|
email:
|