Fix intent classifier missing Research button requests
Two fixes for the intent model failing to route 'Research: X' messages
to research_topic:
1. Fast-path in classify_intent: if the message matches ^Research:\s+.+
(the exact format the UI Research button always sends), skip the LLM
call entirely and return research_topic with high confidence. This is
100% reliable and saves an unnecessary model call for this pattern.
2. Expanded research_topic rule examples in the system prompt to include
"Research: X" prefix format, shopping-style queries ("research where
to buy X"), and clarification that the topic is everything after the
keyword — improves LLM routing for natural-language research requests
that don't match the previous narrow examples.
Root cause: qwen2.5:1.5b misclassified "Research: where to buy three-
quarter sleeve tee shirts" as general chat (shopping query phrasing
combined with the colon confused the small model).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -104,12 +104,17 @@ Rules:
|
|||||||
("search for X", "look up X", "what is the latest version of X", "find X online",
|
("search for X", "look up X", "what is the latest version of X", "find X online",
|
||||||
"google X", "what is X" for quick factual answers — NOT when they want a comprehensive note)
|
"google X", "what is X" for quick factual answers — NOT when they want a comprehensive note)
|
||||||
- research_topic: user wants to research a topic and create a comprehensive note from web sources
|
- research_topic: user wants to research a topic and create a comprehensive note from web sources
|
||||||
("research X", "research X and make a note", "compile notes on X", "write a report on X",
|
("research X", "Research: X", "research X and make a note", "compile notes on X", "write a report on X",
|
||||||
"deep dive into X", "find everything about X", "comprehensive guide to X")
|
"deep dive into X", "find everything about X", "comprehensive guide to X",
|
||||||
|
"research where to buy X", "research how to X", "research X and ship to me" — the topic
|
||||||
|
is everything after "Research:" or "research")
|
||||||
- "ack": one short, natural sentence confirming the action (tool path only). Vary phrasing — do not always start with "Let me". Omit (null) for chat-only responses.
|
- "ack": one short, natural sentence confirming the action (tool path only). Vary phrasing — do not always start with "Let me". Omit (null) for chat-only responses.
|
||||||
- Do NOT wrap the JSON in markdown code fences."""
|
- Do NOT wrap the JSON in markdown code fences."""
|
||||||
|
|
||||||
|
|
||||||
|
_RESEARCH_PREFIX = re.compile(r"^[Rr]esearch:\s+(.+)", re.DOTALL)
|
||||||
|
|
||||||
|
|
||||||
async def classify_intent(
|
async def classify_intent(
|
||||||
user_message: str,
|
user_message: str,
|
||||||
tools: list[dict],
|
tools: list[dict],
|
||||||
@@ -127,6 +132,21 @@ async def classify_intent(
|
|||||||
if not tools:
|
if not tools:
|
||||||
return IntentResult()
|
return IntentResult()
|
||||||
|
|
||||||
|
# Fast-path: "Research: <topic>" is the canonical format sent by the Research
|
||||||
|
# button in the UI. It always means research_topic — skip the LLM call entirely.
|
||||||
|
valid_names = {t.get("function", {}).get("name") for t in tools}
|
||||||
|
if "research_topic" in valid_names:
|
||||||
|
m = _RESEARCH_PREFIX.match(user_message.strip())
|
||||||
|
if m:
|
||||||
|
topic = m.group(1).strip()
|
||||||
|
logger.info("Intent fast-path: 'Research:' prefix → research_topic, topic='%s'", topic[:80])
|
||||||
|
return IntentResult(
|
||||||
|
tool_name="research_topic",
|
||||||
|
arguments={"topic": topic},
|
||||||
|
confidence="high",
|
||||||
|
ack=f"I'll research that and compile a comprehensive note.",
|
||||||
|
)
|
||||||
|
|
||||||
tool_summary = _build_tool_summary(tools)
|
tool_summary = _build_tool_summary(tools)
|
||||||
today = date_type.today().isoformat()
|
today = date_type.today().isoformat()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user