leon 1 mesiac pred
rodič
commit
6521c53c45

+ 0 - 10
langchain/.gitignore

@@ -1,10 +0,0 @@
-# Python-generated files
-__pycache__/
-*.py[oc]
-build/
-dist/
-wheels/
-*.egg-info
-
-# Virtual environments
-.venv

+ 0 - 1
langchain/.python-version

@@ -1 +0,0 @@
-3.11

+ 0 - 0
langchain/README.md


+ 0 - 6
langchain/main.py

@@ -1,6 +0,0 @@
-def main():
-    print("Hello from 02-langchain!")
-
-
-if __name__ == "__main__":
-    main()

+ 0 - 7
langchain/pyproject.toml

@@ -1,7 +0,0 @@
-[project]
-name = "02-langchain"
-version = "0.1.0"
-description = "Add your description here"
-readme = "README.md"
-requires-python = ">=3.11"
-dependencies = []

+ 0 - 652
langchain/test.ipynb

@@ -1,652 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "code",
-   "execution_count": 9,
-   "id": "03d8e409",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "微积分是研究函数的变化率(微分)与累积量(积分)及其相互关系的数学分支。\n"
-     ]
-    }
-   ],
-   "source": [
-    "from langchain_openai import ChatOpenAI\n",
-    "from dotenv import load_dotenv\n",
-    "import os\n",
-    "\n",
-    "api_key = os.getenv('OPENAI_API_KEY')\n",
-    "\n",
-    "# 创建 DeepSeek 聊天模型实例\n",
-    "# base_url 指向 DeepSeek 的兼容端点,而非 OpenAI 官方地址\n",
-    "load_dotenv()\n",
-    "llm = ChatOpenAI(\n",
-    "    model_name=\"deepseek-v4-flash\",              # DeepSeek 的对话模型\n",
-    "    api_key=api_key,                    # 在 platform.deepseek.com 获取\n",
-    "    base_url=\"https://api.deepseek.com\"      # DeepSeek API 地址\n",
-    ")\n",
-    "\n",
-    "# invoke 是 LangChain 统一的调用方法,返回 AIMessage 对象\n",
-    "response = llm.invoke(\"用一句话解释什么是微积分\")\n",
-    "print(response.content)  # .content 拿到纯文本"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 3,
-   "id": "366dc781",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "装饰器(Decorator)在你看来可能挺唬人,但说白了它就是“给函数穿衣服”——在不改变函数本身代码的前提下,给函数加一些额外的功能,比如记录日志、计算运行时间、校验权限等。\n",
-      "\n",
-      "想象一下:你有一个非常简单的函数,它只是说“你好”。如果每次调用这个函数之前,你都想先确认一下对方有没有权限(比如是否登录),你不想改动函数内部的代码(因为可能有很多地方都用它),那就可以写一个“包装器”函数,把这个“你好”函数像礼物一样包起来,在这个包装器里先做权限检查,再调用原函数。这个包装器就是**装饰器**。\n",
-      "\n",
-      "Python 里的装饰器用 `@` 符号放在函数定义上面,像这样:\n",
-      "\n",
-      "```python\n",
-      "def decorator(func):\n",
-      "    def wrapper():\n",
-      "        print(\"检查权限...\")  # 额外功能\n",
-      "        func()               # 调用原函数\n",
-      "        print(\"记录日志...\")  # 额外功能\n",
-      "    return wrapper\n",
-      "\n",
-      "@decorator\n",
-      "def say_hello():\n",
-      "    print(\"你好\")\n",
-      "```\n",
-      "\n",
-      "当你调用 `say_hello()` 时,实际上执行的是装饰器内部的 `wrapper` 函数,它会先打印“检查权限…”,然后打印“你好”,最后打印“记录日志…”。而 `say_hello` 本身的代码完全没有被改动过。\n",
-      "\n",
-      "所以,装饰器就是一个**高阶函数**(接收函数作为参数),它内部定义一个新函数(包装函数),在新函数中加入额外操作,然后返回这个新函数。Python 的 `@` 语法糖只是让你写起来更方便——本质上就是 `say_hello = decorator(say_hello)` 这一步的简写。\n",
-      "\n",
-      "**一句话总结**:装饰器就是给函数“套个壳”,在不改原函数代码的前提下,让函数拥有新的技能。\n"
-     ]
-    }
-   ],
-   "source": [
-    "from langchain_core.messages import SystemMessage, HumanMessage\n",
-    "\n",
-    "# SystemMessage:设定模型的\"人设\",相当于给它一个角色卡\n",
-    "# HumanMessage:用户说的话\n",
-    "# AIMessage:模型之前的回答(用于多轮对话)\n",
-    "\n",
-    "messages = [\n",
-    "    SystemMessage(content=\"你是一个资深的 Python 技术博主,擅长用大白话解释概念\"),\n",
-    "    HumanMessage(content=\"解释一下什么是装饰器?\"),\n",
-    "]\n",
-    "\n",
-    "response = llm.invoke(messages)\n",
-    "print(response.content)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 10,
-   "id": "3ef122de",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "片名:星际穿越(Interstellar)\n",
-      "年份:2014\n",
-      "导演:克里斯托弗·诺兰\n",
-      "评分:8.6\n"
-     ]
-    }
-   ],
-   "source": [
-    "from pydantic import BaseModel, Field\n",
-    "from langchain.chat_models import init_chat_model\n",
-    "\n",
-    "# 定义你期望的输出结构(Pydantic 模型)\n",
-    "class MovieInfo(BaseModel):\n",
-    "    \"\"\"电影信息\"\"\"\n",
-    "    title: str = Field(description=\"电影名称\")\n",
-    "    year: int = Field(description=\"上映年份\")\n",
-    "    director: str = Field(description=\"导演\")\n",
-    "    rating: float = Field(description=\"评分(10分制)\")\n",
-    "\n",
-    "llm = init_chat_model(\n",
-    "    model=\"qwen-plus\",\n",
-    "    model_provider=\"openai\",\n",
-    "    api_key=os.getenv('QWEN_API_KEY'),\n",
-    "    base_url=\"https://dashscope.aliyuncs.com/compatible-mode/v1\"\n",
-    ")\n",
-    "\n",
-    "# .with_structured_output() 会自动把 Schema 注入 prompt,\n",
-    "# 并在底层做 JSON 解析和类型校验\n",
-    "structured_llm = llm.with_structured_output(MovieInfo)\n",
-    "\n",
-    "result = structured_llm.invoke(\"介绍一下电影《星际穿越》\")\n",
-    "\n",
-    "# 返回的是 MovieInfo 对象,可以直接用属性访问\n",
-    "print(f\"片名:{result.title}\")\n",
-    "print(f\"年份:{result.year}\")\n",
-    "print(f\"导演:{result.director}\")\n",
-    "print(f\"评分:{result.rating}\")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 12,
-   "id": "5ddf6b79",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "流浪地球\n"
-     ]
-    }
-   ],
-   "source": [
-    "from typing_extensions import TypedDict\n",
-    "\n",
-    "# 方式二:TypedDict(更轻量,无运行时校验)\n",
-    "class MovieTypedDict(TypedDict):\n",
-    "    title: str\n",
-    "    year: int\n",
-    "    director: str\n",
-    "    rating: float\n",
-    "\n",
-    "structured_llm = llm.with_structured_output(MovieTypedDict)\n",
-    "result = structured_llm.invoke(\"介绍一下电影《流浪地球》\")\n",
-    "# 返回的是普通 dict\n",
-    "print(result[\"title\"])"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 13,
-   "id": "2b6e9160",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "{'director': '饺子', 'rating': 8.4, 'title': '哪吒之魔童降世', 'year': 2019}\n"
-     ]
-    }
-   ],
-   "source": [
-    "# 方式三:JSON Schema(最灵活,跨语言通用)\n",
-    "json_schema = {\n",
-    "    \"title\": \"MovieInfo\",\n",
-    "    \"description\": \"电影信息对象\",\n",
-    "    \"type\": \"object\",\n",
-    "    \"properties\": {\n",
-    "        \"title\":    {\"type\": \"string\",  \"description\": \"电影名称\"},\n",
-    "        \"year\":     {\"type\": \"integer\", \"description\": \"上映年份\"},\n",
-    "        \"director\": {\"type\": \"string\",  \"description\": \"导演\"},\n",
-    "        \"rating\":   {\"type\": \"number\",  \"description\": \"评分(10分制)\"}\n",
-    "    },\n",
-    "    \"required\": [\"title\", \"year\", \"director\", \"rating\"]\n",
-    "}\n",
-    "\n",
-    "structured_llm = llm.with_structured_output(json_schema)\n",
-    "result = structured_llm.invoke(\"介绍一下电影《哪吒之魔童降世》\")\n",
-    "print(result)  # 返回的是 dict"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 14,
-   "id": "cf4a8346",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "[SystemMessage(content='你是一个叫 小助手 的 AI 助手,说话风格简洁专业', additional_kwargs={}, response_metadata={}), HumanMessage(content='什么是机器学习?', additional_kwargs={}, response_metadata={})]\n"
-     ]
-    }
-   ],
-   "source": [
-    "from langchain_core.prompts import ChatPromptTemplate\n",
-    "\n",
-    "# 定义一个带变量的对话模板\n",
-    "# {name} 和 {question} 是占位符,运行时会被替换\n",
-    "chat_template = ChatPromptTemplate.from_messages([\n",
-    "    (\"system\", \"你是一个叫 {name} 的 AI 助手,说话风格简洁专业\"),\n",
-    "    (\"human\", \"{question}\")\n",
-    "])\n",
-    "\n",
-    "# 填充变量,生成最终的消息列表\n",
-    "messages = chat_template.format_messages(name=\"小助手\", question=\"什么是机器学习?\")\n",
-    "print(messages)\n",
-    "# 输出:\n",
-    "# [SystemMessage(content='你是一个叫 小助手 的 AI 助手,说话风格简洁专业'),\n",
-    "#  HumanMessage(content='什么是机器学习?')]"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 15,
-   "id": "dfd55f3a",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "给我讲一个关于程序员的笑话\n",
-      "请用幽默的风格,写一篇关于加班的短文,字数不超过100字\n"
-     ]
-    }
-   ],
-   "source": [
-    "from langchain_core.prompts import PromptTemplate\n",
-    "\n",
-    "# 单变量模板\n",
-    "prompt = PromptTemplate.from_template(\"给我讲一个关于{topic}的笑话\")\n",
-    "print(prompt.format(topic=\"程序员\"))\n",
-    "# → \"给我讲一个关于程序员的笑话\"\n",
-    "\n",
-    "# 多变量模板\n",
-    "prompt = PromptTemplate(\n",
-    "    template=\"请用{style}的风格,写一篇关于{topic}的短文,字数不超过{limit}字\",\n",
-    "    input_variables=[\"style\", \"topic\", \"limit\"]\n",
-    ")\n",
-    "print(prompt.format(style=\"幽默\", topic=\"加班\", limit=100))"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 16,
-   "id": "86f7eb00",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "请分析成都在2026年06/26/2026, 16:36:19的天气趋势\n"
-     ]
-    }
-   ],
-   "source": [
-    "from langchain_core.prompts import PromptTemplate\n",
-    "from datetime import datetime\n",
-    "\n",
-    "# 一个需要三个变量的模板\n",
-    "prompt = PromptTemplate(\n",
-    "    template=\"请分析{city}在{year}年{date}的天气趋势\",\n",
-    "    input_variables=[\"city\", \"year\", \"date\"]\n",
-    ")\n",
-    "\n",
-    "def get_datetime():\n",
-    "    now = datetime.now()\n",
-    "    return now.strftime(\"%m/%d/%Y, %H:%M:%S\")\n",
-    "\n",
-    "# partial() 可以预填部分变量\n",
-    "# 注意:date 传的是函数引用而非调用结果,每次 format 时会重新执行\n",
-    "partial_prompt = prompt.partial(\n",
-    "    city=\"成都\",\n",
-    "    year=\"2026\",\n",
-    "    date=get_datetime)  # 动态获取当前日期\n",
-    "\n",
-    "\n",
-    "# 只需填剩余的变量(这里已经全部填完了)\n",
-    "print(partial_prompt.format())"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 17,
-   "id": "74918bf5",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "你是一个精通网络流行语的翻译官。请把黑话翻译成正式的职场语言。\n",
-      "\n",
-      "\n",
-      "黑话: YYDS\n",
-      "翻译: 永远的神(极度赞美)\n",
-      "\n",
-      "黑话: 绝绝子\n",
-      "翻译: 太棒了(强烈赞叹)\n",
-      "\n",
-      "黑话: 躺平\n",
-      "翻译: 心态平和、不再内卷(不争不抢的生活态度)\n",
-      "\n",
-      "黑话: 下头\n",
-      "翻译:\n"
-     ]
-    }
-   ],
-   "source": [
-    "from langchain_core.prompts import FewShotPromptTemplate, PromptTemplate\n",
-    "\n",
-    "# 第一步:准备示例数据\n",
-    "examples = [\n",
-    "    {\"input\": \"YYDS\",   \"output\": \"永远的神(极度赞美)\"},\n",
-    "    {\"input\": \"绝绝子\", \"output\": \"太棒了(强烈赞叹)\"},\n",
-    "    {\"input\": \"躺平\",   \"output\": \"心态平和、不再内卷(不争不抢的生活态度)\"},\n",
-    "]\n",
-    "\n",
-    "# 第二步:定义每个示例的展示格式\n",
-    "example_prompt = PromptTemplate(\n",
-    "    input_variables=[\"input\", \"output\"],\n",
-    "    template=\"黑话: {input}\\n翻译: {output}\"\n",
-    ")\n",
-    "\n",
-    "# 第三步:组装完整的 Few-Shot Prompt\n",
-    "prompt = FewShotPromptTemplate(\n",
-    "    examples=examples,               # 示例列表\n",
-    "    example_prompt=example_prompt,   # 每个示例的格式\n",
-    "\n",
-    "    prefix=\"你是一个精通网络流行语的翻译官。请把黑话翻译成正式的职场语言。\\n\",  # 前缀(指令)\n",
-    "    suffix=\"黑话: {input}\\n翻译:\",                                           # 后缀(用户问题)\n",
-    "    input_variables=[\"input\"]\n",
-    ")\n",
-    "\n",
-    "# 第四步:生成最终 prompt\n",
-    "final_prompt = prompt.format(input=\"下头\")\n",
-    "print(final_prompt)\n",
-    "# 输出效果:\n",
-    "# 你是一个精通网络流行语的翻译官。请把黑话翻译成正式的职场语言。\n",
-    "#\n",
-    "# 黑话: YYDS\n",
-    "# 翻译: 永远的神(极度赞美)\n",
-    "#\n",
-    "# 黑话: 绝绝子\n",
-    "# 翻译: 太棒了(强烈赞叹)\n",
-    "#\n",
-    "# 黑话: 躺平\n",
-    "# 翻译: 心态平和、不再内卷(不争不抢的生活态度)\n",
-    "#\n",
-    "# 黑话: 下头\n",
-    "# 翻译:"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 18,
-   "id": "9c999e85",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "量子计算是一种利用量子力学中的叠加和纠缠等特性,通过量子比特并行处理信息,从而在特定问题上实现远超经典计算机性能的新型计算方式。\n"
-     ]
-    }
-   ],
-   "source": [
-    "from langchain_core.prompts import PromptTemplate\n",
-    "from langchain_openai import ChatOpenAI\n",
-    "\n",
-    "llm = ChatOpenAI(\n",
-    "    model_name=\"deepseek-v4-flash\",\n",
-    "    api_key=api_key,\n",
-    "    base_url=\"https://api.deepseek.com\"\n",
-    ")\n",
-    "\n",
-    "prompt = PromptTemplate.from_template(\"请用一句话解释什么是{concept}\")\n",
-    "\n",
-    "# 用管道符 | 把 prompt 和 llm 连起来,就构成了一条链\n",
-    "chain = prompt | llm\n",
-    "\n",
-    "# invoke 时只需传入变量,prompt 填充和模型调用自动完成\n",
-    "result = chain.invoke({\"concept\": \"量子计算\"})\n",
-    "print(result.content)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 19,
-   "id": "da3321b8",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "秦始皇统一六国的顺序为:韩、赵、魏、楚、燕、齐。\n"
-     ]
-    }
-   ],
-   "source": [
-    "from langchain_core.prompts import ChatPromptTemplate\n",
-    "from langchain_core.output_parsers import StrOutputParser\n",
-    "from langchain_openai import ChatOpenAI\n",
-    "\n",
-    "llm = ChatOpenAI(\n",
-    "    model_name=\"deepseek-v4-flash\",\n",
-    "    api_key=api_key,\n",
-    "    base_url=\"https://api.deepseek.com\"\n",
-    ")\n",
-    "\n",
-    "# 定义对话模板\n",
-    "prompt = ChatPromptTemplate.from_messages([\n",
-    "    (\"system\", \"你是一个中国历史专家,回答简洁明了\"),\n",
-    "    (\"user\", \"{input}\")\n",
-    "])\n",
-    "\n",
-    "# StrOutputParser 把 AIMessage 转成纯字符串\n",
-    "# 这样链的输出就是 str,而非 AIMessage 对象\n",
-    "parser = StrOutputParser()\n",
-    "\n",
-    "# 三段式链:Prompt → LLM → Parser\n",
-    "chain = prompt | llm | parser\n",
-    "\n",
-    "result = chain.invoke({\"input\": \"秦始皇统一六国的顺序是什么?\"})\n",
-    "print(result)  # 直接是字符串,不需要 .content"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 20,
-   "id": "3d1fab11",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "['大熊猫繁育研究基地', '宽窄巷子', '武侯祠']\n"
-     ]
-    }
-   ],
-   "source": [
-    "from langchain_core.output_parsers import CommaSeparatedListOutputParser\n",
-    "from langchain_core.prompts import ChatPromptTemplate\n",
-    "\n",
-    "parser = CommaSeparatedListOutputParser()\n",
-    "\n",
-    "# get_format_instructions() 会生成一段\"输出格式要求\"的文字\n",
-    "# 比如 \"Your response should be a list of comma separated values...\"\n",
-    "format_instructions = parser.get_format_instructions()\n",
-    "\n",
-    "prompt = ChatPromptTemplate.from_messages([\n",
-    "    (\"system\", f\"你是一个旅游顾问。{{format_instructions}}\"),\n",
-    "    (\"human\", \"推荐{city}的{count}个必去景点\")\n",
-    "])\n",
-    "\n",
-    "chain = prompt | llm | parser\n",
-    "\n",
-    "result = chain.invoke({\n",
-    "    \"city\": \"成都\",\n",
-    "    \"count\": 3,\n",
-    "    \"format_instructions\": format_instructions\n",
-    "})\n",
-    "print(result)  # ['武侯祠', '锦里', '大熊猫繁育研究基地'] ← 直接是 list"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 22,
-   "id": "cd62de23",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "书名:朝花夕拾\n",
-      "作者:鲁迅\n",
-      "体裁:['散文', '回忆性散文']\n",
-      "<class '__main__.BookInfo'>\n"
-     ]
-    }
-   ],
-   "source": [
-    "from typing import List\n",
-    "from pydantic import BaseModel, Field\n",
-    "from langchain_core.output_parsers import PydanticOutputParser\n",
-    "from langchain_core.prompts import ChatPromptTemplate\n",
-    "\n",
-    "# 定义数据结构\n",
-    "class BookInfo(BaseModel):\n",
-    "    \"\"\"书籍信息\"\"\"\n",
-    "    book_name: str = Field(description=\"书名\")\n",
-    "    author: str = Field(description=\"作者\")\n",
-    "    genres: List[str] = Field(description=\"体裁列表\")\n",
-    "\n",
-    "# 创建解析器,它会自动生成 JSON Schema 格式要求\n",
-    "parser = PydanticOutputParser(pydantic_object=BookInfo)\n",
-    "\n",
-    "prompt = ChatPromptTemplate.from_messages([\n",
-    "    (\"system\", \"你是一个图书管理员。请按格式要求输出,使用中文。\\n{format_instructions}\"),\n",
-    "    (\"human\", \"从以下简介中提取书籍信息:\\n{introduction}\")\n",
-    "])\n",
-    "\n",
-    "chain = prompt | llm | parser\n",
-    "\n",
-    "introduction = \"\"\"\n",
-    "《朝花夕拾》原名《旧事重提》,是鲁迅的散文集,收录1926年创作的10篇回忆性散文。\n",
-    "文集以记事为主,饱含抒情气息,反映了作者青少年时期的生活。\n",
-    "\"\"\"\n",
-    "\n",
-    "result = chain.invoke({\n",
-    "    \"introduction\": introduction,\n",
-    "    \"format_instructions\": parser.get_format_instructions()\n",
-    "})\n",
-    "\n",
-    "print(f\"书名:{result.book_name}\")       # 朝花夕拾\n",
-    "print(f\"作者:{result.author}\")          # 鲁迅\n",
-    "print(f\"体裁:{result.genres}\")          # ['散文集', '回忆性散文']\n",
-    "print(type(result))                      # <class '__main__.BookInfo'>"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 23,
-   "id": "9f0e16c5",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "嗨,小明!很高兴认识你,作为一名程序员同行,咱们可是“自己人”啦!👨‍💻 不知道你平时主要写什么方向的代码?是前端、后端、全栈,还是对某个领域(比如AI、游戏、嵌入式)特别感兴趣?或者最近在忙什么有趣的项目吗?\n",
-      "\n",
-      "如果有任何技术问题、职业发展困惑,或者想聊聊编程的趣事,随时都可以问我~ 当然,如果你只是想打个招呼,我也很乐意陪你闲聊!😄\n",
-      "你的名字我目前还不知道呢!😊 我们的对话刚刚开始,你还没有告诉我你的名字。如果你愿意的话,可以告诉我,这样我就能用你的名字来称呼你啦!或者你希望我继续用“你”来称呼也行。\n"
-     ]
-    }
-   ],
-   "source": [
-    "\n",
-    "# 第一轮\n",
-    "r1 = llm.invoke(\"我叫小明,我是一名程序员\")\n",
-    "print(r1.content)  # \"你好,小明!程序员是个很棒的职业...\"\n",
-    "\n",
-    "# 第二轮:问它记不记得\n",
-    "r2 = llm.invoke(\"我叫什么名字?\")\n",
-    "print(r2.content)  # \"抱歉,我无法知道你的名字...\" ← 完全忘了"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 1,
-   "id": "5758f6ef",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "get_weather\n",
-      "查询指定城市的实时天气信息\n",
-      "\n",
-      "    Args:\n",
-      "        location: 城市名称,如\"北京\"、\"成都\"\n",
-      "{'location': {'title': 'Location', 'type': 'string'}}\n",
-      "成都的天气:Partly cloudy,温度:27°C\n"
-     ]
-    }
-   ],
-   "source": [
-    "from langchain.tools import tool\n",
-    "import requests\n",
-    "\n",
-    "@tool\n",
-    "def get_weather(location: str) -> str:\n",
-    "    \"\"\"查询指定城市的实时天气信息\n",
-    "    \n",
-    "    Args:\n",
-    "        location: 城市名称,如\"北京\"、\"成都\"\n",
-    "    \"\"\"\n",
-    "    # 调用免费天气 API\n",
-    "    url = f\"https://wttr.in/{location}?format=j1&lang=zh\"\n",
-    "    response = requests.get(url)\n",
-    "    data = response.json()\n",
-    "\n",
-    "    current = data['current_condition'][0]\n",
-    "    weather_desc = current['weatherDesc'][0]['value']\n",
-    "    temp = current['temp_C']\n",
-    "\n",
-    "    return f\"{location}的天气:{weather_desc},温度:{temp}°C\"\n",
-    "\n",
-    "# @tool 装饰器自动提取的信息\n",
-    "print(get_weather.name)         # \"get_weather\"\n",
-    "print(get_weather.description)  # \"查询指定城市的实时天气信息\"\n",
-    "print(get_weather.args)         # {'location': {'title': 'Location', 'type': 'string'}}\n",
-    "\n",
-    "# 工具可以直接调用\n",
-    "result = get_weather.invoke({\"location\": \"成都\"})\n",
-    "print(result)  # \"成都的天气:Sunny,温度:28°C\""
-   ]
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "02_langchain (3.11.x)",
-   "language": "python",
-   "name": "python3"
-  },
-  "language_info": {
-   "codemirror_mode": {
-    "name": "ipython",
-    "version": 3
-   },
-   "file_extension": ".py",
-   "mimetype": "text/x-python",
-   "name": "python",
-   "nbconvert_exporter": "python",
-   "pygments_lexer": "ipython3",
-   "version": "3.11.15"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}