// Command dispatcher 启动 sundynix-dispatcher —— 第 4 层 AI Agent 调度集群。 package main import ( "context" "log" "os" "os/signal" "syscall" "time" "github.com/sundynix/sundynix-dispatcher/internal/eino" "github.com/sundynix/sundynix-dispatcher/internal/harness" "github.com/sundynix/sundynix-dispatcher/internal/llm" dnats "github.com/sundynix/sundynix-dispatcher/internal/nats" ) func main() { natsURL := envOr("NATS_URL", "nats://localhost:4222") pool := llm.NewPool() // LLM Pool: vLLM / Ollama 集群 breaker := harness.NewCircuitBreaker() // Harness: 熔断降级中心 // Harness: LLM 自动化评测(规则 + LLM-as-judge,模型就绪时启用)。 eval := harness.NewEvaluator(pool.Ready, func(ctx context.Context, sys, user string) (string, error) { return pool.Chat(ctx, []llm.ChatMessage{{Role: "system", Content: sys}, {Role: "user", Content: user}}) }) sub := dnats.MustConnect(natsURL) defer sub.Close() // 配置控制面:启动时取激活模型配置,并订阅热更新。 cctx, ccancel := context.WithTimeout(context.Background(), 3*time.Second) if cfg, _ := sub.RequestModelConfig(cctx); cfg != nil { pool.SetConfig(cfg) } else { log.Println("[dispatcher] 未取到在线模型配置,降级桩运行(控制台配置后将热更新)") } ccancel() if _, err := sub.SubscribeModelConfigUpdated(pool.SetConfig); err != nil { log.Printf("[dispatcher] subscribe model config: %v", err) } // sub 同时作为 Token 回流出口(TokenSink)、MCP 工具调用出口(ToolCaller)与执行事件出口(ExecSink)。 orch, err := eino.NewOrchestrator(pool, breaker, eval, sub, sub, sub) if err != nil { log.Fatalf("[dispatcher] build eino graph: %v", err) } // 监听退出信号,优雅停止消费。 ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) defer stop() log.Println("[dispatcher] consuming sundynix.tasks.* (Ctrl-C to quit)") if err := sub.ConsumeTasks(ctx, orch.Handle); err != nil && err != context.Canceled { log.Fatalf("[dispatcher] exit: %v", err) } } func envOr(key, def string) string { if v := os.Getenv(key); v != "" { return v } return def }