敖雨燕 发表于 2025-6-30 01:38:22

AI编程在OOP场景下探索

AI编程在OOP场景下探索<br><br>背景<br><br>     我们Spring AI工程引用代码如下,由于基于Mock单元测试下ChatClient总是为空,异常是<br>Cannot invoke "org.springframework.ai.chat.client.ChatClient.prompt(String)" because "this.chatClient" is null<br>     Spring AI 1.0.0的正式发布时间为2025年5月20日<br>业务逻辑代码<br><br>@Service<br>public class TaskMcpCallServerServices implements AiService, ChatService {<br>private final ChatClient chatClient;<br>    /**<br>     * Constructs a new TaskMcpCallServerServices instance.<br>     * @param aiClientBuilder the ChatClient builder used to create the chat client<br>     */<br>public TaskMcpCallServerServices(ChatClient.Builder chatClientBuilder) {<br>this.chatClient = chatClientBuilder.build();<br>    }<br>    @Override<br>public ChatClient getChatClient() {<br>return chatClient;<br>    }<br>    @Override<br>    /**<br>     * Gets AI response for the given prompt by calling the MCP server.<br>     * @param prompt the input prompt to send to the AI<br>     * @return ResponseEntity containing the AI response<br>     */<br>public ResponseEntity getAiResponse(String prompt) {<br>String response = this.chatClient<br>                .prompt(prompt)<br>                .call()<br>                .content();<br>return ResponseEntity.ok(response);<br>    }<br>}<br>单元测试代码<br><br>@ExtendWith(MockitoExtension.class)<br>class TaskMcpCallServerServicesTest {<br><br>    @Mock<br>    private ChatClient.Builder chatClientBuilder;<br><br>    @Mock<br>    private ChatClient chatClient;<br><br>    @InjectMocks<br>    private TaskMcpCallServerServices taskMcpCallServerServices;<br><br>    @Test<br>    void testGetAiResponse() {<br>      // Given<br>      String testPrompt = "test prompt";<br>      String expectedResponse = "test response";<br>      <br>      when(chatClientBuilder.build()).thenReturn(chatClient);<br><br>      // When<br>      ResponseEntity<String> actualResponse = taskMcpCallServerServices.getAiResponse(testPrompt);<br><br>      // Then<br>      assertEquals(expectedResponse, actualResponse.getBody());<br>    }}<br>实践<br><br>Qwen3-Thinking模型<br><br><br>看上去解决问题思路没有问题,但实际还是不能解决ChatClient空指针问题。<br>基于Trae+Germin2.5 Flash模型对话如下:<br><br><br>我们查看修改后代码,并不理想<br>@RestController<br>@RequestMapping("/tools")<br>public class ToolController {<br>private final AiService aiService;<br>public ToolController(AiService aiService, ChatService chatService) {<br>this.aiService = aiService;<br>    }<br>    /**<br>     * 使用阿里云对话服务(AMAP)进行文本对话<br>     *<br>     * @param prompt 用户输入的对话内容<br>     * @return ResponseEntity 包含对话结果的HTTP响应<br>     */<br>    @GetMapping("")<br>public ResponseEntity amap(String prompt) {<br>return aiService.getAiResponse(prompt);<br>    }<br>}<br><br><br>Claude4<br><br><br>存在如下问题,大模型的知识还是跟不上组件更新<br>java: 找不到符号<br>   符号:   类 CallPromptSpec<br>   位置: 接口 org.springframework.ai.chat.client.ChatClient<br><br><br>TongYi Lingma-Qwen3-thinking再次尝试<br><br>请对当前类引用类型ChatClient进行完全隔离,ChatClient来自Spring AI框架,我们期望隔离它,并且可以替换为其他AI类库的实现,请基于OOP编程原则修改相关关联代码。<br><br>单元测试没有修复,第二轮对话修复单元测试问题<br><br>最终Qwen3达到期望的结果<br>/**<br> * 聊天客户端适配器接口<br> * 提供统一的方法调用规范,可扩展支持不同AI框架的实现<br> */<br>public interface ChatAdapter {<br>    /**<br>   * 执行AI对话请求<br>   * @param prompt 用户输入内容<br>   * @return 返回处理结果<br>   */<br>    String chat(String prompt);<br>}/**<br> * Spring AI框架适配器实现<br> */<br>@Component<br>public class SpringAiChatAdapter implements ChatAdapter {<br>    private final ChatClient chatClient;<br><br>    public SpringAiChatAdapter(ChatClient chatClient) {<br>      this.chatClient = chatClient;<br>    }<br><br>    @Override<br>    public String chat(String prompt) {<br>      return chatClient.prompt(prompt).call().content();<br>    }<br>}@Service<br>public class TaskMcpCallServerServices implements AiService {<br>    private final ChatAdapter chatAdapter;<br><br>    /**<br>   * Constructs a new TaskMcpCallServerServices instance.<br>   * @param chatAdapter the ChatAdapter instance to use<br>   */<br>    public TaskMcpCallServerServices(ChatAdapter chatAdapter) {<br>      this.chatAdapter = chatAdapter;<br>    }<br><br>    @Override<br>    /**<br>   * Gets AI response for the given prompt by calling the MCP server.<br>   * @param prompt the input prompt to send to the AI<br>   * @return ResponseEntity containing the AI response<br>   */<br>    public ResponseEntity getAiResponse(String prompt) {<br>      String response = this.chatAdapter.chat(prompt);<br>      return ResponseEntity.ok(response);<br>    }<br>}单元测试代码@ExtendWith(MockitoExtension.class)<br>class TaskMcpCallServerServicesTest {<br><br>    @Mock<br>    private ChatAdapter chatAdapter;<br><br>    @InjectMocks<br>    private TaskMcpCallServerServices taskMcpCallServerServices;<br><br>    @BeforeEach<br>    public void before()<br>    {<br>      MockitoAnnotations.openMocks(this);<br>      taskMcpCallServerServices = new TaskMcpCallServerServices(chatAdapter);<br>    }<br><br>    @Test<br>    void testGetAiResponse() {<br>      // Given<br>      String testPrompt = "test prompt";<br>      String expectedResponse = "test response";<br>      <br>      when(chatAdapter.chat(testPrompt)).thenReturn(expectedResponse);<br><br>      // When<br>      ResponseEntity actualResponse = taskMcpCallServerServices.getAiResponse(testPrompt);<br><br>      // Then<br>      assertEquals(expectedResponse, actualResponse.getBody());<br>    }}<br>Trae中Germin 2.5 Flash<br><br><img width="761" height="4515" title="image"alt="image" src="https://img2024.cnblogs.com/blog/15172/202506/15172-20250629215310234-1225760750.png" border="0">新生成文件,编译不通过,并且多次修复未果<img width="901" height="459" title="image"alt="image" src="https://img2024.cnblogs.com/blog/15172/202506/15172-20250629215311080-1443906469.png" border="0">Trae基于DeepSeek V3  0324实践<br><br><img width="694" height="603" title="image"alt="image" src="https://img2024.cnblogs.com/blog/15172/202506/15172-20250629215311935-345557468.png" border="0">存在单元测试问题,第二轮修复单元测试成功<img width="1594" height="612" title="image"alt="image" src="https://img2024.cnblogs.com/blog/15172/202506/15172-20250629215312967-735929455.png" border="0"><br>/**<br> * Interface defining the contract for AI client implementations.<br> * Provides abstraction for different AI service providers.<br> */<br>public interface AiClient {<br>    /**<br>     * Gets AI-generated response for the given prompt.<br>     * @param prompt the input text to send to the AI service<br>     * @return the AI response content<br>     */<br>String getResponse(String prompt);<br>}<br>/**<br> * Service class for handling MCP server calls and AI responses.<br> * Implements AiService interface to provide AI response generation functionality.<br> */<br>@Service<br>public class TaskMcpCallServerServices implements AiService {<br>private final AiClient aiClient;<br>    /**<br>     * Constructs a new TaskMcpCallServerServices instance.<br>     * @param aiClient the AI client implementation<br>     */<br>public TaskMcpCallServerServices(AiClient aiClient) {<br>this.aiClient = aiClient;<br>    }<br>    @Override<br>    /**<br>     * Gets AI response for the given prompt by calling the MCP server.<br>     * @param prompt the input prompt to send to the AI<br>     * @return ResponseEntity containing the AI response<br>     */<br>public ResponseEntity getAiResponse(String prompt) {<br>String response = this.aiClient.getResponse(prompt);<br>return ResponseEntity.ok(response);<br>    }<br>}<br>直接让Claude4 重构<br><br><img width="1477" height="930" title="image"alt="image" src="https://img2024.cnblogs.com/blog/15172/202506/15172-20250629215314150-806432650.png" border="0"><br><font size="3">重构基本是成功的,还使用简单工厂,但新生成UnitTest依赖的API存在版本问题,最终效果如下</font><img width="1253" height="666" title="image"alt="image" src="https://img2024.cnblogs.com/blog/15172/202506/15172-20250629215315250-1662111963.png" border="0">总结<br><br>一、AI编程在OOP场景下的探索意义<br><br>1. 代码生成与模式识别的范式突破<br><br><br>[*]自动化模式实现:AI可通过分析海量开源代码库,自动生成符合设计模式的类结构(如工厂模式、单例模式),减少开发者对模式记忆的依赖。例如,GitHub Copilot已能根据注释生成完整的策略模式实现。<br>[*]语义化代码补全:基于上下文的代码生成超越了传统IDE的语法补全,能理解“实现一个可序列化的订单对象”这类自然语言需求,直接生成符合OOP原则的类定义。<br>2. 重构与演化的智能辅助<br><br><br>[*]架构漂移检测:AI可分析类之间的耦合度、继承层次深度等指标,量化代码异味(Code Smell),辅助决策是否需要引入依赖注入或抽象层。<br>[*]API演进预测:通过学习类库的历史更新日志,AI能预测未来版本可能弃用的方法,提前建议开发者使用适配器模式进行兼容性封装。<br>3. 领域特定语言(DSL)的生成<br><br><br>[*]OOP到DSL的映射:AI可将通用OOP结构转化为特定领域的DSL(如金融风控规则引擎),通过组合策略模式与状态模式,自动生成可配置的业务规则类。<br>二、版本API知识更新滞后的挑战<br><br>1. 知识衰减的典型场景<br><br><br>[*]方法弃用链:例如,Java中java.util.Date到java.time包的迁移,涉及SimpleDateFormat到DateTimeFormatter的替换,但AI可能因训练数据滞后继续推荐旧API。<br>[*]语义化变更:Python 3.10中collections.abc模块的调整,导致直接继承collections.MutableSequence的类需要修改导入路径。<br>2. 上下文提示词的局限性<br><br><br>[*]局部最优陷阱:当开发者询问“如何实现一个线程安全的队列”,AI可能仅推荐queue.Queue而忽略项目已依赖的第三方库(如deque的线程安全封装)。<br>[*]隐式依赖缺失:若类库A的v2版本移除了对类库B的兼容层,AI可能无法从代码上下文中推断出这种跨版本依赖关系。<br>三、专家级综合判断的必要性<br><br>1. 领域知识的不可替代性<br><br><br>[*]业务逻辑映射:例如,在金融系统中,专家能判断某个API变更是否影响交易回滚逻辑,而AI可能仅关注语法正确性。<br>[*]历史债务权衡:专家可评估重构成本与收益,决定是立即迁移到新API还是通过适配器模式暂时兼容。<br>2. 认知推理链的构建<br><br><br>[*]因果推断:当AI建议使用新API时,专家会追问“该API在分布式环境下的线程安全性如何?”“是否有已知的性能回退案例?”<br>[*]反事实分析:专家可模拟“如果采用备选方案B,未来升级到C版本时是否需要二次重构?”<br>四、人机协同的进化路径<br><br>1. 增强型提示工程<br><br><br>[*]多模态输入:将API文档、提交历史、Issue跟踪系统数据融入上下文,例如提示词中包含“此方法在v2.1中标记为@Deprecated,但Issue #1234显示v3.0将恢复”。<br>[*]动态知识注入:通过插件机制实时更新本地知识库,如将Maven仓库的最新版本元数据作为上下文补充。<br>2. AI与专家的协作范式<br><br><br>[*]建议-验证循环:AI生成候选方案,专家通过批判性思维筛选(如“此方案是否违反里氏替换原则?”)。<br>[*]可解释性增强:要求AI输出决策树(如“选择该API是因为其支持泛型,而旧版本仅处理Object类型”)。<br>3. 持续学习的工程实践<br><br><br>[*]自动化测试用例生成:针对API变更,AI可生成覆盖边界条件的单元测试,专家只需验证测试用例的有效性。<br>[*]金丝雀发布策略:在开发分支先部署AI建议的代码,通过监控日志和性能指标,由专家决定是否合并到主分支。<br>五、未来展望:自适应OOP系统<br><br>最终,OOP与AI的融合将走向自适应软件系统:<br><br>[*]动态类加载:根据运行时环境自动选择API版本(如开发环境用最新版,生产环境用稳定版)。<br>[*]演化式设计:类结构不再静态定义,而是通过AI持续优化继承链和组合关系,类似生物体的自然选择过程。<br>这一进程要求开发者从“代码编写者”转型为“系统架构师+AI训练师”,在OOP的抽象层次与AI的生成能力之间构建新的认知桥梁。<br><br><br>来源:程序园用户自行投稿发布,如果侵权,请联系站长删除<br>免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: AI编程在OOP场景下探索