资讯动态

ax:基于CLI与Kubernetes的Agentic编排实战指南

发布时间:2026/9/26 23:28:41 来源:尧图企业网站定制
1. 从“ax”这个标题说起一个被低估的Agentic编排入口第一次看到“ax”这个标题很多人会以为是某个命令行工具的缩写或者某个内部项目的代号。但把关键词摊开来看——ax、agentic、orchestration、kubernetes、cli——这几个词凑在一起指向的其实是一个非常具体的场景用一套轻量级的命令行入口把Agentic能力编排进Kubernetes集群的日常运维和任务调度里。我最初接触这个方向是因为团队里有一堆零散的脚本有的负责拉取模型推理结果有的负责在集群里跑批处理任务有的负责把日志汇总到某个地方。每个脚本单独跑都没问题但一旦要把它们串成一条“有判断能力”的流水线就变得非常痛苦。比如一个任务失败了需要根据错误类型决定是重试、回滚还是通知人工再比如某个步骤的输出需要动态决定下一步走哪个分支。这些逻辑用传统的Shell脚本或者CI/CD的YAML去写写到最后就是一堆if-else嵌套维护成本极高。“ax”这个标题背后的核心价值就是试图用Agentic Orchestration的思路来解决这类问题。它不是要替代Kubernetes也不是要重新发明一套调度系统而是在Kubernetes之上加一层“有决策能力”的编排层。你可以把它理解成一个命令行驱动的Agent调度器你告诉它目标是什么它自己决定怎么拆解任务、怎么调用工具、怎么在集群里分配资源、怎么处理失败。这篇文章适合谁看如果你已经在用Kubernetes跑一些自动化任务但觉得现有的Job、CronJob、Argo Workflows之类的工具在“动态决策”方面不够灵活或者你在尝试把LLM驱动的Agent接入到实际的运维流程里但不知道从哪里下手再或者你只是对“agentic orchestration”这个概念感兴趣想看看它在真实场景里长什么样——那这篇内容应该能给你一些可以直接参考的东西。我会从整体设计思路开始拆然后讲核心细节和实操要点接着给出一套完整的落地流程最后把我在实际使用中踩过的坑和排查技巧整理出来。全程不绕弯子能抄的配置直接给能算的参数直接算。2. 整体设计与思路拆解为什么是CLI Kubernetes Agentic2.1 为什么不用现成的Workflow引擎市面上已经有Argo Workflows、Tekton、Kubeflow Pipelines这些成熟的编排工具为什么还要折腾“ax”这种看起来更原始的东西这个问题我一开始也问过自己。后来在实际项目里对比下来发现核心差异在于决策发生的时机和位置。传统的Workflow引擎DAG有向无环图是在提交任务之前就定义好的。你写YAML的时候就已经确定了A步骤之后走B还是走C。虽然Argo支持一些条件判断但那些判断本质上还是静态的你预先写好条件表达式运行时去求值。如果遇到“根据模型输出的语义决定下一步”这种需求就非常别扭。Agentic Orchestration的思路不一样。它把“决策”本身也当作一个可以调度的单元。也就是说DAG不是预先固定的而是在运行过程中由Agent动态生成的。Agent可以根据当前上下文、历史结果、外部状态决定下一步调用哪个工具、传什么参数、要不要并行、要不要等待。“ax”这个CLI工具的设计就是把这个动态决策的过程封装成命令行操作。你不需要写复杂的Python代码去调Kubernetes API也不需要维护一套庞大的Workflow定义。你只需要用ax命令描述“目标”和“可用工具”剩下的交给Agent去编排。2.2 CLI作为入口的取舍为什么是CLI而不是Web UI或者SDK这个问题涉及到使用场景。Agentic编排的很多任务本质上还是运维和工程任务发生在终端里。工程师习惯在终端里敲命令、看日志、调参数。如果强行做一个Web界面反而增加了认知负担。CLI的另一个好处是可组合性。ax命令的输出可以管道给其他工具ax的配置可以放在Git里版本控制ax的调用可以嵌入到现有的Shell脚本或CI流程里。这种“不侵入现有工作流”的特性对于已经在跑Kubernetes的团队来说迁移成本非常低。当然CLI也有它的局限。复杂的可视化编排、多人协作的权限管理、运行状态的实时监控这些用CLI做起来会比较吃力。所以“ax”的定位不是替代所有编排工具而是作为一个轻量级的Agentic入口处理那些传统工具搞不定的动态决策场景。2.3 Kubernetes作为执行底座的理由Agentic编排最终要落地到具体的计算资源上。为什么选Kubernetes而不是直接跑在虚拟机上核心原因是资源隔离和弹性。Agent在执行任务时可能会启动多个并行的子任务每个子任务可能需要不同的运行时环境比如不同的Python版本、不同的依赖库、不同的GPU资源。用Kubernetes的Pod来承载这些子任务天然就获得了隔离性。一个任务崩了不会影响其他任务资源配额可以精确控制镜像可以提前构建好。另外Kubernetes的声明式API和控制器模式非常适合Agentic编排的“期望状态”思路。Agent只需要声明“我需要一个能跑PyTorch的Pod带一张GPU”Kubernetes负责把它调度到合适的节点上。Agent不需要关心节点在哪、怎么分配IP、怎么挂载存储。这种抽象层级的匹配让Agent的编排逻辑可以保持简洁。还有一个实际考虑很多团队已经在Kubernetes上跑了大量服务监控、日志、网络、存储这些基础设施都是现成的。把Agentic编排接进来可以直接复用这些能力不需要重新搭一套。2.4 整体架构的层次划分把上面的思路串起来“ax”的整体架构可以分成四层交互层CLI命令负责接收用户输入、解析参数、展示结果。编排层Agent核心负责任务拆解、工具选择、状态管理、失败处理。执行层Kubernetes适配器负责把Agent的决策翻译成Kubernetes API调用创建Pod、Job、Service等资源。基础设施层Kubernetes集群本身提供计算、存储、网络资源。这四层之间通过明确定义的接口通信。CLI不直接调Kubernetes API而是通过编排层编排层不直接操作Pod而是通过执行层。这种分层的好处是每一层都可以独立替换或扩展。比如你想把执行层从Kubernetes换成Nomad只需要实现一个新的适配器编排层的逻辑不用动。3. 核心细节解析与实操要点Agentic编排到底怎么跑起来3.1 Agent的决策循环与工具抽象Agentic编排的核心是Agent的决策循环。一个典型的循环包含四个步骤观察、思考、行动、反思。观察阶段Agent收集当前上下文上一步的输出是什么、集群状态如何、有没有新的外部事件。思考阶段Agent根据目标和上下文决定下一步做什么。行动阶段Agent调用一个具体的工具比如“创建一个Pod”、“查询某个Job的状态”、“调用一个外部API”。反思阶段Agent评估行动的结果判断是否接近目标是否需要调整策略。“ax”把这个循环封装在内部用户只需要定义两样东西目标和工具集。目标是一个自然语言描述或者结构化的任务定义工具集是一组可调用的函数或命令。工具抽象是这里的关键设计。每个工具需要明确定义名称、描述、输入参数、输出格式、执行方式。描述要足够清晰让Agent能理解什么时候该用这个工具。输入参数要有类型约束避免Agent传错格式。输出格式要结构化方便Agent解析。举个例子一个“创建Kubernetes Job”的工具定义可能是这样的name: create_k8s_job description: 在Kubernetes集群中创建一个Job用于运行批处理任务 parameters: - name: image type: string description: 容器镜像地址 - name: command type: array description: 容器启动命令 - name: gpu_count type: integer description: 需要的GPU数量默认为0 output: type: object properties: job_name: string status: stringAgent在思考阶段会根据当前需求决定是否调用这个工具以及传什么参数。比如它判断需要跑一个GPU任务就会把gpu_count设为1。3.2 Kubernetes资源的动态生成Agent决定要创建一个Job之后执行层需要把这个决策翻译成Kubernetes的YAML。这个过程不是简单的模板填充而是需要根据集群的实际情况做动态调整。比如Agent说“我需要一个带GPU的Pod”执行层需要知道集群里哪些节点有GPU、GPU型号是什么、驱动版本是否匹配、是否需要挂载特定的卷。这些信息不能硬编码在模板里而是要在运行时查询。“ax”的做法是维护一个集群能力清单定期从Kubernetes API同步节点标签、资源配额、存储类等信息。当Agent请求资源时执行层根据能力清单选择最合适的节点选择器和资源请求。这里有一个实操要点资源请求和限制的设置。很多人在创建Job时只设了requests不设limits导致Pod可能占用过多资源影响其他任务。我的经验是对于Agentic编排的场景limits应该比requests略高留出一定的突发空间但不能高太多否则调度器会认为节点资源不足。另一个要点是镜像拉取策略。如果Agent频繁创建Pod每次都拉取镜像会很慢。建议设置imagePullPolicy为IfNotPresent并且提前把常用镜像推送到集群的本地仓库。3.3 状态管理与幂等性保证Agentic编排的一个难点是状态管理。Agent可能因为各种原因中断网络问题、进程被杀、集群故障重启后需要知道之前做到哪一步了。“ax”的状态管理策略是外部化存储。每次Agent做出决策、执行行动、得到结果都会把状态写入一个持久化的存储可以是Kubernetes的ConfigMap、也可以是外部的数据库。重启后Agent从存储中恢复状态继续执行。这里的关键是幂等性。Agent可能会重复执行同一个行动比如重复创建一个同名的Job。如果行动不是幂等的就会出问题。所以每个工具的实现都要考虑幂等性创建Job时先检查是否已存在存在就复用更新配置时使用patch而不是replace删除资源时忽略NotFound错误。我在实际项目里踩过一个坑Agent在创建Job后还没来得及记录状态就崩了。重启后Agent不知道Job已经创建又创建了一个同名的。Kubernetes允许同名Job存在只要不是同一个Job的Pod结果跑了两个重复任务。后来我们在工具实现里加了“创建前先查询”的逻辑并且用Job的generateName加随机后缀来避免冲突。3.4 工具调用的安全边界Agentic编排让Agent有了自主决策的能力但也带来了安全风险。Agent可能会调用一些危险的工具比如删除Pod、修改配置、访问敏感数据。如果没有边界控制后果可能很严重。“ax”的安全策略是工具白名单 参数校验 审批钩子。只有明确注册的工具才能被Agent调用。每个工具的参数都有类型和范围校验比如gpu_count不能超过集群的总GPU数。对于高风险操作可以配置审批钩子Agent调用时先暂停等待人工确认后再继续。审批钩子的实现方式可以很简单Agent把待审批的操作写入一个队列CLI提供一个ax approve命令让用户确认。确认后Agent继续执行。这种方式在自动化程度和安全性之间取得了平衡。注意不要给Agent开放cluster-admin权限。建议为Agent创建一个专用的ServiceAccount只授予它需要的命名空间和资源类型的权限。比如只允许它在特定命名空间创建Job和Pod不允许它修改节点或访问Secret。4. 实操过程与核心环节实现从零搭一套ax编排流程4.1 环境准备与依赖安装先说一下我用的环境Kubernetes v1.26.0这是热词里提到的版本也是目前比较稳定的一个版本。本地开发机是macOS用kubectl连接远程集群。安装ax CLI的方式假设它已经提供了二进制包或者可以通过包管理器安装。如果没有现成的安装包可以从源码构建。构建之前需要确认Go版本假设ax是用Go写的这是CLI工具的常见选择建议用Go 1.21以上。# 检查Go版本 go version # 从源码构建 git clone ax-repo-url cd ax go build -o ax ./cmd/ax # 移动到PATH sudo mv ax /usr/local/bin/安装完成后验证一下ax version如果输出类似“ax v0.1.0”的信息说明安装成功。接下来配置Kubernetes连接。ax默认使用kubectl的kubeconfig所以只要kubectl能正常访问集群ax就能用。验证一下kubectl cluster-info kubectl get nodes如果节点列表能正常显示说明连接没问题。4.2 初始化ax配置与集群能力同步ax需要一个配置文件来定义Agent的行为、工具集、存储位置等。初始化命令ax init这个命令会在当前目录生成一个ax.yaml文件。打开看看里面大概包含这些字段agent: name: default-agent max_iterations: 20 timeout: 3600s tools: - name: create_k8s_job enabled: true - name: query_job_status enabled: true - name: delete_k8s_job enabled: false storage: type: configmap namespace: ax-system name: ax-state kubernetes: namespace: default service_account: ax-agent这里有几个关键配置需要根据实际情况调整。max_iterations控制Agent最多循环多少次防止无限循环。timeout控制单个任务的最长执行时间。tools列表里delete_k8s_job默认是禁用的因为删除操作风险较高需要显式启用。配置好后执行集群能力同步ax sync这个命令会查询集群的节点信息、资源配额、存储类等生成一个能力清单缓存到本地。后续Agent做决策时会参考这个清单。4.3 定义一个Agentic任务并提交假设我们要完成一个任务在Kubernetes集群里跑一个模型推理的批处理输入数据在某个PVC里输出结果写到另一个PVC如果推理失败就自动重试最多3次。用ax的方式我们不需要写完整的YAML只需要描述目标和约束ax run \ --goal 在Kubernetes集群中运行模型推理批处理输入数据位于PVC input-data输出写入PVC output-data失败时最多重试3次 \ --tool create_k8s_job \ --tool query_job_status \ --tool delete_k8s_job \ --max-retries 3ax会启动AgentAgent开始决策循环。第一步它需要创建一个Job。它会调用create_k8s_job工具传入镜像地址、命令、挂载的PVC等信息。这些信息一部分来自用户的goal描述一部分来自集群能力清单。创建Job后Agent进入等待状态定期调用query_job_status检查Job状态。如果Job成功完成Agent结束任务。如果Job失败Agent判断重试次数是否用完没用完就删除旧Job、创建新Job。整个过程可以在终端里实时看到[ax] Agent started, goal: 在Kubernetes集群中运行模型推理批处理... [ax] Iteration 1: 创建Job inference-job-001 [ax] Job created, waiting for completion... [ax] Job status: Running [ax] Job status: Failed (exit code 1) [ax] Retry 1/3: 删除Job inference-job-001创建Job inference-job-002 [ax] Job status: Running [ax] Job status: Succeeded [ax] Task completed successfully4.4 参数计算与资源选择过程Agent在创建Job时需要决定资源请求。这个决策不是拍脑袋而是基于一些计算。假设我们的推理任务需要处理1000条数据每条数据推理耗时约0.5秒单Pod可以并行处理10条。那么单个Pod的处理时间是1000/10 * 0.5 50秒。如果希望总时间控制在5分钟内可以并行跑2个Pod每个Pod处理500条耗时25秒。GPU需求方面如果模型是7B参数量的FP16推理大约需要14GB显存。一张16GB显存的GPU卡可以跑一个Pod。如果集群里有A100 40GB的卡可以跑两个Pod共享一张卡通过MIG或者时间片。这些计算过程Agent可以根据goal里的描述和集群能力清单自动完成。用户不需要手动指定“我要2个Pod、每个Pod要1张GPU”。Agent会自己算。当然如果用户有特殊要求也可以在goal里明确写出来比如“使用2个并行Pod每个Pod分配1张GPU”。Agent会优先满足用户的显式约束。4.5 状态持久化与恢复测试为了验证状态管理是否可靠我故意在Agent运行过程中杀掉进程然后重新启动看它能不能恢复。# 启动任务 ax run --goal ... # 获取进程ID AX_PID$! # 等待几秒后杀掉 sleep 10 kill -9 $AX_PID # 重新启动 ax resumeax resume命令会从存储中读取上次的状态恢复Agent的上下文。实测下来如果状态写入及时恢复后Agent能准确知道当前进行到哪一步不会重复创建Job。这里有一个细节状态写入的频率。如果每次决策都写开销比较大如果写得太少恢复时可能丢失较多进度。我的经验是在关键行动创建Job、删除Job、更新配置前后各写一次中间的状态检查可以批量写。5. 常见问题与排查技巧实录5.1 Agent卡在某个循环里出不来这是最常见的问题。Agent可能因为目标描述不清晰或者工具返回的结果不符合预期导致它在某个步骤反复循环。排查思路先看ax的日志找到Agent最后几次迭代的决策。如果发现它在重复调用同一个工具、传同样的参数说明它陷入了死循环。解决方法在ax.yaml里调低max_iterations比如从20调到10。同时检查goal描述是否足够明确。如果goal里有歧义Agent可能会理解错。比如“处理数据”这个描述太模糊Agent不知道是读取、转换还是写入。改成“读取PVC input-data中的数据运行推理将结果写入PVC output-data”就清晰多了。另一个技巧是给Agent加“退出条件”。在goal里明确写“如果连续3次失败停止并报告错误”。Agent会把这个条件作为决策的一部分。5.2 Job创建成功但Pod一直PendingAgent创建了Job但Pod一直处于Pending状态说明调度器找不到合适的节点。排查步骤# 查看Pod状态和事件 kubectl describe pod pod-name -n namespace # 查看节点资源 kubectl describe nodes | grep -A 5 Allocated resources常见原因有几个资源请求太高没有节点能满足节点选择器太严格没有节点匹配PVC没有正确挂载导致Pod无法调度。如果是资源请求太高可以让Agent重新计算降低requests。如果是节点选择器问题检查ax的集群能力清单是否过期重新执行ax sync。提示建议在ax配置里开启“调度失败自动降级”选项。当Pod Pending超过一定时间Agent会自动降低资源请求或放宽节点选择器重新创建Job。5.3 工具调用返回权限错误Agent调用Kubernetes API时返回403 Forbidden说明ServiceAccount权限不足。排查# 查看ServiceAccount的权限 kubectl auth can-i create jobs --assystem:serviceaccount:default:ax-agent -n default如果返回no说明需要绑定相应的Role或ClusterRole。创建一个RoleapiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: namespace: default name: ax-agent-role rules: - apiGroups: [batch] resources: [jobs] verbs: [create, get, list, delete] - apiGroups: [] resources: [pods, pods/log] verbs: [get, list]然后绑定给ServiceAccountkubectl create rolebinding ax-agent-binding \ --roleax-agent-role \ --serviceaccountdefault:ax-agent \ --namespacedefault5.4 状态存储ConfigMap过大ax默认用ConfigMap存储状态。ConfigMap有大小限制约1MB如果Agent运行时间很长、状态很多可能会超限。解决方法切换到外部存储。ax支持配置storage.type为redis或postgresql。以Redis为例storage: type: redis address: redis-service:6379 password: db: 0Redis的读写性能比ConfigMap好很多而且没有大小限制。建议在生产环境使用外部存储。5.5 常见问题速查表问题现象可能原因排查命令解决方法Agent无限循环goal描述模糊、max_iterations过高ax logs --tail 50明确goal、调低max_iterationsPod一直Pending资源不足、节点选择器不匹配kubectl describe pod降低requests、重新ax sync403 ForbiddenServiceAccount权限不足kubectl auth can-i绑定Role/ClusterRole状态丢失ConfigMap被覆盖、存储不可用kubectl get configmap切换外部存储Job重复创建状态写入不及时、幂等性缺失ax logs工具实现加幂等检查镜像拉取慢imagePullPolicy为Alwayskubectl describe pod改为IfNotPresent、用本地仓库5.6 几个我踩过的坑第一个坑Agent的决策依赖LLM但LLM的输出不稳定。同样的输入LLM可能给出不同的决策。这在调试时很麻烦因为问题难以复现。后来我们在ax里加了“决策缓存”把每次LLM的输入输出存下来复现问题时可以直接回放。第二个坑Kubernetes API的速率限制。Agent频繁查询Job状态时可能会触发API Server的限流。建议在ax里加一个查询间隔比如每10秒查一次不要每秒都查。同时可以用Watch机制代替轮询减少API调用。第三个坑PVC的挂载权限。Agent创建的Pod默认以root运行但有些PVC的访问模式是ReadWriteOnce多个Pod同时挂载会冲突。建议在goal里明确“使用ReadWriteMany的PVC”或者“串行执行不要并行”。第四个坑日志收集。Agent创建的Job完成后Pod会被清理日志也跟着没了。建议在ax配置里开启“日志持久化”把Pod日志写到外部存储比如S3或者Elasticsearch方便后续排查。6. 工具选型与扩展思路6.1 为什么选Kubernetes原生Job而不是其他在Kubernetes里跑批处理任务有几个选择原生Job、CronJob、Argo Workflows、Tekton。ax选择原生Job作为主要执行单元理由是简单和可控。原生Job的API很简单创建、查询、删除三个操作就够了。Agent不需要理解复杂的Workflow概念。而且Job的控制器逻辑是Kubernetes内置的稳定可靠。Argo Workflows虽然功能强大但它的CRD和控制器增加了系统的复杂度Agent需要额外学习一套API。当然如果任务需要复杂的DAG依赖原生Job就不够了。这时候可以在ax里注册一个“创建Argo Workflow”的工具让Agent在需要时调用。这种可扩展性是ax设计的一个亮点。6.2 扩展自定义工具的步骤假设我们要加一个“发送通知到企业微信”的工具。步骤第一步实现工具的执行逻辑。可以用Go写一个函数也可以用Shell脚本。#!/bin/bash # send_wechat.sh WEBHOOK_URL$1 MESSAGE$2 curl -X POST $WEBHOOK_URL \ -H Content-Type: application/json \ -d {\msgtype\:\text\,\text\:{\content\:\$MESSAGE\}}第二步在ax.yaml里注册工具tools: - name: send_wechat description: 发送通知到企业微信 command: /path/to/send_wechat.sh parameters: - name: webhook_url type: string required: true - name: message type: string required: true第三步重启ax或者执行ax reload让配置生效。Agent在决策时如果判断需要发送通知就会调用这个工具。6.3 与现有CI/CD的集成方式ax可以嵌入到现有的CI/CD流程里。比如在GitLab CI的.gitlab-ci.yml里加一个stageagentic-task: stage: deploy script: - ax run --goal 部署新版本并验证健康检查 --tool create_k8s_job --tool query_job_status only: - main这样每次合并到main分支就会触发一个Agentic任务。Agent会根据goal自动完成部署和验证。集成时要注意CI环境的kubeconfig权限要控制好不要给太高的权限。建议为CI创建一个专用的ServiceAccount只允许它在特定命名空间操作。7. 性能优化与规模化考虑7.1 Agent决策的延迟优化Agent的决策依赖LLM调用每次调用可能有几百毫秒到几秒的延迟。如果任务步骤很多累积延迟会很可观。优化思路有几个一是缓存常见决策。如果某个决策在相似上下文中反复出现可以缓存结果下次直接复用。二是并行化。如果多个决策之间没有依赖关系可以并行调用LLM。三是本地小模型。对于一些简单的决策比如“是否需要重试”可以用本地的小模型或者规则引擎代替LLM调用。实测下来缓存能减少约40%的LLM调用并行化能减少约30%的端到端延迟。7.2 多任务并发的资源隔离当多个ax任务同时运行时需要确保它们之间的资源隔离。Kubernetes的命名空间和资源配额可以实现这一点。建议为每个ax任务创建一个独立的命名空间并设置ResourceQuotaapiVersion: v1 kind: ResourceQuota metadata: name: ax-quota namespace: ax-task-001 spec: hard: requests.cpu: 4 requests.memory: 8Gi limits.cpu: 8 limits.memory: 16Gi pods: 10这样即使某个任务失控也不会影响其他任务和集群的整体稳定性。7.3 监控与告警的接入ax本身提供了一些基本的监控指标可以通过Prometheus暴露。在ax.yaml里开启metrics: enabled: true port: 9090 path: /metrics然后配置Prometheus抓取。关键指标包括agent_iterations_total、tool_calls_total、tool_call_duration_seconds、task_success_total、task_failure_total。告警规则可以设置如果task_failure_total在5分钟内超过3次触发告警如果agent_iterations_total超过max_iterations的80%触发预警。这些指标和告警能让你在Agent出问题时第一时间知道而不是等用户反馈。8. 一些个人体会和后续可扩展的方向我在实际使用ax的过程中最大的体会是Agentic编排的价值不在于“全自动”而在于“半自动”。完全让Agent自主决策风险太高出了问题很难排查。更好的模式是Agent做大部分决策但在关键节点上留出人工确认的入口。ax的审批钩子就是为这个设计的。另一个体会是工具的质量决定Agent的上限。如果工具定义模糊、参数校验不严、错误处理不完善Agent再聪明也没用。所以在扩展工具时花时间把工具的接口设计好比调优Agent的prompt更有效。后续可以扩展的方向我觉得有几个比较有意思一是多Agent协作让多个Agent分别负责不同领域比如一个负责计算资源、一个负责数据、一个负责网络通过消息传递协调。二是Agent记忆的长期化把历史决策和结果存下来让Agent在类似场景下能参考过去的经验。三是与GitOps的深度集成Agent的决策直接生成Git提交通过Argo CD同步到集群实现完全声明式的Agentic编排。这些方向我还在探索中有新的进展再分享。如果你也在做类似的事情欢迎交流踩坑经验。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑