链载Ai

标题: AI写代码的“上下文陷阱”:为什么AI总是写错?如何系统性解决? [打印本页]

作者: 链载Ai    时间: 前天 19:01
标题: AI写代码的“上下文陷阱”:为什么AI总是写错?如何系统性解决?

一、如何充分使用模型能力

关键要点:完整+精确+聚焦的上下文是充分使用模型能力的关键。在这个认知之下思考如何系统性的构建满足这个条件的上下文?

这4个关键点的应用中还涉及到尺度的把握(信息的细致程度),而这个尺度会随着模型的能力提升而变化。如早期的模型需要非常详尽的内容输入,当模型能力提升后可以自主从代码中获得足够的背景知识。

二、AI协作编程的方法

2.1. 应用级记忆结构

关键要点:像设计系统架构一样设计上下文架构,暗合近期讨论比较多的上下文工程(context engineering)的概念。在这个认知之下思考如何高效、准确的维护这个上下文工程?

2.2. AI辅助记忆维护

记忆维护关键点:向AI提供的输入内容和产出验收,本身也可以由AI来辅助生成和验证,同时记忆的维护是渐进的,可跟随实际项目逐步完善。

总结:核心是系统性的分层分模块管理上下文,最大程度让AI辅助维护上下文,每次变更的知识负担就可以大幅度下降(输入具体需求即可),配合渐进式的更新维护,使用AI编程工具的效率正循环就形成了。

2.2.1. 记忆示例

功能模块基于、需求迭代记忆的示例涉及到敏感业务代码,不再此处展示

项目结构和技术栈

---description:globs:alwaysApply:true---#AE评测系统开发指南
## 项目结构
-[demo-start](mdc:demo-start): 项目启动模块,**这个模块中没有业务逻辑, 在我没有明确指令是不要修改此模块中的代码**。-[demo-api](mdc:demo-api):HSFAPI接口定义模块,**对于Demo系统的开发,只关心[demo](mdc:demo-api/src/main/java/com/aliexpress/demo) package下的内容, 其他package内容忽略**-[demo/api](mdc:demo-api/src/main/java/com/aliexpress/demo/api)emo系统的HSFAPI的interface均在这个package下定义, 命名后缀为Service-[demo/model](mdc:demo-api/src/main/java/com/aliexpress/demo/model)emo系统的HSFAPI的model均保存在这个package, 命名后缀为Request、DTO-[demo/common](mdc:demo-api/src/main/java/com/aliexpress/demo/common)emo系统的HSFAPI的enum均保存在这个package下, 命名后缀为Enum-[demo/base](mdc:demo-api/src/main/java/com/aliexpress/demo/base)emo系统的HSFAPI的model的基类均保存在这个package下-[demo-biz](mdc:demo-biz): 业务逻辑实现模块,**对于Demo系统的开发,只关心[demo](mdc:demo-api/src/main/java/com/aliexpress/biz/demo) package下的内容, 其他package内容忽略**-[demo/api](mdc:demo-biz/src/main/java/com/aliexpress/biz/demo/api)emo系统的HSFAPI的实现类均在这个package下定义, 命名后缀为ServiceImpl -[demo/api/converter](mdc:demo-biz/src/main/java/com/aliexpress/biz/demo/api/converter)emo系统的HSFAPI的实现类使用的Converter类均保存在这个package下, 命名后缀为Converter -[demo/api/validate](mdc:demo-biz/src/main/java/com/aliexpress/biz/demo/api/validate)emo系统的HSFAPI的实现类使用的校验类均保存在这个package下, 命名后缀为Validate-[demo/common](mdc:demo-biz/src/main/java/com/aliexpress/biz/demo/common)emo系统的内部的公共类均保存在这个package下, 命名后缀为Enum、Constant-[demo/config](mdc:demo-biz/src/main/java/com/aliexpress/biz/demo/config)emo系统的内部的Diamond、HSF配置类均保存在这个package下, 命名后缀为Config、Configuration-[demo/consumer](mdc:demo-biz/src/main/java/com/aliexpress/biz/demo/consumer)emo系统的MetaQConsumer类均保存在这个package下, 命名后缀为Consumer(消费MetaQ) -[demo/consumer/listener](mdc:demo-biz/src/main/java/com/aliexpress/biz/demo/consumer/listener):Demo系统的Consumer的消费逻辑实现类均保存在这个package下, 命名后缀为Listener(实现消费逻辑)-[demo/demouator](mdc:demo-biz/src/main/java/com/aliexpress/biz/demo/demouator):Demo系统的评估器实现类均保存在这个package下, 命名后缀为demouator,**此处的代码相对比较稳定,在我没有明确指令时不要自行修改**-[demo/executor](mdc:demo-biz/src/main/java/com/aliexpress/biz/demo/executor):Demo系统的通用业务逻辑实现类均保存在这个package下, 命名后缀为Executor-[demo/invoker](mdc:demo-biz/src/main/java/com/aliexpress/biz/demo/invoker):Demo系统的调用AI应用的通用封装类均保存在这个package下,**此处的代码相对比较稳定,在我没有明确指令时不要自行修改**-[demo/task](mdc:demo-biz/src/main/java/com/aliexpress/biz/demo/task):Demo系统的任务提交和任务执行的的通用封装类均保存在这个package下,**此处的代码相对比较稳定,在我没有明确指令时不要自行修改**-[demo/util](mdc:demo-biz/src/main/java/com/aliexpress/biz/demo/util):Demo系统的工具类均保存在这个package下,**此处的代码相对比较稳定,在我没有明确指令时不要自行修改**-[demo-core](mdc:demo-core): 核心功能模块, 包含基础设施和通用组件,**对于Demo系统的开发, 任何时候都不需要关注这个模块中的内容**-[demo-job](mdc:demo-job): 定时任务模块,**对于Demo系统的开发, 任何时候都不需要关注这个模块中的内容**-[demo-workflow](mdc:demo-workflow): 工作流相关模块,**对于Demo系统的开发, 任何时候都不需要关注这个模块中的内容**-[demo-infrastructure](mdc:demo-infrastructure): 基础设施模块, 包含数据访问、外部服务集成等,**对于Demo系统的开发, 主要关心其中操作数据库的相关代码**-[dao/demo](mdc:demo-infrastructure/src/main/java/com/aliexpress/infrastructure/dao/demo):Demo系统的Mybatis-Plus的Mapper类均保存在这个package下,后缀为Mapper-[model/demo](mdc:demo-infrastructure/src/main/java/com/aliexpress/infrastructure/model/demo): Demo系统的Mybatis-Plus的实体类均保存在这个package下,其中PO后缀的是与数据库表直接映射的实体类,其中/model文件夹下的类是和业务层交互的实体类-[model/convert](mdc:demo-infrastructure/src/main/java/com/aliexpress/infrastructure/model/convert):Demo系统的Mybatis-Plus的PO与Model之间的转换类均保存在这个package下,后缀为Converter-[repository](mdc:demo-infrastructure/src/main/java/com/aliexpress/infrastructure/repository):Demo系统的数据库操作类均保存在这个package下,接口后缀为Repository,实现类后缀为RepositoryImpl,核心的作用是调用Mapper与数据库操作、转换PO与Model-[demo-provider](mdc:demo-provider): 服务提供者模块-[hsf/provider](mdc:demo-provider/src/main/java/com/aliexpress/provider/hsf/provider): 增加新的HSF服务Provider需要在 [HsfProviderConfig.java](mdc:demo-provider/src/main/java/com/aliexpress/provider/hsf/provider/HsfProviderConfig.java)类中增加配置-[demo-sdk](mdc:demo-sdk):Demo系统SDK工具模块,**此处的代码相对比较稳定,在我没有明确指令时不要自行修改**
## 主要技术栈
-PandoraBoot: 基于SpringBoot的阿里内部框架-HSF: 阿里内部的RPC框架-Diamond: 阿里内部的配置中心-Tair: 阿里内部的缓存服务-MetaQ: 阿里内部的消息服务-MyBatis-Plus: 轻量级的ORM框架

DAO层代码规范

---description: 根据创建表的SQL生成操作数据库层增删改查代码时引用此文件globs:alwaysApply:false---## 操作数据库编码规范#### 操作DB框架1. 开发框架:使用MyBatis-Plus进行编码2. 调用逻辑:上层通过注入的方式调用Repository的实现,在Repository的实现的实现中调用Mapper,调用Mapper后返回的对象是PO,再通过Converter转换成Model后返回为上层调用方。3. 数据类型的选择:时间字段使用java.util.Date类型4. 使用MyBatis-Plus方法注意事项:注意不要调用deprecated的方法5.Repository层的删除方法:统一使用逻辑删除,逻辑删除字段是is_deleted6.Repository层需操作时需要附加对当前环境的处理:调用[EnvUtil.java](mdc:task-infrastructure/src/main/java/com/aliexpress/qa/task/infrastructure/util/EnvUtil.java)的getEnv().getCode()方法7.Repository层的的分页方法:调用MyBatis-Plus的selectPage方法 ####DAO层PO1.DAO层PO的命名规范为${TableName}PO2.DAO层PO的存放目录[model](mdc:task-infrastructure/src/main/java/com/aliexpress/qa/task/infrastructure/model)
####DAO层Mapper1.DAO层Mapper命名规范为${TableName}Mapper2.DAO层Mapper的存放目录[dao](mdc:task-infrastructure/src/main/java/com/aliexpress/qa/task/infrastructure/dao) ####Repository层1.Repository层interface命名规范为${TableName}Repository2.Repository层实现命名规范为${TableName}RepositoryImpl3.Repository层Model命名规范为${TableName}Model4.Repository层interface的存放目录[repository](mdc:task-infrastructure/src/main/java/com/aliexpress/qa/task/infrastructure/repository)5.Repository层实现的存放目录[repositoryimpl](mdc:task-infrastructure/src/main/java/com/aliexpress/qa/task/infrastructure/repository/impl)6.Repository层Model存放目录[model](mdc:task-infrastructure/src/main/java/com/aliexpress/qa/task/infrastructure/model)
####Converter层1.Converter层命名规范位${TableName}Converter2.Converter层的存放目录[convert](mdc:task-infrastructure/src/main/java/com/aliexpress/qa/task/infrastructure/model/convert)3.Converter代码规范:使用字段进行映射,禁止使用json序列化、BeanUtils.copyProperties等方式
## 参考代码1.DAO层PO参考代码``` javaimportcom.baomidou.mybatisplus.annotation.TableName;importlombok.AllArgsConstructor;importlombok.Builder;importlombok.Data;importlombok.NoArgsConstructor;
${必要的引用}
/*** @author chigong.zxn*/@Data@Builder@TableName(value="${tableName}")@AllArgsConstructor@NoArgsConstructorpublicclass ${TableName}PO{ ${注释} ${只可以使用包装类型,禁止使用基础类型} ${columnName}}```2.DAO层Mapper参考代码,【注意:不需要增加增删改查方法,MyBatis-Plus已经默认通过继承BaseMapper提供】``` javaimportcom.aliexpress.qa.task.infrastructure.model.eval.${TableName}PO;importcom.baomidou.mybatisplus.core.mapper.BaseMapper;importorg.apache.ibatis.annotations.Mapper;
/*** @author chigong.zxn*/@Mapperpublicinterface ${TableName}MapperextendsBaseMapper<${TableName}PO> {}```3.Repository层interface参考代码,【注意:生成基础的增删改查方法】``` javaimportcom.aliexpress.qa.task.infrastructure.model.eval.${TableName}PO;importcom.aliexpress.qa.task.infrastructure.model.eval.${TableName}Model;
/*** @author chigong.zxn*/@Mapperpublicinterface ${TableName}Repository{ ${注释} ${增删改查方法}}```4.Repository层实现参考代码,【注意:继承Repository接口实现基础增删改查方法,调用Mapper生成基础的增删改查方法】``` javaimportcom.aliexpress.qa.task.infrastructure.model.eval.${TableName}PO;importcom.aliexpress.qa.task.infrastructure.model.eval.${TableName}Model;
/*** @author chigong.zxn*/@Mapperpublicinterface ${TableName}RepositoryImplimplements ${TableName}Repository{ ${注释} ${实现Repository增删改查方法}}```5.Repository层Model参考代码``` javaimportlombok.AllArgsConstructor;importlombok.Builder;importlombok.Data;importlombok.NoArgsConstructor;
${必要的引用}
/*** @author chigong.zxn*/@Data@Builder@AllArgsConstructor@NoArgsConstructorpublicclass ${TableName}Model{ ${注释} ${只可以使用包装类型,禁止使用基础类型} ${columnName}}```6.Converter层参考代码,【注意:生成2个静态方法,PO转Model、Model转PO】``` javaimportcom.aliexpress.qa.task.infrastructure.model.eval.${TableName}PO;importcom.aliexpress.qa.task.infrastructure.model.eval.${TableName}Model;
/*** @author chigong.zxn*/publicclass ${TableName}Converter{ ${注释} ${PO转换为Model}
${注释} ${Model转换为PO}}```

API层代码规范

---description:增加HSF接口时引用此文件globs:alwaysApply:false---##API开发规范###服务实现*验证器存放目录:[validate](mdc:task-biz/src/main/java/com/aliexpress/qa/task/biz/eval/api/)*实现要求:必须实现服务验证器*服务实现代码参考:```javaimportcom.alibaba.fastjson.JSON;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importorg.springframework.stereotype.Service;@Servicepublicclass${服务名}ServiceImplimplements${服务名}Service{privatestaticfinalLoggerlogger=LoggerFactory.getLogger(${服务名}ServiceImpl.class);@Autowiredprivate${服务校验器}Validatevalidate;//如果需要调用其他bean也可以在此处引入//如://@Autowired//privateEvalDatasetDetailRepositoryevalDatasetDetailRepository;@Overridepublic${服务方法出参}${服务方法名}(${服务方法请求体}request){logger.info("${服务名}Service.${服务方法名}request:{}",JSON.toJSONString(request));${服务方法出参}response=new${服务方法出参}();try{StringvalidateMsg=validate.${服务方法校验器}Validate(request);if(StringUtils.isNotBlank(validateMsg)){returnResponse.fail(ErrorCode.PARAM_ERROR.name(),validateMsg);}//在此处实现业务逻辑${业务逻辑}}catch(Exceptione){logger.error("${服务名}Service.${服务方法名}error",e);response=Response.fail(ErrorCode.SYSTEM_ERROR.name(),e.getMessage());}logger.info("${服务名}Service.${服务方法名}response:{}",response);returnresponse;}}```###服务验证器*验证器存放目录:[validate](/task-biz/src/main/java/com/aliexpress/qa/task/biz/eval/api/validate/)*验证器代码参考:验证失败则返回失败原因字符串,验证成功则返回空字符串```javaimportcom.aliexpress.qa.task.biz.eval.util.ValidateUtil;importorg.springframework.stereotype.Component;@Componentpublicclass${服务名}Validate{//如果需要调用其他bean也可以在此处引入//如://@Autowired//privateEvalDatasetDetailRepositoryevalDatasetDetailRepository;publicString${服务方法名}Validate(${服务方法请求体}request){//请求体不能为空if(request==null){return"请求参数不能为空";}//基础校验,使用ValidateUtil校验net.sf.ovalannotationStringvalidateMsg=ValidateUtil.validate(request);if(StringUtils.isNotBlank(validateMsg)){returnvalidateMsg;}//写明校验注释#{文档要求的其他校验逻辑}//返回空字符串则校验成功returnStringUtils.EMPTY;}}```###分布式锁使用*服务实现代码参考:```javaimportcom.alibaba.fastjson.JSON;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importorg.springframework.stereotype.Service;importcom.aliexpress.qa.task.infrastructure.util.lock.DistributedLockUtil;@Servicepublicclass${服务名}ServiceImplimplements${服务名}Service{privatestaticfinalLoggerlogger=LoggerFactory.getLogger(${服务名}ServiceImpl.class);@Autowiredprivate${服务校验器}Validatevalidate;@AutowiredprivateDistributedLockUtildistributedLockUtil;//如果需要调用其他bean也可以在此处引入//如://@Autowired//privateEvalDatasetDetailRepositoryevalDatasetDetailRepository;@Overridepublic${服务方法出参}${服务方法名}(${服务方法请求体}request){logger.info("${服务名}Service.${服务方法名}request:{}",JSON.toJSONString(request));${服务方法出参}response=new${服务方法出参}();try{StringvalidateMsg=validate.${服务方法校验器}Validate(request);if(StringUtils.isNotBlank(validateMsg)){returnResponse.fail(ErrorCode.PARAM_ERROR.name(),validateMsg);}//根据业务逻辑要求构建lockKeyStringlockKey=...;//分布式锁,避免并发调度DistributedLocklock=distributedLockUtil.getLock(lockKey);//获取分布式锁try{lock.tryLock(1000L);}catch(GetLockErrorExceptionlockException){returnResponse.fail(ErrorCode.LOCK_ERROR.name(),ErrorCode.LOCK_ERROR.getMessage());}try{//在此处实现业务逻辑${业务逻辑}}finally{lock.unlock();}}catch(Exceptione){logger.error("${服务名}Service.${服务方法名}error",e);response=Response.fail(ErrorCode.SYSTEM_ERROR.name(),e.getMessage());}logger.info("${服务名}Service.${服务方法名}response:{}",response);returnresponse;}}```

单元测试规范

---description:globs:alwaysApply: false---# 单元测试指南
## 测试框架-JUnit Jupiter 5.9.2-Mockito 4.11.0-JUnit Platform 1.9.2
## 严格执行-禁止改变被测试方法的任何行为-private方法测试: 使用反射的方式测试private方法, 禁止改变被测试方法的private```java @BeforeEach voidsetUp() throws NoSuchMethodException { // 获取私有方法 Method privateMethod = TargetClass.class.getDeclaredMethod("privateMethodName", ParameterType1.class, ParameterType2.class); privateMethod.setAccessible(true); }
@Test voidprivateMethodName_Should_ExpectedBehavior_When_StateUnderTest() throws Exception { // given // when Object result = privateMethod.invoke(targetObject, arg1, arg2); // then // assertions } ```-静态方法Mock: 使用MockedStatic方式-staticfinal字段处理: 避免直接测试或mock staticfinal字段(如日志记录器),专注于测试核心业务逻辑和返回值-Mybatis-Plus初始化实体类元数据: mock Mybatis-Plus的```LambdaUpdateWrapper、LambdaQueryWrapper```时,在```@BeforeEach```中使用```TableInfoHelper.initTableInfo(new MapperBuilderAssistant(new MybatisConfiguration(), ""),${实体类名}PO.class);```初始化实体类元数据
## 测试命名规范-使用`@Test`注解标记测试方法-测试方法名应该清晰表达测试目的,并且测试方法名必须包含被测试的方法名-格式:`${被测试方法名}_Should_ExpectedBehavior_When_StateUnderTest`-示例:`buildQuery_Should_ReturnQueryWithEntrustBizId_When_UserHasEntrustPermission`
## 测试最佳实践### Mock策略-优先测试核心业务逻辑,避免过度依赖基础设施组件的验证-对于不可变的静态组件(如staticfinal字段),采用行为验证而非状态验证-当无法直接mock某个组件时,考虑通过测试输出结果来间接验证行为-Mock对象使用: 只能对`mock()`创建的对象使用`when()`进行stub,禁止对真实对象(如通过builder模式创建的对象)使用`when()`### 测试重点-专注于方法的返回值、异常抛出、状态变更等核心行为-避免测试框架细节、日志输出等非核心功能-保持测试的简洁性和可维护性

模块功能文档规范

---description:globs:alwaysApply:false---##生成记忆-创建记忆文件夹:记忆文件统一存放在[.cursor/memory](mdc:.cursor/memory),如果我提供了指定了文件目录则按照我提供的文件夹存放,如果我没提供则根据需要梳理的链路自动起名创建文件夹-创建记忆文件:如果我提供了名字,则按照我提供的名字创建,如果我没有提供,则根据需要梳理的链路自动创建文件,已`.md`格式的文件维护记忆。-记忆文件内容要求:必须包含一个完整的链路图,并且将必要的代码入口、核心的代码逻辑放在记忆文档中。


技术方案文档规范
---description:globs:alwaysApply: false---## 生成开发任务-创建任务文件夹:当我要求你创建一个开发任务时,你需要根据`当前分支`的名称在 [.cursor/task](mdc:.cursor/task) 文件中查找是否有对应任务的文件,如果没有则创建一个任务文件夹-创建任务文件:在以`当前分支`命名的文件夹中,创建当前任务的详细描述文件,使用`.md`的文件格式生成文档内容,文件名根据我的要求自动生成一个中文名
## 文档内容规范-文档结构:保持简洁,专注技术方案。在没有明确要求时不包含开发计划、风险控制、上线计划等管理内容-测试要求:单元测试要求,覆盖率达到80%以上-尽量简洁:在满足要求的情况下尽量简洁,如果有需要补充的内容,我会明确的向你表达
## 代码设计规范-枚举使用:新增字符串类型字段时优先考虑枚举定义,避免硬编码-历史兼容:新增字段时考虑历史数据兼容性,提供默认值处理



2.3. 代码生成与测试

平衡效率和质量:核心是控制单个任务不要过大,当下过大的任务质量和验证过程都会失控。

对AI的约束:模型为了获得奖励,有时候会用作弊的方式假装满足用户的要求

多任务并行开发:Cursor本身支持多任务并行开发的能力

开发过程持续更新记忆:类似上文提到的,记忆是逐步完善的,不是一蹴而就的,需要在过程中持续完善记忆。

2.3.1. 对AI的约束示例

AI作弊的CASE:在一个JSON转HTML的任务中,cursor在多轮循环无法解决问题之后,直接生成了一个html的结果文件给我,绕开了使用代码生成html的要求。

严格按照要求执行示例

-禁止作弊:对于生产代码和测试代码的生成,需要完全遵循框架和需求的要求,**禁止通过硬编码的方式直接生成结果或绕开测试等行为**。-严格按照要求写代码:如果我提供了开发任务的.md文档,请严格按照文档要求生成代码,不要擅自发挥。-保持简洁:专注按照我的需求生成技术方案。在没有明确要求时不包含开发计划、风险控制、上线计划等冗余内容

2.4. 工程师的基础能力

三、真实的使用案例

3.1. 初始记忆维护

使用示例

Cursor规则描述

Cursor自动生成

应用基础记忆

输入指令:/Generate Cursor Rules

要求生成特定的规则

基于应用基础记忆

结合代码入口生成

功能模块记忆文档

3.2. 技术方案生成

使用示例

基于功能

模块记忆

生成迭代

技术方案

3.3. 代码开发与测试

使用示例

执行开发任务

执行开发任务

复杂任务拆解

输入指令

将这个方案拆分为多个子任务,并且细化到可供Cursor执行的程度。

任务过程中反思

同项目并行开发

Playwright

MCP

端到端测试

基础处于不可用状态,执行了5~10分钟,无法处理日期组件等复杂组件。

四、AI编程领域的最新趋势

4.1. 编程工具对比

Cursor依然是当下实用性和性价比较高的编程工具,但Claude Code的高任务完成度和其形态的高可玩性正在快速蚕食Cursor的用户市场。以Devin为代表的端到端异步Agent由于其较低的任务完成度,已经逐渐失去了用户的信任,处在黑暗中挣扎的阶段。(此处仅对比当下有代表性的2款热门工具)

近期Cursor的订阅模式的改变(Pro不限量)也可以侧面感受到来自ClaudeCode的竞争压力,从能力层面上ClaudeCode目前更强一些,但是Cursor放开Pro订阅的使用限制,是从成本和用量上拉开优势进行错位竞争,先留住用户,再追赶能力。(个人理解)

4.2. ClaudeCode使用体验

使用示例

安装和启动

#安装(需要NPM)npminstall-g@anthropic-ai/claude-code#进入项目目录cd~/your-project#启动claude


启动视图

使用了claude-code-router介入openrouter api的界面,订阅用户稍有区别

运行模式

创建技术方案

拆解子任务

并行开发

达到限额

ClaudeCode

工具集

ClaudeCode

解决真实问题







欢迎光临 链载Ai (https://www.lianzai.com/) Powered by Discuz! X3.5