Featured image of post 生产级 Agent 部署架构:Docker Compose 全栈方案

生产级 Agent 部署架构:Docker Compose 全栈方案

你写了一个 Agent——它调工具、搜知识库、跟用户对话。本地跑得很好。然后你要把它部署到生产环境。

这时候问题来了:Agent 跑在哪个容器里?怎么给它配工具权限?出了安全问题怎么阻断?挂了怎么知道?

这不是把 Flask 应用扔到 Docker 里就能解决的问题。Agent 的生产部署需要一套专门的架构——网关层做访问控制、运行时层做行为监控、可观测性层做全链路追踪。这篇文章把这三层全部搭起来。

这是 AI Agent 工程实战系列的第八篇,也是收官篇。前面七篇分别讲了 RAG 检索精度Agent 记忆系统Tool Calling 可靠性与容错推理延迟优化状态管理与持久化多 Agent 编排模式Agent 可观测性。这一篇把所有这些组件装进同一个 Docker Compose 栈。

📌 本系列终篇:一、RAG 检索精度提升实战 → 二、Agent 记忆系统设计 → 三、Tool Calling 可靠性与容错 → 四、推理延迟优化 → 五、状态管理与持久化 → 六、多 Agent 编排模式 → 七、Agent 可观测性八、生产级 Agent 部署架构(终篇)


一、三层部署架构

Agent 生产部署需要三层,缺一层都有安全或运维盲区:

┌─────────────────────────────────────────────────┐
│   用户请求(HTTP / MCP / WebSocket)              │
└─────────────────────────────────────────────────┘
                      ↓
┌─────────────────────────────────────────────────┐
│  第一层:网关层(MCPZERO / Lasso)                │
│  ─ 工具 ACL、速率限制、Prompt 注入检测、审计日志   │
└─────────────────────────────────────────────────┘
                      ↓
┌─────────────────────────────────────────────────┐
│  第二层:运行时层(Agent Runtime + ClawGuard)     │
│  ─ Agent 执行引擎、工具调用、eBPF 行为监控         │
└─────────────────────────────────────────────────┘
                      ↓
┌─────────────────────────────────────────────────┐
│  第三层:可观测性层(OpenTelemetry + Grafana)     │
│  ─ Trace 采集、指标聚合、仪表盘、告警               │
└─────────────────────────────────────────────────┘
职责 关键组件
网关层 所有请求的入口,做鉴权、限流、注入检测 MCPZERO / nginx / OPA
运行时层 Agent 实际执行,工具调用管理,安全隔离 Agent Runtime / ClawGuard / Docker
可观测性层 Trace + Metrics + Logging OpenTelemetry Collector / Prometheus / Grafana

这三层用 docker-compose 组织,每层独立容器、独立扩缩、独立升级。


二、Docker Compose 全栈部署

# docker-compose.yml
version: '3.8'

networks:
  agent-net:
    driver: bridge
    ipam:
      config:
        - subnet: 172.20.0.0/16

services:

  # ════════════════════════════════════════════
  # 第一层:网关层
  # ════════════════════════════════════════════

  mcp-gateway:
    image: mcpzero/gateway:latest
    ports:
      - "8080:8080"        # 对外入口
      - "9090:9090"        # 管理 API
    volumes:
      - ./gateway/policies:/policies:ro     # 策略文件
      - ./gateway/config.yaml:/config.yaml:ro
    environment:
      - GATEWAY_LOG_LEVEL=info
      - GATEWAY_RATE_LIMIT=100/min
      - GATEWAY_UPSTREAM=http://agent-runtime:8000
    networks:
      - agent-net
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9090/health"]
      interval: 30s
      retries: 3
    restart: unless-stopped
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 512M

  # ════════════════════════════════════════════
  # 第二层:运行时层
  # ════════════════════════════════════════════

  agent-runtime:
    build: ./runtime
    ports:
      - "8000:8000"        # Agent API
    volumes:
      - ./runtime/tools:/tools:ro          # 注册的工具
      - ./runtime/config:/config:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro  # ClawGuard 监控
    environment:
      - AGENT_MODEL=gpt-5.6
      - AGENT_MAX_TOKENS=8192
      - AGENT_TOOL_TIMEOUT=30s
      - OTLP_ENDPOINT=http://otel-collector:4318
    networks:
      - agent-net
    depends_on:
      - mcp-gateway
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
      interval: 30s
      retries: 3
    restart: unless-stopped
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 4G

  clawguard:
    image: clawguard/agent:latest
    privileged: true       # 需要 eBPF 权限
    volumes:
      - /sys/kernel/debug:/sys/kernel/debug:ro
      - /sys/kernel/tracing:/sys/kernel/tracing:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./clawguard/config.yaml:/config.yaml:ro
      - clawguard_data:/data
    environment:
      - CLAWGUARD_MODE=monitor    # monitor / enforce
      - CLAWGUARD_SINK=otel
    networks:
      - agent-net
    restart: unless-stopped
    deploy:
      resources:
        limits:
          cpus: '1'
          memory: 1G

  # ════════════════════════════════════════════
  # 第三层:可观测性层
  # ════════════════════════════════════════════

  otel-collector:
    image: otel/opentelemetry-collector-contrib:0.112
    ports:
      - "4317:4317"        # gRPC
      - "4318:4318"        # HTTP
    volumes:
      - ./otel/otel-collector.yaml:/etc/otel-collector.yaml:ro
    command: ["--config=/etc/otel-collector.yaml"]
    networks:
      - agent-net
    restart: unless-stopped
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 512M

  prometheus:
    image: prom/prometheus:v2.53
    ports:
      - "9091:9090"
    volumes:
      - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - prometheus_data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.retention.time=30d'
    networks:
      - agent-net
    restart: unless-stopped
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 1G

  grafana:
    image: grafana/grafana:11.1
    ports:
      - "3000:3000"
    volumes:
      - ./grafana/dashboards:/etc/grafana/provisioning/dashboards:ro
      - ./grafana/datasources:/etc/grafana/provisioning/datasources:ro
      - grafana_data:/var/lib/grafana
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD}
      - GF_INSTALL_PLUGINS=grafana-piechart-panel
    networks:
      - agent-net
    depends_on:
      - prometheus
    restart: unless-stopped
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 512M

  # ── 可选的向量存储(用于记忆 / RAG) ──
  qdrant:
    image: qdrant/qdrant:v1.12
    ports:
      - "6333:6333"
    volumes:
      - qdrant_data:/qdrant/storage
    networks:
      - agent-net
    restart: unless-stopped

volumes:
  prometheus_data:
  grafana_data:
  qdrant_data:
  clawguard_data:

零配置启动

docker compose up -d
# 验证各组件健康状态
curl http://localhost:9090/health      # MCPZERO 网关
curl http://localhost:8000/health      # Agent Runtime
curl http://localhost:3000             # Grafana

这个栈启动后得到的是一个完整的 Agent 生产环境:网关层做安全控制,运行层做 Agent 执行和内核级监控,可观测性层让所有行为可见。


三、网关层:MCPZERO 安全网关配置

网关是 Agent 的第一道防线。所有请求先过网关,再做路由。MCPZERO 的核心配置:

# gateway/config.yaml
gateway:
  name: production-gateway
  version: "1.0"

  # ── 入站过滤 ──
  inbound:
    rate_limit: 100/min
    max_prompt_length: 32000
    blocked_keywords:
      - "ignore previous instructions"
      - "forget your rules"
      - "system prompt override"

  # ── 出站控制(Tool ACL) ──
  upstream:
    host: agent-runtime
    port: 8000
    timeout: 60s

  # ── Tool 权限控制 ──
  tools:
    allowlist:                    # 只允许这些工具
      - code_search
      - read_document
      - slack_send
      - github_pr_list
    denylist:                     # 禁止这些工具
      - execute_shell
      - delete_file
      - write_to_production_db
    per_tool_rate_limit:
      slack_send: 10/min
      code_search: 30/min

  # ── Prompt 注入检测 ──
  injection_detection:
    enabled: true
    sensitivity: medium           # low / medium / high
    custom_patterns:
      - "(?i)\\b(drop|truncate|delete)\\s+(table|database)"
      - "(?i)(sudo|chmod\\s+777|rm\\s+-rf)"

  # ── 审计日志 ──
  audit:
    enabled: true
    sink: otlp                   # 推送到 OpenTelemetry
    log_all_tool_calls: true
    log_prompt_hash: true        # 不存原始 prompt,只存 hash

关键设计原则

  • 默认拒绝:tools 必须是 allowlist 模式,不允许的工具自动拦截
  • 每个工具单独限流:slack_send 和 code_search 的速率限制不同,防止一个工具被滥用拖慢其他工具
  • Prompt hash 存储:审计日志不存原始 prompt 内容,只存 hash 用于查重和溯源,兼顾合规和隐私

四、运行时层:Agent Runtime + ClawGuard

4.1 Agent Runtime 架构

Agent Runtime 是个轻量的 HTTP 服务,接收网关转发过来的请求,协调 LLM + 工具调用:

# runtime/app.py — Agent Runtime 入口

from fastapi import FastAPI
from pydantic import BaseModel
from opentelemetry import trace
import httpx, json

app = FastAPI()
tracer = trace.get_tracer("agent-runtime")

class AgentRequest(BaseModel):
    session_id: str
    messages: list
    tools: list[str] = []

@app.post("/chat")
async def agent_chat(req: AgentRequest):
    with tracer.start_as_current_span("agent.run") as span:
        span.set_attribute("session.id", req.session_id)
        span.set_attribute("agent.tools.count", len(req.tools))

        # 1. LLM 判断需要调用哪些工具
        with tracer.start_as_current_span("llm.plan") as plan_span:
            plan = await llm_plan(req.messages, req.tools)
            plan_span.set_attribute("llm.plan.tools", json.dumps(plan))

        # 2. 执行工具调用
        results = []
        for tool_call in plan.tool_calls:
            with tracer.start_as_current_span(f"tool.{tool_call.name}") as tool_span:
                tool_span.set_attribute("tool.name", tool_call.name)
                tool_span.set_attribute("tool.params", json.dumps(tool_call.params))
                result = await execute_tool(tool_call)
                tool_span.set_attribute("tool.success", result.success)
                results.append(result)

        # 3. 生成最终回复
        with tracer.start_as_current_span("llm.respond") as resp_span:
            reply = await llm_generate(req.messages, results)
            resp_span.set_attribute("llm.response.tokens", reply.total_tokens)

        return {"reply": reply.text, "trace_id": span.get_span_context().trace_id}

4.2 ClawGuard 运行时监控

ClawGuard 通过 eBPF 无侵入地监控 Agent 的所有系统调用——文件读写、网络连接、进程创建。不需要改 Agent 代码:

# clawguard/config.yaml
clawguard:
  mode: monitor                 # monitor(只记录)或 enforce(拦截)
  
  # ── 监控范围 ──
  capture:
    - syscall: execve           # 监控进程创建
      target: agent-runtime
    - syscall: connect          # 监控网络连接
      target: agent-runtime
    - syscall: openat           # 监控文件访问
      target: agent-runtime
      path_pattern: "/etc/passwd, /data/production/*"

  # ── 异常规则 ──
  rules:
    - name: "block-unexpected-exec"
      condition: "execve.comm != 'python3' && execve.comm != 'node'"
      action: alert             # monitor 模式仅告警
    - name: "block-prod-db-access"
      condition: 'connect.dest_port == 5432 && connect.dest_ip != "172.20.0.10"'
      action: alert
    - name: "block-sensitive-files"
      condition: 'openat.path matches "/etc/shadow|/home/*/.ssh/*"'
      action: alert

  # ── 输出 ──
  sink:
    type: otlp                  # 推送到 OpenTelemetry
    endpoint: http://otel-collector:4318

ClawGuard 与网关的分工

  • 网关层管「Agent 不应该做什么」——工具级 ACL、Prompt 注入检测
  • ClawGuard 管「Agent 运行时不能做什么」——系统调用级行为监控

两者互补:网关拦截了工具层面的违规,ClawGuard 捕获了绕过网关后的底层异常行为。


五、可观测性层:Trace + Metrics + Dashboard

工程实战系列的 第七篇 详细讲了 Agent 的 Span 设计、Trace 结构和行为基线建模。这里只展示如何把那些概念落地到实际配置。

5.1 OpenTelemetry Collector

# otel/otel-collector.yaml
receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318

processors:
  batch:
    timeout: 3s
    send_batch_size: 512
  # 采样:全量保留 metrics 和错误 trace,
  # 正常 trace 按 10% 采样
  probabilistic_sampler:
    hash_seed: 42
    sampling_percentage: 10

exporters:
  prometheus:
    endpoint: 0.0.0.0:8889
    namespace: agent
    resource_to_telemetry_conversion:
      enabled: true
  debug:
    verbosity: normal

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [probabilistic_sampler, batch]
      exporters: [debug]
    metrics:
      receivers: [otlp]
      processors: [batch]
      exporters: [prometheus, debug]

5.2 Prometheus 指标

Agent Runtime 暴露的关键指标:

# Agent 请求总数
agent_requests_total{agent="assistant-v3", version="1.2.0"}
# 工具调用延迟
agent_tool_latency_seconds{tool="code_search"}
# LLM token 消耗
agent_llm_tokens_total{model="gpt-5.6", type="output", unit="tokens"}
# 工具调用成功率
agent_tool_success_ratio{tool="slack_send"}
# 网关拦截次数
gateway_blocked_requests_total{reason="injection_detected"}
# ClawGuard 告警数
clawguard_alerts_total{rule="block-unexpected-exec"}

5.3 Grafana 仪表盘

预配置的 Agent 监控仪表盘包含四个面板:

面板 1:Agent 健康状态(左上)

├── QPS(最近 5 分钟折线图)
├── P50 / P95 / P99 延迟(柱状图)
├── 错误率(百分比仪表盘)
└── 工具调用成功率(按工具分组的柱状图)

面板 2:网关安全(右上)

├── 拦截请求数(按原因聚合的饼图)
├── 速率限制命中数(时间序列)
├── Prompt 注入检测(最近 10 条审计记录)
└── 活跃连接数(折线图)

面板 3:Runtime 状态(左下)

├── 活跃 Session 数(折线图)
├── 工具调用分布(按工具 + 按时段的热力图)
├── LLM token 消耗速率(按模型分组的面积图)
└── Agent 决策路径(Tool call 链深度分布直方图)

面板 4:ClawGuard eBPF 监控(右下)

├── 系统调用事件率(按类型分组的折线图)
├── 异常规则命中数(柱状图)
├── 敏感文件访问记录(最近 20 条日志)
└── 容器进程白名单偏离报警(表格)

数据源配置和 dashboard JSON 文件直接挂载到 Grafana 容器:

# grafana/datasources/datasource.yaml
apiVersion: 1
datasources:
  - name: Prometheus
    type: prometheus
    access: proxy
    url: http://prometheus:9090
    isDefault: true

六、横向扩缩与生产硬化

6.1 多 Agent 水平扩展

当单个 Agent Runtime 不够用(QPS > 100 或内存 > 4GB),用 docker-compose scale 扩展:

# 扩展到 3 个 Agent Runtime 实例
docker compose up -d --scale agent-runtime=3

# 反向代理做负载均衡
# 修改 gateway 配置,upstream 指向多个 agent-runtime
# gateway/config.yaml — 多实例上游
upstream:
  hosts:
    - agent-runtime:8000
    - agent-runtime-2:8000
    - agent-runtime-3:8000
  strategy: least_connections  # 最小连接优先

6.2 K8s 部署(可选)

对于需要自动扩缩容、滚动更新的团队,K8s 部署模式:

# k8s/agent-runtime-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: agent-runtime
spec:
  replicas: 3
  selector:
    matchLabels:
      app: agent-runtime
  template:
    spec:
      containers:
        - name: runtime
          image: agent-runtime:latest
          resources:
            requests:
              memory: "2Gi"
              cpu: "1"
            limits:
              memory: "4Gi"
              cpu: "2"
          livenessProbe:
            httpGet:
              path: /health
              port: 8000
---
# HPA:CPU > 70% 或 QPS > 100 时自动扩容
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: agent-runtime-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: agent-runtime
  minReplicas: 2
  maxReplicas: 10
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70

6.3 生产硬化清单

项目 配置 优先级
容器非 root 运行 user: nobodyrunAsNonRoot: true P0
网络隔离 API 只监听 agent-net,不暴露到 host P0
密钥管理 .env 文件不 commit,使用 secrets manager P0
资源限制 每个容器设 CPU/memory limits P1
日志轮转 docker-compose 配置 logging: max-size: "10m" max-file: "3" P1
健康检查 每个关键服务配置 healthcheck P1
安全更新 每周自动拉取基础镜像安全更新 P2

七、与安全系列架构的衔接

本系列第七篇讲的是 Agent 可观测性的「数据面」——Trace 怎么设计、Span 怎么打。这一篇是「控制面」——这些 Trace 数据怎么收、存在哪、仪表盘怎么配置。

同时,这篇的 MCPZERO 网关配置和之前安全系列的 从零搭建企业级 MCP 安全架构 是同一个 Gateway 的不同视角——那篇侧重安全策略的声明式配置(OPA/Rego),这篇侧重把 Gateway 放进部署栈(Docker Compose + 可观测性集成)。

三者形成完整体系:

安全系列 2.4: MCPZERO + OPA 策略引擎 → 网关层的安全策略定义
工程系列 07:   OpenTelemetry + LangFuse → 可观测性的数据标准
工程系列 08:   Docker Compose + Grafana → 全栈的落地部署

写在最后

这一篇把工程实战系列的最后一环补上了。回头看整个系列,从 RAG 检索精度开始,经过记忆系统、Tool Calling 可靠性、推理延迟、状态管理、多 Agent 编排、可观测性,到今天这篇部署架构——刚好形成了一个完整的工程闭环。

这个系列停在这里很合适。它不是「写完了所有关于 Agent 工程的东西」,而是「建立了一套覆盖开发到生产的思维框架」。以后碰到任何 Agent 工程问题,都能在这个框架里找到自己的位置:是 RAG 检索的问题?看第一篇。是推理太慢?看第四篇。是不知道出了什么问题?看第七篇和第八篇。

后续重心会转回 AI Agent 安全系列。工程系列的八个主题中已经埋了不少安全伏笔——Tool Calling 容错里的供应链风险,状态管理里的记忆泄露,部署架构里的网关防御——这些会在安全系列里一一展开。


本系列第八篇,全系列终篇。全系列目录:一、RAG 检索精度 → 二、Agent 记忆系统 → 三、Tool Calling 可靠性 → 四、推理延迟优化 → 五、状态管理 → 六、多 Agent 编排 → 七、Agent 可观测性八、生产级 Agent 部署架构

By AI博士 万戈