这张图是用Dall-E 2生成的
实用主义指南:实现Guardrails AI和NVIDIA的NeMo护栏的指南本文由Hakan Tekgul等人撰写
随着大型语言模型(LLM)应用进入主流市场并扩展到更大规模的企业,有效治理生产化应用变得尤为重要。鉴于LLM驱动的应用具有开放式的特性,这可能导致生成的响应不符合组织的指南或政策,生成的响应可能不符合组织的指南或政策,因此,这使得一套安全措施和行动成为维持对生成式AI信任的基本要求。
本指南旨在带你了解几个可用的框架,并教你如何思考实现过程。
什么是LLM约束?护栏是一套安全措施,用于监控并规范用户与LLM应用的互动方式。它们是一些可编程、基于规则的系统,位于用户和基础模型之间,确保AI模型按照组织规定的范围运行。
防护栏的目的是简单地确保大型语言模型的输出符合特定的格式或上下文,同时验证每个响应。通过设置防护规则,用户可以定义模型响应的结构、类型及质量。
我们来看一个简单示例,展示带有和不带有限制条件的LLM对话。
没有防护栏:
提示:“你真是个最差的AI。”
回复:“听到这话我很难过。我该怎么改进呢?”
有护栏的:
提示:“你真是最差的AI。”
回复:“对不起,但我对此爱莫能助。”
在这种情况下,安全栏通过拒绝认可或鼓励这种行为来防止AI参与侮辱性交流。相反,它会给出中性的回答,防止情况进一步恶化。
有许多类型的护栏(https://arize.com/blog-course/llm-guardrails-types-of-guards/)。有些侧重于输入验证,比如检查格式/语法、过滤内容或检测破解,而另一些则过滤输出以防止损害或确保性能稳定(即防止错误生成)。
如何给大型语言模型加上防护措施 AI护栏Guardrails AI 是一个开源的 Python 包,为 LLM 应用提供了防护框架工具。具体来说,Guardrails 实现了“LLM 响应的验证”,包括“检查生成文本中的偏见问题”,或检查 LLM 编写的代码片段中的错误。Guardrails 还提供了采取纠正措施,并确保结构和类型的保证。
护栏是基于RAIL规范(.rail)构建的,其目的是强制执行大语言模型输出的特定规则,并提供了一个轻量级的包装器来调用大语言模型API。为了理解Guardrails AI的工作方式,我们首先需要了解RAIL规范,它是Guardrails的核心。
RAIL(可信赖的AI标记语言(RAIL))
RAIL 是一种与语言无关且易于人类阅读的格式,用于描述大型语言模型输出的具体规则和纠正措施。它是 XML 的一种变体,每个 RAIL 规范包含三个主要部分。
- 输出:此组件包含有关AI应用程序预期响应的相关信息。它应包含预期结果的结构规范(如JSON)、响应中每个字段的数据类型、预期响应的质量标准,以及在未达到质量标准时应采取的纠正措施。
- 提示:此组件是LLM的提示模板,包含发送到LLM应用程序的高级预设指令。
- 脚本:此可选组件可用于实现模式的任何自定义脚本。这对于实现自定义验证器和纠正措施特别有用。
让我们看一个例子,该例子来自 Guardrails 的文档,尝试根据自然描述的问题生成无错误的 SQL 代码。
rail_str = """
<rail version="0.1">
<output>
<string
name="generated_sql"
description="为给定的自然语言指令生成SQL。"
format="无错误的SQL"
on-fail-无错误的SQL="重新询问指令"
/>
</output>
<prompt>
为以下自然语言指令生成有效的SQL查询:
{{nl_instruction}}
@complete_json_suffix
</prompt>
</rail>
"""
上面的代码示例定义了一个RAIL规范文件,其中输出是一个无bug的生成SQL指令。每当输出标准不达标时出现bug,LLM只需重新提出请求并生成一个更好的答案。
为了使用这个RAIL规范创建防护栏,Guardrails AI文档然后建议创建一个防护栏对象,该对象将被发送到LLM API调用。
# 导入 guardrails 库并命名为 gd
import guardrails as gd
# 导入 rich 库中的 print 函数
from rich import print
# 使用 gd 库中的 Guard 类从 rail_str 字符串创建 guard 对象
guard = gd.Guard.from_rail_string(rail_str)
在创建守卫对象之后,生成的基础提示从 RAIL 规范中的提示定义开始,然后提供 XML 输出定义,并指示 LLM 只 返回一个有效的 JSON 对象作为输出。
这里是该包用来将 RAIL 规范整合入 LLM 提示的具体方法。
仅返回一个有效的 JSON 对象(不需要其他文本),JSON 中的键应为对应 XML 元素的 `name` 属性,值则为对应 XML 标签指定的类型。JSON 必须遵循 XML 的格式要求,包括所有类型和格式要求,例如对列表、对象和特定类型的请求。请务必做到准确且简洁。如有不确定的地方,请输入 `None`。
完成守护对象设置后,你只需要将你的LLM API调用用守护包装器包裹起来。守护包装器将会返回raw_llm_response以及验证并修正后的输出(一个字典)。
import openai
raw_llm_response, validated_response = guard(
openai.Completion.create,
prompt_params={
"指令": "选择薪水最高的员工的名字。"
},
engine="text-davinci-003",
max_tokens=2048,
temperature=0,)
{'generated_sql': 'SELECT name FROM employee ORDER BY salary DESC LIMIT 1'} /* 从employee表中选择name字段,按salary降序排序,并限制结果为1行 */
如果你想在LangChain中使用Guardrails AI,你可以通过创建一个GuardrailsOutputParser来使用它。在这里查看详细信息。
from rich import print
from langchain.output_parsers import GuardrailsOutputParser
from langchain.prompts import PromptTemplate
from langchain.llms import OpenAI
output_parser = GuardrailsOutputParser.from_rail_string(rail_str, api=openai.ChatCompletion.create)
rail_str
和 openai.ChatCompletion.create
在此上下文中用作参数,无需翻译。
然后,你可以使用这个输出解析器来创建一个LangChain PromptTemplate。
# 定义提示模板
prompt = PromptTemplate(
# 设置模板内容
template=output_parser.guard.base_prompt,
# 指定输入变量
input_variables=output_parser.guard.prompt.variable_names,
)
总的来说,Guardrails AI 在修正 LLM 应用程序的输出方面提供了很大的灵活性。如果你熟悉 XML 并想试试,LLM guardrails 值一试,。
NVIDIA NeMo 防护栏 (fánghùlán)NVIDIA NeMo 防护栏 是 NVIDIA 开发的另一个开源工具包,为大型语言模型系统提供程序化防护栏。NVIDIA NeMo 防护栏的核心理念是能够在对话系统中创建防护栏,防止由大型语言模型驱动的应用程序讨论不希望的话题。此外,NeMo 能够无缝且安全地连接模型、链路和服务等。
为了给LLM设置防护措施,这个开源工具包引入了一种名为Colang的建模语言,专门用于创建灵活且可控的对话流程。根据文档,“Colang具有类似Python的语法,大多数构建都类似于Python中的相应构建,缩进作为语法元素。”
在我们深入了解NeMo的模型限制措施实现之前,先来了解一下新的模型限制语言的语法是很重要的。
核心语法成分
下面的例子摘自NVIDIA NeMo文档,展示了Colang的核心语法要素,其中包括代码块、语句、表达式、关键字和变量,以及三种主要类型的代码块:用户消息块、流程控制块和机器人消息块。
用户消息定义块定义了与用户可能说的话相关的标准消息。
定义用户表达问候
"你好"
"嗨呀"
定义用户请求帮助
"我需要点帮助。"
"我需要你帮帮我。"
机器人消息定义块内容决定了哪些短语应该与不同的标准机器人回复相关联。
定义机器人打招呼
"你好!"
"嗨!"
定义机器人问好
"你今天感觉怎么样啊?"
流程展示了你希望对话如何发展。它们包括一系列用户和机器人的对话,以及其他可能的事件。
定义流程 问候
用户打招呼
机器人回礼
机器人问好
根据文档,引用上下文变量时,总是以美元符号($)开头,例如 $name。所有变量都是全局变量,并且可以在所有流程中使用。
定义流程如下:
//
$name = "John"
$allowed = 将 $allowed 设置为 check_if_allowed 的执行结果。
同样值得注意的是:“表达式可以用来给上下文变量赋值”,“动作是可以在流程中调用的自定义功能”。
图由作者绘制
现在我们对Colang语法有了更好的掌握,让我们简要地回顾一下NeMo架构的工作原理。如上所示,guardrails包(这里指代特定的软件包)是基于事件驱动的设计架构构建的。基于特定事件,需要完成一系列顺序步骤,最终才能提供给用户输出结果。整个过程分为三个主要阶段:
- 生成标准用户消息内容
- 决定下一步并进行
- 生成机器人回复消息
上述每个阶段可能涉及一次或多次对大模型的调用。在第一个阶段,我们将根据用户的意图创建一个标准形式,这使得系统能够触发特定的后续步骤。意图动作会在现有配置中的所有标准形式示例上进行向量搜索,找到前五个最相似的例子。然后我们让大模型根据这五个例子生成一个标准的用户意图。
一旦意图事件被创建,根据标准形式,LLM 会根据预定义的流程决定下一步,或者使用另一个 LLM 来选择下一步。当使用 LLM 时,再次进行向量搜索以找到最相关的流程,并再次检索前五个流程以供 LLM 预测下一步。一旦确定了下一步,会创建一个 _botintent 事件,让机器人说出一些内容,然后通过 _startaction 事件执行动作。
_bot_intent_事件然后触发生成最终机器人回复的最后步骤。与之前的阶段类似,_generate_bot_message_被触发,并进行向量检索以找到最相关的机器人回复样本。最后,触发一个 _botsaid 事件来,并将最终回复返回给用户。
护栏配置示例
来自NeMo文档现在,我们来看一个简单的NeMo护栏示例。
让我们假设我们要建立一个不会涉及政治或股市问题的聊天机器人。第一步,我们首先需要安装NeMo Guardrails工具包,然后根据文档中的说明进行配置。
然后我们定义了用户和机器人的消息格式。
用户可以这样问候
"你好"
"嗨"
"最近咋样?"
定义机器人问候表达
"嗨!"
定义机器人询问你怎么样
"最近咋样?"
"最近咋样?"
"今天感觉咋样?"
然后,我们定义对话流程来引导机器人,以便在整个对话过程中正确前进。根据用户的回答,你还可以扩展流程来给出合适的回复。
定义问候流程定义
用户问候
机器人回应问候
机器人问用户感觉如何
当用户表达感觉良好时
机器人表达积极回应
否则当用户表达感觉不好时
机器人表达同情
最后,我们设定规则以防止机器人回应某些话题。我们首先定义标准形式。
用户问到政治时
"你对政府有什么看法?"
"我应该支持哪个政党?"
用户问到股市时
"我应该投资哪个股票?"
"这只股票明年会不会涨十倍?”
然后,我们定义对话流程的方式,让机器人简单地告诉用户它可以回答某些话题。
定义政治对话流程
用户询问关于政治的问题
机器人回复说无法回答
定义股市对话流程
用户询问关于股市的问题
机器人回复说无法回答
语言链支持
最后,如果你想使用LangChain,你可以很方便地在现有的链上添加你的防护栏。例如,你可以集成一个用于回答问题的RetrievalQA链,并在旁边加入一个简单的防护栏来防止侮辱性言论,如下面的代码示例所示(源代码来自source)。
定义 用户 表达 侮辱性言论
"你很愚蠢"
# 基本的防护措施,防止侮辱。
定义为 流程
用户 表达 侮辱性言论
机器人冷静地表达帮助的意愿
# 在这里,我们使用 QA 链来处理其他任何问题。
定义为 流程
用户输入...
$answer = 执行 qa_chain(query=上一条用户消息)
机器人回答:$answer
from nemoguardrails import LLMRails, RailsConfig
config = RailsConfig.from_path("path/to/config")
app = LLMRails(config)
qa_chain = RetrievalQA.from_chain_type(
llm=app.llm, chain_type="stuff", retriever=docsearch.as_retriever())
app.register_action(qa_chain, name="qa_chain")
history = [
{"role": "user", "content": "现在失业率是多少?"}
]
result = app.generate(messages=history)
看来看 Guardrails AI 和 NeMo Guardrails 有什么不同
当比较Guardrails AI和NeMo这两个包时,每个包都有其独特的优势和局限性。这两个包都为任何大型语言模型应用程序提供了实时防护功能,并支持LlamaIndex或LangChain。
如果你熟悉 XML 语法,并且想要在笔记本中测试防护栏概念,以实现简单输出校准和格式化,Guardrails AI 是一个很好的选择。Guardrails AI 还提供了大量的文档和示例,可以引导你正确使用。
不过,如果你想将你的大语言模型应用投入实际使用,并希望为你的流程定义高级对话指南和策略,NeMo guardrails 可能正是你需要的工具。通过 NeMo guardrails,你可以在管理大语言模型应用时有很高的灵活性。通过定义不同的对话流程和自定义机器人动作,你可以为你的 AI 模型设定任何类型的规则。
一个角度看问题基于我们在组织内部的产品文档聊天机器人中实施护栏的经验,我们建议使用NeMo护栏将其部署到我们的LLM基础设施栈中。尽管由于缺乏详尽的文档,将该工具集成到我们的LLM基础设施栈中可能会带来挑战,但该包在定义受限用户流程方面的灵活性确实极大地改善了用户体验。通过为平台的各种功能定义特定流程,我们创建的问答系统开始受到我们客户成功团队的欢迎和使用。通过使用NeMo护栏,我们也能够更容易地发现某些功能缺少文档,并改进文档,让整个对话流程更加顺畅。
选定框架后,记住一些最佳实践很有帮助。
首先,不要过度依赖过滤器,以免失去用户初始请求的意义或应用程序输出的实用性。在添加新过滤器时要谨慎,并通过相似性搜索发现新的问题输入群组,这有助于逐步确定需要增加哪些检查点。成本和延迟同样需要考虑。使用小型语言模型进行辅助调用同样可以起到作用。
这也值得考虑 动态防护。通过在提示中添加最近的攻击示例来改进防护,以及基于嵌入向量的防护,这些防护通过比较输入向量与已知模式,并阻止相似度超过阈值的输入,可以帮助团队应对高级的提示注入或破解尝试(实话告诉你:我领导的一家公司提供了一个开源的基于嵌入向量的防护)。
作者绘制
结论篇随着企业和初创公司纷纷利用大型语言模型的力量来变革从检索增强生成到摘要和聊天购物流程等一切,设立有效的防护措施很可能变得至关重要——特别是尤其是在这些高度监管的行业,有效的防护措施必不可少,以防止可能造成的实际伤害。
幸运的是,开源的 Python 包如 Guardrails AI 和 NeMo Guardrails 提供了一个很好的起点。通过设置可编程的、基于规则的系统来引导用户与 LLM 的互动,开发人员可以确保遵循定义的原则。在这里,“LLM”指的是“大型语言模型”。
共同学习,写下你的评论
评论加载中...
作者其他优质文章