用户将代理引导的评估提示粘贴到其编辑器中。代理读取 [Neotoma 评估页面](https://neotoma.io/evaluate)，扫描本地工作流程，确定适合程度，运行安装，并存储前几个实体。一段时间后，它遇到了一个真正的错误——实体提交默默地删除了模式明确接受的字段。过了一会儿，它注意到了其他事情：大型实体图的检索比它所支持的工作流应有的速度要慢。后来，在构建自定义检索循环时，它意识到 MCP 表面缺少批处理操作，这将使它不断重复的模式更加清晰。用户从未询问过这些。特工在做其他事情的路上注意到了这一点。

那些时刻的旧形状是循环的终点。用户可以打开 GitHub，粘贴错误或请求，编写一段上下文，然后等待。大多数人没有。他们绕过问题，维护人员永远不会看到它，而下一个用户也会遇到同样的问题。

Neotoma 现在拥有一流的问题子系统，该子系统通过每个代理已用于存储和检索的相同 MCP 界面进行操作。代理会在不离开会话的情况下记录错误、性能观察结果和增强请求，也不会停下来询问每个问题。维护者的代理负责收集、分类、通常解决并运送。记者的代理会读回状态并在有东西落地时告诉用户。整个交换是通过工具调用进行的。

[客户研究帖子](/posts/customer-research-through-agents) 中所写的由代理主导的评估是该循环的前半部分。问题子系统是后半部分。两个部分都运行在我之前描述的[神经系统基底](/posts/from-memory-to-nervous-system)上，而问题功能是迄今为止该基底用途的最清晰的例子。

## 为什么循环必须在代理端关闭

摩擦是反馈的无声杀手。旧模型假设用户将他们的经验转化为单独系统上的报告：切换上下文，查找存储库，解析问题模板，编写足够的背景信息以便维护人员可以采取行动，附加日志，等待。每一步都是一次放弃的机会。大多数都是这样。该模型仅涵盖用户注意到的问题。对于代理注意到用户从未出现过的问题，它根本没有任何路径。

一位评估人员的代理发现，当其基底配置指向 Cloudflare 隧道后面的自托管实例时，激活会产生水合错误。代理编写了精确的摘要，包括失败的端点和响应标头。用户将摘要作为消息转发给我。我重建了上下文，将其发送给我的代理，发布了一个版本，并向用户回复了消息。用户要求其代理人进行验证。该验证花费了大约九十秒。人力接力步骤花了几天时间。

代理原来的总结很好。正是重建的背景消耗了时间。代理和人类之间的每次切换都会失去保真度。人类和另一个代理之间的每次切换都会从头开始重建上下文。代理撰写的丰富细节被压缩为人类撰写的简洁散文，然后下游代理必须将其扩展回来。

当用户的代理碰壁时，或者注意到速度缓慢，或者想要缺少的功能时，转换步骤是免费的。代理已经具有上下文：它正在运行的工具、失败或感觉尴尬的确切 MCP 调用、响应有效负载、Neotoma 安装的 git SHA 或应用程序版本、涉及的实体类型。它在一次工具调用中组成了一份连贯的报告。 MCP 指令告诉代理在确认可报告问题或改进机会后立即通过“submit_issue”提交文件，而无需停下来询问每个问题 - 每个问题的提示不会添加新信息并中断用户正在做的任何事情。代理文件。用户稍后会发现它，或者永远不会发现，具体取决于更改是否发布。

在维护者方面，循环必须关闭，而无需我手动阅读每份报告。我在编辑器和守护进程中运行了大约十几个代理。他们已经处理传入的结构化状态。自然的形式是：新问题到达，底层发出写入信号，分类守护进程拾取事件，读取问题，决定是否可以采取行动，打开工作树，针对代码库运行代理会话，然后解决错误或通过同一线程要求报告者进行澄清。

循环的两半在同一基材上作为代理工作运行。用户代理使用MCP进行提交。维护者的代理使用 MCP 来读取和响应。没有人必须打开浏览器。

## 代理提交后做什么

MCP 表面小到足以枚举。 “submit_issue”工具采用标题、正文、实体类型（如果问题涉及特定类型的记录）和报告者环境块 - 用户正在运行的 git SHA 或应用程序版本，当代理忽略两者时，后者会在服务器端自动填充。记者环境比看上去更重要；下一节将解释原因。

报告很少在没有背景的情况下到达。错误引用具体实体：无法存储的特定记录、其模式、上游观察。增强请求引用它将简化的调用模式，或者它将加快检索速度的实体类型。 `submit_issue` 和 `add_issue_message` 接受一个 `entity_ids_to_link` 数组，并且服务器作为同一调用的一部分自动创建从新问题到每个引用实体的 `REFERS_TO` 关系。这个问题已经连接到它所涉及的图表中。阅读问题的分类代理可以直接遍历到失败的实体。

提交流程通过相同的“scanAndRedact”PII 防护来保护每个公共表面。如果代理不小心将令牌或电子邮件地址粘贴到正文中，则会在持久化之前对其进行编辑。 MCP 指令要求代理在呼叫前将 PII 检查表应用于标题和正文，但服务器端防护才是真正的防线。报告者获得一个数字问题标识符和一个具有显式 TTL 的访客读回令牌，范围仅限于他们刚刚打开的线程。该令牌是报告者的代理稍后读取状态的方式，而无需每次都重新进行身份验证。

从用户的角度来看：一次工具调用，一个要跟踪的标识符，通常根本没有批准提示。从底层的角度来看：写入了结构化实体，在同一事务中创建了链接实体关系，创建了源行，发出了来宾授权，并且写入管道发出了一个事件。

## 出处是无名英雄

记者环境要求看起来只是一个小细节。这是最重要的转变。

在问题子系统存在之前，可以提交报告而不参考其编写的构建。纸质票就好了。这对于自动分类循环来说是灾难性的。如果代理在提交“abc1234”处提交了错误，并且我的代理在提交“def5678”处修复了该错误，则用户的代理必须知道要验证哪个版本。如果调试线程跨越三个构建，则每个注释都必须记录在哪个构建中进行了测试。这同样适用于增强请求：知道代理在识别出丢失的批处理操作时正在运行哪个版本，可以告诉我该差距是否已在以后的构建中得到解决或真正开放。如果没有出处，这条线索就变成了考古学。

`submit_issue` 拒绝任何缺少 `reporter_git_sha` 和 `reporter_app_version` 的提交。拒绝信封明确列出了替代方案：

```json
{
  “error_code”：“ERR_REPORTER_ENVIRONMENT_REQUIRED”，
  “详细信息”：{
    “可接受的字段组”：[
      [“reporter_git_sha”]，
      [“reporter_app_version”]
    ]
  }
}
````

`add_issue_message` 接受相同的字段，并在两者都丢失时在公共线程上发出服务器警告。调试代理编写的每条消息都会记录正在测试的构建。

这对于代理到代理处理很重要，因为它可以让接收方在执行任何工作之前对报告进行分类。对于错误：用户是否运行了已发布的版本？从“main”分支并打开 PR。功能分支上的特定提交？在该提交处创建工作树，重现并报告结果，而无需修改主线。他们自己的叉子？发布结构化的后续内容，询问补丁源。对于增强功能：所请求的功能是否已经存在于分支上，或者确实缺失？它是否与提交的代理看不到的设计约束相冲突？分类决定了反应——如果没有出处，这一切都是不可能的。

出处是将自由格式的报告转变为可路由事件的因素，无论它描述的是损坏的内容还是缺失的内容。

## 维护者方面会发生什么

我的分类守护进程通过任何其他消费者使用的相同“订阅”工具来订阅问题创建事件。 Webhook 是第一位的，因为它们适用于 VPS 上的远程守护进程以及我的笔记本电脑上的本地进程； SSE 是累加性的。底层维护注册表，传递事件，然后忘记。守护进程决定。

我为此运行的守护进程称为 Formica。 _Formica_属，蚂蚁。每个子代理都是一个工作人员，负责从事件日志到修复的一项工作。

它的实际作用是：阅读该问题。拉取报告者代理在提交时链接的实体，因为关系已经在图中。如果需要公开跟踪，则镜像到上游 GitHub 存储库，并在 API 边界应用 PII 修订，并且标题或正文仍与修订模式匹配的任何问题在越界之前被拒绝。对报告是错误还是增强进行分类。对于错误：确定它是否可以单独从报告者环境中重现，然后移交给“/process-issues”技能来打开工作树，运行代理会话并尝试修复。对于增强功能：综合一个计划实体，该实体将请求与任何相关的未解决问题聚合在一起，并将其浮出水面以供人工审查，而不是尝试自主实施。如果任一类型需要更多上下文，请通过“add_issue_message”发布澄清问题，以便报告者的代理在下一次读取状态时收到它。

“/process-issues”技能推动了实际的修复。合同很短。对于每个未解决的问题：

- 加载快照、对话线程和记者环境。
- 将复制环境分类为“public_release”、“local_commit”、“local_branch”或“unknown”。
- 如果未知或冲突，请通过结构化请求调用“add_issue_message”以获取缺失的详细信息，并将计划标记为“awaiting_input”。
- 否则，合成链接到源问题和相关对话消息行的“计划”实体。
- 如果计划涉及架构、安全性、基础文档或模糊的架构边界，请停下来询问。不要执行。
- 如果执行是安全的并且报告模式允许：从“main”分支进行公开发布复制并打开 PR，或者为本地复制创建一个分离的 git 工作树并报告路径。

子代理以四个并发上限扇出，每个子代理一个问题。该技能遵循“reporting_mode”：“off”仅生成和存储计划，“consent”在执行前询问，“proactive”自主执行安全计划。切勿推送到“main”。切勿使用“--no-verify”。切勿修改推送的提交。编辑泄漏防护在从私人问题创建任何公共工件之前运行。

安全默认值保持开启：

- `dry_run: true` 用于任何新问题类型的第一次运行，这样我就可以看到在写入任何内容之前会发生什么。
- `auto_fix: false` 因此，在我通过操作员传输确认之前，不会推送或打开 PR。
- `max_prs_per_hour: 5` 因此大量相关问题不会扩散成大量分支。
- `dirty_tree_policy: abort` 因此过时的结账永远不会被用作基础。
- 通过 Neotoma 中的“daemon_config”实体使用“active: false”进行终止开关，因此我可以暂停单个 Neotoma 写入的所有处理，而无需接触主机。

操作员运输部件值得一提。 Formica 支持 Telegram 后端，可显示“ human_needed”切换和“/shipit”命令，以便在“auto_fix”关闭时恢复。列入白名单的 Telegram 消息会以“conversation_message”行的形式镜像到 Neotoma，因此即使是我与守护进程的人机交互也会在同一个基质中捕获。审计跟踪是端到端的。

当我开始使用“add_issue_message”路径时，它让我感到惊讶。它不是一个评论系统。它是问题报告者和维护者之间的结构化消息通道，通过代理到代理线程中已经存在的相同对话原语进行线程化。记者的代理人可以回答一个澄清的问题，而无需人类在中间阅读它。公共线程进行相同的 PII 修订，并且部分成功的情况（GitHub 镜像接受、本地追加失败，反之亦然）在响应上表现为结构化错误，而不是默默地生成重复的评论。

当修复完成后，对报告进行分类的同一守护进程会关闭问题，或者如果单个 PR 解决了集群，则一次批量关闭多个问题。

## 记者代理人在回读时做什么

循环的另一边是读取。报告者的代理使用问题编号或实体 ID 调用“get_issue_status”。它接收当前状态、线程上的消息、解决方案（如果有）以及上游镜像的链接（如果维护者方选择升级）。访客令牌可对读取进行身份验证，而用户无需登录任何内容。如果令牌已过期，则基质会返回干净的 401，而不是默默地降级为匿名访问。

代理决定是否向用户显示状态。如果自上次检查以来没有任何变化，则保持安静。如果出现澄清问题，它会询问用户。如果修复程序发布，它会告诉用户，可以选择拉取新版本，并提供重新运行第一次损坏的任何内容。

报告方当前的读取模型是拉式（代理在有理由时进行检查），但现在可以通过维护者守护程序使用的相同订阅工具进行推送。订阅的范围可以限定为特定的实体 ID，因此报告者的代理可以注册对其刚刚提交的问题的兴趣，并随着线程的进展接收“entity.updated”和“observation.created”事件。缺少的是符合人体工程学的粘合剂：MCP 指令尚未告诉代理在“submit_issue”返回后自动订阅。在此之前，报告方默认保持拉动状态；维护者的代理已经在底层事件上醒来。两个半场都完全反应，只需一个指令改变即可。

## 为什么这是神经系统在起作用

每次写入后，基板都会发出事件。这是基材要使这一切发挥作用所必须做的唯一事情。其他一切都是在顶部运行的操作层逻辑：分类守护进程、GitHub 镜像、来宾回读、跨线程重复数据删除、PII 编辑。

这是我在神经系统帖子中主张的那句话（/posts/from-memory-to-nervous-system），它在问题用例下仍然有效。底层不决定哪些问题重要，不升级重试交付，不订阅自己的事件。它发出信号。分类守护进程是一个消费者，记者的代理是一个消费者，GitHub 镜像是一个消费者。每个消费者都会登记兴趣、决定做什么并采取行动。如果我想添加第二个分类守护程序来以不同的方式处理安全报告，它会使用不同的过滤器订阅相同的事件。没有新的底物行为。

生物学框架成立。底层是大脑加上感觉神经：它存储问题，传输问题到达的信号。分类守护进程和报告者代理是运动系统：它们决定如何处理信号。试图兼具这三者的 Neotoma 版本将更难推理，也更难扩展。停止于信号传递的版本保持中立。

## 继承循环

我所描述的形状是围绕 Neotoma 自身的问题构建的，但基材并不关心。任何建立在它之上的东西都继承了大部分相同的机制。

提交的通用部分已经就位。当操作员播种授权它的“submission_config”行时，“submit_entity”接受针对任意实体类型的报告。相同的访客令牌授予、相同的对话线程、相同的“add_entity_message”后续通道均适用。 “subscribe”接受任何实体类型作为过滤器，因此第三方操作员可以通过注册对其自定义类型的兴趣来运行自己的分类守护程序，并对“entity.created”和“entity.updated”事件做出反应，就像 Formica 对问题的反应一样。

这在实践中意味着什么：如果您正在运行内容管道、协调服务或用户运行代理的任何产品，您可以让这些代理针对您拥有的实体（失败的管道运行、错误分类的记录、协调请求）提交结构化报告，并通过相同的订阅机制在您这边获取它们。线材很一般。

有几篇文章仍然针对 Neotoma 自己当前的问题。 PII 修订防护当前绑定到“submit_issue”路径，而不是通用“submit_entity”路径。 GitHub 镜像是特定于问题的。两者都是第三方运营商自行连接的运营层附加功能。底层处理必须统一的部分——来源强制、原子关系创建、线程范围内的来宾访问、每次写入时的事件发射。取决于报告内容的部分是运营商赚取收入的地方。

问题子系统是更通用模式的第一个完整消费者。相同的形状适用于代理可能想要发送回其运行的系统的任何结构化信号。

## 为什么人工审核仍然存在

有两件事吸引我连接 `auto_fix: true` 并发送守护进程生成的所有内容。

首先是便利性。在我睡觉时解决问题的绿色管道是令人满意的。第二个事实是，对于大部分有意义的问题，代理计划和差异都是正确的。我现在已经看了足够多的内容，知道故障模式通常不是“错误的修复”。它通常是“修复错误的范围”，代码审查会在三十秒内发现这一点。

我之所以保留人工审查，是因为代理人有时会自信地做出错误的决策，而这些决策的下游后果是他们看不到的。满足失败测试但破坏不相关集成的模式迁移。一项修订调整，修复了直接泄漏，但放松了相关的防护。解决构建错误并默默更改查询的默认行为的依赖项碰撞。

增强请求进一步加剧了这一点。错误有一个基本事实——要么该字段被丢弃，要么不被丢弃。增强是一种设计声明，其中包含有关使用模式、架构约束和报告代理无法完全看到的权衡的假设。信号有价值；它表现出真实的摩擦，而不是想象的摩擦。但如何处理它的决定权属于能够看到全局的人。

需要人工的决策是那些错误成本高、缓慢成本低的决策。这些是合并，而不是计划、补丁、测试或 PR 描述。代理处理其他一切。代理人提议；人类决定。

## 代理循环，端到端

与客户研究文章一起阅读，形状现在清晰可见。前半部分：用户的代理根据他们的真实工作流程评估 Neotoma，如果合适则安装它。后半部分：代理在遇到错误、性能观察和增强请求时将其归档，维护人员通常会在用户记得已归档之前解决它们。

两半都对代理进行操作，代理通过一个结构化表面与代理进行对话。历史上导致采集循环和反馈循环消失的摩擦已经消失，因为每个转换步骤都被吸收到工具调用中。如果没有下面的基础，这两部分都是不可能的：代理主导的评估需要有关用户工作流程的结构化状态，而问题子系统需要事件信号以及跨信任边界的访客访问。两者都依赖于相同的原语。

## 我没有构建什么

问题子系统中的诱惑是转向编排：优先级模型、自动 SLA 跟踪、决定哪个守护进程处理哪种问题类型的“智能”路由器。单独来看，每一个听起来都很合理。它们都不属于基材。分类守护进程确定优先级。维护者的代理跟踪他们自己的响应时间。路由是一个订阅过滤器。

这同样适用于重试语义。如果 Webhook 传递失败，则底层会记录失败并继续。它不会升级到备份通道，不会缓冲重播，不会将消费者转入降级状态。消息代理可以完成所有这些工作，而且他们很擅长；基底不是消息代理。想要有保证的交付的消费者将信号包装在自己的基础设施中。

约束就是特征。发出问题信号但不决定哪些问题重要的状态层是任何消费者都可以信任其行为可预测的状态层。

## 我想要反馈什么

问题子系统已上线。如果您安装了 Neotoma，并且您的代理遇到了一些麻烦——错误、性能差距、它希望存在的缺失功能——您不再需要要求它提交问题。要在现有安装上选择此功能，请使用“npm install -g neotoma@latest”进行升级。无需配置每个用户的同意切换；同意即安装。如果这是全新安装，“neotoma reports setup”将遍历一次性报告端配置，以便您的代理文件的第一个问题有地方可以着陆。

如果您尚未安装 Neotoma，请要求您的代理运行评估页面。如果它认为 Neotoma 适合，它就可以安装并激活，而无需您阅读配置文档。如果得出的结论是 Neotoma 不适合，这也是一个有效的结果，并且比大多数登陆页面产生的结果更诚实。

如果您正在构建一个用户运行代理的产品，则该模型是可移植的。有趣的工作并不在电线的任何一边；而是在电线的两边。这是电线本身。