|
|
@@ -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
|
|
|
-}
|