各位关注 AI 工程化的朋友,大家好。
最近在梳理大模型 Agent 落地路径时,不少开发者都在讨论DeepSeek Harness这个新名词。它听起来有点像“给 DeepSeek 加了一个外部工具包”,但实际上,Harness 在大模型工程领域有更具体的含义:它负责把模型的推理能力“套”进一个可控制的执行链路中,让模型不只是聊天,而是能调用工具、读取结果、判断下一步动作,最终完成一个真实任务。
本文不会只停留在概念层面。我会从一个开发者的角度,完整拆解 DeepSeek Harness 的定位、核心组成、从 API 调用到 Harness 配置再到可运行示例的全过程,并整理高频报错的排查思路和工程落地建议。无论你是刚接触 DeepSeek API,还是已经在做 Agent 类项目,这篇文章都值得收藏备用。
1. DeepSeek Harness 是什么
1.1 一句话理解 Harness
Harness 直译是“马具、挽具”,引申含义是“把动力源接入工作流的那套连接装置”。在大模型领域,Harness通常指围绕模型能力构建的一套执行框架,它规定模型在什么时候输出、输出之后做什么、工具调用的结果如何回填给模型,以及整个循环在什么条件下终止。
所以 DeepSeek Harness 并不是“DeepSeek 官方新发布的一个模型”,更准确的理解是:它是一套面向 DeepSeek 模型的 Agent 执行框架,或者说是一种工程模式。社区里也有类似的提法,比如 Codex Harness,它同样是把代码生成模型接入自动编码执行环境。
简单来说:
- 直接调用 DeepSeek API,得到的是“模型回复文本”;
- 接入 Harness 之后,得到的是“模型完成任务的结果”。
1.2 它解决了什么问题
直接使用大模型 API 时,很多开发者会遇到这几个问题:
第一,模型无法访问外部数据。你问它“帮我查一下当前目录下最大的三个文件”,它回答不了,因为它没有文件系统权限。
第二,模型无法执行代码。它生成的 Python 脚本是否正确,只能靠你手动复制去跑。
第三,多步任务没有循环控制。例如“分析这个 CSV 文件,然后用 Matplotlib 画图,最后把图保存下来”,这不是一次对话能完成的,需要多次调用模型,不断把中间结果反馈进去。
第四,结果不可验证。模型说“代码已经修复”,但你没有自动化的方式确认修复是否真的通过测试。
DeepSeek Harness 要解决的核心问题,就是把模型从“生成器”变成“执行者”,通过工具注册、结果解析、循环控制和安全策略,让模型能在一个受控环境中完成真实任务。
1.3 常见应用场景
根据我观察到的社区使用情况,DeepSeek Harness 常见的落地场景包括这几类:
- 自动化代码生成:让模型根据需求生成代码,自动执行测试,并根据测试结果自我修复;
- 数据管道调度:模型负责解析自然语言查询,生成 SQL 或 Python 脚本,再交给执行器运行;
- 智能运维脚本:模型根据日志或监控数据,自动生成排查脚本并执行;
- 个人 AI 助手:把文件读写、命令执行、网络请求封装成工具,让模型按需调用。
如果你之前接触过 OpenAI 的 Function Calling 或 Agent 模式,那么 Harness 可以理解为更工程化、更强调执行链路闭环的一种实现方式。
2. 环境准备与版本说明
在搭建 DeepSeek Harness 之前,需要先准备好基础环境。需要注意,DeepSeek 的 API 和模型版本更新速度比较快,本文示例以常见环境为例,重点演示配置思路,版本需要根据你的项目实际情况调整。
2.1 基础环境要求
建议使用以下环境:
- 操作系统:Windows 10/11,macOS 12+,或 Ubuntu 20.04+;
- 编程语言版本:Python 3.9 以上,推荐 3.10 或 3.11;
- 包管理工具:pip 或 conda;
- 大模型 API:DeepSeek API,需要提前在开放平台注册并创建 API Key;
- 可选:Node.js 18+(如果使用 TypeScript 版本实现)。
2.2 获取 DeepSeek API Key
这一步非常关键。Harness 所有对模型能力的调用,最终都会落到 DeepSeek API 上。
访问 DeepSeek 开放平台,注册账号后,在控制台创建一个 API Key。创建完成后,务必把 Key 保存在安全的位置,例如本地.env文件或环境变量中,不要提交到公共代码仓库。
创建项目目录:
mkdir deepseek-harness-demo cd deepseek-harness-demo创建 Python 虚拟环境:
python -m venv venv source venv/bin/activate # Windows 下执行 venv\Scripts\activate安装依赖:
pip install openai python-dotenv这里使用openaiPython 包,是因为 DeepSeek API 兼容 OpenAI 的接口协议,我们可以通过配置base_url来访问 DeepSeek 的服务,不需要额外引入 SDK。
2.3 目录结构规划
为了后续扩展,建议按下面的结构组织项目:
deepseek-harness-demo/ ├── .env # 存放 API Key ├── requirements.txt # 依赖列表 ├── main.py # 入口文件 ├── harness/ │ ├── __init__.py │ ├── core.py # Harness 核心循环 │ ├── tools.py # 工具注册与执行 │ └── config.py # 配置项 └── tools/ ├── __init__.py └── file_tools.py # 文件操作工具这样一个简单分层可以让后续新增工具变得更方便,也方便做单元测试。
3. Harness 的核心组成与设计思路
3.1 核心组成
无论 Harness 的复杂程度如何,它通常由四部分组成。
第一部分是“模型交互层”。这一层负责和 DeepSeek API 通信,发送用户请求,接收模型回复。由于 DeepSeek API 兼容 OpenAI 协议,所以可以直接复用openai库。
第二部分是“工具层”。工具层定义模型可以调用哪些能力,比如“执行 Python 代码”“读取文件”“运行 Shell 命令”。每个工具需要有名称、描述、输入参数定义,以及对应的执行函数。
第三部分是“循环控制层”。这是 Harness 的引擎核心,负责:
- 把用户请求和系统提示词一起发送给模型;
- 判断模型回复中是否包含工具调用请求;
- 有工具调用请求时,执行对应工具,并把结果返回给模型;
- 没有工具调用请求时,把模型最终回复返回给用户。
第四部分是“安全与审计层”。它负责限制工具的执行范围、记录调用日志、设置超时和重试机制。实际项目中这一层非常重要,尤其是生产环境。
3.2 与直接调用 API 的对比
直接调用 API 的代码如下:
from openai import OpenAI client = OpenAI( api_key="sk-xxx", base_url="https://api.deepseek.com" ) response = client.chat.completions.create( model="deepseek-chat", messages=[{"role": "user", "content": "计算 1 到 100 的和"}] ) print(response.choices[0].message.content)这段代码能正常返回“1 到 100 的和是 5050”,但模型并不是真的“计算”了,而是依赖训练时的知识。如果问题换成“统计当前目录下 Python 文件的数量”,模型就无法回答了,因为它看不到文件系统。
接入 Harness 之后,模型可以调用一个run_bash工具来执行ls *.py | wc -l,然后把命令执行结果作为上下文继续推理,最终给出准确答案。
这就是 Harness 的价值:它把“模型的知识”和“环境的能力”连接起来了。
3.3 “模型即决策者,Harness 即执行框架”这一模式
有一个概念需要区分:DeepSeek Harness 不是要替代 DeepSeek 模型,也不是改变模型本身的推理方式。模型仍然负责理解意图、生成代码和判断结果,Harness 负责的是模型之外的执行环境。
我们可以把它类比成一个“员工和办公系统”的关系:
- 模型是员工,负责思考;
- Harness 是办公系统,负责提供数据、工具和流程;
- 员工决定做什么,办公系统决定能做什么、能查什么、能调用什么。
所以在设计 Harness 时,最重要的问题是:**我们要给模型暴露哪些工具?每个工具允许做什么?不允许做什么?**这决定了 Harness 的能力边界和安全边界。
4. 完整实战:从零搭建一个 DeepSeek Harness 示例
下面我们把上面提到的思路落到代码上。这个示例会实现一个简化的 Harness,支持两个工具:
- 执行 Python 表达式
- 读取本地文件内容
通过这个示例,你可以清晰地看到 Harness 的运行过程。
4.1 第一步:配置 .env 环境变量
在项目根目录创建.env文件:
DEEPSEEK_API_KEY=sk-your-api-key DEEPSEEK_BASE_URL=https://api.deepseek.com DEEPSEEK_MODEL=deepseek-chat这里的DEEPSEEK_MODEL使用的是deepseek-chat。如果你的账号有权限访问其他模型,可以自行调整成对应的模型名称。
4.2 第二步:定义工具层
创建harness/tools.py,定义工具注册机制和执行逻辑。
# 文件路径:harness/tools.py import ast from pathlib import Path def eval_python(expression: str) -> str: """ 计算 Python 表达式,返回字符串结果。 只允许安全的字面量表达式,禁止执行语句。 """ try: # 使用 ast.literal_eval 保证只处理字面量,避免任意代码执行 result = ast.literal_eval(expression) return str(result) except Exception as e: return f"表达式执行失败: {e}" def read_file(file_path: str) -> str: """ 读取文本文件内容,限制在当前项目目录内。 """ # 限制文件路径,防止读取任意系统文件 root = Path(__file__).resolve().parent.parent target = (root / file_path).resolve() if not str(target).startswith(str(root)): return "无权访问该路径" try: with open(target, "r", encoding="utf-8") as f: return f.read()[:2000] except Exception as e: return f"文件读取失败: {e}" # 工具注册表:模型看到的是函数描述,Harness 执行的是这里对应的函数 TOOL_REGISTRY = { "eval_python": { "description": "计算一个 Python 表达式。适合数学计算、字符串处理等场景。", "parameters": { "type": "object", "properties": { "expression": { "type": "string", "description": "要计算的 Python 表达式" } }, "required": ["expression"] }, "function": eval_python, }, "read_file": { "description": "读取当前项目目录下的文本文件。", "parameters": { "type": "object", "properties": { "file_path": { "type": "string", "description": "相对于项目根目录的文件路径" } }, "required": ["file_path"] }, "function": read_file, }, }这里有一个很重要的设计:ast.literal_eval只处理 Python 字面量,不会执行import、__import__、open等操作,这比直接使用eval安全得多。
4.3 第三步:定义 Harness 核心循环
创建harness/core.py,实现 Harness 的主逻辑。
# 文件路径:harness/core.py import json from openai import OpenAI from .tools import TOOL_REGISTRY class DeepSeekHarness: def __init__(self, api_key: str, base_url: str, model: str): self.client = OpenAI(api_key=api_key, base_url=base_url) self.model = model self.messages = [] self.max_iterations = 5 def _build_system_prompt(self) -> str: tools_desc = [] for name, meta in TOOL_REGISTRY.items(): tools_desc.append( f"- {name}: {meta['description']}\n 参数: {json.dumps(meta['parameters'], ensure_ascii=False)}" ) tools_text = "\n".join(tools_desc) return ( "你是一个能调用工具的助手。当用户的问题需要通过计算、文件读取等操作完成时," "请调用合适的工具。工具执行结果会以 system 消息返回给你。\n" "可用工具:\n" + tools_text + "\n" "规则:\n" "1. 如果需要单位转换或计算,优先使用 eval_python 工具。\n" "2. 如果用户提到文件内容,使用 read_file 工具。\n" "3. 工具调用结果会出现在后续消息中,结合结果给出最终回复。" ) def run(self, user_query: str) -> str: self.messages = [ {"role": "system", "content": self._build_system_prompt()}, {"role": "user", "content": user_query}, ] for _ in range(self.max_iterations): response = self.client.chat.completions.create( model=self.model, messages=self.messages, temperature=0.2, ) assistant_message = response.choices[0].message content = assistant_message.content or "" tool_calls = getattr(assistant_message, "tool_calls", None) # 没有工具调用,说明模型已经给出最终答案 if not tool_calls: return content # 把模型的工具调用请求追加到消息列表 self.messages.append({ "role": "assistant", "content": content, "tool_calls": [ { "id": tc.id, "type": "function", "function": tc.function, } for tc in tool_calls ], }) # 逐个执行工具 for tc in tool_calls: function_name = tc.function.name arguments = json.loads(tc.function.arguments or "{}") tool_meta = TOOL_REGISTRY.get(function_name) if tool_meta is None: result = f"未知工具: {function_name}" else: result = tool_meta["function"](**arguments) # 把工具执行结果返回给模型 self.messages.append({ "role": "tool", "tool_call_id": tc.id, "content": str(result), }) return "已达到最大迭代次数,任务未能完成。"这段代码是 Harness 最小可运行版本的核心。请注意,我们并没有实现完整的 Function Calling 协议解析,而是使用了getattr(assistant_message, "tool_calls", None)来做兼容,这是因为不同版本的openai库返回对象结构略有差异,实际编译运行时以你安装的版本为准。
如果你的openai库版本较低,不支持tool_calls字段,可以改用以下兼容方式:
function_call = getattr(assistant_message, "function_call", None)多数情况下,DeepSeek API 已经支持 OpenAI 最新的 Function Calling 协议,推荐将openai库升级到较新版本。
4.4 第四步:编写入口文件
创建main.py:
# 文件路径:main.py import os from dotenv import load_dotenv from harness.core import DeepSeekHarness load_dotenv() api_key = os.getenv("DEEPSEEK_API_KEY") base_url = os.getenv("DEEPSEEK_BASE_URL", "https://api.deepseek.com") model = os.getenv("DEEPSEEK_MODEL", "deepseek-chat") if not api_key: raise ValueError("请先在 .env 文件中配置 DEEPSEEK_API_KEY") harness = DeepSeekHarness( api_key=api_key, base_url=base_url, model=model, ) if __name__ == "__main__": query = "计算 12345 * 6789 的结果" print("用户问题:", query) answer = harness.run(query) print("模型回答:", answer)4.5 第五步:运行与验证
执行:
python main.py预期输出:
用户问题: 计算 12345 * 6789 的结果 模型回答: 12345 * 6789 = 83810205这里模型并不是直接“记住”了答案,而是 Harness 识别到这是一个计算任务,调用eval_python工具得到结果,再基于结果组织回答。
为了验证 Harness 的工具调用链路生效,可以在eval_python里加一行调试输出:
def eval_python(expression: str) -> str: print(f"[工具调用] eval_python 接收参数: {expression}") ...重新运行后,控制台会显示工具被调用的日志,这就说明模型已经不仅仅是文本回复,而是真正进入了“思考-调用-获得结果-再回答”的循环。
再测试文件读取能力。在项目根目录创建一个测试文件:
echo "hello from harness" > demo.txt修改main.py中的 query:
query = "读取 demo.txt 文件内容,并告诉我文件里写了什么"运行后,模型会先调用read_file工具,读取内容后再回答。
4.6 扩展:让模型生成可执行脚本
上面的示例只覆盖了简单的工具调用。更贴近真实 Agent 场景的是:让模型生成一段 Python 代码,Harness 负责执行代码并返回结果。
这里涉及一个安全取舍。如果完全信任模型生成的代码,直接使用exec()存在较大风险。作为开发示例,可以建立一个“沙箱工具”,把代码执行限制在某个隔离目录内。
# 文件路径:harness/tools.py import subprocess import tempfile import os def run_python_code(code: str) -> str: """ 执行一段 Python 代码(仅用于本地演示)。 注意:生产环境应使用 Docker 或沙箱执行,禁止直接 exec 不受信任代码。 """ with tempfile.TemporaryDirectory() as tmpdir: script_path = os.path.join(tmpdir, "script.py") with open(script_path, "w", encoding="utf-8") as f: f.write(code) try: result = subprocess.run( ["python", script_path], capture_output=True, text=True, timeout=10, ) if result.returncode == 0: return result.stdout else: return f"执行错误: {result.stderr}" except subprocess.TimeoutExpired: return "执行超时"这个工具的原理是:把模型生成的代码写入临时文件,再用subprocess新起一个进程执行,同时设置超时时间,避免模型代码死循环拖垮主程序。
注册到TOOL_REGISTRY:
"run_python_code": { "description": "执行一段 Python 代码,返回代码的标准输出。适合用代码解决实际问题的场景。", "parameters": { "type": "object", "properties": { "code": { "type": "string", "description": "要执行的 Python 代码" } }, "required": ["code"] }, "function": run_python_code, },然后测试一个更复杂的问题:
query = "写一个 Python 代码,计算文件 demo.txt 的行数,并输出结果。"模型会生成类似如下的代码,并由 Harness 执行:
with open('demo.txt', 'r', encoding='utf-8') as f: lines = f.readlines() print(len(lines))这样,Harness 就把“意图理解”“代码生成”“代码执行”“结果回传”四个环节串联起来了。
5. 常见问题与排查思路
在实际运行 DeepSeek Harness 的过程中,新手最容易遇到下面这些问题。
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
| 请求返回 401 Unauthorized | API Key 错误、未配置环境变量 | 检查.env文件和load_dotenv()是否执行 |
| 返回 404 Not Found | base_url配置错误或模型名不可用 | 确认 DeepSeek API 地址和模型名称 |
| 模型没有调用工具 | 系统提示词不够明确,或参数传递格式不符 | 在提示词中强化“必须使用工具完成任务”的描述 |
| 工具调用报错“未知工具” | 函数名与注册表 key 不一致 | 检查TOOL_REGISTRY中的 key 和模型返回的 function name 是否匹配 |
| 执行耗时过长 | 模型多次循环调用工具 | 设置max_iterations上限,控制在 5~10 次 |
| 文件读取越权 | read_file没有做路径限制 | 使用resolve()校验路径是否在项目根目录内 |
| openai 库版本兼容问题 | 不同版本tool_calls字段有差异 | 升级openai到新版本,或兼容处理function_call |
| 响应内容不稳定 | 模型温度参数偏高 | 在调用中设置temperature=0.2或更低 |
5.1 模型不调用工具怎么办
这是最常见的现象。根本原因通常不是模型能力问题,而是系统提示词中没有明确说明“什么时候必须调用工具”。
建议在_build_system_prompt中使用强约束:
如果用户的问题需要通过代码、文件、计算、命令来完成,你必须先调用对应工具,不要凭空回答。只有工具执行结果返回后,你才能给出最终答案。同时,可以在第一次调用时检查返回的 assistant message 内容,确认模型选择的是“直接回复”还是“工具调用”。
5.2 工具执行结果为空怎么办
有些 Python 脚本执行后没有标准输出,但执行成功了。Harness 会把空字符串返回给模型,模型可能不知道发生了什么。
解决方案:在工具函数里约定,如果没有输出,返回一个明确的成功标记:
return result.stdout if result.stdout else "执行成功(无输出)"5.3 API 超时怎么处理
在DeepSeekHarness.run中,可以为 API 调用添加超时时间:
response = self.client.chat.completions.create( model=self.model, messages=self.messages, temperature=0.2, timeout=30, # 30 秒超时 )同时建议给工具执行函数也加上超时,比如上面subprocess.run中的timeout=10。
5.4 如何观察调用过程
可以在工具函数中增加日志:
import logging logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s") logger = logging.getLogger(__name__)在每个工具被调用时记录参数,在run的循环中记录当前是第几次迭代。这样排错会快很多。
6. 最佳实践与工程建议
6.1 明确工具边界
Harness 的能力边界就是工具列表的边界。模型只能调用你主动注册的工具,所以不要把危险操作暴露成工具,除非有严格的权限控制。
建议:
- 文件读取工具限制访问根目录;
- 命令执行工具禁止以 root 权限运行;
- 网络请求工具限制允许访问的域名范围;
- 生产环境使用 Docker 容器隔离模型生成的代码执行。
6.2 把系统提示词和工具描述当成代码来维护
很多开发者把系统提示词当成“随手写的字符串”,但这其实是最该版本化的内容。建议把系统提示词、工具描述放到独立的配置文件中,进入版本管理。因为工具描述变了,模型的调用行为也会变,这本身就是一部分业务逻辑。
6.3 控制循环次数和成本
Harness 每多一次工具调用,就会多消耗一次模型 API 调用。假设一个任务需要 5 次工具调用,意味着至少 6 次 API 请求。成本控制和循环次数直接相关。
建议:
self.max_iterations = 5 # 不要设置过大同时记录每次调用的 token 消耗,方便事后分析:
usage = response.usage print(f"本轮消耗 prompt_tokens={usage.prompt_tokens}, completion_tokens={usage.completion_tokens}")6.4 重视输出可验证性
在生产环境中,不要直接信任模型的最终回答。Harness 应该返回结构化的结果,比如:
{ "answer": "83810205", "tool_calls": [ {"name": "eval_python", "arguments": "12345 * 6789", "result": "83810205"} ], "iterations": 2 }这样上层系统可以对工具调用结果做校验,比如计算任务可以直接校验结果数值,文件任务可以校验文件是否存在。
6.5 安全第一:不要直接 exec
我见过不少示例代码直接使用exec(model_generated_code)来执行模型生成的代码。这在本地学习时可以,但绝不能直接用于生产环境。模型生成的代码可能包含危险的系统调用、无限循环、或者访问敏感数据。
更安全的方案是:
- 使用 Docker 容器执行;
- 使用
subprocess+ 超时 + 非特权用户; - 对文件系统、网络、环境变量做最小化授权;
- 所有执行日志留存,便于审计。
6.6 日志与审计
所有工具调用都应该记录日志,至少包含:
- 用户原始请求;
- 模型生成的工具调用参数;
- 工具执行结果;
- 迭代轮次;
- 总 token 消耗。
这样当模型给出错误答案时,你可以回溯是哪一步出了问题。
7. 从 Harness 到 Agent 的进阶方向
7.1 从单工具到多工具协作
上面的示例是单个工具调用。真实项目中,模型可能需要先调用搜索工具,再调用代码执行工具,最后调用写文件工具。多工具协作的关键在于:工具参数的传递是否顺畅、模型是否能根据前一个工具的结果决定下一个工具的参数。
建议把工具执行结果设计成结构化数据,而不是纯文本。例如读取文件返回的不只是字符串,还包含文件路径、文件大小、读取耗时等元数据,这样模型能做出更准确的判断。
7.2 引入“反思”机制
当工具执行报错时,Harness 可以直接把错误信息返回给模型,让模型自己修正。这就是“自我反思”模式。
例如,模型生成了一段有语法错误的代码,工具返回报错信息,下一次模型调用时会看到错误内容,并重新生成修复后的代码。这个循环就是我们常说的“Agent 自愈能力”。
在代码层面,只需要确保工具的错误信息足够详细:
return f"执行错误,退出码: {result.returncode}\n错误详情:\n{result.stderr}"7.3 接入 Codex 模式的启发
最近的社区讨论里,Codex Harness和DeepSeek Harness经常被并列提及。Codex 是 OpenAI 的编码智能体,它之所以能完成较长的编码任务,就是因为有一个精心设计的 Harness:模型生成代码、环境执行测试、错误信息回填、模型修复代码,如此循环直到测试通过。
DeepSeek Harness 也可以套用类似模式。比如:
- 模型读取需求文档;
- 模型生成项目代码;
- Harness 运行测试用例;
- 测试失败时把报错信息给模型;
- 模型修复代码,再次运行测试。
这个循环非常适合自动化编码和重构场景,也是 Harness 模式最有价值的地方。你不需要等待官方发布什么“完整版 Harness”,自己动手实现一个最小版本就能跑通闭环。
7.4 多模态和插件化扩展
如果你后续想扩展 Harness 能力,可以从这几个方向入手:
- 增加更多工具类型:数据库查询、API 请求、文件上传、邮件发送;
- 插件化设计:让每个工具作为独立插件加载,通过配置文件决定启用哪些;
- 多模型切换:Harness 不绑定 DeepSeek 一个模型,只需修改
base_url和model字段,即可切换到其他兼容接口的模型服务。
8. 总结
本文围绕DeepSeek Harness展开,梳理了 Harness 的概念、核心组成、与直接调用 API 的区别,并手写了一个最小可运行的 Harness 示例。代码涵盖了工具注册、核心循环、文件读取、代码执行等多个环节,你可以直接复制运行,也可以基于它扩展出自己的 Agent 框架。
需要记住的关键点有几个:
- Harness 是“执行框架”,不是模型本身;
- 工具定义决定了模型的能力边界;
- 安全控制必须在 Harness 设计时考虑,而不是运行后补救;
- 循环次数、超时、日志是 Harness 的三个基础指标;
- 模型生成代码的执行要做到沙箱化,禁止直接信任。
下一步,建议你在本地部署 DeepSeek 相关环境时,先跑通本文示例,然后尝试增加一个工具,比如“获取当前时间”或“读取目录列表”,感受一下模型从“文字聊天”到“任务执行”的转变。再往后,可以研究如何将 Harness 与 Docker 沙箱结合,实现更完整、更安全的编码 Agent。
如果本文对你有帮助,可以收藏备用,后续在实际搭建过程中遇到问题,也欢迎在评论区讨论。