feat(model): 工作模型与 JARVIS 语音模型分开配置 + 语音任务路由到快模型

模型配置加"用途"维度:工作主力(chat,要强)与 JARVIS 语音(voice,要快/低时延)各配各激活,
语音任务走语音模型池,未配置则透明回落工作模型——不影响现有功能。

- contract: ConfigKindVoice="voice" + Meta[model_profile]=voice(与 intent==report 同类路由)
- gateway: ServeConfig/broadcastActive 循环纳入 voice;submitVoiceTask 打 model_profile=voice 标记
- dispatcher: 第二个 llm.Pool(voicePool)吃 voice 配置热更新;board.useVoice 从 Meta 派生(含快照);
  Orchestrator.agentPool(b) 按黑板选池——语音且语音池就绪→语音池,否则工作池;
  agent 生成路径(graph/react/coordinator/compose)全改走 agentPool(b),报告/护栏/记忆固定工作池
- admin: 模型页三 Tab(工作主力/JARVIS语音/向量化),复用 ModelManager;api Kind 加 voice

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Blizzard
2026-07-22 11:39:17 +08:00
parent b6927247da
commit aec7ad949c
15 changed files with 102 additions and 50 deletions
+2 -2
View File
@@ -74,8 +74,8 @@ func main() {
bus := nats.MustConnect(natsURL) // 接入 NATS 零拷贝骨干网 + 声明任务流
defer bus.Close()
// 配置控制面:按 kind 响应消费方(Dispatcher=chat / mcp-go=embedding)的配置请求。
for _, kind := range []string{contract.ConfigKindChat, contract.ConfigKindEmbedding} {
// 配置控制面:按 kind 响应消费方(Dispatcher=chat/voice / mcp-go=embedding)的配置请求。
for _, kind := range []string{contract.ConfigKindChat, contract.ConfigKindEmbedding, contract.ConfigKindVoice} {
k := kind
if _, err := bus.ServeConfig(k, func() *contract.ModelConfig {
return db.ActiveConfig(context.Background(), k) // chat 含 Fallbacks(其它模型作备用)
+1 -1
View File
@@ -566,7 +566,7 @@ func (h *Handler) TestModel(c *gin.Context) {
// broadcastActive 重新广播各 kind 当前激活配置,触发对应消费方热更新。
// chat 配置带 Fallbacks(其它已登记 chat 模型作备用),dispatcher 据此重建 failover 链。
func (h *Handler) broadcastActive(ctx context.Context) {
for _, kind := range []string{contract.ConfigKindChat, contract.ConfigKindEmbedding} {
for _, kind := range []string{contract.ConfigKindChat, contract.ConfigKindEmbedding, contract.ConfigKindVoice} {
if cfg := h.db.ActiveConfig(ctx, kind); cfg != nil {
// 广播失败 = dispatcher/mcp-go 拿不到新配置,症状是"控制台改了模型却不生效",
// 而改配置的人这边一切正常。必须留痕,否则只能靠猜。
@@ -65,6 +65,7 @@ func (s *voiceSession) submitVoiceTask(transcript, graphOverride string) (string
task.Meta[contract.MetaUserID] = s.uid
task.Meta[contract.MetaTenantID] = billingTenant
task.Meta[contract.MetaSessionID] = s.sessionID
task.Meta[contract.MetaModelProfile] = contract.ModelProfileVoice // 语音任务走 JARVIS 快模型(未配则回落工作模型)
if err := s.h.launchCore(ctx, s.uid, task); err != nil {
return "", err