v2.0: 新增recordExperience/getExperienceContext经验累积系统
This commit is contained in:
parent
fc80c22fdd
commit
3224386d67
@ -1,83 +1,110 @@
|
||||
// ═══════════════════════════════════════
|
||||
// 铸渊工程Agent · HLDP大脑记录器
|
||||
// 记录认知推理链,而非流水账
|
||||
// ═══════════════════════════════════════
|
||||
// HLDP-ZY://agents/zhuyuan-dev-agent/modules/brain-writer.js
|
||||
// @guardian: ICE-GL-ZY001 · 铸渊
|
||||
// @sovereign: TCS-0002∞ · 冰朔
|
||||
// @copyright: 国作登字-2026-A-00037559
|
||||
// 铸渊工程Agent · HLDP大脑记录器 v2.0
|
||||
// v2.0: 新增 recordExperience · recordLesson · getExperienceContext
|
||||
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
const AGENT_ID = process.env.AGENT_ID || "ICE-GL-BD001";
|
||||
const TERRITORY = path.join(__dirname, "..", "agents", AGENT_ID.replace("ICE-GL-BD", "BD"));
|
||||
const EXPERIENCE_DIR = path.join(TERRITORY, "experience");
|
||||
|
||||
if (!fs.existsSync(TERRITORY)) {
|
||||
console.warn("[BrainWriter] 领地不存在: " + TERRITORY + " · 将不写入认知记录");
|
||||
}
|
||||
function ensureExpDir() { if (!fs.existsSync(EXPERIENCE_DIR)) { try { fs.mkdirSync(EXPERIENCE_DIR, { recursive: true }); } catch(e) {} } }
|
||||
|
||||
/**
|
||||
* 写入一条认知记录
|
||||
*/
|
||||
function record(taskId, entry) {
|
||||
if (!fs.existsSync(TERRITORY)) return;
|
||||
|
||||
const file = path.join(TERRITORY, "brain", "cognitive-record.hldp");
|
||||
const lines = [
|
||||
"",
|
||||
"@task: " + taskId,
|
||||
"@time: " + new Date().toISOString(),
|
||||
"@input: " + (entry.input || ""),
|
||||
"@decision: " + (entry.decision || ""),
|
||||
"@execution: " + (entry.execution || ""),
|
||||
"@failure: " + (entry.failure || "无"),
|
||||
"@reasoning: " + (entry.reasoning || ""),
|
||||
"@fix: " + (entry.fix || ""),
|
||||
"@learned: " + (entry.learned || ""),
|
||||
"@confidence: " + (entry.confidence || "N/A"),
|
||||
"@new_knowledge: " + (entry.new_knowledge ? "true" : "false")
|
||||
];
|
||||
|
||||
const lines = ["","@task: " + taskId,"@time: " + new Date().toISOString(),"@input: " + (entry.input || ""),"@decision: " + (entry.decision || ""),"@execution: " + (entry.execution || ""),"@failure: " + (entry.failure || "无"),"@reasoning: " + (entry.reasoning || ""),"@fix: " + (entry.fix || ""),"@learned: " + (entry.learned || ""),"@confidence: " + (entry.confidence || "N/A"),"@new_knowledge: " + (entry.new_knowledge ? "true" : "false")];
|
||||
fs.appendFileSync(file, lines.join("\n") + "\n", "utf-8");
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录错误模式
|
||||
*/
|
||||
function recordExperience(planId, summary) {
|
||||
ensureExpDir();
|
||||
if (!fs.existsSync(TERRITORY)) return;
|
||||
const entry = { plan_id: planId, timestamp: new Date().toISOString(), summary: { total: summary.total || 0, done: summary.done || 0, failed: summary.failed || 0, skipped: summary.skipped || 0 }, lessons: [], errors: [] };
|
||||
if (summary.results) {
|
||||
for (const r of summary.results) {
|
||||
if (r.ok) {
|
||||
entry.lessons.push({ type: "success", action: r.action, target: r._task_target || "", detail: r._substep_detail || "" });
|
||||
} else if (r.skipped) {
|
||||
const errMsg = (r.error || "").slice(0, 200);
|
||||
let rootCause = "未知";
|
||||
if (errMsg.includes("illegal operation on a directory")) rootCause = "路径指向目录而非文件";
|
||||
else if (errMsg.includes("not found")) rootCause = "Shell命令不存在";
|
||||
else if (errMsg.includes("待指定") || errMsg.includes("未指定")) rootCause = "LLM扩展返回了模糊占位符";
|
||||
else if (errMsg.includes("无效")) rootCause = "参数验证失败";
|
||||
entry.errors.push({ action: r.action, target: r._task_target || "", error: errMsg, root_cause: rootCause });
|
||||
entry.lessons.push({ type: "failure", action: r.action, target: r._task_target || "", error: errMsg, root_cause: rootCause, learned: "下次执行时需要确保" + rootCause });
|
||||
}
|
||||
}
|
||||
}
|
||||
const expFile = path.join(EXPERIENCE_DIR, planId + "-" + Date.now() + ".json");
|
||||
fs.writeFileSync(expFile, JSON.stringify(entry, null, 2), "utf-8");
|
||||
updateExperienceIndex(planId, entry);
|
||||
console.log("[BrainWriter v2] 经验已记录: " + planId + " · " + entry.lessons.length + " 条经验");
|
||||
return entry;
|
||||
}
|
||||
|
||||
function updateExperienceIndex(planId, entry) {
|
||||
const indexFile = path.join(EXPERIENCE_DIR, "index.json");
|
||||
let index = { total: 0, plans: [], top_errors: [] };
|
||||
if (fs.existsSync(indexFile)) { try { index = JSON.parse(fs.readFileSync(indexFile, "utf-8")); } catch(e) {} }
|
||||
index.total++;
|
||||
index.plans.push({ plan_id: planId, timestamp: entry.timestamp, summary: entry.summary });
|
||||
for (const lesson of entry.lessons) {
|
||||
if (lesson.type === "failure") {
|
||||
const existing = index.top_errors.find(e => e.root_cause === lesson.root_cause);
|
||||
if (existing) existing.count++;
|
||||
else index.top_errors.push({ root_cause: lesson.root_cause, count: 1, example: (lesson.error||"").slice(0, 100) });
|
||||
}
|
||||
}
|
||||
index.top_errors.sort((a, b) => b.count - a.count);
|
||||
index.top_errors = index.top_errors.slice(0, 10);
|
||||
index.plans = index.plans.slice(-20);
|
||||
fs.writeFileSync(indexFile, JSON.stringify(index, null, 2), "utf-8");
|
||||
}
|
||||
|
||||
function getExperienceContext() {
|
||||
const indexFile = path.join(EXPERIENCE_DIR, "index.json");
|
||||
if (!fs.existsSync(indexFile)) return "";
|
||||
try {
|
||||
const index = JSON.parse(fs.readFileSync(indexFile, "utf-8"));
|
||||
const lines = ["","【BD001历史执行经验】"," 总执行次数: " + index.total];
|
||||
if (index.plans.length > 0) lines.push(" 最近: " + index.plans.slice(-3).map(p => p.plan_id + "(" + p.summary.done + "/" + p.summary.total + ")").join(", "));
|
||||
if (index.top_errors.length > 0) {
|
||||
lines.push(" 常见错误:");
|
||||
for (const e of index.top_errors.slice(0, 5)) lines.push(" - " + e.root_cause + " (" + e.count + "次)");
|
||||
}
|
||||
return lines.join("\n");
|
||||
} catch(e) { return ""; }
|
||||
}
|
||||
|
||||
function recordErrorPattern(pattern) {
|
||||
if (!fs.existsSync(TERRITORY)) return;
|
||||
const file = path.join(TERRITORY, "memory", "error-patterns.json");
|
||||
const data = JSON.parse(fs.readFileSync(file, "utf-8"));
|
||||
|
||||
// 检查是否已有同类模式
|
||||
const existing = data.patterns.find(p => p.type === pattern.type);
|
||||
if (existing) {
|
||||
existing.count = (existing.count || 1) + 1;
|
||||
existing.last_seen = new Date().toISOString();
|
||||
} else {
|
||||
data.patterns.push({
|
||||
type: pattern.type,
|
||||
description: pattern.description,
|
||||
count: 1,
|
||||
first_seen: new Date().toISOString(),
|
||||
last_seen: new Date().toISOString(),
|
||||
examples: [pattern.example]
|
||||
});
|
||||
}
|
||||
|
||||
if (existing) { existing.count++; existing.last_seen = new Date().toISOString(); }
|
||||
else { data.patterns.push({ type: pattern.type, description: pattern.description, count: 1, first_seen: new Date().toISOString(), last_seen: new Date().toISOString(), examples: [pattern.example] }); }
|
||||
fs.writeFileSync(file, JSON.stringify(data, null, 2), "utf-8");
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录成长里程碑
|
||||
*/
|
||||
function recordMilestone(event) {
|
||||
if (!fs.existsSync(TERRITORY)) return;
|
||||
const file = path.join(TERRITORY, "brain", "growth-timeline.json");
|
||||
const data = JSON.parse(fs.readFileSync(file, "utf-8"));
|
||||
data.milestones.push({
|
||||
time: new Date().toISOString(),
|
||||
event: event,
|
||||
project: process.env.CURRENT_PROJECT_ID || "unknown"
|
||||
});
|
||||
data.milestones.push({ time: new Date().toISOString(), event: event, project: process.env.CURRENT_PROJECT_ID || "unknown" });
|
||||
fs.writeFileSync(file, JSON.stringify(data, null, 2), "utf-8");
|
||||
}
|
||||
|
||||
module.exports = { record, recordErrorPattern, recordMilestone, TERRITORY, AGENT_ID };
|
||||
function recordLesson(type, detail) {
|
||||
ensureExpDir();
|
||||
if (!fs.existsSync(TERRITORY)) return;
|
||||
const lessonFile = path.join(EXPERIENCE_DIR, "raw-lessons.jsonl");
|
||||
fs.appendFileSync(lessonFile, JSON.stringify({ time: new Date().toISOString(), type, detail }) + "\n", "utf-8");
|
||||
}
|
||||
|
||||
module.exports = { record, recordErrorPattern, recordMilestone, recordExperience, recordLesson, getExperienceContext, TERRITORY, AGENT_ID };
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user