标签 代码审查 下的文章

写在前面,本人目前处于求职中,如有合适内推岗位,请加:lpshiyue 感谢。

优秀的架构不是一次性的设计杰作,而是通过持续评审、债务治理和渐进式重构形成的有机体系

在构建了高可用的容灾体系后,我们面临一个更根本的挑战:如何确保系统架构本身具备持续演进的能力?架构评审与技术债治理正是连接短期交付压力与长期架构可持续性的关键桥梁。本文将深入探讨架构质量属性、演进式重构方法论与风险评估框架,帮助企业构建既满足当前需求又适应未来变化的弹性架构体系。

1 架构可持续性:从静态设计到动态演进

1.1 架构治理的范式转变

传统架构观将系统设计视为一次性活动,而现代架构实践强调持续演进的理念。根据行业数据,拥有成熟架构治理体系的企业在系统维护成本上比缺乏治理的组织低40%,新功能交付速度快35%。

架构可持续性的三大支柱

  • 质量属性守护:通过明确的质量标准防止架构腐化
  • 技术债主动管理:将债务治理融入日常开发流程
  • 演进式重构机制:在保证业务连续性的前提下持续优化

这种转变使架构工作从项目制活动转变为产品全生命周期的核心实践,确保了系统在整个生命周期内保持健康状态。

1.2 架构评审的价值重估

有效的架构评审不是障碍而是赋能,其核心价值体现在三个维度:

风险防控价值:提前识别设计缺陷,降低后期重构成本。数据表明,架构阶段发现的问题修复成本是编码阶段的1/10,生产环境的1/100。

知识传递价值:通过评审过程促进团队间架构共识,减少认知偏差。

质量内建价值:将架构原则和质量要求植入设计阶段,而非事后修补。

2 架构质量属性:可持续性的衡量基准

2.1 核心质量属性体系

架构质量属性为评审提供客观标准,避免主观判断的随意性。完整的质量属性体系涵盖多个维度:

运行期质量属性关注系统执行时的表现:

  • 性能:响应时间、吞吐量、资源利用率
  • 可靠性:故障率、可用性、容错能力
  • 安全性:数据保护、访问控制、漏洞防护

演进期质量属性影响系统变更和维护成本:

  • 可维护性:代码清晰度、模块化、文档完整性
  • 可扩展性:水平/垂直扩展能力、耦合度
  • 可测试性:单元测试覆盖率、集成测试便利性
// 可测试性设计示例:依赖注入提升可测试性
public class OrderService {
    private final PaymentGateway paymentGateway;
    private final InventoryService inventoryService;
    
    // 通过构造函数注入依赖,便于测试时mock
    public OrderService(PaymentGateway paymentGateway, InventoryService inventoryService) {
        this.paymentGateway = paymentGateway;
        this.inventoryService = inventoryService;
    }
    
    public boolean processOrder(Order order) {
        // 业务逻辑
        return true;
    }
}

依赖注入设计提升可测试性

2.2 质量属性的优先级权衡

不同业务场景下,质量属性的优先级需要差异化设置。一刀切的标准往往导致过度设计或质量不足。

系统类型关键质量属性次要质量属性权衡考量
电商交易一致性、可用性、性能可扩展性、可维护性强一致性可能降低性能
大数据平台可扩展性、吞吐量实时性、一致性最终一致性提升吞吐量
IoT边缘计算可靠性、安全性可维护性、性能离线能力优先于实时性

质量属性权衡框架帮助团队基于业务上下文做出合理决策:

# 质量属性权衡决策记录
decision_id: "perf-vs-maintainability"
context: "订单查询服务需要优化响应时间"
constraints: 
  - "必须在200ms内返回结果"
  - "团队规模小,维护成本需控制"
alternatives:
  - option: "引入缓存层"
    pros: ["性能提升明显"]
    cons: ["缓存一致性复杂化"]
  - option: "数据库查询优化"
    pros: ["架构简单"]
    cons: ["性能提升有限"]
decision: "采用缓存层,但增加缓存失效策略"
rationale: "业务要求性能优先,可通过工具降低维护成本"

架构决策记录模板

3 架构评审体系:多层次、全流程的质量保障

3.1 分层评审机制

有效的架构评审需要多层次覆盖,针对不同变更范围实施相应粒度的评审。

战术级评审针对日常技术决策和代码变更,通过轻量级流程保障基础质量:

  • 代码审查:每个PR必须经过至少一名核心成员审查
  • 设计讨论:复杂功能在实现前进行团队内设计评审
  • 工具辅助:静态分析、代码规范检查自动化

战略级评审针对系统级架构变更,通过正式流程保障一致性:

  • 架构委员会:跨部门专家组成,评审重大架构决策
  • 决策文档:使用ADR(Architecture Decision Record)记录关键决策
  • 影响分析:评估变更对现有系统的影响范围

混合评审模型平衡效率与质量控制:

graph TD
    A[变更请求] --> B{变更规模评估}
    B -->|小型变更| C[轻量评审]
    B -->|中型变更| D[团队评审]
    B -->|大型变更| E[架构委员会评审]
    C --> F[实施]
    D --> F
    E --> F
    F --> G[效果追踪]
    
    style C fill:#e1f5fe
    style D fill:#fff3e0
    style E fill:#f3e5f5

分层评审流程根据变更规模差异化处理

3.2 架构评审工作流设计

科学的评审流程确保效率效果的平衡。四步评审法是经过验证的有效方法:

初步评审阶段聚焦架构原则符合度,评估技术选型合理性。评审重点包括:

  • 技术栈与公司标准的一致性
  • 第三方组件成熟度与许可合规
  • 非功能需求的可实现性

详细设计阶段深入接口定义、数据模型和技术实现细节。关键检查点包括:

  • API设计是否符合RESTful规范或领域规范
  • 数据模型是否满足查询需求和一致性要求
  • 异常处理机制是否完备

最终评审阶段确认所有实施细节,评估风险和回滚方案。重点关注:

  • 实施计划的可操作性
  • 回滚方案的完备性
  • 监控和告警策略的覆盖度

实施监控阶段跟踪架构落地效果,及时发现问题。通过度量和复盘持续改进。

3.3 评审指标与成功标准

量化指标使架构评审客观可衡量,避免主观意见主导决策。

架构健康度指标

  • 耦合度:模块间依赖数量,衡量系统复杂度
  • 依赖稳定性:违反依赖规则的百分比
  • 架构一致分:代码实现与设计文档的一致性评分

技术债指标

  • 代码重复率:重复代码占总代码量的比例
  • 测试覆盖率:单元测试覆盖的代码比例
  • 文档完备率:API文档、设计文档的完整性

通过建立这些指标的基线目标和改进路线,架构评审从主观讨论转向数据驱动的决策过程。

4 技术债治理:从被动应对到主动管理

4.1 技术债的本质与分类

技术债是Ward Cunningham提出的隐喻,指为加速开发而采取的技术捷径所带来的长期成本。如同金融债务,技术债会产生"利息",即增加的维护成本。

技术债的四象限分类(Martin Fowler)提供系统化管理框架:

谨慎的(Prudent)鲁莽的(Reckless)
故意的(Deliberate)明知有更好方案但权衡后选择捷径明知是错误方案仍选择实施
无心的(Inadvertent)实施时不知有更好方案因知识不足而引入错误

技术债的三层结构帮助精准识别债务来源:

  • 代码级债务:代码坏味道、重复代码、复杂函数
  • 架构级债务:模块耦合过高、单点故障、技术栈落后
  • 基础设施债务:部署复杂、监控缺失、测试环境不稳定

4.2 技术债识别与评估体系

建立系统化识别机制是技术债治理的第一步。

自动化扫描工具持续检测技术债:

# 技术债扫描配置示例
technical_debt_scan:
  code_quality:
    - tool: sonarqube
      metrics: [complexity, duplication, code_smells]
  dependencies:
    - tool: dependabot
      metrics: [outdated_deps, security_vulnerabilities]
  architecture:
    - tool: structure101
      metrics: [cyclic_dependencies, modularity]

技术债评估矩阵基于影响和修复成本确定优先级:

-- 技术债优先级评估SQL示例
SELECT 
    debt_id,
    debt_type,
    impact_level,      -- 对业务的影响程度
    repair_cost,       -- 修复成本估算
    interest_cost,     -- 利息成本(每月额外维护成本)
    risk_exposure,     -- 风险暴露度
    (impact_level * risk_exposure) / repair_cost as priority_score
FROM technical_debts
WHERE status = 'identified'
ORDER BY priority_score DESC;

技术债优先级量化评估

4.3 技术债偿还策略

技术债治理需要多元化偿还策略,避免"一次性还清"的不切实际期望。

日常化偿还将技术债修复纳入正常开发节奏:

  • 男孩 Scout 规则:每次修改代码时使其比发现时更好
  • 技术债标签:在任务管理中标记技术债项目,纳入迭代计划
  • 专项修复迭代:定期安排专门的技术债修复周期

止损策略防止新债务产生:

  • 代码规范:通过静态检查防止新坏味道
  • 架构守护:通过依赖关系检查防止架构退化
  • 流水线门禁:质量门禁阻止债务积累

某大型互联网公司通过"20%时间用于技术债修复"的策略,在一年内将关键系统的平均复杂度降低30%,缺陷率下降45%。

5 演进式重构:可持续架构的实现路径

5.1 重构的策略选择

演进式重构强调小步快跑,通过持续的小规模改进避免大规模重写的高风险。

重构的时机选择至关重要:

  • 扩展功能时:在添加新功能时顺带重构相关模块
  • 修复缺陷时:理解代码逻辑后立即重构改善可读性
  • 代码审查时:发现设计问题立即提出重构建议
  • 定期维护窗口:专门安排重构时间块

重构风险控制策略

// 渐进式重构示例:通过特性开关降低风险
public class OrderService {
    private final FeatureToggle featureToggle;
    
    public Order processOrder(Order order) {
        if (featureToggle.isEnabled("new_processing_logic")) {
            return newOrderProcessing(order);
        } else {
            return legacyOrderProcessing(order);
        }
    }
    
    // 新逻辑逐步验证,可快速回退
    private Order newOrderProcessing(Order order) {
        // 重构后的实现
    }
}

通过特性开关实现渐进式重构

5.2 架构演进模式

不同架构风格需要不同的演进策略。

微服务架构演进

  • 绞杀者模式:逐步用新服务替换单体功能
  • 并行模式:新功能用新架构实现,旧功能逐步迁移
  • 分支化模式:通过抽象层兼容多版本实现

单体架构演进

  • 模块化先行:在单体内实施模块化,为拆分做准备
  • 数据库解耦:逐步拆分数据库,降低耦合度
  • 接口标准化:定义清晰接口,为未来微服务化铺路

成功的架构演进需要保持系统始终可发布,避免长期功能分支导致的合并困难。

6 风险评估框架:数据驱动的决策支持

6.1 风险识别与分类

架构风险需要系统化识别,而非依赖个人经验。

技术风险维度

  • 实现风险:技术方案可行性、团队技能匹配度
  • 集成风险:系统间兼容性、接口一致性
  • 性能风险:负载能力、资源消耗预估

管理风险维度

  • 进度风险:估算准确性、依赖任务进度
  • 资源风险:人员可用性、基础设施准备度
  • 范围风险:需求稳定性、变更频率

风险矩阵评估法量化风险影响:

graph LR
    A[风险识别] --> B[概率评估]
    A --> C[影响评估]
    B --> D[风险值计算]
    C --> D
    D --> E[优先级排序]
    
    style A fill:#f5f5f5
    style B fill:#fff3e0
    style C fill:#fff3e0
    style D fill:#e8f5e8
    style E fill:#f3e5f5

风险矩阵评估流程

6.2 风险应对策略库

建立系统化应对策略提高风险处理效率。

风险规避:改变计划消除风险源头,如选择更成熟技术栈
风险转移:通过外包或保险将风险转嫁第三方
风险缓解:采取措施降低风险概率或影响,如增加测试
风险接受:对低概率或低影响风险明确接受并准备预案

架构决策风险检查表

risk_checklist:
  - id: "perf_risk"
    question: "是否进行性能压测?"
    mitigation: "制定性能测试计划"
  - id: "sec_risk"  
    question: "是否进行安全评估?"
    mitigation: "安排安全渗透测试"
  - id: "dep_risk"
    question: "是否有第三方依赖风险?"
    mitigation: "评估替代方案"

6.3 风险监控与预警

建立持续风险监控机制,及时发现新风险。

技术指标监控

  • 复杂度增长趋势:识别设计腐化早期信号
  • 构建失败频率:评估代码库稳定性
  • 测试覆盖率变化:衡量质量保障水平

过程指标监控

  • 迭代交付稳定性:评估团队交付节奏健康度
  • 缺陷逃逸率:衡量质量门禁有效性
  • 技术债增长率:监控债务积累速度

通过Dashboard可视化这些指标,团队可以实时掌握系统健康状况,及时干预潜在风险。

7 治理体系落地:从理论到实践

7.1 组织保障与文化培育

技术治理需要组织机制保障,而非依赖个人英雄主义。

架构治理委员会负责制定标准和评审重大决策:

  • 跨部门代表:确保各视角平衡
  • 定期会议机制:保证决策效率
  • 决策透明化:所有决策及理由公开可查

工程师文化培育使质量成为团队自觉追求:

  • 技术分享机制:定期分享架构经验教训
  • 代码评审文化:相互评审成为标准实践
  • 质量激励机制:奖励优秀技术贡献

7.2 工具链与平台支持

自动化工具是治理体系落地的加速器

架构治理工具链

# 架构治理工具栈示例
architecture_governance:
  design: 
    - tool: "structurizr"  # 架构图即代码
    - tool: "arc42"        # 架构文档模板
  analysis:
    - tool: "sonarqube"    # 代码质量分析
    - tool: "jqassistant"  # 架构规则检查
  decision:
    - tool: "adr-tools"    # 架构决策记录
  monitoring:
    - tool: "prometheus"   # 系统指标监控
    - tool: "grafana"      # 指标可视化

平台工程支持通过内部开发者平台降低架构治理成本:

  • 标准化模板:新项目基于最佳实践模板创建
  • 自助式工具:团队可自主进行架构分析
  • 质量门禁:流水线自动阻断不符合架构标准的变更

7.3 度量和反馈循环

建立闭环改进机制确保治理体系持续优化。

治理效能度量

  • 架构评审效率:从提交到决策的平均时间
  • 技术债解决率:已解决债务占总债务比例
  • 架构一致性:代码实现与设计文档的一致性

定期复盘机制

  • 季度架构评估:评估整体架构健康度
  • 案例深度分析:选择典型项目进行深度复盘
  • 治理流程优化:基于反馈优化评审流程和标准

某金融科技公司通过建立完整的架构治理体系,在两年内将系统平均可用性从99.9%提升至99.99%,新功能交付周期从月级缩短到周级。

总结

架构评审与技术债治理是现代软件工程的核心竞争力,它将系统架构从"一次性设计"转变为"持续演进过程"。通过质量属性定义、演进式重构和风险评估框架的协同作用,企业可以构建既满足当前业务需求又具备未来适应性的弹性架构体系。

成功治理的三要素

  1. 体系化思维:将架构治理视为完整体系而非孤立活动
  2. 数据驱动:基于度量而非主观感受做出决策
  3. 渐进式推进:小步快跑而非一次性完美主义

避免的常见陷阱

  • 过度治理:过多流程阻碍创新和效率
  • 形式主义:重文档轻实质,评审流于形式
  • 短期导向:忽视技术债积累的长期成本

架构治理的终极目标不是创建完美架构,而是建立持续改进的机制和能力,使系统能够随着业务需求和技术发展而有机演进。


📚 下篇预告
《数据平台全景与角色分工——OLTP、OLAP、批/流与数据湖的版图与边界》—— 我们将深入探讨:

  • 🗄️ 数据架构演进:从传统数据库到现代数据平台的技术路径
  • 处理范式:OLTP事务处理、OLAP分析计算、批处理与流处理的适用场景
  • 🏗️ 数据湖与数据仓库:逻辑架构、存储分层与查询优化策略
  • 👥 角色协作:数据工程师、分析师、科学家在数据平台中的职责边界
  • 🔄 流水线设计:数据采集、加工、服务与治理的全链路管理

点击关注,构建高效可靠的数据平台体系!

今日行动建议

  1. 评估当前系统架构质量属性,建立可量化的健康度指标体系
  2. 制定技术债识别和分类标准,建立债务台账和偿还计划
  3. 设计分层架构评审机制,平衡控制力度和团队自主性
  4. 引入演进式重构实践,将架构改进融入日常开发流程
  5. 建立架构风险评估框架,数据驱动技术决策

从上次说起

我的skill都可以在这里看到

安装也是非常的简洁

npx skills add BenedictKing/codex-review
npx skills add BenedictKing/tavily-web
npx skills add BenedictKing/context7-auto-research
npx skills add BenedictKing/exa-search
npx skills add BenedictKing/firecrawl-scraper

上下文占用非常少,主打的就是一个省钱还好用


📌 转载信息
原作者: Foward
转载时间: 2026/1/25 08:04:37

SonarQube Server 2025.6.1.117629 - 代码质量、安全与静态分析工具

SonarQube Server 2025 Release 6 (macOS, Linux, Windows) - 代码质量、安全与静态分析工具

Self-managed static analysis tool for continuous codebase inspection

请访问原文链接:https://sysin.org/blog/sonarqube/ 查看最新版。原创作品,转载请保留出处。

作者主页:sysin.org


SonarQube Server

代码质量和安全性由您掌控

SonarQube Server
之前称为 SonarQube,本地部署的用于持续代码库检查的静态分析工具

保持 AI 生成的代码干净

释放 AI 编码助手的强大功能,而无需承担不良、不安全代码的风险。SonarQube Server 是您的干净代码解决方案,可以部署在任何地方、本地或云环境中。

SonarQube Server

受到 700 万开发者和 400,000 多个组织的使用和喜爱

提高代码质量的代码质量工具

您的代码是一项商业资产。通过 SonarQube Server 达到干净代码状态,实现代码的最高价值。

SonarQube Server 功能:

  • 代码智能

    利用 SonarQube 的深度洞察,更全面地了解您的代码库。通过减少认知负荷来提高开发人员的生产力。

  • 与顶级 DevOps 平台集成

    轻松加入项目。与 GitHub Actions、GitLab CI/CD、Azure Pipelines、Bitbucket Pipelines 和 Jenkins 集成,以自动触发分析并显示您工作地点的代码运行状况。

  • 代码审查

    通过 SonarQube 的质量阈值,防止不符合策略的代码进入生产环境。消除人工编写和 AI 生成代码中的问题,从而降低后期修复成本。

  • 高性能和可操作性

    按照您的方式进行部署,无论是在本地、在云中、作为服务器、使用 Docker 或 Kubernetes。多线程、多个计算引擎和特定于语言的加载可提供最佳性能。

  • 顶级分析速度和准确性

    在几分钟而不是几小时内收到可操作的清洁代码指标 (sysin)。Clean as You Code 会在您工作时检查较小的代码片段,为您提供有关新代码质量的准确反馈。

  • 重要语言的关键安全规则

    在您的开发工作流程中,在正确的时间和正确的位置无缝地发现编码问题。受益于 6,000 多个规则以及行业领先的 Java、C#、PHP、Python 等污点分析。

  • 共享、统一的配置

    设置特定的编码标准,使您的团队在代码健康方面保持一致并实现您的代码质量目标。另外,“边编程边学习” 可将开发人员的技能提升到同样高的水平。

  • 用于 IDE 的 SonarQube

    添加 SonarQube for IDE 扩展并将其连接到 SonarQube 服务器,以便在编码时动态查找编码问题,并确保您的团队遵循单一受监管的编码标准。

  • 测量代码覆盖率

    查看测试执行的代码库的百分比,以获得有关代码运行状况的宝贵见解。引导您到覆盖率低的领域进行改进。

Sonar 的人工智能

AI 辅助编码,由 SONAR 改进

  • 新的 AI 代码保证

    Sonar AI 代码保证是一个强大且简化的流程,用于通过结构化和全面的分析来验证 AI 生成的代码。这确保了每一段新代码在投入生产之前都符合最高的质量和安全标准。

  • AI CodeFix 简介

    Sonar AI CodeFix 是一项强大的功能 (sysin),可为代码分析解决方案 SonarQube Server 和 SonarQube Cloud 发现的问题提供代码修复建议。只需单击一下,您就可以获得有关如何解决一系列问题的建议,从而简化问题解决流程。

笔者提示:此类功能通常需要有效服务合同。

安全漏洞检测

增强的开发人员安全工具 | 安全与机密信息检测

  • 静态代码分析

    Sonar 的静态应用程序安全测试 (SAST) 引擎可检测代码中的安全漏洞,以便在构建和测试应用程序之前消除这些漏洞。使用 SAST 为复杂项目实现强大的应用程序安全性和合规性。

  • 机密信息检测

    SonarQube Server 包含一个强大的机密信息检测工具,这是用于检测和删除代码中机密信息的最全面的解决方案之一。与 SonarQube for IDE 一起使用,它可以防止机密信息泄露并成为严重的安全漏洞。

  • 安全标准合规性

    SonarQube Server 可帮助您遵守通用代码安全标准,例如 NIST SSDF。将 SonarQube Server 与 SonarQube for IDE 结合使用,可以自动检查项目代码是否存在安全漏洞,并提高整体代码质量。

基于开源,满足所有需求的版本

SonarQube Server 版本:

  • Community Build

    免费开源,可提高开发效率和代码质量。

  • Developer Edition

    小型团队和企业的基本功能。

  • Enterprise Edition

    为现代企业提供更深入的见解和绩效。

  • Data Center Edition

    任务关键型高可用性、可扩展性和性能。

什么是 LTA 版本

LONG-TERM ACTIVE

SonarQube Server Long-Term Active (LTA)

为客户提供最佳体验、创新功能和世界一流的支持,以实现持续的业务成功。

什么是长期活跃 (LTA)

LTA 是指每 12 个月发布一次的 SonarQube Server 版本(以前称为长期支持或 LTS)。它是产品的功能完整版本,将保持活动状态更长的时间。大型组织有时更愿意继续使用 LTA,因为他们无法经常升级,而是选择每 12 个月升级一次。

系统要求

操作系统要求:

建议运行在虚拟机环境中,推荐使用本站原创虚拟机模板 OVF,简单、精准、高效。

软件要求已更新:包含在文档中。

新增功能

SonarQube Server 2025.6:先沉浸(vibe),再以前所未有的速度验证

2025 年 12 月 11 日

SonarQube Server 2025.6

AI 已经将开发瓶颈从 “写代码” 转移到 “验证代码”。确保代码可靠、安全、可维护,已成为软件开发生命周期中最关键的一步。SonarQube Server 2025.6 加速了这一验证流程,将其直接嵌入您的日常工作流中。通过更深的集成、大幅加速的分析性能以及扩展的语言支持,本次发布帮助团队拥抱 “先沉浸、再验证(vibe, then verify)” 的理念,更自信地交付软件。

2025.6 新功能一览

  • 加速工作流:新增 Jira Cloud 与 Slack 集成。
  • 更快反馈:JavaScript/TypeScript 分析速度提升最高 40%。
  • 即时修复:在 IDE 中新增 58 个 JavaScript/TypeScript 快速修复。
  • 现代语言支持:全面支持 Swift(5.9–6.1)和 Python 3.14。
  • AI/ML 保障:为 PyTorch、Apex 和 Ruby 提供高效分析。
  • 基础设施代码:新增 Go 和 Shell/Bash 的代码质量规则 (sysin)。
  • 合规性:完整覆盖 MISRA C++:2023、OWASP Top 10 2025 与 STIG V6R3。
  • 供应链安全:支持导入 CycloneDX 和 SPDX SBOM。

通过深度工作流集成加速您的团队

为了帮助团队跟上庞大的代码量,SonarQube 专注于消除摩擦、加快反馈循环。使用 JavaScript/TypeScript 的开发者将立即注意到在大型项目中最高 40% 的分析速度提升,从而缩短等待时间,加速代码评审。同时,SonarQube 让修复问题变得比以往更简单:58 个全新的 “快速修复” 让您在 IDE 中即可快速处理问题。此外,将代码质量融入组织工作流也变得前所未有的顺畅:全新的 Jira Cloud 集成可立即将代码问题转成可追踪的任务 (sysin);Slack 集成则可在质量门状态变化时实时发送通知,让团队在构建无法通过质量门时可以更快速地响应。

无与伦比的语言与合规覆盖

SonarQube 2025.6 大幅扩展其在行业内对语言覆盖的领先优势,让您能自信采用新技术并满足最严苛的合规要求。SonarQube 现已为最新版本的 Python 3.14 与 Swift(5.9–6.1)提供全方位的代码安全与代码质量支持,包括 Swift 的 SAST 与秘钥检测。对于构建机器学习应用的开发者,SonarQube 提供 PyTorch 的 AI/ML 保障,帮助实现高效代码。在云原生领域,您将获得大量新的 Go 规则,以及 Shell/Bash 脚本的代码质量与代. 码安全分析。最后,在 SonarQube Server Enterprise 和 Data Center 版本中,SonarQube 提供对全部 179 条 MISRA C++:2023 指南、STIG V6R3 及新版 OWASP Top 10 2025 的完整覆盖,为您的合规与风险团队提供通过严格标准所需的保证。

通过 Advanced SAST 和 SBOM 保护您的供应链

在供应链攻击不断增加的当下,代码安全绝不能被事后处理。此次发布强化了 SonarQube “集成代码质量与代码安全” 的核心使命。SonarQube Advanced Security 中的 Advanced SAST 功能已针对 C#、Java 以及现在的 Python 的主流库进行了刷新与优化,以发现其他工具遗漏的复杂、隐蔽漏洞。为了让您对所有组件拥有全面可见性 (sysin),SonarQube Advanced Security 现在支持导入 CycloneDX 和 SPDX 格式的 SBOM(软件物料清单),实现对任意组件的统一依赖性与漏洞报告。通过这些增强功能,SonarQube 确保您的组织能够以快速且自信的方式验证每一行代码——无论是开发者编写的还是 AI 生成的。

更多详细功能介绍,请查阅官方文档。

下载地址

版本历史:

SonarQube Server 2025.1 LTA Data Center Edition for macOS, Linux, Windows | January 2025 | 2025.1.0.102418

SonarQube Server 2025 Release 2 Data Center Edition for macOS, Linux, Windows | March 2025 | 2025.2.0.105476

SonarQube Server 2025 Release 3 Data Center Edition for macOS, Linux, Windows | May 2025 | 2025.3.0.108892

SonarQube Server 2025 Release 3.1 Data Center Edition for macOS, Linux, Windows | Jun 2025 | 2025.3.1.109879

SonarQube Server 2025 Release 4.2 Data Center Edition for macOS, Linux, Windows | July 2025 | 2025.4.2.112048

SonarQube Server 2025 Release 5 Data Center Edition for macOS, Linux, Windows | September 2025 | 2025.5.0.113872 (2025-09-24)

SonarQube Server 2025 Release 6 Data Center Edition for macOS, Linux, Windows | December 2025 | 2025.6.0.117042 (2025-12-11)

当前版本:

SonarQube Server 2025 Release 6.1 Data Center Edition for macOS, Linux, Windows | December 2025 | 2025.6.1.117629 (2026-01-20)

更多:HTTP 协议与安全

公司的 im 有水印,就不发图了,简单总结一下

  1. 大数据/医疗部门因使用 ai 生成代码导致生产环境服务器负载拉爆且历史数据被大范围覆盖
  2. it 部门排查开发电脑的 ai 相关软件,禁止 ai 自动代码生成
  3. 所有研发部门安排时间重新 review 近半年所有代码
  4. 对应研发部门的开发和测试绩效当月为 D(意味着 2026 年没有年终奖了,但是 2025 还是可以有的)


哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈(先笑一下🤣
他们怎么敢的啊,又不是自己的项目,我用 ai 都只拿当搜索引擎,代码都是我自己的测试确认后才写到项目里面去


我一直强调,ai 真的不能帮你背 D 绩效啊喂!

我先来

推荐做法

  • 引导 AI 出方案你来 review, review 通过了以后,先让 AI 先写测试用例,让测试用例失败,让 AI 自动修复测试用例,你来 review 修复方案和代码。
  • 多用 plan 模式,确认没问题了才让 AI 生成代码,不要一把梭不停的让 AI 修改代码 ,改来改去可能越改越奇怪,最好是把计划做好,这样效率和准确率更高。

不推荐

  • 你来出方案,让 AI 实现,你来测试,让 AI 修复代码。

AI生成代码质量难以把控!本文分享来自美团的技术实践,三大策略破解AI编程痛点。单测快速验证逻辑正确性,安全网保护存量代码演进,TDD模式精准传递需求。告别「看起来没问题」的错觉,构建AI时代的代码质量保障体系。

一、引言

目前,国内外很多AI Coding助手能在几秒钟内生成完整代码块,大大提升了开发效率,但这种高速开发模式也带来了潜在风险——与人工编码不同是,AI Coding助手生成代码存在两个特殊风险:其一,AI Coding助手依赖于上下文与模型自身的能力,输出的代码质量相对不可控。其二,AI生成的代码虽然逻辑通顺、结构完整,但可能隐藏着难以察觉的边界问题或逻辑缺陷。

核心问题:我们如何快速的验证AI生成代码的质量和可靠性?

本文旨在分享如何借助单元测试,让AI编程合作更高效可靠,主要解决三个常见痛点:

  1. 肉眼审查困境:AI一次性生成大量代码时,难以快速准确判断逻辑完备性;
  2. 存量代码信任危机:如何验证AI修改老代码时,不会产生非预期的结果;
  3. 需求传达难题:如何精准向AI表达复杂需求并快速验证。

针对上述三个常见痛点,本文提出采用不同的单元测试策略来应对以上问题。每个策略都针对一个特定痛点设计:策略一通过测试解决肉眼审查的局限性;策略二构建单测安全网应对存量代码的信任问题;策略三则采用TDD模式优化需求传达与验证流程。下文将依次展开说明,希望能对大家有所帮助或启发。

二、策略一:单测检验AI代码逻辑正确性

2.1 问题背景

传统的人工代码审查在AI生成的大量代码面前显得低效且不可靠。在软件测试实践中,有着测试左移(Shift Left Testing)的概念,本质上是借助工具和测试手段更早地发现问题和预防问题。在AI Coding时代,这一理念尤为关键:跳过单元测试直接集成测试看似”抄近路”,实则是将风险后置——开发阶段几分钟能发现的Bug,在集成测试环境可能需要较长定位修复,这中间包含了代码部署、环境准备、测试条件的准备、问题定位、开发人员修复、再次部署验证等一系列漫长的环节。

相比之下,单元测试具有独特的优势:它能够独立运行、快速验证结果,并且可以无限次重复执行。这种测试方式就像是为项目进行的一次性投资,却能为整个开发周期构建起一张可靠的“安全网”。它不仅能实时验证AI Coding生成的代码是否正确,更能持续保障未来代码的质量稳定性,让开发团队始终对代码库保持信心。

2.2 案例:分页查询接口的隐蔽Bug

任务背景:实现一个支持多条件筛选的复杂分页查询接口pageQueryRobot

AI生成了如下核心查询逻辑:

public List<AgentRobotE> pageQueryRobotsByCondition(List<Long> shopIds, String chatSceneCode,
        Boolean enabled, Integer pageNo, Integer pageSize) {
    // ... 前置校验代码 ...

    // 分页查询机器人基础信息
    int offset = (pageNo - 1) * pageSize;
    List<AgentRobotEntity> entities = robotIds.stream()
            .skip(offset)
            .limit(pageSize)
            .map(robotId -> agentRobotDAO.getRobotById(robotId, false))
            .filter(Objects::nonNull)
            // 问题代码:类型不匹配的隐蔽Bug
            .filter(entity -> enabled == null || Objects.equals(entity.getEnabled(), enabled ? 1 : 0))
            .filter(entity -> Objects.equals(entity.getChatSceneCode(), chatSceneCode))
            .collect(Collectors.toList());

    return entities.stream()
            .map(this::convertToModel)
            .filter(Objects::nonNull)
            .collect(Collectors.toList());
}

问题分析:这段代码看起来逻辑完整,但第8行的过滤逻辑包含了多个复杂元素:

  • 三元运算符 enabled ? 1 : 0
  • Objects.equals 的使用
  • Boolean到Integer的隐式逻辑转换

仅凭肉眼很难发现其中的类型不匹配问题。

单元测试发现问题:通过AI编写了17个全面的单元测试用例,覆盖:

  • 正常场景:各种有效参数组合
  • 边界场景:null值、空集合处理
  • 参数组合:enabled为true/false/null的不同情况
@Test
public void testPageQueryWhenEnabledIsTrue() {
    // arrange
    List<Long> shopIds = Arrays.asList(12345L, 67890L);
    String chatSceneCode = "SCENE_C";
    Boolean enabled = true;  // 测试enabled为true的情况

    // 模拟数据库返回的实体,enabled字段为Boolean类型
    AgentRobotEntity mockEntity = new AgentRobotEntity();
    mockEntity.setEnabled(true);  // 注意:这里是Boolean类型
    mockEntity.setChatSceneCode("SCENE_C");

    when(agentRobotDAO.getRobotById(anyLong(), eq(false))).thenReturn(mockEntity);

    // act
    List<AgentRobotE> result = repository.pageQueryRobotsByCondition(
        shopIds, chatSceneCode, enabled, 1, 10);

    // assert - 这个测试失败了!
    assertEquals(1, result.size());  // 期望返回1个结果,实际返回0个
}

测试运行结果:当enabled为true时测试失败!

问题定位:通过测试失败,快速定位到过滤逻辑的问题:

// 错误的逻辑:entity.getEnabled()返回Boolean类型,但与Integer比较
Objects.equals(entity.getEnabled(), enabled ? 1 : 0)
// 当enabled=true时,比较的是 Objects.equals(Boolean.TRUE, 1) -> false
// 当enabled=false时,比较的是 Objects.equals(Boolean.TRUE, 0) -> false

正确修复:

// 修复后:直接比较Boolean类型
.filter(entity -> enabled == null || Objects.equals(entity.getEnabled(), enabled))

意外收获:在审查测试覆盖的代码时,还发现了N+1查询的性能问题:

// 存在性能问题的代码
.map(robotId -> agentRobotDAO.getRobotById(robotId, false))  // 每个robotId单独查询

成果验证:修复后,所有17个单元测试用例全部通过,代码质量得到保障。

三、策略二:构建安全网保护存量代码

3.1 问题场景

AI对存量代码的修改挑战更大。AI看到的可能只是函数或类的局部,无法理解背后的业务规则和历史包袱。如何放心的让AI修改已有的代码?

在进行AI Coding前,需要确保旧有逻辑,处于单元测试的完全覆盖保护中,这就像在开启汽车的“自动辅助驾驶”功能前,必须先系好安全带一样。这条“安全带”就是我们完善的、可运行的单元测试集。

  • 快速验证,精准反馈:AI生成修改后的代码无需人工逐行对比,只需运行单元测试即可获得即时反馈。测试失败的用例直接揭示AI修改中存在的问题——要么触及了不应改动的逻辑,要么未能正确实现预期变更。这种反馈机制既高效又客观。
  • 清晰界定修改边界:单元测试结果帮助我们明确判断——AI的修改是否精准实现了目标?在引入新功能的同时是否完整保留了原有逻辑?通过区分预期内的失败(主动修改旧逻辑)和意外失败(破坏现有功能),我们获得了优化AI方案的明确方向,大幅提升了迭代效率。

3.2 案例:延迟回复策略的用户范围扩展

业务背景:需要将消息延迟回复服务从原来的平台A、平台B的用户扩展到平台C用户。

原始代码分析:

// TextDelayReplyStrategy.java 中的核心逻辑
private boolean needSkip(ChatHistoryE chatHistoryE) {
    UserDTO UserDTO = UserHelper.parseUser(chatHistoryE.getUserId());
    return MessageSendDirectionEnum.CLIENT_SEND.value != chatHistoryE.getMessageStatus()
               || MessageShieldEnum.RECEIVER_SHIELD.value == chatHistoryE.getShield()
               || UserDTO == null
               || !UserType.isLoginUser(UserDTO.getUserType());  // 关键判断逻辑
}

这个needSkip方法决定了哪些用户类型需要跳过延迟回复处理。原逻辑中,UserType.isLoginUser()只覆盖平台A、平台B的登录用户,不包括平台C用户。

修改前的安全网构建:

按照“分析-测试-实施-验证”方法论,首先完善单元测试:

// 针对现有逻辑的保护性测试
@Test
public void testNeedSkipWithAUser() {
    // 平台A用户不应被跳过
    ChatHistoryE chatHistory = buildChatHistory(A_USER_ID);
    assertFalse(strategy.needSkip(chatHistory));
}

@Test
public void testNeedSkipWithBUser() {
    // 平台B用户不应被跳过
    ChatHistoryE chatHistory = buildChatHistory(B_USER_ID);
    assertFalse(strategy.needSkip(chatHistory));
}

@Test
public void testNeedSkipWithCUser() {
    // 平台C在修改前应被跳过
    ChatHistoryE chatHistory = buildChatHistory(C_USER_ID);
    assertTrue(strategy.needSkip(chatHistory));  // 修改前的预期行为
}

@Test
public void testNeedSkipWithGuestUser() {
    // 游客用户应被跳过
    ChatHistoryE chatHistory = buildChatHistory(GUEST_USER_ID);
    assertTrue(strategy.needSkip(chatHistory));
}

运行基线测试:确保所有测试通过,建立基线状态

[INFO] Tests run: 15, Failures: 0, Errors: 0, Skipped: 0
[INFO] 所有现有逻辑测试通过,可以安全修改

AI辅助修改实施:

向AI提供需求:”将平台C用户也纳入延迟回复服务范围”

AI分析代码后给出修改方案:

// 修改后的代码
private boolean needSkip(ChatHistoryE chatHistoryE) {
    UserDTO UserDTO = UserHelper.parseUser(chatHistoryE.getUserId());
    return MessageSendDirectionEnum.CLIENT_SEND.value != chatHistoryE.getMessageStatus()
               || MessageShieldEnum.RECEIVER_SHIELD.value == chatHistoryE.getShield()
               || UserDTO == null
               || !UserType.isAorBorCLoginUser(UserDTO.getUserType());  // 扩展用户范围
}

验证阶段的精准反馈:

修改后运行测试集:

# 运行结果
[INFO] Tests run: 15, Failures: 1, Errors: 0, Skipped: 0
[ERROR] testNeedSkipWithCProviderUser: expected:<true> but was:<false>

结果分析:

✅ testNeedSkipWithAUser - 通过(平台A用户逻辑未变)
✅ testNeedSkipWithBUser - 通过(平台B用户逻辑未变)
❌ testNeedSkipWithCUser - 失败(平台C预期的变更)
✅ testNeedSkipWithGuestUser - 通过(游客用户逻辑未变)

更新期望值:

@Test
public void testNeedSkipWithCUser() {
    // 修改后:平台C不应被跳过
    ChatHistoryE chatHistory = buildChatHistory(C_USER_ID);
    assertFalse(strategy.needSkip(chatHistory));  // 更新期望值
}

最终验证:

[INFO] Tests run: 15, Failures: 0, Errors: 0, Skipped: 0
[INFO] 所有测试通过,修改安全完成

这种方法将开发者从“担心AI改坏代码”的不信任中解放出来,明确知道哪些功能被影响,哪些保持不变,实现安全、高效的存量代码演进。

四、策略三:TDD思想驱动AI开发

4.1 “先生成,后验证”的局限

前面两节所提到的策略可以归类为”先生成,后验证”,在一定的场景下仍然存在两个问题:

  • 提示词驱动:开发者反复修改自然语言描述,AI产出不确定,返工频繁;
  • 肉眼审查:生成测试用例仍然需要人工验证,一旦用例较多,效率依然低下。

4.2 TDD模式的革命性转变

TDD 核心理念:

  • 测试先行:先写测试,再写实现代码。
  • 小步快跑:以微小增量推进开发,每次只解决一个问题。
  • 设计驱动:测试即需求文档,驱动接口设计和代码结构。
  • 安全网:测试集提供即时反馈,支持安全重构。

整个开发过程严格遵循 Red -> Green -> Refactor 的循环。

  • 🔴 Red: 先编写一个失败的单元测试,用代码来定义我们期望实现的功能。
  • 🟢 Green: 编写最精简的业务代码,让测试恰好通过。
  • 🔵 Refactor: 在测试持续通过的前提下,重构优化代码的设计和质量。

借助测试驱动开发(TDD)思想,我们先为AI提供一份清晰、无歧义的“需求说明书”和“验收标准”,然后指导它进行代码的生成。这个过程的核心是“🔴 红-🟢 绿-🔵 重构”循环,它将我们的每一次的对话,都转化为一次可验证的、可累加的进步。采用“先验证,后实现”的红-绿-重构循环,将模糊的需求转化为精确的代码语言。

4.3 案例:优惠券使用规则引擎的复杂逻辑

业务需求:开发一个智能优惠券使用规则引擎,支持”多券叠加使用和最优组合推荐”

传统困难

  • 自然语言描述:“实现优惠券规则引擎,支持多种券类型的叠加使用,并智能推荐最优使用方案”
  • AI需要猜测:哪些券可以叠加?什么是“最优”?有哪些使用限制?
  • 反复沟通:多次修改提示词,AI理解仍然偏离业务实际

第一次尝试:AI理解为“简单累加所有优惠”

// AI第一次实现 - 过于简化
public BigDecimal calculateDiscount(Order order, List<Coupon> coupons) {
    return coupons.stream()
        .map(coupon -> coupon.getDiscountAmount())
        .reduce(BigDecimal.ZERO, BigDecimal::add);
}
// 问题:忽略了券的使用条件、互斥规则、叠加限制

第二次尝试:AI理解为“选择面额最大的券”

// AI第二次实现 - 逻辑错误
public List<Coupon> selectOptimalCoupons(Order order, List<Coupon> availableCoupons) {
    return availableCoupons.stream()
        .filter(coupon -> order.getTotalAmount().compareTo(coupon.getMinOrderAmount()) >= 0)
        .max(Comparator.comparing(Coupon::getDiscountAmount))
        .map(List::of)
        .orElse(Collections.emptyList());
}
// 问题:只考虑单券最大优惠,未考虑多券组合的更优效果

第三次尝试:AI尝试复杂逻辑但引入更多问题

// AI第三次实现 - 逻辑混乱
public CouponUsageResult applyCoupons(Order order, List<Coupon> coupons) {
    // 各种复杂的if-else嵌套,但缺乏清晰的业务规则
    // 没有处理券的互斥关系
    // 没有考虑计算顺序对最终优惠的影响
    // 边界条件处理不当
}

经过多轮提示词优化,每次都需要重新解释复杂的业务规则,仍不满足预期。

TDD方式的完整循环:

🔴 红色阶段:用测试定义需求

编写测试用例,精确定义复杂的业务规则:

@Test
public void testCouponUsageWithBasicStackingRules() {
    // 构造订单:总价100元,包含数码产品
    Order order = new Order()
        .setTotalAmount(new BigDecimal("100.00"))
        .addItem("数码产品", new BigDecimal("100.00"));
    
    // 构造可用优惠券
    List<Coupon> availableCoupons = Arrays.asList(
        new Coupon().setType("满减券").setCondition("满50减10").setDiscountAmount(new BigDecimal("10")),
        new Coupon().setType("打折券").setCondition("数码类9折").setDiscountRate(new BigDecimal("0.9")),
        new Coupon().setType("免邮券").setCondition("免运费").setDiscountAmount(new BigDecimal("5"))
    );
    
    // 期望结果:满减券和免邮券可叠加,打折券与满减券互斥,应选择最优组合
    CouponUsageResult result = CouponEngine.calculateOptimalUsage(order, availableCoupons);
    
    // 验证最优方案:使用打折券+免邮券 (90+0=90元,比满减券+免邮券的85元更优)
    assertEquals(2, result.getUsedCoupons().size());
    assertTrue(result.getUsedCoupons().stream().anyMatch(c -> "打折券".equals(c.getType())));
    assertTrue(result.getUsedCoupons().stream().anyMatch(c -> "免邮券".equals(c.getType())));
    assertEquals(new BigDecimal("95.00"), result.getFinalAmount()); // 100*0.9 + 0 - 5运费
}

@Test  
public void testCouponMutualExclusionRules() {
    Order order = new Order().setTotalAmount(new BigDecimal("200.00"));
    
    List<Coupon> availableCoupons = Arrays.asList(
        new Coupon().setType("满减券").setCondition("满100减30").setDiscountAmount(new BigDecimal("30")),
        new Coupon().setType("打折券").setCondition("全场8折").setDiscountRate(new BigDecimal("0.8")),
        new Coupon().setType("新用户专享").setCondition("首单5折").setDiscountRate(new BigDecimal("0.5"))
    );
    
    CouponUsageResult result = CouponEngine.calculateOptimalUsage(order, availableCoupons);
    
    // 验证互斥规则:新用户券与其他券互斥,且优惠最大,应该单独使用
    assertEquals(1, result.getUsedCoupons().size());
    assertEquals("新用户专享", result.getUsedCoupons().get(0).getType());
    assertEquals(new BigDecimal("100.00"), result.getFinalAmount()); // 200 * 0.5
}

@Test
public void testCouponUsageConditionValidation() {
    Order order = new Order()
        .setTotalAmount(new BigDecimal("30.00"))
        .setUserLevel("普通用户")
        .addItem("服装", new BigDecimal("30.00"));
    
    List<Coupon> availableCoupons = Arrays.asList(
        new Coupon().setCondition("满50减10"), // 不满足金额条件
        new Coupon().setCondition("VIP专享9折"), // 不满足用户等级条件  
        new Coupon().setCondition("数码类8折"), // 不满足品类条件
        new Coupon().setCondition("无门槛5元券").setDiscountAmount(new BigDecimal("5")) // 满足条件
    );
    
    CouponUsageResult result = CouponEngine.calculateOptimalUsage(order, availableCoupons);
    
    // 验证条件判断:只有无门槛券可用
    assertEquals(1, result.getUsedCoupons().size());
    assertEquals("无门槛5元券", result.getUsedCoupons().get(0).getCondition());
    assertEquals(new BigDecimal("25.00"), result.getFinalAmount());
}

运行测试:

[ERROR] testCouponUsageWithBasicStackingRules: 
Class CouponEngine doesn't exist
[ERROR] testCouponMutualExclusionRules:
Method calculateOptimalUsage not found

红色阶段成功:测试失败,但复杂的业务规则已经通过代码精确表达。

🟢 绿色阶段:AI精确实现

将失败的测试用例提供给AI:“请实现CouponEngine.calculateOptimalUsage方法,让这些测试通过”

AI分析测试用例后,精确理解了复杂的业务规则:

  1. 券类型包括满减券、打折券、免邮券、新用户券等
  2. 不同券有不同的叠加和互斥规则
  3. 需要验证使用条件(金额、用户等级、商品类别)
  4. 要计算最优的券使用组合

AI生成的实现方案:

public class CouponEngine {
    public static CouponUsageResult calculateOptimalUsage(Order order, List<Coupon> availableCoupons) {
        // 1. 过滤出满足使用条件的券
        List<Coupon> eligibleCoupons = availableCoupons.stream()
            .filter(coupon -> isEligible(order, coupon))
            .collect(Collectors.toList());
        
        // 2. 生成所有可能的券组合(考虑互斥规则)
        List<List<Coupon>> validCombinations = generateValidCombinations(eligibleCoupons);
        
        // 3. 计算每种组合的最终优惠,选择最优方案
        return validCombinations.stream()
            .map(combination -> calculateResult(order, combination))
            .min(Comparator.comparing(CouponUsageResult::getFinalAmount))
            .orElse(new CouponUsageResult(order.getTotalAmount(), Collections.emptyList()));
    }
    
    private static boolean isEligible(Order order, Coupon coupon) {
        String condition = coupon.getCondition();
        
        // 金额条件检查
        if (condition.contains("满") && condition.contains("减")) {
            BigDecimal minAmount = extractMinAmount(condition);
            if (order.getTotalAmount().compareTo(minAmount) < 0) return false;
        }
        
        // 用户等级检查
        if (condition.contains("VIP") && !"VIP用户".equals(order.getUserLevel())) {
            return false;
        }
        
        // 商品类别检查
        if (condition.contains("数码类") && !order.hasCategory("数码产品")) {
            return false;
        }
        
        return true;
    }
    
    private static List<List<Coupon>> generateValidCombinations(List<Coupon> coupons) {
        List<List<Coupon>> combinations = new ArrayList<>();
        
        // 生成所有子集组合
        for (int i = 0; i < Math.pow(2, coupons.size()); i++) {
            List<Coupon> combination = new ArrayList<>();
            for (int j = 0; j < coupons.size(); j++) {
                if ((i & (1 << j)) != 0) {
                    combination.add(coupons.get(j));
                }
            }
            
            // 检查组合是否符合互斥规则
            if (isValidCombination(combination)) {
                combinations.add(combination);
            }
        }
        
        return combinations;
    }
    
    private static boolean isValidCombination(List<Coupon> combination) {
        // 检查互斥规则
        boolean hasDiscountCoupon = combination.stream().anyMatch(c -> "打折券".equals(c.getType()));
        boolean hasReduceCoupon = combination.stream().anyMatch(c -> "满减券".equals(c.getType()));
        boolean hasNewUserCoupon = combination.stream().anyMatch(c -> "新用户专享".equals(c.getType()));
        
        // 新用户券与其他券互斥
        if (hasNewUserCoupon && combination.size() > 1) {
            return false;
        }
        
        // 打折券与满减券互斥
        if (hasDiscountCoupon && hasReduceCoupon) {
            return false;
        }
        
        return true;
    }
    
    private static CouponUsageResult calculateResult(Order order, List<Coupon> usedCoupons) {
        BigDecimal finalAmount = order.getTotalAmount();
        
        // 按照优先级顺序应用优惠
        for (Coupon coupon : usedCoupons) {
            if ("打折券".equals(coupon.getType())) {
                finalAmount = finalAmount.multiply(coupon.getDiscountRate());
            } else if ("满减券".equals(coupon.getType()) || "无门槛5元券".equals(coupon.getCondition())) {
                finalAmount = finalAmount.subtract(coupon.getDiscountAmount());
            } else if ("免邮券".equals(coupon.getType())) {
                // 免邮券单独处理运费
                finalAmount = finalAmount.subtract(coupon.getDiscountAmount());
            }
        }
        
        return new CouponUsageResult(finalAmount, usedCoupons);
    }
}

运行测试:

[INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0
[INFO] All tests passed!

绿色阶段成功:测试通过,复杂的业务逻辑完全正确。

🔵 重构阶段:优化代码质量

在测试保护下,对AI生成的代码进行质量优化:

public class CouponEngine {
    // 提取常量,增强可读性
    private static final Set<String> MUTUALLY_EXCLUSIVE_TYPES = Set.of("打折券", "满减券");
    private static final String NEW_USER_COUPON_TYPE = "新用户专享";
    
    public static CouponUsageResult calculateOptimalUsage(Order order, List<Coupon> availableCoupons) {
        if (CollectionUtils.isEmpty(availableCoupons)) {
            return new CouponUsageResult(order.getTotalAmount(), Collections.emptyList());
        }
        
        // 使用策略模式优化条件验证
        List<Coupon> eligibleCoupons = availableCoupons.stream()
            .filter(coupon -> CouponValidator.isEligible(order, coupon))
            .collect(Collectors.toList());
        
        // 使用组合算法优化券组合生成
        List<List<Coupon>> validCombinations = CouponCombinator.generateValidCombinations(eligibleCoupons);
        
        // 使用计算引擎优化折扣计算
        return validCombinations.stream()
            .map(combination -> DiscountCalculator.calculateResult(order, combination))
            .min(Comparator.comparing(CouponUsageResult::getFinalAmount))
            .orElse(new CouponUsageResult(order.getTotalAmount(), Collections.emptyList()));
    }
}

// 职责分离:券验证器
class CouponValidator {
    public static boolean isEligible(Order order, Coupon coupon) {
        return AmountValidator.validate(order, coupon) &&
               UserLevelValidator.validate(order, coupon) &&
               CategoryValidator.validate(order, coupon);
    }
}

// 职责分离:券组合器
class CouponCombinator {
    public static List<List<Coupon>> generateValidCombinations(List<Coupon> coupons) {
        return PowerSetGenerator.generate(coupons).stream()
            .filter(MutualExclusionChecker::isValidCombination)
            .collect(Collectors.toList());
    }
}

// 职责分离:折扣计算器
class DiscountCalculator {
    public static CouponUsageResult calculateResult(Order order, List<Coupon> usedCoupons) {
        // 按优先级排序券,确保计算顺序正确
        List<Coupon> sortedCoupons = usedCoupons.stream()
            .sorted(Comparator.comparing(CouponPriorityResolver::getPriority))
            .collect(Collectors.toList());
        
        BigDecimal finalAmount = order.getTotalAmount();
        
        for (Coupon coupon : sortedCoupons) {
            finalAmount = applyCouponDiscount(finalAmount, coupon);
        }
        
        return new CouponUsageResult(finalAmount, usedCoupons);
    }
    
    private static BigDecimal applyCouponDiscount(BigDecimal currentAmount, Coupon coupon) {
        return CouponTypeHandler.getHandler(coupon.getType())
            .applyDiscount(currentAmount, coupon);
    }
}

重构验证:

[INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0
[INFO] 重构完成,测试持续通过,代码结构更清晰,职责分离更明确

协作模式转变:开发者不再需要为如何描述复杂的业务规则而烦恼,现在只需专注于设计精确的测试场景——我们负责定义“做什么”和“预期结果”,而AI则负责实现具体的“怎么做”。这种明确的分工让复杂逻辑的开发变得既可控又高效。

通过这种方式,我们能够确保:

  1. 需求表达精准无歧义
  2. 边界条件全面覆盖
  3. 实现过程完全可控
  4. 重构过程安全可靠

当需要开发新场景时,只需新增测试用例即可,完全不必担心会破坏原有逻辑。这种开发模式不仅提升了效率,更确保了系统的稳定性和可维护性。

五、实践要点

5.1 环境配置

确保AI Agent能执行mvn test命令

设定明确的行为准则(Rule),让AI能够知道我们现在遵循的开发范式,防止AI为了通过测试”作弊”修改业务代码。一个借助TDD思想驱动代码生成的执行准则如下

# AI Agent 行为准则:TDD 测试驱动开发

## 1. 总则

### 1.1. 概述
为了确保 AI Agent 遵循 TDD(测试驱动开发)的开发模式,Agent 必须严格按照 **Red-Green-Refactor** 三个阶段的循环进行开发。在执行每个阶段前,Agent 必须向开发者明确声明其当前所处的阶段。

本准则旨在确保 Agent 遵循正确的 TDD 开发流程,避免跳过关键步骤。

### 1.2. 环境配置:强制使用指定的 settings.xml
**核心要求**: 所有对 `mvn@ 命令的调用(如 mvn test@, mvn compile@ 等),都**必须**使用 --settings@ (或 -s@) 参数来指定一个自定义的 settings.xml` 文件,以确保能够访问内部的 Maven 仓库。

- **命令格式示例**: `mvn --settings [settings.xml的绝对路径] test`
- **`settings.xml` 文件路径**: `[settings.xml的绝对路径]`

Agent 在执行任何 Maven 命令前,必须确认此路径已被正确配置和使用。

---

## 2. TDD 三阶段循环

### 2.1. 第一阶段:RED (写失败的测试)

#### 2.1.1. 目标
编写一个**必然失败**的测试用例,明确定义即将实现的功能需求。

#### 2.1.2. 核心准则
- **允许**: Agent 可以在 `src/test/` 目录下创建新的测试文件或添加新的测试方法
- **要求**:
  - 测试必须是失败的(因为对应的实现代码尚未存在或不完整)
  - 一次只测试一个功能点
  - 测试代码要简单清晰
  - 测试名称要明确表达测试意图
- **禁止**: Agent **不能**修改 `src/main/` 目录下的任何现有代码
- **验证**: 运行测试必须显示红色(失败状态)

#### 2.1.3. 交互示例
- **开发者提示**: "我需要实现一个计算器的加法功能"
- **Agent 回应**: "已激活 **RED 阶段**。我将先编写一个失败的测试用例来定义加法功能的需求。"

### 2.2. 第二阶段:GREEN (让测试通过的最简实现)

#### 2.2.1. 目标
编写**最简单**的实现代码,让当前失败的测试通过。

#### 2.2.2. 核心准则
- **允许**: Agent 可以创建、修改 `src/main/` 目录下的代码
- **要求**:
  - 优先考虑最简单的实现方式
  - 专注于满足当前测试用例
  - 快速实现功能让测试通过
- **禁止**:
  - **不能**修改测试代码
  - **不考虑**代码质量和性能优化
  - **不进行**过度设计
- **验证**: 运行测试必须显示绿色(通过状态)

#### 2.2.3. 交互示例
- **Agent 回应**: "已激活 **GREEN 阶段**。我将实现最简单的代码来让刚才的测试通过,不考虑优化和设计。"

### 2.3. 第三阶段:REFACTOR (重构优化)

#### 2.3.1. 目标
在保持测试通过的前提下,改进代码的设计、质量和可维护性。

#### 2.3.2. 核心准则
- **允许**: Agent 可以重构 `src/main/` 目录下的实现代码
- **要求**:
  - 改进代码设计和质量
  - 消除重复代码
  - 提高代码可读性和可维护性
  - 每次重构后必须运行测试确保通过
- **禁止**:
  - **不能**修改测试的行为和期望
  - **不能**破坏现有功能
- **验证**: 重构过程中和完成后,所有测试必须保持绿色

#### 2.3.3. 交互示例
- **Agent 回应**: "已激活 **REFACTOR 阶段**。我将重构代码以提高质量,同时确保所有测试保持通过状态。"

---

## 3. TDD 最佳实践

### 3.1. 循环节奏
- **小步快走**: 每个 Red-Green-Refactor 循环应该很短(几分钟到十几分钟)
- **频繁验证**: 每个阶段完成后都要运行测试验证
- **逐步推进**: 一次只关注一个小功能点

### 3.2. 测试质量要求
- **快速执行**: 单元测试应该在秒级内完成
- **独立性**: 测试之间不应该有依赖关系
- **可重复性**: 测试结果应该是确定的和可重复的
- **清晰命名**: 测试方法名应明确表达测试意图

### 3.3. 代码质量保证
- **持续重构**: 在每个循环的 REFACTOR 阶段改进代码
- **消除重复**: 遵循 DRY(Don't Repeat Yourself)原则
- **保持简洁**: 代码应该简洁明了,易于理解

### 3.4. 流程控制
Agent 在每个阶段转换时,必须:
1. 明确声明即将进入的阶段
2. 说明当前阶段的具体目标
3. 完成阶段后验证结果
4. 确认是否继续下一个循环

5.2 掌握单测语法

AI擅长基础用例覆盖,但复杂业务场景、边界条件仍有可能需要开发者手动编写。不要完全依赖AI构造用例。

5.3 选择合适场景与策略

快速决策法则:

  • 简单功能:单个方法,逻辑直观,采用“先实现,后验证”;
  • 复杂业务逻辑:多分支判断、算法计算、状态转换,采用TDD“先验证,后实现”;
  • 存量代码修改:采用“安全网保护”策略;
  • 提示词难以描述需求时:测试用例是最好的需求文档,采用TDD让代码直接表达需求。

5.4 持续维护

单元测试必须与业务代码演进保持同步。一个过时的、无人维护的测试集,其价值会迅速归零,甚至成为负资产。

六、结语

如今,单元测试已被赋予全新的意义——它不再被视为一种“开发负担”,而是进化成为AI Coding时代的“质量引擎”。

我们构建起三重关键保障:

  • 策略一:以客观检验替代主观判断,让AI代码告别“看起来没问题”的错觉;
  • 策略二:为存量代码筑起防护墙,使修改存量代码安全可控,降低演进风险;
  • 策略三:用测试作为与AI的沟通语言,精准传递复杂需求与预期。

更深层次的变化在于,我们正在重新定义开发者的核心价值:当我们从“思考提示词”转向“思考测试用例”,本质上是从AI代码被动的审查者,转变为了主动的需求设计者与质量掌控者。这不仅加速开发进程,更显著提升代码质量。这正是AI时代中,开发者与智能工具协同进化的优秀范式。

整理 | 华卫、Tina

过去一年,编码 Agent 的变化速度,已经快到让人很难用“功能升级”来形容。

如果把时间拨回到一年前,Agent 还主要停留在代码补全、对话式改几行代码的阶段;而今天,在 Cursor 内部,工程师已经开始同时运行多个 Agent 并行“甩活儿”,让它们在代码库中自主修改、调试、复盘,再由人类在最后阶段集中审核结果。开发者不再盯着 Agent 的每一步操作,而是开始习惯“等它跑完再看答案”。

在最近一次访谈中,Cursor 工程负责人 Jason Ginsberg 给出了一个明确判断:这不是渐进式优化,而是一场正在发生的“换代”。更重要的是,他把这场变化的时间窗口,压缩到了未来三到六个月——在他看来,Agent 将不只是“更聪明”,而是会真正接管更长周期、更复杂的工程任务,整个行业的工作方式也将随之重塑。

下面是详细对话内容,我们在不改变原意的基础上进行了翻译和删减,以飨读者。

一年多时间,编码 Agent“翻天覆地”

Harrison Chase:Jason,你能跟大家简单介绍一下自己吗?也给大家讲讲 Cursor 是什么吧。

 

Jason Ginsberg:好的。我目前在做一款 AI 编程工具,已经在 Cursor 工作了六个月,担任该产品的工程负责人。不过说实话,我日常的大部分时间还是在写代码和做设计工作。在加入 Cursor 之前,我在 Notion 负责 Notion Mail 相关工作。几年前,我创办了一家名为 Skiff 的公司,后来这家公司被 Notion 收购了。所以,我一直都在从事产品开发相关的工作,而且主要聚焦在生产力工具领域。

 

Harrison Chase:非常棒。我有很多话题想和你探讨。要不我先抛砖引玉,问问你对编码 Agent 的发展历程,以及这些年来人机交互模式演变的看法吧。你们可以说是这个领域的先行者之一,我认为编码 Agent 的发展经历了几个阶段的转变:从最初的代码自动补全,到集成在集成开发环境(IDE)中的对话式交互,再到如今出现的各类终端工具,以及基于云端的异步 Agent。我很想听听你的看法,你觉得这样概括其用户体验的演变历程是否准确?或者你们团队是如何看待这一发展过程的?

 

Jason Ginsberg:我认为编码 Agent 的发展确实可以用 “翻天覆地” 来形容,而且这些变革基本上都是在一年多一点的时间里发生的。正如你所说,Cursor 最早开启了代码自动补全的先河,这种模式主要是在逐行的层面上提供辅助,适用范围也基本局限在单个文件内。而此后,几乎每隔几个月,我们就不得不提升产品的抽象层级,这其实是一个极具挑战性的产品设计难题。显然,Agent 的出现让开发者能够在多个文件之间灵活切换,并且可以放心地让 Agent 自主完成代码修改工作。

 

在过去两个月左右的时间里,我发现行业又出现了新的转变:开发者现在已经能够做到从项目启动到结束全程信任 Agent,并且会对整个代码库中多个文件的内容进行批量审核。因此,我们不得不对产品的整体布局进行大幅重新设计,将核心从逐行的代码差异对比,转向更偏向代码审查的模式。

 

展望未来的产品开发方向,我们的工作重心其实会更多地放在多 Agent 协同运行上。我们需要实现的是,能够快速验证这些 Agent 是否在正常运行,并且可以让它们并行工作,同时避免受到当前单一对话模式下各种选项和选择的束缚。

 

Harrison Chase:推动这些变革的核心因素是什么?仅仅是因为大模型的性能变得越来越好,还是有其他更多的影响因素?

 

Jason Ginsberg:我认为大模型性能的提升是一个很关键的因素,这让开发者能够更加信任 Agent 编写的代码质量。要知道,以前大家必须对 Agent 生成的代码进行非常全面细致的审查。

同时,现在也有了更完善的代码审查工具。比如我们有 BugBot,市场上其实还有很多类似的工具,它们都能够自动检查代码中存在的问题。

 

此外,我觉得从行业文化层面来看,开发者们对 Agent 工具的接受度和使用信心也在不断增强,甚至可以说已经 “上瘾” 于这类工具带来的便捷。而且,一旦习惯了完全依赖 Agent 进行编码的工作模式,再切换回传统的编码方式其实是很困难的。所以现在,我们能看到越来越多的开发者已经将 Agent 辅助编程作为默认的工作方式。

最顶尖工程师的干活秘诀:全靠 Agent?

Harrison Chase:你观察到大家使用 Cursor 的方式都有哪些不同?或者你自己平时是怎么使用 Cursor 的?

 

Jason Ginsberg:其实在我们公司内部,工程师们使用 Cursor 的方式就五花八门。甚至团队里有几位工程师,他们完全不使用 Cursor 的 Agent 功能,比如负责安全和基础设施的同事。所以,确实有一部分用户非常依赖代码自动补全功能,日常使用中大部分操作都是基于补全功能完成的。但令人意外的是,我发现团队里一些最顶尖的工程师,我们称他们为 “核心用户”,他们做任何工作都会完全依赖 Agent,甚至会同时运行多个 Agent 并行处理任务。

 

至于我个人的使用习惯,我并不会去设计那些复杂繁琐的提示词,也没有什么所谓的 “Agent 使用秘籍”。我写的提示词往往都很简短,甚至还会带有拼写错误。我会针对手头不同的工作任务,或者同一个问题的不同模块,同时启动多个 Agent,然后等待它们返回结果。

 

目前我用得最多的是我们今天刚刚发布的一个新功能:调试模式。这个模式下,Agent 能够通过生成日志来进行自我评估,之后开发者复现相关操作步骤,Agent 就会通过查看日志判断问题是否得到解决。这个功能非常实用,因为它相当于通过投入算力去不断尝试解决问题,最终攻克那些手动排查起来极为棘手的难题。

 

Harrison Chase:调试模式具体是什么样的?为什么需要专门设置这样一个模式?难道不能自动完成调试吗?直接给 Agent 下达调试指令不也可以吗?

 

Jason Ginsberg:其实我也认同你的这个想法。所以在开发调试模式的时候,我们内部确实有过不少争论。主要原因在于,Cursor 目前已经有很多功能模式了,如规划模式、询问模式等等,这些模式其实不太容易被用户发现。我们一直认为,这些模式都很实用,理想的状态应该是,Agent 能够根据用户的操作场景,自动匹配并启用最合适的模式,无需用户手动切换。

 

而现阶段调试模式之所以需要手动开启,是因为它的交互方式比较特殊。在运行过程中,Agent 会暂停当前的工作,向用户提问以获取反馈。如果用户不熟悉这种交互逻辑,可能会觉得比较困扰。

 

Harrison Chase:Agent 具体会询问哪些问题,又需要用户提供什么样的反馈呢?

 

Jason Ginsberg:我举个例子吧。假设我正在开发一个前端应用,遇到了一个很让人头疼的问题:菜单总是在左上角弹出。这时候我会对Agent说:“这个菜单需要锚定到按钮的位置。” 随后,Agent 会启动服务器,并在整个代码库中添加大量日志,同时提出一系列可能导致该问题的假设,如 “可能是某个定位参数设置错误”、“可能是事件绑定逻辑有问题” 等。之后,Agent 会提示我:“麻烦你点击这个按钮,打开菜单,看看问题是否解决。” 如果我反馈问题依然存在,Agent 就会查看生成的日志,然后分析判断:“这个假设成立,那两个假设不成立”。通常这样反复两三次之后,Agent 往往就能找出并解决问题。

 

Harrison Chase:你觉得人类还需要手动操作多久?就不能让 Agent 自主完成点击、测试这类操作吗?

 

Jason Ginsberg:一两个月内,毕竟这个行业的发展速度实在太快了。

 

Harrison Chase:刚才你提到了 Agent 的多种不同模式,比如规划模式、解释模式、调试模式等等。这些模式在实际应用中到底意味着什么?难道只是为 Agent 设置不同的提示词这么简单吗?还是说背后有更复杂的逻辑?

 

Jason Ginsberg:很多时候,确实就是修改一下系统层面的提示词。不过在某些情况下,我们也需要对用户界面进行相应的调整。比如规划模式现在也加入了交互提问功能,运行过程中会主动打断用户操作,寻求反馈。用户有时也可以自行设置参数,如调整 Agent 打断的频率等。再比如询问模式,它不只是依赖特定的系统提示词,还会限制 Agent 调用某些与文件编辑相关的工具,以此来保证功能的稳定性和可靠性。

 

Harrison Chase:回到之前的话题,关于大家使用 Cursor 的不同方式,你觉得未来使用编码 Agent 或者说 Cursor,存在所谓的 “最佳方式” 吗?

 

Jason Ginsberg:我觉得并没有什么 “最佳方式”,具体的使用方法很大程度上取决于工程师的个人工作习惯以及他们所处理的具体工作内容。目前行业里,既有异步运行Agent的应用场景,也有开发者深度参与、实时交互的模式,就像一边编程、一边像画画一样实时调整代码或者进行可视化的编辑操作。不过我经常在推特上看到一些所谓的 “Agent 使用技巧”,其实对此我是有点持保留态度的。很多人会说 “这才是使用 Agent 的最佳方式”,但在我看来,这些技巧往往是凭空杜撰的。

 

我们团队内部其实并不会使用那些冗长复杂的提示词,也不会采用多阶段规划的策略。大多数时候,我们都是快速迭代,如果 Agent 运行的结果不理想,就直接终止进程,重新启动 Agent。通常这种方式的效率是最高的。

自然 “唠嗑”是 Cursor 最终交互模式?

Harrison Chase:如果让你预测一下一年后的情况,你认为开发者在 IDE、终端以及其他形态的载体上使用 Cursor 的时间占比会是怎样的?

 

Jason Ginsberg:当然,我肯定会带有一定的主观偏向性。但我认为,终端工具并不会成为用户的首选。我觉得,真正驱动行业发展的是用户对Agent的信任度不断提升,他们更希望等到Agent完成所有工作后再查看最终的修改结果,然后决定是否采纳,同时也愿意让 Agent 运行更长的时间,以实现更智能的处理。

 

而 IDE 之所以至关重要,是因为它是为整个软件开发周期量身打造的工具。从项目的构思规划,到运行代码修改、查看代码内容、清晰对比代码差异、提交代码合并请求,再到在浏览器中预览效果所有这些环节,都可以无缝集成在 IDE 的模块化功能之中。这一点其实很容易被忽视,毕竟 IDE 的这些功能是经过了数十年的发展才逐步完善起来的。

 

我认为,当前行业的一个明显趋势是,产品层面的设计变得越来越重要。现在 Cursor 用户使用频率最高的功能,如规划模式,其实都需要可视化编辑器的支持,用户需要能够在编辑器中添加注释,并进行实时交互。一旦脱离了按钮、弹窗和菜单这些可视化交互元素,用户与工具的交互难度会大大增加。

 

不过,我觉得未来并非所有操作都必须局限在笔记本电脑的 IDE 中完成。这种模式并不会被完全取代,具体的使用场景会根据实际需求灵活变化,适用的场景也会更加广泛。用户在更多场景下,都能够使用到 Cursor 这样的工具。

 

Harrison Chase:未来会有更多场景都能用上像 Cursor 这样的工具。你们应该有对应的官网吧?用户可以直接在网页上进行交互操作,是这个思路吗?

 

Jason Ginsberg:对,我们确实有官网。这么做的原因是用户可以通过手机等设备随时随地访问。我觉得在不远的将来,用户完全可以戴着 AirPods,开启语音模式,和Agent实时沟通、碰撞想法,让Agent不断优化方案。等用户到了办公室,打开笔记本电脑,就已经有一堆代码修改记录或者演示视频等着审核了,到时候只需要简单确认通过或者驳回就行。如果某些细节还需要微调,再把项目下载到本地修改就好。

 

Harrison Chase:我认为 Cursor 真正的优势,在于围绕 Agent 交互打造的整套设计和用户体验体系。你之前在 Notion 工作过,我记得即便是在生成式 AI 普及之前,Notion 的设计和用户体验就已经广受认可了。当然,他们在生成式 AI 时代也很好地完成了转型。从一家在生成式 AI 普及前就拥有出色设计积淀且顺利完成转型的公司,再到如今专注 Agent 相关工作,你觉得 Agent 的出现给产品设计和用户体验带来了哪些变化?现在的工作模式和之前有相似之处吗?

 

Jason Ginsberg:我觉得总体来说,我们产品的大部分设计其实并不是 AI 专属的。要知道,产品可用的交互组件和用户体验模式就那么多,市面上的应用本质上也都是基于一些传统的模式搭建的,如收件箱、仪表盘、聊天界面,这些都是很成熟的设计。所以我们的工作核心,更多是把这些现有的设计模式进行合理组合,然后在产品中恰当地呈现出来。这一点和 Notion 的产品理念是相通的,同时也是 Cursor 和集成开发环境(IDE)的核心特质:极高的模块化程度。

 

作为用户,你会发现每个人的 IDE 界面布局都可以千差万别。你可以自定义面板布局,把任意组件拖放到任意位置,和坐在你旁边的同事设置出完全不同的界面。我认为这种模块化设计对产品的适应性至关重要,毕竟如我之前所说,Agent 的能力发展日新月异,用户对产品的需求和期待几乎每隔几周就会发生变化。几个月前我们推出 Cursor 2.0 的时候,并没有把原来的产品推倒重来,只是把各个功能模块重新组合,调整为侧边栏收件箱式的管理布局,同时优化了聊天界面的信息密度而已。

 

Harrison Chase:听你这么说,很多组件的底层逻辑其实是相通的。那有没有出现新的组件?或者某些组件的优先级发生了变化?毕竟这些组件最初都是为 “人类与软件交互”“人类通过软件协作” 的场景设计的,现在加入了 Agent 这个新角色。这其中有没有产生什么新的变化?还是说其实本质上没有太大不同?

 

Jason Ginsberg:我认为底层的设计逻辑和核心要素其实没有变,关键变化在于谁在主导界面交互。而在这个核心框架下,其实可以演变出无数种交互形式。就拿交互的抽象层级来说,一年前大家使用Agent的时候,都恨不得盯着它的每一步操作,全程 “盯梢”。但现在 Agent 的操作步骤变得无比繁杂,用户根本看不过来。所以我们需要优化信息呈现方式:如何对操作步骤进行分组?如何提炼关键信息?

 

当用户足够信任 Agent 的操作后,我们就需要把重点放在文件的实际修改内容上,并且为这些修改添加更详细的注释说明。当然,我们也可以进一步提升交互的灵活度,比如聊天对象不再局限于单个 Agent,而是可以同时和多个 Agent 对话。这就需要一套更智能的后台交互逻辑来支撑 ,系统要能识别用户在和哪个子 Agent 对话,并且协调这些 Agent 完成对应的修改。未来这种交互的抽象层级还会不断提升。

 

Harrison Chase:你觉得交互的抽象层级最高能达到什么程度?我知道预测未来很难,但还是想听听你的看法。

 

Jason Ginsberg:我觉得未来,我们现在看到的各种操作选项,如选择模型、选择功能模式、选择运行环境这些都会逐渐消失。最终的交互模式会变得像和真人对话一样自然。但这并不意味着任何人都能随便写代码,在那个阶段,这个工具依然是为专业工程师服务的。因为你还是需要具备专业的行业术语知识,清楚自己想要修改的内容是什么。做产品的人,要明确自己想要的工作流程和功能需求;做基础设施的人,要足够了解代码库,知道什么样的架构和系统设计最适合当前要开发的项目。

 

而且我想强调的是,随着抽象层级的提升,我们并不会摒弃现有的功能。用户依然可以随时深入底层,查看细节、调整参数。只是产品的默认交互方式会不断优化升级。

Cursor 内部工作揭秘:少审代码、高频反馈

Harrison Chase:你之前提到了人类在 Agent 工作流程中的角色,比如查看代码差异、进行代码审查。你觉得 AI 会给代码审查工作带来哪些改变?

 

Jason Ginsberg:首先,就我们产品团队的工作模式来说,现在人工审查的比重已经大幅降低了。我们有一个叫 BugBot 的工具,它会自动检测代码问题,并且自主完成修复,还会在持续集成(CI)流程中不断迭代优化。这个工具的表现非常出色,也让我们对 AI 审查的代码质量更有信心。

 

其次是信息的语义化分组。用户查看代码差异时,可以清晰地看到 Agent 做了哪些修改。我们甚至可以展示 Agent 的原始指令,更理想的状态是,Agent 能够像人类一样,在处理大型代码合并请求时,为每一处修改附上注释,说明这么做的原因。我觉得这虽然算不上颠覆性的变革,但确实能给代码审查工作带来显著的优化。

 

Harrison Chase:出于好奇,我想问一下,Cursor 的工程师用 Cursor 写代码,用 BugBot 审查代码,那他们还需要和其他工程师沟通协作吗?

 

Jason Ginsberg:哈哈,这个问题很有意思。如果你以工程师的身份加入 Cursor,会立刻发现一个现象:所有人都在深度使用自家产品。我记得我入职第一周的时候,修改了一个快捷键设置。那个快捷键是 Alt+Shift+Command+J,非常冷门,我当时觉得选这个键肯定没人会注意到。结果刚改完不到半分钟,就有三个同事在 Slack 上发来消息:“你改的这个快捷键直接打乱了我的工作流程!到底怎么回事?”几乎任何产品改动,都会立刻收到同事们的强烈反馈。我觉得这其实是一件好事,大家就是在这种高频的反馈和交流中,快速推进产品迭代的。

 

Harrison Chase:从组织管理的角度,你们有没有采取什么措施来鼓励或者引导这种高频反馈的协作模式?毕竟大量的反馈涌进来,有时候也会让人应接不暇。

 

Jason Ginsberg:在我创办自己的公司之前,工程师们也会用邮件沟通,但用得并不多。大家甚至会说:“邮件只用来收垃圾邮件和购物通知,可别用它来发长篇大论的工作内容。”而在Agent这个赛道工作,其实完全不需要依赖邮件这种低效的沟通方式。我们团队的所有人都全身心投入工作,毕竟这是一个竞争非常激烈的领域,大家都对产品开发充满热情,会自然而然地用各种即时沟通工具协作。

 

另外,我在规划产品功能时,会遵循一个核心原则:我能开发什么功能,让自己的日常工作更轻松? 具体来说,就是思考 “做什么能帮我明天更高效地完成工作,不用再处理那些烦人的报错和问题”。这个原则指导着我们的大部分工作。毕竟这种功能开发出来之后,我们自己能立刻受益,比如修复了一个烦人的漏洞,以后上班就不用再被这个问题困扰了。

迭代狂飙背后,核心功能竟来自员工 “自嗨”?

Harrison Chase:你觉得你们的产品路线图,有多大比例是由 “让自己工作更轻松” 这个需求驱动的?又有多大比例是来自外部用户的需求?这个比例随着公司发展有变化吗?

 

Jason Ginsberg:这个比例确实随着公司规模的扩大在变化。现在我们也会制定月度的产品路线图和目标,但说实话,我们很多核心功能都来自自下而上的创新。比如 Cursor 的Agent功能,这可以说是大家提到 Cursor 时最先想到的核心功能。这个功能是我们团队的一个人开发的,最开始所有人都不看好这个想法,但他很快做出了原型。大家试用之后都惊叹:“哇,这东西居然真的能用!”

 

我之前提到的调试模式也是如此。感恩节假期的时候我闲着没事,就开发了这个自己很需要的功能,现在这个功能也即将上线。这些功能的开发初衷,都是为了解决团队内部的需求。我们判断一个功能是否具备发布条件,一个重要的衡量标准就是内部的使用率和认可度。

 

Harrison Chase:你们的产品迭代速度快得惊人,是怎么保持这种高效的开发节奏的?

 

Jason Ginsberg:说实话,我们的工作流程其实非常精简,没有太多繁琐的制度。公司里虽然有几间会议室,也有一两位产品经理,但我们很少通过撰写文档或者开对齐会议来推进工作,大部分的讨论和决策都是在代码层面完成的。而这一切能够实现的核心原因,是我们对人才的极高要求。今年年初的时候,公司总共也就 20 人左右。之所以团队规模增长缓慢,就是因为我们的招聘门槛高到近乎苛刻。我们会反复评估:这个人很优秀,但他能成为团队里最顶尖的那批人吗?

 

正因为团队里的每个人都足够出色,所以我们可以放心地把任务交给任何一个人。团队成员的主观能动性都极强,从提出想法、设计用户体验,到在推特上回复用户的支持请求、和企业客户沟通需求,再到最终将功能落地,整个流程都能独立完成。所以说,我们能保持这样的速度,归根结底还是人的因素。

 

Harrison Chase:你们是如何规划产品路线图的?你刚才提到了以月为单位的规划周期,这是目前的常规规划时长吗?有没有更长期的规划?另外,行业技术迭代的速度实在太快了,你们是如何平衡 “跟进现有技术浪潮” 和 “实现技术跨越式发展” 这两者的?会不会主动预判技术趋势,提前布局未来方向?

 

Jason Ginsberg:我们确实会投入不少精力去思考未来,比如预判未来三个月可能实现的技术突破,然后主动押注相关方向,团队里有相当一部分人都在做这类前瞻性的工作。我们制定的月度路线图更多是围绕核心产品功能展开,聚焦于用户的实际需求以及那些能优化日常使用体验的功能。而那些需要投入两个月时间重构底层逻辑的重大项目,则会纳入更长期的规划范畴。

此外,我们的应变能力其实非常强。

 

有时候我们会提前拿到新模型的测试版本,试用之后如果发现它在某些方面表现特别出色,团队成员往往会主动利用周末时间加班,争取在新模型正式发布前就完成相关功能的开发。很多重要功能其实几天之内就能搭建完成。

 

Harrison Chase:说到模型,你们发布了自研的 Composer 模型。开发这个模型的初衷是什么?目前用户的使用情况如何?这个模型有没有改变大家使用 Cursor 的习惯?

 

Jason Ginsberg:我们发现,工程师使用我们产品时的编码场景,需要有专门适配的模型来支撑。Composer 模型就是针对这类场景打造的,它定位非常明确,具备速度快、质量高、逻辑智能三大特点,尤其适合 “人机实时协作” 场景。我自己做前端开发时就经常用它,因为我需要频繁做出细微的交互设计决策,这就要求 Agent 能在几秒内给出反馈。Composer 就像一个高效的协作伙伴,能快速响应需求、碰撞想法,和那些适用于长周期异步任务的模型形成了很好的互补。

 

Harrison Chase:Cursor 的 Agent 相关研发工作是全员参与,还是有专门的团队负责?

 

Jason Ginsberg:我们确实有专门的团队负责 Agent 的性能优化,他们主要聚焦于工具链、调度框架的搭建以及效果评估。但正如我之前所说,我们的团队架构并不僵化,没有严格限制大家的工作范围。比如核心产品团队的工程师在开发规划模式时,如果需要对Agent进行调整,就会和Agent团队密切协作。而且在开发过程中,我们依然会深度使用自家产品进行测试,团队成员会分享使用感受,以此来评估功能的实际效果。

 

Harrison Chase:无论是 Agent 团队的成员,还是其他团队中擅长 Agent 研发的工程师,他们身上有没有什么共同特质?他们的专业背景或者个人能力有没有什么特别之处?

 

Jason Ginsberg:我觉得他们大多是偏产品方向的人才,而不是传统意义上的机器学习或算法研究专家。这些人经常在不同团队之间轮岗,因为Agent研发需要对用户的最终使用体验有很强的直觉,同时还要能准确解读团队的反馈意见。

 

Harrison Chase:上周你们和 OpenAI 合作发布了一篇博客,内容是针对 OpenAI 的新模型优化 Cursor 的 Agent 调度框架。我在推特上经常看到大家讨论 “Agent 调度框架” 这个概念。你们是如何看待模型的底层支撑架构的?这类架构是否需要和特定模型深度绑定?比如 Composer 模型和 CodeLlama 模型,对应的架构会不会有很大差异?

 

Jason Ginsberg:我其实没有深度参与这方面的工作,但据我了解,我们的核心目标是打造高度灵活的架构。毕竟我们需要不断尝试新技术、新功能模式,所以架构必须能够随着模型能力的升级快速适配。

 

Harrison Chase:很有道理。毕竟整个行业都在飞速变化。

开放问答

提问者 1:刚才提到了新增的可视化浏览器功能,我发现有些工具比如 Lovable 也有类似的功能。请问这个功能是朝着 “沉浸式可视化编码” 的方向发展吗?

 

Jason Ginsberg:我觉得它并不是为沉浸式可视化编码设计的。就像我之前说的,这个功能最初是我为自己开发的,我本身就是一名做产品的工程师,它的核心用户群体其实是专业工程师和设计师。大家在开发应用时,肯定都遇到过这种情况:精心设计的界面,最后却变成了大家都看腻了的紫黄渐变配色。这个功能就是为了让大家能够精准把控细节,比如把内边距调整到精确的像素值。它为用户提供了一套更直观的 “视觉化操作语言”,比纯文本指令的精度更高。

 

而且就算不使用侧边栏,你也可以直接点击页面元素,随时输入提示词下达指令。借助这个功能,你可以在几秒内同时启动六个 Agent。如果开启热重载功能,你的网站会实时呈现修改效果,用起来其实还挺有意思的。

 

提问者 2:我特别喜欢你们的浏览器 Agent,一直在用。但我发现一个小瑕疵:我想持续迭代优化设计方案,可 Agent 总是会中断我的工作,直接提交代码合并请求。未来有没有可能实现不间断的持续迭代?

 

Jason Ginsberg:当然可以。未来的发展方向就是让 Agent 具备自主评估能力,根据需求长时间持续运行、循环迭代。现在的调试模式还需要人工点击按钮来确认日志信息,但这只是过渡方案。理想的状态是,Agent能够自主完成评估、迭代,直到彻底解决问题。

 

提问者 3:我不知道你是否深度参与 Agent 相关的研发工作,但我注意到 Cursor 的内存管理功能做得很好。它可以根据工程师个人、部门乃至整个公司的偏好、规则和流程,自主管理相关信息。我们都知道,信息和上下文对 Agent 来说至关重要。请问你们有没有计划进一步拓展和升级这个功能?尤其是在长上下文处理方面,你们有什么思路?

 

Jason Ginsberg:我们正在进行大量的实验和探索。目前已经落地了规则管理、内存记忆、技能库等多个功能模块。现阶段,我们主要在研究高效的信息摘要技术。另外,借助我们的自研模型,我们也在探索让模型自主识别对话或代码中反复出现的关键信息。当然,跨组织的信息共享功能也很值得探索。不过这里有个需要注意的点,相关规则和信息可能会随着模型的迭代而过时。所以我们必须确保用户能够轻松更新这些内容,避免被过时的规则束缚。

 

提问者 4:关于你们发布的 Composer 模型,我认识一些开发者,他们基于 Gemini 模型微调了一个医疗领域的专用模型。但他们发现,这个微调后的模型效果还不如直接用原生 Gemini 模型做单次提示词调用。他们分析的原因是,微调模型需要持续维护,要跟上 Gemini 等基础模型的更新节奏。请问你们是如何制定策略,确保 Composer 模型不会落伍的?

 

Jason Ginsberg:你说的是 Composer 模型,对吧?我们会持续对它进行迭代优化,它并不是一个静态的模型。我们的核心关注点,是在速度和智能之间找到最佳平衡点,满足 Cursor 用户在大部分场景下的需求。不过在长上下文处理这类特定领域,我们确实还有提升空间。

 

提问者 5:我自己是产品经理,一直在用 Cursor 做原型开发,甚至在团队里还客串设计师,用它替代 Figma。我很好奇,有没有用户是在使用 Cursor 之前,从未安装过任何集成开发环境(IDE)的?这类用户会不会成为你们未来重点关注的群体?毕竟现在的编码 Agent 已经足够强大,很多工作都能在上面完成。

 

Jason Ginsberg:坦白说,我们目前并没有把这类用户作为核心关注点。当然,我们认同工具的使用门槛确实需要不断降低,而且 Cursor 的易用性也在持续提升,比如新增的浏览器工具对设计师就很友好。但我们的核心目标,其实是赋能顶尖工程师。我们一直在思考:如何让世界上最优秀的工程师变得更加强大?在这个过程中,我们开发的工具自然会惠及更多人群。不过在产品优化方面,我们确实还有很多工作要做,如优化新手引导和环境配置流程。毕竟设计师和产品经理在配置 GitHub 等工具时,经常会遇到困难。我们希望通过优化这些环节,吸引更多用户尝试 Cursor。

 

提问者 6:我一直在尝试用 Cursor 做智能合约的验证矩阵构建和试运行逻辑测试。请问在深度质量检测和安全加固方面,有没有什么不太为人知的实用工作流可以推荐?或者刚才提到的调试工具能不能派上用场?我对智能合约的质量检测特别感兴趣。

 

Jason Ginsberg:说实话,我们正在尝试让 Agent 自主完成测试工作,不过这项功能目前还没有完全发布。对于从事质量检测工作的人员来说,我强烈推荐试试我们刚发布的调试模式。这个功能定位问题的逻辑非常清晰,几乎可以说是确定性的,用起来会很有帮助。

 

提问者 7:您认为未来两到四个月,Cursor 面临的最大机遇是什么?会不会是语音 Agent?

 

Jason Ginsberg:我觉得机遇不在于语音 Agent。用户现阶段最核心的需求,其实是让 Agent 变得更智能、运行时间更长、能处理的任务更多。现在的很多 Agent,本质上只是在 “读取代码”,并不能真正判断修改后的代码是否有效。未来的发展空间非常大,我们可以投入更多算力,让 Agent 承担更多人类目前负责的校验工作。我觉得未来三到六个月,整个行业都会迎来巨大的变革,非常值得期待。

 

参考链接:

https://www.youtube.com/watch?v=dKSGK-fPFyU

整理 | 华卫、Tina

过去一年,编码 Agent 的变化速度,已经快到让人很难用“功能升级”来形容。

如果把时间拨回到一年前,Agent 还主要停留在代码补全、对话式改几行代码的阶段;而今天,在 Cursor 内部,工程师已经开始同时运行多个 Agent 并行“甩活儿”,让它们在代码库中自主修改、调试、复盘,再由人类在最后阶段集中审核结果。开发者不再盯着 Agent 的每一步操作,而是开始习惯“等它跑完再看答案”。

在最近一次访谈中,Cursor 工程负责人 Jason Ginsberg 给出了一个明确判断:这不是渐进式优化,而是一场正在发生的“换代”。更重要的是,他把这场变化的时间窗口,压缩到了未来三到六个月——在他看来,Agent 将不只是“更聪明”,而是会真正接管更长周期、更复杂的工程任务,整个行业的工作方式也将随之重塑。

下面是详细对话内容,我们在不改变原意的基础上进行了翻译和删减,以飨读者。

一年多时间,编码 Agent“翻天覆地”

Harrison Chase:Jason,你能跟大家简单介绍一下自己吗?也给大家讲讲 Cursor 是什么吧。

 

Jason Ginsberg:好的。我目前在做一款 AI 编程工具,已经在 Cursor 工作了六个月,担任该产品的工程负责人。不过说实话,我日常的大部分时间还是在写代码和做设计工作。在加入 Cursor 之前,我在 Notion 负责 Notion Mail 相关工作。几年前,我创办了一家名为 Skiff 的公司,后来这家公司被 Notion 收购了。所以,我一直都在从事产品开发相关的工作,而且主要聚焦在生产力工具领域。

 

Harrison Chase:非常棒。我有很多话题想和你探讨。要不我先抛砖引玉,问问你对编码 Agent 的发展历程,以及这些年来人机交互模式演变的看法吧。你们可以说是这个领域的先行者之一,我认为编码 Agent 的发展经历了几个阶段的转变:从最初的代码自动补全,到集成在集成开发环境(IDE)中的对话式交互,再到如今出现的各类终端工具,以及基于云端的异步 Agent。我很想听听你的看法,你觉得这样概括其用户体验的演变历程是否准确?或者你们团队是如何看待这一发展过程的?

 

Jason Ginsberg:我认为编码 Agent 的发展确实可以用 “翻天覆地” 来形容,而且这些变革基本上都是在一年多一点的时间里发生的。正如你所说,Cursor 最早开启了代码自动补全的先河,这种模式主要是在逐行的层面上提供辅助,适用范围也基本局限在单个文件内。而此后,几乎每隔几个月,我们就不得不提升产品的抽象层级,这其实是一个极具挑战性的产品设计难题。显然,Agent 的出现让开发者能够在多个文件之间灵活切换,并且可以放心地让 Agent 自主完成代码修改工作。

 

在过去两个月左右的时间里,我发现行业又出现了新的转变:开发者现在已经能够做到从项目启动到结束全程信任 Agent,并且会对整个代码库中多个文件的内容进行批量审核。因此,我们不得不对产品的整体布局进行大幅重新设计,将核心从逐行的代码差异对比,转向更偏向代码审查的模式。

 

展望未来的产品开发方向,我们的工作重心其实会更多地放在多 Agent 协同运行上。我们需要实现的是,能够快速验证这些 Agent 是否在正常运行,并且可以让它们并行工作,同时避免受到当前单一对话模式下各种选项和选择的束缚。

 

Harrison Chase:推动这些变革的核心因素是什么?仅仅是因为大模型的性能变得越来越好,还是有其他更多的影响因素?

 

Jason Ginsberg:我认为大模型性能的提升是一个很关键的因素,这让开发者能够更加信任 Agent 编写的代码质量。要知道,以前大家必须对 Agent 生成的代码进行非常全面细致的审查。

同时,现在也有了更完善的代码审查工具。比如我们有 BugBot,市场上其实还有很多类似的工具,它们都能够自动检查代码中存在的问题。

 

此外,我觉得从行业文化层面来看,开发者们对 Agent 工具的接受度和使用信心也在不断增强,甚至可以说已经 “上瘾” 于这类工具带来的便捷。而且,一旦习惯了完全依赖 Agent 进行编码的工作模式,再切换回传统的编码方式其实是很困难的。所以现在,我们能看到越来越多的开发者已经将 Agent 辅助编程作为默认的工作方式。

最顶尖工程师的干活秘诀:全靠 Agent?

Harrison Chase:你观察到大家使用 Cursor 的方式都有哪些不同?或者你自己平时是怎么使用 Cursor 的?

 

Jason Ginsberg:其实在我们公司内部,工程师们使用 Cursor 的方式就五花八门。甚至团队里有几位工程师,他们完全不使用 Cursor 的 Agent 功能,比如负责安全和基础设施的同事。所以,确实有一部分用户非常依赖代码自动补全功能,日常使用中大部分操作都是基于补全功能完成的。但令人意外的是,我发现团队里一些最顶尖的工程师,我们称他们为 “核心用户”,他们做任何工作都会完全依赖 Agent,甚至会同时运行多个 Agent 并行处理任务。

 

至于我个人的使用习惯,我并不会去设计那些复杂繁琐的提示词,也没有什么所谓的 “Agent 使用秘籍”。我写的提示词往往都很简短,甚至还会带有拼写错误。我会针对手头不同的工作任务,或者同一个问题的不同模块,同时启动多个 Agent,然后等待它们返回结果。

 

目前我用得最多的是我们今天刚刚发布的一个新功能:调试模式。这个模式下,Agent 能够通过生成日志来进行自我评估,之后开发者复现相关操作步骤,Agent 就会通过查看日志判断问题是否得到解决。这个功能非常实用,因为它相当于通过投入算力去不断尝试解决问题,最终攻克那些手动排查起来极为棘手的难题。

 

Harrison Chase:调试模式具体是什么样的?为什么需要专门设置这样一个模式?难道不能自动完成调试吗?直接给 Agent 下达调试指令不也可以吗?

 

Jason Ginsberg:其实我也认同你的这个想法。所以在开发调试模式的时候,我们内部确实有过不少争论。主要原因在于,Cursor 目前已经有很多功能模式了,如规划模式、询问模式等等,这些模式其实不太容易被用户发现。我们一直认为,这些模式都很实用,理想的状态应该是,Agent 能够根据用户的操作场景,自动匹配并启用最合适的模式,无需用户手动切换。

 

而现阶段调试模式之所以需要手动开启,是因为它的交互方式比较特殊。在运行过程中,Agent 会暂停当前的工作,向用户提问以获取反馈。如果用户不熟悉这种交互逻辑,可能会觉得比较困扰。

 

Harrison Chase:Agent 具体会询问哪些问题,又需要用户提供什么样的反馈呢?

 

Jason Ginsberg:我举个例子吧。假设我正在开发一个前端应用,遇到了一个很让人头疼的问题:菜单总是在左上角弹出。这时候我会对Agent说:“这个菜单需要锚定到按钮的位置。” 随后,Agent 会启动服务器,并在整个代码库中添加大量日志,同时提出一系列可能导致该问题的假设,如 “可能是某个定位参数设置错误”、“可能是事件绑定逻辑有问题” 等。之后,Agent 会提示我:“麻烦你点击这个按钮,打开菜单,看看问题是否解决。” 如果我反馈问题依然存在,Agent 就会查看生成的日志,然后分析判断:“这个假设成立,那两个假设不成立”。通常这样反复两三次之后,Agent 往往就能找出并解决问题。

 

Harrison Chase:你觉得人类还需要手动操作多久?就不能让 Agent 自主完成点击、测试这类操作吗?

 

Jason Ginsberg:一两个月内,毕竟这个行业的发展速度实在太快了。

 

Harrison Chase:刚才你提到了 Agent 的多种不同模式,比如规划模式、解释模式、调试模式等等。这些模式在实际应用中到底意味着什么?难道只是为 Agent 设置不同的提示词这么简单吗?还是说背后有更复杂的逻辑?

 

Jason Ginsberg:很多时候,确实就是修改一下系统层面的提示词。不过在某些情况下,我们也需要对用户界面进行相应的调整。比如规划模式现在也加入了交互提问功能,运行过程中会主动打断用户操作,寻求反馈。用户有时也可以自行设置参数,如调整 Agent 打断的频率等。再比如询问模式,它不只是依赖特定的系统提示词,还会限制 Agent 调用某些与文件编辑相关的工具,以此来保证功能的稳定性和可靠性。

 

Harrison Chase:回到之前的话题,关于大家使用 Cursor 的不同方式,你觉得未来使用编码 Agent 或者说 Cursor,存在所谓的 “最佳方式” 吗?

 

Jason Ginsberg:我觉得并没有什么 “最佳方式”,具体的使用方法很大程度上取决于工程师的个人工作习惯以及他们所处理的具体工作内容。目前行业里,既有异步运行Agent的应用场景,也有开发者深度参与、实时交互的模式,就像一边编程、一边像画画一样实时调整代码或者进行可视化的编辑操作。不过我经常在推特上看到一些所谓的 “Agent 使用技巧”,其实对此我是有点持保留态度的。很多人会说 “这才是使用 Agent 的最佳方式”,但在我看来,这些技巧往往是凭空杜撰的。

 

我们团队内部其实并不会使用那些冗长复杂的提示词,也不会采用多阶段规划的策略。大多数时候,我们都是快速迭代,如果 Agent 运行的结果不理想,就直接终止进程,重新启动 Agent。通常这种方式的效率是最高的。

自然 “唠嗑”是 Cursor 最终交互模式?

Harrison Chase:如果让你预测一下一年后的情况,你认为开发者在 IDE、终端以及其他形态的载体上使用 Cursor 的时间占比会是怎样的?

 

Jason Ginsberg:当然,我肯定会带有一定的主观偏向性。但我认为,终端工具并不会成为用户的首选。我觉得,真正驱动行业发展的是用户对Agent的信任度不断提升,他们更希望等到Agent完成所有工作后再查看最终的修改结果,然后决定是否采纳,同时也愿意让 Agent 运行更长的时间,以实现更智能的处理。

 

而 IDE 之所以至关重要,是因为它是为整个软件开发周期量身打造的工具。从项目的构思规划,到运行代码修改、查看代码内容、清晰对比代码差异、提交代码合并请求,再到在浏览器中预览效果所有这些环节,都可以无缝集成在 IDE 的模块化功能之中。这一点其实很容易被忽视,毕竟 IDE 的这些功能是经过了数十年的发展才逐步完善起来的。

 

我认为,当前行业的一个明显趋势是,产品层面的设计变得越来越重要。现在 Cursor 用户使用频率最高的功能,如规划模式,其实都需要可视化编辑器的支持,用户需要能够在编辑器中添加注释,并进行实时交互。一旦脱离了按钮、弹窗和菜单这些可视化交互元素,用户与工具的交互难度会大大增加。

 

不过,我觉得未来并非所有操作都必须局限在笔记本电脑的 IDE 中完成。这种模式并不会被完全取代,具体的使用场景会根据实际需求灵活变化,适用的场景也会更加广泛。用户在更多场景下,都能够使用到 Cursor 这样的工具。

 

Harrison Chase:未来会有更多场景都能用上像 Cursor 这样的工具。你们应该有对应的官网吧?用户可以直接在网页上进行交互操作,是这个思路吗?

 

Jason Ginsberg:对,我们确实有官网。这么做的原因是用户可以通过手机等设备随时随地访问。我觉得在不远的将来,用户完全可以戴着 AirPods,开启语音模式,和Agent实时沟通、碰撞想法,让Agent不断优化方案。等用户到了办公室,打开笔记本电脑,就已经有一堆代码修改记录或者演示视频等着审核了,到时候只需要简单确认通过或者驳回就行。如果某些细节还需要微调,再把项目下载到本地修改就好。

 

Harrison Chase:我认为 Cursor 真正的优势,在于围绕 Agent 交互打造的整套设计和用户体验体系。你之前在 Notion 工作过,我记得即便是在生成式 AI 普及之前,Notion 的设计和用户体验就已经广受认可了。当然,他们在生成式 AI 时代也很好地完成了转型。从一家在生成式 AI 普及前就拥有出色设计积淀且顺利完成转型的公司,再到如今专注 Agent 相关工作,你觉得 Agent 的出现给产品设计和用户体验带来了哪些变化?现在的工作模式和之前有相似之处吗?

 

Jason Ginsberg:我觉得总体来说,我们产品的大部分设计其实并不是 AI 专属的。要知道,产品可用的交互组件和用户体验模式就那么多,市面上的应用本质上也都是基于一些传统的模式搭建的,如收件箱、仪表盘、聊天界面,这些都是很成熟的设计。所以我们的工作核心,更多是把这些现有的设计模式进行合理组合,然后在产品中恰当地呈现出来。这一点和 Notion 的产品理念是相通的,同时也是 Cursor 和集成开发环境(IDE)的核心特质:极高的模块化程度。

 

作为用户,你会发现每个人的 IDE 界面布局都可以千差万别。你可以自定义面板布局,把任意组件拖放到任意位置,和坐在你旁边的同事设置出完全不同的界面。我认为这种模块化设计对产品的适应性至关重要,毕竟如我之前所说,Agent 的能力发展日新月异,用户对产品的需求和期待几乎每隔几周就会发生变化。几个月前我们推出 Cursor 2.0 的时候,并没有把原来的产品推倒重来,只是把各个功能模块重新组合,调整为侧边栏收件箱式的管理布局,同时优化了聊天界面的信息密度而已。

 

Harrison Chase:听你这么说,很多组件的底层逻辑其实是相通的。那有没有出现新的组件?或者某些组件的优先级发生了变化?毕竟这些组件最初都是为 “人类与软件交互”“人类通过软件协作” 的场景设计的,现在加入了 Agent 这个新角色。这其中有没有产生什么新的变化?还是说其实本质上没有太大不同?

 

Jason Ginsberg:我认为底层的设计逻辑和核心要素其实没有变,关键变化在于谁在主导界面交互。而在这个核心框架下,其实可以演变出无数种交互形式。就拿交互的抽象层级来说,一年前大家使用Agent的时候,都恨不得盯着它的每一步操作,全程 “盯梢”。但现在 Agent 的操作步骤变得无比繁杂,用户根本看不过来。所以我们需要优化信息呈现方式:如何对操作步骤进行分组?如何提炼关键信息?

 

当用户足够信任 Agent 的操作后,我们就需要把重点放在文件的实际修改内容上,并且为这些修改添加更详细的注释说明。当然,我们也可以进一步提升交互的灵活度,比如聊天对象不再局限于单个 Agent,而是可以同时和多个 Agent 对话。这就需要一套更智能的后台交互逻辑来支撑 ,系统要能识别用户在和哪个子 Agent 对话,并且协调这些 Agent 完成对应的修改。未来这种交互的抽象层级还会不断提升。

 

Harrison Chase:你觉得交互的抽象层级最高能达到什么程度?我知道预测未来很难,但还是想听听你的看法。

 

Jason Ginsberg:我觉得未来,我们现在看到的各种操作选项,如选择模型、选择功能模式、选择运行环境这些都会逐渐消失。最终的交互模式会变得像和真人对话一样自然。但这并不意味着任何人都能随便写代码,在那个阶段,这个工具依然是为专业工程师服务的。因为你还是需要具备专业的行业术语知识,清楚自己想要修改的内容是什么。做产品的人,要明确自己想要的工作流程和功能需求;做基础设施的人,要足够了解代码库,知道什么样的架构和系统设计最适合当前要开发的项目。

 

而且我想强调的是,随着抽象层级的提升,我们并不会摒弃现有的功能。用户依然可以随时深入底层,查看细节、调整参数。只是产品的默认交互方式会不断优化升级。

Cursor 内部工作揭秘:少审代码、高频反馈

Harrison Chase:你之前提到了人类在 Agent 工作流程中的角色,比如查看代码差异、进行代码审查。你觉得 AI 会给代码审查工作带来哪些改变?

 

Jason Ginsberg:首先,就我们产品团队的工作模式来说,现在人工审查的比重已经大幅降低了。我们有一个叫 BugBot 的工具,它会自动检测代码问题,并且自主完成修复,还会在持续集成(CI)流程中不断迭代优化。这个工具的表现非常出色,也让我们对 AI 审查的代码质量更有信心。

 

其次是信息的语义化分组。用户查看代码差异时,可以清晰地看到 Agent 做了哪些修改。我们甚至可以展示 Agent 的原始指令,更理想的状态是,Agent 能够像人类一样,在处理大型代码合并请求时,为每一处修改附上注释,说明这么做的原因。我觉得这虽然算不上颠覆性的变革,但确实能给代码审查工作带来显著的优化。

 

Harrison Chase:出于好奇,我想问一下,Cursor 的工程师用 Cursor 写代码,用 BugBot 审查代码,那他们还需要和其他工程师沟通协作吗?

 

Jason Ginsberg:哈哈,这个问题很有意思。如果你以工程师的身份加入 Cursor,会立刻发现一个现象:所有人都在深度使用自家产品。我记得我入职第一周的时候,修改了一个快捷键设置。那个快捷键是 Alt+Shift+Command+J,非常冷门,我当时觉得选这个键肯定没人会注意到。结果刚改完不到半分钟,就有三个同事在 Slack 上发来消息:“你改的这个快捷键直接打乱了我的工作流程!到底怎么回事?”几乎任何产品改动,都会立刻收到同事们的强烈反馈。我觉得这其实是一件好事,大家就是在这种高频的反馈和交流中,快速推进产品迭代的。

 

Harrison Chase:从组织管理的角度,你们有没有采取什么措施来鼓励或者引导这种高频反馈的协作模式?毕竟大量的反馈涌进来,有时候也会让人应接不暇。

 

Jason Ginsberg:在我创办自己的公司之前,工程师们也会用邮件沟通,但用得并不多。大家甚至会说:“邮件只用来收垃圾邮件和购物通知,可别用它来发长篇大论的工作内容。”而在Agent这个赛道工作,其实完全不需要依赖邮件这种低效的沟通方式。我们团队的所有人都全身心投入工作,毕竟这是一个竞争非常激烈的领域,大家都对产品开发充满热情,会自然而然地用各种即时沟通工具协作。

 

另外,我在规划产品功能时,会遵循一个核心原则:我能开发什么功能,让自己的日常工作更轻松? 具体来说,就是思考 “做什么能帮我明天更高效地完成工作,不用再处理那些烦人的报错和问题”。这个原则指导着我们的大部分工作。毕竟这种功能开发出来之后,我们自己能立刻受益,比如修复了一个烦人的漏洞,以后上班就不用再被这个问题困扰了。

迭代狂飙背后,核心功能竟来自员工 “自嗨”?

Harrison Chase:你觉得你们的产品路线图,有多大比例是由 “让自己工作更轻松” 这个需求驱动的?又有多大比例是来自外部用户的需求?这个比例随着公司发展有变化吗?

 

Jason Ginsberg:这个比例确实随着公司规模的扩大在变化。现在我们也会制定月度的产品路线图和目标,但说实话,我们很多核心功能都来自自下而上的创新。比如 Cursor 的Agent功能,这可以说是大家提到 Cursor 时最先想到的核心功能。这个功能是我们团队的一个人开发的,最开始所有人都不看好这个想法,但他很快做出了原型。大家试用之后都惊叹:“哇,这东西居然真的能用!”

 

我之前提到的调试模式也是如此。感恩节假期的时候我闲着没事,就开发了这个自己很需要的功能,现在这个功能也即将上线。这些功能的开发初衷,都是为了解决团队内部的需求。我们判断一个功能是否具备发布条件,一个重要的衡量标准就是内部的使用率和认可度。

 

Harrison Chase:你们的产品迭代速度快得惊人,是怎么保持这种高效的开发节奏的?

 

Jason Ginsberg:说实话,我们的工作流程其实非常精简,没有太多繁琐的制度。公司里虽然有几间会议室,也有一两位产品经理,但我们很少通过撰写文档或者开对齐会议来推进工作,大部分的讨论和决策都是在代码层面完成的。而这一切能够实现的核心原因,是我们对人才的极高要求。今年年初的时候,公司总共也就 20 人左右。之所以团队规模增长缓慢,就是因为我们的招聘门槛高到近乎苛刻。我们会反复评估:这个人很优秀,但他能成为团队里最顶尖的那批人吗?

 

正因为团队里的每个人都足够出色,所以我们可以放心地把任务交给任何一个人。团队成员的主观能动性都极强,从提出想法、设计用户体验,到在推特上回复用户的支持请求、和企业客户沟通需求,再到最终将功能落地,整个流程都能独立完成。所以说,我们能保持这样的速度,归根结底还是人的因素。

 

Harrison Chase:你们是如何规划产品路线图的?你刚才提到了以月为单位的规划周期,这是目前的常规规划时长吗?有没有更长期的规划?另外,行业技术迭代的速度实在太快了,你们是如何平衡 “跟进现有技术浪潮” 和 “实现技术跨越式发展” 这两者的?会不会主动预判技术趋势,提前布局未来方向?

 

Jason Ginsberg:我们确实会投入不少精力去思考未来,比如预判未来三个月可能实现的技术突破,然后主动押注相关方向,团队里有相当一部分人都在做这类前瞻性的工作。我们制定的月度路线图更多是围绕核心产品功能展开,聚焦于用户的实际需求以及那些能优化日常使用体验的功能。而那些需要投入两个月时间重构底层逻辑的重大项目,则会纳入更长期的规划范畴。

此外,我们的应变能力其实非常强。

 

有时候我们会提前拿到新模型的测试版本,试用之后如果发现它在某些方面表现特别出色,团队成员往往会主动利用周末时间加班,争取在新模型正式发布前就完成相关功能的开发。很多重要功能其实几天之内就能搭建完成。

 

Harrison Chase:说到模型,你们发布了自研的 Composer 模型。开发这个模型的初衷是什么?目前用户的使用情况如何?这个模型有没有改变大家使用 Cursor 的习惯?

 

Jason Ginsberg:我们发现,工程师使用我们产品时的编码场景,需要有专门适配的模型来支撑。Composer 模型就是针对这类场景打造的,它定位非常明确,具备速度快、质量高、逻辑智能三大特点,尤其适合 “人机实时协作” 场景。我自己做前端开发时就经常用它,因为我需要频繁做出细微的交互设计决策,这就要求 Agent 能在几秒内给出反馈。Composer 就像一个高效的协作伙伴,能快速响应需求、碰撞想法,和那些适用于长周期异步任务的模型形成了很好的互补。

 

Harrison Chase:Cursor 的 Agent 相关研发工作是全员参与,还是有专门的团队负责?

 

Jason Ginsberg:我们确实有专门的团队负责 Agent 的性能优化,他们主要聚焦于工具链、调度框架的搭建以及效果评估。但正如我之前所说,我们的团队架构并不僵化,没有严格限制大家的工作范围。比如核心产品团队的工程师在开发规划模式时,如果需要对Agent进行调整,就会和Agent团队密切协作。而且在开发过程中,我们依然会深度使用自家产品进行测试,团队成员会分享使用感受,以此来评估功能的实际效果。

 

Harrison Chase:无论是 Agent 团队的成员,还是其他团队中擅长 Agent 研发的工程师,他们身上有没有什么共同特质?他们的专业背景或者个人能力有没有什么特别之处?

 

Jason Ginsberg:我觉得他们大多是偏产品方向的人才,而不是传统意义上的机器学习或算法研究专家。这些人经常在不同团队之间轮岗,因为Agent研发需要对用户的最终使用体验有很强的直觉,同时还要能准确解读团队的反馈意见。

 

Harrison Chase:上周你们和 OpenAI 合作发布了一篇博客,内容是针对 OpenAI 的新模型优化 Cursor 的 Agent 调度框架。我在推特上经常看到大家讨论 “Agent 调度框架” 这个概念。你们是如何看待模型的底层支撑架构的?这类架构是否需要和特定模型深度绑定?比如 Composer 模型和 CodeLlama 模型,对应的架构会不会有很大差异?

 

Jason Ginsberg:我其实没有深度参与这方面的工作,但据我了解,我们的核心目标是打造高度灵活的架构。毕竟我们需要不断尝试新技术、新功能模式,所以架构必须能够随着模型能力的升级快速适配。

 

Harrison Chase:很有道理。毕竟整个行业都在飞速变化。

开放问答

提问者 1:刚才提到了新增的可视化浏览器功能,我发现有些工具比如 Lovable 也有类似的功能。请问这个功能是朝着 “沉浸式可视化编码” 的方向发展吗?

 

Jason Ginsberg:我觉得它并不是为沉浸式可视化编码设计的。就像我之前说的,这个功能最初是我为自己开发的,我本身就是一名做产品的工程师,它的核心用户群体其实是专业工程师和设计师。大家在开发应用时,肯定都遇到过这种情况:精心设计的界面,最后却变成了大家都看腻了的紫黄渐变配色。这个功能就是为了让大家能够精准把控细节,比如把内边距调整到精确的像素值。它为用户提供了一套更直观的 “视觉化操作语言”,比纯文本指令的精度更高。

 

而且就算不使用侧边栏,你也可以直接点击页面元素,随时输入提示词下达指令。借助这个功能,你可以在几秒内同时启动六个 Agent。如果开启热重载功能,你的网站会实时呈现修改效果,用起来其实还挺有意思的。

 

提问者 2:我特别喜欢你们的浏览器 Agent,一直在用。但我发现一个小瑕疵:我想持续迭代优化设计方案,可 Agent 总是会中断我的工作,直接提交代码合并请求。未来有没有可能实现不间断的持续迭代?

 

Jason Ginsberg:当然可以。未来的发展方向就是让 Agent 具备自主评估能力,根据需求长时间持续运行、循环迭代。现在的调试模式还需要人工点击按钮来确认日志信息,但这只是过渡方案。理想的状态是,Agent能够自主完成评估、迭代,直到彻底解决问题。

 

提问者 3:我不知道你是否深度参与 Agent 相关的研发工作,但我注意到 Cursor 的内存管理功能做得很好。它可以根据工程师个人、部门乃至整个公司的偏好、规则和流程,自主管理相关信息。我们都知道,信息和上下文对 Agent 来说至关重要。请问你们有没有计划进一步拓展和升级这个功能?尤其是在长上下文处理方面,你们有什么思路?

 

Jason Ginsberg:我们正在进行大量的实验和探索。目前已经落地了规则管理、内存记忆、技能库等多个功能模块。现阶段,我们主要在研究高效的信息摘要技术。另外,借助我们的自研模型,我们也在探索让模型自主识别对话或代码中反复出现的关键信息。当然,跨组织的信息共享功能也很值得探索。不过这里有个需要注意的点,相关规则和信息可能会随着模型的迭代而过时。所以我们必须确保用户能够轻松更新这些内容,避免被过时的规则束缚。

 

提问者 4:关于你们发布的 Composer 模型,我认识一些开发者,他们基于 Gemini 模型微调了一个医疗领域的专用模型。但他们发现,这个微调后的模型效果还不如直接用原生 Gemini 模型做单次提示词调用。他们分析的原因是,微调模型需要持续维护,要跟上 Gemini 等基础模型的更新节奏。请问你们是如何制定策略,确保 Composer 模型不会落伍的?

 

Jason Ginsberg:你说的是 Composer 模型,对吧?我们会持续对它进行迭代优化,它并不是一个静态的模型。我们的核心关注点,是在速度和智能之间找到最佳平衡点,满足 Cursor 用户在大部分场景下的需求。不过在长上下文处理这类特定领域,我们确实还有提升空间。

 

提问者 5:我自己是产品经理,一直在用 Cursor 做原型开发,甚至在团队里还客串设计师,用它替代 Figma。我很好奇,有没有用户是在使用 Cursor 之前,从未安装过任何集成开发环境(IDE)的?这类用户会不会成为你们未来重点关注的群体?毕竟现在的编码 Agent 已经足够强大,很多工作都能在上面完成。

 

Jason Ginsberg:坦白说,我们目前并没有把这类用户作为核心关注点。当然,我们认同工具的使用门槛确实需要不断降低,而且 Cursor 的易用性也在持续提升,比如新增的浏览器工具对设计师就很友好。但我们的核心目标,其实是赋能顶尖工程师。我们一直在思考:如何让世界上最优秀的工程师变得更加强大?在这个过程中,我们开发的工具自然会惠及更多人群。不过在产品优化方面,我们确实还有很多工作要做,如优化新手引导和环境配置流程。毕竟设计师和产品经理在配置 GitHub 等工具时,经常会遇到困难。我们希望通过优化这些环节,吸引更多用户尝试 Cursor。

 

提问者 6:我一直在尝试用 Cursor 做智能合约的验证矩阵构建和试运行逻辑测试。请问在深度质量检测和安全加固方面,有没有什么不太为人知的实用工作流可以推荐?或者刚才提到的调试工具能不能派上用场?我对智能合约的质量检测特别感兴趣。

 

Jason Ginsberg:说实话,我们正在尝试让 Agent 自主完成测试工作,不过这项功能目前还没有完全发布。对于从事质量检测工作的人员来说,我强烈推荐试试我们刚发布的调试模式。这个功能定位问题的逻辑非常清晰,几乎可以说是确定性的,用起来会很有帮助。

 

提问者 7:您认为未来两到四个月,Cursor 面临的最大机遇是什么?会不会是语音 Agent?

 

Jason Ginsberg:我觉得机遇不在于语音 Agent。用户现阶段最核心的需求,其实是让 Agent 变得更智能、运行时间更长、能处理的任务更多。现在的很多 Agent,本质上只是在 “读取代码”,并不能真正判断修改后的代码是否有效。未来的发展空间非常大,我们可以投入更多算力,让 Agent 承担更多人类目前负责的校验工作。我觉得未来三到六个月,整个行业都会迎来巨大的变革,非常值得期待。

 

参考链接:

https://www.youtube.com/watch?v=dKSGK-fPFyU

AI生成代码质量难以把控!本文分享来自美团的技术实践,三大策略破解AI编程痛点。单测快速验证逻辑正确性,安全网保护存量代码演进,TDD模式精准传递需求。告别「看起来没问题」的错觉,构建AI时代的代码质量保障体系。

一、引言

目前,国内外很多AI Coding助手能在几秒钟内生成完整代码块,大大提升了开发效率,但这种高速开发模式也带来了潜在风险——与人工编码不同是,AI Coding助手生成代码存在两个特殊风险:其一,AI Coding助手依赖于上下文与模型自身的能力,输出的代码质量相对不可控。其二,AI生成的代码虽然逻辑通顺、结构完整,但可能隐藏着难以察觉的边界问题或逻辑缺陷。

核心问题:我们如何快速的验证AI生成代码的质量和可靠性?

本文旨在分享如何借助单元测试,让AI编程合作更高效可靠,主要解决三个常见痛点:

  1. 肉眼审查困境:AI一次性生成大量代码时,难以快速准确判断逻辑完备性;
  2. 存量代码信任危机:如何验证AI修改老代码时,不会产生非预期的结果;
  3. 需求传达难题:如何精准向AI表达复杂需求并快速验证。

针对上述三个常见痛点,本文提出采用不同的单元测试策略来应对以上问题。每个策略都针对一个特定痛点设计:策略一通过测试解决肉眼审查的局限性;策略二构建单测安全网应对存量代码的信任问题;策略三则采用TDD模式优化需求传达与验证流程。下文将依次展开说明,希望能对大家有所帮助或启发。

二、策略一:单测检验AI代码逻辑正确性

2.1 问题背景

传统的人工代码审查在AI生成的大量代码面前显得低效且不可靠。在软件测试实践中,有着测试左移(Shift Left Testing)的概念,本质上是借助工具和测试手段更早地发现问题和预防问题。在AI Coding时代,这一理念尤为关键:跳过单元测试直接集成测试看似”抄近路”,实则是将风险后置——开发阶段几分钟能发现的Bug,在集成测试环境可能需要较长定位修复,这中间包含了代码部署、环境准备、测试条件的准备、问题定位、开发人员修复、再次部署验证等一系列漫长的环节。

相比之下,单元测试具有独特的优势:它能够独立运行、快速验证结果,并且可以无限次重复执行。这种测试方式就像是为项目进行的一次性投资,却能为整个开发周期构建起一张可靠的“安全网”。它不仅能实时验证AI Coding生成的代码是否正确,更能持续保障未来代码的质量稳定性,让开发团队始终对代码库保持信心。

2.2 案例:分页查询接口的隐蔽Bug

任务背景:实现一个支持多条件筛选的复杂分页查询接口pageQueryRobot

AI生成了如下核心查询逻辑:

public List<AgentRobotE> pageQueryRobotsByCondition(List<Long> shopIds, String chatSceneCode,
        Boolean enabled, Integer pageNo, Integer pageSize) {
    // ... 前置校验代码 ...

    // 分页查询机器人基础信息
    int offset = (pageNo - 1) * pageSize;
    List<AgentRobotEntity> entities = robotIds.stream()
            .skip(offset)
            .limit(pageSize)
            .map(robotId -> agentRobotDAO.getRobotById(robotId, false))
            .filter(Objects::nonNull)
            // 问题代码:类型不匹配的隐蔽Bug
            .filter(entity -> enabled == null || Objects.equals(entity.getEnabled(), enabled ? 1 : 0))
            .filter(entity -> Objects.equals(entity.getChatSceneCode(), chatSceneCode))
            .collect(Collectors.toList());

    return entities.stream()
            .map(this::convertToModel)
            .filter(Objects::nonNull)
            .collect(Collectors.toList());
}

问题分析:这段代码看起来逻辑完整,但第8行的过滤逻辑包含了多个复杂元素:

  • 三元运算符 enabled ? 1 : 0
  • Objects.equals 的使用
  • Boolean到Integer的隐式逻辑转换

仅凭肉眼很难发现其中的类型不匹配问题。

单元测试发现问题:通过AI编写了17个全面的单元测试用例,覆盖:

  • 正常场景:各种有效参数组合
  • 边界场景:null值、空集合处理
  • 参数组合:enabled为true/false/null的不同情况
@Test
public void testPageQueryWhenEnabledIsTrue() {
    // arrange
    List<Long> shopIds = Arrays.asList(12345L, 67890L);
    String chatSceneCode = "SCENE_C";
    Boolean enabled = true;  // 测试enabled为true的情况

    // 模拟数据库返回的实体,enabled字段为Boolean类型
    AgentRobotEntity mockEntity = new AgentRobotEntity();
    mockEntity.setEnabled(true);  // 注意:这里是Boolean类型
    mockEntity.setChatSceneCode("SCENE_C");

    when(agentRobotDAO.getRobotById(anyLong(), eq(false))).thenReturn(mockEntity);

    // act
    List<AgentRobotE> result = repository.pageQueryRobotsByCondition(
        shopIds, chatSceneCode, enabled, 1, 10);

    // assert - 这个测试失败了!
    assertEquals(1, result.size());  // 期望返回1个结果,实际返回0个
}

测试运行结果:当enabled为true时测试失败!

问题定位:通过测试失败,快速定位到过滤逻辑的问题:

// 错误的逻辑:entity.getEnabled()返回Boolean类型,但与Integer比较
Objects.equals(entity.getEnabled(), enabled ? 1 : 0)
// 当enabled=true时,比较的是 Objects.equals(Boolean.TRUE, 1) -> false
// 当enabled=false时,比较的是 Objects.equals(Boolean.TRUE, 0) -> false

正确修复:

// 修复后:直接比较Boolean类型
.filter(entity -> enabled == null || Objects.equals(entity.getEnabled(), enabled))

意外收获:在审查测试覆盖的代码时,还发现了N+1查询的性能问题:

// 存在性能问题的代码
.map(robotId -> agentRobotDAO.getRobotById(robotId, false))  // 每个robotId单独查询

成果验证:修复后,所有17个单元测试用例全部通过,代码质量得到保障。

三、策略二:构建安全网保护存量代码

3.1 问题场景

AI对存量代码的修改挑战更大。AI看到的可能只是函数或类的局部,无法理解背后的业务规则和历史包袱。如何放心的让AI修改已有的代码?

在进行AI Coding前,需要确保旧有逻辑,处于单元测试的完全覆盖保护中,这就像在开启汽车的“自动辅助驾驶”功能前,必须先系好安全带一样。这条“安全带”就是我们完善的、可运行的单元测试集。

  • 快速验证,精准反馈:AI生成修改后的代码无需人工逐行对比,只需运行单元测试即可获得即时反馈。测试失败的用例直接揭示AI修改中存在的问题——要么触及了不应改动的逻辑,要么未能正确实现预期变更。这种反馈机制既高效又客观。
  • 清晰界定修改边界:单元测试结果帮助我们明确判断——AI的修改是否精准实现了目标?在引入新功能的同时是否完整保留了原有逻辑?通过区分预期内的失败(主动修改旧逻辑)和意外失败(破坏现有功能),我们获得了优化AI方案的明确方向,大幅提升了迭代效率。

3.2 案例:延迟回复策略的用户范围扩展

业务背景:需要将消息延迟回复服务从原来的平台A、平台B的用户扩展到平台C用户。

原始代码分析:

// TextDelayReplyStrategy.java 中的核心逻辑
private boolean needSkip(ChatHistoryE chatHistoryE) {
    UserDTO UserDTO = UserHelper.parseUser(chatHistoryE.getUserId());
    return MessageSendDirectionEnum.CLIENT_SEND.value != chatHistoryE.getMessageStatus()
               || MessageShieldEnum.RECEIVER_SHIELD.value == chatHistoryE.getShield()
               || UserDTO == null
               || !UserType.isLoginUser(UserDTO.getUserType());  // 关键判断逻辑
}

这个needSkip方法决定了哪些用户类型需要跳过延迟回复处理。原逻辑中,UserType.isLoginUser()只覆盖平台A、平台B的登录用户,不包括平台C用户。

修改前的安全网构建:

按照“分析-测试-实施-验证”方法论,首先完善单元测试:

// 针对现有逻辑的保护性测试
@Test
public void testNeedSkipWithAUser() {
    // 平台A用户不应被跳过
    ChatHistoryE chatHistory = buildChatHistory(A_USER_ID);
    assertFalse(strategy.needSkip(chatHistory));
}

@Test
public void testNeedSkipWithBUser() {
    // 平台B用户不应被跳过
    ChatHistoryE chatHistory = buildChatHistory(B_USER_ID);
    assertFalse(strategy.needSkip(chatHistory));
}

@Test
public void testNeedSkipWithCUser() {
    // 平台C在修改前应被跳过
    ChatHistoryE chatHistory = buildChatHistory(C_USER_ID);
    assertTrue(strategy.needSkip(chatHistory));  // 修改前的预期行为
}

@Test
public void testNeedSkipWithGuestUser() {
    // 游客用户应被跳过
    ChatHistoryE chatHistory = buildChatHistory(GUEST_USER_ID);
    assertTrue(strategy.needSkip(chatHistory));
}

运行基线测试:确保所有测试通过,建立基线状态

[INFO] Tests run: 15, Failures: 0, Errors: 0, Skipped: 0
[INFO] 所有现有逻辑测试通过,可以安全修改

AI辅助修改实施:

向AI提供需求:”将平台C用户也纳入延迟回复服务范围”

AI分析代码后给出修改方案:

// 修改后的代码
private boolean needSkip(ChatHistoryE chatHistoryE) {
    UserDTO UserDTO = UserHelper.parseUser(chatHistoryE.getUserId());
    return MessageSendDirectionEnum.CLIENT_SEND.value != chatHistoryE.getMessageStatus()
               || MessageShieldEnum.RECEIVER_SHIELD.value == chatHistoryE.getShield()
               || UserDTO == null
               || !UserType.isAorBorCLoginUser(UserDTO.getUserType());  // 扩展用户范围
}

验证阶段的精准反馈:

修改后运行测试集:

# 运行结果
[INFO] Tests run: 15, Failures: 1, Errors: 0, Skipped: 0
[ERROR] testNeedSkipWithCProviderUser: expected:<true> but was:<false>

结果分析:

✅ testNeedSkipWithAUser - 通过(平台A用户逻辑未变)
✅ testNeedSkipWithBUser - 通过(平台B用户逻辑未变)
❌ testNeedSkipWithCUser - 失败(平台C预期的变更)
✅ testNeedSkipWithGuestUser - 通过(游客用户逻辑未变)

更新期望值:

@Test
public void testNeedSkipWithCUser() {
    // 修改后:平台C不应被跳过
    ChatHistoryE chatHistory = buildChatHistory(C_USER_ID);
    assertFalse(strategy.needSkip(chatHistory));  // 更新期望值
}

最终验证:

[INFO] Tests run: 15, Failures: 0, Errors: 0, Skipped: 0
[INFO] 所有测试通过,修改安全完成

这种方法将开发者从“担心AI改坏代码”的不信任中解放出来,明确知道哪些功能被影响,哪些保持不变,实现安全、高效的存量代码演进。

四、策略三:TDD思想驱动AI开发

4.1 “先生成,后验证”的局限

前面两节所提到的策略可以归类为”先生成,后验证”,在一定的场景下仍然存在两个问题:

  • 提示词驱动:开发者反复修改自然语言描述,AI产出不确定,返工频繁;
  • 肉眼审查:生成测试用例仍然需要人工验证,一旦用例较多,效率依然低下。

4.2 TDD模式的革命性转变

TDD 核心理念:

  • 测试先行:先写测试,再写实现代码。
  • 小步快跑:以微小增量推进开发,每次只解决一个问题。
  • 设计驱动:测试即需求文档,驱动接口设计和代码结构。
  • 安全网:测试集提供即时反馈,支持安全重构。

整个开发过程严格遵循 Red -> Green -> Refactor 的循环。

  • 🔴 Red: 先编写一个失败的单元测试,用代码来定义我们期望实现的功能。
  • 🟢 Green: 编写最精简的业务代码,让测试恰好通过。
  • 🔵 Refactor: 在测试持续通过的前提下,重构优化代码的设计和质量。

借助测试驱动开发(TDD)思想,我们先为AI提供一份清晰、无歧义的“需求说明书”和“验收标准”,然后指导它进行代码的生成。这个过程的核心是“🔴 红-🟢 绿-🔵 重构”循环,它将我们的每一次的对话,都转化为一次可验证的、可累加的进步。采用“先验证,后实现”的红-绿-重构循环,将模糊的需求转化为精确的代码语言。

4.3 案例:优惠券使用规则引擎的复杂逻辑

业务需求:开发一个智能优惠券使用规则引擎,支持”多券叠加使用和最优组合推荐”

传统困难

  • 自然语言描述:“实现优惠券规则引擎,支持多种券类型的叠加使用,并智能推荐最优使用方案”
  • AI需要猜测:哪些券可以叠加?什么是“最优”?有哪些使用限制?
  • 反复沟通:多次修改提示词,AI理解仍然偏离业务实际

第一次尝试:AI理解为“简单累加所有优惠”

// AI第一次实现 - 过于简化
public BigDecimal calculateDiscount(Order order, List<Coupon> coupons) {
    return coupons.stream()
        .map(coupon -> coupon.getDiscountAmount())
        .reduce(BigDecimal.ZERO, BigDecimal::add);
}
// 问题:忽略了券的使用条件、互斥规则、叠加限制

第二次尝试:AI理解为“选择面额最大的券”

// AI第二次实现 - 逻辑错误
public List<Coupon> selectOptimalCoupons(Order order, List<Coupon> availableCoupons) {
    return availableCoupons.stream()
        .filter(coupon -> order.getTotalAmount().compareTo(coupon.getMinOrderAmount()) >= 0)
        .max(Comparator.comparing(Coupon::getDiscountAmount))
        .map(List::of)
        .orElse(Collections.emptyList());
}
// 问题:只考虑单券最大优惠,未考虑多券组合的更优效果

第三次尝试:AI尝试复杂逻辑但引入更多问题

// AI第三次实现 - 逻辑混乱
public CouponUsageResult applyCoupons(Order order, List<Coupon> coupons) {
    // 各种复杂的if-else嵌套,但缺乏清晰的业务规则
    // 没有处理券的互斥关系
    // 没有考虑计算顺序对最终优惠的影响
    // 边界条件处理不当
}

经过多轮提示词优化,每次都需要重新解释复杂的业务规则,仍不满足预期。

TDD方式的完整循环:

🔴 红色阶段:用测试定义需求

编写测试用例,精确定义复杂的业务规则:

@Test
public void testCouponUsageWithBasicStackingRules() {
    // 构造订单:总价100元,包含数码产品
    Order order = new Order()
        .setTotalAmount(new BigDecimal("100.00"))
        .addItem("数码产品", new BigDecimal("100.00"));
    
    // 构造可用优惠券
    List<Coupon> availableCoupons = Arrays.asList(
        new Coupon().setType("满减券").setCondition("满50减10").setDiscountAmount(new BigDecimal("10")),
        new Coupon().setType("打折券").setCondition("数码类9折").setDiscountRate(new BigDecimal("0.9")),
        new Coupon().setType("免邮券").setCondition("免运费").setDiscountAmount(new BigDecimal("5"))
    );
    
    // 期望结果:满减券和免邮券可叠加,打折券与满减券互斥,应选择最优组合
    CouponUsageResult result = CouponEngine.calculateOptimalUsage(order, availableCoupons);
    
    // 验证最优方案:使用打折券+免邮券 (90+0=90元,比满减券+免邮券的85元更优)
    assertEquals(2, result.getUsedCoupons().size());
    assertTrue(result.getUsedCoupons().stream().anyMatch(c -> "打折券".equals(c.getType())));
    assertTrue(result.getUsedCoupons().stream().anyMatch(c -> "免邮券".equals(c.getType())));
    assertEquals(new BigDecimal("95.00"), result.getFinalAmount()); // 100*0.9 + 0 - 5运费
}

@Test  
public void testCouponMutualExclusionRules() {
    Order order = new Order().setTotalAmount(new BigDecimal("200.00"));
    
    List<Coupon> availableCoupons = Arrays.asList(
        new Coupon().setType("满减券").setCondition("满100减30").setDiscountAmount(new BigDecimal("30")),
        new Coupon().setType("打折券").setCondition("全场8折").setDiscountRate(new BigDecimal("0.8")),
        new Coupon().setType("新用户专享").setCondition("首单5折").setDiscountRate(new BigDecimal("0.5"))
    );
    
    CouponUsageResult result = CouponEngine.calculateOptimalUsage(order, availableCoupons);
    
    // 验证互斥规则:新用户券与其他券互斥,且优惠最大,应该单独使用
    assertEquals(1, result.getUsedCoupons().size());
    assertEquals("新用户专享", result.getUsedCoupons().get(0).getType());
    assertEquals(new BigDecimal("100.00"), result.getFinalAmount()); // 200 * 0.5
}

@Test
public void testCouponUsageConditionValidation() {
    Order order = new Order()
        .setTotalAmount(new BigDecimal("30.00"))
        .setUserLevel("普通用户")
        .addItem("服装", new BigDecimal("30.00"));
    
    List<Coupon> availableCoupons = Arrays.asList(
        new Coupon().setCondition("满50减10"), // 不满足金额条件
        new Coupon().setCondition("VIP专享9折"), // 不满足用户等级条件  
        new Coupon().setCondition("数码类8折"), // 不满足品类条件
        new Coupon().setCondition("无门槛5元券").setDiscountAmount(new BigDecimal("5")) // 满足条件
    );
    
    CouponUsageResult result = CouponEngine.calculateOptimalUsage(order, availableCoupons);
    
    // 验证条件判断:只有无门槛券可用
    assertEquals(1, result.getUsedCoupons().size());
    assertEquals("无门槛5元券", result.getUsedCoupons().get(0).getCondition());
    assertEquals(new BigDecimal("25.00"), result.getFinalAmount());
}

运行测试:

[ERROR] testCouponUsageWithBasicStackingRules: 
Class CouponEngine doesn't exist
[ERROR] testCouponMutualExclusionRules:
Method calculateOptimalUsage not found

红色阶段成功:测试失败,但复杂的业务规则已经通过代码精确表达。

🟢 绿色阶段:AI精确实现

将失败的测试用例提供给AI:“请实现CouponEngine.calculateOptimalUsage方法,让这些测试通过”

AI分析测试用例后,精确理解了复杂的业务规则:

  1. 券类型包括满减券、打折券、免邮券、新用户券等
  2. 不同券有不同的叠加和互斥规则
  3. 需要验证使用条件(金额、用户等级、商品类别)
  4. 要计算最优的券使用组合

AI生成的实现方案:

public class CouponEngine {
    public static CouponUsageResult calculateOptimalUsage(Order order, List<Coupon> availableCoupons) {
        // 1. 过滤出满足使用条件的券
        List<Coupon> eligibleCoupons = availableCoupons.stream()
            .filter(coupon -> isEligible(order, coupon))
            .collect(Collectors.toList());
        
        // 2. 生成所有可能的券组合(考虑互斥规则)
        List<List<Coupon>> validCombinations = generateValidCombinations(eligibleCoupons);
        
        // 3. 计算每种组合的最终优惠,选择最优方案
        return validCombinations.stream()
            .map(combination -> calculateResult(order, combination))
            .min(Comparator.comparing(CouponUsageResult::getFinalAmount))
            .orElse(new CouponUsageResult(order.getTotalAmount(), Collections.emptyList()));
    }
    
    private static boolean isEligible(Order order, Coupon coupon) {
        String condition = coupon.getCondition();
        
        // 金额条件检查
        if (condition.contains("满") && condition.contains("减")) {
            BigDecimal minAmount = extractMinAmount(condition);
            if (order.getTotalAmount().compareTo(minAmount) < 0) return false;
        }
        
        // 用户等级检查
        if (condition.contains("VIP") && !"VIP用户".equals(order.getUserLevel())) {
            return false;
        }
        
        // 商品类别检查
        if (condition.contains("数码类") && !order.hasCategory("数码产品")) {
            return false;
        }
        
        return true;
    }
    
    private static List<List<Coupon>> generateValidCombinations(List<Coupon> coupons) {
        List<List<Coupon>> combinations = new ArrayList<>();
        
        // 生成所有子集组合
        for (int i = 0; i < Math.pow(2, coupons.size()); i++) {
            List<Coupon> combination = new ArrayList<>();
            for (int j = 0; j < coupons.size(); j++) {
                if ((i & (1 << j)) != 0) {
                    combination.add(coupons.get(j));
                }
            }
            
            // 检查组合是否符合互斥规则
            if (isValidCombination(combination)) {
                combinations.add(combination);
            }
        }
        
        return combinations;
    }
    
    private static boolean isValidCombination(List<Coupon> combination) {
        // 检查互斥规则
        boolean hasDiscountCoupon = combination.stream().anyMatch(c -> "打折券".equals(c.getType()));
        boolean hasReduceCoupon = combination.stream().anyMatch(c -> "满减券".equals(c.getType()));
        boolean hasNewUserCoupon = combination.stream().anyMatch(c -> "新用户专享".equals(c.getType()));
        
        // 新用户券与其他券互斥
        if (hasNewUserCoupon && combination.size() > 1) {
            return false;
        }
        
        // 打折券与满减券互斥
        if (hasDiscountCoupon && hasReduceCoupon) {
            return false;
        }
        
        return true;
    }
    
    private static CouponUsageResult calculateResult(Order order, List<Coupon> usedCoupons) {
        BigDecimal finalAmount = order.getTotalAmount();
        
        // 按照优先级顺序应用优惠
        for (Coupon coupon : usedCoupons) {
            if ("打折券".equals(coupon.getType())) {
                finalAmount = finalAmount.multiply(coupon.getDiscountRate());
            } else if ("满减券".equals(coupon.getType()) || "无门槛5元券".equals(coupon.getCondition())) {
                finalAmount = finalAmount.subtract(coupon.getDiscountAmount());
            } else if ("免邮券".equals(coupon.getType())) {
                // 免邮券单独处理运费
                finalAmount = finalAmount.subtract(coupon.getDiscountAmount());
            }
        }
        
        return new CouponUsageResult(finalAmount, usedCoupons);
    }
}

运行测试:

[INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0
[INFO] All tests passed!

绿色阶段成功:测试通过,复杂的业务逻辑完全正确。

🔵 重构阶段:优化代码质量

在测试保护下,对AI生成的代码进行质量优化:

public class CouponEngine {
    // 提取常量,增强可读性
    private static final Set<String> MUTUALLY_EXCLUSIVE_TYPES = Set.of("打折券", "满减券");
    private static final String NEW_USER_COUPON_TYPE = "新用户专享";
    
    public static CouponUsageResult calculateOptimalUsage(Order order, List<Coupon> availableCoupons) {
        if (CollectionUtils.isEmpty(availableCoupons)) {
            return new CouponUsageResult(order.getTotalAmount(), Collections.emptyList());
        }
        
        // 使用策略模式优化条件验证
        List<Coupon> eligibleCoupons = availableCoupons.stream()
            .filter(coupon -> CouponValidator.isEligible(order, coupon))
            .collect(Collectors.toList());
        
        // 使用组合算法优化券组合生成
        List<List<Coupon>> validCombinations = CouponCombinator.generateValidCombinations(eligibleCoupons);
        
        // 使用计算引擎优化折扣计算
        return validCombinations.stream()
            .map(combination -> DiscountCalculator.calculateResult(order, combination))
            .min(Comparator.comparing(CouponUsageResult::getFinalAmount))
            .orElse(new CouponUsageResult(order.getTotalAmount(), Collections.emptyList()));
    }
}

// 职责分离:券验证器
class CouponValidator {
    public static boolean isEligible(Order order, Coupon coupon) {
        return AmountValidator.validate(order, coupon) &&
               UserLevelValidator.validate(order, coupon) &&
               CategoryValidator.validate(order, coupon);
    }
}

// 职责分离:券组合器
class CouponCombinator {
    public static List<List<Coupon>> generateValidCombinations(List<Coupon> coupons) {
        return PowerSetGenerator.generate(coupons).stream()
            .filter(MutualExclusionChecker::isValidCombination)
            .collect(Collectors.toList());
    }
}

// 职责分离:折扣计算器
class DiscountCalculator {
    public static CouponUsageResult calculateResult(Order order, List<Coupon> usedCoupons) {
        // 按优先级排序券,确保计算顺序正确
        List<Coupon> sortedCoupons = usedCoupons.stream()
            .sorted(Comparator.comparing(CouponPriorityResolver::getPriority))
            .collect(Collectors.toList());
        
        BigDecimal finalAmount = order.getTotalAmount();
        
        for (Coupon coupon : sortedCoupons) {
            finalAmount = applyCouponDiscount(finalAmount, coupon);
        }
        
        return new CouponUsageResult(finalAmount, usedCoupons);
    }
    
    private static BigDecimal applyCouponDiscount(BigDecimal currentAmount, Coupon coupon) {
        return CouponTypeHandler.getHandler(coupon.getType())
            .applyDiscount(currentAmount, coupon);
    }
}

重构验证:

[INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0
[INFO] 重构完成,测试持续通过,代码结构更清晰,职责分离更明确

协作模式转变:开发者不再需要为如何描述复杂的业务规则而烦恼,现在只需专注于设计精确的测试场景——我们负责定义“做什么”和“预期结果”,而AI则负责实现具体的“怎么做”。这种明确的分工让复杂逻辑的开发变得既可控又高效。

通过这种方式,我们能够确保:

  1. 需求表达精准无歧义
  2. 边界条件全面覆盖
  3. 实现过程完全可控
  4. 重构过程安全可靠

当需要开发新场景时,只需新增测试用例即可,完全不必担心会破坏原有逻辑。这种开发模式不仅提升了效率,更确保了系统的稳定性和可维护性。

五、实践要点

5.1 环境配置

确保AI Agent能执行mvn test命令

设定明确的行为准则(Rule),让AI能够知道我们现在遵循的开发范式,防止AI为了通过测试”作弊”修改业务代码。一个借助TDD思想驱动代码生成的执行准则如下

# AI Agent 行为准则:TDD 测试驱动开发

## 1. 总则

### 1.1. 概述
为了确保 AI Agent 遵循 TDD(测试驱动开发)的开发模式,Agent 必须严格按照 **Red-Green-Refactor** 三个阶段的循环进行开发。在执行每个阶段前,Agent 必须向开发者明确声明其当前所处的阶段。

本准则旨在确保 Agent 遵循正确的 TDD 开发流程,避免跳过关键步骤。

### 1.2. 环境配置:强制使用指定的 settings.xml
**核心要求**: 所有对 `mvn@ 命令的调用(如 mvn test@, mvn compile@ 等),都**必须**使用 --settings@ (或 -s@) 参数来指定一个自定义的 settings.xml` 文件,以确保能够访问内部的 Maven 仓库。

- **命令格式示例**: `mvn --settings [settings.xml的绝对路径] test`
- **`settings.xml` 文件路径**: `[settings.xml的绝对路径]`

Agent 在执行任何 Maven 命令前,必须确认此路径已被正确配置和使用。

---

## 2. TDD 三阶段循环

### 2.1. 第一阶段:RED (写失败的测试)

#### 2.1.1. 目标
编写一个**必然失败**的测试用例,明确定义即将实现的功能需求。

#### 2.1.2. 核心准则
- **允许**: Agent 可以在 `src/test/` 目录下创建新的测试文件或添加新的测试方法
- **要求**:
  - 测试必须是失败的(因为对应的实现代码尚未存在或不完整)
  - 一次只测试一个功能点
  - 测试代码要简单清晰
  - 测试名称要明确表达测试意图
- **禁止**: Agent **不能**修改 `src/main/` 目录下的任何现有代码
- **验证**: 运行测试必须显示红色(失败状态)

#### 2.1.3. 交互示例
- **开发者提示**: "我需要实现一个计算器的加法功能"
- **Agent 回应**: "已激活 **RED 阶段**。我将先编写一个失败的测试用例来定义加法功能的需求。"

### 2.2. 第二阶段:GREEN (让测试通过的最简实现)

#### 2.2.1. 目标
编写**最简单**的实现代码,让当前失败的测试通过。

#### 2.2.2. 核心准则
- **允许**: Agent 可以创建、修改 `src/main/` 目录下的代码
- **要求**:
  - 优先考虑最简单的实现方式
  - 专注于满足当前测试用例
  - 快速实现功能让测试通过
- **禁止**:
  - **不能**修改测试代码
  - **不考虑**代码质量和性能优化
  - **不进行**过度设计
- **验证**: 运行测试必须显示绿色(通过状态)

#### 2.2.3. 交互示例
- **Agent 回应**: "已激活 **GREEN 阶段**。我将实现最简单的代码来让刚才的测试通过,不考虑优化和设计。"

### 2.3. 第三阶段:REFACTOR (重构优化)

#### 2.3.1. 目标
在保持测试通过的前提下,改进代码的设计、质量和可维护性。

#### 2.3.2. 核心准则
- **允许**: Agent 可以重构 `src/main/` 目录下的实现代码
- **要求**:
  - 改进代码设计和质量
  - 消除重复代码
  - 提高代码可读性和可维护性
  - 每次重构后必须运行测试确保通过
- **禁止**:
  - **不能**修改测试的行为和期望
  - **不能**破坏现有功能
- **验证**: 重构过程中和完成后,所有测试必须保持绿色

#### 2.3.3. 交互示例
- **Agent 回应**: "已激活 **REFACTOR 阶段**。我将重构代码以提高质量,同时确保所有测试保持通过状态。"

---

## 3. TDD 最佳实践

### 3.1. 循环节奏
- **小步快走**: 每个 Red-Green-Refactor 循环应该很短(几分钟到十几分钟)
- **频繁验证**: 每个阶段完成后都要运行测试验证
- **逐步推进**: 一次只关注一个小功能点

### 3.2. 测试质量要求
- **快速执行**: 单元测试应该在秒级内完成
- **独立性**: 测试之间不应该有依赖关系
- **可重复性**: 测试结果应该是确定的和可重复的
- **清晰命名**: 测试方法名应明确表达测试意图

### 3.3. 代码质量保证
- **持续重构**: 在每个循环的 REFACTOR 阶段改进代码
- **消除重复**: 遵循 DRY(Don't Repeat Yourself)原则
- **保持简洁**: 代码应该简洁明了,易于理解

### 3.4. 流程控制
Agent 在每个阶段转换时,必须:
1. 明确声明即将进入的阶段
2. 说明当前阶段的具体目标
3. 完成阶段后验证结果
4. 确认是否继续下一个循环

5.2 掌握单测语法

AI擅长基础用例覆盖,但复杂业务场景、边界条件仍有可能需要开发者手动编写。不要完全依赖AI构造用例。

5.3 选择合适场景与策略

快速决策法则:

  • 简单功能:单个方法,逻辑直观,采用“先实现,后验证”;
  • 复杂业务逻辑:多分支判断、算法计算、状态转换,采用TDD“先验证,后实现”;
  • 存量代码修改:采用“安全网保护”策略;
  • 提示词难以描述需求时:测试用例是最好的需求文档,采用TDD让代码直接表达需求。

5.4 持续维护

单元测试必须与业务代码演进保持同步。一个过时的、无人维护的测试集,其价值会迅速归零,甚至成为负资产。

六、结语

如今,单元测试已被赋予全新的意义——它不再被视为一种“开发负担”,而是进化成为AI Coding时代的“质量引擎”。

我们构建起三重关键保障:

  • 策略一:以客观检验替代主观判断,让AI代码告别“看起来没问题”的错觉;
  • 策略二:为存量代码筑起防护墙,使修改存量代码安全可控,降低演进风险;
  • 策略三:用测试作为与AI的沟通语言,精准传递复杂需求与预期。

更深层次的变化在于,我们正在重新定义开发者的核心价值:当我们从“思考提示词”转向“思考测试用例”,本质上是从AI代码被动的审查者,转变为了主动的需求设计者与质量掌控者。这不仅加速开发进程,更显著提升代码质量。这正是AI时代中,开发者与智能工具协同进化的优秀范式。

我的工作流是一个围绕 superpowers 插件Loop,superpowers 的理念是:先思考再动手。当你提出一个需求,不会急于写代码,而是先退一步问你"你真正想要实现什么",通过对话梳理出完整的设计方案,再分步执行。

核心设计是 masterworker 分离。

  • 脑暴会话 (master):专注于思考和设计,输出高质量的设计文档和执行计划
  • 执行会话 (worker):专注于代码实现,执行详细的计划

分享一下我的 ClaudeCode 工作流:Kitty + Zed + superpowers,可以减少和 AI 的反复拉扯,一次做对1

1、需求录入 - 首先我会在 Zed 上进行需求录入,采用 md 格式。这一步非常重要,我大概有 30% 的时间花在需求录入上,我会把能想到的关于此需求的背景、最终目标、可行的技术方案、风险点、外部 API 文档等等一切资源,都在需求文档中说明。对于需求文档,我不会太在意格式,会有比较多口语化的表达。

2、脑暴阶段 - 把需求 MD 喂给 Claude,调用 /superpowers:brainstorm 和 claude 进行思维碰撞。这个阶段不写任何代码,只讨论设计方案和实现细节,最终输出 design.mdimplement.md,保证最终的实现方案是完美符合我的预期的。

3、 执行阶段 - 这里我会选择新起一个 ClaudeCode 会话,而不是在脑暴会话中进行代码实现。新会话的好处:一、原先脑暴会话已经经过多轮对话了,一般情况下上下文会比较满,新会话响应更快,并且不会“犯傻”;二、implement.md 足够详细,无需额外上下文

4、 CodeReview - 在 Zed 中进行代码审查和功能验收。关于代码审查,对于一些代码细节和实现原理,这里我会使用 zed-agent 来辅助我进行代码 review,当然,你也可以在终端新建一个 ClaudeCode 会话或者使用 Zed 的 Claude Agent。原则是尽量不在脑暴和执行会话中引入太多不必要的问题,保持这两个会话的「干净」。发现问题后,将改进项写入新的需求 MD

5、 LOOP - 改进项 MD 喂回脑暴会话,开始下一轮脑暴迭代

非常简单,但是效果超群。充分的前期设计可以提升 AI 的效率和质量,避免多次的来回拉扯。

举个真实案例:我用这套工作流将个人博客从 Quarz 框架迁移到 Astro 框架。脑暴阶段确认好设计方案后,我让 Claude 执行计划,然后就去睡午觉了。醒来发现 Claude Code 已经完美完成任务——中间零中断,一次成功,共计 5000+ 行代码变更。

我的工作流是一个围绕 superpowers 插件Loop,superpowers 的理念是:先思考再动手。当你提出一个需求,不会急于写代码,而是先退一步问你"你真正想要实现什么",通过对话梳理出完整的设计方案,再分步执行。

核心设计是 masterworker 分离。

  • 脑暴会话 (master):专注于思考和设计,输出高质量的设计文档和执行计划
  • 执行会话 (worker):专注于代码实现,执行详细的计划

分享一下我的 ClaudeCode 工作流:Kitty + Zed + superpowers,可以减少和 AI 的反复拉扯,一次做对1

1、需求录入 - 首先我会在 Zed 上进行需求录入,采用 md 格式。这一步非常重要,我大概有 30% 的时间花在需求录入上,我会把能想到的关于此需求的背景、最终目标、可行的技术方案、风险点、外部 API 文档等等一切资源,都在需求文档中说明。对于需求文档,我不会太在意格式,会有比较多口语化的表达。

2、脑暴阶段 - 把需求 MD 喂给 Claude,调用 /superpowers:brainstorm 和 claude 进行思维碰撞。这个阶段不写任何代码,只讨论设计方案和实现细节,最终输出 design.mdimplement.md,保证最终的实现方案是完美符合我的预期的。

3、 执行阶段 - 这里我会选择新起一个 ClaudeCode 会话,而不是在脑暴会话中进行代码实现。新会话的好处:一、原先脑暴会话已经经过多轮对话了,一般情况下上下文会比较满,新会话响应更快,并且不会“犯傻”;二、implement.md 足够详细,无需额外上下文

4、 CodeReview - 在 Zed 中进行代码审查和功能验收。关于代码审查,对于一些代码细节和实现原理,这里我会使用 zed-agent 来辅助我进行代码 review,当然,你也可以在终端新建一个 ClaudeCode 会话或者使用 Zed 的 Claude Agent。原则是尽量不在脑暴和执行会话中引入太多不必要的问题,保持这两个会话的「干净」。发现问题后,将改进项写入新的需求 MD

5、 LOOP - 改进项 MD 喂回脑暴会话,开始下一轮脑暴迭代

非常简单,但是效果超群。充分的前期设计可以提升 AI 的效率和质量,避免多次的来回拉扯。

举个真实案例:我用这套工作流将个人博客从 Quarz 框架迁移到 Astro 框架。脑暴阶段确认好设计方案后,我让 Claude 执行计划,然后就去睡午觉了。醒来发现 Claude Code 已经完美完成任务——中间零中断,一次成功,共计 5000+ 行代码变更。

如果你…

  • 对一个项目只开了一个 Agent,在无聊地等回复,欲求不满
  • 对一个项目多开了几个 Agent,它们开始疯狂打架、互删代码
  • git stash 用得比 git commit 还多
  • 终端开了 10 个 tab,已经分不清哪个是哪个了
  • 让 AI 重构,结果想回滚却不知道它改了哪些文件
  • 想让 Claude 帮你 review 代码,但又不想打断当前正在写的东西
  • 创建了多个 worktree 来回切换 Agent,编辑器,终端。手指按得快抽筋

那么可能你需要 EnsoAI 来重构你的 AI 辅助开发流


核心理念:

一个分支,一个工作区(Agent+Terminal + 编辑器 + Git 管理)

EnsoAI 将 Git Worktree 与 AI Agent 绑定。每个 worktree 都是独立的工作空间,拥有:

  • 独立的持久化 AI 对话
  • 独立的终端会话
  • 独立的编辑器状态

可以前往官网: https://enso.j3.do/ 在首页演示区中试用体验核心理念


快速安装

macOS (Homebrew)

brew tap j3n5en/ensoai
brew install --cask ensoai

Windows (Scoop)

scoop bucket add ensoai https://github.com/J3n5en/scoop-ensoai
scoop install ensoai

Github 地址: GitHub - J3n5en/EnsoAI: Multiple Agents, Parallel Flow
官网地址: https://enso.j3.do


功能介绍

多 Agent 矩阵

无缝切换 Claude、Codex、Gemini 或自定义 Agent。每个 Worktree 都有独立的持久化 AI 会话

内置 Git 管理器

优雅的可视化 Git 面板。通过键盘即可完成差异对比、暂存修改和提交代码。

内置代码编辑器

基于 Monaco 构建的轻量级编辑器。支持 50+ 种语言高亮,Markdown 实时同步预览

AI 代码审查(需要 claude)

自动生成高质量的 Commit Message,并利用 AI 助手对代码变更进行深度审查与优化。

三栏合并工具

内置 Jetbrains 式的三栏合并编辑器。清晰展示冲突来源,支持一键采纳变更与实时结果预览,让解决冲突变得轻松愉悦。

更多功能:

  • Jetbrains 式的项目全局搜索
  • 强兼 Claude Code 插件式的识别选中个发送代码段功能(claude only)
  • Worktree 管理
  • 远程共享 agent 会话(基于 happy 和 hapi)
  • 400 + 种主题切换
  • quick open 快速联合熟悉工具进行开发(VSCode,Jetbrains,Ghostty,Iterm2…)

欢迎大家 PR ~ happy hacking!


📌 转载信息
原作者:
J3n5en
转载时间:
2025/12/30 10:33:15

[bsgit user="wusimpl"]AntigravityQuotaWatcher[/bsgit]

功能展示

![Antigravity IDE 模型配额监控器插件 [开源](支持 Win/Mac 系统) 1](https://xiaohack.oss-cn-zhangjiakou.aliyuncs.com/typecho/2025/11/2947478344.png!mark)
![Antigravity IDE 模型配额监控器插件 [开源](支持 Win/Mac 系统) 2](https://xiaohack.oss-cn-zhangjiakou.aliyuncs.com/typecho/2025/11/3305152143.png!mark)

使用方法

下载插件,安装,重启,Over(github README 有详细方法)

可配置项

可配置项

插件原理

Antigravity 通过内建的本地语言服务器通信获取数据,插件就是拿到这些端点,然后请求获取数据然后解析。开发过程的难点是获取 crsf token,最后在 AI 的帮助下还是很轻松地拿到了。

几点说明

Gemini Low 和 High 共用一个配额
Claude 和 Claude Thinking 共用一个配额
GPT-OSS 单独一个配额
所以你们在插件里面看到的公用一个配额的模型剩余用量是一样的,Google 也是偷懒…
配额更新默认每 30s 刷新一次,可以在配置里面修改。

Antigravity 目前还只能算半成品,复杂一点的项目出错概率不小,需要等 Google 慢慢迭代修复,或者训练专门针对 code agent 的模型。不过胜在免费,拿来小修小改,做点 Code Review 之类的问题还是不大。