feat: 技能检索LLM语义匹配+SDLC能力声明功能菜单(项目/Bug/测试/迭代)
This commit is contained in:
parent
488ba4daa4
commit
50c9220d2d
@ -357,6 +357,35 @@ class AgentExecutor:
|
||||
except Exception:
|
||||
return self.config.skills.base_dir
|
||||
|
||||
async def _llm_select_skills(self, user_input: str, catalog, max_skills: int) -> List[str]:
|
||||
"""用 LLM 从技能目录选最相关的 N 个技能(语义匹配,非关键词硬编码)。"""
|
||||
if not catalog:
|
||||
return []
|
||||
catalog_text = "\n".join(f"- {name}: {desc}" for name, desc in catalog)
|
||||
prompt = (
|
||||
f"以下是可用技能目录(技能名: 描述):\n{catalog_text}\n\n"
|
||||
f"用户需求:{user_input}\n\n"
|
||||
f"请从上述目录中选出与用户需求最相关的至多 {max_skills} 个技能,"
|
||||
f"只返回技能名的 JSON 数组,如 [\"a\", \"b\"]。没有相关技能返回 []。"
|
||||
)
|
||||
try:
|
||||
from pipeline_service.llm_bridge import llm_call_msgs
|
||||
import json as _json
|
||||
import re as _re
|
||||
content = await llm_call_msgs(
|
||||
[{"role": "user", "content": prompt}],
|
||||
model=self.model_name,
|
||||
temperature=0,
|
||||
)
|
||||
m = _re.search(r"\[[^\]]*\]", content or "")
|
||||
if m:
|
||||
names = _json.loads(m.group(0))
|
||||
return [n for n in names if isinstance(n, str)]
|
||||
return []
|
||||
except Exception as e:
|
||||
logger.error(f"_llm_select_skills failed: {e}")
|
||||
return []
|
||||
|
||||
async def _build_system_prompt(self, user_input: str) -> str:
|
||||
"""组装完整 system prompt = 基础 prompt + 记忆 + 技能 + 工具列表"""
|
||||
prompt = self.config.system_prompt
|
||||
@ -385,15 +414,27 @@ class AgentExecutor:
|
||||
|
||||
# 注入技能(六级隔离:global→org→pipeline→role→project→user)
|
||||
if self.config.skills.enabled and self._skill_loader:
|
||||
skill_block = self._skill_loader.build_prompt_block(
|
||||
user_input=user_input,
|
||||
pipeline_id=self.pipeline_id if self.config.skills.enable_pipeline else "",
|
||||
role=self.role if self.config.skills.enable_role else "",
|
||||
project_id=self.project_id if self.config.skills.enable_project else "",
|
||||
org_id=self.org_id if self.config.skills.enable_org else "",
|
||||
user_id=self.user_id if self.config.skills.enable_user else "",
|
||||
max_skills=self.config.skills.max_skills_per_turn,
|
||||
)
|
||||
pipeline_id = self.pipeline_id if self.config.skills.enable_pipeline else ""
|
||||
role = self.role if self.config.skills.enable_role else ""
|
||||
project_id = self.project_id if self.config.skills.enable_project else ""
|
||||
org_id = self.org_id if self.config.skills.enable_org else ""
|
||||
user_id = self.user_id if self.config.skills.enable_user else ""
|
||||
# 技能检索必须 LLM 做(语义匹配,非关键词硬编码)
|
||||
catalog = self._skill_loader.get_skill_catalog(
|
||||
pipeline_id=pipeline_id, role=role, project_id=project_id,
|
||||
org_id=org_id, user_id=user_id)
|
||||
names = await self._llm_select_skills(
|
||||
user_input, catalog, self.config.skills.max_skills_per_turn)
|
||||
if names:
|
||||
skill_block = self._skill_loader.build_prompt_block_by_names(
|
||||
names, pipeline_id=pipeline_id, role=role, project_id=project_id,
|
||||
org_id=org_id, user_id=user_id)
|
||||
else:
|
||||
# LLM 无结果兜底:按 scope+名字列出前 N 个(不传 user_input,走 fallback 分支)
|
||||
skill_block = self._skill_loader.build_prompt_block(
|
||||
pipeline_id=pipeline_id, role=role, project_id=project_id,
|
||||
org_id=org_id, user_id=user_id,
|
||||
max_skills=self.config.skills.max_skills_per_turn)
|
||||
if skill_block:
|
||||
prompt += f"\n\n{skill_block}"
|
||||
|
||||
|
||||
@ -610,6 +610,12 @@ def register_sdlc_ability():
|
||||
system_prompt=SDL_PROMPT,
|
||||
handlers=SDL_HANDLERS,
|
||||
roles=SDL_ROLES,
|
||||
menus=[
|
||||
{"label": "📁 项目", "icon": "", "url": "/pipeline-sdlc/sd_projects/index.ui", "type": "popup"},
|
||||
{"label": "🐛 Bug", "icon": "", "url": "/pipeline-sdlc/sd_bugs/index.ui", "type": "popup"},
|
||||
{"label": "🧪 测试用例", "icon": "", "url": "/pipeline-sdlc/sd_test_cases/index.ui", "type": "popup"},
|
||||
{"label": "🔄 迭代", "icon": "", "url": "/pipeline-sdlc/sd_iterations/index.ui", "type": "popup"},
|
||||
],
|
||||
)
|
||||
register_ability(ability)
|
||||
return ability
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user