通过AI学习agent-Day2(附技术栈清单)
今天是第二天,以下是这两天的知识点与该方法的体验。
文章目录
- 一、虚拟环境:为什么不能直接用系统 Python
- 二、项目骨架:先分清代码应该放在哪里
- 三、.gitignore:保护不该提交的文件
- 四、Git 基础:commit 和 push 的区别
- 五、Python 类型注解
- 六、Pydantic 入门
- 七、Pydantic 的校验与报错
- 八、第一次 LLM API 调用
- 九、messages 结构:system、user、assistant
- 十、封装 call_llm 函数
- 十一、temperature 参数
- 十二、多轮对话 chat(messages)
- 两天的学习感受
- 附加
- 核心技术栈
- 后端开发
- AI / LLM 应用
- 工程化与部署
- 技术栈一览
一、虚拟环境:为什么不能直接用系统 Python
项目一开始先创建了虚拟环境.venv。
虚拟环境的作用是隔离项目依赖。每个项目可以有自己独立的 Python 包和版本,避免不同项目之间互相影响。
比如:
ai-intern-agent/ .venv/常用命令:
python-m venv.venv.\.venv\Scripts\activate pip list命令行前面出现(.venv),说明当前已经进入虚拟环境。
.venv不应该提交到 GitHub,原因是:
- 体积大
- 和本机 Python 环境相关
- 别人可以通过
requirements.txt重新安装依赖
二、项目骨架:先分清代码应该放在哪里
项目不是随便堆文件,而是要提前规划目录职责。
当前项目结构大致是:
ai-intern-agent/ app/ api/ routes/ core/ schemas/ services/ main.py scripts/ tests/ docs/ .gitignore README.md目录职责:
app/:正式应用代码app/main.py:项目入口app/schemas/:Pydantic 数据模型scripts/:练习脚本或临时验证脚本tests/:后续测试代码docs/:学习记录和项目文档
这两天踩过一个坑:终端当前路径不在项目根目录时,运行脚本会找不到app模块。后来理解了,运行脚本时要确认自己在项目根目录:
pwd三、.gitignore:保护不该提交的文件
.gitignore用来告诉 Git 哪些文件不要提交。
目前至少需要包含:
.venv/ __pycache__/ .env其中.env很重要,因为它通常会保存 API Key 等敏感信息,绝对不能提交到 GitHub。
四、Git 基础:commit 和 push 的区别
这两天也练习了 Git 的基本流程:
git status git add.git commit-m"提交说明"git push origin main我之前误以为 commit 后 GitHub 就能看到代码,后来发现不是这样。
区别是:
git commit:提交到本地仓库 git push:推送到 GitHub 远程仓库简单记忆:
git add 选文件 git commit 存到本地 git push 上传 GitHub五、Python 类型注解
类型注解主要不是给 Python 运行时强制检查用的,而是为了让代码更清晰,也方便 IDE 提示。
示例:
defget_app_name()->str:return"AI Intern Agent"-> str表示这个函数预期返回字符串。
类型注解的好处:
- 提高代码可读性
- 方便编辑器提示
- 后续配合工具检查代码质量
- 让函数输入输出更明确
六、Pydantic 入门
Pydantic 用来定义数据模型和校验数据结构。
普通dict很灵活,但也容易出错,比如字段名写错、类型不对,Python 不一定会提醒。
Pydantic 可以把数据结构固定下来。
示例:
frompydanticimportBaseModelclassHealthResponse(BaseModel):status:strservice:strversion:str="0.1.0"这里定义了一个HealthResponse模型,包含三个字段:
statusserviceversion
其中version有默认值。
创建对象:
health_response=HealthResponse(status="ok",service="ai-intern-agent",)print(health_response.model_dump())输出:
{'status': 'ok', 'service': 'ai-intern-agent', 'version': '0.1.0'}可以看到,即使没有手动传入version,Pydantic 也会自动补上默认值。
七、Pydantic 的校验与报错
我还测试了错误输入:
bad_response=HealthResponse(status=["not","a","string"],service="ai-intern-agent",)因为status定义的是str,但实际传入的是list,所以 Pydantic 会抛出ValidationError。
为了让程序不直接崩掉,可以用try/except捕获:
frompydanticimportValidationErrortry:bad_response=HealthResponse(status=["not","a","string"],service="ai-intern-agent",)print(bad_response.model_dump())exceptValidationErroraserror:print("有错误:")print(error)这让我理解了 Pydantic 的几个核心能力:
- 定义数据结构
- 校验字段类型
- 提供默认值
- 用
.model_dump()转成普通字典 - 报错信息能指出哪个字段有问题
八、第一次 LLM API 调用
Day1 下午的内容是跑通第一次 LLM API 调用。
大致流程是:
.env 里保存 API Key ↓ python-dotenv 读取环境变量 ↓ OpenAI SDK 创建 client ↓ client.chat.completions.create(...) ↓ 读取模型回复示例结构:
importosfromdotenvimportload_dotenvfromopenaiimportOpenAI load_dotenv()api_key=os.getenv("DEEPSEEK_API_KEY")base_url=os.getenv("DEEPSEEK_BASE_URL")model=os.getenv("LLM_MODEL")client=OpenAI(api_key=api_key,base_url=base_url,)response=client.chat.completions.create(model=model,messages=[{"role":"system","content":"You are a helpful assistant."},{"role":"user","content":"你好,请用一句话介绍你自己"},],)print(response.choices[0].message.content)这里没有把 API Key 写死在代码里,而是从.env读取。
九、messages 结构:system、user、assistant
LLM API 里的messages是一个列表,每条消息都有role和content。
常见角色:
system:设定模型角色、规则、输出风格 user:用户输入的问题或任务 assistant:模型之前的回复示例:
messages=[{"role":"system","content":"You are a helpful assistant."},{"role":"user","content":"什么是 RAG?"},]不能把所有内容都塞进user里,因为工程上要职责分离:
system放稳定规则user放本次任务输入assistant放历史回复
这样后面封装函数、多轮对话和 Agent 状态管理都会更清晰。
十、封装 call_llm 函数
原因是如果每次都复制一大段client.chat.completions.create(...),代码会重复,而且不方便维护。
封装后:
defcall_llm(prompt:str,system_prompt:str="",temperature:float=0.7,)->str:messages=[]ifsystem_prompt:messages.append({"role":"system","content":system_prompt})messages.append({"role":"user","content":prompt})response=client.chat.completions.create(model=model,messages=messages,temperature=temperature,)returnresponse.choices[0].message.content调用:
reply=call_llm(prompt="请用一句话描述什么是 AI Agent",system_prompt="You are a helpful assistant.",temperature=0.7,)print(reply)封装函数的好处:
- 减少重复代码
- 后续更容易修改模型参数
- 业务逻辑和 API 调用逻辑分开
- 方便复用到 FastAPI 或 Agent 工作流里
十一、temperature 参数
temperature控制模型输出的随机性。
实验结果:
temperature=0:三次输出几乎一样,更稳定temperature=1:三次输出变化更明显,更发散
适用场景:
temperature=0: 适合分类、字段抽取、JSON 输出、JD 分析等稳定任务 temperature=1: 适合头脑风暴、文案生成、博客标题、创意表达等开放任务后面做 JD 分析和结构化输出时,应该优先使用较低的 temperature。
十二、多轮对话 chat(messages)
最后实现了多轮对话函数:
defchat(messages:list[dict])->str:response=client.chat.completions.create(model=model,messages=messages,)returnresponse.choices[0].message.content测试流程:
messages=[{"role":"system","content":"You are a helpful assistant."},{"role":"user","content":"什么是 RAG?"},]first_reply=chat(messages)print(first_reply)messages.append({"role":"assistant","content":first_reply})messages.append({"role":"user","content":"它和微调有什么区别?"})second_reply=chat(messages)print(second_reply)这里最重要的理解是:
LLM 不会自动记住上一次脚本调用的内容。
如果想让它理解第二轮问题里的“它”,就必须把前面的历史 messages 一起传给模型。
也就是说,多轮对话的上下文是我们自己维护的。
两天的学习感受
跟着AI的节奏来会发现时间根本用不完,我安排3小时的学习计划,真实执行时一个小时即可完成,所以我决定将时间驱动改为知识点驱动,这样ai在引领学习时不会局限于当日任务,状态好时进度也会更快。
附加
核心技术栈
后端开发
- FastAPI— Web 框架,路由设计、依赖注入、中间件、文件上传、流式响应、WebSocket
- Pydantic v2— 数据校验与序列化,嵌套模型、字段约束、自定义校验器
- SQLAlchemy 2.0 + SQLite— ORM 数据持久化,模型定义、会话管理、关系映射
- async/await + httpx— 异步编程,异步 HTTP 调用 LLM API
- pytest— 测试体系,fixture、TestClient、mock、覆盖率
AI / LLM 应用
- OpenAI / DeepSeek API— LLM 调用、Prompt 工程、结构化输出
- RAG 全链路— Embedding 向量化、文本切分、Chroma 向量数据库、Top-K 检索
- Tool Calling— LLM 函数调用,工具 schema 定义与执行
- LangGraph— Agent 工作流编排,状态图、条件路由、多节点协作
工程化与部署
- Docker + docker-compose— 容器化部署,多环境配置、健康检查
- GitHub Actions— CI/CD 自动化,lint → test → build → deploy
- Render / Railway— 云端部署上线
- structlog— 结构化日志,request_id 链路追踪、错误码体系
- JWT + API Key— 认证鉴权与接口安全
技术栈一览
语言 Python 3.12+ ────────────────────────────────── 后端框架 FastAPI · Uvicorn · Pydantic v2 数据库 SQLAlchemy 2.0 · SQLite 异步 async/await · httpx 测试 pytest · pytest-cov AI/LLM OpenAI API · DeepSeek API · Prompt Engineering RAG Embedding · Chroma · 文本切分 · Top-K检索 Agent Tool Calling · LangGraph DevOps Docker · docker-compose · GitHub Actions 部署 Render · Railway 工程规范 ruff · pre-commit · structlog · JWT