本文来自《AI 应用开发课程》月份 1 课程文档,已整理为网站文章版本。
学习目标
学完本节后,你应当能够:
- 使用
uv初始化 Python 项目。 - 理解虚拟环境、依赖、锁文件的作用。
- 创建月份 1 的第一个练习项目
llm_api_lab。
前置知识
- 已完成
01-Python语言补位/模块
1. 为什么月份 1 统一用 uv
因为它同时解决了几个问题:
- 创建项目
- 安装依赖
- 管理虚拟环境
- 管理锁文件
- 统一运行命令
对初学者来说,这比混用 pip、venv、requirements.txt、poetry 更容易保持稳定。
2. 初始化项目
进入你的工作目录后执行:
uv init llm_api_lab
cd llm_api_lab
预期结果:
- 目录被创建
- 出现
pyproject.toml - 出现项目入口文件
3. 安装依赖
执行:
uv add httpx pydantic python-dotenv
uv add --dev pytest ruff
说明:
httpx:后面用于异步 HTTP 请求pydantic:做数据建模和校验python-dotenv:加载.envpytest:测试ruff:代码检查
4. 同步依赖与运行
执行:
uv sync
uv run python --version
预期结果:
uv创建并使用项目自己的环境- 能在该环境里运行 Python
5. 推荐初始化目录
将项目逐步整理成:
llm_api_lab/
├── app/
│ ├── __init__.py
│ ├── config.py
│ ├── models.py
│ └── services/
├── tests/
├── .env.example
├── README.md
└── pyproject.toml
6. 为什么一开始就要放 README 和 tests
因为月份 1 练的是“工程化”,不是“随手试验”。
README.md保证可重现tests/保证可回归
7. 第一个运行脚本
创建一个最小入口,例如 main.py:
def main() -> None:
print("llm_api_lab initialized")
if __name__ == "__main__":
main()
执行:
uv run python main.py
8. 实操任务
- 初始化
llm_api_lab - 安装依赖
- 创建
app/、tests/、.env.example、README.md - 运行第一个入口脚本
9. 自测题
uv相比只用pip带来了哪些统一能力?- 为什么不能把月份 1 所有内容都写在一个项目里?
- 为什么
README.md从第一天就要存在?
10. 作业与验收
验收标准:
- 项目能用
uv成功运行 - 依赖安装完成
- 目录结构清晰
- 你能说明每个依赖准备干什么
11. 常见错误
- 初始化后不进入项目目录就开始装依赖
- 把所有练习写在顶层目录
- 不写
.env.example
12. 本章与前文关系
前面的 Python 语言补位模块,让你具备了“能写、能读、能改”月份 1 代码的最低语言基础。本章开始,重点从“语言能力”切换到“项目能力”。
这一章要解决的核心问题是:
当你不再只是写一个
.py脚本,而是准备做一个可迭代的小项目时,应该如何初始化它?
这一步是后面所有工程化内容的起点。
13. 本章在研发助手项目中的位置
研发助手项目最终会有:
- 独立项目目录
- 明确依赖
- 可复现环境
- README
.env.example- 测试目录
而这些都从本章开始建立。也就是说,第 4 周综合项目其实不是凭空起一个大工程,而是在本章的项目初始化方式上不断扩展。
14. 为什么月份 1 统一使用 uv
并不是因为 uv 是唯一正确选择,而是因为月份 1 需要一个足够统一、足够稳定、足够轻量的 Python 项目管理方式。
你可以把 uv 理解为帮你统一做了几件原本容易散落的事:
- 创建项目
- 管理依赖
- 管理虚拟环境
- 运行命令
- 维护锁定依赖版本
这对初学者尤其重要,因为它减少了“工具链分裂”带来的认知负担。
15. uv、虚拟环境、依赖锁定分别在解决什么问题
uv
负责把“项目管理”这件事统一起来。
虚拟环境
负责让每个项目有自己的依赖隔离空间,避免不同项目互相污染。
锁定依赖
负责让你和别人、以及未来的自己,在尽量一致的依赖版本上运行项目。
如果这三者不分清,很多人会误以为:
- 装上依赖就等于完成工程化
实际上,工程化的重点是“稳定、清晰、可复现”。
16. 错误示例 vs 正确示例
错误示例:随手在任何目录安装依赖
pip install httpx fastapi pytest
问题:
- 你很快会忘记这个环境到底服务于哪个项目
- 不同项目之间会相互污染
- 难以重现依赖版本
正确示例:先初始化项目,再在项目内部管理依赖
uv init llm_api_lab
cd llm_api_lab
uv add httpx pydantic python-dotenv
uv add --dev pytest ruff
这个顺序的价值不是“命令更整齐”,而是你从一开始就在建立项目边界。
17. 完整文件级示例:一个最小教学型项目骨架
下面不是要你一次性实现所有内容,而是让你看到月份 1 项目初始化完成后,一个健康的最小骨架应该长什么样。
llm_api_lab/
├── app/
│ ├── __init__.py
│ ├── config.py
│ ├── models.py
│ └── services/
│ └── __init__.py
├── tests/
│ └── __init__.py
├── .env.example
├── README.md
├── main.py
└── pyproject.toml
main.py
"""月份 1 llm_api_lab 的最小入口。"""
def main() -> None:
print("llm_api_lab initialized")
if __name__ == "__main__":
main()
.env.example
DEEPSEEK_API_KEY=
DEEPSEEK_BASE_URL=https://api.deepseek.com
DEEPSEEK_MODEL=deepseek-chat
README.md
# llm_api_lab
月份 1 第 1 周练习项目,用于承载 Python 工程化与最小 LLM 调用练习。
18. 逐段解释这组项目骨架
为什么现在就有 app/
因为月份 1 后面的内容最终都会进入项目内部模块。你现在提前把主目录建好,后面就不会一直在顶层目录乱堆文件。
为什么现在就有 tests/
因为测试不是“最后有空再补”。从第一周开始把测试目录放进去,可以帮助你形成默认工程习惯。
为什么现在就有 .env.example
因为你后面一定会接 API Key。提前把配置承载方式固定下来,会让后面每一章更顺。
为什么 README.md 这么早就存在
因为可重现性是工程的一部分。哪怕只是第 1 周练习项目,也应该让未来的自己知道它是干什么的。
19. pyproject.toml 到底是什么
如果用一句话概括:
pyproject.toml是 Python 项目的核心配置文件。
在月份 1,你不需要掌握它的全部生态历史,但至少要理解它的作用:
- 描述项目元信息
- 记录依赖
- 作为工具配置入口
后面 ruff、测试和项目信息都会围绕它展开。
20. 从最小初始化到工程项目的递进
第一步:能创建项目
有目录、有入口、有依赖管理。
第二步:能承载配置与模型
加入 config.py、models.py。
第三步:能承载服务逻辑
加入 services/、后续加入 clients/。
第四步:能对外暴露
第 3 周接上 FastAPI,第 4 周进入综合项目。
你要意识到:uv init 不是终点,而是一个结构化项目生命周期的起点。
21. 调试与排错:本章常见问题
问题一:不在项目目录里执行命令
会导致依赖装到错误位置,或者配置文件不在你以为的目录。
问题二:顶层目录和项目目录混淆
例如你以为自己在 llm_api_lab 里,实际还在 month1-workspace 顶层。
问题三:以为项目骨架是“多余的形式主义”
这是典型误解。月份 1 后面的项目整洁度,几乎都取决于这里的骨架是否稳定。
22. 本章完成后你应该具备的能力
完成本章后,你应当做到:
- 能独立初始化一个月份 1 练习项目。
- 能解释为什么要独立项目目录。
- 能说明
pyproject.toml、README.md、.env.example为什么一开始就要存在。 - 能搭出后续可扩展的目录骨架。
23. 如果你卡在这里,先回看哪几章
- 目录和环境总混乱:回看 02-环境准备与学习方法.md
- 模块边界不清楚:回看 02-函数-模块-包.md
24. 从本章过渡到下一章的桥接说明
接下来进入 02-ruff日志env配置.md。
本章只是把“项目壳子”搭起来了。下一章要往这个壳子里放入真正的工程基础设施:环境变量、日志和代码检查。也就是从“有项目目录”升级到“项目具备最小工程感”。