diff --git a/README.md b/README.md index 125aebf..e6d8ec6 100644 --- a/README.md +++ b/README.md @@ -16843,3 +16843,2612 @@ tools = [web_search, retriever_tool] * 比如 * 短文本:https://www.runoob.com/python3/python3-tutorial.html * 长文本: https://file.xdclass.net/video/2024/selenium/biji.html + + + +### AI智能体中心实战之AI网盘查询助手 + +#### LLM大模型如何访问MySQL业务数据库 + +* 需求背景: **为什么需要 SQL Agent?** + + * LangChain如何整合大模型操作业务数据库 + + * 未来场景下,用户更倾向于用自然语言提问(如“销售额最高的产品是什么?”),而非编写复杂 SQL。 + + * 非技术人员(如产品经理、业务人员)无需学习 SQL 即可查询数据库。 + + * 包括开发对应的业务智能体,实现数据库的查询和操作 + + + +* 什么是`create_sql_agent` + + * 创建能通过自然语言与SQL数据库交互的AI智能体,自动生成/执行SQL查询并解析结果 + + * 核心能力 + + | **功能** | **说明** | + | :----------------- | :----------------------------------------------------------- | + | 自然语言转 SQL | 将用户问题(如“统计每个地区的销量”)转化为 SQL 查询语句。 | + | 安全执行查询 | 连接数据库执行 SQL,默认只读模式防止数据误修改。 | + | 结果解析与自然语言 | 将数据库返回的原始数据(如 `[1500, 2000]`)转换为用户友好的回答(如“总销售额为 $3500”)。 | + | 错误处理与重试 | 自动修正 SQL 语法错误或逻辑问题(如字段名拼写错误)。 | + + * 应用场景 + + * 非技术人员通过对话查询数据库 + * 数据分析,自动生成复杂报表 + * 结合业务系统的问答机器人 + + * 核心语法 + + * 相关包 `from langchain_community.agent_toolkits.sql.base import create_sql_agent` + + ```python + agent = create_sql_agent( + llm=ChatOpenAI(temperature=0, model="gpt-5"), # 必需:大模型 + toolkit=SQLDatabaseToolkit(db=db, llm=llm), # 必需:数据库工具包 + agent_type=AgentType.ZERO_SHOT_REACT_DESCRIPTION, # Agent类型 + verbose=True, # 显示详细执行过程 + prefix="""你是一个专业的MySQL专家...""", # 自定义提示前缀 + suffix="""请始终检查你的查询结果...""" # 自定义提示后缀 + ) + ``` + +* 什么是`SQLDatabaseToolkit` + + * 是 LangChain 中专门用于 **连接 SQL 数据库并集成相关操作工具** 的模块包。 + * 本质上是一个容器,将数据库连接与多个预构建的 SQL 操作工具打包整合 + + 1 + + * 核心语法 + + * 相关包 `from langchain_community.agent_toolkits.sql.toolkit import SQLDatabaseToolkit` + + image-20250429170519143 + + ```python + #使用 SQLDatabase.from_uri 连接数据库,自动读取表结构。 + db = SQLDatabase.from_uri( + database_uri="数据库连接信息", + include_tables=['account_file', 'storage'], + custom_table_info={"account": "查询账号相关的表"}) + + #SQLDatabaseToolkit 封装了查询执行、表结构查看等底层操作。 + toolkit = SQLDatabaseToolkit(db=db, llm=ChatOpenAI()) + ``` + + + +* 案例讲解(伪代码) + + ```python + # 1. 连接数据库 + db = SQLDatabase.from_uri("mysql+pymysql://root:xdclass.net168@39.108.115.128:3306/dcloud_aipan") + + # 2. 初始化大模型 + llm = ChatOpenAI( + temperature=0, + model="gpt-4", + openai_api_key="sk-your-key" + ) + + # 3. 创建工具包 + toolkit = SQLDatabaseToolkit(db=db, llm=llm) + + # 4. 创建SQL Agent + agent = create_sql_agent( + llm=llm, + toolkit=toolkit, + verbose=True, + agent_type=AgentType.ZERO_SHOT_REACT_DESCRIPTION, + handle_parsing_errors=True # 自动处理解析错误 + ) + + # 5. 执行自然语言查询 + questions = [ + "有多少位客户?", + "显示销售额前5的产品及其总销售额" + ] + + for question in questions: + print(f"\n问题:{question}") + response = agent.invoke({"input": question}) + print(f"答案:{response['output']}") + ``` + + + +#### SQL Agent智能体操作MySQL数据库实战 + +* 需求 + + * 实现了一个基于SQL Agent的智能数据库查询系统 + * 用户可以通过自然语言提问的方式,获取网盘数据库中的相关信息。 + * 系统能够自动解析用户的自然语言问题,生成对应的SQL查询语句,并返回查询结果 + +* 编码实战 + + ```python + import os + from langchain_community.agent_toolkits.sql.base import create_sql_agent + from langchain_community.agent_toolkits.sql.toolkit import SQLDatabaseToolkit + from langchain_community.utilities import SQLDatabase + from langchain_openai import ChatOpenAI + from langchain.agents.agent_types import AgentType + + # 设置OpenAI API密钥 + llm = ChatOpenAI( + model_name="qwen-plus", + base_url="https://dashscope.aliyuncs.com/compatible-mode/v1", + api_key="sk-005c3c25f6d042848b29d75f2f020f08", + temperature=0 + ) + + # 1. 连接数据库 + db = SQLDatabase.from_uri( + f"mysql+pymysql://root:xdclass.net168@39.108.115.28:3306/dcloud_aipan", + #include_tables=['account_file', 'storage','account'], + custom_table_info={"account": "查询账号相关的表","account_file": "查询文件夹和文件内容相关的表","storage": "查询存储相关就查询这个表"}, # 自定义表描述 + ) + + # 2. 初始化工具包 + toolkit = SQLDatabaseToolkit(db=db, llm=llm) + print(f"包含工具数量:{len(toolkit.get_tools())}") + print("工具列表:", [tool.name for tool in toolkit.get_tools()]) + + # 3. 创建SQL Agent + agent = create_sql_agent( + llm=llm, + toolkit=toolkit, + prefix="""你是一个专业的网盘数据库查询助手。请遵循以下规则: + 1. 所有回答必须使用中文 + 2. 回答要简洁明了,避免技术术语 + 3. 如果遇到查询错误,请尝试用更简单的方式重新组织查询 + 4. 对于数据查询结果,请用通俗易懂的语言解释 + 5. 如果用户的问题不明确,请主动询问更多细节""", + verbose=True, + agent_type=AgentType.ZERO_SHOT_REACT_DESCRIPTION, + handle_parsing_errors=True + ) + + # 4. 定义查询函数 + def ask_question(question): + try: + print(f"\n正在处理您的问题:{question}") + response = agent.invoke({"input": question}) + return response["output"] + except Exception as e: + print(f"系统提示:处理查询时遇到技术问题") + return "抱歉,系统暂时无法处理您的请求。请尝试用更简单的方式描述您的问题,或者稍后再试。" + + # 5. 测试不同问题 + questions = [ + "数据库有多少个表", + "有多少个账号", + "有多少个文件夹" + ] + + for q in questions: + answer = ask_question(q) + print(f"\n问题:{q}") + print(f"回答:{answer}") + print("-" * 50) + ``` + + ![image-20250429205355439](./img/image-20250429205355439.png) + +* `create_sql_agent`相关使用注意事项 + + * 提升生成准确率 + + * 添加表注释:在数据库表中添加字段描述(如通过 COMMENT),帮助 LLM 理解字段含义 + + * 安全限制, 只读模式 + + * 参数文档(过期忽略)https://python.langchain.com/api_reference/community/utilities/langchain_community.utilities.sql_database.SQLDatabase.html + + ```python + db = SQLDatabase.from_uri( + "sqlite:///sales.db", + include_tables=["sales", "products"], # 限制可访问的表 + custom_table_info={"sales": "只允许查询,禁止修改"}, # 自定义表描述 + view_support=False # 禁止访问视图 + ) + ``` + + * 生成的 SQL 包含不存在的字段 + + * 解决方案:检查 SQLDatabaseToolkit 是否包含最新表结构,在提示中明确字段范围 + + ```python + CUSTOM_PROMPT = """你只能使用以下字段: + - products: product_id, product_name, category, price + - sales: sale_id, product_id, sale_date, quantity + 问题:{question}""" + ``` + + * 复杂 JOIN 查询失败 + + * 解决方案:提供few_shot案例 + + ```python + examples = [ + ("如何查询产品对应的销售记录?", "SELECT * FROM sales JOIN products ON sales.product_id = products.product_id") + ] + ``` + + * 其他 + + * **数据库权限控制**:生产环境务必限制为只读。 + * **提示工程优化**:通过添加表结构描述、示例数据提升准确率。 + * **错误防御**:处理 SQL 注入、无效查询等边界情况 + +#### AI网盘智答Agent需求说明和开发实战 + +* 需求说明 + + * 实现的智能网盘查询系统,通过自然语言处理技术,让用户能够使用自然语言查询网盘中的文件信息。 + + * 核心功能 + + * 文件查询功能 + * 查看文件列表、查看文件详细信息、查看文件夹内容 + * 文件统计功能 + * 统计文件数量、统计文件类型分布、统计存储空间使用情况 + * 存储空间管理 + * 查看已使用空间、查看剩余空间、查看空间使用率 + + * 备注 + + * 前面多个智能体采用流式响应输出,大家基本掌握了 + * AI网盘智答智能体采用一次性输出的方式进行, + * 个人网盘数据库读取需要鉴权,和聊天助理智能体类似 + * SQL Agent智能体的回复准确性,和大模型参数、能力、提示词工程强相关,也包括用户的提问内容 + + * 业务流程说明: + + * 用户请求: 用户发送自然语言查询、身份验证、获取用户ID + * 参数处理:处理查询参数、注入用户ID + * 创建代理:初始化SQL代理、准备查询环境 + * 执行查询:执行数据库查询、获取查询结果 + * 返回结果:返回JSON格式响应 + + ``` + ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ + │ │ │ │ │ │ + │ 用户请求 │────▶│ 身份验证 │────▶│ 参数处理 │ + │ │ │ │ │ │ + └─────────────┘ └─────────────┘ └──────┬──────┘ + │ + ▼ + ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ + │ │ │ │ │ │ + │ 返回结果 │◀────│ 执行查询 │◀────│ 创建代理 │ + │ │ │ │ │ │ + └─────────────┘ └─────────────┘ └─────────────┘ + ``` + + image-20250429175110088 + +* 编码实战 + + * 创建`pan_schemas.py` + + ```python + from pydantic import BaseModel + from typing import Optional, Dict, Any, List + from datetime import datetime + + class PanQueryRequest(BaseModel): + """网盘查询请求模型""" + account_id: Optional[int] = None # 从token中获取,请求中可选 + query: str + + class FileInfo(BaseModel): + """文件信息模型""" + id: int # account_file表的ID + file_id: int # 实际存储的文件ID + file_name: str + file_type: str + file_suffix: str + file_size: int + gmt_create: datetime + gmt_modified: datetime + + class StorageInfo(BaseModel): + """存储空间信息""" + used_size: int + total_size: int + used_percentage: float + + class FileStatistics(BaseModel): + """文件统计信息模型""" + total_files: int + total_size: int + file_types: Dict[str, int] + recent_files: List[FileInfo] + + class PanQueryResponse(BaseModel): + """网盘查询响应模型""" + type: str + data: Dict[str, Any] + ``` + + * 创建路由文件 + + ```python + from fastapi import APIRouter, Depends + from models.pan_schemas import PanQueryRequest + from agents.pan_agent import process_pan_query + from core.auth import get_current_user + + # 创建路由 + router = APIRouter( + prefix="/api/pan", + tags=["网盘查询"], + ) + + @router.post("/query") + async def query_pan( + request: PanQueryRequest, + current_user: dict = Depends(get_current_user) + ): + """网盘查询接口""" + # 设置用户ID + request.account_id = current_user["account_id"] + # 调用代理处理请求 + return await process_pan_query(request) + ``` + + +#### AI网盘智答Agent之MySQL数据安全隔离实战 + +* 需求 + + * 问题一:大模型操作Mysql数据库如何做到个人数据隔离,不会查询到别人的数据? + * 问题二:大模型响应给调用方的内容格式如何限制? + * 问题三:大模型如何更精确的执行用户的查询需求? + +* 解决方案:【!!!!提示词工程!!!】 + + ```markdown + 你是一个智能网盘助手,专门用于查询用户的网盘文件信息。你只能执行查询操作,不能执行任何修改数据的操作。 + + 重要警告: + 1. 你绝对不能生成或编造任何数据 + 2. 你只能返回实际查询到的数据 + 3. 如果查询没有结果,必须返回空结果 + 4. 任何生成或编造数据的行为都是严重错误 + 5. 你只能使用数据库中的实际数据 + 6. 不能对查询结果进行任何修改或补充 + 7. 不能生成示例数据或占位数据 + 8. 不能假设或推测数据 + 9. 不能使用模板或示例数据 + 10. 不能对数据进行任何形式的加工或美化 + + 数据库表结构说明: + - account_file: 用户文件表 + - id: 文件ID(account_file表的主键) + - account_id: 用户ID + - is_dir: 是否为文件夹(0不是,1是) + - parent_id: 上层文件夹ID(顶层为0) + - file_id: 实际存储的文件ID + - file_name: 文件名称 + - file_type: 文件类型(common/compress/excel/word/pdf/txt/img/audio/video/ppt/code/csv) + - file_suffix: 文件后缀名 + - file_size: 文件大小(字节) + - del: 是否删除(0未删除,1已删除) + - del_time: 删除时间 + - gmt_create: 创建时间 + - gmt_modified: 更新时间 + + - storage: 存储信息表 + - id: 记录ID + - account_id: 用户ID + - used_size: 已使用空间(字节) + - total_size: 总空间(字节) + - gmt_create: 创建时间 + - gmt_modified: 更新时间 + + 你可以处理以下类型的查询请求: + 1. 文件查询 + - 查看我的文件列表 + - 搜索特定文件 + - 查看文件详细信息 + - 查看文件夹内容(参考语法:select ) + - 查看最近修改的文件 + + 2. 文件统计 + - 统计文件数量 + - 统计文件类型分布 + - 统计存储空间使用情况 + - 查看最近上传的文件 + + 3. 存储空间 + - 查看已使用空间 + - 查看剩余空间 + - 查看空间使用率 + + + 重要限制: + 1. 你只能执行 SELECT 查询,不能执行任何修改数据的操作 + 2. 所有查询必须包含 account_id 条件,确保数据安全 + 3. 不能执行以下操作: + - 删除文件 + - 修改文件 + - 创建文件 + - 移动文件 + - 重命名文件 + - 清空回收站 + - 修改存储空间 + 4. 如果用户请求执行任何修改操作,请礼貌地拒绝并说明原因 + 5. 如果查询没有结果,必须返回空结果,不能生成示例数据 + 6. 绝对不能生成或编造任何数据 + 7. 只能返回实际查询到的数据 + 8. 不能对数据进行任何形式的加工或美化 + + 处理请求时请注意: + 1. 必须使用 account_id 过滤用户数据,确保数据安全 + 2. 对于文件夹查询,使用 is_dir=1 和 parent_id + 3. 对于文件类型查询,使用 file_type 字段 + 4. 对于模糊查询,使用 LIKE 和通配符 + 5. 对于时间相关的查询,使用 gmt_create 和 gmt_modified + 6. 对于空间统计,使用 storage 表 + 7. 结果要简洁明了,突出重点 + 8. 所有查询必须包含 account_id 条件 + 9. 查询文件信息时,必须返回 account_file 表的 id 和 file_id + 10. 所有响应必须返回 JSON 格式的数据,包含完整的文件信息 + 11. 如果查询没有结果,返回空数组或空对象,不要生成示例数据 + 12. 绝对不能生成或编造任何数据 + + 响应格式必须符合以下模型结构: + 1. 文件列表响应: + {{ + "type": "file_list", + "data": List[FileInfo] # FileInfo包含id, file_id, file_name, file_type, file_suffix, file_size, gmt_create, gmt_modified + }} + + 2. 存储空间信息响应: + {{ + "type": "storage_info", + "data": StorageInfo # StorageInfo包含used_size, total_size, used_percentage + }} + + 3. 文件统计信息响应: + {{ + "type": "file_statistics", + "data": FileStatistics # FileStatistics包含total_files, total_size, file_types, recent_files + }} + + 请根据用户的问题,使用 SQL 查询来获取信息,并返回符合上述格式的 JSON 数据。 + 重要警告:你绝对不能生成或编造任何数据,只能返回实际查询到的数据。任何生成或编造数据的行为都是严重错误 + ``` + + + +* 调用接口响应示例说明 + + * 存储相关 + + ```json + { + "code": 0, + "data": { + "type": "storage_info", + "data": { + "used_size": 2000, + "total_size": 104857600, + "used_percentage": 0.0019073486328125 + } + }, + "msg": "", + "type": "text" + } + ``` + + * 文件统计相关 + + ```json + { + "code": 0, + "data": { + "type": "file_statistics", + "data": { + "total_files": 2, + "total_size": 2000 + } + }, + "msg": "", + "type": "text" + } + ``` + + * 文件查询相关 + + ```json + { + "code": 0, + "data": { + "type": "file_list", + "data": [ + { + "id": 1889313223002312705, + "file_id": 1889313222733877250, + "file_name": "344144.png", + "file_type": "IMG", + "file_suffix": "png", + "file_size": 1000, + "gmt_create": "2025-02-11T13:59:08", + "gmt_modified": "2025-02-11T14:02:15" + }, + { + "id": 1889313269047382017, + "file_id": 1889313268749586433, + "file_name": "344144_1739282359741.png", + "file_type": "IMG", + "file_suffix": "png", + "file_size": 1000, + "gmt_create": "2025-02-11T13:59:19", + "gmt_modified": "2025-02-11T14:02:15" + } + ] + }, + "msg": "", + "type": "text" + } + ``` + + + +#### AI网盘智答Agent之SQLAgent智能体开发 + +* 需求 + + * 创建智能网盘查询agent的函数,它将自然语言查询转换为SQL查询,并执行数据库操作 + + * 核心功能 + + - 创建数据库连接 + + - 初始化LLM(大语言模型) + + - 配置SQL工具包 + + - 设置代理提示模板 + + - 创建SQL代理实例 + +* 编码实战(部分对象和代码可以抽取出来-作业自己完成) + + ```python + from langchain_community.agent_toolkits.sql.base import create_sql_agent + from langchain_community.agent_toolkits.sql.toolkit import SQLDatabaseToolkit + from langchain_community.utilities import SQLDatabase + from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder + from typing import Dict, Any, List, Union + import json + from core.llm import get_default_llm + from core.config import settings + from models.json_response import JsonData + from models.pan_schemas import PanQueryRequest + import logging + from langchain.agents.agent_types import AgentType + + logger = logging.getLogger(__name__) + + def create_pan_agent() -> Any: + """创建网盘查询代理""" + # 创建数据库连接,只读模式 + db = SQLDatabase.from_uri( + f"mysql+pymysql://{settings.MYSQL_USER}:{settings.MYSQL_PASSWORD}@{settings.MYSQL_HOST}:{settings.MYSQL_PORT}/{settings.MYSQL_DATABASE}", + include_tables=['account_file', 'storage'] + ) + + # 创建 LLM + llm = get_default_llm() + + # 创建 SQL 工具包,只包含查询工具 + toolkit = SQLDatabaseToolkit(db=db, llm=llm) + + # 创建提示模板 + prompt = ChatPromptTemplate.from_messages([ + ("system", """你是一个智能网盘助手,专门用于查询用户的网盘文件信息。你只能执行查询操作,不能执行任何修改数据的操作。 + + 重要警告: + 1. 你绝对不能生成或编造任何数据 + 2. 你只能返回实际查询到的数据 + 3. 如果查询没有结果,必须返回空结果 + 4. 任何生成或编造数据的行为都是严重错误 + 5. 你只能使用数据库中的实际数据 + 6. 不能对查询结果进行任何修改或补充 + 7. 不能生成示例数据或占位数据 + 8. 不能假设或推测数据 + 9. 不能使用模板或示例数据 + 10. 不能对数据进行任何形式的加工或美化 + + 数据库表结构说明: + - account_file: 用户文件表 + - id: 文件ID(account_file表的主键) + - account_id: 用户ID + - is_dir: 是否为文件夹(0不是,1是) + - parent_id: 上层文件夹ID(顶层为0) + - file_id: 实际存储的文件ID + - file_name: 文件名称 + - file_type: 文件类型(common/compress/excel/word/pdf/txt/img/audio/video/ppt/code/csv) + - file_suffix: 文件后缀名 + - file_size: 文件大小(字节) + - del: 是否删除(0未删除,1已删除) + - del_time: 删除时间 + - gmt_create: 创建时间 + - gmt_modified: 更新时间 + + - storage: 存储信息表 + - id: 记录ID + - account_id: 用户ID + - used_size: 已使用空间(字节) + - total_size: 总空间(字节) + - gmt_create: 创建时间 + - gmt_modified: 更新时间 + + 你可以处理以下类型的查询请求: + 1. 文件查询 + - 查看我的文件列表 + - 搜索特定文件 + - 查看文件详细信息 + - 查看文件夹内容 + - 查看最近修改的文件 + + 2. 文件统计 + - 统计文件数量 + - 统计文件类型分布 + - 统计存储空间使用情况 + - 查看最近上传的文件 + + 3. 存储空间 + - 查看已使用空间 + - 查看剩余空间 + - 查看空间使用率 + + + 重要限制: + 1. 你只能执行 SELECT 查询,不能执行任何修改数据的操作 + 2. 所有查询必须包含 account_id 条件,确保数据安全 + 3. 不能执行以下操作: + - 删除文件 + - 修改文件 + - 创建文件 + - 移动文件 + - 重命名文件 + - 清空回收站 + - 修改存储空间 + 4. 如果用户请求执行任何修改操作,请礼貌地拒绝并说明原因 + 5. 如果查询没有结果,必须返回空结果,不能生成示例数据 + 6. 绝对不能生成或编造任何数据 + 7. 只能返回实际查询到的数据 + 8. 不能对数据进行任何形式的加工或美化 + + 处理请求时请注意: + 1. 必须使用 account_id 过滤用户数据,确保数据安全 + 2. 对于文件夹查询,使用 is_dir=1 和 parent_id + 3. 对于文件类型查询,使用 file_type 字段 + 4. 对于模糊查询,使用 LIKE 和通配符 + 5. 对于时间相关的查询,使用 gmt_create 和 gmt_modified + 6. 对于空间统计,使用 storage 表 + 7. 结果要简洁明了,突出重点 + 8. 所有查询必须包含 account_id 条件 + 9. 查询文件信息时,必须返回 account_file 表的 id 和 file_id + 10. 所有响应必须返回 JSON 格式的数据,包含完整的文件信息 + 11. 如果查询没有结果,返回空数组或空对象,不要生成示例数据 + 12. 绝对不能生成或编造任何数据 + + 响应格式必须符合以下模型结构: + 1. 文件列表响应: + {{ + "type": "file_list", + "data": List[FileInfo] # FileInfo包含id, file_id, file_name, file_type, file_suffix, file_size, gmt_create, gmt_modified + }} + + 2. 存储空间信息响应: + {{ + "type": "storage_info", + "data": StorageInfo # StorageInfo包含used_size, total_size, used_percentage + }} + + 3. 文件统计信息响应: + {{ + "type": "file_statistics", + "data": FileStatistics # FileStatistics包含total_files, total_size, file_types, recent_files + }} + + 请根据用户的问题,使用 SQL 查询来获取信息,并返回符合上述格式的 JSON 数据。 + 重要警告:你绝对不能生成或编造任何数据,只能返回实际查询到的数据。任何生成或编造数据的行为都是严重错误。"""), + ("human", "{input}"), + MessagesPlaceholder(variable_name="agent_scratchpad"), + ]) + + # 创建 SQL 代理 + agent = create_sql_agent( + llm=llm, + toolkit=toolkit, + verbose=True, + agent_type="openai-tools", + prompt=prompt, + handle_parsing_errors=True, + max_iterations=10 + ) + + return agent + + ``` + + + +#### AI网盘智答Agent之非流式响应和数据提取 + +* 需求 + + * 开发处理网盘查询请求的核心函数,负责协调整个查询流程,从接收请求到返回结果。 + * 解析代理输出,处理不同类型的结果,返回标准化的 JsonData 响应 + + * 核心功能 + + - 接收查询请求 + + - 创建查询代理 + + - 执行查询处理 + + - 格式化响应结果 + + - 错误处理 + +* 编码实战 + + ```python + async def process_pan_query(request: PanQueryRequest) -> JsonData: + """处理网盘查询请求 + + Args: + request: 查询请求对象,包含用户ID和查询内容 + + Returns: + JsonData: 查询结果,包含文件列表、存储信息等 + """ + agent = create_pan_agent() + + # 构建查询输入 + query_input = f"用户ID为 {request.account_id} 的 {request.query}" + + # 获取代理输出 + response = await agent.ainvoke({"input": query_input}) + + if "output" not in response: + return JsonData.error("未获取到有效响应") + + output = response["output"] + + # 解析输出数据 + try: + data = json.loads(output) if isinstance(output, str) else output + if isinstance(data, list): + return JsonData.success({ + "type": "file_list", + "data": data + }) + return JsonData.success({ + "type": data.get("type", "text"), + "data": data.get("data", data) + }) + except json.JSONDecodeError: + return JsonData.success({ + "type": "text", + "data": {"content": str(output)} + }) + ``` + +* 主路由配置 `app.include_router(pan.router)` + + + +#### AI网盘智答Agent之全链路测试实战+面试题 + +* 需求回顾 + + * 实现的智能网盘查询系统,通过自然语言处理技术,让用户能够使用自然语言查询网盘中的文件信息。 + * 核心功能 + * 文件查询功能 + * 查看文件列表、查看文件详细信息、查看文件夹内容 + * 文件统计功能 + * 统计文件数量、统计文件类型分布、统计存储空间使用情况 + * 存储空间管理 + * 查看已使用空间、查看剩余空间、查看空间使用率 + * bug修复 + * PanQueryRequest入参的AccountID + * create_pan_agent入参 + * agent_type="openai-tools" + * JsonData.success({"type": data.get("type"),"data": data.get("data")}) + +* 全链路测试 + + * 问题一: 我的图片文件有哪些 + + * 问题二:图片文件有多少,大小是多少 + + * 问题三:存储空间使用情况 + +* 注意【面试题】 + + * SQL Agent智能体的回复准确性,和大模型参数、温度、能力、提示词工程强相关,也包括用户的提问内容 + + * 比如更详细的表结构Schema说明,提问改写,提供FewShot样例等,都是可以提高准确度 + + * 增强 Schema 理解 + + ```python + # 在提示词中添加增强元数据描述 + prefix = """ + 你连接的数据库包含以下关键表: + [Customers] 客户表(重要字段:CustomerId, FirstName, LastName, Country) + [Invoices] 发票表(与 Customers 通过 CustomerId 关联) + 优先使用 JOIN 代替子查询,注意 Country 字段存储的是国家全称 + """ + ``` + + * Few-Shot Learning 通过示例引导生成模式 + + ```python + examples = [ + { + "input": "法国客户数量是多少?", + "query": "SELECT COUNT(*) FROM Customers WHERE Country = 'France'" + }, + { + "input": "显示最新的5张发票", + "query": "SELECT * FROM Invoices ORDER BY InvoiceDate DESC LIMIT 5" + } + ] + ``` + + + + + +### Java业务系统整合Python大模型服务 + +#### Java业务系统整合Python大模型服务讲解 + +* 需求 + + * 企业在业务+AI项目中采用多语言技术栈,多数是 Java+Python + * 主要是基于技术生态、业务需求和技术特性的考虑,不同编程语言的技术优势互补 + * **Java特性**: + - **企业级开发**:Spring生态(Spring Boot/Cloud)的成熟解决方案(事务管理、分布式架构) + - 具有良好的面向对象设计、丰富的类库、强大的并发处理能力 + - 成熟的开发工具链,适合处理复杂的业务逻辑、事务管理、数据持久化等任务。 + * **Python特性**: + - 在数据科学、机器学习、人工智能等领域具有明显的优势。 + - Python 拥有丰富的机器学习和深度学习库,如 TensorFlow、PyTorch 等 + - 能够方便地进行数据处理、模型训练和算法实现 + +* 参考常见系统架构设计 + + - 采用前后端分离模式,Java系统作为主业务处理平台 + + - Python服务作为AI能力提供方,通过REST API进行跨语言通信 + + - 在两个系统之间传输的格式,通常使用 JSON 格式 + + ``` + +-------------------+ HTTP/REST +-------------------+ + | SpringBoot业务系统 | <--------------> | Python大模型服务 | + | (Java/Kotlin) | JSON数据交互 | (FastAPI) | + +-------------------+ +-------------------+ + ``` + + - SpringBoot 业务系统可以作为客户端,向 Python 大模型服务发送 HTTP 请求,传递相关的业务数据,如用户输入的文本等。 + + - Python 大模型服务接收到请求后,进行相处理,利用大模型的能力生成结果,将结果通过 HTTP 响应给 SpringBoot 业务系统。 + + - 在 SpringBoot 中,可以使用 RestTemplate 或 WebClient 等工具来实现 HTTP 请求的发送和接收。 + + - 在 Python 端使用合适的 Web 框架,如 Flask 或 FastAPI 等来搭建大模型服务接口。 + +* AI智能化网盘业务架构图 + + * 方式一:可以前端请求到Python模型服务 + * 方式二:可以前端经过Java后端,再由Java请求到模型服务 + * 具体哪个方式都可以,看公司业务需求 + * 本章是主要讲解方式二的技术知识点,课程最终采用方式一的进行, + + image-20250418190055953 + + + +#### Java调用大模型服务问题和响应式编程 + +* **需求背景**:Java调用大模型服务的典型特征 + + * 调用链路 `[Java Web 前端] --> [Spring Boot API] --> [Python 大模型服务(FastAPI)]` + * 高延迟 + * 大模型推理耗时较长(如 GPT生成文本可能需要 2~10 秒) + * 同步阻塞调用会占用线程资源,导致系统吞吐量下降 + * 流式输出 + * 部分大模型支持流式返回结果(逐 Token 生成) + * 传统 HTTP 请求-响应模式无法实时获取中间结果 + +* **解决方案:Java响应式编程** + + * **非阻塞调用优化资源利用** + + * 1 个事件循环线程可处理 数千个并发请求 + * 线程资源消耗减少 80%+(对比线程池模式) + + ```java + // 传统同步调用(阻塞线程) + @GetMapping("/chat/sync") + public String generateChatSync(String content) { + // 线程在此阻塞等待 Python 响应 + return restTemplate.postForObject(pythonUrl, content, String.class); + } + + // 响应式调用(非阻塞) + @GetMapping("/chat/async") + public Mono generateChatAsync(String content) { + return webClient.post() + .uri(pythonUrl) + .bodyValue(content) + .retrieve() + .bodyToMono(String.class); // 不阻塞线程 + } + ``` + + * **流式处理大模型输出** + + * 当 Python 服务返回逐段生成的文本时,前端可以实时显示生成过程。 + + ```java + // 处理流式响应(如 SSE) + @GetMapping(value = "/chat/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) + public Flux streamNotes(String prompt) { + return webClient.post() + .uri("/python/stream-generate") + .bodyValue(prompt) + .retrieve() + .bodyToFlux(String.class) // 接收流式数据 + .map(chunk -> "部分结果: " + chunk) + .onBackpressureBuffer(50); // 控制处理速度 + } + ``` + + * 性能对比数据:在 4 核 8GB 云服务器上测试(Python 服务部署独立实例) + + | **场景** | 同步阻塞方式 | Mono/Flux 方式 | 提升效果 | + | :---------------- | :----------- | :------------- | :------- | + | 1000 并发请求 QPS | 82 | 460 | 5.6x | + | 平均响应时间 | 3200ms | 180ms | 94%↓ | + | CPU 使用率 | 95% | 40% | 58%↓ | + | 内存占用 | 2.1GB | 860MB | 59%↓ | + + + +* 响应式编程概念:什么是背压(Backpressure) + + * 背压是响应式编程中的一个概念,用于处理数据生产者和消费者速度不匹配的问题。 + + * 当生产者产生数据的速度超过消费者处理的速度时,会导致数据积压,最终可能引起内存溢出或系统崩溃。 + + * 背压机制就是让**消费者能够通知生产者调整数据发送的速率**,从而避免这种情况。 + + * 生活中的例子 + + * 比如水龙头和桶,如果水开得太大,桶装不下,水就会溢出。 + * 这时候如果桶能告诉水龙头关小一点,就是背压的作用 + + * **背压就像给数据流装了一个智能阀门,根据系统的消化能力动态调节流量,支持多个策略** + + | 策略 | 现实类比 | 适用场景 | + | :---------------------- | :------------- | :----------------- | + | 缓冲(Buffer) | 用更大的桶暂存 | 允许短暂突发流量 | + | 丢弃最新(Drop Latest) | 丢掉新出水 | 实时性要求高的场景 | + | 丢弃最旧(Drop Oldest) | 替换掉旧的水 | 需要最新数据的场景 | + | 限速(Rate Limit) | 让水管慢点出水 | 稳定处理能力场景 | + + + +* 什么是Flux 和 Mono + + * **Flux** 和 **Mono** 是 **Reactor 响应式编程框架** 中的核心类(Spring WebFlux 基于 Reactor 实现),用于表示异步数据流。 + * 它们是响应式编程的基础,专为处理**非阻塞、背压(Backpressure)** 数据流设计。 + + | **特性** | **Flux** | **Mono** | + | :--------------- | :----------------------------------------------------------- | :----------------------------------------------------------- | + | **数据元素数量** | 0~N 个元素(多值流) | 0~1 个元素(单值流) | + | **典型场景** | 分页查询、实时数据流、集合处理
多个元素(列表、流式数据) | HTTP 请求响应、数据库单条记录查询
单个元素(对象、Optional) | + | **操作符支持** | 支持所有流操作符 | 支持单值操作符(如 `map`, `flatMap`) | + | **订阅行为** | 持续推送数据直到完成或错误 | 推送单个数据或立即完成 | + | **背压处理** | 必须处理背压 | 无需显式处理背压 | + + * 何时不该使用 Flux/Mono? + + * 简单 CRUD 应用:低并发场景下,同步代码更易维护 + * CPU 密集型任务:响应式模型无法提升计算性能 + * 已有阻塞代码库:混用阻塞/非阻塞可能导致线程饥饿 + + * 案例语法说明 + + * 添加依赖 + + ```xml + + org.springframework.boot + spring-boot-starter-webflux + + ``` + + * 直接创建 + + ```java + // 创建 Flux + Flux flux1 = Flux.just("A", "B", "C"); // 固定元素 + Flux flux2 = Flux.range(1, 5); // 数字序列 + Flux flux3 = Flux.interval(Duration.ofSeconds(1)); // 定时生成 + + Flux flux = Flux.range(1, 10); + //.filter(n -> n % 2 == 0) + //.map(n -> n * 10); + //测试 + flux.subscribe(System.out::println); + + + // 创建 Mono + Mono mono1 = Mono.just("Hello"); // 单值 + Mono mono3 = Mono.error(new RuntimeException("Error")); // 错误信号 + ``` + + * 从集合/数组转换 + + ```java + /** + * 使用Reactor的Flux从不同数据源创建响应式流 + * 本方法展示两种创建Flux的常用方式: + * 1. 从List集合创建Flux流 + * 2. 从数组创建Flux流 + * 无参数 + * 无返回值 + */ + public void test(){ + // 从List集合创建Flux并订阅消费 + List list = Arrays.asList("Java", "Python"); + Flux fluxFromList = Flux.fromIterable(list); + fluxFromList.subscribe(System.out::println); + + // 从数组创建Flux并订阅消费 + String[] array = {"Apple", "Banana"}; + Flux fluxFromArray = Flux.fromArray(array); + fluxFromArray.subscribe(System.out::println); + } + ``` + + * 整合WebClient + + ```java + Mono userMono = webClient.get() + .uri("/users/{id}", 123) + .accept(MediaType.APPLICATION_JSON) + .retrieve() + .onStatus(HttpStatusCode::is4xxClientError, + response -> Mono.error(new ClientException("Client error"))) + .bodyToMono(User.class); + ``` + + + +#### Java响应式编程核心技术之WebClient + +* 需求背景 + + * 传统同步请求的痛点 + + ```java + // 传统RestTemplate示例(同步阻塞) + RestTemplate restTemplate = new RestTemplate(); + ResponseEntity response = restTemplate.getForEntity(url, String.class); // 阻塞当前线程 + ``` + + * 存在的问题: + + * 线程资源浪费(等待IO时线程被阻塞) + * 扩展性差(高并发场景性能骤降) + * 响应式编程需求(实时数据流处理) + + + +* WebClient 响应式 HTTP 客户端 + + * 核心特性 + + * 非阻塞 I/O:基于 Reactor Netty 实现异步通信 + * 函数式 API:链式调用风格 + * 流式处理:支持 Server-Sent Events (SSE) 和 Streaming JSON + * 与 Spring 生态集成:自动配置、指标采集、异常处理 + + * 使用场景 + + * 微服务间通信,第三方API调用 + * 响应式数据聚合,大文件流式传输 + + * 与 RestTemplate 对比 + + | 特性 | WebClient | RestTemplate | + | :------- | :------------------------- | :--------------- | + | 编程模型 | 响应式(Reactive) | 同步阻塞 | + | 并发处理 | 基于事件循环(Event Loop) | 线程池阻塞 | + | 资源消耗 | 低(少量固定线程) | 高(线程池扩容) | + | 适用场景 | 高并发、低延迟 | 传统 CRUD 应用 | + +* 案例实战 + + * 基础语法 + + ```java + // 创建实例 + WebClient client = WebClient.builder() + .baseUrl("https://api.example.com") + .defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE) + .build(); + + // GET 请求 + Mono userMono = client.get() + .uri("/users/{id}", 1) + .retrieve() + .bodyToMono(User.class); + + // POST 请求 + Mono> response = client.post() + .uri("/users") + .bodyValue(new User("Alice", 30)) + .retrieve() + .toBodilessEntity(); + + // 处理流式响应 + Flux prices = client.get() + .uri("/stocks/stream") + .accept(MediaType.TEXT_EVENT_STREAM) + .retrieve() + .bodyToFlux(StockPrice.class); + ``` + + * 综合案例实战 + + ```java + @Test + public void testWebClient() { + // 创建请求体 + Map body = new HashMap<>(); + body.put("url", "https://www.runoob.com/python3/python3-function.html"); + body.put("summary_type", "简洁点"); + body.put("language", "中文"); + + String requestBodyJson = JsonUtil.obj2Json(body); + log.info("请求参数: {}", requestBodyJson); + + // 创建WebClient + WebClient webClient = WebClient.builder() + .baseUrl("http://localhost:8000") + .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .defaultHeader(HttpHeaders.ACCEPT, MediaType.TEXT_EVENT_STREAM_VALUE) + .build(); + + // 发送POST请求并处理流式响应 + Flux response = webClient.post() + // 设置目标API端点 + .uri("/api/document/stream") + // 设置JSON格式请求体(自动序列化) + .bodyValue(requestBodyJson) + // 发送请求并获取响应 + .retrieve() + // 将响应体转换为持续接收字符串的流式对象 + .bodyToFlux(String.class); + + // 处理流式响应 + response.subscribe( + chunk -> { + log.info("收到数据块: {}", chunk); + }, + error -> { + log.error("发生错误: {}", error.getMessage()); + }, + () -> { + log.info("流式响应完成"); + } + ); + + // 等待响应完成,设置较长的超时时间 + response.blockLast(Duration.ofSeconds(60)); + } + ``` + + +#### 网盘SpringBoot项目整合模型服务实战 + +* 需求 + + * AI智能化网盘项目整合WebClient,流式调用Python模型服务 + * 使用方式和上述案例场景一样,直接转移代码过来即可 + * 最终前端调用Spring Boot,再调用Python 实现全链路流式响应 + * 测试接口:AI聊天智能体(需要JWT校验) + +* 编码实战 + + * 文件增加配置 + + ```yaml + stream: + base-url: http://localhost:8000 + chat-stream-path: /api/chat/stream + timeout: + connect: 30s + response: 5m + read: 5m + write: 5m + pool: + max-connections: 100 + max-idle-time: 5m + max-life-time: 10m + pending-acquire-timeout: 30s + evict-in-background: 120s + ``` + + * 新增`WebClientConfig` 配置类 + + ```java + @Data + @Configuration + @ConfigurationProperties(prefix = "stream") + public class WebClientConfig { + + private String baseUrl; + + private String chatStreamPath; + + /** + * 超时配置 + */ + private Timeout timeout = new Timeout(); + + /** + * 连接池配置 + */ + private Pool pool = new Pool(); + + @Data + public static class Timeout { + private Duration connect; + private Duration response; + private Duration read; + private Duration write; + } + + @Data + public static class Pool { + private int maxConnections; + private Duration maxIdleTime; + private Duration maxLifeTime; + private Duration pendingAcquireTimeout; + private Duration evictInBackground; + } + + @Bean + public WebClient webClient() { + // 创建连接池 + ConnectionProvider provider = ConnectionProvider.builder("stream-connection-pool") + .maxConnections(pool.getMaxConnections()) + .maxIdleTime(pool.getMaxIdleTime()) + .maxLifeTime(pool.getMaxLifeTime()) + .pendingAcquireTimeout(pool.getPendingAcquireTimeout()) + .evictInBackground(pool.getEvictInBackground()) + .build(); + + // 配置 HttpClient + HttpClient httpClient = HttpClient.create(provider) + .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, (int) timeout.getConnect().toMillis()) + .responseTimeout(timeout.getResponse()) + .doOnConnected(conn -> conn + .addHandlerLast(new ReadTimeoutHandler(timeout.getRead().getSeconds(), TimeUnit.SECONDS)) + .addHandlerLast(new WriteTimeoutHandler(timeout.getWrite().getSeconds(), TimeUnit.SECONDS)) + ); + + // 创建 WebClient + return WebClient.builder() + .baseUrl(baseUrl) + .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + .defaultHeader(HttpHeaders.ACCEPT, MediaType.TEXT_EVENT_STREAM_VALUE) + .clientConnector(new ReactorClientHttpConnector(httpClient)) + .build(); + } + } + ``` + + * 开发StreamService + + ```java + @Slf4j + @Service + //简化@Autowired书写, 声明的注入对象必须加上final修饰,是基于构造方法为属性赋值,容器通过调用类的构造方法将其进行依赖注入 + @RequiredArgsConstructor + public class StreamService { + + private final WebClient webClient; + private final WebClientConfig webClientConfig; + + + /** + * 处理聊天流式请求 + */ + public Flux handleChatStream(String token, String message) { + Map body = new HashMap<>(); + body.put("message", message); + + return sendRequest(webClientConfig.getChatStreamPath(), body, token); + } + + /** + * 发送请求的通用方法 + * @param path 请求路径 + * @param body 请求体 + * @param token 认证token,可为null + * @return 响应流 + */ + private Flux sendRequest(String path, Map body, String token) { + try { + String requestBodyJson = JsonUtil.obj2Json(body) + + WebClient.RequestBodySpec requestSpec = webClient.post() + .uri(path) + .contentType(MediaType.APPLICATION_JSON); + + if (token != null) { + requestSpec.header("token", token); + } + + return requestSpec.bodyValue(requestBodyJson) + .retrieve() + .bodyToFlux(String.class) + .doOnError(error -> log.error("Error in stream: {}", error.getMessage())) + .doOnComplete(() -> log.info("Stream completed")); + + } catch (Exception e) { + log.error("Error processing request: {}", e.getMessage()); + return Flux.just("Invalid request format"); + } + } + } + ``` + + +* 编码实战 + + ```java + @RestController + @RequestMapping("/api/chat") + @RequiredArgsConstructor + public class StreamController { + + private final StreamService streamService; + + /** + * 聊天流式接口 + * + curl -N -X POST \ + -H "Content-Type: application/json" \ + -H "token: XDCLASSeyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJYRENMQVNTIiwiYWNjb3VudElkIjoxOTE2NzMzMjEzMjU3MjkzODI1LCJ1c2VybmFtZSI6IjAwMDAiLCJpYXQiOjE3NDYxNTI2MzMsImV4cCI6MTc0Njc1NzQzM30.Gp143lg51WdpJtjOcpIkXkXAKzOwuFEpu2qvkWKyejc" \ + -d "我喜欢什么运动" \ + http://localhost:8080/api/chat/stream + */ + @PostMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) + public Flux chatStream( + @RequestHeader("token") String token, + @RequestBody String message + ) { + return streamService.handleChatStream(token, message); + } + + } + ``` + +* 全链路测试实战 + + * 启动FastAPI智能体中心项目 + * 启动AI网盘Spring Boot后端业务项目 + * 前端触发请求,实现流式响应内容 + +* 注意 + + * 具体后端业务和智能体如何整合,常见的就是课程本章讲解的方案 + * 大家公司里面开发就可以跟进情况选择,两类都是可以进行的 + + + +### 下一个互联网5年-如何编写大模型简历 + +#### 没有对比就没有伤害-看下什么是垃圾简历 + +* 注意 + + * 有部分同学比较急,想先进行投递简历,我们这边就先进入编写简历和面试问答板块 + + * 前端页面也不是关键,面试官也不看这个,讲完简历编写和面试问答事项,再进行前后端联调和其他内容 + +* 写正式简历前,先看下一个面试官眼中的垃圾简历 + + * 换位思考下,你是面试官,你看到这样的简历会约面吗,指出问题,再对比自己的简历 + + ![image-20250503110127541](./img/image-20250503110127541.png) + + ![image-20250503110211729](./img/image-20250503110211729.png) + +#### 下一个5年-如何写一份合格的高级工程师简历 + +* 课程知识点 + * 学我们这个AI大课的同学,多数是本身是前端、后端、测试、运维等方向的同学 + * 大模型智能体开发本身就是新的岗位方向,招聘平台普遍要求是本身技能+大模型开发能力 + * 比如:前端+AI大模型、后端+AI大模型、测试+AI大模型、运维+AI大模型 + * 很多大模型公司的技术人员,都是现学、现做,工程化标准目前都没,但是大体思路都类似,面试官也是 + * 大模型智能体开发不像互连网行业里面前端、后端出来10多年,很多成熟的标准 + * 注意 + * 大模型智能体开发 总体是偏后端方向,任何一个方向的高级岗都是离不开后端 + * 否则无法独立带一个项目,总不可能工作8年的前端还是切图仔,那就被年轻的淘汰了 + * 简历里面的AI大模型板块占比应该如何 + * 本身方向占比5~6成、AI大模型方向占比4~5成即可 + * 如果应聘的是纯AI大模型智能体开发,那可以多点,6~8成 + * 投递岗位搜索: AI大模型开发工程师、大模型应用开发工程师 + +* 特别重要注意事项 + + * 简历不要照抄,不要通篇一律拿过去,每个人的情况不一样,需要结合实际调整,否则就是一眼假,没面试机会 + * 比如工作年限、学历、求职城市、过往公司行业、岗位级别,每个人都是不一样的!!!! + * **如果是找工作,麻烦写完简历发我查看,如果能过得了我这个高级面试官的眼光,那简历还会差吗?** + * 另外记住一个点 + * 常规简历需要2个以上亮点项目,毕业3年以上则需要3个以上亮点项目,不是管理系统 + * 如果简历的亮点项目不够,可以找课程顾问,折扣学其他领域的项目,包装进去。 + * 我们这个AI大课可以包装两个项目,简历里面不同领域项目越多,约面机会越大 + * 95%的公司会进行背景调查,企查查电话核对等,空窗期问题等,很多注意事项,找我咨询 + + +#### D哥教你编写优秀的简历之个人信息板块 + +* 合格的简历编写【课程会提供每个板块内容,但是不提供组合起来的简历,请每个人使用网上的简历模版修改发我】 + + * 个人信息板块 + + * 技术栈板块 + + * 项目板块 + + * 个人评价 + +* 参考【简历模版可以去WPS找,百度搜索简历模版,大厂刷题班里面也有】 + + ![image-20250503112608773](./img/image-20250503112608773.png) + +* 个人信息板块【有多个注意事项】 + + * 姓名:小滴课堂-老王 + + * 工作年限:4年 + + * 学历:本科 【统招和非统招注意事项】 + + * 专业:软件工程 【科班和非科班注意事项,包括中途转行】 + + * 学校:广州大学 + + * 求职岗位:AI大模型开发工程师/高级Java后端工程师【岗位级别注意事项】 + + * 联系方式:xxx@email.com + + * 手机号:13113777333 + + + +* 技术栈板块【可以结合自己的调整、比如本身是前端、测试方向,那也可以把相关技能加入】 + + * 编程语言与框架 + - 熟练Java后端开发,熟练使用SpringBoot3.x全家桶、掌握WebFlux响应式编程 + - 熟练使用SpringCloud/Dubbo等微服务框架,具备服务容错、限流、熔断等治理经验 + - 熟练使用分布式缓存链路追踪、日志收集、监控告警,具备大规模分布式系统性能优化经验 + - 掌握Mysql数据库分库分表, 具备数据库调优、慢查询优化、索引优化经验 + - 熟悉分布式系统设计,包括消息队列(Kafka/RabbitMQ)、缓存(Redis)、分布式存储(MinIO/OSS)等 + + 2. AI大模型开发 + - 熟练掌握Python开发,熟练FastAPI框架、LangChain框架等AI开发技术 + - 熟悉Prompt Engineering,能设计高质量的提示工程方案 + - 熟练掌握RAG(检索增强生成)架构,构建企业级知识库 + - 深入理解LangChain框架,能开发复杂的AI Agent应用 + - 熟悉主流大语言模型(GPT、ChatGLM、通义千问等)特性及应用场景 + - 掌握向量数据库应用开发,熟练使用Milvus进行语义检索 + 3. 架构设计 + - 具备微服务架构设计经验,熟悉分布式系统开发 + - 掌握AI大模型应用架构设计,包括高可用、容错、性能优化等 + - 具备AI应用性能优化与成本控制经验,有一定的大模型微调经验 + - 熟悉向量数据库(Milvus)、大规模语言模型应用开发 + - 熟悉DevOps实践,具备CI/CD pipeline搭建经验 + + + +#### 简历项目编写之企业智能云盘系统-知识库平台 + +* 简历里面项目模块的注意事项 + + * 项目介绍 + * 项目技术选型 + * 项目个人职责 + * 参考格式 + + image-20250503121359088 + + + +* 项目板块编写 + + * 项目名称:企业智能云盘系统|企业级知识库平台【不要照抄,可以选几个类似的名称+前缀】 + + * 项目介绍 + + * 企业级智能知识管理平台,集成AI大模型能力,支持多类型文件存储和实现文档智能化管理和处理 + * 提供基于AI的文件内容理解和知识抽取,解决公司文件数量大时检索困难,定位文件耗时 + * 企业文档、会议记录、培训材料等分散在不同系统;传统关键词搜索无法理解语义,找资料耗时; + * 缺乏自动化知识提取和更新机制,缺乏智能问答和推荐能力,知识难以快速应用等问题 + * 支持多种存储方案无缝切换(公有云、私有化部署),适合集团子公司快速部署和使用 + + * 技术选型 + + * 后端技术和存储:SpringBoot3.x + MyBatisPlus + WebFlux+MinIO分布式存储 + OSS对象存储+Redis集群 + 本地缓存 + + - AI服务技术栈:Python3.x + FastAPI + LangChain+向量数据库Milvus+RAG架构 大模型支持DeepSeek/通义千问等模型接入 + + + + * 个人核心职责【**选择性抄取,比如 不可能实习生独立负责项目总体架构吧**】 + + * 项目总体设计和把控 + + * 和产品经理对接,包括梳理现有公司文档库问题和各个部门使用情况,结合技术手段优化 + * 团队后端技术和AI大模型技术选型、业务功能规划和项目架构、数据库架设计、业务系统越权攻击处理等 + + * 培训公司技术同事AI编码插件使用、优化代码问题和统一接口文档和技术prompt提示词 + * 存储引擎核心开发 + * Amazon S3组建封装,设计实现存储引擎抽象层,基于设计模式设计统一存储接口 + * 支持多种存储方案,实现存储引擎自动切换和降级机制 + + - 文件管理核心模块 + + - 多层级展示⽂件夹列表和⼦⽂件夹技术设计和编码实现,多层级文件批量移动和复制功能设计 + - 多层级文件删除模块和回收站、容量控制等设计 + - 多文件分享模块设计和基于自定义注解实现一键转存功能开发和实现 + + - 大文件传输和秒传模块开发: + + - 开发文件秒传功能,基于MD5+文件指纹, 设计断点续传和分片上传核心算法 + - 实现文件分片上传、分片设计架构,和断点续传核心逻辑,支持大文件传输 + - 文件上传和下载架构链路优化和设计,前端直连存储引擎安全交互方案和开发 + + - AI文档处理系统开发 + + - Prompt提示词工程开发和通用大模型方法模块开发,一键切换不同大模型 + - 智能文档解析引擎,开发多格式文档解析器,支持Office/PDF/在线文档等主流格式 + - 实现基于FastAPI的流式文档处理服务,设计文档结构化处理流程,提取关键信息 + + * 实现基于Milvus的语义检索功能,开发混合检索策略,结合关键词和语义搜索 + + - RAG系统架构设计与实现 + + - 知识库构建流程设计,实现文档自动分片和开发文档向量化处理管道,设计增量更新和版本管理机制 + - 检索系统优化,实现混合检索策略(关键词+语义),开发MMR(最大边际相关)算法 + + - 文档助手Agent开发 + + - 实现基于LangChain的文档处理Agent,开发多Agent协同工作机制,设计任务分解和结果合并策略 + - 支持多类型文档解析和总结、改写等,支持本地多文件解析和在线网页内容提取 + - 实现文档分片并行处理,支持大文件提取和解析,开发内存管理和垃圾回收 + +#### 企业智能云盘系统知识库平台常见面试指标 + +* 项目面试常见题目【灵活应答,结合项目公司情况】 + + * 团队项目规模和开发周期是如何的? + + * 团队构成: + * 总人数:7人 + * 后端开发:3人(本人担任技术负责人) + * 前端开发:2人 + * 测试运维:2人 + * 开发周期: + * 一期(核心功能):1个月 + + * 二期(AI能力):1个月 + + * 持续迭代优化::6个月+ + + * 项目生产环境服务器多少节点,配置多少? + + * 部署架构: + - 服务器配置: + * 应用服务器:4台 16核32G(阿里云ECS) + * AI推理服务器:16台 32核64G+V100 GPU + * 运维部门部署对应的大模型,公司里面的多个项目组都有AI功能,目前多个项目组进行使用,资金预算有限,所以就没独立采购 + * 也可以说是使用算力平台或者云平台,比如阿里云百炼上面的模型进行使用 + * 数据库服务器:2台 16核64G(主从) + * 缓存服务器:2台 8核16G(Redis集群) + - 中间件部署: + * MinIO集群:8台 32核64G,配置12块 2TB SSD. + * 向量数据库服务器(分片配置 6个分片,每分片2副本 ) + * Milvus协调节点:2台 16核32G + * Milvus数据节点:4台 32核64G + * Milvus查询节点:4台 32核64G+T4 GPU + * 总内存配置:512GB,支持10亿级向量检索 + - 监控告警: + * Prometheus + Grafana监控系统 + * ELK日志分析平台,自研告警平台(企业微信/钉钉通知) + + * 取得怎样的成绩 + + * 技术指标【技术人员关心的】: + + * 存储性能: + * 支持单文件最大100GB,总存储容量PB级 + * 大文件传输速度提升200%,支持断点续传 + * 文件秒传成功率达95%,平均耗时<1s + + * AI服务性能: + * 检索响应时间<200ms,准确率90%,文档解析准确率95%,支持20+种格式 + * AI模型平均推理时间<500ms,系统可用性达到99.99% + + - 系统性能: + * 峰值并发支持8000+ QPS【区分接口类型】 + * API平均响应时间<100ms + * 系统故障自动恢复时间<1分钟 + + * 业务指标【产品运营和技术负责人、老板关心的】: + + - 数据指标: + * 日均处理文件100GB+,文件总量达到1PB + * AI服务日处理文档1万+,准确率95%,用户满意度提升50%,投诉率降低60% + - 运营指标: + * 文档管理效率提升30%,存储成本降低40%,运维人力投入减少50% + * 系统部署时间从天级缩短到小时级,问题定位时间从小时级缩短到分钟级 + - 效率提升: + * 员工知识获取效率提升60%,新员工培训时间缩短40% + * 客户服务响应时间减少50%, 知识复用率提升80% + - 成本节约: + * 知识管理成本降低45%,培训成本降低35% + * 人力成本节省50%,IT运维成本降低30% + - 智能化水平: + * OCR识别准确率98%,摘要生成质量评分4.5/5,关键信息提取准确率93% + + * 技术影响: + + - 获得公司年度最佳技术创新奖,存储引擎架构申请技术专利1项 + - 团队获得季度最佳团队奖,方案在集团多子公司成功推广 + + + +#### 简历项目编写之对话交互类业务-智能客服 + +* 项目板块编写 + + * 项目名称:智能客服机器人平台【可以包装 AI医生、AI律师、智慧政务等对话类型交互的业务】 + + * 项目介绍:企业级智能客服系统,解决以下核心问题【需求问题,面试官会问为啥要做,选择性抄取】 + + * 人工客服痛点 + * 人力成本高:需要大量客服人员24小时在线,人力成本逐年上升 + * 培训周期长:新客服培训周期3-6个月,流失率高达30% + * 服务质量不稳定:不同客服水平参差不齐,服务标准难统一 + * 知识更新慢:产品迭代快,客服知识更新滞后,答案准确性受影响 + * 工作强度大:重复性工作多,客服人员倦怠感强,影响服务质量 + * 质量监控难:人工质检覆盖率低,问题发现滞后 + * 用户体验问题: + * 响应速度慢:高峰期平均等待时间超过10分钟,用户流失率高 + * 服务不连续:跨班交接时服务断层,用户需重复描述问题 + * 解决效率低:简单问题也需人工介入,一次性解决率低于60% + * 服务时间受限:非工作时间无法提供及时服务,影响用户体验 + * 多语言支持弱:国际化服务能力不足,跨境业务支持困难 + + * 技术选型 + + * 后端技术栈:SpringBoot3.x + MyBatisPlus + WebFlux+Redis集群 + ElasticSearch+Kafka集群 + * AI服务技术栈:Python3.x + FastAPI + LangChain+向量数据库Milvus +基于RAG架构+DeepSeek/ChatGLM/通义千问等模型接入 + + * 核心架构:采用分布式微服务架构,实现服务高可用和弹性伸缩,基于LangChain实现多轮对话管理和知识库检索 + + + + * 个人核心职责【**选择性抄取,有些不会的或者没能构思出来的则不加入,避免被问到不会**】 + + * 智能对话系统开发 + + - 多轮对话引擎,实现基于Redis的对话历史持久化,实现基于LRU的对话历史缓存 + + - 开发对话摘要生成机制,优化长对话性能,设计上下文压缩算法,保持85%信息完整度 + + - 对话流程管理,实现基于状态机的对话流程控制,开发动态意图识别和纠错机制 + + - 实现个性化对话风格定制功能,支持意图识别和多工具调用、自定义多类型响应 + + - 人机协作平台: + * 实现无缝人机交接和上下文传递,开发实时建议生成和质量评估设计客服辅助决策系统 + * 实现多样化回答生成策略,开发敏感信息实时过滤,设计个性化语气调整机制 + + * 知识库管理系统 + * 知识更新机制,实现知识自动抽取和结构化,设计知识质量评估体系 + * 检索优化,实现混合检索策略,提升准确率,开发热点问题缓存机制,设计知识推荐算法 + * 智能问答系统开发 + - 问答链设计,实现基于LangChain的可定制问答链,开发多轮对话上下文管理,设计答案质量评估体系 + - 提示词工程,开发动态提示词模板系统,实现提示词自动优化机制,设计特定领域知识注入方案 + * 其他模版参考 + * 设计并实现基于大语言模型的对话引擎,开发上下文管理模块,支持长对话理解 + * 优化对话响应时间,将平均响应时间从2s降低到0.5s + * 开发基于LangChain的智能对话Agent,支持工具调用和知识检索 + * 实现基于Redis的分布式会话管理,支持百万级并发会话,支持多用户多会话方式进行 + + * **项目规模**: + + - 团队构成: + * 总人数:9人 + * 后端开发:3人(本人负责对话系统) + * 前端开发:2人 + * AI算法:2人 + * 测试运维:2人 + - 开发周期: + * 一期(对话系统):2个月 + * 二期(持续优化):3个月 + + * 部署架构: + + - 服务器配置: + * 应用服务器:4台 16核32G(阿里云ECS) + * AI推理服务器:16台 32核64G+V100 GPU + * 运维部门部署对应的大模型,公司里面的多个项目组都有AI功能,目前多个项目组进行使用,资金预算有限,所以就没独立采购 + * 也可以说是使用算力平台或者云平台,比如阿里云百炼上面的模型进行使用 + * 数据库服务器:2台 16核64G(主从) + * 缓存服务器:2台 8核16G(Redis集群) + - 中间件部署: + * ElasticSearch集群:8台 16核32G + * 向量数据库服务器(分片配置 6个分片,每分片2副本 ) + * Milvus协调节点:2台 16核32G + * Milvus数据节点:2台 32核64G + * Milvus查询节点:2台 32核64G+T4 GPU + - 监控告警: + * Prometheus + Grafana监控系统 + * ELK日志分析平台,自研告警平台(企业微信/钉钉通知) + + * 取得怎样的成绩 + + * 技术指标: + - 系统支持日均10万+用户咨询, 90%问题响应时间<1s,峰值QPS>1000 + - AI回答准确率90%,知识覆盖率95%, 系统可用性99.99% + * 智能路由性能: + * 路由准确率达98%, 平均等待时间<30s + * 紧急事件响应时间<10s, 客服资源利用率提升40% + + - 知识库性能: + * 知识更新延迟<1分钟, 知识检索准确率95% + * 热点问题命中率98%, 知识库容量支持千万级条目 + + * 业务价值: + + - 成本效益: + * 客服人力成本降低40%, 培训成本降低50% + * 运营成本降低35%, ROI提升200% + - 服务质量: + * 客户满意度提升35%, 问题一次解决率提升45% + * 服务7*24小时全天候可用, 知识库更新周期从天级缩短到分钟级 + + + +#### 教你如何打造独一无二的高级工程师简历 + +* 超级技巧:如何打造更加独一无二的简历? + + * 当前AI智能化云盘还有很多个人负责的模块,可以包装简历进去,查看我们大课的课程目录和学习笔记 + * 很多知识点都可以包装到个人负责的模块,放心大胆写进去,只要你掌握好课程的内容 + * 想要简历更好,就需要多动手和花时间,不能等饭喂到嘴,这个就丧失思考能力,也就失去了教育的本质 + * **我团队里面招聘和留人,经常说 xue li ,不是你大学的学历,而是这个学力,强调的是学习能力** + * 就是按照老师的方法论进行,翻阅课程笔记,然后自己思考总结挖掘知识点,编写简历发我过审 + * 举个例子 + * 第三十八章 **嵌⼊模型性能优化 ,采用CacheBackedEmbeddings解决嵌⼊⽣成成本⾼、重复计算浪费、响应速度慢瓶颈** + * 第四十二章 **MultiQueryRetriever ⼤模型召回率优化,通过⽣成多个相关查询来增强检索效果,解决单⼀查询不够全⾯或存在歧义的问题** + * 第四十三章 **RunnableParallel并⾏链的知识点,多个任务并行链,同时处理多个数据流提高效率** + * 还有更多... + +* 投递面试周期 + + * 想招聘一个靠谱的人员真的不容易,不止阿里这边,有时我会帮朋友的公司进行招聘相关技术人员,毕竟我经验多 + + * 情况是这样的 + + * 招聘平台上的一个开发岗位,能收到一堆投递人员,一天能收到几百份上千份,常规我应该开心才对,但是却悲催了 + + ![image-20250503105739654](./img/image-20250503105739654.png) + + * 简历普遍存在严重的问题,就这样说吧:100个简历,里面90%项目都是雷同 + * 比如XX外卖系统、XX点餐系统、XX课堂、XX头条 + * 不是说这些项目不行,起码包装像样点,不用技术点、技术选项、错别字都一样 + + * 我不排斥培训机构出来的同学,而且还很欣赏,特别是在职提升的我很看重,但是上面的这些我不 会约面,为什么? + * 因为学的不到家,师从哪里,怎样的老师教怎样的学生,多数人员都经不起提问,因为他们只停留在CRUD阶段而已 + * 我想招聘一个可以干活,不拖团队后腿的人都很难,就很简单,生产环境出现了问题,他们估计都没接触过生产环境 + * 由于大量的人员简历投递,且简历都很丰富,导致真正有能力的人容易被遗漏,这个是目前比较麻烦的问题 + * 所以有些有能力的同学,你们遇到的这个问题,**最好的就是持续投递+坚持,8分技术+2分运气,投递面试周期20到25天** + * 有些额外投递技巧, 就加我微信私聊,是金子总会被发现的,普遍15~20天找到不错的Offer + + + +* 备注 + + * 如果微信二维码失效,微信号是这个 【xdclass6】,简历记得发我过审核,还有其他注意事项等 + * AI大模型开发需要多练习项目,类似大家刚入行前端或者后端,熟能生巧 + * 后续小滴课堂会出专门的AI项目大课,不讲基础,直接讲复杂大型项目开发 + +### AI智能化网盘前后端联调综合实战 + +#### 前端基础环境和AI智能化云盘服务跨域配置 + +* 需求 + + * 安装前端项目所需要技术框架、相关环境说明和准备 + * 前后端分离架构,前端请求后端服务和AI模型服务,需要开启跨域配置 + +* 前端相关环境依赖 + + * 技术点: Vue3、TypeScript、Element Plus、Axios、Pinia、Vue Router等 + + * 需要的依赖 + + * npm和yarn就是前端的包管理,类似Java的Maven和Python的pip + + * 版本 `Node.js >= 16.0.0` 和 `npm >= 8.0.0 或 yarn >= 1.22.0` + + * 环境安装 ,也可以搜索相关博文,Node环境(里面会顺带npm):https://nodejs.org/zh-cn + + * 课程项目电脑的安装的相关版本 `npm install -g yarn` + + image-20250503155805463 + +* 案例实战 + + * 后端网盘项目配置跨域,创建`MyCorsFilter.java` + + ```java + @Configuration + public class MyCorsFilter { + + @Bean + public CorsFilter corsFilter() { + //创建 CORS 配置对象 + CorsConfiguration config = new CorsConfiguration(); + //支持域 + config.addAllowedOriginPattern("*"); + //是否发送 Cookie + config.setAllowCredentials(true); + //支持请求方式 + config.addAllowedMethod("*"); + //允许的原始请求头部信息 + config.addAllowedHeader("*"); + //暴露的头部信息 + config.addExposedHeader("*"); + //添加地址映射 + UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource(); + corsConfigurationSource.registerCorsConfiguration("/**", config); + //返回 CorsFilter 对象 + return new CorsFilter(corsConfigurationSource); + } + } + ``` + + * FastAPI服务开启跨域配置 + + ```java + app.add_middleware( + CORSMiddleware, + allow_origins=["*"], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], + ) + ``` + + + +#### AI智能化云盘-前端项目环境配置和构建 + +* 需求 + + * 搭建AI智能化云盘的前端相关开发环境,进行前后端联调 + * 前端技术框架和环境要求 + * 编辑器VSCode + * Node环境 + +* 前端效果 + + ![image-20250502230152621](./img/image-20250502230152621.png) + +* 前端代码下载, 使用**【wget】或者【浏览器】远程下载相关依赖包(需要替换群里最新的)** + + ```shell + 原生资料下载方式(账号 - 密码 - ip地址 - 端口 需要替换群里最新的,【其他路径不变】) + wget --http-user=用户名 --http-password=密码 http://ip:端口/dcloud_pan/aipan_front_end.zip + + #比如 命令行下 + wget --http-user=admin --http-password=xdclass.net888 http://47.115.31.28:9088/dcloud_pan/aipan_front_end.zip + + + # 比如 浏览器直接访问 + http://47.115.31.28:9088/dcloud_pan/aipan_front_end.zip + ``` + +* 运行实战 + + * 解压代码,导入VSCode编辑器 + * 构建项目依赖 + + ```shell + #如果没安装yarn,则可以通过npm进行安装 + sudo npm install -g yarn + + #配置源,国内的淘宝源 + yarn config set registry https://registry.npmmirror.com + + #配置源,官方源 + yarn config set registry https://registry.yarnpkg.com + + #安装依赖 + yarn install + + # 开发环境运行 + yarn serve + + #生产环境打包构建 + yarn build + ``` + + + +#### AI智能化云盘-前端配置文件修改和后端联调 + +* 需求【本集不提供前端课程代码】 + + * 课程代码使用上集下载好的,修改后端的服务器地址即可 + * 最终上线前端,直接打包编译好的代码,上传到阿里云OSS即可 + + ![image-20250502230846228](./img/image-20250502230846228.png) + +* 配置修改实战 + + * Spring Boot 后端服务器请求地址修改 + + * Fast API 模型服务器请求地址修改 + +* 基础功能测试 + + ![image-20250503160856611](./img/image-20250503160856611.png) + +* 注意 + + * 前端、后端、AI大模型服务 肯定有不少Bug,包括很多可以优化地方 + * 大家可以基于现有代码进行优化,二次开发,但是不建议开源上传网上哈 + * 打包后的dist文件就可以上传到静态文件服务器,比如nginx,阿里云oss等进行访问 + + + + + +#### AI智能化云盘后端Bug缺陷修复实战 + +**简介: AI智能化云盘后端Bug缺陷修复实战** + +* 后端网盘项目Bug修复 + + * 文件批量移动功能修复 + + image-20250505175724176 + + * 网盘分享功能问题修复 + + image-20250505175523502 + + * 前端分享链接修改 + + image-20250505175611890 + +* 如果还有其他有问题的,可以直接修复即可 + +### AI智能化网盘项目云服务器部署上线 + +#### 阿里云服务器多节点配置实操-按量付费 + +* 需求 + + * 为了方便后续部署多个节点和程序,直接购买阿里云服务器包年包月比较高 + * 课程采用案例付费的方式,购买多台阿里云服务器,进行多节点部署 + * 花费几十块钱,部署完成验证后即可释放 + +* 服务器要求 + + * 采购4核8G服务器多台, 如果课程后续部署服务器不够,也是参考这个进行购买演示 + + * 每台服务器都安装Docker基本环境,其他环境课程使用的时候按需安装 + + ```sh + ————————Docker-ce社区版本———————— + #运行以下命令,下载docker-ce的yum源。 + sudo wget -O /etc/yum.repos.d/docker-ce.repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo + + #运行以下命令,安装Docker。 + sudo yum -y install docker-ce + + #执行以下命令,检查Docker是否安装成功。 + sudo docker -v + + #执行以下命令,启动Docker服务,并设置开机自启动。 + sudo systemctl start docker + sudo systemctl enable docker + + #执行以下命令,查看Docker是否启动。 + sudo systemctl status docker + + #配置Docker镜像加速 + ([ -f /etc/docker/daemon.json ] || mkdir -p /etc/docker) && echo '{ "registry-mirrors" : [ "https://docker.m.daocloud.io", "https://noohub.ru", "https://huecker.io", "https://dockerhub.timeweb.cloud" ] }' > /etc/docker/daemon.json && sudo systemctl restart docker && sleep 1 && docker info | grep -A 4 "Registry Mirrors" + ``` + + * Git安装和配置SSH Key + + ```sh + yum install git + ``` + + + +#### FastAPI模型服务Docker部署打包配置编写 + +* 需求 + + * 方便快速扩容和多个节点进行,相关服务都采用容器部署 + * 编写相关的的Docker容器构建脚本,则统一使用阿里云ECS服务器上进行构建 + * 有条件的利用构建DevOps链路(公司里面一般有Jenkins基建)进行自动化部署上线 + +* 完整的FastAPI项目下载【本集的FastAPI项目,包括 `requirements.txt` 不在这集课程资料提供,在线下载】 + + * 使用**【wget】或者【浏览器】远程下载相关依赖包(需要替换群里最新的 微信 xdclass6)** + + ```shell + 原生资料下载方式(账号 - 密码 - ip地址 - 端口 需要替换群里最新的,【其他路径不变】) + wget --http-user=用户名 --http-password=密码 http://ip:端口/dcloud_pan/dcloud_ai_agent_docker.zip + + #比如 命令行下 + wget --http-user=admin --http-password=xdclass.net888 http://47.115.31.28:9088/dcloud_pan/dcloud_ai_agent_docker.zip + + # 比如 浏览器直接访问 + http://47.115.31.28:9088/dcloud_pan/dcloud_ai_agent_docker.zip + ``` + + * 阿里云ECS服务器解压相关 `unzip dcloud_ai_agent_docker.zip` + +* Dockerfile编写实战 + + ```shell + # 构建阶段 + FROM python:3.12.6-slim as builder + + # 设置工作目录 + WORKDIR /app + + # 设置环境变量 + ENV PYTHONUNBUFFERED=1 \ + PYTHONDONTWRITEBYTECODE=1 \ + PIP_NO_CACHE_DIR=1 \ + DEBIAN_FRONTEND=noninteractive + + # 配置系统源为阿里云源 + RUN echo "deb http://mirrors.aliyun.com/debian/ bullseye main contrib non-free" > /etc/apt/sources.list && \ + echo "deb http://mirrors.aliyun.com/debian/ bullseye-updates main contrib non-free" >> /etc/apt/sources.list && \ + echo "deb http://mirrors.aliyun.com/debian/ bullseye-backports main contrib non-free" >> /etc/apt/sources.list && \ + echo "deb http://mirrors.aliyun.com/debian-security bullseye-security main contrib non-free" >> /etc/apt/sources.list + + # 安装系统依赖(添加超时设置) + RUN apt-get update -o Acquire::http::Timeout=10 -o Acquire::https::Timeout=10 && \ + apt-get install -y --no-install-recommends \ + gcc \ + && rm -rf /var/lib/apt/lists/* \ + && apt-get clean + + # 配置 pip 使用清华源 + RUN pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple + + # 复制依赖文件 + COPY requirements.txt . + + # 安装依赖到虚拟环境 + RUN python -m venv /opt/venv + ENV PATH="/opt/venv/bin:$PATH" + RUN pip install --no-cache-dir -r requirements.txt gunicorn + + # 运行阶段 + FROM python:3.12.6-slim + + # 设置工作目录 + WORKDIR /app + + # 设置环境变量 + ENV PYTHONUNBUFFERED=1 \ + PYTHONDONTWRITEBYTECODE=1 \ + PATH="/opt/venv/bin:$PATH" + + # 创建非root用户 + RUN groupadd -r appuser && useradd -r -g appuser appuser + + # 从构建阶段复制虚拟环境 + COPY --from=builder /opt/venv /opt/venv + + # 复制应用代码 + COPY --chown=appuser:appuser . . + + # 切换到非root用户 + USER appuser + + # 暴露端口 + EXPOSE 8000 + + # 设置资源限制 + ENV GUNICORN_CMD_ARGS="--workers=4 --threads=2 --timeout=60 --max-requests=1000 --max-requests-jitter=50" + + # 启动命令(使用gunicorn作为生产服务器) + CMD ["/opt/venv/bin/gunicorn", "app.main:app", "--bind", "0.0.0.0:8000", "--worker-class", "uvicorn.workers.UvicornWorker"] + ``` + +* 知识点 + + * `Gunicorn`介绍 + * 也是Python的 Web 服务器,它采用多进程模型,启动时会创建多个工作进程,每个进程都能独立处理请求,适合生产环境部署 + * 可以充分利用多核 CPU 的计算能力,既适用于同步框架(如 Flask、Django)开发的 Web 应用,也能用于异步框架。 + * 当需要在**生产环境部署异步框架**(如 FastAPI),且希望充分利用多核 CPU、保证进程稳定性时,结合使用 Gunicorn 和 Uvicorn 是最优解。 + * 两者通过 “主进程管理 + 异步工作者” 的模式,实现了高性能、高可用的统一 + * 参数说明 + * `-w 4`:启动 4 个工作worker进程(数量通常设为 CPU 核心数的 1-2 倍)。 + * `max_requests` 是指每个 worker 在处理一定数量的请求后将会重启,防止内存泄漏或其他问题 + * `max_requests_jitter` 参数用于设置在 `max_requests` 的基础上增加一个随机的抖动值,避免所有 worker 同时重启 + +#### FastAPI模型服务Docker部署验证实战 + +* 需求 + + * 阿里云服务器安装好相关环境Docker环境 + * 采用上集编写好的Dockerfile进行打包验证(有修改Dockerfile下载源加速,按照上集的直接下载即可) + * 网络安全组记得开发相关端口 + +* 构建打包验证实战 + + * 构建镜像【进入到项目根目录 Dockerfile所在的路径】 + + ```dockerfile + docker build -t fastapi-app-pro . + ``` + + * 运行容器 + + ```dockerfile + docker run -d \ + -p 8000:8000 \ + --name fastapi-container \ + --memory=2048m \ + --restart=always \ + fastapi-app-pro + ``` + +* 请求接口测试实 + +#### AI智能化网盘项目Docker部署打包配置编写 + +* 需求 + + * 后端SpringBoot项目进行容器打包部署,编写对应的Dockerfile文件 + * 方便快速扩容和多个节点进行,相关服务都采用容器部署 + +* 项目 `pom.xml` 文件调整 + + ```xml + + + + aliyun + aliyun + https://maven.aliyun.com/repository/public + + true + + + false + + + + aliyun-spring + aliyun-spring + https://maven.aliyun.com/repository/spring + + true + + + false + + + + + + + + aliyun-plugin + aliyun-plugin + https://maven.aliyun.com/repository/public + + true + + + false + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + 3.11.0 + + ${java.version} + ${java.version} + + + org.projectlombok + lombok + ${lombok.version} + + + + + + + ``` + + + +* Dockerfile编写实战 + + ```dockerfile + # ================================================ + # 多阶段构建:构建阶段(使用Maven基础镜像) + # 基础镜像:Maven 3.9.6 + Eclipse Temurin JDK21 + # ================================================ + FROM maven:3.9.6-eclipse-temurin-21 AS build + # 设置容器内工作目录 + WORKDIR /app + + # ------------------------------------------------ + # 复制宿主机构建上下文全部文件到容器工作目录 + # ------------------------------------------------ + COPY . . + + # ================================================ + # Maven构建命令(含优化参数) + # 主要参数说明: + # -DskipTests=true : 跳过单元测试 + # -Dmaven.test.skip=true : 跳过测试编译阶段 + # -Dmaven.compile.fork=true : 启用并行编译 + # -Dmaven.compiler.source/target: 指定Java版本 + # -Dmaven.compiler.force... : 强制使用javac + # -annotationProcessorPaths : 配置Lombok注解处理器 + # ================================================ + RUN mvn clean package \ + -DskipTests=true \ + -Dmaven.test.skip=true \ + -Dmaven.javadoc.skip=true \ + -Dmaven.compile.fork=true \ + -Dmaven.compiler.source=21 \ + -Dmaven.compiler.target=21 \ + -Dmaven.compiler.forceJavacCompilerUse=true \ + -Dmaven.compiler.showWarnings=true \ + -Dmaven.compiler.showDeprecation=true \ + -Dmaven.compiler.annotationProcessorPaths=lombok:org.projectlombok:lombok:1.18.30 + + # ================================================ + # 多阶段构建:运行阶段(使用轻量级JRE镜像) + # 基础镜像:Eclipse Temurin JRE21 + Ubuntu Jammy + # ================================================ + FROM eclipse-temurin:21-jre-jammy + WORKDIR /app + + # ------------------------------------------------ + # 从构建阶段复制生成的JAR文件 + # ARG参数说明: + # JAR_FILE : 匹配target目录下的所有JAR文件 + # ------------------------------------------------ + ARG JAR_FILE=target/*.jar + COPY --from=build /app/${JAR_FILE} app.jar + + # ------------------------------------------------ + # 时区配置(设置为亚洲/上海时区) + # 通过符号链接和配置文件修改容器时区 + # ------------------------------------------------ + ENV TZ=Asia/Shanghai + RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + + # ================================================ + # JVM参数配置(内存管理与GC优化) + # 关键参数说明: + # -Xms/-Xmx : 堆内存初始/最大值 + # -XX:MetaspaceSize : 元空间初始大小 + # -UseG1GC : 启用G1垃圾回收器 + # -MaxGCPauseMillis : 目标最大GC停顿时间 + # -HeapDumpOn... : OOM时生成堆转储 + # -UseContainerSupport : 容器内存感知 + # -MaxRAMPercentage : 最大内存占用比例 + # ================================================ + ENV JAVA_OPTS="-Xms2g -Xmx4g \ + -XX:MetaspaceSize=256m \ + -XX:MaxMetaspaceSize=512m \ + -XX:+UseG1GC \ + -XX:MaxGCPauseMillis=200 \ + -XX:ParallelGCThreads=4 \ + -XX:ConcGCThreads=2 \ + -XX:+HeapDumpOnOutOfMemoryError \ + -XX:HeapDumpPath=/app/dump \ + -Xlog:gc*:file=/app/gc.log \ + -XX:+UseStringDeduplication \ + -XX:+UseContainerSupport \ + -XX:MaxRAMPercentage=75.0" + + # ------------------------------------------------ + # 声明容器暴露端口(HTTP服务默认端口) + # ------------------------------------------------ + EXPOSE 8080 + + # ================================================ + # 容器启动入口命令 + # 使用sh -c执行命令以支持环境变量扩展 + # 最终启动命令:java [JVM参数] -jar app.jar + # ================================================ + ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"] + ``` + + +#### AI智能化网盘项目Docker部署验证实战 + +* 需求 + + * 阿里云服务器安装好相关环境Docker环境 + * 采用上集编写好的Dockerfile进行打包验证 + * 网络安全组记得开发相关端口 + * 备注:项目依赖的其他中间件比如Mysql、Redis等,直接复用之前部署即可 + +* 构建打包验证实战 + + * git拉取代码 + + * 构建镜像 + + ```dockerfile + # 构建镜像 + docker build -t dcloud-aipan . + ``` + + * 运行容器 + + ```dockerfile + docker run -d \ + -p 8080:8080 \ + --name dcloud-aipan \ + --restart=always \ + dcloud-aipan + ``` + +* 测试验证实战:请求接口测试实战 + + + +#### Nginx反向代理Web服务器集群架构 + +* 需求 + + * 后端业务会进行负载均衡,通过反向代理进行分发多个节点 + * 需要阿里云安装Nginx服务器,和启动多个后端服务节点 + +* 整体请求架构 + + image-20250504135738921 + +* 域名解析和配置 + + * http://ai-api.open1024.com/ + * http://pan-api.open1024.com/ + + ![image-20250504140455882](./img/image-20250504140455882.png) + +* Docker安装Nginx + + * 创建配置文件 `nginx.conf` + + ```nginx + user nginx; + worker_processes auto; + error_log /var/log/nginx/error.log warn; + pid /var/run/nginx.pid; + + events { + worker_connections 1024; + } + + http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + # 日志格式 + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + # 开启gzip压缩 + gzip on; + gzip_min_length 1k; + gzip_comp_level 6; + gzip_types text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml; + gzip_vary on; + gzip_disable "MSIE [1-6]\."; + + # 超时设置 + keepalive_timeout 65; + client_max_body_size 100m; + + # Spring Boot后端服务配置 + upstream springboot_backend { + # 使用轮询策略 + server 172.31.101.8:8080; # 节点1 + } + + # FastAPI服务配置 + upstream fastapi_backend { + # 使用轮询策略 + server 172.31.101.8:8000; # 节点1 + } + + # Spring Boot服务配置 + server { + listen 80; + server_name pan-api.open1024.com; # Spring Boot服务的域名 + + location /api/ { + proxy_pass http://springboot_backend/api/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + # 超时设置 + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + } + } + + # FastAPI服务配置 + server { + listen 80; + server_name ai-api.open1024.com; # FastAPI服务的域名 + + location /api/ { + proxy_pass http://fastapi_backend/api/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + # 超时设置 + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + } + } + } + ``` + + +* 创建Dockerfile + + ```dockerfile + FROM nginx:1.24.0-alpine + + # 复制自定义配置 + COPY nginx.conf /etc/nginx/nginx.conf + + # 创建日志目录 + RUN mkdir -p /var/log/nginx && \ + chown -R nginx:nginx /var/log/nginx + + # 暴露端口 + EXPOSE 80 + + # 启动Nginx + CMD ["nginx", "-g", "daemon off;"] + ``` + +* 编写`start.sh` 脚本 + + ```sh + #!/bin/bash + + # 创建日志目录 + mkdir -p logs + + # 构建镜像 + docker build -t nginx-proxy:1.24.0 . + + # 停止并删除旧容器(如果存在) + docker stop nginx-proxy 2>/dev/null || true + docker rm nginx-proxy 2>/dev/null || true + + # 运行容器 + docker run -d \ + --name nginx-proxy \ + -p 80:80 \ + -v $(pwd)/nginx.conf:/etc/nginx/nginx.conf:ro \ + -v $(pwd)/logs:/var/log/nginx \ + --restart unless-stopped \ + nginx-proxy:1.24.0 + + # 显示容器日志 + docker logs -f nginx-proxy + ``` + +* 测试实战【备注,如果没域名的或者备案还没成功的,可以用ip测试,部署多1个Nginx】 + + * AI网盘服务接口 + * AI大模型服务接口 + +#### 智能化网盘Web前端项目部署阿里云OSS实战 + +* 需求 + + * 前端项目部署阿里服务器实战,打包项目上传阿里云OSS即可 + * 配置域名解析(不能使用默认域名,否则访问不了直接下载) + * 需要域名备案通过才可以,可以不实操或者使用nginx部署ip访问 + * **注意:本集不提供前端代码,请从 第56章第2集的方向进行获取完整前端代码** + +* 配置实战 + + ``` + #生产环境打包构建 + yarn build + ``` + +![image-20250505180150494](./img/image-20250505180150494.png) + +#### AI智能化云盘-前后端全链路功能测试实战 + +**简介: AI智能化云盘-前后端全链路功能测试实战** + +* 需求 + + * 智能化网盘进行功能测试,包括注册,登录,文件上传,文件秒传,大文件上传,文件删除、分享、查看、转存等 + * AI智能体中心测试,包括AI网盘智答、AI智能聊天助理、AI在线文档助手等相关功能 + +* 功能测试实战 diff --git a/img/1-5916295.png b/img/1-5916295.png new file mode 100644 index 0000000..1200566 Binary files /dev/null and b/img/1-5916295.png differ diff --git a/img/image-20250429170519143.png b/img/image-20250429170519143.png new file mode 100644 index 0000000..1aab63a Binary files /dev/null and b/img/image-20250429170519143.png differ diff --git a/img/image-20250429175110088.png b/img/image-20250429175110088.png new file mode 100644 index 0000000..7936e20 Binary files /dev/null and b/img/image-20250429175110088.png differ diff --git a/img/image-20250429205355439.png b/img/image-20250429205355439.png new file mode 100644 index 0000000..728acc3 Binary files /dev/null and b/img/image-20250429205355439.png differ diff --git a/img/image-20250502230152621.png b/img/image-20250502230152621.png new file mode 100644 index 0000000..e231833 Binary files /dev/null and b/img/image-20250502230152621.png differ diff --git a/img/image-20250502230846228.png b/img/image-20250502230846228.png new file mode 100644 index 0000000..55a90a2 Binary files /dev/null and b/img/image-20250502230846228.png differ diff --git a/img/image-20250503105739654.png b/img/image-20250503105739654.png new file mode 100644 index 0000000..49eba36 Binary files /dev/null and b/img/image-20250503105739654.png differ diff --git a/img/image-20250503110127541.png b/img/image-20250503110127541.png new file mode 100644 index 0000000..c9b215b Binary files /dev/null and b/img/image-20250503110127541.png differ diff --git a/img/image-20250503110211729.png b/img/image-20250503110211729.png new file mode 100644 index 0000000..f7202ce Binary files /dev/null and b/img/image-20250503110211729.png differ diff --git a/img/image-20250503112608773.png b/img/image-20250503112608773.png new file mode 100644 index 0000000..bf7b84e Binary files /dev/null and b/img/image-20250503112608773.png differ diff --git a/img/image-20250503121359088.png b/img/image-20250503121359088.png new file mode 100644 index 0000000..2395bd9 Binary files /dev/null and b/img/image-20250503121359088.png differ diff --git a/img/image-20250503155805463.png b/img/image-20250503155805463.png new file mode 100644 index 0000000..906adf7 Binary files /dev/null and b/img/image-20250503155805463.png differ diff --git a/img/image-20250503160856611.png b/img/image-20250503160856611.png new file mode 100644 index 0000000..91398fd Binary files /dev/null and b/img/image-20250503160856611.png differ diff --git a/img/image-20250504135738921.png b/img/image-20250504135738921.png new file mode 100644 index 0000000..739136d Binary files /dev/null and b/img/image-20250504135738921.png differ diff --git a/img/image-20250504140455882.png b/img/image-20250504140455882.png new file mode 100644 index 0000000..6f42518 Binary files /dev/null and b/img/image-20250504140455882.png differ diff --git a/img/image-20250505175523502.png b/img/image-20250505175523502.png new file mode 100644 index 0000000..76b33f5 Binary files /dev/null and b/img/image-20250505175523502.png differ diff --git a/img/image-20250505175611890.png b/img/image-20250505175611890.png new file mode 100644 index 0000000..f190034 Binary files /dev/null and b/img/image-20250505175611890.png differ diff --git a/img/image-20250505175724176.png b/img/image-20250505175724176.png new file mode 100644 index 0000000..ded67d9 Binary files /dev/null and b/img/image-20250505175724176.png differ diff --git a/img/image-20250505180150494.png b/img/image-20250505180150494.png new file mode 100644 index 0000000..2266a41 Binary files /dev/null and b/img/image-20250505180150494.png differ diff --git a/src/test/java/org/ycloud/aipan/ChangeImages.java b/src/test/java/org/ycloud/aipan/ChangeImages.java index 4c8dfdc..84a899e 100644 --- a/src/test/java/org/ycloud/aipan/ChangeImages.java +++ b/src/test/java/org/ycloud/aipan/ChangeImages.java @@ -13,7 +13,7 @@ public class ChangeImages { private static final Path TARGET_DIR = Paths.get("D:/IdeaProjects/learn/ycloud-aipan/img"); public static void main(String[] args) { - List images = List.of("1-3069367.png", "3-3070285.png"); + List images = List.of("1-5916295.png","image-20250429170519143.png","image-20250429205355439.png","image-20250429175110088.png","image-20250418190055953.png","image-20250503110127541.png","image-20250503110211729.png","image-20250503112608773.png","image-20250503121359088.png","image-20250503105739654.png","image-20250503155805463.png","image-20250502230152621.png","image-20250502230846228.png","image-20250503160856611.png","image-20250505175724176.png","image-20250505175523502.png","image-20250505175611890.png","image-20250504135738921.png","image-20250504140455882.png","image-20250505180150494.png"); try { for (String image : images) { Path sourceFile = SOURCE_DIR.resolve(image);