AI代码生成工具smol developer:三步构建完整应用,实现人机协同开发
1. 项目概述:当你的代码库拥有了一位“实习生”
如果你是一名开发者,尤其是经常需要从零开始搭建新项目、或者需要快速验证某个想法的原型,那么你肯定对“脚手架”这个概念不陌生。从经典的create-react-app到vue-cli,这些工具极大地简化了项目初始化流程。但它们都有一个共同的局限:它们是静态的、预设好的。它们能给你一个标准的起点,却无法理解你脑海中那个独特、具体、甚至有点“古怪”的产品需求。
现在,想象一下,你有一个不知疲倦、学习能力超强的“实习生”。你只需要用自然语言,像跟同事描述需求一样,告诉它:“嘿,帮我做一个带拖拽功能的在线白板应用,前端用React,后端用Node.js,数据存到MongoDB里,用户能实时看到彼此的修改。” 几个小时后,一个完整、可运行、结构清晰的项目代码库就摆在了你面前。这个“实习生”就是smol-ai/developer,一个被社区戏称为“小个子开发者”的AI代码生成代理。
它的核心哲学是“以人为本、连贯的完整程序合成”。这听起来很学术,但说白了,它旨在成为你个人专属的“初级开发者”。它不是一个试图取代你的“超级AI”,而是一个强大的辅助工具。你可以把它嵌入到你的工作流中,进行“人机协同”开发:你负责提出想法、制定规范、审查代码;它负责将你的想法快速转化为具体的、可执行的代码骨架,甚至解决一些你不太熟悉的API调用细节。这种模式将开发从“写每一行代码”转变为“工程化地管理提示词”,是一种思维范式的转变。
2. 核心设计思路:如何让AI理解并构建完整应用
让一个大语言模型(LLM)生成几行代码片段并不难,难的是让它生成一个包含多个文件、文件间存在复杂依赖关系、并且能真正运行起来的完整应用程序。smol developer的成功,关键在于它设计了一套精巧的“三步走”策略,来保证生成代码的连贯性和可用性。
2.1 第一步:制定全局开发计划
当你输入一个如“构建一个HTML/JS/CSS井字棋游戏”的提示时,smol developer做的第一件事不是立刻开始写代码,而是让模型(默认是GPT-4)先进行“规划”。
这个规划阶段会生成一个名为shared_dependencies.md的虚拟文档。这个文档是整个项目的“大脑”或“设计文档”,它包含了模型对项目的整体理解:
- 技术栈选择:基于你的描述,决定使用哪些库或框架(例如,对于Web游戏,可能选择纯原生JS,或引入Canvas库)。
- 核心数据结构:定义游戏的状态对象,比如棋盘如何表示(二维数组?一维数组?)、当前玩家、游戏状态(进行中、平局、获胜)。
- 组件/模块划分:识别出需要哪些文件,如
index.html,style.css,game.js,并初步定义它们之间的职责边界。 - 共享变量与函数:明确哪些变量(如
currentPlayer,boardState)和函数(如checkWinner(),resetGame())需要在多个文件间共享和调用。
为什么这一步至关重要?如果没有这个全局规划,模型在生成每个文件时都像是在“盲人摸象”。它可能会为
game.js里的棋盘定义一个叫grid的变量,却在index.html里试图访问一个叫board的DOM元素,导致运行时错误。shared_dependencies.md强制模型在动笔前先通盘思考,建立统一的“术语表”,这是保证多文件代码一致性的基石。
2.2 第二步:生成文件路径清单
有了全局计划,下一步就是将其具体化为需要创建的文件列表。smol developer会调用一个专门的函数,基于你的原始提示和上一步生成的shared_dependencies.md,让模型列出一个文件路径数组。
例如,对于井字棋游戏,可能会返回:
["index.html", "style.css", "script.js"]对于一个更复杂的Chrome扩展,可能会返回:
["manifest.json", "popup.html", "popup.js", "content_script.js", "background.js", "styles.css"]这里用到了OpenAI的“函数调用”功能。这个API允许开发者定义函数的结构(参数、类型),然后模型会返回一个符合该结构的JSON对象。这比让模型直接输出自由文本要可靠得多,因为它强制输出格式,极大地减少了模型“胡言乱语”或格式错误的风险,使得程序能够稳定地解析出文件列表。
2.3 第三步:并行生成每个文件的代码
这是最耗时的步骤,但smol developer通过并行化进行了优化。它会遍历上一步得到的文件路径数组,为每个文件发起一次独立的API调用,生成其具体内容。
关键点在于,每次生成单个文件的代码时,都会将原始提示和shared_dependencies.md作为上下文一并发送给模型。这相当于在告诉模型:“你现在要写popup.js文件了,别忘了我们之前约定好的整体架构和共享变量哦。” 这种方式极大地减少了文件间的不一致和“幻觉”(即模型凭空捏造不存在的依赖或接口)。
生成完成后,这些代码块会被写入到指定的目录中,一个完整的、立即可运行(或接近可运行)的项目就诞生了。
3. 三种使用模式详解与实操
smol developer提供了三种不同粒度的使用方式,适应从快速原型到深度集成的各种场景。
3.1 Git仓库模式:快速启动的人机循环
这是最经典、最直观的使用方式,适合绝大多数想要体验或快速构建原型的开发者。
环境准备与运行首先,你需要一个Python环境(建议3.8+)和Poetry(一个现代的Python依赖管理工具)。如果你没有Poetry,可以通过pip install poetry安装。
# 1. 克隆仓库 git clone https://github.com/smol-ai/developer.git cd developer # 2. 安装依赖(Poetry会自动创建虚拟环境) poetry install # 3. 设置你的OpenAI API密钥 export OPENAI_API_KEY='你的-api-key-here' # 4. 运行!从一句描述开始 poetry run python main.py "一个使用Flask框架的待办事项API,包含GET/POST/DELETE端点,数据用JSON文件存储"运行后,你会在当前目录下看到一个名为generated_app(或你指定的)的新文件夹,里面就是生成的完整代码。
人机协同工作流这个模式的核心价值在于“循环”。生成代码不是终点,而是起点。
- 初代生成:你给出一个基础提示,生成第一版代码。
- 运行与审查:你尝试运行它。很可能会遇到错误,或者发现功能不完整。
- 迭代提示:这时,你不是自己去修改代码,而是将错误信息或新增的需求,直接追加到你的提示文件中(比如
prompt.md)。# 原始提示 构建一个Flask待办事项API。 # 第一次运行后发现的错误 错误:`json.dump` 时遇到 `TypeError: Object of type TodoItem is not JSON serializable`。 请修复序列化问题。 # 新增需求 另外,请为每个待办事项添加一个 `created_at` 时间戳字段。 - 重新生成:再次运行
main.py,指向这个更新后的prompt.md文件。smol developer会读取整个提示(包括历史错误和需求),重新生成代码,通常会覆盖原有文件,但会智能地保留你手动修改过的部分(如图片资源)。 - 循环直至满意:重复步骤2-4,直到应用达到你的要求。
这种模式将AI定位为一个“服从命令的初级开发者”。当你发现它的代码有瑕疵时,你不是去“调试AI”,而是像给下属分派任务一样,清晰地指出问题所在。当AI生成的代码足够好时,你可以直接接手进行微调;当它卡住时,你可以随时接管,没有任何“感情伤害”或技术债务。
3.2 库模式:将“小开发者”嵌入你的应用
如果你希望在自己的工具、平台或工作流中集成自动代码生成能力,库模式是你的选择。smol developer的核心逻辑被封装成了一个Python包:smol_dev。
安装与基础集成
pip install smol_dev集成到你的Python脚本中非常简单:
from smol_dev.prompts import plan, specify_file_paths, generate_code_sync # 1. 用户输入的产品描述 user_prompt = "一个命令行工具,用于批量重命名当前目录下的图片文件,添加前缀和序列号。" # 2. 生成全局计划 shared_deps = plan(user_prompt) print("项目计划:", shared_deps[:500]) # 预览一部分 # 在这里,你可以将计划展示给用户确认或编辑 # user_approved_plan = ask_user_to_review(shared_deps) # 3. 基于计划,列出所需文件 file_paths = specify_file_paths(user_prompt, shared_deps) print(f"需要生成的文件:{file_paths}") # 4. 为每个文件生成代码 generated_files = {} for file_path in file_paths: code = generate_code_sync(user_prompt, shared_deps, file_path) generated_files[file_path] = code # 你可以选择写入磁盘,或存入数据库,或通过UI展示 # with open(f"output/{file_path}", "w") as f: # f.write(code) print("代码生成完成!")高级控制与异步处理对于需要生成大型项目或希望提升响应速度的场景,你可以使用异步版本并加入更多控制逻辑:
import asyncio from smol_dev.prompts import generate_code async def generate_project_async(prompt, output_dir="generated"): shared_deps = plan(prompt) file_paths = specify_file_paths(prompt, shared_deps) # 创建输出目录 os.makedirs(output_dir, exist_ok=True) # 并发生成所有文件的代码 tasks = [] for fp in file_paths: task = asyncio.create_task(generate_code(prompt, shared_deps, fp)) tasks.append((fp, task)) # 等待所有任务完成并写入文件 for file_path, task in tasks: code = await task full_path = os.path.join(output_dir, file_path) os.makedirs(os.path.dirname(full_path), exist_ok=True) # 处理子目录 with open(full_path, "w", encoding="utf-8") as f: f.write(code) print(f"已生成: {full_path}") # 运行异步函数 asyncio.run(generate_project_async("一个简单的Python网络爬虫,爬取豆瓣电影Top250并保存为CSV。"))这种模式给了你极大的灵活性。你可以用它来构建:
- 内部低代码平台:让非技术人员通过表单描述需求,后台自动生成CRUD应用骨架。
- IDE插件:在VSCode或JetBrains系列IDE中,通过一个命令快速生成模块代码。
- 教育工具:根据学生描述的概念,自动生成示例代码供其学习和修改。
3.3 API模式:标准化智能体接口
为了更方便地被其他服务调用,smol developer实现了Agent Protocol标准。这是一个旨在统一AI智能体交互方式的开放协议。启动API服务后,任何兼容该协议的客户端都可以通过HTTP请求来创建代码生成任务。
启动与调用示例
# 在项目根目录下启动API服务器 poetry run api # 或 python smol_dev/api.py服务器默认运行在http://localhost:8000。之后,你可以使用任何HTTP客户端(如curl或Postman)与之交互。
使用curl进行任务交互
# 1. 创建一个新任务 curl --request POST \ --url http://localhost:8000/agent/tasks \ --header 'Content-Type: application/json' \ --data '{ "input": "创建一个Python脚本,使用requests库查询当前天气(模拟即可),并打印出来。" }' # 响应示例:{"task_id":"abc123...", "input":"...", "artifacts":[]} # 2. 执行该任务的一步(对于smol-dev,一步通常就完成生成) curl --request POST \ --url http://localhost:8000/agent/tasks/abc123.../steps # 响应中会包含生成的结果,如代码文件列表或直接的文件内容使用官方Python客户端对于更复杂的集成,使用官方客户端库更便捷:
import asyncio from agent_protocol_client import AgentApi, ApiClient, TaskRequestBody async def create_code_via_api(prompt): async with ApiClient(host="http://localhost:8000") as api_client: api_instance = AgentApi(api_client) # 创建任务 task_req = TaskRequestBody(input=prompt) task = await api_instance.create_agent_task(task_request_body=task_req) print(f"任务已创建,ID: {task.task_id}") # 执行步骤(生成代码) step = await api_instance.execute_agent_task_step(task_id=task.task_id) # step.output 或 step.artifacts 中包含了生成的结果 print(f"步骤输出: {step.output}") # 通常,生成的文件会以“工件”的形式返回,你需要进一步读取 for artifact in step.artifacts: print(f"文件: {artifact.file_name}, 内容预览: {artifact.relative_path}") asyncio.run(create_code_via_api("生成一个FastAPI的‘Hello World’应用。"))API模式使得smol developer可以轻松地被集成到自动化流水线、聊天机器人或其他需要按需生成代码的系统中。
4. 实战经验与核心技巧
经过大量项目实践,社区总结出了一些让smol developer发挥最大效能的“心法”。这些技巧往往比工具本身的使用更重要。
4.1 提示词工程:从模糊到精确的艺术
smol developer的输入是自然语言提示,其质量直接决定输出代码的质量。好的提示词不是命令,而是清晰、无歧义的“产品规格说明书”。
反面例子:“做一个博客网站。” 这个提示太模糊了。用什么技术栈?需要用户注册吗?有评论功能吗?文章支持Markdown吗?模型会基于其训练数据中的“平均博客”来生成,结果可能完全不符合你的预期。
正面例子:
项目:个人静态博客生成器 核心功能: 1. 使用Python的Flask框架作为后端。 2. 博客文章以Markdown文件格式存储在 `posts/` 目录下。 3. 首页 (`/`) 列出所有文章,按发布日期倒序排列,显示标题、摘要和日期。 4. 文章页面 (`/post/<slug>`) 渲染对应的Markdown为HTML。 5. 需要一个简单的管理页面 (`/admin`,密码保护为 `admin123`),可以在此页面创建新的Markdown文章并保存到 `posts/`。 6. 前端使用Bootstrap 5进行基本样式美化。 7. 使用SQLite数据库存储文章的元数据(标题、slug、发布日期、文件路径)。 请生成完整的、可运行的代码。这个提示明确了技术栈(Flask, Bootstrap, SQLite)、数据存储方式(文件+数据库)、核心路由、甚至包含了一个简单的安全需求。模型生成的目标代码会清晰得多。
高级技巧:使用Markdown混合描述与示例Markdown是编写提示的绝佳格式,因为它允许你自由混合文本描述和代码块。
构建一个与用户进行猜数字游戏的命令行脚本。 游戏规则: 1. 程序在1-100之间随机生成一个数字。 2. 用户有7次猜测机会。 3. 每次猜测后,程序应提示“太高”、“太低”或“恭喜你猜对了!”。 4. 如果7次都没猜对,显示正确答案。 **请严格按照以下Python代码风格编写:** - 使用 `argparse` 处理可选的 `--max-number` 和 `--max-guesses` 参数。 - 将游戏逻辑封装在一个名为 `NumberGame` 的类中。 - 在主函数 `main()` 中运行游戏。 - 包含详细的文档字符串。 示例性的主函数结构: ```python def main(): parser = argparse.ArgumentParser(description='猜数字游戏') parser.add_argument('--max-number', type=int, default=100, help='最大数字(默认100)') parser.add_argument('--max-guesses', type=int, default=7, help='最大猜测次数(默认7)') args = parser.parse_args() game = NumberGame(max_number=args.max_number, max_guesses=args.max_guesses) game.play() if __name__ == "__main__": main() ```通过提供具体的代码结构和风格要求,你可以极大地约束模型的输出,使其更符合你的编码习惯和项目规范。
4.2 利用“复制粘贴编程”攻克陌生API
这是smol developer一个非常强大的用法。当你需要让模型使用一个它训练数据中可能没有、或者信息不全的API时,不需要自己去写封装,直接把官方文档的curl示例或者你从网络请求中捕获的输入输出粘贴进去。
场景:你需要让生成的Chrome扩展调用一个较新的、GPT-3可能不知道的第三方服务API(例如,Anthropic的Claude API)。
做法:
- 打开浏览器开发者工具,使用该API进行一次成功的调用。
- 在“Network”标签页中找到该请求,右键选择“Copy as cURL”。
- 将复制到的cURL命令和返回的JSON响应,直接粘贴到你的提示词中。
... (其他应用描述) 这个扩展需要调用Claude API来总结网页内容。以下是API调用的具体方式: 请求示例(cURL):curl https://api.anthropic.com/v1/messages
-H "x-api-key: your-api-key"
-H "anthropic-version: 2023-06-01"
-H "content-type: application/json"
-d '{ "model": "claude-3-opus-20240229", "max_tokens": 1024, "messages": [{"role": "user", "content": "Hello, world"}] }'
成功响应示例(JSON):{ "id": "msg_013Zva2CMHLNnXjNJJKqJ2EF", "type": "message", "role": "assistant", "content": [{"type": "text", "text": "Hi! I'm Claude."}], "model": "claude-3-opus-20240229", "stop_reason": "end_turn", "usage": {"input_tokens": 10, "output_tokens": 5} }
请根据以上格式,在 `background.js` 中编写一个函数 `callClaudeAPI(prompt)` 来调用此API并处理响应。通过提供具体的输入输出范例,你实际上是在“教”模型这个API的用法。模型通常能很好地理解并生成正确的调用代码。这大大降低了学习和集成新API的门槛。
4.3 调试与迭代:将错误信息转化为燃料
当生成的代码运行出错时,传统的做法是直接阅读错误栈,然后手动修改代码。在smol developer的工作流中,你可以将这个过程“外包”给AI。
- 捕获错误:运行生成的程序,复制完整的错误信息。
- 反馈给提示:将错误信息追加到你的
prompt.md文件末尾。
Traceback (most recent call last): File "app.py", line 15, in from database import init_db ModuleNotFoundError: No module named 'database'(之前的提示内容...) --- 【运行错误反馈】 运行 `python app.py` 时出现以下错误:看起来 `database.py` 文件没有被正确生成或导入。请检查并修复。 - 重新生成:再次运行
main.py。模型会读取整个提示,包括新的错误信息,并尝试在下一轮生成中修复这个问题。它可能会创建缺失的database.py文件,或者修正app.py中的导入语句。
这种“错误驱动”的迭代方式,感觉就像是在填写一份开发日志。你不需要知道具体的修复方法,只需要清晰地指出问题所在。对于复杂的依赖错误或逻辑bug,你甚至可以使用项目自带的debugger.py脚本,它会读取整个代码库和错误信息,让模型给出更具体的代码修改建议。
4.4 处理复杂依赖与文件间协调
对于涉及多个文件且依赖紧密的项目(如Chrome扩展、全栈应用),保证文件间的一致性是一大挑战。smol developer的shared_dependencies.md机制是解决此问题的核心,但有时仍不够。
技巧:在提示中显式命名关键元素如果发现生成的代码中,前端组件和后端接口对同一个数据对象的命名不一致(例如前端叫userData,后端叫user_info),你可以在初始提示中就进行强制约定。
项目:用户仪表盘 **重要:整个项目中,用户对象的数据结构必须统一使用以下字段名:** - `id` (整数) - `username` (字符串) - `email` (字符串) - `created_at` (ISO格式字符串) 在JavaScript前端、Python后端API和SQLite数据库表中,都必须使用这些**精确的字段名**。通过这种强制约定,你可以引导模型在各个文件中使用统一的术语,减少集成时的摩擦。
5. 性能、成本与局限性考量
在将smol developer用于生产或高频次原型开发前,有几个现实因素必须考虑。
5.1 生成速度与API成本
目前,生成一个中等复杂度的项目(5-10个文件)大约需要2到4分钟,主要时间花费在等待GPT-4的API响应上。这背后是实实在在的API调用成本。
成本估算示例: 假设你的提示词加上shared_dependencies总计1500个token,每个文件生成的提示平均1000个token,生成5个文件。
- 计划阶段:输入1500 token,输出假设800 token。GPT-4输入$0.03/1K tokens,输出$0.06/1K tokens。成本 ≈ (1.5 * 0.03) + (0.8 * 0.06) = $0.093。
- 生成5个文件:每个文件输入(1500+1000)=2500 token,输出平均500 token。总成本 ≈ 5 * [(2.5 * 0.03) + (0.5 * 0.06)] = 5 * (0.075 + 0.03) = $0.525。
- 总计:生成一个项目约需$0.62。
这只是一次生成的成本。如果进行3-4轮“提示-生成-调试”的循环,成本可能达到2-3美元。对于个人探索或小团队原型设计,这是可以接受的。但对于需要批量生成或作为公共服务,成本会迅速累积。
优化建议:
- 使用GPT-3.5 Turbo进行迭代:对于非关键性的迭代或简单项目,可以在
main.py中使用--model=gpt-3.5-turbo-0613参数。它的成本低一个数量级(约$0.0015/1K tokens输入,$0.002/1K tokens输出),速度也更快,虽然代码质量和对复杂指令的遵循度可能稍逊于GPT-4。 - 精炼提示词:避免在提示词中包含无关的上下文。清晰、简洁的提示能减少token消耗。
- 本地模型:如果拥有强大的GPU资源,可以探索将
smol developer的后端切换到开源的、可本地部署的大语言模型(如CodeLlama、DeepSeek-Coder)。这需要修改底层的模型调用逻辑,但能彻底消除API成本。
5.2 当前局限性
smol developer是一个强大的原型工具,但并非万能。
- 无法处理复杂业务逻辑:它擅长生成结构性的、模式化的代码(如CRUD接口、基础UI、配置文件)。但对于需要深度领域知识、复杂算法或独特业务规则的逻辑,它很可能生成错误或过于简单的代码。它生成的是“骨架”和“血肉”,但“灵魂”(核心业务逻辑)仍需开发者注入。
- 依赖管理是盲区:它不会为你运行
npm install或pip install -r requirements.txt。它生成的package.json或requirements.txt可能遗漏依赖,或者版本不兼容。你需要手动检查和安装依赖。社区在探索让AI自主解决依赖的方案,但这涉及到执行任意代码的安全风险,非常复杂。 - 上下文长度限制:尽管GPT-4的上下文窗口已很大(如32K),但对于极其庞大的项目或需要将整个SDK文档作为上下文时,仍然可能不够用。这限制了它能一次性理解和生成的项目规模。
- “幻觉”问题:模型有时会“自信地”生成一些不存在的库函数或API用法。虽然
shared_dependencies机制缓解了文件间的不一致,但单个文件内部的逻辑“幻觉”仍需人工审查。 - 迭代中的状态丢失:在Git仓库模式下,重新生成通常会覆盖文件。如果你在AI生成的代码基础上手动添加了大量逻辑,重新生成可能会丢失这些修改。一种策略是让AI只生成你尚未手动修改的文件,或者将AI生成的部分与手写部分严格模块化。
5.3 安全与生产就绪性
切勿直接将生成代码用于生产!smol developer生成的代码是一个极佳的起点和原型,但在投入生产环境前,必须经过严格的安全审计和测试。
- 安全检查:仔细审查所有用户输入处理、数据库查询、文件操作、第三方API调用,确保没有注入漏洞、路径遍历等安全问题。
- 依赖审计:检查所有生成的依赖包及其版本,确保没有已知的安全漏洞。
- 全面测试:为生成的核心功能编写单元测试和集成测试。AI生成的代码的边界情况处理往往比较薄弱。
6. 生态与未来展望
smol developer的理念激发了一个活跃的社区,出现了许多分支和变体,丰富了其生态系统。
主要分支/替代实现:
- smol-dev-js:一个纯JavaScript/TypeScript的实现。它的一个有趣特性是支持“增量提示”,你可以针对现有代码库的特定部分进行提示修改,而不是每次都从头生成整个项目。
- smol-ai-dotnet和smol-dev-go:分别为C#/.NET和Golang生态提供了原生实现,让这些语言的开发者也能享受同等的便利。
- smol-plugin:专注于根据API的Markdown描述,自动生成符合OpenAI插件规范的代码,简化了ChatGPT插件的开发流程。
这些分支表明,smol developer的核心工作流(规划->文件列表->并行生成)具有普适性,可以适配不同的编程语言和模型后端。
未来的可能性:
- 自我引导:一个有趣的方向是让
smol developer能够分析现有的代码库,并反向生成描述该代码库的提示词(prompt.md)。这样,你就可以从一个现有项目开始,让AI理解它,然后在此基础上进行修改或扩展,实现真正的“代码理解与演化”。 - 集成测试与自愈:让生成流程包含一个自动化的测试步骤。生成代码后,自动运行基本的测试(如语法检查、单元测试),如果失败,则将测试错误作为新的输入反馈给模型,让它自我修复,形成闭环。
- 环境感知与依赖解决:与Docker或Nix等容器化/声明式环境管理工具结合,让AI不仅生成应用代码,还能生成构建和运行环境所需的配置文件,实现“开箱即用”。
- 多模态与UI生成:结合图像生成或UI设计模型,从产品草图或线框图直接生成前端代码,将原型设计到代码实现的链路进一步缩短。
从我个人的使用经验来看,smol developer最大的价值不在于替代开发者,而在于极大地压缩了从想法到可运行原型之间的“摩擦”。它把那些繁琐、重复、需要查阅大量文档的脚手架搭建工作自动化了,让开发者能更早、更频繁地接触到“可运行的东西”,从而更快地进行验证、反馈和迭代。它就像是一个永远在线、随叫随到、能力还在不断增长的编程伙伴,虽然有时会犯些小错,但只要你能清晰地描述问题,它总能给出有价值的、可供进一步加工的代码草案。在这个快速试错的时代,这种能力无疑是一把利器。
