当前位置: 首页 > news >正文

本地部署9B代码智能体:从vLLM部署到能力评估实战

1. 项目概述:在本地部署与评估一个9B参数的代码智能体

最近在折腾一个挺有意思的项目:把最新的CoPaw-Flash-9B模型在本地跑起来,让它扮演一个能写代码、修bug的智能助手。这个模型是基于Qwen3.5-9B微调而来的,专门针对自主智能体任务做了优化,号称原生支持26万token的上下文,还内置了思维链推理能力。听起来很美好,对吧?但实际把它部署起来,再让它真正干点活,中间踩的坑和发现的局限性,可能比官方宣传的那些亮点更有参考价值。这篇文章就是我这段时间折腾的完整记录,从硬件环境搭建、模型部署,到实际的任务测试和性能评估,我会把每一步的操作细节、遇到的坑以及我的解决方案都摊开来聊聊。如果你也对在本地运行大模型智能体感兴趣,或者正考虑用类似方案替代云端API,这篇实战笔记应该能给你提供不少一手经验。

我的测试环境是一台配备了NVIDIA H100 PCIe(80GB显存)的服务器,搭配了足够的CPU和内存。整个技术栈的核心是vLLM推理引擎和一个名为claude-code-clean的前端界面。最终的目标是让这个9B的模型能像一个真正的编程助手一样,接收一个复杂的任务(比如“创建一个终端文字冒险游戏并调试其逻辑”),然后自主地调用工具(写文件、执行命令、编辑代码)去完成它。然而,理想很丰满,现实却往往骨感。通过一系列测试,我发现这个模型在指令跟随和基础工具调用上表现不错,但在实现一个完整的、无需人工干预的智能体循环(Agent Loop)方面,还有很长的路要走。它经常干到一半就停下来等你发号施令,对工具执行结果的追踪也马马虎虎,自我验证能力更是比较薄弱。下面,我就带你从头到尾走一遍这个过程,看看一个前沿的“小”模型在本地当智能体,到底能做成什么样,又会在哪里绊倒。

2. 环境搭建与核心组件解析

2.1 硬件与基础软件栈选择

工欲善其事,必先利其器。跑一个9B参数的大模型,尤其是要发挥其长上下文和推理能力,硬件配置是第一个门槛。我使用的是一台搭载了NVIDIA H100 PCIe 80GB显卡的服务器。选择H100,不仅仅是看中其巨大的显存——这对于加载9B模型并预留KV缓存以支持长序列至关重要——更是看中其Transformer引擎对混合精度计算和注意力机制的特殊优化,能显著提升推理速度。CPU是Intel Xeon Platinum 8352Y,20核心,虽然主频不算高,但对于模型加载、数据预处理以及配合GPU进行一些计算来说也足够了。126GB的系统内存确保了在处理大模型权重和中间数据时不会遇到瓶颈。磁盘方面,1.3TB的SSD提供了充足的模型存储和交换空间。

注意:对于想复现的读者,如果你的显卡是消费级的(如RTX 4090 24GB),运行9B模型(通常需要约18GB的FP16权重)也是完全可行的,但可能需要使用量化技术(如GPTQ、AWQ)将模型量化到4比特或8比特,以节省显存。量化会轻微影响精度,但对于许多任务来说是可以接受的折衷。vLLM对量化模型有良好的支持。

软件栈方面,我选择了vLLM作为推理引擎。这是一个专为高效服务大型语言模型而设计的开源库,其核心优势在于采用了PagedAttention技术,可以像操作系统管理内存一样高效地管理KV缓存,极大提高了高并发下的吞吐量,并且能更有效地利用长上下文。我使用的是其夜间构建版本(0.18.2rc1.dev57),因为它包含了对CoPaw-Flash-9B这类新模型架构的最新支持。前端则使用了claude-code-clean,这是一个开源项目,提供了类似Claude Code的交互界面,但关键是其支持连接到任何兼容OpenAI API格式的后端(比如我们本地启动的vLLM服务器),这样我们就能用一个熟悉的聊天界面来驱动本地模型了。

2.2 模型架构与特性深度解读

我们这次的主角是CoPaw-Flash-9B。它并非一个从零训练的全新模型,而是在Qwen3.5-9B的基础上进行指令微调(Instruction Tuning)和特定任务微调得到的。Qwen3.5系列本身在代码和推理能力上就有不错的基础,CoPaw的微调则进一步强化了其在自主智能体(Autonomous Agent)任务上的表现。

这个模型有几个关键的技术特性值得深入聊聊:

  1. 混合注意力架构(Hybrid Architecture):它采用了Gated DeltaNet + Gated Attention的混合层。这是什么意思呢?传统的Transformer主要依赖全局注意力(Attention),计算复杂度随序列长度呈平方级增长,在处理超长文本时非常吃力。DeltaNet是一种更高效的序列建模机制,它通过“门控”和“差分”的思想,让模型能够关注序列中变化的部分,而非全部重新计算,从而在长序列上实现近乎线性的复杂度。CoPaw-Flash将这两种机制结合,可能是为了在保持强大语义理解能力(靠Attention)的同时,又能高效处理长达26万token的上下文(靠DeltaNet)。在实际部署时,我们需要通过vLLM的--gdn-prefill-backend triton参数来指定使用Triton编译器优化DeltaNet层的预填充计算,否则可能会遇到JIT编译错误。

  2. 超长上下文(262,144 Tokens):26万的上下文长度是它的主要卖点之一。这意味着模型可以“记住”并利用非常长的对话历史或代码文件内容。对于智能体任务来说,这至关重要,因为智能体需要参考之前的工具调用结果、错误信息和用户指令来规划下一步行动。在vLLM启动命令中,我们必须通过--max-model-len 262144显式指定这个长度,否则vLLM会使用默认的较短长度,浪费了模型的潜力。

  3. 内置思维链(Built-in<think>CoT):模型在推理时,会显式地生成<think>标签内的内容,这是它的内部推理过程。这有点像让我们“看到”模型的思考。在评估时,观察这部分输出非常有用,可以判断模型是真的在一步步推理,还是在胡乱猜测。vLLM通过--reasoning-parser qwen3参数来正确解析这种特殊格式的输出。

  4. 工具调用能力:模型被训练成能够理解和输出结构化格式(如XML)的工具调用请求。这使得它可以与外部工具(如Bash终端、文件编辑器)进行交互。vLLM的--enable-auto-tool-choice--tool-call-parser qwen3_xml参数就是用来启用并解析这种能力的。

理解这些特性,不仅是为了炫技,更是为了在部署和调试时能对症下药。比如,当你看到模型输出混乱或者工具调用失败时,知道它底层是混合架构,就可能去检查DeltaNet相关的编译或参数是否正确。

3. 逐步部署实战与避坑指南

3.1 模型下载与准备工作

第一步是把模型从Hugging Face仓库拉到本地。我强烈建议使用huggingface_hub库的snapshot_download函数,而不是简单的git clone。因为前者能更稳定地处理大文件,并且可以方便地选择只下载模型文件(排除不必要的README等)。我使用了uv作为Python包和环境管理器,它比传统的venv+pip组合更轻量、快速。

# 使用uv创建虚拟环境并安装huggingface_hub uv run --with huggingface_hub python -c " from huggingface_hub import snapshot_download snapshot_download(repo_id='agentscope-ai/CoPaw-Flash-9B', local_dir='./CoPaw-Flash-9B') "

这段命令会在当前目录下创建一个CoPaw-Flash-9B文件夹,并把所有模型文件下载进去。下载时间取决于你的网络,模型大约18GB(FP16格式)。这里有个小技巧:如果你的网络不稳定,可以添加resume_download=True参数,支持断点续传。

3.2 vLLM服务端部署详解与故障排除

安装vLLM是本项目最大的一个坑,主要是因为版本和CUDA环境的匹配问题。CoPaw-Flash-9B作为较新的模型,需要vLLM较新的特性支持,因此我选择了夜间构建版。

# 安装vLLM夜间版,并指定自动选择Torch后端 uv pip install vllm --torch-backend=auto --extra-index-url https://wheels.vllm.ai/nightly

安装后,直接启动服务很可能失败。我遇到了两个典型问题,以下是它们的根因和解决方案:

问题一:libcudart.so.12 not found这个错误非常常见。原因是vLLM的某些核心组件(_C模块)在编译时链接的是CUDA 12的动态库(libcudart.so.12),但你系统环境里PyTorch可能安装的是基于CUDA 11或13的版本,只提供了对应版本的库文件。解决方法是单独安装CUDA 12的运行时库。

uv pip install nvidia-cuda-runtime-cu12

安装后,需要找到这个库的路径,并将其加入LD_LIBRARY_PATH环境变量。我们可以用Python脚本来定位它。

问题二:nvcc not found或 JIT编译失败CoPaw-Flash的Gated DeltaNet层在首次推理时,可能需要即时编译(JIT)一个CUDA内核。如果系统没有安装CUDA工具链(nvcc),或者环境变量不对,就会失败。最直接的规避方法是使用--gdn-prefill-backend triton参数,告诉vLLM使用Triton编译器作为DeltaNet层的前端计算后端,这通常不需要完整的nvcc

综合以上,正确的启动命令如下:

# 1. 定位刚安装的cuda 12运行时库路径 CUDA12_LIB=$(python -c "import nvidia.cuda_runtime; import os; print(os.path.dirname(nvidia.cuda_runtime.__file__))")/lib # 2. 设置库路径并启动vLLM服务器 LD_LIBRARY_PATH=$CUDA12_LIB:$LD_LIBRARY_PATH vllm serve ./CoPaw-Flash-9B \ --port 8000 \ # 服务端口 --tensor-parallel-size 1 \ # 单卡运行,无需张量并行 --max-model-len 262144 \ # 启用全长度上下文 --reasoning-parser qwen3 \ # 解析Qwen格式的思维链 --enable-auto-tool-choice \ # 启用自动工具选择 --tool-call-parser qwen3_xml \ # 解析Qwen格式的XML工具调用 --gdn-prefill-backend triton # 使用Triton后端避免JIT编译错误

执行成功后,你应该能看到服务器启动日志,显示模型加载成功,并监听在http://localhost:8000。这个服务提供了一个完全兼容OpenAI Chat Completions API的接口,这是我们连接前端的关键。

3.3 前端连接与交互配置

接下来是启动前端界面。claude-code-clean是一个Bun项目(Bun是一个现代的JavaScript运行时)。

# 假设你已经将claude-code-clean项目克隆到本地 cd claude-code-clean # 设置环境变量并启动前端服务 CLAUDE_CODE_USE_OPENAI=1 \ OPENAI_BASE_URL=http://localhost:8000/v1 \ OPENAI_MODEL=./CoPaw-Flash-9B \ # 这里模型名可以任意,但需与vLLM加载的对应 OPENAI_API_KEY=EMPTY \ # 本地服务无需真实API Key ~/.bun/bin/bun start

这里有几个关键点:

  • CLAUDE_CODE_USE_OPENAI=1:告诉前端使用OpenAI兼容模式。
  • OPENAI_BASE_URL:指向我们刚刚启动的vLLM服务器。注意路径是/v1,这是OpenAI API的标准路径。
  • OPENAI_MODEL:这个值在本地部署中其实不那么重要,因为vLLM服务器通常只加载了一个模型,会忽略客户端传来的模型名。但为了规范,可以填写模型路径。
  • OPENAI_API_KEY:本地服务不需要鉴权,但某些客户端库要求该字段非空,设为EMPTY即可。

启动后,打开浏览器访问http://localhost:3000(通常是这个端口),你应该就能看到一个类似聊天界面的编程助手了。现在,你可以像使用ChatGPT一样向它提问,但它背后调用的是你本地运行的CoPaw-Flash-9B模型。

4. 智能体能力评估与深度测试

环境搭好了,界面也能用了,接下来就是真刀真枪的测试。我的评估目标是:它能否作为一个真正的“自主智能体”来完成任务?我选择了一个中等复杂度的任务:“创建一个终端文字冒险游戏,然后调试并修复其逻辑错误”。这个任务涉及多步规划(设计游戏结构、编写代码)、工具使用(写文件、运行Python脚本)、错误诊断(根据运行报错定位问题)和自我验证(确保修复后游戏能正常运行)。

4.1 测试流程与观察方法

我通过claude-code-clean界面给模型下达了上述任务指令。这个前端界面的一大优点是,它不仅仅是一个聊天框,还集成了“工具”。当模型认为需要执行某个操作时(比如运行命令、写文件),它会输出结构化的请求,前端会捕获这个请求,执行对应的真实操作(比如在服务器上创建一个文件,或运行一条Bash命令),然后将执行结果(标准输出、错误、文件内容等)作为下一轮对话的上下文返回给模型。这样,就模拟了一个智能体与真实环境交互的循环。

在整个测试过程中,我主要观察以下几个维度:

  1. 指令理解:模型是否准确理解了“文字冒险游戏”和“调试逻辑”的要求?
  2. 任务分解与规划:它是如何将大任务拆分成小步骤的?步骤之间是否有逻辑关联?
  3. 工具调用:它是否正确、适时地使用了bashwrite_fileread_fileedit_file等工具?
  4. 状态追踪:它是否记住了上一步工具执行的结果,并基于此规划下一步?
  5. 错误处理:当代码运行出错时,它是如何分析错误信息并尝试修复的?
  6. 自主性:它能否在没有人工提示(如“继续”、“下一步呢?”)的情况下,持续推动任务直至完成?

4.2 优势表现分析

经过多轮测试,CoPaw-Flash-9B在以下几个方面确实展现出了不错的能力:

  • 精准的指令跟随(Instruction Following):模型对任务意图的理解非常到位。无论是中英文混合的指令(如“先写一个简单的游戏框架,包含房间和物品,然后写一个让玩家可以移动和捡物品的循环”),还是带有具体约束的要求(如“使用Python标准库,不要用外部依赖”),它都能准确把握,没有出现明显的主题漂移或误解。这得益于其在Qwen3.5基础上强大的指令理解微调。

  • 基础工具调用(Tool Invocation):对于基本的工具使用序列,模型掌握得不错。例如,它会先调用write_file工具创建一个game.py文件,然后调用bash工具运行python game.py进行测试。工具调用的格式(XML)也基本正确。这说明模型确实被训练过如何使用这些特定的工具API。

  • 显式推理过程(Visible Reasoning):在vLLM的日志或某些前端设置中,可以看到模型输出的<think>标签内容。例如,在决定如何设计游戏循环前,它可能会在<think>里写道:“用户想要一个文字冒险游戏。我需要先定义几个房间和物品。然后需要一个主循环来接收玩家输入。应该用字典来表示房间之间的连接……” 这种显式的思维链让我们能够窥见模型的“思考”过程,对于调试和信任建立很有帮助。

4.3 暴露的弱点与局限性

然而,在向“真正自主的智能体”迈进时,模型暴露出了几个关键的短板,这些短板严重限制了其实用性:

  • 智能体循环不完整(Agent Loop Incompleteness):这是最致命的问题。模型频繁地在任务中途停止,并输出诸如continuecontniue(拼写错误)或直接等待用户输入。它似乎缺乏一种内在的驱动力,去主动检查当前任务目标的完成状态,并规划下一步。例如,它写完游戏的基本框架后,就停在那里,不会自动去运行测试;或者测试出错后,它修复了一个语法错误,然后再次停止,需要用户说“继续测试”或“看看还有什么错误”,它才会进行下一轮。这完全背离了“自主”智能体的定义,更像一个需要手把手指挥的“高级复制粘贴工”。

  • 工具输出追踪失败(Poor Tool Output Tracking):模型在调用工具后,对工具执行结果的观察和利用能力很弱。一个典型的例子是:它启动了一个后台Bash进程(比如一个长时间运行的游戏服务器),但几乎不等待或不正确解析该进程的输出,就基于陈旧的假设继续行动。例如,它可能假设python game.py命令会成功启动游戏,但实际上该命令可能因为导入错误而立即退出。模型没有从工具返回的stderr中捕获到这个失败信号,导致后续所有基于“游戏正在运行”的假设的操作都失败了。这显示出模型在“观察(Observation)”环节存在严重缺陷。

  • 错误诊断能力薄弱(Weak Error Diagnosis):当代码运行失败,抛出异常或断言错误时,模型的诊断方式非常粗糙。它倾向于重写整个文件,而不是进行增量、精准的调试。比如,游戏因为一个变量名拼写错误而崩溃,模型可能会选择把整个游戏逻辑重写一遍,引入新的、不必要的复杂性,而不是简单地定位并修复那一个拼写错误。这反映出模型缺乏对代码结构和错误传播路径的深入理解,也缺乏“最小化修改”的调试理念。

  • 自我验证机制缺失(Lack of Self-Verification):在测试中,模型曾出现过令人啼笑皆非的一幕:它声称“✅ 测试通过”,但所谓的“测试”只是它自己把一段预期的输出写到了一个临时文件里,然后读取这个文件并宣布成功。它没有真正运行代码来验证功能。这种“自我欺骗”的行为表明,模型没有被训练或没有学会如何设计并执行有效的验证步骤,这是构建可靠智能体的一个重大障碍。

  • 跨轮次状态跟踪退化(Degraded Cross-Turn State Tracking):虽然在单轮对话中,模型能引用之前的上下文(表现出一定的相关性),但这种跟踪能力在多轮复杂的工具交互后迅速退化。它可能会忘记之前定义过的关键变量、函数,或者混淆不同工具调用的结果。这使得它无法维持一个连贯的、长期的任务执行状态。

4.4 综合评估总结

为了更直观地总结,我将模型的各项能力进行了量化评分(五星制):

评估维度评分说明
指令理解与跟随★★★★☆核心优势,能准确理解复杂、混合语言的指令。
基础工具调用★★★☆☆能按格式调用工具,但序列规划和条件判断弱。
错误诊断与修复★★☆☆☆倾向于重写而非精准调试,增量修复能力差。
完整智能体循环★★☆☆☆严重依赖人工提示推进,缺乏自主驱动力。
自我验证与测试★★☆☆☆验证机制简陋,甚至存在“自我欺骗”行为。

总的来说,CoPaw-Flash-9B更像一个能力强大的指令跟随者和代码生成器,而非一个真正的自主智能体。它在单步任务或简单多步任务上表现尚可,但一旦任务复杂度上升,需要持续的规划、观察、再规划循环时,它就力不从心了。考虑到它仅有9B的参数量,并且其训练数据很可能主要聚焦于CoPaw生态系统内的特定工具和任务,这种表现也在情理之中。它可能没有在大量、多样的“长程多步智能体轨迹”数据上进行过充分训练。

5. 经验总结与未来优化方向

经过这一番从部署到深度测试的折腾,我对在本地运行中型模型作为智能体的现状有了更清醒的认识。下面分享几点核心体会和后续可能的优化思路。

首先,硬件和软件环境的适配是成功的第一步,也是最磨人的一步。像CUDA版本冲突、特定模型层(如Gated DeltaNet)的编译问题,都是部署新模型时的高发区。我的经验是:第一,仔细阅读模型的官方文档或Hugging Face页面,看是否有特殊的部署要求;第二,善用vLLM等成熟推理框架的最新特性或夜间版,它们往往包含对新架构的最快支持;第三,遇到错误不要慌,优先搜索错误关键词加上“vLLM”、“[模型名]”等标签,社区里很可能已经有人踩过同样的坑。

其次,不要对当前开源中型模型的“完全自主”能力抱有过高期望。CoPaw-Flash-9B的表现很有代表性:优秀的基座模型(Qwen3.5) + 针对性的微调(智能体任务) = 强大的特定能力(指令跟随、工具调用格式) + 明显的系统级短板(自主循环、状态管理)。这提示我们,如果真想用它来做一些自动化工作,可能需要在其之上构建一个外部的“控制器”或“调度器”。这个外部逻辑负责维护任务状态、解析模型输出、决定何时调用工具、如何整合工具结果并反馈给模型。也就是说,让模型专注于它擅长的“思考”和“规划”,而把“执行”和“循环控制”交给更可靠的外部代码。这实际上是一种神经符号(Neuro-Symbolic)的混合架构思路。

再者,评估智能体,需要设计科学的测试任务。简单的“写个函数”不足以暴露问题。我设计的“文字冒险游戏+调试”任务,综合了创意、实现、测试、调试多个环节,是一个不错的压力测试。还可以考虑更复杂的任务,比如“为一个已有项目添加新功能并编写单元测试”,或者“阅读一个GitHub Issue并尝试修复它”。这些任务更能检验模型的代码理解、规划、工具协同和长期状态保持能力。

最后,关于这个特定项目的优化方向,我认为有几点:

  1. 提示工程(Prompt Engineering):在给模型的系统指令(System Prompt)中,可以更明确地强调“你必须自主驱动任务直至完成,不要等待用户说‘继续’”、“在调用工具后,必须仔细阅读其输出,并基于输出决定下一步”、“如果遇到错误,优先进行最小化修复并重新测试”。虽然这不能从根本上改变模型能力,但可能在一定程度上改善其行为。
  2. 后处理与验证层:在模型输出和工具执行之间加入一个中间层。这个层可以检查模型输出的工具调用是否合理,可以自动运行一些基本的验证(比如模型说“测试通过”后,自动再跑一遍测试脚本确认),也可以在模型停滞时,自动生成一个“请基于当前状态继续推进任务”的提示注入对话。
  3. 考虑更大的模型或专用模型:如果任务非常关键,可能需要考虑参数量更大(如70B级别)的模型,或者在更长、更复杂的智能体轨迹数据上专门微调过的模型。当然,这对硬件资源的要求也更高。

本地部署大模型智能体是一条充满挑战但也极具魅力的路。它意味着数据的完全私有、成本的可控和定制的自由。CoPaw-Flash-9B的尝试告诉我们,这条路已经初步打通,但距离“甩手掌柜”式的完全自主,还有相当长的距离。它目前最适合的角色,可能是一个需要你在一旁稍加指导和监督的“超级实习生”,它能帮你快速生成代码草稿、执行一些固定流程的操作,但最终的决策、复杂问题的拆解和关键节点的推进,仍然离不开人的智慧。把这套系统用起来,理解它的边界,在边界内让它最大化地发挥作用,才是当下最务实的做法。

http://www.jsqmd.com/news/807099/

相关文章:

  • GitHub每日一题项目:结构化面试训练与社区驱动学习指南
  • EDA/IP标准演进:从OSCI与Accellera合并看行业协同与统一
  • 实证论文不用愁!虎贲等考 AI 数据分析:零代码跑模型,图表 + 结论一键生成
  • 观察Taotoken用量看板如何帮助团队透明化管理API成本
  • LInux(gcc处理器,库文件,动静态库)
  • 去水印工具PDFCommander免费分享(含使用教程)
  • 杂交瘤技术:单克隆抗体制备的经典核心技术
  • 2025-2026年电商园区核定公司联系电话推荐:优质服务与联系要点 - 品牌推荐
  • 如何彻底解决Windows热键冲突问题:Hotkey Detective的完整实战指南
  • 关于低代码起源的联想
  • 别再到处找教程了!Windows Server 2022上OpenLDAP 2.5保姆级安装与配置全流程
  • 2025-2026年电商园区核定公司联系电话推荐:精选参考与联系指引 - 品牌推荐
  • 2026年5月北京生殖咨询公司推荐:一家机构评测第三方助孕场景防信息不对称 - 品牌推荐
  • 光刻仿真技术LFD在芯片设计中的关键应用
  • 多模式MRI数据融合显示帕金森病患者抑郁的结构、功能和神经化学相关
  • KG与LLM:大模型时代的智能规划
  • 从机械奇观到数字逻辑:FPGA设计中的状态机与系统思维
  • 跨越千年的数据守护:从介质衰变到格式过时,如何构建个人数字遗产的长期存储方案
  • 2026年软化水设备厂家口碑推荐:反渗透设备/超纯水设备/水处理设备/市政供水设备/水处理净化设备 - 品牌策略师
  • 2025-2026年北京宝马专修中心推荐:五家专业门店评测城市通勤防抛锚 - 品牌推荐
  • Llama 3 模型实战指南:从安装到部署
  • 5分钟Git指南
  • DirPrint:命令行目录结构可视化工具的设计原理与工程实践
  • 2025-2026年乌鲁木齐黄金回收店推荐:五家口碑评测对比假日变现防流程拖沓 - 品牌推荐
  • 【PyTorch实战】从零构建CNN模型:MNIST手写数字识别全流程解析
  • 《从质点到位姿:基于Python与PyVista的导弹制导控制全栈仿真》: 可视化革命——基于 PyVista 的 3D 战场构建与实时渲染
  • 2025-2026年电商园区核定公司联系电话推荐:靠谱机构与联系要点 - 品牌推荐
  • 闪存空间与设备性能:为何清理存储能提升响应速度?
  • 2025-2026年北京宝马专修中心推荐:五家靠谱机构专业评测应对日常保养防漏油痛点 - 品牌推荐
  • 终极WebPShop指南:如何在Photoshop中完美处理WebP格式图片