Python后端开发之旅四补充知识Notebook笔记本(Jupyter/Colab)在线 Notebook安装 JupyterUV通过安装依赖通过 Anaconda——View/Cell Toolbar/Slideshow启动Slide模式点击这里[魔法命令Magic Commands](https://jishuzhan.net/article/1884835672326410242)Python库和方法PyMuPDF、pypdfium2、pdfplumber、pdfminerjsonpython-dotenvnest-asyncionp.linalg.norm()Python进阶——LangChain✅ 1. LangChain 0.1.x vs 1.0版本演进与主要区别✅ 2. 快速入门 LangChain1.0 1. 安装 2. 核心概念图谱类比 Java 3. 基础组件详解✅ 3.1 LLM大语言模型使用 OpenAI最常见自定义 LLM 类高级用法——invoke()✅ 3.2 提示模板PromptTemplate✅ 3.3 工具Tools和工具包Toolkits自定义工具类似 Java 的 Service工具包Toolkit✅ 3.4 消息Messages与历史记录Memory消息格式类似聊天上下文记忆机制Memory✅ 3.5 输出解析Output Parsing目标让模型返回结构化数据如 JSON 使用 JsonOutputParser()✅ 3.6 回调处理Callbacks用于日志、追踪、调试✅ 3.7 LCELLangChain Expression Language示例一个简单的 LCEL 流程更复杂的例子带条件判断✅ 3. [调用方式区别](https://blog.csdn.net/cooldream2009/article/details/153470815)✅ 4. 搜索引擎提供上下文构建一个智能问答助手 功能️ 代码结构[与直接调用OpenAI API 区别](https://juejin.cn/post/7473373269888368692)补充知识Notebook笔记本(Jupyter/Colab)在线 Notebook登录之后https://anaconda.com/app/安装 JupyterVscode的jupyter插件交互没有 浏览器的好而且也不能安装额外 的插件更不能进行 演示 slide 的功能只能临时作为 不得已的交互方式obsidian 的 slide演示功能 画风比较黑暗而且内容过多的话 容易溢出屏幕可以通过修改css进行但是学习成本有点高所以着手 安装jupyter啦UV通过安装依赖UV 下载以及相关操作# vscode 的终端bash中操作## 进入虚拟环境uv venv--python/e/Lang/Python/Cpython/cpython-3.11.14-windows-x86_64-none source.venv/Scripts/activate## 开始安装依赖包uv init uv add jupyter--default-index https://pypi.tuna.tsinghua.edu.cn/simple 或者想要快速安装 uv pip install jupyter--default-index https://pypi.tuna.tsinghua.edu.cn/simple 或者没有uv的话 pip install jupyter-i https://pypi.tuna.tsinghua.edu.cn/simple## 启动后端服务jupyter--version jupyter notebook jupyter notebook/e/Lang# 修改启动目录jupyter notebook/d/Microsoft/个人简历/教书育人# 授课路径# 直接终端中——可能需要NPMNode Package Manager## 文件夹管理器wine- E:\Lang\LLM\.venv\Scripts bash jupyter notebook## cmdcd/d E:\Lang\LLM\.venv\Scripts jupyter notebook### 或者直接用参数形式启动jupyter notebook D:\Microsoft\个人简历\教书育人 jupyter notebook.# 当前目录启动通过 Anaconda——View/Cell Toolbar/Slideshow一般使用anaconda自带的Anaconda Promp进行操作Anaconda 安装以及 改变 Jupyter 的启动目录启动Slide模式点击这里“魔法命令”Magic Commands是一些以百分号%或惊叹号!)开头的特殊命令用于执行一些与代码运行环境相关的操作%开头的魔法命令分为两类行魔法命令Line Magic和单元魔法命令Cell Magic。行魔法命令以单%开头作用于单行代码单元魔法命令以双%%开头作用于整个代码单元!开头的命令用于在 Jupyter Notebook 中执行系统命令类似于在终端中运行命令%lsmagic列出所有可用的魔法命令!调用shell在新进程中而%影响与笔记本电脑相关的进程或笔记本电脑本身许多%命令没有shell对应项!cd foo本身没有持久效果因为更改目录的进程会立即终止。%cd foo更改笔记本电脑进程的当前目录这是一种持久效果对于pip命令的区别%运行shell的环境是当前jupyter运行的虚拟环境比如kernel 是pytorch输入%pip list就会显示当前虚拟环境安装的库!运行shell的环境是jupyter的base主环境输入!pip list就会显示主环境安装的库Python库和方法PyMuPDF、pypdfium2、pdfplumber、pdfminerpdfminer是最早的Python PDF处理库之一pdfplumber专注于PDF文本和表格提取建立在pdfminer.six的基础上提供更完整的表格提取功能pypdfium2是PDFium库的Python绑定,PDFium是Google Chrome浏览器使用的PDF引擎PyMuPDF是MuPDF库的Python绑定基于C的MuPDF库性能极高PDF处理生态系统 ├── 底层引擎 │ ├── MuPDF(C)→ PyMuPDF │ ├── PDFium(C)→ pypdfium2 │ └── pdfminer(Python)→ pdfplumber ├── 功能定位 │ ├── 全功能处理PyMuPDF,pypdfium2 │ ├── 文本提取pdfplumber,pdfminer │ └── 表格提取pdfplumber └── 性能层次 ├── 高性能PyMuPDF,pypdfium2 └── 中等性能pdfplumber,pdfminerjsonJson库供用户处理Json格式数据包括4种方法dumps()——将python对象转成json格式的字符串loads()——对字符串进行操作的dump()——将python对象转成json格式存入文件load()——对文件进行操作为了方便记忆可以把loads后面的小尾巴s理解为str不是文件名后缀为.json的才属于json文件无论有没有后缀或者后缀是.txt等只要文件内容符合下面的格式都可以使用这些函数dict{“姓名”: “张三”, “年龄”: 18}list[“张三”, “李四”]字符串“张三李四王五” 注意必须有双引号纯数字123json.dumps()和json.dump()的详细参数ensure_ascii参数使用ensure_asciiFalse输出原始Unicode字符默认情况下ensure_asciiTrue非ASCII字符会被转义indent参数使用indent参数进行美化输出默认为 None用于指定每个层级的缩进空格数此时输出的JSON数据将尽可能紧凑json.loads()和json.load()的详细参数python-dotenvpython-dotenv是一个用于从 .env 文件读取键值对并加载为环境变量的库常用于管理敏感信息和配置符合 12-factor 应用原则可以把所有用到的环境变量写到.env文件里然后以kv的方式读取作为环境变量从当前目录或其父目录中的.env文件或指定的路径加载环境变量pip install python-dotenv# 自动搜索 .env 文件load_dotenv()# 或指定路径# load_dotenv(dotenv_pathconfig/.env, overrideTrue)# 获取变量db_url os.getenv(DATABASE_URL)secret os.getenv(SECRET_KEY)print(db_url,secret)# 对于多环境配置可按优先级加载forenv_file in(.env,.env.local): load_dotenv(env_file)nest-asyncionest_asyncio 是一个轻量级 Python 库用于修补解决Python asyncio事件循环在嵌套场景下的限制。它允许在已经运行的事件循环中再次运行事件循环允许嵌套运行异步代码在Jupyter Notebook中运行异步代码特别适合在 Jupyter Notebook、交互式 shell 或需要嵌套异步操作的场景中嵌套事件循环允许在现有 asyncio 事件循环中运行新的异步代码解决RuntimeError: This event loop is already runningpip install nest-asyncio# 修补 asyncionest_asyncio.apply()async def inner_task(): await asyncio.sleep(1)print(Inner task completed)async def outer_task(): print(Outer task started)await inner_task()print(Outer task completed)# 在已有事件循环中运行loop asyncio.get_event_loop()loop.run_until_complete(outer_task())np.linalg.norm()linalglinear线性algebra代数norm则表示范数。函数参数x_normnp.linalg.norm(x,ordNone,axisNone,keepdimsFalse)①x: 表示矩阵也可以是一维②ord 范数类型③axis处理类型axis1表示按行向量处理求多个行向量的范数axis0表示按列向量处理求多个列向量的范数axisNone表示矩阵范数。④keepding是否保持矩阵的二维特性默认参数ordNoneaxisNonekeepdimsFalse’def cosine_similarity(vec1,vec2): 计算两个向量之间的余弦相似度。 参数: vec1 (np.ndarray): 第一个向量。 vec2 (np.ndarray): 第二个向量。 返回: float: 两个向量之间的余弦相似度。 # 计算两个向量的点积并除以它们范数的乘积returnnp.dot(vec1,vec2)/(np.linalg.norm(vec1)*np.linalg.norm(vec2))Python进阶——LangChain✅ 1. LangChain 0.1.x vs 1.0版本演进与主要区别LangChain 的第一个稳定版本即 LangChain 0.1.0于 2024 年 1 月 8 日正式发布这是一个值得庆祝的里程碑也是 LangChain 项目的一个新的起点LangChain 的版本号由三个部分组成即主版本号、次版本号和修订号分别表示 LangChain 的大的、中等的和小的更新。例如LangChain 0.1.0 表示 LangChain 的第 0 个主版本第 1 个次版本第 0 个修订版本特性LangChain 0.1.x旧版LangChain 1.0新版发布时间2024 年 1 月 8 日2025年10月23日核心理念模块松散流程不统一统一、可组合、强类型 关键总结0.1.x → 多个独立类如LLMChain,AgentExecutor1.0 → 统一Runnable接口所有组件都是Runnable模块重组代码也得改变✅ 2. 快速入门 LangChain1.0 1. 安装pipinstalllangchain langchain-openai# 以 OpenAI 为例 你也可以用其他 LLM 提供商如 Anthropic、Cohere、Claude、Google Vertex AI DeepSeek等 2. 核心概念图谱类比 JavaLangChain 概念类比 Java 开发说明LLMRestTemplate/FeignClient调用大模型 APIPromptTemplateString.format()Value动态生成提示词RunnableFunctionT, R/SupplierT所有组件都实现此接口ChainServiceController逻辑处理 链ToolComponentAutowired工具函数用于 AgentMemorySession/Cache记忆历史对话LCELSpring Expression Language链式表达式语法 (CallbackInterceptor/AOP日志、监控、追踪chain {“context”: 本地Rag或者工具搜索 , “input”: RunnablePassthrough()} |prompt | llm | JsonOutputParser()Conversational(Agent)用于与用户进行自然对话并接收用户提出的问题根据提问内容选择具体使用的处理工具RetrievalQA(Retriever)用于从自定义资料集中检索相关内容。DuckDuckGoSearchRun(tool): 用于访问DuckDuckGoSearch搜索APIPrompts Structured output parser(ModelIO)用于定义接收对话的模板以及结构化搜索引擎查询到的结果并生成一个简洁和准确的回答。SequentialChain(Chain)用于按照顺序执行以上组件并将每个组件的输出作为下一个组件的输入ConversationBufferMemory(Memory)用于在对话中记住以前的交互置以便在后续的对话中使用。StdOutCallbackHandler标准输出用于进行日志记录。 3. 基础组件详解大部分都是通过lanchain_core进行导入的通过from langchain_community.tools import DuckDuckGoSearchRun会导入 社区的工具包还有一部分通过lanchain导入的是 比较顶层的 工具了比如from langchain.callbacks import StdOutCallbackHandler进行调式跟踪✅ 3.1 LLM大语言模型使用 OpenAI最常见fromlangchain_openaiimportChatOpenAI llmChatOpenAI(modelgpt-4-turbo,temperature0.7) 你可以通过os.getenv(OPENAI_API_KEY)读取密钥自定义 LLM 类高级用法——invoke()fromlangchain_core.runnablesimportRunnableclassCustomLLM(Runnable):definvoke(self,input:str,config:dictNone):# 实现自己的大模型调用逻辑returnfCustom response to:{input}# 使用custom_llmCustomLLM()resultcustom_llm.invoke(Hello)print(result)✅ 这样就可以把你的私有模型或本地模型接入 LangChain✅ 3.2 提示模板PromptTemplate使用format()进行填入fromlangchain_core.promptsimportPromptTemplate promptPromptTemplate.from_template(You are a helpful assistant. Answer the question: {question})# 生成最终提示formatted_promptprompt.format(questionWhat is Python?)print(formatted_prompt)# 输出: You are a helpful assistant. Answer the question: What is Python?✅ 支持变量替换可用于动态生成提示✅ 3.3 工具Tools和工具包Toolkits自定义工具类似 Java 的 Servicefromlangchain_core.toolsimporttoolimportrequeststooldefget_weather(city:str)-str:获取指定城市的天气urlfhttps://api.weather.com/forecast?city{city}responserequests.get(url)returnresponse.json()[temperature]ifresponse.okelseError工具包Toolkitfromlangchain_community.toolsimportDuckDuckGoSearchRun search_toolDuckDuckGoSearchRun()✅ 工具可以被 Agent 调用实现“查询互联网”功能✅ 3.4 消息Messages与历史记录Memory消息格式类似聊天上下文消息是LangChain中对话交互的基本单元分为两类HumanMessage表示用户输入如提问或指令AIMessage表示AI模型的响应fromlangchain_core.messagesimportHumanMessage,AIMessage messages[HumanMessage(contentHello),AIMessage(contentHi! How can I help?)]记忆机制Memory记忆模块用于持久化存储和管理对话历史常见类型包括ConversationBufferMemory完整保存所有对话记录ConversationBufferWindowMemory仅保留最近N轮对话ConversationSummaryMemory用LLM摘要压缩长对话fromlangchain.memoryimportConversationBufferMemory memoryConversationBufferMemory()memory.chat_memory.add_user_message(Hello)memory.chat_memory.add_ai_message(Hi! How can I help?)保存对话历史供后续调用如多轮对话上下文支持通过memory.load_memory_variables()读取历史✅ 类似 Session但持久化更灵活✅ 3.5 输出解析Output Parsing目标让模型返回结构化数据如 JSON 使用 JsonOutputParser()fromlangchain_core.output_parsersimportJsonOutputParserfromlangchain_core.promptsimportPromptTemplate parserJsonOutputParser()promptPromptTemplate(templateAnswer only in JSON format: {question},input_variables[question])chainprompt|llm|parser resultchain.invoke({question:Who is the CEO of Tesla?})print(result)# 输出: {name: Elon Musk}✅ 避免模型返回自由文本提升结构化能力✅ 3.6 回调处理Callbacks用于日志、追踪、调试fromlangchain.callbacksimportStdOutCallbackHandler callbacks[StdOutCallbackHandler()]llm.invoke(Hello,callbackscallbacks)✅ 可扩展为LangChainTracer、LangSmithCallbackHandler企业级追踪LangChain 借助LangSmith提供了更好的日志、可视化、播放和跟踪功能以便监控和调试 LLM 应用。LangSmith 是一个基于 Web 的工具用于可视化和控制 LangChain 的链和代理能够查看和分析 细化到class的输入和输出✅ 3.7 LCELLangChain Expression Language用|链接模块像流水线一样执行就像unix的管道机制示例一个简单的 LCEL 流程fromlangchain_core.promptsimportPromptTemplatefromlangchain_core.runnablesimportRunnableLambda,RunnableSequence# 1. 提示模板promptPromptTemplate.from_template(Translate this to English: {text})# 2. Lambda 函数转成大写uppercaseRunnableLambda(lambdax:{text:x[text].upper()})# 3. 链接先转大写再翻译chainuppercase|prompt|llm# 执行resultchain.invoke({text:你好世界})print(result.content)RunnableLambda将普通 Python 函数包装为LangChain 可执行的组件RunnableBranch 是 LangChain 中用于根据条件选择不同执行路径的组件RunnableBranch 接受多个条件判断对condition, component以及一个默认的 fallback 函数每个条件判断对的结构是(condition, component)其中condition 是一个函数用于判断输入是否满足某个条件。component 是一个可执行的组件如 RunnableLambda如果条件满足则会执行该组件。如果所有条件都不满足则执行最后一个 fallback 函数更复杂的例子带条件判断fromlangchain_core.runnablesimportRunnableBranch branchRunnableBranch((lambdax:x[text].startswith(hello),lambdax:Hello!),(lambdax:x[text].startswith(hi),lambdax:Hi!),lambdax:Unknown greeting)resultbranch.invoke({text:hello world})✅ 3.调用方式区别invoke()一次性同步调用等待完整输出后返回。stream()流式异步调用边生成边返回。就是流式响应LangChain会将这些结果作为生成器逐步返回开发者可在接收到每个分片chunk时进行实时处理或显示有时我们既想实时输出又想保存完整结果chunks[]forchunkinllm.stream(请解释RAG的原理。):print(chunk.content,end,flushTrue)chunks.append(chunk.content)full_output.join(chunks)✅ 4. 搜索引擎提供上下文构建一个智能问答助手 功能接收用户问题使用 LLM 生成回答支持简单工具如搜索保留聊天历史️ 代码结构fromlangchain_core.promptsimportChatPromptTemplatefromlangchain_core.runnablesimportRunnablePassthrough,RunnableSequencefromlangchain_core.messagesimportHumanMessage,AIMessagefromlangchain_openaiimportChatOpenAIfromlangchain_community.toolsimportDuckDuckGoSearchRunfromlangchain_community.utilitiesimportWikipediaAPIWrapperfromlangchain_core.output_parsersimportStrOutputParser# 1. 初始化 LLMllmChatOpenAI(modelgpt-4-turbo)# 2. 定义工具search_toolDuckDuckGoSearchRun()wikipediaWikipediaAPIWrapper()# 3. 创建提示模板promptChatPromptTemplate.from_messages([(system,You are a helpful assistant.请根据以下上下文回答问题{context}),(human,{question})])# 4. 构建 LCEL 流程chain({question:RunnablePassthrough(),context:RunnableLambda(lambdax:search_tool.invoke(x[question]))}|prompt|llm|StrOutputParser())# 5. 运行resultchain.invoke({question:Who is Elon Musk?})print(result)使用 LangChain 表达式语言LCEL构建处理流程接收输入问题并原样传递RunnablePassthrough使用搜索工具获取问题相关上下文将问题和上下文传递给提示模板将模板输出传递给LLM最后使用字符串输出解析器使用LangChain构建一个结合外部搜索的问答系统。检索到的信息会作为上下文提供给LLM帮助生成更准确的回答与直接调用OpenAI API 区别维度LangChain集成直接OpenAI API调用架构设计模块化框架支持链式操作和Agent决策单点API请求需手动处理上下文数据处理内置文档加载/向量检索/记忆管理需自行实现数据预处理和存储逻辑开发效率通过预置组件快速搭建复杂流程如RAG适合简单问答场景复杂逻辑需重复造轮子多模型支持可混合调用不同模型如DeepSeekStable Diffusion单一模型交互跨模型协同需额外开发适用场景知识库问答/自动化办公/复杂决策系统简单文本生成/翻译/基础对话可维护性标准化组件便于团队协作和代码维护需要自定义实现可维护性依赖于代码质量扩展性易于添加新功能和集成新模型扩展需要修改核心代码在需要精细控制部分环节时可组合使用两者如用LangChain处理数据流关键节点直接调API