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",{})
|
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
|
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):
|
async def _call_llm(model, msgs, temp):
|
||||||
hdrs = {"Authorization": f"Bearer {model.api_key or ''}", "Content-Type": "application/json"}
|
hdrs = {"Authorization": f"Bearer {model.api_key or ''}", "Content-Type": "application/json"}
|
||||||
payload = {"model": model.model_id, "messages": msgs, "temperature": temp}
|
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)
|
return '可用项目:\n'+'\n'.join(lines)
|
||||||
proj = await _find_project(sor, name)
|
proj = await _find_project(sor, name)
|
||||||
if not proj:
|
if not proj:
|
||||||
allp = await sor.sqlExe("SELECT name FROM sd_projects ORDER BY created_at DESC LIMIT 15",{})
|
# LLM classification: ask LLM to match user input against project list
|
||||||
return 'FAIL: 未找到。可用: '+', '.join([getattr(r,'name','') for r in (allp or [])])
|
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']:
|
if proj.id == ctx['pid']:
|
||||||
return f'已在「{proj.name}」项目中,无需切换'
|
return f'已在「{proj.name}」项目中,无需切换'
|
||||||
await _save_ctx(sor, uid, proj.id)
|
await _save_ctx(sor, uid, proj.id)
|
||||||
@ -445,10 +472,7 @@ if action == 'send_message':
|
|||||||
return
|
return
|
||||||
|
|
||||||
repos_str = ', '.join([r['n'] for r in ctx['repos']]) or '无'
|
repos_str = ', '.join([r['n'] for r in ctx['repos']]) or '无'
|
||||||
# Load all project names so LLM can match user's input
|
env_text = f"【当前项目: {ctx['pname'] or '未选择'}】— 所有操作在当前项目内完成\n工作空间: {ctx['ws'] or '未设置'} | 仓库: {repos_str}"
|
||||||
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}"
|
|
||||||
system = AGENT_PROMPT.replace('__TOOLS__',TOOLS_TEXT).replace('__ENV__',env_text)
|
system = AGENT_PROMPT.replace('__TOOLS__',TOOLS_TEXT).replace('__ENV__',env_text)
|
||||||
msgs = [{"role":"system","content":system}]
|
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 []):
|
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