2026年1月

在产品研发全生命周期中,需求管理是产品工作的起点与核心,而产品需求池则是所有需求的“统一入口”与“管理中枢”。从客户反馈、业务诉求到用户建议、内部创意,各类需求杂乱分散的问题,往往导致需求遗漏、优先级混乱、落地无追踪,最终让产品研发偏离业务核心。产品需求池管理工具的核心价值,不在于单纯的“需求收纳”,而在于建立从需求汇聚、筛选评估、优先级排序到落地追踪、复盘优化的全流程闭环管理机制,让每一个需求都有迹可循、每一次决策都有据可依,让产品研发始终围绕业务价值与用户需求展开。一套适配的需求池管理工具,能让产品团队的需求管理从“被动应对”变为“主动规划”,从“零散无序”变为“体系化管控”,最终提升产品迭代的效率与价值。

一、为什么产品团队必须用工具做需求池管理?

很多中小团队认为“需求少,用表格/文档就能管需求池”,但随着产品迭代深入、需求来源增多、跨团队协作频繁,人工管理的弊端会逐步暴露,最终成为产品研发的“效率瓶颈”。真正有效的产品需求池管理,需要解决需求全生命周期的核心痛点,回答产品团队、业务方、研发团队最关心的关键问题:
• 需求是否全汇聚:内外部所有需求是否都统一收纳,有无遗漏、重复的情况?
• 信息是否标准化:每一条需求的背景、目标、受众、价值是否清晰,是否具备可评估性?
• 优先级是否明确:需求的排序是否贴合业务战略、用户价值,是否让研发团队有清晰的执行方向?
• 落地是否可追踪:需求从立项、开发、测试到上线,每一个阶段的进度是否透明,是否有明确的负责人与时间节点?
• 价值是否可验证:需求上线后的效果是否能复盘,是否实现了预期的业务/用户价值,是否为后续需求决策提供参考?
产品需求池管理工具,正是为解决这些问题而生。它通过标准化的需求录入模板、结构化的评估维度、可视化的优先级排序、全链路的进度追踪、数据化的复盘分析,让需求管理从“人工手动操作”变为“工具化高效管控”,让产品团队、业务方、研发团队对需求形成统一的认知、统一的标准、统一的节奏,避免因需求管理混乱导致的产品研发返工、版本延期、价值偏离。

二、哪些团队最需要专业的产品需求池管理工具?

中大型产品研发团队

这类团队产品模块多、业务线复杂、需求提报量庞大,人工管理无法实现需求的精细化管控,易出现需求遗漏、优先级混乱、落地无追踪的问题。专业的需求池管理工具能实现需求的标准化、体系化管控,提升需求管理效率,让产品研发围绕核心业务展开。

跨团队/跨地域协作的产品团队

当产品团队与业务、研发团队跨部门、跨地域协作时,线下沟通效率低、信息差明显,人工管理无法实现需求进度的实时同步。需求池管理工具能打破空间与部门壁垒,让所有协作方共享统一的需求信息,实现高效的跨团队协同。

业务场景复杂的ToB产品团队

ToB产品的需求多来自企业客户,需求个性化强、关联业务流程复杂,且需要严格的需求评估与价值验证。需求池管理工具能通过标准化的评估维度、全链路的落地追踪、数据化的复盘分析,确保客户需求的落地质量与价值实现,提升客户满意度。

快速迭代的互联网ToC产品团队

ToC产品研发节奏快、版本迭代频繁,对需求的优先级排序与落地效率要求高。需求池管理工具能实现需求的快速提报、科学排序、实时追踪,让研发团队聚焦高价值、高紧急的需求,保障产品迭代节奏,快速响应市场与用户需求。

有明确业务战略的企业产品团队

这类团队的产品研发需要紧密贴合企业的业务战略,避免研发与业务脱节。需求池管理工具能通过结构化的需求评估维度,将需求与业务战略绑定,确保优先落地符合业务战略的高价值需求,让产品成为实现业务目标的核心载体。

非产品岗位提报需求频繁的团队

当销售、客服、业务部门等非产品岗位需要频繁提报需求时,人工管理会导致需求提报门槛高、信息不规范、沟通成本高。需求池管理工具能提供快捷的需求提报入口、标准化的录入模板,降低非产品岗位的提报门槛,同时确保需求信息的完整性与规范性。

三、工具推荐:适配不同场景的产品需求池管理工具

各类工具的核心能力、易用性与扩展性不同,适配不同团队规模与场景,选择核心是“适配”而非“最优”。

  1. 专业需求管理工具:中大型/精细化管理团队首选
    专为需求管理设计,功能精细化,适配对需求管控有高要求的中大型团队、ToB团队。
    • ProductPlan:国际主流,核心优势为可视化路线图与科学优先级排序,适配全球化协作团队;
    • 需求魔方:国产适配性强,支持多源汇聚、跨团队评审与全链路追踪,适配中大型ToB/ToC团队;
    • UserStoryMap:聚焦敏捷研发,以用户故事地图绑定需求与场景,适配敏捷互联网团队。
  2. 轻量化协同看板工具:中小/初创团队快速落地之选
    以看板为核心,操作简单、易上手,满足中小团队核心需求管理与跨团队协同。
    • 板栗看板:自定义需求卡片与字段,支持拖拽更新进度,协同便捷,适配中小团队快速落地;
    • 飞书项目/钉钉项目:与办公工具无缝集成,适配已使用飞书/钉钉的中小团队;
    • Trello/Asana:国际轻量化工具,自定义度高,适配跨地域协作的小型/初创团队。
  3. 通用文档/表格工具:微型团队临时过渡之选
    含Excel、WPS、语雀等,非专用工具,仅具备基础录入、筛选功能,操作门槛极低,适合刚起步、需求极少的微型团队临时使用。优势是零学习成本,劣势是无查重、追踪等功能,需求量增加后易混乱。
    多数团队初期最优解:“轻量化协同看板工具+通用文档工具”,兼顾核心需求管控与资料留存;后期可根据团队规模与管理要求,升级为专业工具或一体化研发管理工具。

四、常见问题答疑

Q1:微型团队需求少,有必要引入专业的需求池管理工具吗?
A:无需引入专业工具,轻量化协同看板工具(如板栗看板)或通用表格工具即可满足核心需求,重点是建立简单的需求管理规范,避免需求遗漏。当团队规模扩大、需求提报量增多后,再逐步升级工具。

Q2:非产品岗位人员不会用工具,导致需求提报效率低怎么办?
A:核心是降低使用门槛:一是选择操作简单、易用性强的工具,如轻量化协同看板工具,无需复杂学习即可上手;二是制作简易的提报教程,通过图文、短视频的形式教非产品岗位人员操作;三是设立专人对接,非产品岗位人员可先将需求口头/文字告知对接人,由对接人统一在工具中录入。

Q3:需求优先级经常因业务方要求而变动,工具能解决这个问题吗?
A:工具本身无法直接解决优先级变动问题,但能让优先级变动更科学、更透明:一是通过工具建立结构化的评估维度,让优先级排序有客观标准,减少业务方的主观干预;二是在工具中记录优先级变动的原因、审批人,实现变动可追溯;三是将优先级变动后的影响同步在工具中,如研发任务调整、版本延期等,让业务方清晰了解变动的后果。

Q4:需求上线后的效果复盘难以落地,工具能提供哪些帮助?
A:工具能通过标准化的复盘维度、数据化的记录方式,让复盘落地更简单:一是在工具中为每一条需求设置“价值目标”“验收标准”字段,上线后对照字段验证效果;二是支持将需求与产品核心指标关联,直接录入复盘数据,实现价值量化;三是在工具中记录复盘结果、改进建议,为后续需求决策提供参考,形成闭环。

Q5:如何避免工具中的需求成为“僵尸需求”(提报后无评估、无落地)?
A:可通过工具设置+流程规范双重管控:一是在工具中为需求设置“有效期限”,超过期限未评估的需求,自动提醒产品负责人;二是建立需求清理机制,定期(如每月)对工具中的“僵尸需求”进行排查,经评估无价值的需求直接关闭,有价值但暂不落地的需求标记为“暂缓”,并记录暂缓原因;三是在工具中明确需求评估的时间节点,确保需求提报后及时得到评估。

五、结语

产品需求池管理的本质,是对产品研发源头的管控,而产品需求池管理工具,是实现这一管控的高效载体。在产品研发越来越注重效率与价值的今天,杂乱无章的需求管理,必然会导致产品研发偏离核心、资源浪费、效率低下;而体系化的需求管理,能让产品团队始终围绕业务价值与用户需求展开研发,让每一次迭代都有明确的目标,让每一份研发资源都能发挥最大价值。
工具本身没有好坏,只有适配与否。对于产品团队而言,无需盲目追求功能复杂的专业工具,而是要根据自身的团队规模、业务场景、工作习惯,选择最适配的工具,同时建立统一的需求管理流程与使用规范,让工具真正成为需求管理的“助力”,而非“负担”。
真正的高效需求管理,从来不是工具的单向作用,而是工具+流程+文化的三者结合。当工具成为全员的工作习惯,当流程成为全员的行为准则,当“以价值为导向、以数据为依据”成为需求管理的核心文化,产品需求池管理才能真正实现体系化、高效化,产品研发才能真正做到“有的放矢”,最终打造出贴合业务、满足用户的优质产品。

文 / Kenyon,由于公众号推流的原因,请在关注页右上角加星标,这样才能及时收到新文章的推送。

摘要:本文以电商物流行业为背景,详细介绍如何运用领域驱动设计(DDD)来设计一款电商物流ERP的系统。从领域识别、上下文界定,到实体、值对象、聚合根、领域事件等领域对象的分析与提取,结合UML图表展示,为架构师提供一套完整的DDD实践方法论。

引言

大家好,我是Kenyon!在前面的文章中,我们探讨了架构设计的原则、方法和工具。今天,我们将聚焦于一个具体的实践场景——如何在电商物流行业中应用领域驱动设计(下文统一使用DDD)这个架构方法来构建一套电商物流ERP这样的系统。

电商物流ERP示例图
先简单介绍一下电商物流ERP是什么,它们是一款专门为跨境电商卖家提供订单管理、仓储管理、物流管理等一体化服务的系统。这样的系统涉通常会及到很多个复杂的业务领域,所以如何做到清晰地划分领域和系统的边界、识别核心业务、设计合理的领域模型,是系统是否能成功非常关键的步骤。DDD作为一种专注于业务领域的设计方法,它能很好地帮助我们去做好这些工作。

下面,我们会按照DDD的核心设计步骤,先从领域识别开始,然后逐步深入到领域对象的分析与提取,最终通过UML图表来展示一个完整的设计系统设计方案。

一、DDD是什么?

在实践开始之前,让我们先回顾一下DDD相关的核心概念,这有助于让我们更好地理解后续的整个设计和落地的过程:

  1. 领域:指的是特定业务范围的知识、规则和实践的总和。比如拿电商物流行业来说,就是我们常说的订单管理、物流管理、仓储管理等这些业务功能和模块。
  2. 子域:指的是领域的细分,通常分为核心域、支撑域和通用域,每个子域都有自己的业务逻辑和数据模型。比如订单管理子域、仓储管理子域、物流管理子域等。
  3. 限界上下文:领域模型的边界,明确在边界内术语、概念和业务规则之间能保持一致,是一个语义上完整的业务单元。我感觉这个是一个比较容易混淆的地方,因为不同限界上下文之间可能存在相同术语但含义不同的情况,需要通过上下文映射来协调。例如,在"订单管理"限界上下文中,"订单"指的是客户的购买请求,包含商品、数量、价格等信息;而在"物流管理"限界上下文中,"订单"可能指的是需要配送的包裹信息,包含收件人、地址、配送方式等信息。这两个上下文虽然都有"订单"概念,但含义和处理逻辑不同,因此需要划分为不同的限界上下文。
  4. 实体:具有唯一标识的领域对象,其状态可以随时间变化。比如订单、客户、产品等,跟我们开发过程中常说的实体(Entity)是一个意思。
  5. 值对象:描述性的领域对象,没有唯一标识,通常是不可变的,比如像订单里面的地址、金额,物流运输过程中的时间间隔等。
  6. 聚合根:聚合的根实体,是聚合对外的唯一入口点,负责维护聚合的一致性和完整性。比如订单(Order)是订单聚合的根实体,客户(Customer)是客户聚合的根实体,产品(Product)是产品聚合的根实体等。
  7. 聚合:一组具有内聚关系的实体和值对象的集合,聚合内的对象只能通过聚合根来访问,聚合根负责维护聚合的一致性和完整性。比如订单聚合包含订单(Order)、订单行项(OrderItem)、收货地址(ShippingAddress)等,仓储聚合包含仓库(Warehouse)、库位(Location)、库存记录(InventoryRecord)等。
  8. 领域事件:领域中发生的重要事件,通常用于跨聚合或限界上下文的通信。比如订单创建事件(OrderCreatedEvent)、订单状态变更事件(OrderStatusChangedEvent)、物流状态更新事件(LogisticsStatusUpdatedEvent)等。
  9. 领域服务:封装不属于任何实体或值对象的业务逻辑,负责协调多个聚合之间的操作。比如订单管理领域服务(OrderDomainService)、仓储管理领域服务(WarehouseDomainService)、物流管理领域服务(LogisticsDomainService)等。
  10. 仓储:负责持久化聚合和提供聚合的访问方法,是领域模型与外部存储系统(如数据库、消息队列等)之间的桥梁,负责将聚合从内存中持久化到存储中,以及从存储中加载聚合到内存中。比如订单管理仓储(OrderRepository)、仓储管理仓储(WarehouseRepository)、物流管理仓储(LogisticsRepository)等。
  11. 用户界面:负责与用户交互,展示领域模型的状态和处理用户输入。比如订单管理用户界面(OrderController)、仓储管理用户界面(WarehouseController)等。
  12. CQRS模式:将命令(写操作)和查询(读操作)分离开来,分别由不同的处理逻辑和数据存储。比如订单管理命令查询分离(OrderCommandQuerySeparation)、仓储管理命令查询分离(WarehouseCommandQuerySeparation)等。

二、电商物流领域的识别与划分

2.1 业务场景分析

根据上面说举例的DDD的概念示例,我们可以把电商物流ERP这样的系统所涉及的主要业务场景按下面这样的方式来进行划分:

  • 订单管理:接收来自不同电商平台的订单,处理订单状态变更、订单取消等操作
  • 产品管理:管理商品信息、库存状态、SKU等
  • 仓储管理:仓库规划、库位管理、库存盘点
  • 物流管理:选择物流渠道、生成物流标签、跟踪物流状态
  • 采购管理:根据库存水平自动或手动生成采购单
  • 财务管理:订单对账、费用核算、报表生成
  • 客户管理:管理买家信息、沟通记录
  • 平台集成:与Amazon、eBay、Shopify等电商平台的对接

2.2 子域划分

基于上述业务场景,我们可以将电商物流领域划分为以下子域:

子域类型子域名称描述重要性
核心域订单管理处理订单生命周期,是系统的核心价值
核心域物流管理管理物流渠道和物流状态,直接影响客户体验
支撑域仓储管理支持订单和物流的执行,管理库存
支撑域产品管理管理商品信息,为订单和仓储提供基础数据
支撑域采购管理保证库存充足,支持销售业务
支撑域财务管理处理财务核算,为决策提供数据
支撑域客户管理管理客户信息,提升服务质量
通用域平台集成与外部电商平台对接,获取订单数据
通用域用户管理系统用户认证和授权

2.3 限界上下文界定

根据子域划分,我们可以界定出以下限界上下文:

限界上下文示例图

三、领域对象分析与提取

下面我们开始分析系统中所涉及到的订单上下文的领域对象。

3.1 订单上下文

3.1.1 实体与值对象

实体

  • 订单(Order):订单的实体,具有唯一订单号,状态会随着订单处理的过程变化而更新。
  • 订单行项(OrderItem):订单中的商品明细,与订单关联。

值对象

  • 订单状态(OrderStatus):表示订单的当前状态,如待处理、已发货、已完成等。
  • 收货地址(ShippingAddress):描述收货位置,无唯一标识,如果是电商系统的话,这里可以设计成有唯一标识的实体。
  • 付款信息(PaymentInfo):描述付款方式和状态,无唯一标识,如果是电商系统的话,这里也可以设计成有唯一标识的实体。

3.1.2 聚合根与聚合

聚合根

  • 订单(Order):作为聚合根,负责管理订单、订单项、订单状态、收货地址、付款信息等,如果用充血模型的话,这里还应包含了订单创建、更新、取消等业务操作的逻辑处理。

聚合

  • 订单聚合:包含订单、订单行项、收货地址、付款信息等。

3.1.3 领域事件

  • 订单创建事件(OrderCreatedEvent):当新订单创建时触发。
  • 订单状态变更事件(OrderStatusChangedEvent):当订单状态发生变化时触发。
  • 订单发货事件(OrderShippedEvent):当订单发货时触发。
  • 订单完成事件(OrderCompletedEvent):当订单完成时触发。

3.1.4 领域服务

  • 订单处理服务(OrderProcessingService):处理订单的创建、修改、取消等操作。
  • 订单同步服务(OrderSyncService):与电商平台同步订单数据。

订单上下文的示例图如下:
订单上下文的示例图

3.2 物流上下文

下面我们开始分析系统中所涉及到的物流上下文的领域对象。

3.2.1 实体与值对象

实体

  • 物流单(LogisticsOrder):具有唯一物流单号,状态随物流过程变化。
  • 物流渠道(LogisticsChannel):物流服务提供商,如FedEx、UPS等,每个物流渠道都有自己的物流单号生成规则和费用计算方式。

值对象

  • 物流状态(LogisticsStatus):表示物流的当前状态,如已揽收、运输中、已送达等。
  • 物流标签(LogisticsLabel):包含物流信息的标签,用于贴在包裹上,无唯一标识。
  • 物流费用(LogisticsFee):物流服务的费用,无唯一标识。

3.2.2 聚合根与聚合

聚合根

  • 物流单(LogisticsOrder):作为聚合根,负责管理物流状态、物流标签、物流费用等。

聚合

  • 物流单聚合:包含物流单、物流状态、物流标签、物流费用等。

3.2.3 领域事件

  • 物流单创建事件(LogisticsOrderCreatedEvent):当新物流单创建时触发。
  • 物流状态变更事件(LogisticsStatusChangedEvent):当物流状态发生变化时触发。
  • 物流标签生成事件(LogisticsLabelGeneratedEvent):当物流标签生成时触发。
  • 物流完成事件(LogisticsCompletedEvent):当物流完成时触发。

3.2.4 领域服务

  • 物流单处理服务(LogisticsOrderProcessingService):处理物流单的创建、修改等操作。
  • 物流渠道服务(LogisticsChannelService):管理物流渠道信息,计算物流费用。
  • 物流跟踪服务(LogisticsTrackingService):跟踪物流状态,更新物流信息。

物流上下文的示例图如下:
物流上下文的示例图

3.3 仓储上下文

下面我们来分析和提取系统中仓储上下文的相关领域对象。

3.3.1 实体与值对象

实体

  • 仓库(Warehouse):用来存放商品的场所及相关的信息,具有唯一标识。
  • 库位(Location):为了方便仓库的管理而划分出来具体位置,用于存放商品及方便管理库存。
  • 库存记录(InventoryRecord):记录商品在仓库中的实际的库存以及变化的情况。

值对象

  • 库存状态(InventoryStatus):用于表示库存的状态,如正常、不足、过剩等。
  • 库存变动(InventoryMovement):记录库存的变动情况,如入库、出库、调拨等。

3.3.2 聚合根与聚合

聚合根

  • 仓库(Warehouse):作为聚合根,负责管理库位和库存记录。

聚合

  • 仓库聚合:包含仓库、库位、库存记录等。

3.3.3 领域事件

  • 库存变动事件(InventoryMovementEvent):当库存发生变动时触发。
  • 库存不足事件(InventoryShortageEvent):当库存不足时触发。
  • 库存盘点事件(InventoryCountEvent):当库存盘点完成时触发。

3.3.4 领域服务

  • 仓库管理服务(WarehouseManagementService):管理仓库信息,如创建、修改仓库。
  • 库存管理服务(InventoryManagementService):管理库存记录,如入库、出库、调拨等。
  • 库存盘点服务(InventoryCountService):执行库存盘点,调整库存数量。

仓储上下文的示例图如下:
仓储上下文的示例图

3.4 产品上下文

下面,我们来介绍产品上下文的实体、值对象、聚合根和聚合。

3.4.1 实体与值对象

实体

  • 产品(Product):具有唯一标识的商品信息。
  • SKU(StockKeepingUnit):产品的库存单位,是库存管理的最小单位。
  • 产品分类(ProductCategory):对产品进行分类管理。

值对象

  • 产品属性(ProductAttribute):描述产品的特性,如颜色、尺寸等。
  • 产品价格(ProductPrice):产品的价格信息,无唯一标识。

3.4.2 聚合根与聚合

聚合根

  • 产品(Product):作为聚合根,负责管理SKU和产品属性。

聚合

  • 产品聚合:包含产品、SKU、产品属性、产品价格等

3.4.3 领域事件

  • 产品创建事件(ProductCreatedEvent):当新产品创建时触发。
  • 产品更新事件(ProductUpdatedEvent):当产品信息更新时触发。
  • SKU创建事件(SKUCreatedEvent):当新SKU创建时触发。

3.4.4 领域服务

  • 产品管理服务(ProductManagementService):管理产品信息,如创建、修改产品。
  • SKU管理服务(SKUManagementService):管理SKU信息,如创建、修改SKU。
  • 产品分类服务(ProductCategoryService):管理产品分类,如创建、修改分类。

以下是产品上下文的类图:
产品上下文的示例图

四、限界上下文集成

在DDD中,限界上下文之间的集成是一个重要的环节。我们需要设计合理的集成方式,确保各个上下文之间能够顺畅地通信和协作。

4.1 上下文映射

上下文映射描述了限界上下文之间的关系和集成方式。对于我们的电商物流系统,主要的上下文映射关系如下:

源上下文目标上下文关系类型集成方式
订单上下文物流上下文上游/下游事件发布/订阅模式
订单上下文仓储上下文上游/下游事件发布/订阅模式
订单上下文产品上下文上游/下游同步调用模式
仓储上下文采购上下文上游/下游事件发布/订阅模式
物流上下文财务上下文上游/下游事件发布/订阅模式
订单上下文财务上下文上游/下游事件发布/订阅模式
平台集成上下文订单上下文上游/下游同步调用模式
平台集成上下文产品上下文上游/下游同步调用模式

4.2 集成模式

根据上下文映射关系,我们可以采用以下集成模式:

  1. 事件发布/订阅模式:适用于事件驱动的集成,如订单状态变更事件触发物流单的创建。
  2. 同步调用模式:适用于需要立即获取结果的场景,如订单创建时获取产品信息。
  3. 共享数据库模式:适用于关系紧密的上下文,但需要注意数据一致性,如通过本地事务+数据库约束来确保数据的幂等性和完整性。
  4. 防腐层模式:适用于与外部系统集成,如与电商平台的对接。

上下文集成示例图如下:
集成上下文的示例图

五、领域模型到代码的转换

5.1 架构分层

在将领域模型转换为代码时,我们可以采用经典的DDD分层架构:

  1. 接口层(Interface Layer):负责处理用户请求和响应
  2. 应用层(Application Layer):协调领域对象完成业务操作
  3. 领域层(Domain Layer):包含领域模型和业务逻辑
  4. 基础设施层(Infrastructure Layer):提供技术支持,如持久化、消息传递等

如下图所示:
DDD分层架构

5.2 代码结构示例

以下是一个简化的代码结构示例,展示了如何组织我们的领域模型代码:

src/
├── application/           # 应用层
│   ├── command/           # 命令处理
│   ├── query/             # 查询处理
│   └── service/           # 应用服务
├── domain/                # 领域层
│   ├── order/             # 订单子域
│   │   ├── aggregate/     # 聚合
│   │   ├── entity/        # 实体
│   │   ├── event/         # 领域事件
│   │   ├── repository/    # 仓储接口
│   │   ├── service/       # 领域服务
│   │   └── valueobject/   # 值对象
│   ├── logistics/         # 物流子域
│   ├── warehouse/         # 仓储子域
│   └── product/           # 产品子域
├── infrastructure/        # 基础设施层
│   ├── persistence/       # 持久化
│   ├── messaging/         # 消息传递
│   └── external/          # 外部系统集成
└── interface/             # 接口层
    ├── controller/        # 控制器
    ├── dto/               # 数据传输对象
    └── validator/         # 验证器

六、实践建议与注意事项

6.1 实践建议

  1. 采用事件风暴(Event Storming):通过结构化的工作坊形式,与业务专家和开发团队共同参与,使用便签等可视化工具,识别领域事件、命令、聚合根、政策等核心领域元素,梳理业务流程和规则,从而构建出一个共识度高、贴近业务本质的领域模型。
  2. 从小规模开始:先选择一个核心子域进行DDD实践,积累经验后再扩展到其他子域,切莫一开始就尝试对整个系统进行DDD设计。
  3. 业务操作放到聚合根里面:聚合根是业务操作的入口,将业务逻辑放到聚合根中可以确保数据的一致性和完整性,而且修改起来也比较方便。
  4. 持续迭代:领域模型不是一成不变的,需要根据业务变化持续调整和优化,保持与业务需求的同步。
  5. 注重团队协作:DDD需要架构师、开发者和业务专家的紧密协作,确保对业务需求的理解和准确实现。
  6. 使用领域术语:在代码和文档中使用统一的领域术语,避免技术术语与业务术语混用,确保所有团队成员对领域的理解是一致的。

6.2 注意事项

  1. 避免过度设计:根据系统规模和复杂度,合理应用DDD概念,不要生搬硬套,否则只会适得其反。
  2. 关注性能:DDD虽然对架构的扩展和演进有帮助,但是其带来的复杂性也是不少的,所以在设计领域模型时,需要考虑系统性能,避免过度复杂的对象关系,导致性能问题。
  3. 保持限界上下文的独立性:避免上下文之间的耦合,确保每个上下文都能独立演进,互不干扰。
  4. 注意数据一致性:在分布式环境中,需要设计合理的机制确保数据一致性,避免数据不一致问题。
  5. 平衡业务价值与技术实现:在追求领域模型完美的同时,也要考虑技术实现的可行性和成本。

七、总结

本文以电商物流行业为背景,详细介绍了如何运用领域驱动设计(DDD)来设计一款电商物流ERP的系统。从领域识别、子域划分、限界上下文界定,到实体、值对象、聚合根、领域事件等领域对象的分析与提取,我们构建了一个完整的领域模型。

同时,我们通过一系列的UML图表来辅助整个系统的设计后,我们可以清晰地看到系统的整体结构和各个组件之间的关系。这种可视化的方式不仅有助于团队成员理解系统设计,也为后续的开发和维护提供了重要的参考。

DDD是一种强大的设计方法,它能够帮助我们更好地理解业务需求,设计出更加符合业务本质的系统。在实践中,我们需要结合具体的业务场景,灵活运用DDD的核心概念和方法,不断优化和完善领域模型。

本文是作者通过个人的实践经验得出来的,希望能够通过抛砖引玉,为大家在日常工作中应用DDD的时候提供一些参考和启发。如果你有任何问题或建议,欢迎在评论区留言讨论。


互动话题:您有实践过DDD吗?在实践DDD的时候有遇到过哪些挑战呢?当时是如何解决的?欢迎在评论区分享你的经验!

工具附录

关于作者

Kenyon,资深软件架构师,15年的软件开发和技术管理经验,从程序员做到企业技术高管。多年企业数字化转型和软件架构设计经验,善于帮助企业构建高质量、可维护的软件系统,目前专注技术管理、架构设计、AI技术应用和落地;全网统一名称"六边形架构",欢迎关注交流。

原创不易,转载请联系授权,如果觉得有帮助,请点赞、收藏、转发三连支持!

快来关注我吧!

🎗️ 最近在折腾终端设备的 ipv6 ,和 chatgpt 大战三百回合,两三天了始终给不出有效的解决方案。

很久之前已经跑通的路径为:

光猫拨号(光猫带路由功能,此处称为一级路由)

二级路由 wan 口连接光猫 lan 口,一般都是这样连接的吧

二级路由用的是 pandvan 系统,经过简单设置,二级路由下的设备都可以获取 ipv6.

简单来说就是:

光猫(一级路由) + 二级路由 + 子设备 👉子设备可以完美获取公网 ipv6


最近更换了路由器,刷的是 immortalwrt 。并且需要在原先二级路由下新增一个三级路由,这个三级路由是无线连接(不清楚到底是算中继还是桥接)到二级路由的。并且三级路由还得必须增加一层 nat ,是一个新的网段。 为了让这个三级路由器下面的设备获取到 ipv6 ,折腾了好几天,始终没法成功。 每天都在和 chatgpt 对话 → 重置路由器,反复循环,gpt 也始终给不了好的解决方案。

简单来说就是:

光猫(一级路由) + 二级路由 + 三级路由 + 子设备, 👉子设备始终无法获取公网 ipv6.


无奈还是想到用 google 搜索一下试试,果然发现了好东西,最终成功解决 ipv6 的问题。

  1. 第一个有用的资料是来自一个博客,核心思路就是: [光猫 + 二级路由器] 转换成 [ 光猫 + 交换机] 。原先的二级路由器设置成交换机模式,原先的 [三级路由器] 自动提升成为 [二级路由器] ,和原先跑通的方案很相似。

  2. 此时 chatgpt 告诉我, [光猫 + 有线连接路由器] 能成功让子设备获取到 ipv6 ,但是 [光猫 + 无线中继的路由器] 绝无可能,说什么无线中继模式下 RA 通告自动丢弃,sta 接口不会中继 ipv6 前缀到到子设备 balabala 。

  3. 我让它就按照有线连接的模式,给我如何让 ipv6 透传到子设备,它给的方案越来越离谱,要上这个插件,那个插件。

  4. 无奈还是继续 google 搜索,发现了恩山论坛的一个帖子,原样设置之后,顺利让二级路由下的子设备拿到 ipv6.

👇恩山帖子截图如下,非常有帮助👇


openwrt 的 ipv6 中继/透传,使得终端设备获取公网 ipv6

img

不过我还是有个疑问:

❓/64 地址的 ipv6 只能经过路由器透传一次吗?能否继续经过一次路由器透传呢?

在日常生活和工作中,我们经常需要计算日期相关的问题:距离某个重要日子还有多少天?两个日期之间相隔多久?某个日期的前后几天是什么时候?如果手动计算这些问题,不仅费时费力,还容易出错。今天给大家分享一款我使用Vue3开发的在线日期计算器工具,帮助您轻松解决各种日期计算难题。

在线工具网址:https://see-tool.com/date-calculator

工具截图:

什么是日期计算器?

日期计算器是一款专门用于处理日期相关计算的在线工具。这款工具基于现代化的Vue3框架开发,采用响应式设计,界面简洁美观,交互流畅。它可以帮助您快速完成日期加减、日期差值计算、工作日计算等常见操作,无需下载安装任何软件,打开浏览器即可使用。

主要功能介绍

1. 日期加减计算

这是最常用的功能之一。您可以在指定日期的基础上,增加或减少天数、月数、年数,快速得到目标日期。

使用场景:

  • 计算合同到期日期(如:签约日期后90天)
  • 推算预产期或宝宝满月日期
  • 计算还款日、缴费截止日等
  • 规划旅行行程(出发日期后7天是什么时候)

操作方法:

  1. 选择起始日期
  2. 输入要增加或减少的时间(天/月/年)
  3. 点击计算,立即得到结果

2. 日期差值计算

计算两个日期之间相隔的时间,结果可以精确到年、月、日,甚至小时和分钟。

使用场景:

  • 计算恋爱纪念日已经过了多少天
  • 统计项目周期时长
  • 计算年龄(精确到天)
  • 查看距离生日、节假日还有多久
  • 计算员工工龄

操作方法:

  1. 选择开始日期
  2. 选择结束日期
  3. 系统自动计算并显示相隔的天数、周数、月数等

3. 工作日计算

排除周末和法定节假日,计算实际工作日天数,这对于项目管理和工作安排特别有用。

使用场景:

  • 计算项目实际工作日
  • 统计考勤天数
  • 规划工作进度
  • 计算交付周期

4. 星期几查询

快速查询某个日期是星期几,方便安排活动和会议。

使用场景:

  • 查询历史事件发生在星期几
  • 规划周末活动
  • 安排会议时间

工具特点与优势

✅ 完全免费

无需注册登录,无需付费,所有功能完全免费使用。

✅ 操作简单

界面简洁直观,无需学习成本,上手即用。只需简单的点击和输入,就能完成复杂的日期计算。

✅ 计算精准

采用标准的日期算法,确保计算结果准确无误,包括闰年、大小月等特殊情况都能正确处理。

✅ 多种格式支持

支持多种日期格式输入和输出,满足不同使用习惯。

✅ 隐私安全

所有计算都在您的浏览器本地完成,不会上传至服务器,完全保护您的隐私。

✅ 跨平台使用

支持电脑、手机、平板等各种设备,随时随地都能使用。

在线工具网址:https://see-tool.com/date-calculator

工具截图:

一、核心功能设计

日期计算器包含四个独立模块:

  1. 日期间隔计算: 计算两个日期之间的天数、周数、月数、年数
  2. 日期加减计算: 在基准日期上加减指定时间单位
  3. 年龄计算: 精确计算年龄(年/月/日)
  4. 工作日计算: 统计工作日、周末天数

二、日期间隔计算实现

2.1 核心计算逻辑

const dateDiff = computed(() => {
  if (!startDate.value || !endDate.value) {
    return { days: 0, weeks: 0, months: 0, years: 0 }
  }

  const start = new Date(startDate.value)
  const end = new Date(endDate.value)

  // 确保开始日期小于结束日期(自动排序)
  const [earlierDate, laterDate] = start <= end ? [start, end] : [end, start]

  let diffTime = laterDate.getTime() - earlierDate.getTime()

  // 如果包含结束日期,增加一天
  if (includeEndDate.value) {
    diffTime += 24 * 60 * 60 * 1000
  }

  const diffDays = Math.floor(diffTime / (1000 * 60 * 60 * 24))

  // 计算精确的月数差异
  let months = (laterDate.getFullYear() - earlierDate.getFullYear()) * 12
  months += laterDate.getMonth() - earlierDate.getMonth()

  // 如果日期不足一个月,减去一个月
  if (laterDate.getDate() < earlierDate.getDate()) {
    months--
  }

  // 计算年数
  const years = Math.floor(months / 12)

  return {
    days: diffDays,
    weeks: Math.floor(diffDays / 7),
    months: Math.max(0, months),
    years: Math.max(0, years)
  }
})

关键点:

  1. 自动排序: 无论用户输入顺序,自动识别较早和较晚的日期
  2. 包含结束日期: 可选项,影响天数计算(+1天)
  3. 精确月数: 考虑日期不足一个月的情况
  4. 负数保护: 使用 Math.max(0, value) 防止负数

2.2 辅助工具函数

// 交换开始和结束日期
const swapDates = () => {
  const temp = startDate.value
  startDate.value = endDate.value
  endDate.value = temp
}

// 设置结束日期为今天
const setToday = (type) => {
  if (!process.client) return
  const today = new Date().toISOString().split('T')[0]
  if (type === 'diff') {
    endDate.value = today
  }
}

三、日期加减计算实现

3.1 核心计算逻辑

const calculatedDate = computed(() => {
  if (!baseDate.value) {
    return ''
  }

  if (!amount.value || amount.value === 0) {
    return baseDate.value
  }

  const base = new Date(baseDate.value)
  // 根据操作类型确定正负
  const value = operation.value === 'add' ? parseInt(amount.value) : -parseInt(amount.value)

  switch (unit.value) {
    case 'days':
      base.setDate(base.getDate() + value)
      break
    case 'weeks':
      base.setDate(base.getDate() + (value * 7))
      break
    case 'months':
      base.setMonth(base.getMonth() + value)
      break
    case 'years':
      base.setFullYear(base.getFullYear() + value)
      break
  }

  return base.toISOString().split('T')[0]
})

关键点:

  1. 操作符处理: 减法通过负数实现,统一使用加法逻辑
  2. 原生 Date API: 利用 setDate/setMonth/setFullYear 自动处理溢出
  3. 格式化输出: toISOString().split('T')[0] 获取 YYYY-MM-DD 格式

3.2 获取星期几

const getWeekday = (dateStr) => {
  if (!dateStr) return ''
  const weekdays = tm('dateCalculator.weekdays')
  if (!weekdays || !Array.isArray(weekdays)) return ''
  const date = new Date(dateStr)
  return weekdays[date.getDay()] || ''
}

说明:

  • getDay() 返回 0-6,其中 0 代表周日
  • 从国际化配置中读取星期名称数组

四、年龄计算实现

4.1 精确年龄计算

const age = computed(() => {
  if (!birthDate.value || !ageCalculateDate.value) {
    return { years: 0, months: 0, days: 0, totalDays: 0 }
  }

  const birth = new Date(birthDate.value)
  const calculate = new Date(ageCalculateDate.value)

  // 如果出生日期晚于计算日期,返回0
  if (birth > calculate) {
    return { years: 0, months: 0, days: 0, totalDays: 0 }
  }

  // 计算精确年龄
  let years = calculate.getFullYear() - birth.getFullYear()
  let months = calculate.getMonth() - birth.getMonth()
  let days = calculate.getDate() - birth.getDate()

  // 调整天数
  if (days < 0) {
    months--
    // 获取上个月的天数
    const lastMonth = new Date(calculate.getFullYear(), calculate.getMonth(), 0)
    days += lastMonth.getDate()
  }

  // 调整月数
  if (months < 0) {
    years--
    months += 12
  }

  // 计算总天数
  const totalDays = Math.floor((calculate.getTime() - birth.getTime()) / (1000 * 60 * 60 * 24))

  return {
    years: Math.max(0, years),
    months: Math.max(0, months),
    days: Math.max(0, days),
    totalDays: Math.max(0, totalDays)
  }
})

关键点:

  1. 逐级调整: 先调整天数,再调整月数,最后得到年数
  2. 借位逻辑: 天数不足时从月份借位,月份不足时从年份借位
  3. 上月天数: 使用 new Date(year, month, 0) 获取上月最后一天
  4. 总天数: 单独计算,用于显示"已活xx天"

4.2 派生数据计算

// 模板中使用
Math.floor(age.totalDays / 30.44)  // 总月数(平均每月30.44天)
Math.floor(age.totalDays / 7)      // 总周数
age.totalDays                      // 总天数

五、工作日计算实现

5.1 核心计算逻辑

const workDays = computed(() => {
  if (!workStartDate.value || !workEndDate.value) {
    return { total: 0, weekdays: 0, weekends: 0 }
  }

  const start = new Date(workStartDate.value)
  const end = new Date(workEndDate.value)

  // 确保开始日期不大于结束日期
  if (start > end) {
    return { total: 0, weekdays: 0, weekends: 0 }
  }

  let weekdays = 0
  let weekends = 0
  const current = new Date(start)

  // 包含开始和结束日期
  while (current <= end) {
    const dayOfWeek = current.getDay()
    if (dayOfWeek === 0 || dayOfWeek === 6) { // 周日=0, 周六=6
      weekends++
    } else {
      weekdays++
    }
    current.setDate(current.getDate() + 1)
  }

  return {
    total: weekdays + weekends,
    weekdays: excludeWeekends.value ? weekdays : weekdays + weekends,
    weekends
  }
})

关键点:

  1. 逐日遍历: 从开始日期循环到结束日期,逐日判断
  2. 星期判断: getDay() 返回 0(周日) 或 6(周六) 为周末
  3. 可选排除: 根据 excludeWeekends 决定是否排除周末
  4. 包含边界: 包含开始和结束日期

六、状态管理

6.1 响应式状态定义

// Tab 切换
const activeTab = ref('difference')

// 日期间隔计算
const startDate = ref('')
const endDate = ref('')
const includeEndDate = ref(false)

// 日期加减计算
const baseDate = ref('')
const operation = ref('add')      // 'add' | 'subtract'
const amount = ref(0)
const unit = ref('days')          // 'days' | 'weeks' | 'months' | 'years'

// 工作日计算
const workStartDate = ref('')
const workEndDate = ref('')
const excludeWeekends = ref(true)

// 年龄计算
const birthDate = ref('')
const ageCalculateDate = ref('')

6.2 初始化默认值

onMounted(() => {
  if (!process.client) return
  const today = new Date().toISOString().split('T')[0]
  startDate.value = today
  endDate.value = today
  baseDate.value = today
  workStartDate.value = today
  workEndDate.value = today
  birthDate.value = ''  // 不设置默认出生日期
  ageCalculateDate.value = today
})

说明:

  • 使用 process.client 判断避免 SSR 问题
  • 出生日期不设默认值,避免误导用户

七、日期处理技巧

7.1 Date 对象的自动溢出处理

// JavaScript 的 Date 会自动处理溢出
const date = new Date('2024-01-31')
date.setMonth(date.getMonth() + 1)  // 自动变为 2024-03-02(2月没有31日)

7.2 获取上月最后一天

// 将日期设为0,会自动回退到上月最后一天
const lastDayOfLastMonth = new Date(year, month, 0)

7.3 日期格式化

// ISO 格式转 YYYY-MM-DD
const dateStr = new Date().toISOString().split('T')[0]

八、核心算法总结

日期间隔计算:
  时间戳相减 → 转换为天数
  年月日逐级计算 → 处理借位

日期加减计算:
  原生 Date API → 自动处理溢出

年龄计算:
  年月日分别相减 → 逐级调整借位

工作日计算:
  逐日遍历 → 判断星期几 → 统计分类

核心原则:

  1. 利用原生 API: Date 对象的自动溢出处理
  2. 边界处理: 防止负数、空值、非法日期
  3. 精确计算: 考虑月份天数差异、闰年等特殊情况
  4. 用户友好: 自动排序、可选配置、实时计算

在 AI 技术日新月异的今天,AI Agent(智能体)正逐渐从概念走向落地。它不仅能进行对话,更具备了思考、规划和执行任务的能力。然而,构建一个成熟的 Agent 系统,并非简单的 API 调用,而是多种核心技术协同工作的结果。

在深入开发之前,理清这些基础概念,有助于我们更好地理解 AI 系统的底层运行逻辑。


一、 智能的内核:大语言模型与交互边界

1. LLM(大语言模型):通识大脑

LLM 是 Agent 的核心引擎。它拥有强大的语言理解能力,但它是一个“静态大脑”,其知识停留在训练截止的那一刻,无法感知企业内部的私有数据。

2. Context Window(上下文窗口):短期记忆

这是模型单次交互能处理的信息上限。

  • 局限: 即使窗口再大,也不能盲目塞入所有数据。正如在数学题中加入无关的干扰信息会降低准确率一样,过长的背景会导致模型“注意力不集中”,甚至产生幻觉。

3. Prompt Engineering(提示工程):沟通的艺术

  • Zero-shot(零样本): 不给示例,直接下指令。这要求指令必须高度具体(如:从“写个政策”优化为“写个 200 字符合 GDPR 标准的隐私政策”)。
  • Few-shot(少样本): 提供几个理想的问答示例,这能有效地规范 AI 输出的语气(Tone)和特定格式。
  • Chain of Thought(思维链): 引导 AI 展示推理步骤,强制模型分配更多计算资源在逻辑推导上,从而处理复杂问题。


二、 知识的扩展:从“翻书”到“记忆”

为了让 AI 访问私有数据,我们需要构建一套“外挂硬盘”。

4. 向量数据库 vs 传统数据库

传统的 SQL 数据库是基于值或关键词的匹配(如 LIKE %vacation%)。而向量数据库(如 ChromaDB, Pinecone)则是基于含义(Meaning)的匹配。即使搜索词不一致,只要语义接近,系统就能精准定位。

5. Embeddings 与数据预处理

  • 数据切分(Chunking): 我们不能将 500GB 的文档直接塞给 AI。必须将其切成小块。
  • 重叠(Overlap): 在切分时,通常会保留一定的文字重叠。这能防止上下文在切分处丢失,从而大幅提升检索的准确性。
  • Embeddings: 将切分好的文本块转化为高维数字向量,让计算机能够以数学方式计算语义的相关性。

6. RAG(检索增强生成):知识的补丁

RAG 是目前解决 AI 幻觉的最优方案。它通过“检索 -> 增强 -> 生成”的流程,让 AI 像是在参加开卷考试:先去数据库里“翻书”找到事实,再根据事实组织答案。


三、 行动的逻辑:框架、编排与协议

7. LangChain:开发的“胶水”层

LangChain 是一个强大的抽象层,旨在简化开发流程。

  • 核心价值: 它像管道一样将模型、提示词模板和向量库连接起来。有了它,你从 OpenAI 切换到 Google Gemini 可能只需要更改一行代码,极大地提高了系统的灵活性。

8. LangGraph:有状态的“总导演”

当任务需要循环和决策时,简单的线性管道就不够用了。

  • 节点与边: LangGraph 通过节点(步骤)和边(路径)构建工作流。
  • 共享状态(State): 这是它的核心。它维护着一个在各节点间传递的“字典”,记录着当前的文档、评分等信息。基于这个状态,系统可以执行复杂逻辑:例如“如果合规分数低于 75 分,则循环回退到搜索节点重新查阅”。

9. MCP(模型上下文协议):标准化的“USB 接口”

这是连接外部工具(如 GitHub、数据库)的通用标准。它让 AI 具备了“即插即用”的能力,开发者无需为每个工具编写特定的硬编码集成,只需符合 MCP 协议,Agent 就能自主调用。


四、 总结:各组件是如何协同工作的?

构建一个完整的 AI 系统,本质上是让这些组件各司其职、形成闭环:

  1. 准备: 文档经过切分与重叠处理,通过 Embeddings 存入向量数据库
  2. 触发: 用户提问,LangChain 调度 RAG 流程,根据语义意图找回知识。
  3. 决策: LangGraph 根据当前状态判断:是直接回答,还是需要循环修正?
  4. 执行: 如果需要实时数据,通过 MCP 协议调用外部工具。
  5. 产出: LLM 结合所有事实与逻辑推理,输出最终方案。

理清了这些基石,你就已经掌握了从“对话机器人”跨越到“全能 Agent”的底层蓝图。

本文由mdnice多平台发布

这是 最全面的 Claude Code Python 技能目录Agent – Claude Code skills 精选导航站精选 2,847个 经过 GitHub 社区验证(累计 3,500,000+ Stars)的 Python 开发工具,涵盖 Web 开发、数据科学、机器学习、自动化脚本等所有 Python 编程场景。无论你使用 Django、Flask 还是 FastAPI,这些 Claude Code Python 技能 都能显著提升你的开发效率和代码质量,让你的 Python 开发工作 更加高效智能。

📊 Claude Code Python 技能目录统计

Claude Python 开发工具整体数据

  • Claude Code Python 技能总数: 2,847个顶级开发工具
  • 平均 GitHub Stars: 1,234 (社区高度认可)
  • 总 Stars 数: 3,512,458 (累计社区验证)
  • 活跃维护的 Python Skills: 2,103个 (74%)
  • 具有 AI 深度分析: 1,856个 (65%)

分类分布

Web框架          ████████████████ 38% (1,082个)
数据科学         ████████████ 24% (683个)
自动化工具       ████████ 16% (456个)
API开发          ██████ 12% (342个)
测试工具         ████ 8% (228个)
其他             ██ 2% (56个)

热度等级

等级Stars范围技能数量占比
🔥🔥🔥🔥🔥 超热门5000+89个3%
🔥🔥🔥🔥 很热门1000-5000342个12%
🔥🔥🔥 热门500-1000567个20%
🔥🔥 流行100-5001,124个39%
🔥 新兴0-100725个26%

🏆 Top 20 Claude Code Python 技能排行榜

1. Django Full Stack Wizard - 顶级 Claude Code Python 开发技能 ⭐ 12,456 🔥🔥🔥🔥🔥

强烈推荐 | Python Web框架 | 全栈开发

这款 Claude Code Python 技能 是全面的 Django 开发助手,使用 Claude AI 引擎从项目初始化到生产部署提供完整支持,让 Python Web 开发 效率提升 5 倍。

核心功能:

  • ✅ Django项目脚手架生成 (含最佳实践配置)
  • ✅ Model设计助手 (自动生成migration)
  • ✅ Class-based Views快速生成
  • ✅ REST API自动化 (Django REST Framework)
  • ✅ 测试用例自动生成
  • ✅ 性能优化建议 (N+1查询检测)

适用场景:

  • 电商平台开发
  • 内容管理系统 (CMS)
  • 企业级Web应用
  • SaaS产品后端

技术亮点:

# 自动生成完整的CRUD API
django-wizard generate api Product --fields "name:str,price:decimal,stock:int"

# 生成内容:
✓ models.py (含验证器)
✓ serializers.py (DRF)
✓ views.py (ViewSet)
✓ urls.py (路由配置)
✓ tests.py (完整测试)
✓ admin.py (后台管理)

用户评价:

"将Django开发速度提升了5倍,生成的代码质量堪比资深开发者。" - Sarah Chen, Tech Lead

集成框架:

  • Django 4.2+
  • Django REST Framework
  • Celery (异步任务)
  • Django Channels (WebSocket)

定价: 免费开源

查看详情 | GitHub | 文档


2. FastAPI Code Generator - 高性能 Claude Code Python API 技能 ⭐ 9,834 🔥🔥🔥🔥🔥

强烈推荐 | Python API开发 | 高性能

这款 Claude Code FastAPI 技能 基于 OpenAPI 规范快速生成 FastAPI 项目,使用 Python 编程助手 自动生成文档和测试,是 Python 开发工具 中 API 开发的首选。

核心功能:

  • ⚡ 从OpenAPI spec生成完整项目
  • 📝 自动生成Pydantic模型
  • 🔐 JWT认证开箱即用
  • 📊 自动化API文档 (Swagger + ReDoc)
  • ✅ 异步处理支持
  • 🐳 Docker配置生成

性能优势:

传统Flask API:   1,200 req/s
FastAPI (生成):  8,500 req/s

性能提升: 708% ⬆️

使用示例:

# 从OpenAPI规范生成项目
fastapi-gen create --spec api-spec.yaml --db postgres

# 生成完整项目结构:
✓ app/models/     # SQLAlchemy模型
✓ app/schemas/    # Pydantic schemas
✓ app/api/        # API路由
✓ app/core/       # 配置和安全
✓ tests/          # Pytest测试
✓ docker-compose.yml

真实案例:
某金融科技公司使用此技能,API开发时间从 3周缩短到2天

兼容性:

  • Python 3.9+
  • PostgreSQL / MySQL / MongoDB
  • Redis (缓存)
  • Celery / RQ (任务队列)

社区:

  • GitHub Stars: 9,834
  • 贡献者: 156
  • 使用公司: 450+

查看详情 | 立即试用


3. Pandas Data Wizard - 数据分析 Claude Code Python 技能 ⭐ 8,234 🔥🔥🔥🔥

推荐 | Python 数据分析 | ETL

这款 Claude Code Python 数据科学技能 是智能数据处理助手,使用 Claude AI 自动化 90% 的数据清洗和分析工作,是 Python 开发工具 中数据处理的首选。

核心能力:

  • 🧹 智能数据清洗 (缺失值、异常值、重复值)
  • 📊 自动化探索性分析 (EDA)
  • 🔄 数据转换管道生成
  • 📈 可视化代码自动生成
  • 💾 多格式导入导出 (CSV, Excel, JSON, SQL)

AI增强:

  • 自动检测数据类型并建议转换
  • 识别数据质量问题
  • 推荐最佳可视化方式
  • 生成数据质量报告

示例场景:

场景1: 快速数据清洗

# 自然语言指令
"清洗sales_data.csv: 删除重复行,填充缺失值,转换日期格式"

# 自动生成代码:
import pandas as pd

df = pd.read_csv('sales_data.csv')

# 删除重复行
df = df.drop_duplicates()

# 智能填充缺失值
df['price'] = df['price'].fillna(df['price'].median())
df['category'] = df['category'].fillna(df['category'].mode()[0])

# 日期转换
df['date'] = pd.to_datetime(df['date'], format='%Y-%m-%d')

# 数据质量报告
print(f"处理前: {len(df_raw)} 行")
print(f"处理后: {len(df)} 行")
print(f"删除重复: {len(df_raw) - len(df)} 行")

场景2: 自动化EDA

# 生成完整的探索性分析报告
pandas-wizard analyze sales_data.csv --output report.html

# 生成内容:
✓ 数据概览 (行列数、内存使用)
✓ 数值列统计 (均值、中位数、分布)
✓ 分类列分析 (唯一值、频率)
✓ 相关性矩阵
✓ 缺失值分析
✓ 异常值检测
✓ 20+可视化图表

支持的操作:

  • 数据清洗: 12种智能策略
  • 数据转换: 15种常见转换
  • 聚合分析: groupby、pivot、merge自动化
  • 时间序列: 自动重采样和滚动计算

性能:

  • 处理速度: 比手动快 10倍
  • 内存优化: 自动选择最优数据类型
  • 大数据支持: Dask集成,支持TB级数据

学习资源:

查看详情


4. PyTest Master Tester - 测试自动化 Claude Code Python 技能 ⭐ 7,456 🔥🔥🔥🔥

推荐 | Python 测试 | 质量保证

这款 Claude Code Python 测试技能 是智能测试用例生成器,使用 Claude AI 自动创建全面的单元测试和集成测试,将 Python 开发 中的测试效率提升 4,800%。

核心功能:

  • 🧪 从函数签名自动生成测试
  • 🎯 智能边界测试用例
  • 🔄 Mock对象自动化
  • 📊 覆盖率分析和改进建议
  • ⚡ 并行测试执行

测试质量:

传统手写测试:
- 覆盖率: 65%
- 编写时间: 4小时/模块

AI生成测试:
- 覆盖率: 92%
- 生成时间: 5分钟/模块

效率提升: 4,800% ⬆️

智能特性:

# 分析这个函数
def calculate_discount(price: float, user_type: str, coupon: Optional[str]) -> float:
    """计算折扣后价格"""
    # 复杂的业务逻辑...
    pass

# AI自动生成全面测试:
def test_calculate_discount_regular_user():
    assert calculate_discount(100.0, "regular", None) == 100.0

def test_calculate_discount_vip_user():
    assert calculate_discount(100.0, "vip", None) == 90.0

def test_calculate_discount_with_coupon():
    assert calculate_discount(100.0, "regular", "SAVE10") == 90.0

def test_calculate_discount_invalid_price():
    with pytest.raises(ValueError):
        calculate_discount(-10.0, "regular", None)

def test_calculate_discount_boundary_cases():
    assert calculate_discount(0.0, "vip", None) == 0.0
    assert calculate_discount(9999.99, "vip", "SAVE50") == 4499.995

# 共生成 15个测试用例,覆盖所有边界情况

集成框架:

  • pytest
  • unittest
  • coverage.py
  • hypothesis (property-based testing)

查看详情


5. Selenium Automation Pro - Web 自动化 Claude Code Python 技能 ⭐ 6,789 🔥🔥🔥🔥

推荐 | Python 自动化 | Web爬虫

这款 Claude Code Python 自动化技能 是智能 Web 自动化工具,提供从 UI 操作到数据提取的完整 Python 开发 方案,支持分布式爬取和反爬虫策略。

核心能力:

  • 🤖 录制-回放功能 (记录浏览器操作)
  • 🔍 智能元素定位 (自动选择最佳selector)
  • 📦 数据提取模板生成
  • 🛡️ 反爬虫策略内置
  • ⚙️ 分布式爬取支持

使用场景:

场景1: 自动化测试

# 自然语言生成测试
"登录网站, 搜索Python书籍, 添加第一本到购物车, 验证购物车数量"

# 生成Selenium代码:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait

driver = webdriver.Chrome()

# 登录
driver.get("https://example.com/login")
driver.find_element(By.ID, "username").send_keys("testuser")
driver.find_element(By.ID, "password").send_keys("password")
driver.find_element(By.ID, "login-button").click()

# 等待登录完成
WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.ID, "search-box"))
)

# 搜索
search_box = driver.find_element(By.ID, "search-box")
search_box.send_keys("Python")
search_box.submit()

# 添加到购物车
first_book = driver.find_element(By.CSS_SELECTOR, ".book-item:first-child .add-to-cart")
first_book.click()

# 验证
cart_count = driver.find_element(By.ID, "cart-count").text
assert cart_count == "1", f"Expected 1 item, got {cart_count}"

场景2: 数据爬取

# 配置爬虫
selenium-pro crawl \
  --url "https://example.com/products" \
  --paginate ".next-page" \
  --extract "title:.product-title, price:.price, rating:.rating" \
  --output products.json

# 自动处理:
✓ 页面滚动加载
✓ 动态内容等待
✓ 分页自动翻页
✓ 反爬虫策略 (随机延迟、User-Agent轮换)
✓ 失败重试
✓ 数据去重

反爬虫对策:

  • User-Agent池 (100+ 真实UA)
  • 代理IP集成
  • JavaScript渲染
  • 验证码识别 (OCR集成)
  • 行为模拟 (鼠标轨迹、滚动)

性能:

  • 并发爬取: 支持10-100个browser实例
  • 分布式: Scrapy-Selenium集成
  • 速度: 1000页/小时

查看详情


📚 按分类浏览 Claude Code Python 技能

Python Web 开发技能 (1,082个 Claude Code 工具)

Django 生态 Claude Code Python 技能 (456个)

  • Claude Code Django 项目生成工具
  • Django REST API 开发技能
  • Django Admin 定制 Python 技能
  • Django ORM 优化 Claude Code 工具
  • Django 部署自动化技能
  • 查看全部 Claude Code Django 技能

Flask 生态 Claude Code Python 技能 (342个)

FastAPI 生态 Claude Code Python 技能 (284个)


Claude Code Python 数据科学技能 (683个工具)

Python 数据处理技能 (298个 Claude Code 工具)

数据可视化 (187个)

机器学习 (198个)


自动化工具 (456个技能)

Web自动化 (187个)

任务自动化 (156个)

系统管理 (113个)


📦 推荐 Claude Code Python 技能包

包1: Python Web 全栈开发 Claude Skills 组合

包含 Claude Code Python 技能: 8个顶级开发工具
总 GitHub Stars: 56,789

  1. Django Full Stack Wizard - Claude Code Python 全栈技能
  2. FastAPI Code Generator - Python API 开发工具
  3. SQLAlchemy Helper - 数据库 ORM 技能
  4. Celery Task Manager - 异步任务 Python 工具
  5. Redis Cache Assistant - 缓存优化技能
  6. Nginx Config Generator - 部署配置工具
  7. Docker Compose Builder - 容器化 Python 技能
  8. Pytest Master Tester - 测试自动化工具

适合: Python 全栈开发者、创业公司使用 Claude Code

一键安装 Claude Code Python 技能包


包2: 数据科学分析包

包含技能: 6个
总Stars: 42,345

  1. Pandas Data Wizard
  2. NumPy Calculator Pro
  3. Matplotlib Chart Builder
  4. Seaborn Visual Master
  5. Scikit-learn Trainer
  6. Jupyter Notebook Helper

适合: 数据分析师、数据科学家

一键安装


包3: 自动化测试包

包含技能: 5个
总Stars: 31,234

  1. Pytest Master Tester
  2. Selenium Automation Pro
  3. Locust Load Tester
  4. Coverage Reporter
  5. Mock Data Generator

适合: QA工程师、测试团队

一键安装


💡 使用建议

新手入门路径

第1周: Web开发基础

  • Django Full Stack Wizard
  • 完成官方教程
  • 构建第一个项目

第2周: 数据处理

  • Pandas Data Wizard
  • 学习数据清洗
  • 分析真实数据集

第3周: 自动化

  • Selenium Automation Pro
  • 编写爬虫脚本
  • 自动化日常任务

第4周: 测试

  • Pytest Master Tester
  • 为项目添加测试
  • 实现CI/CD

进阶开发者路径

聚焦领域:

  1. 选择主攻方向 (Web/数据/AI)
  2. 精通该领域Top 5技能
  3. 贡献开源项目
  4. 开发自己的技能

技能组合示例:

  • 后端专家: FastAPI + SQLAlchemy + Celery + Redis
  • 数据专家: Pandas + NumPy + Matplotlib + Scikit-learn
  • 全栈专家: Django + React + PostgreSQL + Docker

📊 技能对比工具

启动对比工具 - 并排比较最多5个技能

对比维度:

  • ✓ 功能对比
  • ✓ 性能测试
  • ✓ 易用性评分
  • ✓ 社区活跃度
  • ✓ 学习曲线
  • ✓ 成本分析

🎓 学习资源

官方文档

视频教程

社区


❓ Claude Code Python 技能常见问题

如何选择适合的 Claude Code Python 技能?

  1. 明确 Python 开发需求: 确定你要解决的问题(Web 开发、数据科学、自动化等)
  2. 查看 Claude Code 推荐: 筛选"强烈推荐"的 Python Skills
  3. 阅读 Claude Skills 详情: 查看功能、案例和 GitHub Stars
  4. 试用 Claude Code 工具: 大部分 Python 开发技能 提供免费试用
  5. 评估 Python 编程效果: 根据实际效果决定是否采用

Claude Code Python 技能之间兼容吗?

大部分 Claude Code Python 技能 可以同时使用。每个 Python Skills 详情页会标注:

  • ✅ 完全兼容 - 可安全组合使用的 Claude Code 工具
  • ⚠️ 可能冲突 - 需要配置的 Python 技能
  • ❌ 不兼容 - 不建议同时使用

如何更新 Claude Code Python 技能?

# 更新单个 Claude Code Python 技能
claude-code skill update django-wizard

# 更新所有 Python 开发技能
claude-code skill update --all

# 查看 Claude Code 技能更新日志
claude-code skill changelog django-wizard

Claude Code Python 技能可以离线使用吗?

  • 基础 Python 功能: 完全离线 - 本地 Claude Code 执行
  • AI 增强功能: 需要联网(可选) - Claude AI 智能分析
  • 企业私有部署: Claude Code 企业版支持完全离线

🔗 更多 Claude Code 技能目录

按编程技术栈浏览 Claude Skills

按开发场景浏览 Claude Code 工具

Claude Code 特色技能集合

Agent – Claude Code skills 精选导航站


一、发布前必知:价值与前提

为什么要发布到 Maven 中央仓库?

  • 全局可访问:任何使用 Maven、Gradle 的开发者都能轻松引入,无需额外配置私有仓库
  • 标准化保障:遵循严格的发布规范,提升组件的可信度与安全性
  • 版本自动管理:中央仓库会妥善保存各版本,避免依赖冲突与版本混乱
  • 社区认可:开源共享是技术成长的重要途径,优质组件能获得更多反馈与迭代

发布前提

  • 组件非敏感信息:中央仓库所有内容公开,严禁发布企业私有代码或涉密逻辑
  • 遵守开源协议:推荐使用 Apache License 2.0 等主流开源协议,避免版权纠纷
  • 准备必要工具:已安装 Maven(配置好环境变量)、可访问 GitHub/Gitee 等代码仓库

二、核心步骤:从配置到发布全流程

第一步:Sonatype 平台配置(获取发布权限)

Maven 中央仓库由 Sonatype 维护,所有发布操作需通过其平台授权:

  1. 访问 Sonatype 官网注册或登录账号,建议绑定常用邮箱
    image.png
  2. 申请 Namespace:登录后进入 Publish 页面,点击 "Add Namespace",格式需遵循反向 DNS 规则
  • 有自有域名:如 www.example.com 对应 com.example
  • 无域名:使用代码仓库地址,GitHub 用户填 io.github. 用户名,Gitee 用户填 io.gitee. 用户名
    image.png
  1. 验证 Namespace:点击 "Verify Namespace",系统会生成验证密钥,需在对应代码仓库创建同名公开仓库,完成后点击 "Verify Namespace",显示 "Verified" 即通过
    image.png
    image.png
  2. 生成访问 Token:点击右上角用户名 →View Account→Generate User Token,复制生成的用户名和密码,后续用于 Maven 认证(仅显示一次,务必保存)
    image.png
    image.png
    image.png

第二步:GPG 密钥配置(保障代码安全)

为防止组件被篡改,中央仓库要求所有发布的文件必须经过 GPG 签名:

  1. 下载安装 GPG:前往 GnuPG 官网,根据系统选择对应版本(Windows 选 Gpg4win,Mac 选 Mac GPG)
    image.png
  2. 生成密钥对:打开终端 / 命令提示符,输入 gpg --gen-key,按提示填写真实姓名、邮箱(与 Sonatype 账号一致),设置密钥密码并牢记
    image.png
    image.png
  3. 记录密钥 ID:生成成功后,找到输出中 "pub" 行后的一串字符(如 519314C3477B2B3122A13EC8123FB84FB9BC06DE),这是你的公钥 ID
    image.png
  4. 上传公钥至公共服务器:执行 gpg --keyserver hkp://keyserver.ubuntu.com:11371 --send-keys 你的密钥ID,让中央仓库能验证签名合法性
  5. 验证 gpg 秘钥: 有两种方式可以验证秘钥,一种是通过 gpg 命令: gpg --keyserver keyserver.ubuntu.com --recv-keys xxxxxx;另外一种方式直接到 https://keyserver.ubuntu.com/秘钥平台查询:
    image.png
    image.png
    出现以上内容表明秘钥发布成功。

第三步:Maven 环境配置(关联认证信息)

打开 Maven 的 settings.xml 文件(通常在 conf 目录下),添加以下配置:

<!-- Sonatype访问权限配置 -->
<servers>
    <server>
        <id>central</id>
        <username>Sonatype生成的Token用户名</username>
        <password>Sonatype生成的Token密码</password>
    </server>
</servers>
<!-- GPG签名配置 -->
<profiles>
    <profile>
        <id>gpg</id>
        <properties>
            <gpg.executable>gpg</gpg.executable>
            <gpg.keyname>你的GPG绑定邮箱</gpg.keyname>
            <gpg.passphrase>你的GPG密钥密码</gpg.passphrase>
            <gpg.useagent>true</gpg.useagent>
        </properties>
    </profile>
</profiles>

第四步:项目 POM 文件配置(标准化组件信息)

修改待发布项目的 pom.xml,补充必要信息(直接复制替换占位符即可):

<project>
    <!-- 核心信息:GroupID需与验证通过的Namespace一致 -->
    <groupId>io.github.你的用户名</groupId>
    <artifactId>组件名称</artifactId>
    <version>1.0.0.RELEASE</version>
    <!-- 必须是正式版本,禁止SNAPSHOT -->
    <url>你的代码仓库地址(如https://github.com/用户名/仓库名)</url>
    <!-- 许可证信息(推荐Apache 2.0) -->
    <licenses>
        <license>
            <name>The Apache License, Version 2.0</name>
            <url>https://www.apache.org/licenses/LICENSE-2.0</url>
        </license>
    </licenses>
    <!-- 开发者信息 -->
    <developers>
        <developer>
            <name>你的姓名</name>
            <email>你的邮箱</email>
        </developer>
    </developers>
    <!-- 代码仓库信息 -->
    <scm>
        <connection>scm:git:你的仓库克隆地址(如https://github.com/用户名/仓库名.git)</connection>
        <developerConnection>scm:git:你的仓库SSH地址(如git@github.com:用户名/仓库名.git)</developerConnection>
        <url>你的仓库网页地址</url>
    </scm>
    <!-- 必要插件配置 -->
    <build>
        <plugins>
            <!-- 源码打包插件 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-source-plugin</artifactId>
                <version>3.3.0</version>
                <executions>
                    <execution>
                        <id>attach-sources</id>
                        <goals>
                            <goal>jar-no-fork</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <!-- Javadoc打包插件 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-javadoc-plugin</artifactId>
                <version>2.9.1</version>
                <configuration>
                    <charset>UTF-8</charset>
                    <encoding>UTF-8</encoding>
                    <docencoding>UTF-8</docencoding>
                    <additionalparam>-Xdoclint:none</additionalparam>
                </configuration>
                <executions>
                    <execution>
                        <id>attach-javadocs</id>
                        <goals>
                            <goal>jar</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <!-- GPG签名插件 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-gpg-plugin</artifactId>
                <version>3.1.0</version>
                <executions>
                    <execution>
                        <id>sign-artifacts</id>
                        <phase>verify</phase>
                        <goals>
                            <goal>sign</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <!-- 中央仓库发布插件 -->
            <plugin>
                <groupId>org.sonatype.central</groupId>
                <artifactId>central-publishing-maven-plugin</artifactId>
                <version>0.4.0</version>
                <extensions>true</extensions>
                <configuration>
                    <publishingServerId>central</publishingServerId>
                    <tokenAuth>true</tokenAuth>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

第五步:打包上传与发布

  1. 推送项目代码:将配置好的项目推送到对应的 GitHub/Gitee 仓库(确保仓库公开)
  2. 执行部署命令:打开终端,进入项目根目录,执行 mvn clean deploy -Dmaven.test.skip=true,过程中会提示输入 GPG 密钥密码,输入后等待执行完成
  3. 等待 Sonatype 审核:登录 Sonatype 平台,在 Deployments 中可看到状态(PUBLISHING 为审核中),审核时间通常为几小时到 1 天,状态变为 PUBLISHED 即发布成功
    image.png

三、验证与使用:让别人轻松引入你的组件

发布成功后,可通过 Maven 中央仓库搜索页,输入 GroupID 或组件名称查询你的组件。其他开发者只需在 pom.xml 中添加以下依赖,即可直接使用:

<dependency>
    <groupId>io.github.你的用户名</groupId>
    <artifactId>组件名称</artifactId>
    <version>1.0.0.RELEASE</version>
</dependency>

四、注意事项与避坑指南

  1. 版本不可逆:发布后的版本无法删除或修改,务必做好测试再发布,建议遵循语义化版本规范
  2. 隐私保护:严禁发布包含密钥、敏感业务逻辑的组件,一旦发布无法撤回
  3. 常见错误处理:

    • 提示 "Namespace 不允许":检查 POM 文件的 GroupID 与 Sonatype 验证通过的 Namespace 完全一致
    • 提示 "SNAPSHOT 不被允许":将版本号改为正式版本(如 1.0.0.RELEASE),中央仓库不接受快照版本
    • 签名验证失败:确认 GPG 密钥已上传至公共服务器,且 settings.xml 中 GPG 配置信息正确

至此,你的组件就正式加入 Maven 中央仓库的生态了!从自己用的工具到全球开发者可复用的组件,只差这一套标准化的发布流程。如果遇到问题,可参考 Sonatype 官方文档或留言交流,祝你发布顺利 ~

告别脚本地狱:为什么我们选择用 C# 打造现代化构建系统

揭秘 HagiCode 项目如何利用 Nuke 实现类型安全、跨平台且高度可扩展的自动化构建流程,彻底解决传统构建脚本的维护痛点。

<!-- truncate -->

背景

在软件开发的漫长旅途中,"构建"这个词往往让人又爱又恨。爱的是,一键点击,代码变成产品,那是程序员最迷人的时刻;恨的是,维护那一堆乱糟糟的构建脚本,简直是噩梦。

在很多项目中,我们习惯了用 Python 写脚本,或者用 XML 配置文件(想象一下那段被 <property> 支配的恐惧)。但随着项目复杂度的提升,尤其是像 HagiCode 这样涉及前后端、多平台、多语言混合开发的项目,传统的构建方式开始显得力不从心。脚本逻辑分散、缺乏类型检查、IDE 支持弱……这些问题像一个个小坑,时不时就让开发团队绊个跟头。

为了解决这些痛点,在 HagiCode 项目中,我们决定引入 Nuke —— 一个基于 C# 的现代化构建系统。它不仅仅是一个工具,更像是一种对构建流程的重新思考。今天,我们就来聊聊为什么选择它,以及它是如何让我们的开发体验"起飞"的。

关于 HagiCode

嘿,介绍一下我们正在做的东西

我们正在开发 HagiCode —— 一款 AI 驱动的代码智能助手,让开发体验变得更智能、更便捷、更有趣。

智能 —— AI 全程辅助,从想法到代码,让编码效率提升数倍。便捷 —— 多线程并发操作,充分利用资源,开发流程顺畅无阻。有趣 —— 游戏化机制和成就系统,让编码不再枯燥,充满成就感。

项目正在快速迭代中,如果你对技术写作、知识管理或者 AI 辅助开发感兴趣,欢迎来 GitHub 看看~

核心剖析:为什么是 Nuke?

你可能心里会犯嘀咕:"哎呀,构建系统那么多,比如 Make、Gradle,甚至直接用 Shell 脚本不行吗?为啥非得整一个 C# 的?"

这其实是个好问题。Nuke 的核心魅力在于它把我们最熟悉的编程语言特性带进了构建脚本的世界。

1. 将构建流程模块化:Target 的艺术

Nuke 的设计理念非常清晰:一切皆为目标

在传统的脚本里,我们可能会写出几百行线性执行的代码,逻辑错综复杂。而在 Nuke 中,我们将构建流程分解为独立的 Target(目标)。每个目标只负责一件事,比如:

  • Clean: 清理输出目录
  • Restore: 还原依赖包
  • Compile: 编译代码
  • Test: 运行单元测试

这种设计非常符合单一职责原则。就像搭积木一样,我们可以随意组合这些 Target。更重要的是,Nuke 允许我们定义 Target 之间的依赖关系。比如,你想要 Test,那系统会自动检查你是否先执行了 Compile;想要 Compile,自然得先 Restore

这种依赖关系图不仅让逻辑更清晰,还极大地提高了执行效率,Nuke 会自动分析最优执行路径。

2. 类型安全:告别拼写错误的噩梦

用过 Python 写构建脚本的朋友肯定遇到过这种尴尬:脚本跑了五分钟,最后报错说 Confi.guration 拼写错了,或者传了一个字符串给了一个本该是数字的参数。

使用 C# 编写构建脚本最大的优势就是 类型安全。这意味着:

  • 编译时检查:你在敲代码的时候,IDE 就会告诉你哪里错了,不用等到运行时才发现。
  • 重构无忧:如果你想改个变量名或者方法名,IDE 的重构功能一键搞定,不用全局搜索替换提心吊胆。
  • 智能提示:强大的 IntelliSense 会自动补全代码,你不需要去翻文档记那些生僻的 API。

3. 跨平台:统一的构建体验

以前在 Windows 上写 .bat,在 Linux 上写 .sh,为了兼容两者,还得写个 Python 脚本。现在,只要是 .NET Core(现 .NET 5+)能跑的地方,Nuke 就能跑。

这意味着无论团队成员是使用 Windows、Linux 还是 macOS,无论是用 Visual Studio、VS Code 还是 Rider,大家执行的都是同一套逻辑。这就极大地消除了"在我机器上能跑"这类环境差异导致的问题。

4. 参数与配置管理

Nuke 提供了一套非常优雅的参数解析机制。你不需要手动去解析 string[] args,只需要定义一个属性,加上 [Parameter] 特性,Nuke 就会自动处理命令行参数和配置文件的映射。

比如,我们可以轻松定义构建配置:

[Parameter("Configuration to build - Default is 'Debug'")]
readonly Configuration BuildConfiguration = IsLocalBuild ? Configuration.Debug : Configuration.Release;

Target Compile => _ => _
    .DependsOn(Restore)
    .Executes(() =>
    {
        // 在这里使用 BuildConfiguration,它是类型安全的
        DotNetBuild(s => s
            .SetConfiguration(BuildConfiguration)
            .SetProjectFile(SolutionFile));
    });

这种写法既直观又不容易出错。

实践指南:如何在项目中落地

空谈误国,实干兴邦。让我们看看在 HagiCode 项目中,具体是怎么落地这套方案的。

1. 规划项目结构

我们不想让构建脚本污染项目根目录,也不想搞得像某些 Java 项目那样目录结构深不见底。所以,我们将所有与 Nuke 相关的构建文件统一放置在 nukeBuild/ 文件夹中。

这样做的好处是:

  • 项目根目录保持清爽。
  • 构建逻辑内聚,方便管理。
  • 新成员加入时,一眼就能看到"哦,这是构建相关的逻辑"。

2. 设计清晰的 Target 依赖链

在设计 Target 时,我们遵循了一个原则:原子化 + 依赖流

每个 Target 应该足够小,只做一件事。比如 Clean 就只管删文件,不要在里面顺便做打包。

推荐的依赖流大概是这个样子的:

Clean -> Restore -> Compile -> Test -> Pack

当然,这不是绝对的。比如如果你只想跑个测试,不想打包,Nuke 允许你直接执行 nuke Test,它会自动处理好前置的 Restore 和 Compile 步骤。

3. 完善的错误处理与日志

构建脚本最怕的是什么?是报错信息不明确。比如构建失败了,日志只显示 "Error: 1",这就让人很抓狂。

在 Nuke 中,由于我们可以直接使用 C# 的异常处理机制,因此可以非常精确地捕获和报告错误。

Target Publish => _ => _
    .DependsOn(Test)
    .Executes(() =>
    {
        try 
        {
            // 尝试发布到 NuGet
            DotNetNuGetPush(s => s
                .SetTargetPath(ArtifactPath)
                .SetSource("https://api.nuget.org/v3/index.json")
                .SetApiKey(ApiKey));
        }
        catch (Exception ex)
        {
            Log.Error($"发布失败了,兄弟们检查一下 Key 对不对: {ex.Message}");
            throw; // 确保构建进程以非零退出码结束
        }
    });

4. 集成测试保障质量

构建脚本本身也是代码,也需要测试。Nuke 允许我们为构建流程编写测试,确保当我们修改了构建逻辑后,不会破坏现有的发布流程。这在持续集成(CI)流水线中尤为重要。

总结

通过引入 Nuke,HagiCode 的构建流程变得前所未有的顺畅。它不仅仅是一个工具的替换,更是工程化思维的提升。

我们收获了什么?

  • 可维护性:代码即配置,逻辑清晰,新人也能快速上手。
  • 稳定性:强类型检查减少了 90% 以上的低级错误。
  • 一致性:跨平台的统一体验,消除了环境差异。

如果说以前写构建脚本是"在黑暗中摸索",那么使用 Nuke 就像是"开着灯走夜路"。如果你受够了维护那些难以调试的脚本语言,不妨试试把构建逻辑也搬到 C# 的世界里来,也许你会发现,原来构建也可以这么优雅。

参考资料


感谢您的阅读,如果您觉得本文有用,快点击下方点赞按钮👍,让更多的人看到本文。

本内容采用人工智能辅助协作,经本人审核,符合本人观点与立场。

RustFS 默认通过 9001 端口登录控制台,9000 端口使用 API,为了安全合规,通常采用启用 HTTPS、反向代理(诸如 nginx、traefik、caddy 等)的方式来更加安全的使用 RustFS。本文分享一种更加安全的方式,通过 Cloudflare tunnel 来访问你的 RustFS 实例。

安装 RustFS

RustFS 支持二进制、Docker 以及 Helm Chart 的安装方式,详细方法可以查看官网安装指南。将如下内容写入 docker-compose.yml 文件:

services:
  rustfs:
    image: rustfs/rustfs:latest
    container_name: rustfs
    hostname: rustfs
    environment:
      - RUSTFS_VOLUMES=/data/rustfs{1...4}
      - RUSTFS_ADDRESS=0.0.0.0:9000
      - RUSTFS_CONSOLE_ENABLE=true
      - RUSTFS_CONSOLE_ADDRESS=0.0.0.0:9001
      - RUSTFS_ACCESS_KEY=rustfsadmin
      - RUSTFS_SECRET_KEY=rustfsadmin
      - RUSTFS_TLS_PATH=/opt/tls
    ports:
      - "9000:9000"  # API endpoint
      - "9001:9001"  # Console
    volumes:
      - data1:/data/rustfs1
      - data2:/data/rustfs2
      - data3:/data/rustfs3
      - data4:/data/rustfs4
      - ./certs:/opt/tls

    networks:
      - rustfs

networks:
  rustfs:
    driver: bridge
    name: rustfs

volumes:
  data1:
  data2:
  data3:
  data4:

运行如下命令

docker compose up -d

即可安装好一个 RustFS 实例:

docker compose ps
NAME      IMAGE                          COMMAND                  SERVICE   CREATED          STATUS          PORTS
rustfs    rustfs/rustfs:1.0.0-alpha.81   "/entrypoint.sh rust…"   rustfs    22 minutes ago   Up 22 minutes   0.0.0.0:9000-9001->9000-9001/tcp, [::]:9000-9001->9000-9001/tcp

配置 Cloudflare tunnel

配置 Cloudflare tunnel 大体分为 域名配置tunnel 配置 两部分。

域名配置

域名配置是为了后期能够更方便的访问 RustFS。

  • 使用 Cloudflare 账号登录 Cloudflare Domain 界面;
  • 在左侧导航栏,Account home,如果你已经有域名,则选择 Onboard a domain,否则可选择 Buy a domain
  • 如果选择 Onboard a domain,点击该选项后,在出现的界面中输入你的域名,然后继续往下走,直到在最后选择 Continue to activation
  • 如果一切顺利,可以在域名管理首页看到添加成功的域名,其 Status 会显示为 Active

image.png

tunnel 配置

  • 使用 Cloudflare 账号登录 Cloudflare Dashboard
  • 在左侧导航栏,选择 Networks -> Connectors,在右侧界面点击 Create a tunnel
  • 在 tunnel 类型中,选择 Select Clouflared
  • Install and run connectors 中,根据 RustFS 实例所在服务器的操作系统信息,选择相应的安装方式。安装完毕后,可以在服务器上查看 cloudflared 服务的状态。运行正常后点击 Next

    systemctl status cloudflared
    ● cloudflared.service - cloudflared
         Loaded: loaded (/etc/systemd/system/cloudflared.service; enabled; preset: enabled)
         Active: active (running) since Fri 2026-01-16 21:18:53 CST; 6 days ago
       Main PID: 2538004 (cloudflared)
          Tasks: 10 (limit: 4375)
         Memory: 31.3M (peak: 38.7M swap: 8.2M swap peak: 15.3M)
            CPU: 18min 16.159s
         CGroup: /system.slice/cloudflared.service
  • Route Traffic 中,配置 HostnameService 信息。

    • Hostname 中填写的域名可用于后续访问 RustFS 实例,可以在 Domain 字段中选择 域名配置 部分添加好的域名。如果想通过子域名访问,也可以在 Subdomain 字段中输入子域名名称。
    • Service 选择服务类型和 URL。对于上述安装的 RustFS 实例,Type 可以选择 HTTP/HTTPS(如果启用了 HTTPS,可选择 HTTPS,否则用 HTTP),URL 为 localhost:9001

    image.png

  • 点击 Complete setup 完成配置。

上述配置结束后,可以在 Connectors 界面看到添加好的 tunnel,如果一切顺利,则可以看到 Status 为绿色的 HEALTHY

在 Hostname 和 Service 设置页面的 Additional application settings 部分,点击 HTTP Settings,在 HTTP Host Header 部分,输入访问 RustFS 的域名,这是为了避免后续使用出现签名错误。

登录验证

恭喜你,如果你顺利完成了上述两部分的配置后,那么现在你就可以通过你配置好的域名来访问 RustFS 实例了。本文配置的域名为 rustfs.xiaomage.vip,所以在浏览器中输入 https://rustfs.xiaomage.vip 即可访问 RustFS 实例:

image.png

输入 rustfsadmin/rustfsadmin 即可登录。

接下来就可以通过多种方式来使用 RustFS 实例了,比如 mcrc 以及 rclone

通过 mc 使用 RustFS

mc 是 Minio 的专属客户端,由于 RustFS 是 S3 兼容的,而且是 Minio 的平替,所以可以用 mc 来操作 RustFS。

前提

mc --version
mc version RELEASE.2025-08-29T21-30-41Z (commit-id=f7560841be167a94b7014bf8a504e0820843247f)
Runtime: go1.24.6 darwin/arm64
Copyright (c) 2015-2025 MinIO, Inc.
MinIO Enterprise License

使用

# 添加 `alias`
mc alias set rustfs https://rustfs.xiaomage.vip rustfsadmin rustfsadmin

# 创建存储桶
mc mb rustfs/hello

# 列出存储桶
mc ls rustfs
[2026-01-23 21:39:36 CST]     0B hello/
[2026-01-23 20:12:59 CST]     0B test/

# 上传文件到存储桶
echo "123456" > 1.txt
mc cp 1.txt rustfs/hello
/tmp/1.txt:                         ██████████████████████████████████████████████████████████████████████████████████ 100.0% 7 B       1 B/s      

# 查看上传的文件
mc ls rustfs/hello
[2026-01-23 21:40:44 CST]     7B STANDARD 1.txt

更多用法可自行探索。

通过 rclone 使用 RustFS

rclone是一个命令行工具,可以对不同云提供商上的文件和目录进行同步。

前提

rclone --version
rclone v1.72.1
- os/version: ubuntu 24.04 (64 bit)
- os/kernel: 6.8.0-71-generic (x86_64)
- os/type: linux
- os/arch: amd64
- go/version: go1.25.5
- go/linking: static
- go/tags: none

使用

  • 配置 rclone

执行 rclone config 命令,根据 RustFS 实例信息,一步步进行配置。配置完成后,会生成一个 ~/.config/rclone/rclone.conf 文件,一般内容如下:

[rustfs]
type = s3
provider = Minio
access_key_id = rustfsadmin
secret_access_key = rustfsadmin
endpoint = https://rustfs.xiaomage.vip
region = us-east-1
force_path_style = true
由于目前 RustFS 还未向 rclone 官方提 PR 以增加 RustFS provider 信息,因此使用 Minio 作为 provider。
  • 开始使用
# 列出存储桶和对象

rclone ls rustfs: --s3-sign-accept-encoding=false
        7 hello/1.txt
    11792 test/1.log
   520512 test/123.mp3
     7394 test/2.log
   147240 test/321.mp3
   

# 查看某个对象内容
rclone cat rustfs:hello/1.txt --s3-sign-accept-encoding=false
123456 

对于其他用法,可以通过 rclone --help 来自行探索。

注意:添加 --s3-sign-accept-encoding=false 参数是因为 Cloudflare 会对 Accept-Encoding 参数进行修改,在 S3 协议中,这种变更会导致 SignatureDoesNotMatch 错误,详情可以查看 RustFS issue

通过 rc 使用 RustFS

rc 是 RustFS 的 Client,用来对 RustFS 进行操作。目前,刚发布 0.1.1。可以使用 cargo 或源码编译安装。

rc --version
rc 0.1.1

目前提供 aliaslsmbrb 等多种常规命令。使用方式和 mc 类似。

# 设置 alias
rc alias set rustfs https://rustfs.xiaomage.vip rustfsadmin rustfsadmin
✓ Alias 'rustfs' configured successfully.

# 列出存储桶
rc ls rustfs
[2026-01-23 13:39:36]         0B hello/
[2026-01-23 13:56:57]         0B rclone/
[2026-01-23 12:12:59]         0B test/

# 创建存储桶
rc mb rustfs/client
✓ Bucket 'rustfs/client' created successfully.

更多用法,可以通过 rc --help 进行查看并自行探索,使用过程中有任何问题,可以在 GitHub Issue中进行反馈。

Adobe 系列应用原生支持 Windows on ARM

Adobe 近期为 Premiere Pro、After Effects、Audition 以及 Media Encoder 推出 26.0 版本更新,正式原生支持 Windows on ARM,可直接在搭载高通 Snapdragon X 系列 ARM 架构处理器的 Windows 设备上运行。相应软件要求用户系统至少为 Windows 11(Build 26100.2033),配备至少 16GB RAM 内存,并使用 Qualcomm Adreno GPU 驱动 31.0.121.1 及更新版本。Adobe 同时明确表示,旧版应用(25.x 及更早版本应用)并未为 Windows on ARM 设备设计或测试,无法保证正常运行。不过 ARM 原生版仍存在一定功能限制,例如 Premiere Pro 暂不支持 Loudness Radar、Wraptor DCP 导出、GoPro CineForm 的导入导出以及 P2 Movie 格式导出等;After Effects 缺少 Cinema 4D 渲染器,仅支持专为 Windows ARM 编译的第三方插件等。来源


因 Grok 传播色情伪造内容,X 平台受到欧盟调查

近几周以来,多国 X 平台用户举报 Grok 生成色情伪造内容并在平台传播。近期,英国通信管理局已正式针对 X 是否违反英国《在线安全法案》展开调查,而后法国以及印度也相继表态,对 X 发出正式指控。随着全球性声讨持续升级,欧盟正式发出调查指令,本次调查覆盖全部 27 个欧盟成员国,重点核查 X 是否依《数字服务法案》充分评估并缓解相关风险。该法案针对相关网络有害及非法内容划定了严格监管红线,而网络平台未能妥善处理非法内容与虚假信息,或违反相关规定,欧盟方面最高可对其处以全球年营业额 6% 的罚款。来源


国家新闻出版署公布 2026 年 1 月游戏审批信息

1 月 26 日,国家新闻出版署正式公布了《2026 年 1 月份国产网络游戏审批信息》以及《2026 年进口网络游戏审批信息》。其中,国产游戏共计 177 款,包含《斗罗大陆:启程》《我叫 MT5》等;进口游戏共计 5 款,包含《彩虹六号:攻势》《愤怒的小鸟:经典归来》《秘境夺金》等。来源1来源2


国家邮政局部署 2026 年春运期间寄递服务保障工作

国家邮政局近日印发《2026 年春运期间寄递服务保障工作方案》(以下简称《工作方案》),强调要统筹满足人民群众寄递需求和保障快递员合法权益,扎实做好 2026 年春运期间寄递服务保障工作。邮政企业、快递企业要聚焦节前人民群众购置年货需求,及时揽收并按约定提供寄递服务。中国邮政集团有限公司要确保邮政普遍服务持续提供。各快递企业要科学预测业务量变化,合理制订春节假期运营计划,提前向社会公示/公布服务时间、服务地域并严格按照公示/公布信息提供服务,满足春节假期基本寄递服务需求。

同时多家快递也公布了 2026 年春节期间服务公告,其中顺丰速运、京东物流、德邦等企业公告显示,将保障春节寄递服务需求,并加收高峰期资源调节费,以应对资源调配需求。来源


Apple 发布新款 AirTag 等新品

1 月 26 日,Apple 推出新款 AirTag,售价保持不变,仍为单件装 249 元,四件装 849 元。新款 AirTag 配备了与 iPhone 17 等机型相同的第二代超宽带技术芯片,更易被定位,查找范围相比前代扩大最高 50%。升级的蓝牙芯片也让用户首次可以通过 Apple Watch Series 9 或后续表款、Apple Watch Ultra 2 或后续表款使用精确查找功能寻找 AirTag。内置扬声器音量也比前代提升 50%。新款 AirTag 无缝集成共享物品位置功能,可以暂时将遗落物品的位置信息安全共享给受信赖的第三方,Apple 与超过 50 家航司直接合作,通过共享物品位置功能,用户可以将遗落物品的位置信息共享给合作航空公司的顾客服务团队,以便其协助找回延误的行李等遗失物品。来源

1 月 26 日,Apple 发布新款 Apple Watch Unity Connection 编织单圈表带,以纪念黑人历史月并赞颂联结的力量。该表带将于本周晚些时候在 Apple Store 零售店有售,售价 779 元。来源


HMD 发布 HMD Watch X1 与 P1 等多款新品

HMD 发布了 Watch X1 与 P1 两款新品智能手表。Watch X1 采用 1.43 英寸 AMOLED 显示屏,峰值亮度 600 尼特,分辨率 466*466,支持 AOD 功能与 IP68 防尘抗水,AOD 开启续航可达 5 天。Watch P1 采用 1.83 英寸 LCD 屏幕,峰值亮度 550 尼特,分辨率 240*284,防尘抗水等级 IP67,续航达 4 天。两者基于自有的 RTOS,可通过 HMD Watch 应用控制。HMD 另外还发布了 HMD Dub X50 Pro、Dub X50、Dub S60、Dub P70、Dub P60、Dub P50 六款 TWS 耳机。来源

HMD Watch X1


微软发布 Maia 200 AI 加速器芯片

1 月 26 日,微软公布了 Maia 200 芯片。Maia 200 基于台积电三纳米制程,带有原生 FP8/FP4 张量核心,7 TB/s 带宽的 216GB HBM3e 内存系统,与 272MB 片上 SRAM。微软称 Maia 200 是突破性的推理加速器,比上代 Maia 100 快 30%。目前该芯片已部署于微软的美中数据中心与美西 3 号数据中心。来源


Nintendo 发布「闲聊花花」

上周,Nintendo 在官网以及 Youtube 中公布其新款周边闲聊花花(Talking Flower),这款周边的外形采至超级马里奥中的经典 NPC。「闲聊花花」体积小巧,适合作为家中或是桌面的摆件使用。当用户在没有操作它时,它偶尔会「自言自语」,大概每小时两次。用户也可以点击花前的按钮和它进行互动,每次按下都会收获不同的惊喜。「闲聊花花」目前已知支持中文、英文、日文、韩文等 10 国语言,并支持切换。该周边预计在今年的 3 月 12 日正式发售,售价 4,500 日元。来源


看看就行的小道消息

  • 昨日,贾跃亭发布微博,宣称 FF EAI 机器人目前正式完成首款产品美国法规的相关认证工作,即将正式启动销售。此外,其它首批产品的法规认证也在快速推进中,有望很快完成并实现「发布即销售,销售即交付」策略,目标发布当月开始交付。来源
  • 近日,腾讯召开 2025 年度员工大会。大会中马化腾表示,针对微信生态 AI 智能化的问题,腾讯也在进行慎重评估,因为 AI 全家桶未必是大家都喜欢的,未来将继续坚持去中心化,以兼顾用户需求和隐私安全的方式来思考规划微信的智能生态。来源
  • 据外媒爆料,Google 将基于 Material 3 Expressive 的基础针对 Android 17 的 UI 以及交互进行改版设计,其中最为明显是模糊效果将会大幅增加,而这种效果与 Apple 的 Liquid Glass 还是存在一定差异,Google 的模糊处理看起来更加的克制或轻盈。后续该设计的改版是否仅存在系统设置,还是在 app 中也会平展开来,有待观察。来源
  • 据界面新闻 1 月 26 日报道,腾讯旗下 AI 助手「元宝」启动新功能「元宝派」内测。该功能定位为多人社交空间,用户可创建或加入「派」实现 AI 辅助聊天、共享屏幕、协同观影听音乐等互动玩法。其底层接入了腾讯会议的音视频能力,并打通微信、QQ 的分享链路,支持一键邀请好友加入。与传统单一对话机器人不同,腾讯试图通过社交关系提升 AI 工具粘性。在「元宝派」中,AI 可充当社交润滑剂或效率工具,例如活跃群聊氛围、管理日程任务。来源
  • 暴雪娱乐于 1 月 26 日发布 35 周年纪念视频,并宣布于 1 月 29 日、2 月 4 日、2 月 9 日、2 月 11 日分别发布《魔兽世界》《守望先锋》《炉石传说》《暗黑破坏神》四款游戏的「重大游戏公告」。来源
  • 微软 2026 年一月 Windows 11 更新补丁引发了包括无法关机、应用损坏、应用卡死在内的一系列 bug。随后微软发布了编号为 KB5078127/KB50781432 等的多个紧急修复补丁。但最新消息显示,该系列修复补丁会导致一部分用户遭遇「UNMOUNTABLE_BOOT_VOLUME」错误,无法开机。微软已知悉这一状况,并建议遭遇该问题的用户采取手动恢复处理。来源
  • 2026 年 1 月 2 日,全球 .ai 后缀域名突破一百万个,预计去年全年为其所属地英国海外领土安圭拉(Anguilla)带去超七千万美元收入。来源


少数派的近期动态

  • 我们正在优化并改进新的首页版式,如果你在使用过程中发现了任何问题或者有改进建议,请通过反馈表单告知我们。首页反馈收集
  • 将设计装进耳朵:少数派×飞傲联名 CD 机盖板设计大赛已经开始啦。了解详情
  • 比第三方 Apps 更好使:盘点 Apple 生态经典好用的原生应用。看看都有啥

你可能错过的文章

> 下载 少数派 2.0 客户端、关注 少数派公众号,解锁全新阅读体验 📰

> 实用、好用的 正版软件,少数派为你呈现 🚀

    小时候生活在乡下,家里、邻居,路上,都是抓老鼠的猫,

    他们白天在睡大觉,

    夜里出来活动,抓老鼠,各种溜达,两眼放光

    长大后生活在了城中,现在的猫,包括家里的,还有流浪猫

    要么半夜叫春,晚上半睡半活动,要么胡吃闷睡,

    这大早晨,路上车流量高峰,一只猫,速度飞快的,横冲路中间想去对面,

    我的车急刹,让过去了,心惊肉跳,

    可,跟我并行的车不知道有猫横冲,压上去了💀

    正好前面红绿灯,我停下车,

    后视镜望着静静躺地上的猫,几秒后,全身抽搐几十秒后

    一切都静下来了。

    哎,希望它下辈子的这个时辰在睡大觉,

    这样才有精神头晚上抓耗子🐭。

    SafariGoogleRedirect

    SafariGoogleRedirect( Safari · Google 重定向)是一个 Tampermonkey/Greasemonkey 用户脚本,专为 Safari 浏览器在中国大陆地区使用 Google 搜索时 设计,用于解决 Google 搜索跳 中间层 问题,提升用户体验。


    功能特性

    • 自动重定向
      当 iPhone 地区设置为中国大陆, Safari 设置为谷歌搜索时, 自动将访问的 Google 中国搜索页面(www.google.cn)或 Safari 搜索跳转产生的中间层页面,重定向到 Google 国际版(www.google.com),解决 Safari 大陆地区 Google 搜索先弹出 中间层 确认页的问题。

    • 最小 URL 构造
      构造最简洁搜索 URL ,仅保留 q(搜索关键词)参数,去除多余参数(如 hlieoeclient 等),增强隐私安全, 保证搜索 URL 干净、统一。

    • 加载动画改善闪烁体验
      在重定向之前,页面显示 Google Logo + CSS Loading 动画,减少中间层页面闪烁感,让用户体验更加平滑。

    • 深浅色主题自适应
      自动检测 iOS 系统深色/浅色模式,动画颜色和背景色随主题变化:


      • 浅色模式 → 白色背景 + 蓝色加载动画
      • 深色模式 → 深灰背景 + 亮蓝加载动画
    • 保留搜索词
      智能提取并保留原搜索关键词,确保重定向后搜索结果一致、连贯。

    • 轻量高效
      无依赖、纯前端脚本,运行在 document-start 阶段,执行速度快,用户几乎感觉不到跳转。

    • 兼容性好
      支持 HTTP/HTTPS 协议,覆盖 iOS 地区设置为中国大陆, Safari 设置为谷歌搜索的所有 iOS 版本;也可适配未来可能的 Google 中间层。

    • 历史记录友好
      使用 location.replace 进行重定向,不污染浏览历史,返回键不会回到中间层页面。


    安装方法

    1. 在 iPhone 安装 Tampermonkey 或 任意 提供用户脚本功能 的 Safari 浏览器扩展, 有收费的, 有免费的自行选择, 任意一个都可以.
    2. 在你选择使用的扩展中, 添加脚本, URL 为 https://raw.githubusercontent.com/garinasset/SafariGoogleRedirect/main/SafariGoogleRedirect.user.js
    3. 下载添加后, 启用 Safari · Google 重定向
    4. 在 Safari 中选择 Google 作为搜索引擎, 在地址栏键入关键词, 进行搜索时,脚本会自动:
      1. 显示临时中间层( Logo + 动画)
      2. 自动跳转到 Google 国际版并为你展示搜索结果


    使用效果示例

    • 输入搜索词 test
    原始 URL 重定向后 URL
    https://www.google.cn/search?q=test&hl=zh-CN&client=safari&ie=UTF-8 https://www.google.com/search?q=test

    ✅ 完全去掉多余参数,只保留搜索关键词 q
    ✅ 避免 Safari 弹出中间层确认页
    ✅ 中间页显示 Logo + 动画,深浅色主题自适应
    ✅ 保持搜索结果一致


    更新与反馈


    许可证

    MIT License

    引言:受够了 Word 排版?

    马上就是金三银四招聘季了,相信很多兄弟已经开始准备简历了。

    作为一名开发者,我最头疼的事情不是写 Bug ,而是更新简历。每次打开 Word ,都要在“内容”和“格式”之间反复横跳。调一下边距,整个文档炸了;换个字体,两页变成三页了。

    更糟糕的是数据安全问题。一旦 PDF 发出去,你就失去了控制权。猎头会把你的简历存进库里,然后在即使你不找工作的时候也疯狂打电话骚扰你,甚至把你的简历倒卖给培训机构。

    我就在想:为什么我们不能用写代码的方式写简历?

    我们熟悉 Markdown ,我们喜欢 Git 的版本控制,我们崇尚 **"Content is King"**。
    于是,趁着春节假期,我开发了 LinkCV —— 一个专为极客打造的 Markdown 简历平台。

    👉 体验地址: link-cv.com


    核心理念:Markdown + AI + Privacy

    在这个项目中,我坚持了三个原则:

    1. Markdown First: 只关注内容。别管字体字号,样式交给 CSS ,排版交给系统。
    2. AI 注入灵魂: 接入 DeepSeek / Gemini 模型。不知道怎么吹自己的项目?写个大概,一键让 AI 帮你润色成 STAR 法则的专业描述。
    3. 隐私至上: 这是我最想做的功能 —— 阅后即焚


    亮点功能介绍

    1. 阅后即焚 (Burn After Reading) 🔥

    这是最酷的功能。
    以前发简历是发文件,现在你可以生成一个 加密链接
    你可以设置:

    • 有效期: 比如“3 天后失效”。
    • 访问限制: 比如“限制访问 5 次”。

    这意味着,你可以发给猎头一个链接。既保证了他们能看、能转给 HR ,又防止了你的简历被无限期留存和倒卖。一旦面试流程结束,链接自动 404 ,你的隐私重新回归你自己。

    2. AI 智能润色与翻译 🤖

    支持中、英、日多语言一键翻译。
    针对程序员的简历,我专门微调了 Prompt ,效果提升显著。

    👀 看看效果 (以 Elon Musk 为例):

    马斯克英文简历

    马斯克中文简历

    (上面这两个链接就是用 LinkCV 生成的真实页面,点进去体验一下丝滑的加载速度)

    3. 多端适配与完美 PDF 📄

    虽然是网页版,但我花了很多精力处理 CSS @media print。直接在浏览器按 Ctrl + P (或点击导出),就能得到一份完美分页、不会截断的 A4 简历 PDF 。


    技术栈 (Tech Stack)

    为了保证最快的加载速度和最好的 SEO ,我选择了目前 Next.js 生态最新的技术栈:

    • Framework: Next.js 15 (App Router) - 全面拥抱 React Server Components 。
    • Database: PostgreSQL + Prisma - 数据安全存储。
    • Styling: Tailwind CSS - 极简主义设计。
    • AI: Google Gemini / DeepSeek V3 。


    写在最后

    这是一个开发者写给开发者的工具。

    如果你也准备在三月份看机会,或者纯粹厌倦了 Word 排版,欢迎来试用 LinkCV 。工具目前完全免费(后续可能会有 Pro 版,但基础功能管够)。

    祝大家在金三银四都能拿到满意的 Offer !🚀

    📍 官网直达: link-cv.com
    (PS: 也就是个独立开发作品,还在快速迭代中,有 Bug 轻喷,欢迎在评论区提建议!)

    引言

    在多模态AI系统中,图像处理链已成为一个新兴的安全漏洞点。Trail of Bits的安全研究人员最近揭示了一种巧妙的攻击方法:通过利用图像缩放算法,在高分辨率图像中嵌入隐藏的提示词。这些隐藏指令在图像被AI系统下采样时才会显现,从而触发提示注入,导致潜在的数据泄露或其他恶意行为。该技术已证明对谷歌的Gemini CLI、Vertex AI等生产级系统有效,尽管谷歌视其为默认配置下的非正式漏洞,但它暴露了AI图像预处理链的普遍弱点。

    这项攻击源于2020年的图像缩放攻击理论,已被进一步武器化为针对LLM的间接提示注入工具。研究人员开源了Anamorpher框架,允许用户生成和测试此类攻击图像。本文档将从原理入手,逐步剖析攻击机制、工具实现、实际效果及防御策略,帮助读者全面理解这一威胁,并探讨其在AI安全领域的启示。

    常见图像缩放算法

    在机器学习和图像处理领域,图像缩放算法是预处理链中的关键组件,常用于调整输入图像尺寸以匹配模型要求。这些算法主要通过插值方法计算新像素值,尤其在下采样(缩小图像)时易受攻击影响。现代框架如OpenCV、Pillow(用于PyTorch)、tf.image(TensorFlow)和scikit-image支持多种算法,但实现细节(如抗锯齿选项或默认参数)可能导致跨库差异,从而要求攻击者进行针对性优化。

    以下表格概述了常见算法的核心机制、优缺点,以及在ML库中的典型实现和攻击相关性(基于2025年最新实践,包括对多模态AI系统的潜在漏洞):

    算法名称 核心机制 优缺点分析 ML库实现与攻击相关性
    最近邻插值(Nearest Neighbor) 直接选取最近像素值作为输出像素,无需计算平均或多项式。 速度最快,但易产生锯齿和块状失真,适合实时应用。 Pillow和OpenCV默认支持,默认偏移参数(如Pillow的offset=2)易于精确操纵单个像素,常用于强攻击以最小扰动注入隐藏模式。
    双线性插值(Bilinear) 使用2x2邻域像素进行线性加权平均,先水平后垂直插值。 平衡速度与质量,输出稍模糊,抗锯齿效果中等。 OpenCV和TensorFlow广泛使用,支持抗锯齿选项;权重矩阵简单(中心2x2区域),攻击需优化暗区像素以绕过检测。
    双三次插值(Bicubic) 基于4x4邻域的三次多项式插值,使用更多像素计算平滑曲线。 输出更平滑、自然,但计算密集,速度较慢。 TensorFlow、OpenCV和scikit-image优化实现;滤波器参数差异大,攻击涉及复杂约束优化,但提供更高隐蔽性。
    Lanczos 采用sinc函数对扩展邻域(通常8x8或更大)进行加权滤波。 高质量,减少振铃效应,但易受莫尔纹干扰,计算量大。 scikit-image和SciPy专用于专业处理;权重分布广,攻击需操纵更多像素,适用于弱攻击以最大化视觉差异。
    区域平均(Area) 计算目标像素对应原始区域的像素平均值,类似于盒滤波。 简单高效,专用于下采样,避免锯齿,但细节丢失多。 Pillow优化用于图像缩小;平均化特性要求攻击分布扰动于整个区域,易于检测但在ML管道中常见。

    这些算法在2025年的ML生态中(如PyTorch、TensorFlow)常与图像增强或超分辨率技术结合使用,例如结合深度学习模型(如ISR)来提升质量,但也增加了攻击表面。 选择算法时需考虑计算效率与视觉保真度,尤其在多模态AI系统中,下采样漏洞可能被利用注入恶意提示。

    图像缩放攻击原理

    图像缩放攻击是一种针对机器学习预处理阶段的对抗技术,主要利用下采样(图像缩小)过程中的像素丢弃和加权机制。通常,原始图像尺寸超过模型输入要求,因此系统会自动缩放,导致部分像素信息丢失。这一漏洞允许攻击者操纵输入图像,使其在人类眼中正常,但缩放后输出完全不同,从而误导下游AI模型或应用。

    关键定义

    • 图像 S:原始源图像(大小 m×n),攻击者希望攻击图像在视觉上与之相似。
    • 图像 A:攻击输入图像(大小 m×n),作为缩放函数的输入,包含隐藏扰动。
    • 图像 D:缩放输出(大小 m'×n'),实际传递给模型的图像。
    • 图像 T:目标图像(大小 m'×n'),攻击者期望D与之匹配,通常嵌入恶意内容(如隐藏提示词)。

    攻击目标

    攻击有两个主要目标:

    1. 最小化扰动:对S施加最小修改生成A,确保A与S在人类感知中几乎相同(e.g., 使用L2范数量化视觉相似度)。
    2. 输出控制:确保缩放后的D与T高度相似(误差在阈值内),从而实现语义欺骗,如将羊图像缩放后变为狼以绕过分类器。

    信号处理视角的解释

    攻击根源于下采样与卷积的交互作用。现代缩放过程包括:

    1. 插值计算:使用卷积核(滤波器,如bilinear权重)对原始像素加权求和。
    2. 下采样:根据输出尺寸丢弃像素,仅保留部分信息。

    缩放函数本质上是欠采样(surjective),多个输入可映射到同一输出。数学建模为: \text{ScaleFunc}(A) = CL \cdot A \cdot CR 其中CL和CR是基于插值算法的系数矩阵(e.g., bilinear的权重集中在中心区域)。攻击通过逆向求解这些矩阵(经验或源码分析),然后使用二次规划(QP)优化扰动:强攻击为凸优化,弱攻击为凹优化,可分解为行/列子问题以降低复杂度(从O(n²)到向量级)。像素值约束在[0, 255]内,确保A合法。

    此原理使攻击独立于具体ML模型,影响框架(如Caffe、TensorFlow)、云服务和浏览器。检测方法包括随机像素移除或相似度度量(如余弦相似度<0.5表示攻击)。

    利用Anamorpher进行攻击

    该攻击分为两个核心步骤:

    1. 算法识别:使用指纹技术(如棋盘格图案测试)推断AI系统的缩放算法和库。
    2. 攻击图像生成:基于诱饵图像和提示词文本,创建A。开源工具Anamorpher简化此过程,支持4:1下采样比。

    Anamorpher工具剖析

    Anamorpher的攻击根植于图像缩放的信号处理本质。下采样过程涉及卷积核加权和像素丢弃,本质上是欠采样函数:多个高分辨率输入可映射到同一低分辨率输出。攻击者通过逆向优化,操纵高分辨率图像的特定像素(权重高的区域),确保下采样输出匹配目标payload(如包含提示词的文本图像)。

    数学上,缩放函数可近似为矩阵形式: D = CL \cdot A \cdot CR 其中:

    • A 为攻击图像(高分辨率输入)。
    • D 为下采样输出(目标payload T 的近似)。
    • CL 和 CR 为基于插值算法的系数矩阵(e.g., Bilinear的权重集中在中心2x2区域)。

    优化目标采用约束最小二乘法:

    • 最小化扰动 \|A - S\|^2(S 为原始图像,确保视觉隐蔽)。
    • 约束 \|D - T\|^2 < \epsilon(输出误差阈值)。
    • 额外约束像素值在[0, 255]内,并考虑伽马校正(sRGB到线性光转换)以匹配人类感知。

    Anamorpher利用零空间扰动(null space perturbation)增强自然性:在保持均值和采样像素不变的前提下,添加随机噪声。工具针对4:1下采样比(e.g., 4x4块到1像素)优化,适用于生产AI系统如Gemini CLI和Vertex AI。

    攻击算法与实现细节

    Anamorpher聚焦三种主流下采样算法:Nearest Neighbor、Bilinear和Bicubic。每个算法的实现考虑了库差异(如OpenCV的BGR vs. Pillow的RGB),并在线性光空间操作以避免伽马失真。生成流程:将提示词文本渲染为目标图像T(4:1比例),然后优化诱饵图像S生成A。

    下面以三类常见插值为主线,说明“缩放输出由哪些输入像素主导”。你可以把它理解为:插值核决定了局部像素的权重分配,从而决定了攻击优化的“着力点”。

    Nearest Neighbor实现

    Nearest Neighbor简单高效,仅选取最近像素。Anamorpher使用Pillow库,默认偏移offset=2(中心像素)。

    实现步骤如下

    1. 空间转换:sRGB到线性光(伽马≈2.2)。
    2. 零空间求解:使用SVD分解约束矩阵C(采样像素不变 + 块均值不变),提取基B(14x16矩阵)。
    3. 块优化:遍历4x4块,计算diff(采样像素与T差异)。若lam≤0,直接修改采样像素;否则闭式解最小二乘:

      \min \| \delta \|^2 + \lambda^2 (\sum \delta)^2 \quad s.t. \quad \delta_k = diff

      解:\delta_k = diff,其他\delta_j = -diff \cdot \lambda^2 / (1 + 15\lambda^2)。
      4. 扰动添加:若eps>0,使用B添加零空间噪声。
      5. 伽马校正:对T应用gamma_target(默认1.0)调整亮度。

    参数:

    • lam(默认0.25):均值权重,平衡边界可见性和嵌入效果。
    • eps:扰动强度,提升自然感。
    • gamma_target:亮度校正(>1增强对比,<1突出暗部)。
    • offset:采样位置。

    此实现针对单像素操纵,隐蔽性高,但易产生块边界。

    Bilinear实现

    Bilinear使用2x2加权平均。Anamorpher以OpenCV为例,支持抗锯齿。

    实现步骤如下

    1. 格式转换:BGR到sRGB,再到线性光。
    2. 权重矩阵:中心2x2区域(w1-w4)。
    3. 暗区掩码:基于dark-frac(默认0.3)限制编辑最暗30%像素,提升隐蔽。
    4. 约束优化:遍历4x4块,计算diff。最小二乘求解(类似Nearest,但约束可编辑像素和权重平方和)。
    5. 零空间扰动 + 更新
    6. 评估:下采样后计算MSE(越小越好)和PSNR(>30dB高质量)。

    参数:

    • lam, eps, gamma。
    • dark-frac:编辑比例。
    • anti-alias:抗锯齿开关。

    优化聚焦暗区,适用于复杂纹理图像。

    Bicubic实现

    Bicubic使用4x4三次多项式,平滑性强。实现类似Bilinear,但滤波器更复杂。Bicubic继承Bilinear框架,调整插值函数为三次多项式。Anamorpher强调自定义参数测试,结果因浮点优化而异(建议5次运行)。

    参数:同Bilinear,支持额外滤波器调整。

    三种实现共享线性空间操作和约束优化框架,但权重分布差异导致Nearest最简单(单像素)、Bicubic最复杂(16像素加权)。

    实战攻击

    我这里使用Anamorpher自带的示例图像,内含的提示词为从Google Calendar窃取数据并发送至攻击者邮箱,无需确认。 他的机制是payload嵌入高分辨率图像的暗区,利用bicubic插值,通过最小二乘优化调整像素(针对亮度通道的高权重像素),下采样后产生高对比红色背景文本;基于Nyquist-Shannon采样定理利用混叠效应。 我分别在genspark和gemini cli都进行测试,都能成功进行提示词注入。

    genspark

    image-20251017104506208

    gemini cli

    image-20251017104700964

    防御方法

    不要使用图像缩小,而是简单地限制上传尺寸。对于任何转换,尤其是如果需要缩小,最终用户应该始终能够看到模型实际看到的输入预览。

    参考文章

    https://github.com/trailofbits/anamorpher

    https://www.usenix.org/conference/usenixsecurity19/presentation/xiao

    题⽬描述

    输⼊⼀个⻓度为 n 整数数组,数组⾥⾯可能含有相同的元素,实现⼀个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前⾯部分,所有的偶数位于数组的后⾯部分,对奇数和奇数,偶数和偶数之间的相对位置不做要求,但是时间复杂度和空间复杂度必须如下要求。

    数据范围:0 ≤ n ≤ 50000,数组中每个数的值 0 ≤ val ≤ 10000

    要求:时间复杂度 O(n),空间复杂度 O(1)

    示例 1
    输⼊:[1,2,3,4]
    返回值:[1,3,2,4]
    说明:[3,1,2,4]或者[3,1,4,2]也是正确答案

    示例 2
    输⼊:[1,3,5,6,7]
    返回值:[1,3,5,7,6]
    说明:[3,1,5,7,6]等也是正确答案

    思路及解答

    两次遍历

    第一次遍历收集奇数,第二次遍历收集偶数

    这种方法虽然简单易懂,但需要额外空间,不符合题目要求

    public class Solution {
        public int[] reorderArray(int[] nums) {
            if (nums == null || nums.length == 0) {
                return new int[0];
            }
            
            int[] result = new int[nums.length];
            int index = 0;
            
            // 第一次遍历:收集所有奇数
            for (int num : nums) {
                if (num % 2 == 1) {
                    result[index++] = num;
                }
            }
            
            // 第二次遍历:收集所有偶数
            for (int num : nums) {
                if (num % 2 == 0) {
                    result[index++] = num;
                }
            }
            
            return result;
        }
    }
    • 时间复杂度:O(n)
    • 空间复杂度:O(n)

    双指针交换(推荐)

    这道题需要奇数在⼀半,偶数在另外⼀半就可以,并没有要求他们之间的顺序,那么就可以⽤双指针,⼀个指针在左边,⼀个指针在右边,⽐如 1,3,5,6,7 :

    左指针往右遍历直到找到偶数,也就是 6 停下来,

    右指针往左⾛,直到找到第⼀个奇数,也就是 7 停下来。

    两者交换:

    左指针继续往右边⾛,两个指针相遇,结束,这个时候其实偶数已经全部在右边了。

    这个例⼦⾥⾯只经过⼀次交换,如果是多次交换,那么结束的条件同样也是两个指针相遇。

    public class Solution {
        public int[] reorderArray(int[] nums) {
            if (nums == null || nums.length <= 1) {
                return nums;
            }
            
            int left = 0;                    // 左指针,从数组开头开始
            int right = nums.length - 1;     // 右指针,从数组末尾开始
            
            while (left < right) {
                // 左指针向右移动,直到找到偶数
                while (left < right && nums[left] % 2 == 1) {
                    left++;
                }
                
                // 右指针向左移动,直到找到奇数
                while (left < right && nums[right] % 2 == 0) {
                    right--;
                }
                
                // 如果左指针仍在右指针左边,交换奇偶数
                if (left < right) {
                    int temp = nums[left];
                    nums[left] = nums[right];
                    nums[right] = temp;
                    left++;
                    right--;
                }
            }
            
            return nums;
        }
    }
    • 时间复杂度:O(n),每个元素最多被访问一次
    • 空间复杂度:O(1),只使用了常数级别的额外空间

    1. 频率:已经坚持 6 个月,共 70 天,平均一周 3 练。

    2. 目前容量:500 俯卧撑,300 哑铃飞鸟,250 个深蹲,时长 1.5h 。

    3. 目标,目前体重 140 ,希望能减到 130 ,并练出腹肌。

    4. 工作可以尽力干,不能竭力干,最近新闻上过劳死有点吓人。

    5. 祝大家都健康✔✔

    Google/Cloudflare/Quad9 这些 DoT/DoH (即使走代理),在电信线路下查成功率在 smartdns 里都显示 90%以上,另一条移动宽带,惨不忍睹,只有 30-40%,有没有移动好用的?还是墙中墙就这样了?