mirror of
https://github.com/ollama/ollama.git
synced 2025-03-27 18:22:14 +01:00
Previously we decoded and re-encoded JSON schemas during validation, which served no purpose since json.RawMessage already validates JSON syntax. Worse, the re-encoding lost field ordering from the original schema, which affects inference quality during step-by-step reasoning. While fixing this ordering issue by using json.RawMessage directly, testing revealed that schema_to_grammar (from llama.cpp) also fails to preserve field order during grammar generation. This appears to be the root cause of inference degradation. This change prevents us from mangling the user's original schema order, but we still need to address the ordering issue in schema_to_grammar. That will be a separate change. Updates #7978
81 lines
1.6 KiB
Go
81 lines
1.6 KiB
Go
package llama
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// https://github.com/ollama/ollama/issues/7978
|
|
const issue7978JSONSchema = `{
|
|
"type": "object",
|
|
"properties": {
|
|
"steps": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object",
|
|
"properties": {
|
|
"explanation": { "type": "string" },
|
|
"output": { "type": "string" }
|
|
},
|
|
"required": ["explanation", "output"],
|
|
"additionalProperties": false
|
|
}
|
|
},
|
|
"final_answer": { "type": "string" }
|
|
},
|
|
"required": ["steps", "final_answer"],
|
|
"additionalProperties": false
|
|
}`
|
|
|
|
func TestIssue7978(t *testing.T) {
|
|
t.Skip("schema_to_grammar is broken; skipping until fixed")
|
|
|
|
g := SchemaToGrammar([]byte(issue7978JSONSchema))
|
|
if g == nil {
|
|
t.Fatal("failed to convert JSON schema to grammar")
|
|
}
|
|
|
|
t.Logf("grammar:\n%s", g)
|
|
t.Log()
|
|
|
|
var sawSteps bool
|
|
s := bufio.NewScanner(bytes.NewReader(g))
|
|
for s.Scan() {
|
|
line := s.Text()
|
|
if strings.Contains(line, "steps") {
|
|
sawSteps = true
|
|
}
|
|
if strings.Contains(line, "final-answer") && !sawSteps {
|
|
t.Error("expected 'steps' before 'final-answer'")
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSchemaToGrammer(t *testing.T) {
|
|
t.Skip("schema_to_grammar is broken; skipping until fixed")
|
|
|
|
cases := []struct {
|
|
schema string
|
|
prefix []byte // nil is check as nil
|
|
}{
|
|
{`invalid`, nil},
|
|
|
|
// Simple heuristic/smoke test
|
|
{`{"type":"object"}`, []byte("object ::=")},
|
|
}
|
|
|
|
for _, c := range cases {
|
|
t.Run("x", func(t *testing.T) {
|
|
g := SchemaToGrammar([]byte(c.schema))
|
|
if c.prefix == nil && g != nil {
|
|
t.Fatalf("grammar = %v, want nil", g)
|
|
}
|
|
if !bytes.HasPrefix(g, c.prefix) {
|
|
t.Errorf("grammar = %q, want %q", g, c.prefix)
|
|
}
|
|
})
|
|
}
|
|
}
|