AI编程在OOP场景下探索


AI编程在OOP场景下探索

背景

     我们Spring AI工程引用代码如下,由于基于Mock单元测试下ChatClient总是为空,异常是

Cannot invoke “org.springframework.ai.chat.client.ChatClient.prompt(String)” because “this.chatClient” is null

     Spring AI 1.0.0的正式发布时间为2025年5月20日

业务逻辑代码

@Service

public class TaskMcpCallServerServices implements AiService, ChatService {

private final ChatClient chatClient;

    /**

     * Constructs a new TaskMcpCallServerServices instance.

     * @param aiClientBuilder the ChatClient builder used to create the chat client

     */

public TaskMcpCallServerServices(ChatClient.Builder chatClientBuilder) {

this.chatClient = chatClientBuilder.build();

    }

    @Override

public ChatClient getChatClient() {

return chatClient;

    }

    @Override

    /**

     * Gets AI response for the given prompt by calling the MCP server.

     * @param prompt the input prompt to send to the AI

     * @return ResponseEntity containing the AI response

     */

public ResponseEntity<String> getAiResponse(String prompt) {

String response = this.chatClient

                .prompt(prompt)

                .call()

                .content();

return ResponseEntity.ok(response);

    }

}

单元测试代码

@ExtendWith(MockitoExtension.class)
class TaskMcpCallServerServicesTest {

@Mock
private ChatClient.Builder chatClientBuilder;

@Mock
private ChatClient chatClient;

@InjectMocks
private TaskMcpCallServerServices taskMcpCallServerServices;

@Test
void testGetAiResponse() {
// Given
String testPrompt = "test prompt";
String expectedResponse = "test response";

when(chatClientBuilder.build()).thenReturn(chatClient);

// When
ResponseEntity<String> actualResponse = taskMcpCallServerServices.getAiResponse(testPrompt);

// Then
assertEquals(expectedResponse, actualResponse.getBody());
}
}

实践

Qwen3-Thinking模型

看上去解决问题思路没有问题,但实际还是不能解决ChatClient空指针问题。

基于Trae+Germin2.5 Flash模型对话如下:

我们查看修改后代码,并不理想

@RestController

@RequestMapping(“/tools”)

public class ToolController {

private final AiService aiService;

public ToolController(AiService aiService, ChatService chatService) {

this.aiService = aiService;

    }

    /**

     * 使用阿里云对话服务(AMAP)进行文本对话

     *

     * @param prompt 用户输入的对话内容

     * @return ResponseEntity 包含对话结果的HTTP响应

     */

    @GetMapping(“”)

public ResponseEntity<String> amap(String prompt) {

return aiService.getAiResponse(prompt);

    }

}

Claude4

存在如下问题,大模型的知识还是跟不上组件更新

java: 找不到符号
   符号:   类 CallPromptSpec
   位置: 接口 org.springframework.ai.chat.client.ChatClient

TongYi Lingma-Qwen3-thinking再次尝试

请对当前类引用类型ChatClient进行完全隔离,ChatClient来自Spring AI框架,我们期望隔离它,并且可以替换为其他AI类库的实现,请基于OOP编程原则修改相关关联代码。

单元测试没有修复,第二轮对话修复单元测试问题

最终Qwen3达到期望的结果

/**
* 聊天客户端适配器接口
* 提供统一的方法调用规范,可扩展支持不同AI框架的实现
*/
public interface ChatAdapter {
/**
* 执行AI对话请求
* @param prompt 用户输入内容
* @return 返回处理结果
*/
String chat(String prompt);
}
/**
* Spring AI框架适配器实现
*/
@Component
public class SpringAiChatAdapter implements ChatAdapter {
private final ChatClient chatClient;

public SpringAiChatAdapter(ChatClient chatClient) {
this.chatClient = chatClient;
}

@Override
public String chat(String prompt) {
return chatClient.prompt(prompt).call().content();
}
}
@Service
public class TaskMcpCallServerServices implements AiService {
private final ChatAdapter chatAdapter;

/**
* Constructs a new TaskMcpCallServerServices instance.
* @param chatAdapter the ChatAdapter instance to use
*/
public TaskMcpCallServerServices(ChatAdapter chatAdapter) {
this.chatAdapter = chatAdapter;
}

@Override
/**
* Gets AI response for the given prompt by calling the MCP server.
* @param prompt the input prompt to send to the AI
* @return ResponseEntity containing the AI response
*/
public ResponseEntity<String> getAiResponse(String prompt) {
String response = this.chatAdapter.chat(prompt);
return ResponseEntity.ok(response);
}
}
单元测试代码
@ExtendWith(MockitoExtension.class)
class TaskMcpCallServerServicesTest {

@Mock
private ChatAdapter chatAdapter;

@InjectMocks
private TaskMcpCallServerServices taskMcpCallServerServices;

@BeforeEach
public void before()
{
MockitoAnnotations.openMocks(this);
taskMcpCallServerServices = new TaskMcpCallServerServices(chatAdapter);
}

@Test
void testGetAiResponse() {
// Given
String testPrompt = "test prompt";
String expectedResponse = "test response";

when(chatAdapter.chat(testPrompt)).thenReturn(expectedResponse);

// When
ResponseEntity<String> actualResponse = taskMcpCallServerServices.getAiResponse(testPrompt);

// Then
assertEquals(expectedResponse, actualResponse.getBody());
}
}

Trae中Germin 2.5 Flash

新生成文件,编译不通过,并且多次修复未果

Trae基于DeepSeek V3  0324实践

存在单元测试问题,第二轮修复单元测试成功

/**

* Interface defining the contract for AI client implementations.

* Provides abstraction for different AI service providers.

*/

public interface AiClient {

    /**

     * Gets AI-generated response for the given prompt.

     * @param prompt the input text to send to the AI service

     * @return the AI response content

     */

String getResponse(String prompt);

}

/**

* Service class for handling MCP server calls and AI responses.

* Implements AiService interface to provide AI response generation functionality.

*/

@Service

public class TaskMcpCallServerServices implements AiService {

private final AiClient aiClient;

    /**

     * Constructs a new TaskMcpCallServerServices instance.

     * @param aiClient the AI client implementation

     */

public TaskMcpCallServerServices(AiClient aiClient) {

this.aiClient = aiClient;

    }

    @Override

    /**

     * Gets AI response for the given prompt by calling the MCP server.

     * @param prompt the input prompt to send to the AI

     * @return ResponseEntity containing the AI response

     */

public ResponseEntity<String> getAiResponse(String prompt) {

String response = this.aiClient.getResponse(prompt);

return ResponseEntity.ok(response);

    }

}

直接让Claude4 重构


重构基本是成功的,还使用简单工厂,但新生成UnitTest依赖的API存在版本问题,最终效果如下

总结

一、AI编程在OOP场景下的探索意义
1. 代码生成与模式识别的范式突破
  • 自动化模式实现:AI可通过分析海量开源代码库,自动生成符合设计模式的类结构(如工厂模式、单例模式),减少开发者对模式记忆的依赖。例如,GitHub Copilot已能根据注释生成完整的策略模式实现。
  • 语义化代码补全:基于上下文的代码生成超越了传统IDE的语法补全,能理解“实现一个可序列化的订单对象”这类自然语言需求,直接生成符合OOP原则的类定义。
2. 重构与演化的智能辅助
  • 架构漂移检测:AI可分析类之间的耦合度、继承层次深度等指标,量化代码异味(Code Smell),辅助决策是否需要引入依赖注入或抽象层。
  • API演进预测:通过学习类库的历史更新日志,AI能预测未来版本可能弃用的方法,提前建议开发者使用适配器模式进行兼容性封装。
3. 领域特定语言(DSL)的生成
  • OOP到DSL的映射:AI可将通用OOP结构转化为特定领域的DSL(如金融风控规则引擎),通过组合策略模式与状态模式,自动生成可配置的业务规则类。
二、版本API知识更新滞后的挑战
1. 知识衰减的典型场景
  • 方法弃用链:例如,Java中java.util.Datejava.time包的迁移,涉及SimpleDateFormatDateTimeFormatter的替换,但AI可能因训练数据滞后继续推荐旧API。
  • 语义化变更:Python 3.10中collections.abc模块的调整,导致直接继承collections.MutableSequence的类需要修改导入路径。
2. 上下文提示词的局限性
  • 局部最优陷阱:当开发者询问“如何实现一个线程安全的队列”,AI可能仅推荐queue.Queue而忽略项目已依赖的第三方库(如deque的线程安全封装)。
  • 隐式依赖缺失:若类库A的v2版本移除了对类库B的兼容层,AI可能无法从代码上下文中推断出这种跨版本依赖关系。
三、专家级综合判断的必要性
1. 领域知识的不可替代性
  • 业务逻辑映射:例如,在金融系统中,专家能判断某个API变更是否影响交易回滚逻辑,而AI可能仅关注语法正确性。
  • 历史债务权衡:专家可评估重构成本与收益,决定是立即迁移到新API还是通过适配器模式暂时兼容。
2. 认知推理链的构建
  • 因果推断:当AI建议使用新API时,专家会追问“该API在分布式环境下的线程安全性如何?”“是否有已知的性能回退案例?”
  • 反事实分析:专家可模拟“如果采用备选方案B,未来升级到C版本时是否需要二次重构?”
四、人机协同的进化路径
1. 增强型提示工程
  • 多模态输入:将API文档、提交历史、Issue跟踪系统数据融入上下文,例如提示词中包含“此方法在v2.1中标记为@Deprecated,但Issue #1234显示v3.0将恢复”。
  • 动态知识注入:通过插件机制实时更新本地知识库,如将Maven仓库的最新版本元数据作为上下文补充。
2. AI与专家的协作范式
  • 建议-验证循环:AI生成候选方案,专家通过批判性思维筛选(如“此方案是否违反里氏替换原则?”)。
  • 可解释性增强:要求AI输出决策树(如“选择该API是因为其支持泛型,而旧版本仅处理Object类型”)。
3. 持续学习的工程实践
  • 自动化测试用例生成:针对API变更,AI可生成覆盖边界条件的单元测试,专家只需验证测试用例的有效性。
  • 金丝雀发布策略:在开发分支先部署AI建议的代码,通过监控日志和性能指标,由专家决定是否合并到主分支。
五、未来展望:自适应OOP系统

最终,OOP与AI的融合将走向自适应软件系统

  • 动态类加载:根据运行时环境自动选择API版本(如开发环境用最新版,生产环境用稳定版)。
  • 演化式设计:类结构不再静态定义,而是通过AI持续优化继承链和组合关系,类似生物体的自然选择过程。

这一进程要求开发者从“代码编写者”转型为“系统架构师+AI训练师”,在OOP的抽象层次与AI的生成能力之间构建新的认知桥梁。