feat: 第四轮功能增强 - LLM 思维记忆优化、DevTools 记忆UI、9个新工具、5分钟自我思考
- 优化 LLM 思维方式和记忆方法(类别/重要性/关键词/相似度合并/衰减) - DevTools 记忆查询 UI 重新设计(类别筛选/排序/星标/搜索) - 新增 9 个 LLM 工具:calculator, datetime, file_ops, http_request, json_ops, text, random, crypto, markdown - 管理员主对话 5 分钟自我思考增强(工具调用/记忆提取/记忆维护)
This commit is contained in:
@@ -0,0 +1,370 @@
|
||||
package tools
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/big"
|
||||
mathrand "math/rand"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// RandomTool provides random generation utilities for the LLM.
|
||||
// Supports random numbers, UUIDs, passwords, and list operations.
|
||||
type RandomTool struct{}
|
||||
|
||||
// NewRandomTool creates a random generation tool.
|
||||
func NewRandomTool() *RandomTool {
|
||||
return &RandomTool{}
|
||||
}
|
||||
|
||||
// Definition returns the tool definition for LLM function calling.
|
||||
func (t *RandomTool) Definition() ToolDefinition {
|
||||
return ToolDefinition{
|
||||
Name: "random",
|
||||
Description: "随机生成工具。生成随机数、UUID、安全密码,或从列表中随机选取/打乱元素。",
|
||||
Parameters: map[string]interface{}{
|
||||
"type": "object",
|
||||
"properties": map[string]interface{}{
|
||||
"action": map[string]interface{}{
|
||||
"type": "string",
|
||||
"enum": []string{"number", "uuid", "password", "pick", "shuffle"},
|
||||
"description": "操作类型。number: 生成随机整数;uuid: 生成UUID v4;password: 生成安全密码;pick: 从列表随机选取;shuffle: 随机打乱列表",
|
||||
},
|
||||
"min": map[string]interface{}{
|
||||
"type": "number",
|
||||
"description": "随机数最小值(用于 number 操作),默认 0",
|
||||
},
|
||||
"max": map[string]interface{}{
|
||||
"type": "number",
|
||||
"description": "随机数最大值(用于 number 操作),默认 100",
|
||||
},
|
||||
"length": map[string]interface{}{
|
||||
"type": "integer",
|
||||
"description": "密码长度(用于 password 操作),默认 16",
|
||||
},
|
||||
"items": map[string]interface{}{
|
||||
"type": "array",
|
||||
"description": "列表项(用于 pick/shuffle 操作),字符串数组",
|
||||
"items": map[string]interface{}{
|
||||
"type": "string",
|
||||
},
|
||||
},
|
||||
"count": map[string]interface{}{
|
||||
"type": "integer",
|
||||
"description": "选取数量(用于 pick 操作),默认 1",
|
||||
},
|
||||
},
|
||||
"required": []string{"action"},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Execute performs random generation operations.
|
||||
func (t *RandomTool) Execute(ctx context.Context, arguments map[string]interface{}) (*ToolResult, error) {
|
||||
action, ok := arguments["action"].(string)
|
||||
if !ok || action == "" {
|
||||
return &ToolResult{
|
||||
ToolName: "random",
|
||||
Success: false,
|
||||
Error: "缺少 action 参数",
|
||||
}, nil
|
||||
}
|
||||
|
||||
switch action {
|
||||
case "number":
|
||||
return t.handleNumber(arguments)
|
||||
case "uuid":
|
||||
return t.handleUUID()
|
||||
case "password":
|
||||
return t.handlePassword(arguments)
|
||||
case "pick":
|
||||
return t.handlePick(arguments)
|
||||
case "shuffle":
|
||||
return t.handleShuffle(arguments)
|
||||
default:
|
||||
return &ToolResult{
|
||||
ToolName: "random",
|
||||
Success: false,
|
||||
Error: fmt.Sprintf("未知操作: %s,支持: number, uuid, password, pick, shuffle", action),
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// handleNumber generates a random integer in [min, max].
|
||||
func (t *RandomTool) handleNumber(arguments map[string]interface{}) (*ToolResult, error) {
|
||||
minVal := getFloatArg(arguments, "min", 0)
|
||||
maxVal := getFloatArg(arguments, "max", 100)
|
||||
|
||||
if minVal > maxVal {
|
||||
minVal, maxVal = maxVal, minVal
|
||||
}
|
||||
|
||||
minI := int64(minVal)
|
||||
maxI := int64(maxVal)
|
||||
|
||||
// Use crypto/rand for secure random
|
||||
rangeVal := maxI - minI + 1
|
||||
if rangeVal <= 0 {
|
||||
return &ToolResult{
|
||||
ToolName: "random",
|
||||
Success: false,
|
||||
Error: "无效的数值范围",
|
||||
}, nil
|
||||
}
|
||||
|
||||
n, err := rand.Int(rand.Reader, big.NewInt(rangeVal))
|
||||
if err != nil {
|
||||
// Fallback to math/rand
|
||||
result := minI + mathrand.Int63n(rangeVal)
|
||||
return &ToolResult{
|
||||
ToolName: "random",
|
||||
Success: true,
|
||||
Data: fmt.Sprintf("随机整数 [%d, %d]: %d", minI, maxI, result),
|
||||
}, nil
|
||||
}
|
||||
|
||||
result := minI + n.Int64()
|
||||
return &ToolResult{
|
||||
ToolName: "random",
|
||||
Success: true,
|
||||
Data: fmt.Sprintf("随机整数 [%d, %d]: %d", minI, maxI, result),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// handleUUID generates a UUID v4 string.
|
||||
func (t *RandomTool) handleUUID() (*ToolResult, error) {
|
||||
uuid := make([]byte, 16)
|
||||
_, err := rand.Read(uuid)
|
||||
if err != nil {
|
||||
return &ToolResult{
|
||||
ToolName: "random",
|
||||
Success: false,
|
||||
Error: fmt.Sprintf("生成UUID失败: %v", err),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Set version 4 and variant bits
|
||||
uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4
|
||||
uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant 10
|
||||
|
||||
uuidStr := fmt.Sprintf("%08x-%04x-%04x-%04x-%012x",
|
||||
uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:16])
|
||||
|
||||
return &ToolResult{
|
||||
ToolName: "random",
|
||||
Success: true,
|
||||
Data: fmt.Sprintf("UUID v4: %s", uuidStr),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// handlePassword generates a secure random password.
|
||||
func (t *RandomTool) handlePassword(arguments map[string]interface{}) (*ToolResult, error) {
|
||||
length := getIntArg(arguments, "length", 16)
|
||||
if length < 4 {
|
||||
length = 16
|
||||
}
|
||||
if length > 128 {
|
||||
length = 128
|
||||
}
|
||||
|
||||
uppercase := "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
lowercase := "abcdefghijklmnopqrstuvwxyz"
|
||||
digits := "0123456789"
|
||||
symbols := "!@#$%^&*()_+-=[]{}|;:,.<>?"
|
||||
|
||||
allChars := uppercase + lowercase + digits + symbols
|
||||
|
||||
password := make([]byte, length)
|
||||
|
||||
// Ensure at least one of each character type
|
||||
password[0] = uppercase[secureIndex(len(uppercase))]
|
||||
password[1] = lowercase[secureIndex(len(lowercase))]
|
||||
password[2] = digits[secureIndex(len(digits))]
|
||||
password[3] = symbols[secureIndex(len(symbols))]
|
||||
|
||||
// Fill remaining with random characters from all sets
|
||||
for i := 4; i < length; i++ {
|
||||
password[i] = allChars[secureIndex(len(allChars))]
|
||||
}
|
||||
|
||||
// Shuffle the password
|
||||
shuffleBytes(password)
|
||||
|
||||
passwordStr := string(password)
|
||||
|
||||
return &ToolResult{
|
||||
ToolName: "random",
|
||||
Success: true,
|
||||
Data: fmt.Sprintf("安全密码 (长度: %d):\n%s\n\n字符集: 大写字母 + 小写字母 + 数字 + 特殊符号",
|
||||
length, passwordStr),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// handlePick randomly picks items from a list.
|
||||
func (t *RandomTool) handlePick(arguments map[string]interface{}) (*ToolResult, error) {
|
||||
items := getStringSliceArg(arguments, "items")
|
||||
if len(items) == 0 {
|
||||
return &ToolResult{
|
||||
ToolName: "random",
|
||||
Success: false,
|
||||
Error: "缺少 items 参数或列表为空",
|
||||
}, nil
|
||||
}
|
||||
|
||||
count := getIntArg(arguments, "count", 1)
|
||||
if count < 1 {
|
||||
count = 1
|
||||
}
|
||||
if count > len(items) {
|
||||
count = len(items)
|
||||
}
|
||||
|
||||
// Shuffle indices and pick first 'count'
|
||||
indices := make([]int, len(items))
|
||||
for i := range indices {
|
||||
indices[i] = i
|
||||
}
|
||||
shuffleInts(indices)
|
||||
|
||||
picked := make([]string, 0, count)
|
||||
for i := 0; i < count; i++ {
|
||||
picked = append(picked, items[indices[i]])
|
||||
}
|
||||
|
||||
var result strings.Builder
|
||||
result.WriteString(fmt.Sprintf("从 %d 个选项中随机选取 %d 个:\n", len(items), count))
|
||||
for i, p := range picked {
|
||||
result.WriteString(fmt.Sprintf(" %d. %s\n", i+1, p))
|
||||
}
|
||||
|
||||
return &ToolResult{
|
||||
ToolName: "random",
|
||||
Success: true,
|
||||
Data: result.String(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// handleShuffle randomly shuffles a list.
|
||||
func (t *RandomTool) handleShuffle(arguments map[string]interface{}) (*ToolResult, error) {
|
||||
items := getStringSliceArg(arguments, "items")
|
||||
if len(items) == 0 {
|
||||
return &ToolResult{
|
||||
ToolName: "random",
|
||||
Success: false,
|
||||
Error: "缺少 items 参数或列表为空",
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Make a copy and shuffle
|
||||
shuffled := make([]string, len(items))
|
||||
copy(shuffled, items)
|
||||
shuffleStrings(shuffled)
|
||||
|
||||
var result strings.Builder
|
||||
result.WriteString(fmt.Sprintf("随机打乱结果 (共 %d 项):\n", len(shuffled)))
|
||||
for i, s := range shuffled {
|
||||
result.WriteString(fmt.Sprintf(" %d. %s\n", i+1, s))
|
||||
}
|
||||
|
||||
return &ToolResult{
|
||||
ToolName: "random",
|
||||
Success: true,
|
||||
Data: result.String(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// --- Helper functions ---
|
||||
|
||||
// getFloatArg extracts a float64 argument with fallback.
|
||||
func getFloatArg(arguments map[string]interface{}, key string, fallback float64) float64 {
|
||||
if v, ok := arguments[key]; ok {
|
||||
switch val := v.(type) {
|
||||
case float64:
|
||||
return val
|
||||
case int:
|
||||
return float64(val)
|
||||
case int64:
|
||||
return float64(val)
|
||||
case json.Number:
|
||||
f, err := val.Float64()
|
||||
if err == nil {
|
||||
return f
|
||||
}
|
||||
}
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
|
||||
// getIntArg extracts an int argument with fallback.
|
||||
func getIntArg(arguments map[string]interface{}, key string, fallback int) int {
|
||||
if v, ok := arguments[key]; ok {
|
||||
switch val := v.(type) {
|
||||
case float64:
|
||||
return int(val)
|
||||
case int:
|
||||
return val
|
||||
case int64:
|
||||
return int(val)
|
||||
}
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
|
||||
// getStringSliceArg extracts a string slice argument.
|
||||
func getStringSliceArg(arguments map[string]interface{}, key string) []string {
|
||||
if v, ok := arguments[key]; ok {
|
||||
switch val := v.(type) {
|
||||
case []interface{}:
|
||||
result := make([]string, 0, len(val))
|
||||
for _, item := range val {
|
||||
if s, ok := item.(string); ok {
|
||||
result = append(result, s)
|
||||
} else {
|
||||
result = append(result, fmt.Sprintf("%v", item))
|
||||
}
|
||||
}
|
||||
return result
|
||||
case []string:
|
||||
return val
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// secureIndex returns a cryptographically secure random index in [0, max).
|
||||
func secureIndex(max int) int {
|
||||
if max <= 1 {
|
||||
return 0
|
||||
}
|
||||
n, err := rand.Int(rand.Reader, big.NewInt(int64(max)))
|
||||
if err != nil {
|
||||
return mathrand.Intn(max)
|
||||
}
|
||||
return int(n.Int64())
|
||||
}
|
||||
|
||||
// shuffleBytes shuffles a byte slice using Fisher-Yates with crypto/rand.
|
||||
func shuffleBytes(data []byte) {
|
||||
for i := len(data) - 1; i > 0; i-- {
|
||||
j := secureIndex(i + 1)
|
||||
data[i], data[j] = data[j], data[i]
|
||||
}
|
||||
}
|
||||
|
||||
// shuffleInts shuffles an int slice using Fisher-Yates with crypto/rand.
|
||||
func shuffleInts(data []int) {
|
||||
for i := len(data) - 1; i > 0; i-- {
|
||||
j := secureIndex(i + 1)
|
||||
data[i], data[j] = data[j], data[i]
|
||||
}
|
||||
}
|
||||
|
||||
// shuffleStrings shuffles a string slice using Fisher-Yates with crypto/rand.
|
||||
func shuffleStrings(data []string) {
|
||||
for i := len(data) - 1; i > 0; i-- {
|
||||
j := secureIndex(i + 1)
|
||||
data[i], data[j] = data[j], data[i]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user