基于十二要素应用的智能体驱动架构:从单体到AI原生应用演进
1. 项目概述从单体应用到智能体驱动的现代应用架构最近在梳理团队内部微服务治理规范时我反复思考一个问题当我们将一个庞大的单体应用拆解成数十个甚至上百个独立的微服务后我们是否真的获得了预期的敏捷性与可维护性还是说我们只是将“巨石”打碎变成了更难管理的“碎石堆”这种思考让我重新审视了经典的“十二要素应用”The Twelve-Factor App方法论。这套诞生于云原生萌芽期的原则定义了现代SaaS应用应具备的十二个特质如代码库、依赖、配置、后端服务、构建发布运行、进程、端口绑定、并发、易处理、开发与生产环境等价、日志、管理进程。它曾是指导我们构建可扩展、可部署Web应用的圣经。然而时代在演进。今天我们构建的应用不再仅仅是处理HTTP请求、操作数据库的“被动响应式”系统。随着大语言模型LLM能力的爆发应用的核心逻辑正越来越多地由“智能体”Agent来驱动。这些智能体具备理解、推理、规划和执行复杂任务的能力它们可能是代码生成助手、数据分析师、自动化工作流引擎或是直接面向用户的对话式界面。传统的“十二要素”原则在智能体成为应用核心组件的今天是否依然完全适用我们又该如何将智能体优雅地集成到现代应用架构中这正是“humanlayer/12-factor-agents”这个项目标题所指向的核心命题。它不是一个具体的工具库或框架而是一个架构理念与设计模式的集合。其核心思想是将“十二要素应用”的原则进行适应性的延伸和重构用以指导我们设计、开发和运维那些以“智能体”为核心构建块的新型应用。它试图回答一个由多个智能体协作构成的、健壮的、可扩展的、易于运维的“智能体驱动型应用”Agent-Driven Application应该长什么样这不仅仅是技术选型问题更是对软件工程范式的一次深刻演进。2. 核心理念拆解当智能体成为一等公民要理解“12-factor-agents”我们必须先跳出将智能体视为“一个函数调用”或“一个外部API服务”的简单视角。在传统应用中我们调用一个机器学习模型通常只是传入数据、获取预测结果模型本身是无状态、被动的计算单元。但智能体不同尤其是具备记忆、工具使用和规划能力的智能体它们本质上是有状态的、主动的、长期运行的“进程”或“服务”。2.1 对经典“十二要素”的继承与扬弃“12-factor-agents”并非全盘否定经典而是有选择地继承、强化并在必要时引入新的原则。强力继承的原则II. 依赖Dependencies 智能体的依赖管理更为复杂。它不仅仅包括Python包更包括其核心——大语言模型如GPT-4、Claude-3、本地部署的Llama等、嵌入模型、向量数据库客户端、各种工具如搜索引擎API、代码执行环境的SDK。必须通过requirements.txt、poetry或conda等工具显式声明并隔离所有依赖确保智能体在任何环境开发、测试、生产中都能获得完全一致的运行时能力。III. 配置Config 智能体对配置的敏感度极高。模型API密钥、端点URL、温度temperature、最大令牌数max_tokens、系统提示词system prompt模板、工具访问权限等都必须通过环境变量来管理。绝对禁止将API密钥硬编码在代码或提示词模板中。一个良好的实践是使用类似pydantic-settings的库定义一个强类型的配置类自动从环境变量加载并验证。VI. 进程Processes 智能体应作为无状态进程运行。这意味着智能体单次会话session或任务task的内部状态如对话历史、中间规划步骤不应存储在进程内存中而应外置到后端服务如Redis、数据库中。这样智能体进程可以随时被终止、重启或横向扩展而不会丢失核心任务上下文。智能体进程本身应是“无状态”的但其处理的“任务”是有状态的。XI. 日志Logs 智能体的可观测性Observability至关重要而日志是其基石。智能体的日志不应只是简单的print语句而应结构化地输出其完整的“思考链”Chain-of-Thought。这包括接收到的用户请求、拆解的子任务、调用的工具及其输入输出、向LLM发送的提示词可脱敏、LLM返回的响应、最终的行动决策等。这些日志应作为事件流event stream输出到stdout然后由运行环境如Docker、Kubernetes收集并汇聚到像ELK、Loki或DataDog这样的集中式日志系统中便于调试、审计和性能分析。需要重新诠释或强化的原则IV. 后端服务Backing Services 智能体的“后端服务”清单极大地扩展了。除了传统的数据库、消息队列、缓存现在还包括LLM即服务 OpenAI API、Anthropic Claude API、Azure OpenAI等。向量数据库 Pinecone、Weaviate、Qdrant、Milvus用于存储和检索智能体的知识RAG。工具服务 外部API如SerpAPI搜索、GitHub API、内部业务系统接口、代码沙箱环境。会话状态存储 用于持久化智能体多轮对话历史的存储服务如Redis。 智能体必须将这些服务都视为附加资源通过配置如连接字符串、API端点来绑定使得在不同环境间切换时例如从本地测试的Mock LLM切换到生产环境的真实LLM只需修改配置而无需改动代码。V. 构建发布运行Build, Release, Run 智能体应用的构建阶段可能包含额外的步骤例如构建 不仅打包代码和依赖还可能包括下载特定的嵌入模型文件、预计算知识库的向量索引如果索引是应用的一部分。发布 将构建产物如Docker镜像与特定的配置环境变量组合形成一个不可变的发布版本。这个版本应明确包含其所依赖的智能体能力描述如“使用GPT-4模型具备网络搜索和Python代码执行工具”。运行 在运行环境中启动一个或多个智能体进程。这些进程可能以Web服务器形式提供HTTP API、消息队列消费者形式、或常驻后台任务的形式运行。需要引入的新考量智能体作为独立生命周期单元 经典“十二要素”关注应用进程。在智能体驱动型应用中每个智能体或智能体集群可能拥有独立的构建、发布、运行生命周期。你可以独立于主Web应用去更新一个负责“代码审查”的智能体而无需重启整个系统。工具的动态发现与绑定 智能体的能力通过“工具”来扩展。如何让智能体在运行时安全、可控地发现和绑定新的工具是一个新的架构挑战。这可能需要一个内部的“工具注册中心”。成本与速率限制管理 LLM API调用是核心成本中心。智能体架构必须内置成本监控和速率限制机制防止因智能体逻辑错误如循环调用或恶意请求导致巨额账单。2.2 智能体驱动型应用的核心架构模式基于以上理念一个典型的“12-factor-agents”风格的应用架构可能呈现以下形态智能体运行时层 这是智能体的执行环境。通常是一个轻量级的服务框架如基于FastAPI负责加载智能体配置、管理工具集、提供API端点或消息监听器。每个智能体进程在这里被实例化。工具抽象层 所有外部能力数据库查询、API调用、代码执行都被封装成统一的“工具”接口。工具的实现需要严格处理错误、超时并生成结构化的输出供智能体理解。工具层应独立于具体的智能体逻辑便于复用和测试。状态与记忆管理层 提供持久化存储服务用于保存智能体的会话状态、任务历史、长期记忆如果具备。这确保了智能体的无状态进程特性。编排与协调层可选但常见 当任务需要多个智能体协作完成时例如一个分析需求需要“数据获取Agent”、“分析Agent”和“报告生成Agent”接力需要一个协调者。这可以是一个简单的消息队列如RabbitMQ、Redis Stream也可以是一个更复杂的编排引擎如LangGraph、微软的AutoGen框架。可观测性层 集成日志、指标Metrics和追踪Tracing。指标包括LLM调用延迟、令牌消耗、工具调用成功率、任务完成时间等。追踪则能完整记录一个用户请求流经多个智能体的全过程。3. 从零搭建一个“12-factor-agents”风格应用的实操指南理论说再多不如动手搭一个。我们以一个简单的“智能数据分析助手”为例它接收用户用自然语言提出的数据问题如“上个月销售额最高的产品是什么”自动编写并执行SQL查询然后生成文字分析报告。3.1 环境与依赖声明首先我们严格遵循“依赖”原则。使用pyproject.tomlPoetry工具来管理依赖这比requirements.txt更现代能更好地处理依赖冲突。[tool.poetry] name data-analysis-agent version 0.1.0 description A 12-factor compliant data analysis agent authors [Your Name youexample.com] [tool.poetry.dependencies] python ^3.10 fastapi ^0.104.0 uvicorn {extras [standard], version ^0.24.0} langchain ^0.0.340 langchain-openai ^0.0.2 openai ^1.3.0 sqlalchemy ^2.0.23 psycopg2-binary ^2.9.9 # 假设使用PostgreSQL pydantic ^2.5.0 pydantic-settings ^2.1.0 redis ^5.0.0 # 用于状态缓存 structlog ^23.2.0 # 结构化日志 [tool.poetry.group.dev.dependencies] pytest ^7.4.0 pytest-asyncio ^0.21.0 httpx ^0.25.0 [build-system] requires [poetry-core] build-backend poetry.core.masonry.api注意这里引入了langchain但它只是一个快速实现智能体逻辑的框架选择。在严格的生产环境中你可能希望基于更底层的SDK如OpenAI Python库构建以减少抽象层带来的复杂性和不可控性。这里为演示方便使用LangChain。3.2 基于环境变量的配置管理使用pydantic-settings创建强类型配置。所有敏感信息和环境相关配置都从这里读取。# config.py from pydantic_settings import BaseSettings, SettingsConfigDict from pydantic import SecretStr class Settings(BaseSettings): # 应用基础配置 app_name: str Data Analysis Agent log_level: str INFO # LLM 配置 openai_api_key: SecretStr openai_model: str gpt-4-turbo-preview openai_base_url: str | None None # 可用于配置代理或自定义端点 # 数据库配置 database_url: SecretStr # 格式postgresql://user:passhost:port/dbname # Redis配置用于缓存会话状态 redis_url: str redis://localhost:6379/0 # 智能体特定配置 agent_system_prompt: str 你是一个专业的数据分析师助手。你的职责是 1. 理解用户关于数据的问题。 2. 根据数据库结构将提供给你编写正确、安全、高效的SQL查询语句。 3. 执行查询如果允许并解释查询结果。 4. 用清晰、易懂的语言向用户总结分析发现。 注意你只能访问被授权的数据库表和视图。任何数据修改INSERT/UPDATE/DELETE操作都必须明确拒绝。 model_config SettingsConfigDict( env_file.env, env_file_encodingutf-8, case_sensitiveFalse ) settings Settings()对应的.env文件切记加入.gitignoreOPENAI_API_KEYsk-你的真实密钥 DATABASE_URLpostgresql://user:passwordlocalhost:5432/analytics_db REDIS_URLredis://redis-host:6379/0 LOG_LEVELDEBUG3.3 构建智能体进程与工具我们创建一个FastAPI应用作为智能体的“进程”载体并定义其工具。# main.py from fastapi import FastAPI, HTTPException from contextlib import asynccontextmanager import structlog from redis import asyncio as aioredis from config import settings from agent.core import AnalysisAgent logger structlog.get_logger() # 生命周期管理 asynccontextmanager async def lifespan(app: FastAPI): # 启动时连接Redis初始化智能体 logger.info(Starting up agent service) app.state.redis aioredis.from_url(settings.redis_url, decode_responsesTrue) app.state.agent AnalysisAgent( llm_api_keysettings.openai_api_key.get_secret_value(), llm_modelsettings.openai_model, llm_base_urlsettings.openai_base_url, database_urlsettings.database_url.get_secret_value(), system_promptsettings.agent_system_prompt, redis_clientapp.state.redis ) await app.state.agent.initialize() logger.info(Agent service started successfully) yield # 关闭时清理连接 logger.info(Shutting down agent service) await app.state.redis.close() logger.info(Agent service shut down) app FastAPI(titlesettings.app_name, lifespanlifespan) app.post(/api/analyze) async def analyze_data(query: str, session_id: str | None None): 核心分析端点。 session_id: 可选用于多轮对话中保持上下文。 try: logger.info(Analysis request received, queryquery, session_idsession_id) result await app.state.agent.run(query, session_id) logger.info(Analysis request completed, session_idsession_id) return {success: True, session_id: result.session_id, answer: result.answer, sql_query: result.sql_query_used} except Exception as e: logger.error(Analysis request failed, errorstr(e), exc_infoTrue) raise HTTPException(status_code500, detailfAnalysis failed: {str(e)}) app.get(/health) async def health_check(): return {status: healthy}智能体的核心实现agent/core.py# agent/core.py import asyncio from typing import Optional from pydantic import BaseModel from langchain.agents import AgentExecutor, create_openai_tools_agent from langchain_openai import ChatOpenAI from langchain.memory import RedisChatMessageHistory from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain.tools import Tool import structlog from .tools import query_database_tool, get_db_schema_tool # 假设的工具实现 logger structlog.get_logger() class AgentResult(BaseModel): session_id: str answer: str sql_query_used: Optional[str] None class AnalysisAgent: def __init__(self, llm_api_key: str, llm_model: str, database_url: str, system_prompt: str, redis_client, llm_base_url: Optional[str] None): self.llm ChatOpenAI( api_keyllm_api_key, modelllm_model, base_urlllm_base_url, temperature0.1, # 分析任务要求低随机性 max_tokens2000 ) self.database_url database_url self.system_prompt system_prompt self.redis_client redis_client self.agent_executor: Optional[AgentExecutor] None async def initialize(self): 初始化工具和智能体执行器。模拟异步初始化如测试数据库连接。 logger.info(Initializing analysis agent) # 1. 定义工具集 tools [ get_db_schema_tool(self.database_url), query_database_tool(self.database_url) # 此工具应包含安全限制如只读 ] # 2. 构建提示词模板 prompt ChatPromptTemplate.from_messages([ (system, self.system_prompt), MessagesPlaceholder(variable_namechat_history), (human, {input}), MessagesPlaceholder(variable_nameagent_scratchpad) ]) # 3. 创建智能体 agent create_openai_tools_agent(self.llm, tools, prompt) # 4. 创建执行器注意LangChain的AgentExecutor默认非异步这里需要适配 self.agent_executor AgentExecutor(agentagent, toolstools, verboseTrue, handle_parsing_errorsTrue) logger.info(Analysis agent initialized) async def run(self, user_query: str, session_id: Optional[str] None) - AgentResult: if not self.agent_executor: raise RuntimeError(Agent not initialized) # 生成或使用传入的session_id current_session_id session_id or fsession_{int(asyncio.get_event_loop().time())} # 从Redis获取历史消息实现多轮对话 message_history RedisChatMessageHistory( session_idcurrent_session_id, urlself.redis_client.connection_pool.connection_kwargs[url] ) chat_history message_history.messages logger.info(Executing agent, session_idcurrent_session_id, queryuser_query) # 执行智能体 # 注意此处需要处理LangChain同步API与异步FastAPI的兼容问题。 # 一个生产级实现应将智能体执行放入线程池或使用完全异步的智能体框架。 try: # 这里为简化使用同步调用。实际应用中应使用 asyncio.to_thread result await asyncio.to_thread( self.agent_executor.invoke, {input: user_query, chat_history: chat_history} ) output result.get(output, No output generated.) # 记录本次交互到历史 message_history.add_user_message(user_query) message_history.add_ai_message(output) # 从结果中提取使用的SQL查询这需要自定义工具的输出格式 sql_used self._extract_sql_from_result(result) logger.info(Agent execution successful, session_idcurrent_session_id) return AgentResult( session_idcurrent_session_id, answeroutput, sql_query_usedsql_used ) except Exception as e: logger.error(Agent execution failed, errorstr(e), exc_infoTrue, session_idcurrent_session_id) raise def _extract_sql_from_result(self, result: dict) - Optional[str]: # 简化实现假设工具调用记录在 intermediate_steps 中 # 实际需要根据具体工具和LangChain版本调整 steps result.get(intermediate_steps, []) for action, observation in steps: if hasattr(action, tool) and action.tool query_database: # 假设action.tool_input包含SQL return action.tool_input.get(query) return None3.4 结构化日志与可观测性我们使用structlog进行结构化日志记录。在config.py中初始化日志配置。# config.py 补充日志配置 import structlog import logging import sys def configure_logging(level: str): timestamper structlog.processors.TimeStamper(fmtiso) shared_processors [ structlog.stdlib.add_log_level, structlog.stdlib.add_logger_name, timestamper, structlog.processors.StackInfoRenderer(), structlog.processors.format_exc_info, structlog.processors.UnicodeDecoder(), structlog.stdlib.ProcessorFormatter.wrap_for_formatter, ] structlog.configure( processorsshared_processors [structlog.stdlib.ProcessorFormatter()], logger_factorystructlog.stdlib.LoggerFactory(), cache_logger_on_first_useTrue, ) formatter structlog.stdlib.ProcessorFormatter( foreign_pre_chainshared_processors, processors[ structlog.stdlib.ProcessorFormatter.remove_processors_meta, structlog.dev.ConsoleRenderer(colorsTrue) if sys.stderr.isatty() else structlog.processors.JSONRenderer() ], ) handler logging.StreamHandler() handler.setFormatter(formatter) root_logger logging.getLogger() root_logger.addHandler(handler) root_logger.setLevel(getattr(logging, level.upper())) # 降低某些嘈杂库的日志级别 for _log in [uvicorn.access, httpx, openai]: logging.getLogger(_log).setLevel(logging.WARNING) return structlog.get_logger() # 在Settings类初始化后调用 logger configure_logging(settings.log_level)这样在代码中通过logger.info(event, keyvalue)记录的日志会输出为结构化的JSON生产环境或彩色控制台信息开发环境非常利于后续的聚合与分析。4. 部署、运维与扩展考量遵循“十二要素”的智能体应用其部署和运维会顺畅很多。4.1 容器化与进程管理为应用创建Dockerfile确保构建、发布、运行阶段分离。# Dockerfile FROM python:3.10-slim as builder WORKDIR /app ENV PYTHONPATH/app ENV PYTHONDONTWRITEBYTECODE1 ENV PYTHONUNBUFFERED1 RUN pip install poetry1.7.0 COPY pyproject.toml poetry.lock ./ RUN poetry export -f requirements.txt --output requirements.txt --without-hashes FROM python:3.10-slim as runtime WORKDIR /app COPY --frombuilder /app/requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . # 以非root用户运行 RUN useradd -m -u 1000 agentuser chown -R agentuser:agentuser /app USER agentuser EXPOSE 8000 # 使用环境变量传递配置 CMD [uvicorn, main:app, --host, 0.0.0.0, --port, 8000]使用Docker Compose或Kubernetes部署时通过环境变量注入所有配置。# docker-compose.yml 示例 version: 3.8 services: analysis-agent: build: . ports: - 8000:8000 environment: - OPENAI_API_KEY${OPENAI_API_KEY} - DATABASE_URLpostgresql://${DB_USER}:${DB_PASSWORD}postgres:5432/${DB_NAME} - REDIS_URLredis://redis:6379/0 - LOG_LEVELINFO depends_on: - postgres - redis restart: unless-stopped # 健康检查 healthcheck: test: [CMD, curl, -f, http://localhost:8000/health] interval: 30s timeout: 10s retries: 3 postgres: image: postgres:15-alpine environment: - POSTGRES_DB${DB_NAME} - POSTGRES_USER${DB_USER} - POSTGRES_PASSWORD${DB_PASSWORD} volumes: - postgres_data:/var/lib/postgresql/data redis: image: redis:7-alpine command: redis-server --appendonly yes volumes: - redis_data:/data volumes: postgres_data: redis_data:4.2 水平扩展与并发由于智能体进程是无状态的会话状态外置到Redis我们可以轻松地水平扩展。在Kubernetes中只需增加Deployment的副本数。负载均衡器如Kubernetes Service将请求分发到不同的智能体实例。所有实例共享同一个Redis和数据库因此会话连续性得以保持。并发处理FastAPI基于异步ASGI能高效处理大量并发请求。但需要注意LLM API调用通常是同步且耗时的几百毫秒到数秒。为了避免阻塞事件循环所有LLM调用和可能阻塞的I/O操作如复杂数据库查询都应使用asyncio.to_thread或移入后台任务队列如Celery、RQ中处理。在上面的简化示例中我们使用了asyncio.to_thread来包装同步的LangChain调用但这只是一个权宜之计。生产系统更推荐使用完全异步的智能体库或将长任务提交到消息队列由后台工作进程处理。4.3 监控与告警可观测性层需要收集日志 如前所述结构化的智能体“思考链”日志。指标 使用Prometheus客户端库如prometheus-fastapi-instrumentator暴露指标。agent_requests_total 请求总数。agent_request_duration_seconds 请求耗时分布。llm_calls_total 按模型、状态分类的LLM调用次数。llm_tokens_used 消耗的提示词和完成令牌数这是成本核心。tool_calls_total 按工具类型分类的调用次数和失败率。追踪 使用OpenTelemetry集成追踪一个用户请求从入口经过智能体、多次LLM调用、多个工具调用的完整链路。基于这些数据在Grafana中建立仪表盘并设置告警规则如LLM API错误率1%、平均响应时间10s、令牌消耗速率异常增高等。5. 常见陷阱、优化与进阶思考在实际落地“12-factor-agents”模式时你会遇到一些经典陷阱。5.1 陷阱一智能体的“有状态”幻觉问题开发者很容易不经意间让智能体进程在内存中维护状态比如将对话历史存储在全局变量或实例属性中。这会导致扩展时状态丢失或者进程重启后上下文断裂。解决 严格遵守“进程无状态”原则。任何需要跨请求持久化的状态对话历史、任务中间结果都必须存储到外部服务Redis、数据库。智能体进程在每次调用时根据session_id从外部存储加载所需上下文。5.2 陷阱二工具调用的安全性与沙箱问题 智能体可以执行SQL、调用外部API、甚至运行代码。如果没有严格的沙箱和权限控制可能导致SQL注入、无限循环、高额API账单或数据泄露。解决SQL工具 使用参数化查询绝对禁止拼接SQL字符串。为智能体连接配置只读数据库用户并限制其只能访问特定的表和视图。代码执行工具 必须在完全隔离的沙箱环境如Docker容器、安全的云函数环境中运行并设置严格的超时、内存和CPU限制。API调用工具 为外部API配置严格的速率限制和预算告警。使用API网关或代理来增加一层控制和监控。工具动态加载 不是所有工具都对所有智能体开放。可以根据智能体的角色或任务类型在运行时动态加载其被授权的工具集。5.3 陷阱三LLM API的脆弱性与成本问题 LLM API可能不稳定、有速率限制且调用成本不菲。智能体的逻辑错误可能导致多次不必要的LLM调用推高成本。解决重试与退避 为LLM调用实现指数退避的重试机制处理暂时的网络故障或API限流。缓存 对频繁出现的、确定性较高的用户查询可以将最终的LLM响应或中间步骤如生成的SQL缓存起来。可以使用Redis键为查询内容的哈希。预算与熔断 实现一个简单的令牌计数器当单个会话或单个用户在一定时间窗口内消耗的令牌超过阈值时熔断该会话的LLM调用返回错误或降级响应。备用模型 配置一个更便宜、更快速的备用模型如GPT-3.5-turbo当主模型GPT-4不可用或响应太慢时可以降级使用。5.4 进阶智能体编排与工作流对于复杂任务单个智能体可能力不从心。这时需要引入编排层。例如使用LangGraph来定义多个智能体之间的协作工作流。# 一个简化的编排示例思路 from langgraph.graph import StateGraph, END from typing import TypedDict class AgentState(TypedDict): question: str sql_query: str | None query_result: str | None analysis: str | None final_answer: str | None def plan_step(state: AgentState): 规划智能体理解问题决定是否需要查询数据。 # 调用LLM判断 # 返回下一个节点名称如 query_db 或 direct_answer pass def query_db_step(state: AgentState): 查询智能体生成并执行SQL。 # 使用专门的SQL生成/执行工具 pass def analyze_step(state: AgentState): 分析智能体解读查询结果。 pass def finalize_step(state: AgentState): 汇总智能体生成最终回答。 pass # 构建图 workflow StateGraph(AgentState) workflow.add_node(planner, plan_step) workflow.add_node(query_db, query_db_step) workflow.add_node(analyzer, analyze_step) workflow.add_node(finalizer, finalize_step) workflow.set_entry_point(planner) workflow.add_conditional_edges(planner, decide_next_node) # 根据规划结果路由 workflow.add_edge(query_db, analyzer) workflow.add_edge(analyzer, finalizer) workflow.add_edge(finalizer, END) app workflow.compile()这种基于图的工作流将复杂的智能体逻辑可视化、模块化每个节点可以独立开发、测试和部署更符合“十二要素”中“进程”独立的概念。5.5 智能体版本管理与A/B测试当智能体成为核心业务逻辑时其迭代升级需要像代码一样被管理。版本化 智能体的配置特别是系统提示词、工具集、依赖的LLM模型都应该有明确的版本号并与Docker镜像标签绑定。A/B测试 可以通过在路由层如API网关根据用户ID或请求特征将流量分发到不同版本的智能体。关键是比较不同版本在关键指标如任务完成率、用户满意度、平均处理时间、成本上的表现。回滚 由于所有配置都来自环境变量且进程无状态回滚到一个旧版本的智能体镜像通常和更新Kubernetes Deployment的镜像标签一样简单。将“十二要素应用”的原则应用于智能体驱动的系统不是一次性的工作而是一个持续的架构纪律。它迫使我们在享受LLM带来的强大能力的同时不放弃软件工程数十年积累下来的关于可维护性、可扩展性和可运维性的宝贵经验。这正是在AI时代构建可靠、可信、可持续的软件系统的关键所在。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2561782.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!