收益:
- 设置访问控制 (ACL),根据用户权限过滤检索
- 编写一个可靠的提示模板,正确放置上下文和用户问题
- 在多轮对话中练习问题独立性和历史管理
我们建立了架构;现在让我们让它变得安全、一致和对话。本单元包含三个关键主题:(1)根据用户权限过滤检索的访问控制,(2)正确放置上下文和问题的强大提示模板,(3)多轮聊天中的问题独立性和对话历史管理。如果没有这三者,助理要么会泄露数据,给出不一致的答案,要么在后续问题上崩溃。
访问控制:未经授权的数据永远不应到达
企业最大的风险:用户不应该看到的文档泄露到响应中。初学者一个非常常见的错误是“告诉模型在提示时‘显示隐藏文档’”。这不安全。模型可能会忘记指令,或者提示注入可能会逃避指令。正确的地方是检索阶段:未经授权的作品根本不应该被带进来。
执行此操作的方法是应用您在搜索过程中放置在每个部分上的权限元数据(部门、角色、隐私级别)作为过滤器。您可以在应用程序层安全地确定用户是谁(身份和角色),并向调用添加 ACL(访问控制列表)过滤器。
# 按权限检索过滤(概念)user =authenticate(session) # 从可信源进行身份验证 = user.roles + ["everyone"] # 例如["HR", "admin"]result = vektor_db.search( vektor=embed(question), top_k=20, filter={"permission_group": {"in": allowed}, # 仅允许的部分 "privacy": {"lte": user.level}} # 级别以下)
注意:切勿向模型询问权限或依赖提示。身份和权限由应用程序的可信层确定;检索过滤器是强制性的,提示指令只是附加层。 “我在提示中写了它”并不是安全。
实体提示模板
提示模板是将检索中的上下文、用户问题和行为指令汇集在一起的骨架。一个好的模板的组成部分:角色/任务描述、行为规则(基础、我不知道许可、资源请求、语气)、上下文、问题。
你是一名企业人力资源助理。您的工作是仅根据以下上下文回答员工问题。规则:- 如果答案在上下文中不明确,请写“我在文档中找不到有关此内容的信息,请与人力资源团队联系”。不要猜测,不要编造。- 如果上下文中的来源有冲突,请以官方政策为依据,并说明矛盾之处。- 在每个声明的末尾添加您所依赖的来源作为[来源:文件,部分]。- 用简短、清晰和专业的语言回答。上下文:{numbered_parts}问题:{user_question}
对上下文部分([1]、[2]、...)进行编号可以更轻松地引用模型。另外,在每篇文章的开头写下来源,以便模型可以正确引用它。
提示:保持提示模板不变,并始终将变量(上下文、问题)放在相同的位置。由于某些系统中的即时缓存,固定模板既可以提高可测试性,又可以降低成本。
背景:[1](来源:ik_el_kitabi.pdf,第 5.2 节)年带薪休假为 14 天...[2] (来源:ik_el_kitabi.pdf,第 5.4 节)工龄超过 5 年的人员可享受 20 天的休假...
弱提示/强提示
弱(无基础、无来源、身份混杂):
使用这些文档并回答问题:{parts}用户:{question}# 问题:模型断章取义、编造、未引用来源、# 任意表现出矛盾。
强(角色+规则+编号上下文+源强制):
你是...只需依靠上下文即可。否则,就说“我不知道”。出现冲突时,选择官方政策。将 [来源:...] 添加到每个声明中。上下文:[1]... [2]... 问题:{问题}# 结果:答案忠实于上下文、来源并正确处理矛盾。
多轮对话管理
真正的用户不会问一个问题就不管它;说话。 “我有多少天年假?” →“那六年的员工呢?” →“如何申请?”光是第二个问题和第三个问题是没有意义的;取决于之前的上下文。
你需要解决两个问题。第一个是检索:使后续问题独立(问题重写)。 “那6年的员工呢?” →“工龄6年的员工可以享受多少天年假?”您用这个独立问题进行搜索。第二个用于生产:您还可以将对话历史记录提供给模型,以便它能够一致地继续。
# 两步:独立→搜索→生成历史记录(概念)独立= model.uret(“使用对话历史记录使问题本身易于理解:\ nHistory:{history} \ n问题:{follow_question}”)context =检索(independent)#使用独立问题搜索answer = model.uret(prompt(context,history,follow_question))
随着历史记录的增长(长时间的对话),一次发送所有内容会变得昂贵并填满上下文窗口。解决办法:总结前几轮或者保留最后N轮,将前几轮减少到总结。因此,成本仍然受到控制并保持一致性。
状态
问题
解决方案
后续问题没有上下文
检索搜索毫无意义
使问题独立(重写)
长聊
成本和窗口膨胀
过去旅行的总结
用户更改了主题
旧环境被感染
减少过去对新话题的影响
不同旅行团的授权可能有所不同
泄漏风险
每轮重新应用 ACL 过滤器
三个迷你箱
案例 1——带有提示的“安全”谬误。某公司将机密薪资文件放在助理身上,任何人都可以询问,但提示中只写了“不要提供薪资信息”。当用户以迂回的方式提出问题时,该模型泄露了薪资范围。当将 ACL 过滤器添加到检索中时(工资部分仅适用于 HR 角色),漏洞就完全关闭了;因为这个零件再也没有被带来了。
案例 2——无背景的跟踪。在支持助理中,用户询问“返回期限?” →“破损的产品怎么办?”系统为“损坏的产品”带来了无关的零件。当添加问题独立性(“损坏产品的退货期限是多长?”)时,正确答案率从 44% 增加到 90%。
案例3——肿胀的过去。在与助手的 30 轮聊天中,每次通话都会发送完整的历史记录;每轮成本增加3倍,响应速度变慢。当我们改用保留最后 6 轮并汇总之前的结构时,代币成本下降了 62%,并且保持了一致性。
常见错误
- 将权限留给提示:模型忘记/绕过; ACL 过滤器在检索时是强制的。
- 未枚举上下文:模型无法引用正确的来源。
- 不独立后续问题:检索毫无意义。
- 盲目发送所有历史记录:成本和延迟呈爆炸式增长;总结。
- 不写矛盾规则:模型可能将不可靠的来源呈现为官方的。
综上所述
- 在检索阶段通过元数据过滤器实现访问控制;切勿携带未经授权的零件。
- 身份和权限由可信应用层确定;及时的指示只是额外的一层防御。
- 强大的提示模板包括角色、行为规则(基础、不知道权限、来源、冲突)、编号上下文和问题。
- 在多轮对话中,后续问题被解耦,模型产生与历史一致的答案。
- 通过总结悠久的历史,成本和上下文窗口得到控制;每轮都会重新应用 ACL。
应用任务
(1) 为自己的助理定义至少三个权限组(例如每个人、部门、经理),并在表格中写出哪种文档类型对哪个组开放。 (2)根据自己的角色和语气改编并编写上述提示模板;对上下文进行编号和来源。 (3)编写三轮现实对话场景(问题→跟进→跟进)并手动生成每个后续问题的独立版本。 (4) 用一句话解释为什么在这种情况下每一轮都应该重新应用 ACL 过滤器。
清单
- [ ] 我使用检索过滤器实现访问控制,我只是不依赖提示。
- [ ] 我在提示模板中添加了接地、我不知道权限、来源和冲突规则。
- [ ] 我给出了编号和引用的上下文部分。
- [ ] 我在检索之前将后续问题独立出来。
- [ ] 我通过总结较长的对话历史记录来管理成本和窗口。