feat: 经验库每日 AI 巡检 + 管理面板——①experience_audit 表:逐条评审(具体可执行/无过时坐标/非对话续语/配方与序列一致 checklist),keep 直接归档、delete 标 pending 待人工,绝不自动删;人工 kept 后不再重复建议;②web_server 注册每日 03:47 巡检 job(Asia/Shanghai);③API:经验列表(含巡检建议)/确认删除/保留/手动触发巡检;④AI 控制台右上角「🧠 经验库」面板:经验卡片 + 建议徽章与理由 + 删除(confirm)/保留按钮
This commit is contained in:
@@ -296,3 +296,87 @@ function endRun(){
|
||||
_agentStream = null;
|
||||
scrollChat();
|
||||
}
|
||||
|
||||
// ================== 经验库(自进化记忆管理) ==================
|
||||
function openExpLib(){
|
||||
document.getElementById('agent-exp-overlay').style.display = 'flex';
|
||||
loadExpLib();
|
||||
}
|
||||
function closeExpLib(){
|
||||
document.getElementById('agent-exp-overlay').style.display = 'none';
|
||||
}
|
||||
function loadExpLib(){
|
||||
const list = document.getElementById('exp-lib-list');
|
||||
apiGet('/api/agent/experience').then(r=>{
|
||||
if(!r||!r.ok){ showToast((r&&r.error)||'加载失败','error'); return; }
|
||||
document.getElementById('exp-lib-last').textContent =
|
||||
(r.last ? ('最近巡检 ' + r.last + ':' + (r.last_summary||'')) : '');
|
||||
if(r.running){
|
||||
list.innerHTML = '<div class="text-muted" style="padding:20px;text-align:center">🔍 AI 巡检进行中(约 1 分钟),完成后请刷新…</div>';
|
||||
return;
|
||||
}
|
||||
const exps = r.experiences||[];
|
||||
if(!exps.length){
|
||||
list.innerHTML = '<div class="text-muted" style="padding:20px;text-align:center">暂无经验——跑一轮带手机操作的任务后会自动沉淀</div>';
|
||||
return;
|
||||
}
|
||||
list.innerHTML = '';
|
||||
exps.forEach(e=>{
|
||||
const a = e.audit||{};
|
||||
const card = document.createElement('div');
|
||||
card.style.cssText = 'border:1px solid var(--card-line);border-radius:10px;padding:9px 13px;background:#0d1117';
|
||||
// 徽章
|
||||
let badge = '';
|
||||
if(a.action === 'pending' && a.verdict === 'delete'){
|
||||
badge = '<span style="background:#7f1d1d;color:#fecaca;font-size:10.5px;padding:1px 8px;border-radius:9px;margin-left:8px">⚠ 建议删除</span>';
|
||||
}else if(a.action === 'kept'){
|
||||
badge = '<span style="background:#0f3d2e;color:#a7f3d0;font-size:10.5px;padding:1px 8px;border-radius:9px;margin-left:8px">' +
|
||||
(a.verdict === 'delete' ? '已人工保留' : '✓ 已保留') + '</span>';
|
||||
}
|
||||
let actBtns = '';
|
||||
if(a.action === 'pending'){
|
||||
actBtns = '<button class="btn btn-xs btn-danger" onclick="expDelete(' + e.id + ')">确认删除</button>'
|
||||
+ '<button class="btn btn-xs" onclick="expKeep(' + e.id + ')">保留</button>';
|
||||
}else{
|
||||
actBtns = '<button class="btn btn-xs" style="border-color:#7f1d1d;color:#f87171" onclick="expDelete(' + e.id + ')" title="强制删除此经验">删除</button>';
|
||||
}
|
||||
card.innerHTML =
|
||||
'<div style="display:flex;align-items:center;gap:6px;font-size:12px">'
|
||||
+ '<span class="text-muted" style="font-family:var(--mono)">#' + e.id + '</span>'
|
||||
+ '<span class="text-muted">' + esc(e.created_at||'') + '</span>'
|
||||
+ '<span class="text-muted">引用 ' + (e.hits||0) + ' 次</span>' + badge
|
||||
+ '<span style="flex:1"></span>' + actBtns + '</div>'
|
||||
+ '<div style="font-size:13px;color:#e5e7eb;margin:5px 0 3px">' + esc(e.task_prompt) + '</div>'
|
||||
+ '<div class="text-muted" style="font-size:11.5px;line-height:1.6;white-space:pre-wrap">' + esc((e.recipe||'').slice(0,220)) + '</div>'
|
||||
+ (a.action === 'pending' && a.reason
|
||||
? '<div style="font-size:11.5px;color:#fbbf24;margin-top:5px">AI 建议理由:' + esc(a.reason)
|
||||
+ (a.score ? '(评分 ' + a.score + '/10)' : '') + '</div>'
|
||||
: '');
|
||||
list.appendChild(card);
|
||||
});
|
||||
});
|
||||
}
|
||||
function triggerExpAudit(){
|
||||
apiPost('/api/agent/experience/audit',{}).then(r=>{
|
||||
if(r&&r.ok){
|
||||
showToast('巡检已启动,约 1 分钟完成','success');
|
||||
document.getElementById('exp-lib-list').innerHTML =
|
||||
'<div class="text-muted" style="padding:20px;text-align:center">🔍 AI 巡检进行中…</div>';
|
||||
// 完成后自动刷新
|
||||
setTimeout(()=>{ if(document.getElementById('agent-exp-overlay').style.display==='flex') loadExpLib(); }, 90000);
|
||||
}else showToast((r&&r.error)||'巡检启动失败','error');
|
||||
});
|
||||
}
|
||||
function expDelete(id){
|
||||
if(!confirm('确认删除该经验?删除后不可恢复(下次相似任务不再自动参考)。')) return;
|
||||
apiPost('/api/agent/experience/delete',{id:id}).then(r=>{
|
||||
if(r&&r.ok){ showToast('已删除','success'); loadExpLib(); }
|
||||
else showToast((r&&r.error)||'删除失败','error');
|
||||
});
|
||||
}
|
||||
function expKeep(id){
|
||||
apiPost('/api/agent/experience/keep',{id:id}).then(r=>{
|
||||
if(r&&r.ok){ showToast('已保留,后续不再重复建议','success'); loadExpLib(); }
|
||||
else showToast((r&&r.error)||'操作失败','error');
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user