LLM 抽象层怎么设计?让 AI 应用不被某一个模型厂商绑定
上一篇文章讨论了 AI 应用的配置系统。配置系统解决的是一个问题项目运行时应该使用哪个模型、哪个 API Key、哪个服务地址、哪个超时时间。但配置系统本身并不负责调用模型。当配置准备好以后AI 应用马上会遇到下一个问题业务代码应该如何调用大模型很多 Demo 会这样写fromopenaiimportOpenAI clientOpenAI(api_keysk-xxx)responseclient.chat.completions.create(modelgpt-4o,messages[{role:user,content:请总结这段文字}],)print(response.choices[0].message.content)这段代码很直观也很适合快速验证想法。但如果项目继续发展就会出现很多工程问题。今天使用 OpenAI。明天可能要切到 DeepSeek。后天可能要同时支持 Qwen。某些场景需要流式输出。某些场景需要更长的超时时间。某些场景需要记录 token 用量。某些场景需要在主模型失败时降级到备用模型。如果业务代码里到处都是某个厂商 SDK 的调用方式项目就会很难维护。所以在 AI Scaffold 这样的工程化脚手架里需要有一层专门负责模型调用。这一层就是 LLM 抽象层。一、为什么不能在业务代码里直接调用模型 SDK直接调用模型 SDK 最大的问题是业务逻辑和基础设施逻辑混在了一起。业务代码真正关心的通常是给模型一段输入。拿到模型返回的结果。必要时处理流式输出。必要时拿到 token 用量。但具体使用哪个模型厂商、怎么初始化客户端、参数名字叫什么、返回结构是什么很多时候不应该由业务代码直接关心。例如 OpenAI 风格的调用可能是responseclient.chat.completions.create(modelgpt-4o,messagesmessages,temperature0.7,)另一个模型供应商可能是responseclient.chat(model_namexxx,promptprompt,streamFalse,)返回结果也可能不同。有的结果在response.choices[0].message.content里。有的结果在response.output_text里。有的结果会返回一个事件流。有的结果会额外包含 token 统计。如果每个业务模块都自己适配这些差异项目会慢慢变成这样ifprovideropenai:# OpenAI 调用逻辑...elifproviderdeepseek:# DeepSeek 调用逻辑...elifproviderqwen:# Qwen 调用逻辑...短期看这是最快的写法。长期看这是最难维护的写法。因为模型供应商的差异会扩散到整个项目。一旦要切换模型就需要改很多地方。一旦要增加重试就需要复制很多逻辑。一旦要做测试就很难把模型调用替换成 mock。所以模型调用应该集中在一层里。业务代码不应该直接依赖具体 SDK而应该依赖一个统一接口。二、LLM 抽象层到底解决什么问题LLM 抽象层不是为了把代码写得更复杂。它的目标是把模型供应商差异收敛起来。一个合理的 LLM 抽象层至少应该解决几个问题。第一统一调用方式。不管底层是 OpenAI、DeepSeek、Qwen业务代码都使用同一种调用方法。例如resultllm.chat(messages)第二统一返回结构。业务代码不需要关心不同 SDK 的原始返回格式而是拿到一个统一的结果对象。例如print(result.content)print(result.model)print(result.usage)第三统一配置入口。模型供应商、模型名称、API Key、超时时间、温度参数都从配置系统读取。业务模块不应该自己读取环境变量。第四统一错误处理。超时、限流、鉴权失败、网络失败、模型不可用都应该有统一的异常类型或处理策略。第五支持流式输出。很多 AI 应用需要边生成边展示所以抽象层应该支持普通调用和流式调用。第六支持扩展新模型。当项目需要接入新的模型供应商时最好只新增一个 Provider而不是修改所有业务模块。第七方便测试。测试时可以使用 Fake LLM 或 Mock LLM不必真实调用外部模型服务。这些能力放在一起就构成了 AI 应用工程化里的模型调用底座。三、不要把 LLM 抽象层设计成万能框架设计 LLM 抽象层时容易走向另一个极端一开始就想支持所有模型、所有参数、所有调用模式。这会让抽象层变得很重。对于脚手架项目来说更好的做法是先抓住最核心的能力。例如第一版只需要支持普通对话调用。流式对话调用。基础参数传入。统一返回结果。基础错误处理。新 Provider 扩展能力。暂时不需要一开始就把所有高级能力都塞进去。例如批量推理、函数调用、多模态输入、结构化输出、缓存、路由和降级都可以作为后续扩展。抽象层的价值不是一开始覆盖所有场景。而是先建立一个稳定边界上层业务不直接依赖模型厂商。底层模型供应商可以替换和扩展。只要这个边界建立起来后续功能就可以逐步生长。四、一个简单的 LLM 接口应该长什么样在 Python 项目里可以先定义一个基础接口。例如fromabcimportABC,abstractmethodfromtypingimportIterableclassBaseLLM(ABC):abstractmethoddefchat(self,messages:list[dict])-LLMResponse:passabstractmethoddefstream_chat(self,messages:list[dict])-Iterable[LLMChunk]:pass这个接口先表达两个核心能力普通调用。流式调用。普通调用一次性返回完整结果。流式调用逐步返回模型生成的片段。然后定义统一的返回对象。fromdataclassesimportdataclassdataclassclassLLMUsage:prompt_tokens:int|NoneNonecompletion_tokens:int|NoneNonetotal_tokens:int|NoneNonedataclassclassLLMResponse:content:strmodel:str|NoneNoneprovider:str|NoneNoneusage:LLMUsage|NoneNoneraw:object|NoneNonedataclassclassLLMChunk:content:strdone:boolFalseraw:object|NoneNone这里有一个细节返回对象里保留了raw字段。这是为了在需要排查问题时还能拿到原始响应。但业务代码默认不应该依赖raw。如果业务代码大量读取raw说明抽象层没有真正隔离底层差异。五、Provider 是 LLM 抽象层的核心LLM 抽象层通常可以分成两部分统一接口。具体 Provider。统一接口定义项目内部怎么调用模型。Provider 负责适配具体模型供应商。例如项目结构可以这样设计llm/ ├── __init__.py ├── base.py ├── schema.py ├── factory.py └── providers/ ├── __init__.py ├── openai_provider.py ├── deepseek_provider.py └── qwen_provider.py其中base.py放基础接口。schema.py放统一返回结构。factory.py根据配置创建具体 LLM 实例。providers/放不同模型供应商的适配代码。这样业务代码只需要这样写fromllm.factoryimportcreate_llm llmcreate_llm()resultllm.chat([{role:user,content:请总结这段内容}])print(result.content)业务代码不需要知道底层到底是 OpenAI、DeepSeek 还是 Qwen。这就是 Provider 模式的价值。六、Factory 应该和配置系统配合上一篇文章提到AI 应用需要统一配置系统。LLM 抽象层应该直接使用这套配置。例如配置对象里可以有这些字段classSettings:llm_provider:stropenaillm_model:strgpt-4ollm_temperature:float0.7llm_timeout:int60openai_api_key:str|NoneNonedeepseek_api_key:str|NoneNoneqwen_api_key:str|NoneNoneFactory 根据配置创建不同 Provider。fromconfig.settingsimportsettingsfromllm.providers.openai_providerimportOpenAIProviderfromllm.providers.deepseek_providerimportDeepSeekProviderfromllm.providers.qwen_providerimportQwenProviderdefcreate_llm():ifsettings.llm_provideropenai:returnOpenAIProvider(api_keysettings.openai_api_key,modelsettings.llm_model,temperaturesettings.llm_temperature,timeoutsettings.llm_timeout,)ifsettings.llm_providerdeepseek:returnDeepSeekProvider(api_keysettings.deepseek_api_key,modelsettings.llm_model,temperaturesettings.llm_temperature,timeoutsettings.llm_timeout,)ifsettings.llm_providerqwen:returnQwenProvider(api_keysettings.qwen_api_key,modelsettings.llm_model,temperaturesettings.llm_temperature,timeoutsettings.llm_timeout,)raiseValueError(fUnsupported LLM provider:{settings.llm_provider})这样配置系统和 LLM 抽象层就串起来了。如果想从 OpenAI 切换到 DeepSeek理论上只需要修改配置LLM_PROVIDERdeepseek LLM_MODELdeepseek-chat DEEPSEEK_API_KEYyour-api-key上层业务代码不需要改。这就是工程化设计带来的稳定性。七、Provider 内部应该适配差异而不是暴露差异Provider 的职责是把具体厂商 SDK 转换成项目内部统一接口。例如 OpenAIProvider 可以这样写fromopenaiimportOpenAIfromllm.baseimportBaseLLMfromllm.schemaimportLLMResponse,LLMUsageclassOpenAIProvider(BaseLLM):def__init__(self,api_key:str,model:str,temperature:float,timeout:int):self.clientOpenAI(api_keyapi_key,timeouttimeout)self.modelmodel self.temperaturetemperaturedefchat(self,messages:list[dict])-LLMResponse:responseself.client.chat.completions.create(modelself.model,messagesmessages,temperatureself.temperature,)usageNoneifresponse.usage:usageLLMUsage(prompt_tokensresponse.usage.prompt_tokens,completion_tokensresponse.usage.completion_tokens,total_tokensresponse.usage.total_tokens,)returnLLMResponse(contentresponse.choices[0].message.contentor,modelself.model,provideropenai,usageusage,rawresponse,)这里业务代码看不到 OpenAI SDK 的细节。业务代码只拿到LLMResponse。如果以后切换到 DeepSeekProvider只要 DeepSeekProvider 也返回LLMResponse上层代码就不需要变化。Provider 内部可以有差异。Provider 对外应该尽量一致。八、流式输出也应该统一很多 AI 应用需要流式输出。例如聊天机器人、写作助手、代码生成工具都希望模型边生成边展示。如果不做抽象不同供应商的流式接口差异会直接进入业务层。所以 LLM 抽象层需要提供统一的流式接口。例如forchunkinllm.stream_chat(messages):print(chunk.content,end)OpenAIProvider 内部可以这样适配fromllm.schemaimportLLMChunkdefstream_chat(self,messages:list[dict]):streamself.client.chat.completions.create(modelself.model,messagesmessages,temperatureself.temperature,streamTrue,)foreventinstream:contentevent.choices[0].delta.contentorifcontent:yieldLLMChunk(contentcontent,rawevent)yieldLLMChunk(content,doneTrue)上层业务不关心底层事件结构。只关心每次拿到一个LLMChunk。这样无论后续是 WebSocket、SSE 还是命令行输出都可以基于统一的流式接口实现。九、错误处理不能到处写 try except模型调用经常会失败。常见原因包括API Key 未配置。API Key 无效。网络超时。请求频率过高。模型名称错误。上下文长度超限。供应商服务不可用。如果每个业务模块都自己写try except错误处理会非常分散。LLM 抽象层可以定义统一异常。例如classLLMError(Exception):passclassLLMAuthError(LLMError):passclassLLMTimeoutError(LLMError):passclassLLMRateLimitError(LLMError):passclassLLMProviderError(LLMError):passProvider 内部负责把具体 SDK 异常转换成这些统一异常。业务层只需要处理项目内部异常。例如try:resultllm.chat(messages)exceptLLMTimeoutError:return模型响应超时请稍后再试exceptLLMRateLimitError:return当前请求较多请稍后重试exceptLLMError:return模型服务暂时不可用这样错误处理会更清晰。同时也方便后续接入日志、告警和降级策略。十、超时、重试和降级应该放在哪里LLM 调用是外部服务调用。外部服务调用就一定要考虑超时。如果没有超时控制一个请求可能卡住很久。如果没有重试控制短暂网络波动就会导致用户请求失败。如果没有降级策略主模型不可用时整个应用就不可用。但这些逻辑不应该散落在业务代码里。更合理的位置是放在 LLM 抽象层或更上层的模型路由层。例如第一版可以先在 Provider 初始化时支持 timeoutOpenAI(api_keyapi_key,timeouttimeout)后续再加入简单重试defchat_with_retry(llm,messages,retries:int2):last_errorNonefor_inrange(retries1):try:returnllm.chat(messages)exceptLLMTimeoutErroraserror:last_errorerrorraiselast_error再往后可以设计模型路由primary_llmcreate_llm(provideropenai)fallback_llmcreate_llm(providerdeepseek)try:resultprimary_llm.chat(messages)exceptLLMError:resultfallback_llm.chat(messages)不过对于脚手架早期版本来说不一定要马上实现复杂路由。先把接口边界设计好后面扩展会更自然。十一、Prompt 和 LLM 抽象层要保持边界有些项目会把 Prompt 拼接逻辑写进 LLM Provider。这通常不是一个好习惯。LLM Provider 应该负责模型调用。Prompt 管理应该属于 Prompt 层或业务层。例如不要这样设计llm.summarize_article(article_text)llm.generate_title(topic)llm.extract_keywords(content)这些方法看起来方便但它们把业务语义塞进了 LLM 层。更合理的方式是messagesprompt_manager.render(namesummarize_article,variables{article_text:article_text},)resultllm.chat(messages)LLM 层只关心 messages。Prompt 层负责生成 messages。业务层负责决定使用哪个 Prompt。这样模块边界会更清楚。后续如果要做 Prompt 版本管理也不会影响 LLM Provider。十二、测试时需要 Fake LLMAI 应用测试有一个很现实的问题不能每次测试都真实调用模型。原因很简单。真实调用会产生费用。真实调用速度慢。真实调用结果不稳定。真实调用还依赖网络和外部服务状态。所以 LLM 抽象层应该方便替换成 Fake LLM。例如fromllm.baseimportBaseLLMfromllm.schemaimportLLMResponse,LLMChunkclassFakeLLM(BaseLLM):def__init__(self,content:strfake response):self.contentcontentdefchat(self,messages:list[dict])-LLMResponse:returnLLMResponse(contentself.content,modelfake-model,providerfake,)defstream_chat(self,messages:list[dict]):yieldLLMChunk(contentself.content)yieldLLMChunk(content,doneTrue)测试业务逻辑时可以注入 FakeLLM。deftest_summary_workflow():llmFakeLLM(content这是一段摘要)workflowSummaryWorkflow(llmllm)resultworkflow.run(很长的文章内容)assertresult.summary这是一段摘要这样测试就不会依赖真实模型服务。这也是抽象层非常重要的价值。它不仅让生产环境可切换也让测试环境可控制。十三、LLM 抽象层在 AI Scaffold 里的位置在 AI Scaffold 里LLM 抽象层可以作为核心模块之一。项目结构可以这样安排app/ ├── main.py ├── workflows/ │ └── summary_workflow.py ├── prompts/ │ └── summary_prompt.md ├── llm/ │ ├── __init__.py │ ├── base.py │ ├── schema.py │ ├── factory.py │ ├── exceptions.py │ └── providers/ │ ├── openai_provider.py │ ├── deepseek_provider.py │ └── qwen_provider.py ├── config/ │ └── settings.py └── tests/ └── test_summary_workflow.pyCLI 创建项目时可以默认生成llm/base.py llm/schema.py llm/factory.py llm/exceptions.py llm/providers/同时在.env.example里给出模型相关配置LLM_PROVIDERopenai LLM_MODELgpt-4o LLM_TEMPERATURE0.7 LLM_TIMEOUT60 OPENAI_API_KEY DEEPSEEK_API_KEY QWEN_API_KEY这样开发者生成项目后就能很清楚地知道模型配置在哪里。模型调用在哪里。业务代码应该依赖什么接口。新增模型供应商应该改哪个位置。这比把所有模型调用写在业务函数里更适合长期维护。十四、总结LLM 抽象层是 AI 应用工程化里非常关键的一层。它解决的不是“怎么调用某一个模型 API”。它解决的是“如何让整个项目不被某一个模型厂商绑定”。一个合理的 LLM 抽象层至少应该做到业务代码不直接依赖具体模型 SDK。使用统一的chat和stream_chat接口。使用统一的返回结构。Provider 内部适配不同厂商差异。Factory 根据配置系统创建具体模型实例。错误处理、超时、重试可以逐步集中管理。测试环境可以使用 Fake LLM。后续新增模型供应商时不影响上层业务代码。对于 AI Scaffold 来说配置系统决定使用哪个模型。LLM 抽象层决定如何调用这个模型。当这两层建立起来以后项目就不再是简单的 Prompt Demo而是开始具备真正的工程化基础。下一篇文章可以继续讨论 Prompt 管理为什么 Prompt 不应该散落在业务代码里以及如何把 Prompt 做成可维护、可复用、可版本化的项目资产。

相关新闻

OPC DCOM 跨域/工作组连接:5个防火墙与安全策略配置要点

OPC DCOM 跨域/工作组连接:5个防火墙与安全策略配置要点

OPC DCOM跨域连接实战:防火墙与安全策略的黄金法则 在工业自动化系统中,OPC(OLE for Process Control)作为数据交换的标准协议,其稳定性和安全性直接影响生产系统的可靠运行。而当OPC采用DCOM(分布式组件对…

2026/7/11 16:55:17阅读更多 →
Tokio Console 诊断工具实战:从 Task 火焰图到 Waker 统计的性能瓶颈定位

Tokio Console 诊断工具实战:从 Task 火焰图到 Waker 统计的性能瓶颈定位

Tokio Console 诊断工具实战:从 Task 火焰图到 Waker 统计的性能瓶颈定位 一、异步代码的盲区:为什么 flamegraph 看不懂 Tokio 程序 传统性能分析工具(perf、flamegraph)在分析 Tokio 异步程序时,常常产生令人困惑的结…

2026/7/11 16:50:15阅读更多 →
PIC18F4682与PAM8904构建高效声光报警系统

PIC18F4682与PAM8904构建高效声光报警系统

1. 项目背景与核心组件选型在工业控制和智能家居领域,可靠的通知系统是保障设备安全运行和用户及时响应的关键环节。基于PIC18F4682微控制器和PAM8904音频驱动器的组合,能够构建一套响应迅速、可定制化的声光报警解决方案。这套系统特别适合需要多种警报…

2026/7/11 16:50:15阅读更多 →
FFmpeg H.264 裁剪与拼接:SPS/PPS 数据丢失的 2 种修复方案与原理

FFmpeg H.264 裁剪与拼接:SPS/PPS 数据丢失的 2 种修复方案与原理

FFmpeg H.264 裁剪与拼接:SPS/PPS 数据丢失的深度修复指南1. H.264 码流结构与 SPS/PPS 的关键作用H.264 视频编码标准之所以能在保持高压缩率的同时提供优秀画质,很大程度上得益于其精心设计的码流结构。在这个结构中,**序列参数集(SPS)和图…

2026/7/11 17:45:21阅读更多 →
004、模拟增益与数字增益:增益分配策略对信噪比和图像质量的实战影响

004、模拟增益与数字增益:增益分配策略对信噪比和图像质量的实战影响

004、模拟增益与数字增益:增益分配策略对信噪比和图像质量的实战影响一个让我熬夜三天的bug 2018年某款旗舰机的前置摄像头,暗光自拍噪点像雪花一样。ISP团队说sensor输出已经调到最大模拟增益了,再往上加就是数字增益。我盯着log看了三个小时…

2026/7/11 17:45:21阅读更多 →
STM32L151ZD与L9958电机控制方案解析

STM32L151ZD与L9958电机控制方案解析

1. L9958与STM32L151ZD的黄金组合解析 在电机控制领域,L9958驱动芯片与STM32L151ZD微控制器的组合堪称经典搭档。L9958是STMicroelectronics推出的多通道H桥驱动器,专为汽车级应用设计,具有高达40V的驱动电压和3A的峰值输出电流能力。其内置的…

2026/7/11 17:45:21阅读更多 →
一、ZooKeeper集群安装

一、ZooKeeper集群安装

准备3台机器安装zookeeper集群 zoo1:192.168.40.190 zoo2:192.168.40.191 zoo3:192.168.40.192 3台机器全部需要安装 进入/opt文件夹下 cd /opt 下载zookeeper 官网下载地址Releases - Apache ZooKeeper,选择稳定版本 点击…

2026/7/11 17:45:21阅读更多 →
直流负载管理系统设计:G6D-ASI继电器与PIC18LF46K22应用

直流负载管理系统设计:G6D-ASI继电器与PIC18LF46K22应用

1. 直流负载管理的挑战与优化思路在现代电子设备设计中,直流负载管理一直是工程师面临的关键挑战之一。特别是在需要高精度控制和高效能耗的场合,传统的继电器控制方案往往存在响应速度慢、功耗高、体积大等问题。而G6D-ASI功率继电器与PIC18LF46K22微控…

2026/7/11 17:45:21阅读更多 →
医院陪诊系统源码:用户端+陪诊师端+管理后台整体架构设计方案

医院陪诊系统源码:用户端+陪诊师端+管理后台整体架构设计方案

很多人第一次接触医院陪诊APP/小程序时,看到的是预约、下单、支付这些页面。对于开发人员来说,真正需要花时间打磨的却是后台业务逻辑。一个订单从创建到完成,要经过派单、接单、服务、结算、评价等多个环节,只要其中某个节点设计…

2026/7/11 17:40:20阅读更多 →
从GitHub安全案例解析常见漏洞与防护实践

从GitHub安全案例解析常见漏洞与防护实践

1. 项目概述:从GitHub Trending看安全实战 最近在GitHub Trending上看到一个项目,叫 skills4/skills ,它因为一些安全漏洞案例被大家讨论。这其实是一个挺典型的场景:一个旨在展示或教授某种技能的仓库,本身却成了安…

2026/7/10 12:10:00阅读更多 →
MLT 2026启示:因果推理与概率建模驱动下一代LLM应用

MLT 2026启示:因果推理与概率建模驱动下一代LLM应用

# MLT 2026启示:因果推理与概率建模驱动下一代LLM应用## 一、背景与挑战:从“黑箱预测”到“可信推理”2026年6月,第7届机器学习与趋势国际会议(MLT 2026)将在悉尼召开。会议议程中,“因果与可解释机器学习…

2026/7/11 15:18:12阅读更多 →
通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御

通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御

1. 项目概述与漏洞背景最近在梳理一些历史OA系统的安全风险时,通达OA v11.6版本中的一个老漏洞又进入了我的视线。这个漏洞位于/general/bi_design/appcenter/report_bi.func.php文件中,是一个典型的SQL注入点。虽然这个漏洞的利用方式看起来并不复杂&am…

2026/7/11 15:11:32阅读更多 →
Premiere Pro 2025安装失败原因与AGSIS验证绕过指南

Premiere Pro 2025安装失败原因与AGSIS验证绕过指南

1. 为什么2025版PR安装比以往更“磨人”?——从弹窗警告到路径陷阱的真实处境 Premiere Pro 2025版不是简单的一次版本迭代,它是一道分水岭。我从去年底开始帮影视工作室、高校剪辑实验室和自由职业者部署2025环境,累计处理了137台设备&#…

2026/7/11 0:03:43阅读更多 →
5款实用macOS系统优化工具:让你的Mac运行更流畅更高效

5款实用macOS系统优化工具:让你的Mac运行更流畅更高效

5款实用macOS系统优化工具:让你的Mac运行更流畅更高效 【免费下载链接】open-source-mac-os-apps 🚀 Awesome list of open source applications for macOS. https://t.me/s/opensourcemacosapps 项目地址: https://gitcode.com/gh_mirrors/op/open-so…

2026/7/11 0:03:43阅读更多 →
5分钟完全掌握:ComfyUI ControlNet预处理器终极使用指南

5分钟完全掌握:ComfyUI ControlNet预处理器终极使用指南

5分钟完全掌握:ComfyUI ControlNet预处理器终极使用指南 【免费下载链接】comfyui_controlnet_aux ComfyUIs ControlNet Auxiliary Preprocessors 项目地址: https://gitcode.com/gh_mirrors/co/comfyui_controlnet_aux 想要让AI图像生成真正听从你的指挥吗&…

2026/7/11 0:03:43阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/11 16:20:28阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/10 22:20:33阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/10 17:29:22阅读更多 →