2026-02-28 17:48:33 +08:00
|
|
|
package agent
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"fmt"
|
|
|
|
|
"strings"
|
|
|
|
|
)
|
|
|
|
|
|
2026-03-05 17:44:19 +08:00
|
|
|
// 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))
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-28 17:48:33 +08:00
|
|
|
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)
|
|
|
|
|
}
|