【Azure 架构师学习笔记 】- Azure AI(21) - Azure Agent进阶优化

本文属于【Azure 架构师学习笔记】系列

本文属于【Azure AI】系列

接上文 【Azure 架构师学习笔记 】- Azure AI(20) - Azure Agent实战落地

一、前言(承接第四篇)

上一篇我们成功实现了职场办公型Azure Agent,完成了"读取Word/PDF/TXT文件→自动总结→保存结果"的完整闭环,复用了第三篇的"记忆+多工具"架构,解决了手动处理单个文件的重复工作,代码可直接运行、容错性强,完全贴合职场基础办公需求。

但在实际职场场景中,我们常常会遇到「批量处理多个文件」(如批量总结10个会议纪要、批量提取多个PDF关键信息)、「需要Excel格式保存结果」(方便统计、汇报和数据对比)的高频需求,同时缺乏进度提示,处理多个文件时无法判断进度,体验不够流畅。

这一篇我们基于第四篇的实战代码,进行三大核心进阶优化,全程复用你已有的Azure GPT-4模型、azure_config.json配置文件和依赖环境,代码可直接复制运行,无需额外配置,新手也能轻松上手,完美衔接第四篇的实战成果,让Agent从"单次处理"升级为"高效批量处理",真正适配高强度办公场景。

本篇核心目标:实现「批量处理多个文件」「Excel格式保存结果」「实时进度提示」三大功能,优化Agent的稳定性和交互体验,解决批量文件处理效率低、结果统计不便的痛点,同时延续前四篇的模块化架构,保持代码的扩展性和连贯性。

二、实操准备

复用前面的Azure环境、Python环境和所有依赖包,无需重新安装之前的依赖(python-docx、PyPDF2、openpyxl等),只需确认以下2点即可:

  1. 确认已安装openpyxl依赖(上一篇已安装,用于Excel保存),若未安装,打开CMD/PowerShell执行以下命令:pip install openpyxl --user

  2. 确认azure_config.json文件存在(与本篇代码放在同一目录)。

提示:若忘记依赖安装状态,可直接执行上述openpyxl安装命令,重复安装不会影响环境;批量处理时,建议将需要处理的所有文件(Word/PDF/TXT)放在同一个文件夹中,方便Agent遍历读取,提升处理效率。

三、代码

将以下代码保存为agent_advanced.py,建议放在同一目录(无需重新输入Azure配置,直接复用前序配置文件):

python 复制代码
from openai import AzureOpenAI
import json
import os
from docx import Document  # 读取Word文件(复用上一篇)
from PyPDF2 import PdfReader  # 读取PDF文件(复用上一篇)
import openpyxl  # Excel保存(复用上一篇依赖,新增逻辑)
import datetime  # 时间戳、进度计时(新增)

# ===================== 1. Azure配置加载 =====================
CONFIG_FILE = "azure_config.json"

def load_azure_config():
    """加载Azure OpenAI配置,沿用前四篇的容错处理,避免配置错误导致程序崩溃"""
    if os.path.exists(CONFIG_FILE):
        try:
            with open(CONFIG_FILE, "r", encoding="utf-8") as f:
                config = json.load(f)
            # 验证核心配置是否完整(适配GPT-4部署,与前四篇一致)
            required_keys = ["azure_endpoint", "api_key", "deployment_name"]
            if all(key in config for key in required_keys):
                return config
            else:
                print("⚠️  Azure配置文件不完整,将重新引导输入")
        except Exception as e:
            print(f"⚠️  配置文件读取失败({str(e)}),将重新引导输入")
    
    # 若配置文件不存在/读取失败,引导用户重新输入并生成新文件(与前四篇逻辑一致)
    config = {
        "azure_endpoint": input("请输入Azure Endpoint:"),
        "api_key": input("请输入Azure OpenAI API Key:"),
        "deployment_name": input("请输入GPT-4模型部署名称:")
    }
    with open(CONFIG_FILE, "w", encoding="utf-8") as f:
        json.dump(config, f, ensure_ascii=False, indent=4)
    return config

# 初始化Azure OpenAI客户端(稳定调用GPT-4,版本与前四篇一致)
config = load_azure_config()
client = AzureOpenAI(
    azure_endpoint=config["azure_endpoint"],
    api_key=config["api_key"],
    api_version="2024-08-01-preview"  # 兼容GPT-4的稳定版本,与前四篇保持一致
)

# ===================== 2. 核心工具模块(新增批量+Excel保存,复用前四篇工具) =====================
# 工具1:读取文件(完全复用上一篇,无修改,保证功能连贯性)
def read_file(file_path: str) -> str:
    """读取文件内容,自动识别文件格式,返回纯文本,容错处理沿用前四篇思路"""
    if not os.path.exists(file_path):
        return f"❌ 文件不存在,请检查文件路径是否正确(当前路径:{file_path})"
    
    file_ext = os.path.splitext(file_path)[1].lower()
    try:
        if file_ext == ".docx":  # Word文件
            doc = Document(file_path)
            content = "\n".join([para.text for para in doc.paragraphs if para.text.strip()])
        elif file_ext == ".pdf":  # PDF文件
            reader = PdfReader(file_path)
            content = "\n".join([page.extract_text() for page in reader.pages if page.extract_text().strip()])
        elif file_ext == ".txt":  # TXT文件
            with open(file_path, "r", encoding="utf-8") as f:
                content = f.read()
        else:
            return f"❌ 不支持该文件格式({file_ext}),仅支持.docx/.pdf/.txt"
        
        if not content.strip():
            return "❌ 文件内容为空,无法进行处理"
        return content
    except Exception as e:
        return f"❌ 文件读取失败:{str(e)}(可能是文件损坏或格式异常)"

# 工具2:文本总结(完全复用上一篇,无修改,适配批量处理场景)
def summary_tool(text: str) -> str:
    """文件内容总结工具,GPT-4驱动,沿用前四篇逻辑,贴合职场汇报需求"""
    try:
        response = client.chat.completions.create(
            model=config["deployment_name"],
            messages=[
                {"role": "system", "content": "你是职场办公总结助手,总结文件内容时,需突出核心要点、关键数据和结论,语言简洁、专业,控制在150字内,避免冗余,适配职场汇报场景。"},
                {"role": "user", "content": f"请总结以下文件内容:\n{text}"}
            ],
            temperature=0.2  # 降低随机性,确保总结结果稳定、准确,与前四篇一致
        )
        return response.choices[0].message.content.strip()
    except Exception as e:
        return f"❌ 总结失败:{str(e)}(请检查Azure配置或网络连接)"

# 工具3:结果保存(升级,支持TXT/Excel双格式,新增Excel保存逻辑)
def save_result(result_list: list, save_format: str = "txt", file_name: str = None) -> str:
    """保存处理结果,支持TXT(单个/批量)和Excel(批量优先),延续前四篇简洁实用思路"""
    # 自动生成文件名(含时间戳),适配批量/单个场景
    if not file_name:
        now = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
        file_name = f"agent_advanced_result_{now}"
    
    try:
        if save_format.lower() == "excel":
            # 新增:Excel格式保存(批量处理优先,支持单个结果)
            wb = openpyxl.Workbook()
            ws = wb.active
            # 设置表头(适配批量统计,清晰直观)
            ws.append(["处理时间", "文件名称", "文件路径", "处理结果"])
            # 填充数据(支持单个结果和批量结果)
            for item in result_list:
                ws.append([
                    item["time"],
                    item["file_name"],
                    item["file_path"],
                    item["result"]
                ])
            # 调整列宽,避免内容溢出
            ws.column_dimensions['A'].width = 20
            ws.column_dimensions['B'].width = 30
            ws.column_dimensions['C'].width = 50
            ws.column_dimensions['D'].width = 80
            # 保存Excel文件
            excel_path = f"{file_name}.xlsx"
            wb.save(excel_path)
            return f"✅ 批量结果已保存为Excel:{os.path.abspath(excel_path)}"
        else:
            # 复用上一篇TXT保存逻辑,适配批量处理
            txt_path = f"{file_name}.txt" if file_name.endswith(".txt") else f"{file_name}.txt"
            with open(txt_path, "w", encoding="utf-8") as f:
                f.write(f"Agent批量处理结果({datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')})\n")
                f.write("="*80 + "\n")
                for idx, item in enumerate(result_list, 1):
                    f.write(f"【第{idx}个文件】\n")
                    f.write(f"文件名称:{item['file_name']}\n")
                    f.write(f"文件路径:{item['file_path']}\n")
                    f.write(f"处理结果:{item['result']}\n")
                    f.write("-"*80 + "\n")
            return f"✅ 批量结果已保存为TXT:{os.path.abspath(txt_path)}"
    except Exception as e:
        return f"❌ 结果保存失败:{str(e)}(请检查目录写入权限)"

# 工具4:批量处理文件(新增核心工具,适配职场批量需求)
def batch_process(folder_path: str) -> list:
    """批量处理文件夹下所有Word/PDF/TXT文件,返回处理结果列表,用于后续保存"""
    # 验证文件夹是否存在
    if not os.path.isdir(folder_path):
        return [{"time": "", "file_name": "", "file_path": folder_path, "result": f"❌ 文件夹不存在,请检查路径是否正确"}]
    
    # 遍历文件夹,筛选支持的文件格式
    file_list = [f for f in os.listdir(folder_path) if f.lower().endswith((".docx", ".pdf", ".txt"))]
    if not file_list:
        return [{"time": "", "file_name": "", "file_path": folder_path, "result": "❌ 文件夹下无支持的文件(仅支持.docx/.pdf/.txt)"}]
    
    # 批量处理,记录每个文件的处理结果
    result_list = []
    total = len(file_list)
    for idx, file_name in enumerate(file_list, 1):
        # 拼接完整文件路径
        file_path = os.path.join(folder_path, file_name)
        # 读取文件内容(复用工具1)
        file_content = read_file(file_path)
        # 处理结果(读取失败则直接记录错误,读取成功则总结)
        if file_content.startswith("❌"):
            result = file_content
        else:
            result = summary_tool(file_content)
        # 记录当前处理结果(含时间戳,方便统计)
        result_list.append({
            "time": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
            "file_name": file_name,
            "file_path": file_path,
            "result": result
        })
        # 新增:进度提示,实时显示处理进度
        progress = (idx / total) * 100
        print(f"📊 批量处理进度:{idx}/{total}({progress:.1f}%),当前处理:{file_name}")
    
    return result_list

# ===================== 3. 进阶Agent核心(整合所有工具,沿用前四篇架构) =====================
class AdvancedAgent:
    def __init__(self):
        self.history = []  # 多轮记忆(复用第三、四篇的记忆机制)
        self.last_file_path = None  # 记录最近一次读取的文件路径(复用上一篇)
        self.last_folder_path = None  # 新增:记录最近一次批量处理的文件夹路径
        # 工具映射,沿用前四篇的字典映射逻辑,新增批量处理工具
        self.tools = {
            "读取文件": read_file,
            "总结文件": summary_tool,
            "保存结果": save_result,
            "批量处理": batch_process
        }
    
    def parse_intent(self, instruction: str) -> tuple:
        """智能解析用户指令,优化批量处理识别,沿用前四篇关键词匹配逻辑"""
        instruction_lower = instruction.lower()
        file_path = None
        folder_path = None
        
        # 提取文件路径(复用上一篇逻辑)
        if any(ext in instruction for ext in [".docx", ".pdf", ".txt"]):
            import re
            pattern = r"([^\s]+?\.(docx|pdf|txt))"
            match = re.search(pattern, instruction)
            if match:
                file_path = match.group(1)
                self.last_file_path = file_path
        else:
            file_path = self.last_file_path
        
        # 新增:提取文件夹路径(适配批量处理指令)
        if any(keyword in instruction_lower for keyword in ["批量", "文件夹", "目录"]):
            import re
            # 提取文件夹路径(适配空格、中文路径)
            pattern = r"([^\s]+?[\\/][^\s]+?)(?=\s|$)"
            match = re.search(pattern, instruction)
            if match:
                folder_path = match.group(1)
                self.last_folder_path = folder_path
        else:
            folder_path = self.last_folder_path
        
        # 判断任务类型,新增批量处理意图识别,与前四篇逻辑一致
        if any(keyword in instruction_lower for keyword in ["批量", "批量处理"]):
            return "批量处理", folder_path, instruction
        elif any(keyword in instruction_lower for keyword in ["读取", "打开"]):
            return "读取文件", file_path, instruction
        elif any(keyword in instruction_lower for keyword in ["总结", "概括", "提炼"]):
            return "总结文件", file_path, instruction
        elif any(keyword in instruction_lower for keyword in ["保存", "导出"]):
            # 识别保存格式(Excel/TXT)
            save_format = "excel" if "excel" in instruction_lower else "txt"
            return "保存结果", save_format, instruction
        else:
            return "未知", None, instruction
    
    def run(self, instruction: str) -> str:
        """Agent运行入口,串联批量处理、Excel保存、进度提示全流程,沿用前四篇核心逻辑"""
        print(f"🔍 Agent接收指令:{instruction}")
        intent, param, raw_instruction = self.parse_intent(instruction)
        
        # 处理不同任务类型
        if intent == "批量处理":
            if not param:
                result = "❌ 未识别到文件夹路径,请输入包含文件夹的指令(如:批量处理 D:/docker/files)"
            else:
                print(f"🚀 开始批量处理文件夹:{param}")
                print(f"📌 正在筛选文件夹下支持的文件(.docx/.pdf/.txt)...")
                # 调用批量处理工具,获取结果列表
                batch_result = self.tools["批量处理"](param)
                # 批量处理完成后,自动保存结果(默认Excel格式,贴合职场统计需求)
                save_result = self.tools["保存结果"](batch_result, save_format="excel")
                # 统计处理情况(成功/失败数量)
                success_count = len([item for item in batch_result if not item["result"].startswith("❌")])
                fail_count = len(batch_result) - success_count
                result = f"✅ 批量处理完成!\n📊 处理统计:共{len(batch_result)}个文件,成功{success_count}个,失败{fail_count}个\n{save_result}"
                # 存入记忆
                self.history.append(("批量处理", param, result))
        
        elif intent == "读取文件":
            # 复用上一篇逻辑,无修改,保证连贯性
            if not param:
                result = "❌ 未识别到文件路径,请先读取文件(如:读取文件 D:/test.pdf),再输入「总结这个文件」"
            else:
                result = self.tools["读取文件"](param)
                if not result.startswith("❌"):
                    self.last_file_path = param
                    self.history.append(("读取文件", param, result[:50] + "..."))
        
        elif intent == "总结文件":
            # 复用上一篇逻辑,无修改,支持"总结这个文件"指令
            if not param:
                result = "❌ 未识别到文件路径,请先读取文件(如:读取文件 D:/test.pdf),再输入「总结这个文件」"
            else:
                file_content = self.tools["读取文件"](param)
                if file_content.startswith("❌"):
                    result = file_content
                else:
                    result = self.tools["总结文件"](file_content)
                    self.history.append(("总结文件", param, result))
        
        elif intent == "保存结果":
            # 升级:支持手动选择保存格式(Excel/TXT),复用记忆逻辑
            if not self.history:
                result = "❌ 暂无可保存的结果,请先处理文件(读取/总结/批量处理)"
            else:
                # 判断是否为批量处理结果
                last_task, last_param, last_result = self.history[-1]
                if last_task == "批量处理":
                    # 批量结果已自动保存,提示用户可手动指定格式保存
                    result = f"📌 最近一次为批量处理({last_param}),已自动保存为Excel格式\n若需保存为TXT格式,输入:保存结果 TXT"
                else:
                    # 单个结果保存,支持指定格式
                    save_result = self.tools["保存结果"](
                        [{"time": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                          "file_name": os.path.basename(last_param),
                          "file_path": last_param,
                          "result": last_result}],
                        save_format=param
                    )
                    result = save_result
        
        else:
            # 未识别到任务类型,提示优化,新增批量处理指令示例
            result = "❌ 未识别到任务,请输入以下类型的指令:\n1. 读取文件:包含.docx/.pdf/.txt路径(如:读取 D:/会议纪要.docx)\n2. 总结文件:包含文件路径或先读取文件后输入「总结这个文件」\n3. 批量处理:包含文件夹路径(如:批量处理 D:/docker/files)\n4. 保存结果:可选指定格式(如:保存结果 Excel / 保存结果 TXT)"
        
        # 存入记忆,控制记忆长度(沿用第三、四篇逻辑,保留最近5次交互)
        self.history.append(("用户指令", raw_instruction, result))
        if len(self.history) > 5:
            self.history.pop(0)
        
        return result

# ===================== 4. 运行测试(进阶场景,直接复制样本测试) =====================
if __name__ == "__main__":
    # 初始化高效办公型Agent,沿用前四篇的初始化逻辑
    advanced_agent = AdvancedAgent()
    print("✅ 高效办公型Azure Agent已启动(基于GPT-4驱动)")
    print("📌 支持功能:单次处理(复用上一篇)+ 批量处理 + Excel/TXT双格式保存 + 实时进度提示")
    print("📌 示例指令(直接复制使用):")
    print("   1. 批量处理 D:/docker/files (将所有文件放在files文件夹中)")
    print("   2. 读取文件 D:/docker/会议纪要.docx")
    print("   3. 总结这个文件 (先读取文件后使用)")
    print("   4. 保存结果 Excel (保存为Excel格式,适合统计)")
    print("📌 输入「退出」即可结束运行")
    
    # 交互测试,模拟职场批量办公场景,延续前四篇的交互风格
    while True:
        user_input = input("\n请输入指令:")
        if user_input in ["退出", "exit", "quit"]:
            print("❌ Agent已停止运行")
            break
        # 运行Agent并输出结果
        result = advanced_agent.run(user_input)
        print(f"\nAgent:{result}\n")

启动成功:

四、测试

测试前准备:在电脑中创建一个文件夹(如:D:/docker/files),放入2-5个Word/PDF/TXT文件(用于批量测试);

测试样本1:批量处理文件夹

复制以下指令(替换成你自己的文件夹路径),粘贴到Agent的「请输入指令:」后面:

批量处理 D:/docker/files

预期结果:1. Agent会提示"正在筛选文件夹下支持的文件";2. 实时显示进度(如:1/3(33.3%),当前处理:会议纪要.pdf);3. 处理完成后,自动保存为Excel文件,返回保存路径;4. 显示处理统计(成功/失败数量),完美实现批量处理+进度提示+Excel保存。

测试样本2:Excel格式手动保存

  1. 先输入:读取文件 D:/docker/files/会议纪要.pdf(替换成你的文件路径);

  2. 再输入:总结这个文件;

  3. 最后输入:保存结果 Excel。

预期结果:Agent将总结结果保存为Excel文件,返回保存路径,打开Excel可看到"处理时间、文件名称、文件路径、处理结果"四大表头,数据清晰,适合职场统计和汇报。

测试样本3:TXT格式保存

完成测试样本2的总结后,输入:

保存结果 TXT

预期结果:Agent将总结结果保存为TXT文件,返回保存路径,格式与上一篇一致,确保兼容性,满足不同保存需求。

测试样本4:多轮批量+记忆测试

  1. 先输入:批量处理 D:/docker/files;

  2. 再输入:保存结果 TXT;

  3. 最后输入:读取文件 D:/docker/会议纪要.docx。

预期结果:Agent能连贯处理批量和单次任务,记忆功能正常,批量处理结果可重复保存为不同格式。

五、核心知识点讲解

  1. 新增模块核心逻辑
  • 批量处理模块:通过os.listdir遍历文件夹,筛选支持的文件格式,循环调用上一篇的读取和总结工具,实现批量处理;同时记录每个文件的处理结果,用于后续批量保存,逻辑简洁,复用前序工具,避免重复开发。

  • Excel保存模块:基于openpyxl依赖,创建工作簿和工作表,设置表头和列宽,将批量处理结果按"时间、文件名、路径、结果"整理保存,贴合职场统计需求,同时支持单个结果保存,兼容性强;

  • 进度提示模块:通过"当前处理数量/总数量"计算进度百分比,实时打印进度信息,解决批量处理时"无反馈、不知道进度"的痛点,提升交互体验;

  • 意图解析优化:新增文件夹路径提取逻辑,自动识别"批量处理"指令,支持自然语言输入(如"批量处理D:/files""批量总结文件夹"),延续前四篇"无需死板输入指令头"的设计思路。

  1. 与前四篇的衔接要点

本次进阶Agent完全复用前四篇的核心资源和架构逻辑,无需重复操作,重点衔接以下5点:

  • 配置复用:Azure配置加载、客户端初始化代码完全复用,azure_config.json文件通用,无需重新输入Endpoint、API Key;

  • 工具复用:读取文件、文本总结工具完全复用第四篇,无任何修改,保证功能连贯性和一致性;

  • 架构复用:沿用第三篇的"工具映射字典"和"多轮记忆"架构,新增批量处理、Excel保存工具只需添加映射,无需重构核心代码,延续扩展性优势;

  • 交互复用:Agent的启动提示、交互风格、容错逻辑与前四篇完全一致,新增批量处理指令示例,降低学习成本;

  • 依赖复用:完全复用第四篇安装的所有依赖(python-docx、PyPDF2、openpyxl),无需额外安装,上手更顺畅。

  1. 可扩展性说明

本次进阶Agent的架构可进一步扩展,延续前四篇"模块化扩展"的思路,后续可基于此代码添加以下职场高级功能:

  • 支持Excel文件的批量读取和总结(提取表格数据,生成数据分析报告);

  • 添加邮件发送功能(将批量处理的Excel/TXT结果自动发送到指定邮箱,适配汇报场景);

  • 支持文件筛选(批量处理时,可指定仅处理某一种格式的文件,如仅批量总结PDF);

  • 添加日志记录功能(记录每次处理的详细信息,方便后续追溯和问题排查)。

总结与系列回顾

总结

本篇我们基于第四篇的实战代码,完成了Azure Agent的进阶优化,实现了「批量处理文件」「Excel格式保存结果」「实时进度提示」三大核心功能,复用了前四篇的Azure配置、核心工具和架构逻辑,代码可直接运行、容错性强,完美解决了职场中批量文件处理效率低、结果统计不便的痛点,让Agent从"单次处理"升级为"高效办公助手"。

通过本次实操,你不仅掌握了批量处理、Excel保存、进度提示的核心代码,还进一步巩固了前四篇的模块化扩展思路------新增功能无需重构核心,只需添加对应工具,为后续开发更复杂的办公功能打下了坚实基础。

  1. 系列文章回顾

本系列文章从基础到实战、从单次处理到批量优化,逐步搭建了一个完整的职场办公型Azure Agent,全程新手友好,代码可直接复制运行,核心成果回顾如下:

  • 第二篇(基础入门):实现极简版Azure Agent,掌握Azure GPT-4调用、配置文件生成,核心功能:文本总结;

  • 第三篇(升级增强):新增多轮记忆、多工具调度,优化意图解析,核心功能:文本总结+智能问答(带记忆);

  • 第四篇(实战落地):新增文件读取、TXT保存,实现"读文件→总结→保存"闭环,核心功能:单次文件处理;

  • 第五篇(进阶优化):新增批量处理、Excel保存、进度提示,核心功能:批量文件处理+高效统计,适配高强度办公场景。

至此,一个完整的、可落地、可扩展的职场办公型Azure Agent已搭建完成。

接下来的系列打算尝试一下AI 的其他部分。

相关推荐
睿观·ERiC2 小时前
跨境电商 AI Agent 赛道爆发:从开源生态到垂直 Skill 落地,2026 年 3 月核心技术动态盘点
人工智能·开源
AC赳赳老秦2 小时前
OpenClaw 系统监控实战指南:构建高效的电脑/服务器状态监控与自动告警系统
服务器·开发语言·人工智能·php·ai-native·deepseek·openclaw
fof9202 小时前
Base LLM | 从 NLP 到 LLM 的算法全栈教程 第三天
人工智能·自然语言处理
MadPrinter2 小时前
deer-flow:ByteDance 开源的 SuperAgent Harness 终极指南
ai·开源·自动化·openclaw
刘 大 望2 小时前
MCP详细介绍以及IDE和Spring AI中应用
java·ide·人工智能·spring·ai·aigc·ai编程
无她022 小时前
AI为什么能“触类旁通”?万字拆解词嵌入(Embeddings)的底层逻辑
人工智能
广州赛远2 小时前
埃夫特ER6L码垛机器人防护服等级解析:避开选型误区与性能陷阱
网络·人工智能
Cx330❀2 小时前
Linux System V标准简介
大数据·linux·运维·服务器·人工智能
TG_yunshuguoji2 小时前
阿里云渠道商:百炼模型调优实战 5 步完成高效训练
人工智能·机器学习·阿里云·云计算