Files
Maven/cmd/semantic-router-experiment/slice22/heads_main.go
T

65 lines
2.1 KiB
Go

package main
import (
"fmt"
"os"
"github.com/kami/maven/internal/router"
"github.com/kami/maven/internal/router/semantic"
)
// headsMain runs the deployed cascade minus the resident LLM: stage-0
// grammars → routing heads (fine-tuned e5 copy + softmax, router_heads.onnx,
// 0.6 decline threshold) → ONNX-embedder nearest-centroid classifier →
// 0.55 confidence gate. This is what a production turn takes when the model
// server is out (docs/routing.md: pickLLMRouter degrades to the classifier).
//
// The classifier is seeded from models/seeds like the daemon's seedClassifier,
// embedded with the real multilingual-e5-small model rather than the block
// hash, so this is the closest headless reproduction of the authoritative
// router output the slice-22 report can run.
//
// Requires the ONNX model files and a libonnxruntime.so. Pass the library via
// the MAVEN_ONNX_LIB environment variable, exactly as the daemon does.
func headsMain(poolPath, outPath string) {
lib := os.Getenv("MAVEN_ONNX_LIB")
if lib == "" {
fmt.Fprintln(os.Stderr, "heads mode needs MAVEN_ONNX_LIB pointing at libonnxruntime.so")
os.Exit(2)
}
const (
embedModel = "models/embedder/multilingual-e5-small/model_quantized.onnx"
tokPath = "models/embedder/multilingual-e5-small/tokenizer.json"
headsModel = "models/embedder/router-heads/router_heads.onnx"
)
emb, err := router.NewONNXEmbedder(embedModel, tokPath, lib)
if err != nil {
fmt.Fprintf(os.Stderr, "heads: embedder: %v\n", err)
os.Exit(1)
}
defer emb.Close()
cls := router.NewClassifier(emb)
seedClassifier(cls)
heads, err := router.NewRouterHeads(headsModel, tokPath)
if err != nil {
fmt.Fprintf(os.Stderr, "heads: %v\n", err)
os.Exit(1)
}
defer heads.Close()
acts := router.DefaultActMatcher{Fns: semantic.ExperimentActVerbs()}
r := router.New(router.Config{
Grammars: router.StageZeroGrammars(acts),
Classifier: cls,
Extractor: router.Extractor{
Time: router.StubDateTimeParser{},
Acts: acts,
Facts: router.DefaultFactParser{},
},
Threshold: 0.55,
Heads: heads,
})
runOverPool(r, poolPath, outPath)
}