大模型代码生成探讨与实践

 

随着大语言模型(LLM)在软件开发领域的应用日益深入,我们正从最初将其视为“黑盒”许愿机,转向探索更精准、可控、可信的“白盒”协同开发模式。代码生成不再是一次性的“魔法”,而是演变为一个需要开发者与 AI 精密协作的结构化流程。

本文将深入探讨并实践四种主流的大模型代码生成方法论:参考示例法上下文约束法测试驱动法分步验证策略。我们将特别聚焦于“上下文约束法”的强大能力,展示它如何通过不同的实践形式,将 AI 从一个简单的工具转变为真正的编程伙伴。


1. 参考示例法 (Few-shot Learning)

核心思想:此方法的核心是“模仿学习”。开发者向大模型提供一个或多个具体的、高质量的代码片段作为“范例”(shots),然后要求模型基于这些范例的风格、结构和逻辑去完成一个新的、类似的任务。这就像教徒弟一样,师傅先做一遍,徒弟跟着学。

深度实践

A. 场景描述 

在一个项目中,已有一个用于获取用户数据的函数 fetchUserById,它包含了标准的日志记录、错误处理和数据返回结构。现在,我们需要创建一个功能类似但用于获取订单数据的 fetchOrderById 函数,并确保其风格与前者完全一致。

B. Prompt 设计 

代码段

 

# Task
请参考下面的 `fetchUserById` 函数示例,为我编写一个新的函数 `fetchOrderById`。

# Reference Example (`fetchUserById`)
```javascript
import axios from 'axios';
import logger from './logger';

/**
 * Fetches a user by their ID.
 * @param {string} userId The ID of the user to fetch.
 * @returns {Promise<{success: boolean, data: object|null, error: string|null}>}
 */
export const fetchUserById = async (userId) => {
  logger.info(`Attempting to fetch user with ID: ${userId}`);
  try {
    const response = await axios.get(`/api/v1/users/${userId}`);
    return { success: true, data: response.data, error: null };
  } catch (error) {
    logger.error(`Failed to fetch user ${userId}:`, error.message);
    return { success: false, data: null, error: error.message };
  }
};

Instructions

  1. 新函数名为 fetchOrderById
  2. 它接收一个 orderId 参数。
  3. 请求的 API 端点是 /api/v1/orders/${orderId}
  4. 严格遵循示例中的日志记录方式、try-catch 错误处理结构以及返回对象的格式。

C. AI 的预期输出


 
```javascript
import logger from './logger';
import axios from 'axios';

/**
 * Fetches an order by its ID.
 * @param {string} orderId The ID of the order to fetch.
 * @returns {Promise<{success: boolean, data: object|null, error: string|null}>}
 */
export const fetchOrderById = async (orderId) => {
  logger.info(`Attempting to fetch order with ID: ${orderId}`);
  try {
    const response = await axios.get(`/api/v1/orders/${orderId}`);
    return { success: true, data: response.data, error: null };
  } catch (error) {
    logger.error(`Failed to fetch order ${orderId}:`, error.message);
    return { success: false, data: null, error: error.message };
  }
};

小结:参考示例法是实现代码风格和模式统一的最快途径之一,但其效果高度依赖范例的质量。


2. 上下文约束法 (Context Constraint Method)

核心思想:这是目前最强大、最核心的AI协同方法论。其本质是通过提供结构化、高密度、无歧义的上下文信息,来精确地约束和引导AI的思考路径和输出结果。它将开发者从一个“提问者”转变为一个“AI任务设计师”,通过精心设计的上下文,将AI的创造力引导到正确的方向上。

这种方法有多种实践形式,从简单到高级,包括:

具体实践一:模板约束法 (Constraining by Template)

这种实践侧重于约束代码的“结构”与“骨架”。开发者提供一个带有占位符的“代码模板”,AI的任务是在这个固定的结构内“填空”。

A. 场景描述

在一个 Spring Boot 项目中,团队规定所有 Controller 方法必须返回统一的 ApiResponse 对象并包含标准的异常处理。

B. Prompt 设计 ✍️

代码段

 

# Task
请使用下面提供的代码模板,为我实现一个“根据ID获取用户信息”的 Controller 方法。

# Code Template
```java
@GetMapping("/{id}")
public ApiResponse<[DTO类型]> [方法名](@PathVariable Long id) {
    try {
        // TODO: [调用 Service 层获取数据]
        return ApiResponse.success([DTO对象]);
    } catch (ResourceNotFoundException e) {
        return ApiResponse.error(404, e.getMessage());
    } catch (Exception e) {
        // TODO: [添加日志记录]
        return ApiResponse.error(500, "Internal Server Error");
    }
}

Instructions

  1. 方法名: getUserById
  2. DTO类型: UserDTO
  3. 调用 Service: 注入 UserService 并调用 userService.findUserById(id)
  4. 日志记录: 使用 log.error("Error getting user by id: {}", id, e);


C. AI 的预期输出


```java
@GetMapping("/{id}")
public ApiResponse getUserById(@PathVariable Long id) {
    try {
        UserDTO userDto = userService.findUserById(id);
        return ApiResponse.success(userDto);
    } catch (ResourceNotFoundException e) {
        return ApiResponse.error(404, e.getMessage());
    } catch (Exception e) {
        log.error("Error getting user by id: {}", id, e);
        return ApiResponse.error(500, "Internal Server Error");
    }
}

小结:模板约束法是保证代码结构和团队规范一致性的利器。

具体实践二:规范驱动法 (Constraining by Specification)

这种实践侧重于约束代码的“功能”与“契约”**。开发者通过详细定义输入、输出、核心逻辑和边界情况,为AI提供一份清晰的“功能说明书”。

A. 场景描述 

您需要编写一个 Python 函数,该函数接收一个用户对象列表,并按年龄分组。

B. Prompt 设计 

代码段

# Task
请为我实现一个名为 `group_users_by_age` 的 Python 函数。

# Specification
'''
def group_users_by_age(users: list[dict]) -> dict:
    """
    将用户列表按照年龄进行分组。
    - Args:
        users (list[dict]): 用户字典列表,每个字典含 'name'(str) 和 'age'(int)。
    - Returns:
        dict: 以年龄为键,姓名列表为值的字典。
    - Raises:
        TypeError: 如果输入不是列表。
    - Behavior:
        - 输入空列表,返回空字典。
        - 忽略列表中格式不正确的数据。
    """
    # TODO: Implement the logic here
'''

小结:规范驱动法是确保核心业务逻辑正确、鲁棒的有效手段。

 

 

 


3. 测试驱动法 (Test-Driven Development)

核心思想:这是一种“需求即测试,目标即通过”的高级用法。开发者不再用自然语言描述需求,而是直接编写一组能够精确定义需求的、初期会“失败”的单元测试用例。然后,AI的任务只有一个:编写出能让所有测试用例都“通过”的业务代码。

深度实践

A. 场景描述 

你需要开发一段逻辑严密、边界条件复杂的算法或业务逻辑,例如一个计算购物车折扣的函数。

B. Prompt 设计 

代码段

 

# Task
请编写 JavaScript 函数 `calculateTotalPrice`,使其能够通过以下所有的 Jest 单元测试。

# Failing Unit Tests
```javascript
describe('calculateTotalPrice', () => {
  it('should not apply discount for regular user under 100', () => {
    expect(calculateTotalPrice(80, 'REGULAR')).toBe(80);
  });
  it('should apply 10% discount for regular user over 100', () => {
    expect(calculateTotalPrice(200, 'REGULAR')).toBe(180);
  });
  it('should apply 20% discount for VIP user', () => {
    expect(calculateTotalPrice(80, 'VIP')).toBe(64);
  });
});

Instructions

函数签名应为 calculateTotalPrice(basePrice, userType)。请实现这个函数。

小结:测试驱动法是生成高可靠性、高正确性代码的黄金标准。

4. 分步验证策略 (Step-by-Step Validation)

核心思想:此方法将大模型视为一个真正的“结对编程伙伴”。开发者将一个复杂的开发任务拆解成一系列逻辑上连续的、更小的步骤。在每一步,开发者都会向模型提出明确的子任务,并对模型返回的结果进行审查(Validation)、确认或修正,然后再进行下一步。这是一个“交互-验证-迭代”的闭环过程。

深度实践

A. 场景描述

要为一个现有系统增加“用户注册成功后发送欢迎邮件”的功能。这涉及到修改现有服务、创建新服务等,需要周全的计划。

B. Prompt 设计 (第一步:规划)

```prompt
# Task:
我要实现一个“用户注册成功后发送欢迎邮件”的需求。

# Context:
主调用方法位于 `UserService` 类的 `register` 方法中。

# Best Practices:
- 功能需通过独立的 `EmailService` 处理。
- 邮件发送应异步执行。

# Action:
请列举为了实现此需求,需要修改或新增哪些文件和方法。
**第一步,只输出规划清单,不要生成任何具体实现代码

C.开发者确认后,可进行第二步

“好的,计划看起来很棒。现在请为我生成 EmailService.java 的代码。”

 

 

小结:分步验证策略将复杂问题简单化,让开发者始终掌握主导权,是处理大型或不确定性任务的最佳选择。


 

四种方法论直观对比

方法论 核心思想 优点 缺点 适用场景
参考示例法 模仿学习,举一反三

- 简单直接,易于上手。

- 快速统一代码风格。

- 强依赖范例质量。

- 难于应对创新性任务。

代码风格迁移、生成重复模式的代码。
上下文约束法 提供结构化信息,精确引导

- 输出高度可控、可预测。

-大幅提升代码采纳率。

- 降低AI“幻觉”。

- 需要前期投入精力设计上下文(模板、规范、蓝图)。

- 对开发者的设计能力有要求。

- 相对机械不够灵活

所有追求高质量、高可用性代码生成的场景,是专业开发的核心方法。
测试驱动法 需求即测试,目标即通过

- 需求定义极其明确。

- 代码质量有测试保障,可靠性最高。

- 对开发者编写测试能力要求高。

- 不适用于UI、探索性编程等。

核心算法、复杂业务逻辑、对可靠性要求极高的模块。
分步验证策略 化整为零,交互迭代

- 过程完全透明,开发者全程主导。

- 灵活性强,可随时调整。

- 适合处理大型、不确定性任务。

- 交互次数多,时间成本相对较高。 大型功能实现、代码重构、与AI结对调试复杂问题。

 

你可能感兴趣的:(大模型,人工智能,经验分享)