diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..2c96e81
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+.env
+.jbeval
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/99_react_agent.py b/99_react_agent.py
new file mode 100644
index 0000000..3debcb9
--- /dev/null
+++ b/99_react_agent.py
@@ -0,0 +1,202 @@
+"""
+ReAct Agent(基于 DeepSeek Function Calling 实现)
+
+ReAct = Reasoning + Acting:模型先"想"(决定是否调用工具、调用哪个),
+再"做"(执行工具),拿到"观察结果"后继续下一轮思考,直到给出最终答案。
+"""
+
+import os
+import json
+from openai import OpenAI
+from dotenv import load_dotenv
+
+load_dotenv()
+
+client = OpenAI(
+ api_key=os.environ.get("DEEPSEEK_API_KEY"),
+ base_url="https://api.deepseek.com",
+)
+
+MODEL = "deepseek-chat" # 换成你实际可用的模型名
+MAX_STEPS = 8 # 防止死循环的最大推理步数
+
+
+# ============================================================
+# 1. 工具实现层:每个工具就是一个普通的 Python 函数
+# ============================================================
+def get_weather(location: str) -> str:
+ """模拟天气查询接口"""
+ fake_db = {
+ "杭州": "30℃,晴,东南风 2 级",
+ "北京": "25℃,多云",
+ "上海": "28℃,小雨",
+ }
+ return fake_db.get(location, f"{location}:暂无该城市天气数据")
+
+
+def calculator(expression: str) -> str:
+ """一个安全的四则运算计算器"""
+ allowed = set("0123456789+-*/(). ")
+ if not set(expression) <= allowed:
+ return "错误:表达式包含非法字符"
+ try:
+ return str(eval(expression, {"__builtins__": {}}, {}))
+ except Exception as e:
+ return f"计算失败:{e}"
+
+
+# 工具名 -> 函数 的注册表,Agent 靠它做分发
+TOOL_REGISTRY = {
+ "get_weather": get_weather,
+ "calculator": calculator,
+}
+
+
+# ============================================================
+# 2. 工具描述层:告诉模型有哪些工具可用(JSON Schema)
+# ============================================================
+TOOLS_SCHEMA = [
+ {
+ "type": "function",
+ "function": {
+ "name": "get_weather",
+ "description": "获取指定城市的当前天气",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "location": {"type": "string", "description": "城市名,如杭州"},
+ },
+ "required": ["location"],
+ },
+ },
+ },
+ {
+ "type": "function",
+ "function": {
+ "name": "calculator",
+ "description": "计算一个数学表达式,例如 '30 - 25'",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "expression": {"type": "string", "description": "要计算的数学表达式"},
+ },
+ "required": ["expression"],
+ },
+ },
+ },
+]
+
+
+# ============================================================
+# 3. 系统提示词:定义 Agent 的行为方式
+# ============================================================
+SYSTEM_PROMPT = """你是一个可以使用工具的智能助手。
+
+工作要求:
+1. 先思考问题需要哪些信息,判断是否需要调用工具。
+2. 需要外部信息(天气、计算等)时,必须调用工具,不要凭空编造。
+3. 可以连续多次调用工具;每一步只做当前最必要的事。
+4. 拿到工具结果后,用简洁的中文给出最终答案。
+"""
+
+
+# ============================================================
+# 4. 核心:ReAct 循环
+# ============================================================
+def run_react_agent(user_query: str, max_steps: int = MAX_STEPS, verbose: bool = True):
+ """
+ 执行 ReAct 循环:
+ 思考(Thought) -> 行动(Action) -> 观察(Observation) -> 再思考 ... -> 最终答案
+ 返回 (最终答案, 完整消息历史)
+ """
+ messages = [
+ {"role": "system", "content": SYSTEM_PROMPT},
+ {"role": "user", "content": user_query},
+ ]
+
+ for step in range(1, max_steps + 1):
+ if verbose:
+ print(f"\n{'=' * 20} Step {step} {'=' * 20}")
+
+ # ---------- Thought:让模型决定下一步做什么 ----------
+ response = client.chat.completions.create(
+ model=MODEL,
+ messages=messages,
+ tools=TOOLS_SCHEMA,
+ tool_choice="auto",
+ )
+ assistant_msg = response.choices[0].message
+
+ # 把模型的回复写入历史(必须手动构造,content 为 None 时补成 "")
+ msg_dict = {"role": "assistant", "content": assistant_msg.content or ""}
+ if assistant_msg.tool_calls:
+ msg_dict["tool_calls"] = [tc.model_dump() for tc in assistant_msg.tool_calls]
+ messages.append(msg_dict)
+
+ if verbose and assistant_msg.content:
+ print(f"[Thought] {assistant_msg.content}")
+
+ # ---------- 终止条件:模型不再请求工具,直接给出答案 ----------
+ if not assistant_msg.tool_calls:
+ final_answer = assistant_msg.content or ""
+ if verbose:
+ print(f"[Final] {final_answer}")
+ return final_answer, messages
+
+ # ---------- Action + Observation:执行所有工具调用 ----------
+ for tool_call in assistant_msg.tool_calls:
+ name = tool_call.function.name
+
+ # 注意:arguments 是 JSON 字符串,必须解析成 dict 再传参
+ try:
+ args = json.loads(tool_call.function.arguments or "{}")
+ except json.JSONDecodeError:
+ args = {}
+
+ if verbose:
+ print(f"[Action] {name}({json.dumps(args, ensure_ascii=False)})")
+
+ func = TOOL_REGISTRY.get(name)
+ if func is None:
+ result = f"错误:未知工具 {name}"
+ else:
+ try:
+ result = func(**args)
+ except Exception as e:
+ result = f"工具执行异常:{e}"
+
+ result = str(result)
+ if verbose:
+ print(f"[Observation] {result}")
+
+ # 工具结果必须带上 tool_call_id,一一对应
+ messages.append({
+ "role": "tool",
+ "tool_call_id": tool_call.id,
+ "content": result,
+ })
+
+ # 超过最大步数仍未收敛
+ fallback = "抱歉,我在限定步骤内没能得出结论。"
+ if verbose:
+ print(f"[Final] {fallback}")
+ return fallback, messages
+
+
+# ============================================================
+# 5. 运行入口
+# ============================================================
+if __name__ == "__main__":
+ # 单轮测试
+ for q in ["杭州天气怎么样?", "杭州和北京温差多少度?"]:
+ print(f"\n\n########## 用户:{q} ##########")
+ answer, history = run_react_agent(q)
+ print(f"回答:{answer}")
+
+ # 如果想做成多轮对话的交互式 Agent,可以这样:
+ # while True:
+ # q = input("\n你:")
+ # if q in ("exit", "quit"):
+ # break
+ # answer, _ = run_react_agent(q)
+ # print("助手:", answer)
\ No newline at end of file
diff --git a/tets.py b/tets.py
new file mode 100644
index 0000000..8c9a920
--- /dev/null
+++ b/tets.py
@@ -0,0 +1,41 @@
+import base64
+from openai import OpenAI
+api_key='sk-83c3ebe6b1b04bdf93c3c4be9b17736d'
+client = OpenAI(api_key=api_key, base_url="https://api.deepseek.com")
+files = client.files.list()
+for f in files.data:
+ print(f.id, f.filename)
+with open("zky.png", "rb") as f:
+ b64 = base64.b64encode(f.read()).decode("utf-8")
+
+response = client.chat.completions.create(
+ model="deepseek-flash",
+ messages=[
+ {
+ "role": "user",
+ "content": [
+ {"type": "text", "text": "这张图片里有什么?"},
+ {
+ "type": "image_url",
+ "image_url": {"url": f"data:image/jpeg;base64,{b64}"},
+ },
+ ],
+ }
+ ],
+)
+print(response.choices[0].message.content)
+
+
+response = client.chat.completions.create(
+ model="deepseek-flash",
+ messages=[
+ {
+ "role": "user",
+ "content": [
+ {"type": "text", "text": "这张图片里有什么?"},
+ {"type": "file", "file_id": "file-api-01ab723a-0bd1-4e38-b373-a25278eb3baf"},
+ ],
+ }
+ ],
+)
+print(response.choices[0].message.content)
\ No newline at end of file
diff --git a/w1_d1/git.md b/w1_d1/git.md
new file mode 100644
index 0000000..db85211
--- /dev/null
+++ b/w1_d1/git.md
@@ -0,0 +1,412 @@
+## git介绍
+
+- 思考1:任何项目,是否有多个版本?如果是,每个版本的代码是否需要保存?
+ - 有多个版本,每个版本的代码都要保存。如果没有其他工具可能就是一个文件夹一个版本,那样版本一多就乱了
+- 思考2:公司里的项目一般是多人开发的,要不要共享代码?
+ - 要共享代码,但是传统共享代码,就是微信传递、u盘传递等
+- 以上问题,都可以由`git`这个工具解决
+- git是什么?
+ - 一款分布式的版本管理、多人协作工具
+- 集中式版本管理
+ - 一个团队的代码,全部集中存到一个服务器上。所以如果这个服务器挂,版本都没了
+- 分布式版本管理
+ - 一个团队的代码,整体是存到服务器上的,但是当某个人下载这份代码,会相当于下载了全部的副本,这就叫分布式。好处:数据不易丢失
+- 总结:git是什么?
+ - 就是一款分布式的版本管理、多人协作的工具
+ - 作用1:控制和记录版本变化
+ - 作用2:方便多人协作共享代码
+ - .......
+
+## git下载与安装
+
+[官网](https://git-scm.com/downloads)
+
+- 下载完了后就建议下一步下一步直到完成,毛都不要改
+- 建议:开发软件就建议装在C盘
+- 如何判断安装成功?
+ - windows系统可以:右键看有没有 `git bash here`,有就代表成功
+ - 或者windows和mac都可以在`终端`(cmd、小黑窗),输入git按回车,如果出现一大坨英文,就代表成功
+
+## git 配置用户名与邮箱
+
+- 作用:用来标识自己是谁
+
+- 配置方法:
+ - 打开小黑窗
+ - 方法1:右键开始菜单,然后点运行,然后输入cmd按回车
+ - 快捷键winows键+r再输入cmd回车
+ - 方法2:
+ - 随便打开一个文件夹,在地址栏上输入cmd按回车
+ - mac直接搜“终端”两个字
+- 命令如下
+
+```Bash
+# git config user.name 你的目标用户名
+# git config user.email 你的目标邮箱名
+
+# 使用--global参数,配置全局的用户名和邮箱,只需要配置一次即可
+# 用户名有意义即可
+# 邮箱要真实可用
+git config --global user.name mm
+git config --global user.email mm@mmm.com
+
+# 查看配置信息
+git config --list
+
+# 取消配置 - 把它们从配置文件里删掉 - 一般不用
+git config --unset --global user.name
+git config --unset --global user.email
+```
+
+- 总结:
+ - 把`gitee`上的用户名和邮箱配置到git上
+ - 要配置几次?
+ - 1次
+ - 有什么用?
+ - 可以给服务器识别你的身份
+ - 命令为
+
+```Bash
+git config --global user.name 用户名
+git config --global user.email 邮箱
+```
+
+## 初始化仓库
+
+- git作用:可以做版本管理,相当于游戏里的`存档`
+- 并不是说你电脑上安装了git,那么所有的项目都被管理了
+- 而是你要给这个项目做**初始化仓库**的操作,才代表这个项目被git管理了
+- 如果希望一个项目被`git`要用 `git init`初始化这个项目
+- 步骤:
+ - 来到这个项目文件夹,右键`git bash here`会弹出一个专门给`git`用的小黑窗,而且直接就在这个项目的路径上,输入
+
+```Bash
+git init
+- 敲完会在这个项目文件夹里多一个 `.git`的隐藏文件夹,所以如果以后在项目中看到有这个文件夹,代表这个项目已经被`git`管理,就不用再初始化了
+```
+
+- 注意:
+
+ `.git`文件夹不能删了,删了就相当于所有的`版本`都没了,只留下当前代码
+
+ - 有些人即使初始化了也看不到这个文件夹,是因为系统设置了隐藏文件夹不可见,所以可以通过下图设置
+
+ 
+
+ - 请问一个项目`搞一次`,而且这个项目如果已经有了,就不搞
+
+## git - 记录改动
+
+
+
+- 作用:相当于就是产生`存档`
+- git三大区域:
+ - 工作区:就是指项目代码
+ - 暂存区和仓库区:对我们而言是不可见的
+- 如果你`工作区`改动了代码,想产生一个`存档`,就要先把改动加到`暂存区`,再加到`仓库区`
+- 先改代码,然后敲命令
+
+```Bash
+# 查看当前状态
+git status
+
+# 把当前改动到的所有文件都加到暂存区
+git add .
+# 添加某个文件到暂存区 -- 用的少
+git add 文件名
+
+# 把暂存区的内容提交到仓库区
+git commit -m'本次操作的说明文字'
+```
+
+- 如果仓库此时没有任何新的改动,`git status`会出现`干净`的提示
+
+ 
+
+## git - 快速提交的说明
+
+```Bash
+git commit -a -m '提交说明'
+```
+
+- 仅能用于本就存在于仓库的文件
+- 仓库中新建的文件,还是得先加到`暂存区`,再提交到`仓库区`
+
+## git - 修改已提交的说明文字
+
+- 如果刚刚提交的文字不小心写错了,可以修改
+
+```Bash
+git commit --amend
+```
+
+- 此时会进入到编辑模式,默认的编辑器非常难用
+ - 进入后你需要输入`i`,代表进入修改,然后通过键盘上下左右改动光标位置,再把你需要的文字删掉或改掉
+ - 改完后,还得按一下`esc`键,然后英文状态下输入 `:wq`按回车才代表修改完成
+ - ```
+ git config --global core.editor "notepad"
+ ```
+
+
+
+## git - 查看记录
+
+```Bash
+# 查看详细记录
+git log
+
+# 一行显示每条记录
+git log --oneline
+```
+
+## git - 回滚记录
+
+- 作用:可以把代码恢复到某个记录的状态
+- 命令
+
+```Bash
+git reset --hard 记录的hash值(记录的id)
+- 如何获取记录的hash值?
+git log
+# 用的多
+git log --oneline
+```
+
+- 注意:
+ - 回滚到某个记录后,你再`git log`只能看到当前记录和它之前的,后面的看不到
+ - 要想看到全部操作记录,用
+
+```Bash
+git reflog
+```
+
+- 练习:
+ - 要求产生至少3个记录
+ - 能自由切换3个记录的代码
+ - 最后一次一定要回滚到最新记录
+
+## git - 配置被git忽略的文件
+
+- 有些文件可能不需要被git管理,例如一些自己手写的笔记,密码等,那就可以配置忽略文件
+- 需要在仓库根目录,新建 `.gitignore`文件,在这个文件里写需要被忽略的文件,例
+
+```JavaScript
+密码.md
+情书.md
+小电影
+```
+
+- 如果这些文件被git忽略,将不会被提交,也不受git记录变化而变化
+
+## git - 分支的概念
+
+- 所谓分支,就是指把当前的代码克隆一份
+- 这样做的好处是:可以按员工开分支代码,一人负责一个分支,好处是方便管理,以及某一个分支有问题绝对不影响其他分支
+- git初始化后,默认就会有一个分支叫`master`,我们也称之为主分支
+- 开发中有个规范:**主分支上不直接进行开发**,它里面只保留经过测试的最稳定的版本代码,开发不会直接在这个分支上进行
+- 所以还会在主分支的基础上克隆出一份代码(开一个新的分支),分支名叫`develop`或者`dev`,代表是专门用来开发的分支
+- 再然后在 `develop`基础上又开多个分支,不同的人负责不同的分支,他们写完代码,又各自合并到develop分支,然后经过大量测试和试运行发现很稳定,就合并到 `master`产生一个稳定的版本
+
+
+
+## git - 分支操作
+
+- 命令如下
+
+```Bash
+# 查看当前所有分支
+git branch
+# 新建分支
+git branch 分支名
+# 切换分支
+git checkout 分支名
+
+# 新建分支并切换过去
+git checkout -b 分支名
+```
+
+- 合并分支一定要小心(要找对分支、确保写的代码都已经提交了),再切换到想合并的目标分支
+ - 比如我想合并到`develop`,我就要先切换到`develop`
+
+```Bash
+git checkout develop
+```
+
+- 合并语法
+
+```Bash
+git merge 分支名
+# 例如:当前是develop分支,然后你写git merge zs,意思就是把zs分支的代码合并到develop里面
+git merge zs
+```
+
+- 练习要求:
+ - 默认有master分支,需要新建develop分支,再然后在develop基础上创建`dy`、`ls`
+ - `dy`写`dy`,`ls`写`ls`的代码(新建dy.html,ls.html)
+ - 每个分支写完了先提交到当前分支
+ - 然后合并到develop
+ - 等develop有所有代码了,再合并到`master`
+
+## git - 分支合并冲突
+
+- 工作中必须学会如何解决冲突
+
+
+
+- 当不同分支负责人员改动到同一个文件,合并时就会产生冲突
+
+- 如果冲突了,在vscode中将看到如下界面
+
+ 
+
+- 三个选项具体怎么选要看需求
+
+ - 例如1:当前的有bug,所以领导指派李四去修复bug,然后合并过来,肯定是保留李四,也就是保留合并过来的(点第二个按钮)
+ - 例如2: 如果当前分支代码比较多,还包含了要合并过来的分支的代码,就选第一个
+ - 例如3:如果两段代码分别是完成不同的功能,而且这两个功能都要,就选第三个都保留
+
+## git - 删除分支
+
+```Bash
+git branch -d 分支名
+# 强行删
+git branch -D 分支名
+```
+
+- 如果你要删某个分支,你要确保不在这个分支上,才可以删
+- 如果被删的分支有新的记录,但是还没有合并,那么也删不掉,用`git branch -D 分支名`
+
+
+
+## 远程仓库 - 建库、删库
+
+- 建库
+
+
+
+- 删库
+
+ 
+
+ 
+
+## 远程仓库 - 添加团队成员
+
+
+
+## 远程仓库 - 推送
+
+- 让本地仓库跟远程仓库建立链接
+
+```Bash
+git remote add 起一个远程仓库名字 仓库地址
+git remote add origin https://gitee.com/xpzll/viewdemo95.git
+```
+
+- 推送代码到远程仓库
+
+```Bash
+git push -u origin "master"
+```
+
+- 以上两段命令,gitee上可以复制
+- 第一次推送会需要登录,但是这个登录只要成功一次,后面都不用登录
+
+
+
+## 远程仓库 - 开源
+
+
+
+## 远程仓库 - 多远程仓库连接
+
+```Bash
+# 建立链接
+git remote add origin 仓库地址
+```
+
+- remote是远程的意思
+- add是添加的意思
+- origin只是给这个远程仓库的连接起了一个名字叫origin
+
+```Bash
+# 把本地仓库推送到 origin 连接的远程仓库,并且也把远程仓库分支叫为master
+git push -u origin "master"
+```
+
+- 所以如果你一个本地仓库,要推送多个远程仓库,要建立新的连接,而新的连接名字不能重复
+
+```Bash
+# 也就是说连接到这个新仓库的别名叫xx
+git remote add xx 新仓库地址
+
+## 意思是把本地仓库推送到xx这个连接的远程仓库
+git push -u xx "master"
+```
+
+## 远程仓库 - 删除连接
+
+- 工作中一般一个本地仓库只连接一个远程仓库
+- 问题来了如果之前我在本地建立了一个连接,而且连接名字叫origin,后面再建立连接除非改名字,不然还叫origin会报错
+- 但是我就是想用origin,就把之前的origin删掉
+
+```Bash
+git remote remove origin
+```
+
+## 远程仓库 - 克隆
+
+- 作用:把远程仓库的代码克隆下来
+
+```Bash
+# 要么这个仓库是开源,要么你是这个仓库的成员
+git clone 仓库地址
+```
+
+## 远程仓库 - 拉取
+
+- 作用:可以把远程仓库最新的代码拉取下来
+
+```Bash
+git pull
+```
+
+## 解决推送冲突
+
+
+
+- 解决办法:
+ - 先`git pull`拉取最新代码
+ - 再`git push`
+- 注意:
+ - 为什么以后只要写 `git push`,因为完整写法是之前空仓库用一次就够了,后面都不是空仓库,直接`push`
+
+## windows的凭据管理器
+
+- 它把密码保存到windows的凭据管理器里了
+- 如果你不想用了,就去里面删除,如果删除了下次还得输入
+- 最多就是去里面修改它,因为我可能把gitee账号密码给改了,那这里也得修改
+- 或者如果公司刚好也是用gitee,而且公司没给你发电脑,你用的还是自己的电脑,而且还要满足公司的gitee没用你的邮箱,而是直接给你指派了邮箱,这时候就去要修改
+
+## SSH私钥与公钥方式
+
+- 因为有人的电脑因为系统原因是没有凭据管理的,那就意味着每次都要输入账号和密码
+
+- 所以还有一种方式叫使用`私钥`配合`公钥`的形式来免登录
+
+ 
+
+- 在任意小黑窗里输入如下命令
+
+```Bash
+ssh-keygen -t ed25519 -C "你的邮箱地址"
+```
+
+- 以后去到公司,公司负责人会问你要你的邮箱,或者问你要公钥
+- 如果是要邮箱,就要用`https`,然后输入账号和密码来登录
+- 如果问你要公钥,你就在电脑上生成公钥和私钥,再把公钥部分的内容发给负责人
+- 公钥文件以 `.pub`结尾,去`~/.ssh`文件夹找文件
+- ~代表自己电脑的个人文件夹
+- 例如: `C:\Users\你电脑的用户名\.ssh`
+- 如果是账号密码登录用 `https`的仓库地址
+- 如果是公钥用`ssh`的仓库地址
\ No newline at end of file
diff --git a/w1_d2/deepseek_api.py b/w1_d2/deepseek_api.py
new file mode 100644
index 0000000..50d7261
--- /dev/null
+++ b/w1_d2/deepseek_api.py
@@ -0,0 +1,6 @@
+import json
+b={1:2}
+a='{"name":null}'
+b.get(1)
+j=json.loads(a)
+print(j.get('name'))
\ No newline at end of file
diff --git a/w1_d2/llm-api-demo/01_deepseek_demo.py b/w1_d2/llm-api-demo/01_deepseek_demo.py
new file mode 100644
index 0000000..6f33bb9
--- /dev/null
+++ b/w1_d2/llm-api-demo/01_deepseek_demo.py
@@ -0,0 +1,21 @@
+# Please install OpenAI SDK first: `pip3 install openai`
+import os
+from openai import OpenAI
+from dotenv import load_dotenv
+load_dotenv()
+client = OpenAI(
+ api_key=os.environ.get('DEEPSEEK_API_KEY'),
+ base_url="https://api.deepseek.com")
+
+response = client.chat.completions.create(
+ model="deepseek-v4-pro",
+ messages=[
+ {"role": "user", "content": "Hello"},
+ ],
+ stream=False,
+ reasoning_effort="high",
+ extra_body={"thinking": {"type": "enabled"}}
+)
+
+print(response.model_dump_json(indent=2))
+print(response.choices[0].message.content)
\ No newline at end of file
diff --git a/w1_d2/llm-api-demo/02_qwen_demo.py b/w1_d2/llm-api-demo/02_qwen_demo.py
new file mode 100644
index 0000000..9d3c744
--- /dev/null
+++ b/w1_d2/llm-api-demo/02_qwen_demo.py
@@ -0,0 +1,23 @@
+# https://docs.bailian.console.aliyun.com/zh/model-studio/qwen-api-via-openai-chat-completions
+import os
+from openai import OpenAI
+from dotenv import load_dotenv
+load_dotenv()
+WorkspaceId='llm-zw41x57m8nuezmhp'
+
+client = OpenAI(
+ # 若没有配置环境变量,请用百炼API Key将下行替换为:api_key="sk-xxx"
+ api_key=os.getenv("DASHSCOPE_API_KEY"),
+ base_url=f"https://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/compatible-mode/v1",
+)
+
+completion = client.chat.completions.create(
+ # 模型列表:https://help.aliyun.com/zh/model-studio/getting-started/models
+ model="deepseek-v4.1-flash",
+ messages=[
+ {"role": "system", "content": "You are a helpful assistant."},
+ {"role": "user", "content": "你是谁?"},
+ ]
+)
+print(completion.model_dump_json(indent=2))
+print(completion.choices[0].message.content)
\ No newline at end of file
diff --git a/w1_d2/llm-api-demo/03_streaming_demo.py b/w1_d2/llm-api-demo/03_streaming_demo.py
new file mode 100644
index 0000000..f074177
--- /dev/null
+++ b/w1_d2/llm-api-demo/03_streaming_demo.py
@@ -0,0 +1,37 @@
+import os
+from openai import OpenAI
+from dotenv import load_dotenv
+
+load_dotenv()
+
+client = OpenAI(
+ api_key=os.environ.get("DEEPSEEK_API_KEY"),
+ base_url="https://api.deepseek.com",
+)
+
+response = client.chat.completions.create(
+ model="deepseek-v4-flash",
+ messages=[
+ {"role": "system", "content": "You are a helpful assistant."},
+ {"role": "user", "content": "请用三句夸赞一下大帝,大帝是我爸爸"}
+ ],
+ stream=True, # 开启流式输出
+ # 不设置 reasoning_effort 和 extra_body 中的 thinking,即不使用深度思考
+ reasoning_effort="high",
+ extra_body={"thinking": {"type": "enabled"}}
+)
+
+# count = 0
+# for chunk in response:
+# content = chunk.choices[0].delta.content
+# if content:
+# count += 1
+# print(f"[{count}] {content}")
+
+# 逐块输出内容
+for chunk in response:
+ print(chunk)
+ # ChatCompletionChunk(id='c2291fe4-6757-4de8-a7bb-5033f6a8bd03', choices=[Choice(delta=ChoiceDelta(content='', function_call=None, refusal=None, role='assistant', tool_calls=None), finish_reason=None, index=0, logprobs=None)], created=1790050006, model='deepseek-flash', object='chat.completion.chunk', moderation=None, obfuscation=None, service_tier=None, system_fingerprint='aeb56401ca74e127821c4f9126dcb669', usage=None)
+ content = chunk.choices[0].delta.content
+ if content: # 避免输出 None
+ print(content, end="", flush=True)
\ No newline at end of file
diff --git a/w1_d2/llm-api-demo/04_multi_turn_demo.py b/w1_d2/llm-api-demo/04_multi_turn_demo.py
new file mode 100644
index 0000000..26cf61b
--- /dev/null
+++ b/w1_d2/llm-api-demo/04_multi_turn_demo.py
@@ -0,0 +1,47 @@
+# 作业:
+# 1.完成多轮对话的demo
+# 2.完成让用户选择不同模型的调用不同模型的回复demo
+# 3.完成一次持久化存储对话
+# 4.完成一次流式输出demo
+# 5.完成RAG流程图的绘制
+# 6.选做:调用xiaomi、硅基流动、chatgpt等其他 AI API 服务
+import os
+from openai import OpenAI
+from dotenv import load_dotenv
+load_dotenv()
+
+client = OpenAI(
+ api_key=os.getenv("DASHSCOPE_API_KEY"),
+ base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
+)
+
+model = "qwen-plus"
+
+messages = [
+ {
+ "role": "system",
+ "content": "你是一名聊天高手,幽默,嘲讽用户,自带 emoji表情",
+ }
+]
+
+while True:
+ question = input("用户:").strip()
+
+ if question.lower() in {"exit", "quit"}:
+ print("对话结束")
+ break
+
+ if not question:
+ continue
+
+ messages.append({"role": "user", "content": question})
+
+ response = client.chat.completions.create(
+ model=model,
+ messages=messages,
+ )
+
+ answer = response.choices[0].message.content
+ messages.append({"role": "assistant", "content": answer})
+
+ print(f"AI:{answer}")
\ No newline at end of file
diff --git a/w1_d2/llm-api-demo/05_deepseek_api_params_demo.py b/w1_d2/llm-api-demo/05_deepseek_api_params_demo.py
new file mode 100644
index 0000000..b6313db
--- /dev/null
+++ b/w1_d2/llm-api-demo/05_deepseek_api_params_demo.py
@@ -0,0 +1,272 @@
+# -*- coding: utf-8 -*-
+"""
+DeepSeek API 参数教学演示脚本
+用法:
+ python demo.py # 默认跑 stream 示例
+ python demo.py 1 # 跑第1个示例(model)
+ python demo.py 8 # 跑第8个示例(tools)
+"""
+import os
+import sys
+import json
+from openai import OpenAI
+from dotenv import load_dotenv
+
+load_dotenv()
+
+client = OpenAI(
+ api_key=os.environ.get("DEEPSEEK_API_KEY"),
+ base_url="https://api.deepseek.com",
+)
+
+MODEL = "deepseek-chat"
+
+
+# ---------- 1. model ----------
+def demo_model():
+ print("【1. model —— 指定模型】")
+ response = client.chat.completions.create(
+ model=MODEL,
+ messages=[{"role": "user", "content": "你好,请用一句话自我介绍。"}],
+ )
+
+ print(response.choices[0].message.content)
+ print(response.model_dump_json(indent=2))
+
+
+# ---------- 2. messages ----------
+def demo_messages():
+ print("【2. messages —— 系统/用户/历史消息】")
+ response = client.chat.completions.create(
+ model=MODEL,
+ messages=[
+ {"role": "system", "content": "你是一个只用文言文回答的助手。"},
+ {"role": "user", "content": "什么是API?"},
+ {"role": "assistant", "content": "应用程序接口也。"},
+ {"role": "user", "content": "那什么是流式输出?"},
+ ],
+ )
+ print(response.choices[0].message.content)
+
+
+# ---------- 3. stream ----------
+def demo_stream():
+ print("【3. stream —— 流式输出】")
+ response = client.chat.completions.create(
+ model=MODEL,
+ messages=[{"role": "user", "content": "用三句话介绍AI的流式输出的作用。"}],
+ stream=True,
+ )
+ for chunk in response:
+ content = chunk.choices[0].delta.content
+ if content:
+ print(content, end="", flush=True)
+ print() # 收尾换行
+
+
+# ---------- 4. temperature ----------
+def demo_temperature():
+ print("【4. temperature —— 随机性】")
+ prompt = [{"role": "user", "content": "我姓朱,给我小孩起个名字,要有一个凯字,命中缺少需要一个带水的,只给1个。"}]
+
+ cold = client.chat.completions.create(
+ model=MODEL, messages=prompt, temperature=0.2
+ )
+ hot = client.chat.completions.create(
+ model=MODEL, messages=prompt, temperature=2.0
+ )
+
+ print("低温(0.2):", cold.choices[0].message.content.strip())
+ print("高温(2.0):", hot.choices[0].message.content.strip())
+
+
+# ---------- 5. top_p ----------
+def demo_top_p():
+ print("【5. top_p —— 候选词概率范围】")
+ response = client.chat.completions.create(
+ model=MODEL,
+ messages=[{"role": "user", "content": "续写:从前有座山,"}],
+ top_p=0.9,
+ )
+ print(response.choices[0].message.content)
+
+
+# ---------- 6. max_tokens ----------
+def demo_max_tokens():
+ print("【6. max_tokens —— 限制输出长度】")
+ response = client.chat.completions.create(
+ model=MODEL,
+ messages=[{"role": "user", "content": "讲一个很长的故事。"}],
+ max_tokens=50,
+ )
+ print(response.choices[0].message.content)
+ print("结束原因:", response.choices[0].finish_reason) # 可能是 "length"
+
+
+# ---------- 7. response_format ----------
+def demo_response_format():
+ print("【7. response_format —— 结构化输出】")
+ response = client.chat.completions.create(
+ model=MODEL,
+ messages=[
+ {"role": "system", "content": "你是一个文本提取助手,输出json格式"},
+ {"role": "user", "content": "我叫刘杰,性别男,爱好女,工资null"},
+ ],
+ response_format={"type": "json_object"},
+ )
+ text = response.choices[0].message.content
+ print("原始输出:", text)
+
+ # 验证是不是合法 JSON
+ try:
+ print(type(text))
+ data = json.loads(text)
+ print("解析成功:", data,type(data))
+ except json.JSONDecodeError as e:
+ print("解析失败:", e)
+
+
+# ---------- 8. tools ----------
+def demo_tools():
+ print("【8. tools —— 声明外部工具】")
+ tools = [
+ {
+ "type": "function",
+ "function": {
+ "name": "get_weather",
+ "description": "查询指定城市的天气",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "city": {"type": "string", "description": "城市名"}
+ },
+ "required": ["city"],
+ },
+ },
+ },
+ {
+ "type": "function",
+ "function": {
+ "name": "get_handsome_boy_score",
+ "description": "查询学生的帅气程度",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "name": {"type": "string", "description": "人名"}
+ },
+ "required": ["name"],
+ },
+ },
+ }
+ ]
+
+ response = client.chat.completions.create(
+ model=MODEL,
+ # messages=[{"role": "user", "content": "北京今天天气怎么样?"}],
+ messages=[{"role": "user", "content": "李毅长的怎么样?"}],
+ tools=tools,
+ )
+
+ msg = response.choices[0].message
+ if msg.tool_calls:
+ call = msg.tool_calls[0]
+ print("要调用的函数:", call.function.name)
+ print("参数:", call.function.arguments)
+ else:
+ print("模型直接回答:", msg.content)
+
+
+# ---------- 9. tool_choice ----------
+def demo_tool_choice():
+ print("【9. tool_choice —— 控制工具选择】")
+ tools = [
+ {
+ "type": "function",
+ "function": {
+ "name": "get_weather",
+ "description": "查询指定城市的天气",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "city": {"type": "string", "description": "城市名"}
+ },
+ "required": ["city"],
+ },
+ },
+ }
+ ]
+
+ # 三种模式演示
+ modes = [
+ ("auto", "auto"),
+ ("none", "none"),
+ ("强制get_weather", {"type": "function", "function": {"name": "get_weather"}}),
+ ]
+
+ for label, choice in modes:
+ response = client.chat.completions.create(
+ model=MODEL,
+ messages=[{"role": "user", "content": "朱凯源是谁?"}],
+ tools=tools,
+ tool_choice=choice,
+ )
+ msg = response.choices[0].message
+ if msg.tool_calls:
+ print(f"[{label}] 调用工具 -> {msg.tool_calls[0].function.arguments}")
+ else:
+ print(f"[{label}] 直接回答 -> {msg.content}")
+
+
+# ---------- 10. extra_body ----------
+def demo_extra_body():
+ print("【10. extra_body —— 厂商私有参数】")
+ # 说明:这里以 deepseek-reasoner 的 thinking 控制为例,
+ # 具体字段名请以官方文档为准。若模型不支持,可能报错。
+ try:
+ response = client.chat.completions.create(
+ model="deepseek-reasoner",
+ messages=[{"role": "user", "content": "9.11 和 9.8 哪个大?"}],
+ extra_body={"thinking": {"type": "enabled"}}, # "enabled/disabled"
+ )
+ print(response.choices[0].message.content)
+ print(response.model_dump_json(indent=4))
+ except Exception as e:
+ print("调用失败(可能模型或字段不支持):", e)
+
+
+# ---------- 调度 ----------
+DEMOS = {
+ 1: demo_model,
+ 2: demo_messages,
+ 3: demo_stream,
+ 4: demo_temperature,
+ 5: demo_top_p,
+ 6: demo_max_tokens,
+ 7: demo_response_format,
+ 8: demo_tools,
+ 9: demo_tool_choice,
+ 10: demo_extra_body,
+}
+
+
+def main():
+ if len(sys.argv) < 2:
+ choice = 3 # 默认跑 stream
+ else:
+ try:
+ choice = int(sys.argv[1])
+ except ValueError:
+ print("参数必须是 1~10 的数字")
+ return
+
+ if choice not in DEMOS:
+ print(f"没有编号 {choice} 的示例,可用:{sorted(DEMOS.keys())}")
+ return
+
+ print("=" * 50)
+ DEMOS[choice]()
+ print("=" * 50)
+
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/w1_d2/llm-api-demo/06_dashscope.py b/w1_d2/llm-api-demo/06_dashscope.py
new file mode 100644
index 0000000..05fb328
--- /dev/null
+++ b/w1_d2/llm-api-demo/06_dashscope.py
@@ -0,0 +1,17 @@
+import os
+import dashscope
+
+from dotenv import load_dotenv
+load_dotenv()
+dashscope.base_http_api_url = 'https://maas.qianwenaiapi.com/api/v1'
+messages = [
+ {'role': 'system', 'content': 'You are a helpful assistant.'},
+ {'role': 'user', 'content': 'Who are you?'}
+]
+response = dashscope.Generation.call(
+ api_key=os.getenv('DASHSCOPE_API_KEY'),
+ model='qwen-plus',
+ messages=messages,
+ result_format='message'
+)
+print(response)
\ No newline at end of file
diff --git a/w1_d2/llm-api-demo/07_fastapi_ds.py b/w1_d2/llm-api-demo/07_fastapi_ds.py
new file mode 100644
index 0000000..9e6457e
--- /dev/null
+++ b/w1_d2/llm-api-demo/07_fastapi_ds.py
@@ -0,0 +1,30 @@
+# Please install OpenAI SDK first: `pip3 install openai`
+import os
+from openai import OpenAI
+from dotenv import load_dotenv
+load_dotenv()
+from fastapi import FastAPI
+
+app=FastAPI()
+
+@app.get('/')
+def call_llm(user_input,model="deepseek-v4-pro"):
+ client = OpenAI(
+ api_key=os.environ.get('DEEPSEEK_API_KEY'),
+ base_url="https://api.deepseek.com")
+
+ response = client.chat.completions.create(
+ model=model,
+ messages=[
+ {"role": "system", "content": "You are a helpful assistant"},
+ {"role": "user", "content": user_input},
+ ],
+ stream=False,
+ reasoning_effort="high",
+ extra_body={"thinking": {"type": "enabled"}}
+ )
+ return response.choices[0].message.content
+
+if __name__ =='__main__':
+ import uvicorn
+ uvicorn.run(app,host='0.0.0.0',port=8001)
\ No newline at end of file
diff --git a/w1_d2/llm-api-demo/08_fastapi_stream.py b/w1_d2/llm-api-demo/08_fastapi_stream.py
new file mode 100644
index 0000000..81e89a0
--- /dev/null
+++ b/w1_d2/llm-api-demo/08_fastapi_stream.py
@@ -0,0 +1,69 @@
+import os
+import json
+from fastapi import FastAPI
+from fastapi.responses import StreamingResponse
+from openai import OpenAI
+from dotenv import load_dotenv
+
+load_dotenv()
+
+app = FastAPI()
+
+client = OpenAI(
+ api_key=os.environ.get("DEEPSEEK_API_KEY"),
+ base_url="https://api.deepseek.com",
+)
+
+
+def stream_generator(user_input: str, model: str):
+ try:
+ response = client.chat.completions.create(
+ model=model,
+ messages=[
+ {"role": "system", "content": "You are a helpful assistant"},
+ {"role": "user", "content": user_input},
+ ],
+ stream=True, # 关键:开启流式
+ reasoning_effort="high",
+ extra_body={"thinking": {"type": "enabled"}},
+ )
+
+ for chunk in response:
+ if not chunk.choices:
+ continue
+
+ delta = chunk.choices[0].delta
+
+ # DeepSeek 推理内容,如果有就单独发一个 reasoning 事件
+ reasoning = getattr(delta, "reasoning_content", None)
+ if reasoning:
+ yield f"event: reasoning\ndata: {json.dumps(reasoning, ensure_ascii=False)}\n\n"
+
+ # 最终回答内容
+ content = getattr(delta, "content", None)
+ if content:
+ yield f"data: {json.dumps(content, ensure_ascii=False)}\n\n"
+
+ yield "event: done\ndata: [DONE]\n\n"
+
+ except Exception as e:
+ yield f"event: server_error\ndata: {json.dumps(str(e), ensure_ascii=False)}\n\n"
+
+
+@app.get("/")
+def call_llm(user_input: str, model: str = "deepseek-v4-pro"):
+ return StreamingResponse(
+ stream_generator(user_input, model),
+ media_type="text/event-stream",
+ headers={
+ "Cache-Control": "no-cache",
+ "Connection": "keep-alive",
+ "X-Accel-Buffering": "no", # Nginx 下禁用缓冲
+ },
+ )
+
+
+if __name__ == "__main__":
+ import uvicorn
+
+ uvicorn.run(app, host="0.0.0.0", port=8001)
\ No newline at end of file
diff --git a/w1_d2/llm-api-demo/requirements.txt b/w1_d2/llm-api-demo/requirements.txt
new file mode 100644
index 0000000..f0dd0ae
--- /dev/null
+++ b/w1_d2/llm-api-demo/requirements.txt
@@ -0,0 +1 @@
+openai
\ No newline at end of file
diff --git a/w1_d2/teach_demo/main.py b/w1_d2/teach_demo/main.py
new file mode 100644
index 0000000..6d019f9
--- /dev/null
+++ b/w1_d2/teach_demo/main.py
@@ -0,0 +1,66 @@
+import os
+import json
+from fastapi import FastAPI
+from fastapi.responses import StreamingResponse
+from openai import OpenAI
+from dotenv import load_dotenv
+
+load_dotenv()
+
+app = FastAPI()
+
+client = OpenAI(
+ api_key=os.environ.get("DEEPSEEK_API_KEY"),
+ base_url="https://api.deepseek.com",
+)
+
+
+def stream_generator(user_input: str, model: str):
+ try:
+ response = client.chat.completions.create(
+ model=model,
+ messages=[
+ {"role": "system", "content": "You are a helpful assistant"},
+ {"role": "user", "content": user_input},
+ ],
+ stream=True,
+ # reasoning_effort 与 thinking 参数需按当前 DeepSeek 官方文档核验
+ reasoning_effort="high",
+ extra_body={"thinking": {"type": "enabled"}},
+ )
+
+ for chunk in response:
+ if not chunk.choices:
+ continue
+ delta = chunk.choices[0].delta
+
+ reasoning = getattr(delta, "reasoning_content", None)
+ if reasoning:
+ yield f"event: reasoning\ndata: {json.dumps(reasoning, ensure_ascii=False)}\n\n"
+
+ content = getattr(delta, "content", None)
+ if content:
+ yield f"data: {json.dumps(content, ensure_ascii=False)}\n\n"
+
+ yield "event: done\ndata: [DONE]\n\n"
+
+ except Exception as e:
+ yield f"event: server_error\ndata: {json.dumps(str(e), ensure_ascii=False)}\n\n"
+
+
+@app.get("/chat")
+def call_llm(user_input: str, model: str = "deepseek-chat"):
+ return StreamingResponse(
+ stream_generator(user_input, model),
+ media_type="text/event-stream",
+ headers={
+ "Cache-Control": "no-cache",
+ "Connection": "keep-alive",
+ "X-Accel-Buffering": "no",
+ },
+ )
+
+
+if __name__ == "__main__":
+ import uvicorn
+ uvicorn.run(app, host="0.0.0.0", port=8001)
\ No newline at end of file
diff --git a/w1_d3/0_yield_review.py b/w1_d3/0_yield_review.py
new file mode 100644
index 0000000..64db951
--- /dev/null
+++ b/w1_d3/0_yield_review.py
@@ -0,0 +1,42 @@
+def my_generator():
+ print("开始")
+ yield 1
+ print("继续")
+ yield 2
+ print("结束")
+ yield 3
+
+# g = my_generator() # 注意:此时函数体不会执行!
+# print(g,type(g)) #
+# # print(print,type(print))
+# print(next(g)) # 输出:开始 \n 1
+# print(next(g)) # 输出:继续 \n 2
+# print(next(g)) # 输出:结束 \n 3
+# # print(next(g)) # 榨干了
+
+# g2=my_generator()
+# for i in g2:
+# print(i)
+
+# print(len(g2)) # 生成器没有len方法
+
+
+# import time
+# def slow_generator():
+# for i in range(5):
+# yield f"第 {i+1} 条数据\n"
+# time.sleep(1) # 故意慢一点,方便观察
+#
+# g3=slow_generator()
+# for i in g3:
+# print(i)
+
+
+
+
+
+
+import json
+d=json.dumps('\n\n')
+print(d)
+# print('1\n\n2')
\ No newline at end of file
diff --git a/w1_d3/1_StreamingResponse.py b/w1_d3/1_StreamingResponse.py
new file mode 100644
index 0000000..11563a7
--- /dev/null
+++ b/w1_d3/1_StreamingResponse.py
@@ -0,0 +1,33 @@
+# main.py
+import time
+from fastapi import FastAPI
+from fastapi.responses import StreamingResponse
+
+app = FastAPI()
+def slow_generator():
+ for i in range(5):
+ yield f"第 {i+1} 条数据\n"
+ time.sleep(1) # 故意慢一点,方便观察
+
+@app.get("/non-stream")
+def stream():
+ return StreamingResponse(
+ slow_generator(),
+ media_type="text/plain", # 先用最简单的 text/plain
+ )
+
+@app.get("/stream")
+def stream():
+ return StreamingResponse(
+ slow_generator(),
+ media_type="text/event-stream", # 关键:改成 SSE 类型
+ headers={
+ "Cache-Control": "no-cache",
+ "Connection": "keep-alive",
+ "X-Accel-Buffering": "no", # Nginx 下禁用缓冲
+ },
+ )
+
+if __name__ == '__main__':
+ import uvicorn
+ uvicorn.run(app,host='127.0.0.1',port=8001)
\ No newline at end of file
diff --git a/w1_d3/2_index.html b/w1_d3/2_index.html
new file mode 100644
index 0000000..f30ecf0
--- /dev/null
+++ b/w1_d3/2_index.html
@@ -0,0 +1,146 @@
+
+
+
+
+
+ DeepSeek 流式对话
+
+
+
+ 💬 DeepSeek 流式对话
+
+ 等待输入…
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/w1_d3/2_sse.py b/w1_d3/2_sse.py
new file mode 100644
index 0000000..dbaa85f
--- /dev/null
+++ b/w1_d3/2_sse.py
@@ -0,0 +1,76 @@
+import os
+import json
+from fastapi import FastAPI
+from fastapi.responses import StreamingResponse
+from openai import OpenAI
+from dotenv import load_dotenv
+from starlette.middleware.cors import CORSMiddleware
+
+load_dotenv()
+
+app = FastAPI()
+
+client = OpenAI(
+ api_key=os.environ.get("DEEPSEEK_API_KEY"),
+ base_url="https://api.deepseek.com",
+)
+
+app.add_middleware(
+ CORSMiddleware,
+ allow_origins=["*"], # 生产环境改成具体域名
+ allow_methods=["*"],
+ allow_headers=["*"],
+)
+
+
+def stream_generator(user_input: str, model: str):
+ try:
+ response = client.chat.completions.create(
+ model=model,
+ messages=[
+ {"role": "system", "content": "You are a helpful assistant"},
+ {"role": "user", "content": user_input},
+ ],
+ stream=True,
+ # reasoning_effort 与 thinking 参数需按当前 DeepSeek 官方文档核验
+ reasoning_effort="high",
+ extra_body={"thinking": {"type": "enabled"}},
+ )
+
+ for chunk in response:
+ if not chunk.choices:
+ continue
+ delta = chunk.choices[0].delta
+ import time
+ time.sleep(0.5)
+
+ reasoning = getattr(delta, "reasoning_content", None)
+ if reasoning:
+ yield f"event: reasoning\ndata: {json.dumps(reasoning, ensure_ascii=False)}\n\n"
+
+ content = getattr(delta, "content", None)
+ if content:
+ yield f"event: content\ndata: {json.dumps(content, ensure_ascii=False)}\n\n"
+
+ yield "event: done\ndata: [DONE]\n\n"
+
+ except Exception as e:
+ yield f"event: server_error\ndata: {json.dumps(str(e), ensure_ascii=False)}\n\n"
+
+
+@app.get("/chat")
+def call_llm(user_input: str, model: str = "deepseek-chat"):
+ return StreamingResponse(
+ stream_generator(user_input, model),
+ media_type="text/event-stream",
+ headers={
+ "Cache-Control": "no-cache",
+ "Connection": "keep-alive",
+ "X-Accel-Buffering": "no",
+ },
+ )
+
+
+if __name__ == "__main__":
+ import uvicorn
+ uvicorn.run(app, host="0.0.0.0", port=8001)
\ No newline at end of file
diff --git a/w1_d3/3_toolcalls.py b/w1_d3/3_toolcalls.py
new file mode 100644
index 0000000..eab83d0
--- /dev/null
+++ b/w1_d3/3_toolcalls.py
@@ -0,0 +1,55 @@
+from openai import OpenAI
+
+client = OpenAI(
+ api_key='sk-83c3ebe6b1b04bdf93c3c4be9b17736d',
+ base_url="https://api.deepseek.com",
+)
+
+
+def send_messages(messages,model="deepseek-flash"):
+ response = client.chat.completions.create(
+ model=model,
+ messages=messages,
+ tools=tools
+ )
+ return response.choices[0].message
+
+
+tools = [
+ {
+ "type": "function",
+ "function": {
+ "name": "get_weather",
+ "description": "Get weather of a location, the user should supply a location first.",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "location": {
+ "type": "string",
+ "description": "The city and state, e.g. San Francisco, CA",
+ }
+ },
+ "required": ["location"]
+ },
+ }
+ },
+]
+
+messages = [{"role": "user", "content": "How's the weather in Hangzhou, Zhejiang?"}]
+AI_message = send_messages(messages)
+print(AI_message,type(AI_message))
+print(f"User>\t {messages[0]['content']}")
+print(f"AI>\t {AI_message.content}")
+# AI_message_dict={"role": "assitant", "content": "I'll check the current weather in Hangzhou, Zhejiang for you."}
+tool = AI_message.tool_calls[0]
+messages.append(AI_message)
+# messages.append(AI_message_dict)
+# =================================
+# 调用函数返回结果
+tool_result={"role": "tool", "tool_call_id": tool.id, "content": "24℃"}
+# =================================
+
+messages.append(tool_result)
+print(messages)
+message = send_messages(messages)
+print(f"Model>\t {message.content}")
\ No newline at end of file
diff --git a/w1_d3/4_toolcalls2.py b/w1_d3/4_toolcalls2.py
new file mode 100644
index 0000000..c383bb0
--- /dev/null
+++ b/w1_d3/4_toolcalls2.py
@@ -0,0 +1,85 @@
+from openai import OpenAI
+import os
+from dotenv import load_dotenv
+
+load_dotenv()
+
+client = OpenAI(
+ api_key=os.environ.get("DEEPSEEK_API_KEY"),
+ base_url="https://api.deepseek.com",
+)
+
+# 1. 定义一个获取天气的工具
+tools = [
+ {
+ "type": "function",
+ "function": {
+ "name": "get_weather",
+ "description": "获取指定城市的天气",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "location": {"type": "string", "description": "城市名,如杭州"},
+ },
+ "required": ["location"],
+ },
+ },
+ }
+]
+
+# 2. 用户提问
+messages = [{"role": "user", "content": "你好,杭州的天气怎么样"}]
+
+# 第一次调用模型:模型会返回 tool_calls
+response = client.chat.completions.create(
+ model="deepseek-v4-pro", # 换成你实际可用的模型名,如 deepseek-v4-pro
+ messages=messages,
+ tools=tools, # 传入工具列表
+)
+
+# 获取模型的回复(通常包含 tool_calls)
+assistant_msg = response.choices[0].message
+print(assistant_msg)
+print(assistant_msg.model_dump_json(indent=2))
+print(assistant_msg.content)
+print("模型第一次回复:", assistant_msg.content)
+
+
+if assistant_msg.tool_calls:
+ name=assistant_msg.tool_calls[0].function.name
+ print(name)
+ import json
+ r=json.loads(assistant_msg.tool_calls[0].function.arguments)
+ print(r)
+ arg=r.get('location')
+ print(arg)
+ tool_id=assistant_msg.tool_calls[0].id
+ print(tool_id)
+
+
+ name2=assistant_msg.tool_calls[1].function.name
+ print(name)
+ import json
+ r2=json.loads(assistant_msg.tool_calls[1].function.arguments)
+ print(r)
+ arg2=r.get('location')
+ print(arg)
+ tool_id2=assistant_msg.tool_calls[1].id
+ print(tool_id)
+
+def get_weather(location: str) -> str:
+ return f"{location}的天气为 880℃"
+
+tools_map={'get_weather':get_weather}
+tools_result=tools_map.get(name)(**r)
+tools_result=tools_map.get(name2)(**r2)
+print(tools_result)
+messages.append(assistant_msg)
+messages.append({'role':"tool","tool_call_id": tool_id,'content':tools_result})
+
+response = client.chat.completions.create(
+ model="deepseek-v4-pro", # 换成你实际可用的模型名,如 deepseek-v4-pro
+ messages=messages,
+ tools=tools, # 传入工具列表
+)
+print("模型第二次回复:", response.choices[0].message.content)
diff --git a/w1_d3/5_toolcalls3.py b/w1_d3/5_toolcalls3.py
new file mode 100644
index 0000000..19f84ca
--- /dev/null
+++ b/w1_d3/5_toolcalls3.py
@@ -0,0 +1,86 @@
+from openai import OpenAI
+import os
+from dotenv import load_dotenv
+
+load_dotenv()
+
+client = OpenAI(
+ api_key=os.environ.get("DEEPSEEK_API_KEY"),
+ base_url="https://api.deepseek.com",
+)
+
+# 1. 定义一个获取天气的工具
+tools = [
+ {
+ "type": "function",
+ "function": {
+ "name": "get_weather",
+ "description": "获取指定城市的天气",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "location": {"type": "string", "description": "城市名,如杭州"},
+ },
+ "required": ["location"],
+ },
+ },
+ }
+]
+
+# 2. 用户提问
+messages = [{"role": "user", "content": "你好,杭州和深圳的天气怎么样"}]
+
+# 第一次调用模型:模型会返回 tool_calls
+response = client.chat.completions.create(
+ model="deepseek-v4-pro", # 换成你实际可用的模型名,如 deepseek-v4-pro
+ messages=messages,
+ tools=tools, # 传入工具列表
+)
+
+# 获取模型的回复(通常包含 tool_calls)
+assistant_msg = response.choices[0].message
+print(assistant_msg)
+print(assistant_msg.model_dump_json(indent=2))
+print(assistant_msg.content)
+print("模型第一次回复:", assistant_msg.content)
+
+
+if assistant_msg.tool_calls:
+ name=assistant_msg.tool_calls[0].function.name
+ print(name)
+ import json
+ r=json.loads(assistant_msg.tool_calls[0].function.arguments)
+ print(r)
+ arg=r.get('location')
+ print(arg)
+ tool_id=assistant_msg.tool_calls[0].id
+ print(tool_id)
+
+
+ name2=assistant_msg.tool_calls[1].function.name
+ print(name2)
+ import json
+ r2=json.loads(assistant_msg.tool_calls[1].function.arguments)
+ print(r2)
+ arg2=r2.get('location')
+ print(arg2)
+ tool_id2=assistant_msg.tool_calls[1].id
+ print(tool_id2)
+
+def get_weather(location: str) -> str:
+ return f"{location}的天气为 880℃"
+
+tools_map={'get_weather':get_weather}
+tools_result=tools_map.get(name)(**r)
+tools_result2=tools_map.get(name2)(**r2)
+print(tools_result)
+messages.append(assistant_msg)
+messages.append({'role':"tool","tool_call_id": tool_id,'content':tools_result})
+messages.append({'role':"tool","tool_call_id": tool_id2,'content':tools_result2})
+
+response = client.chat.completions.create(
+ model="deepseek-v4-pro", # 换成你实际可用的模型名,如 deepseek-v4-pro
+ messages=messages,
+ tools=tools, # 传入工具列表
+)
+print("模型第二次回复:", response.choices[0].message.content)
diff --git a/w1_d3/6_toolcalls4.py b/w1_d3/6_toolcalls4.py
new file mode 100644
index 0000000..e57968a
--- /dev/null
+++ b/w1_d3/6_toolcalls4.py
@@ -0,0 +1,85 @@
+from openai import OpenAI
+import os
+from dotenv import load_dotenv
+
+load_dotenv()
+
+client = OpenAI(
+ api_key=os.environ.get("DEEPSEEK_API_KEY"),
+ base_url="https://api.deepseek.com",
+)
+
+# 1. 定义一个获取天气的工具
+tools = [
+ {
+ "type": "function",
+ "function": {
+ "name": "get_weather",
+ "description": "获取指定城市的天气",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "location": {"type": "string", "description": "城市名,如杭州"},
+ },
+ "required": ["location"],
+ },
+ },
+ }
+]
+
+# 2. 用户提问
+messages = [{"role": "user", "content": "你好,杭州和深圳和北京的天气怎么样"}]
+
+# 第一次调用模型:模型会返回 tool_calls
+response = client.chat.completions.create(
+ model="deepseek-v4-pro", # 换成你实际可用的模型名,如 deepseek-v4-pro
+ messages=messages,
+ tools=tools, # 传入工具列表
+)
+
+# 获取模型的回复(通常包含 tool_calls)
+assistant_msg = response.choices[0].message
+print(assistant_msg)
+print(assistant_msg.model_dump_json(indent=2))
+print(assistant_msg.content)
+print("模型第一次回复:", assistant_msg.content)
+
+def get_weather(location: str) -> str:
+ return f"{location}的天气为 8℃"
+tools_map={'get_weather':get_weather}
+messages.append(assistant_msg)
+if assistant_msg.tool_calls:
+ # for i in range(len(assistant_msg.tool_calls)):
+ # name=assistant_msg.tool_calls[i].function.name
+ # print(name)
+ # import json
+ # r=json.loads(assistant_msg.tool_calls[i].function.arguments)
+ # print(r)
+ # arg=r.get('location')
+ # print(arg)
+ # tool_id=assistant_msg.tool_calls[i].id
+ # print(tool_id)
+ # tools_result = tools_map.get(name)(**r)
+ # messages.append({'role': "tool", "tool_call_id": tool_id, 'content': tools_result})
+
+ for tool_call in assistant_msg.tool_calls:
+ name=tool_call.function.name
+ print(name)
+ import json
+ r=json.loads(tool_call.function.arguments)
+ print(r)
+ arg=r.get('location')
+ print(arg)
+ tool_id=tool_call.id
+ print(tool_id)
+ tools_result = tools_map.get(name)(**r)
+ messages.append({'role': "tool", "tool_call_id": tool_id, 'content': tools_result})
+
+
+
+response = client.chat.completions.create(
+ model="deepseek-v4-pro", # 换成你实际可用的模型名,如 deepseek-v4-pro
+ messages=messages,
+ tools=tools, # 传入工具列表
+)
+print("模型第二次回复:", response.choices[0].message.content)
diff --git a/w1_d3/7_toolcalls5.py b/w1_d3/7_toolcalls5.py
new file mode 100644
index 0000000..e19baaf
--- /dev/null
+++ b/w1_d3/7_toolcalls5.py
@@ -0,0 +1,101 @@
+from openai import OpenAI
+import os
+import json
+from dotenv import load_dotenv
+
+load_dotenv()
+
+client = OpenAI(
+ api_key=os.environ.get("DEEPSEEK_API_KEY"),
+ base_url="https://api.deepseek.com",
+)
+
+# 1. 定义一个获取天气的工具
+tools = [
+ {
+ "type": "function",
+ "function": {
+ "name": "get_weather",
+ "description": "获取指定城市的天气",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "location": {"type": "string", "description": "城市名,如杭州"},
+ },
+ "required": ["location"],
+ },
+ },
+ }
+]
+
+# 工具实现
+def get_weather(location: str) -> str:
+ return f"{location}的天气为 8℃"
+
+tools_map = {'get_weather': get_weather}
+
+# ====================== 【新增:工具执行函数】======================
+def execute_tool_calls(tool_calls, tools_map: dict) -> list:
+ """
+ 执行模型返回的tool_calls,返回tool角色消息列表,用于追加到messages
+ :param tool_calls: response.choices[0].message.tool_calls
+ :param tools_map: 工具名字 -> 函数 的映射字典
+ :return: list[dict] tool消息数组
+ """
+ tool_messages = []
+ for tool_call in tool_calls:
+ func_name = tool_call.function.name
+ print(f"调用工具:{func_name}")
+ # 解析参数
+ args = json.loads(tool_call.function.arguments)
+ print(f"参数:{args}")
+ # 获取工具函数并执行
+ func = tools_map[func_name]
+ result = func(**args)
+ # 组装tool消息
+ tool_msg = {
+ "role": "tool",
+ "tool_call_id": tool_call.id,
+ "content": result
+ }
+ tool_messages.append(tool_msg)
+ return tool_messages
+# ==================================================================
+
+# 2. 用户提问
+messages = [{"role": "user", "content": "你好,杭州和深圳和北京的天气怎么样"}]
+
+# 第一次调用模型:模型会返回 tool_calls
+response = client.chat.completions.create(
+ model="deepseek-v4-pro",
+ messages=messages,
+ tools=tools,
+)
+
+# 获取模型的回复
+assistant_msg = response.choices[0].message
+print(assistant_msg)
+print(assistant_msg.model_dump_json(indent=2))
+print(assistant_msg.content)
+print("模型第一次回复:", assistant_msg.content)
+
+# 把assistant消息放进对话上下文
+messages.append(assistant_msg)
+
+# 如果存在工具调用,执行工具
+if assistant_msg.tool_calls:
+ # 调用封装好的函数,拿到tool消息列表
+ tool_msg_list = execute_tool_calls(assistant_msg.tool_calls, tools_map)
+ # 批量追加tool结果到对话
+ messages.extend(tool_msg_list)
+
+ # 第二次请求模型,传入工具返回结果
+ response = client.chat.completions.create(
+ model="deepseek-v4-pro",
+ messages=messages,
+ tools=tools,
+ )
+ print("模型第二次回复:", response.choices[0].message.content)
+
+# 思考题:如何让你的程序 实现自己判断是否还需要再次请求大模型的调用
+# 参考思路:当大模型不再需要工具调用的时候就结束大模型请求
\ No newline at end of file
diff --git a/w1_d3/8_toolcalls6.py b/w1_d3/8_toolcalls6.py
new file mode 100644
index 0000000..74adfdb
--- /dev/null
+++ b/w1_d3/8_toolcalls6.py
@@ -0,0 +1,78 @@
+from openai import OpenAI
+import os
+import json
+import requests
+from dotenv import load_dotenv
+
+load_dotenv()
+
+client = OpenAI(
+ api_key=os.environ.get("DEEPSEEK_API_KEY"),
+ base_url="https://api.deepseek.com",
+)
+
+# 1. 定义一个获取天气的工具
+tools = [
+ {
+ "type": "function",
+ "function": {
+ "name": "get_weather",
+ "description": "获取指定城市的天气",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "location": {"type": "string", "description": "城市名,如杭州"},
+ },
+ "required": ["location"],
+ },
+ },
+ }
+]
+
+# 2. 用户提问
+messages = [{"role": "user", "content": "杭州天气怎么样?"}]
+
+# 第一次调用模型:模型会返回 tool_calls
+response = client.chat.completions.create(
+ model="deepseek-chat", # 换成你实际可用的模型名,如 deepseek-v4-pro
+ messages=messages,
+ tools=tools, # 传入工具列表
+)
+
+# 获取模型的回复(通常包含 tool_calls)
+assistant_msg = response.choices[0].message
+print("模型第一次回复:", assistant_msg)
+
+# 3. 将模型的回复加入对话历史(必须转换为字典,否则 API 会报错)
+messages.append(assistant_msg.model_dump()) # 或 dict(assistant_msg)
+
+
+def get_weather(location: str) -> str:
+ """调用高德地图天气API查询真实天气"""
+ url = "https://restapi.amap.com/v3/weather/weatherInfo"
+ params = {
+ "key": os.getenv("GAODE_API_KEY"),
+ "city": location,
+ "extensions": "all",
+ "output": "json"
+ }
+ response = requests.get(url, params=params)
+ data = response.json()
+ return json.dumps(data, ensure_ascii=False, indent=2)
+
+# 4. 执行工具调用
+if assistant_msg.tool_calls:
+ tool_call = assistant_msg.tool_calls[0]
+ args = json.loads(tool_call.function.arguments)
+ result = get_weather(args["location"])
+ tool_result = {"role": "tool", "tool_call_id": tool_call.id, "content": result}
+ messages.append(tool_result)
+
+# 5. 第二次调用模型,将工具返回的结果发给模型,生成最终回答
+final_response = client.chat.completions.create(
+ model="deepseek-chat",
+ messages=messages,
+ tools=tools,
+)
+final_answer = final_response.choices[0].message.content
+print("最终回答:", final_answer)
\ No newline at end of file
diff --git a/w1_d3/9.py b/w1_d3/9.py
new file mode 100644
index 0000000..6924aed
--- /dev/null
+++ b/w1_d3/9.py
@@ -0,0 +1,125 @@
+import smtplib
+from email.mime.text import MIMEText
+from openai import OpenAI
+import os
+import json
+from dotenv import load_dotenv
+
+load_dotenv()
+
+client = OpenAI(
+ api_key=os.environ.get("DEEPSEEK_API_KEY"),
+ base_url="https://api.deepseek.com",
+)
+
+# 1. 定义工具描述
+tools = [
+ {
+ "type": "function",
+ "function": {
+ "name": "get_weather",
+ "description": "获取指定城市的天气",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "location": {"type": "string", "description": "城市名,如杭州"},
+ },
+ "required": ["location"],
+ },
+ },
+ },
+ {
+ "type": "function",
+ "function": {
+ "name": "send_email_qq",
+ "description": "使用QQ邮箱SMTP发送纯文本邮件",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "text": {"type": "string", "description": "邮件正文内容"},
+ "subject": {"type": "string", "description": "邮件主题"},
+ },
+ "required": ["text", "subject"],
+ },
+ },
+ }
+]
+
+# 工具实现
+def get_weather(location: str) -> str:
+ return f"{location}的天气为 8℃"
+
+def send_email_qq(text, subject):
+ mail_host = "smtp.qq.com"
+ mail_port = 465
+ mail_user = "wolin105@qq.com"
+ mail_pass = "pingnllumhbzbceg" # QQ邮箱授权码
+ sender = mail_user
+ receivers = "jzk.jie@qq.com"
+
+ message = MIMEText(text, 'plain', 'utf-8')
+ message["From"] = sender
+ message["To"] = receivers
+ message["Subject"] = subject
+
+ try:
+ smtp = smtplib.SMTP_SSL(mail_host, mail_port)
+ smtp.login(mail_user, mail_pass)
+ smtp.sendmail(sender, [receivers], message.as_string())
+ smtp.quit()
+ print("邮件发送成功")
+ return "邮件发送成功"
+ except Exception as e:
+ err_msg = f"邮件发送失败: {e}"
+ print(err_msg)
+ return err_msg
+
+tools_map = {'get_weather': get_weather, 'send_email_qq': send_email_qq}
+
+def execute_tool_calls(tool_calls, tools_map: dict) -> list:
+ """执行模型返回的tool_calls,返回tool角色消息字典列表"""
+ tool_messages = []
+ for tool_call in tool_calls:
+ func_name = tool_call.function.name
+ print(f"\n调用工具:{func_name}")
+ args = json.loads(tool_call.function.arguments)
+ print(f"参数:{args}")
+ func = tools_map[func_name]
+ result = func(**args)
+ tool_msg = {
+ "role": "tool",
+ "tool_call_id": tool_call.id,
+ "content": result
+ }
+ tool_messages.append(tool_msg)
+ return tool_messages
+
+
+if __name__ == "__main__":
+ messages = [
+ {"role": "user", "content": "帮我发一个邮件,邮件内容是描述今天学了functioncalling的心得,主题是学习心得,只输出文本即可"}
+ ]
+
+ # ✅ while循环自动多轮工具调用,直到模型不再返回tool_calls
+ while True:
+ response = client.chat.completions.create(
+ model="deepseek-v4-pro",
+ messages=messages,
+ tools=tools,
+ )
+ assistant_msg = response.choices[0].message
+ print("\n=====模型返回assistant消息对象=====")
+ print(assistant_msg)
+
+ # ✅ 关键修复:转成字典,再追加到messages,不能直接append对象!
+ messages.append(assistant_msg.model_dump())
+
+ # 判断是否还有工具调用
+ if not assistant_msg.tool_calls:
+ # 没有工具调用,拿到最终回答,退出循环
+ print("\n模型最终回复:", assistant_msg.content)
+ break
+
+ # 执行工具,拿到tool消息
+ tool_msg_list = execute_tool_calls(assistant_msg.tool_calls, tools_map)
+ messages.extend(tool_msg_list)
diff --git a/w1_d3/99_requests_deepseek_api.py b/w1_d3/99_requests_deepseek_api.py
new file mode 100644
index 0000000..9aac26d
--- /dev/null
+++ b/w1_d3/99_requests_deepseek_api.py
@@ -0,0 +1,38 @@
+import requests
+import json
+
+url = "https://api.deepseek.com/responses"
+
+payload = json.dumps({
+ "model": "deepseek-flash",
+ "input": "你好",
+ "instructions": "string",
+ "reasoning": {
+ "effort": "none"
+ },
+ "max_output_tokens": 4096,
+ "stream": False,
+ "temperature": 1,
+ "top_p": 1,
+ "text": {
+ "format": {
+ "type": "text",
+ "name": "string",
+ "schema": {}
+ }
+ },
+ "tools": None,
+ "tool_choice": "none",
+ "top_logprobs": None,
+ "user": "string"
+})
+print(payload,type(payload))
+headers = {
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json',
+ 'Authorization': 'Bearer sk-83c3ebe6b1b04bdf93c3c4be9b17736d'
+}
+
+response = requests.request("POST", url, headers=headers, data=payload)
+
+print(response.text)
\ No newline at end of file
diff --git a/w1_d3/base_func.py b/w1_d3/base_func.py
new file mode 100644
index 0000000..77c7873
--- /dev/null
+++ b/w1_d3/base_func.py
@@ -0,0 +1,38 @@
+#
+# def get_weather(location):
+# return f"{location}的天气为 30℃"
+#
+#
+# r=get_weather('sz')
+# print(r)
+#
+# # 字符串 映射 对象
+# d2={'get_weather':get_weather}
+# print(d2['get_weather'])
+# print(d2.get('get_weather'))
+#
+# # 方式1: 使用中间变量
+# f=d2.get('get_weather')
+# r=f('sz')
+# print(r)
+#
+# # 方式2: 直接一步到位
+# r=d2.get('get_weather')('sz')
+# print(r)
+#
+# args={'location':'sz'}
+# print(get_weather(**args))
+
+
+# def get_weather(location,province):
+# return f"{province}{location}的天气为 30℃"
+#
+# ars={'location':'sz','province':'gd'}
+# print(get_weather(**ars))
+# print(get_weather(location='sz',province='gd'))
+
+MES=['user','ai']
+L=['tool1','tool2','tool3']
+# MES.append(L)
+MES.extend(L)
+print(MES)
\ No newline at end of file
diff --git a/w1_d3/gode_get_weather.py b/w1_d3/gode_get_weather.py
new file mode 100644
index 0000000..3fcdaab
--- /dev/null
+++ b/w1_d3/gode_get_weather.py
@@ -0,0 +1,35 @@
+import requests, json
+import os
+from dotenv import load_dotenv
+
+load_dotenv(override=True)
+
+# key='8e3ff61eecb810dcce3bc5377b739222'
+def get_weather(city):
+ """
+ 查询高德地图天气函数
+ :param city_adcode: 必要参数,字符串类型,城市的 adcode 编码,例如北京市是 110000
+ :return:高德地图天气 API 查询结果,JSON 格式字符串,包含实况/预报天气信息
+ """
+ # Step 1. 高德地图天气 API 地址
+ url = "https://restapi.amap.com/v3/weather/weatherInfo"
+
+ # Step 2. 设置请求参数(完全按高德官方要求)
+ params = {
+ "key": os.getenv("GAODE_API_KEY"), # 高德 Web 服务 API Key
+ # "key": key, # 高德 Web 服务 API Key
+ "city": city, # 城市
+ "extensions": "all", # base=实况天气,all=预报天气
+ "output": "json" # 返回 JSON 格式
+ }
+
+ # Step 3. 发送 GET 请求
+ response = requests.get(url, params=params)
+
+ # Step 4. 解析响应并返回 JSON 字符串
+ data = response.json()
+ return json.dumps(data, ensure_ascii=False, indent=2)
+
+print(get_weather("深圳")) # 查询深圳天气
+print(get_weather("北京")) # 查询北京天气
+print(get_weather("乌鲁木齐")) # 查询乌鲁木齐天气
\ No newline at end of file
diff --git a/w1_d3/object_property.py b/w1_d3/object_property.py
new file mode 100644
index 0000000..8d0e2ca
--- /dev/null
+++ b/w1_d3/object_property.py
@@ -0,0 +1,57 @@
+from dataclasses import dataclass
+
+# 最内层:人
+@dataclass
+class Person:
+ name: str
+ age: int
+ job: str
+
+# 城市:里面包含 Person 对象
+@dataclass
+class City:
+ city_name: str
+ people: Person # 成员是 Person 对象
+
+# 省份:里面包含城市列表
+@dataclass
+class Province:
+ province_name: str
+ city_list: list[City]
+
+# 最外层顶级对象 Country,对标 LLM 的 res 返回对象
+@dataclass
+class Country:
+ country_name: str
+ province_list: list[Province]
+# 先造最内层的人
+p = Person(name="张三", age=20, job="程序员")
+
+# 造城市,把人塞进去
+hz = City(city_name="杭州市", people=p)
+
+# 造省份,把城市放进列表
+zj = Province(province_name="浙江省", city_list=[hz])
+
+# 顶级大对象:整个中国,对标 res
+china = Country(
+ country_name="中国",
+ province_list=[zj]
+)
+# 直接打印顶级对象 dataclass 友好一点,但依然不能直接拿内层数据
+print(china)
+
+# 逐层拆解,和 LLM 取值一一对应
+# 1.取省份列表
+provinces = china.province_list
+# 2.取第0个省份
+zhejiang = provinces[0]
+# 3.取该省第0个城市
+hangzhou = zhejiang.city_list[0]
+# 4.拿到人对象,取 name
+person_name = hangzhou.people.name
+
+print(person_name) # 张三
+print(hangzhou.people.age) # 20
+result = china.province_list[0].city_list[0].people.name
+print(result)
diff --git a/w1_d3/property.py b/w1_d3/property.py
new file mode 100644
index 0000000..f009cc1
--- /dev/null
+++ b/w1_d3/property.py
@@ -0,0 +1,35 @@
+from functools import cached_property
+
+class Person:
+ def __init__(self, height, bmi):
+ self.height = height
+ self.bmi = bmi
+
+ @cached_property
+ def weight(self):
+ print("====正在执行复杂计算====")
+ return self.height ** 2 * self.bmi
+
+
+p = Person(1.75, 22)
+
+# 第一次访问:执行函数,打印日志,保存结果
+print(p.weight)
+# 第二次访问:直接读缓存!不会打印日志,不重新计算
+print(p.weight)
+print(p.weight)
+
+
+class Person2:
+ def __init__(self, height, bmi):
+ self.height = height
+ self.bmi = bmi
+
+ @property
+ def weight(self):
+ print("====每次都重新计算====")
+ return self.height ** 2 * self.bmi
+
+p2 = Person2(1.75,22)
+print(p2.weight)
+print(p2.weight)
diff --git a/w1_d3/send_email_qq.py b/w1_d3/send_email_qq.py
new file mode 100644
index 0000000..20e5f17
--- /dev/null
+++ b/w1_d3/send_email_qq.py
@@ -0,0 +1,54 @@
+import smtplib
+from email.mime.text import MIMEText
+
+
+
+# Please install OpenAI SDK first: `pip3 install openai`
+import os
+from openai import OpenAI
+from dotenv import load_dotenv
+load_dotenv()
+client = OpenAI(
+ api_key=os.environ.get('DEEPSEEK_API_KEY'),
+ base_url="https://api.deepseek.com")
+
+response = client.chat.completions.create(
+ model="deepseek-v4-pro",
+ messages=[
+ {"role": "user", "content": "帮我写三句幽默笑话,以国伟不要开头"},
+ ],
+ stream=False,
+ reasoning_effort="high",
+ extra_body={"thinking": {"type": "enabled"}}
+)
+
+
+text=response.choices[0].message.content
+print(text)
+
+
+def send_email_qq(text,subject):
+ mail_host = "smtp.qq.com" # 官方指定
+ mail_port = 465
+ mail_user = "wolin105@qq.com"
+ mail_pass = "pingnllumhbzbceg" # 注意:不是登录密码
+ sender = mail_user
+ receivers = "1426833948@qq.com"
+
+
+
+ message = MIMEText(text, 'plain', 'utf-8')
+ message["From"] = sender
+ message["To"] = receivers
+ message["Subject"] = subject
+
+ try:
+ smtp = smtplib.SMTP_SSL(mail_host, mail_port)
+ smtp.login(mail_user, mail_pass)
+ smtp.sendmail(sender, [receivers], message.as_string())
+ smtp.quit()
+ print("邮件发送成功")
+ except Exception as e:
+ print(f"邮件发送失败: {e}")
+
+send_email_qq(text,'笑话')
\ No newline at end of file
diff --git a/zky.png b/zky.png
new file mode 100644
index 0000000..e6e6536
Binary files /dev/null and b/zky.png differ