Wan2.1-umt5代码生成效果实测:对比Claude Code的Python脚本编写能力

最近在代码生成领域,开源模型的表现越来越亮眼。特别是像Wan2.1-umt5这样的模型,经常被开发者拿来和Claude Code这样的知名闭源模型做比较。很多人好奇,一个免费开源的模型,在写代码这件事上,到底能不能和那些需要付费订阅的“明星选手”掰掰手腕?

为了回答这个问题,我决定做一次直接的对比实测。我挑选了几个开发者日常工作中最常遇到的编程场景,让Wan2.1-umt5和Claude Code分别来写Python脚本。我们不谈复杂的架构,也不看那些遥不可及的参数,就看最实际的东西:生成的代码能不能跑起来?逻辑对不对?写出来的代码风格怎么样?

这篇文章,我就把这次对比的完整过程和结果展示给你看。你可以把它看作是一次“代码生成能力”的公开测评,看看在真实的编程任务面前,开源模型的表现究竟如何。

1. 实测准备与对比方法

在开始之前,我先简单说明一下这次对比是怎么设计的。我的目标不是搞一个学术化的评测,而是模拟一个普通开发者遇到需求时的真实场景。

我选择了三个有代表性的Python编程任务,覆盖了不同的难度和常见用途:

  1. 数据爬虫任务:写一个爬取网页公开信息(比如新闻标题)的脚本。
  2. Web API接口任务:写一个简单的FastAPI服务,提供数据查询功能。
  3. 数据处理脚本任务:写一个读取CSV文件、进行数据清洗和简单分析的脚本。

对于每个任务,我会给Wan2.1-umt5和Claude Code完全相同的、用自然语言描述的需求提示。然后,我会从下面几个最实在的维度来评估它们生成的代码:

  • 代码正确性:这是底线。生成的代码能不能在不报错的情况下运行起来?这是第一关。
  • 逻辑完整性:代码有没有遗漏关键步骤?比如爬虫忘了处理异常,或者API没写返回格式。逻辑闭环做得好不好。
  • 代码风格与可读性:生成的代码看起来舒不舒服?变量命名清不清晰?有没有写必要的注释?这对于后续维护很重要。
  • 实用性考量:代码里有没有包含一些贴心的、面向实际使用的细节?比如建议的库安装命令,或者运行代码的示例。

我不会给代码打分,因为分数有时候太抽象了。我会把两个模型生成的代码都完整地贴出来,并附上我的运行结果和观察笔记。是好是坏,你可以自己判断,我也会分享我的使用感受。

2. 任务一:数据爬虫脚本生成对比

第一个任务,我们来试试写一个爬虫。需求很简单:“写一个Python脚本,使用requests和BeautifulSoup库,爬取某个新闻网站首页(例如Hacker News)的新闻标题和链接,并将结果打印出来。”

这个任务考验的是模型对常用库的熟悉程度,以及组装基础功能模块的能力。

2.1 Wan2.1-umt5生成的爬虫代码

以下是Wan2.1-umt5根据上述需求生成的代码:

import requests
from bs4 import BeautifulSoup

def scrape_news_titles(url):
    """
    爬取指定新闻网站首页的新闻标题和链接。

    Args:
        url (str): 目标新闻网站的首页URL。

    Returns:
        list: 包含字典的列表,每个字典有'title'和'link'键。
    """
    try:
        # 发送HTTP请求
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
        }
        response = requests.get(url, headers=headers, timeout=10)
        response.raise_for_status()  # 检查请求是否成功

        # 解析HTML内容
        soup = BeautifulSoup(response.content, 'html.parser')

        # 假设新闻标题在<h2>标签内,链接在<a>标签的href属性中
        # 注意:实际选择器需要根据目标网站结构调整
        news_items = []
        for item in soup.find_all('article', class_='story'):  # 示例选择器
            title_elem = item.find('h2')
            link_elem = item.find('a', href=True)

            if title_elem and link_elem:
                title = title_elem.get_text(strip=True)
                # 处理相对链接
                link = link_elem['href']
                if link.startswith('/'):
                    from urllib.parse import urljoin
                    link = urljoin(url, link)

                news_items.append({'title': title, 'link': link})

        return news_items

    except requests.exceptions.RequestException as e:
        print(f"网络请求出错: {e}")
        return []
    except Exception as e:
        print(f"解析过程出错: {e}")
        return []

if __name__ == "__main__":
    # 示例:爬取Hacker News首页
    target_url = "https://news.ycombinator.com/"
    results = scrape_news_titles(target_url)

    if results:
        print(f"从 {target_url} 爬取到 {len(results)} 条新闻:\n")
        for idx, news in enumerate(results, 1):
            print(f"{idx}. {news['title']}")
            print(f"   链接: {news['link']}\n")
    else:
        print("未爬取到任何新闻。")

运行与观察笔记:

  1. 直接运行:将代码中的target_url改为一个结构简单的测试网站(如某个博客),并调整soup.find_all中的选择器(如将'article', class_='story'改为'h2')后,脚本可以成功运行并打印出标题和链接。
  2. 代码亮点
    • 结构完整:定义了清晰的函数,包含文档字符串说明参数和返回值。
    • 健壮性考虑:使用了try-except块捕获网络请求和解析异常,并设置了请求超时和User-Agent头,这对爬虫很重要。
    • 细节处理:注意到了相对链接转绝对链接的问题,使用了urljoin方法。
    • 可读性好:变量命名清晰,有基础注释,主程序部分给出了使用示例。
  3. 待改进点:代码中的CSS选择器('article', class_='story')是针对某个特定网站结构的示例。模型在注释里提醒了这一点,但生成的代码本身没有提供更通用的选择器方案或指导用户如何自行查找。对于新手来说,拿到代码后还需要自己研究目标网站的HTML结构。

2.2 Claude Code生成的爬虫代码

接下来是Claude Code针对同一需求生成的代码:

import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin

def scrape_hacker_news():
    """Scrape Hacker News homepage for story titles and links."""
    url = "https://news.ycombinator.com/"
    
    try:
        # Send request with headers to mimic browser
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
        }
        response = requests.get(url, headers=headers, timeout=10)
        response.raise_for_status()
        
        # Parse HTML
        soup = BeautifulSoup(response.text, 'html.parser')
        
        # Find all story rows on Hacker News
        stories = []
        story_rows = soup.find_all('tr', class_='athing')
        
        for row in story_rows:
            # Find title link within the row
            title_elem = row.find('span', class_='titleline').find('a')
            if title_elem:
                title = title_elem.text
                link = title_elem['href']
                
                # Convert relative URLs to absolute
                if link.startswith('item?id='):
                    # Hacker News internal links
                    link = urljoin(url, link)
                elif link.startswith('/'):
                    # Other relative links
                    link = urljoin('https://news.ycombinator.com/', link)
                    
                stories.append({
                    'title': title,
                    'link': link,
                    'source': 'Hacker News'
                })
        
        return stories
        
    except requests.exceptions.RequestException as e:
        print(f"Request failed: {e}")
        return []
    except Exception as e:
        print(f"Error during scraping: {e}")
        return []

def print_stories(stories):
    """Print scraped stories in a readable format."""
    if not stories:
        print("No stories found.")
        return
        
    print(f"\nFound {len(stories)} stories:\n")
    for i, story in enumerate(stories, 1):
        print(f"{i}. {story['title']}")
        print(f"   Link: {story['link']}")
        print(f"   Source: {story['source']}")
        print()

if __name__ == "__main__":
    stories = scrape_hacker_news()
    print_stories(stories)

运行与观察笔记:

  1. 直接运行:这段代码针对Hacker News网站,使用了该网站特定的HTML类名(class_='athing'class_='titleline')。直接运行,可以成功爬取到Hacker News首页的新闻标题和链接,无需修改。
  2. 代码亮点
    • 高度针对性:代码完全为Hacker News定制,选择器精准,开箱即用。
    • 逻辑更细致:特别处理了Hacker News的内部链接格式('item?id='),考虑到了目标网站的特殊性。
    • 功能分离:将爬取逻辑和打印逻辑分离成两个函数,结构更清晰。
    • 输出信息更丰富:在结果中增加了'source'字段。
  3. 对比思考:Claude Code的代码在这个特定任务上“完成度”更高,因为它直接给出了可运行、有针对性的解决方案。而Wan2.1-umt5的代码更像一个“模板”,需要用户根据实际情况调整选择器。这反映了两者不同的风格:一个倾向于提供具体解决方案,另一个倾向于提供通用框架。

3. 任务二:Web API接口生成对比

第二个任务,我们提升一点难度,看看它们编写Web服务的能力。需求是:“使用FastAPI框架,创建一个简单的图书查询API。需要有一个GET接口 /books,返回一个预设的图书列表(包含id、title、author字段)。再有一个GET接口 /books/{book_id},根据id返回对应的图书信息。”

这个任务考验模型对现代Web框架的掌握,以及设计API路由和数据结构的能力。

3.1 Wan2.1-umt5生成的FastAPI代码

Wan2.1-umt5生成的FastAPI应用代码如下:

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import List, Optional

app = FastAPI(title="Simple Book API", description="A simple API for book information.")

# 定义数据模型
class Book(BaseModel):
    id: int
    title: str
    author: str

# 模拟数据库中的图书数据
fake_books_db = [
    Book(id=1, title="The Great Gatsby", author="F. Scott Fitzgerald"),
    Book(id=2, title="To Kill a Mockingbird", author="Harper Lee"),
    Book(id=3, title="1984", author="George Orwell"),
    Book(id=4, title="Pride and Prejudice", author="Jane Austen"),
]

@app.get("/")
async def root():
    return {"message": "Welcome to the Book API. Try /books or /books/{id}."}

@app.get("/books", response_model=List[Book])
async def get_all_books():
    """获取所有图书列表。"""
    return fake_books_db

@app.get("/books/{book_id}", response_model=Book)
async def get_book_by_id(book_id: int):
    """根据ID获取特定图书。"""
    book = next((book for book in fake_books_db if book.id == book_id), None)
    if book is None:
        raise HTTPException(status_code=404, detail="Book not found")
    return book

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

运行与观察笔记:

  1. 直接运行:安装fastapiuvicorn后,直接运行该脚本,API服务成功启动。访问http://127.0.0.1:8000/bookshttp://127.0.0.1:8000/books/1,均能返回正确的JSON数据。
  2. 代码亮点
    • 框架使用规范:正确导入了FastAPI和Pydantic,使用BaseModel定义了清晰的数据结构。
    • API设计完整:完全按照需求实现了两个端点,根路径还有欢迎信息。
    • 错误处理到位:在/books/{book_id}接口中,使用next()函数查找图书,并在未找到时抛出带有404状态码的HTTPException,这是RESTful API的常见做法。
    • 生产就绪细节:在__main__中直接集成了uvicorn服务器启动代码,方便测试运行。为FastAPI应用设置了titledescription
  3. 整体感受:这段代码非常扎实,几乎可以直接用于一个简单的原型项目或微服务中。它展示了模型对FastAPI生态的良好理解。

3.2 Claude Code生成的FastAPI代码

Claude Code生成的代码如下:

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import List

app = FastAPI()

# Pydantic model for Book
class Book(BaseModel):
    id: int
    title: str
    author: str

# In-memory database
books = [
    Book(id=1, title="The Catcher in the Rye", author="J.D. Salinger"),
    Book(id=2, title="The Hobbit", author="J.R.R. Tolkien"),
    Book(id=3, title="Brave New World", author="Aldous Huxley"),
    Book(id=4, title="The Lord of the Rings", author="J.R.R. Tolkien"),
]

@app.get("/")
async def read_root():
    return {"message": "Book API is running. Use /books or /books/{id}"}

@app.get("/books", response_model=List[Book])
async def read_books():
    """Get all books."""
    return books

@app.get("/books/{book_id}", response_model=Book)
async def read_book(book_id: int):
    """Get a specific book by ID."""
    for book in books:
        if book.id == book_id:
            return book
    raise HTTPException(status_code=404, detail="Book not found")

# Additional endpoint example
@app.get("/books/search/")
async def search_books(author: str = None):
    """Search books by author (optional query parameter)."""
    if author:
        filtered_books = [b for b in books if b.author.lower() == author.lower()]
        return filtered_books
    return books

运行与观察笔记:

  1. 直接运行:同样成功运行,所有接口工作正常。
  2. 代码亮点
    • 简洁直接:代码非常简洁,没有多余的装饰,直奔主题。
    • 额外的功能:除了需求中的两个端点,Claude Code“额外赠送”了一个/books/search/端点,支持按作者查询图书。这展示了它的“拓展性思维”。
    • 清晰的逻辑:在read_book函数中使用for循环查找图书,逻辑对初学者非常友好。
  3. 对比思考:两者都高质量地完成了核心需求。Wan2.1-umt5的代码在“规范性”和“生产细节”上略胜一筹(如应用描述、集成服务器启动)。而Claude Code的代码则更“灵活”和“有创意”,主动增加了一个实用的搜索功能。这可以看作是“严谨工程师”和“贴心助手”两种风格的差异。

4. 任务三:数据处理脚本生成对比

最后一个任务,我们回到数据领域,看看处理结构化数据的能力。需求是:“编写一个Python脚本,使用pandas库读取一个名为sales_data.csv的文件。假设文件包含date, product, quantity, revenue字段。请计算:1) 总销售额(revenue总和)。2) 最畅销的产品(quantity总和最大)。3) 将结果输出到一个新的CSV文件summary.csv中。”

这个任务综合考察了模型对pandas API的熟悉度、数据聚合操作以及文件读写能力。

4.1 Wan2.1-umt5生成的数据处理代码

Wan2.1-umt5生成的脚本如下:

import pandas as pd

def process_sales_data(input_file, output_file):
    """
    处理销售数据CSV文件,计算关键指标并保存结果。

    Args:
        input_file (str): 输入CSV文件路径。
        output_file (str): 输出结果CSV文件路径。
    """
    try:
        # 1. 读取数据
        df = pd.read_csv(input_file)
        print(f"成功读取文件: {input_file}")
        print(f"数据形状: {df.shape}")

        # 2. 计算总销售额
        total_revenue = df['revenue'].sum()
        print(f"总销售额: ${total_revenue:.2f}")

        # 3. 计算最畅销产品(按销售数量)
        # 按产品分组并汇总数量
        product_sales = df.groupby('product')['quantity'].sum().reset_index()
        # 找到数量最大的行
        top_product_row = product_sales.loc[product_sales['quantity'].idxmax()]
        top_product_name = top_product_row['product']
        top_product_quantity = top_product_row['quantity']

        print(f"最畅销产品: {top_product_name} (总销量: {top_product_quantity})")

        # 4. 创建汇总结果的DataFrame
        summary_data = {
            'metric': ['Total Revenue', 'Top Selling Product', 'Top Product Quantity'],
            'value': [f"${total_revenue:.2f}", top_product_name, str(top_product_quantity)]
        }
        summary_df = pd.DataFrame(summary_data)

        # 5. 保存结果到CSV
        summary_df.to_csv(output_file, index=False)
        print(f"分析结果已保存至: {output_file}")

        # 6. 在控制台也打印一下结果表格
        print("\n--- 分析摘要 ---")
        print(summary_df.to_string(index=False))

    except FileNotFoundError:
        print(f"错误:找不到输入文件 '{input_file}',请检查路径。")
    except KeyError as e:
        print(f"错误:CSV文件中缺少必要的列: {e}")
    except Exception as e:
        print(f"处理数据时发生未知错误: {e}")

if __name__ == "__main__":
    # 使用示例
    input_csv = "sales_data.csv"  # 请确保此文件存在
    output_csv = "summary.csv"
    process_sales_data(input_csv, output_csv)

运行与观察笔记:

  1. 直接运行:准备一个符合字段假设的sales_data.csv文件后,脚本成功运行,在控制台打印了计算结果,并生成了summary.csv文件。
  2. 代码亮点
    • 健壮性突出:异常处理非常全面,涵盖了文件不存在、列名错误等常见问题,并给出了清晰的错误提示。
    • 逻辑步骤清晰:将计算过程分解为读取、计算、汇总、保存等步骤,注释明确。
    • 输出形式多样:既将结果保存为CSV,也在控制台进行了格式化打印,方便即时查看。
    • 考虑周全:在汇总DataFrame中,将数值和字符串分开处理(如金额前加$),使输出更美观。
  3. 整体感受:这是一个非常“可靠”和“用户友好”的脚本。它不仅仅完成了计算,还充分考虑到了实际使用中可能遇到的问题,像一个经验丰富的开发者写的工具脚本。

4.2 Claude Code生成的数据处理代码

Claude Code生成的脚本如下:

import pandas as pd

# Read the CSV file
df = pd.read_csv('sales_data.csv')

# Display basic info about the data
print("Data Overview:")
print(df.info())
print("\nFirst few rows:")
print(df.head())

# 1. Calculate total revenue
total_revenue = df['revenue'].sum()
print(f"\n1. Total Revenue: ${total_revenue:,.2f}")

# 2. Find best-selling product by quantity
product_quantity = df.groupby('product')['quantity'].sum()
best_product = product_quantity.idxmax()
best_quantity = product_quantity.max()

print(f"2. Best-Selling Product: {best_product}")
print(f"   Total Quantity Sold: {best_quantity:,}")

# 3. Additional analysis: Revenue by product
product_revenue = df.groupby('product')['revenue'].sum().sort_values(ascending=False)
print(f"\n3. Revenue by Product (sorted):")
for product, revenue in product_revenue.items():
    print(f"   {product}: ${revenue:,.2f}")

# 4. Create a summary DataFrame
summary = pd.DataFrame({
    'Metric': ['Total Revenue', 'Best-Selling Product', 'Best-Selling Product Quantity'],
    'Value': [f"${total_revenue:,.2f}", best_product, f"{best_quantity:,}"]
})

# 5. Save to CSV
summary.to_csv('summary.csv', index=False)
print(f"\nSummary saved to 'summary.csv'")

# 6. Show the summary
print("\nSummary Table:")
print(summary)

运行与观察笔记:

  1. 直接运行:同样成功运行,完成了核心计算并生成了摘要文件。
  2. 代码亮点
    • 探索性分析:代码开头就加入了df.info()df.head(),这对于初次接触数据集的用户非常有用,是一个很好的数据分析习惯。
    • 额外的洞察:和上一个任务类似,Claude Code“超额完成”了需求,主动计算并打印了“按产品划分的销售额”排序列表,提供了更多业务洞察。
    • 代码紧凑:使用product_quantity.idxmax().max()在一行内获取最畅销产品名和销量,非常简洁。
    • 输出格式美观:在打印金额和数量时使用了:,.2f:,的格式化方法,增加了千位分隔符,使数字更易读。
  3. 对比思考:Wan2.1-umt5的脚本像一个“健壮的工具”,重点在于封装和错误处理,适合集成到自动化流程中。Claude Code的脚本则像一个“交互式分析笔记”,重点在于探索和展示,提供了更多即时的、可视化的信息,更适合在Jupyter Notebook等环境中进行快速分析。

5. 总结与感受

经过这三个不同场景的对比实测,我对Wan2.1-umt5和Claude Code在代码生成上的能力有了更具体的认识。总的来说,两者的表现都超出了我的预期,但风格和侧重点确实有所不同。

Wan2.1-umt5给我的感觉更像一个“扎实的工程师”。它生成的代码结构清晰,非常注重健壮性和规范性。你会看到完善的异常处理、清晰的函数文档、以及对生产环境细节的考虑(比如API的标题描述、爬虫的请求头设置)。它提供的代码可能不会给你太多“惊喜”,但通常很可靠,基础打得非常牢,稍作调整就能投入到实际使用中。对于希望获得稳健、可维护代码的开发者来说,这是一个很大的优点。

Claude Code则更像一个“思维活跃的助手”。它非常擅长理解你的意图,并且经常能给出超出你原始需求的、更有“想法”的代码。比如,它会主动添加一个搜索API端点,或者在你的数据分析脚本里多算几个指标。它的代码往往更简洁、更“Pythonic”,并且非常注重输出结果的可读性和即时反馈(比如打印数据预览)。这种风格在快速原型设计、探索性编程或者学习新库时特别有帮助。

在代码的正确性上,两者在这次测试中都做到了“一次生成,基本可运行”。在逻辑完整性上,也都很好地满足了核心需求。最大的差异就在于上述的风格和“附加值”上。

所以,到底哪个更好?我觉得这取决于你的具体场景和偏好。如果你需要的是一个稳定、可靠、开箱即用的代码生成工具,并且不介意(甚至需要)一个通用的、需要你稍作适配的代码框架,那么Wan2.1-umt5作为开源模型,其表现已经极具竞争力。如果你更看重模型的“理解力”和“创造力”,希望它能帮你拓展思路,提供更贴心、更完整的解决方案,那么Claude Code的优势也很明显。

这次实测让我看到,开源模型在代码生成这个赛道上,已经能够提供非常接近甚至在某些方面媲美顶级闭源模型的体验。对于广大开发者来说,这无疑是个好消息,意味着我们有了更多高质量、可自由使用的选择。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐