package agent import ( "context" "encoding/json" "fmt" "time" "github.com/gogf/gf/v2/frame/g" ) // ReActAgent 实现 ReAct 模式的智能体 type ReActAgent struct { cfg *ModelConfig tools []*ToolInfo systemPrompt string maxStep int } // NewReActAgent 创建 ReAct 智能体 func NewReActAgent(cfg *ModelConfig, tools []*ToolInfo, systemPrompt string, maxStep int) *ReActAgent { return &ReActAgent{ cfg: cfg, tools: tools, systemPrompt: systemPrompt, maxStep: maxStep, } } // Run 执行 ReAct 循环 // 标准流程: 思考 → 行动(调用工具) → 观察(工具结果) → 重复 → 最终回答 func (a *ReActAgent) Run(ctx context.Context, userInput string) (string, error) { messages := []*ChatMessage{ {Role: RoleSystem, Content: a.systemPrompt}, {Role: RoleUser, Content: userInput}, } g.Log().Infof(ctx, "ReAct 开始执行,maxStep=%d, tools=%d", a.maxStep, len(a.tools)) for step := 0; step < a.maxStep; step++ { g.Log().Infof(ctx, "ReAct step %d/%d: 调用模型...", step+1, a.maxStep) startTime := time.Now() result, err := CallChatModel(ctx, a.cfg, &ChatRequest{ Messages: messages, MaxTokens: a.cfg.MaxTokens, Temperature: a.cfg.Temperature, Tools: a.tools, }) elapsed := time.Since(startTime) if err != nil { return "", fmt.Errorf("step %d: 模型调用失败: %w", step, err) } g.Log().Infof(ctx, "ReAct step %d/%d: 模型返回 (耗时 %v), content_len=%d, ToolCalls=%d", step+1, a.maxStep, elapsed, len(result.Content), len(result.ToolCalls)) messages = append(messages, &ChatMessage{ Role: RoleAssistant, Content: result.Content, ToolCalls: result.ToolCalls, }) // 无工具调用 → 最终回答 if len(result.ToolCalls) == 0 { g.Log().Infof(ctx, "ReAct step %d/%d: 无工具调用,返回最终结果", step+1, a.maxStep) return result.Content, nil } // 执行每个工具调用 for _, tc := range result.ToolCalls { tool := a.findTool(tc.Name) if tool == nil { g.Log().Warningf(ctx, "ReAct step %d: 未知工具: %s", step+1, tc.Name) messages = append(messages, &ChatMessage{ Role: RoleTool, Content: fmt.Sprintf("未知工具: %s", tc.Name), Name: tc.Name, ToolCallID: tc.ID, }) continue } var args map[string]any if err := json.Unmarshal([]byte(tc.Arguments), &args); err != nil { g.Log().Warningf(ctx, "ReAct step %d: 参数解析失败: %v", step+1, err) messages = append(messages, &ChatMessage{ Role: RoleTool, Content: fmt.Sprintf("参数解析失败: %v", err), Name: tc.Name, ToolCallID: tc.ID, }) continue } g.Log().Infof(ctx, "ReAct step %d: 调用工具 %s, 参数: %s", step+1, tc.Name, tc.Arguments) toolStart := time.Now() output, err := tool.Func(ctx, args) toolElapsed := time.Since(toolStart) if err != nil { output = fmt.Sprintf("工具执行失败: %v", err) g.Log().Warningf(ctx, "ReAct step %d: 工具 %s 执行失败 (耗时 %v): %v", step+1, tc.Name, toolElapsed, err) } else { truncated := output if len(truncated) > 200 { truncated = truncated[:200] + "..." } g.Log().Infof(ctx, "ReAct step %d: 工具 %s 执行成功 (耗时 %v), 结果长度=%d", step+1, tc.Name, toolElapsed, len(output)) } messages = append(messages, &ChatMessage{ Role: RoleTool, Content: output, Name: tc.Name, ToolCallID: tc.ID, }) } } g.Log().Errorf(ctx, "ReAct 达到最大步骤数 %d,生成未完成", a.maxStep) return "", fmt.Errorf("达到最大步骤数 %d,生成未完成", a.maxStep) } func (a *ReActAgent) findTool(name string) *ToolInfo { for _, t := range a.tools { if t.Name == name { return t } } return nil }