书接上回,继续往下讲,本节会说一下模型的路由和网关
模型的路由和网关
随着应用程序复杂性的增加和涉及的模型越来越多,
出现了两种类型的工具来帮助使用多个模型:路由和网关
1. 路由
应用程序可以使用不同的模型来响应不同类型的查询。
为不同的查询使用不同的解决方案有几个好处。
首先,这允许您拥有专门的解决方案,
例如一个专门用于技术故障排除的模型和另一个专门用于订阅的模型。
专用模型的性能可能比通用模型更好。
其次,这可以帮助您节省成本。
可以将更简单的查询路由到更便宜的模型,
而不是将所有查询路由到昂贵的模型。
路由器通常由一个意向分类器组成,用于预测用户尝试做什么。
根据预测的意图,将查询路由到相应的解决方案。
例如,对于客户支持聊天机器人,如果目的是:
- 重置密码 – >将此用户路由到有关密码重置的页面
- 要更正计费错误 – >将此用户路由到人工操作员
- 要排查技术问题 – >将此查询路由到为排查问题而优化的模型
意向分类器还可以帮助系统避免超出范围的对话。
例如,可以有一个目的分类器来预测查询是否超出范围。
如果认为查询不合适(例如,如果用户询问您会在即将到来的选举中投票给谁),
聊天机器人可以使用其中一个常用回答礼貌地拒绝参与而不会浪费 API 调用。:
作为聊天机器人,我没有投票的能力。
如果您对我们的产品有任何疑问,我很乐意提供帮助。
如果系统可以访问多个操作,则路由器可以涉及下一个操作预测器,
以帮助系统决定下一步要执行的操作。
一个有效的操作是要求澄清查询是否不明确。
例如,在响应查询“冻结”时,
系统可能会问
“您是要冻结您的账户还是谈论天气”,
或者只是说“对不起。您能详细说明一下吗"?
意图分类器和下一步行动预测器可以是通用模型或专用分类模型。
专用分类模型通常比通用模型小得多、速度更快,
因此系统可以使用多个分类模型,而不会产生显著的额外延迟和成本。
2 网关
模型网关是一个中间层,允许以统一和安全的方式与不同的模型交互。
模型网关最基本的功能是使开发人员能够以相同的方式访问不同的模型,
无论是自托管模型还是 OpenAI 或 Google 等商业 API 背后的模型。
如果模型 API 发生更改,只需更新模型网关,而不必更新使用此模型 API 的所有应用程序。
在最简单的形式中,模型网关是一个统一的包装器,类似于下面的代码示例。
此示例并不意味着具有功能性,因为它不包含任何错误检查或优化:
import google.generativeai as genai
import openai
def openai_model(input_data, model_name, max_tokens):
openai.api_key = os.environ["OPENAI_API_KEY"]
response = openai.Completion.create(
engine=model_name,
prompt=input_data,
max_tokens=max_tokens
)
return {"response": response.choices[0].text.strip()}
def gemini_model(input_data, model_name, max_tokens):
genai.configure(api_key=os.environ["GOOGLE_API_KEY"])
model = genai.GenerativeModel(model_name=model_name)
response = model.generate_content(input_data, max_tokens=max_tokens)
return {"response": response["choices"][0]["message"]["content"]}
@app.route('/model', methods=['POST'])
def model_gateway():
data = request.get_json()
model_type = data.get("model_type")
model_name = data.get("model_name")
input_data = data.get("input_data")
max_tokens = data.get("max_tokens")
if model_type == "openai":
result = openai_model(input_data, model_name, max_tokens)
elif model_type == "gemini":
result = gemini_model(input_data, model_name, max_tokens)
return jsonify(result)
模型网关是访问控制和成本管理。
不需要向每个想要访问 OpenAI API 的人提供加密令牌(这很容易泄露),
而是只允许人们访问模型网关,从而创建一个集中且受控的访问点。
网关还可以实施精细的访问控制,指定哪个用户或应用程序应该有权访问哪个模型。
此外,网关可以监控和限制 API 调用的使用,防止滥用并有效管理成本。
模型网关还可用于实施回退策略以克服速率限制或 API 故障(不幸的是,后者很常见)。
当主 API 不可用时,网关可以将请求路由到替代模型,
在短暂等待后重试,或以其他正常方式处理故障。
这可确保应用程序能够平稳运行而不会中断。
由于请求和响应已经流经网关,因此它是实现其他功能(如负载均衡、日志记录和分析)的好地方。
一些网关服务甚至提供缓存和安全机制。
(这里插一句,后端的研发同学应该很熟悉,基本上跟微服务体系里业务网关一样的作用)
鉴于网关的实现相对简单,因此有许多现成的网关。
包括 Portkey 的网关、MLflow AI 网关、
WealthSimple 的 llm-gateway、TrueFoundry、Kong 和 Cloudflare。
与 scoring 一样,routing 也在 model gateway 中。
与用于评分的模型一样,用于路由的模型通常比用于生成的模型小。
使用缓存减少延迟
缓存可能是 AI 平台中最被低估的组件。
因为缓存可以显著降低应用程序的延迟和成本。
缓存技术也可以在训练期间使用,不过这篇的重点介绍用于推理的缓存。
一些常见的推理缓存技术包括提示缓存、精确缓存和语义缓存。
提示缓存通常由您使用的推理 API 实现。在评估推理库时,了解它支持的缓存机制会很有帮助。
1 Prompt cache
应用程序中的许多提示词都有重叠的文本段。
例如,所有查询都可以共享相同的系统提示符。
提示词缓存会存储这些重叠的区段以供重复使用,因此只需处理一次。
不同提示中常见的重叠文本段是系统提示符。
如果没有 prompt cache,模型需要处理每个查询的系统提示。
使用 prompt cache,它只需要为第一个查询处理一次系统提示。
对于系统提示较长的应用程序,提示缓存可以显著降低延迟和成本。
如果系统提示符是 1000 个令牌,并且应用程序今天生成了 100 万个模型 API 调用,
那么 prompt 缓存将使每天免于处理大约 10 亿个重复输入令牌!
但是,这并非完全免费,
与 KV 缓存一样,prompt 缓存大小可能相当大,并且需要大量的工程工作。
提示缓存对于涉及长文档的查询也很有用。
例如,如果许多用户查询与同一长文档(例如书籍或代码库)相关,
则可以缓存此长文档以跨查询重复使用。
自 2023 年 11 月 Gim 等人引入以来,提示缓存已被纳入模型 API 中。
谷歌宣布 Gemini API 将于 2024 年 6 月以上下文缓存的名义提供此功能。
与常规输入令牌相比,缓存的输入令牌可享受 75% 的折扣,
但必须为缓存存储支付额外费用(截至撰写本文时,每小时 1.00 美元/100 万个令牌)。
鉴于 prompt cache 的明显好处,如果它变得像 KV cache 一样流行,我不会感到惊讶。
虽然 llama.cpp 也有提示缓存,但它似乎只缓存整个提示并适用于同一聊天会话中的查询。
它的文档是有限的,但我通过阅读代码猜测,在长时间的对话中,它会缓存以前的消息,只处理最新的消息。
2 精准缓存
如果 prompt 缓存和 KV 缓存对于基础模型是唯一的,
那么精确缓存则更通用、更直接。
系统存储已处理的项目,以便稍后在请求确切的项目时重复使用。
例如,如果用户要求模型汇总产品,则系统会检查缓存以查看是否缓存了该产品的摘要。
如果是,请获取此摘要。
如果没有,请汇总产品并缓存摘要。
精确缓存还用于基于嵌入的检索,以避免冗余的向量搜索。
如果传入查询已在向量搜索缓存中,请获取缓存的搜索结果。
如果没有,请对此查询执行向量搜索并缓存结果。
缓存对于需要多个步骤(例如思维链)和/
或耗时操作(例如检索、SQL 执行或 Web 搜索)的查询特别有吸引力。
可以使用内存中存储实现精确缓存,以便快速检索。
但是,由于内存中存储有限,因此也可以使用 PostgreSQL、Redis
等数据库或分层存储来实现缓存,以平衡速度和存储容量。
拥有逐出策略对于管理缓存大小和保持性能至关重要。
常见的驱逐策略包括最近最少使用 (LRU)、最不常用 (LFU) 和先进先出 (FIFO)。
缓存查询的时间取决于再次调用此查询的可能性。
特定于用户的查询(例如“What’s the status of my recent order”
(我的最近订单的状态如何)不太可能被其他用户重复使用,因此不应缓存。
同样,缓存时间敏感的查询(例如“How’s the weather?”
(天气怎么样?一些团队训练一个小型分类器来预测是否应该缓存查询。)
3.语义缓存
与精准缓存不同,语义缓存不要求传入查询与任何缓存的查询相同。
语义缓存允许重用类似的查询。
假设一个用户问“What’s the capital of Vietnam”,模型生成答案“河内”。
后来,另一个用户问“What’s the capital city of Vietnam?”,
这是同一个问题,但多了个词“city”。
语义缓存的思想是系统可以重用答案 “Hanoi” 而不是从头开始计算新的查询。
语义缓存仅在可靠的方法来确定两个查询在语义上是否相似时才有效。
一种常见的方法是基于 embedding 的相似性,其工作原理如下:
- 对于每个查询,使用 embedding 模型生成其嵌入。
- 使用向量搜索查找最接近当前查询嵌入的缓存嵌入。假设此相似性分数为 X。
- 如果 X 大于设置的相似性阈值,则认为缓存的查询与当前查询相同,并返回缓存的结果。
如果没有,请处理此当前查询并将其与其嵌入和结果一起缓存。
此方法需要向量数据库来存储缓存查询的嵌入。
与其他缓存技术相比,语义缓存的价值更加可疑,因为它的许多组件都容易出现故障。
它的成功依赖于高质量的嵌入、函数向量搜索和值得信赖的相似性指标。
设置正确的相似度阈值也可能很棘手,需要大量的试验和错误。
如果系统将传入的查询误认为与另一个查询相似,则从缓存中获取的返回响应将不正确。
此外,语义缓存可能非常耗时且计算密集,因为它涉及向量搜索。
此向量搜索的速度和成本取决于缓存 embedding 向量数据库的大小。
如果缓存命中率很高,语义缓存可能仍然值得,
这意味着可以通过利用缓存结果有效地回答很大一部分查询。
但是,在整合语义缓存的复杂性之前,请确保评估与之相关的效率、成本和性能风险。
添加缓存系统后,平台如下所示。
KV 缓存和提示缓存通常由模型 API 提供程序实现,因此它们不会显示在此图中。
如果我必须可视化它们,我会将它们放在 Model API 框中。
后续的内容咱们会讲一下:
- 添加复杂逻辑和写入操作
- AI 应用平台的可观察性
- AI 应用 Pipeline 构建
原文链接:https://huyenchip.com/2024/07/25/genai-platform.html