Transcription
如果您可以使用最强大的云端 AI 模型处理您私有的公司文档,而无需将任何敏感信息泄露到您的网络之外,那会怎么样?没有真实姓名,没有财务信息。云端 LLM 永远不会看到其中的任何内容。让我向您展示一下那是什么样的。
所以,如果我们进入聊天并提出问题,嗯,告诉我关于 Sarah Williams 的情况,她是一名员工。所以,它正在对 Sarah Williams 进行混合搜索,我们得到了一些信息,这都是正常的。您会期望 LLM 做到这一点。假设它能够搜索文档并检索信息。但有趣的是,我们在这里使用的是 Claude Haiku,而 Haiku 并没有看到这些信息。
所以,如果我们进入 Langfuse,进入这个特定的跟踪,首先,您可以看到发送的消息,即“告诉我关于 Pamela Nelson 的情况”,这与“告诉我关于 Sarah Williams 的情况”不同。所以,我们已经将 Sarah Williams 的名字匿名化为 Pamela Nelson。我们将该映射保存在 Superbase 的注册表中,然后 Claude Haiku 会触发一个工具调用。所以,它正在将查询 Pamela Nelson 传递给我们的搜索文档工具。所以,这会回到我们的系统中。我们将它从 Pamela Nelson 换回 Sarah Williams。我们触发我们的混合搜索工具,该工具返回大量包含机密敏感信息的块。然后我们再次进行编辑和匿名化这些信息,您可以在那里看到。首选名称为 Pamela Nelson。然而,这并不是这些文件中的内容。是 Sarah Williams。所以,这些经过编辑和匿名化的信息会返回给 Haiku。您可以在这里看到其中一些编辑。所以,这里有一个社会安全号码的编辑。我们有美国护照、美国驾照,而所有这些信息实际上都在这个文件中。同样,这不一定代表数据在企业中应该如何存储。
然后,Haiku 的响应基于搜索结果,这是我找到的关于 Pamela Nelson 的信息,您再次获得完整的详细信息,然后进行去匿名化并在屏幕上输出,正如您在这里看到的。所以,即使只是一个简单的消息,在工具调用、匿名化、编辑之间,实际上有很多事情正在发生。我们正在将此作为我们基于 Claude 代码的代理 RAG 系列的一部分来构建,我们创建了一个完全由 AI 代理组成的 Web 应用程序,该应用程序基于私有公司知识。
至于构建本身,我们正在使用一些新东西,即 Claude Code 的代理团队。这最近与 Opus 4.6 六一起发布,它允许您并行启动多个 Claude 实例,每个实例负责研究过程的一部分或构建的一部分,所有这些都由团队负责人协调,正如您在这里看到的。如果您正在关注这个构建系列,您可以在下面的存储库中获取此阶段的要求。但是,如果您想跳过,代码库可供我们社区的成员,即 AI Automators 使用。在社区内,您可以克隆代码库,对其进行自定义,并真正使其成为您自己的。
所以,您刚刚看到了编辑和匿名化的实际应用。但这一切有什么意义呢?您知道答案。这是隐私法规,GDPR、HIPPA、CCPA、PCIDSS。企业越大,在实施和部署 AI 系统时,治理就越严格。风险是真实存在的。AI 系统本质上是可以通过社会工程学操纵的软件,这是一个相当可怕的前景。我们正在谈论提示注入、数据泄露等问题,如果我们看看有什么风险,我们正在看 PII,个人身份信息,医疗记录,财务记录,商业秘密,等等。
数据有很多种方式会从 AI 系统中泄露。公司内的用户实际上可能会输入敏感信息,或者代理本身能够查询私有知识库或通过 API 或 MCP 连接到具有敏感信息的连接系统。在我们上一个视频中,我们构建了一个可以查询文件系统的系统。所以,如果您没有关于 AI 代理可以访问的数据的策略和仔细的控制,那么总有泄露的可能性。
当您将数据发送给 Anthropic、Google 或 OpenAI 等云提供商时,您就完全信任他们会安全地处理这些数据。有时这种信任可能是错误的,就像 OpenAI 不得不披露现在已匿名化的 ChatGPT 日志一样,但它仍然设定了一个总是有点令人担忧的先例。
大多数提供商,如 Anthropic 和 OpenAI,都有数据处理协议和 API 服务条款的附加条款,他们承诺不使用您的数据进行训练,不共享,不出售,并有数据保留政策。这实际上是您的法律保障。但总的来说,在法律保障之上再增加一个技术保障是值得的。这个技术保障可以在数据沿链的某个地方发生数据泄露时减少影响范围。它通过确保敏感数据一开始就不会被发送来做到这一点。
老实说,这里的黄金标准是完全将整个系统在防火墙后进行气隙隔离,并在您的网络内运行,这样您就可以完全控制它。我在之前的视频中已经讲过这一点,我非常喜欢这种方法,但您需要考虑权衡。
第一个是模型智能。OpenAI 的旗舰 5.3 模型比您可能只能在本地运行的 GPT OSS 200 亿模型功能强大得多。幸运的是,本地模型越来越好,但直到硬件方面取得真正的突破之前,这将是一个长期的限制。
这让我想到第二个问题,那就是硬件。RAM 的成本正在飙升,而实际上几乎不可能获得一个体面的 GPU。所以,如果您使用云模型,无论是出于选择还是被迫,答案很可能就是编辑和匿名化。关键是在敏感数据离开您的网络之前将其剥离或替换。如果存在真正的风险,就不要将其放在任何 AI 系统附近。如果您根本不连接它,您甚至不需要进行编辑。
我们今天构建的解决方案基于 Microsoft Presidio,这是一个用于编辑和匿名化的开源框架。这是两种截然不同的方法。所以,对于完全编辑,它基本上是破坏性的。它就像单向加密。无法解密。所以,例如,护照号码会变成一串星号,无法将其翻译回其原始含义。对于信用卡号等内容,值得考虑这一点,您肯定不应该以明文形式存储它们,银行账号、IBAN、加密密钥、社会安全号码、护照、驾照等。但同样,这很大程度上取决于您的用例。这取决于您的业务是什么。
而完全编辑是不可逆的,相反的是可逆匿名化。在这里,例如,姓名 Daniel Walsh 被识别为一个人。这个日期被识别为一个日期。重要的是,您保留了这些键值对的映射。所以,当 LLM 以这个人的标签响应时,您可以将其换回姓名 Daniel Walsh。可逆匿名化更适合不太敏感的信息,但仍然是您想要保护的信息。例如,个人身份信息、地点、地址、电子邮件地址、人名,以及可能与这些人相关的日期和时间。
回到这个占位符的想法,它实际上是如何工作的?您如何识别这是名字,那是日期?嗯,重要的是要说没有单一的检测方法可以单独完成。这些是相互叠加的层,它始于模式匹配,如 reax。所以,这对于结构化的个人身份信息非常有效。例如电子邮件地址、IP 地址、电话号码,这些都有固定的模式。但它也适用于具有校验和验证的内容,例如信用卡号。
第二个是命名实体识别。这些是理解语言的 AI 模型。所以,它可以识别一个名字,即使它在训练数据中从未见过。
上下文增强是添加到系统的另一层。所以,这里有一个任意数字,但它能够查看它前面的内容,以了解这很可能是社会安全号码,因为它出现在实际数据本身之前。这样它就可以提高置信度分数,表明这是一个社会安全号码。
即使有这三层,我们仍然无法捕捉到所有内容。所以,可以使用本地 LLM 来处理边缘情况。所以,这对于模糊的 PII 或像 555 这样的例子非常有效。之前的模式无法捕捉到这一点。而本地 LLM 可以对其进行推理,并找出这是一个数字。它可以与电话号码相关联,然后它可以提高围绕它的置信度分数。
Microsoft Presidio 尚不支持本地 LLM,但您可以将其构建到架构中,我在这套系统中就是这样做的,这让我们不得不面对一个不幸的真相,即实体识别并不完美。有很多关于这方面的研究,但即使是最好的系统也可能遗漏超过 5% 的敏感实体,而其他研究表明这个比例可能要高得多。这就是为什么您需要纵深防御。这是一个分层的方法,包括技术保障、法律保障和组织保障、政策、访问控制。
所以,当您到达识别这些占位符之类的实体时,您实际上会怎么做?嗯,最佳实践是使用代理数据。所以,例如,Daniel Walsh 翻译成 Toby Elliot,或者这个日期翻译成那个日期。因为您有一个映射,您可以在向用户呈现答案时反转该过程。所以,这个句子,例如,“Sarah Mitchell 来自这家公司,在那个日期联系了关于发票的事”,翻译成这些占位符。例如,Presidio 库的所有层都能识别它。然后您可以使用 Python 中的 faker 库来生成代理数据。所以,您可以生成假的姓名和公司,然后将其输入到 LLM。研究表明,这可以从 LLM 生成更好的响应,因为它可以看到这是一个连贯的句子。而这只是一个带有空白占位符的抽象句子,可能会导致 LLM 输出不佳。
所以,主要的流程基本上是用户提出一个问题。它会经过匿名化层。它会分配代理,将其保存到注册表中,然后使用修改后的消息命中云端 LLM,然后它会通过另一个过程来去匿名化或重新识别占位符或代理,然后生成对用户的响应。
但事情会变得相当复杂。所以,这里只是一个标准的工具调用。例如,消息进来,它被匿名化,命中云端 LLM,假设它想触发向量搜索。所以,它将使用代理名称来运行查询。所以,它会将其传回应用程序。我们需要插入真实姓名,运行搜索,然后再次进行实体提取、实体解析,并将修改后的块发送回 LLM 进行推理,以再次生成我们需要更新的响应。
当您有多个工具调用时,这会变得相当复杂。这里我们有向量搜索和文本到 SQL。而实体解析确实很难。我将给您举个例子。在一篇描述我的文章中,例如,我可能在文章中被称为许多名字。Daniel Walsh、D. Walsh、Mr. Daniel Walsh、Dan Walsh。如果没有实体解析,仅仅通过 Faker 库生成名字,文本中识别出的每个人都会被赋予一个随机的名字。所以,通过实体解析,至少,我们将能够将其分配给同一个名字,同一个代理。甚至更好的是创建它的变体,类似于左边的。但这非常困难,在某种程度上需要 LLM 来完成。
还有我们系统提示中的反转问题,对于我们的云端 LLM。我们要求它打印它收到的确切代理形式。这样,我们就可以在输出给用户之前正确地重新识别并替换正确的数值。这确实将其引向了正确的方向。它解决了许多关于尝试识别返回的名字的问题。
但是,还有其他类型的问题需要推理或计算,这些问题根本不适用于这种代理值。例如,日期计算。这张发票逾期多少天?如果您将真实日期与虚假日期进行交换,您显然会得到错误的答案。或者财务计算,这张发票总额的增值税是多少?如果您对发票中的所有项目都有代理值,它永远不会得到正确答案。位置推理,送货地址离我们的仓库有多远?如果送货地址已更改,那显然是错误的。所以,这些是这种方法的真正局限性。
在我们开始讨论架构之前,我只想说,如果您觉得这个视频有用或有帮助,请在下方点赞,并确保订阅以观看我们本系列的下一个视频。这真的对我们很有帮助。
这是我们解决方案的最终架构版本。在深入研究之前,我想谈谈我实际上是如何构建它的。一开始我并没有一个完整的关于这个架构将如何工作的心理模型。您将在几分钟内看到构建过程。我最初与 Claude Code 进行了一个头脑风暴阶段,试图弄清楚我们到底在构建什么,结果发现第一阶段的版本根本行不通。它过于复杂,它很混乱。我肯定也没有让事情变得更好。但 Claude Code 的好处在于,您可以边构建边进行测试和原型设计。我的第一个版本没有成功,但我需要经历这个过程才能达到最终成功的版本。所以,如果您正在使用附带的 PRD 进行构建,您的体验将与您在此视频中看到的体验不同,因为该 PRD 反映了最终版本,它确实有效。但正如您将看到的,它确实是一个非常有趣的构建过程。
所以,这个架构看起来是这样的。我们有用户输入的原始文本。这是我们之前讨论过的句子。它通过 Microsoft Presidio 进行实体识别。所以,它能够识别文本中的敏感实体,正如您在那里看到的。然后,我们在这一点上将其分成两条不同的路径。
第一条是硬编辑路径。所以,类似于之前的演示,有一些实体我想要硬编辑。信用卡号、社会安全号码、健康保险号码。所以,它会经过这个流程,Presidio 库会为它识别的任何实体插入占位符。但然后我还有另一个本地 LLM 调用,我将其用作安全网,因为 Presidio 无法捕捉所有内容。所以,它会将编辑后的文本传递给它,看看是否需要进行任何其他硬编辑,如果有,它会将其从文本中删除,然后将其呈现给用户。
在另一条路径上,这些是我们想要匿名化但希望可逆的实体。所以,我们想创建代理。所以,一旦识别出实体,它就会进入 faker 库来生成代理名称。同样,那个例子,如果一个人的名字以多种不同的变体出现,他们都会得到不同的代理值。所以,从这里开始,我们经过实体解析或聚类过程。我构建了两个版本。我构建了一个本地 LLM 版本,我们使用 Quinn 380 亿模型,并询问文本中列出的哪些实体实际上是同一个真实世界的实体。还有一个算法版本,它基于昵称库、标准缩写等进行聚类。所以,通过其中一种方式,我们最终能够识别和聚类正确的个人。这对于名字来说确实非常重要,比其他任何事情都重要。
所以,一旦实体被解析,我们就进行替换过程。然后我们将这些实体、这些映射保存到 Superbase 的注册表中。该注册表是线程特定的。它是对话特定的。您将在视频后面看到,最初我选择了创建一个全局注册表,这是没有意义的。它永远不会奏效。我不知道我在想什么。但有了完整的解决方案,它是线程特定的,我认为这更有意义。一旦它们被替换,并且硬编辑也到位,新的文本就会像您在那里看到的那样提供给云端 LLM。
这就是架构的概览以及整个 Web 应用程序的当前状态。我们构建了一个具有 React 前端和 Python 后端的应用程序。它使用 Superbase,我已将其本地部署。其他人可能会使用远程版本,但它将其用作 PostgreSQL 数据库,但也用于存储桶、存储、身份验证等。然后前端有一个 VIT 开发服务器。后端有一个 UVORN 后端服务器,然后所有这些都提供给 Web 浏览器。您将在视频中看到我使用本地 LLM。所以,我在这里的服务器上运行 LM Studio。我拥有 Quinn 380 亿。我拥有 Quinn3 0.60 亿嵌入模型。所有这些都是本地的。对于云模型,我使用 OpenRouter 和 Claude Haiku,但您实际上可以使用任何模型。
好的,让我们开始实际的构建。希望您喜欢这次旅程。
好的,要启用这些实验性的代理团队,我们只需要设置一个环境变量。嗯,我在这里 Cloud 文件夹下的 settings.json 文件中进行设置。现在我正在使用危险权限命令运行 Claude。我已经在虚拟机管理程序上设置了一个虚拟机,所以我已经从文件系统的角度将其锁定。它对互联网有开放的访问权限。所以,它不是 100% 安全的。但同时,这个应用程序中没有敏感数据。代码库本身没有什么真正敏感的。所以,如果出于任何原因,您知道,Claude 被提示注入并压缩了整个目录并将其发送到别处。这真的不是世界末日。所以,我可以在我的设置中运行危险的跳过权限。当然,我也不建议您使用它,除非您知道自己在做什么,并且您了解运行它的后果。
酷。所以,在 Claude Code Agent Teams 文档中,他们说如果您是代理团队的新手,您应该从一个边界清晰、不需要编写代码的任务开始,他们推荐研究任务。而且我们无论如何都需要对我们正在构建的编辑系统进行研究。我想在这个代理 RAG 应用程序中创建一个编辑系统。所以,在这个应用程序中,我们有一个知识库,我们可以上传文档,我们还有一个代理聊天屏幕,人们可以与 LLM 聊天,然后它可以遍历或搜索这些文档来输出响应。代理还可以访问 SQL 工具来查询数据库。所以,编辑系统应该在多个领域工作。在摄入时,它应该在创建嵌入时进行编辑,或者对于 SQL 查询,SQL 查询的结果应该被编辑。这样,发送给模型的内容始终是匿名的。但然后我们也需要一种方法来反转这一点。所以,当我们从代理在屏幕上输出文本时,例如,我们需要将代理数据换回真实数据。我想为此使用 Microsoft Presidio,它似乎是这种编辑最流行的开源平台。然而,这个库没有一个可以实际存储代理数据及其映射到真实数据的保险库的概念。您能启动一个代理团队来处理这项研究吗?我希望团队中的一名成员研究 Microsoft Presidio,看看这个库,了解它是如何工作的,然后我希望另一名研究代理审查我们这个应用程序的当前架构,并找出我们需要更改的接触点,以便这个编辑系统能够真正工作。例如,摄入文档,确保它们在摄入时被匿名化,理解代理工具,因为如果它命中第三方 SQL 表或 API,我们如何作为它与 LLM 之间的接口进行匿名化?然后我们如何反转这一切?如果我遗漏了其他任何东西,如果我们还需要其他研究代理,请告诉我。
所以,我刚刚复制了它。是的,它很高兴与这三个研究代理一起工作。而且,这会消耗令牌。我们在 60 秒内就达到了 112,000 个令牌。现在,我使用的是最高计划,所以我应该没问题。而且我没有在这里设置 T-Mook。我在 Windows 上,所以我实际上看不到所有这些研究人员在做什么。但我们可以看看各种不同的研究人员,看看发生了什么。所以,架构研究人员,我当然可以给他发消息。所以,这正在探索项目结构并弄清楚发生了什么。所以,我们的 Langchain 研究人员已经完成。任务一和任务三仍在进行中。所以,让我们来看看其中一个。让我们去我们的 Presidio 研究人员。所以,它进行了一些网络搜索。有趣的是,它实际上没有克隆项目,而 Langchain 研究人员确实克隆了项目。所以,让我们回到团队负责人。我们的 Langchain 研究人员已经优雅地关闭了,现在协调员或团队负责人正在给子代理发送消息以检查他们的状态。太好了。所以,所有三个研究人员都已完成。他们已经生成了报告,这些报告现在在 agent 下面的 research 文件夹中。我们这里有一个小总结。所以,对于 Microsoft Presidio 30 多个 PII 实体类型。所以,Langchain 的保险库模式。它是一个保险库,一个简单的嵌套字典,然后是的,Faker 生成类型适当的代理。酷。这样,是的,我们得到假的姓名或假的电子邮件或假的电话号码,而不是简单的占位符。然后是关于模糊匹配的一些内容,我认为这会很麻烦。架构接触点。所以,识别了 21 个接触点,12 个高优先级,3 个中优先级,6 个低优先级摄入、聊天工具、流式传输。哦,是的,流式传输将是一个问题。我们需要提前处理流式传输并设置某种代理。我认为聊天界面将逐个令牌地输出。所以,我们基本上需要缓冲它。所以,让我看看完整的文档。而且它们并不缺乏细节。三份文件之间大约有 2000 字。所以,我需要花些时间阅读这些。Presidio 库的研究看起来相当彻底。它与我在各种可用文档中阅读的内容大部分相同。无论如何,Langchain 研究文档很有趣,因为它是我自己没有找到的东西。所以,端到端的流程,它是如何工作的,以及保险库的保存和查找发生在哪里。然后是架构接触点。所以,我们需要修改我们的摄入管道。所以,这很好。是的,在提取元数据之前进行匿名化。在嵌入之前进行匿名化。我们将匿名化内容也存储在完整的 markdown 中。然后我们有 PII 到令牌映射保险库存储。好的,我很高兴继续。所以,让我们来处理我们的架构决策。正如您所看到的,我使用的是 vanilla Claude Code。在上一期视频中,我们使用了 GSD 框架。我今天特意不使用它,因为我想测试代理团队。
好的,现在我们有一些问题需要回答。所以,嵌入应该从原始文本还是匿名化文本生成?所以,让我们选择匿名化文本。双重存储是有好处的。这样您就可以看到哪些已被匿名化,哪些没有。而且我相信某些法规要求您能够对其进行审计。目前,我们只使用嵌入匿名化文本,以免过于复杂。
PII 保险库的范围应该是多少?这决定了同一个人在不同文档中是否会获得相同的占位符。我们是为每个文档和每个线程进行代理数据,还是只是为我们应用程序内的每个用户进行,还是全局的?在某种程度上,我认为全局可能是有意义的,因为如果您在一个文档中有一个特定的名字,并且同一个名字也来自 SQL 查询,我们应该能够为这个名字使用相同的占位符。同样,如果有人在前台提出一个涉及该名字的问题,我们需要能够插入该占位符。这是一个关键的架构决策。我认为一个单一的全局保险库在这里最有意义。
我与 Claude 就这个架构进行了长时间的来回讨论。它试图让事情过于复杂。我认为它有点混淆了授权和实际的匿名化。而且我们已经内置了授权。有角色级别的安全性,所以登录的用户只能看到他们自己的文档。现在可以有全局共享文档,这就是很多混淆的来源。所以,我认为这没问题,如果在测试中我发现了一些问题,我们可能会再次回顾它。
助手响应是否应该以去匿名化形式存储,即真实姓名在聊天历史数据库中被匿名化?这是一个非常好的问题。理论上,在聊天历史数据库中保留真实姓名是可以的,除非您继续进行对话,我们将把线程发送给 LLM。所以,在某种程度上,它必须是占位符。我认为实际上,我们需要将占位符存储在聊天历史数据库中,因为如果我们继续与 LLM 进行对话线程,数据将从历史表中提取并注入到实际的调用中。然而,重要的是,从前端的角度来看,用户看到的是真实姓名。所以,更多的是在视图方面,当我们实际从聊天历史表中提取数据以通过 API 呈现时,比如说,从后端到前端,我们需要进行交换,这样用户只会看到真实姓名,而 LLM 只会看到匿名化姓名。
好的,我认为它对此很满意。它简化了架构。它声称在数据库中存储匿名化数据,即占位符。我们在提供聊天历史时在 API 层进行去匿名化,这是有道理的。
文件名和元数据中的 PII 是否应该被匿名化?比如,事情变得棘手,因为块元数据和文件名路径对 LLM 是可见的。所以,可以说您必须对其进行匿名化。我可能会暂时跳过它,因为它只会增加复杂性。这是第二阶段,正如它所说的,例如 John Smith contract.pdf。让我们推迟到稍后阶段,让我们只专注于实际的核心数据来回传递。我们控制着元数据,所以我们可以确保,例如,在提取元数据时,我们不提取 PII。
好的,它对此很满意,并询问我是否准备好制定实施计划?我将提示它提出更多问题,因为我认为我们还没有完全弄清楚。我们在上下文方面还可以。我们在这里是 43%。所以,一旦它超过 50%,我们可能会考虑完成这个过程。
代理占位符值的格式应该是怎样的?这会影响 LLM 对文本的推理能力。是的。所以,绝对是逼真的假数据,通过 faker。系统应该检测和匿名化哪些 PII 实体类型?Presidio 支持 30 多种类型。更多的类型意味着更强的隐私,但更具侵略性的编辑可能会对非 PII 文本产生误报。所以,我们可以选择核心 PII、核心加财务、医疗,以及它们支持的所有内容,包括地点和国籍以及日期,可根据部署进行配置。让我们选择核心加财务医疗。
用户消息应该以什么格式存储在数据库中?用户输入真实姓名。例如,John Smith 对合同说了什么?存储原始,即时匿名化,还是存储匿名化?这与我几分钟前问过的聊天历史问题类似。我需要考虑这个架构。我不需要数据库完全没有 PII。我只需要确保 LLM 无法访问任何 PII,例如,因为您想要对块嵌入进行文本匿名化的原因是不想将您的原始敏感文本发送到云端。所以,这与实际的聊天历史是不同的用例,因为基本上任何 API 调用都会包含敏感数据。任何 SQL 查询都会包含敏感数据。所以,在数据库中拥有这些信息是可以的。
好的,我认为我对此很满意。所以,数据库中的 PII 完全没问题。硬性规定是 PII 永远不会到达 LLM 或任何外部服务。现在它也询问文档块。所以,嵌入必须基于匿名化文本。所以,考虑到这一点,也许我们应该两者都做。也许我们应该存储匿名化版本。这样,当检索到 LLM 上下文时,它就没问题了,但同时也要存储原始版本。它永远不会发送给 LLM,但我们可以实际看到什么被匿名化了。我认为我们确实需要这个,即使只是为了调试目的,看看它是否真的有效。所以,进行这种头脑风暴和来回讨论非常重要。就像我本人也不完全确定架构一样。所以,把它阐述清楚是好的。
编辑系统应该一直开启吗?我认为我们将回答“是”,它一直开启。我认为从系列的角度来看,我们可能会在此基础上分叉该库,因为我知道很多人不需要这种级别的安全性和编辑,它只会给代码库带来很多膨胀和大量的条件逻辑。
那么,对于在编辑系统存在之前已经摄入的文档怎么办?这不会发生。从一个全新的知识库开始,再次,没有必要过度复杂化。SQL 工具查询包含真实 PII 的真实数据库表,例如销售数据。当 LLM 使用假名生成 SQL 查询时。啊,是的,在执行之前,我们需要将其换回真实姓名。但 SQL 表是外部的。我们无法匿名化实际的数据库。我们应该如何处理?所以,是的,在执行之前,将假名换回 SQL 查询中的真实姓名。然后,在返回给 LLM 之前,对结果集进行匿名化。真实的数据库保持不变。我认为这必须是这样。对于任何 API 调用也必须如此。而这确实是事情变得复杂的地方。
LLM 通过 SSE 以小文本块流式传输响应。像 Noah Ross 这样的假名可能会跨越多个块。在发送到前端之前,我们需要进行去匿名化。我们应该如何处理?缓冲并检测。当用户输入包含真实 PII 的消息时,例如“John Smith 说了什么?”。在发送给 LLM 之前,我们会对其进行匿名化。但是,用户应该在聊天 UI 中看到他们原始的消息还是匿名化版本?显然是原始消息。
是否应该有任何 UI 可视化编辑系统?不,它必须完全不可见。例如,我们将通过 Langfuse 进行查看,以确保它确实有效。也许作为第二阶段,我们可以构建某种管理员面板,您可以在其中查看和了解哪些内容已被匿名化和去匿名化。但目前,是的,将 UI 推迟到稍后阶段。
LLM 有时可能会产生幻觉或修改它给出的假名。Noah Roads 变成 N Roads 或 Mr. Roads。Langchain 使用模糊匹配 Levin 距离进行去匿名化来处理这个问题。我们应该实施模糊匹配吗?我认为我们确实需要。是的,我认为我们绝对需要。
好的,这是完成的摘要。我将再次问这个问题。我将要求它深入研究。我们将再进行一轮提问,然后我们就可以开始了。所以,实体匹配很棘手。当 John Smith 出现在文档 A 中,而 John Smith 出现在文档 B 中时,系统应该将它们视为相同的实体,相同的假名或代理吗?像 J. Smith、John Smith、John A. Smith 这样的变体呢?我认为它只能是相同的字符串映射到相同的代理。John Smith 与 J.Smith 不同。我们不是要为每个名字创建一个唯一的 ID。我们只是想确保这些信息不会到达 LLM。所以,我们基本上没有创建配置文件。它只是键值对。Faker 可以生成一个与保险库中已有的真实实体发生冲突的名字。例如,Faker 生成 Jane Doe 作为代理,但 Jane Doe 是一个真人。这是一个真正的问题。是的,我认为在签名之前我们会检查保险库,以避免冲突。从 Faker 文档来看,他们说要警惕生日悖论,即冲突的可能性比您想象的要大得多。所以,您需要围绕它进行设计。
文档是否仅限于英语,还是可能包含多语言文档?目前我们选择英语。我回到关于实体匹配的问题。John Smith 出现在文档 A 中,然后是 J.Smith、John A. Smith。问题是,如果它们都是完全不同的名字,如果它们都是完全不同的占位符,那么这可能会让 LLM 感到困惑。就像这显然是同一个人。John A. Smith。如果它们都在一个段落的上下文中,如果它引用了 John Smith、J.Smith 和 John A. Smith,那么他们谈论的是同一个人很有可能。而如果这些是完全不同的名字,那么在 LLM 生成响应时,您将失去所有意义。我可能会要求它回到这个问题。
Presidio 使用任何模型进行实体检测吗?主要选项会影响准确性与速度。什么最重要?让我们选择最准确的模型,即 Transformer 模型。我有一个不错的显卡可以用来做这个。文档中是否有任何特定领域的实体类型是它无法开箱即用的?没有。如果 Presidio 错误地将某物识别为 PII,会发生什么?例如,如果它将 Paris 识别为人名而不是城市,或者将看起来像电话号码的产品代码识别为人名。我认为我们只能接受并继续处理。有一个我们可以调整以减少它的置信度阈值,但我们永远无法达到 100%。
所以,我们拥有的子代理可以进行自己的 LLM 调用,并进行自己的流式传输。它们当然需要访问保险库。这应该与主代理调用共享相同的匿名化上下文吗?是的。
好的,所有这些都完成了。我只是要求它回到那个问题。我的担忧是,这将过于严格,我们只会得到不同的代理。是的。所有这些选项都不是很好。它只是大大增加了复杂性。我认为这可能是 LLM 编辑模型也会好得多的地方。目前,让我们只进行不区分大小写的匹配,也许以后会更智能。
好的,就是这样。让我们继续实施计划。我将在这里描述我们将如何使用 Claude Agent Teams 来实际构建这个功能集。所以,如果有任何共同的功能,比如说数据库模式,所有子代理都将依赖于此,我宁愿提前完成,然后如果有什么可以并行进行的话,至少我们有一个坚实的基础。我们不希望子代理都试图创建数据库表或只是产生幻觉的结构。所以,我们希望所有共同点都提前构建好,然后在此之后进行并行处理。
好的,它将写出计划。我意识到我们已经使用了 50% 的上下文窗口。所以,希望它不会产生太多幻觉。哦,酷,我可以看到下一个计划是第 15 号。所以,PII 编辑系统。好的。所以,我们已经写好了计划。PII 编辑系统。这是一个复杂的多阶段构建,具有 Claude Agent Teams 的基础和并行执行流。所以,我们将使用 Microsoft Presidio 来实施该计划。确保真实 PII 永远不会到达 LLM 或外部 API 服务。使用 Faker 库生成逼真的假值,并使用全局保险库进行可逆匿名化。去匿名化发生在 API 层,数据提供给前端之前。优秀。核心原则是,用户看到真实数据。数据库存储真实数据。LLM 看到假数据。完美。
所以,我们还可以做的一件事是加密 PII 保险库中的值。所以,我认为这取决于数据。如果它们是信用卡号,例如,它们不应该以明文形式存储在 PostgreSQL 表中。它们肯定应该被加密。如果是一个名字和一个姓氏,它可能不需要加密。但重要的是它不会离开防火墙到达 LLM。所以,对于这一点,我将把加密留给第二阶段,但我认为这取决于您保存的数据类型以及它有多敏感。
所以,关键数据流,摄入,上传文件,提取文本,匿名化,两者都存储,这没问题。从匿名化文本创建嵌入,持久化保险库映射。然后聊天用户消息从数据库加载。即时匿名化用户消息。检索的块已经包含匿名化内容。将它们发送给 LLM。这很好。这一切都进行得很顺利。LLM 使用假名生成工具调用。SQL 去匿名化查询,执行,然后匿名化结果并返回给 LLM,等等。网络搜索。我完全忘了这是一个工具。我可能会删除它,因为对于这种锁定系统,我无法想象我们甚至会使用网络搜索作为工具。所以我将删除它。
所以,零阶段是建立基础,然后第一阶段是并行集成流。所以,它们都将使用零阶段构建的这个编辑服务,然后我们将使用我们的代理团队来完成。所以,流 A 是摄入管道集成。流 B 是聊天和流式传输集成。流 C 是工具集成。
好的,我认为我们准备好了。我在一个单独的分支上。所以,让我们清除会话。让我们开始构建零阶段。所以,我没有要求代理团队,所以它不一定需要启动一个,即使它被启用为环境变量。在它工作的时候,让我们启动我们的服务,以便我们可以跟踪进度。而且我还需要 Docker 运行。
好的,本地主机已启动并运行。所以,至少现在 Claude 可以与实际应用程序进行验证。
好的,零阶段基础已完成。嗯,我们已经添加了依赖项。我看到它下载了 spaCy 库。编辑服务现在已就位,就是这个。我们还为编辑服务创建了后端测试,这很棒。我们确实需要进一步扩展这个测试套件。然后数据库现在有了 PII 保险库表,并且我们已将这些列添加到 chunks 表中。所以,让我们看看它们。我认为我们在端口 8000,这是 chunks 表。匿名化内容在那里。是的。这是 PII 保险库。所以,我们有实体类型、原始值、代理值、规范化键,以及一个创建时间戳。优秀。到目前为止非常满意。这进行得很顺利。所以,希望第二阶段也能顺利进行,使用我们的代理团队。所以,我将清除会话,因为我们已经占用了上下文窗口的 50%。所以,事情变得有点紧张。所以,这是计划号 22。我重命名了它。所以,让我们启动我们的代理团队来构建这个计划的第一阶段。我真的应该安装 team,这样我们就可以看到不同的代理实际运行,而无需在它们之间跳转。
好的,编排正在开始。所以,流 A 摄入管道 PII 集成,与此同时,让我们删除系统中的数据,因为我们说过我们不会使事物向后兼容。所以,让我们删除文档。我们现在有三个代理并行运行。所以,这是流 A 摄入,它正在启动其余两个代理。让我们看看流 A 摄入,它已经开始进行更改,这是我们的第二个代理,我们的聊天代理。让我们看看他,看看发生了什么。酷。所以,您是 PII 编辑阶段一团队的队友。您的名字是 Stream B Chat,这是提供的任务,并且已经启动。所以,我们现在有了 Stream C,我们的工具。所以,又一个队友,有一个详细的计划,并且也在取得进展。所以,让我们回到我们的团队负责人。所以,流 A 已经完成,在它工作的时候,让我们启动另一个 Claude 会话。实际上,我有一个在这里。我正在为我的代理 RAG 应用程序构建一个完整的编辑系统。我需要测试数据来实际验证功能集。您能创建像记事本文件这样的东西,供我们用于摄入,并确保这些文件包含 PII 信息、信用卡号、护照号、Microsoft Presidio 在使用编辑时查找的任何内容,并具有许多不同的变体,名字、姓氏、缩写等。然后,您还能创建一个数据库表的合成测试套件吗?我们将将其连接到代理,看看我们的编辑实际上是如何工作的。请将所有这些放入 test-files 文件夹。
好的,它正在运行。而且,实际上,所有流都已完成,这真是太不可思议了。它是否要求我重新启动后端并运行验证,或者继续做其他事情?我希望它进行验证,因为您确实需要一个计划、构建和验证的周期。话虽如此,我们已经占用了上下文窗口的 80%。所以,我只是告诉它我将结束会话,并询问,您能否创建一个非常小的文件来引导下一个代理?
好的,交接已完成。让我们看看它,以确保下一个代理知道他在做什么。所以,让我们清除这个会话。我们的合成数据已准备就绪。所以,我将把所有这些复制出来。所以,我说我们准备好接手上一个代理留下的工作。所以,请看交接文件。另外,这是我们可以用来验证功能的测试套件。所以,它正在运行单元测试套件。正如您在这里看到的,这是我们的 test_redaction_service.py。所以,现在我们可以开始进行端到端测试了。所以,它正在为我们上传测试数据。我们有我们的测试员工目录,包含姓名、电话号码、出生日期、护照号码、驾照、薪资号码、银行账号、IBAN、信用卡号。是的。好的。好的,我认为这并不完全代表数据的存储方式,但无论如何,对于测试来说是好的。然后我们有客户记录,包含类似的敏感信息。所以,它已经开始进行端到端测试了。它没有使用子代理,也没有使用代理团队。所以,它已经上传了文档,我们可以在那里看到,我们也可以看到块。所以,我们有匿名化内容,也有实际内容。所以,姓名已被匿名化,电子邮件地址。让我们检查一下保险库。是的。PII 保险库。酷。看看这个。所以,我们有原始值、代理值、规范化名称。是的。所以,这是我们在规划阶段讨论过的区分大小写的匹配。然后我们有实体类型。所以,地点、人物、SSN、电子邮件地址。所以,保险库已填充。现在它正在检查聊天端到端。所以,我当然会自己进行端到端测试,并检查它实际生成的代码,但很高兴看到它自己进行验证。好的。而且 SSC 解析存在问题。在某种程度上,我宁愿它不尝试自己修复这些东西。如果它只是创建一个我们可以独立处理的错误列表,因为我们的上下文窗口正在填满,我们可以
拥有多个子代理在每个单独的错误上运行。例如,这是文档,在创建合成数据的另一个 Claude 会话中,我会要求它创建一些我可以用来测试功能的提示。好的。好的。我将停止另一个会话,然后我将只要求它,呃,不要试图修复问题。只需创建一个我们可以单独处理的错误列表。好的。然后我们现在有了我们的 redaction 测试提示,它们在这里。所以,再说一遍,这是我们端到端测试套件的一小部分。所以,我会要求它更新我们的交接文档,以便我们可以让另一个代理加入。所以,有四个错误需要我们处理。让我们清除我们的会话。让我们把这个文件拖回来。然后我会问,你能启动多个通用子代理来处理这些错误吗?所以,让我们尽可能地并行化,以便尽快完成。很酷。所以,它将并行启动三个代理。有兴趣看看它是否使用子代理或代理团队。所以,让我们看看。是的,它已经启动了子代理。我们没有主要的任务协调代理。所以,我们可以看到一个已经消耗了 63,000 个 token。那个 48,000。这个 34,000。所以,它是一个 token 密集型的。是的。是的。所以,看起来代理一已经完成。好的,代理二也完成了。它找到了并修复了四个错误。好的,全部完成。下一步,让我们重新启动后端。所以,让我们这样做。所以,我们将重新启动所有内容,然后进行测试。所以,现在我们如何进行测试?通常,我们会使用 Langsmith。显然,Langsmith 不是本地的。我们可以使用 Langfuse。不过,我还没有在服务器上设置它。为了这个目的,让我们只使用 Langsmith。但是,如果我们显然在使用实际的真实世界敏感数据,您不一定会将内容保存到 Langsmith 的跟踪中。但我们暂时只使用它。好的。所以,这是 Langsmith。现在,如果我们问一个问题,让我回到我的虚拟机。玛格丽特·汤普森的电话号码和电子邮件地址是什么?让我们从那里开始。好的。所以,它已经进入文档搜索。它找不到搜索结果中的玛格丽特·汤普森。好的。让我们实际弄清楚这里发生了什么。所以,这些信息在哪里?所以,玛格丽特·汤普森在其中一个文件中。客户投诉。ext Acme Technologies 包括员工记录。所以,这是我们的消息。玛格丽特·汤普森的电话号码是多少?实际上发生的是,它发送了诺玛·菲舍尔的电话号码和卡罗尔·李的地址。所以我认为它将电子邮件替换为卡罗尔·李,并将玛格丽特·汤普森替换为诺玛·菲舍尔,而诺玛·菲舍尔就在那里。啊,玛格丽特·汤普森,当然,这是原始值。好的。所以,所以这条消息被发送了。然后它被添加到保险库。创建了一个代理,诺玛·菲舍尔,然后发送了。然而,玛格丽特·汤普森似乎还没有在这个数据库中。哦,不,她有。这是玛格丽特·汤普森。是的。所以,这是这些系统中的实体解析挑战。所以,我们有玛吉·汤普森,玛格丽特·埃莉诺·汤普森,玛格丽特·汤普森,以及玛格丽特·汤普森的。然后还有一个电子邮件地址。好的,所以这其中的一些元素正在起作用,但有一个更根本的问题。所以,它正确地将这种个人姓名替换为代理。所以,诺玛·菲舍尔,你可以在那里看到它。无论出于何种原因,它都会删除电子邮件并插入卡罗尔·李。所以,我们会再次解决这个问题。但更大的问题是,玛格丽特·汤普森,她在这个我们上传的文档中。所以,这是 PII 记录。你可以看到她名字有很多变体。玛格丽特·埃莉诺·汤普森。玛吉·汤普森。玛格丽特·汤普森在电子邮件地址中。玛吉在这里提到。M.Th Thompson 在那里。有很多描述这个实体的方式,而系统在将其解析为单个实体方面遇到了很多麻烦。所以,如果我们看看这里,你可以看到玛吉是布莱恩·霍夫曼。玛吉·汤普森是迈克尔·威尔逊。玛格丽特·埃莉诺·汤普森是丹尼尔·威廉姆斯。玛格丽特·汤普森是罗纳德·加西亚。玛格丽特·汤普森的是诺玛·菲舍尔。你拥有所有这些代理值,并且你完全失去了对这个实际人物是谁的连贯性。所以,用这种方法不可能输出一个准确的答案。所以,我将把这个问题扔回给 Claude,让他分析代码库,看看它是否可以进行任何调整,或者这是 Microsoft Presidio 库中实际模型的根本限制。为此,我将只使用计划模式,因为我不想让它立即进行任何代码更改。我们确实有本地 LLM,我仍然认为在这里的解决方案可能是使用本地 LLM 来进行某种实体解析。例如,我们在 graph rag 中使用它,其中 LLM 实际上提取实体和关系。所以,使用本地 LLM 是绝对可能的。这肯定会减慢速度,但我们可能会获得更好的结果,而且我只是想看看我们是否尽可能地利用了 Microsoft Presidio 的开箱即用功能。是的。正如它所说,这不是一个错误。嗯,所以我们需要实体规范化或实体链接之类的东西,而且我们确实有一个本地 LLM。所以,我们能用本地 LLM 来帮助解决这个问题吗?所以,我认为我能描述这个问题的最好方式是,它是一个不连贯的混乱,根本不起作用。所以,我认为我们可能需要稍微改变一下架构,以及其他一些事情。我将使用这个例子。所以,玛格丽特·汤普森的电话号码是多少?现在,我们的知识库中只有一个文件,那就是这个员工记录文件。玛格丽特·汤普森。在这个员工文件中,你可以看到她名字有很多变体。玛格丽特·埃伦或汤普森,首选姓名,玛吉·汤普森。我们在这里有玛吉。我们那里有 M. Thompson。但是,一个人可以有很多名字的变体。例如,汤普森小姐,汤普森夫人。所以,在我们这里的解决方案中实际发生的是,当这些数据被处理和摄取时,它会经过实体识别和匿名化阶段。所以,如果我们打开匿名化的完整 markdown,你可以看到员工一,也就是玛格丽特·埃莉诺·汤普森,全名安德鲁·古德,首选姓名芭芭拉·桑德斯,米歇尔·布朗是电子邮件地址。所以,我们有一些名字的痕迹。玛吉现在是特里·威尔斯。加里·普尔在这里提到。所以,这绝对是一团糟。文本中完全缺乏连贯性。难怪 Adam 不知道该怎么处理。这只是在匿名化然后反匿名化信息方面的一个主要问题。我们需要能够使用一致的标准占位符。所有这些引用实际上是同一个人。正如你在这里看到的。所以,我们这里的系统正在发生什么,让我们把它复制出来。让我们把它带到 hugging face 上的 Microsoft Presidio 演示中,然后让我们选择突出显示并粘贴进去。在这里,我们可以看到它正在识别实体。这是一个实体。这是一个实体。所以,这些是名字。罗伯特·汤普森是一个紧急联系人姓名。MT Thompson Maggie。所以,这些人都是。所以,Presidio 通过 spacey 库或 reax 模式等准确地提取实体。但问题是我们正在使用我们的 faker 库来插入代理名称。而这个系统不够复杂。我们基本上需要将其发送到本地 LLM 来识别这些人是相同的,并且这些都是相同的引用。而这只是这种可逆匿名化过程的一个主要限制,特别是当你处理这种类型的自由文本时,因为文本可以以任何形式出现,而 LLM 也会以任何形式生成它。所以,在某种程度上,你需要一个 LLM 来正确地映射这些实体,才能使其具有一定的连贯性。所以,我认为我们需要做的是将这些名字聚类起来。这样,我们就只为特定的实体提供一个 faker 名称。所以,玛格丽特或玛吉·汤普森将始终被引用为同一个 faker 名称。所以,这应该能稍微提高连贯性。例如,当你处理一个员工记录时,你不会得到五个或六个不同的名字,而实际上是同一个员工。而对于这种聚类,最好使用本地 LLM。所以,我们可能会启动这个项目的第二阶段,我们可能会考虑完全简化这个架构,因为它被过度设计了,而且我们正在使事情复杂化,因为我们有能力运行本地模型。也许我们最好只运行本地嵌入。这样,我们就无需走上匿名化文档块的道路。所以,我们只需要担心 LLM 和应用程序之间的接口。所以,当数据发送到 LLM 时,我们进行 redaction 和匿名化,当它返回时,我们进行反匿名化。所以,也许不是有一个全局保险库,让我们只保留一个对话保险库。本质上,它是一个实体映射的累积注册表。所以,随着对话线程的发展,我们会跟踪我们实际使用的化名,以便我们可以不断地替换它们。现在,在本地使用 LLM 绝对会增加这个应用程序的延迟。但我认为这种类型的匿名化只有在你处理非常结构化的输入时才真正有效。而我们在这里处理的是一个自然语言接口,任何人都可以对它说任何话。所以,我认为,我们需要某种本地 LLM。好的。所以,让我们和 Claude 聊聊,让我们来规划一下这些更改。我正在审阅初始阶段的产品需求文档,其中肯定有一些我们需要返工的元素。一方面,我可以从头开始,但这里有很多东西我们可以重用。为此,让我们实际使用计划模式,而不是编辑模式。我们希望对这个实现进行一些更改。我们可能已经大大地过度复杂化了它。我已经对其进行了端到端测试,而且我们采取的这种方法存在根本性问题。好的,所以,让我们让规划代理们开始工作吧。所以,它已经启动了三个子代理,而不是团队成员。所以,我们可以看到一个正在探索 PI redaction 系统。另一个正在检查摄取流程,另一个正在检查数据库模式。而且,根据你的用例,这种程度的本地 LLM 和本地嵌入模型集成。你可以完全隔离运行整个系统,具体取决于你的内部用户数量和所需的硬件。但是,对于更安全的实现,最好完全隔离运行。让我们看看我们在这里安装了哪些本地模型。让我们退出沙盒。 [鼻息声] 我有 lama 和 LM Studio,但也许我们只用 LM Studio。所以我有一个 Quinn 3。这些模型太大了。320 亿,200 亿。让我去模型库。我们想要一些快的。所以,Quinn 3。让我们试试 Quinn 3 80 亿模型。然后看看效果如何。它设置为 Q4,略高于 6GB。好的,它正在下载。所以,它正在询问哪个本地 LLM 基础设施。现在,我已经 [鼻息声] 设置好了。所以,这个应用程序已经集成了本地 LLM,用于这个原型。我们是否也应该在检索到的文档块发送到云 LLM 之前对其进行匿名化,还是只关注用户消息?首先,我们需要从用户消息中创建 Margaret Thompson 的实体。但如果我们在块中看到 Margaret Thompson,那也必须是同一个实体。所以,嗯,是的,两者都需要。好的。所以,我们有了计划。所以,我们有第一阶段数据库迁移。第二阶段从摄取管道中剥离匿名化。第三阶段重写或 redaction 服务。所以,很多清理工作。也许从头开始构建会更容易。然后我们有了本地 LLM 实体解析提示。所以,有文本或检测到的实体候选代理和现有注册表。好的。所以,我们只是在提示工程阶段。响应反匿名化提示也是如此。第二阶段和第三阶段可以并行进行。然后第四阶段、第五阶段和第六阶段可以并行进行。然后第七阶段,然后第九阶段。是的。让我们看看。我们的代理团队能否并行启动这些?我们将跟踪我们云文件夹中的 progress.md 文件中的进度。你能启动一个 Claude 代理团队来开始实施我们的新计划吗?这是计划的链接,并且只为初始阶段启动工作程序。另外,请在 PII reduction progress markdown 文件中跟踪进度。所以,我们可以使用这个来添加和删除代理,当我们用完上下文时。所以,我们的团队在这里进展顺利。工作程序一已经完成,工作程序二也完成了。所以,我们只是在等待工作程序三完成。好的,第一波完成。所有三个并行阶段都已完成。所以,第一阶段,数据库迁移已完成。我们已经从摄取流程中剥离了匿名化,重写了 redaction 服务,并清理了需求。现在我实际上没有太多可以测试的了。上下文窗口在这里是 39%,还可以。所以,让我们启动第二波。所以,我们的第二波有三个工作人员作为团队的一部分。所以,我们的团队负责人正在跟踪他们。但如果我们进入工作程序四,例如,你可以看到它已经完成了它的工作,然后它正在检查工作程序五。让我们进入工作程序六。它目前正在进行其任务。我真的很喜欢这种流程,这种代理团队协作和编排。我肯定需要安装 T-Ux 来关注它们在做什么,但拥有团队领导的想法很不错。在不做大规模审查的情况下,我将让它完成,然后让我们进行一些端到端测试。但我认为,我们向 Claude 指示,在我创建这个计划时,识别哪些元素可以并行完成与顺序完成,这一点非常重要。我们希望工作程序建立在坚实的基础上,如果存在共享资源、共享模块、数据库模式等。所以,到目前为止,这是一种相当好的方法。好的,所有单元测试都已通过。所以,让我们实际自己测试一下。所以,我们现在使用了本地 LLM 实体解析,用于 PII 实体解析。这太棒了。所以,让我们为 LLM 配置保留 Open Router。对于我们的嵌入配置,我们将使用本地嵌入模型。是的,我们已经安装了 Quinn 3 text embeddings。所以,让我们加载那个模型。所以,让我们选择 Quinn 3 80 亿模型。所以,让我们也加载它。这次的联系长度,比如说 80,000。然后对于本地 LLM,有基础 URL。然后我们的模型名称是这个。好的。所以,让我们保存更改。实际上,让我们只是用这个模型聊天,以确保它确实有效。好的。是的,那个模型相当快。每秒近 200 个 token。所以,应该没问题。所以,让我们从上传文档开始。所以,这是我们的员工记录。我们把它拖进去。现在它已经生成了元数据,这些元数据本应发送到 LLM。我们只想在这里测试 PII 检测。对 Margaret Thompson 这个名字进行向量搜索。所以,对 John John 的文档搜索。所以,它没有返回任何东西。所以,让我们进入文档。让我们看看发生了什么。所以,文档块确实包含 Margaret Thompson 或 Maggie Thompson。所以,我们应该从向量存储中得到一些东西。我可以看到 LLM 触发了搜索文档。它传递了 John John,这是代理名称,执行了工具调用。我可能会让 Claude 看看这个问题。我们可能需要更多的跟踪和调试。你能测试搜索文档工具的端到端流程吗?它对我来说工作不正常。所以,我们需要用查询来测试。我将粘贴完全相同的查询。使用后端 API 来加快速度。我还将要求它实现一个日志文件,以便我们可以实际在前端进行测试,然后打开日志文件,逐行查看具体发生了什么。好的,所以我们的日志已经到位,并且它已经能够重现问题。我在这里写了 hi,在我的上下文窗口里。所以,我将要求它记下这个错误,然后我会让另一个代理来处理它。好的,它声称已经修复了它。工具调用参数包含代理名称,因为 LLM 只看到了匿名化消息。在执行之前没有对工具参数应用反匿名化。是的,让我们自己测试一下。所以,它正在寻找 Lori Gomez。所以,向量搜索返回了员工记录文档的结果,其中名称 Margaret Thompson 不出现在搜索结果中。好的,让我们打开我们的日志。所以,在这种情况下,Margaret Thompson 是 Taylor Edwards。本地 LM 调用失败。错误 400。响应格式类型必须是 JSON、schema 或 text。好的,所以有问题。好的,让我们再试一次。所以,它正在寻找 Wayne King。我能听到风扇的声音。显然,由于内置了所有这些延迟,速度明显变慢了。但你看,它奏效了。向量搜索在你的知识库中找到了 Margaret Ellaner Thompson 的一个主要匹配项。Margaret Elellanar Thompson 在那个员工记录报告中,我们得到了所有信息。我很好奇到底发生了什么。所以,让我们看看 Wayne King。所以,这是 Wayne King 的第一次提及。此时,注册表中没有任何条目。所以,我们有一个特定的线程服务。所以,一旦生成了代理,也就是 Wayne King,它就调用了实体解析本地 LLM,JSON 对象不支持,所以它重试了,传递 JSON schema 会更好,它解析了一个映射,并将新映射持久化到数据库,是的,线程实体注册表,在那里,这是我们这个示例线程的线程 ID。所以,让我们按该 ID 进行过滤,我们在这次对话中有 68 个实体,第一个是 Margaret Thompson。所以,它被转换成了 Wayne King。太好了。看看这个。所以,现在 Wayne King 代表了所有这些实体。Margaret Thompson,Margaret Thompson 的电子邮件地址。所以我认为这可能有点过于热心,也许在它分配的方式上。所以,例如,如果我问她的电子邮件地址是什么?是的。根据文档,Margaret Eleanor Thompson 的电子邮件地址列为 Margaret Eleanor Thompson。我认为这有点像打地鼠,只是为了解决一些小问题。但我们确实在实现端到端工作,这太棒了。所以我只是说看看截图。看起来代理值跨越了实体边界,这没有意义。我问了她的电子邮件地址是什么,它不知道。好的,它声称已经修复了这个问题。她的电子邮件地址是什么?我们应该同时收到两个电子邮件地址。完美。给你,她的工作电子邮件和她的个人电子邮件。现在让我们检查一下 Langmith。这是问题。她的电子邮件地址是什么?这触发了搜索文档工具调用。让我搜索员工记录,查找 Brandon Nash 的电子邮件地址。这就是工具调用参数。Brandon Nash 电子邮件地址联系人。现在,工具调用的输出显示 Margaret Ellanar Thompson。所以,有数据泄露。但我确实想知道,这实际上是发送给 Anthropic 的,还是仅仅是 Langmith 能看到的?是的,这正是我所想的。所以,Langsmith 正在跟踪实际的执行层,而 Anthropic 在这种情况下只看到匿名化的对话层。所以,这是按设计工作的。我们无论如何都不会在生产中使用 Langsmith。它将是 Langfuse,它将自我托管在防火墙内。所以,那里没有问题。所以,让我们问这个问题,谁关闭了 Meridian Global 交易?据称是 Michael O'Brien。有趣。所以,它没有 redaction Meridian Global。根据搜索结果,Michael O'Brien 完成了交易。所以,那是正确的。所以,这是我们的跟踪。调用了搜索文档和查询销售数据库。根据搜索结果,Jeffrey Lewis 完成了交易。在这里,我们可以看到是 Michael O'Brien。所以,它被替换了。所以,是的,这实际上工作得相当好。所以,我只是暂停了录制,在过去的几个小时里,我做了大量的更改,大量的错误修复,性能改进,一些新功能。所以,让我们来回顾一下其中的一些,因为我们现在已经把它做得非常好了。我在这里的计划文件夹中跟踪了我所做的所有更改。所以我通常会进入计划模式和云代码。它会生成一个计划,然后我将其保存在这里。这有助于跟踪所有内容,而且,如果你只完成了一半的计划,你可以清除上下文窗口,然后粘贴计划说请继续。我做的第一个更改是为某些类型的实体引入了硬 redaction,例如信用卡号、护照号码等。然后第二件事是,到目前为止,我们一直使用 LLM 进行实体解析,但我想尝试一种更简单、更快、更确定的方法,即使用 reax 解析聚类算法。所以,即使它可能不像 LLM 那样复杂,但它可能稍微更可靠一些。所以,通过这个更改,我们现在有了类似的环境变量。第一个是实体解析模式。你可以选择 LLM 或算法,然后你可以列出你想要硬 redaction 的实体,以及你想要创建代理的实体,这样它们就是可逆的。所以,你可以在这里看到,例如,我们正在使用 LLM 解析,这与我做的下一个更改有关,那就是我想简化那个 LLM 调用,因为那个 LLM 调用对于一个小的 80 亿参数模型来说变得过于复杂了。所以,这个更改极大地简化了它。它剥离了所有与人无关的实体噪音,并使输出更加简单。只是一个简单的映射到集群。所以,让我们在这里用我们标准的提问来测试一下。我身后有 LM Studio。所以,你将能够看到实际的调用。所以,我们将问我们标准的提问,你可以看到它正在处理提示,生成嵌入,生成 token,并且你可以看到日志流。而且速度相当快。由于输入和输出的简化,速度比以前快多了。而且我们得到了准确的响应。所以我更改了系统提示,并引导 Claude LLM 确保在输出人物、地点或日期时,它与实际收到的内容保持一致,以便我们能够进行一致的反匿名化。这就是我们在 Margaret Elellanar Trainer 上发现的,我们得到了首选姓名。这里的一切现在都是准确的。让我们要求它检索她的完整雇佣记录。所以,它正在进行多次文档搜索。我更新了它,以便我们现在在工具调用中看到原始名称,而不是代理名称。同样,你可以看到本地模型正在启动。我们现在正在进行 grep 和 glob,因为我们能够实际导航知识库。现在,我做的另一个更改是让它在系统内的子代理中也起作用。所以,再次,如果我们全屏显示,你可以看到这是子代理的思考过程,或者至少是子代理的输出,并且它与最终输出相关联,但重要的是,我提到的硬 redaction,例如健康保险 ID 被 redaction 了,驾驶执照被 redaction 了,子代理过程中的情况也是如此。所以,有一些关于硬 redaction 的错误需要解决,关于工具调用,你看到了它在那里奏效了,但那是由于我使用这个计划进行的修复。通过这个计划,我们实际上实施了一个两阶段的本地 LLM 方法。第一阶段是实体解析,第二阶段是最终的检查,是否有任何高度敏感的实体逃脱了 Presidio 的检测,例如。如果是这种情况,那么这个 LLM 调用会输出需要从输入中硬 redaction 的文本。你可以在这里看到,例如。所以我终于在服务器上设置了 Langfuse,让我们来看看这个。所以,这是提供她完整的雇佣记录。你可以看到有很多不同的工具调用。所以,这个是 Quinn 3 80 亿模型。在这里,这是 PII 检测专家,它正在扫描敏感数据。所以,这是一个不同的提示,与你几分钟前看到的提示不同。然后输出,正如你所看到的,是 Presidio 在文本中识别实体时遗漏的特定实体。例如健康保险 ID,或者这里我们有信用卡号的 CCV 号码。所以,有一个小型模型进行最终的检查,看看是否有其他算法遗漏的 PII 或敏感信息,这是一个非常好的想法,而且我认为 Nvidia 也推出了一个专门针对此的小型模型。这里我们只使用 Quinn 3 80 亿。在这个计划中,我们为代理和硬 redaction 添加了不同的阈值。所以,对于代理,我们不希望有非常低的阈值。这里我们谈论的是地点和姓名。所以,我们希望它比信用卡号或护照号码的硬 redaction 等更不敏感。所以,这就是那个工作的目的。在这里,我处理了不一致的代理。所以,如果我问了五次同样的问题,告诉我关于 Margaret Thompson 的事情,五分之三次它可能能够找到她的详细信息,而其他时候则不能。这是因为我们在分配代理方面存在不一致。所以,那个问题已经解决了。在计划 30 中,我实现了 Langfuse,更新了跟踪。所以,它现在支持 Lang Smith 或 Langfuse。这只是一个环境变量,你可以告诉你想用哪个。计划 31 和 32 是小错误修复或我之前已经涵盖的内容。计划 33 是 PII 性别猜测器,我发现这对于文本中的代词很重要,因为 Margaret Thompson 之类的人物被替换成了 Daniel Walsh,例如,但文本中又将 Margaret 称为她。所以,有一个名为 gender guessesser 的 Python 库,这意味着你可以将其与 Faker 库一起使用来生成特定类型的名称。嗯,这也有所改进。34 是我发现的模糊碰撞。再次,只是一个小错误,因为我正在测试。编号 35 是子代理中的 redaction。所以,有一些子代理的元素没有应用完整的 redaction 服务。所以,那个也修复了。所以,是的,它现在状态相当不错。让我再测试几个。所以,让我们上传更多文档。所以,如果我们添加文件,我有很多测试文件。所以,让我们选择事件报告,比如说。然后让我们也在这里打开它。所以,PII 事件报告。我相信我们老朋友 Margaret 也卷入了这件事。一个网络钓鱼电子邮件诈骗的主题。好的,已完成。所以,让我们回到我们的聊天。告诉我关于 Margaret Thompson 以及她参与的任何事件。所以,我们有许多工具。显然有向量搜索或混合搜索,但也有知识库遍历,你知道,GP 和 glob 和 list 和 tree。现在,它刚刚进行了混合搜索,但你可以看到安全事件以及所有信息都被正确地替换了。正如你在这里看到的,如果我们看最终的生成,你可以看到它说,告诉我关于 Rebecca Romero 的事件。然后我们从 Claude Haiku 获得的最终输出是 Rebecca Romero 是工程部门的高级软件工程师,而我们将其视为 Margaret Elanor Thompson 是高级软件工程师。所以,这里的替换工作正常。我意识到这只运行了向量搜索。所以,让我们要求一份全面的报告。所以,现在它正在触发 analyze document 子代理,并且它正在构建一份关于 Margaret Ellanar Thompson 参与此安全事件的全面报告。而 Claude Haiku 在子代理形式中的这个反馈是完全 redaction 的。我们在这里看到 Margaret 的名字。但同样,如果我们现在进入 Langfuse,我们将能够看到 Haiku 实际上并没有处理这些。这是我们的完整报告。我们有被 redaction 的内容,如 IP 地址、社会安全号码、信用卡号、银行号码,这些都在我们的测试数据中。现在,显然,我并不是说你应该为这种用例使用 LLM,但显然这是一个测试这种 redaction 和代理生成以匿名化和反匿名化的绝佳方式。让我们再放入一个文件进行测试。所以,也许放入会议记录。而且,Margaret 也深度参与其中。所以,这是一个工程更新。这将是一个很好的测试。Margaret 何时会提交即将举行的会议的提案?因为日期会被替换。所以,有兴趣看看这是否有效。好的,又一次混合搜索。所以,它在会议记录中找到了 Margaret 的提及。她将在 go for a con 上发表演讲。旅行已获预先批准。提交演示文稿的具体截止日期在搜索结果中未明确说明。现在我感兴趣的是,这只是系统提示吗?你能加载完整的会议记录吗?我只是从你刚才描述的会议记录中说。是的。所以,它现在正在读取该文档。2025 年 1 月 31 日。是的,就在那里。2025 年 1 月 31 日。我们能看到它是否真的被匿名化了吗?是的,它被匿名化了。是的。Claude Haiku 看到的是 1993 年 1 月 1 日。太棒了。所以,Haiku 被喂了那个日期,然后在它的响应中,它提供了那个日期 1993 年。但是,如果我们进入我们的实体注册表,让我们查找那个代理值。所以,让我们说代理值是这个。有趣。那里是 1 月 31 日。它缺少 2025 年,但它实际上在这里。所以,从跟踪来看,它有两个日期。另一个是 2004 年。所以,那可能是 2025 年的 token。确切地说。给你。这真的奏效得很好。这非常好。显然,还有很多测试要做。我只加载了三个文档。你知道,显然会有数千个文档的知识库和 API 调用以及 SQL 表等等,但这里有一个不错的架构基础。有趣的是,我们不得不经历走错路的这个过程,才能真正弄清楚我们需要简化架构,并且只在本地和云 LLM 之间以及返回时有一个接口,而不是试图围绕它设计整个架构。我相信如果我提前做了足够的工作,我可以在不写任何代码的情况下弄清楚这一点。但我认为这就是 Claude Cold 的好处,你可以通过一些基本的原型设计来即时弄清楚事情,让它来编写代码。希望你喜欢这个构建过程。如果你对零信任 AI 系统的概念感兴趣,那么我强烈建议你看看这个视频。非常感谢你的观看,我们下期再见。