Skip to content

AI编程范式调研

总览中文入门文章:SDD 之外是 Harness 吗?

一个 Harness 资源参考仓库:awesome-harness-engineering

1.1 Vibe Coding

  1. 文章推荐

1.2 SDD

  1. 文章推荐

    这篇文章主要介绍了规格驱动开发(Spec-driven development, SDD)这一AI辅助软件工程新实践,阐述了它通过将清晰的软件规格说明(Spec)作为Prompt来驱动AI生成高质量代码,从而解决“氛围编码(Vibe coding)”带来的无序与代码不可维护问题。

1.3 Harness

  1. 文章推荐
    • [x] Anthropic: Effective harnesses for long-running agents:Anthropic 官方团队分享的 Harness 实践,设计初始化智能体(设定功能列表的 JSON 文件与环境)和编码智能体(单任务增量开发、利用 Git 提交和自动化测试保持环境干净)的“双智能体”协作方案,成功解决了长时运行 AI 智能体(Long-running agents)在跨多上下文窗口任务中容易“急于求成”或“过早宣布胜利”的失败模式。
    • [ ] Addy Osmani: Agent Harness Engineering:Google Chrome 团队工程师写的技术博客。从纯粹的软件工程视角,深度剖析了 Harness 内部的 Hooks(钩子机制)、验证循环的具体做法。
    • [ ] Harness Engineering for AI Coding Agents (Augment Code):补充了前沿大厂的 Monorepo 治理案例(例如 OpenAI 如何用 88 个 AGENTS.md 协作管理庞大的代码库),提供更宏观的 Harness 工业化实践视角。
    • [ ] Anthropic: Harness design for long-running application development 这篇更偏“怎么设计 harness”。一个核心观点是:harness 的每个组件都在编码“模型自己做不到什么”,所以要不断压力测试这些假设;能简化就简化;必要时一次只删一个组件去看效果。这个思路很适合你理解“为什么 harness 比 prompt 更重要”。

1.4 好的实践

  1. 一个 Java 的 Agents.md 关于代码规范的模板,示范了如何把团队的 Java 规范给喂给 AI ,可以在此基础上,做自己的全局代码规范文档。

    markdown
    ## Code Fromatting
    
    - Indentation: 4 spaces.
    - Blank Lines: Use to separate logical blocks of code.
    - Line Length: Maximum 120 characters.
    - Use IntelliJ IDEA default code style for Java.
    
    ## Java Style
    
    - Use UTF-8 encoding.
    - Use descriptive names for classes, methods, and variables.
    - Avoid `var` keyword, prefer explicit types.
    - All method parameters should be `final`.
    - All variables should be declared as `final` where possible.
    - Preference for immutability:
    - Avoid mutations of objects, specially when using for-each loops or Stream API using `forEach()`.
    - Avoid magic numbers and strings; use constants instead.
    - Check emptiness and nullness before operations on collections and strings.
    - Avoid methods using `throws` clause; prefer unchecked exceptions.
    
    - Avoid comments.
    - Comments could be applied for: cron expressions, Regex patterns, TODOs or given/when/then separation in tests.
    - Use `@Override` annotation when overriding methods.
    - Avoid Objects.*isNull() and Objects.*nonNull() for one or two variables; prefer direct null checks for better performance.
    - Wrap multiple conditions in a boolean variable for better readibility
    - Prefer early returns.
    - Avoid else statements when not necessary and try early returns.
    
    ## Lombok Annotations
    
    - Use `@RequiredArgsConstructor` from Lombok for dependency injection via constructor.
    - Use `@Slf4j` from Lombok for logging.
    - Use `@Builder(setterPrefix = "with"))` for complex object creation.
    - Avoid `@Data` annotation; prefer `@Getter` and `@Setter` for granular control.
    
    ## Annotations
    
    - **`@Service`**: For business logic classes.
    - **`@Repository`**: For data access classes that extend JPA repositories or interact with the database.
    - **`@RestController`**: For web controllers.
    - **`@Component`**: For generic Spring components.
    - **`@Configuration`**: For Spring configuration classes.
    - **`@Autowired`**: Prefer constructor injection for production code and field injection only for tests.
    - **`@ConfigurationProperties`**: For binding related properties avoid multiple `@Value` annotations. From more than 2 properties, consider using this annotation.
    - **`@Transactional`**: Only Service classes should be annotated with @Transactional at class level to avoid transaction management in each method.
    - **`@Validated`**: To enable Bean Validation in method parameters or classes.
    - **`@PreAuthorize`**: at the controller layer when using Spring Security to enforce method-level security.
    - Circular dependencies should be avoided. Avoid `@Order` annotation for dependency resolution.
    
    ## Mappers(As a development team choose MapStruct or strictly static Mappers)
    
    **Use MapStruct**
    
    - MapFor mapping between DTOs and entities.
    - Define mapper interfaces with `@Mapper` annotation.
    - Use `@Mapping` annotation for custom field mappings.
    - Use `componentModel = "spring"` to allow Spring to manage mapper instances.
    - Mapper should have as suffix `Mapper` (e.g., `UserMapper`).
    - Name mapper methods clearly (e.g., `toDto`, `toEntity`).
    - Example Mapper Interface:
    
      ```java
      @Mapper(componentModel = "spring")
      public interface UserMapper {
          @Mapping(source = "email", target = "emailAddress")
          UserDTO toDto(User user);
          @Mapping(source = "emailAddress", target = "email")
          User toEntity(UserDTO userDto);
      }
    • For testing mappers, use Mappers.getMapper(UserMapper.class) to get an instance of the mapper.

    Use Static Mappers

    • Define a private constructor to prevent instantiation with UnsupportedOperationException("This class should never be instantiated").

    • Use static methods for mapping between DTOs and entities.

    • Name mapper methods clearly (e.g., toDto, toEntity).

    • Example Static Mapper Class:

      java
      public class UserMapper {
          private UserMapper() {
              throw new UnsupportedOperationException("This class should never be instantiated");
          }
          public static UserDTO toDto(final User user) {
              if (user == null) {
                  return null;
              }
              return UserDTO.builder()
                  .withId(user.getId())
                  .withEmailAddress(user.getEmail())
                  .build();
          }
          public static User toEntity(final UserDTO userDto) {
              if (userDto == null) {
                  return null;
              }
              return User.builder()
                  .withId(userDto.getId())
                  .withEmail(userDto.getEmailAddress())
                  .build();
          }
      }

    Exception Handling

    • Custom Exceptions: Create custom domain exception classes extending RuntimeException.
    • Global Exception Handler: Use @ControllerAdvice and @ExceptionHandler to handle exceptions globally.
    • HTTP Status Codes: Map exceptions to appropriate HTTP status codes in REST controllers.
    • Error Response Structure: Define a consistent error response structure

    Testing

    • Use JUnit 5 for unit and integration testing.
    • Use Mockito for mocking dependencies in unit tests.
    • Use @WebMvcTest(ControllerClass.class) for testing Spring MVC controllers.
    • Use @SpringBootTest for integration tests that require the Spring context.
    • Use given/when/then structure in test methods for clarity.
    • Method naming could follow snake_case or camelCaset convention for test methods (e.g., get_user_by_id_ok, get_user_by_id_not_found_ko).
    • Avoid reflection in tests.
    • Avoid business logic in tests; focus on behavior verification.

    Logging

    • Use @Slf4j annotation from Lombok for logging to avoid boilerplate code with Logger instances.
    • Log at appropriate levels: DEBUG, INFO, WARN, ERROR.
    • Include contextual information in logs (e.g., request IDs, user IDs).
    • Avoid logging sensitive information.
    • Use structured logging for better log management.
    • Format log messages with placeholders (e.g., {}) instead of string concatenation.
    • Logging info code could follow this template: log.info("[MicroserviceName/ModuleName] - API-CALL/METHOD/ACTION: response: {}, userId: {}", body, userId);
    • Logging error code could follow this template: log.error("[MicroserviceName/ModuleName] - API-CALL/METHOD/ACTION: errorMessage: {}, userId: {}", errorMessage, userId);
    
    来源:[Agents.md Guide for Java and Spring Boot Developers](https://josealopez.dev/en/blog/agents-md-java-spring-boot)
  2. 一个有趣的在开始 coding 之前的拆解任务的 prompt

    markdown
    # 🎓 角色设定:顶级编程实战课程设计师 (Curriculum Designer)
    
    你目前是 Codecademy / Udacity 级别的高级课程研发总监。你极其擅长将复杂的真实商业项目,拆解为**面向“高智商但缺乏工程经验的新手程序员”的渐进式实战闯关教程**
    
    我是一名**不编写代码的产品经理兼课程考官**。我将向你提供一份商业产品需求(PRD)。
    你的唯一任务是:基于我的需求,逆向工程设计出一套**《项目全栈落地闯关大纲 (Quest Map)》**。
    
    这套大纲的目的是指导一名“天才学生”一步步从零搭建出生产级应用。你**绝对不要**输出任何具体的业务代码,你的工作是“写教案”。
    
    ## 🧠 核心设计哲学 (Codecademy 模式)
    
    为了让学生在开发中不迷失方向,且每次提交都能获得正向反馈,你设计的关卡必须遵循以下原则:
    
    1. **原子化递进 (Micro-Steps)**
       - 绝对禁止宏大的任务(例如:“开发购物车模块” 是绝对错误的)。
       - 必须拆解为极微小的动作(例如:“关卡 1:渲染购物车静态 UI 骨架”、“关卡 2:编写计算总价的本地纯函数”、“关卡 3:将本地状态接入全局状态管理库”)。
       - **严格防超纲**:必须明确限制学生在当前关卡**禁止**做什么(例如:“本关只画 UI,严禁连接数据库”)。
    
    2. **黑盒验收标准 (Black-box Acceptance Criteria)**
       - 因为我(考官)不看代码,所以每个关卡的通关条件必须是**肉眼可见的物理反馈**
       - 验收标准必须具体到操作步骤。例如:“在终端运行命令 X”、“在浏览器点击按钮 Y”、“在控制台观察到日志 Z”、“在数据库面板看到新增记录 W”。
       - 如果某个后端关卡没有界面,必须要求学生写一个简单的 API 测试脚本或明确要求输出特定的终端日志,以便我验证。
    
    3. **现代工程化与“胶水编程” (Modern Glue Coding)**
       - 引导学生使用成熟的现代技术栈和第三方 SaaS 服务(如 Clerk 鉴权、Supabase 数据库、Vercel 部署等)。
       - 把“阅读并接入某第三方轮子的 API”单独设计为一个关卡。
    
    ## 📋 《闯关大纲》标准输出格式
    
    在理清我的需求后,你必须按以下结构输出 Markdown 格式的教案:
    
    ## 项目需求
    
    _(总结PRD,简述本项目的具体需求)_
    
    ## 阶段 [X]:[阶段名称] (例如:阶段 1:脚手架与静态路由搭建)
    
    _(简述本阶段的学习目标和工程意义)_
    
    ### 🟢 Quest [X.1]:[关卡名称]
    
    - **🎯 关卡目标**:一句话描述本关要完成的单一任务。
    - **🛠️ 推荐工具/轮子**:本关建议使用的库或命令。
    - **🚫 边界限制 (防超纲)**:明确告诉学生本关**不需要**关心什么逻辑。
    - **✅ 考官验收标准 (PM Checklist)**
      - [ ] 测试动作 1:(例如:在根目录执行 `npm run dev`)
      - [ ] 预期结果 1:(例如:浏览器打开 `localhost:3000`,看到包含 "Hello World" 的白屏页面)
      - [ ] 测试动作 2:...
      - [ ] 预期结果 2:...
    
    _(以此类推,穷尽整个产品的所有功能)_
    
    ## 🚦 沟通与设计流程
    
    1. **需求反问**:收到我的 PRD 后,先不要急于出大纲。如果需求中缺失了关键的技术选型约束(比如:想部署在哪?用什么数据库?是否需要移动端适配?),请先向我提问确认。
    2. **大纲草案**:确认无误后,输出完整的《闯关大纲》。
    3. **配合修改**:如果我认为某些关卡的“验收标准”不够直观,或者关卡跨度太大,我会提出意见,你必须重新拆分该关卡。
    4. **抹除修正痕迹**:对大纲发起新的否定/修改/调整指令时,在生成的新的回复中,应直接、流畅地呈现,仿佛它从一开始就是如此。严禁在修正后的大纲中出现引述、反驳或对比旧大纲的语句。输出的大纲必须是正式版本,而不是一篇“被反复修改过”的大纲。

    来源:中文实战:vibe coding 实战心得:让 AI 闯关式编程,成功率提升 400%

  3. 一个我个人认为比较好的任务清单结构,可以用该结构替换掉上面的父任务拆分为的子任务的结构

    json
    {
        "category": "functional",
        "description": "New chat button creates a fresh conversation",
        "steps": [
          "Navigate to main interface",
          "Click the 'New Chat' button",
          "Verify a new conversation is created",
          "Check that chat area shows welcome state",
          "Verify conversation appears in sidebar"
        ],
        "passes": false
      }

    来源:Anthropic: Effective harnesses for long-running agents

  4. 一个我个人认为比较好的 Agents.md 组织的结构,目标:实现渐进式披露,实现较好的上下文管理

    my-project/
    ├── AGENTS.md                        # L1:< 100 行,纯索引
    ├── init.sh                          # 环境苏醒脚本
    └── docs/
        ├── 1-standards/                 # L2:长期稳定,规定"怎么写"
        │   ├── coding-standards.md      # 你已有的 Java 规范
        │   ├── database-conventions.md
        │   ├── testing-standards.md
        │   └── security-guidelines.md
    
        ├── 2-constraints/               # L2:约束型架构规则(非叙述型)
        │   ├── layer-dependencies.md    # 分层依赖规则(什么层能调什么层)
        │   ├── api-contracts.md         # API 设计约定、错误码结构
        │   └── adr/                     # Architecture Decision Records
        │       └── 001-use-mapstruct.md
    
        └── 3-tasks/                     # L3:高频动态,规定"现在干什么"
            ├── CURRENT_PLAN.md          # 当前大任务执行计划(Agent 可更新)
            └── specs/                   # 具体任务 Spec(用完归档)
                └── TASK-101-signin.md