{ "cells": [ { "cell_type": "code", "execution_count": 1, "id": "fb84aa4a", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "片名:现代科幻经典之作\n", "年份:2014\n", "导演:克里斯托弗·诺兰\n", "评分:9.4\n" ] } ], "source": [ "from pydantic import BaseModel, Field\n", "from langchain_openai import ChatOpenAI\n", "import os\n", "from dotenv import load_dotenv\n", "\n", "load_dotenv()\n", "api_key= os.getenv('OPENAI_API_KEY')\n", "base_url= os.getenv('BASE_URL')\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 = ChatOpenAI(\n", " model_name=\"kimi-k2.6\", # DeepSeek 的对话模型\n", " api_key=api_key, # 在 platform.deepseek.com 获取\n", " base_url=base_url # DeepSeek API 地址\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": "99625d1c", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "微积分是研究连续变化的数学分支,核心在于用**微分**分析瞬时变化率、用**积分**计算连续累积,并揭示二者互为逆运算的深刻联系。\n" ] } ], "source": [ "from langchain_openai import ChatOpenAI\n", "\n", "# invoke 是 LangChain 统一的调用方法,返回 AIMessage 对象\n", "response = llm.invoke(\"用一句话解释什么是微积分\")\n", "print(response.content) # .content 拿到纯文本" ] }, { "cell_type": "code", "execution_count": 8, "id": "d5d95460", "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)" ] }, { "cell_type": "code", "execution_count": 9, "id": "d43830b9", "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": 11, "id": "4188e086", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "请分析成都在2026年06/27/2026, 19:28:27的天气趋势\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": 14, "id": "a63bcd44", "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)" ] }, { "cell_type": "code", "execution_count": 4, "id": "5ad80fab", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "量子计算是一种利用量子比特的叠加与纠缠等量子力学特性,并行探索海量可能性,从而指数级加速解决特定复杂问题的新型计算模式。\n" ] } ], "source": [ "from langchain_core.prompts import PromptTemplate\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": 15, "id": "7efa0863", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "韩、赵、魏、楚、燕、齐。\n", "\n", "公元前230年至前221年,十年间依次攻灭,建立秦朝。\n" ] } ], "source": [ "from langchain_core.prompts import ChatPromptTemplate\n", "from langchain_core.output_parsers import StrOutputParser\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", "result2 = chain.invoke({\"input\": \"秦始皇统一六国的顺序是什么?\"})\n", "print(result2) # 直接是字符串,不需要 .content" ] }, { "cell_type": "code", "execution_count": 16, "id": "9a007aa9", "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", "result3 = chain.invoke({\n", " \"city\": \"成都\",\n", " \"count\": 3,\n", " \"format_instructions\": format_instructions\n", "})\n", "print(result3) # ['武侯祠', '锦里', '大熊猫繁育研究基地'] ← 直接是 list" ] }, { "cell_type": "code", "execution_count": null, "id": "dfaa1de2", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "书名:朝花夕拾\n", "作者:鲁迅\n", "体裁:['散文集', '回忆性散文']\n", "\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", "result5 = chain.invoke({\n", " \"introduction\": introduction,\n", " \"format_instructions\": parser.get_format_instructions()\n", "})\n", "\n", "print(f\"书名:{result5.book_name}\") # 朝花夕拾\n", "print(f\"作者:{result5.author}\") # 鲁迅\n", "print(f\"体裁:{result5.genres}\") # ['散文集', '回忆性散文']\n", "print(type(result5)) # " ] }, { "cell_type": "code", "execution_count": 19, "id": "0dd268bc", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "冷笑话:为什么程序员分不清万圣节和圣诞节?\n", "\n", "因为 **Oct 31 == Dec 25**。\n", "五言绝句:代码如潮涌,通宵十指辛。\n", "屏前相对久,不觉又清晨。\n" ] } ], "source": [ "from langchain_core.prompts import ChatPromptTemplate\n", "from langchain_core.output_parsers import StrOutputParser\n", "from langchain_core.runnables import RunnableParallel\n", "\n", "parser = StrOutputParser()\n", "\n", "# 定义两条独立的链\n", "joke_prompt = ChatPromptTemplate.from_template(\"讲一个关于{topic}的冷笑话,越短越好\")\n", "poem_prompt = ChatPromptTemplate.from_template(\"写一首关于{topic}的五言绝句\")\n", "\n", "joke_chain = joke_prompt | llm | parser\n", "poem_chain = poem_prompt | llm | parser\n", "\n", "# 用 RunnableParallel 把两条链并联\n", "# 同一个 topic 会同时发给两条链,结果以 dict 返回\n", "combined = RunnableParallel(joke=joke_chain, poem=poem_chain)\n", "\n", "result = combined.invoke({\"topic\": \"程序员\"})\n", "print(f\"冷笑话:{result['joke']}\")\n", "print(f\"五言绝句:{result['poem']}\")\n", "# 两条链是并行执行的,总耗时约等于较慢的那条,而非两者之和" ] }, { "cell_type": "code", "execution_count": null, "id": "3e27979f", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "你好小明!很高兴认识你。作为一名程序员,你平时主要用什么技术栈?是前端、后端、移动端,还是全栈?\n", "\n", "有什么我可以帮你的吗?比如:\n", "\n", "- 💻 **代码问题** - 调试 Bug、算法优化、代码审查\n", "- 🏗️ **架构设计** - 技术选型、系统设计方案\n", "- 📚 **学习成长** - 新技术趋势、职业规划、面试准备\n", "- ✍️ **文档写作** - 技术文档、博客文章、README 优化\n", "\n", "随时告诉我你目前在做什么项目或遇到什么挑战,我很乐意一起聊聊!\n", "我不知道你的名字。作为 AI,我无法获取你的个人信息,除非你在这轮对话中告诉我。\n", "\n", "如果你愿意,可以告诉我你的名字,这样我就能在之后的交流里用名字称呼你啦。\n" ] } ], "source": [ "# 第一轮\n", "r1 = llm.invoke(\"我叫小明,我是一名程序员\")\n", "print(r1.content) # \"你好,小明!程序员是个很棒的职业...\"\n", "\n", "# 第二轮:问它记不记得 (没有记忆能力)\n", "r2 = llm.invoke(\"我叫什么名字?\")\n", "print(r2.content) # \"抱歉,我无法知道你的名字...\" ← 完全忘了" ] }, { "cell_type": "code", "execution_count": 21, "id": "8b15a431", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'history': [HumanMessage(content='我叫小明,是一名 Python 开发者', additional_kwargs={}, response_metadata={}), AIMessage(content='你好小明!Python 开发者很厉害呢', additional_kwargs={}, response_metadata={}, tool_calls=[], invalid_tool_calls=[])]}\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "C:\\Users\\Lenovo\\AppData\\Local\\Temp\\ipykernel_12480\\3138275549.py:5: LangChainDeprecationWarning: The class `ConversationBufferMemory` was deprecated in LangChain 0.3.1 and will be removed in 2.0.0. Use `langchain.agents.create_agent` instead. For agents that need to remember prior interactions, use `create_agent` with checkpointing or the `Store` API. See https://docs.langchain.com/oss/python/langchain/short-term-memory and https://docs.langchain.com/oss/python/langchain/long-term-memory\n", " memory = ConversationBufferMemory(return_messages=True)\n" ] } ], "source": [ "from langchain_classic.memory import ConversationBufferMemory\n", "\n", "# 创建记忆实例\n", "# return_messages=True 表示返回 Message 对象而非纯文本\n", "memory = ConversationBufferMemory(return_messages=True)\n", "\n", "# 手动添加对话记录\n", "memory.save_context(\n", " {\"input\": \"我叫小明,是一名 Python 开发者\"}, # 用户输入\n", " {\"output\": \"你好小明!Python 开发者很厉害呢\"} # AI 回复\n", ")\n", "\n", "# 查看存储的历史\n", "print(memory.load_memory_variables({}))\n", "# {'history': [HumanMessage(content='我叫小明...'), AIMessage(content='你好小明...')]}" ] }, { "cell_type": "code", "execution_count": 22, "id": "2a28c069", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "你好小明!很高兴认识你。我是你的 AI 助手,有什么我可以帮你的吗?无论是聊天、解答问题,还是帮忙写东西,随时告诉我哦!\n", "你叫**小明**呀!😊 我记得你刚才告诉过我的。\n" ] } ], "source": [ "from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder\n", "from langchain_core.output_parsers import StrOutputParser\n", "from langchain_classic.memory import ConversationBufferMemory\n", "\n", "memory = ConversationBufferMemory(return_messages=True)\n", "\n", "# MessagesPlaceholder 会在运行时被历史消息列表替换\n", "prompt = ChatPromptTemplate.from_messages([\n", " (\"system\", \"你是一个友好的 AI 助手\"),\n", " MessagesPlaceholder(variable_name=\"history\"), # 历史消息插槽\n", " (\"human\", \"{input}\") # 当前用户输入\n", "])\n", "\n", "chain = prompt | llm | StrOutputParser()\n", "\n", "# 第一轮\n", "history = memory.load_memory_variables({})[\"history\"]\n", "r1 = chain.invoke({\"input\": \"我叫小明\", \"history\": history})\n", "print(r1)\n", "memory.save_context({\"input\": \"我叫小明\"}, {\"output\": r1})\n", "\n", "# 第二轮:历史自动带入\n", "history = memory.load_memory_variables({})[\"history\"]\n", "r2 = chain.invoke({\"input\": \"我叫什么?\", \"history\": history})\n", "print(r2) # \"你叫小明呀!\" ← 这次记住了" ] }, { "cell_type": "code", "execution_count": 23, "id": "28d2f01a", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "C:\\Users\\Lenovo\\AppData\\Local\\Temp\\ipykernel_12480\\2439446434.py:8: LangChainDeprecationWarning: The class `ConversationChain` was deprecated in LangChain 0.2.7 and will be removed in 2.0.0. Use `langchain.agents.create_agent` instead. Build a conversational agent with `langchain.agents.create_agent` and persist message history via a LangGraph checkpointer.\n", " chain = ConversationChain(llm=llm, memory=memory)\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "你好小明!很高兴认识你。我也是AI,所以某种意义上咱们也算是\"同行\",都是靠代码和逻辑来工作的,哈哈。\n", "\n", "作为程序员,你现在主要专注于哪个方向呢?比如**前端开发**(React、Vue、TypeScript这些)、**后端架构**(Java、Go、Python、微服务),还是**移动端**(iOS、Android、Flutter),或者是**数据工程、DevOps、AI算法**之类的领域?\n", "\n", "我自己在处理各种技术话题时接触过不少具体的技术栈和场景,比如:\n", "\n", "- **Web开发**:JavaScript/TypeScript生态、Node.js、Python的Django/FastAPI、Java的Spring Boot\n", "- **数据库**:MySQL、PostgreSQL、Redis、MongoDB,还有SQL优化相关的问题\n", "- **工具链**:Git工作流、Docker容器化、CI/CD流水线、Linux服务器运维\n", "- **AI/数据**:Python的数据处理(Pandas、NumPy)、机器学习基础、API接口设计\n", "\n", "如果你最近在研究什么新技术、遇到了棘手的bug,或者想聊聊架构设计、职业规划、甚至是程序员特有的\"脱发与养生\"话题,我都很乐意陪你聊!你今天想聊点什么呢?\n", "你刚才在第一条消息里就告诉我啦——你是**程序员**呀!你说的是:**\"你好,我叫小明,我是程序员\"**。\n", "\n", "不过你还没告诉我你具体专注在哪个细分方向呢。就像我刚才提到的,程序员这个范畴可太广了:\n", "\n", "- 是做 **Web前端**(写页面、搞交互、调CSS样式)?\n", "- 还是 **后端开发**(设计API、搞数据库、做高并发架构)?\n", "- 或者是 **移动端**(iOS、Android、跨平台开发)?\n", "- 也可能是 **DevOps/SRE**(搭流水线、搞容器化、运维基础设施)?\n", "- 甚至是贴近硬件的 **嵌入式**、或者 **游戏开发**、**AI算法工程师**?\n", "\n", "当然,如果你现在做的是全栈,或者刚刚入行还在探索阶段,也完全没问题!你要不要跟我讲讲你日常主要用什么技术栈,或者最近在折腾什么项目?我很有兴趣听!\n" ] } ], "source": [ "from langchain_classic.chains import ConversationChain\n", "from langchain_classic.memory import ConversationBufferMemory\n", "\n", "\n", "memory = ConversationBufferMemory(return_messages=True)\n", "\n", "# ConversationChain 自动处理:注入历史 → 调用模型 → 保存对话\n", "chain = ConversationChain(llm=llm, memory=memory)\n", "\n", "r1 = chain.invoke({\"input\": \"你好,我叫小明,我是程序员\"})\n", "print(r1[\"response\"])\n", "\n", "r2 = chain.invoke({\"input\": \"我是做什么工作的?\"})\n", "print(r2[\"response\"]) # \"你是程序员呀!\" ← 自动记住" ] }, { "cell_type": "code", "execution_count": 24, "id": "ea8a1231", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "哎呀,听到你这么说,我的心也揪了一下 😢💔\n", "\n", "心情不好的时候真的超难受,就像天空突然灰蒙蒙的 ☁️🌧️ 但你要记得,**感到不开心是完全 OK 的**,不需要强迫自己马上笑起来哦!🫂✨\n", "\n", "如果你想吐吐槽,我在这儿呢 👂🍵 说什么都可以,我当你的专属情绪树洞~ 🌳💬 \n", "如果想自己静静,也没关系,先给你几个温暖小抱抱:\n", "\n", "🧸 **深呼吸**三次,想象把烦恼吹成气球放走~ 🎈 \n", "🍫 **吃点甜甜**的,给大脑来点多巴胺! \n", "🎵 **听首喜欢的歌**,或者看看可爱的小动物视频 🐱🐶🐥 \n", "🌿 **出门走走**,晒晒太阳,哪怕只是五分钟也很治愈 ☀️\n", "\n", "你不是孤单一个人,我在这里陪着你 💛🌈 \n", "**想聊聊发生了什么吗?** 还是希望我直接给你讲个笑话、分享点可爱的事情?😊✨\n" ] } ], "source": [ "from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder\n", "from langchain_classic.chains import ConversationChain\n", "from langchain_classic.memory import ConversationBufferMemory\n", "\n", "# 自定义 prompt,加入个性化设定\n", "prompt = ChatPromptTemplate.from_messages([\n", " (\"system\", \"你是一个爱用 emoji 的开心助手 ✨\"),\n", " MessagesPlaceholder(variable_name=\"history\"),\n", " (\"human\", \"{input}\")\n", "])\n", "\n", "memory = ConversationBufferMemory(return_messages=True)\n", "chain = ConversationChain(llm=llm, memory=memory, prompt=prompt)\n", "\n", "r = chain.invoke({\"input\": \"今天心情不好\"})\n", "print(r[\"response\"]) # 会带着 emoji 回复你" ] }, { "cell_type": "code", "execution_count": 25, "id": "96d44df7", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "e:\\AI大模型开发\\python_base\\.venv\\lib\\site-packages\\IPython\\core\\interactiveshell.py:3579: LangChainDeprecationWarning: RunnableWithMessageHistory is deprecated. Use LangGraph's built-in persistence instead.\n", " exec(code_obj, self.user_global_ns, self.user_ns)\n", "e:\\AI大模型开发\\python_base\\.venv\\lib\\site-packages\\langchain_core\\runnables\\history.py:605: LangChainDeprecationWarning: `connection_string` was deprecated in LangChain 0.2.2 and will be removed in 1.0. Use connection instead.\n", " message_history = self.get_session_history(\n" ] }, { "ename": "ModuleNotFoundError", "evalue": "No module named 'pymysql'", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", "Cell \u001b[1;32mIn[25], line 37\u001b[0m\n\u001b[0;32m 34\u001b[0m \u001b[38;5;66;03m# 使用时通过 config 传入 session_id\u001b[39;00m\n\u001b[0;32m 35\u001b[0m config \u001b[38;5;241m=\u001b[39m {\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mconfigurable\u001b[39m\u001b[38;5;124m\"\u001b[39m: {\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124msession_id\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124muser_001\u001b[39m\u001b[38;5;124m\"\u001b[39m}}\n\u001b[1;32m---> 37\u001b[0m r1 \u001b[38;5;241m=\u001b[39m \u001b[43mchain_with_history\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minvoke\u001b[49m\u001b[43m(\u001b[49m\u001b[43m{\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mquestion\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43m地球到太阳有多远?\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m}\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mconfig\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mconfig\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 38\u001b[0m \u001b[38;5;28mprint\u001b[39m(r1)\n\u001b[0;32m 40\u001b[0m r2 \u001b[38;5;241m=\u001b[39m chain_with_history\u001b[38;5;241m.\u001b[39minvoke({\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mquestion\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m到月球呢?\u001b[39m\u001b[38;5;124m\"\u001b[39m}, config\u001b[38;5;241m=\u001b[39mconfig)\n", "File \u001b[1;32me:\\AI大模型开发\\python_base\\.venv\\lib\\site-packages\\langchain_core\\runnables\\base.py:6006\u001b[0m, in \u001b[0;36mRunnableBindingBase.invoke\u001b[1;34m(self, input, config, **kwargs)\u001b[0m\n\u001b[0;32m 5997\u001b[0m \u001b[38;5;129m@override\u001b[39m\n\u001b[0;32m 5998\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21minvoke\u001b[39m(\n\u001b[0;32m 5999\u001b[0m \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 6002\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Any \u001b[38;5;241m|\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[0;32m 6003\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m Output:\n\u001b[0;32m 6004\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mbound\u001b[38;5;241m.\u001b[39minvoke(\n\u001b[0;32m 6005\u001b[0m \u001b[38;5;28minput\u001b[39m,\n\u001b[1;32m-> 6006\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_merge_configs\u001b[49m\u001b[43m(\u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m)\u001b[49m,\n\u001b[0;32m 6007\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m{\u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mkwargs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs},\n\u001b[0;32m 6008\u001b[0m )\n", "File \u001b[1;32me:\\AI大模型开发\\python_base\\.venv\\lib\\site-packages\\langchain_core\\runnables\\history.py:605\u001b[0m, in \u001b[0;36mRunnableWithMessageHistory._merge_configs\u001b[1;34m(self, *configs)\u001b[0m\n\u001b[0;32m 602\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mlen\u001b[39m(expected_keys) \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m1\u001b[39m:\n\u001b[0;32m 603\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m parameter_names:\n\u001b[0;32m 604\u001b[0m \u001b[38;5;66;03m# If arity = 1, then invoke function by positional arguments\u001b[39;00m\n\u001b[1;32m--> 605\u001b[0m message_history \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_session_history\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 606\u001b[0m \u001b[43m \u001b[49m\u001b[43mconfigurable\u001b[49m\u001b[43m[\u001b[49m\u001b[43mexpected_keys\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m]\u001b[49m\n\u001b[0;32m 607\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 608\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m 609\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m config:\n", "Cell \u001b[1;32mIn[25], line 25\u001b[0m, in \u001b[0;36m\u001b[1;34m(session_id)\u001b[0m\n\u001b[0;32m 17\u001b[0m mysql_url \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mmysql+pymysql://root:password@localhost:3306/mydb\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m 19\u001b[0m \u001b[38;5;66;03m# 用 RunnableWithMessageHistory 包装链\u001b[39;00m\n\u001b[0;32m 20\u001b[0m \u001b[38;5;66;03m# 每次 invoke 时自动加载历史,结束后自动保存\u001b[39;00m\n\u001b[0;32m 21\u001b[0m chain_with_history \u001b[38;5;241m=\u001b[39m RunnableWithMessageHistory(\n\u001b[0;32m 22\u001b[0m chain,\n\u001b[0;32m 23\u001b[0m \u001b[38;5;66;03m# session_id 到 MessageHistory 的映射函数\u001b[39;00m\n\u001b[0;32m 24\u001b[0m \u001b[38;5;66;03m# 每个 session_id 对应一组独立的对话记录\u001b[39;00m\n\u001b[1;32m---> 25\u001b[0m \u001b[38;5;28;01mlambda\u001b[39;00m session_id: \u001b[43mSQLChatMessageHistory\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 26\u001b[0m \u001b[43m \u001b[49m\u001b[43msession_id\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43msession_id\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 27\u001b[0m \u001b[43m \u001b[49m\u001b[43mconnection_string\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmysql_url\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 28\u001b[0m \u001b[43m \u001b[49m\u001b[43mtable_name\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mchat_history\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\n\u001b[0;32m 29\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m,\n\u001b[0;32m 30\u001b[0m input_messages_key\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mquestion\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;66;03m# 用户输入的 key\u001b[39;00m\n\u001b[0;32m 31\u001b[0m history_messages_key\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mhistory\u001b[39m\u001b[38;5;124m\"\u001b[39m \u001b[38;5;66;03m# 历史消息的 key\u001b[39;00m\n\u001b[0;32m 32\u001b[0m )\n\u001b[0;32m 34\u001b[0m \u001b[38;5;66;03m# 使用时通过 config 传入 session_id\u001b[39;00m\n\u001b[0;32m 35\u001b[0m config \u001b[38;5;241m=\u001b[39m {\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mconfigurable\u001b[39m\u001b[38;5;124m\"\u001b[39m: {\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124msession_id\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124muser_001\u001b[39m\u001b[38;5;124m\"\u001b[39m}}\n", "File \u001b[1;32me:\\AI大模型开发\\python_base\\.venv\\lib\\site-packages\\langchain_community\\chat_message_histories\\sql.py:202\u001b[0m, in \u001b[0;36mSQLChatMessageHistory.__init__\u001b[1;34m(self, session_id, connection_string, table_name, session_id_field_name, custom_message_converter, connection, engine_args, async_mode)\u001b[0m\n\u001b[0;32m 198\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39masync_engine \u001b[38;5;241m=\u001b[39m create_async_engine(\n\u001b[0;32m 199\u001b[0m connection, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m(engine_args \u001b[38;5;129;01mor\u001b[39;00m {})\n\u001b[0;32m 200\u001b[0m )\n\u001b[0;32m 201\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m--> 202\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mengine \u001b[38;5;241m=\u001b[39m create_engine(url\u001b[38;5;241m=\u001b[39mconnection, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m(engine_args \u001b[38;5;129;01mor\u001b[39;00m {}))\n\u001b[0;32m 203\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(connection, Engine):\n\u001b[0;32m 204\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39masync_mode \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mFalse\u001b[39;00m\n", "File \u001b[1;32m:2\u001b[0m, in \u001b[0;36mcreate_engine\u001b[1;34m(url, **kwargs)\u001b[0m\n", "File \u001b[1;32me:\\AI大模型开发\\python_base\\.venv\\lib\\site-packages\\sqlalchemy\\util\\deprecations.py:281\u001b[0m, in \u001b[0;36mdeprecated_params..decorate..warned\u001b[1;34m(fn, *args, **kwargs)\u001b[0m\n\u001b[0;32m 274\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m m \u001b[38;5;129;01min\u001b[39;00m kwargs:\n\u001b[0;32m 275\u001b[0m _warn_with_version(\n\u001b[0;32m 276\u001b[0m messages[m],\n\u001b[0;32m 277\u001b[0m versions[m],\n\u001b[0;32m 278\u001b[0m version_warnings[m],\n\u001b[0;32m 279\u001b[0m stacklevel\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m3\u001b[39m,\n\u001b[0;32m 280\u001b[0m )\n\u001b[1;32m--> 281\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m fn(\u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n", "File \u001b[1;32me:\\AI大模型开发\\python_base\\.venv\\lib\\site-packages\\sqlalchemy\\engine\\create.py:617\u001b[0m, in \u001b[0;36mcreate_engine\u001b[1;34m(url, **kwargs)\u001b[0m\n\u001b[0;32m 615\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m k \u001b[38;5;129;01min\u001b[39;00m kwargs:\n\u001b[0;32m 616\u001b[0m dbapi_args[k] \u001b[38;5;241m=\u001b[39m pop_kwarg(k)\n\u001b[1;32m--> 617\u001b[0m dbapi \u001b[38;5;241m=\u001b[39m dbapi_meth(\u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mdbapi_args)\n\u001b[0;32m 619\u001b[0m dialect_args[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdbapi\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m dbapi\n\u001b[0;32m 621\u001b[0m dialect_args\u001b[38;5;241m.\u001b[39msetdefault(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcompiler_linting\u001b[39m\u001b[38;5;124m\"\u001b[39m, compiler\u001b[38;5;241m.\u001b[39mNO_LINTING)\n", "File \u001b[1;32me:\\AI大模型开发\\python_base\\.venv\\lib\\site-packages\\sqlalchemy\\dialects\\mysql\\pymysql.py:116\u001b[0m, in \u001b[0;36mMySQLDialect_pymysql.import_dbapi\u001b[1;34m(cls)\u001b[0m\n\u001b[0;32m 114\u001b[0m \u001b[38;5;129m@classmethod\u001b[39m\n\u001b[0;32m 115\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21mimport_dbapi\u001b[39m(\u001b[38;5;28mcls\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m DBAPIModule:\n\u001b[1;32m--> 116\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43m__import__\u001b[39;49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mpymysql\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n", "\u001b[1;31mModuleNotFoundError\u001b[0m: No module named 'pymysql'" ] } ], "source": [ "from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder\n", "from langchain_core.output_parsers import StrOutputParser\n", "from langchain_core.runnables.history import RunnableWithMessageHistory\n", "from langchain_community.chat_message_histories import SQLChatMessageHistory\n", "\n", "\n", "# 定义 prompt(带历史占位符)\n", "prompt = ChatPromptTemplate.from_messages([\n", " (\"system\", \"你是一个擅长物理的助手\"),\n", " MessagesPlaceholder(variable_name=\"history\"),\n", " (\"human\", \"{question}\")\n", "])\n", "\n", "chain = prompt | llm | StrOutputParser()\n", "\n", "# MySQL 连接串(换成你自己的)\n", "mysql_url = \"mysql+pymysql://root:password@localhost:3306/mydb\"\n", "\n", "# 用 RunnableWithMessageHistory 包装链\n", "# 每次 invoke 时自动加载历史,结束后自动保存\n", "chain_with_history = RunnableWithMessageHistory(\n", " chain,\n", " # session_id 到 MessageHistory 的映射函数\n", " # 每个 session_id 对应一组独立的对话记录\n", " lambda session_id: SQLChatMessageHistory(\n", " session_id=session_id,\n", " connection_string=mysql_url,\n", " table_name=\"chat_history\"\n", " ),\n", " input_messages_key=\"question\", # 用户输入的 key\n", " history_messages_key=\"history\" # 历史消息的 key\n", ")\n", "\n", "# 使用时通过 config 传入 session_id\n", "config = {\"configurable\": {\"session_id\": \"user_001\"}}\n", "\n", "r1 = chain_with_history.invoke({\"question\": \"地球到太阳有多远?\"}, config=config)\n", "print(r1)\n", "\n", "r2 = chain_with_history.invoke({\"question\": \"到月球呢?\"}, config=config)\n", "print(r2)\n", "\n", "r3 = chain_with_history.invoke({\"question\": \"哪个更近?\"}, config=config)\n", "print(r3) # \"月球更近\" ← 能正确理解\"哪个\"指的是前两轮的内容" ] }, { "cell_type": "code", "execution_count": 26, "id": "3b526b47", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "sleep\n", "wolfram-alpha\n", "google-search\n", "google-search-results-json\n", "searx-search-results-json\n", "bing-search\n", "metaphor-search\n", "ddg-search\n", "google-books\n", "google-lens\n", "google-serper\n", "google-scholar\n", "google-finance\n", "google-trends\n", "google-jobs\n", "google-serper-results-json\n", "searchapi\n", "searchapi-results-json\n", "serpapi\n", "dalle-image-generator\n", "twilio\n", "searx-search\n", "merriam-webster\n", "wikipedia\n", "arxiv\n", "golden-query\n", "pubmed\n", "human\n", "awslambda\n", "stackexchange\n", "sceneXplain\n", "graphql\n", "openweathermap-api\n", "dataforseo-api-search\n", "dataforseo-api-search-json\n", "eleven_labs_text2speech\n", "google_cloud_texttospeech\n", "read_file\n", "reddit_search\n", "news-api\n", "tmdb-api\n", "podcast-api\n", "memorize\n", "llm-math\n", "open-meteo-api\n", "requests\n", "requests_get\n", "requests_post\n", "requests_patch\n", "requests_put\n", "requests_delete\n", "terminal\n" ] } ], "source": [ "from langchain_classic.agents import get_all_tool_names\n", "# 获取所有可用工具的名称\n", "tool_names = get_all_tool_names()\n", "for name in tool_names:\n", " print(name)" ] }, { "cell_type": "code", "execution_count": 30, "id": "63b5be40", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "wikipedia A wrapper around Wikipedia. Useful for when you need to answer general questions about people, places, companies, facts, historical events, or other subjects. Input should be a search query. {'query': {'description': 'query to look up on wikipedia', 'title': 'Query', 'type': 'string'}}\n" ] }, { "ename": "ConnectTimeout", "evalue": "HTTPConnectionPool(host='en.wikipedia.org', port=80): Max retries exceeded with url: /w/api.php?list=search&srprop=&srlimit=1&limit=1&srsearch=AI%E4%B9%8B%E7%88%B6&format=json&action=query (Caused by ConnectTimeoutError(, 'Connection to en.wikipedia.org timed out. (connect timeout=None)'))", "output_type": "error", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mTimeoutError\u001b[0m Traceback (most recent call last)", "File \u001b[1;32me:\\AI大模型开发\\python_base\\.venv\\lib\\site-packages\\urllib3\\connection.py:204\u001b[0m, in \u001b[0;36mHTTPConnection._new_conn\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m 203\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m--> 204\u001b[0m sock \u001b[38;5;241m=\u001b[39m \u001b[43mconnection\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcreate_connection\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 205\u001b[0m \u001b[43m \u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_dns_host\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mport\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 206\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mtimeout\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 207\u001b[0m \u001b[43m \u001b[49m\u001b[43msource_address\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msource_address\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 208\u001b[0m \u001b[43m \u001b[49m\u001b[43msocket_options\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msocket_options\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 209\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 210\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m socket\u001b[38;5;241m.\u001b[39mgaierror \u001b[38;5;28;01mas\u001b[39;00m e:\n", "File \u001b[1;32me:\\AI大模型开发\\python_base\\.venv\\lib\\site-packages\\urllib3\\util\\connection.py:85\u001b[0m, in \u001b[0;36mcreate_connection\u001b[1;34m(address, timeout, source_address, socket_options)\u001b[0m\n\u001b[0;32m 84\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m---> 85\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m err\n\u001b[0;32m 86\u001b[0m \u001b[38;5;28;01mfinally\u001b[39;00m:\n\u001b[0;32m 87\u001b[0m \u001b[38;5;66;03m# Break explicitly a reference cycle\u001b[39;00m\n", "File \u001b[1;32me:\\AI大模型开发\\python_base\\.venv\\lib\\site-packages\\urllib3\\util\\connection.py:73\u001b[0m, in \u001b[0;36mcreate_connection\u001b[1;34m(address, timeout, source_address, socket_options)\u001b[0m\n\u001b[0;32m 72\u001b[0m sock\u001b[38;5;241m.\u001b[39mbind(source_address)\n\u001b[1;32m---> 73\u001b[0m \u001b[43msock\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mconnect\u001b[49m\u001b[43m(\u001b[49m\u001b[43msa\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 74\u001b[0m \u001b[38;5;66;03m# Break explicitly a reference cycle\u001b[39;00m\n", "\u001b[1;31mTimeoutError\u001b[0m: [WinError 10060] 由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试失败。", "\nThe above exception was the direct cause of the following exception:\n", "\u001b[1;31mConnectTimeoutError\u001b[0m Traceback (most recent call last)", "File \u001b[1;32me:\\AI大模型开发\\python_base\\.venv\\lib\\site-packages\\urllib3\\connectionpool.py:788\u001b[0m, in \u001b[0;36mHTTPConnectionPool.urlopen\u001b[1;34m(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, preload_content, decode_content, **response_kw)\u001b[0m\n\u001b[0;32m 787\u001b[0m \u001b[38;5;66;03m# Make the request on the HTTPConnection object\u001b[39;00m\n\u001b[1;32m--> 788\u001b[0m response \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_make_request(\n\u001b[0;32m 789\u001b[0m conn,\n\u001b[0;32m 790\u001b[0m method,\n\u001b[0;32m 791\u001b[0m url,\n\u001b[0;32m 792\u001b[0m timeout\u001b[38;5;241m=\u001b[39mtimeout_obj,\n\u001b[0;32m 793\u001b[0m body\u001b[38;5;241m=\u001b[39mbody,\n\u001b[0;32m 794\u001b[0m headers\u001b[38;5;241m=\u001b[39mheaders,\n\u001b[0;32m 795\u001b[0m chunked\u001b[38;5;241m=\u001b[39mchunked,\n\u001b[0;32m 796\u001b[0m retries\u001b[38;5;241m=\u001b[39mretries,\n\u001b[0;32m 797\u001b[0m response_conn\u001b[38;5;241m=\u001b[39mresponse_conn,\n\u001b[0;32m 798\u001b[0m preload_content\u001b[38;5;241m=\u001b[39mpreload_content,\n\u001b[0;32m 799\u001b[0m decode_content\u001b[38;5;241m=\u001b[39mdecode_content,\n\u001b[0;32m 800\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mresponse_kw,\n\u001b[0;32m 801\u001b[0m )\n\u001b[0;32m 803\u001b[0m \u001b[38;5;66;03m# Everything went great!\u001b[39;00m\n", "File \u001b[1;32me:\\AI大模型开发\\python_base\\.venv\\lib\\site-packages\\urllib3\\connectionpool.py:493\u001b[0m, in \u001b[0;36mHTTPConnectionPool._make_request\u001b[1;34m(self, conn, method, url, body, headers, retries, timeout, chunked, response_conn, preload_content, decode_content, enforce_content_length)\u001b[0m\n\u001b[0;32m 492\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m--> 493\u001b[0m \u001b[43mconn\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrequest\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 494\u001b[0m \u001b[43m \u001b[49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 495\u001b[0m \u001b[43m \u001b[49m\u001b[43murl\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 496\u001b[0m \u001b[43m \u001b[49m\u001b[43mbody\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mbody\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 497\u001b[0m \u001b[43m \u001b[49m\u001b[43mheaders\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mheaders\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 498\u001b[0m \u001b[43m \u001b[49m\u001b[43mchunked\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mchunked\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 499\u001b[0m \u001b[43m \u001b[49m\u001b[43mpreload_content\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mpreload_content\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 500\u001b[0m \u001b[43m \u001b[49m\u001b[43mdecode_content\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdecode_content\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 501\u001b[0m \u001b[43m \u001b[49m\u001b[43menforce_content_length\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43menforce_content_length\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 502\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 504\u001b[0m \u001b[38;5;66;03m# We are swallowing BrokenPipeError (errno.EPIPE) since the server is\u001b[39;00m\n\u001b[0;32m 505\u001b[0m \u001b[38;5;66;03m# legitimately able to close the connection after sending a valid response.\u001b[39;00m\n\u001b[0;32m 506\u001b[0m \u001b[38;5;66;03m# With this behaviour, the received response is still readable.\u001b[39;00m\n", "File \u001b[1;32me:\\AI大模型开发\\python_base\\.venv\\lib\\site-packages\\urllib3\\connection.py:500\u001b[0m, in \u001b[0;36mHTTPConnection.request\u001b[1;34m(self, method, url, body, headers, chunked, preload_content, decode_content, enforce_content_length)\u001b[0m\n\u001b[0;32m 499\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mputheader(header, value)\n\u001b[1;32m--> 500\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mendheaders\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 502\u001b[0m \u001b[38;5;66;03m# If we're given a body we start sending that in chunks.\u001b[39;00m\n", "File \u001b[1;32mE:\\python\\python-3.10.8-amd64\\lib\\http\\client.py:1277\u001b[0m, in \u001b[0;36mHTTPConnection.endheaders\u001b[1;34m(self, message_body, encode_chunked)\u001b[0m\n\u001b[0;32m 1276\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m CannotSendHeader()\n\u001b[1;32m-> 1277\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_send_output\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmessage_body\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mencode_chunked\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mencode_chunked\u001b[49m\u001b[43m)\u001b[49m\n", "File \u001b[1;32mE:\\python\\python-3.10.8-amd64\\lib\\http\\client.py:1037\u001b[0m, in \u001b[0;36mHTTPConnection._send_output\u001b[1;34m(self, message_body, encode_chunked)\u001b[0m\n\u001b[0;32m 1036\u001b[0m \u001b[38;5;28;01mdel\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_buffer[:]\n\u001b[1;32m-> 1037\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msend\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmsg\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 1039\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m message_body \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m 1040\u001b[0m \n\u001b[0;32m 1041\u001b[0m \u001b[38;5;66;03m# create a consistent interface to message_body\u001b[39;00m\n", "File \u001b[1;32mE:\\python\\python-3.10.8-amd64\\lib\\http\\client.py:975\u001b[0m, in \u001b[0;36mHTTPConnection.send\u001b[1;34m(self, data)\u001b[0m\n\u001b[0;32m 974\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mauto_open:\n\u001b[1;32m--> 975\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mconnect\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 976\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n", "File \u001b[1;32me:\\AI大模型开发\\python_base\\.venv\\lib\\site-packages\\urllib3\\connection.py:331\u001b[0m, in \u001b[0;36mHTTPConnection.connect\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m 330\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21mconnect\u001b[39m(\u001b[38;5;28mself\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m--> 331\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39msock \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_new_conn\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 332\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_tunnel_host:\n\u001b[0;32m 333\u001b[0m \u001b[38;5;66;03m# If we're tunneling it means we're connected to our proxy.\u001b[39;00m\n", "File \u001b[1;32me:\\AI大模型开发\\python_base\\.venv\\lib\\site-packages\\urllib3\\connection.py:213\u001b[0m, in \u001b[0;36mHTTPConnection._new_conn\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m 212\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m SocketTimeout \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[1;32m--> 213\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m ConnectTimeoutError(\n\u001b[0;32m 214\u001b[0m \u001b[38;5;28mself\u001b[39m,\n\u001b[0;32m 215\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mConnection to \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mhost\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m timed out. (connect timeout=\u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mtimeout\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m)\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[0;32m 216\u001b[0m ) \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01me\u001b[39;00m\n\u001b[0;32m 218\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mOSError\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:\n", "\u001b[1;31mConnectTimeoutError\u001b[0m: (, 'Connection to en.wikipedia.org timed out. (connect timeout=None)')", "\nThe above exception was the direct cause of the following exception:\n", "\u001b[1;31mMaxRetryError\u001b[0m Traceback (most recent call last)", "File \u001b[1;32me:\\AI大模型开发\\python_base\\.venv\\lib\\site-packages\\requests\\adapters.py:696\u001b[0m, in \u001b[0;36mHTTPAdapter.send\u001b[1;34m(self, request, stream, timeout, verify, cert, proxies)\u001b[0m\n\u001b[0;32m 695\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m--> 696\u001b[0m resp \u001b[38;5;241m=\u001b[39m \u001b[43mconn\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43murlopen\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 697\u001b[0m \u001b[43m \u001b[49m\u001b[43mmethod\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mrequest\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 698\u001b[0m \u001b[43m \u001b[49m\u001b[43murl\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43murl\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 699\u001b[0m \u001b[43m \u001b[49m\u001b[43mbody\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mrequest\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mbody\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# type: ignore[arg-type] # urllib3 stubs don't accept Iterable[bytes | str]\u001b[39;49;00m\n\u001b[0;32m 700\u001b[0m \u001b[43m \u001b[49m\u001b[43mheaders\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mrequest\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mheaders\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;66;43;03m# type: ignore[arg-type] # urllib3#3072\u001b[39;49;00m\n\u001b[0;32m 701\u001b[0m \u001b[43m \u001b[49m\u001b[43mredirect\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[0;32m 702\u001b[0m \u001b[43m \u001b[49m\u001b[43massert_same_host\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[0;32m 703\u001b[0m \u001b[43m \u001b[49m\u001b[43mpreload_content\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[0;32m 704\u001b[0m \u001b[43m \u001b[49m\u001b[43mdecode_content\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[0;32m 705\u001b[0m \u001b[43m \u001b[49m\u001b[43mretries\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmax_retries\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 706\u001b[0m \u001b[43m \u001b[49m\u001b[43mtimeout\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mresolved_timeout\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 707\u001b[0m \u001b[43m \u001b[49m\u001b[43mchunked\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mchunked\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 708\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 710\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m (ProtocolError, \u001b[38;5;167;01mOSError\u001b[39;00m) \u001b[38;5;28;01mas\u001b[39;00m err:\n", "File \u001b[1;32me:\\AI大模型开发\\python_base\\.venv\\lib\\site-packages\\urllib3\\connectionpool.py:842\u001b[0m, in \u001b[0;36mHTTPConnectionPool.urlopen\u001b[1;34m(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, preload_content, decode_content, **response_kw)\u001b[0m\n\u001b[0;32m 840\u001b[0m new_e \u001b[38;5;241m=\u001b[39m ProtocolError(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mConnection aborted.\u001b[39m\u001b[38;5;124m\"\u001b[39m, new_e)\n\u001b[1;32m--> 842\u001b[0m retries \u001b[38;5;241m=\u001b[39m \u001b[43mretries\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mincrement\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 843\u001b[0m \u001b[43m \u001b[49m\u001b[43mmethod\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43murl\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43merror\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mnew_e\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m_pool\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m_stacktrace\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43msys\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mexc_info\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m2\u001b[39;49m\u001b[43m]\u001b[49m\n\u001b[0;32m 844\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 845\u001b[0m retries\u001b[38;5;241m.\u001b[39msleep()\n", "File \u001b[1;32me:\\AI大模型开发\\python_base\\.venv\\lib\\site-packages\\urllib3\\util\\retry.py:543\u001b[0m, in \u001b[0;36mRetry.increment\u001b[1;34m(self, method, url, response, error, _pool, _stacktrace)\u001b[0m\n\u001b[0;32m 542\u001b[0m reason \u001b[38;5;241m=\u001b[39m error \u001b[38;5;129;01mor\u001b[39;00m ResponseError(cause)\n\u001b[1;32m--> 543\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m MaxRetryError(_pool, url, reason) \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01mreason\u001b[39;00m \u001b[38;5;66;03m# type: ignore[arg-type]\u001b[39;00m\n\u001b[0;32m 545\u001b[0m log\u001b[38;5;241m.\u001b[39mdebug(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mIncremented Retry for (url=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;132;01m%s\u001b[39;00m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m): \u001b[39m\u001b[38;5;132;01m%r\u001b[39;00m\u001b[38;5;124m\"\u001b[39m, url, new_retry)\n", "\u001b[1;31mMaxRetryError\u001b[0m: HTTPConnectionPool(host='en.wikipedia.org', port=80): Max retries exceeded with url: /w/api.php?list=search&srprop=&srlimit=1&limit=1&srsearch=AI%E4%B9%8B%E7%88%B6&format=json&action=query (Caused by ConnectTimeoutError(, 'Connection to en.wikipedia.org timed out. (connect timeout=None)'))", "\nDuring handling of the above exception, another exception occurred:\n", "\u001b[1;31mConnectTimeout\u001b[0m Traceback (most recent call last)", "Cell \u001b[1;32mIn[30], line 14\u001b[0m\n\u001b[0;32m 10\u001b[0m tool \u001b[38;5;241m=\u001b[39m WikipediaQueryRun(api_wrapper\u001b[38;5;241m=\u001b[39mapi_wrapper)\n\u001b[0;32m 12\u001b[0m \u001b[38;5;28mprint\u001b[39m(tool\u001b[38;5;241m.\u001b[39mname, tool\u001b[38;5;241m.\u001b[39mdescription, tool\u001b[38;5;241m.\u001b[39margs)\n\u001b[1;32m---> 14\u001b[0m \u001b[43mtool\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun\u001b[49m\u001b[43m(\u001b[49m\u001b[43m{\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mquery\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mAI之父\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m}\u001b[49m\u001b[43m)\u001b[49m\n", "File \u001b[1;32me:\\AI大模型开发\\python_base\\.venv\\lib\\site-packages\\langchain_core\\tools\\base.py:1100\u001b[0m, in \u001b[0;36mBaseTool.run\u001b[1;34m(self, tool_input, verbose, start_color, color, callbacks, tags, metadata, run_name, run_id, config, tool_call_id, **kwargs)\u001b[0m\n\u001b[0;32m 1098\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m error_to_raise:\n\u001b[0;32m 1099\u001b[0m run_manager\u001b[38;5;241m.\u001b[39mon_tool_error(error_to_raise, tool_call_id\u001b[38;5;241m=\u001b[39mtool_call_id)\n\u001b[1;32m-> 1100\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m error_to_raise\n\u001b[0;32m 1101\u001b[0m output \u001b[38;5;241m=\u001b[39m _format_output(content, artifact, tool_call_id, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mname, status)\n\u001b[0;32m 1102\u001b[0m run_manager\u001b[38;5;241m.\u001b[39mon_tool_end(output, color\u001b[38;5;241m=\u001b[39mcolor, name\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mname, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n", "File \u001b[1;32me:\\AI大模型开发\\python_base\\.venv\\lib\\site-packages\\langchain_core\\tools\\base.py:1066\u001b[0m, in \u001b[0;36mBaseTool.run\u001b[1;34m(self, tool_input, verbose, start_color, color, callbacks, tags, metadata, run_name, run_id, config, tool_call_id, **kwargs)\u001b[0m\n\u001b[0;32m 1064\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m config_param \u001b[38;5;241m:=\u001b[39m _get_runnable_config_param(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_run):\n\u001b[0;32m 1065\u001b[0m tool_kwargs \u001b[38;5;241m|\u001b[39m\u001b[38;5;241m=\u001b[39m {config_param: config}\n\u001b[1;32m-> 1066\u001b[0m response \u001b[38;5;241m=\u001b[39m context\u001b[38;5;241m.\u001b[39mrun(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_run, \u001b[38;5;241m*\u001b[39mtool_args, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mtool_kwargs)\n\u001b[0;32m 1067\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mresponse_format \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcontent_and_artifact\u001b[39m\u001b[38;5;124m\"\u001b[39m:\n\u001b[0;32m 1068\u001b[0m msg \u001b[38;5;241m=\u001b[39m (\n\u001b[0;32m 1069\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mSince response_format=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mcontent_and_artifact\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m 1070\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124ma two-tuple of the message content and raw tool output is \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m 1071\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mexpected. Instead, generated response is of type: \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m 1072\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mtype\u001b[39m(response)\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m 1073\u001b[0m )\n", "File \u001b[1;32me:\\AI大模型开发\\python_base\\.venv\\lib\\site-packages\\langchain_community\\tools\\wikipedia\\tool.py:38\u001b[0m, in \u001b[0;36mWikipediaQueryRun._run\u001b[1;34m(self, query, run_manager)\u001b[0m\n\u001b[0;32m 32\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21m_run\u001b[39m(\n\u001b[0;32m 33\u001b[0m \u001b[38;5;28mself\u001b[39m,\n\u001b[0;32m 34\u001b[0m query: \u001b[38;5;28mstr\u001b[39m,\n\u001b[0;32m 35\u001b[0m run_manager: Optional[CallbackManagerForToolRun] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[0;32m 36\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28mstr\u001b[39m:\n\u001b[0;32m 37\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"Use the Wikipedia tool.\"\"\"\u001b[39;00m\n\u001b[1;32m---> 38\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mapi_wrapper\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun\u001b[49m\u001b[43m(\u001b[49m\u001b[43mquery\u001b[49m\u001b[43m)\u001b[49m\n", "File \u001b[1;32me:\\AI大模型开发\\python_base\\.venv\\lib\\site-packages\\langchain_community\\utilities\\wikipedia.py:49\u001b[0m, in \u001b[0;36mWikipediaAPIWrapper.run\u001b[1;34m(self, query)\u001b[0m\n\u001b[0;32m 47\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21mrun\u001b[39m(\u001b[38;5;28mself\u001b[39m, query: \u001b[38;5;28mstr\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28mstr\u001b[39m:\n\u001b[0;32m 48\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"Run Wikipedia search and get page summaries.\"\"\"\u001b[39;00m\n\u001b[1;32m---> 49\u001b[0m page_titles \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mwiki_client\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msearch\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 50\u001b[0m \u001b[43m \u001b[49m\u001b[43mquery\u001b[49m\u001b[43m[\u001b[49m\u001b[43m:\u001b[49m\u001b[43mWIKIPEDIA_MAX_QUERY_LENGTH\u001b[49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mresults\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mtop_k_results\u001b[49m\n\u001b[0;32m 51\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 52\u001b[0m summaries \u001b[38;5;241m=\u001b[39m []\n\u001b[0;32m 53\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m page_title \u001b[38;5;129;01min\u001b[39;00m page_titles[: \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mtop_k_results]:\n", "File \u001b[1;32me:\\AI大模型开发\\python_base\\.venv\\lib\\site-packages\\wikipedia\\util.py:28\u001b[0m, in \u001b[0;36mcache.__call__\u001b[1;34m(self, *args, **kwargs)\u001b[0m\n\u001b[0;32m 26\u001b[0m ret \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_cache[key]\n\u001b[0;32m 27\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m---> 28\u001b[0m ret \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_cache[key] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mfn(\u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n\u001b[0;32m 30\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m ret\n", "File \u001b[1;32me:\\AI大模型开发\\python_base\\.venv\\lib\\site-packages\\wikipedia\\wikipedia.py:103\u001b[0m, in \u001b[0;36msearch\u001b[1;34m(query, results, suggestion)\u001b[0m\n\u001b[0;32m 100\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m suggestion:\n\u001b[0;32m 101\u001b[0m search_params[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msrinfo\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124msuggestion\u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m--> 103\u001b[0m raw_results \u001b[38;5;241m=\u001b[39m \u001b[43m_wiki_request\u001b[49m\u001b[43m(\u001b[49m\u001b[43msearch_params\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 105\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124merror\u001b[39m\u001b[38;5;124m'\u001b[39m \u001b[38;5;129;01min\u001b[39;00m raw_results:\n\u001b[0;32m 106\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m raw_results[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124merror\u001b[39m\u001b[38;5;124m'\u001b[39m][\u001b[38;5;124m'\u001b[39m\u001b[38;5;124minfo\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;129;01min\u001b[39;00m (\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mHTTP request timed out.\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mPool queue is full\u001b[39m\u001b[38;5;124m'\u001b[39m):\n", "File \u001b[1;32me:\\AI大模型开发\\python_base\\.venv\\lib\\site-packages\\wikipedia\\wikipedia.py:737\u001b[0m, in \u001b[0;36m_wiki_request\u001b[1;34m(params)\u001b[0m\n\u001b[0;32m 734\u001b[0m wait_time \u001b[38;5;241m=\u001b[39m (RATE_LIMIT_LAST_CALL \u001b[38;5;241m+\u001b[39m RATE_LIMIT_MIN_WAIT) \u001b[38;5;241m-\u001b[39m datetime\u001b[38;5;241m.\u001b[39mnow()\n\u001b[0;32m 735\u001b[0m time\u001b[38;5;241m.\u001b[39msleep(\u001b[38;5;28mint\u001b[39m(wait_time\u001b[38;5;241m.\u001b[39mtotal_seconds()))\n\u001b[1;32m--> 737\u001b[0m r \u001b[38;5;241m=\u001b[39m \u001b[43mrequests\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget\u001b[49m\u001b[43m(\u001b[49m\u001b[43mAPI_URL\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mparams\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mparams\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mheaders\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mheaders\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 739\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m RATE_LIMIT:\n\u001b[0;32m 740\u001b[0m RATE_LIMIT_LAST_CALL \u001b[38;5;241m=\u001b[39m datetime\u001b[38;5;241m.\u001b[39mnow()\n", "File \u001b[1;32me:\\AI大模型开发\\python_base\\.venv\\lib\\site-packages\\requests\\api.py:87\u001b[0m, in \u001b[0;36mget\u001b[1;34m(url, params, **kwargs)\u001b[0m\n\u001b[0;32m 74\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21mget\u001b[39m(\n\u001b[0;32m 75\u001b[0m url: _t\u001b[38;5;241m.\u001b[39mUriType, params: _t\u001b[38;5;241m.\u001b[39mParamsType \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Unpack[_t\u001b[38;5;241m.\u001b[39mGetKwargs]\n\u001b[0;32m 76\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m Response:\n\u001b[0;32m 77\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124mr\u001b[39m\u001b[38;5;124;03m\"\"\"Sends a GET request.\u001b[39;00m\n\u001b[0;32m 78\u001b[0m \n\u001b[0;32m 79\u001b[0m \u001b[38;5;124;03m :param url: URL for the new :class:`Request` object.\u001b[39;00m\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 84\u001b[0m \u001b[38;5;124;03m :rtype: requests.Response\u001b[39;00m\n\u001b[0;32m 85\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[1;32m---> 87\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m request(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mget\u001b[39m\u001b[38;5;124m\"\u001b[39m, url, params\u001b[38;5;241m=\u001b[39mparams, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n", "File \u001b[1;32me:\\AI大模型开发\\python_base\\.venv\\lib\\site-packages\\requests\\api.py:71\u001b[0m, in \u001b[0;36mrequest\u001b[1;34m(method, url, **kwargs)\u001b[0m\n\u001b[0;32m 67\u001b[0m \u001b[38;5;66;03m# By using the 'with' statement we are sure the session is closed, thus we\u001b[39;00m\n\u001b[0;32m 68\u001b[0m \u001b[38;5;66;03m# avoid leaving sockets open which can trigger a ResourceWarning in some\u001b[39;00m\n\u001b[0;32m 69\u001b[0m \u001b[38;5;66;03m# cases, and look like a memory leak in others.\u001b[39;00m\n\u001b[0;32m 70\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m sessions\u001b[38;5;241m.\u001b[39mSession() \u001b[38;5;28;01mas\u001b[39;00m session:\n\u001b[1;32m---> 71\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m session\u001b[38;5;241m.\u001b[39mrequest(method\u001b[38;5;241m=\u001b[39mmethod, url\u001b[38;5;241m=\u001b[39murl, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n", "File \u001b[1;32me:\\AI大模型开发\\python_base\\.venv\\lib\\site-packages\\requests\\sessions.py:651\u001b[0m, in \u001b[0;36mSession.request\u001b[1;34m(self, method, url, params, data, headers, cookies, files, auth, timeout, allow_redirects, proxies, hooks, stream, verify, cert, json)\u001b[0m\n\u001b[0;32m 646\u001b[0m send_kwargs \u001b[38;5;241m=\u001b[39m {\n\u001b[0;32m 647\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtimeout\u001b[39m\u001b[38;5;124m\"\u001b[39m: timeout,\n\u001b[0;32m 648\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mallow_redirects\u001b[39m\u001b[38;5;124m\"\u001b[39m: allow_redirects,\n\u001b[0;32m 649\u001b[0m }\n\u001b[0;32m 650\u001b[0m send_kwargs\u001b[38;5;241m.\u001b[39mupdate(settings)\n\u001b[1;32m--> 651\u001b[0m resp \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39msend(prep, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39msend_kwargs)\n\u001b[0;32m 653\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m resp\n", "File \u001b[1;32me:\\AI大模型开发\\python_base\\.venv\\lib\\site-packages\\requests\\sessions.py:784\u001b[0m, in \u001b[0;36mSession.send\u001b[1;34m(self, request, **kwargs)\u001b[0m\n\u001b[0;32m 781\u001b[0m start \u001b[38;5;241m=\u001b[39m preferred_clock()\n\u001b[0;32m 783\u001b[0m \u001b[38;5;66;03m# Send the request\u001b[39;00m\n\u001b[1;32m--> 784\u001b[0m r \u001b[38;5;241m=\u001b[39m adapter\u001b[38;5;241m.\u001b[39msend(request, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n\u001b[0;32m 786\u001b[0m \u001b[38;5;66;03m# Total elapsed time of the request (approximately)\u001b[39;00m\n\u001b[0;32m 787\u001b[0m elapsed \u001b[38;5;241m=\u001b[39m preferred_clock() \u001b[38;5;241m-\u001b[39m start\n", "File \u001b[1;32me:\\AI大模型开发\\python_base\\.venv\\lib\\site-packages\\requests\\adapters.py:717\u001b[0m, in \u001b[0;36mHTTPAdapter.send\u001b[1;34m(self, request, stream, timeout, verify, cert, proxies)\u001b[0m\n\u001b[0;32m 714\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(e\u001b[38;5;241m.\u001b[39mreason, ConnectTimeoutError):\n\u001b[0;32m 715\u001b[0m \u001b[38;5;66;03m# TODO: Remove this in 3.0.0: see #2811\u001b[39;00m\n\u001b[0;32m 716\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(e\u001b[38;5;241m.\u001b[39mreason, NewConnectionError):\n\u001b[1;32m--> 717\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m ConnectTimeout(e, request\u001b[38;5;241m=\u001b[39mrequest)\n\u001b[0;32m 719\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(e\u001b[38;5;241m.\u001b[39mreason, ResponseError):\n\u001b[0;32m 720\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m RetryError(e, request\u001b[38;5;241m=\u001b[39mrequest)\n", "\u001b[1;31mConnectTimeout\u001b[0m: HTTPConnectionPool(host='en.wikipedia.org', port=80): Max retries exceeded with url: /w/api.php?list=search&srprop=&srlimit=1&limit=1&srsearch=AI%E4%B9%8B%E7%88%B6&format=json&action=query (Caused by ConnectTimeoutError(, 'Connection to en.wikipedia.org timed out. (connect timeout=None)'))" ] } ], "source": [ "#WikipediaQueryRun为例子\n", "#WikipediaQueryRun:用于向维基百科API发送查询并获取数据\n", "# pip install wikipedia -i https://pypi.tuna.tsinghua.edu.cn/simple\n", "from langchain_community.tools import WikipediaQueryRun\n", "from langchain_community.utilities import WikipediaAPIWrapper\n", "\n", "# top_k_results 收索结果的数量\n", "# doc_content_chars_max 单个Document的内容长度\n", "api_wrapper = WikipediaAPIWrapper(top_k_results=1, doc_content_chars_max=100)\n", "tool = WikipediaQueryRun(api_wrapper=api_wrapper)\n", "\n", "print(tool.name, tool.description, tool.args)\n", "\n", "tool.run({\"query\": \"AI之父\"})\n" ] }, { "cell_type": "code", "execution_count": null, "id": "18828223", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "get_weather\n", "查询指定城市的实时天气信息\n", "\n", " Args:\n", " location: 城市名称,如\"北京\"、\"成都\"\n", "{'location': {'title': 'Location', 'type': 'string'}}\n", "成都的天气:Mist,温度:24°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", "\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\"\n" ] }, { "cell_type": "code", "execution_count": null, "id": "71d065a5", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[{'name': 'get_weather', 'args': {'location': '成都'}, 'id': 'get_weather:0', 'type': 'tool_call'}]\n" ] } ], "source": [ "from langchain_core.messages import HumanMessage\n", "\n", "# bind_tools() 把工具的 Schema 注入到模型请求中\n", "llm_with_tools = llm.bind_tools([get_weather])\n", "\n", "# 此时模型已经\"知道\"你有一个叫 get_weather 的工具了\n", "messages = [HumanMessage(content=\"成都今天天气怎么样?\")]\n", "\n", "response = llm_with_tools.invoke(messages)\n", "\n", "# LLM的输出不再是一段自然语言文本,而是一个结构化的JSON对象(tool_calls)。\n", "#这个对象包含了要调用的函数名和所需的参数。\n", "print(response.tool_calls)\n", "# [{'name': 'get_weather', 'args': {'location': '成都'}, 'id': 'call_xxx', 'type': 'tool_call'}]" ] }, { "cell_type": "code", "execution_count": 34, "id": "823792fc", "metadata": {}, "outputs": [], "source": [ "from langchain.tools import tool\n", "from langchain.agents import create_agent\n", "from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder\n", "import requests\n", "\n", "# ─── 第一步:定义工具 ───\n", "@tool\n", "def get_weather(location: str) -> str:\n", " \"\"\"查询指定城市的天气\"\"\"\n", " url = f\"https://wttr.in/{location}?format=j1&lang=zh\"\n", " data = requests.get(url).json()\n", " current = data['current_condition'][0]\n", " desc = current['weatherDesc'][0]['value']\n", " temp = current['temp_C']\n", " return f\"{location}:{desc},{temp}°C\"\n", "\n", "@tool\n", "def multiply(a:int,b:int) ->int:\n", " \"\"\"实现两个整数相乘\"\"\"\n", " return a * b\n", "\n", "tools = [get_weather, multiply]\n", "\n", "# ─── 第三步:创建 Agent ───\n", "# create_agent 把模型、工具、prompt 组装成 Agent\n", "agent = create_agent(\n", " model=llm,\n", " tools=tools,\n", " system_prompt=\"你是一名智能助手,可以调用工具帮助用户解决问题。\"\n", ")\n", "\n", "\n", "\n" ] }, { "cell_type": "code", "execution_count": 35, "id": "11fef074", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "成都目前的天气是**有雾**,气温为**24°C**。\n", "\n", "天气比较温和,但有雾可能会影响能见度,出行请注意安全。\n", "{'messages': [HumanMessage(content='成都的天气怎么样?', additional_kwargs={}, response_metadata={}, id='9255999f-4ff4-474b-aec4-e47b0993466a'), AIMessage(content='', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 44, 'prompt_tokens': 95, 'total_tokens': 139, 'completion_tokens_details': None, 'prompt_tokens_details': None}, 'model_provider': 'openai', 'model_name': 'kimi-k2.6', 'system_fingerprint': None, 'id': 'chatcmpl-6a3fd32cded6d2a434bdf19f', 'finish_reason': 'tool_calls', 'logprobs': None}, id='lc_run--019f0950-e08c-7840-afcf-9e50699bff79-0', tool_calls=[{'name': 'get_weather', 'args': {'location': '成都'}, 'id': 'get_weather:0', 'type': 'tool_call'}], invalid_tool_calls=[], usage_metadata={'input_tokens': 95, 'output_tokens': 44, 'total_tokens': 139, 'input_token_details': {}, 'output_token_details': {}}), ToolMessage(content='成都:Mist,24°C', name='get_weather', id='ecbebc09-8cec-4eec-a6fa-9c2fbc6be296', tool_call_id='get_weather:0'), AIMessage(content='成都目前的天气是**有雾**,气温为**24°C**。\\n\\n天气比较温和,但有雾可能会影响能见度,出行请注意安全。', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 112, 'prompt_tokens': 139, 'total_tokens': 251, 'completion_tokens_details': None, 'prompt_tokens_details': None}, 'model_provider': 'openai', 'model_name': 'kimi-k2.6', 'system_fingerprint': None, 'id': 'chatcmpl-6a3fd32e331afd1aa3a978eb', 'finish_reason': 'stop', 'logprobs': None}, id='lc_run--019f0950-e99d-7af3-8608-be446873e747-0', tool_calls=[], invalid_tool_calls=[], usage_metadata={'input_tokens': 139, 'output_tokens': 112, 'total_tokens': 251, 'input_token_details': {}, 'output_token_details': {}})]}\n" ] } ], "source": [ "res = agent.invoke({\"messages\": [\n", " {\"role\": \"user\",\n", " \"content\": \"成都的天气怎么样?\"\n", " }]})\n", "print(res['messages'][-1].content)\n", "print(res)" ] }, { "cell_type": "code", "execution_count": 36, "id": "cea5f75d", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "5乘以6等于**30**。\n", "{'messages': [HumanMessage(content='5乘以6等于多少?', additional_kwargs={}, response_metadata={}, id='7964f818-144f-4f47-a96c-7072fe69b1c8'), AIMessage(content='', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 52, 'prompt_tokens': 97, 'total_tokens': 149, 'completion_tokens_details': None, 'prompt_tokens_details': None}, 'model_provider': 'openai', 'model_name': 'kimi-k2.6', 'system_fingerprint': None, 'id': 'chatcmpl-6a3fd33860f4459daab95ab2', 'finish_reason': 'tool_calls', 'logprobs': None}, id='lc_run--019f0951-0f28-7413-9ac0-df0e4861a9a3-0', tool_calls=[{'name': 'multiply', 'args': {'a': 5, 'b': 6}, 'id': 'multiply:0', 'type': 'tool_call'}], invalid_tool_calls=[], usage_metadata={'input_tokens': 97, 'output_tokens': 52, 'total_tokens': 149, 'input_token_details': {}, 'output_token_details': {}}), ToolMessage(content='30', name='multiply', id='d76b9a66-03c7-4ab2-b958-03437c7fb002', tool_call_id='multiply:0'), AIMessage(content='5乘以6等于**30**。', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 16, 'prompt_tokens': 137, 'total_tokens': 153, 'completion_tokens_details': None, 'prompt_tokens_details': None}, 'model_provider': 'openai', 'model_name': 'kimi-k2.6', 'system_fingerprint': None, 'id': 'chatcmpl-6a3fd33962827bf3d72d8082', 'finish_reason': 'stop', 'logprobs': None}, id='lc_run--019f0951-154f-7c42-b88a-102657827ef0-0', tool_calls=[], invalid_tool_calls=[], usage_metadata={'input_tokens': 137, 'output_tokens': 16, 'total_tokens': 153, 'input_token_details': {}, 'output_token_details': {}})]}\n" ] } ], "source": [ "res = agent.invoke({\"messages\": [\n", " {\"role\": \"user\",\n", " \"content\": \"5乘以6等于多少?\"\n", " }]})\n", "print(res['messages'][-1].content)\n", "print(res)" ] }, { "cell_type": "code", "execution_count": 9, "id": "7c640a07", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "input_variables=['concept'] input_types={} partial_variables={} template='请用一句话解释什么是{concept}'\n", "请用一句话解释什么是量子计算\n" ] } ], "source": [ "prompt = PromptTemplate.from_template(\"请用一句话解释什么是{concept}\")\n", "print(prompt)\n", "prompt_text = prompt.format(concept=\"量子计算\")\n", "print(prompt_text)" ] }, { "cell_type": "code", "execution_count": 11, "id": "93e6b631", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "first=PromptTemplate(input_variables=['concept'], input_types={}, partial_variables={}, template='请用一句话解释什么是{concept}') middle=[] last=ChatOpenAI(metadata={'lc_versions': {'langchain-core': '1.4.8', 'langchain': '1.3.1', 'langchain-openai': '1.3.3'}}, output_version=None, client=, async_client=, root_client=, root_async_client=, model_name='kimi-k2.6', model_kwargs={}, openai_api_key=SecretStr('**********'), openai_api_base='https://api.moonshot.cn/v1/', openai_proxy=None, stream_chunk_timeout=120.0)\n", "content='量子计算是利用量子比特的叠加与纠缠特性,通过并行处理海量状态组合,在特定问题上实现指数级加速的新型计算模式。' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 328, 'prompt_tokens': 14, 'total_tokens': 342, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 14}, 'cached_tokens': 14}, 'model_provider': 'openai', 'model_name': 'kimi-k2.6', 'system_fingerprint': None, 'id': 'chatcmpl-6a42382505f9bc9091f85259', 'finish_reason': 'stop', 'logprobs': None} id='lc_run--019f12ab-5057-7602-ae1f-005bbbab2831-0' tool_calls=[] invalid_tool_calls=[] usage_metadata={'input_tokens': 14, 'output_tokens': 328, 'total_tokens': 342, 'input_token_details': {'cache_read': 14}, 'output_token_details': {}}\n" ] } ], "source": [ "chain = prompt | llm\n", "# 只传最原始输入变量,中间填充、调用全部自动完成\n", "print(chain)\n", "result = chain.invoke({\"concept\": \"量子计算\"})\n", "print(result)" ] } ], "metadata": { "kernelspec": { "display_name": "defaultInterpreterPath: 3.10.8.final.0", "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.10.8" } }, "nbformat": 4, "nbformat_minor": 5 }