RunnableRails#

本指南将教您如何将使用 NeMo Guardrails 构建的防护栏配置集成到您的 LangChain 应用程序中。本指南中的示例将重点介绍如何使用 LangChain 表达式语言 (LCEL)。

概述#

NeMo Guardrails 提供了一个 LangChain 原生接口,通过 Runnable Protocol 实现了 RunnableRails 类。要开始使用,您必须首先加载防护栏配置并创建一个 RunnableRails 实例

from nemoguardrails import RailsConfig
from nemoguardrails.integrations.langchain.runnable_rails import RunnableRails

config = RailsConfig.from_path("path/to/config")
guardrails = RunnableRails(config)

要在 chain 中为 LLM 模型添加防护栏,您必须使用 RunnableRails 实例“包裹”LLM 模型,即 (guardrails | ...)

我们来看一个使用 prompt、模型和输出解析器的典型示例

from langchain.chat_models import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

prompt = ChatPromptTemplate.from_template("tell me a short joke about {topic}")
model = ChatOpenAI()
output_parser = StrOutputParser()

chain = prompt | model | output_parser

在上述示例中为 LLM 模型添加防护栏

chain_with_guardrails = prompt | (guardrails | model) | output_parser

注意

使用额外的括号对于强制执行 | (管道) 运算符的应用顺序至关重要。

要为现有的 chain (或任何 Runnable) 添加防护栏,您必须以类似的方式对其进行包裹

rag_chain = (
    {"context": retriever | format_docs, "question": RunnablePassthrough()}
    | prompt
    | llm
    | StrOutputParser()
)

rag_chain_with_guardrails = guardrails | rag_chain

您也可以使用相同的方法仅为您 chain 的特定部分添加防护栏。下面的示例 (摘自 RunnableBranch 文档),为 RunnableBranch 中的“anthropic”和“general”分支添加了防护栏

from langchain_core.runnables import RunnableBranch

branch = RunnableBranch(
    (lambda x: "anthropic" in x["topic"].lower(), guardrails | anthropic_chain),
    (lambda x: "langchain" in x["topic"].lower(), langchain_chain),
    guardrails | general_chain,
)

通常,您可以使用防护栏包裹 runnable chain 的任何部分

chain = runnable_1 | runnable_2 | runnable_3 | runnable_4 | ...
chain_with_guardrails = runnable_1 | (guardrails | (runnable_2 | runnable_3)) | runnable_4 | ...

输入/输出格式#

包裹 LLM 模型时支持的输入/输出格式为

输入格式

输出格式

Prompt (即 StringPromptValue)

完成字符串

聊天历史 (即 ChatPromptValue)

新消息 (即 AIMessage)

包裹 chain (或 Runnable) 时支持的输入/输出格式为

输入格式

输出格式

包含 input 键的字典

包含 output 键的字典

包含 input 键的字典

字符串输出

字符串输入

包含 output 键的字典

字符串输入

字符串输出

Prompt 透传#

防护栏配置的作用是验证用户输入、检查 LLM 输出、指导 LLM 模型如何响应等(有关不同类型防护栏的更多详细信息,请参阅 配置指南)。为了实现这一点,防护栏配置可能会对 LLM 或其他模型/API 进行额外的调用(例如,用于事实核查和内容审核)。

默认情况下,当防护栏配置确定可以安全地向 LLM 提供 prompt 时,它将使用作为输入提供的确切 prompt(即字符串、StringPromptValueChatPromptValue)。但是,为了强制执行特定的防护栏(例如,对话防护栏、通用指令),防护栏配置需要更改用于生成响应的 prompt。要启用此行为,这提供了更健壮的防护栏,您必须在创建 RunnableRails 实例时将 passthrough 参数设置为 False

guardrails = RunnableRails(config, passthrough=False)

带有 Guardrails 的 Chains 的输入/输出键#

当使用防护栏配置包裹 chain (或 Runnable) 时,输入和输出可以是字典或字符串。然而,防护栏配置始终处理来自用户的文本输入和来自 LLM 的文本输出。为此,当使用字典时,输入字典中的一个键必须指定为“input text”,输出字典中的一个键必须指定为“output text”。默认情况下,这些键是 inputoutput。要自定义这些键,您必须在创建 RunnableRails 实例时提供 input_keyoutput_key 参数。

guardrails = RunnableRails(config, input_key="question", output_key="answer")
rag_chain_with_guardrails = guardrails | rag_chain

当触发防护栏并需要返回预定义消息时,而不是返回 LLM 的输出,只返回一个带有 output 键的字典

{
  "answer": "I'm sorry, I can't assist with that"
}

使用工具#

防护栏配置还可以使用工具作为对话防护栏的一部分。以下代码片段使用 LLMMathChain 定义了 Calculator 工具。

from langchain.chains import LLMMathChain

tools = []

class CalculatorInput(BaseModel):
    question: str = Field()

llm_math_chain = LLMMathChain(llm=model, verbose=True)
tools.append(
    Tool.from_function(
        func=llm_math_chain.run,
        name="Calculator",
        description="useful for when you need to answer questions about math",
        args_schema=CalculatorInput,
    )
)

为了确保所有数学问题都使用此工具回答,您可以创建如下所示的防护栏并将其包含在您的防护栏配置中

define user ask math question
  "What is the square root of 7?"
  "What is the formula for the area of a circle?"

define flow
  user ask math question
  $result = execute Calculator(tool_input=$user_message)
  bot respond

最后,您将 tools 数组传递给 RunnableRails 实例

guardrails = RunnableRails(config, tools=tools)

prompt = ChatPromptTemplate.from_template("{question}")
chain = prompt | (guardrails | model)

print(chain.invoke({"question": "What is 5+5*5/5?"}))

限制#

RunnableRails 接口的当前实现不支持流式传输。这将在未来的版本中解决。