三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

AI Agent开发实战:从零构建智能体系统与Codex框架应用

AI Agent开发实战:从零构建智能体系统与Codex框架应用

最近在尝试将AI能力集成到业务系统中时,发现单纯调用大模型API往往难以满足复杂的、多步骤的业务需求。无论是构建一个能自动分析数据并生成报表的助手,还是开发一个能理解用户意图并调用多个工具完成任务的智能客服,都需要更系统化的架构。这正是AI Agent(智能体)技术要解决的核心问题。然而,网上关于Agent开发的资料要么过于理论化,要么就是代码片段零散,环境配置一步一个坑,让很多开发者,尤其是初学者望而却步。

本文旨在提供一套从零到一的AI Agent开发实战指南。我们将绕开繁杂的理论空谈,直接聚焦于如何搭建一个可运行、可交互的智能体系统。核心将围绕一个功能强大的Agent开发框架——Codex(此处指代基于大模型的开源智能体框架,非OpenAI Codex代码生成模型)展开,手把手带你完成环境安装、基础开发、核心功能实现,并最终探讨其商业化的可能性。无论你是想学习前沿技术的学生,还是寻求技术落地的开发者,都能从本文中找到清晰的路径和可复现的代码。

1. AI Agent 核心概念与开发价值

在开始敲代码之前,我们有必要厘清几个关键概念,这能帮助我们在后续开发中理解每一步操作的意义。

1.1 什么是 AI Agent(智能体)?

你可以将AI Agent理解为一个“数字员工”。它不仅仅是一个问答机器人,而是一个具备感知、规划、决策、执行能力的自治系统。

  • 感知(Perception): Agent能够理解用户的输入(文本、语音、文件等),并解析出用户的意图和上下文。
  • 规划(Planning): 针对复杂的用户请求,Agent会将其分解为一系列可执行的子任务或步骤。例如,用户说“帮我分析上个月的销售数据并总结成PPT”,Agent需要规划出“获取数据 -> 分析趋势 -> 生成图表 -> 撰写文案 -> 排版成PPT”等多个步骤。
  • 决策(Decision): 在每个步骤中,Agent需要决定调用哪个工具(Tool)或能力来完成任务。是调用数据库查询API,还是使用Python绘图库,或是唤起一个文件生成服务?
  • 执行(Action): Agent实际调用选定的工具,执行具体操作,并获取结果。
  • 反思(Reflection): 高级的Agent还能根据执行结果评估任务完成情况,如果失败或结果不理想,会尝试调整规划或选择其他工具。

与传统的单次问答模型(如ChatGPT基础对话)相比,Agent的核心优势在于任务驱动的自动化和工具使用能力

1.2 为什么选择 Codex 框架进行开发?

“Codex”在AI智能体领域常指一类基于大语言模型(LLM)构建的、用于编排和驱动智能体执行任务的开源框架或平台。它通常提供以下核心功能,使其成为快速开发Agent的理想选择:

  1. 智能体编排引擎: 核心是管理智能体的工作流(Workflow),包括任务分解、工具调用顺序、状态管理等。
  2. 丰富的工具集成: 预置或允许轻松集成各种工具,如网络搜索、代码执行、数据库操作、API调用等,极大地扩展了Agent的能力边界。
  3. 与大模型解耦: 框架本身通常不绑定特定大模型,可以灵活接入 OpenAI GPT、DeepSeek、通义千问等多种LLM作为“大脑”,方便根据成本、性能、合规性进行选择。
  4. 易于开发与部署: 提供清晰的API和开发规范,降低了构建复杂Agent系统的门槛。许多框架还提供了Web UI,方便进行交互测试和监控。

1.3 Agent 开发的典型应用场景与商业价值

理解场景能更好地驱动学习目标。Agent技术可以应用于:

  • 自动化办公: 自动处理邮件、整理会议纪要、生成周报、进行数据透视与分析。
  • 智能客服与销售: 不仅回答问题,还能主动查询订单、推荐产品、完成售后流程。
  • 个性化助手: 深度理解用户习惯,管理个人日程、健康数据,提供定制化建议。
  • 代码助手与DevOps: 理解需求生成代码、自动进行代码审查、执行部署脚本。
  • 内容创作与营销: 根据热点自动生成文章大纲、创作视频脚本、进行多平台发布。

其商业变现路径也较为清晰:可以开发成SaaS服务(按调用次数或订阅收费)、私有化部署解决方案(针对企业客户)、集成到现有产品中作为增值功能,或是开发垂直领域的专业Agent应用(如法律、金融、医疗咨询助手)。

2. 开发环境准备与 Codex 框架安装

工欲善其事,必先利其器。我们将在一个干净的环境下,一步步搭建起Agent开发所需的基础设施。

2.1 基础环境配置

我们选择 Python 作为主要开发语言,这是目前AI领域最主流的语言,生态丰富。

  1. 安装 Python: 确保你的系统已安装 Python 3.8 或更高版本。推荐使用 Python 3.10,它在兼容性和性能上比较均衡。

    # 在终端或CMD中检查Python版本 python --version # 或 python3 --version

    如果未安装,请前往 Python官网 下载安装,并记得勾选“Add Python to PATH”。

  2. 安装 Git: Codex 框架通常托管在 GitHub 上,需要 Git 来克隆代码库。

    # 检查是否安装 git --version

    未安装则从 Git官网 下载安装。

  3. 推荐使用虚拟环境: 为避免包依赖冲突,强烈建议使用venvconda创建独立的Python环境。

    # 使用 venv (Windows) python -m venv agent_env agent_env\Scripts\activate # 激活环境 # 使用 venv (MacOS/Linux) python3 -m venv agent_env source agent_env/bin/activate # 激活环境 # 激活后,命令行提示符前应显示 (agent_env)

2.2 安装 Codex 框架

由于“Codex”可能指代不同的具体项目,这里我们以一个典型的、功能完整的开源AI Agent框架“LangChain”“AutoGen”的安装为例。它们的理念和Codex类似,都是优秀的智能体开发框架。我们以 LangChain 为例,因为它生态极其庞大,教程丰富。

  1. 使用 pip 安装 LangChain

    # 确保已在虚拟环境中 pip install langchain

    这安装了最核心的库。但LangChain的强大在于其“生态工具”,我们还需要安装一些常用组件。

  2. 安装大语言模型接口: 以使用 OpenAI 的模型为例(你需要有自己的API Key)。

    pip install openai

    如果你打算使用其他模型,如 DeepSeek,则安装对应的SDK,例如pip install deepseek-api(请以官方文档为准)。

  3. 安装工具链与可选组件

    # 安装用于网页搜索的工具 pip install duckduckgo-search # 安装用于数学计算和代码执行的工具(谨慎使用,注意安全) pip install numexpr # 安装用于向量数据库(记忆)支持的包 pip install chromadb # 安装用于Web UI的组件(可选,方便调试) pip install langchain-community streamlit

    安装完成后,可以通过pip list查看已安装的包。

2.3 配置 API 密钥与环境变量

为了让你开发的Agent能调用大模型,需要配置API密钥。切勿将密钥直接硬编码在代码中!

  1. 获取API Key

    • OpenAI: 访问 OpenAI Platform 创建密钥。
    • DeepSeek: 访问 DeepSeek 开放平台 创建密钥。
  2. 设置环境变量(推荐)

    • Windows (PowerShell):
      $env:OPENAI_API_KEY = "你的-openai-api-key" # 或 $env:DEEPSEEK_API_KEY = "你的-deepseek-api-key"
    • MacOS/Linux (Terminal):
      export OPENAI_API_KEY='你的-openai-api-key' export DEEPSEEK_API_KEY='你的-deepseek-api-key'
      为了使环境变量永久生效,可以将上述export命令添加到~/.bashrc~/.zshrc文件中,然后执行source ~/.bashrc
  3. 在代码中读取环境变量

    import os from langchain_openai import ChatOpenAI from langchain_deepseek import ChatDeepSeek # 方式1:读取环境变量 openai_api_key = os.getenv("OPENAI_API_KEY") deepseek_api_key = os.getenv("DEEPSEEK_API_KEY") # 方式2:初始化模型(以OpenAI为例) llm = ChatOpenAI( model="gpt-3.5-turbo", # 或 "gpt-4" api_key=openai_api_key, temperature=0.7 # 控制创造性,0-1之间,越高越随机 )

3. Agent 核心组件与原理拆解

现在,我们来深入LangChain框架,理解构建一个Agent所需的几个核心“积木”。

3.1 大脑:大语言模型 (LLM)

LLM是Agent的“大脑”,负责理解、规划和决策。在LangChain中,它被抽象为LLMChatModel对象。

from langchain_openai import ChatOpenAI # 初始化一个Chat模型,这是与Agent对话的基础 llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0) # temperature=0 使输出更确定,适合执行任务;temperature=0.7~0.9 更适合创意性对话。

3.2 手脚:工具 (Tools)

工具是Agent的“手脚”,是它作用于外部世界的方式。一个工具本质上是一个函数,有明确的输入和输出描述,以便LLM理解何时以及如何使用它。

from langchain.agents import Tool from langchain.utilities import DuckDuckGoSearchAPIWrapper # 1. 定义一个工具函数 def get_current_time(query: str) -> str: """当用户询问当前时间时调用此工具。输入应为空字符串或‘time’。""" from datetime import datetime return f"当前时间是:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}" # 2. 使用LangChain内置工具包装器 search = DuckDuckGoSearchAPIWrapper() # 3. 创建Tool对象列表 tools = [ Tool( name="Current Time", # 工具名称,LLM通过名称识别 func=get_current_time, description="当需要知道当前的日期和时间时使用此工具。输入应为空字符串。" ), Tool( name="Web Search", func=search.run, description="当需要回答关于实时信息、最新事件或未知领域的问题时使用此工具。输入是一个搜索查询词。" ), ]

关键点description字段至关重要!LLM完全依赖这个描述来判断是否以及如何调用工具。描述必须清晰、准确。

3.3 调度中心:智能体执行器 (AgentExecutor)

这是Agent的“调度中心”或“操作系统”。它接收用户输入,协调LLM进行思考(决定使用哪个工具),调用工具,获取结果,再将结果反馈给LLM进行下一步思考,直到任务完成或达到步骤限制。

from langchain.agents import initialize_agent, AgentType # 初始化一个智能体 agent = initialize_agent( tools=tools, # 上一步定义的工具列表 llm=llm, # 大脑 agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, # 一种经典的Agent类型,擅长推理和调用工具 verbose=True, # 开启详细日志,方便看到Agent的“思考过程” handle_parsing_errors=True, # 处理解析错误,更健壮 max_iterations=5, # 最大执行步骤,防止无限循环 early_stopping_method="generate" # 停止条件 )

ZERO_SHOT_REACT_DESCRIPTION是一种基于 ReAct (Reason + Act) 范式的Agent,它会在调用工具前输出一个“Thought”(思考),解释为什么选择这个工具。

4. 实战:手把手构建你的第一个智能体

让我们结合以上所有知识,构建一个能查询时间和搜索网络的简易智能体。

4.1 项目结构与代码

创建一个新的Python文件,例如my_first_agent.py

# my_first_agent.py import os from datetime import datetime from langchain_openai import ChatOpenAI from langchain.agents import Tool, initialize_agent, AgentType from langchain.utilities import DuckDuckGoSearchAPIWrapper # --- 第1步:设置环境变量(确保你已提前设置好)--- # 假设 OPENAI_API_KEY 已在环境变量中 # --- 第2步:初始化大脑(LLM)--- print("正在初始化AI大脑...") llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0) # --- 第3步:定义工具(手脚)--- print("正在加载工具...") # 工具1:获取时间 def get_time(query: str) -> str: """返回当前的日期和时间。输入通常为空或‘time’.""" return f"当前日期和时间是:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}" # 工具2:网络搜索(使用DuckDuckGo) search = DuckDuckGoSearchAPIWrapper() # 将函数包装成LangChain的Tool对象 tools = [ Tool( name="Get_Current_Time", func=get_time, description="当用户询问现在几点、今天日期或当前时间时使用。输入可以忽略或为‘time’." ), Tool( name="Search_Internet", func=search.run, description="当问题涉及最新新闻、未知事实、实时信息或需要从网上查找资料时使用。输入是一个搜索关键词或问题。" ), ] # --- 第4步:创建智能体执行器--- print("正在创建智能体...") agent = initialize_agent( tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True, # 非常重要!打开以观察Agent的思考链 handle_parsing_errors=True, max_iterations=4 ) # --- 第5步:与智能体对话--- print("\n===== 你的智能体已上线!输入‘quit’退出 =====") while True: user_input = input("\n你: ") if user_input.lower() == 'quit': print("智能体:再见!") break print("\n--- 智能体开始思考 ---") try: response = agent.run(user_input) print(f"\n智能体: {response}") except Exception as e: print(f"\n抱歉,处理时出现错误: {e}")

4.2 运行与效果演示

在终端中,激活你的虚拟环境,运行这个脚本:

python my_first_agent.py

你会看到类似以下的交互过程(verbose=True让你能看到内部思考):

正在初始化AI大脑... 正在加载工具... 正在创建智能体... ===== 你的智能体已上线!输入‘quit’退出 ===== 你: 现在几点了? --- 智能体开始思考 --- > Entering new AgentExecutor chain... Thought: 用户问现在几点了,我需要使用获取时间的工具。 Action: Get_Current_Time Action Input: time Observation: 当前日期和时间是:2023-10-27 14:30:15 Thought: 我已经得到了当前时间,可以直接回答用户。 Final Answer: 现在是2023年10月27日下午2点30分15秒。 智能体: 现在是2023年10月27日下午2点30分15秒。 你: 今天北京天气怎么样? --- 智能体开始思考 --- > Entering new AgentExecutor chain... Thought: 用户问的是实时天气信息,我需要搜索网络来获取最新数据。 Action: Search_Internet Action Input: 北京 今天 天气 Observation: 北京今天晴转多云,气温5-15摄氏度,西北风3-4级... Thought: 我已经搜索到了北京的天气信息,可以总结给用户。 Final Answer: 根据最新信息,北京今天(10月27日)天气晴转多云,气温在5到15摄氏度之间,西北风3-4级。 智能体: 根据最新信息,北京今天(10月27日)天气晴转多云,气温在5到15摄氏度之间,西北风3-4级。

代码解读

  • Thought: Agent 根据你的问题和工具描述,决定下一步做什么。
  • Action: 它选择要使用的工具。
  • Action Input: 它生成调用该工具的输入参数。
  • Observation: 工具执行后返回的结果。
  • 循环:Agent 根据Observation再次Thought,直到它认为可以给出Final Answer

4.3 核心机制解析:ReAct 框架

我们使用的ZERO_SHOT_REACT_DESCRIPTIONAgent 遵循 ReAct 模式。这是一个非常重要的范式:

  • Reason (思考): LLM分析当前情况(用户问题、已有信息、可用工具),决定下一步行动。
  • Act (行动): LLM选择一个工具并生成调用参数。
  • 观察结果: 工具执行,返回结果。
  • 循环: 将结果作为新的上下文,再次进行Reason,直到问题解决。

这种“思考-行动-观察”的循环,使得Agent能够处理远超单次问答的复杂任务。

5. 进阶实战:构建多功能自动化办公智能体

现在,我们提升难度,构建一个更实用的Agent,它能读取本地文件内容并进行总结。

5.1 新增文件读取工具

我们需要安装额外的库来处理文件。

pip install python-docx PyPDF2 # 用于读取Word和PDF文件

修改my_first_agent.py,增加文件读取工具:

# ... (之前的导入保持不变) import PyPDF2 from docx import Document # --- 在 tools 列表中添加新工具 --- def read_file_content(file_path: str) -> str: """读取指定文本文件、PDF文件或Word文件的内容。输入是文件的完整路径。""" content = "" try: if file_path.endswith('.txt'): with open(file_path, 'r', encoding='utf-8') as f: content = f.read() elif file_path.endswith('.pdf'): with open(file_path, 'rb') as f: reader = PyPDF2.PdfReader(f) for page in reader.pages: content += page.extract_text() + "\n" elif file_path.endswith('.docx'): doc = Document(file_path) for para in doc.paragraphs: content += para.text + "\n" else: content = f"错误:不支持的文件格式 '{file_path}'。请提供 .txt, .pdf 或 .docx 文件。" except FileNotFoundError: content = f"错误:找不到文件 '{file_path}'。请检查路径。" except Exception as e: content = f"读取文件时出错:{e}" # 限制返回内容长度,避免上下文过长 return content[:3000] if len(content) > 3000 else content # 更新 tools 列表 tools = [ Tool( name="Get_Current_Time", func=get_time, description="当用户询问现在几点、今天日期或当前时间时使用。输入可以忽略或为‘time’." ), Tool( name="Search_Internet", func=search.run, description="当问题涉及最新新闻、未知事实、实时信息或需要从网上查找资料时使用。输入是一个搜索关键词或问题。" ), Tool( # 新增的文件读取工具 name="Read_File", func=read_file_content, description="当用户要求读取、总结或分析一个本地文件的内容时使用。输入必须是文件的绝对路径或相对路径(例如:./report.pdf 或 C:/docs/note.txt)。支持 .txt, .pdf, .docx 格式。" ), ] # ... (后续初始化agent和对话循环保持不变)

5.2 运行进阶版智能体

准备一个sample.txt文件放在脚本同目录,内容随意。然后运行Agent。

你: 请帮我总结一下 ./sample.txt 文件的主要内容。 --- 智能体开始思考 --- > Entering new AgentExecutor chain... Thought: 用户要求总结一个本地文件的内容。我需要使用文件读取工具来获取文件内容。 Action: Read_File Action Input: ./sample.txt Observation: (这里是sample.txt文件的实际内容)... 本项目旨在开发一个智能销售助手,主要功能包括客户数据分析、自动生成跟进邮件、以及预测销售趋势... Thought: 我已经获取了文件内容。现在需要总结它。我可以直接基于内容生成一个总结。 Final Answer: 该文件描述了一个“智能销售助手”项目的目标。其主要功能包括:1. 分析客户数据;2. 自动生成客户跟进邮件;3. 预测未来的销售趋势。项目旨在利用自动化提升销售效率。 智能体: 该文件描述了一个“智能销售助手”项目的目标。其主要功能包括:1. 分析客户数据;2. 自动生成客户跟进邮件;3. 预测未来的销售趋势。项目旨在利用自动化提升销售效率。

现在,你的Agent已经具备了感知(读取文件)、规划(先读后总结)、决策(选择Read_File工具)、执行(调用函数并返回结果)的完整能力。你可以继续为其添加更多工具,如写文件、发邮件、调用数据库API等,使其能力不断增强。

6. 常见问题与排查指南 (FAQ)

在开发和使用Agent过程中,你一定会遇到各种问题。以下是高频问题及解决方案。

问题现象可能原因排查与解决思路
运行报错:ModuleNotFoundError: No module named ‘langchain’1. 未安装LangChain。
2. 未在正确的虚拟环境中运行。
1. 执行pip install langchain
2. 在终端确认已激活虚拟环境(命令行前有(env_name))。
报错:AuthenticationErrorInvalid API Key1. API密钥未设置或错误。
2. 环境变量未生效。
3. 账户余额不足或权限问题。
1. 检查密钥是否正确复制,无多余空格。
2. 在代码中print(os.getenv(‘OPENAI_API_KEY’))看是否输出。
3. 登录对应平台检查额度与状态。
Agent 陷入循环,不停调用工具不停止1.max_iterations设置过高或未设置。
2. 工具描述不清晰,导致LLM无法做出最终决策。
3. 任务本身过于开放。
1. 设置合理的max_iterations(如5-10)。
2. 优化工具description,明确其用途和输出。
3. 给Agent更明确的指令,例如“请用一句话总结”。
Agent 选择了错误的工具工具的描述 (description) 不够准确或与其他工具区分度低。仔细打磨工具描述,确保每个工具的职责唯一、清晰。例如,“获取时间”和“搜索网络”的描述必须截然不同。
处理文件时出现编码错误或读取失败1. 文件路径错误。
2. 文件被其他程序占用。
3. PDF文件是扫描版(图片),无法提取文字。
1. 使用绝对路径或确认相对路径正确。
2. 关闭占用文件的程序。
3. 对于扫描PDF,需要使用OCR库(如pytesseract),但这更复杂。
网络搜索工具返回空或错误信息1. 网络问题。
2. DuckDuckGo搜索API限制或变更。
3. 查询词过于复杂。
1. 检查网络连接。
2. 考虑使用其他搜索包装器,如SerpAPI(需注册和API Key)。
3. 简化搜索查询词。
错误:The model ‘gpt-5.6-sol’ is not supported在配置Codex或其他框架时,错误地指定了不存在的模型名称。确认你使用的框架和模型兼容性。使用官方支持的模型名,如gpt-3.5-turbo,gpt-4,deepseek-chat等。
cc switch local proxy failed等网络代理错误系统或代码配置了代理,但与当前网络环境冲突。1. 在代码中临时取消代理设置:import os; os.environ[‘NO_PROXY’] = ‘*’(不推荐长期)。
2. 检查并修正代码或环境变量中的代理配置。

7. 工程最佳实践与进阶方向

当你掌握了基础开发后,以下实践能帮助你构建更稳健、更强大的智能体系统。

7.1 设计清晰可靠的工具

  1. 单一职责: 每个工具只做一件事,并做好。这能让LLM更容易理解和使用。
  2. 健壮的输入验证: 在工具函数内部,对输入参数进行类型和有效性检查,返回明确的错误信息,避免整个Agent崩溃。
  3. 详细的描述description是工具与LLM沟通的唯一桥梁。用自然语言清晰说明:“在什么情况下用我?”、“我需要的输入是什么格式?”、“我会输出什么?”。
  4. 安全边界: 对于执行代码、访问数据库、删除文件等危险操作,必须在工具内部加入权限检查、确认机制或沙箱环境。

7.2 优化智能体性能与成本

  1. 选择合适的模型: 任务简单时,使用gpt-3.5-turbo成本更低、速度更快。任务复杂、需要深度推理时,再考虑gpt-4
  2. 设置迭代限制: 总是通过max_iterationsmax_execution_time限制Agent的运行,防止意外循环消耗大量token。
  3. 使用记忆(Memory): 为Agent添加对话记忆,让它能记住之前的交互。LangChain提供了ConversationBufferMemory等组件。
    from langchain.memory import ConversationBufferMemory memory = ConversationBufferMemory(memory_key=“chat_history”, return_messages=True) # 在初始化agent时传入 memory=memory
  4. 流式输出与异步: 对于耗时任务,使用异步调用和流式输出提升用户体验。

7.3 架构设计与商业化思考

  1. 模块化: 将工具、Agent配置、业务逻辑分离,便于维护和扩展。
  2. 可观测性: 记录Agent的完整思考链(verbose=True的输出),这对于调试和优化至关重要。可以考虑将其存入日志或数据库。
  3. 商业化路径
    • API服务: 将你的智能体封装成RESTful API或WebSocket服务,按调用次数收费。
    • SaaS平台: 开发一个允许用户通过界面自定义工具和流程的低代码平台。
    • 垂直解决方案: 针对法律、金融、电商等特定行业,深度定制工具和知识库,提供高价值的专业Agent。
    • 私有化部署: 为对数据安全要求高的大客户提供本地部署方案。
  4. 持续学习与迭代: Agent领域发展迅猛,关注 LangChain、AutoGen、CrewAI 等主流框架的更新,不断将新的工具和能力集成到你的系统中。

从环境搭建到核心概念,从第一个“Hello World”智能体到具备文件处理能力的进阶版本,我们完成了一次完整的AI Agent开发入门之旅。这条路的关键在于“动手实践”——不断地定义新工具,设计更复杂的任务流程,观察并优化Agent的思考过程。

真正的精通来自于项目锤炼。接下来,我建议你选择一个你熟悉的小领域(比如自动整理学习笔记、监控商品价格、管理个人待办事项),尝试为你的Agent添加3-5个相关的工具,并设计一个完整的工作流。在这个过程中,你会更深刻地体会到工具描述的艺术、任务分解的难点以及记忆管理的重要性。

AI Agent不是遥不可及的未来科技,它已经是开发者手中强大的生产力工具。希望本文提供的这套“脚手架”,能帮助你快速起步,搭建出真正解决实际问题的智能体,并探索出属于你的技术价值与商业可能。如果在实践中遇到具体问题,欢迎在社区交流,共同探讨。

← 返回列表