- agent_handler.go: 新增agent管理接口 - agent_service.go: 扩展agent服务逻辑 - skill_handler.go: 更新skill接口 - chat_service.go: 更新chat服务 - model相关: 新增model仓库和服务 - main.go: 更新路由配置 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
182 lines
4.4 KiB
Go
182 lines
4.4 KiB
Go
package service
|
||
|
||
import (
|
||
"bytes"
|
||
"context"
|
||
"encoding/json"
|
||
"fmt"
|
||
"net/http"
|
||
"time"
|
||
|
||
"x-agents/server/internal/model"
|
||
"x-agents/server/internal/repository"
|
||
|
||
"github.com/google/uuid"
|
||
)
|
||
|
||
type ChatService struct {
|
||
pythonURL string
|
||
agentRepo *repository.AgentRepository
|
||
modelRepo *repository.ModelRepository
|
||
}
|
||
|
||
func NewChatService(pythonURL string, agentRepo *repository.AgentRepository, modelRepo *repository.ModelRepository) *ChatService {
|
||
return &ChatService{
|
||
pythonURL: pythonURL,
|
||
agentRepo: agentRepo,
|
||
modelRepo: modelRepo,
|
||
}
|
||
}
|
||
|
||
type ChatRequest struct {
|
||
AgentID string `json:"agent_id"`
|
||
Message string `json:"message"`
|
||
SessionID string `json:"session_id"`
|
||
ModelID string `json:"model_id"`
|
||
Context map[string]interface{} `json:"context"`
|
||
}
|
||
|
||
// ModelConfig 模型配置,用于传递给 Python 服务
|
||
type ModelConfig struct {
|
||
Provider string `json:"provider"`
|
||
Model string `json:"model"`
|
||
APIKey string `json:"api_key"`
|
||
BaseURL string `json:"base_url"`
|
||
APIEndpoint string `json:"api_endpoint"`
|
||
}
|
||
|
||
type ChatResponse struct {
|
||
Reply string `json:"reply"`
|
||
SessionID string `json:"session_id"`
|
||
ToolsUsed []string `json:"tools_used"`
|
||
Metadata map[string]interface{} `json:"metadata"`
|
||
}
|
||
|
||
// Chat 处理聊天请求
|
||
func (s *ChatService) Chat(ctx context.Context, userID string, req model.AgentRequest) (*model.AgentResponse, error) {
|
||
// 1. 检查 Agent 是否存在
|
||
agent, err := s.agentRepo.FindByID(req.AgentID)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("agent not found: %w", err)
|
||
}
|
||
|
||
// 2. 检查用户权限
|
||
if !agent.IsActive {
|
||
return nil, fmt.Errorf("agent is not active")
|
||
}
|
||
|
||
// 3. 生成会话ID
|
||
sessionID := req.SessionID
|
||
if sessionID == "" {
|
||
sessionID = uuid.New().String()
|
||
}
|
||
|
||
// 4. 如果提供了 ModelID,获取模型配置
|
||
var modelConfig *ModelConfig
|
||
if req.ModelID != "" {
|
||
modelInfo, err := s.modelRepo.FindByID(req.ModelID)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("model not found: %w", err)
|
||
}
|
||
modelConfig = &ModelConfig{
|
||
Provider: modelInfo.Provider,
|
||
Model: modelInfo.Model,
|
||
APIKey: modelInfo.APIKey,
|
||
BaseURL: modelInfo.BaseURL,
|
||
APIEndpoint: modelInfo.APIEndpoint,
|
||
}
|
||
}
|
||
|
||
// 5. 调用 Python 服务
|
||
pythonReq := ChatRequest{
|
||
AgentID: req.AgentID,
|
||
Message: req.Message,
|
||
SessionID: sessionID,
|
||
ModelID: req.ModelID,
|
||
Context: req.Context,
|
||
}
|
||
|
||
// 将模型配置放入 Context 中传递给 Python 服务
|
||
if modelConfig != nil {
|
||
pythonReq.Context = make(map[string]interface{})
|
||
for k, v := range req.Context {
|
||
pythonReq.Context[k] = v
|
||
}
|
||
pythonReq.Context["model_config"] = modelConfig
|
||
}
|
||
|
||
pythonResp, err := s.callPythonChat(ctx, pythonReq)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to call python service: %w", err)
|
||
}
|
||
|
||
return &model.AgentResponse{
|
||
Reply: pythonResp.Reply,
|
||
SessionID: pythonResp.SessionID,
|
||
ToolsUsed: pythonResp.ToolsUsed,
|
||
Metadata: pythonResp.Metadata,
|
||
}, nil
|
||
}
|
||
|
||
func (s *ChatService) callPythonChat(ctx context.Context, req ChatRequest) (*ChatResponse, error) {
|
||
jsonData, err := json.Marshal(req)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
httpReq, err := http.NewRequestWithContext(
|
||
ctx,
|
||
"POST",
|
||
s.pythonURL+"/agent/chat",
|
||
bytes.NewBuffer(jsonData),
|
||
)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
httpReq.Header.Set("Content-Type", "application/json")
|
||
|
||
client := &http.Client{
|
||
Timeout: 120 * time.Second, // Agent 可能需要较长时间
|
||
}
|
||
|
||
resp, err := client.Do(httpReq)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
defer resp.Body.Close()
|
||
|
||
if resp.StatusCode != http.StatusOK {
|
||
return nil, fmt.Errorf("python service returned status: %d", resp.StatusCode)
|
||
}
|
||
|
||
var chatResp ChatResponse
|
||
if err := json.NewDecoder(resp.Body).Decode(&chatResp); err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return &chatResp, nil
|
||
}
|
||
|
||
// ListAgents 获取用户可用的 Agent 列表
|
||
func (s *ChatService) ListAgents(userID string) ([]model.Agent, error) {
|
||
return s.agentRepo.FindByOwnerID(userID)
|
||
}
|
||
|
||
// CreateAgent 创建新的 Agent
|
||
func (s *ChatService) CreateAgent(userID string, name, description string) (*model.Agent, error) {
|
||
agent := &model.Agent{
|
||
ID: uuid.New().String(),
|
||
Name: name,
|
||
Description: description,
|
||
OwnerID: userID,
|
||
IsActive: true,
|
||
}
|
||
|
||
if err := s.agentRepo.Create(agent); err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return agent, nil
|
||
}
|