mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-10-01 15:02:53 +00:00
agent: 更智能的 LLM provider 调度(byModel 精确路由 + AUTO 优先级链)
吸收 llmsproxy 的调度思想适配 HomeAgent“一源一模型”结构:
- RoutableProvider{Model,Priority} 次级接口(不破坏既有 Provider 实现)
- ProviderManager.OrderedProviders 改为按 (优先级 desc, 可用, 默认优先) 稳定排序,
AUTO/空模型走该优先级链
- 新增 ProviderManager.ResolveForModel:精确模型名路由到归属源,找不到回落 AUTO 链
- LuaAdaptedProvider 不再无条件覆写 req.Model;显式模型名原样转发
- LLMSource.Priority + core.llm.sources.<name>.priority 配置项
- process.go: 显式模型走 ResolveForModel,AUTO 走 OrderedProviders
- 新增路由单测(优先级排序 + byModel 解析)
验证: go test ./... 27 包 0 失败;Windows 交叉编译通过;部署后服务健康
This commit is contained in:
66
internal/agent/api/router_test.go
Normal file
66
internal/agent/api/router_test.go
Normal file
@ -0,0 +1,66 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// stubRoutableProvider implements both Provider and RoutableProvider.
|
||||
type stubRoutableProvider struct {
|
||||
name string
|
||||
model string
|
||||
prio int
|
||||
}
|
||||
|
||||
func (s *stubRoutableProvider) Name() string { return s.name }
|
||||
func (s *stubRoutableProvider) Model() string { return s.model }
|
||||
func (s *stubRoutableProvider) Priority() int { return s.prio }
|
||||
func (s *stubRoutableProvider) MaxContextTokens() int { return 4096 }
|
||||
func (s *stubRoutableProvider) Chat(context.Context, *CompletionRequest) (*CompletionResponse, error) {
|
||||
return &CompletionResponse{Content: s.name}, nil
|
||||
}
|
||||
func (s *stubRoutableProvider) ChatStream(context.Context, *CompletionRequest) (<-chan StreamChunk, error) {
|
||||
ch := make(chan StreamChunk, 1)
|
||||
ch <- StreamChunk{Done: true}
|
||||
return ch, nil
|
||||
}
|
||||
|
||||
func TestProviderManagerPriorityOrder(t *testing.T) {
|
||||
m := NewProviderManager()
|
||||
m.Register("low", &stubRoutableProvider{name: "low", prio: 10})
|
||||
m.Register("high", &stubRoutableProvider{name: "high", prio: 90})
|
||||
m.Register("mid", &stubRoutableProvider{name: "mid", prio: 50})
|
||||
|
||||
got := m.OrderedProviders()
|
||||
wantOrder := []string{"high", "mid", "low"}
|
||||
for i, p := range got {
|
||||
if p.Name() != wantOrder[i] {
|
||||
t.Fatalf("order[%d] = %s, want %s (full=%v)", i, p.Name(), wantOrder[i], names(got))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestProviderManagerResolveForModel(t *testing.T) {
|
||||
m := NewProviderManager()
|
||||
m.Register("a", &stubRoutableProvider{name: "a", model: "gpt-5"})
|
||||
m.Register("b", &stubRoutableProvider{name: "b", model: "deepseek"})
|
||||
|
||||
got := m.ResolveForModel("deepseek")
|
||||
if len(got) == 0 || got[0].Name() != "b" {
|
||||
t.Fatalf("resolve deepseek: got %v", names(got))
|
||||
}
|
||||
|
||||
// 未知模型回落 AUTO 链(仍按优先级)
|
||||
got2 := m.ResolveForModel("unknown")
|
||||
if len(got2) == 0 {
|
||||
t.Fatal("unknown model should fall back to auto chain")
|
||||
}
|
||||
}
|
||||
|
||||
func names(ps []Provider) []string {
|
||||
out := make([]string, len(ps))
|
||||
for i, p := range ps {
|
||||
out[i] = p.Name()
|
||||
}
|
||||
return out
|
||||
}
|
||||
Reference in New Issue
Block a user