feat(market): 技能/MCP 分类改为面向用户的业务场景(人群->场景),AI验证期按场景归类
This commit is contained in:
1 parent
6f3fb400a4
commit
9bcf15099f
4 files changed
+136
-38
No files matched your search
@@ -18,7 +18,7 @@ from ..models import (
|
||||
)
|
||||
from ..auth import get_current_user, get_current_user_id, get_current_user_id_optional
|
||||
from ..middleware.log_service import LogService
|
||||
from ..capability_registry import CAPABILITY_TYPES, resolve_auto_model as _resolve_auto_model
|
||||
from ..capability_registry import resolve_auto_model as _resolve_auto_model
|
||||
from app.api.admin.mcp_admin import _test_mcp_server, parse_mcp_config
|
||||
|
||||
router = APIRouter()
|
||||
@@ -207,9 +207,48 @@ def verify_agent_connectivity(platform: str, endpoint: str, api_key: str) -> dic
|
||||
return {"ok": False, "verified": False, "detail": f"地址不可达:{_short_err(e)}"}
|
||||
|
||||
|
||||
# ===== 能力分类(AI 自动归类,任何失败都返回 None,不阻断导入) =====
|
||||
def _classify_capability(name: str, description: Optional[str], content: Optional[str], db: Session) -> Optional[str]:
|
||||
"""用平台文本模型把应用归类到 11 种能力之一;失败返回 None(不阻断导入)。"""
|
||||
# ===== 业务场景分类(面向用户的技能/MCP 分类,与后端模型路由的 capability_registry 解耦) =====
|
||||
# 注意:MarketApp.capability 列在此存放「业务场景 id」(见 MARKET_SCENES),不再是 text/vision 等模型能力。
|
||||
MARKET_SCENES: list = [
|
||||
# 自由职业者
|
||||
{"id": "freelance_content", "label": "内容创作/自媒体", "color": "#F59E0B", "group": "freelance"},
|
||||
{"id": "freelance_client", "label": "客户沟通/提案", "color": "#F97316", "group": "freelance"},
|
||||
{"id": "freelance_finance", "label": "报价合同/记账", "color": "#FBBF24", "group": "freelance"},
|
||||
# 上班从业者
|
||||
{"id": "office_doc", "label": "文档/会议纪要", "color": "#3B82F6", "group": "office"},
|
||||
{"id": "office_data", "label": "数据/报表分析", "color": "#6366F1", "group": "office"},
|
||||
{"id": "office_email", "label": "邮件/协作", "color": "#0EA5E9", "group": "office"},
|
||||
{"id": "office_pm", "label": "项目/周报", "color": "#8B5CF6", "group": "office"},
|
||||
# 育人教育者
|
||||
{"id": "edu_prepare", "label": "备课/课件", "color": "#10B981", "group": "educator"},
|
||||
{"id": "edu_grade", "label": "作业批改/测评", "color": "#14B8A6", "group": "educator"},
|
||||
{"id": "edu_tutor", "label": "学情辅导/答疑", "color": "#22C55E", "group": "educator"},
|
||||
{"id": "edu_home", "label": "家校沟通", "color": "#84CC16", "group": "educator"},
|
||||
# 电商创业
|
||||
{"id": "biz_product", "label": "商品/营销文案", "color": "#EC4899", "group": "commerce"},
|
||||
{"id": "biz_service", "label": "客服/转化", "color": "#F43F5E", "group": "commerce"},
|
||||
{"id": "biz_ops", "label": "运营/投放", "color": "#D946EF", "group": "commerce"},
|
||||
# 通用提效
|
||||
{"id": "general_write", "label": "通用写作", "color": "#64748B", "group": "general"},
|
||||
{"id": "general_research", "label": "资料/调研", "color": "#06B6D4", "group": "general"},
|
||||
{"id": "general_agent", "label": "智能体/自动化", "color": "#A855F7", "group": "general"},
|
||||
]
|
||||
SCENE_GROUPS: list = [
|
||||
{"id": "freelance", "label": "自由职业者"},
|
||||
{"id": "office", "label": "上班从业者"},
|
||||
{"id": "educator", "label": "育人教育者"},
|
||||
{"id": "commerce", "label": "电商创业"},
|
||||
{"id": "general", "label": "通用提效"},
|
||||
]
|
||||
_VALID_SCENE_IDS = {s["id"] for s in MARKET_SCENES}
|
||||
|
||||
|
||||
def _scene_label(scene_id):
|
||||
return next((s["label"] for s in MARKET_SCENES if s["id"] == scene_id), None)
|
||||
|
||||
|
||||
def _classify_scene(name: str, description: Optional[str], content: Optional[str], db: Session) -> Optional[str]:
|
||||
"""用平台文本模型把应用归类到面向用户的业务场景之一;失败返回 None(不阻断导入)。"""
|
||||
try:
|
||||
text_model = _resolve_auto_model("text", db)
|
||||
if not text_model:
|
||||
@@ -225,9 +264,10 @@ def _classify_capability(name: str, description: Optional[str], content: Optiona
|
||||
)
|
||||
if not api_url:
|
||||
return None
|
||||
options = "、".join(f"{c['id']}({c['label']})" for c in CAPABILITY_TYPES)
|
||||
options = "、".join(f"{s['id']}({s['label']})" for s in MARKET_SCENES)
|
||||
sys_prompt = (
|
||||
"你是应用市场的能力分类器。根据应用名称、描述与内容,把它精确归类到下列能力之一:"
|
||||
"你是 AI 应用市场的『业务场景分类器』。请站在使用者视角,根据应用名称、描述与内容,"
|
||||
"判断它最常被哪一类【人群 / 岗位 / 业务场景】的用户使用,并归类到下列场景之一:"
|
||||
f"{options}。\n只返回一个 JSON 对象:{{\"capability\": \"<id>\"}},不要任何额外解释或 Markdown。"
|
||||
)
|
||||
user_text = f"名称:{name}\n描述:{description or ''}\n内容摘要:{(content or '')[:2000]}"
|
||||
@@ -247,7 +287,7 @@ def _classify_capability(name: str, description: Optional[str], content: Optiona
|
||||
data = r.json()
|
||||
text_out = data.get("choices", [{}])[0].get("message", {}).get("content", "")
|
||||
m = re.search(r'"capability"\s*:\s*"([a-z_]+)"', text_out)
|
||||
if m and m.group(1) in {c["id"] for c in CAPABILITY_TYPES}:
|
||||
if m and m.group(1) in _VALID_SCENE_IDS:
|
||||
return m.group(1)
|
||||
return None
|
||||
except Exception:
|
||||
@@ -283,9 +323,9 @@ def detect_capability(
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user),
|
||||
):
|
||||
"""导入前 AI 验证阶段:根据名称/描述/内容识别能力分类,供前台预填并允许用户修改。"""
|
||||
cap = _classify_capability(req.name, req.description, req.skill_content, db)
|
||||
label = next((c["label"] for c in CAPABILITY_TYPES if c["id"] == cap), None)
|
||||
"""导入前 AI 验证阶段:根据名称/描述/内容识别业务场景分类,供前台预填并允许用户修改。"""
|
||||
cap = _classify_scene(req.name, req.description, req.skill_content, db)
|
||||
label = _scene_label(cap)
|
||||
return {"code": 0, "data": {"capability": cap, "label": label}, "message": "ok"}
|
||||
|
||||
|
||||
@@ -528,7 +568,7 @@ def upload_app(
|
||||
)
|
||||
# 能力分类:前端显式指定优先;否则导入阶段由 AI 自动归类;都不行则留空(不阻断导入)
|
||||
_classify_content = req.skill_content or req.download_url or ""
|
||||
app.capability = req.capability or _classify_capability(req.name, req.description, _classify_content, db) or None
|
||||
app.capability = req.capability or _classify_scene(req.name, req.description, _classify_content, db) or None
|
||||
db.add(app)
|
||||
db.commit()
|
||||
db.refresh(app)
|
||||
|
||||
Reference in new issue
Block a user