文章目录
-
- 本文章限时免费,整个专栏写完后将转为收费专栏,请勿转载
- 一、实战前置:准备工作(2分钟搞定)
-
- [1. 完善requirements.txt,新增监控依赖](#1. 完善requirements.txt,新增监控依赖)
- [2. 确认框架目录结构](#2. 确认框架目录结构)
- 二、核心实战1:搭建生产级日志系统(问题排查的核心)
-
- [1. 编写日志工具类(utils/log_utils.py)](#1. 编写日志工具类(utils/log_utils.py))
- [2. 核心日志功能解析](#2. 核心日志功能解析)
- [3. 框架全量接入日志系统(替换所有print/原生logging)](#3. 框架全量接入日志系统(替换所有print/原生logging))
- [4. 配置环境变量(.env),新增日志配置](#4. 配置环境变量(.env),新增日志配置)
- 三、核心实战2:添加监控指标埋点(实时掌握服务状态)
-
- [1. 编写监控工具类(utils/metrics_utils.py)](#1. 编写监控工具类(utils/metrics_utils.py))
- [2. 核心监控指标解析](#2. 核心监控指标解析)
- [3. 框架全量接入监控指标(API+Agent)](#3. 框架全量接入监控指标(API+Agent))
- [4. 本地测试监控指标](#4. 本地测试监控指标)
- 四、实战3:对接Docker+Prometheus+Grafana(可视化监控)
-
- [1. 改造Dockerfile,适配日志和监控](#1. 改造Dockerfile,适配日志和监控)
- [2. 重新构建Docker镜像,运行容器](#2. 重新构建Docker镜像,运行容器)
- [3. 快速搭建Prometheus+Grafana(Docker一键部署)](#3. 快速搭建Prometheus+Grafana(Docker一键部署))
- 五、生产级实战技巧:日志排查+监控告警
-
- [1. 日志排查核心技巧(快速定位问题)](#1. 日志排查核心技巧(快速定位问题))
- [2. 监控告警核心技巧(提前发现异常)](#2. 监控告警核心技巧(提前发现异常))
- 六、实战总结
目前国内还是很缺AI人才的,希望更多人能真正加入到AI行业,共同促进行业进步。想要系统学习AI知识的朋友可以看看我的教程http://blog.csdn.net/jiangjunshow,教程通俗易懂,风趣幽默,从深度学习基础原理到各领域实战应用都有讲解。
本文章限时免费,整个专栏写完后将转为收费专栏,请勿转载
各位小伙伴,咱们的多Agent框架现在能打包、能部署、能对外提供API服务了,但如果现在服务出问题了,比如:API接口响应突然变慢、Agent执行任务报错、容器CPU占用飙到100%,你能快速找到原因吗?
如果没加日志和监控,大概率只能对着终端翻零散的输出,或者凭经验瞎猜,排查问题耗时又费力,这在生产环境绝对是大忌!而完善的日志+监控,就是服务的"眼睛和耳朵":
- 日志:把服务运行的每一步(请求接收、Agent执行、参数传递、错误信息)都按规范记录下来,出问题了顺着日志一查就知道根因;
- 监控:实时采集服务的核心指标(QPS、响应时间、错误率、CPU/内存占用、Agent执行次数),指标异常时能第一时间发现,还能通过可视化面板直观看到服务状态。
这篇咱们就给多Agent框架+API服务做生产级可观测性改造 ,分两大块实战:一是搭建分级日志系统 ,实现日志分级、链路追踪、文件持久化;二是添加监控指标埋点,实现核心指标采集、对接Prometheus。所有代码都无缝衔接之前的API封装和Docker部署,还会教你如何快速对接Grafana做可视化监控,最后给出日志排查和监控告警的实战技巧,让你的Agent服务真正做到"问题可查、状态可监控"~
一、实战前置:准备工作(2分钟搞定)
本次实战不用新增太多依赖,只需要安装一个监控指标采集的库,同时保持框架目录结构不变,新增utils/目录存放日志和监控的工具类,准备工作就两步:
1. 完善requirements.txt,新增监控依赖
在原有依赖基础上,新增prometheus-client(Prometheus官方Python客户端,用于指标埋点和采集),这是2025年Python服务对接Prometheus的标配,轻量无侵入:
txt
# requirements.txt 新增监控依赖
python>=3.8,<3.12
# 原有依赖省略...
fastapi==0.112.0
uvicorn==0.30.6
pyjwt==2.8.0
# 新增监控指标采集依赖
prometheus-client==0.20.0
# 可选:日志轮转,避免单个日志文件过大
logging-handlers-rotating-file==0.1.0
2. 确认框架目录结构
新增utils/目录,用于存放日志工具类log_utils.py和监控工具类metrics_utils.py,目录结构如下(和之前完全兼容):
multi-agent-framework/ # 框架根目录
├── api/ # API封装目录
│ └── api_server.py # API核心代码
├── agents/ # Agent目录
├── framework/ # 框架核心目录
├── tools/ # 工具目录
├── utils/ # 新增:工具类目录
│ ├── log_utils.py # 新增:日志工具类(分级、链路追踪)
│ └── metrics_utils.py # 新增:监控工具类(指标埋点、采集)
├── .env # 环境变量
├── requirements.txt # 依赖清单
├── Dockerfile # Docker打包配置
└── .dockerignore # 忽略文件
二、核心实战1:搭建生产级日志系统(问题排查的核心)
日志是排查问题的根本,生产级的日志系统绝对不能是简单的print(),必须满足分级记录、链路追踪、文件持久化、日志轮转 四个核心要求,咱们用Python内置的logging模块做封装,实现一个通用的日志工具类,整个框架+API服务统一使用,保证日志格式一致、可追溯。
1. 编写日志工具类(utils/log_utils.py)
这是日志系统的核心,实现日志分级(DEBUG/INFO/WARNING/ERROR/CRITICAL)、请求ID链路追踪、日志文件轮转、格式标准化,代码可直接复制,每一行都有注释:
python
# utils/log_utils.py 生产级日志工具类
import logging
import os
import uuid
from logging.handlers import RotatingFileHandler
from datetime import datetime
from dotenv import load_dotenv
# 加载环境变量
load_dotenv()
# 日志配置(从环境变量读取,方便Docker部署动态修改)
LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO").upper() # 日志级别:DEBUG/INFO/WARNING/ERROR/CRITICAL
LOG_DIR = os.getenv("LOG_DIR", "logs") # 日志存储目录
LOG_MAX_BYTES = int(os.getenv("LOG_MAX_BYTES", 1024 * 1024 * 50)) # 单个日志文件最大50M
LOG_BACKUP_COUNT = int(os.getenv("LOG_BACKUP_COUNT", 10)) # 日志文件最多保留10个
LOG_FORMAT = (
"%(asctime)s - %(name)s - %(levelname)s - %(request_id)s - %(message)s"
) # 标准化日志格式,包含请求ID
# 创建日志目录
os.makedirs(LOG_DIR, exist_ok=True)
def get_logger(name: str, request_id: str = None) -> logging.Logger:
"""
获取日志实例
:param name: 日志名称(模块/类名,方便定位)
:param request_id: 请求ID(链路追踪,所有日志关联同一个请求ID)
:return: 配置好的logger
"""
# 初始化logger
logger = logging.getLogger(name)
logger.setLevel(LOG_LEVEL)
# 避免重复添加处理器
if logger.handlers:
return logger
# 定义日志格式器:添加请求ID,无请求ID则生成默认值
class RequestIDFilter(logging.Filter):
def __init__(self, req_id):
self.req_id = req_id or f"default-{uuid.uuid4().hex[:8]}"
def filter(self, record):
record.request_id = self.req_id
return True
# 格式器
formatter = logging.Formatter(LOG_FORMAT, datefmt="%Y-%m-%d %H:%M:%S")
# 请求ID过滤器
req_filter = RequestIDFilter(request_id)
# 1. 控制台处理器:输出到终端,方便开发调试
console_handler = logging.StreamHandler()
console_handler.setLevel(LOG_LEVEL)
console_handler.setFormatter(formatter)
console_handler.addFilter(req_filter)
# 2. 文件处理器:日志持久化,支持轮转(避免文件过大)
log_file = os.path.join(LOG_DIR, f"agent_{datetime.now().strftime('%Y%m%d')}.log")
file_handler = RotatingFileHandler(
filename=log_file,
maxBytes=LOG_MAX_BYTES,
backupCount=LOG_BACKUP_COUNT,
encoding="utf-8"
)
file_handler.setLevel(LOG_LEVEL)
file_handler.setFormatter(formatter)
file_handler.addFilter(req_filter)
# 添加处理器
logger.addHandler(console_handler)
logger.addHandler(file_handler)
# 禁用向上传播,避免重复打印
logger.propagate = False
return logger
# 测试代码(开发时用,生产环境注释)
if __name__ == "__main__":
logger = get_logger("test", request_id="test123456")
logger.debug("这是DEBUG日志:详细调试信息")
logger.info("这是INFO日志:正常运行信息")
logger.warning("这是WARNING日志:潜在风险提示")
logger.error("这是ERROR日志:程序执行错误")
logger.critical("这是CRITICAL日志:严重错误,服务可能中断")
2. 核心日志功能解析
这个日志工具类是生产级标准,比直接用logging强太多,核心亮点:
- 日志分级:按DEBUG/INFO/WARNING/ERROR/CRITICAL分级,生产环境可设为INFO,只记录关键信息,避免日志冗余;开发环境设为DEBUG,查看详细调试信息。
- 链路追踪 :所有日志都包含
request_id,一个请求的所有操作(接收请求→Agent执行→返回结果)都用同一个request_id,出问题时按request_id搜日志,直接定位整个请求链路。 - 日志轮转:单个日志文件最大50M,最多保留10个,避免日志文件无限增大占满磁盘。
- 格式标准化:所有日志统一格式「时间-日志名-级别-request_id-内容」,方便后续日志分析工具(如ELK)解析。
- 全局通用:整个框架所有模块都可以调用这个工具类,保证日志格式一致。
3. 框架全量接入日志系统(替换所有print/原生logging)
接下来把日志工具类接入到API服务、Agent框架核心、各个Agent 中,实现全链路日志记录,核心原则:关键操作记INFO,参数/调试记DEBUG,异常记ERROR,严重错误记CRITICAL。
(1)API服务接入日志(api/api_server.py)
替换原有原生logging,使用新的日志工具类,保证每个请求的日志都关联同一个request_id:
python
# api/api_server.py 改造日志部分
import uuid
# 替换原有logging导入,导入新的日志工具类
from utils.log_utils import get_logger
# 注释原有logging配置代码...
# 初始化FastAPI应用
app = FastAPI(
title="多Agent框架API服务",
description="2025优化版多Agent框架标准化API,带日志和监控",
version="1.0.0"
)
# 全局初始化Agent框架(不变)
MASTER_AGENT = MasterAgent()
SLAVE_AGENTS = [SearchSlaveAgent(), CodeSlaveAgent(), WriteSlaveAgent()]
AGENT_FRAMEWORK = MultiAgentFramework(
collab_mode="parallel",
agents={"master": MASTER_AGENT, "slaves": SLAVE_AGENTS}
)
# 新增:每次请求生成唯一request_id,并存入请求状态
@app.middleware("http")
async def add_request_id(request: Request, call_next):
# 生成唯一request_id(UUID8位,简洁且唯一)
request_id = uuid.uuid4().hex[:8]
# 将request_id存入请求状态
request.state.request_id = request_id
# 执行后续请求
response = await call_next(request)
# 响应头添加request_id,方便调用方追溯
response.headers["X-Request-ID"] = request_id
return response
# 改造健康检查接口
@app.get("/health", summary="服务健康检查")
async def health_check(request: Request):
# 获取当前请求的request_id
request_id = request.state.request_id
# 获取日志实例,关联request_id
logger = get_logger("api.health", request_id)
try:
logger.info("健康检查请求接收,开始检查服务状态")
if AGENT_FRAMEWORK:
logger.info("服务健康检查通过,框架初始化正常")
return BaseResponse(
code=200,
msg="多Agent框架API服务运行正常",
data={"service_status": "running"},
request_id=request_id,
timestamp=datetime.now().strftime("%Y-%m-%d %H:%M:%S")
)
else:
logger.critical("服务健康检查失败,Agent框架初始化失败")
raise Exception("Agent框架初始化失败")
except Exception as e:
logger.error(f"服务健康检查失败,错误原因:{str(e)}", exc_info=True)
return BaseResponse(
code=500,
msg=f"健康检查失败:{str(e)}",
data=None,
request_id=request_id,
timestamp=datetime.now().strftime("%Y-%m-%d %H:%M:%S")
)
# 改造Agent执行接口(核心)
@app.post("/api/v1/agent/run", summary="Agent单任务执行")
async def run_agent(request: Request, task: AgentTaskRequest, user_info: dict = Depends(verify_access_token)):
request_id = request.state.request_id
logger = get_logger("api.run_agent", request_id)
try:
# 记录请求信息(关键参数记INFO,详细参数记DEBUG)
logger.info(f"Agent任务请求接收,用户ID:{user_info['user_id']},协作模式:{task.collab_mode}")
logger.debug(f"Agent任务详细参数:user_task={task.user_task[:100]}...")
# 校验协作模式
valid_modes = ["parallel", "master_slave", "division", "competition"]
if task.collab_mode not in valid_modes:
logger.warning(f"非法协作模式请求,请求模式:{task.collab_mode},合法模式:{valid_modes}")
raise HTTPException(status_code=400, detail=f"非法协作模式,可选:{valid_modes}")
# 执行Agent任务
logger.info("开始执行Agent任务,框架协作模式已切换")
frame = MultiAgentFramework(collab_mode=task.collab_mode, agents={"master": MASTER_AGENT, "slaves": SLAVE_AGENTS})
task_result = frame.run(task.user_task)
# 记录执行成功
logger.info("Agent任务执行完成,开始返回结果")
logger.debug(f"Agent任务执行结果:{task_result[:100]}...")
return BaseResponse(
code=200,
msg="Agent任务执行成功",
data={"collab_mode": task.collab_mode, "task_result": task_result},
request_id=request_id,
timestamp=datetime.now().strftime("%Y-%m-%d %H:%M:%S")
)
except HTTPException as e:
logger.warning(f"Agent任务执行失败,参数错误:{e.detail}")
return BaseResponse(
code=400,
msg=f"参数错误:{e.detail}",
data=None,
request_id=request_id,
timestamp=datetime.now().strftime("%Y-%m-%d %H:%M:%S")
)
except Exception as e:
logger.error(f"Agent任务执行失败,服务器内部错误:{str(e)}", exc_info=True)
return BaseResponse(
code=500,
msg=f"服务器内部错误:{str(e)[:100]}",
data=None,
request_id=request_id,
timestamp=datetime.now().strftime("%Y-%m-%d %H:%M:%S")
)
(2)Agent框架核心接入日志(framework/core.py)
在框架核心执行逻辑中添加日志,记录Agent的创建、任务分发、执行结果,方便定位框架内部问题:
python
# framework/core.py 接入日志工具类
from utils.log_utils import get_logger
class MultiAgentFramework:
def __init__(self, collab_mode: str, agents: dict):
# 初始化日志(框架核心模块,无request_id时用默认值)
self.logger = get_logger("framework.core")
self.collab_mode = collab_mode
self.master_agent = agents.get("master")
self.slave_agents = agents.get("slaves", [])
self.logger.info(f"MultiAgent框架初始化完成,协作模式:{collab_mode},从Agent数量:{len(self.slave_agents)}")
self.logger.debug(f"框架初始化详细信息:master_agent={self.master_agent.__class__.__name__},slave_agents={[a.__class__.__name__ for a in self.slave_agents]}")
def run(self, user_task: str):
self.logger.info(f"框架开始执行用户任务,任务描述:{user_task[:50]}...")
try:
# 根据协作模式执行任务(原有逻辑不变)
if self.collab_mode == "parallel":
self.logger.info("采用并行协作模式,开始分发任务到所有从Agent")
result = self._run_parallel(user_task)
elif self.collab_mode == "master_slave":
self.logger.info("采用主从协作模式,主Agent开始分发任务")
result = self._run_master_slave(user_task)
else:
self.logger.warning(f"未识别的协作模式:{self.collab_mode},使用默认并行模式")
result = self._run_parallel(user_task)
self.logger.info("用户任务执行完成,框架返回执行结果")
return result
except Exception as e:
self.logger.error(f"框架执行用户任务失败,错误原因:{str(e)}", exc_info=True)
raise e
# 改造并行执行方法
def _run_parallel(self, user_task: str):
self.logger.debug("开始并行执行任务,创建异步执行池")
# 原有异步执行逻辑...
self.logger.debug("并行任务执行完成,合并所有从Agent结果")
return merged_result
(3)各个Agent接入日志(agents/master_agent.py/agents/slave_agents.py)
在主Agent和从Agent中添加日志,记录任务接收、工具调用、结果返回,定位单个Agent的问题:
python
# agents/master_agent.py 接入日志
from utils.log_utils import get_logger
class MasterAgent:
def __init__(self):
self.logger = get_logger("agent.master")
self.logger.info("主Agent初始化完成,开始加载任务分发策略")
def dispatch_task(self, user_task: str, slave_agents: list):
self.logger.info(f"主Agent接收分发任务,用户任务:{user_task[:50]}...")
self.logger.debug(f"从Agent列表:{[a.__class__.__name__ for a in slave_agents]}")
# 原有任务分发逻辑...
self.logger.info("主Agent任务分发完成,返回各从Agent执行任务")
return task_list
# agents/slave_agents.py 接入日志
from utils.log_utils import get_logger
class SearchSlaveAgent:
def __init__(self):
self.logger = get_logger("agent.slave.search")
self.logger.info("检索从Agent初始化完成,加载向量检索工具")
def run(self, task: str):
self.logger.info(f"检索从Agent接收执行任务,任务:{task[:50]}...")
try:
# 原有检索逻辑...
self.logger.info("检索从Agent任务执行完成,返回检索结果")
self.logger.debug(f"检索结果:{result[:100]}...")
return result
except Exception as e:
self.logger.error(f"检索从Agent执行失败,错误原因:{str(e)}", exc_info=True)
raise e
# 其他从Agent(CodeSlaveAgent/WriteSlaveAgent)按同样方式接入...
4. 配置环境变量(.env),新增日志配置
在.env文件中新增日志相关配置,方便在Docker中动态修改,不用改代码:
env
# .env 日志配置
LOG_LEVEL=INFO
LOG_DIR=logs
LOG_MAX_BYTES=52428800 # 50M
LOG_BACKUP_COUNT=10
# 原有配置...
OPENAI_API_KEY=sk-xxx
API_HOST=0.0.0.0
API_PORT=8000
三、核心实战2:添加监控指标埋点(实时掌握服务状态)
光有日志还不够,日志是"出问题后查原因",而监控是"出问题前发现异常",生产级服务必须有核心指标的实时监控。咱们用prometheus-client给API服务和Agent框架添加核心指标埋点 ,采集的指标包含API服务指标 和Agent框架指标两大类,同时在FastAPI中添加Prometheus指标采集接口,让Prometheus能自动拉取指标。
1. 编写监控工具类(utils/metrics_utils.py)
封装监控指标的创建和更新方法,实现指标统一管理,支持的指标类型包含:计数器(Counter)、仪表盘(Gauge)、直方图(Histogram),这是Prometheus最常用的三种指标类型,代码可直接复制:
python
# utils/metrics_utils.py 生产级监控工具类
from prometheus_client import Counter, Gauge, Histogram, generate_latest, CONTENT_TYPE_LATEST
from prometheus_client.core import REGISTRY
from fastapi import Response
# ===================== 指标定义(统一管理,避免重复创建) =====================
# 【API服务核心指标】
# API请求总数(Counter:只增不减,记录累计次数)
API_REQUEST_TOTAL = Counter(
"agent_api_request_total",
"Total number of API requests",
["endpoint", "method", "status_code"] # 标签:接口、请求方法、状态码
)
# API请求响应时间(Histogram:统计分布,如P50/P95/P99)
API_REQUEST_DURATION = Histogram(
"agent_api_request_duration_seconds",
"API request duration in seconds",
["endpoint", "method"]
)
# 服务当前活跃请求数(Gauge:可增可减,记录当前值)
API_ACTIVE_REQUESTS = Gauge(
"agent_api_active_requests",
"Number of active API requests",
["endpoint"]
)
# 【Agent框架核心指标】
# Agent任务执行总数(Counter)
AGENT_TASK_TOTAL = Counter(
"agent_task_total",
"Total number of Agent tasks executed",
["collab_mode", "status"] # 标签:协作模式、执行状态(成功/失败)
)
# Agent任务执行时间(Histogram)
AGENT_TASK_DURATION = Histogram(
"agent_task_duration_seconds",
"Agent task execution duration in seconds",
["collab_mode"]
)
# 从Agent数量(Gauge)
AGENT_SLAVE_COUNT = Gauge(
"agent_slave_count",
"Number of slave Agents"
)
# 框架资源占用:CPU使用率(Gauge)、内存使用率(Gauge)
AGENT_CPU_USAGE = Gauge(
"agent_cpu_usage_percent",
"Agent framework CPU usage percent"
)
AGENT_MEM_USAGE = Gauge(
"agent_mem_usage_percent",
"Agent framework memory usage percent"
)
# ===================== 指标操作工具方法 =====================
def record_api_request(endpoint: str, method: str, status_code: int, duration: float):
"""
记录API请求指标
:param endpoint: 接口地址
:param method: 请求方法(GET/POST)
:param status_code: 响应状态码
:param duration: 响应时间(秒)
"""
API_REQUEST_TOTAL.labels(endpoint=endpoint, method=method, status_code=status_code).inc()
API_REQUEST_DURATION.labels(endpoint=endpoint, method=method).observe(duration)
def record_agent_task(collab_mode: str, status: str, duration: float):
"""
记录Agent任务执行指标
:param collab_mode: 协作模式
:param status: 执行状态(success/failed)
:param duration: 执行时间(秒)
"""
AGENT_TASK_TOTAL.labels(collab_mode=collab_mode, status=status).inc()
AGENT_TASK_DURATION.labels(collab_mode=collab_mode).observe(duration)
def set_agent_resource_metrics(cpu: float, mem: float):
"""
设置Agent框架资源占用指标
:param cpu: CPU使用率(0-100)
:param mem: 内存使用率(0-100)
"""
AGENT_CPU_USAGE.set(cpu)
AGENT_MEM_USAGE.set(mem)
# ===================== FastAPI指标采集接口 =====================
async def metrics():
"""
Prometheus指标采集接口,默认地址:/metrics
Prometheus会定时调用此接口拉取指标
"""
return Response(
content=generate_latest(REGISTRY),
media_type=CONTENT_TYPE_LATEST
)
# 初始化从Agent数量指标
def init_agent_metrics(slave_count: int):
"""初始化Agent框架指标"""
AGENT_SLAVE_COUNT.set(slave_count)
AGENT_CPU_USAGE.set(0.0)
AGENT_MEM_USAGE.set(0.0)
2. 核心监控指标解析
采集的指标分为API服务指标 和Agent框架指标,覆盖服务运行的核心维度,Prometheus拉取后可做可视化和告警,关键指标说明:
| 指标类型 | 指标名称 | 指标含义 | 作用 |
|---|---|---|---|
| 计数器 | agent_api_request_total | API请求累计数 | 统计各接口QPS、错误率 |
| 直方图 | agent_api_request_duration | API请求响应时间 | 分析接口响应速度,看P95/P99 |
| 仪表盘 | agent_api_active_requests | 活跃请求数 | 监控服务并发量 |
| 计数器 | agent_task_total | Agent任务执行累计数 | 统计各模式任务执行次数/成功率 |
| 直方图 | agent_task_duration | Agent任务执行时间 | 分析Agent执行效率 |
| 仪表盘 | agent_cpu/mem_usage | 框架CPU/内存使用率 | 监控服务资源占用 |
3. 框架全量接入监控指标(API+Agent)
将监控指标埋点接入到API服务和Agent框架中,实现请求/任务指标自动记录 、资源指标定时采集,核心是在关键节点(请求开始/结束、任务开始/结束)调用监控工具类的方法更新指标。
(1)API服务接入监控指标(api/api_server.py)
添加请求耗时统计、活跃请求数统计,在请求开始和结束时更新指标,同时添加资源指标定时采集:
python
# api/api_server.py 接入监控指标
import time
import psutil
from fastapi import BackgroundTasks
# 导入监控工具类
from utils.metrics_utils import (
record_api_request, API_ACTIVE_REQUESTS,
init_agent_metrics, set_agent_resource_metrics,
metrics as prom_metrics
)
# 全局初始化Agent指标(从Agent数量)
init_agent_metrics(len(SLAVE_AGENTS))
# 注册Prometheus指标采集接口
app.add_api_route("/metrics", prom_metrics, methods=["GET"], summary="Prometheus指标采集接口")
# 新增:定时采集Agent框架资源指标(后台任务,每5秒执行一次)
def collect_resource_metrics():
"""采集CPU和内存使用率,后台定时执行"""
# 获取当前进程的资源占用
process = psutil.Process()
cpu_usage = process.cpu_percent(interval=1)
mem_usage = process.memory_percent()
# 设置资源指标
set_agent_resource_metrics(cpu_usage, mem_usage)
# 改造请求中间件,添加请求耗时和活跃请求数统计
@app.middleware("http")
async def add_request_id_and_metrics(request: Request, call_next):
request_id = uuid.uuid4().hex[:8]
request.state.request_id = request_id
# 监控:记录请求开始时间,增加活跃请求数
start_time = time.time()
endpoint = request.url.path
method = request.method
API_ACTIVE_REQUESTS.labels(endpoint=endpoint).inc()
# 执行请求
response = await call_next(request)
# 监控:减少活跃请求数,计算请求耗时,记录API指标
API_ACTIVE_REQUESTS.labels(endpoint=endpoint).dec()
duration = time.time() - start_time
status_code = response.status_code
record_api_request(endpoint, method, status_code, duration)
# 添加response header
response.headers["X-Request-ID"] = request_id
response.headers["X-Request-Duration"] = f"{duration:.3f}s"
return response
# 改造Agent执行接口,添加Agent任务指标记录
@app.post("/api/v1/agent/run", summary="Agent单任务执行")
async def run_agent(request: Request, task: AgentTaskRequest, user_info: dict = Depends(verify_access_token), background_tasks: BackgroundTasks = BackgroundTasks()):
# 添加上台任务,定时采集资源指标
background_tasks.add_task(collect_resource_metrics)
request_id = request.state.request_id
logger = get_logger("api.run_agent", request_id)
try:
logger.info(f"Agent任务请求接收,用户ID:{user_info['user_id']},协作模式:{task.collab_mode}")
# 记录Agent任务开始时间
task_start = time.time()
# 原有逻辑:校验模式、执行任务
valid_modes = ["parallel", "master_slave", "division", "competition"]
if task.collab_mode not in valid_modes:
logger.warning(f"非法协作模式请求:{task.collab_mode}")
raise HTTPException(status_code=400, detail=f"非法协作模式,可选:{valid_modes}")
frame = MultiAgentFramework(collab_mode=task.collab_mode, agents={"master": MASTER_AGENT, "slaves": SLAVE_AGENTS})
task_result = frame.run(task.user_task)
# 记录Agent任务执行成功指标
task_duration = time.time() - task_start
record_agent_task(collab_mode=task.collab_mode, status="success", duration=task_duration)
logger.info(f"Agent任务执行完成,耗时:{task_duration:.3f}秒")
return BaseResponse(
code=200,
msg="Agent任务执行成功",
data={"collab_mode": task.collab_mode, "task_result": task_result, "task_duration": f"{task_duration:.3f}s"},
request_id=request_id,
timestamp=datetime.now().strftime("%Y-%m-%d %H:%M:%S")
)
except Exception as e:
# 记录Agent任务执行失败指标
task_duration = time.time() - task_start
record_agent_task(collab_mode=task.collab_mode, status="failed", duration=task_duration)
logger.error(f"Agent任务执行失败,耗时:{task_duration:.3f}秒,错误原因:{str(e)}", exc_info=True)
return BaseResponse(
code=500,
msg=f"服务器内部错误:{str(e)[:100]}",
data=None,
request_id=request_id,
timestamp=datetime.now().strftime("%Y-%m-%d %H:%M:%S")
)
# 改造其他接口(/api/v1/token/get),按同样方式添加指标记录...
(2)Agent框架核心接入监控指标(framework/core.py)
在框架任务执行逻辑中,确保指标能正确记录,同时可在从Agent执行中添加更细粒度的指标(可选):
python
# framework/core.py 完善监控指标
class MultiAgentFramework:
def run(self, user_task: str):
self.logger.info(f"框架开始执行用户任务,任务描述:{user_task[:50]}...")
try:
# 原有执行逻辑...
if self.collab_mode == "parallel":
self.logger.info("采用并行协作模式,开始分发任务到所有从Agent")
result = self._run_parallel(user_task)
else:
result = self._run_master_slave(user_task)
self.logger.info("用户任务执行完成,框架返回执行结果")
return result
except Exception as e:
self.logger.error(f"框架执行用户任务失败,错误原因:{str(e)}", exc_info=True)
raise e
4. 本地测试监控指标
启动API服务后,访问http://127.0.0.1:8000/metrics,就能看到所有采集的指标,Prometheus会定时拉取这个地址的指标,本地测试时能看到指标正常输出,说明埋点成功:
bash
# 启动API服务
python api/api_server.py
# 访问指标接口
curl http://127.0.0.1:8000/metrics
四、实战3:对接Docker+Prometheus+Grafana(可视化监控)
咱们的日志和监控已经接入框架,接下来对接Docker,让容器运行时能正常输出日志、暴露指标接口,再快速搭建Prometheus+Grafana实现指标可视化监控,这是生产级的标准搭配,2025年各大云厂商都支持一键部署。
1. 改造Dockerfile,适配日志和监控
修改根目录的Dockerfile,确保日志目录挂载、指标接口暴露,不用大改,只需要确认3点:
dockerfile
# Dockerfile 适配日志和监控
FROM python:3.9-slim AS builder
# 原有构建逻辑不变...
FROM python:3.9-slim
WORKDIR /app
# 原有逻辑不变...
# 确认日志和数据目录创建,权限正确
RUN mkdir -p /app/logs /app/data && chmod 777 /app/logs /app/data
# 暴露API端口和指标接口端口(其实是同一个8000端口)
EXPOSE 8000
# 环境变量:确保日志和监控配置能从环境变量读取
ENV PYTHONUNBUFFERED=1
ENV LOG_LEVEL=INFO
ENV LOG_DIR=/app/logs
# 健康检查:原有逻辑不变...
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD python -c "import requests; requests.get('http://localhost:8000/health')" || exit 1
# 启动命令:运行API服务,包含日志和监控
CMD ["python", "-m", "api.api_server"]
2. 重新构建Docker镜像,运行容器
执行命令重新构建镜像,运行容器时一定要挂载日志目录,避免日志文件随容器删除而丢失:
bash
# 重新构建镜像
docker build -t multi-agent-framework:monitor-v1.0 .
# 生产级运行容器,挂载日志和数据目录,暴露8000端口
docker run -d \
--name agent-monitor-service \
--restart=always \
-p 8000:8000 \
-v $(pwd)/logs:/app/logs \
-v $(pwd)/data:/app/data \
-e OPENAI_API_KEY="sk-xxx" \
multi-agent-framework:monitor-v1.0
# 查看容器日志,确认日志正常输出
docker logs -f agent-monitor-service
3. 快速搭建Prometheus+Grafana(Docker一键部署)
用Docker Compose一键搭建Prometheus+Grafana,不用手动配置,步骤超简单:
(1)创建docker-compose.yml文件
在任意目录创建docker-compose.yml,配置Prometheus和Grafana:
yaml
version: '3.8'
services:
# Prometheus:指标采集和存储
prometheus:
image: prom/prometheus:v2.53.0 # 2025最新稳定版
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus-data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
restart: always
# Grafana:指标可视化和告警
grafana:
image: grafana/grafana:10.4.0 # 2025最新稳定版
ports:
- "3000:3000"
volumes:
- grafana-data:/var/lib/grafana
environment:
- GF_SECURITY_ADMIN_PASSWORD=123456 # Grafana初始密码
restart: always
depends_on:
- prometheus
volumes:
prometheus-data:
grafana-data:
(2)创建Prometheus配置文件(prometheus.yml)
配置Prometheus拉取Agent服务的指标,替换targets为你的Agent服务IP:端口:
yaml
global:
scrape_interval: 5s # 每5秒拉取一次指标,生产环境可设为15s
evaluation_interval: 5s
rule_files:
- "alert_rules.yml" # 告警规则文件(可选)
scrape_configs:
# 采集Prometheus自身指标
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
# 采集Agent框架API服务指标(核心)
- job_name: 'multi-agent-framework'
static_configs:
- targets: ['你的服务器IP:8000'] # 替换为Agent服务的IP和端口
metrics_path: '/metrics' # 指标采集接口
scrape_interval: 5s
(3)一键启动Prometheus+Grafana
bash
# 启动服务
docker-compose up -d
# 查看服务状态
docker-compose ps
(4)Grafana可视化配置
- 访问Grafana:
http://你的服务器IP:3000,账号admin,密码123456(配置文件中设置的); - 添加数据源:选择
Prometheus,地址填http://prometheus:9090,保存; - 导入仪表盘:可导入Python/FastAPI通用仪表盘(ID:12900),或自定义仪表盘,添加咱们的Agent指标(如
agent_api_request_total、agent_task_duration),实现可视化监控。
五、生产级实战技巧:日志排查+监控告警
1. 日志排查核心技巧(快速定位问题)
- 按request_id排查 :调用方反馈问题时,让其提供响应头的
X-Request-ID,按该ID搜索日志,直接定位整个请求链路; - 按日志级别排查:先看ERROR/CRITICAL日志,快速找到错误点,再看INFO/DEBUG日志补充上下文;
- 按模块名排查 :日志名包含模块(如
api.run_agent、agent.slave.search),定位问题出在API层还是Agent层; - 使用日志检索工具:生产环境不要手动翻日志文件,用ELK/PLG栈(Elasticsearch+Logstash+Kibana)做日志检索,支持模糊搜索、按时间筛选。
2. 监控告警核心技巧(提前发现异常)
- 配置核心告警规则:在Prometheus中配置告警规则(如API错误率>5%、接口P95响应时间>3s、CPU使用率>80%持续5分钟);
- 配置告警接收方式:Grafana对接钉钉/企业微信/邮件/短信,告警触发时自动推送;
- 设置仪表盘大屏:在公司监控室挂Grafana大屏,核心指标(QPS、错误率、响应时间、资源占用)一目了然;
- 做指标趋势分析:通过Grafana查看指标趋势,比如QPS随时间的变化,提前做好扩容准备。
六、实战总结
这篇咱们给多Agent框架+API服务搭建了生产级的日志系统和监控体系,实现了服务的"可观测、可排查、可监控",核心成果如下:
- 搭建了分级日志系统,实现日志分级、链路追踪、文件轮转,出问题时能通过request_id快速定位根因,再也不用瞎猜;
- 添加了核心监控指标埋点,覆盖API服务和Agent框架的所有关键维度,能实时掌握服务的QPS、响应时间、资源占用、任务执行情况;
- 无缝对接Docker+Prometheus+Grafana,实现了容器化运行+指标采集+可视化监控,达到工业级生产标准;
- 所有配置都从环境变量读取,支持Docker动态修改,不用改代码,部署超方便。
到这里,咱们的多Agent框架已经完成了开发→优化→打包→部署→API封装→监控日志 的全流程改造,从一个本地脚本变成了可对外提供服务、可跨系统调用、可监控、可排查的生产级AI服务,能真正7×24小时稳定运行在生产环境,为业务创造价值~
目前国内还是很缺AI人才的,希望更多人能真正加入到AI行业,共同促进行业进步。想要系统学习AI知识的朋友可以看看我的教程http://blog.csdn.net/jiangjunshow,教程通俗易懂,风趣幽默,从深度学习基础原理到各领域实战应用都有讲解。
