fix: address Copilot review round 2
- Fix F1/HitRate weighted aggregation: track ValidF1Count separately so computeModeAgg weights F1 by valid scores only, not TotalQuestions - No-context retrieval failure uses 0.0 (genuine bad score) instead of -1.0 sentinel (reserved for API/parse failures) - Validate --timeout > 0 to prevent disabling HTTP timeouts
This commit is contained in:
parent
90a57642b0
commit
8eca3139db
3 changed files with 23 additions and 7 deletions
|
|
@ -36,6 +36,7 @@ type AggMetrics struct {
|
||||||
OverallHitRate float64 `json:"overallHitRate"`
|
OverallHitRate float64 `json:"overallHitRate"`
|
||||||
ByCategory map[int]*CatMetrics `json:"byCategory"`
|
ByCategory map[int]*CatMetrics `json:"byCategory"`
|
||||||
TotalQuestions int `json:"totalQuestions"`
|
TotalQuestions int `json:"totalQuestions"`
|
||||||
|
ValidF1Count int `json:"validF1Count"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// CatMetrics holds metrics for a single category.
|
// CatMetrics holds metrics for a single category.
|
||||||
|
|
@ -43,6 +44,7 @@ type CatMetrics struct {
|
||||||
F1 float64 `json:"f1"`
|
F1 float64 `json:"f1"`
|
||||||
HitRate float64 `json:"hitRate"`
|
HitRate float64 `json:"hitRate"`
|
||||||
QuestionCount int `json:"questionCount"`
|
QuestionCount int `json:"questionCount"`
|
||||||
|
ValidF1Count int `json:"validF1Count"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// EvalLegacy evaluates using legacy session store (raw history + budget truncation).
|
// EvalLegacy evaluates using legacy session store (raw history + budget truncation).
|
||||||
|
|
@ -239,7 +241,10 @@ func aggregateMetrics(qaResults []QAResult) AggMetrics {
|
||||||
}
|
}
|
||||||
byCat := map[int]*CatMetrics{}
|
byCat := map[int]*CatMetrics{}
|
||||||
for cat, acc := range byCatAcc {
|
for cat, acc := range byCatAcc {
|
||||||
cm := &CatMetrics{QuestionCount: acc.hitRateCount}
|
cm := &CatMetrics{
|
||||||
|
QuestionCount: acc.hitRateCount,
|
||||||
|
ValidF1Count: acc.f1Count,
|
||||||
|
}
|
||||||
if acc.f1Count > 0 {
|
if acc.f1Count > 0 {
|
||||||
cm.F1 = acc.f1Sum / float64(acc.f1Count)
|
cm.F1 = acc.f1Sum / float64(acc.f1Count)
|
||||||
}
|
}
|
||||||
|
|
@ -253,6 +258,7 @@ func aggregateMetrics(qaResults []QAResult) AggMetrics {
|
||||||
OverallHitRate: totalHitRate / float64(nHit),
|
OverallHitRate: totalHitRate / float64(nHit),
|
||||||
ByCategory: byCat,
|
ByCategory: byCat,
|
||||||
TotalQuestions: len(qaResults),
|
TotalQuestions: len(qaResults),
|
||||||
|
ValidF1Count: validF1Count,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -298,27 +304,33 @@ func SaveAggregated(results []EvalResult, outDir string) error {
|
||||||
func computeModeAgg(results []EvalResult) AggMetrics {
|
func computeModeAgg(results []EvalResult) AggMetrics {
|
||||||
agg := AggMetrics{ByCategory: map[int]*CatMetrics{}}
|
agg := AggMetrics{ByCategory: map[int]*CatMetrics{}}
|
||||||
for _, r := range results {
|
for _, r := range results {
|
||||||
agg.OverallF1 += r.Agg.OverallF1 * float64(r.Agg.TotalQuestions)
|
agg.OverallF1 += r.Agg.OverallF1 * float64(r.Agg.ValidF1Count)
|
||||||
agg.OverallHitRate += r.Agg.OverallHitRate * float64(r.Agg.TotalQuestions)
|
agg.OverallHitRate += r.Agg.OverallHitRate * float64(r.Agg.TotalQuestions)
|
||||||
agg.TotalQuestions += r.Agg.TotalQuestions
|
agg.TotalQuestions += r.Agg.TotalQuestions
|
||||||
|
agg.ValidF1Count += r.Agg.ValidF1Count
|
||||||
for cat, cm := range r.Agg.ByCategory {
|
for cat, cm := range r.Agg.ByCategory {
|
||||||
existing, ok := agg.ByCategory[cat]
|
existing, ok := agg.ByCategory[cat]
|
||||||
if !ok {
|
if !ok {
|
||||||
existing = &CatMetrics{}
|
existing = &CatMetrics{}
|
||||||
agg.ByCategory[cat] = existing
|
agg.ByCategory[cat] = existing
|
||||||
}
|
}
|
||||||
existing.F1 += cm.F1 * float64(cm.QuestionCount)
|
existing.F1 += cm.F1 * float64(cm.ValidF1Count)
|
||||||
existing.HitRate += cm.HitRate * float64(cm.QuestionCount)
|
existing.HitRate += cm.HitRate * float64(cm.QuestionCount)
|
||||||
existing.QuestionCount += cm.QuestionCount
|
existing.QuestionCount += cm.QuestionCount
|
||||||
|
existing.ValidF1Count += cm.ValidF1Count
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if agg.ValidF1Count > 0 {
|
||||||
|
agg.OverallF1 /= float64(agg.ValidF1Count)
|
||||||
|
}
|
||||||
if agg.TotalQuestions > 0 {
|
if agg.TotalQuestions > 0 {
|
||||||
agg.OverallF1 /= float64(agg.TotalQuestions)
|
|
||||||
agg.OverallHitRate /= float64(agg.TotalQuestions)
|
agg.OverallHitRate /= float64(agg.TotalQuestions)
|
||||||
}
|
}
|
||||||
for _, cat := range agg.ByCategory {
|
for _, cat := range agg.ByCategory {
|
||||||
|
if cat.ValidF1Count > 0 {
|
||||||
|
cat.F1 /= float64(cat.ValidF1Count)
|
||||||
|
}
|
||||||
if cat.QuestionCount > 0 {
|
if cat.QuestionCount > 0 {
|
||||||
cat.F1 /= float64(cat.QuestionCount)
|
|
||||||
cat.HitRate /= float64(cat.QuestionCount)
|
cat.HitRate /= float64(cat.QuestionCount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -211,10 +211,10 @@ func EvalSeahorseLLM(
|
||||||
Question: qa.Question,
|
Question: qa.Question,
|
||||||
Category: qa.Category,
|
Category: qa.Category,
|
||||||
GoldAnswer: qa.AnswerString(),
|
GoldAnswer: qa.AnswerString(),
|
||||||
TokenF1: -1.0,
|
TokenF1: 0.0,
|
||||||
HitRate: 0.0,
|
HitRate: 0.0,
|
||||||
})
|
})
|
||||||
log.Printf("[seahorse-llm] sample=%s q=%d/%d score=-1.00 answer=(no context)",
|
log.Printf("[seahorse-llm] sample=%s q=%d/%d score=0.00 answer=(no context)",
|
||||||
sample.SampleID, total, totalQA)
|
sample.SampleID, total, totalQA)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -305,6 +305,10 @@ func buildLLMOptions() (LLMClientOptions, error) {
|
||||||
}
|
}
|
||||||
apiKey := envOrFlag(flagAPIKey, "MEMBENCH_API_KEY")
|
apiKey := envOrFlag(flagAPIKey, "MEMBENCH_API_KEY")
|
||||||
|
|
||||||
|
if flagTimeout <= 0 {
|
||||||
|
return LLMClientOptions{}, fmt.Errorf("--timeout must be > 0, got %d", flagTimeout)
|
||||||
|
}
|
||||||
|
|
||||||
return LLMClientOptions{
|
return LLMClientOptions{
|
||||||
BaseURL: base,
|
BaseURL: base,
|
||||||
Model: model,
|
Model: model,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue