refactor: add intent_classifier.py, register in init.py, LLM bridge shared
This commit is contained in:
parent
0253615fcc
commit
0423fa3c99
@ -367,5 +367,11 @@ def load_pipeline_service():
|
|||||||
# Load built-in interactive step types
|
# Load built-in interactive step types
|
||||||
load_builtin_types()
|
load_builtin_types()
|
||||||
|
|
||||||
|
# Register intent classifier + LLM bridge (shared across all pipelines)
|
||||||
|
from .intent_classifier import intent_classify
|
||||||
|
from .llm_bridge import llm_call
|
||||||
|
env.intent_classify = intent_classify
|
||||||
|
env.pipeline_llm_call = llm_call
|
||||||
|
|
||||||
debug(f"[{MODULE_NAME}] v{MODULE_VERSION} loaded — pipeline engine with human-in-the-loop support")
|
debug(f"[{MODULE_NAME}] v{MODULE_VERSION} loaded — pipeline engine with human-in-the-loop support")
|
||||||
return True
|
return True
|
||||||
|
|||||||
60
pipeline_service/intent_classifier.py
Normal file
60
pipeline_service/intent_classifier.py
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
"""
|
||||||
|
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": ""}
|
||||||
@ -17,7 +17,7 @@ _model_cache: dict = {}
|
|||||||
|
|
||||||
|
|
||||||
def _decrypt_key(encrypted: str) -> str:
|
def _decrypt_key(encrypted: str) -> str:
|
||||||
"""Decrypt api_key stored with password_encode."""
|
"""Decrypt api_key stored with password_encode. Falls back to plaintext."""
|
||||||
if not encrypted:
|
if not encrypted:
|
||||||
return ""
|
return ""
|
||||||
try:
|
try:
|
||||||
@ -27,7 +27,7 @@ def _decrypt_key(encrypted: str) -> str:
|
|||||||
key = config.password_key
|
key = config.password_key
|
||||||
return unpassword(key, encrypted)
|
return unpassword(key, encrypted)
|
||||||
except Exception:
|
except Exception:
|
||||||
return encrypted
|
return encrypted # already plaintext or decrypt failed
|
||||||
|
|
||||||
|
|
||||||
async def _get_model_config(model_name: str = None) -> dict:
|
async def _get_model_config(model_name: str = None) -> dict:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user