完整学习档案:保留原有章节、代码、失败示例、排错过程和练习。代码反映记录时的环境,不代表每段都是最终版本,也不代表本次发布重新运行了全部示例。请在练习项目中使用自己的环境配置,勿填入生产密钥。
当前学习进度 Python 最少必要知识 100% 完成(面向 AI Agent / 大模型部署)
这里的“100%”不是说已经学完 Python 的全部内容,而是:为了继续学习 AI Agent、大模型 API、服务化与部署,当前阶段真正高频、最少且必要的 Python 基础已经学完。
本笔记边界 本笔记完整整理到 FastAPI 正式课程之前。FastAPI 只在“下一阶段路线”中作为未来方向出现,不展开路由、装饰器、请求模型、服务启动等教程。
1. 学习目标与知识地图
学习 Python 的目标不是一开始成为“Python 语言专家”,而是能够:
- 看懂 AI SDK、Agent 项目和部署代码;
- 修改模型、参数、Prompt、API 地址等配置;
- 使用函数和类组织程序;
- 处理 list、dict、JSON、文件和环境变量;
- 调用 HTTP API,并理解常见错误;
- 看懂
async def、await、并发调用; - 看懂正式 Python 项目的目录结构;
- 使用
.venv和requirements.txt重建项目环境; - 为下一阶段的 FastAPI、Linux、Docker 和服务器部署打好基础。
知识主线:
变量与数据类型
↓
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 变量是什么
变量可以理解为:给数据起一个名字,方便后面的代码引用和修改这个数据。
model = "Qwen"
question = "什么是 AI Agent?"
temperature = 0.7= 在 Python 里主要表示赋值,不是数学中的相等判断。
model = "Qwen"
↓
把右边的字符串 "Qwen" 保存到左边的变量 model变量可以重新赋值:
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 |
是否流式输出、功能开关 |
model = "Qwen" # str
max_tokens = 4096 # int
temperature = 0.7 # float
stream = True # boolPython 的布尔值必须写成:
True
False不能写成 JSON/JavaScript 风格的:
true
false2.3 字符串和数字不能混淆
print(10 + 20) # 30
print("10" + "20") # 1020- 数字的
+是数学加法; - 字符串的
+是文本拼接。
age = 20
next_year = age + 1 # 21如果写成:
age = "20"
# age + 1 会报错,因为 str 不能直接和 int 相加2.4 None 是什么
None 表示:当前没有有效值、没有结果或结果缺失。
result = None它不是字符串:
None # 没有值
"None" # 内容为 None 四个字符的字符串
"" # 空字符串,仍然是 str判断是否为 None,推荐:
if result is None:
print("当前没有结果")牢记
None不等于空字符串""。None表示没有值;""表示有一个字符串,只是它的长度为 0。
3. list 列表
3.1 list 是什么
list 用来保存一组有顺序的数据,最明显的语法特征是方括号 []。
models = ["GPT", "Qwen", "DeepSeek"]列表中的每一项叫元素。
3.2 索引从 0 开始
print(models[0]) # GPT
print(models[1]) # Qwen
print(models[2]) # DeepSeek索引: 0 1 2
元素: "GPT" "Qwen" "DeepSeek"3.3 常用操作
models = ["GPT", "Qwen"]
models.append("DeepSeek")
print(models)
# ["GPT", "Qwen", "DeepSeek"]
print(len(models))
# 3append():在列表末尾添加元素;len():获得列表的元素数量。
3.4 AI 对话中的 list
多轮消息天然是一组有顺序的数据,因此通常用 list:
messages = [
"你好",
"什么是 RAG?",
"请继续解释"
]但只用字符串无法记录“谁说了什么”,因此真实 API 中经常使用 list + dict。
4. dict 字典与 list + dict 组合
4.1 dict 是什么
dict 用来保存带标签的数据,使用大括号 {},每一项是 key: value。
model_info = {
"model": "Qwen",
"temperature": 0.7,
"stream": True
}其中:
"model" → key
"Qwen" → value4.2 通过 key 读取和修改
print(model_info["model"]) # Qwen
model_info["model"] = "GPT"
print(model_info["model"]) # GPTlist 和 dict 的核心区别:
list → 通过位置索引找数据:models[0]
dict → 通过 key 找数据:model_info["model"]4.3 list + dict 表示多轮对话
messages = [
{
"role": "system",
"content": "你是一名 AI 老师"
},
{
"role": "user",
"content": "什么是 Agent?"
},
{
"role": "assistant",
"content": "Agent 是一种能够围绕目标执行任务的 AI 系统"
}
]结构:
messages(list)
│
├── 第 1 个元素(dict)
│ ├── role
│ └── content
│
├── 第 2 个元素(dict)
│ ├── role
│ └── content
│
└── 第 3 个元素(dict)
├── role
└── content读取第二条消息内容:
print(messages[1]["content"])
# 什么是 Agent?先用 [1] 从 list 中找到第二个元素,再用 ["content"] 从这个 dict 中取值。
5. 条件判断 if
5.1 基本结构
model = "Qwen"
if model == "Qwen":
print("使用 Qwen")
elif model == "GPT":
print("使用 GPT")
else:
print("未知模型")if:如果条件为True,执行其代码块;elif:前面的条件不成立时,继续判断另一个条件;else:前面的条件都不成立时执行。
5.2 = 与 ==
model = "Qwen" # 赋值
model == "Qwen" # 比较是否相等,结果为 True 或 False5.3 比较运算
| 写法 | 含义 |
|---|---|
== |
等于 |
!= |
不等于 |
> |
大于 |
< |
小于 |
>= |
大于等于 |
<= |
小于等于 |
5.4 and、or、not
age = 20
has_ticket = True
if age >= 18 and has_ticket:
print("可以进入")and → 两边都为 True,结果才为 True
or → 至少一边为 True,结果就是 True
not → 对布尔结果取反is_logged_in = False
if not is_logged_in:
print("请先登录")6. for 循环
6.1 遍历 list
遍历就是:把一组数据中的元素一个一个取出来处理。
models = ["GPT", "Qwen", "DeepSeek"]
for model in models:
print(model)model 是当前循环临时使用的变量名,类型取决于 models 中的元素类型。这里每个元素都是字符串,所以 model 是 str。
6.2 遍历 list 中的 dict
messages = [
{"role": "user", "content": "你好"},
{"role": "assistant", "content": "你好!"}
]
for message in messages:
print(message["role"], message["content"])这里每次取出的 message 是一个 dict。
6.3 for + if
tools = [
{"name": "search", "enabled": True},
{"name": "weather", "enabled": False},
{"name": "calculator", "enabled": True}
]
for tool in tools:
if tool["enabled"]:
print(tool["name"])输出:
search
calculator6.4 range()
for i in range(5):
print(i)输出 0、1、2、3、4。
for i in range(2, 6):
print(i)输出 2、3、4、5。
range(开始, 结束)包含开始值,不包含结束值,也就是“左闭右开”。
6.5 enumerate()
如果遍历时还需要索引:
models = ["GPT", "Qwen", "DeepSeek"]
for index, model in enumerate(models):
print(index, model)输出:
0 GPT
1 Qwen
2 DeepSeek7. 函数 function
7.1 定义与调用
函数用于封装一段可以重复使用的功能。
def start_agent():
print("Agent 启动")
print("正在处理任务")
print("任务完成")
start_agent()def start_agent()::定义函数;start_agent():调用函数;- 只定义不调用,函数体不会自动执行。
7.2 参数 parameter 与实参 argument
def ask(question):
print("收到问题:", question)
ask("什么是 Agent?")- 定义时的
question是参数; - 调用时传入的
"什么是 Agent?"是实际数据,也常叫实参。
参数相当于函数的数据入口。
7.3 位置参数与关键字参数
def call_model(model, temperature):
print(model)
print(temperature)位置参数按顺序对应:
call_model("Qwen", 0.7)关键字参数直接写参数名,更清晰:
call_model(
model="Qwen",
temperature=0.7
)7.4 默认参数
def call_model(question, model="Qwen", temperature=0.7):
print(question, model, temperature)调用时不传默认参数:
call_model("什么是 RAG?")这次使用:
model = "Qwen"
temperature = 0.7也可以覆盖默认值:
call_model(
question="什么是 Agent?",
model="GPT",
temperature=0.2
)默认参数顺序 没有默认值的参数必须放在有默认值的参数前面。
正确:
def ask(question, model="Qwen"):
pass错误:
# def ask(model="Qwen", question):
# pass7.5 return 返回值
def add(a, b):
return a + b
result = add(10, 20)
print(result) # 30print() 与 return 的区别:
print → 把内容显示给人看
return → 把结果交回给调用方,让程序继续使用如果函数没有明确 return:
def show_answer():
print("这是回答")
result = show_answer()
print(result) # Nonereturn 执行后,本次函数通常立即结束:
def test():
print("开始")
return "完成"
print("这一行不会执行")7.6 返回不同类型
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": "你好"} # dict8. import、第三方库与 pip
8.1 import 是什么
import 表示把其他模块中的功能引入当前代码。
import json
import os也可以只导入某个功能:
from dotenv import load_dotenv
from openai import OpenAI8.2 标准库与第三方库
- Python 标准库:通常随 Python 一起提供,例如
json、os、asyncio; - 第三方库:需要另外安装,例如
requests、python-dotenv、openai。
8.3 pip install 与 import 的区别
pip install requests
→ 把第三方库安装到当前 Python 环境
import requests
→ 在当前代码里使用已经安装好的库安装不等于导入,导入也不能代替安装。
推荐在已激活的虚拟环境中执行:
python -m pip install requests使用 python -m pip 的好处是更明确地让“当前这个 Python”运行对应的 pip。
9. 文件操作与 encoding
9.1 读取文件
with open("prompt.txt", "r", encoding="utf-8") as file:
text = file.read()
print(text)逐项解释:
"prompt.txt" → 文件路径
"r" → read,读取模式
encoding="utf-8" → 使用 UTF-8 文字编码
as file → 把打开后的文件对象临时命名为 file
file.read() → 读取文件内容
text → 保存读到的字符串with 的重要价值是:离开代码块后,Python 会帮助关闭文件,减少忘记关闭文件导致的资源占用。
9.2 写入文件
answer = "这是 AI 回答"
with open("answer.txt", "w", encoding="utf-8") as file:
file.write(answer)"w" 是写入模式,通常会覆盖原内容。
9.3 追加文件
with open("log.txt", "a", encoding="utf-8") as file:
file.write("一条新日志\n")r → read,读取
w → write,写入并通常覆盖
a → append,在末尾追加9.4 encoding 的常见错误
正确:
encoding="utf-8"常见错误:
# encode="utf-8" # 参数名错误
# encoding=" utf-8 " # 不应随意加入空格10. JSON 数据
10.1 JSON 是什么
JSON 是程序之间交换结构化数据时非常常见的文本格式。
Python dict:
data = {
"model": "Qwen",
"stream": True,
"result": None
}JSON:
{
"model": "Qwen",
"stream": true,
"result": null
}关键对应关系:
| Python | JSON |
|---|---|
True |
true |
False |
false |
None |
null |
10.2 JSON 字符串转 Python 数据
import json
text = '{"model": "Qwen", "temperature": 0.7}'
data = json.loads(text)
print(type(data)) # <class 'dict'>
print(data["model"]) # QwenJSON 字符串
↓ json.loads()
Python dict / list 等数据10.3 Python 数据转 JSON 字符串
import json
data = {
"model": "Qwen",
"answer": "你好"
}
text = json.dumps(data, ensure_ascii=False)
print(text)ensure_ascii=False 可以让中文直接显示,而不是显示为 Unicode 转义形式。
Python 数据
↓ json.dumps()
JSON 字符串10.4 load/load 与 loads/dumps
json.loads() → 从字符串读取 JSON
json.dumps() → 转成 JSON 字符串
json.load() → 从文件对象读取 JSON
json.dump() → 把 Python 数据写入 JSON 文件读取 JSON 文件:
with open("config.json", "r", encoding="utf-8") as file:
data = json.load(file)11. try / except 异常处理
11.1 为什么需要异常处理
程序运行时可能出现:
- 文件不存在;
- JSON 格式错误;
- 网络断开;
- API Key 无效;
- 服务器错误;
- 数据类型不符合预期。
使用 try / except 可以捕获错误并给出可理解的处理方式。
try:
number = 10 / 0
except Exception as error:
print("发生错误:", error)11.2 常用结构
try:
# 尝试执行可能出错的代码
result = do_something()
except Exception as error:
# 出错后执行
print("执行失败:", error)
else:
# try 没有出错时执行
print("执行成功")
finally:
# 无论成功还是失败,最后都会执行
print("本次操作结束")当前阶段最需要掌握:
try:
...
except Exception as error:
...11.3 JSON 解析示例
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 写死在代码中
不推荐:
api_key = "sk-真实密钥"风险包括:
- 上传 GitHub 后泄露;
- 分享代码时被他人看到;
- 不同电脑或服务器需要反复修改代码;
- 开发、测试、生产环境难以分离。
12.2 环境变量
import os
api_key = os.getenv("OPENAI_API_KEY")os.getenv() 的作用是:从当前进程已经拥有的环境变量中查找指定名称。
如果不存在,默认返回 None:
if api_key is None:
raise ValueError("缺少 OPENAI_API_KEY")也可以提供默认值:
model = os.getenv("MODEL_NAME", "Qwen")12.3 .env 文件
示例 .env:
OPENAI_API_KEY=你的密钥
MODEL_NAME=QwenPython 中常用 python-dotenv 加载:
import os
from dotenv import load_dotenv
load_dotenv()
api_key = os.getenv("OPENAI_API_KEY")
model = os.getenv("MODEL_NAME", "Qwen")执行顺序:
load_dotenv()
→ 读取 .env,并把值加载进当前进程环境
os.getenv("OPENAI_API_KEY")
→ 从当前进程环境中读取这个变量牢记
os.getenv()不会凭空直接打开并读取.env文件。需要先用load_dotenv()加载,或由操作系统、容器、服务器提前设置环境变量。
12.4 .gitignore
通常应该忽略:
.env
.venv/
__pycache__/
*.pyc.env 常含密钥;.venv 可以重建且体积大。
13. HTTP、API 与 requests
13.1 最小 HTTP 模型
客户端 Client
↓ 发送 HTTP Request
服务器 Server
↓ 处理请求
返回 HTTP Response
↓
客户端读取状态码、响应头和响应内容一个 HTTP 请求通常关心:
- 请求方法:GET、POST 等;
- URL:请求地址;
- Headers:请求头,例如认证信息;
- Query Parameters:URL 查询参数;
- Body:请求体,常使用 JSON;
- Status Code:响应状态码;
- Response Body:响应内容。
13.2 GET 与 POST 的入门理解
GET → 常用于获取资源或查询数据
POST → 常用于提交数据、创建任务或发起模型调用具体语义由 API 文档决定,不能只靠方法名猜测全部行为。
13.3 requests 示例
GET:
import requests
response = requests.get(
"https://example.com/api/models",
timeout=30
)
print(response.status_code)
print(response.text)POST JSON:
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 超时与异常
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 可以理解为创建某一类对象的模板。它可以把相关的数据和行为组织在一起。
class Agent:
pass这里:
class → 定义类
Agent → 类名
pass → 暂时不执行任何操作,占位14.2 object 是什么
对象是根据类创建出来的具体实例。
agent1 = Agent()
agent2 = Agent()Agent → 类、模板
Agent() → 调用这个类并创建对象
agent1 → 保存第一个对象的变量
agent2 → 保存第二个对象的变量agent1 和 agent2 通常是两个独立对象。
14.3 函数与类的区别
函数 function
→ 主要封装一个行为或处理过程
类 class
→ 把一类对象的数据和行为组织在一起
→ 可以创建多个各自拥有独立状态的对象AI Agent 很适合使用类,因为一个 Agent 经常同时拥有:
数据:name、model、status、memory、tools、temperature
行为:start()、run()、stop()、search()、save_memory()14.4 OpenAI 是类,client 是对象
from openai import OpenAI
client = OpenAI()正确理解:
OpenAI → 类
OpenAI() → 调用类,创建一个对象
client → 保存这个对象的变量不要把 OpenAI 说成对象;这里真正创建出的对象由 client 指向。
15. init、self、属性与方法
15.1 __init__ 的作用
class Agent:
def __init__(self, name, model):
self.name = name
self.model = model当前阶段可以理解为:__init__ 是对象创建时自动执行的初始化方法,用来设置对象的初始属性。
agent = Agent("学习助手", "Qwen")大致过程:
调用 Agent 类
↓
创建一个新的 Agent 对象
↓
自动执行 __init__
↓
name 接收 "学习助手"
model 接收 "Qwen"
↓
把它们保存为这个对象的属性严格地说,对象的创建还涉及 __new__,但在当前“最少必要知识”阶段,把 __init__ 理解为初始化对象即可。
15.2 self 是什么
self 表示:当前正在被操作的这个对象本身。
它不是对象在外部的变量名。
agent1 = Agent("搜索助手", "Qwen")
agent2 = Agent("写作助手", "GPT")- 执行
agent1的方法时,self指向agent1所指的对象; - 执行
agent2的方法时,self指向agent2所指的对象。
self ≠ agent1 这个变量名本身
self = 当前正在操作的对象15.3 参数与属性
self.model = model拆开理解:
右边 model
→ __init__ 接收到的参数,主要在本次方法调用中使用
左边 self.model
→ 当前对象自己的 model 属性,会保存在对象上整行意思:
把传进来的
model参数保存到当前对象自己的model属性中。
参数与属性可以使用不同名字:
class Agent:
def __init__(self, selected_model):
self.model = selected_model15.4 对象属性
class Agent:
def __init__(self, name, model):
self.name = name
self.model = model
self.status = "stopped"创建后:
agent = Agent("学习助手", "Qwen")
print(agent.name) # 学习助手
print(agent.model) # Qwen
print(agent.status) # stoppedagent.name、agent.model、agent.status 都是对象属性。
15.5 对象方法
定义在类里面、用于操作对象的函数通常叫方法。
class Agent:
def __init__(self, name):
self.name = name
def run(self, question):
print(self.name, "正在处理:", question)调用:
agent = Agent("学习助手")
agent.run("什么是 RAG?")定义方法时需要写 self,但正常调用时不用手动传入:
agent.run("问题")Python 会把 agent 当前指向的对象自动绑定给 self。
16. 属性修改、对象状态与方法封装
16.1 直接修改属性
agent = Agent("学习助手", "Qwen")
print(agent.model) # Qwen
agent.model = "GPT"
print(agent.model) # GPT对象属性既可以读取,也可以修改。
16.2 通过方法修改属性
class Agent:
def __init__(self, model):
self.model = model
def change_model(self, new_model):
self.model = new_modelagent = Agent("Qwen")
agent.change_model("GPT")
print(agent.model) # GPT为什么不总是直接修改属性?因为方法中可以统一加入:
- 参数检查;
- 权限检查;
- 日志记录;
- 清理缓存;
- 更新多个相关状态;
- 重新建立连接。
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 = value16.3 对象状态
对象状态就是对象在某个时刻保存的一组属性值。
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)agent = Agent("学习助手", "Qwen")
agent.start()
agent.show_info()输出:
名称: 学习助手
模型: Qwen
状态: running这里 start() 把对象状态从 stopped 改成了 running。
16.4 不同对象的状态互相独立
agent1 = Agent("搜索助手", "Qwen")
agent2 = Agent("写作助手", "GPT")
agent1.start()
print(agent1.status) # running
print(agent2.status) # stopped调用 agent1.start() 不会自动修改 agent2。
16.5 属性名与方法名不要冲突
错误设计:
class Agent:
def __init__(self):
self.start = "stopped"
def start(self):
self.start = "running"start 同时被当成属性名和方法名。对象属性可能遮蔽同名方法,最终:
agent.start()可能相当于试图调用一个字符串,从而出现:
TypeError: 'str' object is not callable正确设计:
self.status = "stopped" # 数据状态
def start(self): # 行为
self.status = "running"17. Type Hint 类型提示
17.1 Type Hint 是什么
Type Hint 用来提示参数、变量和返回值预期是什么类型。
def greet(name: str) -> str:
return "你好," + namename: str → 参数 name 预期是字符串
-> str → 函数预期返回字符串Type Hint 的主要价值:
- 提高代码可读性;
- 让编辑器更好地补全和提示;
- 帮助静态检查工具发现问题;
- 让多人协作时接口更清晰;
- 很多 AI、Web 框架会读取类型信息。
Type Hint 通常不会像强类型语言那样,在普通 Python 运行时自动阻止所有错误类型。它主要是提示和约定,仍需要正确的运行时验证。
17.2 参数类型与返回值类型
def add(a: int, b: int) -> int:
return a + bdef call_model(question: str, temperature: float) -> str:
return "模型回答"语法位置:
参数名: 类型
函数括号后 -> 返回类型正确:
def ask(question: str) -> str:
return question17.3 list[str]
表示“列表中的元素预期都是字符串”。
def get_models() -> list[str]:
return ["GPT", "Qwen", "DeepSeek"]models: list[str] = ["GPT", "Qwen"]17.4 dict[str, str]
表示 dict 的 key 是字符串,value 也是字符串。
def get_message() -> dict[str, str]:
return {
"role": "user",
"content": "你好"
}message: dict[str, str] = {
"role": "user",
"content": "什么是 Agent?"
}如果 value 可能是多种类型,简单项目中可以按实际需要写更宽泛的提示;不要为了“看起来高级”而写与真实数据不符的类型。
17.5 None 返回类型
函数只做操作、不返回有效结果时,可以写:
def show_info(name: str) -> None:
print("名称:", name)-> None 表示调用者不应期待一个有效返回值。
17.6 默认参数与 Type Hint 组合
def call_model(
question: str,
model: str = "Qwen",
temperature: float = 0.7,
stream: bool = False
) -> str:
return "模型回答"拆解:
question: str
→ 必填字符串参数
model: str = "Qwen"
→ 字符串参数,默认值为 "Qwen"
temperature: float = 0.7
→ 浮点数参数,默认值为 0.7
stream: bool = False
→ 布尔参数,默认值为 False
-> str
→ 返回字符串调用:
answer = call_model("什么是 Agent?")或:
answer = call_model(
question="什么是 RAG?",
model="GPT",
temperature=0.2,
stream=False
)17.7 class 中的 Type Hint
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
同步代码通常按照顺序执行:前一个操作没有结束,当前执行流就继续等待。
执行任务 A
↓ A 完成
执行任务 B
↓ B 完成
执行任务 C如果三个任务分别等待 2 秒、3 秒、4 秒,而且完全顺序执行,总时间大约是:
2 + 3 + 4 = 9 秒18.2 异步 asynchronous
异步重点是:当当前任务需要等待某个可异步等待的 I/O 时,可以暂时让出执行权,让事件循环推进其他任务;结果就绪后再回来继续。
典型等待:
- 网络请求;
- 数据库响应;
- 文件或消息队列 I/O;
- 定时等待。
异步不等于“所有代码同时运行”,也不等于“自动开启多个 CPU 核心”。
18.3 并发 concurrency
并发表示多个任务在同一段时间内共同推进。它们不一定在同一时刻真的都在 CPU 上执行。
任务 A 运行 → 等待 I/O
↓
事件循环推进任务 B → 等待 I/O
↓
事件循环推进任务 C
↓
A 的结果就绪 → 继续 A18.4 并行 parallelism
并行表示同一时刻确实有多个执行单元在执行不同任务,例如多个 CPU 核心同时进行计算。
CPU 核心 1 → 计算任务 A
CPU 核心 2 → 计算任务 B并行的重点不是“一起开始”,而是同一时刻真正同时执行。
18.5 对比
| 概念 | 核心 |
|---|---|
| 同步 | 当前操作没完成,按当前流程等待 |
| 异步 | 等待可异步 I/O 时允许让出执行权 |
| 并发 | 多个任务在一段时间内交替或共同推进 |
| 并行 | 多个任务在同一时刻真正一起执行 |
19. async / await 与 Event Loop
19.1 async def
async def call_model(question: str) -> str:
...async def 定义的是异步函数,也叫协程函数。调用它通常会得到一个协程对象,不是立刻把整个函数同步执行完。
coroutine = call_model("什么是 Agent?")要在异步环境中等待结果:
result = await call_model("什么是 Agent?")19.2 await
result = await call_model("什么是 Agent?")当前阶段可以理解为:
当前任务要等待
call_model()的异步结果;在它等待期间,让出执行权,让 Event Loop 有机会推进其他已安排的任务;结果就绪后,当前任务从这里继续。
await 只能用于适合等待的 awaitable 对象,并且通常写在 async def 中。
19.3 Event Loop 事件循环
Event Loop 可以理解为异步任务的调度员:
检查哪些任务现在可以继续
↓
推进这些任务
↓
某任务遇到 await 并等待 I/O
↓
暂时推进其他可运行任务
↓
I/O 结果就绪
↓
恢复原任务事件循环不是凭空让同步阻塞代码变异步;它只能在任务真正把控制权交回时调度其他任务。
19.4 一个最小可运行示例
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
async def main() -> None:
a = await task("A", 2)
b = await task("B", 3)
c = await task("C", 4)这段代码的明确顺序是:
启动并等待 A 完成
↓
才开始 B,并等待 B 完成
↓
才开始 C,并等待 C 完成总时间大约 2 + 3 + 4 = 9 秒。
关键不是“任务太快,来不及并发”,而是:代码没有提前把 B、C 安排起来。
20.2 asyncio.gather()
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 秒。
A:2 秒 ─────┐
B:3 秒 ─────────┐
C:4 秒 ─────────────┐
↓
全部完成结果顺序通常与传给 gather() 的 awaitable 顺序对应:
results[0] # A 的结果
results[1] # B 的结果
results[2] # C 的结果20.3 错误处理提醒
默认情况下,其中一个任务抛出异常时,gather() 会把异常传播给等待它的调用方。实际项目要根据业务决定:
- 是否整体失败;
- 是否分别捕获每个任务的错误;
- 是否使用超时;
- 是否需要取消剩余任务。
当前阶段先掌握“共同安排 + 等待全部完成”的核心概念,不必过早复杂化。
21. 异步 I/O 与 requests 同步阻塞
21.1 async def 不会把内部代码自动变异步
下面的代码仍然存在同步阻塞问题:
import requests
async def get_data() -> str:
response = requests.get(
"https://example.com/data",
timeout=30
)
return response.text原因:
async def
→ 只说明这是异步函数
requests.get()
→ 本身仍是同步阻塞 HTTP 请求当 requests.get() 阻塞时,它不会自动通过 await 把控制权交回事件循环,可能阻塞当前线程上的整个 Event Loop。
21.2 真正支持异步的 I/O 客户端
要进行真正的异步 HTTP I/O,通常需要使用提供异步接口的库或 SDK,并对其异步方法使用 await。概念示例:
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 核心结论
async def ≠ 自动异步
async def ≠ 自动并发
await ≠ 把任意同步函数变成异步
顺序 await ≠ gather 并发安排
异步并发 ≠ 多核并行22. Python 项目目录结构
22.1 为什么不把所有代码放进 main.py
小练习可以只有一个文件;项目变大后,把全部代码塞进 main.py 会导致:
- 文件太长,定位错误困难;
- 职责混杂;
- 修改一处容易影响其他部分;
- 不利于测试、复用和多人协作;
- 后期维护成本越来越高。
正式项目通常按职责拆分。
22.2 一个适合入门 Agent 的结构
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可以这样理解:
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 可以导入其他模块:
from app.agent import Agent
def main() -> None:
agent = Agent("学习助手", "Qwen")
answer = agent.run("什么是 Agent?")
print(answer)
if __name__ == "__main__":
main()当前阶段只需知道:
if __name__ == "__main__":常用于表示“当这个文件被直接运行时,执行下面的入口代码”。
23. module、package 与 init.py
23.1 module 模块
一个 .py 文件通常可以称为一个 Python 模块。
model.py → model 模块
tools.py → tools 模块
memory.py → memory 模块从模块导入功能:
from app.model import call_model
from app.tools import search23.2 package 包
package 用来组织多个相关模块。入门时可以把包含多个 .py 模块的 app/ 理解为一个包:
app/
├── __init__.py
├── agent.py
├── model.py
├── tools.py
└── memory.py23.3 __init__.py
__init__.py 是经常放在 Python package 目录里的特殊 Python 文件,用于参与包的初始化和组织。
它:
- 可以是空文件;
- 可以在导入包时执行初始化代码;
- 可以选择性地暴露包内常用名称;
- 不是简单的“模块目录清单”。
示例:
# app/__init__.py
from .agent import Agent之后可能可以:
from app import Agent但当前阶段不必把所有内容都写进 __init__.py。看到它时知道“这里在组织 Python package”就足够。
现代 Python 在一些情况下支持没有
__init__.py的命名空间包,但对普通入门项目而言,显式保留__init__.py往往更清晰。
24. .venv、requirements.txt 与 pip freeze
24.1 为什么需要虚拟环境
不同项目可能需要不同版本的第三方库:
项目 A → openai 1.x
项目 B → 某个不同版本如果全部共用同一套全局环境,升级一个项目的依赖可能破坏另一个项目。虚拟环境为项目提供相对独立的 Python 解释器与第三方包安装位置。
24.2 创建虚拟环境
python -m venv .venv拆解:
python → 使用 Python
-m → 运行一个模块
venv → Python 自带的虚拟环境模块
.venv → 创建出的虚拟环境目录名称.venv 不是 module,而是一个目录,里面通常包含解释器相关文件、Scripts 和第三方包。
24.3 激活虚拟环境
Windows PowerShell:
.\.venv\Scripts\Activate.ps1Windows CMD:
.venv\Scripts\activate.batmacOS / Linux:
source .venv/bin/activate退出虚拟环境:
deactivate退出只是停止当前终端使用它,不会删除 .venv。
24.4 requirements.txt
requirements.txt 是依赖清单,用来告诉使用者项目需要安装哪些第三方依赖。
示例:
openai==1.99.0
python-dotenv==1.1.1
requests==2.32.5安装清单中的全部依赖:
python -m pip install -r requirements.txt24.5 pip freeze
查看当前环境中安装的包及其版本:
python -m pip freeze生成依赖快照的常见命令:
python -m pip freeze > requirements.txt含义:把当前环境中所有已安装包及精确版本写入 requirements.txt。
pip freeze会记录当前环境中的全部已安装包,可能包含项目没有直接使用的包。生成前应确认虚拟环境是这个项目专用且较干净,并检查最终文件内容。
24.6 .venv 和 requirements.txt 的关系
.venv/
→ 已经实际创建并安装好依赖的本地运行环境
requirements.txt
→ 用文字记录“需要安装哪些依赖及版本”的清单类比:
.venv
→ 已经装修完成的房子
requirements.txt
→ 装修材料清单别人不需要复制你整套 .venv,而是根据清单在自己的电脑上重建环境。
因此通常:
.venv/ → 不提交 Git,体积大、与系统相关、可以重建
requirements.txt → 提交 Git,供他人或服务器重建项目代码也不是“导入 .venv 中”。正确关系是:项目代码仍在项目目录,而当前项目使用 .venv 里的 Python 和第三方依赖。
25. 完整项目环境重建流程
这一节是从“拿到一个项目”到“成功运行”的完整清单。
25.1 Windows 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. 退出虚拟环境
deactivate25.2 macOS / Linux
# 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. 退出
deactivate25.3 环境重建的完整逻辑
获得项目代码
↓
进入项目根目录
↓
查看 README / requirements.txt / .env.example
↓
创建本机自己的 .venv
↓
激活 .venv
↓
安装 requirements.txt 中的依赖
↓
创建并填写 .env
↓
确认当前 python 和 pip 来自 .venv
↓
运行 main.py25.4 如何确认当前环境
python --version
python -m pip --version在 Windows 还可以:
Get-Command python如果虚拟环境已正确激活,路径通常会指向项目的 .venv。
25.5 第二天继续开发
不需要重新创建 .venv,通常只需要:
进入项目目录
↓
重新激活 .venv
↓
继续运行或开发只有 .venv 被删除、损坏、Python 版本变化或需要完全重建时,才重新创建。
26. 综合示例:把知识串成一个小型 Agent 项目
以下示例只整合 Python 基础,不涉及 FastAPI。
26.1 目录
my_agent/
├── .env
├── .gitignore
├── requirements.txt
├── main.py
└── app/
├── __init__.py
├── agent.py
└── model.py26.2 .env
MODEL_NAME=Qwen26.3 requirements.txt
python-dotenv==1.1.1版本号只是示例;实际项目应以本机已验证可用的版本为准。
26.4 app/model.py
async def call_model(
question: str,
model: str = "Qwen"
) -> str:
# 这里暂时不接真实模型,仅模拟返回结果
return f"[{model}] 模拟回答:{question}"26.5 app/agent.py
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 answer26.6 main.py
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 逐层拆解
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 中文冒号、括号、逗号与引号
错误:
if model == "Qwen":
print("你好")
“Qwen”
,正确:
if model == "Qwen":
print("你好")必须特别留意:
| 中文全角 | 英文半角 |
|---|---|
: |
: |
( ) |
( ) |
“ ” |
" " |
, |
, |
从 Word、微信、公众号复制代码时,最容易把英文引号自动替换为中文弯引号。
27.2 缩进
Python 使用缩进表示代码层级,推荐每层 4 个空格。
for tool in tools:
if tool["enabled"]:
print(tool["name"])结构:
for
└── if
└── print常见错误是 def、if、for、with 后面的代码没有缩进,或同一层混用不同缩进。
27.3 True / False 大小写
Python:
True
FalseJSON:
true
false不要在 Python 代码里写小写 true/false。
27.4 字符串必须加英文引号
错误:
# model = Qwen
# role = assistantPython 会把 Qwen、assistant 当成变量名。
正确:
model = "Qwen"
role = "assistant"27.5 参数变量不要误写成字符串
错误:
def ask(question):
print("收到问题:", "question")这里打印的是固定文本 question。
正确:
def ask(question):
print("收到问题:", question)27.6 dict key 通常要加引号
错误:
# tool[enabled]
# message[content]这会把 enabled、content 当成变量名。
正确:
tool["enabled"]
message["content"]27.7 dict 各项之间要有逗号
错误:
# user = {
# "name": "Tom"
# "age": 21
# }正确:
user = {
"name": "Tom",
"age": 21
}27.8 encoding 拼写
正确:
with open("result.txt", "w", encoding="utf-8") as file:
file.write("结果")不是 encode=,也不要写成带多余空格的 " utf-8 "。
27.9 self 不等于对象变量名
agent1 → 外部变量名,指向一个对象
self → 方法执行时的当前对象本身执行 agent1.run() 时,self 指向 agent1 当前指向的对象;但 self 不是固定等于字符串形式的名字 agent1。
27.10 参数不等于属性
def __init__(self, model):
self.model = modelmodel → 本次调用接收到的参数
self.model → 保存在对象上的属性只有 model = model 并不能把数据保存到对象上。
27.11 属性名与方法名冲突
不要这样写:
self.start = "stopped"
def start(self):
...正确设计:
self.status = "stopped"
def start(self):
self.status = "running"数据用 status,行为用 start(),避免同名遮蔽。
27.12 拼写要前后一致
错误:
self.maodel = model
print(self.model)正确:
self.model = model
print(self.model)另一个典型错误:
massage → 按摩
message → 消息27.13 方法定义必须有 self
错误:
# def show_info():
# print(self.name)正确:
def show_info(self):
print(self.name)27.14 Type Hint 的语法位置
正确:
def ask(question: str, model: str = "Qwen") -> str:
return "回答"记忆:
参数名: 参数类型 = 默认值
函数括号后 -> 返回类型默认值不是写在类型前面;返回类型不是写在函数名后面。
27.15 OpenAI 是类,client 是对象
client = OpenAI()OpenAI → 类
OpenAI() → 创建对象
client → 保存对象的变量27.16 async 不等于自动并发
async def work():
...只说明定义了异步函数。是否产生并发,还取决于:
- 内部是否真正使用可异步等待的 I/O;
- 是否在适当位置
await; - 是否把多个任务共同安排起来;
- 是否存在事件循环。
27.17 顺序 await 不等于 gather 并发
顺序:
a = await task_a()
b = await task_b()
c = await task_c()这要求完成 A 后才启动 B,完成 B 后才启动 C。
共同安排:
results = await asyncio.gather(
task_a(),
task_b(),
task_c()
)不要把“任务太快所以没来得及并发”当成顺序 await 的原因;真正原因是代码写明了依次启动和等待。
27.18 requests 是同步阻塞调用
async def get_data():
response = requests.get(url)函数外面写了 async def,不会自动把 requests.get() 变成异步请求。
27.19 404 与 401
404 → 路径或资源未找到,优先检查 URL、路由、资源 ID
401 → 身份认证失败,优先检查 API Key、认证头、密钥是否过期不要把所有 HTTP 错误都归结为“网络不好”。
27.20 os.getenv() 不直接读取 .env
load_dotenv()
api_key = os.getenv("OPENAI_API_KEY")先加载,再读取。或者由操作系统/服务器提前注入环境变量。
27.21 None 不等于空字符串
None # 没有值
"" # 长度为 0 的字符串if result is None:
print("没有结果")
if result == "":
print("结果是空字符串")两个判断表达的是不同情况。
27.22 .venv 不是模块,也不装项目代码
.venv/
→ 虚拟环境目录
→ 保存解释器相关文件与已安装依赖
main.py / app/
→ 项目代码,仍在项目目录中项目使用 .venv,不是把项目代码“导入 .venv”。
27.23 __init__.py 不是模块清单
它是包中的特殊 Python 文件,可以为空,也可以执行包初始化或暴露名称;不要把它简单理解成“列出该包所有模块的目录文件”。
28. 最少必要知识速查表
28.1 基础语法
name = "Qwen" # str
count = 10 # int
temperature = 0.7 # float
enabled = True # bool
result = None # 没有值28.2 list / dict
models = ["GPT", "Qwen"]
models.append("DeepSeek")
message = {
"role": "user",
"content": "你好"
}
print(models[0])
print(message["content"])28.3 if / for
for model in models:
if model == "Qwen":
print("找到 Qwen")28.4 函数
def ask(
question: str,
model: str = "Qwen"
) -> str:
return f"[{model}] {question}"28.5 文件
with open("prompt.txt", "r", encoding="utf-8") as file:
prompt = file.read()28.6 JSON
data = json.loads(text)
text = json.dumps(data, ensure_ascii=False)28.7 异常
try:
result = do_something()
except Exception as error:
print("失败:", error)28.8 环境变量
load_dotenv()
api_key = os.getenv("OPENAI_API_KEY")28.9 类与对象
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 异步
async def main() -> None:
results = await asyncio.gather(
task_a(),
task_b()
)
asyncio.run(main())28.11 项目环境
python -m venv .venv
python -m pip install -r requirements.txt
python main.py29. 当前能力验收清单
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. 下一阶段路线
下一阶段按以下顺序推进:
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 变成可访问服务”的阶段。