想象你在古董店发现了一盏神灯。你擦了擦,一个精灵出现并询问它能如何帮忙。你说:“我需要一位最好的工程师来帮我完成工作中那个不可能的项目。”精灵实现了你的愿望,对我来说,最好的工程师可能是约翰·卡马克(John Carmack),于是你得到了他。但精灵有点幽默感,为了安全起见施加了限制:卡马克只能看到你代码库中很小的一部分,也许只有千分之一。而且他完全不记得之前做过什么,每次对话都从零开始。这肯定会让人抓狂,对吧?你知道做事有标准方法,但卡马克不知道。你必须一遍又一遍地解释同样的事情。你面对的是一个天才和一个严重缺陷者的组合,而这正是智能体(Agent)的现状。让我通过一个简单的交互例子,带你看看我们需要重新解释多少次事情。

我们有四个仓库:UI、模块一、模块二和平台。我想更改 UI 并将变更传播到整个系统,好吗?首先,我们更改 UI 库。比如改变一个按钮之类的。这是第一次解释,不可避免。我们必须表达意图,好吗?然后我们发布它。我们去模块一,必须重新解释 UI 库中刚刚发生的事情,以便它能在此处消费该包。注意这通常是不同的人做的对吧?这个图中的每个框都可以由不同的人完成。然后我们发现发布的 UI 库与模块一不兼容。所以我们回到 UI,必须重新解释最初的变更以及遇到的问题。因为这是一个新的智能体,它不知道原始变更,显然也不知道这个问题。假设我们修复了它并再次发布。

我们去模块一,在模块一的背景下解释新的变更(同样的模块)。我的意思是再对模块二做同样的事情。然后我们去平台仓库,解释一切如何契合在一起并在那里实现变更。想象一下发布一周后,UI 组件出现了一个 bug,我们必须修复它。所以我们启动一个在 UI 仓库中的智能体。我们必须再次解释一周前的原始变更以及我们正在看到的这个生产环境问题。所以对于本质上是一个变更的事情,我们有七次解释。而且可能不是同一个人做出这七次解释,但它们确实发生了,对吧?所以这在智能体中非常典型。那么我们如何解决它呢?

这里有很多导致这种体验的问题,但它们大致分为两类。第一类是智能体本质上是受限于仓库的(repo-bound)。智能体通常一次只查看和更改一个仓库。它从未看到整个系统,那可能是成百上千个仓库。所以这是问题的空间部分。第二类是失忆症(amnesia)。智能体忘记了工作,每个会话都以白纸一张开始。在这种情况下,人类成为了记忆者。这是问题的时间部分。让我们更仔细地看看这两点。首先看仓库边界。如果没有模型来展示仓库如何组合在一起,智能体就依赖人类进行研究。它无法将代码与系统的其余部分对齐,比如 UI 变更无法与模块一对齐。因为人类没有解释这一点,所以发布了错误的版本。

它也无法可靠地引用最佳实践和标准,因为这些通常存在于其他仓库中。更糟糕的是,智能体一次写入一个仓库,这意味着它无法验证下游的变更。模块一的 CI 本应在 UI 变更时失败,但它没有。即使智能体在做出 UI 变更时有完美的信息来做这件事,它也无法同时更新消费者。用户必须向每个消费者不完美地重新解释事情。跨 20 个仓库更改内容意味着要重新解释 20 次。这花费了大量的开发人员时间,但也烧掉了大量的 token(计算资源)。第二类问题是智能体会忘记。智能体没有情景记忆,每个会话都是白纸一张。在这种情况下,人类成为了记忆者。

你实际的工作图景是这样的:底部是仓库图,包括你的组织产生的工件以及依赖的每个开源仓库。也许有一千个你拥有的仓库和数万个开源仓库。顶部是所有创建和修改这些代码的智能体会话。会话彼此相关,仓库也彼此相关。所以这个图是你组织工作的忠实写照。它描述了底部有什么以及顶部是如何产生的。这就是你希望你的智能体看到的东西。但它实际看到的是:只有一个会话,代码库的一小部分,没有记忆,好吗?因为它看得太少,它就依赖那个理解系统的人——开发人员。每个开发者手中都握着那部分图景,至少在他们熟悉的领域内是这样。而智能体通常没有这种全局视野。

如果这听起来不疯狂,想象一下一个每次最多只能查看一个文件、且只能回顾五条消息的智能体。这种约束既在空间上(能看到什么),也在时间上(能回溯多久)。你会说这不可能工作。我们现在的情况与这个疯狂的画面类似,而且组织越复杂,这一点就越明显。我将展示我们如何解决它。我交谈过的其他组织也有类似的解决方案,所以请从概念上看待问题和解决方案,而不是具体的工具,尽管这个工具相当酷。我们构建了一个智能体无关的元框架(meta harness),称为 Polygraph。让我展示一下它是做什么的,以及如何修复我们刚才讨论的问题。

我们要达到的第一个想法是:如果一个 GitHub 用户(任何用户)可以访问数千个仓库,其中一些是他们拥有的,许多是开源的,我们可以分析它们并从中提取大量元数据来构建统一的依赖图。那些仓库中没有一行代码被更改,这一切都在侧面发生,对吧?然后我们可以获取这些元数据并馈送给这个元框架,创造出一个大代码库的错觉,智能体可以在此读取和写入任何地方。这是我的个人图景:我有大约 300 个我拥有的仓库,以及数千个项目所依赖的开源仓库。Polygraph 计算每个仓库、每个项目生产了什么,消费了哪些包(按 API),以及产生和消耗了哪些 API 等大量其他信息。

它将这一切缝合在一起,形成一个巨大的代码体,你的智能体可以与之协作。

让我们看看它做了什么,对吧?首先,它会让你启动一个会话以引入相关的仓库。所以,它需要做的是设置源代码、安装依赖项、为每个仓库配置一个代理并将它们连接起来以便协同工作,同时提供一个简洁美观的图形界面,让你在进行非琐碎更改时不会迷失方向。我稍后会向你展示它是如何工作的,对吧?所以,这就是信息的拉取过程。信息拉取只是故事的一部分,好吗?老实说,这部分很简单。更难的是进行更改。

如果你在一个会话中有10个仓库,这意味着你可以有10个拉取请求,好吗?你需要运行CI(持续集成),需要协调所有这些工作。如果一个失败了怎么办?Polygraph将所有CI视为一个向量。就像我们在之前的例子中看到的那样,当我们为UI模块一和模块二运行CI时,如果模块一在Polygraph会话中失败,它会找出谁来解决这个问题:是模块一需要补丁,还是UI组件本身损坏且与模块一不兼容。在这种情况下,每个人都需要打补丁。Polygraph让你将复杂的多仓库更改视为单个仓库的更改。

顺便说一下,同样的机制也解决了情景记忆的问题。因为我们捕获了你的工作,无论涉及多少个仓库、你的意图是什么、涉及的仓库以及拉取请求。我们还捕获了所有代理的踪迹(traces)。因为我们捕获了所有这些内容,我们可以将它们关联起来。现在我们可以说你在一个仓库中的工作与另一个仓库中的工作相连接。这使得我们可以在任何机器上恢复任何会话、任何部分的工作,或者从任何地方引用它。我稍后会再次展示它是如何工作的。

你得到的是一个拥有像你整个组织一样过目不忘记忆的代理。它理解仓库是如何编写的、它们之间的关系以及如何组合在一起,并基本上记得每个开发人员来自每个仓库的每一个会话。这创造了一种完全不同的开发体验。让我展示一下。首先,让我们看看如何创建一个简单的会话:你运行一个命令,并从列表中挑选一些仓库。这是一个只有三个仓库的小型GitHub工作区,因为这是演示。我选择了后端和前端。

假设我需要做一个更改,这个更改会修改API并必须同时更新API以及如何显示内容的方式。我需要给我的会话起个名字,并从已安装的代理中选择一个。我选择了Claude。但任何已安装的代理都以相同的方式工作。记住,Polygraph不是一个代理,它是围绕代理构建的一个元框架(meta harness),使它们更具能力。很快,代理就会启动。在这里我可以像在一个单仓库中一样与它交互,即使涉及多个仓库也是如此。

我可以给它指令,它将规划出更改方案。UI中还有一些很酷的动画效果。最终,它弄清楚这两个仓库之间的关系以及需要进行的更改是什么。我可以要求它实施这些更改。我与它的交互完全等同于我在单仓库中工作时的情况。涉及多个仓库这一事实并不重要,对吧?唯一变得重要的是我有多个拉取请求的部分。但我也会得到一个Polygraph会话,其中包含了这些拉取请求。

如果我查看该会话,我会看到描述部分从概念上描述了工作,某种程度上绕过了仓库边界,说明我们需要在这个仓库中更改某些内容,在那个仓库中也更改某些内容。它让我清楚地了解涉及哪些仓库、拉取请求以及这些仓库中的CI情况,即我需要知道的一切。这大部分内容基本上就像我在单仓库中会看到的一样多。我还捕获了所有代理日志,这对于恢复会话非常重要,我稍后会展示这一点。

现在事情变得有趣了。我已经保存了一次解释。我没有在前端仓库中重新解释后端更改,对吧?我只解释了一次更改,并在两个仓库中都实现了它且达成一致。现在让我们恢复一个会话。假设我想让同事完成后端更改,也许他们拥有该仓库。我将会话发送给他们,他们在他们的机器上恢复它。所以我是在向他们发送会话,他们可以运行命令。不同的机器、一切皆不同,他们使用不同的终端。

他们会在这台机器上重建它。他们没有这个会话记录,对吧?他们从未参与过这项工作。他们可以选择一个代理。他们选择的代理可以是不同的代理,比如我在原始会话中使用了Claude,但假设他们使用的是另一个Cortex。相同的设置过程发生在他们的机器上:同样的仓库、同样的SHA,一切正确配置。代理以类似的方式启动并连接在一起协同工作。

它们都预加载了从我机器上捕获的踪迹,所以他们机器上的后端仓库代理拥有相同的上下文和历史记录。前端仓库的情况也是如此:它签出到正确的SHA,运行着带有正确历史记录的代理。所以我的代理是Claude,他们编码,但我们共享记忆。实际上如小视频所示,他们可以在此处进行更改。但我认为关键部分是记忆共享。

我可以工作,他们也可以工作,我们可以分享我们的记忆,尽管我们使用了不同的代理和不同的机器。我会话的完整状态可以在他们的机器上具现化(materialized)。这与其说是内存,不如说更多是关于状态。附加到会话的世界状态使他们能够继续我的会话,即使他们最初没有参与任何工作。这有点像《星际迷航》中的传送器(transporter)。我会话的所有状态都在他们的机器上具现化,以便他们继续工作。

这就是我通常的工作方式:当有一个需要我审查的拉取请求且我有疑问时,我通常会直接询问那个人。相反,我会将他们的会话在我的机器上恢复,获得完全功能性的精确状态,零设置,然后我就和我的代理讨论我们做出的决定。因为所有这些决策都包含在捕获的踪迹中。所以我的代理确切地知道另一个人对他们的代理说了什么。

顺便提一下,这也很有用:当我想在会话中途从Claude切换到Codex时(如果出了什么问题)。好的,让我们回顾我之前提到的那个案例。

当 Bug 上线生产环境时,我会引用该会话并指出它基本已损坏。然后询问 AI Agent:“你能找出问题所在并进行修复吗?”Agent 会查找相关信息,下载所需内容。如果高层级的描述信息就足够了,那当然很好;否则,它会拉取相关的仓库、代码分片以及 Agent 日志。它将获取原始会话中的所有这些信息,以重建当时的状态,从而执行必要的修复操作,如下所示。实际上它提供了修复方案,对吧?我只需要说:“发生了这种情况,有一个 Bug。”仅此而已。我不需要提供任何额外信息。

到目前为止,我们手动选择了仓库和会话,但这并非必须。与其手工选择仓库,我可以直接告诉 Agent 我想要什么。请记住,图谱拥有关于仓库之间关系的所有智能信息。我可以指示我的 Agent:“找到所有依赖特定版本库的仓库,并对其进行更新。”它知道该怎么做。我不需要手动选择它们,因为它掌握着大量关于当前状况的元数据信息。

我还可以提出较为宽泛的问题,例如:“如果我想写一篇博客文章或技术文呢?”我可以描述我的需求,它会基于仓库之间的关系及其内容,找出最相关的仓库。另一个例子:假设我想在 PR 集合中添加向量索引,并想知道是否有任何人在任何仓库中做过相关的事情供我参考。在这种情况下,如果我执行操作,它会发现几个看似相关的会话。

我可以加载其中一个或两个会话,这有许多用途。举一个小例子:它有助于最佳实践和一致性。与其从零开始做每一件事,导致每个实现都是定制的,我可以让它复制我尊敬的工程师在会话中使用的方案。这样我们跨仓库的代码就保持一致了,这非常重要。

当然还有更多内容。如果你在某个仓库中,我可以询问相关会话,它会优先列出与该仓库相关的会话;反之亦然。如果我是在寻找仓库,它会根据我的会话查看哪些类似的会话通常会引入相关内容。乍看之下似乎很普通,但实际上有很多有趣的智能机制使其变得非常有价值。

最后,到目前为止我展示的所有内容都使用了 Polygraph CLI(当前的元工具 CLI)来启动它,然后你可以在其中启动 Cloat 或 Cortex。但你不必这样使用它。例如,我已经在一个 Cloat 会话中,但它适用于任何情况。我可以直接说:“我觉得增加一个单独的仓库会很有用。”比如我正在 NX 仓库中开发 Vitest 插件,我可以问:“你能把 Vitest 仓库添加到此会话中吗?以便我了解情况。”

在这种情况下,我们将启用 Polygraph,它会自动设置并配置一切,将 Vitest 库(即开源仓库)带入我的会话。现在我的 Agent 可以探索它,了解其工作原理,并可能解决我仓库中的问题。相比 Context7,我更倾向于这种方式,因为如果拥有真实代码,Agent 可以深入挖掘,从而发现深层次的问题。

Agent 在空间和时间上受到限制:它们只能看到代码库的一小部分,且不知道过去的情况。但这两种限制都可以被打破。Polygraph 让 Agent 能够访问组织内可触及的所有代码,包括自有代码和开源代码。因此它在空间上不再受限,任何 Agent 都可以获取全部信息。

它还赋予 Agent完美的记忆能力:发生过的每一件事、做出的每一个决定都触手可及。因为它跨越了开发者边界,而非仅限于单个开发者,Agent 可以拥有比任何单一开发者更多的上下文。就像一家有数千名工程师的组织创建了所有这些会话,它们对彼此都是可访问的。这有点像“博格”集合意识:每位开发者运行的每个 Agent 都贡献于一个巨大的集体智慧中。

如果这很有趣,我的名字是 Victor。你可以在 Twitter 上关注我。如果你想体验一下,请访问 try.poligraph.com 看看它是否适合你。谢谢。