| 72 | } |
| 73 | |
| 74 | func (t *SemanticSearchTool) Execute(ctx context.Context, input map[string]any, tc *tools.ToolContext) (any, error) { |
| 75 | if t.sm == nil || !t.sm.Enabled() { |
| 76 | return nil, errors.New("semantic memory not configured") |
| 77 | } |
| 78 | |
| 79 | rawQuery, _ := input["query"].(string) |
| 80 | if rawQuery == "" { |
| 81 | return nil, errors.New("query is required") |
| 82 | } |
| 83 | |
| 84 | // 可选 top_k |
| 85 | topK := 0 |
| 86 | if v, ok := input["top_k"].(float64); ok { |
| 87 | topK = int(v) |
| 88 | } |
| 89 | |
| 90 | // 可选 metadata |
| 91 | meta := map[string]any{} |
| 92 | if m, ok := input["metadata"].(map[string]any); ok && m != nil { |
| 93 | meta = m |
| 94 | } |
| 95 | |
| 96 | hits, err := t.sm.Search(ctx, rawQuery, meta, topK) |
| 97 | if err != nil { |
| 98 | return nil, err |
| 99 | } |
| 100 | |
| 101 | // 简单序列化 hits 为 JSON 友好的结构 |
| 102 | out := make([]map[string]any, 0, len(hits)) |
| 103 | for _, h := range hits { |
| 104 | out = append(out, map[string]any{ |
| 105 | "id": h.ID, |
| 106 | "score": h.Score, |
| 107 | "metadata": h.Metadata, |
| 108 | }) |
| 109 | } |
| 110 | return out, nil |
| 111 | } |
| 112 | |
| 113 | func (t *SemanticSearchTool) Prompt() string { |
| 114 | return "Use this tool to perform semantic search over previously indexed texts when keyword search is insufficient. " + |