61 lines
1.9 KiB
Python
61 lines
1.9 KiB
Python
"""
|
||
pipeline_service/intent_classifier.py — Reusable intent classification.
|
||
|
||
DSPY can call: await intent_classify(model_name, message, intents, context)
|
||
Registered on ServerEnv in pipeline_service/init.py
|
||
"""
|
||
|
||
import json
|
||
import logging
|
||
|
||
logger = logging.getLogger("pipeline.intent_classifier")
|
||
|
||
INTENT_PROMPT = """你是一个意图分类器。分析用户输入,返回 JSON。
|
||
|
||
可用意图:
|
||
{intent_list}
|
||
|
||
当前上下文:{context_str}
|
||
|
||
返回纯 JSON(不要 markdown 包裹):
|
||
{{"intent":"...","confidence":0.0-1.0,"params":{{"key":"value"...}},"missing_info":"..."}}"""
|
||
|
||
|
||
async def intent_classify(intents: list, message: str, context: dict = None) -> dict:
|
||
"""Classify user intent. Returns {intent, confidence, params, missing_info}.
|
||
|
||
Args:
|
||
intents: [{"name":"new_project","description":"创建新项目"},...]
|
||
message: user input text
|
||
context: {"project_name":"...","iteration_name":"..."}
|
||
"""
|
||
if not intents:
|
||
return {"intent": "chat", "confidence": 0.5, "params": {}, "missing_info": ""}
|
||
|
||
intent_list = "\n".join(
|
||
f"- {i['name']}: {i.get('description','')}" for i in intents
|
||
)
|
||
ctx_parts = []
|
||
if context:
|
||
for k, v in context.items():
|
||
if v:
|
||
ctx_parts.append(f"{k}={v}")
|
||
context_str = ", ".join(ctx_parts) if ctx_parts else "无上下文"
|
||
|
||
prompt = INTENT_PROMPT.format(intent_list=intent_list, context_str=context_str)
|
||
|
||
try:
|
||
from pipeline_service.llm_bridge import llm_call
|
||
raw = await llm_call(
|
||
prompt=f"{prompt}\n\n用户输入:{message}",
|
||
model=None,
|
||
temperature=0.2,
|
||
)
|
||
raw = raw.strip()
|
||
if raw.startswith("```"):
|
||
raw = raw.split("\n", 1)[1].rsplit("```", 1)[0]
|
||
return json.loads(raw)
|
||
except Exception as e:
|
||
logger.warning("intent_classify failed: %s", e)
|
||
return {"intent": "chat", "confidence": 0.3, "params": {}, "missing_info": ""}
|