AI编程在OOP场景下探索

背景

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

java 复制代码
Cannot invoke "org.springframework.ai.chat.client.ChatClient.prompt(String)" because "this.chatClient" is null

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

业务逻辑代码

java 复制代码
@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);

    }

}

单元测试代码

java 复制代码
@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模型

image

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

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

image

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

java 复制代码
@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

image

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

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

TongYi Lingma-Qwen3-thinking再次尝试

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

image

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

image

最终Qwen3达到期望的结果

java 复制代码
/**
 * 聊天客户端适配器接口
 * 提供统一的方法调用规范,可扩展支持不同AI框架的实现
 */
public interface ChatAdapter {
    /**
     * 执行AI对话请求
     * @param prompt 用户输入内容
     * @return 返回处理结果
     */
    String chat(String prompt);
}
java 复制代码
/**
 * 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();
    }
}
java 复制代码
@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);
    }
}

单元测试代码

java 复制代码
@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实践

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

java 复制代码
/**

* 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的生成能力之间构建新的认知桥梁。

相关推荐
JuiceFS7 分钟前
合合信息:基于 JuiceFS 构建统一存储,支撑 PB 级 AI 训练
运维·后端
调试人生的显微镜13 分钟前
iOS 文件深度调试实战 查看用户文件 App 沙盒 系统文件与日志全指南
后端
aiopencode14 分钟前
没有 Mac,如何上架 iOS App?跨平台团队的全流程实践指南
后端
天天摸鱼的java工程师16 分钟前
如何防止重复提交订单?
java·后端·面试
星星电灯猴19 分钟前
Charles 抓不到包怎么办?详解原因与多维解决方案
后端
慕尘_22 分钟前
对于未来技术的猜想:Manus as a Service
前端·后端
秋水丶秋水29 分钟前
Python常见异常和处理方案
后端·python
程序无bug30 分钟前
pring Boot监控方案
java·后端
荔枝爱编程31 分钟前
高性能企业级消息中心架构实现与分享(二)
后端·消息队列·rocketmq
莹莹啦32 分钟前
Java 21 核心特性全景解析:LTS 版本的革命性升级
后端