用 AtomCode 从零开发并部署上线:一个 Flask 待办应用的完整实战
用 AtomCode 从零开发并部署上线:一个 Flask 待办应用的完整实战
本文是一篇全程真机实操的记录。所有命令、输出、HTTP 状态码、Git 提交与仓库地址均来自服务器
117.72.182.3(Ubuntu 22.04 / Python 3.10.12)上的真实执行,非示意。目标:只给 AtomCode 一句需求,让它从零写出一个可运行的 Flask 任务管理应用,然后在服务器上部署上线并推送到全新的 Gitee 仓库。
- 编程执行引擎:AtomCode 4.26.0(模型
deepseek-v4-flash)- 最终成果仓库:
https://gitee.com/LiaCin/atomcode-flask-todo
目录
- 一、这篇文章要证明什么
- 二、整体流程一图看懂
- 三、环境准备
- 四、第 1 步:写清楚需求(Prompt 即规格)
- 五、第 2 步:一条命令让 AtomCode 从零开发
- 六、第 3 步:AtomCode 交付了什么
- 七、第 4 步:跑测试(18 个用例)
- 八、第 5 步:部署上线 + curl 验收
- 九、第 6 步:推送到全新 Gitee 仓库
- 十、安全收尾
- 十一、关键命令速查表
- 十二、踩坑与经验
- 十三、附录:AtomCode 生成的核心代码
一、这篇文章要证明什么
一句话:从一句需求到线上可访问的服务 + 云端代码仓库,全程由 AtomCode 自动完成编码,人只负责"下需求、验收、上线"。
拆成 6 个可验证的步骤:
| 步骤 | 做什么 | 由谁完成 | 验收凭证 |
|---|---|---|---|
| 1 | 写需求(prompt.txt) | 人 | 见 §四 |
| 2 | 从零生成全部代码 | AtomCode | 见 §五、§六 |
| 3 | 自测 | AtomCode 自跑 + 人复跑 | 18 tests OK(§七) |
| 4 | 部署运行 | 人 | curl 200/201(§八) |
| 5 | 新建远程仓库 | 人(Gitee API) | HTTP 201(§九) |
| 6 | 推送代码 | 人(git push) | new branch main(§九) |
二、整体流程一图看懂
核心分工:AtomCode 负责 ②③(写代码 + 自测),人负责 ①④⑤⑥⑦⑧(下需求、验收、部署、建仓、推送)。
三、环境准备
服务器实测环境:
OS : Ubuntu 22.04(内核容器/云主机)
Python : Python 3.10.12
pip : pip 22.0.2
Flask : 3.1.3(已装)
AtomCode: 4.26.0 (/usr/local/bin/atomcode,Rust 二进制)
模型 : deepseek-v4-flash(base_url = https://llm-api.atomgit.com/v1)
工作目录 : /root/projects/flask-todo
AtomCode 是 Rust 单二进制,不依赖 Node 运行时;官方一键安装:
curl -fsSL https://raw.atomgit.com/.../install.sh | sh
四、第 1 步:写清楚需求(Prompt 即规格)
AtomCode 的产出质量,几乎完全取决于需求写得有多具体。这里把需求当"规格说明书"写进 prompt.txt,明确到接口、字段、端口、文件清单:
You are an expert software engineer. Build a complete, runnable Flask
task-management web application in /root/projects/flask-todo.
1. Backend (app.py):
- Flask only, SQLite (tasks.db),tasks 表:id/title/description/done/created_at
- REST API:
GET /api/health -> {"status":"ok"}
GET /api/tasks -> 全部任务(最新在前)
POST /api/tasks -> 创建(JSON title/description),返回 201
GET /api/tasks/<id> -> 单条或 404
PUT /api/tasks/<id> -> 更新,返回更新后对象
DELETE /api/tasks/<id> -> 删除,返回 204
- static/ 目录托管前端;默认监听 127.0.0.1:5000(env PORT 可覆盖;后续为对外访问已改为 0.0.0.0,见 §8.1)
- 启动时自建表;if __name__ == "__main__" 守卫
2. Frontend (static/index.html + app.js + style.css):原生 fetch,无框架
3. requirements.txt: 仅 flask
4. README.md:运行说明 + 接口表
5. test_app.py:用 Flask test client 建任务并断言其出现,可 python3 直接跑
Keep everything local; do NOT expose the server publicly.
经验:接口用"方法 + 路径 + 期望状态码"三元组写死,AtomCode 就不会自由发挥出你不想要的路由。
五、第 2 步:一条命令让 AtomCode 从零开发
用 headless(非交互)模式,让 AtomCode 读需求文件、自动写代码、自动自测:
cd /root/projects/flask-todo
atomcode -y \
-C /root/projects/flask-todo \
--max-turns 30 \
--prompt-file /root/projects/flask-todo/prompt.txt \
--disable-tools none \
> build.log 2>&1
参数拆解:
| 参数 | 作用 |
|---|---|
-y / --dangerously-skip-permissions |
自动批准所有工具调用(无人值守必需) |
-C <dir> |
指定工作目录,代码就地生成 |
--max-turns 30 |
最多 30 个自主回合,防止跑飞 |
--prompt-file |
从文件读需求(比 -p 更适合长规格) |
--disable-tools none |
允许全部工具(读写文件、跑 bash、跑测试) |
build.log 里 AtomCode 的自述(真实节选):
[engine v2] new stack active (model deepseek-v4-flash)
[headless] --dangerously-skip-permissions: all tool calls are auto-approved
...
All 18 tests pass. Let me clean up the temp database file ... and finalize.
All tasks complete. Here's a summary of the project:
也就是说,AtomCode 自己写完代码后,自己跑了 18 个测试并全部通过,才宣布收工。
六、第 3 步:AtomCode 交付了什么
find 实测生成的文件清单:
/root/projects/flask-todo/app.py # Flask 后端(REST + SQLite + 静态托管)
/root/projects/flask-todo/static/index.html # 单页前端
/root/projects/flask-todo/static/app.js # 原生 fetch CRUD
/root/projects/flask-todo/static/style.css # 响应式样式
/root/projects/flask-todo/test_app.py # 18 个 API 测试
/root/projects/flask-todo/requirements.txt # 仅 flask
/root/projects/flask-todo/README.md # 运行说明 + 接口表
/root/projects/flask-todo/build.log # AtomCode 自述日志
AtomCode 生成的接口一览(与需求完全对齐):
| Method | Path | 动作 | 状态码 |
|---|---|---|---|
| GET | /api/health |
健康检查 | 200 |
| GET | /api/tasks |
列出全部(最新在前) | 200 |
| POST | /api/tasks |
创建任务 | 201 |
| GET | /api/tasks/<id> |
查单条 | 200 / 404 |
| PUT | /api/tasks/<id> |
更新 | 200 |
| DELETE | /api/tasks/<id> |
删除 | 204 |
七、第 4 步:跑测试(18 个用例)
人工复跑一遍 AtomCode 写的测试,验证不是"自说自话":
cd /root/projects/flask-todo && python3 test_app.py
真实输出(尾部):
test_get_task ... ok
test_get_task_not_found ... ok
test_health ... ok
test_list_tasks_empty ... ok
test_list_tasks_order ... ok
test_update_task_done ... ok
test_update_task_invalid_done ... ok
test_update_task_not_found ... ok
test_update_task_title ... ok
----------------------------------------------------------------------
Ran 18 tests in 0.133s
OK
覆盖:健康检查、完整 CRUD、参数校验(缺 title / done 非法值)、404 分支、列表排序、静态文件托管。18/18 通过。
八、第 5 步:部署上线 + curl 验收
后台启动服务(干净库,重定向日志):
cd /root/projects/flask-todo
rm -f tasks.db
nohup python3 app.py > /tmp/flask.out 2>&1 &
启动日志(真实,绑定 0.0.0.0 后):
* Serving Flask app 'app'
* Debug mode: on
* Running on all addresses (0.0.0.0)
* Running on http://127.0.0.1:5000
* Running on http://172.16.0.3:5000
* Debugger is active!
端口确认在听(已绑定到全部网卡 0.0.0.0):
$ ss -ltnp | grep 5000
LISTEN 0 128 0.0.0.0:5000 ... users:(("python3",pid=27836,...))
验收 1|健康检查:
$ curl -s -w '\n[HTTP %{http_code}]\n' http://127.0.0.1:5000/api/health
{ "status": "ok" }
[HTTP 200]
验收 2|创建任务(中文入参):
$ curl -s -X POST http://127.0.0.1:5000/api/tasks \
-H 'Content-Type: application/json' \
-d '{"title":"部署验收任务","description":"AtomCode 从零开发并上线"}'
{
"created_at": "2026-07-10T09:38:46.063850+00:00",
"description": "AtomCode 从零开发并上线",
"done": 0,
"id": 1,
"title": "部署验收任务"
}
[HTTP 201]
验收 3|列表回读:
$ curl -s http://127.0.0.1:5000/api/tasks
[ { "id": 1, "title": "部署验收任务", "done": 0, ... } ]
[HTTP 200]
验收 4|前端首页:
$ curl -s -o /dev/null -w 'index.html [HTTP %{http_code}] %{size_download} bytes\n' http://127.0.0.1:5000/
index.html [HTTP 200] 891 bytes
至此,服务已在服务器上真实运行并对外提供 REST + 前端页面。
8.1 改为对外监听 0.0.0.0(公网可访问)
默认 app.py 写的是 host="127.0.0.1",只能本机 127.0.0.1 访问。若要让服务对外部网络开放,只需把启动地址改成 0.0.0.0:
# app.py 第 174-176 行
host = "0.0.0.0" # 原为 "127.0.0.1"
port = int(os.environ.get("PORT", 5000))
app.run(host=host, port=port, debug=True)
改完重启并复验(真实输出):
$ ss -ltnp | grep 5000
LISTEN 0 128 0.0.0.0:5000 ... users:(("python3",pid=27836,...))
$ curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:5000/api/health
200
$ curl -s -o /dev/null -w '%{http_code}\n' http://0.0.0.0:5000/api/health
200
外部可达性还需两步(本次已确认服务器内部 0.0.0.0 绑定成功,但公网探测返回 000):
| 检查项 | 状态 | 说明 |
|---|---|---|
服务绑定 0.0.0.0:5000 |
✅ 已生效 | ss 明确看到 0.0.0.0:5000 |
| 云安全组 / 防火墙放通 5000 | ⚠️ 需手动 | 本机 curl 117.72.182.3:5000 仍 000,需在云控制台入站规则放行 TCP 5000 |
| 本机公网 IP | 117.72.182.3 |
外部访问地址即 http://117.72.182.3:5000 |
改完记得把代码推回仓库:
git commit -m 'chore: bind 0.0.0.0:5000 for external access' && git push(实际已推,commita84c9b4)。
⚠️ 安全红线:
debug=True的开发服务器一旦绑定0.0.0.0暴露到公网,Werkzeug 调试器存在**远程代码执行(RCE)**风险(知道 PIN 或绕过 PIN 即可执行任意命令)。公网开放务必关 debug,见下方生产建议。
生产建议:
app.run(debug=True)仅用于本次验收;正式上线应换gunicorn -w 4 -b 127.0.0.1:5000 app:app+ Nginx 反代(Nginx 监听0.0.0.0:80/443对外,Flask 仍只绑内网),并关闭 debug。若确实要 Flask 直连公网,至少debug=False且加反向代理与访问控制。
九、第 6 步:推送到全新 Gitee 仓库
9.1 用 Gitee API 新建仓库
curl -s -X POST 'https://gitee.com/api/v5/user/repos' \
-H 'Content-Type: application/json' \
-d '{"access_token":"<TOKEN>","name":"atomcode-flask-todo",
"description":"由 AtomCode 从零自动开发的 Flask 任务管理应用",
"private":false,"has_issues":true}'
返回(真实,节选):
{ "full_name": "LiaCin/atomcode-flask-todo",
"html_url": "https://gitee.com/LiaCin/atomcode-flask-todo.git",
"private": true }
[HTTP 201]
⚠️ 注意:即使传
private:false,Gitee 新建仓库默认仍为私有,需要公开可到仓库设置里手动改。
9.2 加 .gitignore(别把库/日志/凭据提交上去)
__pycache__/
*.pyc
tasks.db
build.log
prompt.txt
*.out
.venv/
9.3 配置 Git 身份并提交
该服务器原本没有全局 Git 身份(
/root/.gitconfig不存在),首次提交前必须配置:
git config --global user.name "LiaCin"
git config --global user.email "liacin@gitee.com"
git config --global init.defaultBranch main
cd /root/projects/flask-todo
git init
git add -A
git commit -m "feat: AtomCode 从零生成的 Flask 待办应用(REST API + SQLite + 原生JS前端 + 18测试)"
提交结果(真实):
2deaf20 feat: AtomCode 从零生成的 Flask 待办应用...
---tracked files---
.gitignore
README.md
app.py
requirements.txt
static/app.js
static/index.html
static/style.css
test_app.py
9.4 推送
# 用 token 临时鉴权:https://<用户名>:<TOKEN>@gitee.com/<owner>/<repo>.git
git remote add origin "https://LiaCin:<TOKEN>@gitee.com/LiaCin/atomcode-flask-todo.git"
git branch -M main
git push -u origin main
推送结果(真实):
To https://gitee.com/LiaCin/atomcode-flask-todo.git
* [new branch] main -> main
Branch 'main' set up to track remote branch 'main' from 'origin'.
API 二次核验 default_branch 已变为 main:
$ curl -s 'https://gitee.com/api/v5/repos/LiaCin/atomcode-flask-todo?access_token=<TOKEN>'
... "default_branch":"main" ...
[HTTP 200]
🎉 代码已上云:https://gitee.com/LiaCin/atomcode-flask-todo
十、安全收尾
真机操作后必须做的收尾(本次已全部执行):
- 清除 remote 里的明文 token——push 完把带 token 的 URL 换掉:
核验:git remote set-url origin https://gitee.com/LiaCin/atomcode-flask-todo.gitgit remote -v已不含 token。 - 停掉验收用的 debug 服务:
pkill -f 'python3 app.py'。 - 删除本地含明文凭据的临时脚本(root 密码 / Gitee token 均不落盘)。
- 敏感文件进 .gitignore:
tasks.db、build.log、prompt.txt、*.out不入库。
十一、关键命令速查表
| 阶段 | 命令 |
|---|---|
| 让 AtomCode 开发 | atomcode -y -C <dir> --max-turns 30 --prompt-file prompt.txt --disable-tools none |
| 复跑测试 | python3 test_app.py |
| 后台起服务 | nohup python3 app.py > /tmp/flask.out 2>&1 & |
| 查端口 | ss -ltnp | grep 5000 |
| 健康检查 | curl -s http://0.0.0.0:5000/api/health(或 127.0.0.1) |
| 开放公网 | 改 app.run(host="0.0.0.0") + 云安全组放行 5000 |
| 建 Gitee 仓库 | curl -X POST gitee.com/api/v5/user/repos -d '{"access_token":"..","name":".."}' |
| Git 身份 | git config --global user.name/user.email |
| 首推 | git init && git add -A && git commit -m .. && git push -u origin main |
| 清 token | git remote set-url origin https://gitee.com/<owner>/<repo>.git |
十二、踩坑与经验
| 坑 | 现象 | 解决 |
|---|---|---|
| Gitee token 校验用错方式 | 用 Bearer 头 → 401 |
Gitee 用 ?access_token= 查询参数或 Authorization: token |
| owner 用了显示名 | Lincoln/xxx → 404 |
用 path LiaCin(显示名 name ≠ 仓库 owner path) |
| 新仓库默认私有 | 传 private:false 仍是私有 |
到仓库设置手动改公开 |
| 服务器无 Git 身份 | commit 报 author unknown | 先 git config --global user.name/email |
| token 写进 remote | 明文残留在 .git/config |
push 后立即 git remote set-url 去掉 token |
| headless 权限 | 交互确认卡住 | 无人值守用 -y,并配 --max-turns 兜底 |
| 需求太笼统 | 生成的路由/字段跑偏 | prompt 里把"方法+路径+状态码+字段"写死 |
最大的一条经验:把 prompt.txt 当成给资深工程师的验收标准来写——你写得越像规格说明书,AtomCode 一次成型的概率越高。这次 18 个测试全过、6 个接口零返工,靠的就是需求写得够死。
十三、附录:AtomCode 生成的核心代码
app.py(AtomCode 自动生成,未经人工改动,节选主体):
#!/usr/bin/env python3
"""Flask task-management API with SQLite backend."""
import os, sqlite3
from datetime import datetime, timezone
from flask import Flask, g, jsonify, request, send_from_directory
app = Flask(__name__, static_folder="static")
DATABASE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "tasks.db")
def get_db():
if "db" not in g:
g.db = sqlite3.connect(DATABASE)
g.db.row_factory = sqlite3.Row
return g.db
def init_db():
with app.app_context():
db = get_db()
db.execute("""
CREATE TABLE IF NOT EXISTS tasks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL, description TEXT,
done INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL)""")
db.commit()
@app.route("/api/health")
def api_health():
return jsonify({"status": "ok"})
@app.route("/api/tasks", methods=["POST"])
def api_create_task():
data = request.get_json(silent=True)
if not data or not data.get("title", "").strip():
return jsonify({"error": "title is required"}), 400
title = data["title"].strip()
description = data.get("description", "").strip() or None
now = datetime.now(timezone.utc).isoformat()
db = get_db()
cur = db.execute(
"INSERT INTO tasks (title, description, done, created_at) VALUES (?,?,0,?)",
(title, description, now))
db.commit()
task = db.execute("SELECT * FROM tasks WHERE id=?", (cur.lastrowid,)).fetchone()
return jsonify(dict(task)), 201
# ... GET/PUT/DELETE /api/tasks/<id>、静态托管路由略(结构同上)...
if __name__ == "__main__":
init_db()
port = int(os.environ.get("PORT", 5000))
app.run(host="0.0.0.0", port=port, debug=True) # 已改为对外监听;生产环境应 debug=False
亮点(全部由 AtomCode 自主决定):
- 用
g+teardown_appcontext管理 SQLite 连接,请求级复用、自动关闭; - PUT 更新做了类型与取值校验(
done只允许 0/1,title 必须字符串); created_at用带时区的 ISO8601;列表按created_at DESC排序;- 入口
init_db()幂等建表,端口支持PORT环境变量覆盖。
一句话总结:需求写进一个文件 →
atomcode -y --prompt-file一条命令 → 8 个文件 + 18 个通过的测试自动生成 →curl验收 200/201 → Gitee 建仓 +git push上云。人只做了"下需求、验收、上线",写代码这件事,AtomCode 全包了。成果仓库:
https://gitee.com/LiaCin/atomcode-flask-todo
更多推荐


所有评论(0)