feat: LLM classification for project name matching — _call_llm_raw with temp=0
This commit is contained in:
parent
98d4f5e8ad
commit
9b4f7dd4ae
@ -115,6 +115,20 @@ async def _sel_model(sor, pref):
|
||||
recs = await sor.sqlExe("SELECT id,name,provider,model_id,api_base,api_key FROM llm WHERE status='active' LIMIT 1",{})
|
||||
return recs[0] if recs else None
|
||||
|
||||
async def _call_llm_raw(prompt, temp=0.0):
|
||||
"""Lightweight LLM call for classification tasks. Uses first available model."""
|
||||
to = aiohttp.ClientTimeout(total=30)
|
||||
async with DBPools().sqlorContext(dbname) as sor:
|
||||
model = await _sel_model(sor, None)
|
||||
if not model:
|
||||
return "不存在"
|
||||
hdrs = {"Authorization": f"Bearer {model.api_key or ''}", "Content-Type": "application/json"}
|
||||
payload = {"model": model.model_id, "messages": [{"role":"user","content":prompt}], "temperature": temp}
|
||||
async with aiohttp.ClientSession(timeout=to) as s:
|
||||
async with s.post(f"{model.api_base.rstrip('/')}/chat/completions", headers=hdrs, json=payload) as r:
|
||||
if r.status != 200: raise ValueError(f"LLM {r.status}")
|
||||
return (await r.json())["choices"][0]["message"]["content"]
|
||||
|
||||
async def _call_llm(model, msgs, temp):
|
||||
hdrs = {"Authorization": f"Bearer {model.api_key or ''}", "Content-Type": "application/json"}
|
||||
payload = {"model": model.model_id, "messages": msgs, "temperature": temp}
|
||||
@ -206,8 +220,21 @@ async def _exec_tool(sor, tool, params, ctx, uid, org_id):
|
||||
return '可用项目:\n'+'\n'.join(lines)
|
||||
proj = await _find_project(sor, name)
|
||||
if not proj:
|
||||
allp = await sor.sqlExe("SELECT name FROM sd_projects ORDER BY created_at DESC LIMIT 15",{})
|
||||
return 'FAIL: 未找到。可用: '+', '.join([getattr(r,'name','') for r in (allp or [])])
|
||||
# LLM classification: ask LLM to match user input against project list
|
||||
allp = await sor.sqlExe("SELECT id,name FROM sd_projects ORDER BY created_at DESC LIMIT 20",{})
|
||||
pnames = [getattr(r,'name','') for r in (allp or [])]
|
||||
classify_prompt = f"用户输入: {name}\n项目列表: {', '.join(pnames)}\n\n判断用户想要哪个项目。只回复项目名或\"不存在\"。"
|
||||
try:
|
||||
raw = await _call_llm_raw(classify_prompt, 0.0)
|
||||
matched = raw.strip().strip('"').strip("'")
|
||||
for r in (allp or []):
|
||||
if getattr(r,'name','') == matched:
|
||||
proj = r; break
|
||||
except:
|
||||
pass
|
||||
if not proj:
|
||||
allp2 = await sor.sqlExe("SELECT name FROM sd_projects ORDER BY created_at DESC LIMIT 15",{})
|
||||
return 'FAIL: 未找到。可用: '+', '.join([getattr(r,'name','') for r in (allp2 or [])])
|
||||
if proj.id == ctx['pid']:
|
||||
return f'已在「{proj.name}」项目中,无需切换'
|
||||
await _save_ctx(sor, uid, proj.id)
|
||||
@ -445,10 +472,7 @@ if action == 'send_message':
|
||||
return
|
||||
|
||||
repos_str = ', '.join([r['n'] for r in ctx['repos']]) or '无'
|
||||
# Load all project names so LLM can match user's input
|
||||
all_projects = await sor.sqlExe("SELECT name FROM sd_projects ORDER BY created_at DESC LIMIT 20",{})
|
||||
proj_list = ', '.join([getattr(p,'name','') for p in (all_projects or [])])
|
||||
env_text = f"【当前项目: {ctx['pname'] or '未选择'}】\n所有项目: {proj_list}\n工作空间: {ctx['ws'] or '未设置'} | 仓库: {repos_str}"
|
||||
env_text = f"【当前项目: {ctx['pname'] or '未选择'}】— 所有操作在当前项目内完成\n工作空间: {ctx['ws'] or '未设置'} | 仓库: {repos_str}"
|
||||
system = AGENT_PROMPT.replace('__TOOLS__',TOOLS_TEXT).replace('__ENV__',env_text)
|
||||
msgs = [{"role":"system","content":system}]
|
||||
for h in (await sor.sqlExe("SELECT role,content FROM pipeline_conversations WHERE created_by=${u}$ ORDER BY created_at ASC LIMIT 20",{"u":uid}) or []):
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user