AI Agent到底是什么
用 Android 类比:
| Android 世界 | AI Agent 世界 | 说明 |
|---|---|---|
| App | Agent 应用 | 一个能自主完成任务的程序 |
| 用户点击按钮触发事件 | 用户发一句话(prompt) | 输入的来源 |
ViewModel 处理业务逻辑 |
LLM(大模型)做推理决策 | "大脑" |
| 调用 Retrofit 请求后端 API | Agent 调用 "工具"(Tool/Function) | 与外部世界交互 |
LiveData/Flow 回调更新 UI |
流式返回(streaming)逐字输出 | 异步数据流 |
| Room 数据库存本地数据 | 向量数据库 / 记忆存储 | 存储"记忆" |
一句话:AI Agent = LLM(大脑)+ Tools(手脚)+ Memory(记忆)+ 编排逻辑(Loop 循环决策)。
它和普通程序最大的区别:决策不是你写死的 if-else,而是模型根据上下文动态决定下一步做什么。
Python基础知识
AI开发
常用工具
- Homebrew : macOS上装各种软件,类似Android的应用市场
- pyenv: 管理多个python版本,切换用哪个,类似多个JDK版本切换
- venv: 给每个项目隔离依赖库,类似Android中每个Gradle项目独立的dependencies
- pip: 在venv里面装具体的库,类似Gradle中的implementation
- Ollama: 在本地跑大模型,提供API,相当于一个跑在你电脑上的模型服务器
关键:
- pyenv选Python版本
- 用该版本建venv隔离依赖
- pip在venv里装库
- 代码调用Ollama提供的本地模型
pyenv
安装: brew install pyenv
配置: 这里用的是zsh,把pyenv初始化写进~/.zshrc:
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshrc
echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zshrc
echo 'eval "$(pyenv init -)"' >> ~/.zshrc
生效: source ~/.zshrc
那句 eval "$(pyenv init -)" 是灵魂——它让 pyenv 接管 python 命令。漏了它,你切了版本却发现 python --version 没变化,就是这个原因。
安装Python
# 查看已安装python版本,初次为空
pyenv versions
# 安装一个版本
pyenv install 3.12.4
# 设为全局默认
pyenv global 3.12.4
安装完后可以通过python --version 验证版本。
版本切换的三个层级
pyenv global 3.12.4 # 全局默认
pyenv local 3.12.4 # 当前目录(项目级),生成.python-version文件,最常用
pyenv shell 3.12.4 # 仅当前中端口临时用
优先级: local(项目) > shell(终端) > global(全局)
pyenv local生成的.python-version文件会跟着项目走,cd进目录自动切换到对应版本,就像gradle-wrapper.properties锁定Gradle版本,建议提交Git。
创建项目 + 虚拟环境(venv)
虚拟环境(virtual environment) 就是解决办法:在项目目录里建一个 .venv/ 文件夹,里面放一份独立的 Python 解释器(其实是符号链接)和一份独立的 site-packages(第三方包的存放处)。"激活"虚拟环境的本质,就是把 .venv/bin 插到 PATH 最前面,让你敲的 python 命中项目里的那个,而不是系统那个。
一句话类比:.venv/ 就是这个项目专属的 Gradle 缓存 + 专属的 JDK。
- 创建项目目录
- 进入目录,锁定这个项目的python版本
pyenv local 3.12.4 # 生成.python-version文件 - 创建并激活虚拟环境
python -m venv venv # 创建虚拟环境(生成venv文件夹)
source venv/bin/activate # 激活
激活成功后,命令行提示符前面会出现(venv):
(venv) c@Cs-MacBook-Pro aitest1 %
判断有没有激活,就看有没有(venv),每次开始工作都要先激活,用完再deactivate退出。
venv 一旦创建,就绑定了创建它时 pyenv 选定的那个 Python 版本。想换 Python 版本,要先 deactivate、pyenv local 改版本、删掉旧 venv、重新 python -m venv venv。
Ollama部署本地模型
Ollama是一个让你在本地电脑上一个命令行就能跑开源大模型的工具。 它的关键特征是: 提供一个OpenAI兼容的本地API(地址http://localhost:11434/v1)
这意味着: 你用标准的openai Python库写代码,只要把base_url指向本地Ollama,就能调用本地模型。
将来要切到真正的云端OpenAI/其他厂商,改一个URL即可,代码几乎不用动。
安装: brew install ollama
启动: ollama serve
看到它监听127.0.0.1:11434就说明服务起来了,保持这个窗口开着。
拉取模型
新开一个终端窗口,拉两个模型:
# 对话模型:qwen2.5(7B,中文能力好,约 4-5GB)
ollama pull qwen2.5
# 向量模型:nomic-embed-text(做第 03 章 RAG 用,很小)
ollama pull nomic-embed-text
命令行先聊两句,确认模型能用:
ollama run qwen2.5
查看已装模型:
ollama list
回到刚才激活了venv那个终端的项目目录窗口,安装需要用到的库:
pip install openai python-dotenv chromadb fastapi uvicorn
记录当前项目的依赖清单:
pip freeze > requirements.txt
requirements.txt要提交Git,别人执行pip install -r requirements.txt就能一键复现同样的依赖。
相关知识
FastAPI
FastAPI是2018年出现的现代Python Web框架,专注于快速构建API。 核心特点是:
-
原生异步: 基于ASGI(Asynchronous Server Gateway Interface)标准,路由函数可以写async def,天然适合调用 大模型API这种等待网络I/O的场景,等待期间可以处理其他请求。
-
数据驱动: 用Python类型注解 + Pydantic(一个"数据校验"库,用 Python 类来描述"数据应该长什么样",然后自动帮你检查和转换数据。) 定义请求/响应结构,框架自动完成参数解析、类型转换、数据校验。
-
轻量: FastAPI 只管路由+校验+文档,数据库、后台任务等都自己挑库组装,自由度高。
uvicorn
uvicorn是运行FastAPI的ASGI服务器。
- FastAPI只定义请求来了怎么处理,不会监听端口,uvicorn负责监听端口、解析HTTP、把请求递给FastAPI。
- 基于uvloop(Cython实现的高性能事件循环),是性能最好的Python异步服务器之一
- 开发时uvicorn main:app --reload,生成时 --workers 4多进程部署
整体流程: 客户端 -> uvicorn(网络层) -> FastAPI(业务层) -> 你的代码
写配置文件(把连哪个模型抽出来)
即使使用本地Ollama,也要用.env管理配置 -- 这样将来切云端只改这一个文件,代码不动。
新建.env(你的真实配置,不提交Git):
# 指向本地 Ollama 的 OpenAI 兼容接口
LLM_BASE_URL=http://localhost:11434/v1
# Ollama 不校验 key,随便填一个非空值即可
LLM_API_KEY=ollama
# 对话模型
LLM_MODEL=qwen2.5
# 向量模型(后面用)
EMBED_MODEL=nomic-embed-text
新建 .env.example(模板,只有变量名,提交 Git):
LLM_BASE_URL=
LLM_API_KEY=
LLM_MODEL=
EMBED_MODEL=
新建 .gitignore:
venv/
.env
__pycache__/
*.pyc
.chroma/
注意 .env 和 venv/ 都被 ignore 掉了:密钥不进 Git、笨重的虚拟环境不进 Git。.python-version、.env.example、requirements.txt 则要提交,它们让环境可复现。
import os
from dotenv import load_dotenv
from openai import OpenAI
load_dotenv()
client = OpenAI(
base_url = os.environ["LLM_BASE_URL"],
api_key = os.environ["LLM_API_KEY"],
)
resp = client.chat.completions.create(
model=os.environ["LLM_MODEL"],
messages=[
{"role": "user", "content": "用一句话确认你在正常工作。"},
],
)
print("模型恢复: ", resp.choices[0].message.content)
print("环境成功")
术语对照速查表(Android → 服务端/AI)
| 你熟悉的 | 对应的 | 一句话解释 |
|---|---|---|
| Gradle | pip / poetry / uv | 包和依赖管理工具 |
build.gradle |
requirements.txt / pyproject.toml |
依赖声明文件 |
| Kotlin 协程 | Python asyncio | 异步并发方案 |
| Retrofit | httpx / requests | HTTP 客户端 |
| OkHttp 拦截器 | 中间件 middleware | 请求拦截处理 |
| Room | SQLAlchemy | ORM 数据库框架 |
| SharedPreferences | Redis / 配置文件 | 简单键值存储 |
| APK | Docker 镜像 | 可分发的运行单元 |
| 应用市场分发 | K8s 部署编排 | 分发+运行管理 |
| Firebase Crashlytics | Sentry / Prometheus | 崩溃/性能监控 |
| ProGuard/R8 | —(Python 一般不混淆) | — |
| ANR/卡顿优化 | QPS/延迟优化 | 性能指标 |
安装Python
macOS一般自带Python,但不要用系统自带的,推荐用版本管理工具。
# 推荐用 uv(新一代工具,又快又省心,相当于更好用的 Gradle)
# 安装 uv
curl -LsSf https://astral.sh/uv/install.sh | sh
# 用 uv 安装并管理 Python 版本
uv python install 3.12
uv
uv类似Android开发中的Gradle + SDK Manager二合一。即管Python版本,又管依赖。
uv是一个用Rust编写的Python包管理和项目管理工具,由Astral(也是Ruff的开发团队)出品。它的目标是替代pip、pip-tools、pipenv、poetry、pyenv等一整套工具,用一个统一的命令行工具搞定。
核心特点:
-
快: 这是它最大的卖点。依赖解析和安装比pip快10-100倍,因为用Rust实现且有全局缓存。
-
一体化: 包管理、虚拟环境、Python版本管理、项目依赖锁定都集成在一起。
- 兼容pip: 提供uv pip子命令,用法基本和pip一致,迁移成本低。
虚拟环境(相当于给每个项目独立的Gradle配置)
在 Android 里,每个项目的依赖是隔离的。Python 默认所有包装到全局,很容易冲突。虚拟环境就是给每个项目一个独立的依赖空间。
# 创建一个项目
mkdir my-ai-app && cd my-ai-app
# 用 uv 初始化项目(生成 pyproject.toml,相当于 build.gradle)
uv init
# 添加依赖(相当于在 build.gradle 里加 implementation)
uv add requests
# 运行脚本
uv run main.py
对照表:
| Android/Gradle | Python/uv |
|---|---|
build.gradle |
pyproject.toml |
implementation 'xxx' |
uv add xxx |
./gradlew build |
uv sync |
./gradlew run |
uv run xxx.py |
.gradle/ 缓存 |
.venv/ 虚拟环境目录 |
不用uv时的处理,在项目目录下执行安装:
python3 -m venv .venv #建一个“独立药箱”,避免污染系统Python
source .venv/bin/activate # 激活虚拟环境
pip install -r requirements.txt # 安装依赖
虚拟环境(venv): 给每个项目单独一份Python包目录。不同项目依赖的版本经常冲突,虚拟环境就是 给每个项目发一个独立药箱,互不干扰。看到命令行提示符前面多了(.venv)就说明进去了。
异步变成async/await
AI服务端要同时处理很多请求、要等LLM慢慢返回,全靠异步。
import asyncio
# async def 定义协程函数,相当于 Kotlin 的 suspend fun
async def fetch_data(id: int) -> str:
await asyncio.sleep(1) # await 相当于 Kotlin 的挂起点
return f"数据{id}"
# 并发执行多个(相当于 Kotlin 的 async {} + awaitAll)
async def main():
# 顺序执行(慢,3秒)
a = await fetch_data(1)
# 并发执行(快,1秒搞定三个)
results = await asyncio.gather(
fetch_data(1),
fetch_data(2),
fetch_data(3),
)
print(results)
asyncio.run(main()) # 启动事件循环,相当于 runBlocking
记住:调用一个 async def 函数,必须 await 它,否则它不会真正执行(返回的是个协程对象)。这点和 Kotlin suspend 类似——只能在协程环境里调用。
dataclass (对标Kotlin data class)
from dataclasses import dataclass
@dataclass
class Message:
role: str
content: str
msg = Message(role="user", content="你好")
print(msg) # 自动有好看的打印、相等比较,和 Kotlin data class 一样
AI Agent应用本质
AI Agent应用本质就是一个服务端:
手机App/网页请求过来,你的服务端调用LLM、查数据、返回结果。
FastAPI
Python服务端框架首选FastAPI -- 快、自带文档、原生支持异步和类型校验
uv add fastapi uvicorn
-
fastapi: 框架本身
-
uvicorn: 运行服务器(相当于Tomcat,负责真正跑起来监听端口)
新建main.py:
from fastapi import FastAPI
app = FastAPI()
@app.get("/") # 相当于 Ktor 的 get("/") { }
def read_root():
return {"message": "你好,服务端世界"}
@app.get("/users/{user_id}") # 路径参数,相当于 @GET("users/{id}")
def get_user(user_id: int):
return {"user_id": user_id, "name": "Ducc"}
启动:
uv run uvicorn main:app --reload
# --reload:改代码自动重启,相当于 Android 的 Apply Changes
打开浏览器:
- http://127.0.0.1:8000/ → 看到 JSON
- http://127.0.0.1:8000/docs → 自动生成的交互式接口文档(FastAPI 杀手锏,相当于自带一个 Postman)
@app.get("/") 这种 @开头 的叫装饰器(decorator),相当于 Java/Kotlin 的注解 + AOP。它把下面的函数"注册"成一个路由处理器。你在 Retrofit 用 @GET,在 FastAPI 用 @app.get,形似神也似。
请求与响应模型: Pydantic(对标数据类 + Gson + 参数校验)
真实接口要接收复杂JSON。 FastAPI用Pydantic定义数据模型 -- 它是加强版dataclass,自带校验和JSON互转。
from fastapi import FastAPI
from pydantic import BaseModel, Field
app = FastAPI()
# 定义请求体模型(相当于 Kotlin data class + Gson + 校验注解)
class ChatRequest(BaseModel):
message: str
user_id: int
temperature: float = Field(default=0.7, ge=0, le=2) # 带范围校验
# 定义响应模型
class ChatResponse(BaseModel):
reply: str
tokens_used: int
@app.post("/chat", response_model=ChatResponse)
def chat(req: ChatRequest): # FastAPI 自动把 JSON 解析成 ChatRequest
# req.message / req.user_id 直接用,且已校验过
return ChatResponse(reply=f"收到:{req.message}", tokens_used=10)
Pydantic 的强项:自动校验。如果 App 传来 temperature: 5,FastAPI 直接返回 422 错误并说明原因,你一行校验代码都不用写。这在 Android 里相当于 Gson 解析 + 手动 require() 校验,现在全自动。
记住:dataclass 用于内部数据,Pydantic BaseModel 用于接口收发数据。AI 开发中 Pydantic 无处不在。
异步接口
调LLM很慢(几秒),如果同步处理,一个请求会卡住整个服务,所以AI服务器接口几乎都写成async。
import httpx # 异步 HTTP 客户端,相当于 Retrofit/OkHttp
@app.post("/chat")
async def chat(req: ChatRequest):
async with httpx.AsyncClient() as client:
# await 期间,服务器可以去处理别的请求(不阻塞)
resp = await client.post("https://api.llm.com/v1/chat", json={...})
return resp.json()
数据库
SQLAlchemy是Python版的Room。
安装: uv add sqlalchemy
- 关系型(SQL):PostgreSQL / MySQL。结构化数据、要事务、要 join。默认选它。
- 向量数据库:Pinecone / Milvus / pgvector。存"文本的向量表示",做语义搜索(第三部分 RAG 会详讲)。这是 AI 应用的特色数据库。
缓存: Redis(对标SharedPreferences + 内存缓存,但在服务端)
Redis(Remote Dictionary Server)是一个高性能的键值对数据库,常用于缓存、会话管理等场景。
它支持多种数据结构(如字符串、哈希、列表等),并提供快速的内存操作。
Redis的核心特征:
- 高性能: 数据存储在内存中,读写速度极快
- 持久性: 支持RDB和AOF两种持久化方式
- 灵活性: 支持多种数据类型和丰富命令
- 简单易用: 提供直观的API,易于集成
Redis 是一个超快的内存键值数据库。用途:
- 缓存 LLM 结果(相同问题不重复花钱调模型)
- 存会话状态、限流计数器
- 做消息队列
安装: uv add redis
import redis
r = redis.Redis(host="localhost", port=6379)
# 存(带过期时间,相当于带 TTL 的缓存)
r.set("answer:你好", "你好呀", ex=3600) # 1小时后过期
# 取
cached = r.get("answer:你好")
if cached:
return cached # 命中缓存,省一次 LLM 调用($$$)
Redis像一个全服务器共享的、超快的、会自动过期的SharedPreferences。
认证和授权(对标登录token)
在Android里存token、每次请求都带上,服务端这边要验证token。
两种常见方式:
- API Key: 调用方带一个固定密钥(Authorization: Bearer sk-xxx)。简单,适合服务间调用。
- JWT:登录后发一个带签名的令牌,服务端验签就知道是谁,无需查库。适合用户登录场景。
项目架构
my-ai-app/
├── pyproject.toml # 依赖(build.gradle)
├── app/
│ ├── main.py # 入口,注册路由(Application)
│ ├── routers/ # 路由层(相当于 Controller/UI 层)
│ │ └── chat.py
│ ├── models/ # Pydantic 模型(data class)
│ │ └── schemas.py
│ ├── services/ # 业务逻辑(相当于 ViewModel/UseCase)
│ │ └── llm_service.py
│ ├── db/ # 数据库(相当于 Repository/Room)
│ │ └── database.py
│ └── core/ # 配置、认证(相当于 di/util)
│ └── config.py
分层思想和 Android 的 Clean Architecture 一模一样:UI(路由) → ViewModel(service) → Repository(db)。你的架构能力可以直接迁移。
Agent框架
-
LangChain: 生态大、组件多、也重且抽样层厚,需要现成RAG/工具链时用
-
LangGrap: 把Agent建模成状态图,适合复杂多步/多Agent流程,复杂编排时用,理念很好
LangGraph 的"状态图"思想值得了解——它像 Android 里用状态机管理复杂 UI 流程,把 Agent 的每一步建成节点,转移条件清晰可控,适合生产级复杂 Agent。
复杂任务可以拆给多个专职 Agent,像一个团队。
[主管 Agent (Orchestrator)]
/ | \
[检索 Agent] [编码 Agent] [审查 Agent]
常见模式:
- 线:Agent A 的输出给 Agent B(像责任链)。
- 主管调度:一个主 Agent 决定把子任务分给哪个专家 Agent。
- 辩论/投票:多个 Agent 独立解,再汇总,提高可靠性。
类比:像微服务架构,每个 Agent 职责单一,通过消息协作。初期别过度设计,单 Agent 能解决就别上多 Agent。
部署与上线
在Android里,上线 = 打APK -> 传应用市场 -> 用户下载到手机运行。代码运行在用户设备上。
服务端上线完全相反: 代码运行在你的服务器上,用户通过网络访问。
所以需要操心一堆Android时不用管的事: 服务器怎么来、怎么让它一致或者、崩了怎么办、流量大了怎么扩、怎么监控、怎么省钱。
上线全景图
本地代码
│ ① 容器化(Docker) —— 把代码+环境打包成"镜像"
▼
Docker 镜像
│ ② 推到镜像仓库(Registry)
▼
│ ③ 部署到服务器 / K8s 集群
▼
线上运行
├─ ④ 负载均衡 + 多实例(扛并发/QPS)
├─ ⑤ 自动扩缩容(流量大自动加机器)
├─ ⑥ 监控告警 + 日志(出问题能发现)
└─ ⑦ CI/CD(以后改代码自动重新走这套流程)
容器化: Docker(对标打APK,但打的是整个运行环境)
为什么需要Docker?
Android有个经典问题: 在我手机上好好的,在别的机型崩了。
服务端更严重,在我的电脑上跑的好好的,上服务器就报错(Python版本不同、缺依赖、环境变量没配...)
Docker的解决方案:
- 把你的代码 + Python运行时 + 所有依赖 + 配置,整个打包成一个镜像(Image).
- 这个镜像在任何装了Docker的机器上以容器(container)方式运行,环境100%一致,都能跑出一模一样的结果。
类比:
- Docker镜像 = APK: 一个自包含的、可分发的运行单元
- 镜像(Image):应用的「模板」,只读的打包文件。
-
容器(Container):镜像运行起来的实例,可以启动、停止、删除。
- 最早为了解决环境问题的解决思路是: 把软件运行所需的操作系统片段、依赖库、配置文件全部打包成一个独立的盒子(容器/镜像),这个盒子 在任何支持该技术的机器上都是开箱即用,这个最早的解决方案就是虚拟机(带环境安装的一种解决方案,它可以在一中操作系统里面运行另一种操作系统,)。
- 但是虚拟机的资源占用多、冗余步骤多,而且启动慢(启动操作系统需要多久、启动虚拟机就要多久)
- 由于虚拟机存在上面这些缺点,Linux发展出了另一种虚拟化技术: Linux容器(Linux Containers,缩写为LXC).
- Linux容器不是模拟一个完整的操作系统,而是对进程进行隔离。 由于容器是进程级别的,相比虚拟机有很多有事,例如启动快、资源占用少、体积小。
- Docker属于Linux容器的一种封装,提供简单易用的容器使用接口,它是目前最流行的容器解决方案。
- Docker将应用程序与该程序的依赖,打包在一个文件里面。运行这个文件,就会生成一个虚拟容器。程序在这个虚拟容器里运行, 就好像在真实的物理机上运行一样,有了Docker,就不用担心环境问题。
-
Dockerfile:一个文本文件,描述怎么构建镜像。
- Docker Hub:公共的镜像仓库,可以下载别人做好的镜像(如 MySQL、Redis、Nginx)。
- 区别: APK里只有你的代码,Docker镜像里连操作系统环境都打包了。
三个概念的关系
-
Dockerfile(菜谱) -- build -- 镜像(做好的预制菜) -- run -- 容器(端上桌的一份菜)
-
镜像是只读模板,容器是运行中的实例,一个镜像可以起N个容器
- 容器之间、容器和宿主机之间默认隔离(文件、网络、进程都隔离),宿主机 = 运行Docker的那台机器,也就是你的电脑或云服务器。
写一个Dockerfile(相当于build.gradle的打包配置)
在项目根目录建Dockerfile:
# 基础镜像:一个装好 Python 3.12 的最小 Linux 环境
FROM python:3.12-slim
# 容器内的工作目录
WORKDIR /app
# 先复制依赖声明并安装(利用缓存,依赖没变就不重装,加速构建)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 复制项目代码进镜像
COPY . .
# 声明服务监听的端口
EXPOSE 8000
# 容器启动时执行的命令(启动你的 FastAPI 服务)
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
构建和运行
# 构建镜像(相当于 ./gradlew assembleRelease 打 APK)
docker build -t my-ai-agent:v1 .
# 运行容器(相当于把 App 装到设备上跑)
docker run -p 8000:8000 -e OPENAI_API_KEY=sk-xxx my-ai-agent:v1
# │ └─ 注入密钥(环境变量,别打进镜像!)
# └─ 把容器的8000端口映射到本机8000
访问 http://localhost:8000/docs,服务就在容器里跑起来了。
docker-compose(本地一键起多个服务)
AI 应用通常不止一个服务(还有 Redis、数据库)。docker-compose.yml 一次拉起全套(本地开发/测试很方便):
services:
api:
build: .
ports: ["8000:8000"]
environment:
- OPENAI_API_KEY=${OPENAI_API_KEY}
depends_on: [redis, db]
redis:
image: redis:7
db:
image: postgres:16
environment:
- POSTGRES_PASSWORD=secret
启动:
docker compose up # 一键启动 api + redis + db
QPS(Queries Per Second,每秒查询数)
每秒钟你的服务能处理多少个请求,是衡量服务容量的核心指标。
类比: 一家餐厅每秒能接待几桌客人
- QPS 100 = 每秒能处理100个请求
- 如果实际来了QPS 200但你只扛得住100,多的请求就会排队、超时、甚至502崩溃。
并发(Concurrency)
同一时刻正在处理的请求数。和QPS相关但不同。
并发数 大约等于 QPS * 平均响应时间
举例:QPS=100,每个请求平均耗时 2 秒 → 同时有约 200 个请求在处理中。
这对 AI 服务特别重要:因为 LLM 响应慢(动辄 2~10 秒),响应时间长 → 同样 QPS 下并发数很高 → 很吃资源。这就是为什么第二部分强调接口要写 async(一台机器能同时"等"很多慢请求,不阻塞)。
延迟(Latency,响应时间)
一个请求从发出到收到响应的耗时。
关注分位数而不是平均值:
- P50: 中位数,一半请求比这快
- P99: 99%的请求比这快(即最慢的1%有多慢),生成最关注P99,因为它代表最差体验。
吞吐量(Throughput)
单位时间成功处理的总请求量,本质和QPS一个意思,强调总处理能力。
负载均衡与水平扩展(多开几个客服窗口)
两种扩展方式:
- 垂直扩展: 单机加CPU/内存,类似给一个人加班加钱
- 水平扩展: 多加几台机器,类似多雇几个人
负载均衡(Load Balancer)
多台机器后,请求该发给哪台服务器?
负载均衡在最前面,把流量均匀分给后面的多个实例
类似: 银行门口的叫号机,把客户分配到空闲的窗口
Kubernetes(K8s):容器编排(对标"应用市场 + 自动运维")
为什么需要 K8s?
有了 Docker 镜像和多实例需求,新问题来了:
- 谁来启动这几十个容器?
- 有容器崩了谁来自动重启?
- 流量涨了谁来自动加实例、跌了谁来减?
- 怎么滚动更新不中断服务?
手动管理几十上百个容器是噩梦。K8s 就是自动干这些的"容器运维总管"。
类比:
- 你告诉应用市场"我要发布这个 App",市场负责分发、更新、下架。
- 你告诉 K8s"我要 10 个这个服务的实例,一直保持这个数,崩了自动补",K8s 负责实现并维持这个状态。
核心思想:声明式。你只声明"我想要的最终状态",K8s 自动让现实达到并维持它。(有点像 Jetpack Compose 的声明式 UI——你声明 UI 长什么样,框架负责渲染和更新。)
CI/CD: 自动化流水线(对标打apk)
在Android上用过CI自动打包APK,服务端的CI/CD是: 代码一提交,自动测试->构建镜像-> 部署上线
GIL
GIL(Global Interpreter Lock,全局解释器锁) 是 CPython(就是官方那个 Python)里的一把大锁:同一时刻只允许一个线程执行 Python 字节码。
这句话的后果非常反直觉:在 Python 里开 4 个线程做纯计算,不会比 1 个线程快,甚至可能更慢(因为多了切换开销)。这和 Android 上开线程池加速计算的经验完全相反。
为什么会有它?简化了 CPython 内部内存管理(引用计数不用逐对象加锁),代价是牺牲了多核并行。注意 GIL 是 CPython 的实现细节,不是 Python 语言规范;3.13 起有一个实验性的"free-threaded"构建可以关掉它,但目前生产环境还不是默认。
Agent Harness
从 Harness 工程的视角看,可以把 LLM 抽象为核心组件 Model,把 Agent 边界内负责支撑模型运行及 模型与环境交互的代码、配置和服务统称为 Harness。
两个视角并非替代关系,而是不同抽象层次上对同一 Agent 实现的描述。 Harness 的核心是原公式中的“上下文管理 + 工具接口”,再加上三层保障机制: 约束(限定 Agent 能 做什么、不能做什么)、 验证(检查 Agent 做得对不对)和纠正(做错了怎么补救)。 用方程展开生产形态下的完整组成: - Agent = Model + Harness - Harness = 上下文管理 + 工具接口 + 约束 + 验证 + 纠正 - Agent ↔ Environment
以 Claude Code 为例,它的 Harness 中绝大部分代码都是约束、验证与纠正,而非上下文与工具——工具本 身(文件读写、命令执行、搜索)只是一小部分,而围绕这些工具构建的保障机制才是真正的核心。这些机制包括: - 流程状态管理:追踪 Agent 当前执行到哪一步 - 多层上下文压缩:当信息太多时自动精简 - 权限分类:控制哪些操作需要用户确认 熔断器(Circuit Breaker): - 当错误连续发生时自动“断电”停止重试——就像家里电路短路时保险丝会自动跳 闸,防止整个系统崩溃 - 错误恢复机制:捕获异常、回滚到上一稳定状态、重试或交还给人类
行业正在从“能做事”向“可靠地做事”转变, Harness 工程因此成为 Agent 系统的核心竞争力。