package service import ( "context" "fmt" "os" "strings" "time" "ai-agent-scaffold-go/internal/config" "ai-agent-scaffold-go/internal/llm" "ai-agent-scaffold-go/internal/model" ) // AssembleAll 从配置表批量组装 Agent func AssembleAll(ctx context.Context, tables map[string]model.AiAgentConfigTable, timeout time.Duration) ([]model.RegisteredAgent, error) { var agents []model.RegisteredAgent for _, table := range tables { agent, err := assembleOne(ctx, table, timeout) if err != nil { return nil, fmt.Errorf("assemble %s: %w", table.AppName, err) } agents = append(agents, *agent) } return agents, nil } // assembleOne 组装单个 Agent 配置 func assembleOne(ctx context.Context, table model.AiAgentConfigTable, timeout time.Duration) (*model.RegisteredAgent, error) { apiCfg := table.Module.AiAPI completionsURL := strings.TrimRight(apiCfg.BaseURL, "/") + "/" + strings.TrimLeft(apiCfg.CompletionsPath, "/") // 1. 创建 OpenAI 客户端 client := llm.NewOpenAIClient(completionsURL, apiCfg.APIKey, table.Module.ChatModel.Model, timeout) // 2. 创建 ChatModel(当前无外部工具,后续可扩展) chatModel := llm.NewChatModelAdapter(client, nil) // 3. 构建 Agent 映射表 agentMap := map[string]model.Agent{} for _, agentCfg := range table.Module.Agents { agent := NewLLMAgent(agentCfg.Name, agentCfg.Instruction, agentCfg.Description, agentCfg.OutputKey, chatModel) agentMap[agentCfg.Name] = agent } // 4. 构建 Workflow Agent for _, wfCfg := range table.Module.AgentWorkflows { subs := make([]model.Agent, 0, len(wfCfg.SubAgents)) for _, subName := range wfCfg.SubAgents { sub, ok := agentMap[subName] if !ok { return nil, fmt.Errorf("workflow %q references unknown agent %q", wfCfg.Name, subName) } subs = append(subs, sub) } var wfAgent model.Agent switch wfCfg.Type { case model.WorkflowTypeSequential: wfAgent = NewSequentialAgent(wfCfg.Name, wfCfg.Description, subs) case model.WorkflowTypeParallel: wfAgent = NewParallelAgent(wfCfg.Name, wfCfg.Description, subs) case model.WorkflowTypeLoop: wfAgent = NewLoopAgent(wfCfg.Name, wfCfg.Description, subs, wfCfg.MaxIterations) default: return nil, fmt.Errorf("unknown workflow type: %s", wfCfg.Type) } agentMap[wfCfg.Name] = wfAgent } // 5. 解析入口 Agent entryName := table.Module.Runner.AgentName entryAgent, ok := agentMap[entryName] if !ok { return nil, fmt.Errorf("entry agent %q not found", entryName) } // 6. 创建 Runner runner := NewRunner(table.AppName, entryAgent) return &model.RegisteredAgent{ AppName: table.AppName, AgentID: table.Agent.AgentID, AgentName: table.Agent.AgentName, AgentDesc: table.Agent.AgentDesc, Runner: runner, }, nil } // LoadAndAssemble 从配置文件路径列表加载并组装所有 Agent func LoadAndAssemble(ctx context.Context, paths []string, timeout time.Duration) ([]model.RegisteredAgent, error) { merged := make(map[string]model.AiAgentConfigTable) for _, raw := range paths { path := strings.TrimSpace(raw) if path == "" { continue } expanded := os.ExpandEnv(path) tables, err := config.LoadAgentTablesFile(expanded) if err != nil { return nil, err } for name, table := range tables { merged[name] = table } } if len(merged) == 0 { return nil, fmt.Errorf("no agent tables loaded") } return AssembleAll(ctx, merged, timeout) }