📖 Day 14 学习页:测试、优化与部署

Day 14:测试、优化与部署

🎯 今日目标:给项目装上"安全网"(pytest 测试套件,不花一分钱 API 费), 再把整个服务装进 Docker 容器——docker run 一条命令在任何机器上跑起来。

🛠 项目脚手架:project_day11_15/(开发都在这个目录里) | 📋 验收清单

⏱ 今日安排(约 2 小时)

时间内容方式
25min理论学习:Agent 项目的测试策略 + Docker 基础阅读
60min测试:跑通 tests/ 三个测试文件,全部变绿编码
35min部署:docker build + docker run操作

📖 第一步:Agent 项目怎么测(测试金字塔)

层级测什么要不要 Key/网络
单元测试memory 裁剪/隔离、tools 注册/安全路径——纯逻辑不要(tests/test_memory.py、test_tools.py)
API 集成测试路由 → Agent → 响应 全链路(monkeypatch 掉 LLM,返回固定回答)不要(tests/test_api.py)
真实冒烟测试打一次真实 API 验证配置要(手动跑一次即可,不进 CI)

核心技巧:monkeypatch 掉 LLM 调用——把 llm.chat 替换成返回固定响应的假函数, Agent 循环、记忆、路由全部真实跑,只有 LLM 是假的。测试快、稳、免费, 而且能模拟各种 LLM 行为(正常回答 / 要求调工具 / 抛异常)。

Docker 三个关键点(Dockerfile 已给好,要能逐行讲清)

FROM python:3.12-slim                 # 1. 瘦基础镜像
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app ./app                        # 2. 依赖先装、代码后拷——层缓存:
                                      #    改代码不触发重装依赖,重建快一个量级
EXPOSE 8000
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
                                      # 3. --host 0.0.0.0:容器内必须监听所有网卡,
                                      #    否则端口映射后外面访问不到(新手第一坑)

环境变量在部署时的正确姿势:docker run -e DEEPSEEK_API_KEY=sk-xxx ...—— Key 走环境变量进容器,永远不写进镜像(.dockerignore 已排除 .env)。

🛠 第二步:动手实操

  1. 跑测试:pip install pytest httpx → pytest tests/ -v。Day 12 没完成的部分现在是红的——把 TODO 补完让它们变绿, 这就是测试驱动。三个文件:test_memory(记忆/隔离)、test_tools(注册/安全路径, 含 ../../etc/passwd 必须被拒的用例)、test_api(monkeypatch LLM 的全链路)。
  2. 加一条你自己的测试(TODO 7.3):往 tests/ 里补一个你认为最可能出 bug 的场景 (比如:用户消息超长时记忆被正确裁剪)。
  3. 构建镜像:docker build -t dev-agent . → docker run --rm -e DEEPSEEK_API_KEY=你的key -p 8000:8000 dev-agent → 浏览器开 http://127.0.0.1:8000/static/index.html 聊天。 没有 Docker 环境就先跳过,读完 Dockerfile 能讲清每一行也算达标。
  4. 优化盘点(对照检查):max_tokens 已设?历史已裁剪?相同请求有缓存思路? token 统计有入口?——都在前几天的代码里,确认没被删掉。

✅ 第三步:验收(Day 14 部分)

  • pytest tests/ -v 全绿(无 Key 环境也能全绿)
  • docker run 后 /health 通、聊天可用(或能逐行讲清 Dockerfile)
  • .env 和 workspace/ 不在镜像里(docker run ... ls /app 自查)
  • 对照 交付清单 Day 14 部分打勾

⚠️ 避坑

  • ❌ 集成测试直接打真实 API → 慢、贵、结果不稳定;monkeypatch 是标准做法
  • ❌ Dockerfile 里 COPY . . 且没有 .dockerignore → .env 里的 Key 进镜像 = 泄露密钥
  • ❌ uvicorn 忘了 --host 0.0.0.0 → 容器外永远访问不通
  • ❌ 异步测试直接 def → 拿不到事件循环;用 pytest-asyncio 或像 test_api 一样用 TestClient 同步壳
  • ❌ 一次都不跑测试就继续开发 → 回归只能靠手点;pytest 要变成肌肉记忆

🔗 延伸资源