生产部署:3 台 2C4G 云服务器,把企业级 Agent 真正跑起来的完整方案|AgentX 专栏⑩

本文是 AgentX 技术专栏第十篇,也是收官篇。基于真实项目部署产物(Dockerfile / docker-compose.yml / deploy.sh / server-init.sh / .env.example),从技术简介到设计思路,从核心脚本到生产踩坑,循序渐进拆解 AgentX 如何用 3 台 2C4G 低配云服务器,把一个企业级 Agent 平台真正跑起来——让 Java 程序员一次性看懂"从代码到上线"的最后一公里。


本文速览:

  • 为什么"本地能跑"和"生产能跑"是两回事?AI 应用部署的独特难点
  • 三节点拓扑:推理节点 / 存储节点 / 监控节点,每台机器干什么
  • Dockerfile 多阶段构建:为什么编译镜像和运行镜像要分开
  • ZGC + MaxRAMPercentage=75%:低配机器上的 JVM 调优
  • server-init.sh 裸机初始化:动态 Swap、Docker 镜像加速、NVIDIA 残留清理
  • deploy.sh 一键部署:git pull → 构建 → 健康验证的完整闭环
  • 三个生产部署大坑:容器访问宿主机 Ollama、内存超配 OOM、健康检查误杀

文章约 40 KB,是整个专栏的落地收尾——建议从头读。读完文末有完整部署代码包(含全部脚本 + 三节点配置)获取方式。


一、先抛个问题:为什么"本地能跑"不等于"能上线"

很多人做 AI 应用,本地 mvn spring-boot:run 跑得好好的,一到部署就傻眼。因为本地和生产之间隔着一条鸿沟:

维度 本地开发 生产环境
依赖服务 都在一台机器(localhost) 分散在多台服务器,跨网络
资源 16G 内存随便造 2C4G,抠着用
启动 IDE 点一下 要能一键部署、自动重启
故障 重启 IDE 要能自愈、要有监控
配置 写死在代码里 要能按环境注入
GPU 无所谓 没有 GPU,CPU 跑大模型

尤其是 AI 应用,还有几个独特的部署难点:

  1. 大模型推理吃资源——Ollama 跑 qwen2.5 即使是 CPU 版也要好几 G 内存
  2. 依赖组件多——LLM、向量库(Milvus)、缓存(Redis)、追踪(Jaeger),一个都不能少
  3. 启动慢——大模型加载 + 向量库初始化,冷启动可能要分钟级
  4. 长连接——SSE 流式对话,健康检查不能误判

这篇文章就来拆解 AgentX 怎么在3 台 2C4G 的低配云服务器上,把这些难点逐个解决,做到"一行命令上线、挂了自动重启、出问题能追踪"。

这是整个专栏的收官篇。前面 9 篇讲的是"怎么写",这一篇讲"怎么上线"——没有这一步,再好的代码也只是个 demo。


二、技术简介:AI 应用的生产部署需要什么

2.1 部署的本质是"环境复制 + 依赖编排 + 故障自愈"

一个生产级部署方案,至少要回答三个问题:

问题 解决手段
怎么保证哪台机器都能跑? 容器化(Docker)—— 把运行环境打包进镜像
多个依赖组件怎么协同? 编排(docker compose)—— 一份配置拉起所有服务
挂了怎么办? 健康检查 + 自动重启 + 监控告警

2.2 AgentX 的部署技术栈

技术 作用 为什么选它
Docker 多阶段构建 打包应用 编译/运行分离,镜像瘦身
docker compose 单机编排 比 K8s 轻,2C4G 跑得动
Shell 脚本(deploy/init) 自动化 无依赖,任何 Linux 都能跑
环境变量(.env) 配置注入 一份镜像跑多环境
ZGC JVM 垃圾回收 低延迟,停顿亚毫秒级

2.3 为什么不用 K8s?

这是很多人的第一反应——“上生产不就该上 K8s 吗?”

方案 资源开销 学习成本 适合规模
docker compose 极低 单机 / 几台机器
K8s 高(光控制面就吃 1-2G) 陡峭 几十台 + 弹性伸缩

对 3 台 2C4G 的机器来说,K8s 的控制面开销就能吃掉一台机器的资源。 个人项目、中小企业的 Agent 平台,docker compose 足够了。技术选型的核心是"匹配规模",不是"追新"——这也呼应了专栏②讲的预算约束哲学。


三、设计思路:四条低成本生产部署的核心原则

原则一:职责分离,三节点拓扑

把所有东西堆一台机器上,2C4G 必然撑不住。AgentX 按职责把服务拆到三台机器:

┌─────────────────────────────────────────────────────────────────┐
│  Server A · 推理节点(124.223.22.34)                            │
│    ├── AgentX 后端(Spring Boot 容器)                          │
│    └── Ollama(同机独立部署,qwen2.5 + bge-m3)                  │
│    特点:CPU 密集,大模型推理的主战场                            │
├─────────────────────────────────────────────────────────────────┤
│  Server B · 存储节点(10.0.0.15,内网)                          │
│    ├── Redis(短期记忆 / 会话)                                  │
│    └── Milvus(长期记忆 / RAG 向量库)                          │
│    特点:内存 + 磁盘密集,数据持久化的主战场                     │
├─────────────────────────────────────────────────────────────────┤
│  Server C · 监控节点(8.140.221.150,北京)                      │
│    ├── Jaeger(链路追踪,呼应专栏⑦)                            │
│    └── Nginx(反向代理 / 入口)                                  │
│    特点:独立隔离,监控不与业务争资源                            │
└─────────────────────────────────────────────────────────────────┘

为什么这样分? 三类负载的资源特征完全不同:

  • 推理(A)吃 CPU
  • 存储(B)吃内存和磁盘 IO
  • 监控(C)需要独立,不能业务一崩监控也跟着崩

分开之后,每台 2C4G 各司其职,互不抢资源。

原则二:容器化,但只容器化"无状态"的部分

AgentX 后端是无状态的(状态都在 Redis/Milvus),适合容器化。但有两个东西故意不放进容器

组件 是否容器化 原因
AgentX 后端 ✅ 容器 无状态,随便重启
Ollama ❌ 宿主机独立部署 大模型文件几个 G,容器化反而麻烦;且要复用宿主机的 CPU 优化
Redis/Milvus ❌ 独立节点 有状态,数据要持久化,单独管理更稳

容器化不是越多越好。 有状态、重量级、需要复用宿主机资源的组件,独立部署往往更省心。

原则三:配置外置,一份镜像跑多环境

绝不把 IP、密码写死在代码或镜像里。所有环境相关配置走 .env 文件 + 环境变量注入:

镜像(不变)  +  .env(按环境变化)  =  跑在任何环境

开发环境一份 .env,生产环境一份 .env,同一个镜像不用重新构建。这是十二要素应用(12-Factor App)的核心原则之一。

原则四:一切自动化,从裸机到上线两条命令

部署不应该是"照着 100 步文档手敲"。AgentX 把整个流程压缩成两个脚本:

# 1. 裸机第一次:初始化服务器环境
bash server-init.sh

# 2. 之后每次部署/更新:一键
bash deploy.sh

自动化的价值不只是省事,更是消除"人肉操作的不确定性"——脚本每次执行结果一致,不会因为忘了某一步而出错。


四条原则讲完,看具体落地。


四、代码解析:从裸机到上线的完整链路

4.1 Dockerfile:多阶段构建

第一块拼图是把 AgentX 后端打包成镜像。关键是多阶段构建

# ── Stage 1: 编译(Maven + JDK 21)──
FROM maven:3.9-eclipse-temurin-21 AS builder

# 配置阿里云 Maven 镜像,加速依赖下载
COPY maven-settings.xml /root/.m2/settings.xml

WORKDIR /build
COPY pom.xml .
RUN mvn dependency:go-offline -B -q 2>/dev/null || true   # 先下依赖(利用缓存层)
COPY src ./src
RUN mvn clean package -DskipTests -B

# ── Stage 2: 运行(最小的 JRE 镜像)──
FROM eclipse-temurin:21-jre

WORKDIR /app
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

# 只复制编译产物,不带 Maven 和源码
COPY --from=builder /build/target/agentx-1.0.0.jar app.jar

EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
  CMD curl -s --fail http://localhost:8080/api/v1/agents/health || exit 1

ENTRYPOINT ["java", \
  "-server", \
  "-XX:+UseZGC", \
  "-XX:MaxRAMPercentage=75.0", \
  "-Djava.security.egd=file:/dev/./urandom", \
  "-jar", "app.jar"]

为什么要分两个 Stage?

单阶段(错误做法) 多阶段(正确做法)
镜像内容 Maven + JDK + 源码 + 依赖 + jar 只有 JRE + jar
镜像大小 800MB+ 200MB 左右
安全性 源码、构建工具全暴露 只有运行时,攻击面小

Stage 1 用完整的 Maven 镜像编译,Stage 2 用最小的 JRE 镜像运行,最终镜像只保留 Stage 2 的内容。编译用的 Maven、源码全部丢弃。

三个 JVM 参数的讲究:

-XX:+UseZGC               # ZGC 垃圾回收器,停顿亚毫秒级
-XX:MaxRAMPercentage=75.0 # 最多用 75% 容器内存(留 25% 给堆外/系统)
-Djava.security.egd=file:/dev/./urandom  # 用非阻塞随机源,加速启动
  • ZGC:传统 G1 在大堆下 GC 停顿可能几百毫秒,对 SSE 流式对话是灾难。ZGC 停顿亚毫秒级,无论堆多大。
  • MaxRAMPercentage=75%:容器里绝不能-Xmx 写死内存。容器内存限制变了,写死的 -Xmx 不会跟着变,容易 OOM。用百分比让 JVM 自适应容器内存。留 25% 给 Metaspace、线程栈、堆外内存。
  • egd=urandom:JVM 启动时初始化 SecureRandom 会读 /dev/random,没有足够熵时会阻塞。换成 /dev/urandom 非阻塞,启动快好几秒。

4.2 docker-compose.yml:编排与配置注入

有了镜像,用 compose 拉起服务并注入配置:

services:
  agentx-app:
    build: .
    container_name: agentx-app
    ports:
      - "${SERVER_PORT:-8080}:8080"
    environment:
      - SPRING_PROFILES_ACTIVE=${SPRING_PROFILES_ACTIVE:-prod}

      # Redis(Server B: 10.0.0.15)
      - REDIS_HOST=${REDIS_HOST:-10.0.0.15}
      - REDIS_PASSWORD=${REDIS_PASSWORD:-}

      # 统一数据节点 IP(application.yml 通过 DATA_SERVER_IP 引用)
      - DATA_SERVER_IP=${DATA_SERVER_IP:-10.0.0.15}

      # Milvus(Server B)
      - MILVUS_HOST=${MILVUS_HOST:-10.0.0.15}
      - MILVUS_PORT=${MILVUS_PORT:-19530}

      # 监控节点(Server C: 北京 Jaeger)
      - MONITOR_SERVER_IP=${MONITOR_SERVER_IP:-8.140.221.150}

      # OTel 语义标签(呼应专栏⑦)
      - OTEL_SERVICE_NAME=agentx
      - OTEL_RESOURCE_ATTRIBUTES=service.version=1.0.0,deployment.environment=production

      # Ollama(同机独立部署,通过 host.docker.internal 访问宿主机)
      - AI_SERVER_IP=${AI_SERVER_IP:-host.docker.internal}
      - OLLAMA_HOST=${OLLAMA_HOST:-http://host.docker.internal:11434}

    volumes:
      - ./logs:/app/logs          # 日志挂出来,容器删了日志还在
    restart: unless-stopped       # 自愈:非人为停止就自动重启
    extra_hosts:
      - "host.docker.internal:host-gateway"   # 关键:让容器能访问宿主机
    healthcheck:
      test: ["CMD", "curl", "-s", "--fail", "http://localhost:8080/api/v1/agents/health"]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 60s           # 关键:给冷启动 60s 宽限期

networks:
  default:
    name: agentx-network

几个关键设计:

配置 作用
${VAR:-default} 环境变量优先,没有就用默认值——配置外置
restart: unless-stopped 容器挂了自动重启,除非人为停止
extra_hosts: host.docker.internal 让容器访问宿主机的 Ollama(坑一会细讲)
start_period: 60s 冷启动宽限期,避免健康检查误杀(坑三会细讲)
volumes: ./logs 日志持久化到宿主机

注意 DATA_SERVER_IPMONITOR_SERVER_IP 这些——三节点的 IP 全部通过环境变量注入,application.yml 里用 ${DATA_SERVER_IP} 引用。改 IP 不用动代码。


4.3 server-init.sh:裸机一键初始化

一台刚买的云服务器,什么都没有。server-init.sh 把它变成能跑 AgentX 的环境。核心片段:

#!/bin/bash
set -euo pipefail

# ── 动态 Swap:低配机器的救命稻草 ──
TOTAL_MEM=$(awk '/MemTotal/{printf "%d", $2/1024}' /proc/meminfo)
if ! swapon --show | grep -q .; then
    if [ "$TOTAL_MEM" -le 4096 ]; then
        SWAP_SIZE="4G"          # 4G 内存配 4G swap
    elif [ "$TOTAL_MEM" -le 8192 ]; then
        SWAP_SIZE="2G"
    else
        SWAP_SIZE="0"           # 内存充足不配
    fi
    if [ "$SWAP_SIZE" != "0" ]; then
        fallocate -l "$SWAP_SIZE" /swapfile
        chmod 600 /swapfile
        mkswap /swapfile && swapon /swapfile
        echo '/swapfile none swap sw 0 0' >> /etc/fstab
        sysctl vm.swappiness=10              # 尽量用内存,swap 兜底
        echo "vm.swappiness=10" >> /etc/sysctl.conf
    fi
fi

# ── Docker 安装:走阿里云源 ──
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor \
    -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [...signed-by=...] https://mirrors.aliyun.com/docker-ce/linux/ubuntu \
    $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list
apt update -y && apt install -y docker-ce docker-ce-cli containerd.io

# ── 阿里云 ECS 镜像加速 ──
cat > /etc/docker/daemon.json <<EOF
{ "registry-mirrors": ["https://registry.cn-hangzhou.aliyuncs.com"] }
EOF
systemctl restart docker

为什么这些细节重要?

  • 动态 Swap:2C4G 机器跑 Java + 偶尔的内存尖峰,没有 swap 极易 OOM。但 swap 太多又会拖慢,所以 swappiness=10——优先用物理内存,swap 只兜底。
  • swap 大小按内存动态算:4G 内存配 4G swap,8G 配 2G,16G 不配。不是一刀切。
  • 阿里云镜像加速:国内拉 Docker Hub 镜像慢到崩溃,配了加速器才能正常拉镜像。
  • NVIDIA 残留清理(脚本里还有):阿里云 ECS 有时带 NVIDIA 驱动残留,会干扰 apt,开头先清理。

这些都是"国内低配云服务器"才会踩的真实坑,脚本把它们一次性处理掉。


4.4 deploy.sh:一键部署闭环

环境就绪后,deploy.sh 负责"拉代码 → 构建 → 启动 → 验证"的完整闭环:

#!/bin/bash
set -e

PROJECT_PATH="/usr/service/agentx"
CONTAINER_NAME="agentx-app"

# ── 1. 拉取最新代码 ──
if [ ! -d "$PROJECT_PATH" ]; then
    git clone --branch main git@github.com:SuniaW/agentx.git "$PROJECT_PATH"
else
    cd "$PROJECT_PATH"
    git fetch --all
    git reset --hard origin/main      # 强制同步到最新,避免本地冲突
fi
cd "$PROJECT_PATH"

# ── 2. 准备环境变量 ──
[ -f set-env.sh ] && source set-env.sh
[ ! -f .env ] && cp .env.example .env

# ── 3. 构建并启动 ──
docker compose down 2>/dev/null || true
docker compose up -d --build --force-recreate

# ── 4. 健康验证 ──
sleep 10
STATUS=$(docker inspect -f '{{.State.Running}}' "$CONTAINER_NAME")
HEALTH=$(docker inspect -f '{{if .State.Health}}{{.State.Health.Status}}{{else}}running{{end}}' "$CONTAINER_NAME")

if [ "$STATUS" == "true" ]; then
    echo "✅ 部署成功!(health: $HEALTH)"
    docker logs --tail 5 "$CONTAINER_NAME"
else
    echo "❌ 容器未能正常启动,查看:docker logs $CONTAINER_NAME"
fi

# ── 5. 清理过期镜像 ──
docker image prune -f >/dev/null 2>&1 || true

这个脚本体现了"幂等部署"的思想:

  • 首次和更新统一:目录不存在就 clone,存在就 git reset --hard 强制同步。不管是第一次还是第一百次,跑同一个命令。
  • --force-recreate:强制重建容器,确保新代码生效(避免 Docker 缓存导致跑旧代码)。
  • 部署后自动验证:不是 up -d 完就完事,还要 docker inspect 确认容器真的 Running + Healthy。
  • 自动清理docker image prune 删掉旧镜像,防止磁盘被占满(低配机器磁盘也小)。

一行 bash deploy.sh,从拉代码到验证上线全自动。


4.5 整体部署流程串起来

裸机服务器
   │ bash server-init.sh
   ▼
环境就绪(Docker / Swap / 镜像加速 / Git)
   │ 配置 GitHub SSH key
   ▼
bash deploy.sh
   │ git pull → docker compose up --build
   ▼
容器启动 → HEALTHCHECK 探测(60s 宽限)
   │ 健康
   ▼
✅ 上线(access http://124.223.22.34:8080)
   │ 挂了?
   ▼
restart: unless-stopped 自动拉起

从一台空服务器到生产可用,两条命令


五、问题解决:三个生产部署的实战大坑

坑一:容器里的 AgentX 连不上宿主机的 Ollama

现象

本地开发时 OLLAMA_HOST=http://localhost:11434 一切正常。打成容器部署后,AgentX 疯狂报 Connection refused,连不上 Ollama。

原因

容器有自己独立的网络命名空间。容器里的 localhost 指的是容器自己,不是宿主机。而 Ollama 跑在宿主机上(我们故意不容器化它,见原则二)。容器里访问 localhost:11434,等于在容器内部找 Ollama——当然找不到。

解决

用 Docker 提供的特殊域名 host.docker.internal 访问宿主机,并在 compose 里显式声明映射:

environment:
  - OLLAMA_HOST=http://host.docker.internal:11434   # 不是 localhost!
extra_hosts:
  - "host.docker.internal:host-gateway"             # Linux 上必须显式声明
写法 容器里指向 结果
localhost:11434 容器自己 ❌ 连不上
host.docker.internal:11434 宿主机 ✅ 连得上

注意host.docker.internal 在 Docker Desktop(Mac/Win)上自带,但Linux 上必须加 extra_hosts: host-gateway 才能用——这是最容易漏的一步。

教训:容器化一个组件时,要想清楚它依赖的其他服务在哪。容器的网络隔离是把双刃剑——隔离带来干净,也带来"localhost 不再是你以为的 localhost"。


坑二:JVM 内存超配,容器被 OOMKilled

现象

容器跑着跑着突然消失,docker inspect 显示 OOMKilled: true。但应用日志里没有任何 Java 的 OutOfMemoryError——是被系统直接杀掉的。

原因

最初 Dockerfile 里写死了 -Xmx3g。但 2C4G 机器实际可用内存可能只有 3.5G(系统占一部分),JVM 堆 3G + Metaspace + 线程栈 + 堆外内存(ZGC 也用堆外)+ Ollama 偶尔的内存尖峰,加起来超过物理内存。Linux OOM Killer 直接把容器进程杀了——它不管你 Java 内部怎么想,物理内存不够就杀。

解决

绝不写死 -Xmx,用 MaxRAMPercentage 让 JVM 按容器内存的百分比自适应:

# ❌ 危险:写死,容器内存变了它不变
ENTRYPOINT ["java", "-Xmx3g", "-jar", "app.jar"]

# ✅ 安全:按容器内存的 75% 自适应,留 25% 给堆外和系统
ENTRYPOINT ["java", "-XX:MaxRAMPercentage=75.0", "-jar", "app.jar"]

为什么是 75% 而不是 90%?因为堆只是 JVM 内存的一部分:

容器内存 100%
├── JVM 堆(MaxRAMPercentage=75%)
└── 剩余 25%:Metaspace + 线程栈 + ZGC 堆外 + JIT 缓存 + ...

留 25% 给"堆之外的一切",才不会被 OOM Killer 盯上。

教训容器里的 JVM 内存管理和裸机完全不同。裸机你知道总内存多少,容器里内存是被 cgroup 限制的。永远用百分比(MaxRAMPercentage),永远留足堆外空间。


坑三:冷启动太慢,健康检查把刚启动的容器误杀

现象

部署后容器反复重启,日志显示应用其实正常启动了,但每次刚启动就被 restart 拉走重来。陷入"启动→被杀→重启→被杀"的死循环。

原因

AgentX 冷启动慢——要连 Redis、初始化 Milvus 集合、加载 LangChain4j、连 Ollama,全部就绪可能要 40-50 秒。但健康检查从容器一启动就开始探测:

healthcheck:
  test: [...]
  interval: 30s
  retries: 3
  # 没有 start_period!

容器启动后 30s 第一次探测——这时应用还没起好,失败。再 30s、再 30s,连续 3 次失败,Docker 判定 unhealthy,restart 把它杀了重启。但重启后还是同样的慢启动,再次被杀。死循环。

解决

start_period——给冷启动一个"宽限期",这段时间内的探测失败不计入失败次数:

healthcheck:
  test: ["CMD", "curl", "-s", "--fail", "http://localhost:8080/api/v1/agents/health"]
  interval: 30s
  timeout: 5s
  retries: 3
  start_period: 60s     # ✅ 前 60s 是宽限期,探测失败不算数
配置 含义
start_period: 60s 启动后 60s 内,健康检查失败不计数、不触发重启
interval: 30s 宽限期过后,每 30s 探测一次
retries: 3 连续 3 次失败才判 unhealthy

start_period 要设得比"最坏冷启动时间"略长。AgentX 冷启动约 40-50s,设 60s 留足余量。

教训AI 应用冷启动普遍慢(大模型加载、向量库初始化)。健康检查一定要配 start_period,否则慢启动会被自愈机制误判成"启动失败",陷入重启死循环。自愈机制本是好事,配错了反而成了帮凶。


六、总结:一张表 + 五条经验

设计决策回顾

设计决策 解决什么问题
三节点拓扑(推理/存储/监控) 三类负载资源特征不同,分开互不抢资源
Docker 多阶段构建 编译/运行分离,镜像从 800MB 瘦到 200MB
Ollama/Redis/Milvus 不容器化 有状态、重量级组件独立部署更稳
配置全外置(.env + 环境变量) 一份镜像跑多环境,改 IP 不动代码
ZGC + MaxRAMPercentage=75% 低延迟 GC + 容器内存自适应,防 OOM
server-init.sh 裸机初始化 动态 Swap + 镜像加速,国内低配云的坑一次处理
deploy.sh 幂等部署 首次/更新统一,拉代码到验证全自动
start_period + restart 自愈 冷启动宽限 + 自动重启,挂了能起来又不误杀

五条核心经验

  1. "本地能跑"和"生产能跑"差着一整套工程 —— 容器化、编排、配置外置、健康检查、自愈,一个都不能少
  2. 技术选型要匹配规模 —— 3 台 2C4G 用 docker compose 而非 K8s,K8s 的控制面开销能吃掉一台机器
  3. 容器里的 JVM 必须用百分比内存 —— 写死 -Xmx 在容器里是 OOM 的头号元凶
  4. 容器网络的 localhost 不是宿主机的 localhost —— 访问宿主机服务用 host.docker.internal + host-gateway
  5. AI 应用冷启动慢,健康检查必须配 start_period —— 否则自愈机制会误杀慢启动的容器

部署演进路线

如果你要部署自己的 AI 应用,建议这样推进:

  • 第一阶段:单机 docker compose 把所有组件跑起来,先通
  • 第二阶段:拆分有状态组件(Redis/Milvus/Ollama)到独立节点
  • 第三阶段:写 server-init.sh + deploy.sh,把部署自动化
  • 第四阶段:配健康检查 + 自愈 + 监控(接专栏⑦的 Jaeger)
  • 第五阶段:规模上来后再考虑 K8s + CI/CD 流水线

七、写在最后:专栏收官

这是 AgentX 技术专栏的第十篇,也是收官篇

回顾这一路,从专栏②的技术选型,到架构、工具、RAG、记忆、可观测、工作流、MCP,再到这一篇的生产部署——我们完整地走过了一个企业级 Agent 平台"从 0 到上线"的全过程

解决的问题
②③ 怎么选型、怎么设计架构
④⑤⑥ 工具、知识、记忆——Agent 的核心能力
⑦⑧ 可观测、工作流——让它可控、可编排
MCP——接入全球工具生态
部署上线——让前面所有的努力真正跑起来

写这个专栏最大的感受是:做 AI 应用,难的从来不是调用大模型那一行 API,而是把它工程化——让它稳定、可观测、可部署、可演进。而这些恰恰是我们 Java 程序员的看家本领。大模型时代不是要抛弃工程经验,而是把工程经验用在新场景。

如果这个专栏对你有帮助,希望它能成为你做 AI 工程的一份参考。代码全部开源,每一篇都有配套代码包。

专栏会暂告一段落,但 AgentX 项目会持续演进——后续可能会写一些进阶专题(多 Agent 协作、Agent 评估、成本优化等)。欢迎关注,我们下个专题再见。

  • 本文部署代码包 — 公众号回复「部署」获取(含全部脚本 + 三节点配置模板)
  • 完整专栏代码 — 每篇都有独立代码包,回复对应关键词获取
  • 欢迎交流 — 评论区或公众号私信,一起把 AI 工程做扎实

感谢一路读到这里的你。🙏


💬 互动话题:你的 AI 应用部署在什么环境?踩过哪些部署的坑?或者你最想看的下一个专题是什么?评论区聊聊。

关注公众号 【SuniaCoder-AI全栈架构实战】,回复「部署」获取本文完整部署代码包,回复「MCP」获取 MCP 互通代码,回复「工作流」获取工作流引擎代码。


关于作者 & 联系方式

汪旭 / Sunia — Java 全栈开发者,AI 应用工程化实践者

专注企业级 AI 落地,擅长极限资源优化,有 RAG、Agent、知识图谱方向的完整实战经验。

平台 地址 / 说明
CSDN SuniaCoder-AI|13.5 万+ 阅读,RAG/Agent 系列持续更新
微信公众号 搜索【SuniaCoder-AI全栈架构实战】|关注回复「部署」获取本文完整代码包
掘金 SuniaCoder-AI
知乎 SuniaCoder-AI
合作咨询 提供企业私有化大模型部署与定制开发(基础部署 / 企业定制 / 年度维保)欢迎私信洽谈

如果内容对你有帮助,点赞 + 收藏 + 关注是最大的支持,也能让更多需要的人看到这篇文章。


AgentX 专栏导航(完结)

标题 核心内容
一个 Java 开发者的 Agent 实践之路(前言) 专栏总览 / 选题思路
没有 GPU、只有 3 台低配云服务器,我如何选出 AgentX 的技术栈 LangChain4j / Ollama / Milvus / Redis 选型
AgentX 架构设计全解析:一个请求是如何从 HTTP 走到 LLM 再回来的 六层架构 / SSE 流式 / 虚拟线程 / TraceId
工具系统深度实现:从 @Tool 注解到 MCP 协议,构建企业级 Agent 工具体系 ToolRegistry / McpToolServer / @Tool
RAG 进阶:用 Milvus + bge-m3 构建比 ES 更懂语义的企业知识库 向量检索 / bge-m3 / MilvusV2
记忆系统:用 Redis + Milvus 给 AI 配上短期 + 长期双层记忆 ChatMemoryStore / 语义召回 / 多轮上下文
全链路可观测:用 OpenTelemetry + Jaeger 让每次 AI 对话都可追踪可复盘 OTel / Jaeger / SpanExporter / TraceId
工作流引擎:AgentWorkflow 怎么把工具、记忆、流程串成一条流水线 AgentWorkflow / LangGraph / 虚拟线程 / SSE
MCP 协议双向打通:让 AgentX 既能被 Claude 调用,又能调度全球工具生态 MCP / JSON-RPC / 双源合并 / Schema 转换
生产部署:3 台 2C4G 云服务器,把企业级 Agent 真正跑起来的完整方案(本文 · 完结) Docker / 三节点 / ZGC / deploy.sh

上一篇:[MCP 协议双向打通:让 AgentX 既能被 Claude 调用,又能调度全球工具生态|AgentX 专栏⑨]

🎉 专栏完结:感谢一路相伴。AgentX 全系列 10 篇,从选型到上线,希望对你做 AI 工程有所帮助。


Tags#AgentX #生产部署 #Docker #DockerCompose #JVM调优 #ZGC #运维部署 #SpringBoot3 #Java21 #云服务器

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐