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_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")
|
||||
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:
|
||||
"""Decrypt api_key stored with password_encode."""
|
||||
"""Decrypt api_key stored with password_encode. Falls back to plaintext."""
|
||||
if not encrypted:
|
||||
return ""
|
||||
try:
|
||||
@ -27,7 +27,7 @@ def _decrypt_key(encrypted: str) -> str:
|
||||
key = config.password_key
|
||||
return unpassword(key, encrypted)
|
||||
except Exception:
|
||||
return encrypted
|
||||
return encrypted # already plaintext or decrypt failed
|
||||
|
||||
|
||||
async def _get_model_config(model_name: str = None) -> dict:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user