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,228 @@
|
||||
package tools
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// JSONTool provides JSON parsing, querying, and validation for the LLM.
|
||||
type JSONTool struct{}
|
||||
|
||||
// NewJSONTool creates a JSON processing tool.
|
||||
func NewJSONTool() *JSONTool {
|
||||
return &JSONTool{}
|
||||
}
|
||||
|
||||
// Definition returns the tool definition for LLM function calling.
|
||||
func (t *JSONTool) Definition() ToolDefinition {
|
||||
return ToolDefinition{
|
||||
Name: "json_ops",
|
||||
Description: "JSON处理工具。解析JSON字符串并格式化输出、用简单路径查询JSON字段、验证JSON是否合法。",
|
||||
Parameters: map[string]interface{}{
|
||||
"type": "object",
|
||||
"properties": map[string]interface{}{
|
||||
"action": map[string]interface{}{
|
||||
"type": "string",
|
||||
"enum": []string{"parse", "query", "validate"},
|
||||
"description": "操作类型。parse: 解析JSON并格式化输出;query: 用路径查询JSON中的值(如\"users.0.name\"表示取users数组第0个元素的name字段);validate: 验证JSON字符串是否合法",
|
||||
},
|
||||
"json_string": map[string]interface{}{
|
||||
"type": "string",
|
||||
"description": "JSON字符串",
|
||||
},
|
||||
"path": map[string]interface{}{
|
||||
"type": "string",
|
||||
"description": "查询路径(query操作时使用)。支持点分隔和数组索引,如 \"users.0.name\"、\"data.list.2.title\"",
|
||||
},
|
||||
},
|
||||
"required": []string{"action", "json_string"},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Execute performs JSON operations.
|
||||
func (t *JSONTool) Execute(ctx context.Context, arguments map[string]interface{}) (*ToolResult, error) {
|
||||
action, ok := arguments["action"].(string)
|
||||
if !ok || action == "" {
|
||||
return &ToolResult{
|
||||
ToolName: "json_ops",
|
||||
Success: false,
|
||||
Error: "缺少 action 参数",
|
||||
}, nil
|
||||
}
|
||||
|
||||
jsonStr, ok := arguments["json_string"].(string)
|
||||
if !ok || jsonStr == "" {
|
||||
return &ToolResult{
|
||||
ToolName: "json_ops",
|
||||
Success: false,
|
||||
Error: "缺少 json_string 参数",
|
||||
}, nil
|
||||
}
|
||||
|
||||
switch action {
|
||||
case "parse":
|
||||
return t.handleParse(jsonStr)
|
||||
case "query":
|
||||
path, _ := arguments["path"].(string)
|
||||
return t.handleQuery(jsonStr, path)
|
||||
case "validate":
|
||||
return t.handleValidate(jsonStr)
|
||||
default:
|
||||
return &ToolResult{
|
||||
ToolName: "json_ops",
|
||||
Success: false,
|
||||
Error: fmt.Sprintf("未知操作: %s,支持: parse, query, validate", action),
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// handleParse parses a JSON string and returns a formatted version.
|
||||
func (t *JSONTool) handleParse(jsonStr string) (*ToolResult, error) {
|
||||
var data interface{}
|
||||
if err := json.Unmarshal([]byte(jsonStr), &data); err != nil {
|
||||
return &ToolResult{
|
||||
ToolName: "json_ops",
|
||||
Success: false,
|
||||
Error: fmt.Sprintf("JSON解析失败: %v", err),
|
||||
}, nil
|
||||
}
|
||||
|
||||
pretty, err := json.MarshalIndent(data, "", " ")
|
||||
if err != nil {
|
||||
return &ToolResult{
|
||||
ToolName: "json_ops",
|
||||
Success: false,
|
||||
Error: fmt.Sprintf("JSON格式化失败: %v", err),
|
||||
}, nil
|
||||
}
|
||||
|
||||
return &ToolResult{
|
||||
ToolName: "json_ops",
|
||||
Success: true,
|
||||
Data: fmt.Sprintf("解析成功\n格式化输出:\n%s", string(pretty)),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// handleQuery queries a JSON value by dot-notation path.
|
||||
func (t *JSONTool) handleQuery(jsonStr, path string) (*ToolResult, error) {
|
||||
if path == "" {
|
||||
return &ToolResult{
|
||||
ToolName: "json_ops",
|
||||
Success: false,
|
||||
Error: "query 操作需要 path 参数",
|
||||
}, nil
|
||||
}
|
||||
|
||||
var data interface{}
|
||||
if err := json.Unmarshal([]byte(jsonStr), &data); err != nil {
|
||||
return &ToolResult{
|
||||
ToolName: "json_ops",
|
||||
Success: false,
|
||||
Error: fmt.Sprintf("JSON解析失败: %v", err),
|
||||
}, nil
|
||||
}
|
||||
|
||||
value, err := queryPath(data, path)
|
||||
if err != nil {
|
||||
return &ToolResult{
|
||||
ToolName: "json_ops",
|
||||
Success: false,
|
||||
Error: err.Error(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
pretty, err := json.MarshalIndent(value, "", " ")
|
||||
if err != nil {
|
||||
return &ToolResult{
|
||||
ToolName: "json_ops",
|
||||
Success: true,
|
||||
Data: fmt.Sprintf("路径: %s\n值: %v", path, value),
|
||||
}, nil
|
||||
}
|
||||
|
||||
return &ToolResult{
|
||||
ToolName: "json_ops",
|
||||
Success: true,
|
||||
Data: fmt.Sprintf("路径: %s\n值:\n%s", path, string(pretty)),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// handleValidate validates whether a string is valid JSON.
|
||||
func (t *JSONTool) handleValidate(jsonStr string) (*ToolResult, error) {
|
||||
var data interface{}
|
||||
if err := json.Unmarshal([]byte(jsonStr), &data); err != nil {
|
||||
// Try to give a helpful error message
|
||||
errStr := err.Error()
|
||||
// Extract line/position info if available
|
||||
return &ToolResult{
|
||||
ToolName: "json_ops",
|
||||
Success: true,
|
||||
Data: fmt.Sprintf("❌ JSON不合法\n错误: %s", errStr),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Determine JSON type
|
||||
typeName := "object"
|
||||
switch data.(type) {
|
||||
case []interface{}:
|
||||
typeName = "array"
|
||||
case string:
|
||||
typeName = "string"
|
||||
case float64:
|
||||
typeName = "number"
|
||||
case bool:
|
||||
typeName = "boolean"
|
||||
case nil:
|
||||
typeName = "null"
|
||||
}
|
||||
|
||||
size := len(jsonStr)
|
||||
return &ToolResult{
|
||||
ToolName: "json_ops",
|
||||
Success: true,
|
||||
Data: fmt.Sprintf("✅ JSON合法\n类型: %s\n大小: %d bytes", typeName, size),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// queryPath traverses a JSON value using dot-notation and array index syntax.
|
||||
// Examples: "users.0.name", "data.list", "items.2"
|
||||
func queryPath(data interface{}, path string) (interface{}, error) {
|
||||
// Remove leading "$." if present (JSONPath style)
|
||||
path = strings.TrimPrefix(path, "$.")
|
||||
if path == "" || path == "$" {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
parts := strings.Split(path, ".")
|
||||
current := data
|
||||
|
||||
for _, part := range parts {
|
||||
switch v := current.(type) {
|
||||
case map[string]interface{}:
|
||||
var ok bool
|
||||
current, ok = v[part]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("路径 '%s' 中字段 '%s' 不存在", path, part)
|
||||
}
|
||||
|
||||
case []interface{}:
|
||||
idx, err := strconv.Atoi(part)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("路径 '%s' 中 '%s' 不是有效的数组索引", path, part)
|
||||
}
|
||||
if idx < 0 || idx >= len(v) {
|
||||
return nil, fmt.Errorf("路径 '%s' 中索引 %d 越界(数组长度 %d)", path, idx, len(v))
|
||||
}
|
||||
current = v[idx]
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("路径 '%s' 中无法继续导航:'%s' 不是对象或数组", path, part)
|
||||
}
|
||||
}
|
||||
|
||||
return current, nil
|
||||
}
|
||||
Reference in New Issue
Block a user