正如我们在本书中讨论的那样,由于其生成类似人类文本的能力,大型语言模型(LLMs)近年来引起了广泛关注。从创意写作到对话式聊天机器人,这些生成式人工智能模型在各个行业都有各种应用。然而,将这些复杂的神经网络系统从研究阶段推广到实际部署阶段面临着重大挑战。
到目前为止,我们已经讨论了模型、代理、LLM应用以及不同的用例,但在将这些应用部署到生产环境中与客户互动并做出可能具有重大财务影响的决策时,许多问题变得重要。本章探讨了将生成式人工智能,特别是LLM应用投入生产的实际考虑和最佳实践。在部署应用之前,需要确保性能和监管要求,它需要在规模上具有鲁棒性,最后需要进行监控。为了可信赖的部署,保持严格的测试、审计和伦理保障至关重要。我们将讨论评估和可观察性,并涵盖广泛的主题,包括操作化人工智能和决策模型的治理和生命周期管理,包括生成式人工智能模型。
在准备将LLM应用投入生产时,离线评估在受控环境中提供了对模型能力的初步了解,在生产中,可观察性则为在实时环境中持续提供性能洞察。我们将讨论一些适用于两种情况的工具,并提供示例。我们还将讨论LLM应用的部署,并概述可用的工具和部署示例。
在整个章节中,我们将使用LLM应用的实际示例,您可以在本书的GitHub存储库中找到,网址为github.com/benman1/gen...。
本章的主要部分包括:
- 如何准备将LLM应用投入生产
- 如何评估LLM应用
- 如何部署LLM应用
- 如何观察LLM应用
让我们从概述准备LLM应用投入生产所涉及的内容开始吧!
如何使LLM应用准备投入生产
将LLM(大型语言模型)应用部署到生产环境是一个复杂的过程,涵盖了强大的数据管理、伦理预见、高效的资源分配、细致入微的监控以及与行为准则的一致性。确保部署准备就绪的实践包括:
- 数据管理: 对数据质量的严格关注对于避免因训练数据不平衡或不适当而产生的偏见至关重要。对数据的精心筛选和对模型输出的持续审查是减轻新出现偏见的必要步骤。
- 伦理部署和合规性: LLM应用有可能生成有害内容,因此需要进行严格的审查流程、安全准则,并且在敏感领域如医疗保健中需要遵守诸如HIPAA之类的法规。
- 资源管理: LLM的资源需求需要一个既高效又环保可持续的基础设施。基础设施创新有助于降低成本,并解决与LLM能量需求相关的环境问题。
- 性能管理: 模型必须不断监控数据漂移(输入数据模式的变化可能改变模型性能)和随时间的性能下降。及时检测这些偏差需要迅速进行重新训练或调整模型。
- 可解释性: 为了建立信任并为用户提供有关LLM决策过程的洞察,解释性工具对于需要了解模型决策方式的用户越来越重要。
- 数据安全: 保护LLM过程中的敏感信息对于隐私和合规性至关重要。强大的加密措施和严格的访问控制可以增强安全性。
- 模型行为标准: 模型必须符合超出基本功能性能的伦理准则,确保输出是建设性的、无害的,并值得信赖的。这导致了稳定性和社会接受度。
- 幻觉缓解: 幻觉是指LLM在输出中无意生成或召回其训练数据语料库中的敏感个人信息的情况,尽管在输入源中没有提示这些细节,突显了隐私问题和缓解策略的重要性。
为部署LLM应用提供基本建议包括一系列实践,旨在减轻技术挑战、提高性能并确保伦理完整性。首先,开发具有相关基准的标准化数据集,用于测试和衡量模型能力,包括检测回归和与定义目标的一致性。
指标应该是任务特定的,以准确衡量模型的熟练程度。还需要一个强大的框架,其中包括伦理准则、安全协议和审查流程,以防止生成和传播有害内容。人类审阅者在内容验证中起到了重要的检查点作用,并为AI输出带来了伦理判断,确保在所有上下文中都遵守。
具有前瞻性的用户体验可以促进与用户之间透明的关系,同时强调明智的使用。这可以包括预期的不准确性,如有关限制、归因和收集丰富用户反馈的免责声明。
为了解释输出,我们应该投资于解释性方法,解释生成AI模型如何做出决策。可视化注意机制或分析特征重要性可以揭示复杂性的层次,这对于高风险行业如医疗保健或金融来说尤为重要。
我们在第4章"构建功能强大的助手"中讨论了幻觉。缓解技术包括外部检索和工具增强,以提供相关背景,正如我们在第5章"构建像ChatGPT这样的聊天机器人"和第6章"使用生成AI开发软件"中所讨论的。模型回忆私人信息存在危险,持续发展的方法,包括数据过滤、架构调整和推理技术,显示出在缓解这些问题方面有希望。
对于安全性,我们可以通过强化基于角色的访问策略、采用严格的数据加密标准、在可行的情况下采用匿名化最佳实践,并通过合规性审计确保持续验证来增强安全性。在LLM的背景下,安全性是一个庞大的主题,然而,本章将专注于评估、可观察性和部署。
我们需要通过采用分布式技术(如数据并行性或模型并行性)来优化基础设施和资源使用,以促进在多个处理单元之间的工作负载分发。我们可以采用模型压缩等技术或其他计算架构优化,以提高推断速度和延迟管理的效率。模型量化等技术(在第8章"定制LLM及其输出"中讨论)或模型蒸馏也可以帮助减少模型的资源占用。此外,存储模型输出可以减少重复查询的延迟和成本。
通过深思熟虑的规划和准备,生成式人工智能有望从创意写作到客户服务转变产业。然而,在这些系统不断渗透越来越多的领域的同时,深思熟虑地应对这些系统的复杂性仍然至关重要。本章旨在为我们迄今为止未涉及的一些内容提供实用指南,旨在帮助您构建有影响力和负责任的生成式人工智能应用。我们将涵盖数据筛选、模型开发、基础设施、监控和透明性等方面的策略。
在继续讨论之前,有必要对术语进行一些说明。让我们从介绍MLOps及类似术语开始,明确它们的含义和暗示。
术语
MLOps是一种关注可靠高效地部署和维护机器学习模型的范式。它将DevOps的实践与机器学习结合起来,将算法从实验性系统转变为生产系统。MLOps旨在增加自动化、提高生产模型质量,并满足业务和监管要求。
LLMOps是MLOps的一种专门子范畴。它指的是作为产品的一部分对LLMs进行微调和操作所需的操作能力和基础设施。尽管它与MLOps的概念可能没有明显的不同,但区别在于与处理、优化和部署拥有1750亿参数的大型语言模型(如GPT-3)相关的具体要求。
术语LMOps比LLMOps更具包容性,因为它涵盖了各种类型的语言模型,包括LLMs和较小的生成模型。这个术语承认了语言模型及其在操作环境中的相关性的扩展景观。
基础模型编排(Foundational Model Orchestration,FOMO)专门解决了在使用基础模型时面临的挑战,即在广泛数据上训练的模型可以适应广泛的下游任务。它强调了需要管理多步骤流程、与外部资源集成以及协调涉及这些模型的工作流程的需求。
术语ModelOps侧重于AI和决策模型在部署时的治理和生命周期管理。更广泛地说,AgentOps涉及LLMs和其他AI代理的操作管理,确保它们的适当行为,管理其环境和资源访问,并促进代理之间的互动,同时解决与意外结果和不兼容目标相关的问题。
尽管FOMO强调了专门使用基础模型的独特挑战,但LMOps提供了对更广泛范围的语言模型的更全面和包容性的覆盖。LMOps承认了语言模型在各种操作用例中的多功能性和日益重要性,同时仍属于MLOps的更广泛范畴。最后,AgentOps明确强调了由具有特定启发式规则的生成模型组成的代理的互动性质,并包括工具。
所有这些非常专业化的术语的出现突显了该领域的快速发展;然而,它们的长期普及尚不清楚。MLOps被广泛使用,通常包括我们刚刚介绍的许多更专业化的术语。因此,在本章的其余部分,我们将坚持使用MLOps。
在将任何LLM应用投入生产之前,我们应该先评估其输出,因此我们应该从这方面开始。我们将专注于LangChain提供的评估方法。
如何评估LLM应用
LLM部署的关键在于对训练数据的细致策划,以预防偏见,实施人工注释以增强数据,以及建立自动化的输出监控系统。对LLMs进行评估,无论是作为独立实体还是与代理链结合,都是确保它们能够正确运行并产生可靠结果的关键,这是机器学习生命周期的一个组成部分。评估过程确定了模型在效果、可靠性和效率方面的性能。
评估LLMs的目标是了解它们的优点和缺点,提高准确性和效率,同时减少错误,从而最大化它们在解决实际问题中的用处。这个评估过程通常在开发阶段离线进行。离线评估在受控测试条件下提供对模型性能的初步洞察,并包括超参数调整和与同行模型或已建立标准的基准比较等方面。它们是在部署之前对模型进行改进的必要第一步。
尽管人工评估有时被视为黄金标准,但难以扩展,并需要仔细设计以避免受主观偏好或权威语气的影响。有许多标准化的基准测试,例如MBPP用于测试基本的编程技能,而GSM8K用于多步数学推理。API-Bank评估模型在进行API调用决策方面的能力。ARC将模型的问答能力与信息的复杂集成相比较,而HellaSwag利用对抗过滤评估在物理情境中的常识推理。
HumanEval侧重于代码生成的功能正确性而非语法相似性。MMLU评估了在各种主题上的语言理解,指示在专业领域的熟练程度。SuperGLUE通过更具挑战性的任务进一步拓展了GLUE,以监控语言模型的公平性和理解力。TruthfulQA通过基准测试LLM响应的真实性,带来了一个独特的视角,强调了真实性的重要性。
像MATH这样的基准测试要求高水平的推理能力评估。GPT-4在这个基准测试上的表现随着提示方法的复杂性而变化,从少量提示到强化学习和奖励建模方法。值得注意的是,基于对话的微调有时可能削弱了类似MMLU等度量所评估的能力。
评估可以揭示LLM生成输出的相关性、准确性和实用性。像FLAN和FLASK这样的测试强调了行为维度,因此优先考虑了负责任的人工智能系统部署。以下图表比较了FLASK基准测试中若干开源和闭源模型的性能(来源:"FLASK: Fine-grained Language Model Evaluation based on Alignment Skill Sets" by Ye等人,2023年;arxiv.org/abs/2307.10...):
在图表中报告的结果中,Claude是评估所有输出的LLM。这会使结果偏向于Claude及其类似的模型。通常,GPT-3.5或GPT-4被用作评估器,显示了OpenAI模型成为赢家。
在LangChain中,有各种方法来评估LLMs的输出,包括比较链输出、成对字符串比较、字符串距离和嵌入距离。评估结果可用于根据输出的比较确定首选模型。还可以计算置信区间和p值,以评估评估结果的可靠性。
LangChain提供了几种用于评估LLMs输出的工具。一个常见的方法是使用PairwiseStringEvaluator比较不同模型或提示的输出。这会促使评估模型在相同输入的两个模型输出之间进行选择,并汇总结果以确定总体首选模型。
其他评估器允许根据特定标准评估模型输出,例如正确性、相关性和简洁性。CriteriaEvalChain可以在不需要参考标签的情况下根据自定义或预定义的原则对输出进行评分。还可以通过指定不同的聊天模型,如ChatGPT,来配置评估模型。
您可以在书籍的GitHub项目的monitoring_and_evaluation文件夹下在线查看本节中的代码。让我们使用PairwiseStringEvaluator比较不同提示或LLMs的输出,这会促使LLM在给定特定输入的情况下选择首选输出。
比较两个输出
这种评估需要一个评估器、一个输入数据集,以及两个或更多要比较的LLMs、链或代理。评估会汇总结果以确定首选模型。
评估过程涉及几个步骤:
- 创建评估器:使用
load_evaluator()
函数加载评估器,指定评估器的类型(在本例中为pairwise_string)。 - 选择数据集:使用
load_dataset()
函数加载一个输入数据集。 - 定义要比较的模型:使用必要的配置初始化要比较的LLMs、链或代理。这涉及初始化语言模型以及所需的任何其他工具或代理。
- 生成响应:为每个模型生成输出,然后进行评估。通常,这是分批完成的,以提高效率。
- 评估对:通过比较不同模型对每个输入的输出来评估结果。通常使用随机选择顺序来减少位置偏差。
以下是来自成对字符串比较文档的一个示例:
ini
from langchain.evaluation import load_evaluator
evaluator = load_evaluator("labeled_pairwise_string")
evaluator.evaluate_string_pairs(
prediction="there are three dogs",
prediction_b="4",
input="how many dogs are in the park?",
reference="four",
)
评估器的输出应如下所示:
vbnet
{'reasoning': "Both assistants provided a direct answer to the user's question. However, Assistant A's response is incorrect as it stated there are three dogs in the park, while the reference answer indicates there are four. On the other hand, Assistant B's response is accurate and matches the reference answer. Therefore, considering the criteria of correctness and accuracy, Assistant B's response is superior. \n\nFinal Verdict: [[B]]",
'value': 'B',
'score': 0
}
评估结果包括一个介于0和1之间的分数,表示每个代理的有效性,有时还包括解释评估过程并证明分数的推理。在这个特定的例子中,与参考文本进行比较,两个结果基于输入事实上都是不正确的。我们可以移除参考文本,让一个LLM来判断输出。
根据标准进行比较
LangChain提供了几个预定义的评估器,用于不同的评估标准。这些评估器可用于基于特定规则或标准集评估输出。一些常见的标准包括简洁性、相关性、正确性、连贯性、实用性和争议性。
CriteriaEvalChain允许您根据自定义或预定义的标准评估模型的输出。它提供了一种验证LLM或链输出是否符合定义的一组标准的方式。您可以使用该评估器来评估生成的输出的正确性、相关性、简洁性和其他方面。
CriteriaEvalChain可以配置为使用或不使用参考标签。在没有参考标签的情况下,评估器依赖于LLM的预测答案,并根据指定的标准对其进行评分。有了参考标签,评估器将预测的答案与参考标签进行比较,并确定其是否符合标准。
LangChain中默认使用的评估LLM是GPT-4。然而,您可以通过指定其他聊天模型(例如ChatAnthropic或ChatOpenAI)及其所需的设置(例如温度)来配置评估LLM。通过将LLM对象作为参数传递给load_evaluator()
函数,可以加载自定义LLM的评估器。
LangChain支持自定义标准和预定义评估原则。可以使用包含criterion_name: criterion_description对的字典来定义自定义标准。这些标准可用于根据特定要求或规则评估输出。
以下是一个简单的示例:
makefile
custom_criteria = {
"simplicity": "Is the language straightforward and unpretentious?",
"clarity": "Are the sentences clear and easy to understand?",
"precision": "Is the writing precise, with no unnecessary words or details?",
"truthfulness": "Does the writing feel honest and sincere?",
"subtext": "Does the writing suggest deeper meanings or themes?",
}
evaluator = load_evaluator("pairwise_string", criteria=custom_criteria)
evaluator.evaluate_string_pairs(
prediction="Every cheerful household shares a similar rhythm of joy; but sorrow, in each household, plays a unique, haunting melody.",
prediction_b="Where one finds a symphony of joy, every domicile of happiness resounds in harmonious,"
" identical notes; yet, every abode of despair conducts a dissonant orchestra, each"
" playing an elegy of grief that is peculiar and profound to its own existence.",
input="Write some prose about families.",
)
通过这个结果,我们可以得到两个输出的非常细致入微的比较:
vbnet
{'reasoning': 'Response A is simple, clear, and precise. It uses straightforward language to convey a deep and sincere message about families. The metaphor of music is used effectively to suggest deeper meanings about the shared joys and unique sorrows of families.\n\nResponse B, on the other hand, is less simple and clear. The language is more complex and pretentious, with phrases like "domicile of happiness" and "abode of despair" instead of the simpler "household" used in Response A. The message is similar to that of Response A, but it is less effectively conveyed due to the unnecessary complexity of the language.\n\nTherefore, based on the criteria of simplicity, clarity, precision, truthfulness,
and subtext, Response A is the better response.\n\n[[A]]', 'value': 'A', 'score': 1}
或者,您可以使用LangChain中提供的预定义原则,比如Constitutional AI中的原则。这些原则旨在评估输出的道德、有害和敏感方面。在评估中使用原则允许对生成的文本进行更有针对性的评估。
字符串和语义比较
LangChain支持字符串比较和距离度量,用于评估LLM的输出。字符串距离度量,如Levenshtein和Jaro,提供了对预测字符串与参考字符串之间相似性的定量度量。使用诸如SentenceTransformers等模型的嵌入距离计算生成文本与预期文本之间的语义相似性。 嵌入距离评估器可以使用基于GPT-4或Hugging Face嵌入的嵌入模型计算预测字符串与参考字符串之间的向量距离。这度量了两个字符串之间的语义相似性,并可以提供有关生成文本质量的见解。 以下是文档中的一个快速示例:
ini
from langchain.evaluation import load_evaluator
evaluator = load_evaluator("embedding_distance")
evaluator.evaluate_strings(prediction="I shall go", reference="I shan't go")
评估器返回得分0.0966466944859925。您可以在load_evaluator()
调用中使用embeddings
参数更改所使用的嵌入。 这通常比较老的字符串距离度量方法产生更好的结果,但这些方法也是可用的,可以进行简单的单元测试和准确性评估。字符串比较评估器将预测字符串与参考字符串或输入进行比较。 字符串距离评估器使用距离度量,如Levenshtein或Jaro距离,来衡量预测字符串与参考字符串之间的相似性或不相似性。这提供了预测字符串与参考字符串之间相似程度的定量度量。 最后,还有一个代理轨迹评估器,其中使用evaluate_agent_trajectory()
方法来评估输入、预测和代理轨迹。 我们还可以使用LangSmith,LangChain的一个配套项目,旨在促进将LLM应用从原型转向生产,以与数据集比较性能。让我们通过一个示例逐步进行!
运行对数据集的评估
正如我们之前提到的,全面的基准测试和评估,包括测试,对于安全性、健壮性和预期行为至关重要。我们可以在LangSmith中对基准数据集运行评估,接下来我们将看到如何进行。首先,请确保您在LangSmith上创建一个帐户:smith.langchain.com/。 您可以获取一个API密钥,并将其设置为环境变量 LANGCHAIN_API_KEY
。我们还可以为项目ID和追踪设置环境变量:
lua
import os
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_PROJECT"] = "My Project"
这配置LangChain记录追踪。如果我们不告诉LangChain项目ID,它将记录在默认项目中。进行了这些设置后,当我们运行LangChain代理或链时,我们将能够在LangSmith上看到追踪。 让我们记录一次运行!
java
from langchain.chat_models import ChatOpenAI
llm = ChatOpenAI()
llm.predict("Hello, world!")
我们可以在LangSmith上找到所有这些运行。LangSmith在LangSmith项目页面上列出了迄今为止的所有运行:smith.langchain.com/projects 我们还可以通过LangSmith API找到所有运行:
scss
from langsmith import Client
client = Client()
runs = client.list_runs()
print(runs)
我们可以按特定项目或按运行类型(例如,chain)列出运行。每个运行都带有输入和输出,分别为runs[0].inputs
和runs[0].outputs
。 我们可以使用create_example_from_run()
函数从现有代理运行创建数据集,或者从其他任何地方创建数据集。以下是使用一组问题创建数据集的方法:
makefile
questions = [
"A ship's parts are replaced over time until no original parts remain. Is it still the same ship? Why or why not?", # 潘多拉之船悖论
"If someone lived their whole life chained in a cave seeing only shadows, how would they react if freed and shown the real world?", # 柏拉图的寓言
"Is something good because it is natural, or bad because it is unnatural? Why can this be a faulty argument?", # 自然性争议
"If a coin is flipped 8 times and lands on heads each time, what are the odds it will be tails next flip? Explain your reasoning.", # 赌徒谬误
"Present two choices as the only options when others exist. Is the statement "You're either with us or against us" an example of false dilemma? Why?", # 虚假困境
"Do people tend to develop a preference for things simply because they are familiar with them? Does this impact reasoning?", # 熟悉效应
"Is it surprising that the universe is suitable for intelligent life since if it weren't, no one would be around to observe it?", # 类人原理
"If Theseus' ship is restored by replacing each plank, is it still the same ship? What is identity based on?", # 忒修斯之船悖论
"Does doing one thing really mean that a chain of increasingly negative events will follow? Why is this a problematic argument?", # 滑坡谬误
"Is a claim true because it hasn't been proven false? Why could this impede reasoning?", # 无知谬误
]
shared_dataset_name = "Reasoning and Bias"
ds = client.create_dataset(
dataset_name=shared_dataset_name, description="A few reasoning and cognitive bias questions",
)
for q in questions:
client.create_example(inputs={"input": q}, dataset_id=ds.id)
然后,我们可以像这样在数据集上定义LLM代理或链:
python
from langchain.chat_models import ChatOpenAI
from langchain.chains import LLMChain
llm = ChatOpenAI(model="gpt-4", temperature=0.0)
def construct_chain():
return LLMChain.from_string(
llm,
template="Help out as best you can.\nQuestion: {input}\nResponse: ",
)
要在数据集上运行评估,我们可以指定LLM,或者为了并行性,使用构造函数为每个输入初始化模型或LLM应用。现在,为了评估性能并针对我们的数据集,我们需要像在前一节中看到的那样定义评估器:
ini
from langchain.smith import RunEvalConfig
evaluation_config = RunEvalConfig(
evaluators=[
RunEvalConfig.Criteria({"helpfulness": "Is the response helpful?"}),
RunEvalConfig.Criteria({"insightful": "Is the response carefully thought out?"})
]
)
如所见,标准由一个字典定义,其中标准是键,要检查的问题是值。 我们将数据集连同带有评估器的评估配置传递给run_on_dataset()
,以生成度量和反馈:
ini
from langchain.smith import run_on_dataset
results = run_on_dataset(
client=client,
dataset_name=shared_dataset_name,
dataset=dataset,
llm_or_chain_factory=construct_chain,
evaluation=evaluation_config
)
类似地,我们可以将数据集和评估器传递给run_on_dataset()
,以异步方式生成度量和反馈。 我们可以在LangSmith UI中查看评估器的反馈,以确定改进的方向:
我们可以点击其中任何一个评估以查看一些详细信息,例如对于精心思考的评估器,我们会得到包含LLM的原始答案的这个提示:
csharp
You are assessing a submitted answer on a given task or input based on a set of criteria. Here is the data:
[BEGIN DATA]
***
[Input]: Is something good because it is natural, or bad because it is unnatural? Why can this be a faulty argument?
***
[Submission]: The argument that something is good because it is natural, or bad because it is unnatural, is often referred to as the "appeal to nature" fallacy. This argument is faulty because it assumes that what is natural is automatically good or beneficial, and what is unnatural is automatically bad or harmful. However, this is not always the case. For
example, many natural substances can be harmful or deadly, such as certain plants or animals. Conversely, many unnatural things, such as modern medicine or technology, can greatly benefit our lives. Therefore, whether something is natural or unnatural is not a reliable indicator of its value or harm.
***
[Criteria]: insightful: Is the response carefully thought out?
***
[END DATA]
Does the submission meet the Criteria? First, write out in a step by step manner your reasoning about each criterion to be sure that your conclusion is correct. Avoid simply stating the correct answers at the outset. Then print only the single character "Y" or "N" (without quotes or punctuation) on its own line corresponding to the correct answer of whether the submission meets all criteria. At the end, repeat just the letter again by itself on a new line.
我们得到了这个评估:
kotlin
The criterion is whether the response is insightful and carefully thought out. The submission provides a clear and concise explanation of the "appeal to nature" fallacy, demonstrating an understanding of the concept. It also provides examples to illustrate why this argument can be faulty, showing that the respondent has thought about the question in depth. The response is not just a simple yes or no, but a detailed explanation that shows careful consideration of the question. Therefore, the submission does meet the criterion of being insightful and carefully thought out.
提高性能的一种方法是使用少量样本提示。LangSmith也可以帮助我们实现这一点。在LangSmith文档中可以找到更多关于这方面的例子。
我们还没有讨论数据注释队列,这是LangSmith中的一个新功能,它解决了在原型制作后出现的一个关键缺口。每个日志可以通过错误等属性进行过滤,以便关注有问题的情况,或者可以手动进行审查和注释,添加标签或反馈并根据需要进行编辑。编辑后的日志可以添加到数据集中,用于诸如微调模型等用途。
这就结束了这里关于评估的话题。现在,我们已经评估了我们的代理,假设我们对性能感到满意并决定部署它!接下来应该怎么做呢?
如何部署LLM应用
鉴于在各个行业中越来越广泛使用LLM,了解如何有效地将模型和应用程序部署到生产环境中变得至关重要。部署服务和框架可以帮助克服技术难题。有许多不同的方法可以将LLM应用或具有生成AI的应用程序推向生产。
生产部署需要对生成AI生态系统进行研究和了解,其中包括以下不同方面:
- 模型和LLM即服务:LLM和其他模型可以在本地运行,也可以作为API在供应商提供的基础设施上提供。
- 推理启发式:检索增强生成(RAG),思维树等。
- 向量数据库:帮助检索与提示相关的上下文信息。
- 提示工程工具:促进上下文学习,无需昂贵的微调或敏感数据。
- 预训练和微调:针对特定任务或领域专业化的模型。
- 提示记录、测试和分析:受到对理解和改善LLM性能的渴望的启发而兴起的新兴领域。
- 自定义LLM堆栈:一组用于构建和部署基于LLM的解决方案的工具。
我们在第1章《什么是生成AI?》和第3章《开始使用LangChain》中讨论了模型,第4章《构建强大的助手》和第7章《用于数据科学的LLM》中讨论了推理启发法,第5章《构建类似ChatGPT的聊天机器人》中讨论了向量数据库,第8章《定制LLM及其输出》中讨论了提示和微调。在本章中,我们将重点关注部署的日志记录、监控和自定义工具。
LLM通常是通过外部LLM提供商或自托管模型来利用的。使用外部提供商,计算负担由公司(例如OpenAI或Anthropic)承担,而LangChain则促进业务逻辑的实现。然而,自托管开源LLM可以显着降低成本、延迟和隐私问题。
某些基础设施工具提供了完整的解决方案。例如,您可以使用Chainlit部署LangChain代理,创建类似于ChatGPT的UI。关键功能包括中间步骤可视化、元素管理和显示(图像、文本、轮播等)以及云部署。BentoML是一个框架,可以将机器学习应用容器化,将其用作微服务独立运行和扩展,并自动生成OpenAPI和gRPC端点。
您还可以将LangChain部署到不同的云服务端点,例如Azure Machine Learning在线端点。使用Steamship,LangChain开发人员可以快速部署他们的应用,功能包括生产就绪的端点、跨依赖项的水平扩展、应用状态的持久存储以及多租户支持。
维护LangChain的公司LangChain AI正在开发一个名为LangServe的新库。该库建立在FastAPI和Pydantic之上,简化了文档和部署流程。通过与包括GCP的Cloud Run和Replit在内的平台集成,进一步促进了部署,允许从现有的GitHub存储库快速克隆。基于用户反馈,其他平台的额外部署说明将很快推出。
所有这些都有详细的文档,其中包含不同的用例,通常直接涉及LLM。我们已经展示了使用Streamlit和Gradio的示例,并讨论了如何将它们部署到Hugging Face Hub作为示例。
运行LLM应用程序有一些主要要求:
- 可扩展的基础设施,以处理计算密集型模型和潜在的流量峰值
- 低延迟,用于实时提供模型输出
- 持久存储,用于管理长时间的对话和应用程序状态
- API,用于集成到最终用户应用程序
- 监控和日志记录,以跟踪指标和模型行为
在大量用户交互和与LLM服务相关的高成本的情况下,保持成本效益可能是具有挑战性的。管理效率的策略包括自托管模型、根据流量自动调整资源分配、使用抢占式实例、独立扩展和批量请求以更好地利用GPU资源。
工具和基础设施的选择决定了这些要求之间的权衡。灵活性和易用性非常重要,因为我们希望能够迅速迭代,这对于ML和LLM领域的动态性至关重要。避免被束缚在一个解决方案上是至关重要的。一个灵活、可扩展的服务层,适应各种模型,是关键的。模型组合和云提供商的选择是这种灵活性方程的一部分。
为了获得最大程度的灵活性,基础设施即代码(IaC)工具,如Terraform、CloudFormation或Kubernetes YAML文件,可以可靠而快速地重新创建您的基础设施。此外,持续集成和持续交付(CI/CD)流水线可以自动化测试和部署过程,以减少错误并促进更快的反馈和迭代。
设计强大的LLM应用服务可能是一项复杂的任务,需要在评估服务框架时理解权衡和关键考虑因素。利用这些解决方案之一进行部署使开发人员能够专注于开发有影响的AI应用,而不是基础设施。
正如前面提到的,LangChain与几个开源项目和框架(如Ray Serve、BentoML、OpenLLM、Modal和Jina)协同工作。在接下来的章节中,我们将使用不同的工具部署应用程序。我们将从基于FastAPI的聊天服务Web服务器开始。
FastAPI web服务
FastAPI是部署Web服务器的非常受欢迎的选择。设计快速、易于使用且高效,它是一个用于使用Python构建API的现代、高性能的Web框架。Lanarky是一个用于部署LLM应用程序的小型开源库,提供了对Flask API和Gradio的便捷封装,用于部署LLM应用程序。这意味着您可以同时获得REST API端点和浏览器内可视化,而且只需要很少的代码。
Representational State Transfer Application Programming Interface(REST API)是一组规则和协议,允许不同的软件应用程序通过互联网进行通信。它遵循REST的原则,这是一种设计网络应用程序的架构风格。REST API使用HTTP方法(如GET、POST、PUT或DELETE)对资源执行操作,通常以标准格式(例如JSON或XML)发送和接收数据。
在库文档中,有几个示例,包括带有Sources Chain的检索问答、对话检索应用程序以及零猜测代理。通过另一个示例,我们将使用Lanarky实现一个聊天机器人Web服务器。
我们将使用Lanarky设置一个Web服务器,该服务器创建一个包含LLM模型和设置的ConversationChain实例,并定义用于处理HTTP请求的路由。这个配方的完整代码可以在这里找到:github.com/benman1/gen...
首先,我们导入必要的依赖项,包括用于创建Web服务器的FastAPI,以及用于处理LLM对话的ConversationChain和ChatOpenAI,以及一些其他所需的模块:
javascript
from fastapi import FastAPI
from langchain import ConversationChain
from langchain.chat_models import ChatOpenAI
from lanarky import LangchainRouter
from starlette.requests import Request
from starlette.templating import Jinja2Templates
请注意,您需要按照第3章"使用LangChain入门"中的说明设置环境变量。我们可以通过导入config模块中的setup_environment()方法来做到这一点,就像我们在许多其他示例中看到的那样:
arduino
from config import set_environment
set_environment()
现在我们创建一个FastAPI应用程序,它将处理大多数路由,除了Lanarky将在稍后处理的LangChain特定请求:
ini
app = FastAPI()
我们可以创建一个ConversationChain实例,指定LLM模型及其设置:
ini
chain = ConversationChain(
llm=ChatOpenAI(
temperature=0,
streaming=True,
),
verbose=True,
)
将templates变量设置为Jinja2Templates类,指定了模板所在的目录,用于渲染。这指定了网页将如何显示,允许进行各种自定义:
ini
templates = Jinja2Templates(directory="webserver/templates")
使用FastAPI装饰器@app.get定义了一个处理HTTP GET请求的根路径(/)的端点。与此端点关联的函数返回一个模板响应,用于渲染index.html模板:
python
@app.get("/")
async def get(request: Request):
return templates.TemplateResponse("index.html", {"request": request})
创建一个router对象作为LangChainRouter类。该对象负责定义和管理与ConversationChain实例关联的路由。我们可以向路由器添加其他路由,以处理基于JSON的聊天,甚至可以与WebSocket请求一起工作:
ini
langchain_router = LangchainRouter(
langchain_url="/chat", langchain_object=chain, streaming_mode=1
)
langchain_router.add_langchain_api_route(
"/chat_json", langchain_object=chain, streaming_mode=2
)
langchain_router.add_langchain_api_websocket_route("/ws", langchain_object=chain)
app.include_router(langchain_router)
现在我们的应用程序知道如何处理发送到路由器内定义的指定路由的请求,将它们指向适当的函数或处理程序进行处理。
我们将使用Uvicorn运行我们的应用程序。Uvicorn在支持高性能、异步框架(如FastAPI和Starlette)方面表现出色。由于其异步特性,它以处理大量并发连接的能力而闻名,并在重负载下表现良好。
我们可以从终端运行Web服务器,如下所示:
lua
uvicorn webserver.chat:app --reload
该命令启动一个Web服务器,您可以在浏览器中查看,地址为:http://127.0.0.1:8000
--reload开关特别方便,因为它意味着一旦您进行了任何更改,服务器将自动重新启动。
这是我们刚刚部署的聊天机器人应用程序的快照:
我认为这看起来相当不错,考虑到我们所做的工作很少。它还带有一些不错的功能,如REST API、Web UI和WebSocket接口。虽然Uvicorn本身没有内置的负载平衡功能,但它可以与其他工具或技术(如Nginx或HAProxy)一起使用,在部署设置中实现负载平衡,将传入的客户端请求分配到多个工作进程或实例上。将Uvicorn与负载均衡器一起使用可以实现水平扩展,以处理大量流量,提高客户端的响应时间,并增强容错性。最后,Lanarky还与Gradio兼容,所以通过添加几行额外的代码,我们就可以将此Web服务器作为Gradio应用程序运行起来。 在接下来的部分,我们将看到如何使用Ray构建强大且具有成本效益的生成式AI应用程序。我们将使用LangChain进行文本处理构建一个简单的搜索引擎,然后使用Ray进行扩展索引和服务。
Ray
Ray提供了一个灵活的框架,通过在集群中扩展生成式AI工作负载,以满足生产中复杂神经网络的基础架构挑战。Ray支持常见的部署需求,如低延迟服务、分布式训练和大规模批量推断。Ray还可以轻松启动按需微调或将现有工作负载从一台机器扩展到多台机器。其功能包括:
- 使用Ray Train在GPU集群上调度分布式训练作业
- 使用Ray Serve以低延迟规模部署预训练模型
- 使用Ray Data在CPU和GPU上并行运行大规模批量推断
- 编排端到端生成式AI工作流,包括训练、部署和批处理处理
我们将使用LangChain和Ray构建一个简单的搜索引擎,用于Ray文档,这是根据Waleed Kadous为anyscale博客和GitHub上的langchain-ray存储库实现的示例。可以在此处找到:www.anyscale.com/blog/llm-op...
你可以将此视为第5章《构建类似ChatGPT的聊天机器人》食谱的扩展。你还将看到如何将其运行为FastAPI服务器。该食谱的完整代码在此处:github.com/benman1/gen...
首先,我们将摄取和索引Ray文档,以便我们可以快速找到与搜索查询相关的段落:
ini
# 使用LangChain加载Ray文档
loader = RecursiveUrlLoader("docs.ray.io/en/master/")
docs = loader.load()
# 使用LangChain分割器将文档分割成句子
chunks = text_splitter.create_documents(
[doc.page_content for doc in docs],
metadatas=[doc.metadata for doc in docs])
# 使用transformers将句子嵌入向量
embeddings = LocalHuggingFaceEmbeddings('multi-qa-mpnet-base-dot-v1')
# 使用LangChain通过FAISS索引向量
db = FAISS.from_documents(chunks, embeddings)
这通过摄取文档、将其分割成块、嵌入句子和索引向量来构建我们的搜索索引。另外,我们可以通过并行化嵌入步骤来加速索引:
ini
# 定义分片处理任务
@ray.remote(num_gpus=1)
def process_shard(shard):
embeddings = LocalHuggingFaceEmbeddings('multi-qa-mpnet-base-dot-v1')
return FAISS.from_documents(shard, embeddings)
# 将块分割成8个分片
shards = np.array_split(chunks, 8)
# 并行处理分片
futures = [process_shard.remote(shard) for shard in shards]
results = ray.get(futures)
# 合并索引分片
db = results[0]
for result in results[1:]:
db.merge_from(result)
通过在每个分片上并行运行嵌入,我们可以显著减少索引时间。
我们将数据库索引保存到磁盘:
scss
db.save_local(FAISS_INDEX_PATH)
FAISS_INDEX_PATH是一个任意的文件名。我将其设置为faiss_index.db。
接下来,我们将看看如何使用Ray Serve为搜索查询提供服务:
ini
# 加载索引和嵌入
db = FAISS.load_local(FAISS_INDEX_PATH)
embedding = LocalHuggingFaceEmbeddings('multi-qa-mpnet-base-dot-v1')
@serve.deployment
class SearchDeployment:
def __init__(self):
self.db = db
self.embedding = embedding
def __call__(self, request):
query_embed = self.embedding(request.query_params["query"])
results = self.db.max_marginal_relevance_search(query_embed)
return format_results(results)
deployment = SearchDeployment.bind()
# 启动服务
serve.run(deployment)
这应该加载我们生成的索引,并允许我们将搜索查询作为Web端点提供服务!
如果将此保存到名为serve_vector_store.py的文件中,我们可以使用以下命令从search_engine目录中运行服务器:
ini
PYTHONPATH=../ python serve_vector_store.py
在终端中运行此命令会给我看到以下输出:
sql
Started a local Ray instance.
View the dashboard at 127.0.0.1:8265
这条消息向我们展示了仪表板的URL,我们可以在浏览器中访问。然而,搜索服务器正在本地主机的8080端口上运行。我们可以从Python中查询它:
ini
import requests
query = "What are the different components of Ray"
" and how can they help with large language models (LLMs)?"
response = requests.post("http://localhost:8000/", params={"query": query})
print(response.text)
对我来说,服务器获取了Ray用例页面:docs.ray.io/en/latest/r...
我真的很喜欢Ray Dashboard的监控功能,它看起来像这样:
该仪表板非常强大,因为它可以提供大量指标和其他信息。收集指标很容易,因为您只需在部署对象或演员中设置和更新Counter、Gauge、Histogram等类型的变量。对于时间序列图表,您应该安装Prometheus或Grafana服务器。
这个实用指南带您了解了使用LangChain和Ray在本地部署LLM应用的关键步骤。我们首先摄取和索引文档,以支持Ray文档的语义搜索引擎。通过利用Ray的分布式能力,我们并行化了密集的嵌入任务以加速索引时间。然后,我们通过Ray Serve提供了搜索应用,它为低延迟查询提供了灵活的框架。Ray仪表板提供了有关指标的有益监控洞察,如请求速率、延迟和错误。
正如您在GitHub上的完整实现中所看到的,我们还可以将其作为FastAPI服务器启动。这完成了我们使用LangChain和Ray构建的简单语义搜索引擎。
随着模型和LLM应用变得更加复杂,并高度交织到业务应用的结构中,生产过程中的可观察性和监控变得必不可少,以确保它们的准确性、效率和可靠性是持续的。接下来的部分重点介绍了监控LLM的重要性,并突出了全面监控策略要跟踪的关键指标。
如何观察LLM应用
现实世界运营的动态性意味着离线评估中考虑的条件几乎不可能涵盖LLMs在生产系统中可能遇到的所有情景。因此,我们需要在生产环境中实施可观察性------更连续、实时的观察,以捕捉离线测试无法预料到的异常。
我们需要实施监控工具,定期跟踪关键指标。这包括用户活动、响应时间、流量量、财务支出、模型行为模式以及对应用程序的整体满意度。持续监视允许及早检测数据漂移或能力意外下降等异常情况。
可观察性允许在模型与实际输入数据和用户进行交互时监视行为和结果。它包括日志记录、跟踪、追踪和警报机制,以确保系统正常运行、性能优化,并及早发现模型漂移等问题。
追踪、跟踪和监控是软件运营和管理领域的三个重要概念。尽管它们都与理解和改进系统性能有关,但它们各自具有不同的角色。追踪和跟踪是为了保留详细的历史记录以进行分析和调试,而监控旨在实时观察并立即意识到问题,以确保系统在任何时候都能以最佳状态运行。这三个概念都属于可观察性范畴。
监控是持续监视系统或应用程序性能的过程。这可能涉及持续收集和分析与系统健康有关的指标,如内存使用、CPU利用率、网络延迟以及整体应用程序/服务性能(如响应时间)。有效的监控包括建立异常或意外行为的警报系统------在超过某些阈值时发送通知。虽然追踪和跟踪是为了保留详细的历史记录以进行分析和调试,但监控旨在实时观察并立即意识到问题,以确保系统在任何时候都能以最佳状态运行。
监控和可观察性的主要目标是通过实时数据洞察LLM应用程序的性能和行为。这有助于以下方面:
- 防止模型漂移:由于输入数据或用户行为特征的变化,LLM的性能可能会随时间而下降。定期监控可以早期识别这类情况并采取纠正措施。
- 性能优化:通过跟踪推理时间、资源使用和吞吐量等指标,您可以进行调整以提高LLM应用程序在生产中的效率和效果。
- A/B测试:帮助比较模型中轻微差异可能导致不同结果的方式,从而辅助决策改进模型。
- 调试问题:监控有助于识别运行时可能出现的未预料到的问题,从而实现快速解决。
- 避免幻觉:我们希望确保响应的事实准确性,并且------如果我们使用RAG------检索的上下文质量,以及在使用上下文时的足够有效性。
- 确保适当的行为:响应应当相关、完整、有帮助、无害,符合所需的格式,并符合用户的意图。
由于有许多监控方式,因此制定监控策略非常重要。在制定策略时,应考虑以下一些事项:
- 要监控的指标:定义关键的感兴趣指标,如预测准确性、延迟、吞吐量等,基于期望的模型性能。
- 监控频率:监控频率应根据模型对操作的关键性确定------高度关键的模型可能需要接近实时的监控。
- 记录:日志应提供有关LLM执行的每个相关操作的详细信息,以便分析人员可以追踪任何异常。
- 警报机制:如果检测到异常行为或性能急剧下降,系统应发出警报。
在生产中监控LLMs和LLM应用程序具有多重目的,包括评估模型性能、检测异常或问题、优化资源利用以及确保一致且高质量的输出。通过通过验证、影子启动和解释以及可靠的离线评估持续评估LLM应用程序的行为和性能,组织可以识别和缓解潜在风险、保持用户信任,并提供最佳体验。
在监控LLMs和LLM应用程序时,组织可以依赖于一系列多样化的指标,以评估性能和用户体验的不同方面。除了关键的调性、毒性和无害性等关键指标之外,以下是一个扩展列表,涵盖了更广泛的评估领域:
- 推理延迟:衡量LLM应用程序处理请求并生成响应的时间。较低的延迟确保更快、更响应迅速的用户体验。
- 每秒查询(QPS):计算LLM在给定时间内可以处理的查询或请求的数量。监控QPS有助于评估可伸缩性和容量规划。
- 每秒标记(TPS):跟踪LLM应用程序生成标记的速率。TPS指标有助于估算计算资源需求,并了解模型的效率。
- 标记使用:标记数与资源使用(如硬件利用率、延迟和成本)相关。
- 错误率:监视LLM应用程序响应中错误或失败的发生,确保错误率保持在可接受的范围内,以维持输出的质量。
- 资源利用率:衡量计算资源(如CPU、内存和GPU)的消耗,以减少成本并避免瓶颈。
- 模型漂移:通过将其输出与基线或基本事实进行比较,检测LLM应用程序行为随时间的变化,确保模型保持准确并与预期结果一致。
- 超出分布的输入:识别超出LLM训练数据意图分布的输入或查询,这可能导致意外或不可靠的响应。
- 用户反馈指标:监视用户反馈渠道,以获取有关用户满意度的见解,识别改进的领域,并验证LLM应用程序的有效性。
- 用户参与:我们可以追踪用户如何使用我们的应用程序,例如会话的频率和持续时间,或特定功能的使用。
- 工具/检索使用:检索和工具使用的实例的详细信息。
这只是一个小的选择。这个列表可以轻松地通过与任务性能或LLM应用程序行为相关的Site Reliability Engineering(SRE)的许多其他指标进行扩展。
数据科学家和机器学习工程师应使用诸如LIME和SHAP等模型解释工具检查模型的陈旧性、不正确的学习和偏见。最具预测性的特征突然变化可能表明数据泄漏。
离线指标(例如AUC)并不总是与对转化率的在线影响相关,因此重要的是找到可靠的离线指标,这些指标可以转化为业务相关的在线收益,理想情况下是直接的指标,如点击和购买,这些指标直接受到系统的影响。
有效的监控使LLMs成功部署和利用,增强对其能力的信心,并培养用户的信任。然而,需要注意的是,在依赖云服务平台时,应研究服务提供商的隐私和数据保护政策。此部分的所有示例代码都可在GitHub上的对应书籍存储库的monitoring_and_evaluation
目录中找到。
在下一节中,我们将通过监控代理的轨迹开始探索可观察性的旅程。
追踪响应
在这个上下文中,"tracking" 指的是记录响应的全部溯源信息,包括工具、检索、包含的数据以及生成输出的LLM。这对于审核和响应的可重现性非常重要。在本节中,我们将互换使用 "tracking" 和 "tracing" 这两个术语。
"Tracking" 通常指的是记录和管理应用程序或系统中特定操作或一系列操作的信息的过程。例如,在机器学习应用程序或项目中,跟踪可能涉及在不同实验或运行中记录参数、超参数、指标和结果。它提供了一种记录进展和随时间变化的方式。
"Tracing" 是跟踪的一种更专业的形式。它涉及记录软件/系统的执行流程。特别是在分布式系统中,一个单一的事务可能涉及多个服务,跟踪有助于保持审核或面包屑轨迹,提供有关请求路径的详细信息。这种细粒度的视图使开发人员能够了解各个微服务之间的交互,并通过精确定位事务路径中发生故障或延迟的位置来解决问题。
由于代理的广泛行为范围和生成能力,跟踪代理的轨迹可能具有挑战性。LangChain 提供了轨迹跟踪和评估功能,因此通过 LangChain 查看代理的痕迹非常容易!只需在初始化代理或 LLM 时将 return_intermediate_steps 参数设置为 True。
让我们将一个工具定义为一个函数。重用函数文档字符串作为工具描述非常方便。该工具首先向网站地址发送一个 ping,并返回有关传输的数据包和延迟,或者在出现错误的情况下返回错误消息:
python
import subprocess
from urllib.parse import urlparse
from pydantic import HttpUrl
from langchain.tools import StructuredTool
def ping(url: HttpUrl, return_error: bool) -> str:
"""Ping the fully specified url. Must include https:// in the url."""
hostname = urlparse(str(url)).netloc
completed_process = subprocess.run(
["ping", "-c", "1", hostname], capture_output=True, text=True
)
output = completed_process.stdout
if return_error and completed_process.returncode != 0:
return completed_process.stderr
return output
ping_tool = StructuredTool.from_function(ping)
现在,我们设置一个代理,该代理使用这个工具和一个 LLM,通过一个提示进行调用:
ini
from langchain.chat_models import ChatOpenAI
from langchain.agents import initialize_agent, AgentType
llm = ChatOpenAI(model="gpt-3.5-turbo-0613", temperature=0)
agent = initialize_agent(
llm=llm,
tools=[ping_tool],
agent=AgentType.OPENAI_MULTI_FUNCTIONS,
return_intermediate_steps=True, # 重要!
)
result = agent("What's the latency like for https://langchain.com?")
代理报告如下:
rust
The latency for https://langchain.com is 13.773 ms
在 results["intermediate_steps"]
中,我们可以看到关于代理行为的大量信息:
python
[(_FunctionsAgentAction(tool='ping', tool_input={'url': 'https://langchain.com', 'return_error': False}, log="\nInvoking: `ping` with `{'url': 'https://langchain.com', 'return_error': False}`\n\n\n", message_log=[AIMessage(content='', additional_kwargs={'function_call': {'name': 'tool_selection', 'arguments': '{\n "actions": [\n {\n "action_name": "ping",\n "action": {\n "url": "https://langchain.com",\n "return_error": false\n }\n }\n ]\n}'}}, example=False)]), 'PING langchain.com (35.71.142.77): 56 data bytes\n64 bytes from 35.71.142.77: icmp_seq=0 ttl=249 time=13.773 ms\n\n--- langchain.com ping statistics ---\n1 packets transmitted, 1 packets received, 0.0% packet loss\nround-trip min/avg/max/stddev = 13.773/13.773/13.773/0.000 ms\n')]
通过提供对系统的可见性并协助问题识别和优化工作,这种跟踪和评估方式可以非常有帮助。 LangChain文档演示了如何使用轨迹评估器来检查代理生成的完整动作和响应序列,并对OpenAI函数代理进行评分。这可能是非常强大的东西! 让我们超越LangChain,看看还有哪些观测工具可用!
可观测性工具
有许多工具可通过LangChain集成或通过回调使用:
- Argilla:Argilla是一个开源的数据整理平台,可以将用户反馈(人在循环工作流程)与提示和响应集成,以整理用于微调的数据集。
- Portkey:Portkey为LangChain增加了基本的MLOps功能,如监视详细指标、跟踪链、缓存以及通过自动重试提高可靠性。
- Comet.ml:Comet提供强大的MLOps功能,用于跟踪实验、比较模型和优化AI项目。
- LLMonitor:跟踪大量指标,包括成本和使用分析(用户跟踪)、跟踪和评估工具(开源)。
- DeepEval:记录默认指标,包括相关性、偏见和毒性。还可以帮助测试和监控模型漂移或降级。
- Aim:一个用于ML模型可视化和调试的开源平台。它记录输入、输出和组件的序列化状态,使用户可以检查单个LangChain执行并将多个执行进行比较。
- Argilla:用于跟踪训练数据、验证准确性、参数等在机器学习实验中的各种指标的开源平台。
- Splunk:Splunk的机器学习工具包可以提供对生产中机器学习模型的可观测性。
- ClearML:用于自动化训练管道,实现从研究到生产的无缝过渡的开源工具。
- IBM Watson OpenScale:提供有关AI健康状况的见解,快速识别和解决问题,以帮助降低风险。
- DataRobot MLOps:监视和管理模型,以在影响性能之前检测问题。
- Datadog APM 集成:此集成允许捕获LangChain请求、参数、提示完成,并可视化LangChain操作。还可以捕获请求延迟、错误以及令牌/成本使用等指标。
- Weights and Biases (W&B) 跟踪:我们已经展示了使用W&B监视微调收敛的示例,但它还可以用于跟踪其他指标并记录和比较提示。
- Langfuse:使用此开源工具,我们可以方便地监视有关LangChain代理和工具的延迟、成本和分数的详细信息。
- LangKit:从提示和响应中提取信号以确保安全性和安全性。它目前专注于文本质量、相关度指标和情感分析。
还有更多工具处于不同成熟阶段。例如,AgentOps SDK旨在提供一个用于评估和开发强大可靠AI代理的工具包接口,但目前仍处于封闭alpha阶段。
这些集成大多很容易集成到LLM管道中。例如,对于W&B,您可以通过将LANGCHAIN_WANDB_TRACING环境变量设置为True来启用跟踪。或者,您可以使用wandb_tracing_enabled()上下文管理器来跟踪特定的代码块。使用Langfuse,我们可以将langfuse.callback.CallbackHandler()作为参数传递给chain.run()调用。
其中一些工具是开源的,这些平台的优点是它们允许进行全面的定制和在隐私重要的用例中进行本地部署。例如,Langfuse是开源的,并提供自托管选项。选择最适合您需求的选项,并按照LangChain文档中提供的说明启用代理的跟踪。虽然该平台最近才发布,但我相信未来还会有更多的内容,但已经很好地看到代理如何执行的追踪、检测循环和延迟问题。它使共享追踪和统计信息与合作者讨论改进成为可能。
现在让我们看看LangChain的另一个伴随项目LangSmith,它专为可观测性而开发!
LangSmith
LangSmith是由LangChain AI开发和维护的用于调试、测试、评估和监控LLM(Large Language Models)应用的框架。LangChain AI是LangChain的背后组织。LangSmith作为MLOps的有效工具,专门用于LLMs,提供了覆盖MLOps过程多个方面的功能。它可以帮助开发人员通过提供调试、监控和优化功能,将LLM应用从原型推进到生产。
LangSmith允许您:
- 记录来自LangChain代理、链和其他组件的运行轨迹。
- 创建数据集以基准测试模型性能。
- 配置AI辅助评估器以对模型进行评分。
- 查看指标、可视化和反馈,以进行迭代和改进LLMs。
在LangSmith的Web界面上,我们可以获取大量的图表,显示了一系列统计信息,对于优化延迟、硬件效率和成本可能非常有用,正如我们在监控仪表板中所见:
监控仪表板包括以下图表,可以按不同的时间间隔进行细分:
以下是 LangSmith 中用于我们在"如何评估 LLM 应用"部分看到的基准数据集运行的跟踪示例:
该平台本身并非开源,不过,作为 LangSmith 和 LangChain 背后的公司,LangChain AI 为有隐私顾虑的组织提供了一些自托管的支持。然而,LangSmith 有一些替代品,如 Langfuse、Weights and Biases、Datadog APM、Portkey 和 PromptWatch,它们在某些功能上有一些重叠。我们将在这里重点介绍 LangSmith,因为它在评估和监控方面具有大量功能,并且与 LangChain 集成。
在下一节中,我们将演示如何使用 PromptWatch 跟踪 LLM 在生产环境中的提示。
PromptWatch
PromptWatch 记录与交互期间的响应缓存、链执行、提示和生成输出相关的信息。追踪和监控对于调试和确保审计追踪非常有用。通过 PromptWatch.io,您甚至可以追踪LLM链、操作、检索的文档、输入、输出、执行时间、工具详细信息等各个方面,以实现对系统的完全可见性。
确保您在 PromptWatch.io 上注册并获取您的 API 密钥 -- 您可以在账户设置下找到它。
让我们先处理输入部分:
javascript
from langchain import LLMChain, OpenAI, PromptTemplate
from promptwatch import PromptWatch
正如在第3章《LangChain 入门》中所讨论的,我将所有 API 密钥都设置在 set_environment() 函数中。如果您遵循了我的建议,可以在这些导入语句后添加以下内容:
arduino
from config import set_environment
set_environment()
否则,请确保以您喜欢的方式设置环境变量。接下来,我们需要设置一个提示和一个链:
ini
prompt_template = PromptTemplate.from_template("Finish this sentence {input}")
my_chain = LLMChain(llm=OpenAI(), prompt=prompt_template)
使用 PromptTemplate 类,通过一个变量 input 配置了提示模板,指示用户输入应放置在提示内的位置。
我们可以创建一个 PromptWatch 块,在其中使用输入提示调用 LLMChain:
csharp
with PromptWatch() as pw:
my_chain("The quick brown fox jumped over")
这是一个模型根据提供的提示生成响应的简单示例。我们可以在 PromptWatch.io 上看到这个过程。
我们可以看到提示与LLM的响应。我们还获得了一个包含活动时间序列的仪表板,我们可以在其中深入了解特定时间的响应。在实际场景中,这似乎非常有用,可以有效地监控和分析提示、输出和成本。
该平台允许在 Web 界面中进行深入的分析和故障排除,使用户能够识别问题的根本原因并优化提示模板。我们本可以进行更多的探索,例如关于提示模板和版本控制,但在这里我们只能涵盖这么多。promptwatch.io 也可以帮助进行单元测试和版本控制提示模板。
总结
将训练好的LLM从研究阶段引入实际生产中涉及许多复杂的挑战,涉及可扩展性、监控和意外行为等方面。负责任地部署功能强大、可靠的模型涉及对可扩展性、可解释性、测试和监控等方面进行仔细的规划。通过微调、安全干预和防御性设计等技术,我们能够开发出产生有益、无害和可读输出的应用程序。通过谨慎和准备,生成式人工智能在从医学到教育等各行各业都具有巨大的潜在好处。
我们深入研究了部署和用于部署的工具。特别是,我们使用了FastAPI和Ray部署应用程序。在早期的章节中,我们使用了Streamlit。我们本可以探索更多的工具,例如最近推出的LangServe,它是专为LangChain应用程序开发的。虽然它仍然相对新颖,但绝对值得关注未来的更多发展。
对LLMs的评估对于评估它们的性能和质量至关重要。LangChain支持模型之间的比较评估,检查输出是否符合标准,进行简单的字符串匹配以及语义相似度度量。这些提供了对模型质量、准确性和适当生成的不同见解。系统性的评估是确保LLMs产生有用、相关和明智输出的关键。
监控LLMs是部署和维护这些复杂系统的重要方面。随着LLMs在各种应用中的日益普及,确保其性能、有效性和可靠性至关重要。我们讨论了监控LLMs的重要性,强调了全面监控策略要追踪的关键指标,并举例说明了如何在实践中跟踪指标。
我们研究了诸如PromptWatch和LangSmith之类的不同可观测性工具。LangSmith为使用LangChain构建的LLMs提供了强大的跟踪、基准测试和优化功能。其自动化的评估器、指标和可视化有助于加速LLM的开发和验证。
在下一章,让我们讨论生成式人工智能的未来将会是什么样子。