为什么你的下一个 AI Agent 应该是微服务(以及如何使用 C# 和 Docker 构建它)

发布: (2026年2月7日 GMT+8 04:00)
11 分钟阅读
原文: Dev.to

Source: Dev.to

想象一下,一个厨师独自运营一家米其林星级厨房。他会感到力不从心、效率低下,而且一旦生病就可能导致整家餐厅停业。
现在再想象这个厨房被划分为多个专门的工作站——烤架区、糕点站、沙拉准备区。这样速度更快、更具韧性,而且每个工作站都可以独立扩展。

这正是 单体 AI容器化 AI 代理微服务 的根本转变。

这不仅仅是运营上的便利;它是构建能够应对生成式 AI 工作负载不可预测、突发特性的强大多代理系统的架构必然。

核心哲学:无状态、不可变和可扩展

在其核心,AI 代理——无论是复杂的推理引擎还是简单的聊天机器人——都是一个 无状态函数
它接受上下文(提示、历史、工具),并返回响应。关键在于 无状态性。虽然对话本身具有状态,但代理的处理逻辑不应在请求之间保留持久状态。

Source:

容器化:不可变的制品

容器化将您的代理逻辑、依赖项(例如 .NET runtime、ONNX Runtime、CUDA 驱动)和配置打包成一个单一的、不可变的单元。这解决了三个关键的 AI 挑战:

挑战容器的帮助方式
依赖地狱不同的代理可能需要特定的 CUDA 或 PyTorch 版本。容器可以将这些环境相互隔离。
可复现性容器在开发者的笔记本、预发布服务器以及生产的 Kubernetes 集群上运行时表现完全相同。再也不会出现 “在我的机器上可以运行”。
可移植性抽象底层硬件,使得可以在本地使用轻量级 CPU 代理,在云端使用重型 GPU 代理。

编排:空中交通管制

一旦容器化后,你需要一种方式来管理它们的生命周期。Kubernetes 充当空中交通管制,确保:

  • 自愈 – 当容器崩溃时会自动替换。
  • 服务发现 – 代理能够在无需硬编码 IP 的情况下相互发现。
  • 弹性伸缩 – 在高峰负载期间会添加更多实例。

Source:

弹性:服务网格

当多个代理相互交互(例如路由代理、检索代理和生成代理)时,它们形成一个分布式系统。服务网格(例如 Istio)提供了神经系统,处理带指数退避的重试和断路器。这一点至关重要,因为 AI 代理极其不稳定——大语言模型会产生幻觉,网络会超时,GPU 会过载。

Source:

构建 “Hello World” AI 代理微服务

下面是一个 GreetingAgent 的最小化、可投入生产的示例,适用于电商聊天机器人。它演示了核心模式:依赖注入、容器化以及无状态设计。

1️⃣ C# 应用程序 (ASP.NET Core)

using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;

var builder = WebApplication.CreateBuilder(args);

// Register the service for dependency injection
builder.Services.AddSingleton<IGreetingService, GreetingService>();

var app = builder.Build();

// Define the agent endpoint
app.MapGet("/api/greet/{userName}", (string userName, IGreetingService greetingService) =>
{
    var greeting = greetingService.GenerateGreeting(userName);
    return Results.Ok(new { Message = greeting, Timestamp = DateTime.UtcNow });
});

app.Run();

/// <summary>
/// Service contract – enables swapping implementations (e.g., for testing or a real LLM).
/// </summary>
public interface IGreetingService
{
    string GenerateGreeting(string userName);
}

/// <summary>
/// Simple, stateless implementation.
/// </summary>
public class GreetingService : IGreetingService
{
    private static readonly List<string> GreetingTemplates = new()
    {
        "Hello, {0}! Welcome to our AI‑powered platform.",
        "Hi {0}, great to see you today!",
        "Greetings, {0}! How can our AI assist you?"
    };

    public string GenerateGreeting(string userName)
    {
        if (string.IsNullOrWhiteSpace(userName))
            throw new ArgumentException("User name cannot be empty.", nameof(userName));

        var random = Random.Shared;
        var template = GreetingTemplates[random.Next(GreetingTemplates.Count)];
        return string.Format(template, userName);
    }
}

代码中的关键概念

  • IGreetingService 接口 – 实现了依赖倒置;以后可以用真实的大语言模型(LLM)替换实现。
  • 无状态 – 该服务在调用之间不保留任何用户数据。
  • 支持异步 – 在生产环境中 GenerateGreeting 很可能会是 async,并调用外部服务。

2️⃣ Dockerfile(容器化)

# -------------------------------------------------
# Build Stage
# -------------------------------------------------
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src

# Copy csproj and restore as distinct layers
COPY ["GreetingAgentMicroservice.csproj", "./"]
RUN dotnet restore "GreetingAgentMicroservice.csproj"

# Copy everything else and build
COPY . .
RUN dotnet publish "GreetingAgentMicroservice.csproj" \
    -c Release \
    -o /app/publish \
    --no-restore

# -------------------------------------------------
# Runtime Stage
# -------------------------------------------------
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime
WORKDIR /app
COPY --from=build /app/publish .

# Expose the default ASP.NET Core port
EXPOSE 80
ENV ASPNETCORE_URLS=http://+:80

ENTRYPOINT ["dotnet", "GreetingAgentMicroservice.dll"]

Dockerfile 的作用

  1. 多阶段构建 – 在 SDK 镜像中编译应用,然后仅将已发布的输出复制到轻量的 ASP.NET 运行时镜像中。
  2. 不可变性 – 最终镜像是单一、带版本号的制品,可部署到任何环境。
  3. 端口暴露EXPOSE 80 告诉编排系统(Kubernetes、Docker Swarm)该服务监听的端口。

3️⃣ 部署到 Kubernetes(高层概览)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: greeting-agent
spec:
  replicas: 3               # Horizontal scaling
  selector:
    matchLabels:
      app: greeting-agent
  template:
    metadata:
      labels:
        app: greeting-agent
    spec:
      containers:
      - name: greeting-agent
        image: your-registry/greeting-agent:1.0.0
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: greeting-agent-svc
spec:
  selector:
app: greeting-agent
ports:
- protocol: TCP
  port: 80
  targetPort: 80
type: ClusterIP

使用 kubectl apply -f deployment.yaml 部署该清单。Kubernetes 将处理 Pod 生命周期、自我修复,以及在三个副本之间的负载均衡。

回顾

职责
Agent code无状态业务逻辑(例如 GreetingService)。
Container不可变的制品,打包运行时、依赖和配置。
Orchestrator (K8s)生命周期管理、扩展、服务发现。
Service Mesh (optional)弹性模式——重试、熔断、可观测性。

通过将每个 AI 能力视为 containerized micro‑service,您可以获得演进、扩展和从故障中恢复的灵活性——这正是现代生成式 AI 工作负载所需的。 🚀

Source:

Dockerfile(多阶段构建)

# --- Build Stage ---
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src

# Copy csproj and restore dependencies
COPY ["GreetingAgentMicroservice.csproj", "./"]
RUN dotnet restore "GreetingAgentMicroservice.csproj"

# Copy the rest of the source code and build
COPY . .
RUN dotnet publish "GreetingAgentMicroservice.csproj" -c Release -o /app/publish

# --- Final Runtime Stage ---
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS final
WORKDIR /app
COPY --from=build /app/publish .
ENTRYPOINT ["dotnet", "GreetingAgentMicroservice.dll"]

为什么采用这种结构?

  • 多阶段构建: 最终镜像只包含已编译的应用程序和运行时,不包含 SDK 或源代码。这大幅降低了攻击面并显著减小镜像体积。
  • 不可变性: 镜像是一个自包含的制品,在任何环境中运行时都完全一致。

3. 伸缩与高级模式

一旦部署到 Kubernetes 集群,我们就可以应用前面讨论的高级模式。

水平 Pod 自动伸缩 (HPA)

配置 Kubernetes,根据 CPU 使用率或自定义指标(例如请求队列长度)来伸缩 GreetingAgent Pod 的数量。

Sidecar 模式

如果我们想把每一次推理请求记录到 Prometheus,可以为 Pod 附加一个 sidecar 容器。sidecar 与我们的代理并行运行,抓取指标而不影响业务逻辑。

Init Container 模式

假设我们的代理运行需要一个 2 GB 的模型文件。一个 Init Container 可以在主代理容器启动 之前 从 Azure Blob Storage 下载该文件,确保代理只有在文件完全就绪后才开始运行。

结论:从单体到分布式智能

通过将 AI 代理视为无状态、容器化的微服务,我们将它们从脆弱的黑盒转变为分布式系统中具有弹性、可扩展性的组件。这种架构使我们能够:

  • 精确扩展: 仅在需要时分配昂贵的 GPU 资源。
  • 隔离故障: 推荐代理的崩溃不会导致定价代理宕机。
  • 更快创新: 在不重新部署整个应用的情况下,替换单个代理中的模型或框架。

使用 C# 和现代 .NET 提供了实现这些企业级模式所需的强大语言特性——接口、async/await 和依赖注入——并且能够以干净的方式实现。

让我们讨论

  • 无状态性 vs. 内存: AI 代理通常需要对话历史才能发挥作用。如何在保持代理处理逻辑本身无状态且可扩展的前提下,构建对话的“状态”架构?
  • 冷启动问题: 将大型语言模型加载到 GPU 内存可能需要数分钟。你会如何在 Kubernetes 中设计扩展策略,以应对突发流量高峰,避免用户超时?

这里展示的概念和代码直接取自电子书 Cloud‑Native AI & Microservices: Containerizing Agents and Scaling Inference 中的完整路线图。

你可以在这里找到它:Leanpub.com

查看所有其他关于 Python、TypeScript、C# 的编程电子书:Leanpub.com – 作者页面

如果你愿意,也可以在 Amazon 上几乎找到全部作品。

Back to Blog

相关文章

阅读更多 »

量子安全计算的不安全性

量子隐私:为何某些量子技巧无法保护秘密安全 人们曾希望量子技术能够阻止陌生人窃取秘密,就像智能卡……