🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

智能体反馈循环 super3ben/agent-feedback-loop

DeepSeek Harnessv0.9.0
super3ben4 天前有提交已提供中文文档扫描:含敏感能力

面向 Codex、Claude Code 和 Gemini CLI 的本地提示词时反馈学习。中文说明

31.1/100
综合分
2
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/11/3 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

自动兼容检查未通过:engines.node 要求 >=24.15.0,不满足 Node 22.19.0。以下命令仍可尝试,但可能失败。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add super3ben/agent-feedback-loop
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么
dsh 原生插件 · other
装得上吗
本站已在 dsh 0.2.1-rc.5 下真实安装成功
非静态推断
L5 · 运行时冒烟等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 4 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查需源码安装

engines.node 要求 >=24.15.0,不满足 Node 22.19.0

展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✓npm 包agent-feedback-loop @ 0.9.0
✗Node 引擎要求 >=24.15.0 · 基线 Node 22.19 不满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

源码安装时若 pnpm 拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑。

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/12 04:18:34

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件发起外部网络请求
查看扫描证据(共 169 处,展示前 122 条)
  • 读取本地文件
    src/cli.mjs:337
    text = await readFile(file, "utf8");
  • 删除本地文件递归
    src/cli.mjs:985
    await rm(tempHome, { recursive: true, force: true });
  • 写入本地文件
    src/index.mjs:188
    return mkdir(path.dirname(target), { recursive: true, mode: 0o700 })
  • 写入本地文件
    src/index.mjs:189
    .then(() => writeFile(target, launcher, { mode: 0o700 }))
  • 写入本地文件
    src/index.mjs:190
    .then(() => chmod(target, 0o700));
  • 读取本地文件
    src/index.mjs:195
    await access(file);
  • 读取本地文件
    src/index.mjs:212
    info = await lstat(current);
  • 写入本地文件
    src/index.mjs:216
    await mkdir(current, { mode: 0o700 });
  • 读取本地文件
    src/index.mjs:217
    info = await lstat(current);
  • 写入本地文件
    src/index.mjs:225
    if (create) await chmod(directory, 0o700);
  • 写入本地文件
    src/index.mjs:252
    if (!dryRun) await copyFile(file, target);
  • 执行外部命令固定命令
    src/index.mjs:320
    execFile("launchctl", ["bootout", `${domain}/${label}`], {
  • 读取本地文件
    src/index.mjs:349
    const parent = await lstat(path.dirname(plistFile));
  • 读取本地文件
    src/index.mjs:350
    const file = await lstat(plistFile);
  • 删除本地文件
    src/index.mjs:353
    await rm(plistFile, { force: true });
  • 读取本地文件
    src/index.mjs:406
    const text = await readFile(file, "utf8");
  • 删除本地文件
    src/index.mjs:415
    if (!dryRun) await rm(file, { force: true });
  • 删除本地文件递归
    src/index.mjs:423
    if (!dryRun) await rm(entry, { recursive: true, force: true });
  • 删除本地文件
    src/index.mjs:512
    await rm(linkPath, { force: true });
  • 删除本地文件递归
    src/index.mjs:698
    await rm(paths.packRoot, { recursive: true, force: true });
  • 删除本地文件递归
    src/index.mjs:699
    await rm(paths.runtimeRoot, { recursive: true, force: true });
  • 写入本地文件
    src/control-store.mjs:145
    mkdirSync(directory, { recursive: true, mode: 0o700 });
  • 读取本地文件
    src/control-store.mjs:146
    const info = lstatSync(directory);
  • 写入本地文件
    src/control-store.mjs:149
    chmodSync(directory, 0o700);
  • 读取本地文件
    src/control-store.mjs:155
    info = lstatSync(directory);
  • 读取本地文件
    src/control-store.mjs:167
    info = lstatSync(file);
  • 读取本地文件
    src/control-store.mjs:181
    const rootInfo = lstatSync(root);
  • 读取本地文件
    src/control-store.mjs:189
    info = lstatSync(current);
  • 读取本地文件
    src/control-store.mjs:306
    const current = lstatSync(member.source, { bigint: true });
  • 写入本地文件
    src/control-store.mjs:382
    chmodSync(snapshotRoot, 0o700);
  • 删除本地文件递归
    src/control-store.mjs:411
    rmSync(snapshotRoot, { recursive: true, force: true });
  • 写入本地文件
    src/control-store.mjs:2640
    chmodSync(paths.controlDatabase, 0o600);
  • 删除本地文件递归
    src/control-store.mjs:2700
    rmSync(snapshot.snapshotRoot, { recursive: true, force: true });
  • 删除本地文件递归
    src/control-store.mjs:2710
    rmSync(snapshot.snapshotRoot, { recursive: true, force: true });
  • 写入本地文件
    src/crypto-store.mjs:37
    await mkdir(directory, { recursive: true, mode: 0o700 });
  • 读取本地文件
    src/crypto-store.mjs:38
    const info = await lstat(directory);
  • 写入本地文件
    src/crypto-store.mjs:42
    await chmod(directory, 0o700);
  • 读取本地文件
    src/crypto-store.mjs:46
    const info = await lstat(file);
  • 写入本地文件
    src/crypto-store.mjs:50
    await chmod(file, 0o600);
  • 读取本地文件
    src/crypto-store.mjs:51
    return readFile(file);
  • 写入本地文件
    src/crypto-store.mjs:69
    await writeFile(this.keyFile, key, { mode: 0o600, flag: "wx" }).catch(async (writeError) => {
  • 读取本地文件
    src/crypto-store.mjs:91
    const existing = await lstat(file);
  • 写入本地文件
    src/crypto-store.mjs:94
    await chmod(file, 0o600);
  • 写入本地文件
    src/crypto-store.mjs:102
    await writeFile(temporary, envelope, { mode: 0o600, flag: "wx" });
  • 读取本地文件
    src/crypto-store.mjs:107
    const existing = await lstat(file);
  • 删除本地文件
    src/crypto-store.mjs:111
    await rm(temporary, { force: true });
  • 删除本地文件
    src/crypto-store.mjs:129
    await rm(path.join(this.root, `${contentHash}.enc`), { force: true });
  • 读取本地文件
    src/crypto-store.mjs:136
    for (const name of await readdir(this.root)) {
  • 删除本地文件
    src/crypto-store.mjs:142
    await rm(file, { force: true });
  • 读取本地文件
    src/feedback-signal.mjs:227
    const info = await lstat(file);
  • 读取本地文件
    src/status-report.mjs:86
    names = await readdir(reflectionsDir);
  • 读取本地文件
    src/status-report.mjs:94
    const info = await stat(path.join(reflectionsDir, name));
  • 读取本地文件
    src/status-report.mjs:118
    const text = await readFile(path.join(reflectionsDir, fileName), "utf8");
  • 读取本地文件
    src/language.mjs:37
    names = (await readdir(reflectionsDir)).filter((name) => name.endsWith(".md"));
  • 读取本地文件
    src/language.mjs:46
    const text = await readFile(path.join(reflectionsDir, name), "utf8");
  • 读取本地文件
    src/reviewer-runner.mjs:153
    let info = await lstat(current);
  • 读取本地文件
    src/reviewer-runner.mjs:156
    info = await lstat(current);
  • 读取本地文件
    src/reviewer-provider.mjs:67
    await access(candidate, constants.X_OK);
  • 读取本地文件
    src/reviewer-provider.mjs:130
    await Promise.all([access(promptFile, constants.R_OK), access(schemaFile, constants.R_OK)]);
  • 读取本地文件
    src/reviewer-provider.mjs:313
    text = await readFile(configFile, "utf8");
  • 执行外部命令来自配置/变量
    src/reviewer-provider.mjs:419
    child = spawn(command, args, {
  • 写入本地文件
    src/reviewer-provider.mjs:489
    await writeFile(resultFile, JSON.stringify(result), { mode: 0o600, flag: "w" });
  • 写入本地文件
    src/reviewer-provider.mjs:490
    await chmod(resultFile, 0o600);
  • 写入本地文件
    src/reviewer-provider.mjs:547
    await mkdir(workDir, { mode: 0o700 });
  • 写入本地文件
    src/reviewer-provider.mjs:548
    await chmod(privateRoot, 0o700);
  • 写入本地文件
    src/reviewer-provider.mjs:549
    await chmod(workDir, 0o700);
  • 写入本地文件
    src/reviewer-provider.mjs:550
    await writeFile(resultFile, "", { mode: 0o600, flag: "wx" });
  • 删除本地文件递归
    src/reviewer-provider.mjs:591
    await rm(privateRoot, { recursive: true, force: true });
  • 写入本地文件
    src/convergence-probe-context.mjs:527
    if (create) await mkdir(root, { recursive: true, mode: 0o700 });
  • 读取本地文件
    src/convergence-probe-context.mjs:528
    const info = await lstat(root, { bigint: true });
  • 读取本地文件
    src/convergence-probe-context.mjs:545
    const info = await lstat(file, { bigint: true });
  • 删除本地文件
    src/convergence-probe-context.mjs:658
    await rm(temporary, { force: true }).catch(() => {});
  • 写入本地文件
    src/convergence-probe-context.mjs:695
    await rename(file, quarantine);
  • 删除本地文件
    src/convergence-probe-context.mjs:699
    await rm(quarantine);
  • 读取本地文件
    src/convergence-probe-context.mjs:713
    names = (await readdir(this.root)).sort().slice(0, MAX_ORPHAN_INSPECTIONS);
  • 读取本地文件
    src/convergence-identity.mjs:170
    const initial = await lstat(input);
  • 读取本地文件
    src/convergence-identity.mjs:174
    const resolved = await realpath(input);
  • 读取本地文件
    src/convergence-identity.mjs:175
    const resolvedInfo = await lstat(resolved);
  • 读取本地文件
    src/convergence-identity.mjs:184
    const info = await lstat(file);
  • 读取本地文件
    src/convergence-identity.mjs:188
    return readFile(file, "utf8");
  • 写入本地文件
    src/convergence-identity.mjs:246
    await writeFile(lineageFile, `${lineageId}\n`, { flag: "wx", mode: 0o600 });
  • 读取本地文件
    src/design-permit.mjs:85
    const data = await readFile(filePath, "utf8");
  • 读取本地文件
    src/reflection-archive.mjs:40
    entries = await readdir(reflectionsDir, { withFileTypes: true });
  • 读取本地文件
    src/reflection-archive.mjs:55
    info = await stat(filePath);
  • 写入本地文件
    src/reflection-archive.mjs:80
    await mkdir(archiveDir, { recursive: true, mode: 0o700 });
  • 写入本地文件
    src/reflection-archive.mjs:89
    await rename(candidate.path, target);
  • 读取本地文件
    src/codex-host.mjs:31
    await access(file, constants.X_OK);
  • 执行外部命令来自配置/变量
    src/codex-host.mjs:52
    const child = spawn(command, ["app-server"], {
  • 发起网络请求
    src/codex-host.mjs:167
    await session.request("initialize", {
  • 发起网络请求
    src/codex-host.mjs:295
    const listing = await session.request("hooks/list", { cwds: [input.cwd] });
  • 发起网络请求
    src/codex-host.mjs:311
    const beforeListing = await session.request("hooks/list", { cwds: [input.cwd] });
  • 发起网络请求
    src/codex-host.mjs:320
    await session.request("config/batchWrite", {
  • 发起网络请求
    src/codex-host.mjs:325
    const afterListing = await session.request("hooks/list", { cwds: [input.cwd] });
  • 读取本地文件
    src/rules-writer.mjs:318
    try { existing = await readFile(filePath, "utf8"); } catch {}
  • 写入本地文件
    src/rules-writer.mjs:329
    await mkdir(dir, { recursive: true });
  • 写入本地文件
    src/rules-writer.mjs:330
    await writeFile(filePath, content, "utf8");
  • 读取本地文件
    src/rules-writer.mjs:343
    try { info = await stat(filePath); } catch { return false; }
  • 读取本地文件
    src/rules-writer.mjs:345
    const existing = await readFile(filePath, "utf8");
  • 读取本地文件
    src/update-rules-tier.mjs:54
    document = parseReflectionMarkdown(await readFile(job.published_path, "utf8"), {
  • 读取本地文件
    src/reviewer-result-file.mjs:30
    current = await lstat(filePath);
  • 删除本地文件
    src/reviewer-result-file.mjs:38
    await unlink(filePath);
  • 读取本地文件
    src/convergence-migration.mjs:106
    const info = await lstat(input).catch(() => { throw coded("repo_root_invalid"); });
  • 读取本地文件
    src/convergence-migration.mjs:109
    return realpath(input);
  • 读取本地文件
    src/convergence-migration.mjs:121
    const info = await lstat(current).catch(() => { throw coded("legacy_state_missing"); });
  • 读取本地文件
    src/convergence-migration.mjs:157
    const current = await lstat(target).catch(() => { throw coded(`${mode}_replaced`); });
  • 读取本地文件
    src/convergence-migration.mjs:269
    const info = await lstat(lock);
  • 读取本地文件
    src/convergence-migration.mjs:340
    await lstat(paths?.controlDatabase);
  • 写入本地文件
    src/convergence-migration.mjs:773
    try { await mkdir(target, { mode: 0o700 }); } catch (error) {
  • 写入本地文件
    src/convergence-migration.mjs:778
    await writeFile(owner, `${JSON.stringify({ pid: process.pid, acquired_at: new Date().toISOString() })}\n`, {
  • 删除本地文件
    src/convergence-migration.mjs:782
    await unlink(owner).catch(() => {});
  • 删除本地文件
    src/convergence-migration.mjs:783
    await rmdir(target).catch(() => {});
  • 写入本地文件
    src/convergence-migration.mjs:911
    await rename(temporary, stateTarget);
  • 写入本地文件
    src/convergence-migration.mjs:913
    await chmod(stateTarget, 0o600);
  • 删除本地文件
    src/convergence-migration.mjs:918
    if (!renamed) await unlink(temporary).catch(() => {});
  • 读取本地文件
    src/convergence-sdd-adapter.mjs:603
    const rootInfo = await lstat(rootInput);
  • 读取本地文件
    src/convergence-sdd-adapter.mjs:606
    const root = await realpath(rootInput);
  • 读取本地文件
    src/convergence-sdd-adapter.mjs:626
    const info = await lstat(current);
  • 读取本地文件
    src/convergence-sdd-adapter.mjs:644
    const existing = await lstat(location.target);
  • 读取本地文件
    src/convergence-sdd-adapter.mjs:675
    info = await lstat(opened.target);
  • 读取本地文件
    src/convergence-sdd-adapter.mjs:699
    await lstat(target);
  • 删除本地文件
    src/convergence-sdd-adapter.mjs:720
    await unlink(temporary).catch(() => {});
  • 执行外部命令来自配置/变量
    templates/dsh-plugin/index.js:31
    child = spawn(command, args, { cwd, stdio: ["pipe", "pipe", "pipe"], ...(signal ? { signal } : {}) });
扫描于 2026/11/4(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 捕获用户不满
  • 沉淀经验文档

README

由 DeepSeek 最新模型翻译生成
智能体反馈回路 面向 Codex、Claude Code 和 Gemini CLI 的本地提示词时反馈学习。中文说明 运行时版本:0.9.0 反馈学习 1. 提示词钩子捕获符合条件的用户不满,立即返回宿主。 2. 独立的反馈审查器稍后可以检查有界的本地证据。 3. 审查器给出有效结果后,写入 .agent/reflections/ 下的项目 Markdown,不可更改。 4. 后续匹配的提示词读取一小组适用的 Markdown 文档。 当前提示词从不等待反馈审查器。发布截止时间固定在提示词处理时刻,因此处理期间发布的文档只能影响后续匹配的提示词。控制用 SQLite 数据库保存生命周期状态,不保存经验正文。这是直接选取 Markdown,不是 RAG。 自然语言不满覆盖 识别不满不再依赖固定的负面关键词,比如「做错了」或「不合理」。词表与判断之间的空白由三层覆盖: 1. 扩展词表路由。 自然语言抱怨——被要求复述已知信息、对反复出现的问题感到沮丧、反问式追责(「怎么又不知道?」)——直接进入独立完整审查器。 2. LLM 兜底分类器。 词表漏掉、但带有助手指代的消息,交给独立的二分类器(classify-feedback)。它先给理由,再输出 {"dissatisfied": true/false}。是,就把任务交给审查器;否,就丢弃。
展开完整文档(README 剩余 1 节)
智能体反馈回路

面向 Codex、Claude Code 和 Gemini CLI 的本地提示词时反馈学习。中文说明

运行时版本:0.9.0

反馈学习

1. 提示词钩子捕获符合条件的用户不满,立即返回宿主。
2. 独立的反馈审查器稍后可以检查有界的本地证据。
3. 审查器给出有效结果后,写入 .agent/reflections/ 下的项目 Markdown,不可更改。
4. 后续匹配的提示词读取一小组适用的 Markdown 文档。

当前提示词从不等待反馈审查器。发布截止时间固定在提示词处理时刻,因此处理期间发布的文档只能影响后续匹配的提示词。控制用 SQLite 数据库保存生命周期状态,不保存经验正文。这是直接选取 Markdown,不是 RAG。

自然语言不满覆盖

识别不满不再依赖固定的负面关键词,比如「做错了」或「不合理」。词表与判断之间的空白由三层覆盖:

1. 扩展词表路由。 自然语言抱怨——被要求复述已知信息、对反复出现的问题感到沮丧、反问式追责(「怎么又不知道?」)——直接进入独立完整审查器。
2. LLM 兜底分类器。 词表漏掉、但带有助手指代的消息,交给独立的二分类器(classify-feedback)。它先给理由,再输出 {"dissatisfied": true/false}。是,就把任务交给审查器;否,就丢弃。分类器会被告知:智能体自己的借口不能算作用户满意的证据——推脱(「连不通」)不能左右判定。纯操作轮次(「继续」「好的」「等等」)完全跳过调用。分类器按带指代的提示词逐条运行,因此 codex 调用会注入审查器所用的同一套网关路由;没有它,每次 codex 分类都会卡到超时。
3. 确定性升级。 审查器反复拒绝同一类反复出现的问题——每次换一个新借口(事后纠正、「还没部署」、前瞻性请求)——不再拥有最终决定权:同一类问题在 14 天窗口内被拒绝 3 次以上后,下一次拒绝会被替换为一条合成的 Major 经验,由累积的拒绝摘要构建并直接发布。已有发布经验的类别交给正常的复发机制处理,不再堆积重复的元经验。

DeepSeek Harness(dsh)覆盖: install 会附带一个独立原生 harness 插件(dsh-plugin/),并按 dsh plugin add 的方式接入 ~/.dsh/profiles/ 下的每个配置档(node_modules 符号链接、link: 依赖、dsh.profile.bundles 注册)——不涉及桥接包。插件把每条提示词送入 core-hook.sh 再把编译好的规则上下文注入回 harness。harness 不暴露任何对话记录,所以来自无法提供对话记录的方言的提示词会交给分类器处理,而不是被悄悄丢弃;会话能携带对话记录、但还没有指代对象的提示词(首轮)仍然跳过。dsh 来源任务的评审器和分类器子进程跑在宿主命令行上(先 claude,再 codex,再 gemini)。

从已发布的教训到后续会话

发布不等于送达。有三条通道把教训传递下去:

- 评审器契约把用户明确陈述的事实当作事实主张,智能体必须先核实才能反驳;同时把范围越界算作智能体的过错,即使智能体后来纠正了也一样。
- 出现次数达到 Major+3 / Critical+2 / Blocker+1 的族会被编译进 .agent/rules/feedback-loop.md 的托管块。
- 提示词钩子把该托管块注入每条提示词的上下文(上限 6 KB),这样一条反复出现的规则每轮都会被机械地看到,而不依赖模型主动去打开文件。

规则块是投影,不是不断累积的日志

托管块在每次发布时都从存储状态重建,并受固定字节预算约束,所以它不会无限增长,也无需任何人手动清理。三个特性让这一切自动完成:

- 合并。 渲染后正文完全相同的族会被合并。族 id 会把评审器的自由文本 family_key 连同其方法类别一起哈希,所以只要评审器换个说法描述 key,同一条教训就会以新 id 出现。一个实际项目里就有七个这样的重复项,占其规则块的 36.6%。
- 排序。 存活的段落按严重程度、出现次数、最近复发时间排序。没有第三项的话,一个几个月前命中 39 次、之后再没出现过的族,会排在某个本周命中五次的族前面。
- 降级,绝不删除。 放不进预算的族保留一行仅标题的行,写明名称并带上计数。它永远不会被删除:它保持已发布、保持计数,一旦再次复发并排到别的族前面,就自动恢复全文。

写入方保证规则块放得下,这取代了读取方过去在注入时做的字节切片。那个切片会从字符中间截断,悄悄丢掉一个实际规则块的 44%——包括五个已经达标的族。现在规则块超预算,只说明文件是旧版本写的或被手工改过;读取方随后会按整段裁剪,并记录裁掉了多少段。

doctor 在 status.rulesBlock 下报告规则块,带两个独立标志:saturated(投影达到上限——按设计正常工作)和 overBudget(文件已与写入方产出的内容不一致)。两者都不要求你清理任何东西。

评审器服务商环境

分离运行的评审器在宿主命令行(codex、claude 或 gemini)里运行,环境为清理过的环境。只有 PATH、HOME、TMPDIR、LANG、LC_ALL、LC_CTYPE、TZ,以及任何 AFL_REVIEW_* 变量能进入审查进程。命令行工具如果用自己的持久化凭据认证(例如 ~/.codex/auth.json,或 ~/.claude/settings.json 里的 token),无需额外配置就能工作,因为这份状态由命令行工具自己加载,不从 shell 继承。只有纯粹靠 shell 环境变量认证的服务商才需要把这些变量名传进去——比如 ANTHROPIC_BASE_URL/ANTHROPIC_AUTH_TOKEN 这一对,是导出到 shell 里而不是存在命令行工具自己的配置里——这时要通过 AGENT_FEEDBACK_LOOP_REVIEWER_ENV_ALLOWLIST 传入(逗号分隔的允许列表,其值里还必须列出 AGENT_FEEDBACK_LOOP_REVIEWER_ENV_ALLOWLIST 和 AGENT_FEEDBACK_LOOP_REVIEWER_TIMEOUT_MS 本身,这样它们才能活到分离出去的进程里)。单次审查超时默认 300000 ms,认领租约按它缩放,所以一次证据量很大、合法跑上几分钟的审查,不会在生成中途被切断,也不会因租约丢失被丢弃;真实服务商需要更长时间时,用 AGENT_FEEDBACK_LOOP_REVIEWER_TIMEOUT_MS 再调大。

安装与诊断

需要 Node.js 24.15 或更新版本。真正做全局安装、或改动真实 HOME 配置之前,先申请授权。

npm install -g agent-feedback-loop
agent-feedback-loop install --dry-run

先用一个临时 HOME;这样会装一套一次性运行时和 schema,不动真实用户配置:

tmp_home="$(mktemp -d)"
agent-feedback-loop install --home "$tmp_home"
agent-feedback-loop doctor --home "$tmp_home" --live
agent-feedback-loop uninstall --home "$tmp_home"
rm -rf "$tmp_home"

安装会复制包内资源、选定运行时、迁移选定的控制 schema,并配置提示词钩子。它不注册 Stop/AfterAgent 钩子,不启动服务,也不创建学习读取器。

DeepSeek Harness(dsh)

dsh 插件已列入 awesome-dsh-plugin 市场(memory 分类):条目。

如果 dsh home 存在(~/.dsh/profiles/),agent-feedback-loop install 还会把独立原生插件接入每个 harness 配置档:把插件复制到 <packRoot>/dsh-plugin/,链接进配置档的 node_modules,加一条 link: 依赖,并在 dsh.profile.bundles 里注册——最终状态和 dsh plugin add 一样,重复安装也保持幂等。插件由自带的补丁层激活;install 从不写入配置档的 cordis.patch.yml(在那里手写一行会和 bundle 层在 loader 条目 id 上冲突,harness 会拒绝启动)。早于 bundle 注册会自动迁移:它们写入的受管补丁行会被删除。

安装后重启 harness,运行中的实例才能加载插件。dsh home 跟随安装 home(真实用户为 ~/.dsh);传入 --home 并指定一个临时目录,就能在不碰真实配置档的情况下试跑接线。

doctor 返回 { version, status }。status.ready 仍是提示词/Markdown 管线的闸门。

包存在、doctor 静态结果正常,都不等于服务商实际可用,也不等于生产环境有效。

反思清理

两个以读为主的命令管理已发布的 reflections 目录:

agent-feedback-loop reflections effectiveness --project /abs/project
agent-feedback-loop reflections archive --project /abs/project # dry run
agent-feedback-loop reflections archive --project /abs/project --apply # move files

effectiveness 依据投递日志和评审历史回答「这条经验有没有起作用」,并把每个 family 报告为 never_delivered、recurred_after_delivery、too_early_to_tell 或 quiet_since_delivery。它的输出标注为 causality: correlation_only:某个 family 安静,可能是经验生效了,也可能是同类工作再没出现过。不要把它当成有效的证据。

archive 会退役同时满足两个条件的文档:早于 --after-days(默认 30),且从未投递到任何会话;退役即移到 reflections/archive/。已投递的文档无论多旧都不动。这是移动,不是删除,默认只做 dry run。

旧数据导出

反馈数据的旧版导出仍然需要显式触发,且对源只读:

agent-feedback-loop legacy-export --source-db /absolute/legacy.sqlite3 \
--output-dir /absolute/export --dry-run
agent-feedback-loop legacy-export --source-db /absolute/legacy.sqlite3 \
--output-dir /absolute/export --apply

要回滚提示词钩子,先查看 agent-feedback-loop uninstall --dry-run,获得批准后再运行 uninstall。它会禁用钩子,同时保留持久控制数据和密钥,除非操作者另行删除。

证据状态

代码测试、包清单、临时安装的运行时、生产有效性,是四种彼此独立的证据状态。前一种状态通过,不能当成后一种状态来汇报。

结构化日志只包含固定事件名、有界原因码、计数器,以及不透明标识符或哈希。日志里没有原始提示词、diff、评审正文、token,也没有绝对项目路径。
预览分享卡片长什么样 ↓super3ben/agent-feedback-loop
分享 · DeepSeek Harness Hub
super3ben/agent-feedback-loop

面向 Codex、Claude Code 和 Gemini CLI 的本地提示词时反馈学习。中文说明

这是你的仓库?认领条目

回到顶部