← 学习路线
AI 学习

Python AI Agent 学习主笔记 · 完整版

从基础语法到函数、类、JSON、异常、HTTP、异步与工程组织,保留 30 章解释、示例与练习。

康雨 · 发布 · 约 62 分钟

阅读基础:按章节逐步阅读;示例环境见正文

读完可以:查阅原始解释、完整代码和排错上下文

完整笔记:约 30.9 千字与代码字符 · 244 个代码/流程块。可按目录分次查阅;内容来自现有笔记,不补写未记录的经历。

本文目录

完整学习档案:保留原有章节、代码、失败示例、排错过程和练习。代码反映记录时的环境,不代表每段都是最终版本,也不代表本次发布重新运行了全部示例。请在练习项目中使用自己的环境配置,勿填入生产密钥。

当前学习进度 Python 最少必要知识 100% 完成(面向 AI Agent / 大模型部署)

这里的“100%”不是说已经学完 Python 的全部内容,而是:为了继续学习 AI Agent、大模型 API、服务化与部署,当前阶段真正高频、最少且必要的 Python 基础已经学完。

本笔记边界 本笔记完整整理到 FastAPI 正式课程之前。FastAPI 只在“下一阶段路线”中作为未来方向出现,不展开路由、装饰器、请求模型、服务启动等教程。


1. 学习目标与知识地图

学习 Python 的目标不是一开始成为“Python 语言专家”,而是能够:

  1. 看懂 AI SDK、Agent 项目和部署代码;
  2. 修改模型、参数、Prompt、API 地址等配置;
  3. 使用函数和类组织程序;
  4. 处理 list、dict、JSON、文件和环境变量;
  5. 调用 HTTP API,并理解常见错误;
  6. 看懂 async def、await、并发调用;
  7. 看懂正式 Python 项目的目录结构;
  8. 使用 .venv 和 requirements.txt 重建项目环境;
  9. 为下一阶段的 FastAPI、Linux、Docker 和服务器部署打好基础。

知识主线:

text
变量与数据类型
    ↓
list / dict
    ↓
if / for
    ↓
函数 / 参数 / return
    ↓
import / pip / venv
    ↓
文件 / JSON / 异常 / 环境变量
    ↓
HTTP / API / requests
    ↓
class / object / self
    ↓
Type Hint
    ↓
async / await / Event Loop
    ↓
项目结构 / 依赖清单 / 环境重建
    ↓
进入 FastAPI 与部署阶段

2. 变量与基础数据类型

2.1 变量是什么

变量可以理解为:给数据起一个名字,方便后面的代码引用和修改这个数据。

python
model = "Qwen"
question = "什么是 AI Agent?"
temperature = 0.7

= 在 Python 里主要表示赋值,不是数学中的相等判断。

text
model = "Qwen"
       ↓
把右边的字符串 "Qwen" 保存到左边的变量 model

变量可以重新赋值:

python
model = "GPT"
model = "Qwen"

print(model)  # Qwen

第二次赋值后,model 当前指向的是新值 "Qwen"。

2.2 四种基础类型

类型 含义 示例 AI 开发中的常见用途
str 字符串、文本 "Qwen" Prompt、模型名、API Key、回答
int 整数 4096 token 数量、次数、状态码
float 浮点数、小数 0.7 temperature、概率、阈值
bool 布尔值 True 是否流式输出、功能开关
python
model = "Qwen"          # str
max_tokens = 4096       # int
temperature = 0.7       # float
stream = True           # bool

Python 的布尔值必须写成:

python
True
False

不能写成 JSON/JavaScript 风格的:

text
true
false

2.3 字符串和数字不能混淆

python
print(10 + 20)        # 30
print("10" + "20")  # 1020
  • 数字的 + 是数学加法;
  • 字符串的 + 是文本拼接。
python
age = 20
next_year = age + 1  # 21

如果写成:

python
age = "20"
# age + 1 会报错,因为 str 不能直接和 int 相加

2.4 None 是什么

None 表示:当前没有有效值、没有结果或结果缺失。

python
result = None

它不是字符串:

python
None    # 没有值
"None"  # 内容为 None 四个字符的字符串
""      # 空字符串,仍然是 str

判断是否为 None,推荐:

python
if result is None:
    print("当前没有结果")

牢记 None 不等于空字符串 ""。None 表示没有值;"" 表示有一个字符串,只是它的长度为 0。


3. list 列表

3.1 list 是什么

list 用来保存一组有顺序的数据,最明显的语法特征是方括号 []。

python
models = ["GPT", "Qwen", "DeepSeek"]

列表中的每一项叫元素。

3.2 索引从 0 开始

python
print(models[0])  # GPT
print(models[1])  # Qwen
print(models[2])  # DeepSeek
text
索引:   0        1          2
元素: "GPT"  "Qwen"  "DeepSeek"

3.3 常用操作

python
models = ["GPT", "Qwen"]

models.append("DeepSeek")
print(models)
# ["GPT", "Qwen", "DeepSeek"]

print(len(models))
# 3
  • append():在列表末尾添加元素;
  • len():获得列表的元素数量。

3.4 AI 对话中的 list

多轮消息天然是一组有顺序的数据,因此通常用 list:

python
messages = [
    "你好",
    "什么是 RAG?",
    "请继续解释"
]

但只用字符串无法记录“谁说了什么”,因此真实 API 中经常使用 list + dict。


4. dict 字典与 list + dict 组合

4.1 dict 是什么

dict 用来保存带标签的数据,使用大括号 {},每一项是 key: value。

python
model_info = {
    "model": "Qwen",
    "temperature": 0.7,
    "stream": True
}

其中:

text
"model" → key
"Qwen"  → value

4.2 通过 key 读取和修改

python
print(model_info["model"])  # Qwen

model_info["model"] = "GPT"
print(model_info["model"])  # GPT

list 和 dict 的核心区别:

text
list → 通过位置索引找数据:models[0]
dict → 通过 key 找数据:model_info["model"]

4.3 list + dict 表示多轮对话

python
messages = [
    {
        "role": "system",
        "content": "你是一名 AI 老师"
    },
    {
        "role": "user",
        "content": "什么是 Agent?"
    },
    {
        "role": "assistant",
        "content": "Agent 是一种能够围绕目标执行任务的 AI 系统"
    }
]

结构:

text
messages(list)
│
├── 第 1 个元素(dict)
│   ├── role
│   └── content
│
├── 第 2 个元素(dict)
│   ├── role
│   └── content
│
└── 第 3 个元素(dict)
    ├── role
    └── content

读取第二条消息内容:

python
print(messages[1]["content"])
# 什么是 Agent?

先用 [1] 从 list 中找到第二个元素,再用 ["content"] 从这个 dict 中取值。


5. 条件判断 if

5.1 基本结构

python
model = "Qwen"

if model == "Qwen":
    print("使用 Qwen")
elif model == "GPT":
    print("使用 GPT")
else:
    print("未知模型")
  • if:如果条件为 True,执行其代码块;
  • elif:前面的条件不成立时,继续判断另一个条件;
  • else:前面的条件都不成立时执行。

5.2 = 与 ==

python
model = "Qwen"   # 赋值
model == "Qwen"  # 比较是否相等,结果为 True 或 False

5.3 比较运算

写法 含义
== 等于
!= 不等于
> 大于
< 小于
>= 大于等于
<= 小于等于

5.4 and、or、not

python
age = 20
has_ticket = True

if age >= 18 and has_ticket:
    print("可以进入")
text
and → 两边都为 True,结果才为 True
or  → 至少一边为 True,结果就是 True
not → 对布尔结果取反
python
is_logged_in = False

if not is_logged_in:
    print("请先登录")

6. for 循环

6.1 遍历 list

遍历就是:把一组数据中的元素一个一个取出来处理。

python
models = ["GPT", "Qwen", "DeepSeek"]

for model in models:
    print(model)

model 是当前循环临时使用的变量名,类型取决于 models 中的元素类型。这里每个元素都是字符串,所以 model 是 str。

6.2 遍历 list 中的 dict

python
messages = [
    {"role": "user", "content": "你好"},
    {"role": "assistant", "content": "你好!"}
]

for message in messages:
    print(message["role"], message["content"])

这里每次取出的 message 是一个 dict。

6.3 for + if

python
tools = [
    {"name": "search", "enabled": True},
    {"name": "weather", "enabled": False},
    {"name": "calculator", "enabled": True}
]

for tool in tools:
    if tool["enabled"]:
        print(tool["name"])

输出:

text
search
calculator

6.4 range()

python
for i in range(5):
    print(i)

输出 0、1、2、3、4。

python
for i in range(2, 6):
    print(i)

输出 2、3、4、5。

range(开始, 结束) 包含开始值,不包含结束值,也就是“左闭右开”。

6.5 enumerate()

如果遍历时还需要索引:

python
models = ["GPT", "Qwen", "DeepSeek"]

for index, model in enumerate(models):
    print(index, model)

输出:

text
0 GPT
1 Qwen
2 DeepSeek

7. 函数 function

7.1 定义与调用

函数用于封装一段可以重复使用的功能。

python
def start_agent():
    print("Agent 启动")
    print("正在处理任务")
    print("任务完成")


start_agent()
  • def start_agent()::定义函数;
  • start_agent():调用函数;
  • 只定义不调用,函数体不会自动执行。

7.2 参数 parameter 与实参 argument

python
def ask(question):
    print("收到问题:", question)


ask("什么是 Agent?")
  • 定义时的 question 是参数;
  • 调用时传入的 "什么是 Agent?" 是实际数据,也常叫实参。

参数相当于函数的数据入口。

7.3 位置参数与关键字参数

python
def call_model(model, temperature):
    print(model)
    print(temperature)

位置参数按顺序对应:

python
call_model("Qwen", 0.7)

关键字参数直接写参数名,更清晰:

python
call_model(
    model="Qwen",
    temperature=0.7
)

7.4 默认参数

python
def call_model(question, model="Qwen", temperature=0.7):
    print(question, model, temperature)

调用时不传默认参数:

python
call_model("什么是 RAG?")

这次使用:

text
model = "Qwen"
temperature = 0.7

也可以覆盖默认值:

python
call_model(
    question="什么是 Agent?",
    model="GPT",
    temperature=0.2
)

默认参数顺序 没有默认值的参数必须放在有默认值的参数前面。

正确:

python
def ask(question, model="Qwen"):
    pass

错误:

python
# def ask(model="Qwen", question):
#     pass

7.5 return 返回值

python
def add(a, b):
    return a + b


result = add(10, 20)
print(result)  # 30

print() 与 return 的区别:

text
print  → 把内容显示给人看
return → 把结果交回给调用方,让程序继续使用

如果函数没有明确 return:

python
def show_answer():
    print("这是回答")


result = show_answer()
print(result)  # None

return 执行后,本次函数通常立即结束:

python
def test():
    print("开始")
    return "完成"
    print("这一行不会执行")

7.6 返回不同类型

python
def get_model():
    return "Qwen"                     # str


def is_ready():
    return True                       # bool


def get_models():
    return ["GPT", "Qwen"]           # list


def get_message():
    return {"role": "user", "content": "你好"}  # dict

8. import、第三方库与 pip

8.1 import 是什么

import 表示把其他模块中的功能引入当前代码。

python
import json
import os

也可以只导入某个功能:

python
from dotenv import load_dotenv
from openai import OpenAI

8.2 标准库与第三方库

  • Python 标准库:通常随 Python 一起提供,例如 json、os、asyncio;
  • 第三方库:需要另外安装,例如 requests、python-dotenv、openai。

8.3 pip install 与 import 的区别

text
pip install requests
→ 把第三方库安装到当前 Python 环境

import requests
→ 在当前代码里使用已经安装好的库

安装不等于导入,导入也不能代替安装。

推荐在已激活的虚拟环境中执行:

bash
python -m pip install requests

使用 python -m pip 的好处是更明确地让“当前这个 Python”运行对应的 pip。


9. 文件操作与 encoding

9.1 读取文件

python
with open("prompt.txt", "r", encoding="utf-8") as file:
    text = file.read()

print(text)

逐项解释:

text
"prompt.txt"      → 文件路径
"r"               → read,读取模式
encoding="utf-8"  → 使用 UTF-8 文字编码
as file            → 把打开后的文件对象临时命名为 file
file.read()        → 读取文件内容
text               → 保存读到的字符串

with 的重要价值是:离开代码块后,Python 会帮助关闭文件,减少忘记关闭文件导致的资源占用。

9.2 写入文件

python
answer = "这是 AI 回答"

with open("answer.txt", "w", encoding="utf-8") as file:
    file.write(answer)

"w" 是写入模式,通常会覆盖原内容。

9.3 追加文件

python
with open("log.txt", "a", encoding="utf-8") as file:
    file.write("一条新日志\n")
text
r → read,读取
w → write,写入并通常覆盖
a → append,在末尾追加

9.4 encoding 的常见错误

正确:

python
encoding="utf-8"

常见错误:

python
# encode="utf-8"      # 参数名错误
# encoding=" utf-8 "  # 不应随意加入空格

10. JSON 数据

10.1 JSON 是什么

JSON 是程序之间交换结构化数据时非常常见的文本格式。

Python dict:

python
data = {
    "model": "Qwen",
    "stream": True,
    "result": None
}

JSON:

json
{
  "model": "Qwen",
  "stream": true,
  "result": null
}

关键对应关系:

Python JSON
True true
False false
None null

10.2 JSON 字符串转 Python 数据

python
import json

text = '{"model": "Qwen", "temperature": 0.7}'
data = json.loads(text)

print(type(data))       # <class 'dict'>
print(data["model"])   # Qwen
text
JSON 字符串
    ↓ json.loads()
Python dict / list 等数据

10.3 Python 数据转 JSON 字符串

python
import json

data = {
    "model": "Qwen",
    "answer": "你好"
}

text = json.dumps(data, ensure_ascii=False)
print(text)

ensure_ascii=False 可以让中文直接显示,而不是显示为 Unicode 转义形式。

text
Python 数据
    ↓ json.dumps()
JSON 字符串

10.4 load/load 与 loads/dumps

text
json.loads() → 从字符串读取 JSON
json.dumps() → 转成 JSON 字符串
json.load()  → 从文件对象读取 JSON
json.dump()  → 把 Python 数据写入 JSON 文件

读取 JSON 文件:

python
with open("config.json", "r", encoding="utf-8") as file:
    data = json.load(file)

11. try / except 异常处理

11.1 为什么需要异常处理

程序运行时可能出现:

  • 文件不存在;
  • JSON 格式错误;
  • 网络断开;
  • API Key 无效;
  • 服务器错误;
  • 数据类型不符合预期。

使用 try / except 可以捕获错误并给出可理解的处理方式。

python
try:
    number = 10 / 0
except Exception as error:
    print("发生错误:", error)

11.2 常用结构

python
try:
    # 尝试执行可能出错的代码
    result = do_something()
except Exception as error:
    # 出错后执行
    print("执行失败:", error)
else:
    # try 没有出错时执行
    print("执行成功")
finally:
    # 无论成功还是失败,最后都会执行
    print("本次操作结束")

当前阶段最需要掌握:

python
try:
    ...
except Exception as error:
    ...

11.3 JSON 解析示例

python
import json


def parse_json(text):
    try:
        return json.loads(text)
    except Exception as error:
        print("JSON 解析失败:", error)
        return None

try 的范围不宜无节制地扩大。尽量只包住真正可能出错、需要特殊处理的代码,便于定位问题。


12. 环境变量、.env 与 API Key

12.1 为什么不要把 API Key 写死在代码中

不推荐:

python
api_key = "sk-真实密钥"

风险包括:

  • 上传 GitHub 后泄露;
  • 分享代码时被他人看到;
  • 不同电脑或服务器需要反复修改代码;
  • 开发、测试、生产环境难以分离。

12.2 环境变量

python
import os

api_key = os.getenv("OPENAI_API_KEY")

os.getenv() 的作用是:从当前进程已经拥有的环境变量中查找指定名称。

如果不存在,默认返回 None:

python
if api_key is None:
    raise ValueError("缺少 OPENAI_API_KEY")

也可以提供默认值:

python
model = os.getenv("MODEL_NAME", "Qwen")

12.3 .env 文件

示例 .env:

dotenv
OPENAI_API_KEY=你的密钥
MODEL_NAME=Qwen

Python 中常用 python-dotenv 加载:

python
import os
from dotenv import load_dotenv

load_dotenv()

api_key = os.getenv("OPENAI_API_KEY")
model = os.getenv("MODEL_NAME", "Qwen")

执行顺序:

text
load_dotenv()
→ 读取 .env,并把值加载进当前进程环境

os.getenv("OPENAI_API_KEY")
→ 从当前进程环境中读取这个变量

牢记 os.getenv() 不会凭空直接打开并读取 .env 文件。需要先用 load_dotenv() 加载,或由操作系统、容器、服务器提前设置环境变量。

12.4 .gitignore

通常应该忽略:

gitignore
.env
.venv/
__pycache__/
*.pyc

.env 常含密钥;.venv 可以重建且体积大。


13. HTTP、API 与 requests

13.1 最小 HTTP 模型

text
客户端 Client
    ↓ 发送 HTTP Request
服务器 Server
    ↓ 处理请求
返回 HTTP Response
    ↓
客户端读取状态码、响应头和响应内容

一个 HTTP 请求通常关心:

  • 请求方法:GET、POST 等;
  • URL:请求地址;
  • Headers:请求头,例如认证信息;
  • Query Parameters:URL 查询参数;
  • Body:请求体,常使用 JSON;
  • Status Code:响应状态码;
  • Response Body:响应内容。

13.2 GET 与 POST 的入门理解

text
GET  → 常用于获取资源或查询数据
POST → 常用于提交数据、创建任务或发起模型调用

具体语义由 API 文档决定,不能只靠方法名猜测全部行为。

13.3 requests 示例

GET:

python
import requests

response = requests.get(
    "https://example.com/api/models",
    timeout=30
)

print(response.status_code)
print(response.text)

POST JSON:

python
import requests

payload = {
    "model": "Qwen",
    "question": "什么是 Agent?"
}

response = requests.post(
    "https://example.com/api/chat",
    json=payload,
    timeout=30
)

response.raise_for_status()
data = response.json()
print(data)

13.4 常见状态码

状态码 入门含义 常见原因
200 请求成功 正常返回数据
400 请求数据有问题 参数缺失、格式错误
401 未通过身份认证 API Key 缺失、错误、过期
403 已识别但无权限 账号、资源或操作权限不足
404 请求的资源或路径不存在 URL/接口路径写错、资源 ID 不存在
429 请求过多或额度受限 触发频率限制、配额不足
500 服务器内部错误 服务端程序异常

404 不是“网络完全断了”,而通常是服务器收到了请求,但没有找到对应路径或资源。401 重点检查身份认证和 API Key。

13.5 超时与异常

python
import requests

try:
    response = requests.get(
        "https://example.com/api/models",
        timeout=30
    )
    response.raise_for_status()
    data = response.json()
except requests.RequestException as error:
    print("HTTP 请求失败:", error)

为网络请求设置 timeout 很重要,否则程序可能长时间等待。


14. class 与 object

14.1 class 是什么

class 可以理解为创建某一类对象的模板。它可以把相关的数据和行为组织在一起。

python
class Agent:
    pass

这里:

text
class → 定义类
Agent → 类名
pass  → 暂时不执行任何操作,占位

14.2 object 是什么

对象是根据类创建出来的具体实例。

python
agent1 = Agent()
agent2 = Agent()
text
Agent  → 类、模板
Agent() → 调用这个类并创建对象
agent1 → 保存第一个对象的变量
agent2 → 保存第二个对象的变量

agent1 和 agent2 通常是两个独立对象。

14.3 函数与类的区别

text
函数 function
→ 主要封装一个行为或处理过程

类 class
→ 把一类对象的数据和行为组织在一起
→ 可以创建多个各自拥有独立状态的对象

AI Agent 很适合使用类,因为一个 Agent 经常同时拥有:

text
数据:name、model、status、memory、tools、temperature
行为:start()、run()、stop()、search()、save_memory()

14.4 OpenAI 是类,client 是对象

python
from openai import OpenAI

client = OpenAI()

正确理解:

text
OpenAI   → 类
OpenAI() → 调用类,创建一个对象
client   → 保存这个对象的变量

不要把 OpenAI 说成对象;这里真正创建出的对象由 client 指向。


15. init、self、属性与方法

15.1 __init__ 的作用

python
class Agent:
    def __init__(self, name, model):
        self.name = name
        self.model = model

当前阶段可以理解为:__init__ 是对象创建时自动执行的初始化方法,用来设置对象的初始属性。

python
agent = Agent("学习助手", "Qwen")

大致过程:

text
调用 Agent 类
    ↓
创建一个新的 Agent 对象
    ↓
自动执行 __init__
    ↓
name 接收 "学习助手"
model 接收 "Qwen"
    ↓
把它们保存为这个对象的属性

严格地说,对象的创建还涉及 __new__,但在当前“最少必要知识”阶段,把 __init__ 理解为初始化对象即可。

15.2 self 是什么

self 表示:当前正在被操作的这个对象本身。

它不是对象在外部的变量名。

python
agent1 = Agent("搜索助手", "Qwen")
agent2 = Agent("写作助手", "GPT")
  • 执行 agent1 的方法时,self 指向 agent1 所指的对象;
  • 执行 agent2 的方法时,self 指向 agent2 所指的对象。
text
self ≠ agent1 这个变量名本身
self = 当前正在操作的对象

15.3 参数与属性

python
self.model = model

拆开理解:

text
右边 model
→ __init__ 接收到的参数,主要在本次方法调用中使用

左边 self.model
→ 当前对象自己的 model 属性,会保存在对象上

整行意思:

把传进来的 model 参数保存到当前对象自己的 model 属性中。

参数与属性可以使用不同名字:

python
class Agent:
    def __init__(self, selected_model):
        self.model = selected_model

15.4 对象属性

python
class Agent:
    def __init__(self, name, model):
        self.name = name
        self.model = model
        self.status = "stopped"

创建后:

python
agent = Agent("学习助手", "Qwen")

print(agent.name)    # 学习助手
print(agent.model)   # Qwen
print(agent.status)  # stopped

agent.name、agent.model、agent.status 都是对象属性。

15.5 对象方法

定义在类里面、用于操作对象的函数通常叫方法。

python
class Agent:
    def __init__(self, name):
        self.name = name

    def run(self, question):
        print(self.name, "正在处理:", question)

调用:

python
agent = Agent("学习助手")
agent.run("什么是 RAG?")

定义方法时需要写 self,但正常调用时不用手动传入:

python
agent.run("问题")

Python 会把 agent 当前指向的对象自动绑定给 self。


16. 属性修改、对象状态与方法封装

16.1 直接修改属性

python
agent = Agent("学习助手", "Qwen")
print(agent.model)  # Qwen

agent.model = "GPT"
print(agent.model)  # GPT

对象属性既可以读取,也可以修改。

16.2 通过方法修改属性

python
class Agent:
    def __init__(self, model):
        self.model = model

    def change_model(self, new_model):
        self.model = new_model
python
agent = Agent("Qwen")
agent.change_model("GPT")
print(agent.model)  # GPT

为什么不总是直接修改属性?因为方法中可以统一加入:

  • 参数检查;
  • 权限检查;
  • 日志记录;
  • 清理缓存;
  • 更新多个相关状态;
  • 重新建立连接。
python
class Agent:
    def __init__(self, temperature=0.7):
        self.temperature = temperature

    def change_temperature(self, value):
        if not 0 <= value <= 2:
            raise ValueError("temperature 必须在 0 到 2 之间")

        self.temperature = value

16.3 对象状态

对象状态就是对象在某个时刻保存的一组属性值。

python
class Agent:
    def __init__(self, name, model):
        self.name = name
        self.model = model
        self.status = "stopped"

    def start(self):
        self.status = "running"

    def stop(self):
        self.status = "stopped"

    def show_info(self):
        print("名称:", self.name)
        print("模型:", self.model)
        print("状态:", self.status)
python
agent = Agent("学习助手", "Qwen")
agent.start()
agent.show_info()

输出:

text
名称: 学习助手
模型: Qwen
状态: running

这里 start() 把对象状态从 stopped 改成了 running。

16.4 不同对象的状态互相独立

python
agent1 = Agent("搜索助手", "Qwen")
agent2 = Agent("写作助手", "GPT")

agent1.start()

print(agent1.status)  # running
print(agent2.status)  # stopped

调用 agent1.start() 不会自动修改 agent2。

16.5 属性名与方法名不要冲突

错误设计:

python
class Agent:
    def __init__(self):
        self.start = "stopped"

    def start(self):
        self.start = "running"

start 同时被当成属性名和方法名。对象属性可能遮蔽同名方法,最终:

python
agent.start()

可能相当于试图调用一个字符串,从而出现:

text
TypeError: 'str' object is not callable

正确设计:

python
self.status = "stopped"  # 数据状态

def start(self):          # 行为
    self.status = "running"

17. Type Hint 类型提示

17.1 Type Hint 是什么

Type Hint 用来提示参数、变量和返回值预期是什么类型。

python
def greet(name: str) -> str:
    return "你好," + name
text
name: str → 参数 name 预期是字符串
-> str    → 函数预期返回字符串

Type Hint 的主要价值:

  • 提高代码可读性;
  • 让编辑器更好地补全和提示;
  • 帮助静态检查工具发现问题;
  • 让多人协作时接口更清晰;
  • 很多 AI、Web 框架会读取类型信息。

Type Hint 通常不会像强类型语言那样,在普通 Python 运行时自动阻止所有错误类型。它主要是提示和约定,仍需要正确的运行时验证。

17.2 参数类型与返回值类型

python
def add(a: int, b: int) -> int:
    return a + b
python
def call_model(question: str, temperature: float) -> str:
    return "模型回答"

语法位置:

text
参数名: 类型
函数括号后 -> 返回类型

正确:

python
def ask(question: str) -> str:
    return question

17.3 list[str]

表示“列表中的元素预期都是字符串”。

python
def get_models() -> list[str]:
    return ["GPT", "Qwen", "DeepSeek"]
python
models: list[str] = ["GPT", "Qwen"]

17.4 dict[str, str]

表示 dict 的 key 是字符串,value 也是字符串。

python
def get_message() -> dict[str, str]:
    return {
        "role": "user",
        "content": "你好"
    }
python
message: dict[str, str] = {
    "role": "user",
    "content": "什么是 Agent?"
}

如果 value 可能是多种类型,简单项目中可以按实际需要写更宽泛的提示;不要为了“看起来高级”而写与真实数据不符的类型。

17.5 None 返回类型

函数只做操作、不返回有效结果时,可以写:

python
def show_info(name: str) -> None:
    print("名称:", name)

-> None 表示调用者不应期待一个有效返回值。

17.6 默认参数与 Type Hint 组合

python
def call_model(
    question: str,
    model: str = "Qwen",
    temperature: float = 0.7,
    stream: bool = False
) -> str:
    return "模型回答"

拆解:

text
question: str
→ 必填字符串参数

model: str = "Qwen"
→ 字符串参数,默认值为 "Qwen"

temperature: float = 0.7
→ 浮点数参数,默认值为 0.7

stream: bool = False
→ 布尔参数,默认值为 False

-> str
→ 返回字符串

调用:

python
answer = call_model("什么是 Agent?")

或:

python
answer = call_model(
    question="什么是 RAG?",
    model="GPT",
    temperature=0.2,
    stream=False
)

17.7 class 中的 Type Hint

python
class Agent:
    def __init__(self, name: str, model: str = "Qwen") -> None:
        self.name = name
        self.model = model
        self.status = "stopped"

    def start(self) -> None:
        self.status = "running"

    def run(self, question: str) -> str:
        return f"{self.name} 使用 {self.model} 回答:{question}"

18. 同步、异步、并发与并行

18.1 同步 synchronous

同步代码通常按照顺序执行:前一个操作没有结束,当前执行流就继续等待。

text
执行任务 A
    ↓ A 完成
执行任务 B
    ↓ B 完成
执行任务 C

如果三个任务分别等待 2 秒、3 秒、4 秒,而且完全顺序执行,总时间大约是:

text
2 + 3 + 4 = 9 秒

18.2 异步 asynchronous

异步重点是:当当前任务需要等待某个可异步等待的 I/O 时,可以暂时让出执行权,让事件循环推进其他任务;结果就绪后再回来继续。

典型等待:

  • 网络请求;
  • 数据库响应;
  • 文件或消息队列 I/O;
  • 定时等待。

异步不等于“所有代码同时运行”,也不等于“自动开启多个 CPU 核心”。

18.3 并发 concurrency

并发表示多个任务在同一段时间内共同推进。它们不一定在同一时刻真的都在 CPU 上执行。

text
任务 A 运行 → 等待 I/O
                    ↓
事件循环推进任务 B → 等待 I/O
                    ↓
事件循环推进任务 C
                    ↓
A 的结果就绪 → 继续 A

18.4 并行 parallelism

并行表示同一时刻确实有多个执行单元在执行不同任务,例如多个 CPU 核心同时进行计算。

text
CPU 核心 1 → 计算任务 A
CPU 核心 2 → 计算任务 B

并行的重点不是“一起开始”,而是同一时刻真正同时执行。

18.5 对比

概念 核心
同步 当前操作没完成,按当前流程等待
异步 等待可异步 I/O 时允许让出执行权
并发 多个任务在一段时间内交替或共同推进
并行 多个任务在同一时刻真正一起执行

19. async / await 与 Event Loop

19.1 async def

python
async def call_model(question: str) -> str:
    ...

async def 定义的是异步函数,也叫协程函数。调用它通常会得到一个协程对象,不是立刻把整个函数同步执行完。

python
coroutine = call_model("什么是 Agent?")

要在异步环境中等待结果:

python
result = await call_model("什么是 Agent?")

19.2 await

python
result = await call_model("什么是 Agent?")

当前阶段可以理解为:

当前任务要等待 call_model() 的异步结果;在它等待期间,让出执行权,让 Event Loop 有机会推进其他已安排的任务;结果就绪后,当前任务从这里继续。

await 只能用于适合等待的 awaitable 对象,并且通常写在 async def 中。

19.3 Event Loop 事件循环

Event Loop 可以理解为异步任务的调度员:

text
检查哪些任务现在可以继续
    ↓
推进这些任务
    ↓
某任务遇到 await 并等待 I/O
    ↓
暂时推进其他可运行任务
    ↓
I/O 结果就绪
    ↓
恢复原任务

事件循环不是凭空让同步阻塞代码变异步;它只能在任务真正把控制权交回时调度其他任务。

19.4 一个最小可运行示例

python
import asyncio


async def task(name: str, seconds: int) -> str:
    print(name, "开始")
    await asyncio.sleep(seconds)
    print(name, "完成")
    return name


async def main() -> None:
    result = await task("A", 2)
    print("结果:", result)


asyncio.run(main())

asyncio.run(main()) 会建立并运行事件循环,直到 main() 完成。


20. asyncio.gather 与多个异步任务

20.1 顺序 await

python
async def main() -> None:
    a = await task("A", 2)
    b = await task("B", 3)
    c = await task("C", 4)

这段代码的明确顺序是:

text
启动并等待 A 完成
    ↓
才开始 B,并等待 B 完成
    ↓
才开始 C,并等待 C 完成

总时间大约 2 + 3 + 4 = 9 秒。

关键不是“任务太快,来不及并发”,而是:代码没有提前把 B、C 安排起来。

20.2 asyncio.gather()

python
import asyncio


async def main() -> None:
    results = await asyncio.gather(
        task("A", 2),
        task("B", 3),
        task("C", 4)
    )

    print(results)


asyncio.run(main())

可以先理解为:

把多个异步任务一起安排起来,并等待它们全部完成。

理想情况下总时间主要由最慢的 4 秒任务决定,再加少量调度开销,而不是 9 秒。

text
A:2 秒 ─────┐
B:3 秒 ─────────┐
C:4 秒 ─────────────┐
                      ↓
                   全部完成

结果顺序通常与传给 gather() 的 awaitable 顺序对应:

python
results[0]  # A 的结果
results[1]  # B 的结果
results[2]  # C 的结果

20.3 错误处理提醒

默认情况下,其中一个任务抛出异常时,gather() 会把异常传播给等待它的调用方。实际项目要根据业务决定:

  • 是否整体失败;
  • 是否分别捕获每个任务的错误;
  • 是否使用超时;
  • 是否需要取消剩余任务。

当前阶段先掌握“共同安排 + 等待全部完成”的核心概念,不必过早复杂化。


21. 异步 I/O 与 requests 同步阻塞

21.1 async def 不会把内部代码自动变异步

下面的代码仍然存在同步阻塞问题:

python
import requests


async def get_data() -> str:
    response = requests.get(
        "https://example.com/data",
        timeout=30
    )
    return response.text

原因:

text
async def
→ 只说明这是异步函数

requests.get()
→ 本身仍是同步阻塞 HTTP 请求

当 requests.get() 阻塞时,它不会自动通过 await 把控制权交回事件循环,可能阻塞当前线程上的整个 Event Loop。

21.2 真正支持异步的 I/O 客户端

要进行真正的异步 HTTP I/O,通常需要使用提供异步接口的库或 SDK,并对其异步方法使用 await。概念示例:

python
async def get_data() -> str:
    response = await async_http_client.get("https://example.com/data")
    return response.text

这里的 async_http_client.get() 必须确实返回可等待对象;不能只因为函数名里写了 async 就假定它是异步的。

21.3 异步适合什么

特别适合 I/O 等待型任务:

  • 同时等待多个网络请求;
  • 同时等待多个模型 API;
  • Web 服务处理许多互相独立的请求;
  • 数据库、消息队列等外部 I/O。

不一定适合纯 CPU 密集计算。大量图片处理、模型本地推理、复杂数学计算等 CPU/GPU 密集任务,不能仅靠 async/await 获得真正并行加速。

21.4 核心结论

text
async def ≠ 自动异步
async def ≠ 自动并发
await ≠ 把任意同步函数变成异步
顺序 await ≠ gather 并发安排
异步并发 ≠ 多核并行

22. Python 项目目录结构

22.1 为什么不把所有代码放进 main.py

小练习可以只有一个文件;项目变大后,把全部代码塞进 main.py 会导致:

  • 文件太长,定位错误困难;
  • 职责混杂;
  • 修改一处容易影响其他部分;
  • 不利于测试、复用和多人协作;
  • 后期维护成本越来越高。

正式项目通常按职责拆分。

22.2 一个适合入门 Agent 的结构

text
my_agent/
├── .env
├── .gitignore
├── requirements.txt
├── main.py
├── app/
│   ├── __init__.py
│   ├── agent.py
│   ├── model.py
│   ├── tools.py
│   └── memory.py
├── data/
│   └── prompt.txt
└── tests/
    └── test_agent.py

可以这样理解:

text
main.py
→ 程序入口,组织其他模块完成整体流程

app/agent.py
→ Agent 类和核心流程

app/model.py
→ 大模型调用相关功能

app/tools.py
→ 工具定义与调用

app/memory.py
→ 记忆保存和读取

data/
→ Prompt、样例数据等

tests/
→ 测试代码

requirements.txt
→ 项目依赖清单

.env
→ 本机环境配置和密钥,通常不提交

22.3 入口负责组合,不负责包办一切

main.py 可以导入其他模块:

python
from app.agent import Agent


def main() -> None:
    agent = Agent("学习助手", "Qwen")
    answer = agent.run("什么是 Agent?")
    print(answer)


if __name__ == "__main__":
    main()

当前阶段只需知道:

python
if __name__ == "__main__":

常用于表示“当这个文件被直接运行时,执行下面的入口代码”。


23. module、package 与 init.py

23.1 module 模块

一个 .py 文件通常可以称为一个 Python 模块。

text
model.py  → model 模块
tools.py  → tools 模块
memory.py → memory 模块

从模块导入功能:

python
from app.model import call_model
from app.tools import search

23.2 package 包

package 用来组织多个相关模块。入门时可以把包含多个 .py 模块的 app/ 理解为一个包:

text
app/
├── __init__.py
├── agent.py
├── model.py
├── tools.py
└── memory.py

23.3 __init__.py

__init__.py 是经常放在 Python package 目录里的特殊 Python 文件,用于参与包的初始化和组织。

它:

  • 可以是空文件;
  • 可以在导入包时执行初始化代码;
  • 可以选择性地暴露包内常用名称;
  • 不是简单的“模块目录清单”。

示例:

python
# app/__init__.py
from .agent import Agent

之后可能可以:

python
from app import Agent

但当前阶段不必把所有内容都写进 __init__.py。看到它时知道“这里在组织 Python package”就足够。

现代 Python 在一些情况下支持没有 __init__.py 的命名空间包,但对普通入门项目而言,显式保留 __init__.py 往往更清晰。


24. .venv、requirements.txt 与 pip freeze

24.1 为什么需要虚拟环境

不同项目可能需要不同版本的第三方库:

text
项目 A → openai 1.x
项目 B → 某个不同版本

如果全部共用同一套全局环境,升级一个项目的依赖可能破坏另一个项目。虚拟环境为项目提供相对独立的 Python 解释器与第三方包安装位置。

24.2 创建虚拟环境

bash
python -m venv .venv

拆解:

text
python → 使用 Python
-m     → 运行一个模块
venv   → Python 自带的虚拟环境模块
.venv  → 创建出的虚拟环境目录名称

.venv 不是 module,而是一个目录,里面通常包含解释器相关文件、Scripts 和第三方包。

24.3 激活虚拟环境

Windows PowerShell:

powershell
.\.venv\Scripts\Activate.ps1

Windows CMD:

bat
.venv\Scripts\activate.bat

macOS / Linux:

bash
source .venv/bin/activate

退出虚拟环境:

bash
deactivate

退出只是停止当前终端使用它,不会删除 .venv。

24.4 requirements.txt

requirements.txt 是依赖清单,用来告诉使用者项目需要安装哪些第三方依赖。

示例:

text
openai==1.99.0
python-dotenv==1.1.1
requests==2.32.5

安装清单中的全部依赖:

bash
python -m pip install -r requirements.txt

24.5 pip freeze

查看当前环境中安装的包及其版本:

bash
python -m pip freeze

生成依赖快照的常见命令:

bash
python -m pip freeze > requirements.txt

含义:把当前环境中所有已安装包及精确版本写入 requirements.txt。

pip freeze 会记录当前环境中的全部已安装包,可能包含项目没有直接使用的包。生成前应确认虚拟环境是这个项目专用且较干净,并检查最终文件内容。

24.6 .venv 和 requirements.txt 的关系

text
.venv/
→ 已经实际创建并安装好依赖的本地运行环境

requirements.txt
→ 用文字记录“需要安装哪些依赖及版本”的清单

类比:

text
.venv
→ 已经装修完成的房子

requirements.txt
→ 装修材料清单

别人不需要复制你整套 .venv,而是根据清单在自己的电脑上重建环境。

因此通常:

text
.venv/          → 不提交 Git,体积大、与系统相关、可以重建
requirements.txt → 提交 Git,供他人或服务器重建

项目代码也不是“导入 .venv 中”。正确关系是:项目代码仍在项目目录,而当前项目使用 .venv 里的 Python 和第三方依赖。


25. 完整项目环境重建流程

这一节是从“拿到一个项目”到“成功运行”的完整清单。

25.1 Windows PowerShell

powershell
# 1. 进入项目目录
cd path\to\my_agent

# 2. 创建虚拟环境(只需首次创建)
python -m venv .venv

# 3. 激活虚拟环境
.\.venv\Scripts\Activate.ps1

# 4. 升级 pip(可选但常用)
python -m pip install --upgrade pip

# 5. 安装项目依赖
python -m pip install -r requirements.txt

# 6. 根据项目说明配置 .env
# 不要把真实密钥提交到 Git

# 7. 运行项目
python main.py

# 8. 退出虚拟环境
deactivate

25.2 macOS / Linux

bash
# 1. 进入项目目录
cd path/to/my_agent

# 2. 创建虚拟环境
python3 -m venv .venv

# 3. 激活虚拟环境
source .venv/bin/activate

# 4. 安装依赖
python -m pip install --upgrade pip
python -m pip install -r requirements.txt

# 5. 配置 .env 后运行
python main.py

# 6. 退出
deactivate

25.3 环境重建的完整逻辑

text
获得项目代码
    ↓
进入项目根目录
    ↓
查看 README / requirements.txt / .env.example
    ↓
创建本机自己的 .venv
    ↓
激活 .venv
    ↓
安装 requirements.txt 中的依赖
    ↓
创建并填写 .env
    ↓
确认当前 python 和 pip 来自 .venv
    ↓
运行 main.py

25.4 如何确认当前环境

powershell
python --version
python -m pip --version

在 Windows 还可以:

powershell
Get-Command python

如果虚拟环境已正确激活,路径通常会指向项目的 .venv。

25.5 第二天继续开发

不需要重新创建 .venv,通常只需要:

text
进入项目目录
    ↓
重新激活 .venv
    ↓
继续运行或开发

只有 .venv 被删除、损坏、Python 版本变化或需要完全重建时,才重新创建。


26. 综合示例:把知识串成一个小型 Agent 项目

以下示例只整合 Python 基础,不涉及 FastAPI。

26.1 目录

text
my_agent/
├── .env
├── .gitignore
├── requirements.txt
├── main.py
└── app/
    ├── __init__.py
    ├── agent.py
    └── model.py

26.2 .env

dotenv
MODEL_NAME=Qwen

26.3 requirements.txt

text
python-dotenv==1.1.1

版本号只是示例;实际项目应以本机已验证可用的版本为准。

26.4 app/model.py

python
async def call_model(
    question: str,
    model: str = "Qwen"
) -> str:
    # 这里暂时不接真实模型,仅模拟返回结果
    return f"[{model}] 模拟回答:{question}"

26.5 app/agent.py

python
from app.model import call_model


class Agent:
    def __init__(self, name: str, model: str = "Qwen") -> None:
        self.name = name
        self.model = model
        self.status = "stopped"

    def start(self) -> None:
        self.status = "running"

    def stop(self) -> None:
        self.status = "stopped"

    async def run(self, question: str) -> str:
        if self.status != "running":
            return "Agent 尚未启动"

        answer = await call_model(
            question=question,
            model=self.model
        )
        return answer

26.6 main.py

python
import asyncio
import os

from dotenv import load_dotenv

from app.agent import Agent


async def main() -> None:
    load_dotenv()

    model = os.getenv("MODEL_NAME", "Qwen")

    agent = Agent(
        name="学习助手",
        model=model
    )

    agent.start()

    answer = await agent.run("什么是 AI Agent?")
    print(answer)

    agent.stop()


if __name__ == "__main__":
    asyncio.run(main())

26.7 逐层拆解

text
import / from ... import ...
→ 导入标准库、第三方库和项目模块

load_dotenv()
→ 把 .env 中的变量加载进当前进程环境

os.getenv()
→ 读取已经存在于当前进程环境中的值

class Agent
→ 定义 Agent 类

Agent(...)
→ 创建对象

__init__
→ 初始化 name、model、status

self.model
→ 当前对象自己的模型属性

start() / stop()
→ 修改对象状态

question: str / -> str
→ Type Hint

async def
→ 定义异步函数

await call_model(...)
→ 等待异步模型调用结果

asyncio.run(main())
→ 建立并运行事件循环,执行异步入口

27. 个人易错点与纠错清单

这一部分专门根据学习过程中反复出现的错误整理。写完代码后,可以逐项检查。

27.1 中文冒号、括号、逗号与引号

错误:

text
if model == "Qwen":
print("你好")
“Qwen”
,

正确:

python
if model == "Qwen":
    print("你好")

必须特别留意:

中文全角 英文半角
: :
( ) ( )
“ ” " "
, ,

从 Word、微信、公众号复制代码时,最容易把英文引号自动替换为中文弯引号。

27.2 缩进

Python 使用缩进表示代码层级,推荐每层 4 个空格。

python
for tool in tools:
    if tool["enabled"]:
        print(tool["name"])

结构:

text
for
└── if
    └── print

常见错误是 def、if、for、with 后面的代码没有缩进,或同一层混用不同缩进。

27.3 True / False 大小写

Python:

python
True
False

JSON:

json
true
false

不要在 Python 代码里写小写 true/false。

27.4 字符串必须加英文引号

错误:

python
# model = Qwen
# role = assistant

Python 会把 Qwen、assistant 当成变量名。

正确:

python
model = "Qwen"
role = "assistant"

27.5 参数变量不要误写成字符串

错误:

python
def ask(question):
    print("收到问题:", "question")

这里打印的是固定文本 question。

正确:

python
def ask(question):
    print("收到问题:", question)

27.6 dict key 通常要加引号

错误:

python
# tool[enabled]
# message[content]

这会把 enabled、content 当成变量名。

正确:

python
tool["enabled"]
message["content"]

27.7 dict 各项之间要有逗号

错误:

python
# user = {
#     "name": "Tom"
#     "age": 21
# }

正确:

python
user = {
    "name": "Tom",
    "age": 21
}

27.8 encoding 拼写

正确:

python
with open("result.txt", "w", encoding="utf-8") as file:
    file.write("结果")

不是 encode=,也不要写成带多余空格的 " utf-8 "。

27.9 self 不等于对象变量名

text
agent1 → 外部变量名,指向一个对象
self   → 方法执行时的当前对象本身

执行 agent1.run() 时,self 指向 agent1 当前指向的对象;但 self 不是固定等于字符串形式的名字 agent1。

27.10 参数不等于属性

python
def __init__(self, model):
    self.model = model
text
model      → 本次调用接收到的参数
self.model → 保存在对象上的属性

只有 model = model 并不能把数据保存到对象上。

27.11 属性名与方法名冲突

不要这样写:

python
self.start = "stopped"

def start(self):
    ...

正确设计:

python
self.status = "stopped"

def start(self):
    self.status = "running"

数据用 status,行为用 start(),避免同名遮蔽。

27.12 拼写要前后一致

错误:

python
self.maodel = model
print(self.model)

正确:

python
self.model = model
print(self.model)

另一个典型错误:

text
massage → 按摩
message → 消息

27.13 方法定义必须有 self

错误:

python
# def show_info():
#     print(self.name)

正确:

python
def show_info(self):
    print(self.name)

27.14 Type Hint 的语法位置

正确:

python
def ask(question: str, model: str = "Qwen") -> str:
    return "回答"

记忆:

text
参数名: 参数类型 = 默认值
函数括号后 -> 返回类型

默认值不是写在类型前面;返回类型不是写在函数名后面。

27.15 OpenAI 是类,client 是对象

python
client = OpenAI()
text
OpenAI   → 类
OpenAI() → 创建对象
client   → 保存对象的变量

27.16 async 不等于自动并发

python
async def work():
    ...

只说明定义了异步函数。是否产生并发,还取决于:

  • 内部是否真正使用可异步等待的 I/O;
  • 是否在适当位置 await;
  • 是否把多个任务共同安排起来;
  • 是否存在事件循环。

27.17 顺序 await 不等于 gather 并发

顺序:

python
a = await task_a()
b = await task_b()
c = await task_c()

这要求完成 A 后才启动 B,完成 B 后才启动 C。

共同安排:

python
results = await asyncio.gather(
    task_a(),
    task_b(),
    task_c()
)

不要把“任务太快所以没来得及并发”当成顺序 await 的原因;真正原因是代码写明了依次启动和等待。

27.18 requests 是同步阻塞调用

python
async def get_data():
    response = requests.get(url)

函数外面写了 async def,不会自动把 requests.get() 变成异步请求。

27.19 404 与 401

text
404 → 路径或资源未找到,优先检查 URL、路由、资源 ID
401 → 身份认证失败,优先检查 API Key、认证头、密钥是否过期

不要把所有 HTTP 错误都归结为“网络不好”。

27.20 os.getenv() 不直接读取 .env

python
load_dotenv()
api_key = os.getenv("OPENAI_API_KEY")

先加载,再读取。或者由操作系统/服务器提前注入环境变量。

27.21 None 不等于空字符串

python
None  # 没有值
""    # 长度为 0 的字符串
python
if result is None:
    print("没有结果")

if result == "":
    print("结果是空字符串")

两个判断表达的是不同情况。

27.22 .venv 不是模块,也不装项目代码

text
.venv/
→ 虚拟环境目录
→ 保存解释器相关文件与已安装依赖

main.py / app/
→ 项目代码,仍在项目目录中

项目使用 .venv,不是把项目代码“导入 .venv”。

27.23 __init__.py 不是模块清单

它是包中的特殊 Python 文件,可以为空,也可以执行包初始化或暴露名称;不要把它简单理解成“列出该包所有模块的目录文件”。


28. 最少必要知识速查表

28.1 基础语法

python
name = "Qwen"        # str
count = 10            # int
temperature = 0.7    # float
enabled = True        # bool
result = None         # 没有值

28.2 list / dict

python
models = ["GPT", "Qwen"]
models.append("DeepSeek")

message = {
    "role": "user",
    "content": "你好"
}

print(models[0])
print(message["content"])

28.3 if / for

python
for model in models:
    if model == "Qwen":
        print("找到 Qwen")

28.4 函数

python
def ask(
    question: str,
    model: str = "Qwen"
) -> str:
    return f"[{model}] {question}"

28.5 文件

python
with open("prompt.txt", "r", encoding="utf-8") as file:
    prompt = file.read()

28.6 JSON

python
data = json.loads(text)
text = json.dumps(data, ensure_ascii=False)

28.7 异常

python
try:
    result = do_something()
except Exception as error:
    print("失败:", error)

28.8 环境变量

python
load_dotenv()
api_key = os.getenv("OPENAI_API_KEY")

28.9 类与对象

python
class Agent:
    def __init__(self, model: str) -> None:
        self.model = model

    def run(self, question: str) -> str:
        return question


agent = Agent("Qwen")
answer = agent.run("什么是 Agent?")

28.10 异步

python
async def main() -> None:
    results = await asyncio.gather(
        task_a(),
        task_b()
    )


asyncio.run(main())

28.11 项目环境

bash
python -m venv .venv
python -m pip install -r requirements.txt
python main.py

29. 当前能力验收清单

29.1 已掌握

  • 变量与赋值
  • str / int / float / bool / None
  • list / dict / list + dict
  • if / elif / else / and / or / not
  • for / range / enumerate
  • 函数定义与调用
  • 参数、关键字参数、默认参数
  • print 与 return 的区别
  • import 与第三方库
  • pip 与 venv
  • 文件读取、写入、追加、UTF-8
  • JSON 与 Python 数据转换
  • try / except
  • 环境变量、.env、load_dotenv()、os.getenv()
  • HTTP、API、GET、POST、状态码
  • requests 同步调用
  • class / object / __init__ / self
  • 对象属性、方法、属性修改、对象状态
  • Type Hint 参数和返回值
  • list[str] / dict[str, str] / None
  • 同步、异步、并发、并行
  • async / await / Event Loop
  • asyncio.gather()
  • module、package、__init__.py
  • 项目目录拆分
  • .venv、requirements.txt、pip freeze
  • 从零重建项目运行环境

29.2 “100% 完成”的准确含义

当前学习进度:Python 最少必要知识 100% 完成(面向 AI Agent/大模型部署)

这意味着现在已经具备继续学习以下内容的 Python 基础:

  • 阅读 AI SDK 示例;
    • SDK 是 Software Development Kit 的缩写,中文通常叫:软件开发工具包。
  • 调整模型调用参数;
  • 组织简单 Agent 类;
  • 读取配置和环境变量;
  • 理解 HTTP API 调用;
  • 阅读异步服务代码;
  • 看懂常见 Python 项目结构;
  • 在新电脑或服务器上重建依赖环境。

仍然需要在真实项目中反复练习,尤其是:

  • 独立写语法时避免中文符号;
  • 独立排查异常;
  • 阅读第三方库文档;
  • 根据报错定位到文件和行号;
  • 把一个较大的任务拆成多个模块。

30. 下一阶段路线

下一阶段按以下顺序推进:

text
FastAPI
    ↓
Uvicorn
    ↓
HTTP 服务
    ↓
真实 LLM
    ↓
Linux
    ↓
Docker
    ↓
服务器部署

30.1 FastAPI

未来用于把 Python 功能组织成可通过网络访问的 HTTP API 服务。当前笔记只把它列为下一阶段方向,不展开正式教程。

30.2 Uvicorn

未来学习如何运行异步 Web 应用,并让服务监听网络端口。此处不展开配置和命令。

30.3 HTTP 服务

把已经掌握的请求、响应、状态码、JSON 与服务器端处理连接起来。

30.4 真实 LLM

把当前的模拟 call_model() 替换成真实大模型 SDK 或 HTTP API 调用,并处理密钥、超时、限流和错误。

30.5 Linux

学习服务器常用命令、文件路径、权限、进程、日志与环境变量。

30.6 Docker

把程序、Python 版本和依赖打包成可重复运行的容器环境。

30.7 服务器部署

把完整服务部署到远程服务器,并处理端口、域名、HTTPS、进程守护、日志和更新。

最终路线 Python 最少必要知识已经完成。下一步从 FastAPI 开始,进入“把 Python/Agent 变成可访问服务”的阶段。