生成式AI平台是一个非常复杂的系统。本文将从最简单的架构开始,并逐步添加更多组件。在最简单的形式中,应用程序接收查询并将其发送到模型。模型生成回答并将其返回给用户。当前形式下,没有防护措施、增强上下文或优化。模型API指的是第三方API(例如OpenAI、Google、Anthropic)和自托管的API。
从这里开始,可以根据需要添加更多组件。本文所讨论的是常见顺序,但你不必完全遵循。如果你的系统运行良好,可以跳过某些组件。在开发的每个步骤中,评估都是必要的。
通过让模型访问外部数据源和信息收集工具来增强输入的上下文。
设置防护措施以保护系统和用户。
添加模型路由和网关,以支持复杂的Pipeline并增强安全性。
用缓存优化时延和成本。
添加复杂的逻辑和写入操作,以将系统能力最大化。
可观测性使我们可以对系统进行监控和调试,而编排则涉及将所有组件链接在一起。这两个部分都是平台的基本组成部分,我们将在文章最后进行讨论。
本文重点讨论了部署AI应用的总体架构,讨论了构建这些组件所需的组件和注意事项,并不涉及如何构建AI应用,因此不讨论模型评估、应用评估、提示工程、微调、数据标注指南或RAG的分块策略。(这些主题会在即将出版的《AI工程》一书中详细介绍。)
召回率:算法找到近邻的比例。
每秒查询数(QPS):算法每秒能处理的查询数量。这对高流量应用至关重要。
构建时间:构建索引所需的时间。如果需要频繁更新索引(例如数据发生变化),这个指标非常重要。
索引大小:算法创建的索引大小,这对于评估其可扩展性和存储需求至关重要。
文本到SQL:根据用户查询和表的模式,确定需要哪种SQL查询。
SQL执行:执行SQL查询。
生成:基于SQL结果和原始用户查询生成回答。
为了捕捉不符合标准的输出,需要了解失败模式是什么样的。以下是一些失败模式的例子以及捕捉它们的方法。
3
重置密码 -> 将此用户路由到密码重置页面。
更正账单错误 -> 将此用户路由到人工操作员。
解决技术问题 -> 将此查询路由到一个针对技术故障排查进行了微调的模型。
import google.generativeai as genaiimport openaidef 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=['OST'])
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)
对查询使用嵌入模型生成其嵌入表示。
使用向量搜索找到与当前查询嵌入最接近的缓存嵌入。假设这个相似度分数是X。
如果X超过了设定的相似性阈值,则认为缓存的查询与当前查询相同,并返回缓存的结果。如果不超过,则处理当前查询,并将其与嵌入和结果一起缓存。这种方法需要使用向量数据库来存储缓存查询的嵌入表示。
第一个词元生成时间(TTFT):生成第一个词元所需的时间。
词元间时间(TBT):每个词元生成之间的间隔时间。
每秒生成词元数(TPS):生成词元的速率。
每个输出词元生成时间(TPOT):生成每个输出词元所需的时间。
总时延:完成一次回答所需的总时间。
组件定义。你需要告诉编排器你的系统使用了哪些组件,例如模型(包括生成、路由和评分模型),系统可以从中检索数据的数据库以及系统可以执行的操作。与模型网关的直接集成可以帮助简化模型的引入,而一些编排器工具则希望成为网关。许多编排器还支持与评估和监控工具的集成。
串联(或流水线)。你需要告诉编排器从接收用户问题到完成任务这一过程中系统采取的步骤顺序。简而言之,串联就是函数组合。以下是一个串联(流水线)的示例:
处理原始问题。
根据处理后的问题检索相关数据。
将原始问题和检索到的数据结合起来,创建一个符合模型期望格式的提示。
模型根据提示生成回答。
评估该回答。
如果回答被认为是优质的,就返回给用户;如果不满意,则将问题转交给人工操作员。编排器负责在步骤之间传递数据,并可以提供工具,帮助确保当前步骤的输出符合下一步骤的预期格式。
集成和扩展性:评估编排器是否支持已经使用或可能在未来采用的组件。例如,如果想用Llama模型,需要检查编排器是否支持。由于有太多模型、数据库和框架,任何编排器都不可能支持所有东西。因此,还需要考虑编排器的扩展性。如果它不支持特定组件,修改它的难度有多大?
支持复杂的串联:随着应用程序复杂性的增加,你可能需要管理涉及多个步骤和条件逻辑的复杂串联。支持高级功能(如分支、并行处理和错误处理)的编排器将帮助你高效地管理这些复杂性。
易用性、性能和可扩展性:考虑编排器的用户友好性。寻找直观的API、全面的文档和强大的社区支持,能显著降低你和团队的学习难度。同时,避免使用那些会发起隐藏API调用或给应用程序带来时延的编排器。此外,确保编排器在应用程序数量、开发人员数量和流量增长时,能够有效扩展。
| 欢迎光临 链载Ai (https://www.lianzai.com/) | Powered by Discuz! X3.5 |