9p: /route uses LLM classification for task complexity
Write a task description to /route; a cheap local model (OLLIE_ROUTE_BACKEND/
OLLIE_ROUTE_MODEL, defaults to ollama/qwen3:8b) classifies it as worker or
expert. The resolved backend+model for that tier is returned on read.
Explicit tier still supported via JSON {"tier":"expert"} to skip classification.
This commit is contained in:
parent
9fbdbbe642
commit
61d6b0da92
|
|
@ -925,23 +925,73 @@ func (s *Server) write(cs *connState, fc *plan9.Fcall) *plan9.Fcall {
|
|||
return &plan9.Fcall{Type: plan9.Rwrite, Tag: fc.Tag, Count: uint32(len(fc.Data))}
|
||||
}
|
||||
|
||||
// /route: resolve tier to backend+model (per-fid state, like /net/dns)
|
||||
// /route: classify task complexity and resolve to backend+model (per-fid state, like /net/dns)
|
||||
// Write a task description; a cheap model classifies it as worker/expert;
|
||||
// the resolved backend+model is returned on read.
|
||||
if f.path == "/route" {
|
||||
cs.mu.Unlock()
|
||||
var req struct {
|
||||
Tier string `json:"tier"`
|
||||
Backend string `json:"backend"`
|
||||
Task string `json:"task"`
|
||||
Tier string `json:"tier"` // optional: skip classification, use this tier directly
|
||||
Backend string `json:"backend"` // optional: override target backend
|
||||
}
|
||||
if err := json.Unmarshal(fc.Data, &req); err != nil {
|
||||
// Plain text mode: treat as tier name
|
||||
req.Tier = strings.TrimSpace(string(fc.Data))
|
||||
// Plain text mode: treat entire write as task description
|
||||
req.Task = strings.TrimSpace(string(fc.Data))
|
||||
}
|
||||
if req.Tier == "" {
|
||||
req.Tier = "worker"
|
||||
|
||||
tier := req.Tier
|
||||
if tier == "" && req.Task == "" {
|
||||
return errFcall(fc, "provide a task description or explicit tier")
|
||||
}
|
||||
if req.Tier != "worker" && req.Tier != "expert" {
|
||||
return errFcall(fc, "unknown tier: "+req.Tier+" (use worker or expert)")
|
||||
|
||||
// If no explicit tier, classify via LLM
|
||||
if tier == "" {
|
||||
classifyBackend := os.Getenv("OLLIE_ROUTE_BACKEND")
|
||||
if classifyBackend == "" {
|
||||
classifyBackend = "ollama"
|
||||
}
|
||||
classifyModel := os.Getenv("OLLIE_ROUTE_MODEL")
|
||||
if classifyModel == "" {
|
||||
classifyModel = "qwen3:8b"
|
||||
}
|
||||
cbe, err := backend.NewWithName(classifyBackend)
|
||||
if err != nil {
|
||||
return errFcall(fc, "route classifier backend: "+err.Error())
|
||||
}
|
||||
cbe.SetModel(classifyModel)
|
||||
|
||||
classifyPrompt := `Classify this task's complexity. Reply with exactly one word: "worker" or "expert".
|
||||
|
||||
worker: simple, single-file edits, straightforward bug fixes, small features, routine refactoring, documentation, tests for existing code, standard API usage.
|
||||
expert: multi-file architecture changes, security-sensitive code, complex algorithms, system design, debugging subtle issues, performance optimization, unfamiliar domains.
|
||||
|
||||
Task: ` + req.Task
|
||||
|
||||
msgs := []backend.Message{
|
||||
{Role: "user", Content: classifyPrompt},
|
||||
}
|
||||
params := backend.GenerationParams{}
|
||||
ch, err := cbe.ChatStream(context.Background(), msgs, nil, params)
|
||||
if err != nil {
|
||||
return errFcall(fc, "route classification failed: "+err.Error())
|
||||
}
|
||||
var sb strings.Builder
|
||||
for ev := range ch {
|
||||
sb.WriteString(ev.Content)
|
||||
}
|
||||
result := strings.ToLower(strings.TrimSpace(sb.String()))
|
||||
if strings.Contains(result, "expert") {
|
||||
tier = "expert"
|
||||
} else {
|
||||
tier = "worker"
|
||||
}
|
||||
}
|
||||
|
||||
if tier != "worker" && tier != "expert" {
|
||||
tier = "worker"
|
||||
}
|
||||
|
||||
// Resolve backend
|
||||
backendName := req.Backend
|
||||
if backendName == "" {
|
||||
|
|
@ -951,19 +1001,18 @@ func (s *Server) write(cs *connState, fc *plan9.Fcall) *plan9.Fcall {
|
|||
backendName = "openrouter"
|
||||
}
|
||||
// Resolve model from OLLIE_TIER_{TIER}_{BACKEND}
|
||||
tierUpper := strings.ToUpper(req.Tier)
|
||||
tierUpper := strings.ToUpper(tier)
|
||||
backendLower := strings.ToLower(backendName)
|
||||
model := os.Getenv("OLLIE_TIER_" + tierUpper + "_" + backendLower)
|
||||
if model == "" {
|
||||
// Fallback defaults
|
||||
switch req.Tier {
|
||||
switch tier {
|
||||
case "worker":
|
||||
model = "mistralai/devstral-small"
|
||||
case "expert":
|
||||
model = "anthropic/claude-sonnet-4-20250514"
|
||||
}
|
||||
}
|
||||
f.routeResult = []byte(fmt.Sprintf("backend=%s\nmodel=%s\ntier=%s\n", backendLower, model, req.Tier))
|
||||
f.routeResult = []byte(fmt.Sprintf("backend=%s\nmodel=%s\ntier=%s\n", backendLower, model, tier))
|
||||
return &plan9.Fcall{Type: plan9.Rwrite, Tag: fc.Tag, Count: uint32(len(fc.Data))}
|
||||
}
|
||||
|
||||
|
|
|
|||
Reference in New Issue