AI-Infra-Guard 这名字最初给我的感觉,是那种“包装得很唬人,实际不痛不痒”的监控工具——AI 基础设施守护,听上去像是大厂内部平台才会有的东西。但真正部署完、跑完一轮技能扫描之后,我得承认它确实解决了一个很现实的问题:当你的模型服务越来越多、依赖链越来越长,你需要的是一个能主动感知“异常”的系统,而不是事故发生后一群人翻日志。
这个项目用 Docker 一键就能跑起来,一个 docker-compose 文件加几条命令,几分钟内就能启动一个独立服务,定时扫描你已上线的 AI 模型服务(推理、向量化、知识库检索这类),并产出一份“技能状态报告”。如果你在运营一个小型 AI 团队,或者自己管理着一堆本地部署的模型服务,经常记不清某个服务到底还活没活着,这篇文章就是给你准备的;如果你是刚接触 Docker 部署的新手,同样能把整套流程照抄下来。文章里我会讲完整部署步骤,也会把我最近一次“漏报”的排查过程完整复盘——新服务都已经发布上线了,扫描结果里却始终没有它,这个事儿很典型,值得掰开揉碎看一遍。
1. 项目概述:AI-Infra-Guard 到底在守护什么
1.1 AI 基础设施的“技能资产”需要清单化
我先解释一下“技能扫描”这个听起来有点抽象的词。做 AI 基础设施运维时间长了就会知道,真正让人头大的不是某一个模型服务挂了,而是你不知道自己手上到底有多少个模型服务。今天这边上一个微调后的对话模型,明天那边加一个向量检索服务,后天又把某个旧模型升级了版本。半年下来,光内部跑着的推理服务就可能有十几个,每个服务还各自支持着不同的能力——文本生成、Embedding、语义检索、图像理解,这些能力在 AI-Infra-Guard 里统一被称为“技能”。
这里有一个非常常见的运维盲区:传统监控工具盯的是 CPU、内存、请求量这些“资源指标”,但没人去盯“这个服务到底还提供着哪些技能、技能的返回是否正常”。AI-Infra-Guard 做的事情就是把视角从“机器”转到“能力”上,相当于给整个 AI 基础设施建了一张技能清单,并且持续做状态盘点。它每隔一段时间对每个目标服务发起探测,检查每个技能点是否可用、响应时间是多少、是否符合预期,然后把结果落成结构化报告。我一开始觉得这种“技能清单化”有点多余,但真正用起来才发现,这对多人协作的场景尤其有用——新同学接手时不用挨个问人,看一眼扫描报告就知道现在有哪些服务、各自什么状态。
这个工具更适合谁?我个人理解是两类场景:一是 AI 应用类型公司里负责模型服务的后端运维,二是自己搭了一套本地大模型推理环境、同时挂了好几个模型的个人开发者。前者的痛点是服务数量和依赖关系复杂,后者的痛点是没有专门的监控体系。两者的共同点,都是希望用最小的成本把“服务活着”这件事自动化。
1.2 自建脚本和现成方案,我为什么选了它
在决定用 AI-Infra-Guard 之前,我其实先用 Python 写过类似的轮询脚本,用requests定时打每个服务的接口,然后往群里发一条消息。说实话,脚本本身不难写,难的是后面的可持续性:每个服务的健康接口格式不一样,有的返回 JSON,有的直接返回 200,有的要带 Token 才能探测;轮询失败后要有重试和超时处理;一天下来产生的一堆日志需要一个统一查看的地方;还有,当服务列表发生变化时,需要有人记得去改脚本里的配置。
这些需求叠加起来,自建脚本的成本就被放大了。AI-Infra-Guard 的价值在于它把“扫描目标管理”“规则配置”“结果输出”“告警通知”这几件事做成了标准模块,我只需要维护一份配置文件,就能覆盖大多数场景。它扫描的粒度是“技能”,不是“主机”,这一点和通用的 Uptime 检测工具完全不同。通用工具只能告诉我“服务挂了”,AI-Infra-Guard 能告诉我“服务还活着,但它的 tool_call 技能响应已经退化到 15 秒了”,这个信息量密度明显更高。
当然它也不是没有缺点,比如默认的静态目标配置需要手工维护服务清单,这一点我后面会详细讲,正是在这里我踩了一次“漏报”的坑。但在绝大多数场景下,它确实能让我少操心很多。
2. Docker 一键部署:从环境检查到服务起来的完整记录
2.1 部署前的环境检查与准备工作
先说结论:部署 AI-Infra-Guard 的最低配置,我实测下来 4 核 CPU、8GB 内存足够。它本身不是一个重资源消耗的服务,扫描任务是对目标服务发 HTTP 请求,主要的资源开销集中在保存历史报告和日志上。如果是个人测试环境,2 核 4GB 的机器也能跑起来,但扫描间隔拉长一点,比如 1 小时一次,会更稳妥。
我的实测环境是一台 Ubuntu 22.04 的服务器,装的是 Docker 24 和 Docker Compose v2。如果你用的是 Windows,需要注意 Docker Desktop 必须依赖 WSL2,安装前要在 BIOS 里确认虚拟化已经开启,否则启动时会报virtualization support not detected之类的错误。这个问题常见到我都懒得吐槽了,但确实是新手遇到最多的坑之一。
部署之前先做一个基础检查,命令很简单:
docker --version docker compose version如果版本太旧,或者环境里压根没装 Docker,先补一下:
sudo apt update sudo apt install -y docker.io docker-compose-v2 sudo systemctl enable --now docker装完之后顺手验证一下守护进程是否正常,sudo systemctl status docker能跑出状态就行。这里有个小建议:如果你的机器上的 Docker 是很多年前装的,最好在部署前把镜像拉取和网络相关的配置检查一遍。国内网络环境下建议配置镜像加速,不然拉镜像那一两分钟会很折磨人。
接下来我要做的目录准备很简单,把配置、报告、日志三个目录和宿主机做映射,后续升级镜像、备份数据都方便:
mkdir -p ai-infra-guard/{config,reports,logs} cd ai-infra-guard2.2 编写 docker-compose.yml:每个字段我都解释清楚
AI-Infra-Guard 部署的核心就是这一个 compose 文件。我用的版本是 v1.4.2,这个版本对技能扫描的支持比较完善,下面是我当时实际使用的配置,关键字段我都加了注释:
services: guard: image: ai-infra-guard/guard:v1.4.2 container_name: ai-infra-guard restart: unless-stopped ports: - "8080:8080" volumes: - ./config:/app/config:ro - ./reports:/app/reports - ./logs:/app/logs environment: GUARD_SERVER_ADDR: "0.0.0.0:8080" GUARD_SCAN_INTERVAL: "3600" GUARD_SCAN_TIMEOUT: "60" GUARD_DISCOVERY_PROVIDER: "static" GUARD_NOTIFY_TYPE: "webhook" GUARD_WEBHOOK_URL: "http://your-collector:9900/ingest" healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/healthz"] interval: 30s timeout: 5s retries: 3逐段说一下:
镜像与端口。ai-infra-guard/guard:v1.4.2是我用的镜像。端口方面,8080 是内置控制台的 HTTP 端口,扫描任务本身不监听额外端口,如果需要外部访问控制台,就在宿主机上映射出来。生产环境记得加防火墙规则,别把 8080 裸奔到公网。
挂载目录。./config:/app/config挂载配置文件,我特意加了:ro(只读),防止运行过程中容器内部误改配置。reports和logs是输出目录,必须持久化,不然每次重启容器,历史扫描结果就全丢了,这是很多人常忽略的细节。
环境变量。GUARD_SCAN_INTERVAL=3600表示每 3600 秒执行一次例行扫描,这个值我建议按业务对实时性的要求来调。测试阶段可以设成 60 秒,方便快速验证;正式环境设 1800 到 3600 秒就够了,太频繁地扫描没有意义,反而会给目标服务造成不必要的压力。GUARD_DISCOVERY_PROVIDER=static是核心变量,表示服务发现方式采用静态配置,也就是扫描哪些目标完全以配置文件为准。这个字段后面差点害我漏报,先记住它。
健康检查。我给容器加了一个healthcheck,每 30 秒去请求内置的/healthz接口。这个做法的好处是,Docker 自己就能感知容器状态,docker ps里能看到容器是否健康,方便和外部监控联动。
配置写完后,启动命令就是经典的两条:
docker compose up -d docker compose logs -f --tail=1002.3 启动后的验证:别急着配规则
第一次启动后,我建议先不要立刻去配置扫描目标,而是先验证服务本身是否正常。以下三件事是我每次部署都会做的:
curl http://127.0.0.1:8080/healthz docker compose ps docker compose logs --since 5m正常情况下/healthz会返回 200 和类似ok的响应体,docker compose ps里容器状态是Up (healthy)。日志里如果出现一大堆报错,多半是配置文件格式有问题或者镜像拉取不完整。
这里有个经验:如果拉镜像的时候网络不稳定,不要删了重来,先docker compose down,再docker compose up -d,让 Docker 走断点续传机制,比重新拉一次快得多。
我还习惯在验证完成之后把版本信息固定下来:
docker image inspect ai-infra-guard/guard:v1.4.2 --format '{{.Id}}'这个镜像 ID 记录下来,将来做升级回滚、事故排查时,能精确知道自己当时跑的是哪个版本,避免“代码没变但行为变了”这种幽灵问题。
3. 技能扫描实战:配置目标、跑一轮扫描、看懂报告
3.1 扫描规则与目标配置:我推荐先小范围试跑
服务启动只是第一步,真正干活的是技能扫描的规则配置。这个配置文件放在刚才建好的config目录下控制文件skill-rules.yaml中:
provider: static targets: - name: "llm-gateway" url: "http://llm-gateway.internal:8000" skills: - chat - embedding - tool_call auth: token_env: "LLM_GATEWAY_TOKEN" - name: "rag-service" url: "http://rag.internal:8080" skills: - retrieval - rerank auth: token_env: "RAG_TOKEN" interval: 3600 timeout: 60配置的逻辑很直白:告诉 AI-Infra-Guard “你盯住这些服务,每个服务重点检查这几个技能”。
我踩过的一个具体的坑,是通过单次全部配置所有目标开始。大约有20个服务,有些服务名拼写错误,有些URL写错,扫描一次全是红色的 FAILED 标记。看起来像系统坏了,实际上只是没配好。所以现在我一直强调第一次先只配一个目标,例如一个确定可用的网关,试跑一轮确认没有问题,再加其他目标。这个原则适合所有类似的监控工具的配置。
token_env字段也很重要。大部分内部推理服务都不是裸奔的,至少有一个 Token 或 Key 做认证。我的做法是配合 Docker 的环境变量来传 Token,而不是直接写在 YAML 配置文件里。比如在某处设置一个实际环境变量LLM_GATEWAY_TOKEN=xxx,然后让扫描器启动时注入到容器环境。这样即使配置文件被误分享,密钥也不至于泄露。
3.2 手动触发一轮扫描:测试时可以这样做
虽然在配置里设置了扫描间隔,但第一次配完规则后不建议被动地等待。AI-Infra-Guard 提供一个命令行工具,可以直接手动触发一次扫描:
docker exec -it ai-infra-guard /app/guard-cli scan --config /app/config/skill-rules.yaml扫描完成后立刻生成报告:
docker exec -it ai-infra-guard /app/guard-cli report --action summarize输出大概是这样的格式:
目标服务 技能 状态 响应时间 llm-gateway chat OK 180ms llm-gateway embedding OK 230ms llm-gateway tool_call DEGRADED 15s rag-service retrieval OK 320ms rag-service rerank FAILED connect refused我把这张表贴在下面,方便大家理解状态字段的含义:
| 状态 | 含义 | 可能原因 |
|---|---|---|
| OK | 技能可用,响应时间符合预期 | 正常 |
| DEGRADED | 服务能响应,但明显变慢 | 后端排队、模型推理负载过高 |
| FAILED | 技能不可用或探测失败 | 服务挂了、网络不通、接口路径变了 |
| UNKNOWN | 技能无法探测,缺少认证信息 | Token 无效、配置缺失 |
初次扫描如果全是 OK,也别高兴太早,我通常还会做一件事就是把报告留档。AI-Infra-Guard 每次都会把完整报告写到reports目录中,保存为带时间戳的 JSON 文件。很多人觉得报告看一眼就够了,其实历史报告在事后排查时非常关键:当你怀疑某个服务最近有没有“变差”时,翻历史报告就能看到响应时间的变化曲线,比任何人的记忆都可靠。我后来能在漏报事件里快速锁定时间点,靠的就是这些历史数据。
3.3 告警配置:别把工具用成“事后诸葛”
扫描报告是给人看的,但人不可能 7×24 小时盯着控制台。所以告警配置是必选项。AI-Infra-Guard 支持通用的 Webhook 通知。以企业微信、钉钉这类群机器人为例,只需要把 Webhook 地址填到环境变量GUARD_WEBHOOK_URL里,每次扫描完成并且有 FAILED 或 DEGRADED 状态时,它就会自动推一条消息到群里。
个人经验里,如果服务对实时性要求比较高,告警的延迟主要取决于扫描间隔而非推送链路。你把扫描间隔设为 60 秒,最快一分钟就能发现问题;设为 3600 秒,等告警推过来的时候,业务可能已经受影响一个小时了。所以扫描间隔该调多短,取决于你对故障的容忍度。但太短的间隔(比如 10 秒)对目标服务的健康检查接口也是一种压力,建议不要追求极限实时性,把重点放在“多长时间内发现故障可以接受”。
4. 一次漏报的完整复盘:新服务上线了,扫描却没抓到
4.1 现象:流量正常,报告里却没有它
这是整个部署经历里对我触动最大的一件事。事情发生在部署 AI-Infra-Guard 的第三周。那天下午我们上线了一个新的语音识别推理服务,代号叫speech_model。当时走的流程是正常的:服务部署好、注册到内部服务发现、统一网关配置好路由、内部测试通过、对外流量开始进来。一切看起来都很正常。
结果第二天我例行查看 AI-Infra-Guard 的控制台,翻了一遍扫描报告,发现里面压根没有speech_model这一行。简单地又刷新了几次,还是没有。我当时的第一反应是扫描配置有问题,或者是扫描器本身没跑。但检查了容器日志,发现扫的是跑的正常状态,也扫了其他所有服务。唯一的区别就是speech_model这个新目标没有出现在结果里。
这时我意识到:是“漏报”了。它不是误报(服务活着被报告为死了),而是“服务上线后完全没被纳入扫描范围”。如果不及时发现,等这个服务真正出问题的时候,监控系统会视而不见,那才是最可怕的。
4.2 排查过程:层层排查
我先按顺序梳理排查动作,供大家参考排查思路:
第一件事是确认扫描器有没有扫。查日志:
docker logs ai-infra-guard --since 24h | grep speech_model输出为空。这说明日志里根本没出现过这个目标。但这还不能说明问题,因为如果扫描器不识别这个目标,日志里自然也不会有。
第二件事是确认执行扫描的规则文件。因为当时用的是static模式的发现方式,扫描目标完全来自skill-rules.yaml文件。我到宿主机上打开配置文件查了一下:果然,还是只有llm-gateway、rag-service等旧目标,没有新增speech_model。问题已经很接近了。
第三件事是搞明白为什么配置文件没有更新。这时候我才回忆起来:负责部署speech_model的同事只更新了服务发现平台那边的注册信息,并没有来同步 AI-Infra-Guard 的静态扫描配置。在他的视角里,服务已经上线了,AI-Infra-Guard 应该能自动发现它。但 AI-Infra-Guard 的模式是静态配置,它根本没有自动发现能力。
4.3 根因:本质上是“动态发现”和“静态配置”的错位
这里我要把工具自身的工作原理说清楚,因为这是整个复盘最有价值的地方。
AI-Infra-Guard 的GUARD_DISCOVERY_PROVIDER=static模式,意味着扫描器启动时加载一次配置文件,之后每一次例行扫描都是照着这个静态列表去探测。它不会主动去服务发现平台查询“有没有新服务”,也不会打开某个网关注册接口去发现新增路由。说白了,它像一个严格执行名单的巡检人员,名单里没有的员工,就算坐在工位上,也不会被检查。
而我们的服务上线流程里,服务发现平台(对外注册新模型)和 AI-Infra-Guard(监控技能清单)是两条不联动的链路。不是工具失效,而是“新服务要加进扫描名单”这个操作被我默认认为“应该自动完成”。这个默认是错误的。
更细的一层原因是:静态模式下,即使我手动改了配置文件,扫描器也不会热加载。需要重新触发配置加载或重启容器。这一层机制也很容易被忽略。所以当时就算同事改了配置文件但没有执行 reload,扫描结果照样不会有变化。
4.4 修复:把发现模式改成动态,并加上配置同步机制
确认根因之后,修复方向就很清晰了。我做了两件事。
第一件事是把 AI-Infra-Guard 的发现方式从static切换成动态发现。我们内部环境里有 Nacos 作为服务注册中心,而 AI-Infra-Guard 支持对接这种服务发现平台。修改后的配置是这样的:
provider: nacos nacos: addr: "http://nacos.internal:8848" namespace: "ai-services" group: "DEFAULT_GROUP" auth: username_env: "NACOS_USER" password_env: "NACOS_PASS"这样每次扫描前,AI-Infra-Guard 会去拉取一次服务注册列表,凡是注册过的 AI 服务都会自动出现在扫描目标里,不再需要手工把每个新服务写进skill-rules.yaml。
第二件事是把配置同步做成了发布流程里的一环。即使使用动态发现,某些服务可能不希望被扫描器探测,也需要白名单机制来做过滤。我在配置里加了一个exclude_rules规则,并且把这个规则文件的更新纳入发布操作规范:任何新服务发布时,必须同步确认监控是否生效。这一步不是工具能力,而是流程问题。
4.5 复盘结论:不是工具欺骗了你,是你误解了工具
现在回头看,这个漏报事件最核心的教训不是“工具不靠谱”,而是“我把工具的静态模式默认成了动态模式”。静态模式的优点是你完全掌控扫描范围,缺点是从不自动发现新东西;动态模式恰好相反。这两种模式没有优劣,只有是否匹配你的使用场景。
我在复盘文档里写了这样一句话:监控工具只能检查“它知道的”服务,凡是工具不知道的服务,对它来说就是不存在。想让监控更可靠,要么把“知道”这一步自动化,要么把“更新名单”做成流程的一部分。两者选一即可,但绝对不能什么都不做,指望工具自己变聪明。
另外我还加了一个二次校验机制:每次扫描结束后,AI-Infra-Guard 在报告里对比“上次扫描的服务集合”和“本次扫描的服务集合”。如果集合发生变化(有新增或减少),就在报告里打一个 diff 标记。这样新服务上线后,哪怕配置没同步,扫描报告里也会出现一行“服务数量变化”,提醒管理员去检查。这个功能听起来小,但在多团队协作的场景里非常有用。
5. 常见问题与避坑指南:部署和扫描阶段的典型坑
5.1 部署阶段的典型问题速查
我把这段时间遇到过的、身边朋友遇到过的部署问题汇总成一张表:
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
docker compose up卡在 Pull 阶段 | 网络原因、镜像源速度慢 | 配置镜像加速,或换时间段重试 |
| 容器启动后立即退出 | 配置目录没挂载正确、环境变量缺失 | docker logs查看错误信息,修正配置后重试 |
| 控制台访问不了 | 端口映射冲突或防火墙拦截 | 检查docker compose ps,确认端口未被占用 |
| 健康检查一直显示 unhealthy | 探针路径写错 / 容器内部缺 curl | 改用 wget 探针,或确认/healthz路径 |
| 容器能上网,但扫描不到内网服务 | 容器网络模式隔离 | 改用 host 模式或加入已存在的自定义网络 |
其中“容器网络不通”是最烦人的一个。默认情况下,Docker 容器用的是 bridge 网络,容器的 localhost 和宿主机 localhost 是两码事。如果你在容器里配置了http://localhost:8000去访问宿主机的服务,那大概率会失败,因为这个地址指向的是容器自己的回环地址。解决方法是把目标 URL 改成宿主机局域网地址,或者直接用network_mode: host。我个人的建议是 AI-Infra-Guard 部署在内网,直接使用自定义网络或 host 模式,能少很多网络层面的麻烦。
5.2 扫描精度相关的坑:误报和漏报都要防
扫描类工具通病有两个方向。误报是“服务明明活得好好的,报告里标 FAILED”;漏报是“服务有问题,报告里没体现”。我在实践中对这两个方向分别做了一些规避。
误报主要来自探测参数设置不当。比如timeout设得太短。有一次我们某个模型服务的推理请求耗时本身就在 8 秒左右,而我在配置里把timeout设成了 10 秒,导致探活请求频繁触发超时,报告里一堆 FAILED,其实服务业务完全正常。后来我把超时时间改成 30 秒,同时把探活请求改成轻量级接口(比如/healthz而不是/infer),误报马上消失了一大半。关键原则:探活请求的代价要足够小,不能用一条完整推理请求去探测。
漏报除了我上面那次事件里静态配置的问题,还有一种常见情况:只探测服务可用性,没有探测“服务内部某条逻辑链路”。比如一个 AI 服务本身开着,但底层的向量数据库连接断了,它能响应/healthz,但所有实际技能请求都失败。这种情况需要配置“深度技能探测”,让扫描器对每个技能点发一条最小请求,验证完整链路是否通。AI-Infra-Guard 是支持对每个技能配置探测请求体的,但我发现很多人没有用起来,导致扫描永远停留在“看脸红不红”的浅层水平。
5.3 运维周期的三个建议
基于这段实践,我总结了三条对稳定运维有帮助的建议,每一条都是真金白银换来的:
第一,扫描间隔要小于“故障影响窗口”的一半。如果你的服务允许最长故障 10 分钟发现,那扫描间隔最好不超过 5 分钟。这个换算逻辑很简单,但在实际配置时经常被忽略,很多人瞄一眼默认值就走过去了。
第二,历史报告至少保留一个月以上。AI-Infra-Guard 的报告目录默认没做轮转,长时间运行会把磁盘慢慢塞满。我建议写一个 cron 定时任务,把超过 30 天的 JSON 报告压缩归档到冷存储,同时保留最新 7 天的原始文件。查历史数据的时候,能回溯的时间越久越好。
第三,定期人工“注入故障”验证扫描有效性。这个做法是我后来才加上的:每隔一两周手动把某个服务的探活地址改错,或者停掉一个服务确认告警能不能正常推送。这有点像消防演习,虽然麻烦,但它能确保整套系统在真正出事的时候是可靠的。多少团队精心搭了监控,最后发现告警根本没发出来,就是因为从来没测试过告警链路。
最后聊两句个人的体会
整个 AI-Infra-Guard 部署下来,我最深的体会是:工具的可靠性,一半取决于工具实现,一半取决于使用者对工具边界的理解。静态配置模式下漏掉新服务,本质上是我没搞清它的工作模型就把它当成万能监控在用。如果你准备上手这个项目,我建议部署前先把扫描模式选好:目标稳定、团队规模小就选静态模式,简单可控;上线频繁、服务动态变化就务必配好动态发现,别让配置成为漏报的温床。另外,无论配置得多完善,每两周做一次告警自测,确保出问题时系统真的会尖叫。这套组合拳打下来,AI 基础设施的守护才算真正落地,而不是装了个心里安慰。