Skip to content

Commit be47949

Browse files
committed
fix(sql): limit schema search metadata
1 parent e95352b commit be47949

3 files changed

Lines changed: 20 additions & 50 deletions

File tree

‎backend/web/src/main/java/org/jumpserver/chen/web/ai/AgentWebSocketHandler.java‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,8 @@ static List<Map<String, Object>> toolDefinitions() {
409409
"Find related tables",
410410
"Rank table candidates from a business question or keywords using table and column names/comments "
411411
+ "inside the verified active schema. The current table is kept as an anchor. "
412-
+ "Returns brief reasons; inspect_schema can then inspect exact table names. "
412+
+ "Returns table names, scores and match categories without column or comment text; "
413+
+ "inspect_schema can then inspect exact table names. "
413414
+ "Column matching is limited to a bounded set of likely tables. This never reads business rows.",
414415
"{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"query\"],"
415416
+ "\"properties\":{"

‎backend/web/src/main/java/org/jumpserver/chen/web/ai/SchemaSearchRanker.java‎

Lines changed: 18 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@
1717
/** In-memory, metadata-only lexical ranking for the active schema. */
1818
final class SchemaSearchRanker {
1919
private static final int MAX_QUERY_TERMS = 32;
20-
private static final int MAX_MATCH_REASONS = 6;
2120
private static final int CONTEXT_TABLE_BOOST = 5;
2221
private static final int COVERAGE_BONUS = 6;
22+
private static final List<String> MATCH_SOURCES = List.of(
23+
"table_name", "table_comment", "column_name", "column_comment"
24+
);
2325

2426
private SchemaSearchRanker() {
2527
}
@@ -73,12 +75,11 @@ static RankedResults rank(
7375
for (String term : terms) {
7476
int nameScore = fieldScore(term, column.name(), 9, 7, 5);
7577
if (nameScore > 0) {
76-
candidate.match(term, nameScore, "column: " + preview(column.name(), 96));
78+
candidate.match(term, nameScore, "column_name");
7779
}
7880
int commentScore = fieldScore(term, column.comment(), 7, 6, 4);
7981
if (commentScore > 0) {
80-
candidate.match(term, commentScore, "column: " + preview(column.name(), 96)
81-
+ " / " + preview(column.comment(), 128));
82+
candidate.match(term, commentScore, "column_comment");
8283
}
8384
}
8485
}
@@ -112,18 +113,18 @@ private static void addRelationMatches(Candidate candidate, List<String> terms,
112113
String table = candidate.relation.ref().name();
113114
String comment = candidate.relation.comment();
114115
if (normalize(table).equals(exactQuery)) {
115-
candidate.exactMatch(12, "table_name: exact " + preview(table, 128));
116+
candidate.exactMatch(12, "table_name");
116117
} else if (comment != null && normalize(comment).equals(exactQuery)) {
117-
candidate.exactMatch(6, "table_comment: exact " + preview(comment, 160));
118+
candidate.exactMatch(6, "table_comment");
118119
}
119120
for (String term : terms) {
120121
int nameScore = fieldScore(term, table, 18, 12, 8);
121122
if (nameScore > 0) {
122-
candidate.match(term, nameScore, "table_name: " + preview(table, 128));
123+
candidate.match(term, nameScore, "table_name");
123124
}
124125
int commentScore = fieldScore(term, comment, 12, 10, 7);
125126
if (commentScore > 0) {
126-
candidate.match(term, commentScore, "table_comment: " + preview(comment, 160));
127+
candidate.match(term, commentScore, "table_comment");
127128
}
128129
}
129130
}
@@ -212,74 +213,48 @@ private static boolean isCurrentTable(RelationMetadata relation, String currentT
212213
return currentTable != null && currentTable.equals(relation.ref().name());
213214
}
214215

215-
private static String preview(String value, int maximum) {
216-
if (value == null) {
217-
return "";
218-
}
219-
return value.length() <= maximum ? value : value.substring(0, maximum) + "…";
220-
}
221-
222216
record RankedResults(List<Map<String, Object>> candidates, boolean truncated) {
223217
}
224218

225219
private record ScoredRelation(RelationMetadata relation, int score) {
226220
}
227221

228-
private record Match(int weight, String reason) {
229-
}
230-
231222
private static final class Candidate {
232223
private final RelationMetadata relation;
233224
private final boolean currentTable;
234-
private final Map<String, Match> matches = new LinkedHashMap<>();
225+
private final Map<String, Integer> matches = new LinkedHashMap<>();
226+
private final Set<String> matchedSources = new LinkedHashSet<>();
235227
private int exactQueryBonus;
236-
private String exactQueryReason;
237228

238229
private Candidate(RelationMetadata relation, boolean currentTable) {
239230
this.relation = relation;
240231
this.currentTable = currentTable;
241232
}
242233

243-
private void match(String term, int weight, String reason) {
244-
Match previous = matches.get(term);
245-
if (previous == null || weight > previous.weight()) {
246-
matches.put(term, new Match(weight, reason));
247-
}
234+
private void match(String term, int weight, String source) {
235+
matchedSources.add(source);
236+
matches.merge(term, weight, Math::max);
248237
}
249238

250-
private void exactMatch(int weight, String reason) {
239+
private void exactMatch(int weight, String source) {
251240
exactQueryBonus = weight;
252-
exactQueryReason = reason;
241+
matchedSources.add(source);
253242
}
254243

255244
private int score() {
256-
return matches.values().stream().mapToInt(Match::weight).sum()
245+
return matches.values().stream().mapToInt(Integer::intValue).sum()
257246
+ Math.max(0, matches.size() - 1) * COVERAGE_BONUS
258247
+ exactQueryBonus
259248
+ (currentTable ? CONTEXT_TABLE_BOOST : 0);
260249
}
261250

262251
private Map<String, Object> serialize() {
263-
Set<String> reasons = new LinkedHashSet<>();
264-
if (currentTable) {
265-
reasons.add("context_table: current table");
266-
}
267-
if (exactQueryReason != null) {
268-
reasons.add(exactQueryReason);
269-
}
270-
for (Match match : matches.values()) {
271-
reasons.add(match.reason());
272-
if (reasons.size() >= MAX_MATCH_REASONS) {
273-
break;
274-
}
275-
}
276252
Map<String, Object> result = new LinkedHashMap<>();
277253
result.put("table", relation.ref().name());
278-
result.put("comment", preview(relation.comment(), 256));
279254
result.put("score", score());
280255
result.put("matchedKeywords", matches.size());
281256
result.put("currentTable", currentTable);
282-
result.put("matches", List.copyOf(reasons));
257+
result.put("matchedOn", MATCH_SOURCES.stream().filter(matchedSources::contains).toList());
283258
return result;
284259
}
285260
}

‎backend/web/src/main/java/org/jumpserver/chen/web/ai/SqlAgentToolService.java‎

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -461,14 +461,8 @@ private Map<String, Object> searchSchema(
461461
);
462462

463463
Map<String, Object> result = new LinkedHashMap<>();
464-
result.put("query", request.query());
465-
result.put("requestedScope", metadataScopeMap(context.database(), request.schema()));
466-
result.put("resolvedScope", metadataScopeMap(scope.catalog(), scope.schema()));
467464
result.put("candidates", ranked.candidates());
468465
result.put("truncated", ranked.truncated());
469-
result.put("availableRelationCount", available.size());
470-
result.put("searchedRelationCount", columnCandidates.size());
471-
result.put("columnSearchAvailable", catalog.capabilities().columns());
472466
result.put("columnSearchLimited", columnCandidates.size() < available.size());
473467
assertRequestContextCurrent(session, context);
474468
return result;

0 commit comments

Comments
 (0)