K8s GPU调度全链路拆解:从kubectl apply到GPU正常运行

文章目录

    • [K8s GPU 调度:从 apply 到跑起来](#K8s GPU 调度:从 apply 到跑起来)
    • [1. 先看完整链路](#1. 先看完整链路)
    • [2. 第一层:准入控制------还没进调度,先被搜身](#2. 第一层:准入控制——还没进调度,先被搜身)
      • [2.1 ResourceQuota:配额就是预算](#2.1 ResourceQuota:配额就是预算)
      • [2.2 LimitRange:强制声明,不许裸奔](#2.2 LimitRange:强制声明,不许裸奔)
      • [2.3 自定义 Admission Webhook:平台自己的土规矩](#2.3 自定义 Admission Webhook:平台自己的土规矩)
    • [3. 第二层:调度------选节点比选对象还累](#3. 第二层:调度——选节点比选对象还累)
      • [3.1 Device Plugin:给调度器配个导盲犬](#3.1 Device Plugin:给调度器配个导盲犬)
      • [3.2 Filter:先刷掉不合适的](#3.2 Filter:先刷掉不合适的)
      • [3.3 Score:矮子里拔将军](#3.3 Score:矮子里拔将军)
      • [3.4 Reserve:先占个座](#3.4 Reserve:先占个座)
    • [4. 第三层:kubelet + Device Plugin------把"决定"变成"设备号"](#4. 第三层:kubelet + Device Plugin——把"决定"变成"设备号")
      • [4.1 Allocate:甲乙方对话现场](#4.1 Allocate:甲乙方对话现场)
      • [4.2 分配策略:整卡、MIG、Time-Slicing、MPS](#4.2 分配策略:整卡、MIG、Time-Slicing、MPS)
      • [4.3 分配失败:你看到的和实际的不一样](#4.3 分配失败:你看到的和实际的不一样)
    • [5. 第四层:容器运行时------把 GPU 焊进容器](#5. 第四层:容器运行时——把 GPU 焊进容器)
      • [5.1 挂载链](#5.1 挂载链)
      • [5.2 NVIDIA_VISIBLE_DEVICES:你只能看到你该看的](#5.2 NVIDIA_VISIBLE_DEVICES:你只能看到你该看的)
    • [6. 第五层:GPU Operator------把前四层打包成"一键安装"](#6. 第五层:GPU Operator——把前四层打包成"一键安装")
      • [6.1 驱动管理:告别手动挡](#6.1 驱动管理:告别手动挡)
      • [6.2 节点全生命周期](#6.2 节点全生命周期)
    • [7. 常见故障:三个翻车现场](#7. 常见故障:三个翻车现场)
      • [7.1 故障一:Pod 一直 Pending,Events 为空](#7.1 故障一:Pod 一直 Pending,Events 为空)
      • [7.2 故障二:Events 显示 "0/10 nodes are available"](#7.2 故障二:Events 显示 "0/10 nodes are available")
      • [7.3 故障三:调度成功了,启动失败了](#7.3 故障三:调度成功了,启动失败了)
    • [8. 一句话总结](#8. 一句话总结)


P.S. 无意间发现了一个巨牛的人工智能教程,非常通俗易懂,对AI感兴趣的朋友强烈推荐去看看, 传送门https://blog.csdn.net/H1727548

K8s GPU 调度:从 apply 到跑起来

先讲个残酷的事实:你敲下 kubectl apply 的时候,以为自己只是提交了一个 YAML。其实你相当于在 GPU 机房门口按了一下门铃,后面一整条流水线的人开始为你忙活。

这条流水线比外卖平台的链条还长,而且这份"外卖"不能退款------Pod 一旦 Pending,你就只能蹲在 kubectl describe 前面干瞪眼。

今天就把这条链路从头捋一遍。一共五层,每一层都有自己的脾气,少一层,你的 GPU 就只是个价值几十万的摆件。

1. 先看完整链路

一个 Pod 从提交到真正跑起来,大概长这样:

复制代码
kubectl apply -f pod.yaml
│
▼
┌─────────────────────────────────────────────┐
│ 第一层:准入控制 (Admission)                  │
│ GPU 请求是否合法?配额是否够?                 │
└─────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ 第二层:kube-scheduler 调度                   │
│ Filter(过滤节点)→ Score(打分)→ Reserve(预留)│
└─────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ 第三层:kubelet + Device Plugin               │
│ 分配具体 GPU 设备 → 注入环境变量                │
└─────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ 第四层:容器运行时 (nvidia-container-runtime)  │
│ 挂载 GPU 设备 → 设置 cgroup → 启动容器          │
└─────────────────────────────────────────────┘
│
▼
容器内可以调用 CUDA → nvidia-smi 看到 GPU

看懂这张图,你就明白了一件事:GPU 不是 K8s 天生认识的,是人家一层层"抬"上来的。跟公司里推诿扯皮的流程很像,区别是------它们真的能把事办成。

2. 第一层:准入控制------还没进调度,先被搜身

Pod 进了 API Server,别急着上桌,先过安检。

这一层专门干一件事:在 Pod 还没被持久化之前,先检查它是不是个"正经 Pod"。

2.1 ResourceQuota:配额就是预算

yaml 复制代码
apiVersion: v1
kind: ResourceQuota
metadata:
  name: team-ml-gpu
  namespace: team-ml
spec:
  hard:
    requests.nvidia.com/gpu: "16"
    limits.nvidia.com/gpu: "16"

规则很简单:你租户申请的总 GPU 数超过 16 张,API Server 直接拒单,连排队的资格都不给。

像不像你刷爆信用卡?银行连催收短信都懒得给你发,直接冻结。

2.2 LimitRange:强制声明,不许裸奔

yaml 复制代码
apiVersion: v1
kind: LimitRange
metadata:
  name: gpu-limits
  namespace: team-ml
spec:
  limits:
    - type: Container
      min:
        nvidia.com/gpu: "1"   # 必须至少声明 GPU
      max:
        nvidia.com/gpu: "8"   # 单 Pod 最多 8 张

LimitRange 的存在意义,是防两类人:

  • 忘了声明 GPU 的------上了车才发现没买票。
  • 喝多了声明 1000 张 GPU 的。这种需求一般出现在两种情况:跑大模型的,或者刚被裁的。

2.3 自定义 Admission Webhook:平台自己的土规矩

到这一层,GPU 平台就可以玩一些自己的校验了:

  • 检查 Pod 是不是既声明了 GPU 又写了 nodeName------想绕过调度器直接点菜?没门。
  • 根据 GPU 型号自动注入 toleration,减轻用户心智负担。
  • 强制 GPU Pod 必须 limit=request,GPU 不支持超分,谁也别想白嫖。
  • 检查选的 GPU 型号在集群里有没有货。

这里头最贴心的是第二条:自动帮你把"请假条"提前写好,省得每次都被 taint 拦在门外。像不像你妈提前帮你把行李收拾好,你只管出门挨骂。

3. 第二层:调度------选节点比选对象还累

3.1 Device Plugin:给调度器配个导盲犬

kube-scheduler 不会自己扫描 PCIe 总线,它就是个瞎子。全靠 Device Plugin 这个导盲犬跟它报数:这个节点有 8 张卡,型号 A100,显存 80G。

yaml 复制代码
$ kubectl get node gpu-node-1 -o yaml
status:
  capacity:
    cpu: 64
    memory: 512Gi
    nvidia.com/gpu: 8          # Device Plugin 上报
  allocatable:
    nvidia.com/gpu: 8          # 可分配数 = capacity - 系统预留

顺便说一句,GPU 型号、显存这些信息也不是 Device Plugin 报的,是 gpu-feature-discovery 打的 label。这俩一个报数、一个贴标签,配合得像相声里的捧哏逗哏,谁也不抢谁的活。

3.2 Filter:先刷掉不合适的

复制代码
Filter 检查清单(针对 GPU Pod):
1. nvidia.com/gpu 资源够吗?
   Node.allocatable[nvidia.com/gpu] - Node.requested[nvidia.com/gpu] ≥ Pod.request
2. Taint 匹配吗?
   GPU 节点通常有 taint: nvidia.com/gpu=true:NoSchedule
   Pod 必须有对应的 toleration,否则被挡
3. NodeSelector / NodeAffinity 匹配吗?
   Pod 要求 nvidia.com/gpu.product=A100
   节点 label 必须精确匹配
4. CPU/内存/临时存储够吗?同普通 Pod,没有特殊逻辑
5. PodAffinity / PodAntiAffinity 满足吗?
   分布式训练 Pod 通常要求 PodAntiAffinity 分散到不同节点

Filter 就是相亲软件里的左滑右滑:GPU 不够,左滑;taint 没 toleration,左滑;label 不匹配,左滑。一个 Pod 的恋爱,全在这一层结束了。

分布式训练这里有个狠要求:四个 Pod 必须分到四个不同节点。

yaml 复制代码
apiVersion: v1
kind: Pod
spec:
  affinity:
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        - labelSelector:
            matchLabels:
              training-job: llama-70b-epoch3
          topologyKey: kubernetes.io/hostname   # 同节点只能有一个

不是它们关系不好,是 NVLink 就一条。抢带宽比抢最后一块排骨还狠。

3.3 Score:矮子里拔将军

过了 Filter 的节点进入打分环节,0 到 100,谁分高选谁。

CPU 集群的哲学是共同富裕:资源用得越少的节点分越高,Pod 撒得到处都是,谁也别饿着。

GPU 集群不行,GPU 的哲学是钱要花在刀刃上:卡要堆在一个节点上,把整台空闲机器留给后来的多卡任务。

yaml 复制代码
apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
profiles:
  - schedulerName: gpu-scheduler
    plugins:
      score:
        enabled:
          - name: NodeResourcesFit
            weight: 10
    pluginConfig:
      - name: NodeResourcesFit
        args:
          scoringStrategy:
            type: MostAllocated        # 对 GPU 资源用 Bin Packing
            resources:
              - name: nvidia.com/gpu
                weight: 10             # GPU 权重最高
              - name: cpu
                weight: 1
              - name: memory
                weight: 1

看这个配置,GPU 权重 10,CPU 和内存权重 1。调度器的偏心肉眼可见,像极了老师只给主科划重点。

碎片化的痛,经历过的人都懂:每个节点都被占走一两张卡,你手上有个 8 卡任务,放眼全集群愣是凑不齐------就像你想买三室一厅,结果满城都是只剩一间房的楼盘。

3.4 Reserve:先占个座

复制代码
# 调度器缓存(Reserve 后):
Node gpu-a100-01:
  nvidia.com/gpu: 8 allocatable, 6 requested(含当前 Pod 占的 2 张)
  # 实际节点上:GPU 还是 8 张全空闲(kubelet 还没收到指令)

注意,这里只是调度器在自己的小本本上记了一笔,节点上的 GPU 其实还是全空闲的。

这个机制叫乐观锁,翻译成人话就是:调度器觉得这事稳了,但最终成不成,得看 kubelet 那边翻台。

万一等位期间 GPU 被别人抢了,Pod 就会进入 UnexpectedAdmissionError------你约好了人,到地方人家跟你说:我已经跟别人走了。

4. 第三层:kubelet + Device Plugin------把"决定"变成"设备号"

4.1 Allocate:甲乙方对话现场

调度器把 Pod 绑定到节点后,kubelet 开始干活。对 GPU 资源,它会调 Device Plugin 的 Allocate() gRPC 接口,现场大概是这样的:

复制代码
kubelet:
  "DevicePlugin,这个 Pod 请求了 nvidia.com/gpu: 2,
   给我分配 2 张可用的 GPU"
nvidia-device-plugin:
  1. 查看本节点哪些 GPU 还没被分配
  2. 选出 2 张 GPU(如 GPU-0 和 GPU-3)
  3. 返回:
     - 设备路径: /dev/nvidia0, /dev/nvidia3
     - 环境变量: NVIDIA_VISIBLE_DEVICES=GPU-xxx,GPU-yyy
     - 挂载点: /usr/local/nvidia 等驱动文件路径

这段对话是整条链路里最像甲乙方的一环:一个说"给我 2 张卡",另一个翻翻库存,回一句"GPU-0 和 GPU-3,拿走,别客气"。

这些设备路径和环境变量会被写进容器的 OCI spec,然后传给容器运行时。

4.2 分配策略:整卡、MIG、Time-Slicing、MPS

yaml 复制代码
apiVersion: v1
kind: ConfigMap
metadata:
  name: device-plugin-config
data:
  config.yaml: |
    version: v1
    flags:
      migStrategy: mixed
    sharing:
      timeSlicing:
        replicas: 8
    resources:
      - name: nvidia.com/gpu
        replicas: 8

这张 ConfigMap 管两件事:MIG 怎么上报,以及要不要把一张卡切成时间片。示例里俩开关都开了,实际按需配一个就行。

分配策略 Pod 侧声明 含义 隔离级别
默认(整卡) nvidia.com/gpu: 1 整张卡 物理独占
MIG nvidia.com/mig-1g.10gb: 1 一个 MIG 实例:1/7 算力 + 10GB 显存 硬件隔离
Time-Slicing nvidia.com/gpu: 1 逻辑 1/8 张卡(8 来自上面配置的 replicas) 无隔离
MPS nvidia.com/gpu: 1 共享 GPU 算力 显存不隔离

MIG 是隔断房,每间都有自己的锁和门,切完就是真隔离,故障都互不影响;Time-Slicing 是合租客厅,谁都能进,性能全靠自觉。

这里有个特别容易踩的坑:MIG 的资源名(比如 nvidia.com/mig-1g.10gb)不是 ConfigMap 写出来的。插件不造名字,只翻译硬件现状------像前台只负责念号,不负责给你造号。

那资源名哪来的?硬件上切出来的。

复制代码
nvidia-smi -mig-mode 1                 # 开启 MIG 模式(需重启 GPU/驱动后生效)
nvidia-smi mig -cgi 1g.10gb,1g.10gb -C # 创建实例

MIG 要用起来,得打通三层,缺一不可:

在哪配 做什么
① 硬件层 GPU 节点上 nvidia-smi 开 MIG 模式、建实例------资源名真正的"来源"在这
② 插件层 ConfigMap 的 migStrategy 只决定插件怎么上报,不产生资源名
③ 调度层 Pod 的 resources.requests 按资源名请求,与 ① 建出来的实例对得上才能调度

还有个经典疑问:为什么 MIG 的 1g 是 1/7,Time-Slicing 却是 1/8?

因为 7 是硬件写死的。A100 的计算部分按物理单元组边界切,上限就是 7 份,老祖宗定的规矩,改不了;而 8 是你 ConfigMap 里自己写的,想改 4、改 16 都行,跟外卖备注一样自由。

显存又是另一套独立的切片:40GB 的卡每档 5GB,80GB 的卡每档 10GB。所以同样是 1g 算力,40GB 卡上叫 1g.5gb,80GB 卡上叫 1g.10gb,两段拼一起才是完整资源名。

写 Pod 之前先 nvidia-smi mig -lgi 看一眼这张卡上实际有什么,别凭记忆写。不然调度器会用一个 Pending 教你做人。

4.3 分配失败:你看到的和实际的不一样

复制代码
# kubelet 日志中分配失败的典型输出:
"Failed to allocate GPU: no available GPUs meeting request:
 requested 2 GPUs with label nvidia.com/gpu.product=A100,
 found 1 available"

典型的抢单事故:调度器刚说有 2 张,kubelet 真去拿的时候只剩 1 张。其他 Pod 在调度窗口内先下手了。

像极了双十一抢购:购物车里有,结算时没了。

遇到这种情况不用手动干预,调度器会自动重新调度,而且重试间隔会越来越长------像追人被拒后自我安慰的冷静期。

5. 第四层:容器运行时------把 GPU 焊进容器

5.1 挂载链

K8s 默认用 containerd 做容器运行时,containerd 通过 runc 创建容器。GPU 挂载的关键是 nvidia-container-runtime------它是 runc 的一个包装:

复制代码
kubelet
  → CRI Plugin (containerd)
  → containerd-shim
  → nvidia-container-runtime       ← 拦截容器创建
  → nvidia-container-runtime-hook  ← OCI prestart hook
  → 调用 libnvidia-container      ← 挂载 GPU 设备 + 驱动库
  → runc 启动容器

nvidia-container-runtime-hook 在容器启动前偷偷干了一堆活,自动注入这些东西:

复制代码
# 容器内被自动注入:
/dev/nvidia0                             ← GPU 设备文件
/dev/nvidiactl                           ← NVML 控制设备
/dev/nvidia-modeset                      ← 显示模式内核驱动
/dev/nvidia-uvm                          ← 统一虚拟内存
/usr/lib/x86_64-linux-gnu/libcuda.so     ← CUDA 驱动库
/usr/lib/x86_64-linux-gnu/libnvidia-ml.so ← NVML 库
NVIDIA_VISIBLE_DEVICES=GPU-xxx,GPU-yyy   # 容器内 nvidia-smi 只看得到分配的 GPU
NVIDIA_DRIVER_CAPABILITIES=compute,utility

你什么都没做,容器里就什么都有了------比亲妈还周到。

5.2 NVIDIA_VISIBLE_DEVICES:你只能看到你该看的

复制代码
# 节点上有 8 张 GPU
$ kubectl exec gpu-pod -- nvidia-smi -L
GPU 0: NVIDIA A100-SXM4-80GB (UUID: GPU-xxx)   # 只看到分配的 2 张
GPU 1: NVIDIA A100-SXM4-80GB (UUID: GPU-yyy)
# 其余 6 张不可见

节点上有 8 张卡,容器里 nvidia-smi 只显示分给你的那 2 张。

这不是抠门,这叫权限边界。像极了老板只让你看到你该看的报表------你不知道的,就当你不需要知道。

6. 第五层:GPU Operator------把前四层打包成"一键安装"

前面说了这么多,你要是手动挨个部署,光组件就能装一晚上。NVIDIA GPU Operator 用一个 Helm Chart 搞定整个 GPU 节点的生命周期管理:

bash 复制代码
helm install gpu-operator nvidia/gpu-operator \
  --namespace gpu-operator --create-namespace \
  --set driver.enabled=true \          # 自动安装 GPU 驱动(DaemonSet)
  --set mig.strategy=mixed \           # 启用 MIG
  --set devicePlugin.config.name=device-plugin-config

一条命令下去,组件清单长这样:

组件 类型 作用
nvidia-driver-daemonset DaemonSet 在 GPU 节点上安装/更新驱动
nvidia-device-plugin DaemonSet 向 kubelet 注册 GPU 扩展资源
gpu-feature-discovery DaemonSet 自动检测 GPU 型号并打 Node Label
nvidia-dcgm-exporter DaemonSet 导出 GPU 指标(温度/功率/ECC 错误等)
nvidia-mig-manager DaemonSet MIG 分区策略管理
nvidia-operator-validator Job 部署后验证 GPU 环境是否可用
sandbox-validator DaemonSet 持续运行时验证(GPU 健康检查)

6.1 驱动管理:告别手动挡

复制代码
传统方式:
  新 GPU 节点上架 → SSH 登录 → apt install nvidia-driver-535
  → 版本不对 → 卸载重装 → 重启
  → 90% 的节点上架时间花在驱动问题上
GPU Operator 方式:
  新 GPU 节点上架 → 打 label: nvidia.com/gpu.present=true
  → Operator 自动派 Driver DaemonSet Pod 到该节点
  → Pod 内安装/编译驱动 → 自动加载内核模块 → Done
  → 不需要 SSH,不需要重启(大部分情况下)

以前上架一台 GPU 节点,90% 的时间耗在装驱动上:SSH 登录、apt install、版本不对、卸载重装、重启。

现在呢?打个 label,Operator 自动干活。从手动挡到自动挡,驾校教练看了都想转行。

6.2 节点全生命周期

复制代码
节点上架:
1. 服务器到货,装好 OS 和 K8s
2. 打 label: nvidia.com/gpu.present=true
3. GPU Operator 自动部署驱动 + Device Plugin + DCGM
4. nvidia-operator-validator 跑验证
5. 验证通过 → node 自动变为 Ready,GPU 资源可分配
节点运行中:
1. DCGM Exporter 持续采集指标
2. Node Problem Detector 监听 DCGM 指标 → 异常自动打 taint
3. MIG Manager 监控 MIG 配置(被人手动改了 → 自动恢复)
节点下架:
1. kubectl drain gpu-node-1 → Pod 迁移到其他 GPU 节点
2. drain 完 → 节点可以安全关机/送修

上架、运行、下架,三个阶段的活儿它全包了,连 MIG 配置被人手动改了都会偷偷改回来------比物业管家还尽责。

7. 常见故障:三个翻车现场

7.1 故障一:Pod 一直 Pending,Events 为空

复制代码
$ kubectl describe pod training-pod-0
Events: <none>
# 调度器根本没考虑这个 Pod

Events 是空的,说明调度器压根没考虑过你这个 Pod。

比被拒绝更伤人的是根本没被看见------像极了相亲对象已读不回。

复制代码
# 检查 Device Plugin 是否正常运行
kubectl get pods -n gpu-operator -l app=nvidia-device-plugin
# 检查节点上是否有 nvidia.com/gpu
kubectl get nodes -o custom-columns=NAME:.metadata.name,GPU:.status.capacity.'nvidia\.com/gpu'
# 如果没有 → 检查 Device Plugin 日志
kubectl logs -n gpu-operator nvidia-device-plugin-xxx
# "NVML initialized. Number of devices: 0" → 驱动问题,检查驱动是否加载

大概率是 Device Plugin 没起来,或者驱动没加载。日志里那句 Number of devices: 0 就是典型症状:显卡明明插着,驱动就是不认。

7.2 故障二:Events 显示 "0/10 nodes are available"

复制代码
Events:
  Type     Reason            Age   Message
  ----     ------            ----  -------
  Warning  FailedScheduling  2m    0/10 nodes are available:
    3 node(s) had untolerated taint {nvidia.com/gpu: true}
    4 node(s) didn't match Pod's node affinity/selector
    3 Insufficient nvidia.com/gpu

这条报错特别好,它把每个节点拒绝你的原因都列得清清楚楚。

比前任的分手理由还详细,而且人家是讲道理的:

  • 3 个节点被 taint 挡住 → Pod 缺少 toleration,请假条没写。
  • 4 个节点 label 不匹配 → nodeSelector 或 GPU 型号要求不对,门牌号找错了。
  • 3 个节点 GPU 不够 → 空闲数 < 请求数,卡确实不够分。

7.3 故障三:调度成功了,启动失败了

复制代码
Events:
  Type    Reason                  Age   Message
  ----    ------                  ----  -------
  Warning UnexpectedAdmissionError 5s   failed to allocate GPU devices

这是调度器和 kubelet 之间的状态不一致:调度器算的时候有 2 张空闲,kubelet 分配的时候已经被别人抢了。

解决方式也很硬核:不用管。kube-scheduler 会自动重新调度,重试间隔会越来越长,就当它自己在冷静。

8. 一句话总结

Kubernetes 的 GPU 调度不是单一机制,是五层协同:准入控制管合法性和配额,Device Plugin 管上报,调度器管 Filter + Score 选节点,kubelet 管分配具体设备号,容器运行时管挂载。

GPU Operator 再把驱动安装、Device Plugin 部署、MIG 管理、健康监控全打包进 Helm Chart,节点上架打一个 label 就完事。

下次你的 GPU Pod 再 Pending,先别急着骂人。想想这条链路------它比你想象中勤奋,只是偶尔运气不太好。

P.S. 无意间发现了一个巨牛的人工智能教程,非常通俗易懂,对AI感兴趣的朋友强烈推荐去看看,传送门https://blog.csdn.net/H1727548

相关推荐
专注于ai算法的踩坑小达人1 小时前
TabFM(Google Tabular Foundation Model)完整部署手册(PyTorch GPU版)
人工智能·python
Seoyoneh1 小时前
呼叫中心云原生架构实战:微服务拆分与弹性扩容技术解析
人工智能·信息与通信·通信
AI工具测评家1 小时前
降AI后参考文献错位、三线表变乱码?快降重vs快将AI实测:谁能降重后完整保住Word原生排版
人工智能·降重·ai检测·查重·降ai·知网检测
Geek-Chow1 小时前
Hidden Reasoning Tokens Are Silently Truncating Your Structured JSON Output
人工智能
子非鱼eva1 小时前
昇腾开源仓Issue分析解答-CANN精选(二)
人工智能·ai
墨林陌1 小时前
AI 热点日报(2026-09-17):谷歌 Gemini 3.8 Live 双模型发布,OpenAI 联手 Anthropic 共商 AI 安全
人工智能
AI行业应用研究1 小时前
会务问答机器人落地拆解:三级路由、知识库组织与防幻觉——会务小程序能自己回答参会者提问吗?
大数据·人工智能·安全·小程序·架构
海宇服务1 小时前
零信任架构实战:基于海宇公安二要素认证即时版构建自动化号码发卡网关
运维·人工智能·架构·自动化
合米AI SOP系统1 小时前
医疗器械|组件组装工位,合米科技AI SOP视觉防错系统满足高合规要求下的精益生产
大数据·人工智能·科技