停止API付费,我构建了本地AI栈
推动我走向本地AI的那一刻平淡得令人痛苦。我正在测试一个文档摘要的小功能。没什么革命性的。没有自主智能体发射火箭。只是一个开发者反复修改提示词、运行应用、检查输出、再试一次。每次实验都触发一次API请求。单独来看请求很便宜。API费用就是这样掏空你的钱包的。它很少戴着滑雪面具出现。它通过测试、重试、嵌入、后台任务、被遗忘的脚本以及开发者经典的我以后再优化策略悄悄积累。最终我问了一个更有用的问题为什么我要为我自己电脑就能处理的工作负载租用智能所以我停止为大多数开发和内部工具使用付费AI API。我构建了一个本地技术栈。它并非在所有方面都神奇地更好。但它更便宜、更容易控制、更私密而且出乎意料地实用。1、我实际需要的技术栈本地AI技术栈可以变得极其复杂。你可以安装六个编排框架、三个数据库、一个Kubernetes集群、一个可观测性平台以及足够吓跑DevOps工程师的YAML。或者你可以从四个组件开始一个本地模型运行器一个小型应用层一个检索系统一个简单界面我的技术栈是这样的用户界面 ↓ FastAPI应用 ↓ 通过Ollama运行的本地模型 ↓ Qdrant用于文档检索 ↓ 本地文件和应用数据我使用Ollama因为它提供了一种直接的方式来下载、运行和本地调用模型。需要更多推理控制、模型格式或硬件优化的开发者可以使用llama.cpp。它的目标是在广泛的硬件上高效运行模型推理而不需要庞大的服务平台。对于检索我使用了Qdrant。它可以在本地运行并为基于文档的应用提供向量相似性搜索。我用Docker Compose打包支持服务因为手动启动五个终端不是架构是在求救。2、在本地运行模型安装Ollama后我可以用以下命令下载并运行兼容模型ollama pull MODEL_NAME ollama run MODEL_NAME具体模型取决于你的硬件和用例。不要立即下载你的机器技术上能打开的最大模型。一个消耗所有可用内存且回复慢得令人痛苦的模型不是强大。它是家具。从小开始。用真实任务测试它它能分类你的支持消息吗它能提取结构化信息吗它能准确摘要你的文档吗它能遵循你要求的输出格式吗它的响应速度足够实际用户使用吗基准测试有用但你的应用不是在基准图表上运行的。你自己的测试用例更重要。3、替换远程API调用Ollama暴露一个本地HTTP API通常通过localhost。这意味着应用可以像调用托管服务一样调用本地模型。这是一个最小的Python示例import requests def ask_local_model(prompt: str) - str: response requests.post( http://localhost:11434/api/generate, json{ model: MODEL_NAME, prompt: prompt, stream: False, }, timeout120, ) response.raise_for_status() return response.json()[response] print(ask_local_model(用三个要点解释Docker卷。))这个小小的变化很重要。我的提示词实验不再需要远程请求。内部文档不需要离开机器。我可以反复测试而不需要考虑每个略有不同的提示词是否值得再花一笔钱。心理上的差异比预期的更大。当每次实验都附带一个计时器时开发者会变得保守。本地推理让实验重新感觉像正常的软件开发。4、要求模型知道一切本地AI最大的错误之一是期望较小的模型表现得像庞大的托管系统。那是错误的比较。本地模型不需要知道一切。它需要在正确的时刻获取正确的信息。这就是检索增强生成RAG变得有用的地方。过程很直接文档 ↓ 分割成有用的块 ↓ 创建嵌入 ↓ 存储带元数据的向量 ↓ 检索相关块 ↓ 将那些块发送给模型假设我在为一个软件团队构建内部助手。与其问模型我们的部署流程是怎样的我从部署文档中检索最相关的部分并构建这样的提示词仅使用提供的上下文来回答。 上下文 - 生产部署需要已批准的pull request。 - 数据库迁移必须单独审查。 - 回滚使用之前的容器镜像。 问题 我应该如何部署数据库更改现在模型不是在试图回忆它从未学过的私有公司知识。它在解释检索到的证据。这是一个现实得多的工作。5、让输出无聊且可预测聊天界面能做令人印象深刻的演示但生产系统通常需要结构化的结果。我不希望模型在提取发票信息时变得诗意。我要JSON。使用以下结构返回有效的JSON { invoice_number: string or null, supplier: string or null, total: number or null, currency: string or null } 不要添加解释。然后在代码中验证响应import json from pydantic import BaseModel, ValidationError class InvoiceData(BaseModel): invoice_number: str | None supplier: str | None total: float | None currency: str | None def parse_invoice_response(raw_response: str) - InvoiceData: try: data json.loads(raw_response) return InvoiceData.model_validate(data) except (json.JSONDecodeError, ValidationError) as error: raise ValueError(模型返回了无效的发票数据。) from error这不如构建一个多智能体认知工作流令人兴奋。但它更有用。可靠的AI应用通常是由约束、验证、重试、日志记录和良好的失败处理构建的——而不是告诉模型它是世界级专家的激励性提示词。6、真正的好处不仅仅是经济上的我的开发循环变快了我可以调整提示词、测试边缘情况、重新运行评估而不需要跟踪每个请求。敏感数据保持在我的控制下本地处理减少了将内部文档、客户消息、源代码或研究笔记发送到外部服务的需要。但这并不会自动使系统安全。配置不当的本地服务器仍然可以暴露数据。例如数据库和模型端点通常应绑定到本地或私有接口而不是随意暴露到互联网。本地是一个基础设施决策不是一个神奇的隐私贴纸。我可以在没有互联网的情况下工作模型、检索数据库和文档在连接问题期间仍然可用。我获得了架构自由我可以在不重建整个产品的情况下更换模型。应用拥有提示词、检索逻辑、验证和业务规则。模型是一个可替换的组件。这应该是它的样子。7、现实本地AI不是免费的我停止了按请求付费。我没有逃脱成本。本地AI将账单从API使用转移到硬件、电力、存储、维护和工程时间。你还可能面临更慢的推理复杂任务上更低的输出质量模型兼容性问题内存限制更大的应用安装包安全补丁责任更困难的团队部署还有一些场景下托管API仍然是合理的选择。强大的云模型可能更适合困难推理、大上下文窗口、重度多模态工作负载、突发流量激增或者维护推理基础设施成本高于API的产品。这不是宗教信仰。目标不是替换每个云模型。目标是当工作负载不需要时停止默认使用云模型。8、我选择本地还是云的规则我使用本地模型当任务是狭窄且可重复的数据隐私很重要应用必须离线工作请求量使API定价变得令人不舒服较小的模型产生可接受的结果我在开发期间需要无限的实验我考虑托管模型当任务需要更强的推理输出质量比基础设施成本更重要流量不可预测团队无法维护本地推理所需模型无法在可用硬件上有效运行混合系统通常是最明智的答案。在本地运行常规分类、提取、检索和摘要。只将真正困难的请求升级到更强的远程模型——经过用户同意和适当的数据控制。这种方法在不假装笔记本电脑是数据中心的情况下降低了成本。9、一个实用的迁移计划不要在一个周末重写你的整个AI产品。选择一个现有功能。测量它当前的请求量API成本响应时间失败率输出质量隐私要求然后对固定评估集测试本地模型。使用30到100个真实示例。用相同标准对两个系统评分。不要因为本地模型的答案看起来不错就选择它。开发者用这种科学方法已经发布了足够多的bug了。只有当质量、速度和运营成本都可接受时才将该功能移到本地。然后重复。10、我学到了什么最大的教训不是本地模型比托管模型更好。它们并不总是更好。教训是我把付费API当成了自动的起点。它们很方便所以我停止质疑它们是否匹配问题。一旦我在本地构建AI停止感觉像一个神秘的外部智能服务。它又变成了软件。一个在机器上运行的进程。一个我可以替换的端点。一个我可以基准测试的组件。一个需要验证、安全、日志、测试和合理边界的系统。少一些魔法。多一些工程。说实话这就是我需要的升级。原文链接停止API付费我构建了本地AI栈 - 汇智网