diff --git a/README.md b/README.md
index c804afb..b845933 100644
--- a/README.md
+++ b/README.md
@@ -10907,3 +10907,4675 @@ public JsonData list(@RequestParam(value = "parent_id")Long parentId){
* **调试技巧**:使用 `RunnableLambda` 插入日志或数据检查点。
* **容错设计**:结合 `RunnableBranch` 和 提升健壮性
+### 进阶LLM之Agent智能体和Tool工具实战
+
+#### 大模型Agent智能体介绍和应用场景
+
+* 什么是智能体Agent
+
+ * 是一种**具备自主决策能力的AI系统**,通过感知环境、分析信息、调用工具、执行动作的闭环过程完成任务
+
+ * 智能体 = 大语言模型(LLM) + 工具(Tools) + 记忆(Memory)
+
+ * 核心架构
+
+ ```
+ 用户输入 → 大模型推理 → 工具选择 → 执行工具 → 结果验证 → 输出响应
+ ↑ ↓ ↑
+ 记忆系统 ↔ 工具库 ↔ 知识库
+ ```
+
+ * 类比:一个具备自主决策能力的虚拟助手,能根据目标自主调用工具完成任务
+
+
+
+
+
+ * 与传统LLM的关键区别
+
+ | 维度 | 常规LLM | Agent |
+ | :------: | :-----------: | :---------------: |
+ | 交互方式 | 单轮问答 | 多轮决策链 |
+ | 能力范围 | 文本生成 | 工具调用+环境交互 |
+ | 记忆机制 | 短期上下文 | 长期记忆存储 |
+ | 输出形式 | 自然语言 | 结构化动作序列 |
+ | 应用场景 | 内容创作/问答 | 复杂任务自动化 |
+
+
+
+ * 常规大模型和Agent案例场景对比
+
+ | 测试用例 | 传统模式响应 | Agent模式响应 |
+ | :--------------: | :----------: | :---------------------------: |
+ | "北京天气" | 温度数据 | "北京当前晴,12℃,建议穿外套" |
+ | "明天需要带伞吗" | 无法处理 | 调用天气API分析降水概率 |
+ | "上周三天气如何" | 报错 | 自动切换历史天气数据库工具 |
+
+
+
+* 典型应用场景
+
+ * 医疗行业 - 诊断辅助Agent
+
+ * 传统系统痛点:
+
+ * 基于固定规则的专家系统、无法处理复杂症状组合、知识更新依赖人工维护
+
+ * Agent方案关键能力
+
+ * 结合最新医学论文(通过工具实时检索,常规大模型没法获取最新数据)
+ * 自动生成检查建议清单
+ * 保留患者完整诊疗历史
+
+ ```python
+ medical_agent = AgentExecutor(
+ tools=[
+ SymptomAnalyzerTool,
+ MedicalLiteratureTool,
+ LabTestRecommenderTool
+ ],
+ memory=PatientHistoryMemory()
+ )
+
+ # 交互示例
+ response = medical_agent.invoke({
+ "input": "患者女35岁,持续低烧两周,伴有关节痛",
+ "history": "既往有类风湿病史"
+ })
+ # 输出:建议进行抗核抗体检测+推荐专科医生
+ ```
+
+ * 教育行业 - 个性化学习Agent
+
+ * 传统在线教育
+
+ ```python
+ // 固定学习路径
+ public class LearningService {
+ public String getNextStep(String userId) {
+ int score = db.getUserScore(userId);
+ if (score < 60) {
+ return "重新学习第三章";
+ }
+ return "进入第四章";
+ }
+ }
+ ```
+
+ * Agent方案关键能力
+
+ * 动态调整学习路径(基于实时掌握程度)
+ * 多模态教学内容推荐(视频/图文/交互实验)
+ * 自动生成错题分析报告
+
+ ```python
+ class TutorAgent:
+ tools = [
+ KnowledgeGraphTool,
+ ExerciseRecommenderTool,
+ LearningStyleAnalyzerTool
+ ]
+
+ def guide_student(self, studentQuery):
+ # 动态决策:
+ # 1. 分析学生知识薄弱点
+ # 2. 根据学习风格推荐资料
+ # 3. 生成个性化练习计划
+ return self.agent_executor.invoke(studentQuery)
+
+ ```
+
+* Agent智能体案例(伪代码)
+
+ ```python
+ from langchain.agents import AgentExecutor, create_react_agent
+ from langchain import hub
+
+ # 定义工具集
+ tools = [
+ Tool(
+ name="WeatherCheck",
+ func=get_weather_api_data,
+ description="查询实时天气数据"
+ ),
+ Tool(
+ name="CalendarAccess",
+ func=read_google_calendar,
+ description="访问用户日历信息"
+ )
+ ]
+
+ # 构建Agent
+ prompt = hub.pull("hwchase17/react")
+ agent = create_react_agent(
+ llm=ChatOpenAI(temperature=0),
+ tools=tools,
+ prompt=prompt
+ )
+
+ # 执行示例
+ agent_executor = AgentExecutor(agent=agent, tools=tools)
+ result = agent_executor.invoke({
+ "input": "帮我安排明天北京的户外会议,需要考虑天气情况"
+ })
+ print(result["output"])
+
+
+ #典型输出示例
+ 思考过程:
+ 1. 需要确定明天北京的天气(调用WeatherCheck)
+ 2. 查询明天下午2点的天气预报
+ 3. 如果天气适宜,查找明天下午的空闲时段(调用CalendarAccess)
+ 4. 综合结果建议会议时间
+ 最终输出:建议将会议安排在明天下午15:00,天气预报显示晴,气温22℃。
+ ```
+
+
+#### 大模型痛点和LangChain工具Tool实战
+
+* 需求背景:
+
+ * **大模型的短板**:虽然大语言模型(LLM)擅长文本生成,但缺乏:
+ - 实时数据获取能力(如天气/股票)、精确数学计算能力
+ - 专业领域知识(如法律/医疗)、外部系统对接能力
+
+ * Tool工具就是解决这类问题的,通过Tool机制,好比给大模型插入翅膀
+
+* 大模型的Tool工具
+
+ * Tool是LLM与外部世界交互的接口,让大模型能调用外部功能(如API、函数、数据库)
+
+ * 核心
+
+ * 突破大模型静态知识库限制
+ * 实时获取外部数据(如天气/股票)
+ * 执行复杂计算业务逻辑
+ * 连接现有软件系统(如CRM、各个系统API)
+
+ * 工具生命周期
+
+ ```
+ 工具定义 → 2. Agent注册 → 3. 自动调用 → 4. 结果处理
+ ```
+
+* LangChain里面创建工具
+
+ * @tool装饰器
+ * 通过简单的@tool装饰器或StructuredTool即可实现,适用于大多数用例,
+ * @tool但不能同时有同步和异步的方法,只能单独使用
+ * LangChain Runnables
+ * 接受字符串或字典输入的LangChain Runnables使用as_tool方法转换为工具
+ * 允许为参数指定名称、描述和其他模式信息;
+ * 继承BaseTool类:
+ * 通过从BaseTool进行子类化来定义自定义工具,提供了对工具定义的最大控制,但需要编写更多的代码。
+
+
+
+* LangChain里面Tool实战
+
+ * **@tool 装饰器**:用来定义一个简单的工具函数,, 可以直接给函数加上这个装饰器,让函数成为可调用的工具
+
+ * 简单定义, **需要加上文档字符串注释描述,AI才知道工具的用途**
+
+ ```
+ from langchain_core.tools import tool
+
+ @tool
+ def multiply(a: int, b: int) -> int:
+ """把传递的两个参数相乘"""
+ return a * b
+
+ print("工具名称:", multiply.name)
+ print("工具描述:", multiply.description)
+ print("工具参数:", multiply.args)
+ print("工具返回值:", multiply.return_direct)
+ print("工具详细的schema:",multiply.args_schema.model_json_schema())
+
+ print(multiply.invoke({"a": 2, "b": 3}))
+ #定义了一个 `multiply` 工具,用于两个数字相乘,并在调用时显示该工具的名称、描述和参数列表。
+ ```
+
+ * 配置参数
+
+ ```python
+ from pydantic import BaseModel, Field
+ from langchain_core.tools import tool
+
+ class CalculatorInput(BaseModel):
+ a: int = Field(description="第一个参数")
+ b: int = Field(description="第二个参数")
+
+ @tool("multiplication-tool", args_schema=CalculatorInput, return_direct=True)
+ def multiply(a: int, b: int) -> int:
+ """Multiply two numbers."""
+ return a * b
+
+
+ # Let's inspect some of the attributes associated with the tool.
+ print("工具名称:", multiply.name)
+ print("工具描述:", multiply.description)
+ print("工具参数:", multiply.args)
+ print("工具返回值:", multiply.return_direct)
+ print("工具详细的schema:",multiply.args_schema.model_json_schema())
+ ```
+
+ * 核心组件
+
+ | **组件** | **作用** | **示例** |
+ | :---------------------------- | :--------------------------------------------------------- | :----------------------------- |
+ | **名称(name)** | 工具唯一标识符,代理通过名称匹配调用工具 | `wikipedia`、`google_search` |
+ | **描述(description)** | 工具功能的自然语言描述,代理根据描述决定是否调用工具 | "查询维基百科内容" |
+ | **输入参数(args_schema)** | 定义工具的参数格式(Pydantic模型),用于参数校验与提示生成 | `query: str` |
+ | **执行函数(func)** | 实际执行操作的函数(如调用API、运行Shell命令) | `def run(query: str): ...` |
+ | **返回模式(return_direct)** | 若为`True`,代理直接返回工具结果,不再生成额外文本 | 适用于无需进一步推理的简单任务 |
+
+* `StructuredTool ` 介绍
+
+ * 是LangChain中用于定义**结构化参数工具**的基类,相比普通`@tool`装饰器,它支持:
+ - **严格的参数模式定义**(基于Pydantic模型)
+ - **多参数输入校验**
+ - **自动生成工具调用示例**
+ * **适用场景**:需要多个输入参数或复杂参数类型的工具
+
+ | **特性** | **普通@tool装饰器** | **StructuredTool** |
+ | :------------- | :--------------------------- | :------------------------------- |
+ | **参数定义** | 简单参数(单个字符串或字典) | 基于Pydantic模型的严格参数模式 |
+ | **参数校验** | 弱校验(依赖代码逻辑) | 强校验(自动类型检查和格式验证) |
+ | **多参数支持** | 需手动解析字典参数 | 直接映射多个命名参数 |
+ | **使用复杂度** | 快速定义简单工具 | 适合复杂业务逻辑的工具 |
+
+ * 案例实战
+
+ ```python
+ from pydantic import BaseModel, Field
+ from langchain_core.tools import StructuredTool
+
+ # 定义输入参数的数据结构
+ class CalculatorInput(BaseModel):
+ a: int = Field(description="第一个数字")
+ b: int = Field(description="第二个数字")
+
+ # 定义计算函数
+ def multiply(a: int, b: int) -> int:
+ """Multiply two numbers."""
+ return a * b
+
+ # 封装工具
+ calculator = StructuredTool.from_function(
+ func=multiply,
+ name="Calculator",
+ description="用于计算两个数字的乘积",
+ args_schema=CalculatorInput,
+ return_direct=True,
+ )
+
+ print("工具名称:", calculator.name)
+ print("工具描述:", calculator.description)
+ print("工具参数:", calculator.args)
+ print("工具返回值:", calculator.return_direct)
+ print("工具详细的schema:",calculator.args_schema.model_json_schema())
+
+ # 调用工具
+ print("工具调用结果:", calculator.invoke({"a": 2, "b": 3}))
+ ```
+
+* 使用继承`BaseTool`子类进行创建工具
+
+ ```python
+ from pydantic import BaseModel, Field
+ from typing import Type
+ from langchain_core.tools import BaseTool
+ from pydantic import BaseModel
+
+
+ class CalculatorInput(BaseModel):
+ a: int = Field(description="第一个参数")
+ b: int = Field(description="第二个参数")
+
+
+ class CustomCalculatorTool(BaseTool):
+ name: str = "Calculator"
+ description: str = "当你需要计算数学问题时候使用"
+ args_schema: Type[BaseModel] = CalculatorInput
+ return_direct: bool = True
+
+ def _run(
+ self, a: int, b: int
+ ) -> str:
+ """使用工具."""
+ return a * b
+
+
+ calculator = CustomCalculatorTool()
+ print("工具名称:", calculator.name)
+ print("工具描述:", calculator.description)
+ print("工具参数:", calculator.args)
+ print("工具返回值:", calculator.return_direct)
+ print("工具详细的schema:",calculator.args_schema.model_json_schema())
+
+ print(calculator.invoke({"a": 2, "b": 3}))
+ ```
+
+
+#### LLM大模型绑定工具Tool案例实战
+
+* 需求
+
+ * 定义了工具,需要把工具绑定给大模型, 大模型会在合适的时候,选择对应的工具函数
+ * **解决痛点**:如天气查询/股票数据/订单处理等需要实时数据的场景
+ * **类比理解**:给大模型装"手和脚",像钢铁侠的AI助手贾维斯可操作战甲
+ * 注意
+ * 虽然“工具调用”这个名称暗示模型直接执行某些操作,但实际上并非如此!
+ * 模型仅生成工具的参数,实际运行工具(或不运行)取决于用户的需求
+
+
+| 要素 | 作用 | 示例 |
+| :------: | :------------------------------: | :------------------------------: |
+| 工具描述 | 告诉模型工具的功能和使用方法 | 天气查询API的输入输出说明 |
+| 参数解析 | 从自然语言中提取结构化参数 | 提取"北京今天温度"中的城市和日期 |
+| 执行反馈 | 将工具返回结果重新组织成自然语言 | 把JSON天气数据转为口语化描述 |
+
+ * 技术实现流程
+
+ ```
+ 用户输入 → 大模型分析意图 → 选择工具 → 提取参数 → 调用工具 → 结果格式化 → 最终回复
+ ```
+
+* 大模型绑定工具api
+
+ * 支持工具调用功能的聊天模型, 直接使用`.bind_tools( )`方法,传入工具列表即可
+
+ ```python
+ def bind_tools(
+ self,
+ tools: Sequence[Union[Dict[str, Any], Type, Callable, BaseTool]],
+ *,
+ tool_choice: Optional[
+ Union[dict, str, Literal["auto", "none", "required", "any"], bool]
+ ] = None,
+ strict: Optional[bool] = None,
+ parallel_tool_calls: Optional[bool] = None,
+ **kwargs: Any,
+ ) -> Runnable[LanguageModelInput, BaseMessage]:
+ ```
+
+ * 注意:不是全部大模型都是支持绑定工具列表,
+
+ * 大模型绑定工具的伪代码参考
+
+ ```python
+ tools = [add, multiply]
+ from langchain_openai import ChatOpenAI
+ llm = ChatOpenAI(model="gpt-4o-mini")
+ llm_with_tools = llm.bind_tools(tools)
+ query = "What is 3 * 12?"
+ resp = llm_with_tools.invoke(query)
+ ```
+
+
+
+* 工具调用
+
+ * 第一步
+
+ * 大模型如果需要调用工具,则生成响应里面包括了工具调用信息,本身的content内容为空
+
+ * 大模型响应的消息 或消息块 作为工具调用对象的列表,位于`.tool_calls`属性中。
+
+ * 聊天模型可以同时调用多个工具, 包含 工具名称、参数值字典和(可选)标识符的类型字典。
+
+ * 没有工具调用的消息 默认将此属性设置为空列表
+
+ ```python
+ # 使用绑定工具的模型处理用户查询
+ ai_msg = llm_with_tools.invoke(messages)
+
+ # 打印ai_msg对象的tool_calls属性,显示AI消息中包含的工具调用信息
+ print(ai_msg.tool_calls)
+
+ {'tool_calls':
+ [
+ {
+ 'id': 'call_ea723d86cf804a088b946a',
+ 'function': {'arguments': '{"a": 3, "b": 12}', 'name': 'multiply'},
+ 'type': 'function', 'index': 0}
+ ]
+ }
+ ```
+
+ * 第二步
+
+ * 提取大模型响应信息里面的选择的工具,代码编写 选择对应的工具进行执行
+
+ ```python
+ # 遍历AI消息中的工具调用
+ for tool_call in ai_msg.tool_calls:
+ # 根据工具调用的名称选择相应的工具函数
+ selected_tool = {"add": add, "multiply": multiply}[tool_call["name"].lower()]
+ print(f"selected_tool:{selected_tool}")
+ # 调用选中的工具函数并获取结果
+ tool_msg = selected_tool.invoke(tool_call)
+ print(f"tool_msg:{tool_msg}")
+ # 将工具调用的结果添加到messages列表中
+ messages.append(tool_msg)
+ ```
+
+ * `invoke()`执行后,会生成执行结果对象 `ToolMessage`, 包括与模型生成的原始工具调用中的 `id` 匹配的 `tool_call_id`
+
+ ```
+ ToolMessage(content='36', name='multiply', tool_call_id='call_1319a58494c54998842092')]
+ ```
+
+ * 第三步
+
+ * 将工具调用的结果添加到消息messages列表中,再传递给大模型,大模型会重新进行执行,组织对应的语言返回
+
+ ```python
+ # 再次使用绑定工具的模型处理更新后的messages列表
+ reslut = llm_with_tools.invoke(messages)
+ # 打印最终结果
+ print(f"最终结果:{reslut}")
+
+
+ 最终结果: content='3 乘以 12 的结果是 36。' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 16, 'prompt_tokens': 272, 'total_tokens': 288, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'qwen-plus', 'system_fingerprint': None, 'id': 'chatcmpl-b499cd0b-29d4-9d83-8473-e41d7214223d', 'finish_reason': 'stop', 'logprobs': None} id='run-8046aa25-091a-4df3-a49a-aa36811c8d44-0' usage_metadata={'input_tokens': 272, 'output_tokens': 16, 'total_tokens': 288, 'input_token_details': {'cache_read': 0}, 'output_token_details': {}}
+ ```
+
+ 
+
+ 
+
+* 完整案例实战
+
+ ```python
+ from langchain_core.tools import tool
+ from langchain_openai import ChatOpenAI
+ from langchain_core.messages import HumanMessage
+
+ # 定义一个加法工具函数
+ @tool
+ def add(a: int, b: int) -> int:
+ """Adds a and b."""
+ return a + b
+
+ # 定义一个乘法工具函数
+ @tool
+ def multiply(a: int, b: int) -> int:
+ """Multiplies a and b."""
+ return a * b
+
+ # 定义模型
+ llm = ChatOpenAI(
+ model_name = "qwen-plus",
+ base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
+ api_key="sk-005c3c25f6d042848b29d75f2f020f08",
+ temperature=0.7
+ )
+
+ # 将前面定义的工具函数整合到一个列表中
+ tools = [add, multiply]
+
+ # 将工具函数绑定到语言模型
+ llm_with_tools = llm.bind_tools(tools)
+
+ # 定义用户查询
+ query = "3 * 12 结果是多少"
+
+ # 创建一个包含用户查询的messages列表
+ messages = [HumanMessage(query)]
+
+ # 使用绑定工具的模型处理用户查询
+ ai_msg = llm_with_tools.invoke(messages)
+
+ # 打印ai_msg对象,以便用户可以看到AI的消息响应
+ print(ai_msg)
+
+ # 打印ai_msg对象的tool_calls属性,显示AI消息中包含的工具调用信息
+ print(ai_msg.tool_calls)
+
+ # 将AI的消息添加到messages列表中
+ messages.append(ai_msg)
+
+ # 遍历AI消息中的工具调用
+ for tool_call in ai_msg.tool_calls:
+ # 根据工具调用的名称选择相应的工具函数
+ selected_tool = {"add": add, "multiply": multiply}[tool_call["name"].lower()]
+ print(f"selected_tool:{selected_tool}")
+ # 调用选中的工具函数并获取结果
+ tool_msg = selected_tool.invoke(tool_call)
+
+ print(f"tool_msg:{tool_msg}")
+ # 将工具调用的结果添加到messages列表中
+ messages.append(tool_msg)
+
+ # 打印更新后的messages列表
+ print(f"打印更新后的messages列表:{messages}")
+
+ # 再次使用绑定工具的模型处理更新后的messages列表
+ reslut = llm_with_tools.invoke(messages)
+ # 打印最终结果
+ print(res
+ ```
+
+
+#### LangChain内置工具包和联网搜索实战
+
+* LangChain工具包
+
+ * 方便开发者快速使用各种主流工具,LangChain官方加入了很多内置工具,开箱即用
+
+ * 所有工具都是 BaseTool 的子类,且工具是 Runnable可运行组件,支持 invoke、stream 等方法进行调用
+
+ * 也可以通过 name、 description、args、 returu_direct 等属性来获取到工具的相关信息
+
+ * 如果内置工具包不满足,即可以自定义工具
+
+ * 地址(失效忽略即可):https://python.langchain.com/docs/integrations/tools/
+
+
+
+* 如何使用内置工具包【联网搜索例子】
+
+ * 选择对应的工具->安装依赖包->编写代码实战
+
+ * 案例实战
+
+ * 搜索工具:选择 SearchApi,注册时100次免费搜索,注册账号获取 APIKEY
+
+
+
+ * 编写代码
+
+ ```python
+ # 导入操作系统接口模块,用于与环境变量交互
+ import os
+ # 从langchain_community.utilities模块中导入SearchApiAPIWrapper类,用于封装搜索API
+ from langchain_community.utilities import SearchApiAPIWrapper
+
+ # 设置环境变量SEARCHAPI_API_KEY,用于认证搜索API的密钥
+ os.environ["SEARCHAPI_API_KEY"] = "qQBHMQo4Rk8SihmpJjCs7fML"
+
+ # 实例化SearchApiAPIWrapper对象,用于调用搜索API
+ search = SearchApiAPIWrapper()
+
+ # 调用run方法执行搜索操作,参数为查询腾讯股价的中文字符串
+ result = search.run("今天腾讯的股价是多少")
+
+ # 输出搜索结果
+ print(result)
+ ```
+
+ * 拓展
+
+ * SearchApi 包装器可以自定义为使用不同的引擎,如 Google News、Google Jobs、Google Scholar
+
+ * 其他可以在 SearchApi 文档中找到的引擎。执行查询时可以传递 SearchApi 支持的所有参数。
+
+ ```
+ search = SearchApiAPIWrapper(engine="google_jobs")
+ ```
+
+ * 获取元数据
+
+ ```python
+ result_meta = search.results("今天腾讯的股价是多少")
+ print(result_meta)
+ ```
+
+
+#### 兜底降级-LangChain调用工具Tool异常处理
+
+* 需求背景
+
+ * 智能体(Agent)在调用外部工具(如 API、数据库、搜索引擎)时,会遇到各种不可预知的错误
+ * 例如:
+ - 网络请求失败(如 API 无响应)
+ - 权限不足(如访问密钥失效)
+ - 输入参数不合法(如格式错误)
+ - 资源限制(如 API 调用次数超限)
+ * 如果智能体不处理这些错误,会导致:
+ * **程序崩溃**:直接抛出未捕获的异常。
+ * **用户困惑**:返回难以理解的错误堆栈信息。
+ * **无法恢复**:智能体无法根据错误调整策略(如重试或切换工具)
+
+* 解决方案 `ToolException`:
+
+ * 通过 ToolException 统一捕获和处理工具调用中的错误,使智能体具备容错能力和用户友好的错误反馈
+ * ToolException 的核心作用
+ * 统一错误格式:将不同工具的异常转换为标准格式,方便智能体解析。
+ * 错误上下文传递:保留错误原因、工具名称等关键信息。
+ * 使用场景举例
+ * **API 调用失败**:如天气查询接口超时。
+ * **权限校验失败**:如访问数据库的密钥过期。
+ * **输入参数校验**:如用户输入的城市名不存在。
+ * **资源限制**:如每日调用次数用尽。
+
+* 案例实战
+
+ * 方式一:配置响应 `handle_tool_error=True` 默认是false
+
+ ```python
+ from langchain_core.tools import tool, ToolException, StructuredTool
+
+ def search(query: str) -> str:
+ """
+ 执行搜索查询
+ """
+ # 引发一个ToolException来模拟搜索结果为空的情况
+ raise ToolException(f"相关搜索结果为空:{query}")
+
+ # 使用StructuredTool从函数创建一个工具实例
+ # handle_tool_error参数设置为True,表示工具将处理内部异常
+ search_tool = StructuredTool.from_function(
+ func=search,
+ name="search",
+ description="搜索工具",
+ handle_tool_error=True
+ )
+
+ # 调用search_tool的invoke方法来执行搜索工具, 传递一个包含查询参数的字典
+ resp = search_tool.invoke({"query": "腾讯的股价多少"})
+ # 打印搜索工具的响应结果
+ print(resp)
+ ```
+
+ * 方式二:配置响应 `handle_tool_error=”错误信息“`
+
+ ```python
+ from langchain_core.tools import tool, ToolException, StructuredTool
+ def search(query: str) -> str:
+ """
+ 执行搜索查询
+ """
+ # 引发一个ToolException来模拟搜索结果为空的情况
+ raise ToolException(f"相关搜索结果为空:{query}")
+
+ # 使用StructuredTool从函数创建一个工具实例
+ # handle_tool_error参数设置为True,表示工具将处理内部异常
+ search_tool = StructuredTool.from_function(
+ func=search,
+ name="search",
+ description="搜索工具",
+ handle_tool_error="搜索结果失败,请重试"
+ )
+ # 调用search_tool的invoke方法来执行搜索工具,传递一个包含查询参数的字典
+ resp = search_tool.invoke({"query": "腾讯的股价多少"})
+ # 打印搜索工具的响应结果
+ print(resp)
+ ```
+
+ * 方式三:配置自定义处理函数-兜底降级
+
+ ```python
+ from langchain_core.tools import tool, ToolException, StructuredTool
+ def search(query: str) -> str:
+ """
+ 执行搜索查询
+ """
+ # 引发一个ToolException来模拟搜索结果为空的情况
+ raise ToolException(f"相关搜索结果为空:{query}")
+
+ #自定义异常处理函数
+ def _handle_tool_error(error: ToolException) -> str:
+ """
+ 自定义异常处理函数
+ """
+ return f"搜索结果失败,自定义异常,请重试:{error}"
+
+
+ # 使用StructuredTool从函数创建一个工具实例
+ # handle_tool_error参数设置为True,表示工具将处理内部异常
+ search_tool = StructuredTool.from_function(
+ func=search,
+ name="search",
+ description="搜索工具",
+ handle_tool_error=_handle_tool_error
+ )
+ # 调用search_tool的invoke方法来执行搜索工具,传递一个包含查询参数的字典
+ resp = search_tool.invoke({"query": "腾讯的股价多少"})
+ # 打印搜索工具的响应结果
+ print(resp)
+ ```
+
+
+#### 插上翅膀-LLM增加联网搜索功能实
+
+* 需求说明
+
+ * 实现了一个结合大语言模型(LLM)和工具调用的智能问答系统。
+ * 用户可以通过自然语言输入问题,系统会根据问题内容判断是否需要调用外部工具(如搜索引擎或计算工具),返回最终答案。
+
+* 交互流程图
+
+
+
+* 步骤思路
+
+ * 配置SearchAPI的API密钥,
+ * 实例化`SearchApiAPIWrapper`对象,用于调用搜索API。
+ * 定义多个工具函数,供系统在回答问题时调用。
+ - **web_search**: 用于搜索实时信息、最新事件或未知领域知识。
+ - 输入参数:`query`(字符串类型,搜索关键词)。
+ - 返回值:搜索结果的标题和摘要。
+ - **multiply**: 用于计算两个整数的乘积。
+ - 输入参数:`a`和`b`(均为整数类型)。
+ - 返回值:两数相乘的结果。
+ * 初始化大语言模型(LLM),并将其与工具绑定,形成一个智能问答Agent。
+ - **关键点**
+ - 使用`ChatOpenAI`类初始化LLM,指定模型名称、API密钥、温度等参数。
+ - 创建聊天提示模板(`ChatPromptTemplate`),定义系统角色和用户输入格式。
+ - 将工具列表与LLM绑定,具备工具调用能力的Agent。
+ * 构建运行链(`chain`),将用户输入传递给提示模板和Agent,生成响应。
+ - **关键点**
+ - 用户输入通过`RunnablePassthrough`传递到提示模板。
+ - 提示模板生成的消息进一步传递给Agent处理。
+ * 根据据LLM生成的响应,判断是否要调用工具。如果需要调用工具并将结果合并到历史消息中,重新传递给LLM生成最终答案。
+ - **关键点**
+ - 通过`resp.tool_calls`判断是否需要调用工具。
+ - 调用工具后,将结果以`ToolMessage`形式添加到历史消息中。
+ - 最终结果由LLM根据更新的历史消息生成。
+
+* 案例代码实战
+
+ ```python
+ # 基于LangChain 0.3.x的SearchApi工具实战(需安装依赖)
+ # pip install langchain-core langchain-openai langchain-community
+
+ from langchain_community.utilities import SearchApiAPIWrapper
+ from langchain_core.tools import tool
+ from langchain_openai import ChatOpenAI
+ from langchain_core.messages import ToolMessage
+ from langchain_core.runnables import RunnablePassthrough
+ from langchain_core.prompts import ChatPromptTemplate
+
+ import os
+ from langchain_core.tools import tool
+ from pydantic import Field
+ # ======================
+ # 第一步:配置搜索工具
+ # ======================
+ # 注册SearchAPI获取密钥:https://www.searchapi.io/
+
+ # 设置SearchAPI的API密钥
+ os.environ["SEARCHAPI_API_KEY"] = "qQBHMQo4Rk8SihmpJjCs7fML"
+ # 实例化SearchApiAPIWrapper对象,用于调用搜索API
+ search = SearchApiAPIWrapper()
+ # ======================
+ # 第二步:定义搜索工具
+ # ======================
+ @tool("web_search", return_direct=True)
+ def web_search(query: str) -> str:
+ """
+ 当需要获取实时信息、最新事件或未知领域知识时使用,输入应为搜索关键词
+ """
+ try:
+ results = search.results(query) # 获取前3条结果
+ return "\n\n".join([
+ f"来源:{res['title']}\n内容:{res['snippet']}"
+ for res in results['organic_results']
+ ])
+ except Exception as e:
+ return f"搜索失败:{str(e)}"
+
+ @tool("multiply")
+ def multiply(a: int, b: int) -> int:
+ """
+ 把传递的两个参数相乘
+ """
+ return a * b
+
+ # ======================
+ # 第三步:绑定LLM创建Agent
+ # ======================
+ # 初始化大模型
+ llm = ChatOpenAI(
+ model_name = "qwen-plus",
+ base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
+ api_key="sk-005c3c25f6d042848b29d75f2f020f08",
+ temperature=0.7
+ )
+
+ # 创建聊天提示模板
+ prompt = ChatPromptTemplate.from_messages(
+ [
+ ("system", "你是一个AI助手,名称叫老王,请根据用户输入的查询问题,必要时可以调用工具帮用户解答"),
+ ("human", "{query}"),
+ ]
+ )
+
+ # 定义工具字典
+ tool_dict = {
+ "web_search": web_search,
+ "multiply": multiply
+ }
+
+ # 从字典中提取工具列表
+ tools = [ tool_dict[tool_name] for tool_name in tool_dict ]
+
+ # 绑定工具到大模型
+ llm_with_tools = llm.bind_tools(tools=tools)
+
+ # 创建运行链
+ chain = {"query":RunnablePassthrough()} | prompt | llm_with_tools
+
+ # 定义查询
+ query = "你是谁?"
+
+ # 执行链并获取响应
+ resp = chain.invoke({"query":query})
+ print(resp)
+
+ #判断是否需要调用工具 content=''不一定需要调用,根据tool_calls进行判断
+ ```
+
+
+
+* 编码实战
+
+ ```python
+ #判断是否需要调用工具 content=''不一定需要调用,根据tool_calls进行判断
+
+ # ======================
+ # 第四步:获取工具调用
+ # ======================
+ tool_calls = resp.tool_calls
+ if len(tool_calls) <= 0:
+ print(f"不需要调用工具:{resp.content}")
+ else:
+ #将历史消息合并,包括用户输入和AI输出
+ history_messages = prompt.invoke(query).to_messages()
+ history_messages.append(resp)
+ print(f"历史消息:{history_messages}")
+ #循环调用工具
+ for tool_call in tool_calls:
+ tool_name = tool_call.get("name")
+ tool_args = tool_call.get("args")
+ tool_resp = tool_dict[tool_name].invoke(tool_args)
+ print(f"一次调用工具:{tool_name},参数:{tool_args},结果:{tool_resp}")
+ #将工具调用结果添加到历史消息中
+ history_messages.append(
+ ToolMessage(
+ tool_call_id=tool_call.get("id"),
+ name=tool_name,
+ content=tool_resp
+ )
+ )
+ print(f"历史消息:{history_messages}")
+ resp = llm_with_tools.invoke(history_messages)
+ print(f"最终结果:{resp}")
+ print(f"调用工具后的结果:{resp.content}")
+ ```
+
+* 案例测试实战
+
+ ```
+ #query = "9*3是多少"
+ #query = "今天是腾讯股价是多少"
+ ```
+
+* 扩展功能建议
+
+ - **多语言支持**:增加对多种语言的输入和输出支持。
+ - **更多工具集成**:集成更多类型的工具,如翻译工具、图像识别工具等。
+ - **用户反馈机制**:允许用户对系统生成的答案进行评价,优化模型性能。
+
+### 大模型链路调试平台之LangSmith实战
+
+#### 大模型LLM调用链路分析和LangSmith介绍
+
+* 需求背景
+
+ * 开发基于大语言模型(LLM)的智能体时,会遇到以下问题:
+ * 调试困难
+ * LLM 的输出不可预测,难以追踪中间步骤(如思维链、工具调用)。
+ * 错误定位耗时(如工具返回异常,但不知道具体哪一步出错)。
+ * 测试复杂
+ * 需要验证不同输入场景下的输出稳定性。
+ * 手动测试效率低,缺乏自动化验证。
+ * 监控缺失
+ * 生产环境中的智能体行为难以追踪(如 API 调用延迟、错误率)。
+ * 无法分析用户高频问题或模型性能瓶颈。
+
+* **LangSmith 是什么**
+
+ * **LangChain官方出品**的LLM应用开发调试与监控平台
+
+ * 地址:https://smith.langchain.com/
+
+ * 解决大模型应用开发中的**调试困难**、**效果追踪**、**生产监控**三大痛点
+
+ * 类似:Java中的Spring Boot Actuator(监控)、ELK Stack(日志分析)
+
+ * 核心功能说明
+
+ * 调试与追踪
+ - 记录智能体完整执行链路(LLM 调用、工具调用、中间结果)。
+ - 可视化展示每一步的输入输出和耗时。
+ - 统计成功率、延迟等关键指标。
+ * 生产监控
+ - 实时监控 API 调用异常(如超时、错误响应)。
+ - 分析用户高频请求和模型性能趋势
+
+ * 功能矩阵
+
+ | 功能模块 | 作用描述 | 典型应用场景 |
+ | :----------: | :---------------------------------------: | :---------------------: |
+ | 运行追踪 | 记录LLM调用链的完整执行过程 | 调试复杂Chain/Agent逻辑 |
+ | 提示工程分析 | 对比不同Prompt模板的实际效果 | 优化系统提示词 |
+ | 版本对比 | 比对不同模型版本或参数的表现 | 模型升级效果验证 |
+ | 生产监控 | 实时监控API调用指标(延迟、成本、错误率) | 服务健康状态跟踪 |
+ | 团队协作 | 共享调试结果和监控仪表盘 | 多人协作开发LLM应用 |
+
+* LangSmith 系统架构
+
+ * SDK捕获所有LLM相关操作
+ * 加密传输到LangSmith服务端
+ * 数据存储与索引
+ * 可视化界面动态查询
+
+ ```
+ [Your Application]
+ │
+ ▼
+ [LangChain SDK] → [LangSmith API]
+ │ │
+ ▼ ▼
+ [LLM Providers] [Trace Storage]
+ │ │
+ ▼ ▼
+ [External Tools] [Analytics Engine]
+ ```
+
+
+
+* 相关环境实战
+
+ * 注册地址:https://smith.langchain.com/
+
+ 
+
+ * 配置项目前准备
+
+ * 项目安装依赖
+
+ ```
+ pip install langsmith==0.3.19
+ ```
+
+ * 生成密钥,记得保存
+
+ * 配置项目名称(不存在的话会自动新建)
+
+ 
+
+
+#### 大模型调用接入LangSmith分析实战
+
+**简介: 大模型调用接入LangSmith分析实战**
+
+* LangChain接入调用链路分析实战
+
+ * 项目配置
+
+ ```
+ #示例配置
+ import os
+ os.environ["LANGCHAIN_TRACING_V2"] = "true"
+ os.environ["LANGCHAIN_API_KEY"] = "ls_xxxxx" # 替换为实际Key
+ os.environ["LANGCHAIN_PROJECT"] = "My_Project" # 自定义项目名
+ os.environ["LANGSMITH_ENDPOINT"] = "https://api.smith.langchain.com" #后端接口路径
+ ```
+
+ ```python
+ #真正配置
+ import os
+ os.environ["LANGCHAIN_TRACING_V2"] = "true"
+ os.environ["LANGCHAIN_API_KEY"] = "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"
+ os.environ["LANGSMITH_ENDPOINT"] = "https://api.smith.langchain.com"
+ os.environ["LANGSMITH_PROJECT"] = "agent_v1"
+ ```
+
+ * 如果需要本地私有化部署 langfuse
+
+* 案例实战分析
+
+ * 单独案例测试
+
+ ```python
+ import os
+ os.environ["LANGCHAIN_TRACING_V2"] = "true"
+ os.environ["LANGCHAIN_API_KEY"] = "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"
+ os.environ["LANGSMITH_ENDPOINT"] = "https://api.smith.langchain.com"
+ os.environ["LANGSMITH_PROJECT"] = "xdclass_test_v1"
+
+ from langchain_openai import ChatOpenAI
+ import logging
+ logging.basicConfig(level=logging.DEBUG)
+
+ # 初始化大模型
+ llm = ChatOpenAI(
+ model_name = "qwen-plus",
+ base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
+ api_key="sk-005c3c25f6d042848b29d75f2f020f08",
+ temperature=0.7
+ )
+ resp = llm.invoke("什么是智能体")
+ print(resp.content)
+ ```
+
+ 
+
+ * 进阶案例测试【选择之前的案例代码-43.2】
+
+ 
+
+
+### 模型Agent智能体进阶开发实战
+
+#### 大模型智能体之CoT思维链和ReAct推理行动
+
+* 需求背景:为什么需要CoT/ReAct?
+
+ * 问题场景:传统大模型直接输出结果,但复杂任务(数学推理/多步骤决策)易出错
+
+ * 核心需求:让模型展示思考过程 + 动态调整策略
+
+ * 类比理解:
+
+ * 普通模型 → 考试直接写答案
+
+ * CoT → 在试卷上写解题步骤
+
+ * ReAct → 边查公式手册边解题
+
+
+
+* 什么是CoT(思维链,Chain of Thought)
+
+ * **核心机制**:通过显式生成推理步骤得出最终答案
+
+ ```python
+ """
+ 问题:...[输入问题]...
+ 思考步骤:
+ 1. 第一步分析(如提取关键数据)
+ 2. 第二步计算(如公式应用)
+ 3. ...(更多步骤)
+ 最终答案:...[结论]...
+ """
+
+ 比如问题:A超市苹果每斤5元,买3斤送1斤;B超市同品质苹果每斤6元但买二送一。买8斤哪家更划算?
+ CoT推理:
+ 1. A超市实际获得:3+1=4斤,花费3×5=15元 → 单价15/4=3.75元/斤
+ 2. 买8斤需要购买两次活动:4×2=8斤 → 总价15×2=30元
+ 3. B超市每3斤花费6×2=12元 → 单价12/3=4元/斤
+ 4. 买8斤需购买3次活动(3×3=9斤)花费12×3=36元 → 实际单价36/9=4元/斤
+ 5. 结论:A超市更优惠
+ ```
+
+ * 是一种促使大语言模型产生一系列中间推理步骤,进而得出最终答案的技术。
+
+ * 以往的大模型通常直接给出问题的答案,而 CoT 鼓励模型展示其思考过程,就像人类在解决复杂问题时逐步推导一样。
+
+ * 这种方法能增强模型在处理复杂推理任务时的性能,尤其是涉及算术、常识推理和符号操作的任务。
+
+ * 局限性
+
+ * **依赖模型知识**:若模型内部知识错误,推理链条也可能错误(如“太阳绕地球转”)。
+ * **不适用于动态信息**:无法处理需要实时数据的问题(如“今天天气如何”)。
+ * **步骤冗余**:简单问题可能因分步反而降低效率。
+
+ * 案例说明:算术问题
+
+ * 问题:小明有 5 个苹果,小红给他 3 个,然后他吃了 2 个,还剩下多少个苹果?
+ * 无 CoT 回答:“6 个”。
+ * CoT 回答:
+ * 首先,小明原本有 5 个苹果,小红又给了他 3 个,那么此时他拥有的苹果数为 5 + 3 = 8 个。
+ * 接着,他吃了 2 个苹果,所以剩下的苹果数是 8 - 2 = 6 个。
+ * 因此,小明最后还剩下 6 个苹果。
+
+ * 应用场景
+
+ * 教育领域
+ * 用于辅导学生学习数学、科学等学科的推理问题。
+ * 通过展示推理过程,学生能更好地理解解题思路,提高学习效果。
+ * 智能客服
+ * 在回答客户复杂问题时,展示推理过程能让客户更清楚解决方案的由来,增强客户对服务的信任。
+
+
+
+* 什么是ReAct(推理与行动,Reasoning and Acting)
+
+ * **交互逻辑**:循环执行"思考-行动-观察"步骤
+
+ ```python
+ """
+ 问题:...[输入问题]...
+ 思考:当前需要解决的问题是...
+ 行动:调用__工具名称__(参数)
+ 观察:工具返回结果...
+ 思考:根据结果分析...
+ (循环直至得出结论)
+ 答案:...[最终结果]...
+ """
+
+ 比如问题:2027年诺贝尔文学奖得主的代表作是什么?
+ ReAct流程:
+ [思考] 需要先确定最新获奖者 → 调用搜索工具
+ [行动] 使用DuckDuckGo搜索"2027诺贝尔文学奖获得者"
+ [观察] 结果显示:法国作家安妮·艾诺
+ [思考] 需要确认其代表作品 → 调用维基百科工具
+ [行动] 查询维基百科"安妮·艾诺"
+ [观察] 主要作品:《悠悠岁月》《位置》等
+ [结论] 代表作是《悠悠岁月》
+ ```
+
+ * ReAct 是一种让大模型结合推理和行动的范式,不是前端框架React
+
+ * 模型不仅要进行推理,还能根据推理结果调用外部工具(如搜索引擎、数据库等)来获取额外信息,从而更有效地解决问题。
+
+ * 它使模型能够与外部环境交互,拓展了模型的能力边界。
+
+ * ReAct的优势
+
+ * 减少幻觉:通过实时调用外部工具验证信息,降低模型编造错误答案的概率。
+ * 处理复杂任务:适合多步骤问题(如数学计算、事实核查),传统单次生成容易出错。
+ * 透明可解释:模型的推理过程以自然语言呈现,便于人类理解其决策逻辑。
+
+ * 案例说明:
+
+ * 问题:2027 年 NBA 总冠军是哪个队伍?
+ * 无 ReAct 处理:由于模型训练数据可能存在时效性问题,可能无法给出准确答案或给出过时的信息。
+ * ReAct 处理:
+ * 推理:模型意识到自己可能没有最新的 2026 年 NBA 总冠军信息,需要调用外部资源获取。
+ * 行动:调用体育新闻网站的 API 或搜索引擎查询相关信息。
+ * 结果:获取到最新信息后,给出准确回答,如 “2026年 NBA 总冠军是 [具体队伍名称]。
+
+ * 应用场景
+
+ * 知识问答系统
+ * 处理需要实时信息或特定领域最新数据的问题,如财经数据、体育赛事结果、科技动态等。
+
+ * 任务自动化
+ * 在自动化流程中,根据任务需求调用不同的工具和服务,如预订机票、查询物流信息、控制智能家居设备等。
+
+* 技术框架对比
+
+ | 维度 | CoT | ReAct |
+ | :---------------: | :-------------------------------: | :---------------------------------: |
+ | **核心组件** | 纯提示工程,依赖模型知识 | 代理(Agent)+ 工具调用 |
+ | **数据依赖** | 仅依赖内部知识 | 可接入外部数据源/API |
+ | **错误修复** | 单次推理完成 | 可通过多次行动修正结果 |
+ | **适用场景** | 理论推导/数学计算 | 实时信息查询/复杂任务分解 |
+ | **计算开销** | 低 | 中高(涉及外部调用) |
+ | **LangChain组件** | `ChatPromptTemplate` + `LLMChain` | `Agent` + `Tools` + `AgentExecutor` |
+ | **优势** | 简单、透明 | 实时交互,扩展性强 |
+ | **缺点** | 无法获取最新信息 | 依赖工具API的稳定性 |
+
+* 应用场景指南
+
+ | 场景类型 | 推荐方法 | 原因说明 |
+ | :--------------: | :------: | :------------------------: |
+ | 数学/逻辑推理 | CoT | 无需外部数据,单步推理高效 |
+ | 实时数据获取 | ReAct | 需要调用搜索/API工具 |
+ | 多步骤决策任务 | ReAct | 支持动态调整执行路径 |
+ | 知识密集型问答 | CoT | 依赖模型内部知识库 |
+ | 复杂问题分解执行 | 混合架构 | 兼顾推理与执行效率 |
+
+* **开发建议**:
+
+ * **方法选择原则**:
+ - 纯推理 → CoT
+ - 需实时数据 → ReAct
+ * **提示工程技巧**:
+ - CoT需明确定义步骤格式
+ - ReAct要严格规范行动命名(如`调用API名称_参数`)
+ * **常见陷阱**:
+ - CoT可能产生错误中间步骤
+ - ReAct需处理API调用失败情况
+ * 通过`verbose=True`参数观察两种方法的执行过程差异
+ * LangChain框架的模块化设计,可以灵活组合这两种技术,适应不同场景需求
+
+
+#### 大模型的Zero-Shot和Few-Shot案例实战
+
+**简介: 大模型的Zero-Shot和Few-Shot案例讲解**
+
+* **零样本(Zero-Shot)学习**
+
+ * 模型在**没有特定任务训练数据**的情况下,直接通过预训练知识和自然语言理解能力完成任务。
+ * 例如,直接要求模型生成从未见过的任务结果(如翻译、分类)。
+ * **核心原理**:依赖大模型在预训练阶段学习到的通用知识泛化能力
+ * 示例
+ - 用户输入:“将这句话翻译成中文:Hello, how are you?”
+ - 模型输出:“你好”
+
+* **少量样本(Few-Shot)学习【照猫画虎】**
+
+ - 模型通过**少量示例(通常3-5个)** 快速理解任务格式和需求,提升任务表现。
+
+ - 例如,提供几个问答示例后,模型能模仿格式回答新问题。
+
+ - **核心原理**:通过示例激发模型的上下文学习(In-Context Learning)能力,提升输出准确性和一致性。
+
+ - 示例
+
+ ```
+ 输入:“苹果 -> 水果”,输出:“香蕉 -> 水果”
+ 输入:“汽车 -> 交通工具”,输出:“飞机 -> 交通工具”
+ 输入:“猫 ->”,输出:“动物”
+ ```
+
+* 应用场景对比
+
+ | **场景** | **零样本(Zero-Shot)** | **少量样本(Few-Shot)** |
+ | :----------------: | :------------------------: | :------------------------------------------: |
+ | **适用任务复杂度** | 简单任务(如翻译、分类) | 复杂任务(如逻辑推理、特定格式生成) |
+ | **数据依赖** | 无需示例 | 需要少量高质量示例 |
+ | **输出可控性** | 较低(依赖模型预训练知识) | 较高(通过示例明确格式和规则) |
+ | **典型用例** | 快速原型开发、通用问答 | 领域特定任务(如法律文档解析、医疗术语抽取) |
+
+* 案例实战
+
+ * 零样本学习案例:直接通过指令调用大模型生成答案
+
+ ```python
+ from langchain_openai import ChatOpenAI
+ from langchain_core.prompts import ChatPromptTemplate
+
+ # 零样本提示模板
+ zero_shot_prompt = ChatPromptTemplate.from_messages([
+ ("system", "你是一个专业翻译,将文本从{source_lang}翻译到{target_lang}"),
+ ("human", "{text}")
+ ])
+
+ # 初始化大模型
+ llm = ChatOpenAI(
+ model_name = "qwen-plus",
+ base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
+ api_key="sk-005c3c25f6d042848b29d75f2f020f08",
+ temperature=0.7
+ )
+ # 链式调用
+ chain = zero_shot_prompt | llm
+
+ # 执行翻译(中文→英文)
+ response = chain.invoke({
+ "source_lang": "中文",
+ "target_lang": "英文",
+ "text": "今天天气不错,我要学习AI大模型开发"
+ })
+
+ print(response.content)
+
+ ```
+
+ * 少量样本学习案例: 通过示例指导模型理解任务格式
+
+ ```python
+ from langchain_core.prompts import FewShotPromptTemplate, PromptTemplate
+ from langchain_openai import ChatOpenAI
+ # 初始化大模型
+ llm = ChatOpenAI(
+ model_name = "qwen-plus",
+ base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
+ api_key="sk-005c3c25f6d042848b29d75f2f020f08",
+ temperature=0.7
+ )
+ # 示例数据
+ examples = [
+ {
+ "input": "苹果公司的总部在哪里?",
+ "output": "根据我的大量思考:苹果公司的总部位于美国加利福尼亚州的库比蒂诺(Cupertino)。"
+ },
+ {
+ "input": "OpenAI的CEO是谁?",
+ "output": "根据我的大量思考:OpenAI的现任CEO是萨姆·阿尔特曼(Sam Altman)。"
+ }
+ ]
+ # 定义单条示例模板
+ example_template = """
+ 输入:{input}
+ 输出:{output}
+ """
+ example_prompt = PromptTemplate(
+ template=example_template
+ input_variables=["input", "output"],
+ )
+
+ # 构建Few-Shot提示模板
+ few_shot_prompt = FewShotPromptTemplate(
+ examples=examples,
+ example_prompt=example_prompt,
+ suffix="输入:{question}\n输出:",
+ input_variables=["question"]
+ )
+
+ # 创建Chain并调用
+ few_shot_chain = few_shot_prompt | llm
+ response = few_shot_chain.invoke({"question": "亚马逊的创始人是谁?"})
+ print(response.content) # 输出:根据我的大量思考:亚马逊的创始人是杰夫·贝索斯(Jeff Bezos)。
+ ```
+
+* 总结
+
+ * **零样本 vs 少量样本**:
+ - 零样本依赖模型预训练知识,适合通用任务。
+ - 少量样本通过示例提升任务适配性,适合专业场景。
+ * **LangChain 实现要点**:
+ - **零样本**:使用 `AgentType.ZERO_SHOT_REACT_DESCRIPTION` 初始化智能体。
+ - **少量样本**:通过 `PromptTemplate` 设计含示例的提示词。
+ * **设计原则**:
+ - **清晰指令**:明确任务目标和输出格式。
+ - **示例质量**:少量样本的示例需覆盖典型场景。
+
+#### LangChain智能体执行引擎AgentExecutor
+
+* 需求背景:为什么需要 AgentExecutor?
+
+ * 问题:当智能体(Agent)需要执行多步操作(如多次调用工具、循环推理)时,开发者需手动处理:
+ * 执行循环:根据模型输出决定是否继续调用工具。
+ * 错误处理:捕获工具调用或模型解析中的异常。
+ * 流程控制:限制最大迭代次数,防止无限循环。
+ * 日志记录:追踪每一步的输入、输出和中间状态。
+ * 痛点:
+ * 代码冗余:重复编写循环和错误处理逻辑。
+ * 维护成本高:复杂任务中难以保证流程稳定性。
+ * 可观测性差:难以调试多步骤执行过程。
+
+* `AgentExecutor` 介绍
+
+ * LangChain 提供的智能体执行引擎,封装了执行循环、错误处理和日志追踪,让开发者聚焦业务逻辑。
+
+ * 核心功能
+
+ | **功能** | **说明** |
+ | :--------------: | :----------------------------------------------------------: |
+ | **执行循环控制** | 自动迭代执行智能体的 `思考 -> 行动 -> 观察` 流程,直到满足终止条件。 |
+ | **错误处理** | 捕获工具调用异常、模型解析错误,支持自定义重试或回退逻辑。 |
+ | **迭代限制** | 通过 `max_iterations` 防止无限循环(如模型陷入死循环)。 |
+ | **日志与追踪** | 记录每一步的详细执行过程(需设置 `verbose=True`),支持集成 LangSmith。 |
+ | **输入输出处理** | 统一格式化最终结果,隐藏中间步骤细节(除非显式要求输出)。 |
+
+ * 关键参数
+
+ | **参数** | **作用** |
+ | :-------------------------: | :----------------------------------------------------------: |
+ | `agent` | 绑定的智能体实例(如 `create_react_agent` 的返回值)。 |
+ | `tools` | 智能体可调用的工具列表。 |
+ | `verbose` | 是否打印详细执行日志(调试时建议开启)。 |
+ | `max_iterations` | 最大迭代次数,防止死循环。 |
+ | `handle_parsing_errors` | 自动处理模型输出解析错误(如返回无效工具名),可设置为 `True` 或自定义函数。 |
+ | `return_intermediate_steps` | 是否返回中间步骤结果(用于调试或展示完整链路)。 |
+
+* 使用场景:何时需要 `AgentExecutor`
+
+ * **多步骤任务**:
+
+ - 例如:先调用搜索工具获取数据,再调用计算工具处理结果
+
+ ```python
+ # 示例:计算商品折扣价
+ "思考:需要先获取商品价格,再计算折扣。"
+ "行动1:调用 get_price(商品A)"
+ "观察1:价格=100元"
+ "行动2:调用 calculate_discount(100, 20%)"
+ "观察2:折扣价=80元"
+ ```
+
+ * **工具依赖场景**:
+
+ - 例如:预订航班需要先查询航班号,再调用支付接口。
+
+ * **复杂推理任务**:
+
+ - 例如:解决数学问题需多次尝试不同公式。
+
+ * **生产环境部署**:
+
+ - 需保证服务稳定性(自动处理超时、限流等异常)
+
+* 伪代码参考
+
+ ```python
+ from langchain.agents import AgentExecutor
+
+ agent_executor = AgentExecutor(
+ agent=agent,
+ tools=tools,
+ verbose=True,
+ max_iterations=3,
+ handle_parsing_errors=True
+ )
+
+ # 执行查询(自动处理循环和错误)
+ response = agent_executor.invoke({"input": "北京的气温是多少华氏度?"})
+ print(response["output"]) # 输出:25℃ = 77℉
+ ```
+
+
+#### LangChain智能体之initialize_agent开发实战
+
+* 需求背景
+
+ | 手工调用工具的问题 | `initialize_agent`解决方案 |
+ | :----------------------: | :--------------------------: |
+ | 需要手动编写工具选择逻辑 | 自动根据输入选择最合适的工具 |
+ | 缺乏错误重试机制 | 内置异常处理和重试策略 |
+ | 输出格式不统一 | 标准化响应格式 |
+ | 难以处理多工具协作场景 | 自动编排工具调用顺序 |
+
+ * 手动执行需要开发者自己处理任务分解、工具选择、参数生成、结果整合等步骤
+
+ * Agent利用大模型的推理能力自动完成这些步骤,提高了开发效率和系统的灵活性。
+
+ * 解决方案:
+
+ * langchain内置多个方法快速创建智能体,能减少手动编码的复杂性,提升系统的智能性和适应性。
+ * 包括自动化任务分解、动态工具选择、错误处理、结果整合等
+ * 主要包含以下核心方法:
+ * `initialize_agent`:通用初始化方法,快速构建智能体(兼容旧版)返回AgentExecutor。
+ * `create_react_agent`:基于 ReAct 框架的智能体,支持多步推理。
+ * `create_tool_calling_agent`:专为工具调用优化的智能体,支持结构化输出。
+ * 其他方法:如 `create_json_agent`(处理 JSON )、`create_openai_tools_agent`(适配 OpenAI 工具调用格式)
+
+
+ 
+
+* `initialize_agent` 方法介绍
+
+ * 通过封装智能体的决策逻辑和工具调度,旧版方法,未来可能被弃用
+
+ * **适用场景**:快速原型开发、简单任务处理
+
+ * 实现
+
+ * 自动化工具选择:根据输入动态调用合适的工具。
+ * 流程标准化:统一处理错误、重试、结果格式化。
+ * 简化开发:一行代码完成智能体初始化。
+
+ * 语法与参数详解
+
+ ```python
+ from langchain.agents import initialize_agent
+
+ def initialize_agent(
+ tools: Sequence[BaseTool], # 可用工具列表
+ llm: BaseLanguageModel, # 大模型实例
+ agent: Optional[AgentType] = None, # Agent类型
+ verbose: bool = False, # 是否显示详细过程
+ ) -> AgentExecutor:
+ ```
+
+ * **关键参数说明**:`agent_type`
+
+ | AgentType | 适用场景 | 特点 |
+ | :-----------------------------------------: | :------------------------------------: | :-----------------------: |
+ | ZERO_SHOT_REACT_DESCRIPTION | 通用任务处理 | 基于ReAct框架,零样本学习 |
+ | STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION | 结构化输入输出 | 支持复杂参数类型 |
+ | CONVERSATIONAL_REACT_DESCRIPTION | 多轮对话场景 | 保留对话历史上下文 |
+ | SELF_ASK_WITH_SEARCH | 结合自问自答和搜索工具,适合问答场景。 | 自动生成中间问题并验证 |
+
+* 案例实战
+
+ ```python
+ from langchain.agents import initialize_agent, AgentType
+ from langchain_openai import ChatOpenAI
+ from langchain_core.tools import tool
+ from langchain.agents import initialize_agent
+ from langchain_community.utilities import SearchApiAPIWrapper
+ import os
+
+ # 设置SearchAPI的API密钥
+ os.environ["SEARCHAPI_API_KEY"] = "qQBHMQo4Rk8SihmpJjCs7fML"
+ # 实例化SearchApiAPIWrapper对象,用于调用搜索API
+ search = SearchApiAPIWrapper()
+ #定义搜索工具
+ @tool("web_search", return_direct=True)
+ def web_search(query: str) -> str:
+ """
+ 当需要获取实时信息、最新事件或未知领域知识时使用,输入应为搜索关键词
+ """
+ try:
+ results = search.results(query) # 获取前3条结果
+ return "\n\n".join([
+ f"来源:{res['title']}\n内容:{res['snippet']}"
+ for res in results['organic_results']
+ ])
+ except Exception as e:
+ return f"搜索失败:{str(e)}"
+
+ # 使用 @tool 定义进行数学计算的工具
+ @tool("math_calculator", return_direct=True)
+ def math_calculator(expression: str) -> str:
+ """用于进行数学计算,输入应该是一个有效的数学表达式,如 '2 + 3' 或 '5 * 4'"""
+ try:
+ result = eval(expression)
+ return str(result)
+ except Exception as e:
+ return f"计算出错: {str(e)}"
+
+ #不同大模型效果不一样,有些会报错,不支持多个输入参数的工具
+ @tool("multiply")
+ def multiply(a: int, b: int) -> int:
+ """
+ 把传递的两个参数相乘
+ """
+ return a * b
+
+ # 创建工具列表
+ tools = [math_calculator,web_search]
+
+ # 初始化大模型
+ llm = ChatOpenAI(
+ model_name = "qwen-plus",
+ base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
+ api_key="sk-005c3c25f6d042848b29d75f2f020f08",
+ temperature=0.7
+ )
+
+
+ # 使用 initialize_agent 创建代理
+ agent_chain = initialize_agent(
+ tools=tools, # 使用的工具列表
+ llm=llm, # 使用的语言模型
+ agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, # 指定代理类型
+ verbose=True, # 打开详细日志,便于查看代理的思考过程
+ handle_parsing_errors=True #自动处理解析错误,提高Agent的稳定性。
+
+ )
+ #打印对应的智能体,更清晰底层逻辑
+ print(agent_chain.agent.llm_chain)
+ print(agent_chain.agent.llm_chain.prompt.template)
+ print(agent_chain.agent.llm_chain.prompt.input_variables)
+
+ # 测试代理
+ # 需求 1: 计算 5 乘以 6 的结果
+ result1 = agent_chain.invoke({"input":"计算 5 乘以 6 的结果"})
+ print("计算 5 乘以 6 的结果:", result1)
+
+ # 需求 2: 获取当前日期
+ #result2 = agent_chain.run("腾讯最新的股价")
+ #result2 = agent_chain.invoke({"input":"腾讯最新的股价"})
+ #print("腾讯最新的股价:", result2
+ ```
+
+
+#### 个人AI助理智能体之tool_calling_agent实战
+
+* `create_tool_calling_agent `方法介绍
+
+ * 是 LangChain 0.3 新增的智能体创建方法, 要求模型直接返回工具调用参数(如 JSON 格式),减少中间解析错误。
+
+ * **结构化工具调用**:显式调用工具并传递结构化参数(支持复杂数据类型)
+
+ * **多步骤任务处理**:适合需要按顺序调用多个工具的场景
+
+ * **精准控制**:通过自定义 Prompt 模板指导 Agent 行为
+
+ * 方法参数
+
+ ```python
+ from langchain.agents import create_tool_calling_agent
+
+ agent = create_tool_calling_agent(
+ llm: BaseLanguageModel, # 语言模型实例(需支持结构化输出)
+ tools: List[BaseTool], # 工具列表
+ prompt: ChatPromptTemplate # 提示模板(需明确工具调用规则)
+ )
+ ```
+
+ | 参数 | 类型 | 必填 | 说明 |
+ | :----: | :----------------: | :--: | :----------------------------------------------------------: |
+ | llm | BaseLanguageModel | 是 | 支持工具调用的模型(如 `ChatOpenAI`) |
+ | tools | Sequence[BaseTool] | 是 | 工具列表,每个工具需用 `@tool` 装饰器定义 |
+ | prompt | ChatPromptTemplate | 是 | 控制 Agent 行为的提示模板,需包含 `tools` 和 `tool_names` 的占位符 |
+
+* 适用场景
+
+ * API 集成:如调用天气查询、支付接口等需要严格参数格式的场景。
+ * 多工具协作:模型需根据输入动态选择多个工具并传递参数。
+ * 高精度任务:如金融计算、医疗诊断等容错率低的场景。
+
+* 案例实战: 个人AI助理智能体
+
+ ```python
+ from langchain_openai import ChatOpenAI
+ from langchain.agents import create_tool_calling_agent, Tool, AgentExecutor
+ from langchain.tools import tool
+ from datetime import datetime
+ from langchain_core.prompts import ChatPromptTemplate
+
+ # 定义获取当前日期的工具函数
+ @tool
+ def get_current_date() -> str:
+ """获取当前日期"""
+ formatted_date = datetime.now().strftime("%Y-%m-%d")
+ return f"The current date is {formatted_date}"
+
+ # 定义搜索航班的工具函数
+ @tool
+ def search_flights(from_city: str, to_city: str, date: str) -> str:
+ """根据城市和日期搜索可用航班"""
+ return f"找到航班:{from_city} -> {to_city},日期:{date},价格:¥1200"
+
+ # 定义预订航班的工具函数
+ @tool
+ def book_flight(flight_id: str, user: str) -> str:
+ """预订指定航班"""
+ return f"用户 {user} 成功预订航班 {flight_id}"
+
+ # 定义获取股票价格的函数
+ def get_stock_price(symbol) -> str:
+ return f"The price of {symbol} is $100."
+
+ # 创建工具列表,包括获取股票价格、搜索航班、预订航班和获取当前日期的工具
+ tools = [
+ Tool(
+ name="get_stock_price",
+ func=get_stock_price,
+ description="获取指定的股票价格"
+ ),
+ search_flights,
+ book_flight,
+ get_current_date
+ ]
+
+ # 初始化大模型
+ llm = ChatOpenAI(
+ model_name="qwen-plus",
+ base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
+ api_key="sk-005c3c25f6d042848b29d75f2f020f08",
+ temperature=0.7
+ )
+
+ # 定义聊天提示模板
+ prompt = ChatPromptTemplate.from_messages(
+ [
+ ("system", "你是一个AI助手,必要时可以调用工具回复问题"),
+ ("human", "我叫老王,经常出差,身份证号是 4414231993210223213332"),
+ #("placeholder", "{chat_history}"),
+ ("human", "{input}"),
+ ("placeholder", "{agent_scratchpad}"),
+ ]
+ )
+
+ # 创建代理
+ agent = create_tool_calling_agent(llm, tools, prompt)
+
+ # 初始化代理执行器 , verbose=True可以看到思考明细, return_intermediate_steps返回中间结果
+ agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True,return_intermediate_steps=True)
+
+
+ # 运行代理并获取结果
+ result = agent_executor.invoke({"input": "苹果股票是多少?根据我的行程,帮我查询下明天的航班,从广州去北京,并定机票"})
+ print(f"最终结果:{result}"
+ ```
+
+
+#### 旅游规划智能体之react_agent实战
+
+* **ReAct 框架**:
+
+ * **Re**asoning + **Act**ing 是一种结合推理和行动的智能体设计模式
+
+ * 由以下步骤循环组成:
+
+ * **推理(Reason)**:分析当前状态,决定下一步行动(如调用工具或直接回答)。
+ * **行动(Act)**:执行选定的操作(如调用工具、查询数据)。
+ * **观察(Observe)**:获取行动结果,更新状态,进入下一轮循环。
+
+ ```
+ [Thought] <-- 推理阶段(分析当前状况)
+ [Action] <-- 行动阶段(调用工具)
+ [Observation] <-- 环境反馈(工具返回结果)
+ ```
+
+* **`create_react_agent`**
+
+ * LangChain 提供的专用方法,用于创建基于 ReAct 框架的智能体
+
+ * 适合需要**多步动态决策**的任务(如复杂问答、数学问题求解)。
+
+ * 方法参数与语法
+
+ ```python
+ from langchain.agents import create_react_agent
+
+ agent = create_react_agent(
+ llm: BaseLanguageModel, # 必须支持 ReAct 格式
+ tools: Sequence[BaseTool],# 工具集(需详细文档)
+ prompt: ChatPromptTemplate # 必须包含 ReAct 特殊标记
+ ) -> Runnable
+ ```
+
+ * 参考使用的提示模板结构
+
+ ```python
+ # 官方推荐模板(从 hub 获取)
+ prompt = hub.pull("hwchase17/react")
+
+ # 模板核心内容示例:
+ """
+ Answer the following questions using the following tools:
+ {tools}
+ Use the following format:
+
+ Question: the input question
+ Thought: 需要始终进行的思考过程
+ Action: 要执行的动作,必须是 [{tool_names}] 之一
+ Action Input: 动作的输入
+ Observation: 动作的结果
+ ...(重复思考/行动循环)
+ Final Answer: 最终答案
+ """
+ ```
+
+ * 与其它方法的对比选型
+
+ | 场景特征 | 推荐方法 | 原因说明 |
+ | :--------------: | :-----------------------: | :--------------------: |
+ | 需要逐步推理 | create_react_agent | 显式思考链支持复杂逻辑 |
+ | **严格参数传递** | create_tool_calling_agent | 结构化输入更可靠 |
+ | 快速简单任务 | initialize_agent | 开箱即用最简配置 |
+ | 需要自我修正 | create_react_agent | 错误后可重新推理 |
+ | 与人类协作调试 | create_react_agent | 完整思考链易读性好 |
+
+ * 适用场景
+
+ * 多步骤任务:例如:“查询北京的气温,并计算对应的华氏度。”
+ * 动态工具选择:根据中间结果决定下一步调用哪个工具。
+ * 复杂推理任务:例如:“如果明天下雨,推荐室内活动;否则推荐户外活动。
+
+* 案例实战:智能推荐助手
+
+ ```python
+ from langchain_openai import ChatOpenAI
+ from langchain.tools import tool
+ from langchain_community.utilities import SearchApiAPIWrapper
+ import os
+ from langchain_core.prompts import PromptTemplate
+ from langchain.agents import create_react_agent, AgentExecutor
+ @tool
+ def get_weather(city: str) -> str:
+ """获取指定城市的天气"""
+ # 模拟数据
+ weather_data = {
+ "北京": "晴,25℃",
+ "上海": "雨,20℃",
+ "广州": "多云,28℃"
+ }
+ return weather_data.get(city, "暂不支持该城市")
+
+ @tool
+ def recommend_activity(weather: str) -> str:
+ """根据天气推荐活动"""
+ if "雨" in weather:
+ return "推荐室内活动:博物馆参观。"
+ elif "晴" in weather:
+ return "推荐户外活动:公园骑行。"
+ else:
+ return "推荐一般活动:城市观光。"
+
+ # 定义搜索工具
+ os.environ["SEARCHAPI_API_KEY"] = "qQBHMQo4Rk8SihmpJjCs7fML"
+ @tool("web_search", return_direct=True)
+ def web_search(query: str) -> str:
+ """
+ 当需要获取实时信息、最新事件或未知领域知识时使用,输入应为搜索关键词
+ """
+ try:
+ search = SearchApiAPIWrapper()
+ results = search.results(query) # 获取前3条结果
+ return "\n\n".join([
+ f"来源:{res['title']}\n内容:{res['snippet']}"
+ for res in results['organic_results']
+ ])
+ except Exception as e:
+ return f"搜索失败:{str(e)}"
+
+ tools = [get_weather, recommend_activity, web_search]
+
+
+ # 初始化大模型
+ llm = ChatOpenAI(
+ model_name="qwen-plus",
+ base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
+ api_key="sk-005c3c25f6d042848b29d75f2f020f08",
+ temperature=0.7
+ )
+
+
+ # 使用 LangChain 预定义的 ReAct 提示模板,https://smith.langchain.com/hub/hwchase17/react
+ #from langchain import hub
+ #prompt = hub.pull("hwchase17/react")
+
+ # 模板内容示例:
+ template = """
+ Answer the following questions as best you can. You have access to the following tools:
+ {tools}
+ Use the following format:
+ Question: the input question you must answer
+ Thought: you should always think about what to do
+ Action: the action to take, should be one of [{tool_names}]
+ Action Input: the input to the action
+ Observation: the result of the action
+ ... (this Thought/Action/Action Input/Observation can repeat N times)
+ Thought: I now know the final answer
+ Final Answer: the final answer to the original input question
+
+ Begin!
+
+ Question: {input}
+ Thought:{agent_scratchpad}
+ """
+
+ prompt = PromptTemplate.from_template(template)
+
+ # 创建 ReAct 智能体
+ agent = create_react_agent(llm, tools, prompt)
+ agent_executor = AgentExecutor(
+ agent=agent,
+ tools=tools,
+ verbose=True, # 打印详细执行过程
+ max_iterations=3, # 限制最大迭代次数,
+ handle_parsing_errors=lambda _: "请检查输入格式", # 错误处理
+ return_intermediate_steps=True # 保留中间步骤
+ )
+
+ # 执行查询
+ response = agent_executor.invoke({
+ "input": "我在北京玩3天,根据天气推荐活动, 顺便查询腾讯的股价是多少"
+ })
+ print(response)
+ ```
+
+
+
+
+#### LLM综合实战-文档网络智能问答助手开发
+
+* 需求说明
+
+ * 智能体核心功能
+
+ * **多模态知识整合**
+ * 深度结合 **Milvus 向量数据库** 的本地文档知识与 **实时网络搜索能力**,实现对复杂问题的分步解析与回答。
+ * 支持同时处理 **结构化文档问答**(如技术框架详解)和 **实时信息查询**(如股价、日期等动态数据)。
+
+ * **智能工具决策**
+ - 自动判断问题类型:
+ - **文档相关问题**(如 "什么是Milvus?")调用 **Milvus 向量检索工具**,精准匹配本地知识库内容。
+ - **实时信息需求**(如 "腾讯股价")触发 **Web 搜索工具**,获取最新数据。
+ - 支持 **多问题串联回答**,例如一次性处理包含技术解释、时间查询、股价查询的复合任务。
+ * **交互式回答增强**
+ - 通过 **LangChain Agent 框架** 的动态决策流程,展示问题拆解与工具调用的全过程(如中间思考步骤)。
+ - 提供 **结构化输出**,清晰标注每个答案的来源(如 "来自 Milvus 文档" 或 "来自实时搜索")。
+
+* 技术亮点:
+
+ * 工具链集成:无缝融合 Milvus 向量检索 + 网络搜索API + 大模型推理(如 Qwen-Plus)。
+ * 可视化流程:通过 LangSmith 追踪 Agent 的决策路径
+ * 自定义提示模板:支持灵活调整 Agent 的行为逻辑(如切换 create_tool_calling_agent 或 create_react_agent 模式)。
+
+* 应用场景
+
+ * 技术文档问答:快速解析 Milvus 版本、功能、与 LangChain 的集成方法。
+ * 实时数据查询:动态获取股票价格、当前日期等时效性信息。
+ * 多步骤问题处理:如 "解释Milvus的工作原理,同时比较其与Faiss的优劣,最后给出GitHub最新教程链接"。
+
+* 功能效果演示
+
+ 
+
+* 编码实战
+
+```python
+from langchain_community.utilities import SearchApiAPIWrapper
+from langchain_core.tools import tool
+from langchain.agents import AgentExecutor, create_tool_calling_agent,create_react_agent
+
+from langchain.tools.retriever import create_retriever_tool
+from langchain_milvus import Milvus
+
+from langchain.prompts import PromptTemplate,ChatPromptTemplate
+from langchain_community.embeddings import DashScopeEmbeddings
+from langchain_openai import ChatOpenAI
+import os
+from pydantic import Field
+
+os.environ["LANGCHAIN_TRACING_V2"] = "true"
+os.environ["LANGCHAIN_API_KEY"] = "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"
+os.environ["LANGSMITH_ENDPOINT"] = "https://api.smith.langchain.com"
+os.environ["LANGSMITH_PROJECT"] = "agent_v1"
+
+
+# 配置搜索工具
+os.environ["SEARCHAPI_API_KEY"] = "qQBHMQo4Rk8SihmpJjCs7fML"
+search = SearchApiAPIWrapper()
+@tool("web_search")
+def web_search(query: str) -> str:
+ """当需要获取实时信息、最新事件或未知领域知识时使用,输入应为搜索关键词"""
+ try:
+ results = search.results(query) # 获取前3条结果
+ return "\n\n".join([
+ f"来源:{res['title']}\n内容:{res['snippet']}"
+ for res in results['organic_results']
+ ])
+ except Exception as e:
+ return f"搜索失败:{str(e)}"
+
+
+#初始化嵌入模型
+embeddings = DashScopeEmbeddings(
+ model="text-embedding-v2", # 第二代通用模型
+ max_retries=3,
+ dashscope_api_key="sk-005c3c25f6d042848b29d75f2f020f08"
+)
+
+vector_store = Milvus(
+ embeddings,
+ connection_args={"uri": "http://47.119.128.20:19530"},
+ collection_name='doc_qa_db',
+)
+
+#获取检索器
+retriever = vector_store.as_retriever()
+retriever_tool = create_retriever_tool(
+ retriever,
+ "milvus_retriever",
+ "搜索有关 Milvus 的信息。对于任何有关 Milvus 的问题,你必须使用这个工具!",
+)
+
+
+# 初始化大模型
+llm = ChatOpenAI(
+ model_name = "qwen-plus",
+ base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
+ api_key="sk-005c3c25f6d042848b29d75f2f020f08",
+ temperature=0.7
+)
+
+tools = [web_search, retriever_tool]
+
+# #构建提示模板 ,采用create_tool_calling_agent的提示词模版
+```
+
+
+
+* 编码实战
+
+ ```python
+ # #构建提示模板 ,采用create_tool_calling_agent的提示词模版
+ # prompt = ChatPromptTemplate.from_messages([
+ # ("system", "你是一个AI文档助手,拥有多个工具,必要时可以利用工具来回答问题。"),
+ # ("user", "{input}"),
+ # ("placeholder", "{agent_scratchpad}")
+ # ])
+ # # 创建Agent执行器
+ # agent = create_tool_calling_agent(llm, tools,prompt)
+
+ #构建提示模板 ,采用create_react_agent的提示词模版
+ prompt = PromptTemplate.from_template('''Answer the following questions as best you can. You have access to the following tools:
+ {tools}
+
+ Use the following format:
+
+ Question: the input question you must answer
+ Thought: you should always think about what to do
+ Action: the action to take, should be one of [{tool_names}]
+ Action Input: the input to the action
+ Observation: the result of the action
+ ... (this Thought/Action/Action Input/Observation can repeat N times)
+ Thought: I now know the final answer
+ Final Answer: the final answer to the original input question
+
+ Begin!
+
+ Question: {input}
+ Thought:{agent_scratchpad}''')
+ agent = create_react_agent(llm, tools,prompt)
+
+ #创建Agent执行器
+ agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True,handle_parsing_errors=True,return_intermediate_steps=True)
+
+ def run_question(question: str):
+ print(f"\n问题:{question}")
+ result = agent_executor.invoke({"input": question})
+ print(f"\nllm-result:{result}")
+ print(f"\n答案:{result['output']}\n{'='*50}")
+ ```
+
+* 案例测试
+
+ * 提问输入问题
+
+ ```
+ run_question("中文回答下面3个问题:第一个:什么是Milvus,最新的版本是多少,如何整合LangChain框架,其与Faiss的优劣,最后给出GitHub最新教程链接; 第二个:现在的日期是几号;第三个:腾讯的股价是多少")
+ ```
+
+ * LangSmith调用链路分析
+
+ 
+
+ * 切换不同创建agent方法和提示词进行测试
+
+* 打印输出中间思考步骤
+
+ * 使用 AgentExecutor 的 `return_intermediate_steps` 参数
+
+ ```python
+ #print("最终结果:", result["output"])
+ #print("中间步骤:", result["intermediate_steps"])
+
+ def run_question(question: str):
+ print(f"\n问题:{question}")
+ result = agent_executor.invoke({"input": question})
+ print(f"\nllm-result:{result}")
+ print(f"\n答案:{result['output']}\n{'='*50}")
+ # 输出完整执行轨迹
+ print("=== 完整执行链 ===")
+ for step in result["intermediate_steps"]:
+ print(f"Action: {step[0].tool}")
+ print(f"Input: {step[0].tool_input}")
+ print(f"Observation: {step[1]}\n")
+ ```
+
+* 总结说明
+
+ * 在AI智能体开发中,不同的任务需要不同的交互逻辑,因此需要不同类型的智能体来高效处理不同任务。
+ * 例如:
+ - 有些任务需要智能体先“思考”再行动(如解数学题)。
+ - 有些任务需要直接调用工具完成(如查天气、调用计算器)
+ * **关键选择点**:
+ * 任务是否需要分解步骤 → 选`create_react_agent`;
+ * 任务是否单一明确 → 选`create_tool_calling_agent`。
+ * **进阶技巧**:
+ * 混合使用两种智能体(如先用React分解任务,再调用Tool-Calling执行子任务)
+ * 共同点
+ - 均基于大模型(如LLM大模型)驱动。
+ - 依赖预定义的工具集(Tools)。
+ * **底层关系**:
+ * `create_tool_calling_agent` 可视为 `create_react_agent` 的简化版(跳过显式推理步骤)。
+
+
+
+### 老王忘不了的痛-大模型存储记忆实战
+
+#### LLM大模型存储记忆功能介绍和应用场景
+
+* 需求背景:为什么需要存储记忆功能?
+
+ * 长对话上下文遗忘问题
+
+ ```
+ # 示例:第二次提问时模型已“失忆”
+ user_input1 = "我叫张三"
+ ai_response1 = "你好张三!"
+ user_input2 = "我叫什么名字?"
+ ai_response2 = "抱歉,我不知道您的名字。" # 期望回答“张三”
+ ```
+
+ * 大模型(如 GPT-4)单次对话的上下文窗口有限(通常为 4k-128k tokens),导致多轮对话中容易丢失早期信息。
+ * 例如,用户询问 “如何制作蛋糕” 后接着问 “需要烤箱吗”
+ * 模型若无法记住前一轮对话,可能回答 “需要烤箱” 但忘记蛋糕配方的关键步骤。
+
+ * 个性化服务与用户偏好记忆
+
+ * 在客服、教育、医疗等场景中,用户需要模型记住个人信息(如姓名、病史)或历史行为(如订单记录、学习进度)。
+ * 例如,医疗助手需根据患者的历史诊断结果提供建议。
+
+ * 复杂任务的状态管理
+
+ * 涉及多步骤的任务(如旅行规划、代码调试)需要模型跟踪中间状态。
+
+ * 例如,用户要求 “规划上海到北京的三天行程”,模型需记住已推荐的景点、交通方式等。
+
+* LangChain方法
+
+ * 短期记忆:通过 Memory 模块存储对话历史,确保模型在多轮交互中保持连贯
+
+ * 长期记忆:将用户数据存储在外部数据库或向量数据库(如 Milvus、Pinecone),实现跨会话的长期记忆
+
+* 记忆功能的核心设计
+
+ * 两种类型
+
+ | 维度 | 短期记忆 | 长期记忆 |
+ | :------------: | :----------------------------------: | :-----------------------------------------: |
+ | **存储方式** | 内存缓存, 模型输入中的历史消息 | 数据库持久化存储, 向量库/文件 |
+ | **容量限制** | 受上下文窗口限制(如4k-128k tokens) | 理论上无上限 |
+ | **访问速度** | 毫秒级 | 百毫秒级(依赖检索算法) |
+ | **典型应用** | 对话连贯性保持, 即时对话、单次任务 | 个性化服务、用户画像构建,跨会话记忆、知识库 |
+ | **实现复杂度** | 低 | 高 |
+ | **成本** | 低(无额外存储开销) | 中高(需维护存储系统) |
+ | **示例** | 聊天中记住前3轮对话 | 用户资料、项目历史记录 |
+
+ * 记忆的实现方式
+
+ * **短期记忆**:通过拼接历史消息实现(`[用户: 你好][AI: 你好!]`)。
+ * 长期记忆
+ - **结构化存储**:用数据库记录关键信息(如用户喜好)。
+ - **向量化存储**:将文本转为向量存入向量库(如Milvus)。
+ - **混合模式**:短期记忆 + 长期检索增强(RAG)
+
+* 应用场景与案例
+
+ * 个性化教育助手 (伪代码)
+
+ ```python
+ from langchain.memory import VectorStoreRetrieverMemory
+
+ # 初始化记忆系统
+ retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
+ memory = VectorStoreRetrieverMemory(retriever=retriever)
+
+ # 运行示例
+ memory.save_context(
+ {"input": "我的学习目标是掌握微积分"},
+ {"output": "目标已记录,将推荐相关资源"}
+ )
+ memory.save_context(
+ {"input": "请解释洛必达法则"},
+ {"output": f"{explanation} 已添加到你的学习清单"}
+ )
+
+ # 后续对话
+ query = "根据我的目标推荐学习资料"
+ relevant_memories = memory.load_memory_variables({"query": query})
+ # 返回微积分相关记忆
+
+ ```
+
+ * 电商推荐引擎
+
+ ```python
+ from langchain.retrievers import TimeWeightedVectorStoreRetriever
+
+ # 带时间权重的记忆系统
+ retriever = TimeWeightedVectorStoreRetriever(
+ vectorstore=vectorstore,
+ decay_rate=0.95, # 记忆衰减系数
+ k=5
+ )
+
+ # 记忆示例数据
+ retriever.add_documents([
+ Document(page_content="用户2026-12-01购买手机", metadata={"type": "purchase"}),
+ Document(page_content="用户2027-03-15浏览笔记本电脑", metadata={"type": "browse"}),
+ Document(page_content="用户2027-06-20退货耳机", metadata={"type": "return"})
+ ])
+
+ # 获取最新加权记忆
+ relevant_memories = retriever.get_relevant_documents("用户兴趣分析")
+ ```
+
+
+* 大模型长短期记忆选择决策树
+ * 基础用法:短期对话记忆
+ * 进阶用法:长期记忆 + 向量数据库
+ * 高级用法:多用户隔离记忆(会话级)
+
+
+
+
+
+#### LLM存储记忆功能之BaseChatMemory实战
+
+* `BaseChatMemory` 介绍
+
+ * 是 LangChain 中所有**聊天型记忆模块的基类**,定义了记忆存储和检索的通用接口。
+
+ ```
+ from langchain.memory.chat_memory import BaseChatMemory
+ ```
+
+ * 可通过继承此类实现自定义记忆逻辑(如过滤敏感信息、动态清理策略)
+
+ * 注意:部分API虽然过期,但也需要知道核心思想, 新旧我们都有讲
+
+ * 核心作用
+
+ * **标准化接口**:统一 `save_context()`(保存上下文)和 `load_memory_variables()`(加载记忆)方法。
+ * **状态管理**:维护对话历史(`chat_memory` 属性),支持消息的增删改查。
+ * **扩展性**:允许开发者覆盖默认行为(如自定义存储格式、加密数据)
+
+ * 关键属性
+
+ * `chat_memory`
+ * 存储对话消息的容器,类型为 ChatMessageHistory,包含 messages 列表
+ * 每条消息为 BaseMessage 对象,如 HumanMessage、AIMessage
+
+ * 核心方法
+
+ * `save_context` 保存用户输入和模型输出到 chat_memory。
+
+ ```
+ memory.save_context({"input": "你好"}, {"output": "你好!有什么可以帮您?"})
+ # 等价于:
+ memory.chat_memory.add_user_message("你好")
+ memory.chat_memory.add_ai_message("你好!有什么可以帮您?")
+ ```
+
+ * `load_memory_variables` 返回当前记忆内容(通常为 {"history": "对话历史字符串"}
+
+ ```
+ variables = memory.load_memory_variables({})
+ print(variables["history"]) # 输出:Human: 你好\nAI: 你好!有什么可以帮您?
+ ```
+
+ * `clear()` 清空所有记忆
+
+ ```
+ #调用
+ chat_memory.clear()
+ ```
+
+* `BaseChatMemory`的子类
+
+ | **类名** | **说明** |
+ | :------------------------------: | :----------------------------------------------------------: |
+ | `ConversationBufferMemory` | 直接存储原始对话历史(继承 `BaseChatMemory`)。 |
+ | `ConversationBufferWindowMemory` | 仅保留最近 N 轮对话(通过 `k` 参数控制,覆盖消息存储逻辑)。 |
+ | `ConversationSummaryMemory` | 存储模型生成的对话摘要(覆盖 `load_memory_variables` 生成摘要)。 |
+ | 自定义类 | 继承 `BaseChatMemory`,按需重写 `save_context` 或 `load_memory_variables` |
+
+* 案例实战
+
+ * `ConversationBufferMemory`
+
+ ```python
+ from langchain.memory import ConversationBufferMemory
+
+ # 初始化对话缓冲记忆
+ memory = ConversationBufferMemory(
+ memory_key="chat_history", #存储进去的Key,和获取的时候需要保持一致
+ return_messages=True,
+ )
+
+ # 添加用户消息和 AI 消息
+ memory.chat_memory.add_user_message("你的名字是什么")
+ memory.chat_memory.add_ai_message("二当家")
+
+ # 加载记忆内容
+ memory_variables = memory.load_memory_variables({})
+ print("记忆内容:", memory_variables)
+ ```
+
+ * `ConversationBufferWindowMemory `
+
+ * 滑动窗口式对话记忆, 此类在对话记录中引入窗口机制,仅保存最近的 `k` 条对话历史。
+ * **k 参数**:定义窗口大小,表示最多保留的对话记录条数, 适合长对话或对历史要求不高的应用。
+
+ ```python
+ from langchain.memory import ConversationBufferWindowMemory
+
+ # 初始化窗口记忆,设置窗口大小为 2
+ memory = ConversationBufferWindowMemory(k=2, memory_key="chat_history")
+
+ # 保存一些消息
+ memory.save_context({"input": "你叫什么名字"}, {"output": "你好,我是三当家"})
+ memory.save_context({"input": "小滴课堂怎么样"}, {"output": "小滴课堂是适合初学者的计算机学习平台"})
+ memory.save_context({"input": "好的,我去了解下"}, {"output": "希望对你有帮助!"})
+
+ # 获取窗口内的对话历史
+ window_history = memory.load_memory_variables({})
+ print("当前窗口内的对话历史:", window_history)
+ ```
+
+
+
+
+
+
+#### 【面试题】LLM存储优化-大量长对话如何解决
+
+* 面试官
+ * 传统对话系统每次交互独立,模型无法感知历史对话内容,如何解决?
+ * 长对话超出模型的Token处理能力,导致信息截断或性能下降,如何解决?
+
+* **大模型场景题目的需求背景【重要】**
+
+ * **大模型的上下文限制**
+ * 大语言模型(如GPT-4、DeepSeek等虽然能处理复杂的对话任务
+ * 但其输入长度存在限制(如Token上限),无法直接存储长期对话历史
+ * **对话连贯性需求**
+ * 实际应用中(如客服系统、智能助手),用户问题常依赖上下文。
+ * 例如,用户先问“人工智能的定义”,再要求“详细说明”,模型需基于历史回答才能生成合理响应
+ * 资源优化需求
+ * 直接存储完整对话历史会占用大量内存或数据库资源,且频繁传递完整上下文会增加计算成本。
+
+ | 问题类型 | 具体表现 | 后果 |
+ | :------: | :----------------------------: | :------------------------: |
+ | 技术限制 | 长对话超出模型上下文窗口 | 关键信息丢失,回答质量下降 |
+ | 效率瓶颈 | 全量历史数据检索耗时(>500ms) | 响应延迟影响用户体验 |
+ | 业务需求 | 需快速定位历史问题关键点 | 客服质检、争议溯源效率低 |
+ | 合规风险 | 存储用户敏感对话原文 | 数据泄露风险增加 |
+
+* 面试回答要点
+
+ * **核心目标**
+ * 通过摘要存储实现对话上下文的长期维护,解决大模型Token限制与对话连贯性问题。
+ * 技术实现
+ * 记忆模块:LangChain提供ConversationBufferMemory(完整历史)和ConversationSummaryMemory(摘要存储)等
+ * 摘要生成:调用LLM对历史对话生成摘要,后续交互仅传递摘要而非完整历史
+ * **优势**
+ - 减少Token消耗,适配模型输入限制。
+ - 提升对话系统的长期记忆能力。
+ - 支持分布式存储(如MongoDB、Milvus),扩展性强
+
+* `ConversationSummaryMemory`
+
+ * 通过模型生成对话的摘要,帮助保留重要信息,而不保存完整历史,适合需要长期记忆的场景。
+
+ * 原理就是提示词,让AI帮出来摘要,而且可以定制
+
+ ```python
+ 请将以下对话压缩为简短摘要,保留用户需求和关键结果:
+ 对话历史:
+ {history}
+
+ 当前对话:
+ Human: {input}
+ AI: {output}
+ 摘要:
+ """
+ ```
+
+ * **load_memory_variables**:返回当前会话的摘要信息。
+
+ ```python
+ from langchain.memory import ConversationSummaryMemory
+ from langchain_openai import ChatOpenAI
+
+ # 初始化大模型
+ llm = ChatOpenAI(
+ model_name = "qwen-plus",
+ base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
+ api_key="sk-005c3c25f6d042848b29d75f2f020f08",
+ temperature=0.7
+ )
+ # 初始化摘要记忆
+ memory = ConversationSummaryMemory(llm=llm)
+ # 模拟对话
+ memory.save_context({"input": "你叫什么名字?"}, {"output": "你好,我是三当家。"})
+ memory.save_context({"input": "你能告诉我机器学习吗?"}, {"output": "机器学习是人工智能的一个分支。"})
+ # 获取摘要
+ summary = memory.load_memory_variables({})
+ print("当前对话摘要:", summary)
+ ```
+
+
+
+#### 基于LangChain的带摘要存储对话系统实战
+
+* 实战案例
+
+ * 基于LangChain的带摘要存储对话系统
+
+ ```python
+ from langchain.memory import ConversationSummaryMemory
+ from langchain_openai import ChatOpenAI
+ from langchain_core.runnables import RunnablePassthrough
+ from langchain_core.output_parsers import StrOutputParser
+ from langchain_core.prompts import ChatPromptTemplate
+ from langchain.chains import LLMChain
+
+ # 初始化大模型
+ llm = ChatOpenAI(
+ model_name = "qwen-plus",
+ base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
+ api_key="sk-005c3c25f6d042848b29d75f2f020f08",
+ temperature=0.7
+ )
+
+ # 初始化模型和记忆模块
+ memory = ConversationSummaryMemory(
+ llm=llm,
+ memory_key="chat_history", # 与prompt中的变量名一致
+ return_messages=True
+ )
+
+ # 定义提示模板(必须包含chat_history占位符)
+ prompt = ChatPromptTemplate.from_messages([
+ ("system", "你是一个助手,需基于对话历史回答问题。当前摘要:{chat_history}"),
+ ("human", "{input}")
+ ])
+
+ # # 创建链并绑定记忆模块
+ # chain = LLMChain(
+ # llm=llm,
+ # prompt=prompt,
+ # memory=memory,
+ # verbose=True # 调试时查看详细流程
+ # )
+ # 定义LCEL链式流程
+ chain = (
+ # 注入输入和记忆
+ RunnablePassthrough.assign(
+ chat_history=lambda _: memory.load_memory_variables({})["chat_history"]
+ )
+ | prompt # 将输入传递给提示模板
+ | llm # 调用模型
+ | StrOutputParser() # 解析模型输出为字符串
+ )
+
+ # 模拟多轮对话
+ user_inputs = [
+ "人工智能的定义是什么?",
+ "小滴课堂上面有什么课程可以学习",
+ "人工智能它在医疗领域有哪些应用?"
+ ]
+
+ for query in user_inputs:
+ # 执行对话
+ response = chain.invoke({"input": query})
+
+ # 打印结果
+ print(f"\n用户:{query}")
+ print(f"AI:{response}")
+ #使用 LLMChain 而非原始LCEL链时,每次 invoke() 会自动调用 memory.save_context()。
+ #手动调用场景需显式保存:
+ memory.save_context({"input": query}, {"output": response})
+ print("当前记忆摘要:", memory.load_memory_variables({})["chat_history"])
+ ```
+
+ * 示例输出
+
+ ```markdown
+ 用户:人工智能的定义是什么?
+ AI:人工智能是模拟人类智能的计算机系统...
+ 当前记忆摘要: 用户询问人工智能的定义,助手解释了其核心是通过算法模拟人类认知能力。
+
+ 用户:小滴课堂上面有什么课程可以学习
+ AI:如果“小滴课堂”是一个特定的学习平台,建议直接查询该平台提供的课程列表以获取最新信息
+ 当前记忆摘要: 首先询问了人工智能的定义,AI解释了人工智能是计算机科学的一个分支,随后,人类问到“小滴课堂”上有什么课程可以学习
+
+ 用户:它在医疗领域有哪些应用?
+ AI:在医疗影像分析、药物研发...
+ 当前记忆摘要: 用户问及医疗应用,助手提到影像分析、药物研发和个性化诊疗是主要方向。
+ ```
+
+ * 关键步骤讲解
+
+ * **链式组合 (`|` 操作符)**
+ 通过管道符连接多个组件:
+ - `RunnablePassthrough`:传递原始输入
+ - `prompt`:格式化提示词
+ - `llm`:调用大模型
+ - `StrOutputParser`:解析输出为字符串
+ * **记忆管理**
+ - `memory.load_memory_variables()`:加载当前摘要到提示词
+ - `memory.save_context()`:手动保存对话记录(LCEL需要显式保存)
+ * **变量绑定**
+ 使用 `RunnablePassthrough.assign` 动态注入 `chat_history` 变量,确保与提示模板匹配
+
+ * 注意: 变量名一致性
+
+ - `memory_key` 必须与提示模板中的变量名一致(示例中均为 `chat_history`)。
+ - 错误示例:如果模板用 `{summary}` 但 `memory_key` 设为 `history`,会导致变量未注入
+
+* LCEL与 LLMChain 的核心区别
+
+ | 特性 | LCEL 实现 | LLMChain 实现 |
+ | :------------- | :--------------------------- | :------------------ |
+ | **记忆管理** | 需手动调用 `save_context` | 自动保存上下文 |
+ | **链式组合** | 支持任意步骤组合 | 固定结构 |
+ | **调试灵活性** | 可插入日志中间件 | 依赖 `verbose=True` |
+ | **扩展性** | 容易添加路由、分支等复杂逻辑 | 适合简单线性流程 |
+
+#### MessagesPlaceholder和多轮AI翻译助手实战
+
+* `MessagesPlaceholder `介绍
+
+ * 是 LangChain 中用于在 **聊天型提示模板(ChatPromptTemplate)** 中动态插入消息列表的占位符。
+
+ * 允许开发者将历史对话记录、系统消息等结构化地嵌入到 Prompt 中,从而支持多轮对话场景的上下文管理
+
+ * 适用场景
+
+ * 多角色对话:在聊天机器人中,区分系统指令、用户输入和AI响应。
+ * 历史对话注入:将历史消息作为上下文传递给模型,确保对话连贯性。
+ * 模块化Prompt设计:灵活组合不同来源的消息(如系统消息、检索结果等)
+
+ * 与普通PromptTemplate的区别
+
+ * PromptTemplate:用于单字符串模板,适合简单问答。
+
+ * ChatPromptTemplate:专为多角色消息设计,必须使用 MessagesPlaceholder 处理消息列表
+
+ * 例如
+
+ ```python
+ ChatPromptTemplate.from_messages([
+ ("system", "你是一个助手"),
+ MessagesPlaceholder(variable_name="history"),
+ ("human", "{input}")
+ ])
+ ```
+
+ * 核心功能对比
+
+ | 功能特性 | MessagesPlaceholder | 传统列表存储 |
+ | :--------------: | :--------------------------: | :----------------: |
+ | **动态插入** | ✅ 支持运行时动态调整消息顺序 | ❌ 固定顺序 |
+ | **消息类型感知** | ✅ 区分 system/human/AI | ❌ 统一存储为字符串 |
+ | **内存集成** | ✅ 自动与Memory组件同步 | ❌ 需手动管理 |
+ | **结构化操作** | ✅ 支持消息元数据 | ❌ 纯文本存储 |
+
+* 使用步骤
+
+ * 定义模板与占位符
+
+ * 在 ChatPromptTemplate 中通过 MessagesPlaceholder 声明占位位置
+ * **并指定变量名(需与 Memory 模块的 memory_key 一致)**
+
+ ```python
+ from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
+
+ prompt = ChatPromptTemplate.from_messages([
+ ("system", "你是一个翻译助手"),
+ MessagesPlaceholder(variable_name="chat_history"),
+ ("human", "{input}")
+ ])
+ ```
+
+ * 绑定记忆模块
+
+ * 使用 ConversationBufferMemory 或 ConversationSummaryMemory 存储对话历史,
+ * 并确保 memory_key 与占位符变量名匹配
+
+ ```python
+ from langchain.memory import ConversationBufferMemory
+
+ memory = ConversationBufferMemory(
+ memory_key="chat_history", # 必须与MessagesPlaceholder的variable_name一致
+ return_messages=True # 返回消息对象而非字符串
+ )
+ ```
+
+ * 链式调用与历史管理
+
+ * 在链式调用中自动注入历史消息,需使用 LLMChain 或 `RunnableWithMessageHistory`
+
+ ```python
+ from langchain.chains import LLMChain
+ from langchain_community.chat_models import ChatOpenAI
+
+ llm = ChatOpenAI()
+ chain = LLMChain(llm=llm, prompt=prompt, memory=memory)
+ ```
+
+* 案例测试
+
+ ```python
+ from langchain.memory import ConversationBufferMemory
+ from langchain_community.chat_models import ChatOpenAI
+ from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
+ from langchain.chains import LLMChain
+ from langchain_openai import ChatOpenAI
+
+ # 1. 初始化模型与记忆模块
+ # 初始化大模型
+ llm = ChatOpenAI(
+ model_name = "qwen-plus",
+ base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
+ api_key="sk-005c3c25f6d042848b29d75f2f020f08",
+ temperature=0.7
+ )
+
+ memory = ConversationBufferMemory(
+ memory_key="chat_history",
+ return_messages=True
+ )
+
+ # 2. 定义包含MessagesPlaceholder的Prompt模板
+ prompt = ChatPromptTemplate.from_messages([
+ ("system", "你是一个翻译助手,需参考历史对话优化翻译结果。"),
+ MessagesPlaceholder(variable_name="chat_history"),
+ ("human", "请翻译以下内容:{input}")
+ ])
+
+ # 3. 创建链并绑定记忆
+ chain = LLMChain(llm=llm, prompt=prompt, memory=memory)
+
+ # 4. 模拟多轮对话
+ user_inputs = [
+ "Translate 'Hello' to Chinese",
+ "Use the translation in a sentence",
+ "Now translate 'Goodbye'"
+ ]
+
+ for query in user_inputs:
+ response = chain.invoke({"input": query})
+ print(f"用户:{query}")
+ print(f"AI:{response['text']}\n")
+ print("当前对话历史:", memory.load_memory_variables({})["chat_history"], "\n")
+ ```
+
+ * LCEL表达式案例
+
+ ```python
+ from langchain.memory import ConversationBufferMemory
+ from langchain_community.chat_models import ChatOpenAI
+ from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
+ from langchain.chains import LLMChain
+ from langchain_openai import ChatOpenAI
+ from langchain_core.runnables import RunnablePassthrough
+ from langchain_core.output_parsers import StrOutputParser
+
+ # 1. 初始化模型与记忆模块
+ # 初始化大模型
+ llm = ChatOpenAI(
+ model_name = "qwen-plus",
+ base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
+ api_key="sk-005c3c25f6d042848b29d75f2f020f08",
+ temperature=0.7
+ )
+
+ memory = ConversationBufferMemory(
+ memory_key="chat_history",
+ return_messages=True
+ )
+
+ # 2. 定义包含MessagesPlaceholder的Prompt模板
+ prompt = ChatPromptTemplate.from_messages([
+ ("system", "你是一个翻译助手,需参考历史对话优化翻译结果。"),
+ MessagesPlaceholder(variable_name="chat_history"),
+ ("human", "请翻译以下内容:{input}")
+ ])
+
+
+ # 3. 创建链并绑定记忆
+ #chain = LLMChain(llm=llm, prompt=prompt, memory=memory)
+ #定义LECL表达式,构建chain
+ chain = (
+ RunnablePassthrough.assign(
+ chat_history = lambda _ : memory.load_memory_variables({})['chat_history']
+ )
+ | prompt
+ | llm
+ | StrOutputParser()
+ )
+
+ # 4. 模拟多轮对话
+ user_inputs = [
+ "Translate 'Hello' to Chinese",
+ "Use the translation in a sentence",
+ "Now translate 'Goodbye'"
+ ]
+
+ for query in user_inputs:
+ response = chain.invoke({"input": query})
+ print(f"用户:{query}")
+ print(f"AI:{response}\n")
+ memory.save_context({"input": query}, {"output": response})
+ print("当前对话历史:", memory.load_memory_variables({})["chat_history"], "\n")
+ ```
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#### 第6集 LLM复杂记忆存储-多会话隔离案例实战
+
+**简介:LLM复杂记忆存储-多会话隔离案例实战**
+
+* 背景与需求
+
+ * 当多个会话同时与对话系统交互时,需确保每个会话的对话历史独立存储,避免以下问题:
+
+ - **数据混淆**:会话A的对话内容泄露给会话B。
+ - **上下文丢失**:不同会话的对话历史互相覆盖。
+ - **隐私安全**:敏感信息因隔离不当导致泄露。
+
+ * **典型场景**
+
+ - **客服系统**:不同会话咨询需独立记录。
+ - **教育应用**:每个学生与AI助教的对话需单独存档。
+ - **医疗助手**:患者健康信息需严格隔离。
+
+ * **解决方案:为每个会话分配唯一ID,通过ID隔离的对话历史。**
+
+
+
+* `RunnableWithMessageHistory` 介绍
+
+ * 是 LangChain 中用于**动态管理多用户对话历史**的高级封装类,主要解决以下问题
+
+ * **会话隔离**:为不同用户/会话(通过 `session_id`)独立存储对话历史。
+ * **记忆注入**:自动将历史消息注入到链的每次执行中,无需手动传递。
+ * **灵活存储**:支持自定义历史存储后端(内存、数据库、Redis 等)。
+
+ * 核心参数
+
+ ```
+ from langchain_core.runnables.history import RunnableWithMessageHistory
+ ```
+
+ | 参数 | 类型 | 必填 | 说明 |
+ | :--------------------: | :-------------------------------------: | :--: | :-------------------------------------: |
+ | `runnable` | Runnable | 是 | 基础处理链(需支持消息历史输入) |
+ | `get_session_history` | Callable[[str], BaseChatMessageHistory] | 是 | 根据session_id获取历史存储实例的函数 |
+ | `input_messages_key` | str | 否 | 输入消息在字典中的键名(默认"input") |
+ | `history_messages_key` | str | 否 | 历史消息在字典中的键名(默认"history") |
+
+ * 使用场景
+
+ * **多用户对话系统**:为每个用户维护独立的对话历史(如客服系统)。
+ * **长期会话管理**:结合数据库存储历史,支持跨设备会话恢复。
+
+* 案例实战
+
+ ```
+ from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
+ from langchain_openai.chat_models import ChatOpenAI
+ from langchain_core.messages import HumanMessage
+ from langchain_core.runnables.history import RunnableWithMessageHistory
+ from langchain_community.chat_message_histories import ChatMessageHistory
+
+ # 存储会话历史的字典,可以改其他存储结构
+ store = {}
+ # 获取会话历史的函数 如果给定的session_id不在store中,则为其创建一个新的ChatMessageHistory实例
+ def get_session_history(session_id):
+ if session_id not in store:
+ store[session_id] = ChatMessageHistory()
+ return store[session_id]
+
+ # 初始化大模型
+ model = ChatOpenAI(
+ model_name = "qwen-plus",
+ base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
+ api_key="sk-005c3c25f6d042848b29d75f2f020f08",
+ temperature=0.7
+ )
+
+ # 构建聊天提示模板,包含系统消息、历史消息占位符和人类消息
+ prompt = ChatPromptTemplate.from_messages(
+ [
+ (
+ "system",
+ "你是一个小滴课堂AI助手,擅长能力{ability}。用30个字以内回答",
+ ),
+ MessagesPlaceholder(variable_name="history"),
+ ("human", "{input}"),
+ ]
+ )
+
+ # 创建Runnable管道,将提示模板和模型结合在一起
+ runnable = prompt | model
+
+ # 创建带有会话历史的Runnable ,使用get_session_history函数来管理会话历史
+ with_message_history = RunnableWithMessageHistory(
+ runnable,
+ get_session_history,
+ input_messages_key="input", #输入消息在字典中的键名(默认"input")
+ history_messages_key="history", #历史消息在字典中的键名(默认"history")
+ )
+
+ # 第一次调用带有会话历史的Runnable,提供用户输入和会话ID
+ response1=with_message_history.invoke(
+ {"ability": "Java开发", "input": HumanMessage("什么是jvm")},
+ config={"configurable": {"session_id": "user_123"}},#历史信息存入session_id
+ )
+ print(f"response1:{response1.content}",end="\n\n")
+
+ # 第二次调用带有会话历史的Runnable,用户请求重新回答上一个问题
+ response2=with_message_history.invoke(
+ {"ability": "Java开发", "input": HumanMessage("重新回答一次")},
+ config={"configurable": {"session_id": "user_123"}},#历史信息存入session_id,如果改为其他session_id,则不会关联到之前的会话历史
+ )
+ print(f"response2:{response2.content}",end="\n\n")
+
+ # 打印存储的会话历史
+ print(f"存储内容:{store}")
+ ```
+
+
+
+
+
+
+
+
+
+
+
+
+
+#### 第7集 再进阶复杂存储-多租户多会话隔离案例实战
+
+**简介:再进阶复杂存储-多用户多会话隔离案例实战**
+
+* 需求背景
+
+ * 系统需要支持多个用户访问,每个用户拥有唯一的标识符(`user_id`)。
+ * 用户之间的会话历史完全隔离,避免数据混淆。
+ * 业务场景中,存在一个用户多个会话的场景
+ * 存储里面需要支持多用户,多会话的方案, 支持不同用户在多个会话中与AI助手交互。
+
+* 目标:
+
+ * **多租户支持**:每个用户拥有独立的标识符(`user_id`),确保不同用户之间的数据隔离。
+ * **多会话支持**:每个用户可以同时维护多个会话(`session_id`),每个会话的历史记录相互独立。
+ * **灵活扩展性**:支持自定义存储结构和参数配置,便于未来扩展到分布式存储或其他存储介质
+
+* 知识点
+
+ * `history_factory_config`
+
+ - 是一个配置列表,用于定义额外的可配置字段,(如 `user_id` 和 `session_id`),这些字段可以影响会话历史的生成逻辑。
+ - 通过自定义参数来增强系统的灵活性,例如指定用户标识符或对话标识符,从而实现多租户或多会话的支持
+
+ * `ConfigurableFieldSpec`
+
+ * 是一个类,用于定义一个可配置字段的元信息,包括字段的 ID、类型、名称、描述、默认值等。
+
+ ```
+ from langchain_core.runnables import ConfigurableFieldSpec
+ ```
+
+ * 为 `RunnableWithMessageHistory` 提供灵活的参数支持,使得开发者可以通过配置动态调整行为。
+
+ | 参数名 | 类型 | 描述 | 示例值 |
+ | :------------ | :----- | :----------------------------------------------------------- | :--------------------- |
+ | `id` | `str` | 字段的唯一标识符,用于在配置中引用该字段。 | `"user_id"` |
+ | `annotation` | `type` | 字段的数据类型,用于类型检查和验证。 | `str` |
+ | `name` | `str` | 字段的名称,通常用于UI展示或调试信息。 | `"用户ID"` |
+ | `description` | `str` | 字段的描述信息,用于说明该字段的用途。 | `"用户的唯一标识符。"` |
+ | `default` | `any` | 字段的默认值,如果未提供值时使用。 | `""` |
+ | `is_shared` | `bool` | 是否为共享字段。如果为 `True`,则该字段在整个运行过程中保持不变。 | `True` |
+
+* 解决方案
+
+ * 使用 `user_id` 和 `session_id` 组合作为键值,存储在全局字典 `store` 中。
+ * 在调用 `get_session_history` 函数时,传入 `user_id` 和 `session_id`,确保获取正确的会话历史。
+
+* 案例实战
+
+ ```
+ from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
+ from langchain_openai.chat_models import ChatOpenAI
+ from langchain_core.messages import HumanMessage
+ from langchain_core.runnables.history import RunnableWithMessageHistory
+ from langchain_community.chat_message_histories import ChatMessageHistory
+ from langchain_core.runnables import ConfigurableFieldSpec
+
+ # 存储会话历史的字典,可以改其他存储结构
+ store = {}
+ # 获取会话历史的函数 如果给定的session_id不在store中,则为其创建一个新的ChatMessageHistory实例
+ def get_session_history(user_id: str,session_id: str):
+ if (user_id, session_id) not in store:
+ store[(user_id, session_id)] = ChatMessageHistory()
+ return store[(user_id, session_id)]
+
+
+ # 初始化大模型
+ model = ChatOpenAI(
+ model_name = "qwen-plus",
+ base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
+ api_key="sk-005c3c25f6d042848b29d75f2f020f08",
+ temperature=0.7
+ )
+
+ # 构建聊天提示模板,包含系统消息、历史消息占位符和人类消息
+ prompt = ChatPromptTemplate.from_messages(
+ [
+ (
+ "system",
+ "你是一个小滴课堂AI助手,擅长能力{ability}。用30个字以内回答",
+ ),
+ MessagesPlaceholder(variable_name="history"),
+ ("human", "{input}"),
+ ]
+ )
+
+ # 创建Runnable管道,将提示模板和模型结合在一起
+ runnable = prompt | model
+
+ # 创建带有会话历史的Runnable ,使用get_session_history函数来管理会话历史
+ with_message_history = RunnableWithMessageHistory(
+ runnable,
+ get_session_history,
+ input_messages_key="input", #输入消息在字典中的键名(默认"input")
+ history_messages_key="history", #历史消息在字典中的键名(默认"history")
+ # 定义一些自定义的参数
+ history_factory_config=[
+ ConfigurableFieldSpec(
+ id="user_id",
+ annotation=str,
+ name="用户ID",
+ description="用户的唯一标识符。",
+ default="",
+ is_shared=True,
+ ),
+ ConfigurableFieldSpec(
+ id="session_id",
+ annotation=str,
+ name="对话 ID",
+ description="对话的唯一标识符。",
+ default="",
+ is_shared=True,
+ ),
+ ]
+ )
+
+ # 第一次调用带有会话历史的Runnable,提供用户输入和会话ID
+ response1=with_message_history.invoke(
+ {"ability": "Java开发", "input": HumanMessage("什么是jvm")},
+ config={'configurable' : { "user_id" : "1" , "session_id" : "1" }}
+ )
+ print(f"response1:{response1.content}",end="\n\n")
+
+ # 第二次调用带有会话历史的Runnable,用户请求重新回答上一个问题
+ response2=with_message_history.invoke(
+ {"ability": "Java开发", "input": HumanMessage("重新回答一次")},
+ #历史信息存入session_id,如果改为其他session_id,则不会关联到之前的会话历史
+ config={'configurable' : { "user_id" : "1" , "session_id" : "2" }},
+
+ )
+ print(f"response2:{response2.content}",end="\n\n")
+ # 打印存储的会话历史
+ print(f"存储内容:{store}")
+ ```
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#### 第8集 大模型长期记忆解决方案和案例实战《上》
+
+**简介:大模型长期记忆解决方案和案例实战**
+
+* 长期记忆的核心需求
+
+ * 大模型(LLM)本身不具备长期记忆能力,需通过外部系统实现以下目标:
+ * **跨会话记忆持久化**:用户多次对话中产生的关键信息需永久存储。
+ * **多用户隔离**:不同用户的对话历史严格隔离,避免数据泄露。
+ * **高效检索**:快速提取历史信息辅助当前对话生成。
+ * **动态更新**:支持记忆的增量添加和过期清理。
+ * 解决思路:
+ * 持久化存储:将会话历史保存到数据库/缓存,支持跨会话读取。
+ * 高效检索:通过语义搜索或键值查询快速定位历史信息。
+ * 动态更新:根据新交互持续补充用户画像。
+
+* LangChain提供的存储方案
+
+ * 地址(失效忽略即可):https://python.langchain.com/docs/integrations/memory/
+
+ * `RedisChatMessageHistory` 存储介绍
+
+ 
+
+ * 内置的 Redis 消息历史存储工具,将会话记录以结构化形式保存至 Redis
+
+ | 特性 | 价值 |
+ | :-------------: | :----------------------------------------------------------: |
+ | 低延迟(<1ms) | 实时响应交互需求 |
+ | 丰富数据结构 | 灵活存储消息/元数据/关系, 使用 JSON 格式存储,支持复杂消息类型(如带元数据的消息) |
+ | 持久化选项 | RDB+AOF保障数据安全 |
+ | 集群支持 | 横向扩展应对高并发 |
+ | 自动过期(TTL) | 合规数据自动清理, 通过 `expire` 参数设置历史记录保存时间(如 30 天自动删除 |
+
+ * LangChain 的 `RedisChatMessageHistory` 等组件默认依赖 JSON 格式存储对话历史,ReJSON 提供天然的兼容性
+ * 数据存储结构
+
+
+
+
+
+
+
+* 什么是Redis-Stack
+
+ * 是Redis 官方推出的 集成化发行版,预装了多个高性能模块和工具,专为现代应用设计。
+
+ * **开箱即用**:无需手动安装模块,直接支持搜索、JSON、图数据库等高级功能。
+
+ * **开发友好**:更适合需要复杂查询、实时分析、AI 应用的场景(如大模型上下文管理、聊天记录检索)。
+
+ * **统一体验**:通过 Redis Stack 命令行或客户端库统一访问所有功能。
+
+ | 模块/工具 | 功能 |
+ | :------------------ | :----------------------------------- |
+ | **RediSearch** | 全文搜索、二级索引 |
+ | **RedisJSON** | 原生 JSON 数据支持 |
+ | **RedisGraph** | 图数据库(基于属性图模型) |
+ | **RedisTimeSeries** | 时间序列数据处理 |
+ | **RedisBloom** | 概率数据结构(布隆过滤器、基数估算) |
+ | **RedisInsight** | 图形化管理工具 |
+
+ * 何时选择 Redis Stack?
+
+ * 全文检索(如聊天记录搜索)。
+ * 直接操作 JSON 数据(如存储大模型的对话上下文)。
+ * 时间序列分析(如监控聊天频率)。
+ * 图关系查询(如社交网络分析)。
+ * 简化开发流程:避免手动配置多个模块的兼容性和依赖。
+
+ * LLM整合如果直接使用之前的Redis服务端会报错,新版单独安装 RedisStack 服务端,才支持相关Redis搜索
+
+ * 之前部署的Redis可以卸载,或者更改端口,也可以配置密码,使用方式一样,redis-stack 7.X版本都可以
+
+ ```
+ docker run -d \
+ --name redis-stack \
+ -p 6379:6379 \
+ -p 8001:8001 \
+ redis/redis-stack:latest
+ ```
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#### 第9集 大模型长期记忆解决方案和案例实战《下》
+
+**简介:大模型长期记忆解决方案和案例实战**
+
+* 案例实战
+
+ * 安装依赖
+
+ ```
+ pip install langchain-redis==0.2.0 redis==5.2.1
+ ```
+
+ * 案例测试
+
+ ```
+ from langchain_redis import RedisChatMessageHistory
+ import os
+
+ REDIS_URL = os.getenv("REDIS_URL", "redis://47.119.128.20:6379")
+ #配置了密码 REDIS_URL = "redis://:your_password@your_ip:6379"
+ #REDIS_URL = os.getenv("REDIS_URL", "redis://:abc123456@39.108.115.28:6379")
+
+ # 初始化 RedisChatMessageHistory
+ history = RedisChatMessageHistory(session_id="user_123", redis_url=REDIS_URL)
+
+ # 新增消息
+ history.add_user_message("Hello, AI assistant!")
+ history.add_ai_message("Hello! How can I assist you today?")
+
+ # 检索消息
+ print("Chat History:")
+ for message in history.messages:
+ print(f"{type(message).__name__}: {message.content}")
+ ```
+
+ * 编码实战
+
+ ```
+ from langchain_core.chat_history import BaseChatMessageHistory
+ from langchain_core.messages import AIMessage, HumanMessage
+ from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
+ from langchain_core.runnables.history import RunnableWithMessageHistory
+ from langchain_openai import ChatOpenAI
+ from langchain_redis import RedisChatMessageHistory
+
+ #存储历史会话的字典
+
+ REDIS_URL="redis://47.119.128.20:6379"
+ #定义函数,用于获取会话历史
+ def get_redis_history(session_id: str):
+ return RedisChatMessageHistory(session_id, redis_url=REDIS_URL)
+
+ # 初始化大模型
+ model = ChatOpenAI(
+ model_name = "qwen-plus",
+ base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
+ api_key="sk-005c3c25f6d042848b29d75f2f020f08",
+ temperature=0.7
+ )
+
+ # 构建聊天提示模板,包含系统消息、历史消息占位符和人类消息
+ prompt = ChatPromptTemplate.from_messages(
+ [
+ ("system","你是一个小滴课堂AI助手,擅长能力{ability}。用30个字以内回答",),
+ MessagesPlaceholder(variable_name="history"),
+ ("human", "{input}"),
+ ]
+ )
+
+ #创建基础链
+ chain = prompt | model
+
+ with_message_history = RunnableWithMessageHistory(
+ chain, get_redis_history, input_messages_key="input", history_messages_key="history"
+ )
+
+ #第一次调用,提供用户输入和会话ID
+ resp1 = with_message_history.invoke(
+ {"ability":"Java开发", "input":HumanMessage("什么是JVM")}, #替换提示词
+ config={"configurable":{"session_id":"user_123"} }) #会话唯一ID
+
+ print(f"resp1={resp1.content}",end="\n\n")
+
+ resp2 = with_message_history.invoke(
+ {"ability":"Java开发", "input":HumanMessage("重新回答一次")}, #替换提示词
+ config={"configurable":{"session_id":"user_123"} }) #会话唯一ID
+
+ print(f"resp2={resp2.content}",end="\n\n")
+ ```
+
+ * 注意: 安全起见,RedisStack还是需要配置密码,避免入侵挖矿
+
+ ```
+ docker run -d \
+ --name redis-stack \
+ -p 6379:6379 \
+ -p 8001:8001 \
+ -e REDIS_ARGS="--requirepass abc123456" \
+ redis/redis-stack:latest
+ ```
+
+ * 多租户多会话方案
+
+ ```
+ from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
+ from langchain_openai.chat_models import ChatOpenAI
+ from langchain_core.messages import HumanMessage
+ from langchain_core.runnables.history import RunnableWithMessageHistory
+ from langchain_community.chat_message_histories import ChatMessageHistory
+ from langchain_core.runnables import ConfigurableFieldSpec
+ from langchain_redis import RedisChatMessageHistory
+
+ #存储历史会话的字典
+
+ REDIS_URL="redis://:abc123456@47.119.128.20:6379"
+
+ # 获取会话历史的函数 如果给定的session_id不在store中,则为其创建一个新的ChatMessageHistory实例
+ def get_session_history(user_id: str,session_id: str):
+ uni_key = user_id+"_"+session_id
+
+ return RedisChatMessageHistory(
+ session_id=uni_key,
+ redis_url=REDIS_URL)
+
+
+
+ # 初始化大模型
+ model = ChatOpenAI(
+ model_name = "qwen-plus",
+ base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
+ api_key="sk-005c3c25f6d042848b29d75f2f020f08",
+ temperature=0.7
+ )
+
+ # 构建聊天提示模板,包含系统消息、历史消息占位符和人类消息
+ prompt = ChatPromptTemplate.from_messages(
+ [
+ (
+ "system",
+ "你是一个小滴课堂AI助手,擅长能力{ability}。用30个字以内回答",
+ ),
+ MessagesPlaceholder(variable_name="history"),
+ ("human", "{input}"),
+ ]
+ )
+
+ # 创建Runnable管道,将提示模板和模型结合在一起
+ runnable = prompt | model
+
+ # 创建带有会话历史的Runnable ,使用get_session_history函数来管理会话历史
+ with_message_history = RunnableWithMessageHistory(
+ runnable,
+ get_session_history,
+ input_messages_key="input", #输入消息在字典中的键名(默认"input")
+ history_messages_key="history", #历史消息在字典中的键名(默认"history")
+ # 定义一些自定义的参数
+ history_factory_config=[
+ ConfigurableFieldSpec(
+ id="user_id",
+ annotation=str,
+ name="用户ID",
+ description="用户的唯一标识符。",
+ default="",
+ is_shared=True,
+ ),
+ ConfigurableFieldSpec(
+ id="session_id",
+ annotation=str,
+ name="对话 ID",
+ description="对话的唯一标识符。",
+ default="",
+ is_shared=True,
+ ),
+ ]
+ )
+
+ # 第一次调用带有会话历史的Runnable,提供用户输入和会话ID
+ response1=with_message_history.invoke(
+ {"ability": "Java开发", "input": HumanMessage("什么是jvm")},
+ config={'configurable' : { "user_id" : "user_1" , "session_id" : "session_1" }}
+ )
+ print(f"response1:{response1.content}",end="\n\n")
+ # 打印存储的会话历史
+ print(get_session_history("user_1","session_1").messages)
+
+ # 第二次调用带有会话历史的Runnable,用户请求重新回答上一个问题
+ response2=with_message_history.invoke(
+ {"ability": "Java开发", "input": HumanMessage("重新回答一次")},
+ config={'configurable' : { "user_id" : "user_2" , "session_id" : "session_1" }},
+ )
+ print(f"response2:{response2.content}",end="\n\n")
+ # 打印存储的会话历史
+ print(get_session_history("user_2","session_1").messages)
+ ```
+
+
+
+
+
+
+
+
+
+
+
+ **愿景:"IT路上的持续充电平台,让技术不再难学"**
+**更多高级课程请访问 xdclass.net**
+
+### 第四十八章 大模型服务必备FastAPI Web框架
+
+
+
+#### 第1集 Python Web框架Fast API技术介绍
+
+**简介: Python Web框架Fast API技术介绍**
+
+* 需求背景:现代Web开发痛点
+
+ * 传统框架(如Flask、Django)对异步支持弱,性能受限。
+ * 手动编写API文档耗时且易过时、缺乏自动化数据验证,易出现安全漏洞。
+
+* FastAPI是什么?
+
+ - 一个基于 Python 3.8+ 的现代 Web 框架,专为构建高性能 API 设计。
+ - 官方地址:
+ - https://github.com/fastapi/fastapi
+ - https://fastapi.tiangolo.com/
+ - 关键特性:
+ - ⚡ 高性能:基于Starlette(异步)和Pydantic(数据验证)
+ - 📚 自动文档:集成Swagger UI和Redoc,代码即文档。
+ - ✅ 强类型安全:Python类型提示 + Pydantic模型,减少Bug。
+ - 🚀 易学易用:代码简洁,适合快速开发API。
+ - 适用场景
+ * 构建 RESTful API 或 大模型 服务,微服务架构中的独立服务模块。
+ * 需要自动生成 API 文档的项目。
+ * **核心价值**:FastAPI = 高性能 + 强类型 + 自动文档。
+ - **优点**:
+ - 开发效率高(代码量减少 40%+)
+ - 严格的类型提示减少运行时错误。
+ - **缺点**:
+ - 生态相对较新(插件和社区资源少于 Django/Flask)。
+ - 学习曲线略高(需熟悉 异步编程)。
+
+* 什么是 Uvicorn(类似Java 生态的Tomcat)
+
+ * 是一个轻量级、高性能的 **ASGI(Asynchronous Server Gateway Interface)服务器**
+ * 专门运行异步 Python Web 应用(如 FastAPI、Starlette 或 Django Channels)。
+ * 类似传统 WSGI 服务器 的异步升级版,支持 HTTP/1.1、WebSockets 和 ASGI 标准。
+ * **核心功能**
+ * **异步处理**:基于 `asyncio` 库,原生支持 `async/await`,适合高并发场景(如实时通信、高频 API 调用)。
+ * **高性能**:使用 C 语言编写的 `uvloop` 和 `httptools` 加速网络请求处理。
+ * **自动重载**:开发时通过 `--reload` 参数监听代码变动,自动重启服务。
+ * **协议支持**: HTTP/1.1 、WebSocket、实验性 HTTP/2(需额外配置)
+ * 与 FastAPI 的关系
+ * 依赖关系:FastAPI 本身不包含服务器,需通过 Uvicorn(或其他 ASGI 服务器)启动。
+ * 协同工作流程:
+ * 用户通过 Uvicorn 启动 FastAPI 应用。
+ * Uvicorn 监听 HTTP 请求,将请求转发给 FastAPI 处理。
+ * FastAPI 处理请求并返回响应,由 Uvicorn 发送给客户端
+
+* 类似产品对比
+
+ | 框架 | 语言 | 特点 | 适用场景 |
+ | :-------------- | :------ | :----------------------------------- | :---------------------- |
+ | **Flask** | Python | 轻量级、灵活,但同步且无内置数据验证 | 小型应用、快速原型开发 |
+ | **Django** | Python | 全功能(ORM、Admin),但重量级、同步 | 复杂 Web 应用(如 CMS) |
+ | **Express** | Node.js | 高并发,但动态类型易出错 | JS 生态的 API 开发 |
+ | **Spring Boot** | Java | 企业级功能,但配置复杂、启动慢 | 大型分布式系统 |
+ | **FastAPI** | Python | 高性能、异步、类型安全、自动文档 | 高并发 API、微服务 |
+
+
+
+
+
+
+
+
+
+
+
+
+
+#### 第2集 FastAPI环境安装和基础案例实战
+
+**简介: FastAPI环境安装和基础案例实战**
+
+* 环境安装
+
+ * FastAPI 依赖 Python 3.8 及更高版本, 安装fastapi版本 `0.115.12`
+ * 安装命令
+ * 安装依赖库. `pip install "fastapi[standard]"`
+ * 安装uvicorn服务器 `pip install "uvicorn[standard]"`
+
+* 案例实战
+
+ * 创建第一个Fast API应用
+
+ ```
+ from typing import Union
+
+ from fastapi import FastAPI
+
+ # 创建FastAPI实例
+ app = FastAPI()
+
+ #http请求方式类型:get、post、put、update、delete
+ #不带参数访问路由
+ @app.get("/")
+ def read_root():
+ return {"Hello": "World11"}
+
+
+ # 带参数访问,比如 http://127.0.0.1:8000/items/5?q=xd
+ # q参数通过 Union[str, None] 表示可以是字符串类型或空,这样就允许在请求中不提供 q 参数。
+ @app.get("/items/{item_id}")
+ def read_item(item_id: int, q: Union[str, None] = None):
+ return {"item_id": item_id, "q": q}
+ ```
+
+ * 启动服务
+
+ ```
+ #语法:uvicorn 文件的相对路径:实例名 --reload
+ #--reload:代码修改后自动重启(仅开发环境)
+ uvicorn main:app --reload
+
+ #指定程序监听端口
+ uvicorn main:app --port 8002 --reload
+
+ #下面这个方式也可以
+ fastapi dev main.py
+ ```
+
+ * 访问API与文档
+
+ * API地址:`http://localhost:8000`
+ * 交互文档:`http://localhost:8000/docs`
+ * 备用文档( 另一种交互式文档界面,具有清晰简洁的外观 ):`http://localhost:8000/redoc`
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#### 第3集 进阶FastAPI Web多案例参数请求实战
+
+**简介: 进阶FastAPI Web多案例参数请求实战**
+
+* 路由与 HTTP 方法
+
+ ```
+ from fastapi import FastAPI
+
+ app = FastAPI()
+
+ @app.get("/items/{item_id}")
+ def read_item(item_id: int): # 自动类型转换和验证
+ return {"item_id": item_id}
+
+ @app.post("/items/")
+ def create_item(item: dict):
+ return {"item": item}
+
+ @app.put("/items/{item_id}")
+ def update_item(item_id: int, item: dict):
+ return {"item_id": item_id, "updated_item": item}
+
+ @app.delete("/items/{item_id}")
+ def delete_item(item_id: int):
+ return {"status": "deleted", "item_id": item_id}
+
+ ```
+
+* 请求头Header操作
+
+ ```
+ from fastapi import Header
+
+ @app.get("/header")
+ def read_item(item_id: int, token: str = Header("token")):
+ return {"token": token,"item_id": item_id}
+
+ ```
+
+* 获取多个请求头
+
+ ```
+ from fastapi import Request
+ @app.get("/all-headers/")
+ def get_all_headers(request: Request):
+ return dict(request.headers)
+ ```
+
+* 自定义响应头
+
+ ```
+ from fastapi.responses import JSONResponse
+ @app.get("/custom-header/")
+ def set_custom_header():
+ content = {"message": "Hello World"}
+ headers = {
+ "X-Custom-Header": "my_value xdclass.net",
+ "Cache-Control": "max-age=3600"
+ }
+ return JSONResponse(content=content, headers=headers)
+
+ ```
+
+* 自定义响应码
+
+ ```
+ from fastapi import FastAPI, status,Response
+
+ @app.get("/status_code", status_code=200)
+ def create_item(name: str):
+ if name == "Foo":
+ return Response(status_code=status.HTTP_404_NOT_FOUND)
+ return {"name": name}
+ ```
+
+
+
+
+
+
+
+
+
+
+
+#### 第4集 FastAPI异步编程async-await多案例实战 《上》
+
+**简介: FastAPI异步编程async-await多案例实战**
+
+* 需求背景
+
+ * 什么是同步和异步? 用一个奶茶店买饮料的场景帮理解同步和异步的区别
+
+ * 🧋 **同步(Synchronous)就像传统奶茶店**
+
+ ```
+ 你: 老板,我要一杯珍珠奶茶
+ 店员: 开始制作(5分钟)
+ 你: 干站着等,不能做其他事
+ 店员: 做好了!请取餐
+ 下一位顾客: 必须等前一个人完成才能点单
+ 特点: 必须按顺序处理,前一个任务没完成,后面全卡住
+ ```
+
+ * 🚀 异步(Asynchronous)像智能奶茶店
+
+ ```
+ 你: 扫码下单珍珠奶茶
+ 系统: 收到订单(生成取餐号)
+ 你: 去旁边座位玩手机(不用干等)
+ 店员: 同时处理多个订单
+ 系统: 奶茶做好后叫号通知你
+ 特点: 下单后可以继续做其他事,系统并行处理多个任务
+ ```
+
+ * 对应到代码中
+
+ ```
+ # 同步代码(传统奶茶店模式)
+ def make_tea():
+ print("开始煮茶") # 👨🍳 店员开始工作
+ time.sleep(3) # ⏳ 你干等着
+ print("加珍珠")
+ return "奶茶好了"
+
+ # 异步代码(智能奶茶店模式)
+ async def async_make_tea():
+ print("开始煮茶")
+ await asyncio.sleep(3) # 🚶♂️ 你可以去做其他事
+ print("加珍珠")
+ return "奶茶好了"
+ ```
+
+* 同步和异步关键区别总结【伪代码】
+
+ * 同步版本(存在性能瓶颈)
+
+ ```
+ import requests
+
+ @app.get("/sync-news")
+ def get_news_sync():
+ # 顺序执行(总耗时=各请求之和)
+ news1 = requests.get("https://api1.com").json() # 2秒
+ news2 = requests.get("https://api2.com").json() # 2秒
+ return {"total_time": 4}
+ ```
+
+ * 异步版本(高效并发)
+
+ ```
+ import httpx
+
+ @app.get("/async-news")
+ async def get_news_async():
+ async with httpx.AsyncClient() as client:
+ # 并行执行(总耗时≈最慢的请求)
+ start = time.time()
+ task1 = client.get("https://api1.com")
+ task2 = client.get("https://api2.com")
+ res1, res2 = await asyncio.gather(task1, task2)
+ return {
+ "total_time": time.time() - start # ≈2秒
+ }
+ ```
+
+* 异步编程常见类库介绍
+
+* * `asyncio` 类库
+
+ * Python 中用于编写**单线程并发代码**的库,基于**协程(Coroutine)**和**事件循环(Event Loop)**实现异步编程。
+
+ * 专为处理 I/O 密集型任务(如网络请求、文件读写、数据库操作)设计,提高程序的吞吐量和资源利用率
+
+ * **协程(Coroutine)**
+
+ - 使用 `async def` 定义的函数称为协程,返回一个协程对象,不会立即执行。
+
+ - 协程通过 `await` 关键字挂起自身,将控制权交还给事件循环,直到异步操作完成
+
+ ```
+ async def my_coroutine():
+ await asyncio.sleep(1)
+ print("Done!")
+ ```
+
+ * **事件循环(Event Loop)**
+
+ - 事件循环是异步程序的核心,负责调度和执行协程、处理 I/O 事件、管理回调等。
+
+ - 通过 `asyncio.run()` 或手动创建事件循环来启动。
+
+ ```
+ # 启动事件循环并运行协程
+ asyncio.run(my_coroutine())
+ ```
+
+ * **任务(Task)**
+
+ - 任务是对协程的封装,用于在事件循环中并发执行多个协程。
+
+ - 通过 `asyncio.create_task()` 创建任务
+
+ ```
+ async def main():
+ task = asyncio.create_task(my_coroutine())
+ await task
+ ```
+
+ * **Future**
+
+ - `Future` 是一个底层对象,表示异步操作的最终结果。通常开发者直接使用 `Task`(它是 `Future` 的子类)。
+
+
+
+ * `httpx` 类库
+
+ * Python 中一个现代化、功能丰富的 HTTP 客户端库,支持同步和异步请求
+
+ * `httpx` 是 `requests` 的现代替代品,结合了易用性与强大功能,尤其适合需要异步或 HTTP/2 支持的场景。
+
+ * 同步请求案例
+
+ ```
+ import httpx
+ # GET 请求
+ response = httpx.get("https://httpbin.org/get")
+ print(response.status_code)
+ print(response.json())
+ ```
+
+ * 异步请求案例
+
+ ```
+ import httpx
+ import asyncio
+
+ async def fetch_data():
+ async with httpx.AsyncClient() as client:
+ response = await client.get("https://httpbin.org/get")
+ print(response.json())
+
+ asyncio.run(fetch_data())
+ ```
+
+ * 使用客户端实例(推荐)
+
+ ```
+ # 同步客户端
+ with httpx.Client() as client:
+ response = client.get("https://httpbin.org/get")
+
+ # 异步客户端
+ async with httpx.AsyncClient() as client:
+ response = await client.get("https://httpbin.org/get")
+ ```
+
+
+
+
+
+
+
+
+
+
+
+
+
+#### 第5集 FastAPI异步编程async-await多案例实战 《下》
+
+**简介: FastAPI异步编程async-await多案例实战**
+
+* 案例实战
+
+ * 基础同步和异步编程
+
+ ```
+ from fastapi import FastAPI
+ import asyncio
+ import time
+
+ app = FastAPI()
+
+ # 同步路由执行(顺序阻塞)
+ @app.get("/sync_func")
+ def sync_endpoint():
+ # 模拟耗时操作
+ print("开始任务1") # 立即执行
+ time.sleep(3) # 阻塞3秒
+ print("开始任务2") # 3秒后执行
+ return {"status": "done"}
+
+ # 异步异步执行(非阻塞切换)
+ @app.get("/async_func")
+ async def async_endpoint(): # 异步接口
+ # 必须使用异步库
+ print("开始任务A") # 立即执行
+ await asyncio.sleep(3) # 释放控制权,异步等待
+ print("开始任务B") # 3秒后恢复执行
+ return {"status": "done"}
+ ```
+
+ * 综合案例实战:并发调用外部API
+
+ ```
+ import asyncio
+ import httpx
+ from fastapi import FastAPI
+
+ app = FastAPI()
+
+ """
+ 异步函数:fetch_data
+ 功能:通过HTTP GET请求从指定URL获取数据并返回JSON格式的响应。
+ 参数:
+ url (str): 目标API的URL地址。
+ 返回值:
+ dict: 从目标URL获取的JSON格式数据。
+ """
+ async def fetch_data(url: str):
+ async with httpx.AsyncClient() as client:
+ response = await client.get(url)
+ return response.json()
+
+
+
+ """
+ 路由处理函数:get_news
+ 功能:定义一个FastAPI的GET路由,用于并发获取多个API的数据并返回整合后的结果。
+ """
+ @app.get("/xdclass")
+ async def get_news():
+ start = time.time()
+ # 定义需要请求的API URL列表
+ urls = [
+ "https://api-v2.xdclass.net/api/funny/v1/get_funny",
+ "https://api-v2.xdclass.net/api/banner/v1/list?location=home_top_ad",
+ "https://api-v2.xdclass.net/api/rank/v1/hot_product",
+ "http://localhost:8000/sync1",
+ "http://localhost:8000/sync2",
+ ]
+
+ # 创建并发任务列表,每个任务调用fetch_data函数获取对应URL的数据
+ tasks = [fetch_data(url) for url in urls]
+
+ # 使用asyncio.gather并发执行所有任务,并等待所有任务完成
+ results = await asyncio.gather(*tasks)
+ print(f"共耗时 {time.time() - start} 秒")
+ # 返回整合后的结果
+ return results
+ ```
+
+
+
+* 常见错误模式演示
+
+ ```
+ # 错误示例:在async函数中使用同步阻塞
+ @app.get("/wrong")
+ async def bad_example():
+ time.sleep(5) # 会阻塞整个事件循环!
+
+ # 正确方案1:改用异步等待
+ @app.get("/right1")
+ async def good_example():
+ await asyncio.sleep(5)
+ ```
+
+
+
+* 最佳实践指南
+
+ * **必须使用async的三种场景**
+
+ * 需要await调用的异步库操作
+ * WebSocket通信端点
+ * 需要后台任务处理的接口
+
+ * **以下情况适合同步路由**
+
+ - 纯CPU计算(如数学运算)
+ - 使用同步数据库驱动
+ - 快速返回的简单端点
+
+ * **路由声明规范**
+
+ * 所有路由优先使用`async def`
+ * 仅在必须使用同步操作时用普通 `def`
+
+ * **性能优化建议**
+
+ - 保持async函数轻量化
+ - 长时间CPU密集型任务使用后台线程
+ - 使用连接池管理数据库/HTTP连接
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#### 第6集 进阶FastAPI模型Pydantic 案例实战
+
+**简介: 进阶FastAPI模型Pydantic 案例实战**
+
+* 什么是数据模型
+
+ * 客户端能发送什么数据
+ * 服务端会返回什么数据
+ * 数据验证规则
+
+* 基础模型定义
+
+ ```
+ from pydantic import BaseModel
+
+ # 用户注册模型
+ class UserRegister(BaseModel):
+ username: str # 必填字段
+ email: str | None = None # 可选字段
+ age: int = Field(18, gt=0) # 带默认值和验证
+ ```
+
+* 案例实战
+
+ * 请求体(POST/PUT数据)
+
+ ```
+ from pydantic import BaseModel,Field
+ class Product(BaseModel):
+ name: str
+ price: float = Field(..., gt=0)
+ tags: list[str] = []
+
+ @app.post("/products")
+ async def create_product(product: Product):
+ return product.model_dump()
+
+
+ #测试数据
+ {
+ "name":"小滴",
+ "price":111,
+ "tags":["java","vue"]
+ }
+ ```
+
+ * 返回 Pydantic 模型
+
+ ```
+ from pydantic import BaseModel
+ class Item(BaseModel):
+ name: str
+ description: str = None
+ price: float
+ tax: float = None
+
+ @app.post("/items")
+ async def create_item(item: Item):
+ return item
+
+ #测试数据
+ {
+ "name":"小滴",
+ "price":111,
+ "description":"小滴课堂是在线充电平台"
+ }
+ ```
+
+ * 密码强度验证
+
+ ```
+ from pydantic import BaseModel, field_validator
+
+ class UserRegistration(BaseModel):
+ username: str
+ password: str
+
+ @field_validator('password')
+ def validate_password(cls, v):
+ if len(v) < 8:
+ raise ValueError('密码至少8位')
+ if not any(c.isupper() for c in v):
+ raise ValueError('必须包含大写字母')
+ if not any(c.isdigit() for c in v):
+ raise ValueError('必须包含数字')
+ return v
+
+ @app.post("/register/")
+ async def register(user: UserRegistration):
+ return {"username": user.username}
+
+
+ #测试数据
+ {
+ "username":"小滴",
+ "password":"123"
+ }
+ ```
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ **愿景:"IT路上的持续充电平台,让技术不再难学"**
+**更多高级课程请访问 xdclass.net**
+
+### 第四十九章 FastAPI框架高级技能和综合项目实战
+
+
+
+#### 第1集 FastAPI路由管理APIRouter案例实战
+
+**简介: FastAPI 路由管理APIRouter案例实战**
+
+* 需求背景
+
+ * 代码混乱问题, 未使用路由管理(所有接口堆在main.py中)
+
+ * 所有接口混杂在一个文件中,随着功能增加,文件会变得臃肿难维护。
+
+ ```
+ # main.py
+ from fastapi import FastAPI
+
+ app = FastAPI()
+
+ # 用户相关接口
+ @app.get("/users")
+ def get_users(): ...
+
+ # 商品相关接口
+ @app.get("/items")
+ def get_items(): ...
+
+ # 订单相关接口
+ @app.get("/orders")
+ def get_orders(): ...
+ ```
+
+ * 重复配置问题, 未使用路由管理(重复写前缀和标签)
+
+ * 每个接口都要重复写`/api/v1`前缀和`tags`,容易出错且难以统一修改
+
+ ```
+ # 用户接口
+ @app.get("/api/v1/users", tags=["用户管理"])
+ def get_users_v1(): ...
+
+ # 商品接口
+ @app.get("/api/v1/items", tags=["商品管理"])
+ def get_items_v1(): ...
+ ```
+
+ * 权限控制问题, 未使用路由管理(每个接口单独添加认证)
+
+ * 需要在每个管理员接口重复添加认证依赖。
+
+ ```
+ @app.get("/admin/stats", dependencies=[Depends(admin_auth)])
+ def get_stats(): ...
+
+ @app.post("/admin/users", dependencies=[Depends(admin_auth)])
+ def create_user(): ...
+ ```
+
+
+
+* **使用路由管理(模块化拆分)**
+
+ * 按业务模块拆分,每个文件职责单一。
+
+ ```
+ # 文件结构
+ routers/
+ ├── users.py # 用户路由
+ ├── items.py # 商品路由
+ └── orders.py # 订单路由
+
+ # main.py
+ from routers import users, items, orders
+ app.include_router(users.router)
+ app.include_router(items.router)
+ app.include_router(orders.router)
+ ```
+
+ * 使用路由管理
+
+ ```
+ # 创建管理员专属路由组
+ admin_router = APIRouter(
+ prefix="/admin",
+ dependencies=[Depends(admin_auth)], # 👈 统一认证
+ tags=["管理员"]
+ )
+
+ @admin_router.get("/stats")
+ def get_stats(): ...
+
+ @admin_router.post("/users")
+ def create_user(): ...
+ ```
+
+
+
+* `APIRouter`核心概念
+
+ * 基础使用模板
+
+ ```
+ from fastapi import APIRouter
+
+ router = APIRouter(
+ prefix="/users", # 路由前缀
+ tags=["用户管理"], # OpenAPI分组
+ responses={404: {"description": "资源未找到"}} # 默认响应
+ )
+
+ @router.get("/", summary="获取用户列表")
+ async def list_users():
+ return [{"id": 1, "name": "张三"}]
+ ```
+
+ * 核心配置参数
+
+ | 参数 | 作用 | 示例值 |
+ | :----------: | :--------------: | :---------------------: |
+ | prefix | 路由统一前缀 | "/api/v1" |
+ | tags | OpenAPI文档分组 | ["认证相关"] |
+ | dependencies | 路由组公共依赖项 | [Depends(verify_token)] |
+ | responses | 统一响应定义 | {400: {"model": Error}} |
+
+* 案例实战
+
+ * 创建文件` app/users.py`
+
+ ```
+ from fastapi import APIRouter, HTTPException
+ from pydantic import BaseModel
+ router = APIRouter(
+ prefix="/users", # 路由前缀
+ tags=["用户管理"], # OpenAPI文档分组
+ dependencies=[] # 模块级依赖
+ )
+
+ @router.get("/", summary="获取用户列表")
+ async def list_users():
+ return [{"id": 1, "name": "Alice"}]
+
+ @router.post("/", summary="创建新用户")
+ async def create_user():
+ return {"id": 2, "name": "Bob"}
+
+ class UserCreate(BaseModel):
+ username: str
+ password: str
+
+ @router.post("/register", status_code=201)
+ async def register(user: UserCreate):
+ """用户注册接口"""
+ # 实际应保存到数据库
+ return {"message": "用户创建成功", "username": user.username}
+
+ @router.get("/{user_id}")
+ async def get_user(user_id: int):
+ if user_id > 100:
+ raise HTTPException(404, "用户不存在")
+ return {"user_id": user_id, "name": "虚拟用户"}
+ ```
+
+ * 创建文件 `app/products.py`
+
+ ```
+ # app/api/v1/products.py
+ from fastapi import APIRouter
+ router = APIRouter(
+ prefix="/products",
+ tags=["商品管理"],
+ dependencies=[]
+ )
+
+ @router.get("/search", summary="商品搜索")
+ async def search_products(
+ q: str,
+ min_price: float = None,
+ max_price: float = None
+ ):
+ # 实现搜索逻辑
+ return {"message": "搜索成功"}
+
+ @router.get("/{product_id}", summary="获取商品详情")
+ async def get_product_details(product_id: int):
+ return {"id": product_id}
+
+ ```
+
+ * 创建入口文件 `main.py`
+
+ ```
+ from fastapi import FastAPI
+ from app import users, products
+ import uvicorn
+
+ # 创建FastAPI应用实例
+ app = FastAPI()
+
+ # 注册用户模块的路由
+ app.include_router(users.router)
+
+ # 注册产品模块的路由
+ app.include_router(products.router)
+
+ # 访问路径:
+ # GET /users/ → 用户列表
+ # POST /users/ → 创建用户
+ #...
+
+ # 打印所有注册的路由信息,便于开发者查看和调试
+ for route in app.routes:
+ print(f"{route.path} → {route.methods}")
+
+ # 定义根路径的GET请求处理函数
+ """
+ 处理根路径的GET请求。
+
+ 返回值:
+ dict: 返回一个JSON对象,包含欢迎消息。
+ """
+ @app.get("/")
+ async def root():
+ return {"message": "Hello 小滴课堂"}
+
+
+ # 主程序入口,用于启动FastAPI应用
+ if __name__ == '__main__':
+ # 使用uvicorn运行FastAPI应用,默认监听本地地址和端口
+ uvicorn.run(app,port=8001)
+ ```
+
+* 模块化结构参考
+
+ ```
+ #整体项目结构
+ project/
+ ├── main.py
+ └── routers/
+ ├── __init__.py
+ ├── users.py
+ ├── items.py
+ ├── admin/
+ │ ├── dashboard.py
+ │ └── audit.py
+ └── v2/
+ └── users.py
+ ```
+
+* 总结
+
+ | 实践要点 | 说明 |
+ | :----------: | :------------------------------------: |
+ | 模块化组织 | 按业务功能拆分路由模块 |
+ | 统一前缀管理 | 使用`prefix`参数避免路径重复 |
+ | 文档友好 | 合理使用`tags`和`summary`优化API文档 |
+ | 依赖分层 | 模块级依赖处理认证,路由级处理业务逻辑 |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#### 第2集 FastAPI依赖注入和常见项目结构设计
+
+**简介: FastAPI依赖注入和常见项目结构设计**
+
+* 什么是依赖注入
+
+ * 用于将重复逻辑(如鉴权、数据库连接、参数校验)抽象为可复用的组件,
+
+ * 通过依赖注入(Dependency Injection)自动注入到路由处理函数中,让代码更简洁、模块化且易于测试
+
+ * 核心
+
+ * **代码复用**:避免在多个路由中重复相同逻辑(如权限检查)。
+ * **解耦**:将业务逻辑与基础设施(如数据库、认证)分离。
+ * **层级化**:支持嵌套依赖,构建多层逻辑(如先验证用户,再验证权限)
+
+ * 与 Java Spring 对比
+
+ | **功能** | **FastAPI** | **Spring (Java)** |
+ | :----------- | :-------------------- | :----------------------------- |
+ | **依赖注入** | 函数/类 + `Depends()` | `@Autowired` + 容器管理 |
+ | **作用域** | 默认每次请求 | Singleton/Prototype/Request 等 |
+
+ * 语法案例
+
+ * **定义依赖项函数**
+
+ * 依赖项可以是任何可调用对象(如函数、类),通过 `Depends()` 声明依赖关系
+
+ ```
+ from fastapi import Depends, FastAPI
+
+ app = FastAPI()
+
+ # 定义一个依赖项(函数)
+ def common_params(query: str = None, page: int = 1):
+ return {"query": query, "page": page}
+
+ # 在路由中使用依赖项
+ @app.get("/read_items")
+ async def read_items(params: dict = Depends(common_params)):
+ return params
+
+ #说明:common_params 会被自动调用,结果注入到 params 参数。
+ #访问结果:read_items 中可直接使用 params["query"] 和 params["page"]。
+ ```
+
+ * 类作为依赖项
+
+ * 依赖项也可以是类,适合需要初始化或状态管理的场景, 通过依赖注入机制,将复杂逻辑解耦为可复用的模块
+
+ ```
+ #案例一
+ class DatabaseSession:
+ def __init__(self):
+ self.session = "模拟数据库连接"
+
+ def close(self):
+ print("关闭数据库连接")
+
+ def get_db():
+ db = DatabaseSession()
+ try:
+ yield db
+ finally:
+ db.close()
+
+ @app.get("/users/")
+ async def get_users(db: DatabaseSession = Depends(get_db)):
+ return {"db_session": db.session}
+
+
+ #案例二
+ class Pagination:
+ def __init__(self, page: int = 1, size: int = 10):
+ self.page = page
+ self.size = size
+
+ @app.get("/articles/")
+ async def get_articles(pagination: Pagination = Depends()):
+ return {"page": pagination.page, "size": pagination.size}
+ ```
+
+ * 全局依赖项
+
+ * 为所有路由添加公共依赖项(如统一认证)
+
+ ```
+ app = FastAPI(dependencies=[Depends(verify_token)])
+
+ # 或针对特定路由组:
+ router = APIRouter(dependencies=[Depends(log_request)])
+
+ #在部分管理员接口添加认证依赖。
+ @app.get("/admin/stats", dependencies=[Depends(admin_auth)])
+ def get_stats(): ...
+
+ @app.post("/admin/users", dependencies=[Depends(admin_auth)])
+ def create_user(): ...
+ ```
+
+
+
+* FastAPI 项目结构设计原则
+
+ * 基础分层结构(适合小型项目)
+
+ ```
+ myproject/
+ ├── main.py
+ ├── routers/
+ │ ├── users.py
+ │ └── items.py
+ ├── models/
+ │ └── schemas.py
+ └── dependencies.py
+ ```
+
+ * 模块化拆分结构一(推荐中型项目)
+
+ ```
+ src/
+ ├── app/
+ │ ├── core/ # 核心配置
+ │ │ ├── config.py
+ │ │ └── security.py
+ │ ├── api/ # 路由入口
+ │ │ ├── v1/ # 版本控制
+ │ │ │ ├── users/
+ │ │ │ │ ├── endpoints.py
+ │ │ │ │ └── schemas.py
+ │ │ │ └── items/
+ │ ├── models/ # 数据模型
+ │ ├── services/ # 业务逻辑
+ │ └── utils/ # 工具类
+ ├── tests/ # 测试目录
+ └── requirements.txt
+
+ ```
+
+ * 模块化拆分结构二(推荐中型项目)
+
+ ```
+ myproject/
+ ├── app/ # 应用核心目录
+ │ ├── core/ # 全局配置和工具
+ │ │ ├── config.py # 配置管理
+ │ │ └── security.py # 安全相关工具
+ │ ├── api/ # 路由端点
+ │ │ ├── v1/ # API版本目录
+ │ │ │ ├── users.py
+ │ │ │ ├── items.py
+ │ │ │ └── ai.py
+ │ │ └── deps.py # 公共依赖项
+ │ ├── models/ # Pydantic模型
+ │ │ ├── user.py
+ │ │ └── item.py
+ │ ├── services/ # 业务逻辑层
+ │ │ ├── user_service.py
+ │ │ └── ai_service.py
+ │ ├── db/ # 数据库相关
+ │ │ ├── session.py # 数据库会话
+ │ │ └── models.py # SQLAlchemy模型
+ │ └── utils/ # 工具函数
+ │ └── logger.py
+ ├── tests/ # 测试目录
+ │ ├── test_users.py
+ │ └── conftest.py
+ ├── static/ # 静态文件
+ ├── main.py # 应用入口
+ ├── requirements.txt
+ └── .env # 环境变量
+
+ ```
+
+* 推荐原则【遵循团队规范即可】
+
+ | 原则 | 实施方法 |
+ | :------: | :--------------------------------: |
+ | 单一职责 | 每个文件/类只做一件事 |
+ | 依赖倒置 | 通过依赖注入解耦组件 |
+ | 分层清晰 | 严格区分路由层、服务层、数据访问层 |
+ | 版本控制 | 通过URL路径实现API版本管理 |
+ | 文档友好 | 为每个路由添加summary和description |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#### 第3集 FastAPI+大模型流式AI问答助手实战《上》
+
+**简介: FastAPI+大模型流式AI问答助手实战《上》**
+
+* 需求
+
+ * 开发一个基于AI的问答工具,能够根据用户提供的知识点或主题生成简洁的介绍或解释。
+ * 使用了大语言模型(LLM)来实现流式生成文本的功能,适用于教育、内容创作等场景
+ * FastAPI框架整合LLM大模型,提供HTTP服务
+
+* `StreamingResponse` 介绍
+
+ * FastAPI 的提供了 `StreamingResponse` 是一个用于处理流式传输数据的工具,适用于需要逐步发送大量数据或实时内容的场景。
+
+ * 允许通过生成器逐块发送数据,避免一次性加载全部内容到内存,提升性能和资源利用率。
+
+ ```
+ from fastapi.responses import StreamingResponse
+ ```
+
+ * 核心功能
+
+ * 流式传输:逐步发送数据块,适用于大文件(如视频、日志)、大模型实时生成内容(如LLM响应、服务器推送事件)或长时间运行的任务。
+ * 内存高效:无需将完整数据加载到内存,减少服务器负载。
+ * 异步支持:兼容同步和异步生成器,灵活适配不同场景。
+
+ * 基本用法
+
+ * 在路由中返回 `StreamingResponse` 实例,并传入生成器作为数据源
+
+ * 参数说明
+
+ * `content`: 生成器函数,产生字节或字符串数据块。
+ * `media_type`: 指定 MIME 类型(如 `"text/event-stream"`、`"application/json"`)。
+ * `headers`: 自定义响应头(如 `{"Content-Disposition": "attachment; filename=data.csv"}`)。
+ * `status_code`: 设置 HTTP 状态码(默认为 `200`)。
+
+ * 案例实操
+
+ ```
+ async def ai_qa_stream_generator(query: str):
+ """生成A回答的流式响应"""
+ try:
+ async for chunk in ai_writer.run_stream(query):
+ json_data = json.dumps({"text": chunk})
+ yield f"data: {json_data}\n\n"
+ except Exception as e:
+ error_msg = json.dumps({"error": str(e)})
+ yield f"data: {error_msg}\n\n"
+
+
+ @app.get("/ai_write")
+ async def ai_writer_endpoint(query: str):
+ """AI写作接口,返回流式响应"""
+ return StreamingResponse(
+ ai_qa_stream_generator(query),
+ media_type="text/event-stream",
+ headers={
+ "Cache-Control": "no-cache",
+ "Connection": "keep-alive"
+ }
+ )
+ ```
+
+
+
+* 编码实战 `app/ai_writer.py`
+
+ ```
+ from langchain_openai import ChatOpenAI
+ from langchain_core.prompts import ChatPromptTemplate
+ from langchain_core.output_parsers import StrOutputParser
+ from typing import AsyncGenerator
+
+
+ # 封装AI问答的类
+ class AIWriter:
+ def __init__(self):
+ # 初始化语言模型
+ self.llm = self.llm_model()
+
+ # 定义一个返回自定义语言模型的方法
+ def llm_model(self):
+ #创建模型
+ model = ChatOpenAI(
+ model_name = "qwen-plus",
+ base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
+ api_key="sk-005c3c25f6d042848b29d75f2f020f08",
+ temperature=0.7,
+ streaming=True
+ )
+ return model
+
+ async def run_stream(self, query: str) -> AsyncGenerator[str, None]:
+ """运行AI问答并返回流式响应"""
+ try:
+ # 定义提示模板,要求对文档进行摘要总结
+ prompt_template = "用100个字解释下面的知识点或者介绍:{concept}"
+ # 使用提示模板类创建模板
+ prompt = ChatPromptTemplate.from_template(prompt_template)
+
+ # 定义LLM链,将自定义语言模型和提示模板结合
+ chain = prompt | self.llm | StrOutputParser()
+
+ # 使用流式输出
+ async for chunk in chain.astream({"concept": query}):
+ if isinstance(chunk, str):
+ yield chunk
+ elif isinstance(chunk, dict) and "content" in chunk:
+ yield chunk["content"]
+ else:
+ yield str(chunk)
+ except Exception as e:
+ yield f"发生错误: {str(e)}"
+
+
+
+ async def chat(self, query: str):
+ """处理用户消息并返回流式响应"""
+ try:
+ async for chunk in self.run_stream(query):
+ yield chunk
+ except Exception as e:
+ yield f"发生错误: {str(e)}"
+ ```
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#### 第4集 FastAPI+大模型流式AI问答助手实战《下》
+
+**简介: FastAPI+大模型流式AI问答助手实战《下》**
+
+* 编码实战 `writer_app.py`
+
+ ```
+ import uvicorn
+ from fastapi import FastAPI
+ from fastapi.responses import StreamingResponse
+ from app.ai_writer import AIWriter
+ import json
+
+ app = FastAPI()
+
+ # 初始化智能体
+ ai_writer = AIWriter()
+
+ async def ai_qa_stream_generator(query: str):
+ """生成A回答的流式响应"""
+ try:
+ async for chunk in ai_writer.run_stream(query):
+ json_data = json.dumps({"text": chunk}, ensure_ascii=False)
+ yield f"data: {json_data}\n\n"
+ except Exception as e:
+ error_msg = json.dumps({"error": str(e)})
+ yield f"data: {error_msg}\n\n"
+
+ @app.get("/ai_write")
+ async def ai_writer_endpoint(query: str):
+ """AI写作接口,返回流式响应"""
+ return StreamingResponse(
+ ai_qa_stream_generator(query),
+ media_type="text/event-stream",
+ headers={
+ "Cache-Control": "no-cache",
+ "Connection": "keep-alive"
+ }
+ )
+
+
+ # 启动服务器的命令
+ if __name__ == "__main__":
+ uvicorn.run(app, port=8003)
+ ```
+
+* 如何调试
+
+ * Apifox 提供了专门的 SSE(Server-Sent Events)调试功能,适合处理 AI 大模型的流式响应场景
+ * 配置 SSE,选择接口的请求方法,在请求头中添加 `Accept: text/event-stream` 来启用 SSE。