Adding intent based prompting

This commit is contained in:
Tyler
2026-05-17 15:53:44 -04:00
parent 1f7d54590f
commit 4e2f9d97d7
+141 -10
View File
@@ -781,6 +781,7 @@ FRONTEND_JS_TEMPLATE = r"""
const script_root = __SCRIPT_ROOT__;
const model_init = __MODEL_INIT__;
const session_id_init = __SESSION_ID__;
const intent_init = __INTENT__;
if (session_id_init && !document.cookie.includes('sxng_ai_session')) {
document.cookie = `sxng_ai_session=${session_id_init}; path=/; max-age=1800; SameSite=Lax`;
}
@@ -799,6 +800,14 @@ FRONTEND_JS_TEMPLATE = r"""
__CITATION_HELPER_JS__
(function applyIntentBadge() {
const intentEmoji = {factual:'📖',howto:'🔧',technical:'⌨️',comparison:'⚖️',opinion:'💬',current:'📰',local:'📍'}[intent_init] || '';
if (intentEmoji) {
const label = box ? box.querySelector('.sxng-ai-label') : null;
if (label) label.innerHTML += ` <span style="font-size:0.8em;opacity:0.7;">${intentEmoji}</span>`;
}
})();
__INTERACTIVE_JS_INIT__
async function loadPriorConversation() {
@@ -1083,6 +1092,122 @@ FRONTEND_JS_TEMPLATE = r"""
})();
"""
def _detect_intent(query: str) -> str:
q = query.lower().strip()
if any(w in q for w in ['news', 'latest', 'recent', 'today', 'yesterday',
'this week', 'breaking', '2025', '2026', 'update']):
return 'current'
if any(q.startswith(p) for p in ['how to', 'how do i', 'how can i',
'how do you', 'steps to', 'guide to',
'tutorial', 'how does']):
return 'howto'
if any(w in q for w in ['install', 'configure', 'setup', 'set up',
'enable', 'disable', 'fix', 'repair']):
return 'howto'
if any(w in q for w in ['error', 'exception', 'traceback', 'debug',
'code', 'function', 'script', 'api', 'command',
'terminal', 'bash', 'python', 'javascript',
'docker', 'linux', 'git', 'sql', 'regex']):
return 'technical'
if ' vs ' in q or ' versus ' in q or 'difference between' in q or \
'compare ' in q or (' or ' in q and len(q.split()) < 8):
return 'comparison'
if any(q.startswith(p) for p in ['best ', 'top ', 'worst ', 'should i',
'is it worth', 'recommend']):
return 'opinion'
if any(w in q for w in ['worth it', 'better than', 'best way',
'recommend', 'suggestion', 'advice']):
return 'opinion'
if any(w in q for w in ['near me', 'nearby', 'local', 'in my area',
'closest', 'directions to']):
return 'local'
if any(q.startswith(p) for p in ['what is', 'what are', 'who is',
'who was', 'when did', 'when was',
'where is', 'where was', 'why is',
'why does', 'define ', 'what does']):
return 'factual'
return 'general'
INTENT_CONFIGS = {
'factual': {
'system_suffix': (
"This is a factual question. Provide a direct, accurate definition "
"or explanation. Lead with the core fact. Cite your primary source. "
"2-3 sentences maximum."
),
'task': "DEFINE: State the fact or definition directly. No preamble.",
'format': "Plain prose. No lists. Cite the most authoritative source first."
},
'howto': {
'system_suffix': (
"This is a how-to question. Provide clear, actionable steps. "
"Be specific and practical. Number the key steps if there are more than 2."
),
'task': "INSTRUCT: Give the key steps or method directly. Be actionable.",
'format': "Numbered steps if 3+, otherwise prose. Cite sources for each step."
},
'technical': {
'system_suffix': (
"This is a technical question. Be precise and specific. "
"Include exact commands, syntax, or error explanations where relevant. "
"Prioritize official documentation and technical sources."
),
'task': "TECHNICAL: Provide the precise technical answer. Include specifics.",
'format': "Exact terminology. Commands in backticks if applicable. Cite docs."
},
'comparison': {
'system_suffix': (
"This is a comparison question. Objectively compare the options. "
"Highlight key differences. Avoid picking a winner unless sources clearly support it."
),
'task': "COMPARE: State the key differences between the options directly.",
'format': "Brief parallel structure. Cite a source for each side if available."
},
'opinion': {
'system_suffix': (
"This is a recommendation or opinion question. Synthesize what sources say. "
"Present the consensus view if one exists. Note disagreement if present. "
"Do not present personal opinions as fact."
),
'task': "SYNTHESIZE: State what sources recommend or what consensus says.",
'format': "Lead with the consensus. Note any caveats. Cite sources."
},
'current': {
'system_suffix': (
"This is a current events question. Prioritize the most recent sources. "
"Note the date of information if relevant. Be clear about what is known vs uncertain."
),
'task': "REPORT: State the latest known information directly. Note recency.",
'format': "Lead with most recent fact. Include dates where available. Cite news sources."
},
'local': {
'system_suffix': (
"This is a local or location-based question. "
"Provide relevant location-specific information from sources. "
"Note if information may vary by location."
),
'task': "LOCAL: Provide location-relevant information from sources.",
'format': "Be specific to the location context. Cite local sources."
},
'general': {
'system_suffix': (
"Provide a concise, accurate overview that directly answers the query."
),
'task': "ANSWER FIRST: Lead with the direct answer. No preamble.",
'format': "2-4 sentences. Cite most relevant sources."
},
}
import typing
if typing.TYPE_CHECKING:
from searx.search import SearchWithPlugins
@@ -1396,17 +1521,21 @@ class SXNGPlugin(Plugin):
if not self.api_key:
return Response("Missing API key or query", status=400)
intent = _detect_intent(q)
intent_cfg = INTENT_CONFIGS.get(intent, INTENT_CONFIGS['general'])
logger.debug(f"{PLUGIN_NAME}: detected intent '{intent}' for query: {q[:50]}")
today = time.strftime("%Y-%m-%d")
lang_instruction = f" Respond in {lang}." if lang not in ('all', 'auto') else ""
base_sys = self.system_prompt if self.system_prompt else "You are a direct, citation-accurate search synthesis engine."
SYSTEM = (f"{base_sys} Today is {today}.{lang_instruction} "
base_sys = self.system_prompt if self.system_prompt else \
"You are a direct, citation-accurate search synthesis engine."
SYSTEM = (
f"{base_sys} Today is {today}.{lang_instruction} "
"Output only your final answer. Do not output your thinking process, "
"reasoning steps, or internal monologue. Begin your response with the "
"direct answer immediately. "
"Be concise. Give a 2-4 sentence overview that directly answers the query. "
"The user can ask follow-up questions for more detail. "
"Do not enumerate or list everything from the sources.")
f"direct answer immediately. {intent_cfg['system_suffix']}"
)
max_source_idx = 0
if context_text:
indices = re.findall(r'\[(\d+)\]', context_text)
@@ -1417,9 +1546,7 @@ class SXNGPlugin(Plugin):
"Answer the question directly using the provided context.",
"MUST CITE SOURCES by tailing a sentence with [n] or [n,n] etc. If citing general knowledge, use [*].",
"Never explain your process. The user expects a direct response.",
"Response format must be plain text with no markdown. "
"Be brief: 2-4 sentences maximum. Lead with the direct answer. "
"Cite the most relevant source(s) only. Stop after the overview.",
intent_cfg['format'],
"If sources and general knowledge are insufficient, respond with 'Insufficient information to answer.'"
]
@@ -1428,7 +1555,7 @@ class SXNGPlugin(Plugin):
elif prev_answer:
task = "FOLLOW-UP: Address the new question using prior context. Prioritize the new query."
else:
task = "ANSWER FIRST: Lead with the direct answer. No preamble, no context-setting."
task = intent_cfg['task']
grounding = "GROUNDING: KNOWLEDGE GRAPH > DEEP > SHALLOW." if context_text else "GROUNDING: No sources available. Use general knowledge and cite as [*] which means based on general knowledge."
history_rule = "HISTORY: Refer to prior exchange for context. Ideally, do not repeat any claims." if prev_answer else None
@@ -1770,6 +1897,9 @@ class SXNGPlugin(Plugin):
).hexdigest()[:24]
js_session_id = safe_json(session_id)
detected_intent = _detect_intent(q_clean)
js_intent = safe_json(detected_intent)
b64_context = base64.b64encode(context_str.encode('utf-8')).decode('utf-8')
total_context_count = self.context_deep_count + self.context_shallow_count
@@ -1803,6 +1933,7 @@ class SXNGPlugin(Plugin):
.replace("__SCRIPT_ROOT__", js_script_root) \
.replace("__MODEL_INIT__", js_model_init) \
.replace("__SESSION_ID__", js_session_id) \
.replace("__INTENT__", js_intent) \
.replace("__CITATION_HELPER_JS__", CITATION_HELPER_JS) \
.replace("__INTERACTIVE_JS_INIT__", interactive_js_init) \
.replace("__STREAM_FN_SIG__", stream_fn_sig) \