package agent import ( "encoding/json" "fmt" "strings" ) // reactDecision 是 LLM 在统一 ReAct 循环中返回的结构化 JSON 决策。 // 每轮 LLM 调用都返回这个结构,由 agent 判断是否继续循环。 type reactDecision struct { // Thought 是 LLM 的当前推理过程描述 Thought string `json:"thought"` // Action 是需要调用的工具名称(如 "file"、"shell"、"web_search"),不需要工具时为 "none" 或空 Action string `json:"action"` // ActionInput 是传给工具的输入参数,可以是字符串或结构化对象 ActionInput json.RawMessage `json:"action_input"` // IsFinalAnswer 标记本轮是否为最终回答。true 表示 ReAct 循环结束。 IsFinalAnswer bool `json:"is_final_answer"` // FinalAnswer 当 IsFinalAnswer 为 true 时,包含给用户的最终回复内容 FinalAnswer *string `json:"final_answer"` } // GetActionInputString 将 ActionInput 转为字符串,用于传递给工具的 Call 方法。 // 如果 ActionInput 是 JSON 字符串则去掉引号;如果是对象/数组则保持 JSON 原文。 func (d *reactDecision) GetActionInputString() string { if len(d.ActionInput) == 0 { return "" } // 尝试解析为字符串 var s string if err := json.Unmarshal(d.ActionInput, &s); err == nil { return s } // 非字符串则直接返回 JSON 原文 return strings.TrimSpace(string(d.ActionInput)) } func parseDecision(raw string) (reactDecision, error) { raw = normalizeJSON(raw) start := strings.Index(raw, "{") end := strings.LastIndex(raw, "}") if start < 0 || end < start { return reactDecision{}, fmt.Errorf("no json object found") } raw = raw[start : end+1] var out reactDecision if err := json.Unmarshal([]byte(raw), &out); err != nil { return reactDecision{}, err } return out, nil } func normalizeJSON(raw string) string { raw = strings.TrimSpace(raw) raw = strings.TrimPrefix(raw, "```json") raw = strings.TrimPrefix(raw, "```") raw = strings.TrimSuffix(raw, "```") return strings.TrimSpace(raw) }