前端转 AI 第 20 天:CLI 打包与发布 - 让助手变成真正的命令行工具
昨日回顾
Day 18-19 把测试写完了,核心模块覆盖 90%+。
但有个尴尬的问题——我的助手现在还得这样跑:
cd ~/day19/ai-assistant-v6
python -m src.ai_assistant.main
这根本不像一个"工具"。 真正的命令行工具应该是:
ai-assistant
在任何目录下都能敲。
今天把它打包成真正的 CLI 工具,还能发布到 PyPI 让别人 pip install。
Day 20 目标:把项目打包成可安装的 CLI 工具,理解 Python 打包生态。
一、为什么前端对"打包"很亲切
前端其实天天在打包:
npm run build把源码打成dist/package.json的bin字段声明 CLInpm publish发布到 npm registrynpx直接运行已发布的工具
Python 的打包逻辑几乎一模一样:
| 前端 | Python |
|---|---|
package.json | pyproject.toml |
package.json 的 bin | [project.scripts] |
npm install -g | pip install |
npm link | pip install -e . |
npm publish | twine upload / flit publish |
| npm registry | PyPI |
npx xxx | pipx run xxx |
node_modules/ | site-packages/ |
dist/ | dist/*.whl |
理解了 npm,Python 的打包就是"换个名字"。
二、Python 打包的几种方式
Python 的打包生态比 npm 乱多了——有好几套工具。
| 工具 | 现状 | 推荐度 |
|---|---|---|
setuptools | 老牌、万能、啰嗦 | ⭐⭐⭐ 兼容性好 |
poetry | 一体化、依赖 + 打包 | ⭐⭐⭐⭐ 生态好 |
flit | 极简、只做打包 | ⭐⭐⭐ 简单项目 |
hatch | 现代、官方推荐 | ⭐⭐⭐⭐ 新项目推荐 |
pdm | 现代、PEP 582 | ⭐⭐⭐ |
uv | 极快(Rust)、全能 | ⭐⭐⭐⭐⭐ 2024 后新宠 |
这么多工具怎么选?
好消息: 不管用哪个工具,pyproject.toml 是共同标准。写一份配置,所有工具都能读。
我的建议:
- 学习阶段:用
setuptools(Python 自带,最稳) - 新项目:用
hatch或uv - 团队协作:用
poetry(依赖锁定好)
今天用 setuptools,因为它最简单、最不容易出坑,学会了其他工具 10 分钟能上手。
三、理解 pyproject.toml
先看完整结构(我们从 Day 6 起就在用):
[build-system]
requires = ["setuptools>=68", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "ai-assistant"
version = "0.1.0"
description = "命令行 AI 助手"
readme = "README.md"
requires-python = ">=3.11"
authors = [
{ name = "你的名字", email = "you@example.com" }
]
license = { text = "MIT" }
keywords = ["ai", "agent", "cli"]
dependencies = [
"pydantic>=2.0.0",
"python-dotenv>=1.0.0",
"rich>=13.0.0",
]
[project.optional-dependencies]
dev = ["pytest>=8.0.0", "pytest-cov>=5.0.0", "pytest-asyncio>=0.24.0"]
[project.scripts]
ai-assistant = "ai_assistant.main:main"
[project.urls]
Homepage = "https://github.com/yourname/ai-assistant"
Repository = "https://github.com/yourname/ai-assistant"
三块核心配置
1. [build-system]:用哪个打包工具
[build-system]
requires = ["setuptools>=68", "wheel"]
build-backend = "setuptools.build_meta"
这段不用改,模板化。 意思是"用 setuptools 打包,需要 68 版本以上"。
2. [project]:项目元信息
| 字段 | 必填 | 说明 |
|---|---|---|
name | ✅ | 包名(PyPI 上唯一) |
version | ✅ | 版本号 |
description | 一句话描述 | |
readme | README 文件 | |
requires-python | Python 版本要求 | |
dependencies | 依赖列表(等于 requirements.txt) | |
authors | 作者 | |
license | 开源协议 |
关键点:dependencies 写在这里,等于 requirements.txt。 装包时自动装依赖。
3. [project.scripts]:CLI 入口(最重要!)
[project.scripts]
ai-assistant = "ai_assistant.main:main"
这行的含义:
- 左边
ai-assistant:命令行敲的命令 - 右边
ai_assistant.main:main:调用ai_assistant包的main.py里的main()函数
等价于前端:
// package.json
{
"bin": {
"ai-assistant": "./bin/cli.js"
}
}
一模一样的心智。
四、改造项目结构
1. 复制 Day 19 的项目
cp -r day19/ai-assistant-v6 day20/ai-assistant-v7
cd day20/ai-assistant-v7
2. 检查目录结构
标准 Python 包结构长这样:
ai-assistant-v7/
├── pyproject.toml
├── README.md
├── .gitignore
├── .env.example
├── src/
│ └── ai_assistant/
│ ├── __init__.py
│ ├── __main__.py # ← 新增
│ ├── main.py
│ ├── config.py
│ ├── models.py
│ └── ...
└── tests/
├── conftest.py
├── test_storage.py
└── test_memory.py
关键点:src/ 布局。
为什么用 src/ 布局?
- 避免"意外 import":如果包直接在根目录,测试时可能 import 到源码而不是安装的版本
- 强制显式安装:必须
pip install -e .才能 import,更接近用户实际使用
3. 创建 __main__.py
__main__.py 让包可以这样跑:
python -m ai_assistant
内容:
"""支持 `python -m ai_assistant`"""
from .main import main
if __name__ == "__main__":
main()
同时,[project.scripts] 里的 main() 是给 ai-assistant 命令用的。 两者都可以。
4. 修改 main.py
确保有一个可被调用的 main() 函数:
"""程序入口"""
import argparse
import asyncio
import sys
from .config import config
from .logger import setup_logging, get_logger
from .session import AIAssistant
def parse_args():
parser = argparse.ArgumentParser(
prog="ai-assistant",
description="命令行 AI 助手(本地)",
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
)
parser.add_argument(
"--version",
action="version",
version="%(prog)s 0.1.0",
)
parser.add_argument(
"--no-stream",
action="store_true",
help="关闭流式输出",
)
parser.add_argument(
"--log-level",
default=config.LOG_LEVEL,
choices=["DEBUG", "INFO", "WARNING", "ERROR"],
help="日志级别",
)
return parser.parse_args()
async def async_main(args):
app = AIAssistant(use_stream=not args.no_stream)
try:
await app.run()
finally:
app.close()
def main():
"""CLI 入口函数"""
args = parse_args()
config.ensure_dirs()
setup_logging(args.log_level)
logger = get_logger(__name__)
try:
asyncio.run(async_main(args))
except KeyboardInterrupt:
print("\n已退出")
sys.exit(0)
except Exception as e:
logger.exception("应用崩溃")
print(f"应用崩溃: {e}", file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
main()
这里加了 --version 参数——CLI 工具的标配。
5. 补充 pyproject.toml
[build-system]
requires = ["setuptools>=68", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "ai-assistant-cli-demo" # PyPI 上必须唯一,加个后缀
version = "0.1.0"
description = "命令行 AI 助手 - 前端转 AI 学习项目"
readme = "README.md"
requires-python = ">=3.11"
authors = [
{ name = "前端转 AI" }
]
license = { text = "MIT" }
keywords = ["ai", "agent", "cli", "llm"]
dependencies = [
"pydantic>=2.0.0",
"python-dotenv>=1.0.0",
"rich>=13.0.0",
]
[project.optional-dependencies]
dev = [
"pytest>=8.0.0",
"pytest-cov>=5.0.0",
"pytest-asyncio>=0.24.0",
"build>=1.0.0",
]
[project.scripts]
ai-assistant = "ai_assistant.main:main"
[project.urls]
Homepage = "https://github.com/yourname/ai-assistant"
Repository = "https://github.com/yourname/ai-assistant"
# setuptools 需要的:告诉它去哪找包
[tool.setuptools.packages.find]
where = ["src"]
# pytest 配置
[tool.pytest.ini_options]
testpaths = ["tests"]
asyncio_mode = "auto"
addopts = "-v --tb=short"
注意最后两段——这是 setuptools 的专属配置。
[tool.setuptools.packages.find] 告诉 setuptools 去 src/ 下找包。 不写的话,setuptools 会在根目录找,找不到 ai_assistant。
6. 加一个 README
README.md:
# ai-assistant
命令行 AI 助手(学习项目)。
## 安装
```bash
pip install -e .
使用
# 直接运行
ai-assistant
# 或者
python -m ai_assistant
开发
pip install -e ".[dev]"
pytest
许可
MIT
---
## 五、本地安装(可编辑模式)
### 1. `pip install -e .`
```bash
cd day20/ai-assistant-v7
pip install -e .
-e = editable = 开发模式。
它做了什么:
- 不会复制文件,而是在
site-packages里放一个"指向当前目录"的软链接 - 改代码立刻生效,不用重新安装
- 同时注册
ai-assistant命令
输出:
Obtaining file:///Users/you/day20/ai-assistant-v7
Installing build dependencies ... done
Checking if build backend supports build_editable ... done
...
Successfully built ai-assistant-cli-demo
Successfully installed ai-assistant-cli-demo-0.1.0
2. 测试新命令
在任何目录下:
cd ~
ai-assistant
应该会启动助手!
╭───────────────────────────╮
│ │
│ AI 助手 v2(带记忆) │
│ │
╰───────────────────────────╯
ℹ 会话 ID: a3f9b2e1
你 ›
同时也能:
ai-assistant --version
# ai-assistant 0.1.0
ai-assistant --help
# usage: ai-assistant [-h] [--version] [--no-stream] ...
python -m ai_assistant --version
# ai-assistant 0.1.0
是不是超有成就感? 你的项目从一个"文件夹"变成了真正的"工具"。
3. 卸载
pip uninstall ai-assistant-cli-demo
-e 安装的也能卸载干净。
六、构建分发包
"安装到本地"和"发布给别人"是两回事。
1. 安装 build
pip install build
build 是 Python 官方的构建工具,比老式的 python setup.py sdist 简单得多。
2. 构建
python -m build
输出:
* Creating venv isolated environment...
* Installing packages in isolated environment... (setuptools>=68, wheel)
* Getting build dependencies for sdist...
* Building sdist...
* Building wheel from sdist
* Creating venv isolated environment...
* Installing packages in isolated environment... (setuptools>=68, wheel)
* Getting build dependencies for wheel...
* Building wheel...
Successfully built ai_assistant_cli_demo-0.1.0.tar.gz and ai_assistant_cli_demo-0.1.0-py3-none-any.whl
dist/ 目录下多出两个文件:
dist/
├── ai_assistant_cli_demo-0.1.0.tar.gz # 源码包 (sdist)
└── ai_assistant_cli_demo-0.1.0-py3-none-any.whl # 二进制包 (wheel)
两种包的区别:
| 类型 | 后缀 | 内容 | 用途 |
|---|---|---|---|
| sdist | .tar.gz | 源码 | 需要编译的场景 |
| wheel | .whl | 预构建 | 优先用这个,装得快 |
前端类比:
- sdist ≈ 源码包(含
package.json,装的时候要 build) - wheel ≈ 打包好的
dist/(直接就能用)
3. 从 wheel 安装
pip install dist/ai_assistant_cli_demo-0.1.0-py3-none-any.whl
和从 PyPI 装是一样的效果。 可以把这个 .whl 发给同事,同事 pip install xxx.whl 就能用。
七、发布到 PyPI(了解)
发布 = 上传到 PyPI(Python 官方的包仓库,相当于 npm registry)。
1. 注册账号
- 测试环境:test.pypi.org/
- 生产环境:pypi.org/
先在测试环境玩,别一上来就往生产发。
2. 生成 API Token
登录 → Account settings → API tokens → Add API token
得到一个 pypi-xxx... 开头的 token。
3. 用 twine 上传
pip install twine
# 上传到测试环境
twine upload --repository testpypi dist/*
# 上传到生产
twine upload dist/*
会提示输入用户名和密码:
- 用户名:
__token__ - 密码:粘上
pypi-xxx...
4. 验证
# 从测试环境安装
pip install --index-url https://test.pypi.org/simple/ ai-assistant-cli-demo
或者同事直接:
pip install ai-assistant-cli-demo
你就发布了一个 Python 包!
⚠️ PyPI 的包名是全局唯一的,且不能删除(只能 yank)。测试时一定加后缀,比如
xxx-demo/xxx-test。
5. 自动发布:GitHub Actions
手动上传太麻烦。 生产项目一般配 CI:
# .github/workflows/publish.yml
name: Publish to PyPI
on:
release:
types: [published]
jobs:
publish:
runs-on: ubuntu-latest
permissions:
id-token: write # 用 Trusted Publisher,不用 token
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- run: pip install build
- run: python -m build
- uses: pypa/gh-action-pypi-publish@release/v1
流程:
- 在 GitHub 上创建 release
- Actions 自动构建
- 自动上传 PyPI
这叫 Trusted Publisher(OIDC 认证)——不用手动存 token,更安全。
这部分今天只要知道有这回事,用的时候再查。
八、版本管理
版本号不是随便起的,Python 遵循语义化版本(SemVer):
主版本.次版本.修订号
↑ ↑ ↑
Major Minor Patch
| 变化 | 示例 | 含义 |
|---|---|---|
| Patch | 0.1.0 → 0.1.1 | bug 修复 |
| Minor | 0.1.0 → 0.2.0 | 加功能,向后兼容 |
| Major | 0.1.0 → 1.0.0 | 破坏性变更 |
版本号写在 pyproject.toml 里:
[project]
version = "0.1.0"
但是——手动改太容易忘。 更好的做法:
1. 用 __version__ 变量
src/ai_assistant/__init__.py:
__version__ = "0.1.0"
pyproject.toml 里引用:
[project]
dynamic = ["version"]
[tool.setuptools.dynamic]
version = { attr = "ai_assistant.__version__" }
这样版本号只在源码里改一次,打包时自动读取。
2. 用 setuptools_scm:从 git tag 自动生成
最强方案——版本号从 git tag 来:
[build-system]
requires = ["setuptools>=68", "setuptools_scm>=8"]
build-backend = "setuptools.build_meta"
[project]
dynamic = ["version"]
[tool.setuptools_scm]
然后打 tag 就是发版本:
git tag v0.1.1
git push --tags
打包时版本号自动是 0.1.1。
前端类比: 类似 npm version patch,但更自动化。
建议:
- 学习项目:手动写在
__init__.py - 正式项目:用
setuptools_scm+ git tag
九、用 pipx 隔离安装 CLI 工具
问题: pip install ai-assistant 会装到当前环境,如果你在项目 A 的 venv 里,就污染了。
解决:pipx——专门装 CLI 工具的工具。
# 安装 pipx
brew install pipx # Mac
# 或
pip install --user pipx
# 用 pipx 装工具
pipx install ai-assistant-cli-demo
# 现在 anywhere 都能用
ai-assistant
pipx 会为每个工具创建独立虚拟环境,互不干扰。
前端类比: pipx ≈ npx(全局安装的工具),但更隔离。
推荐: 所有 CLI 工具都用 pipx 装,不用 pip install。
十、实战:把 Day 19 项目完整打包
1. 完整项目结构
ai-assistant-v7/
├── pyproject.toml ✅
├── README.md ✅
├── .gitignore
├── .env.example
├── LICENSE ← 新增
├── src/
│ └── ai_assistant/
│ ├── __init__.py (加 __version__)
│ ├── __main__.py ✅ 新增
│ ├── main.py (加 --version)
│ ├── config.py
│ ├── models.py
│ ├── orm_models.py
│ ├── db_orm.py
│ ├── storage_orm.py
│ ├── llm.py
│ ├── memory.py
│ ├── commands.py
│ ├── ui.py
│ ├── logger.py
│ └── schema.sql
├── tests/
│ ├── conftest.py
│ ├── test_storage.py
│ └── test_memory.py
├── scripts/
│ └── migrate_json_to_db.py
└── dist/ (构建产物,不提交)
2. __init__.py
"""AI 助手 - 命令行工具"""
__version__ = "0.1.0"
3. LICENSE(MIT 示例)
MIT License
Copyright (c) 2026 前端转 AI
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
4. .gitignore 加构建产物
# 已有
__pycache__/
*.py[cod]
.venv/
venv/
.env
data/
logs/
.vscode/
.DS_Store
# 新增
build/
dist/
*.egg-info/
.pytest_cache/
.coverage
htmlcov/
5. 完整构建流程
# 1. 清理旧的
rm -rf build dist *.egg-info
# 2. 跑测试
pytest
# 3. 构建
python -m build
# 4. 检查产物
ls dist/
# ai_assistant_cli_demo-0.1.0-py3-none-any.whl
# ai_assistant_cli_demo-0.1.0.tar.gz
# 5. 在一个干净的环境里测试安装
python -m venv /tmp/test-env
source /tmp/test-env/bin/activate
pip install dist/ai_assistant_cli_demo-0.1.0-py3-none-any.whl
ai-assistant --version
deactivate
rm -rf /tmp/test-env
第 5 步是关键! 不要在自己开发环境测,要在干净环境里测——能发现"忘了声明某个依赖"的问题。
6. 加一个 Makefile(可选但推荐)
Makefile:
.PHONY: install dev test cov build clean publish
install:
pip install -e .
dev:
pip install -e ".[dev]"
test:
pytest
cov:
pytest --cov=src/ai_assistant --cov-report=html
build: clean
python -m build
clean:
rm -rf build dist *.egg-info .pytest_cache .coverage htmlcov
find . -type d -name __pycache__ -exec rm -rf {} +
publish: build
twine upload dist/*
用法:
make dev # 装开发依赖
make test # 跑测试
make build # 打包
make publish # 发布
前端类比: 相当于 package.json 的 scripts,但 Python 用 Makefile 更普遍。
十一、前端视角:Python 打包 vs npm
用一张表彻底对照:
| 环节 | npm | Python (setuptools) |
|---|---|---|
| 项目配置 | package.json | pyproject.toml |
| 声明 CLI | "bin": {...} | [project.scripts] |
| 入口文件 | #!/usr/bin/env node | def main(): ... |
| 本地链接 | npm link | pip install -e . |
| 依赖安装 | npm install | pip install -e . |
| 依赖锁 | package-lock.json | poetry.lock / uv.lock |
| 构建 | npm run build | python -m build |
| 构建产物 | dist/ (JS 文件) | dist/*.whl + *.tar.gz |
| 发布 | npm publish | twine upload / CI |
| 仓库 | npm registry | PyPI |
| 全局安装 | npm i -g | pipx install |
| 免安装运行 | npx | pipx run / uvx |
| 版本来源 | package.json | pyproject.toml / git tag |
最爽的一点:Python 有 -e 模式,改代码立刻生效。 npm 的 link 也能做到,但没这么顺滑。
最烦的一点:Python 的构建工具太多。 npm 就一套,Python 有一堆。选一套用,别纠结。
十二、今日踩坑
- 忘了
[tool.setuptools.packages.find]→ setuptools 找不到src/下的包,打出来的 wheel 是空的 [project.scripts]路径写错 → 比如写成src.ai_assistant.main:main,会报ModuleNotFoundError- PyPI 包名冲突 → 想叫
ai-assistant结果被占了,加前缀或后缀 - 忘了把
dist//build/加到.gitignore→ 提交一堆构建产物 pip install -e .后忘了pip uninstall→ 环境里一堆开发包,冲突README.md里的相对链接在 PyPI 上失效 → PyPI 渲染的是打包时那一刻的内容,别放动态链接license = { text = "MIT" }写成license = "MIT"→ 新版 PEP 639 支持简写,但旧版会报错,兼容起见用老写法- 没在干净环境测 → 自己机器上装了各种库,跑得好好的,用户装完直接
ModuleNotFoundError python -m build报错 "No module named 'build'" → 忘了pip install buildpip install .装了旧版本 → pip 有缓存,加--no-cache-dir或先pip uninstall
十三、阶段小结:Day 16-20 你有了什么
从数据到测试到打包,四天打完了一套"工程化地基":
| Day | 内容 | 产出 |
|---|---|---|
| 16 | SQLite | Database 封装类 |
| 17 | SQLAlchemy ORM | SessionStorageORM |
| 18 | pytest 基础 | tests/ 目录 + 19 个测试 |
| 19 | pytest 进阶 | mock / 集成 / 性能测试 |
| 20 | 打包 | 一个能 pip install 的 CLI 工具 |
你的项目现在有的能力:
- ✅ 数据持久化(SQLite + ORM)
- ✅ 测试保障(90%+ 覆盖率)
- ✅ 命令行工具(
ai-assistant命令) - ✅ 分发包(
.whl能给同事) - ✅ 自动发布(GitHub Actions 可配)
这已经是一个"能拿出来说"的项目了。 简历上可以写:
命令行 AI 助手:基于 Python 3.11,集成 SQLAlchemy + Pydantic + pytest,支持会话持久化、记忆管理、CLI 打包发布,测试覆盖率 90%+。
但它还差一块——它现在只能"本地跑",没有 API。
十四、今日总结
今天核心收获三件事:
[project.scripts]是 Python 的 CLI 入口,等价于 npm 的binpip install -e .是开发模式,改代码立刻生效,本地开发必备python -m build是标准构建工具,产出 wheel + sdist,上传 PyPI 就能发布
一个感受:
前端的"打包发布"是显式的——你有
dist/,有npm publish,每次改动都清楚"这一步是在打包"。
Python 的"打包发布"是隐式的——你的项目一直就是一个"包",pyproject.toml定义了一切,pip install -e .只是"让它知道自己是个包"。
从今天起,你写的 Python 项目不再是"脚本集合",而是"可安装、可分发、可发布"的软件。
这是从"写代码"到"做产品"的关键一步。
Day 20 完成度:✅
明日预告(Day 21)
进入 FastAPI,正式进入后端世界。
- FastAPI 是什么,为什么比 Flask 更适合 AI 应用
- 写第一个接口:
GET /和POST /chat - Pydantic 模型自动校验(Day 11 的成果)
- 自动生成 API 文档(Swagger UI)
- 把
ai-assistant从 CLI 变成 HTTP 服务
准备好,从"命令行"到"服务端"的跨越。
最后
如果这篇对你有用,点个赞让我知道有人在看。
评论区互动: 你之前打包发布过 npm 包吗?感觉 Python 的流程和前端比,哪个更舒服?
有问题评论区见,我们第 21 天继续。
100 天,第 21 天见。
附录:系列目录
已完成 ✅
| 阶段 | 天数 | 内容 |
|---|---|---|
| 基础 | 01-06 | Python 语法、数据结构、函数、OOP、文件、依赖管理 |
| 网络 | 07-08 | HTTP 请求、异步 asyncio |
| 工程 | 09-12 | 正则、装饰器、Pydantic、日志调试 |
| 项目 | 13-14 | 命令行 AI 助手 v1 / v2 |
| 复盘 | 15 | 阶段总结 |
| 数据 | 16-17 | SQLite 数据库、SQLAlchemy ORM |
| 测试 | 18-19 | pytest 入门 + 进阶 |
| 工具 | 20 | CLI 打包与发布 ✅ |
进行中 🎯
| 阶段 | 天数 | 内容 |
|---|---|---|
| 后端 | 21-30 | FastAPI + 完整服务端 |
| 大模型 | 31-45 | LLM API + Prompt 工程 |
| RAG | 46-60 | 向量数据库 + 知识库 |
| Agent | 61-80 | LangChain / 工具调用 |
| 实战 | 81-100 | 完整 Agent 项目上线 |
100 天后见,一起从切图仔变成 Agent 开发者。