用 NGINX 和 OpenTelemetry 给 AI Agent 加一道网络边界

2026-07-08 36 预计阅读时间: 1 分钟
来源: cncf.io AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:9 分钟

很多团队对 AI Agent 的第一反应不是“它能做什么”,而是“我敢不敢把它放进网络里”。这个担心很现实:Agent 会读上下文、调用工具、访问内部服务,一旦边界不清,它就可能从“助手”变成一条难审计的网络路径。来源摘要提到的核心问题正是这个:我们并不总是知道 Agent 到底会做什么,所以需要在网络层给它套上可观察、可限制、可回滚的边界。

NGINX 和 OpenTelemetry 的组合适合做这件事:NGINX 负责把 Agent 的出站或入站流量收口,OpenTelemetry 负责把请求链路、延迟、状态码、调用目标这些信号送进观测系统。它不能让 Agent “绝对安全”,但能把不可见的行为变成可检查的流量记录。

Agent 不应该直接裸连内网

传统服务的调用路径通常比较稳定:服务 A 调服务 B,接口、权限、频率都能提前建模。Agent 不一样,它的行为更像一个运行时决策系统:根据 prompt、工具描述、外部响应不断选择下一步。

这带来几个工程风险:

  • 请求目标不稳定:一次任务可能访问多个内部 API 或外部 SaaS。
  • 失败模式更复杂:工具调用失败后,Agent 可能重试、换路径或生成新的请求。
  • 审计粒度容易缺失:如果只看最终业务结果,很难还原它中间访问过什么。
  • 权限容易漂移:把一个宽权限 token 交给 Agent,等于把一大片网络能力交给了模型驱动的流程。

因此更稳妥的做法是:让 Agent 只知道一个受控入口,比如 http://agent-egress.local,由 NGINX 决定它能转发到哪里、记录什么、拒绝什么。

NGINX 做边界,OpenTelemetry 做证据

可以把这个边界拆成两层职责。

NGINX 侧重点是控制:

  • 只允许访问白名单上游。
  • 对敏感路径做拒绝或额外鉴权。
  • 设置超时、请求体大小、并发和速率限制。
  • 统一注入或传递 trace header。

OpenTelemetry 侧重点是观测:

  • 每个 Agent 请求对应一个 trace。
  • 记录上游目标、状态码、耗时和错误。
  • 把 NGINX、Agent Runtime、工具服务放进同一条调用链。
  • 支持事后回答“这个 Agent 到底访问了什么”。

这里的关键不是把 NGINX 当成普通反向代理,而是把它当成 Agent 的网络控制面。Agent 的工具调用越多,这个控制面越有价值。

可以这样实践:一个最小可改造的边界配置

下面示例是一个可改造的本地实验:用 Docker Compose 启动 NGINX、OpenTelemetry Collector 和 Jaeger。假设你的 Agent 只允许访问一个内部工具服务 tool-api:8080,所有请求都必须经过 NGINX。

创建 docker-compose.yml

services:
  nginx:
    image: nginx:1.25
    ports:
      - "8088:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    depends_on:
      - tool-api

  tool-api:
    image: hashicorp/http-echo:1.0
    command:
      - "-listen=:8080"
      - "-text={\"ok\":true,\"service\":\"tool-api\"}"

  otel-collector:
    image: otel/opentelemetry-collector-contrib:0.96.0
    command: ["--config=/etc/otelcol/config.yaml"]
    volumes:
      - ./otel-collector.yaml:/etc/otelcol/config.yaml:ro
    ports:
      - "4317:4317"
      - "4318:4318"
    depends_on:
      - jaeger

  jaeger:
    image: jaegertracing/all-in-one:1.53
    ports:
      - "16686:16686"

创建 nginx.conf。这个版本使用标准 NGINX 镜像可直接运行,先把边界行为和结构跑起来;如果你的 NGINX 构建包含 OpenTelemetry 模块,可以在此基础上接入原生 trace 导出。

events {}

http {
  log_format agent_json escape=json
    '{'
      '"time":"$time_iso8601",'
      '"request_id":"$request_id",'
      '"remote_addr":"$remote_addr",'
      '"method":"$request_method",'
      '"uri":"$request_uri",'
      '"status":$status,'
      '"upstream":"$upstream_addr",'
      '"upstream_status":"$upstream_status",'
      '"request_time":$request_time'
    '}';

  access_log /var/log/nginx/access.log agent_json;

  limit_req_zone $binary_remote_addr zone=agent_limit:10m rate=5r/s;

  upstream allowed_tool_api {
    server tool-api:8080;
  }

  server {
    listen 80;

    location = /tools/search {
      limit_req zone=agent_limit burst=10 nodelay;

      proxy_set_header X-Request-Id $request_id;
      proxy_set_header X-Agent-Boundary "nginx";
      proxy_set_header Host $host;
      proxy_pass http://allowed_tool_api/;
    }

    location / {
      return 403 '{"error":"agent egress denied"}\n';
      add_header Content-Type application/json;
    }
  }
}

创建 otel-collector.yaml。这个 Collector 配置先把 OTLP 接收和 Jaeger 导出准备好,供你的 Agent Runtime 或带 OpenTelemetry 模块的 NGINX 发送 trace。

receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318

processors:
  batch: {}

exporters:
  otlp/jaeger:
    endpoint: jaeger:4317
    tls:
      insecure: true
  logging:
    verbosity: basic

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [batch]
      exporters: [otlp/jaeger, logging]

启动并测试:

docker compose up -d

curl -i http://localhost:8088/tools/search
curl -i http://localhost:8088/admin/secrets

docker compose logs nginx --tail=20

你应该看到 /tools/search 被代理到 tool-api,而 /admin/secrets 被 NGINX 拒绝。随后打开 Jaeger UI:

open http://localhost:16686

如果你的 Agent 应用已经接入 OpenTelemetry,可以把 trace 发到 Collector:

export OTEL_SERVICE_NAME=agent-runtime
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
export OTEL_TRACES_EXPORTER=otlp

需要改的地方很明确:把 tool-api:8080 换成真实工具服务,把 /tools/search 换成 Agent 允许调用的路径,把限流、超时、鉴权按你的风险等级收紧。

不要只记录成功请求

Agent 边界最有价值的日志往往不是成功请求,而是被拒绝的请求、超时请求、重试请求和访问未知路径的请求。这些信号能暴露 prompt 注入、工具描述误导、权限配置过宽等问题。

可以在告警里重点盯这些模式:

  • 403 增多:Agent 正在尝试访问未授权路径,可能是任务设计问题,也可能是输入被诱导。
  • 5xx 增多:工具服务不稳定,Agent 可能进入重试循环。
  • 请求时间变长:上游慢会放大 Agent 的整体任务延迟。
  • 新路径出现:说明工具调用面发生变化,需要重新审查。

边界策略也要分层。开发环境可以偏宽,方便观察 Agent 行为;生产环境应当默认拒绝,只开放经过评审的工具路径。不要把“我们有 trace”误解为“我们可以放开网络”。可观察性是证据,不是权限模型。

落地清单

接入这类边界时,可以按下面顺序推进:

  1. 让 Agent 所有工具调用先经过单一代理入口。
  2. 用 NGINX 白名单限制上游域名、路径和方法。
  3. 给每个请求生成或传递 request id / trace id。
  4. 将 Agent Runtime、NGINX、工具服务的遥测汇总到同一个 OpenTelemetry Collector。
  5. 对拒绝请求、未知路径、异常重试和高延迟设置告警。
  6. 定期审查工具列表,移除不再使用的网络能力。

这套方案的边界也要讲清楚:NGINX 不能理解模型意图,OpenTelemetry 不能阻止恶意调用,它们提供的是网络层收口和行为证据。真正可靠的 Agent 运行环境还需要最小权限 token、工具级鉴权、输入过滤、输出校验和人工审批。把网络边界先立起来,是因为它简单、可验证,而且一旦出事,能让你知道请求从哪里来、去了哪里、为什么被放行或拒绝。


相关推荐