monitoring.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. """Prometheus 监控指标"""
  2. from prometheus_client import Counter, Histogram, Gauge, generate_latest
  3. from fastapi import APIRouter, Response
  4. import time
  5. import functools
  6. llm_calls_total = Counter(
  7. "llm_calls_total", "Total LLM API calls",
  8. ["model", "status"],
  9. )
  10. llm_duration_seconds = Histogram(
  11. "llm_duration_seconds", "LLM call duration",
  12. ["model"],
  13. buckets=(0.1, 0.5, 1.0, 2.0, 5.0, 10.0, 30.0),
  14. )
  15. llm_tokens_total = Counter(
  16. "llm_tokens_total", "Total tokens used",
  17. ["model", "type"],
  18. )
  19. rag_retrievals_total = Counter(
  20. "rag_retrievals_total", "Total RAG retrievals",
  21. ["method"],
  22. )
  23. rag_duration_seconds = Histogram(
  24. "rag_duration_seconds", "RAG retrieval duration",
  25. ["method"],
  26. buckets=(0.01, 0.05, 0.1, 0.5, 1.0),
  27. )
  28. agent_calls_total = Counter(
  29. "agent_calls_total", "Total Agent invocations",
  30. ["agent_type"],
  31. )
  32. agent_duration_seconds = Histogram(
  33. "agent_duration_seconds", "Agent execution duration",
  34. ["agent_type"],
  35. buckets=(0.5, 1.0, 2.0, 5.0, 10.0, 30.0, 60.0),
  36. )
  37. java_calls_total = Counter(
  38. "java_calls_total", "Total calls to Java backend",
  39. ["endpoint", "status"],
  40. )
  41. java_duration_seconds = Histogram(
  42. "java_duration_seconds", "Java backend call duration",
  43. ["endpoint"],
  44. buckets=(0.01, 0.05, 0.1, 0.5, 1.0, 2.0),
  45. )
  46. kb_sync_duration = Gauge(
  47. "kb_sync_duration_seconds", "Last knowledge base sync duration"
  48. )
  49. kb_sync_documents = Gauge(
  50. "kb_sync_documents_total", "Documents processed in last sync"
  51. )
  52. def monitor_agent(agent_type: str):
  53. """Agent 性能监控装饰器"""
  54. def decorator(func):
  55. @functools.wraps(func)
  56. async def wrapper(*args, **kwargs):
  57. agent_calls_total.labels(agent_type=agent_type).inc()
  58. start = time.perf_counter()
  59. try:
  60. result = await func(*args, **kwargs)
  61. agent_duration_seconds.labels(agent_type=agent_type).observe(
  62. time.perf_counter() - start)
  63. return result
  64. except Exception as e:
  65. agent_duration_seconds.labels(agent_type=agent_type).observe(
  66. time.perf_counter() - start)
  67. raise
  68. return wrapper
  69. return decorator
  70. router = APIRouter(tags=["monitoring"])
  71. @router.get("/metrics")
  72. async def metrics():
  73. return Response(
  74. content=generate_latest(),
  75. media_type="text/plain; charset=utf-8",
  76. )
  77. @router.get("/api/v1/health")
  78. async def detailed_health():
  79. """详细健康检查 (含组件状态)"""
  80. from app.config import settings
  81. status = {"status": "ok", "components": {}}
  82. try:
  83. import os
  84. chroma_path = settings.chroma_db_path
  85. status["components"]["chromadb"] = {
  86. "status": "ok",
  87. "path": chroma_path,
  88. "exists": os.path.exists(chroma_path),
  89. }
  90. except Exception as e:
  91. status["components"]["chromadb"] = {"status": "error", "message": str(e)}
  92. status["status"] = "degraded"
  93. try:
  94. from langchain_openai import ChatOpenAI
  95. llm = ChatOpenAI(
  96. model=settings.llm_model,
  97. api_key=settings.llm_api_key,
  98. base_url=settings.llm_base_url,
  99. max_tokens=5,
  100. )
  101. await llm.ainvoke("ping")
  102. status["components"]["llm"] = {"status": "ok"}
  103. except Exception as e:
  104. status["components"]["llm"] = {"status": "error", "message": str(e)}
  105. status["status"] = "degraded"
  106. try:
  107. from app.tools.java_client import JavaClient
  108. client = JavaClient()
  109. jc = await client._get_client()
  110. resp = await jc.post("/api/admin-auth/login-by-password", json={})
  111. if resp.status_code == 401:
  112. status["components"]["java_backend"] = {"status": "ok", "detail": "需认证(正常)"}
  113. elif resp.status_code == 200:
  114. status["components"]["java_backend"] = {"status": "ok"}
  115. else:
  116. status["components"]["java_backend"] = {"status": "error", "code": resp.status_code, "detail": f"HTTP {resp.status_code}"}
  117. status["status"] = "degraded"
  118. except Exception as e:
  119. status["components"]["java_backend"] = {"status": "error", "detail": str(e)}
  120. status["status"] = "degraded"
  121. return status