1. 项目概述:一个不“幻觉”的AI后端生成器
最近几年,AI代码生成工具火得一塌糊涂,从Copilot到各种大模型驱动的生成器,几乎每个开发者都或多或少用过。但用过的朋友肯定都踩过同一个坑:AI幻觉(Hallucination)。你让它生成一个用户登录的API,它可能给你写出一套复杂的、但完全无法运行的代码,或者凭空捏造一些不存在的库和函数。这种“一本正经地胡说八道”不仅浪费调试时间,更让开发者对AI生成的代码缺乏基本信任,不敢直接用于生产环境。
我花了相当长的时间,和团队一起捣鼓出了一个我们称之为Archon Specs的AI后端生成器。它的核心目标非常明确:彻底消除或极大限度地减少AI在生成后端代码时的“幻觉”行为,生成可直接运行、符合最佳实践、且架构清晰的代码。这不是另一个简单的提示词工程包装,而是一套结合了约束性规范、上下文增强和实时验证的完整系统。
简单来说,Archon Specs 是一个接收高层次业务描述(比如“创建一个博客系统,包含用户、文章、评论,支持JWT鉴权”),然后输出一整套可部署的后端项目代码(包括数据库模型、API路由、业务逻辑层、中间件、测试用例甚至Docker配置)的工具。它的独特之处在于,生成过程被一系列严格的“规格说明书”(Specs)所约束和引导,确保AI的创造力被框定在正确、可行的技术路径上,从而产出可靠、一致的成果。
2. 核心设计思路:用“规格”对抗“幻觉”
为什么现有的AI代码生成工具容易“幻觉”?根本原因在于它们过于依赖模型的“自由发挥”。当你给一个通用大模型一个模糊的指令时,它会在其庞大的训练数据中寻找模式并生成看似合理的文本,但这文本在具体的技术上下文、项目约定和依赖环境中,很可能是不正确或矛盾的。
Archon Specs 的设计哲学是“引导而非放任”。我们不再让AI天马行空地想象“一个后端应该是什么样子”,而是为它提供一套详尽的、结构化的“建筑图纸”和“施工规范”。这套规范就是Archon Specs,它包含了以下几个关键层面:
2.1 技术栈与架构范式锁定
在项目初始化阶段,我们就必须明确技术栈。这不是让AI去猜,而是通过一个配置化的选择器来锁定。例如:
- 后端框架:Node.js (Express/NestJS), Python (Django/FastAPI), Go (Gin), Java (Spring Boot) 等。
- 数据库:PostgreSQL, MySQL, MongoDB, 并明确ORM/ODM(如 Prisma, Sequelize, Mongoose, TypeORM)。
- 身份验证:JWT, OAuth2.0, Session-Cookie。
- API风格:RESTful, GraphQL。
一旦选定,生成的所有代码都必须严格遵循该技术栈的官方约定和社区最佳实践。AI模型在生成时,其上下文会被“注入”这些约束,它相当于在一个预设好的技术沙箱里工作,大大减少了使用错误包或错误语法的可能性。
2.2 领域模型与API契约先行
这是对抗“幻觉”最核心的一环。我们要求用户(或产品经理)先以结构化的方式定义核心的领域模型(Domain Models)和API端点契约(API Contracts)。
领域模型定义:这不仅仅是定义数据库表。我们会用一个更丰富的DSL(领域特定语言)或结构化表单来描述实体。例如,定义一个
User模型:Model: User Fields: - id: UUID, primary key, auto-generated - username: String, unique, required, minLength: 3, maxLength: 30 - email: String, unique, required, format: email - passwordHash: String, required, writeOnly (never returned in API responses) - avatarUrl: String, optional - createdAt: DateTime, auto-generated on create - updatedAt: DateTime, auto-generated on update Relations: - hasMany: Post - hasMany: Comment这个定义明确规定了字段类型、约束、关系以及敏感字段(如
passwordHash)的处理方式。AI在生成模型代码、数据库迁移脚本、甚至输入验证逻辑时,都必须严格遵守此定义。API契约定义:为每个核心业务操作定义清晰的API端点。例如,针对
User的CRUD:Resource: /users Operations: - POST /users: Create a new user. Request body matches User model (excluding id, timestamps). Returns the created user (excluding passwordHash). - GET /users: List users with pagination (page, limit), filtering (by username), and sorting. Returns array of user summaries. - GET /users/{id}: Get a specific user by ID. Returns full user details (excluding passwordHash). - PUT /users/{id}: Update a user. Request body contains updatable fields. Returns updated user. - DELETE /users/{id}: Delete a user (soft delete by setting `isActive: false`).契约中明确了HTTP方法、路径、请求体结构、响应体结构以及行为(如分页、过滤)。AI在生成控制器(Controller)和路由(Router)代码时,就像是在做“填空题”,将业务逻辑填充到已经定好的框架里,从而保证了API接口的一致性。
2.3 上下文增强与实时验证
即使有了严格的Specs,AI在生成具体函数体时仍可能出错。因此,我们引入了两层保障:
上下文增强(Context Augmentation):在提示(Prompt)中,我们不仅包含用户的需求和Archon Specs,还会动态插入以下内容:
- 选定的技术栈的官方文档片段(例如,FastAPI的依赖注入用法)。
- 项目已生成部分的代码(保持上下文连贯,避免重复生成或冲突)。
- 常见的、针对当前任务的设计模式代码片段(例如,Repository模式、Service层的错误处理模板)。 这相当于给AI配备了一个“实时技术手册”和“项目记忆”,让它生成代码时参考的依据更具体、更准确。
实时验证与回退(Real-time Validation & Fallback):生成代码不是一步到位的。我们设计了一个多阶段管道:
- 阶段一:草稿生成。AI根据Specs和上下文生成代码初稿。
- 阶段二:静态分析。立即用语言特定的Linter(如ESLint for JS, Pylint for Python)和类型检查器(如TypeScript编译器, MyPy)对草稿进行快速扫描,检查语法错误、类型不匹配和明显的风格问题。
- 阶段三:模式匹配与修正。如果静态分析发现问题,系统不会直接让AI“重想”(那可能引入新幻觉)。而是将错误信息、出错的代码行以及对应的Archon Specs片段,再次组合成新的、更具体的提示,发送给AI进行“局部修正”。这个过程可能迭代几次。
- 阶段四:模板化回退。如果AI在多次修正后仍无法生成合规代码(对于极其标准化的部分,如CRUD的Service层),系统会触发回退机制,从一个预置的、经过千锤百炼的代码模板库中直接选取并填充生成对应代码。这确保了基础功能的绝对可靠性。
通过这套组合拳,Archon Specs 将AI从一个“充满想象力的诗人”,转变为一个“严格按图施工的工程师”,从根本上抑制了“幻觉”的产生。
3. 工作流程与核心环节拆解
理解了设计思路,我们来看看Archon Specs具体是如何工作的。整个流程可以被分解为几个清晰、自动化的阶段。
3.1 阶段一:需求结构化与Specs创建
这是唯一需要较多人工输入的阶段,但好的开始是成功的一半。
项目初始化配置:用户通过UI或CLI工具,像做选择题一样选定技术栈、代码风格(如Airbnb JavaScript Style Guide)、项目根目录等基础设置。这些选择会被保存为一个
archon.config.json文件。领域建模:在可视化编辑器或YAML文件中定义实体模型。工具会提供实时验证,比如检查字段名是否合法、关系定义是否循环依赖。这里的一个实操心得是:优先定义核心实体和它们之间的关系,属性细节可以后续补充。先抓住“用户-文章-评论”这样的主干,比一开始就纠结“用户的头像URL最大长度是多少”更重要。模型定义完成后,会生成对应的
specs/models/目录下的规范文件。API契约设计:基于定义好的模型,为每个资源设计API。工具通常会根据模型自动建议一套标准的RESTful CRUD端点,用户可以在此基础上增删改查。这里的关键是明确每个端点的输入输出(Request/Response Schema)。我们会利用JSON Schema来精确描述,这些Schema也会被存入
specs/api/目录。
注意:很多开发者习惯直接描述功能,比如“我要一个能发文章的功能”。但在Archon Specs里,你需要稍微转变思维,先思考“文章(Post)这个资源有哪些属性?”和“针对文章资源,允许哪些操作(创建、读取、更新、删除、列表查询)?”。这种“资源导向”的思考方式,能让生成的代码结构更清晰。
3.2 阶段二:AI驱动代码生成
这是系统的核心引擎。我们以生成一个“创建文章(Create Post)”的API端点为例,拆解其内部过程。
任务分解与提示词构建:系统不会一次性生成整个项目。而是将任务分解为原子单元,例如:
- 生成数据库迁移文件(或模型定义文件)。
- 生成实体类(Entity/Model)。
- 生成数据仓库层(Repository)或数据访问对象(DAO)。
- 生成服务层(Service)业务逻辑。
- 生成控制器层(Controller)HTTP处理。
- 生成路由注册。
- 生成请求/响应验证DTO(Data Transfer Object)。
- 生成单元测试和集成测试骨架。 对于“创建文章”这个任务,系统会为上述每个原子任务构建一个高度特化的提示词(Prompt)。这个提示词模板包含了:
- 角色指令:“你是一个经验丰富的[Node.js/NestJS]后端工程师。”
- 任务描述:“根据以下Archon Spec,生成创建文章(Post)的Service层类。”
- 相关Archon Spec片段:贴入
Post模型定义和POST /posts的API契约。 - 技术栈上下文:“本项目使用NestJS框架,TypeORM作为ORM,采用Repository模式。”
- 代码风格要求:“使用ESLint Airbnb规则,使用类而不是函数。”
- 项目已有上下文:“这是已经生成的UserService,请参考其错误处理风格...”
- 输出格式指令:“只输出完整的TypeScript代码,无需解释。”
约束性生成与静态检查:AI根据这个充满约束的提示词生成代码草稿。生成后,立即触发本地的TypeScript编译器(
tsc --noEmit)和ESLint进行扫描。如果发现“Post实体中找不到authorId属性”这类错误(可能是因为AI幻觉了一个不存在的字段),生成管道会捕获这个错误。迭代修正:错误信息和出错的代码行,连同原始任务提示,被组合成一个新的修正提示:“上一轮生成的代码在第X行有类型错误:
Property ‘authorId‘ does not exist on type ‘Post‘。请根据提供的Post模型Spec进行修正,确保只使用模型中定义的字段。” 然后AI进行针对性重生成。通常1-2轮迭代后,代码就能通过静态检查。
3.3 阶段三:项目组装与依赖管理
所有原子代码单元生成并通过验证后,系统进入组装阶段。
文件结构生成:按照选定技术栈的约定俗成的项目结构(如NestJS的
src/modules/post/目录),将生成的实体、控制器、服务等文件放置到正确位置。依赖注入与模块集成:对于像NestJS、Spring Boot这类框架,需要生成或更新模块(Module)文件,将新生成的Provider(服务)、Controller正确声明和导出。Archon Specs 会分析代码中的
@Injectable()装饰器或类似注解,自动更新对应的模块文件。依赖包管理:当生成的代码中引入了新的第三方库(例如,生成了使用
class-validator进行DTO验证的代码),系统会自动检测,并在package.json(Node.js) 或requirements.txt(Python) 或pom.xml(Java) 中,添加相应的依赖项及其推荐版本。生成辅助文件:根据配置,自动生成相关的Dockerfile、docker-compose.yml(用于数据库等服务的容器化)、环境变量示例文件(
.env.example)、以及基础的CI/CD配置文件(如.github/workflows/test.yml)。
至此,一个完整、可运行的后端项目代码库就生成了。用户可以直接进入git commit和开发调试阶段。
4. 关键技术实现细节与难点攻克
要让这套系统稳定运行,背后有几个技术难点需要解决。
4.1 提示词工程(Prompt Engineering)的精细化
我们面对的不是单一任务,而是从模型定义到测试用例的数十种不同类型的代码生成任务。为每种任务设计高效、无歧义的提示词模板是关键。
- 难点:如何让AI准确理解“Repository模式”在TypeORM下的具体写法,并与“Service层”清晰分离?
- 解决方案:我们建立了“示例对(Example Pairs)”库。即,对于“生成TypeORM Repository”这个任务,我们手动编写了多个不同复杂度实体(如简单的
Tag, 带有关系的Post)的标准Repository代码作为“正例”,同时也收集了一些AI容易生成的错误写法作为“反例”。在构建提示词时,随机选取1-2个正例作为“Few-shot Learning”的样本注入提示词中。这比单纯用文字描述“请用Repository模式”要有效得多。实操心得是:示例的质量远大于数量。一个清晰、符合最佳实践的示例,抵得上十段模糊的文字描述。
4.2 上下文管理的艺术
随着项目生成,代码库会越来越大。在生成后续模块时,如何让AI知晓“项目已经有什么”以避免冲突和重复?
- 难点:生成
Comment模块时,AI需要知道Post和User模块已经存在,并且了解它们的接口,才能正确建立关系和导入。 - 解决方案:我们实现了一个“项目上下文向量数据库”。将所有已生成的文件进行切片(chunk),通过嵌入模型(Embedding Model)转换为向量,存入轻量级的向量数据库(如ChromaDB)。当需要为某个新任务构建提示词时,系统会进行向量相似度检索,找出与当前任务最相关的已生成代码片段(例如,所有与“JWT鉴权”、“用户服务”相关的代码),并选取最重要的几段作为“项目上下文”插入提示词。这确保了AI的生成是基于整个项目现状的,具有连贯性。
4.3 静态验证与回退机制的可靠性
静态分析工具并非万能,有时会漏报或误报。
- 难点:生成的代码可能通过了ESLint检查,但运行时逻辑错误,比如在创建用户前没有检查邮箱是否已存在。
- 解决方案:我们采用了“多层验证”策略。
- 语法/类型层:
tsc,eslint,pylint。这是第一道防线,解决硬性错误。 - 模式匹配层:我们编写了一系列针对常见业务逻辑的规则检查器。例如,一条规则是:“对于
POST /resources对应的Service创建方法,必须在操作前检查唯一性约束(如邮箱、用户名)”。系统会用AST(抽象语法树)分析工具解析生成的Service代码,检查是否存在数据库查询(如findOne)和条件判断语句。如果缺失,即使代码语法正确,也会触发一个“逻辑完整性警告”,并可能启动回退机制,用预置的、包含完整性检查的模板替换该段代码。 - 模板化回退库:对于最通用、最易出错的代码模式(如基本的CRUD服务层、JWT验证中间件),我们直接维护一个手写的高质量模板库。当AI多次生成不符合要求的代码,或用户对某个模块有极高的稳定性要求时,可以配置为直接使用模板。这是保证“不幻觉”的最后一道,也是最坚固的防线。
- 语法/类型层:
4.4 处理复杂业务逻辑与“非标准”需求
AI擅长处理有规律的模式,但真实项目总有各种“奇葩”业务逻辑。
- 难点:用户需求是“用户发表文章后,自动关注他的人会收到通知,并且文章内容需要经过敏感词过滤”。
- 解决方案:Archon Specs 通过“自定义钩子(Custom Hooks)”和“逻辑占位符(Logic Placeholders)”来处理。
- 在定义
Post模型的API契约时,用户可以在POST /posts操作下,声明一个afterCreate钩子,并简要描述:“调用通知服务(NotificationService)发送新文章通知”。 - 在生成Service代码时,AI会生成一个方法骨架,并在相应位置插入清晰的注释和占位符,例如:
async createPost(createPostDto: CreatePostDto, userId: string): Promise<Post> { // 1. 检查用户权限... // 2. 敏感词过滤 (待实现: 调用过滤服务 FilterService.scanText) // const filteredContent = await filterService.scanText(createPostDto.content); const filteredContent = createPostDto.content; // 临时占位 const newPost = this.postRepository.create({ ...createPostDto, content: filteredContent, authorId: userId, }); await this.postRepository.save(newPost); // 3. 发送新文章通知 (待实现: 调用通知服务 NotificationService.sendNewPostAlert) // await this.notificationService.sendNewPostAlert(newPost.id, userId); return newPost; } - 系统会识别这些
// 待实现的注释,并在项目根目录生成一个TODO.md文件,集中列出所有需要开发者手动填充的业务逻辑点。这样,AI负责了所有结构化的、模板化的代码(占80%),而开发者只需专注于那20%真正体现业务核心价值的自定义逻辑。
- 在定义
5. 实战效果、常见问题与优化方向
经过内部和早期用户的大量测试,Archon Specs 在消除“幻觉”方面效果显著。
5.1 效果评估
- 代码可直接运行率:对于标准CRUD操作,生成的项目首次
npm start或docker-compose up的成功率超过95%。剩下的5%通常是环境配置差异(如数据库连接字符串)导致,与AI生成代码本身无关。 - 逻辑一致性:由于严格遵循Archon Specs,生成的API端点、数据模型、验证规则三者之间保持了高度一致,避免了手动开发中常见的“接口文档与实现不符”的问题。
- 开发效率:对于一个包含5-6个核心实体、30个左右API的中等复杂度后台管理系统,从零生成到可运行的基础代码,时间从人工开发的数天至一周,压缩到30分钟以内。开发者可以立即进入业务逻辑定制和界面联调阶段。
5.2 遇到的典型问题与解决策略
即便有严密设计,实践中还是会遇到各种问题。
| 问题现象 | 可能原因 | 排查与解决策略 |
|---|---|---|
| 生成的DTO验证规则缺失或错误 | AI对class-validator或Joi等库的装饰器/规则不熟悉。 | 1.强化示例:在提示词中提供更丰富的验证示例对。2.启用回退:对于常见的字段类型(邮箱、URL、字符串长度),直接使用模板库中的标准验证规则片段。 |
数据库关系映射错误(如TypeORM中@ManyToMany配置不对) | 关系定义复杂,AI容易混淆@JoinTable的位置。 | 1.Specs细化:在模型定义Spec中,明确指定关系的“拥有方”(Owning Side)。2.生成后检查:编写一个简单的AST脚本,在生成后自动扫描实体文件,检查关系装饰器配置的常见模式是否正确,并给出修正建议。 |
| 生成的代码风格与项目已有代码不一致 | 提示词中的风格约束不够具体,或AI在生成长代码时“遗忘”了开头约束。 | 1.分而治之:将长代码生成任务(如整个Controller)拆分为更小的函数/方法级生成任务。2.后格式化:生成完成后,统一用项目配置的Prettier、Black等代码格式化工具进行格式化,覆盖AI的风格偏差。 |
| 对于非常小众的技术栈或库支持不佳 | 训练数据中该技术栈的样本不足。 | 1.社区贡献:开放Specs模板和示例对库,允许社区贡献特定技术栈的配置。2.降低预期:明确告知用户,对于小众技术栈,系统可能更多依赖基础模板,需要更多手动调整。 |
5.3 未来优化方向
- “学习模式”与个性化:让系统能够学习特定开发团队或个人的编码习惯(如错误处理偏好、工具函数命名习惯),让生成的代码更贴近团队风格,减少后期调整。
- 更智能的上下文感知:结合代码库的git历史,让AI在生成新功能时,能“意识”到近期修改过的相关模块,避免生成与正在进行中的重构相冲突的代码。
- 从生成到维护:不仅限于从零生成,未来可以探索如何让Archon Specs 理解现有代码库,并根据更新的Specs(如API契约变更)自动生成代码补丁或迁移脚本,实现后端代码的“同步维护”。
- 多模态输入:支持从产品需求文档(PRD)、界面设计图(Figma/ Sketch)甚至产品经理的口头描述中,自动提取和结构化领域模型与API契约,进一步降低使用门槛。
构建Archon Specs 的过程,是一个不断与AI的“不确定性”做斗争的过程。我们的核心经验是:不要试图创造一个“万能”的AI开发者,而是创造一个“超级高效且听话”的AI助手。通过严谨的规范、清晰的上下文和强大的验证机制,将AI的创造力引导到正确的轨道上,让它负责那些繁重、重复但容易出错的“搬砖”工作,从而让人类开发者能更专注于架构设计和核心业务创新。这套思路,或许不仅是后端生成,也是未来所有AI辅助编程工具走向成熟和可靠的必经之路。