Lzy01241010 commited on
Commit
8e87d9c
·
1 Parent(s): 48b03a2

search: parse knowledgeGraph/peopleAlsoAsk; treat 0-result as ok+hint

Browse files

Two robustness fixes for Serper search:
- Fold in knowledgeGraph (description + attributes) and peopleAlsoAsk
blocks. For many queries `organic` is empty but these carry the answer.
- When Serper genuinely returns nothing, return ok=True with an empty
result set + a "reformulate, drop quotes/rare acronyms" hint instead of
ok=False. Previously a 0-result Serper response was treated as a backend
failure, which fell through to the rate-limited DuckDuckGo path and
surfaced a misleading "all search backends failed" error. Now the agent
gets actionable feedback and the DDG 202 noise is gone. Mirrors
inference/tool_search.py "use a less specific query" behaviour.

Files changed (1) hide show
  1. app.py +42 -4
app.py CHANGED
@@ -1403,8 +1403,9 @@ def _serper_search(query: str, max_results: int) -> Dict[str, Any]:
1403
  "body": item.get("snippet", ""),
1404
  }
1405
  )
1406
- # Fold in the answer box and knowledge graph when present; these often
1407
- # carry the exact fact the model is looking for in a compact form.
 
1408
  answer_box = data.get("answerBox") or {}
1409
  if answer_box:
1410
  rows.insert(
@@ -1417,13 +1418,50 @@ def _serper_search(query: str, max_results: int) -> Dict[str, Any]:
1417
  or "",
1418
  },
1419
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1420
  if not rows:
 
 
 
 
 
 
 
1421
  return {
1422
- "ok": False,
1423
  "query": query,
1424
- "error": "Serper returned no organic results",
1425
  "results": [],
 
1426
  "backend": "serper",
 
 
 
 
 
1427
  }
1428
  return {
1429
  "ok": True,
 
1403
  "body": item.get("snippet", ""),
1404
  }
1405
  )
1406
+ # Fold in the answer box, knowledge graph and "people also ask" when
1407
+ # present; for many queries `organic` is empty but these rich blocks
1408
+ # still carry the exact fact the model is looking for.
1409
  answer_box = data.get("answerBox") or {}
1410
  if answer_box:
1411
  rows.insert(
 
1418
  or "",
1419
  },
1420
  )
1421
+ kg = data.get("knowledgeGraph") or {}
1422
+ if kg:
1423
+ kg_body = kg.get("description", "") or ""
1424
+ attrs = kg.get("attributes") or {}
1425
+ if attrs:
1426
+ kg_body = (kg_body + " " + "; ".join(
1427
+ f"{k}: {v}" for k, v in attrs.items()
1428
+ )).strip()
1429
+ if kg.get("title") or kg_body:
1430
+ rows.append(
1431
+ {
1432
+ "title": kg.get("title", "Knowledge graph"),
1433
+ "href": kg.get("descriptionLink") or kg.get("website", ""),
1434
+ "body": kg_body,
1435
+ }
1436
+ )
1437
+ for paa in (data.get("peopleAlsoAsk") or [])[:3]:
1438
+ if paa.get("question"):
1439
+ rows.append(
1440
+ {
1441
+ "title": paa.get("question", ""),
1442
+ "href": paa.get("link", ""),
1443
+ "body": paa.get("snippet", ""),
1444
+ }
1445
+ )
1446
  if not rows:
1447
+ # Serper worked but the query genuinely matched nothing. Return a
1448
+ # SUCCESSFUL-but-empty result (ok=True) carrying an actionable hint,
1449
+ # rather than ok=False — that way the agent is told to reformulate
1450
+ # instead of seeing a scary "all backends failed" message, and we
1451
+ # skip the rate-limited DuckDuckGo fallback (which would also find
1452
+ # nothing). Mirrors inference/tool_search.py's "use a less specific
1453
+ # query" behaviour.
1454
  return {
1455
+ "ok": True,
1456
  "query": query,
 
1457
  "results": [],
1458
+ "cached": False,
1459
  "backend": "serper",
1460
+ "note": (
1461
+ "No results for this query. Reformulate and search again: "
1462
+ "remove quotation marks (they force exact-phrase matching), "
1463
+ "drop rare acronyms, and use fewer / more common keywords."
1464
+ ),
1465
  }
1466
  return {
1467
  "ok": True,