AI Agent监控与可观测性:构建可信赖的智能体系统

为什么Agent需要可观测性? 传统软件的行为是确定性的——同样输入产生同样输出。但Agent的行为由LLM驱动,具有随机性和非确定性。这使得Agent系统更需要完善的可观测性——才能知道Agent"在做什么"、“为什么这么做”、“花了多少钱”。 可观测性三大支柱 1. 日志(Logging) 记录Agent每一步的行为: { "timestamp": "2026-07-16T10:00:01.234Z", "session_id": "sess_abc123", "agent": "research_agent", "action": "tool_call", "tool": "web_search", "input": {"query": "AI芯片市场2025"}, "output": {"results": 5, "top_result": "..."}, "duration_ms": 1234, "tokens": {"input": 25, "output": 0}, "cost_usd": 0.0001, "status": "success" } 日志设计原则: 结构化(JSON而非纯文本) 可关联(session_id + step_id) 可过滤(level, agent, tool等字段) 采样策略(全量记录关键步骤,采样记录调试信息) 2. 指标(Metrics) 量化Agent运行状态: 业务指标: 任务成功率 用户满意度(评分/反馈) 平均完成时间 平均步数 技术指标: LLM调用延迟(p50/p95/p99) 工具调用延迟 Token消耗量 API错误率 每任务成本 资源指标: GPU利用率 内存占用 并发会话数 队列深度 3. 追踪(Tracing) 记录一次完整任务的全链路: Trace: sess_abc123 ├── Span 1: task_planning (1.2s) │ ├── LLM call: gpt-4 (0.8s, 500 tokens) │ └── Output: [search, analyze, report] ├── Span 2: web_search (0.6s) │ ├── tool: search_api │ └── Result: 5 items ├── Span 3: content_analysis (2.1s) │ ├── LLM call: gpt-4 (1.8s, 2000 tokens) │ └── Output: analysis_summary ├── Span 4: report_generation (1.5s) │ ├── LLM call: gpt-4 (1.2s, 1500 tokens) │ └── Output: final_report.md Total: 5.4s, 4000 tokens, $0.06 监控架构 数据采集层 # Agent执行包装器 class TracedAgent: def __init__(self, agent, tracer): self.agent = agent self.tracer = tracer @trace async def run(self, input_data): with self.tracer.span("agent_run") as span: span.set_attr("input", input_data) result = await self.agent.run(input_data) span.set_attr("output", result) span.set_attr("tokens", self.agent.total_tokens) span.set_attr("cost", self.agent.total_cost) return result @trace async def call_tool(self, tool, args): with self.tracer.span("tool_call") as span: span.set_attr("tool", tool.name) span.set_attr("args", args) start = time.time() result = await tool.run(args) duration = time.time() - start span.set_attr("duration_ms", duration * 1000) span.set_attr("result", result) return result 数据存储层 数据类型 存储方案 保留期 日志 Elasticsearch / Loki 30天 指标 Prometheus / InfluxDB 90天 追踪 Jaeger / Tempo 7天 会话记录 PostgreSQL / MongoDB 按需 可视化层 实时仪表盘: ...

2026-07-16 · 2 min · 406 words · 硅基 AGI 探索者

AI Agent的日志分析与故障排查:从黑盒到白盒

AI Agent是天然的"黑盒"——它做了什么、为什么这么做、为什么出错了,这些问题在生产环境中极难回答。一个完善的日志与可观测性体系,是把黑盒变白盒的关键。本文将系统介绍AI Agent的日志设计与故障排查方法论。 一、Agent可观测性的特殊挑战 1.1 与传统服务日志的区别 传统服务的日志是线性的:请求A → 处理 → 响应A。但Agent的执行是非线性的: 用户输入 → 意图理解 → 规划 → 工具调用1 → 工具调用2 → 反思 → → 修正规划 → 工具调用3 → 总结 → 输出 每一步都可能分叉、回退、重试。传统的"一条请求一条日志"模式无法捕捉这种复杂流程。 1.2 核心观测维度 L1: 基础设施层 — GPU利用率、内存、网络 L2: API服务层 — 请求量、延迟、错误率 L3: Agent逻辑层 — 意图、规划、工具调用、反思 L4: LLM推理层 — prompt内容、生成内容、token消耗 L5: 业务效果层 — 任务完成率、用户满意度 大部分团队只关注L1和L2,但Agent故障的根因往往在L3和L4。 二、结构化日志设计 2.1 Trace-Tree模型 Agent的执行过程天然是树状结构,应当用Trace-Tree而非线性日志来记录: @dataclass class AgentTrace: trace_id: str # 全局追踪ID session_id: str # 会话ID root_span: AgentSpan # 根span @dataclass class AgentSpan: span_id: str parent_id: str name: str # e.g., "intent_understanding", "tool_call" span_type: str # think / act / observe / reflect input: dict output: dict start_time: float end_time: float status: str # success / error / timeout metadata: dict # 额外信息 children: List[AgentSpan] 2.2 关键Span类型 class SpanTypes: INTENT = "intent" # 意图理解 PLANNING = "planning" # 规划 TOOL_CALL = "tool_call" # 工具调用 LLM_CALL = "llm_call" # LLM推理 REFLECTION = "reflection" # 反思 DELEGATION = "delegation" # 委托子Agent OUTPUT = "output" # 最终输出 2.3 日志记录实现 class AgentLogger: def __init__(self): self.tracer = DistributedTracer() @contextmanager def span(self, name, span_type, parent_id=None): span = AgentSpan( span_id=generate_id(), parent_id=parent_id, name=name, span_type=span_type, start_time=time.time(), input={}, output={}, status="running", metadata={}, children=[] ) try: yield span span.status = "success" except Exception as e: span.status = "error" span.metadata["error"] = str(e) span.metadata["traceback"] = traceback.format_exc() raise finally: span.end_time = time.time() self.tracer.report(span) def log_llm_call(self, span, prompt, response, model, tokens): """记录LLM调用的详细信息""" span.metadata["llm"] = { "model": model, "prompt_tokens": tokens["prompt"], "completion_tokens": tokens["completion"], "prompt_hash": hash(prompt[:100]), # 隐私保护 "response_length": len(response), "latency_ms": span.duration_ms } def log_tool_call(self, span, tool_name, args, result, success): """记录工具调用""" span.metadata["tool"] = { "name": tool_name, "args_hash": hash(str(args)), # 参数指纹 "result_size": len(str(result)), "success": success } 2.4 完整Trace示例 { "trace_id": "trace_abc123", "session_id": "sess_xyz", "duration_ms": 4500, "status": "success", "spans": [ { "name": "intent_understanding", "type": "intent", "duration_ms": 320, "input": {"user_message": "帮我查下最近的报销进度"}, "output": {"intent": "query_reimbursement", "entities": {}}, "children": [ { "name": "llm_call", "type": "llm_call", "duration_ms": 310, "metadata": { "model": "gpt-4-turbo", "prompt_tokens": 850, "completion_tokens": 45 } } ] }, { "name": "planning", "type": "planning", "duration_ms": 280, "output": {"plan": ["call_finance_api", "summarize_result"]} }, { "name": "tool_call:finance_api", "type": "tool_call", "duration_ms": 1200, "metadata": { "tool": "finance_api", "args": {"user_id": "***", "date_range": "30d"}, "success": true } }, { "name": "llm_call:summarize", "type": "llm_call", "duration_ms": 890, "metadata": { "model": "gpt-4-turbo", "prompt_tokens": 1200, "completion_tokens": 180 } } ] } 三、常见故障模式与排查 3.1 意图误判 症状:Agent执行了正确的工具但回答了错误的问题 ...

2026-07-13 · 4 min · 796 words · 硅基 AGI 探索者

AI Agent的监控与告警系统设计:从指标到洞察

AI Agent的监控与告警系统设计:从指标到洞察 传统软件监控关注"是否在工作"——CPU利用率、内存占用、请求延迟。AI Agent监控需要回答更深的问题——“是否在正常工作”——一个返回200状态码的Agent可能正在给出有害回复。本文分享AI Agent监控告警系统的完整设计。 监控指标体系 基础设施层指标 这是最传统的监控层,和其他微服务监控类似: GPU利用率:计算利用率、显存占用、温度 推理吞吐:每秒token生成数、每秒请求数 延迟分布:P50/P90/P95/P99响应时间 错误率:HTTP错误率、超时率、内部错误率 队列深度:等待处理的请求积压数量 这些指标使用Prometheus采集,Grafana展示。设置阈值告警——GPU利用率>95%持续5分钟、P95延迟>阈值、错误率>1%。 Agent行为层指标 这是AI Agent特有的监控层,关注Agent的行为质量: 工具调用成功率:每次工具调用是否成功完成 工具调用分布:哪些工具被频繁使用、哪些被冷落 对话轮次分布:完成任务平均需要多少轮对话 上下文窗口利用率:对话是否经常接近上下文限制 任务完成率:用户意图是否被成功满足 用户中断率:用户在Agent完成前中断的比例 这些指标反映Agent的"行为健康度"。一个工具调用成功率从95%突然下降到80%的Agent,即使基础设施层一切正常,也需要告警。 内容质量层指标 最深层的监控关注Agent输出的内容质量: 安全审核通过率:输出通过安全过滤的比例 幻觉率:在事实性陈述中出现错误信息的频率(通过抽样检测) 用户满意度信号:点赞/点踩比例、投诉率 重复率:Agent输出是否过于模式化(多个用户得到几乎相同的回复) 多样性指标:输出内容的词汇丰富度和句式变化 内容质量指标的采集更难——需要定期抽样人工审核或使用LLM-as-Judge自动评估。 异常检测设计 基于阈值的静态告警 最简单的告警——指标超过预设阈值就告警。适用于有明确上下界的指标: GPU利用率>95% → 告警 错误率>1% → 告警 安全审核通过率<95% → 告警 阈值告警的局限是"一刀切"——不同时段、不同负载下,正常值范围不同。 基于基线的动态告警 更智能的方法是建立动态基线: 时间序列基线:学习指标的历史模式,当前值偏离基线2σ时告警 同环比对:和上周同时间、昨天同时间对比,变化超过阈值告警 多指标关联:多个指标同时异常时告警(降低单指标噪声) 动态基线能捕捉阈值法遗漏的异常——比如GPU利用率从30%突升到70%虽未超阈值,但变化幅度异常。 基于行为的语义异常 最先进的异常检测关注Agent行为的语义变化: 工具使用模式变化:Agent突然开始频繁调用某个之前很少用的工具 对话长度突增:平均对话轮次从5轮突增到15轮,可能意味着Agent在"挣扎" 输出分布偏移:Agent输出的长度分布、情感分布突然变化 这类异常最难检测,但往往最有价值——它能在用户投诉之前发现问题。 告警分级与路由 不是所有告警都需要立刻处理。我们设计了四级告警体系: P0:紧急(立即响应) Agent完全不可用(错误率>50%) 安全审核通过率<80%(大量有害输出) 数据泄露风险(日志中出现敏感信息) 响应时间:5分钟内确认,15分钟内介入。 P1:重要(1小时内响应) P95延迟超过基线3倍 任务完成率下降>10% GPU利用率持续>95%超过10分钟 响应时间:1小时内确认,4小时内修复。 P2:警告(工作时间响应) 工具调用成功率下降>5% 用户满意度信号下降 上下文利用率接近上限 响应时间:下一工作日内处理。 ...

2026-07-13 · 1 min · 128 words · 硅基 AGI 探索者
AI可观测性

AI系统可观测性搭建

AI系统可观测性的三个支柱 传统软件的可观测性关注延迟、吞吐、错误率。AI系统需要额外关注:token消耗、模型质量漂移、幻觉率、工具调用成功率等AI特有指标。 指标采集 核心指标定义 from prometheus_client import Counter, Histogram, Gauge # 请求指标 REQUEST_TOTAL = Counter('ai_requests_total', 'Total AI requests', ['model', 'status']) REQUEST_LATENCY = Histogram('ai_request_duration_seconds', 'Request duration', ['model']) ACTIVE_REQUESTS = Gauge('ai_active_requests', 'Active requests') # Token指标 TOKEN_INPUT = Counter('ai_tokens_input_total', 'Input tokens', ['model']) TOKEN_OUTPUT = Counter('ai_tokens_output_total', 'Output tokens', ['model']) TOKEN_COST = Counter('ai_token_cost_usd', 'Token cost in USD', ['model']) # 质量指标 HALLUCINATION_RATE = Gauge('ai_hallucination_rate', 'Hallucination rate', ['model']) TOOL_CALL_SUCCESS = Counter('ai_tool_calls_total', 'Tool calls', ['tool', 'status']) # 缓存指标 CACHE_HIT_RATE = Gauge('ai_cache_hit_rate', 'Cache hit rate') 中间件实现 class ObservabilityMiddleware: def __init__(self, app): self.app = app async def __call__(self, request): ACTIVE_REQUESTS.inc() start = time.time() model = request.json.get("model", "unknown") try: response = await self.app(request) duration = time.time() - start REQUEST_TOTAL.labels(model=model, status="success").inc() REQUEST_LATENCY.labels(model=model).observe(duration) if "usage" in response: TOKEN_INPUT.labels(model=model).inc(response["usage"]["prompt_tokens"]) TOKEN_OUTPUT.labels(model=model).inc(response["usage"]["completion_tokens"]) cost = self.calculate_cost(model, response["usage"]) TOKEN_COST.labels(model=model).inc(cost) return response except Exception as e: REQUEST_TOTAL.labels(model=model, status="error").inc() raise finally: ACTIVE_REQUESTS.dec() def calculate_cost(self, model, usage): pricing = {"gpt-4": 0.03, "qwen3-32b": 0.002, "claude-3": 0.015} rate = pricing.get(model, 0.01) return (usage["prompt_tokens"] + usage["completion_tokens"]) / 1000 * rate 链路追踪 from opentelemetry import trace tracer = trace.get_tracer(__name__) class TracedLLMCall: def __init__(self, llm_client): self.client = llm_client async def chat(self, messages, **kwargs): with tracer.start_as_current_span("llm_chat") as span: span.set_attribute("llm.model", kwargs.get("model", "unknown")) span.set_attribute("llm.messages_count", len(messages)) span.set_attribute("llm.temperature", kwargs.get("temperature", 0.7)) start = time.time() response = await self.client.chat(messages, **kwargs) duration = time.time() - start span.set_attribute("llm.duration_ms", duration * 1000) span.set_attribute("llm.prompt_tokens", response["usage"]["prompt_tokens"]) span.set_attribute("llm.completion_tokens", response["usage"]["completion_tokens"]) return response 质量监控 class QualityMonitor: def __init__(self, sample_rate=0.05): self.sample_rate = sample_rate # 采样5%的请求做质量评估 async def evaluate_response(self, query, response, context=None): """异步评估响应质量""" import random if random.random() > self.sample_rate: return None metrics = {} # 幻觉检测 metrics["hallucination"] = await self.detect_hallucination(response, context) # 相关性 metrics["relevance"] = await self.score_relevance(query, response) # 毒性检测 metrics["toxicity"] = await self.detect_toxicity(response) # 记录到Prometheus if metrics["hallucination"]: HALLUCINATION_RATE.inc() else: HALLUCINATION_RATE.dec(0.01) return metrics 告警规则 # Prometheus告警规则 groups: - name: ai_alerts rules: - alert: HighErrorRate expr: rate(ai_requests_total{status="error"}[5m]) / rate(ai_requests_total[5m]) > 0.05 for: 5m annotations: summary: "AI error rate > 5%" - alert: HighLatency expr: histogram_quantile(0.95, ai_request_duration_seconds_bucket) > 30 for: 10m annotations: summary: "P95 latency > 30s" - alert: HighCost expr: rate(ai_token_cost_usd[1h]) > 100 for: 30m annotations: summary: "Hourly cost > $100" - alert: ModelDegradation expr: ai_hallucination_rate > 0.15 for: 1h annotations: summary: "Hallucination rate > 15%" Grafana仪表板 关键面板: ...

2026-07-02 · 2 min · 394 words · 硅基 AGI 探索者
AI性能监控

AI性能监控体系:让系统运行在最佳状态

引言 AI应用的监控比传统软件复杂得多。除了常规的系统指标(CPU、内存、延迟),还需要监控AI特有的指标(输出质量、幻觉率、安全事件)。2026年,AI性能监控已经发展成为一个专门的领域。本文将系统介绍AI性能监控体系的构建。 AI监控的独特需求 传统软件监控 vs AI监控 维度 传统软件 AI应用 延迟 毫秒级 秒级(可接受) 错误类型 崩溃、超时 幻觉、不当内容 质量指标 功能正确性 输出准确性、相关性 成本 服务器成本 API调用成本(按token计) 变化来源 代码部署 代码+模型版本+提示 AI监控的核心指标 AI监控指标体系 ├── 性能指标 │ ├── 延迟(P50/P95/P99) │ ├── 吞吐量 │ └── 并发数 ├── 质量指标 │ ├── 输出准确率 │ ├── 幻觉率 │ ├── 拒绝率 │ └── 用户满意度 ├── 成本指标 │ ├── 每次请求成本 │ ├── 每日总成本 │ └── token效率 ├── 安全指标 │ ├── 有害内容率 │ ├── 注入攻击次数 │ └── 数据泄露事件 └── 可靠性指标 ├── 可用性 ├── 错误率 └── 降级率 监控架构 数据采集层 class MetricsCollector: def __init__(self): self.collectors = [ LatencyCollector(), QualityCollector(), CostCollector(), SafetyCollector(), ReliabilityCollector() ] def record_request(self, request_id, request, response, metadata): """记录每次请求""" for collector in self.collectors: collector.record(request_id, request, response, metadata) 指标计算层 class MetricsCalculator: def calculate(self, raw_metrics): return { "latency": { "p50": percentile(raw_metrics["latencies"], 50), "p95": percentile(raw_metrics["latencies"], 95), "p99": percentile(raw_metrics["latencies"], 99), }, "quality": { "accuracy": raw_metrics["correct"] / raw_metrics["total"], "hallucination_rate": raw_metrics["hallucinations"] / raw_metrics["total"], "refusal_rate": raw_metrics["refusals"] / raw_metrics["total"], }, "cost": { "per_request": raw_metrics["total_cost"] / raw_metrics["total"], "daily": raw_metrics["total_cost"], "token_efficiency": raw_metrics["output_tokens"] / raw_metrics["input_tokens"], }, "safety": { "harmful_rate": raw_metrics["harmful"] / raw_metrics["total"], "injection_attempts": raw_metrics["injections"], }, "reliability": { "availability": 1 - raw_metrics["downtime"] / raw_metrics["total_time"], "error_rate": raw_metrics["errors"] / raw_metrics["total"], } } 告警层 class AlertManager: def __init__(self): self.rules = [ AlertRule("high_latency", "p95_latency > 5000", severity="warning"), AlertRule("critical_latency", "p99_latency > 10000", severity="critical"), AlertRule("high_error", "error_rate > 0.05", severity="critical"), AlertRule("quality_drop", "accuracy < 0.85", severity="warning"), AlertRule("hallucination_spike", "hallucination_rate > 0.1", severity="critical"), AlertRule("cost_spike", "daily_cost > budget * 1.2", severity="warning"), AlertRule("safety_incident", "harmful_rate > 0.01", severity="critical"), ] def check(self, metrics): alerts = [] for rule in self.rules: if rule.evaluate(metrics): alerts.append(rule.create_alert(metrics)) if alerts: self.notify(alerts) return alerts 关键监控实现 延迟监控 class LatencyMonitor: def __init__(self): self.latencies = SlidingWindow(size=10000) def record(self, request_id, start_time, end_time): latency = end_time - start_time self.latencies.append(latency) # 实时检查 if latency > 10: # 超过10秒 self.alert(f"请求 {request_id} 延迟 {latency:.1f}s") def get_stats(self): return { "p50": self.latencies.percentile(50), "p95": self.latencies.percentile(95), "p99": self.latencies.percentile(99), "max": self.latencies.max(), "avg": self.latencies.mean() } 质量监控 class QualityMonitor: def __init__(self): self.sample_rate = 0.1 # 采样10%进行质量评估 self.evaluator = LLMJudge(model="gpt-5") # 用GPT-5评估 async def evaluate(self, request, response): """异步评估输出质量""" if random.random() > self.sample_rate: return # 采样 # 用LLM评估 score = await self.evaluator.evaluate( input=request, output=response, criteria=["accuracy", "relevance", "completeness"] ) if score["accuracy"] < 0.7: self.alert(f"低质量输出检测:{score}") return score 成本监控 class CostMonitor: def __init__(self, daily_budget=100): self.daily_budget = daily_budget self.today_cost = 0 self.costs = [] def record(self, input_tokens, output_tokens, model): cost = calculate_cost(input_tokens, output_tokens, model) self.today_cost += cost self.costs.append({"timestamp": datetime.now(), "cost": cost}) # 预算检查 if self.today_cost > self.daily_budget * 0.8: self.alert("日预算已用80%") if self.today_cost > self.daily_budget: self.alert("日预算超支!") return "stop" # 触发熔断 安全监控 class SafetyMonitor: def __init__(self): self.content_filter = ContentFilter() self.injection_detector = InjectionDetector() def check_input(self, user_input): """检查输入安全性""" if self.injection_detector.is_injection(user_input): self.log_incident("injection_attempt", user_input) return False if self.content_filter.is_harmful(user_input): self.log_incident("harmful_input", user_input) return False return True def check_output(self, output): """检查输出安全性""" if self.content_filter.is_harmful(output): self.log_incident("harmful_output", output) return False return True 可视化仪表板 class MonitoringDashboard: def render(self): return { "overview": { "status": "healthy", # healthy/warning/critical "uptime": "99.97%", "requests_today": 154289, "avg_latency": "1.2s", "cost_today": "$45.30" }, "latency_chart": self.render_latency_chart(), "quality_trend": self.render_quality_trend(), "cost_trend": self.render_cost_trend(), "alerts": self.get_active_alerts(), "top_errors": self.get_top_errors() } 告警策略 告警分级 级别 条件 响应时间 通知方式 P0 系统不可用 立即 电话+短信+邮件 P1 关键指标超标 15分钟 短信+邮件 P2 质量下降 1小时 邮件+IM P3 预警 4小时 IM 告警抑制 def should_suppress(alert, recent_alerts): """避免告警风暴""" # 同类告警5分钟内只发一次 for recent in recent_alerts: if (recent["type"] == alert["type"] and (datetime.now() - recent["timestamp"]).seconds < 300): return True return False 2026年新趋势 1. AI自监控 用AI监控AI:模型自己评估输出质量,自动发现异常。 ...

2026-07-02 · 3 min · 543 words · 硅基 AGI 探索者
Agent链路追踪:OpenTelemetry与Jaeger实战

Agent链路追踪:OpenTelemetry与Jaeger实战

引言 一次Agent对话可能涉及路由决策、向量检索、工具调用、LLM推理等十几个步骤,跨越多个微服务。当用户反馈"Agent回复变慢了"时,如果没有链路追踪,定位瓶颈就像大海捞针。OpenTelemetry + Jaeger的组合为Agent系统提供了端到端的请求追踪能力,让每一次对话的完整路径都清晰可见。 OpenTelemetry架构 ┌──────────────────────────────────────────────────────────┐ │ OpenTelemetry Architecture │ │ │ │ Agent Services │ │ ┌─────────────────────────────────────────────┐ │ │ │ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │ │ │ │ │Router│ │ Tool │ │ LLM │ │Memory│ │ │ │ │ │Service│ │Service│ │Service│ │Service│ │ │ │ │ └──┬───┘ └──┬───┘ └──┬───┘ └──┬───┘ │ │ │ │ │ │ │ │ │ │ │ │ ┌──▼─────────▼─────────▼─────────▼───┐ │ │ │ │ │ OpenTelemetry SDK (Instrument) │ │ │ │ │ └──────────────┬─────────────────────┘ │ │ │ └─────────────────┼───────────────────────┘ │ │ │ │ │ ┌────────▼────────┐ │ │ │ OTLP Exporter │ │ │ └────────┬────────┘ │ │ │ │ │ ┌────────▼────────┐ │ │ │ OTel Collector │ │ │ │ (接收+处理+导出) │ │ │ └────┬───────┬────┘ │ │ │ │ │ │ ┌──────▼┐ ┌──▼──────┐ │ │ │Jaeger │ │Prometheus│ │ │ │(Traces)│ │(Metrics) │ │ │ └───────┘ └─────────┘ │ └──────────────────────────────────────────────────────────┘ SDK初始化 from opentelemetry import trace from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter from opentelemetry.sdk.resources import Resource from opentelemetry.instrumentation.grpc import GrpcInstrumentor from opentelemetry.instrumentation.httpx import HTTPXClientInstrumentor def setup_tracing(service_name: str, otlp_endpoint: str = "otel-collector:4317"): """初始化OpenTelemetry追踪""" resource = Resource.create({ "service.name": service_name, "service.version": "2.0.0", "deployment.environment": "production", }) provider = TracerProvider(resource=resource) # OTLP导出器 exporter = OTLPSpanExporter(endpoint=otlp_endpoint, insecure=True) processor = BatchSpanProcessor( exporter, max_queue_size=2048, max_export_batch_size=512, export_timeout_millis=30000, ) provider.add_span_processor(processor) trace.set_tracer_provider(provider) # 自动注入HTTP/gRPC调用 GrpcInstrumentor().instrument() HTTPXClientInstrumentor().instrument() return trace.get_tracer(service_name) Agent Span设计 class AgentTracer: """Agent专用追踪器""" def __init__(self, tracer): self.tracer = tracer async def trace_request( self, session_id: str, user_input: str, handler: callable ): """追踪完整请求链路""" with self.tracer.start_as_current_span( "agent.request", attributes={ "session.id": session_id, "input.length": len(user_input), "input.language": self._detect_language(user_input), } ) as request_span: try: result = await handler() request_span.set_attribute( "response.length", len(result.get("response", "")) ) request_span.set_attribute( "response.quality_score", result.get("quality_score", 0) ) request_span.set_status(trace.StatusCode.OK) return result except Exception as e: request_span.record_exception(e) request_span.set_status( trace.Status(trace.StatusCode.ERROR, str(e)) ) raise async def trace_routing( self, user_input: str, routing_fn: callable ): """追踪路由决策""" with self.tracer.start_as_current_span( "agent.route", attributes={"input.preview": user_input[:100]} ) as span: decision = await routing_fn() span.set_attributes({ "route.model": decision.get("model", ""), "route.tools": ",".join(decision.get("tools", [])), "route.confidence": decision.get("confidence", 0), "route.reason": decision.get("reason", ""), }) return decision async def trace_tool_call( self, tool_name: str, params: dict, executor: callable ): """追踪工具调用""" with self.tracer.start_as_current_span( f"tool.{tool_name}", attributes={ "tool.name": tool_name, "tool.params_hash": hashlib.md5( json.dumps(params, sort_keys=True).encode() ).hexdigest()[:8], } ) as span: start = time.monotonic() try: result = await executor() latency_ms = (time.monotonic() - start) * 1000 span.set_attributes({ "tool.latency_ms": latency_ms, "tool.success": True, "tool.result_size": len(str(result)), }) return result except Exception as e: span.set_attributes({ "tool.success": False, "tool.error": str(e)[:200], }) span.record_exception(e) raise async def trace_llm_call( self, model: str, prompt: str, generator: callable ): """追踪LLM推理""" with self.tracer.start_as_current_span( f"llm.{model}", attributes={ "llm.model": model, "llm.prompt_length": len(prompt), } ) as span: start = time.monotonic() result = await generator() latency_ms = (time.monotonic() - start) * 1000 span.set_attributes({ "llm.latency_ms": latency_ms, "llm.prompt_tokens": result.get("usage", {}).get("prompt_tokens", 0), "llm.completion_tokens": result.get("usage", {}).get("completion_tokens", 0), "llm.total_tokens": result.get("usage", {}).get("total_tokens", 0), "llm.finish_reason": result.get("finish_reason", ""), }) return result Span层级示例 agent.request (session=abc123) [2000ms] ├── agent.route [15ms] │ ├── embedding.generate [8ms] │ └── similarity.match [5ms] ├── memory.retrieve [50ms] │ ├── vector.search [30ms] │ └── context.assemble [15ms] ├── tool.search [800ms] │ ├── http.get [600ms] │ └── result.parse [50ms] ├── tool.calculator [20ms] ├── llm.gpt-4o [1100ms] │ ├── prompt.build [5ms] │ ├── api.call [1050ms] │ └── response.parse [30ms] └── response.format [15ms] 上下文传播 from opentelemetry.propagate import inject, extract from opentelemetry.trace import get_current_span class TraceContextPropagator: """跨服务Trace上下文传播""" @staticmethod def inject_to_headers(headers: dict = None) -> dict: """注入trace context到HTTP头""" headers = headers or {} inject(headers) return headers @staticmethod def extract_from_headers(headers: dict): """从HTTP头提取trace context""" return extract(headers) @staticmethod def get_current_trace_id() -> str: """获取当前trace ID""" span = get_current_span() if span and span.is_recording(): return format(span.get_span_context().trace_id, "032x") return "" @staticmethod def get_current_span_id() -> str: """获取当前span ID""" span = get_current_span() if span and span.is_recording(): return format(span.get_span_context().span_id, "016x") return "" # 在gRPC metadata中传播 class GrpcTraceInterceptor: """gRPC trace拦截器""" async def intercept(self, method, request, context): # 从metadata提取trace context metadata = dict(context.invocation_metadata()) trace_context = TraceContextPropagator.extract_from_headers(metadata) tracer = trace.get_tracer(__name__) with tracer.start_as_current_span( f"grpc.{method}", context=trace_context, ) as span: # 注入trace context到响应metadata response_metadata = TraceContextPropagator.inject_to_headers() context.set_trailing_metadata( [(k, v) for k, v in response_metadata.items()] ) return await method(request, context) Jaeger查询与分析 class JaegerAnalyzer: """Jaeger数据分析器""" def __init__(self, jaeger_url: str): self.url = jaeger_url async def find_slow_traces( self, service: str, min_duration_ms: int = 2000, limit: int = 20 ) -> list: """查找慢trace""" async with httpx.AsyncClient() as client: response = await client.get( f"{self.url}/api/traces", params={ "service": service, "limit": limit, "minDuration": f"{min_duration_ms}ms", "lookback": "1h", } ) return response.json()["data"] async def analyze_bottleneck( self, trace_id: str ) -> dict: """分析trace瓶颈""" trace = await self._get_trace(trace_id) spans = self._flatten_spans(trace) # 找到最耗时的span slowest = max(spans, key=lambda s: s["duration"]) # 分析Span层级 tree = self._build_span_tree(spans) # 找到关键路径 critical_path = self._find_critical_path(tree) return { "trace_id": trace_id, "total_duration_ms": tree["duration"], "slowest_span": { "name": slowest["operationName"], "duration_ms": slowest["duration"], "service": slowest["process"]["serviceName"], }, "critical_path": [ { "span": s["operationName"], "duration_ms": s["duration"], "service": s["process"]["serviceName"], } for s in critical_path ], "span_count": len(spans), } 性能影响控制 class TracingPerformanceGuard: """追踪性能守护——控制追踪开销""" def __init__(self): self.sampling_rates = { "fast_path": 0.05, # <500ms的请求5%采样 "normal": 0.2, # 500ms-2s的请求20%采样 "slow": 1.0, # >2s的请求100%采样 "error": 1.0, # 错误请求100%采样 } def should_trace(self, estimated_duration_ms: int = 0) -> bool: """决定是否追踪""" if estimated_duration_ms > 2000: rate = self.sampling_rates["slow"] elif estimated_duration_ms > 500: rate = self.sampling_rates["normal"] else: rate = self.sampling_rates["fast_path"] return random.random() < rate @contextmanager def conditional_span(self, tracer, name: str, should_trace: bool): """条件性创建span""" if should_trace: with tracer.start_as_current_span(name) as span: yield span else: yield None 总结 OpenTelemetry为Agent系统提供了统一的、标准化的链路追踪能力。精心设计的Span层级让每一次Agent对话的完整路径都清晰可见——从路由决策到工具调用,从记忆检索到LLM推理。Jaeger的可视化让性能瓶颈一目了然,基于trace的分析能够将排障效率提升数倍。 ...

2026-06-30 · 4 min · 843 words · 硅基 AGI 探索者
Agent日志架构:结构化日志与分布式追踪

Agent日志架构:结构化日志与分布式追踪

引言 Agent系统的日志不仅是排障工具,更是质量改进和安全审计的数据基础。一次Agent对话可能涉及路由决策、记忆检索、工具调用、LLM推理等多个步骤,跨越多个微服务。如何在分布式环境中建立完整的日志链路,是Agent系统可观测性的核心挑战。 日志架构全景 ┌──────────────────────────────────────────────────────┐ │ 日志数据流 │ │ │ │ Agent Services │ │ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │ │ │Router│ │Tool │ │LLM │ │Memory│ │ │ └──┬──┘ └──┬──┘ └──┬──┘ └──┬──┘ │ │ │ │ │ │ │ │ ▼ ▼ ▼ ▼ │ │ ┌──────────────────────────────┐ │ │ │ Fluent Bit (采集) │ │ │ └──────────┬───────────────────┘ │ │ │ │ │ ┌───────┼───────┐ │ │ ▼ ▼ │ │ ┌──────┐ ┌──────────┐ │ │ │ Loki │ │Elasticsearch│ │ │ │(日志) │ │ (全文搜索) │ │ │ └──────┘ └──────────┘ │ │ │ │ │ │ └───────┬───────┘ │ │ ▼ │ │ ┌──────────────┐ │ │ │ Grafana │ │ │ │ (可视化) │ │ │ └──────────────┘ │ └──────────────────────────────────────────────────────┘ 结构化日志标准 import structlog from datetime import datetime import uuid # 结构化日志配置 structlog.configure( processors=[ structlog.stdlib.add_log_level, structlog.processors.TimeStamper(fmt="iso"), structlog.processors.JSONRenderer() ], wrapper_class=structlog.stdlib.BoundLogger, logger_factory=structlog.stdlib.LoggerFactory(), ) logger = structlog.get_logger() class AgentLogger: """Agent专用日志器""" @staticmethod def log_request( session_id: str, request_id: str, user_input: str, route_decision: dict ): """记录请求日志""" logger.info( "agent_request_received", session_id=session_id, request_id=request_id, user_input_length=len(user_input), user_input_preview=user_input[:100], route_model=route_decision.get("model"), route_tools=route_decision.get("tools"), timestamp=datetime.now().isoformat() ) @staticmethod def log_tool_call( session_id: str, request_id: str, tool_name: str, params: dict, result: dict, latency_ms: float, success: bool ): """记录工具调用日志""" logger.info( "tool_call_completed", session_id=session_id, request_id=request_id, tool_name=tool_name, params_hash=hash(str(sorted(params.items()))), result_size=len(str(result)), latency_ms=latency_ms, success=success, error=result.get("error") if not success else None ) @staticmethod def log_llm_call( session_id: str, request_id: str, model: str, prompt_tokens: int, completion_tokens: int, latency_ms: float, quality_score: float = None ): """记录LLM调用日志""" logger.info( "llm_call_completed", session_id=session_id, request_id=request_id, model=model, prompt_tokens=prompt_tokens, completion_tokens=completion_tokens, total_tokens=prompt_tokens + completion_tokens, latency_ms=latency_ms, quality_score=quality_score ) @staticmethod def log_agent_decision( session_id: str, decision_type: str, reasoning: str, action: str, confidence: float ): """记录Agent决策日志——用于审计和改进""" logger.info( "agent_decision", session_id=session_id, decision_type=decision_type, # route, tool_select, terminate reasoning=reasoning[:500], # 截断推理过程 action=action, confidence=confidence ) Trace ID传播 from opentelemetry import trace from opentelemetry.propagate import inject, extract class TracingMiddleware: """分布式追踪中间件""" async def __call__(self, request, call_next): # 提取或生成trace context context = extract(request.headers) tracer = trace.get_tracer(__name__) with tracer.start_as_current_span( "agent_request", context=context, attributes={ "session_id": request.session_id, "user_id": request.user_id, } ) as span: # 在请求上下文中注入trace信息 headers = {} inject(headers) request.trace_context = headers try: response = await call_next(request) span.set_attribute("response.status", "success") span.set_attribute( "response.latency_ms", response.latency_ms ) return response except Exception as e: span.record_exception(e) span.set_status(trace.Status(trace.StatusCode.ERROR)) raise # 在服务间调用时传播Trace ID class ServiceClient: """带Trace传播的服务客户端""" async def call_service( self, service: str, method: str, data: dict, trace_context: dict = None ) -> dict: """调用其他微服务""" headers = { "Content-Type": "application/json", } # 注入trace context if trace_context: headers.update(trace_context) else: inject(headers) # 从当前context注入 # 记录出站调用 tracer = trace.get_tracer(__name__) with tracer.start_as_current_span( f"call_{service}", attributes={ "peer.service": service, "http.method": method, } ) as span: response = await self.http_client.post( f"http://{service}/{method}", json=data, headers=headers ) span.set_attribute("http.status_code", response.status_code) return response.json() 日志关联查询 class LogCorrelator: """日志关联查询器""" async def get_session_timeline( self, session_id: str ) -> list: """获取会话的完整事件时间线""" # 从多个数据源查询 logs = await self.loki.query( f'{{session_id="{session_id}"}} | json' ) traces = await self.jaeger.get_traces( tags={"session_id": session_id} ) metrics = await self.prometheus.query_range( query=f'agent_session_metrics{{session_id="{session_id}"}}', start=..., end=... ) # 合并并按时间排序 events = [] for log in logs: events.append({ "type": "log", "timestamp": log["timestamp"], "level": log["level"], "message": log["message"], **log }) for trace in traces: for span in trace.spans: events.append({ "type": "trace", "timestamp": span.start_time, "span_name": span.name, "duration_ms": span.duration_ms, "service": span.service, **span.tags }) events.sort(key=lambda e: e["timestamp"]) return events 日志采样策略 class LogSampler: """日志采样器——在保证可观测性的前提下控制日志量""" SAMPLING_RULES = { # 正常请求:10%采样 "normal": {"rate": 0.1, "level": "INFO"}, # 错误请求:100%记录 "error": {"rate": 1.0, "level": "ERROR"}, # 慢请求(>5s):100%记录 "slow": {"rate": 1.0, "level": "INFO", "min_latency_ms": 5000}, # 工具调用失败:100%记录 "tool_failure": {"rate": 1.0, "level": "WARN"}, # 安全相关:100%记录 "security": {"rate": 1.0, "level": "INFO"}, # 高价值用户:50%采样 "enterprise": {"rate": 0.5, "level": "INFO"}, } def should_log( self, log_type: str, request: dict, response: dict = None ) -> tuple: """判断是否需要记录日志""" # 优先级判断 if response and response.get("error"): rule = self.SAMPLING_RULES["error"] elif response and response.get("latency_ms", 0) > 5000: rule = self.SAMPLING_RULES["slow"] elif request.get("user_tier") == "enterprise": rule = self.SAMPLING_RULES["enterprise"] else: rule = self.SAMPLING_RULES["normal"] import random if random.random() < rule["rate"]: return True, rule["level"] return False, None 日志分析 class LogAnalyzer: """日志分析器""" async def analyze_session(self, session_id: str) -> dict: """分析单个会话日志""" events = await self.log_store.get_session_events(session_id) analysis = { "session_id": session_id, "total_steps": len(events), "tool_calls": [], "llm_calls": [], "errors": [], "total_tokens": 0, "total_latency_ms": 0, "quality_indicators": {}, } for event in events: if event["type"] == "tool_call": analysis["tool_calls"].append({ "tool": event["tool_name"], "latency_ms": event["latency_ms"], "success": event["success"] }) if not event["success"]: analysis["errors"].append(event) elif event["type"] == "llm_call": analysis["llm_calls"].append({ "model": event["model"], "tokens": event["total_tokens"], "latency_ms": event["latency_ms"] }) analysis["total_tokens"] += event["total_tokens"] analysis["total_latency_ms"] += event.get("latency_ms", 0) return analysis async def detect_anomalies( self, time_window_hours: int = 1 ) -> list: """检测日志异常模式""" anomalies = [] # 1. 突发错误聚集 error_clusters = await self._find_error_clusters(time_window_hours) for cluster in error_clusters: anomalies.append({ "type": "error_cluster", "service": cluster["service"], "error_count": cluster["count"], "time_range": cluster["range"] }) # 2. 异常Token消耗 token_outliers = await self._find_token_outliers(time_window_hours) for outlier in token_outliers: anomalies.append({ "type": "token_anomaly", "session_id": outlier["session_id"], "tokens": outlier["tokens"], "expected": outlier["expected"] }) # 3. 工具调用模式异常 tool_anomalies = await self._find_tool_anomalies(time_window_hours) anomalies.extend(tool_anomalies) return anomalies 日志保留策略 日志类型 热存储(SSD) 温存储(HDD) 冷存储(S3) 错误日志 7天 30天 180天 安全审计 30天 180天 2年 正常请求 3天 14天 90天 Trace数据 3天 7天 30天 指标数据 7天 90天 365天 总结 Agent系统的日志架构需要在"详细度"和"成本"之间取得平衡。结构化日志是一切的基础——没有结构化,就无法进行有效的查询和分析。Trace ID的跨服务传播让分布式追踪成为可能。智能采样策略确保在控制成本的同时不丢失关键信息。 ...

2026-06-30 · 4 min · 785 words · 硅基 AGI 探索者
Agent监控告警最佳实践:从指标到告警全链路

Agent监控告警最佳实践:从指标到告警全链路

引言 Agent系统的监控告警比传统应用复杂一个量级——除了需要监控CPU、内存、延迟等基础设施指标外,还需要监控Token消耗、工具成功率、幻觉率、安全违规率等Agent特有指标。一个没有完善监控的Agent系统就像盲飞——出了问题不知道哪里出了问题,没出问题不知道什么时候会出问题。 2026年,Prometheus + Grafana + AlertManager已成为Agent监控告警的事实标准,但Agent系统需要在此基础上构建专门的监控体系。 指标体系设计 四层指标架构 ┌─────────────────────────────────────────────────────┐ │ Layer 4: Business Metrics │ │ 用户满意度、任务完成率、对话质量评分 │ ├─────────────────────────────────────────────────────┤ │ Layer 3: Agent Metrics │ │ Token消耗、工具调用成功率、幻觉率、安全违规率 │ ├─────────────────────────────────────────────────────┤ │ Layer 2: Application Metrics │ │ 请求QPS、响应延迟、错误率、并发会话数 │ ├─────────────────────────────────────────────────────┤ │ Layer 1: Infrastructure Metrics │ │ CPU、内存、GPU利用率、磁盘IO、网络流量 │ └─────────────────────────────────────────────────────┘ Agent核心指标定义 from prometheus_client import Counter, Histogram, Gauge, Summary # ===== Layer 3: Agent特有指标 ===== # Token消耗 token_usage = Counter( "agent_token_total", "Total tokens consumed", ["tenant_id", "model", "type"] # type: input/output ) # 工具调用 tool_calls = Counter( "agent_tool_calls_total", "Total tool calls", ["tool_name", "status"] # status: success/failed/timeout ) tool_latency = Histogram( "agent_tool_latency_seconds", "Tool execution latency", ["tool_name"], buckets=[0.1, 0.5, 1, 5, 10, 30, 60] ) # Agent质量 hallucination_rate = Gauge( "agent_hallucination_rate", "Hallucination rate (rolling 1h)", ["model"] ) safety_violations = Counter( "agent_safety_violations_total", "Safety violations detected", ["type", "severity"] ) # 循环检测 cycle_detections = Counter( "agent_cycle_detections_total", "Cycle detections", ["cycle_type", "resolution"] # resolution: broken/escalated ) # 会话指标 active_sessions = Gauge( "agent_active_sessions", "Active sessions", ["tenant_id"] ) session_duration = Histogram( "agent_session_duration_seconds", "Session duration", buckets=[10, 30, 60, 120, 300, 600, 1200] ) # 路由决策 routing_decisions = Counter( "agent_routing_decisions_total", "Routing decisions", ["source_model", "target_model", "reason"] ) Prometheus配置 # prometheus.yml global: scrape_interval: 15s evaluation_interval: 15s rule_files: - "agent_alerts.yml" scrape_configs: # Agent应用指标 - job_name: "agent-service" metrics_path: /metrics static_configs: - targets: ["agent-service:9090"] labels: service: "agent" # LLM推理服务 - job_name: "llm-inference" metrics_path: /metrics static_configs: - targets: ["llm-inference:9090"] # 工具执行服务 - job_name: "tool-executor" metrics_path: /metrics static_configs: - targets: ["tool-executor-0:9090", "tool-executor-1:9090"] 告警规则 # agent_alerts.yml groups: - name: agent_infra_alerts rules: # 高错误率 - alert: AgentHighErrorRate expr: | sum(rate(agent_requests_total{status="error"}[5m])) by (service) / sum(rate(agent_requests_total[5m])) by (service) > 0.05 for: 2m labels: severity: critical team: agent-platform annotations: summary: "Agent error rate > 5%" description: "{{ $labels.service }} error rate is {{ $value | humanizePercentage }}" # P99延迟过高 - alert: AgentHighLatency expr: | histogram_quantile(0.99, rate(agent_request_duration_seconds_bucket[5m]) ) > 5 for: 5m labels: severity: warning annotations: summary: "Agent P99 latency > 5s" - name: agent_quality_alerts rules: # 幻觉率过高 - alert: AgentHighHallucination expr: agent_hallucination_rate > 0.05 for: 10m labels: severity: warning team: agent-quality annotations: summary: "Hallucination rate > 5% for {{ $labels.model }}" # 安全违规 - alert: AgentSafetyViolation expr: increase(agent_safety_violations_total[1h]) > 0 labels: severity: critical team: security annotations: summary: "Safety violation detected" # 循环检测频繁 - alert: AgentFrequentCycles expr: | increase(agent_cycle_detections_total[1h]) > 10 for: 5m labels: severity: warning annotations: summary: "Frequent cycle detections (>10/hour)" - name: agent_cost_alerts rules: # Token消耗异常 - alert: AgentTokenSpike expr: | rate(agent_token_total[5m]) > 2 * avg_over_time(rate(agent_token_total[5m])[1h:5m]) for: 10m labels: severity: warning team: agent-platform annotations: summary: "Token consumption spiked 2x above average" # 工具调用失败率 - alert: ToolFailureRate expr: | sum(rate(agent_tool_calls_total{status="failed"}[5m])) by (tool_name) / sum(rate(agent_tool_calls_total[5m])) by (tool_name) > 0.1 for: 5m labels: severity: warning annotations: summary: "Tool {{ $labels.tool_name }} failure rate > 10%" 告警路由与通知 class AlertRouter: """告警路由器""" ROUTING_RULES = { "critical": { "channels": ["pagerduty", "slack:#oncall", "sms"], "escalation_delay_min": 5, "escalation_target": "team-lead", }, "warning": { "channels": ["slack:#alerts"], "escalation_delay_min": 30, "escalation_target": "secondary-oncall", }, "info": { "channels": ["slack:#monitoring"], "escalation_delay_min": None, "escalation_target": None, } } async def handle_alert(self, alert: dict): """处理告警""" severity = alert["labels"]["severity"] rule = self.ROUTING_RULES[severity] # 告警去重 if await self._is_duplicate(alert): logger.debug(f"Duplicate alert suppressed: {alert['fingerprint']}") return # 告警分组 group_key = self._get_group_key(alert) group = await self._get_or_create_group(group_key) group.add_alert(alert) # 发送通知 for channel in rule["channels"]: await self._send_notification(channel, group) # 设置升级定时器 if rule["escalation_delay_min"]: asyncio.create_task( self._schedule_escalation( group, rule["escalation_delay_min"], rule["escalation_target"] ) ) 告警治理 class AlertGovernance: """告警治理——防止告警风暴""" def __init__(self): self.suppression_rules = [] self.rate_limits = {} def should_send(self, alert: dict) -> bool: """判断告警是否应该发送""" # 1. 维护窗口抑制 if self._in_maintenance_window(alert): return False # 2. 依赖抑制——如果上游告警活跃,抑制下游 if self._suppressed_by_dependency(alert): return False # 3. 频率限制——同一告警5分钟内只发一次 alert_key = alert["fingerprint"] if alert_key in self.rate_limits: last_sent = self.rate_limits[alert_key] if (datetime.now() - last_sent).total_seconds() < 300: return False # 4. 告警噪音评分 noise_score = self._calculate_noise_score(alert) if noise_score < 0.3: return False self.rate_limits[alert_key] = datetime.now() return True Grafana仪表板 { "dashboard": { "title": "Agent System Overview", "panels": [ { "title": "Request Rate & Error Rate", "targets": [ { "expr": "sum(rate(agent_requests_total[5m]))", "legendFormat": "QPS" }, { "expr": "sum(rate(agent_requests_total{status=\"error\"}[5m])) / sum(rate(agent_requests_total[5m]))", "legendFormat": "Error Rate" } ] }, { "title": "Token Consumption by Model", "targets": [ { "expr": "sum(rate(agent_token_total[5m])) by (model)", "legendFormat": "{{model}}" } ] }, { "title": "Tool Success Rate", "targets": [ { "expr": "sum(rate(agent_tool_calls_total{status=\"success\"}[5m])) by (tool_name) / sum(rate(agent_tool_calls_total[5m])) by (tool_name)", "legendFormat": "{{tool_name}}" } ] }, { "title": "Active Sessions & Concurrency", "targets": [ { "expr": "agent_active_sessions", "legendFormat": "{{tenant_id}}" } ] } ] } } SLI/SLO定义 # Agent系统SLO定义 slo: availability: target: 99.9% window: 30d query: | 1 - (sum(rate(agent_requests_total{status="error"}[5m])) / sum(rate(agent_requests_total[5m]))) latency_p99: target: 2000ms window: 7d query: | histogram_quantile(0.99, rate(agent_request_duration_seconds_bucket[5m])) quality_score: target: 0.85 window: 7d query: | avg(agent_response_quality_score) safety: target: 99.99% window: 30d query: | 1 - (increase(agent_safety_violations_total[30d]) / sum(increase(agent_requests_total[30d]))) 总结 Agent系统的监控告警需要覆盖从基础设施到业务质量的四个层次。指标设计要全面但不过载,告警规则要精准且有层次,通知路由要高效且不产生噪音。告警治理是长期工作——定期回顾告警有效性,淘汰无用告警,优化有用告警。 ...

2026-06-30 · 4 min · 756 words · 硅基 AGI 探索者
Agent可观测性:追踪、日志与指标的统一方案

Agent可观测性:追踪、日志与指标的统一方案

Agent可观测性:你无法优化你看不见的东西 传统软件的可观测性已经相当成熟——我们有Prometheus做指标、ELK做日志、Jaeger做追踪。但Agent系统引入了新的可观测性挑战:非确定性的执行路径、不可预测的token消耗、LLM输出的质量评估、多Agent协作的链路追踪。2026年,Agent可观测性已经形成了一套独立的最佳实践。 Agent可观测性的三大支柱 ┌───────────────────────────────────────────────────┐ │ Agent 可观测性三大支柱 │ ├─────────────┬─────────────┬───────────────────────┤ │ │ │ │ │ 追踪 │ 日志 │ 指标 │ │ (Traces) │ (Logs) │ (Metrics) │ │ │ │ │ │ Agent执行 │ 结构化事件 │ 性能计数器 │ │ 链路追踪 │ 决策记录 │ 资源消耗 │ │ 跨Agent关联 │ 上下文快照 │ 质量评估 │ │ │ │ │ └─────────────┴─────────────┴───────────────────────┘ 1. 分布式追踪 Agent Trace模型 Agent系统的追踪比传统微服务更复杂,因为一个"请求"可能涉及多轮LLM调用、多次工具调用、跨多个Agent。 from dataclasses import dataclass, field from datetime import datetime from typing import Any, Optional import uuid @dataclass class AgentSpan: """Agent追踪的基本单元""" span_id: str = field(default_factory=lambda: str(uuid.uuid4())) parent_id: Optional[str] = None trace_id: str = "" # 基本信息 name: str = "" # span名称 span_type: str = "" # llm_call / tool_call / agent_step / sub_agent agent_name: str = "" # 哪个Agent start_time: datetime = field(default_factory=datetime.now) end_time: Optional[datetime] = None # Agent特有信息 input_data: Any = None output_data: Any = None model: str = "" # 使用的LLM模型 prompt_tokens: int = 0 completion_tokens: int = 0 cost: float = 0.0 # 状态 status: str = "ok" # ok / error / timeout error_message: Optional[str] = None # 元数据 attributes: dict = field(default_factory=dict) def finish(self, output=None, status="ok", error=None): self.end_time = datetime.now() self.output_data = output self.status = status self.error_message = error @property def duration_ms(self) -> float: if self.end_time: return (self.end_time - self.start_time).total_seconds() * 1000 return 0 追踪实现 class AgentTracer: """Agent追踪器""" def __init__(self, service_name="agent-service"): self.service_name = service_name self.spans: list[AgentSpan] = [] self.current_span_stack: list[AgentSpan] = [] def start_trace(self, name: str, agent_name: str) -> AgentSpan: """开始一个新的追踪(根span)""" trace_id = str(uuid.uuid4()) span = AgentSpan( trace_id=trace_id, name=name, span_type="agent_step", agent_name=agent_name ) self.spans.append(span) self.current_span_stack.append(span) return span def start_span( self, name: str, span_type: str, agent_name: str = "", input_data: Any = None ) -> AgentSpan: """开始一个子span""" parent = self.current_span_stack[-1] if self.current_span_stack else None span = AgentSpan( trace_id=parent.trace_id if parent else str(uuid.uuid4()), parent_id=parent.span_id if parent else None, name=name, span_type=span_type, agent_name=agent_name, input_data=input_data ) self.spans.append(span) self.current_span_stack.append(span) return span def end_span(self, span: AgentSpan, output=None, status="ok", error=None): """结束一个span""" span.finish(output, status, error) if self.current_span_stack and self.current_span_stack[-1].span_id == span.span_id: self.current_span_stack.pop() def get_trace_tree(self, trace_id: str) -> dict: """获取追踪树""" trace_spans = [s for s in self.spans if s.trace_id == trace_id] return self._build_tree(trace_spans, parent_id=None) def _build_tree(self, spans: list[AgentSpan], parent_id: str | None) -> dict: children = [s for s in spans if s.parent_id == parent_id] return [ { "span_id": s.span_id, "name": s.name, "type": s.span_type, "agent": s.agent_name, "duration_ms": s.duration_ms, "tokens": s.prompt_tokens + s.completion_tokens, "cost": s.cost, "status": s.status, "children": self._build_tree(spans, s.span_id) } for s in children ] 使用示例 tracer = AgentTracer() # 开始追踪 root = tracer.start_trace("用户咨询", "router_agent") # Agent执行LLM调用 llm_span = tracer.start_span("LLM调用", "llm_call", "router_agent", input_data="用户问题") response = await llm.complete("...") tracer.end_span(llm_span, output=response.text, status="ok") llm_span.prompt_tokens = response.usage.prompt_tokens llm_span.completion_tokens = response.usage.completion_tokens llm_span.cost = calculate_cost(response.usage, "gpt-4o") # Agent调用工具 tool_span = tracer.start_span("搜索知识库", "tool_call", "router_agent") results = await knowledge_base.search("query") tracer.end_span(tool_span, output=results) # 路由到子Agent sub_agent_span = tracer.start_span("专家Agent处理", "sub_agent", "expert_agent") # ... 子Agent内部会有自己的span ... tracer.end_span(sub_agent_span, output="最终回答") # 结束追踪 tracer.end_span(root, output="最终回答") # 查看追踪树 trace_tree = tracer.get_trace_tree(root.trace_id) 追踪可视化 追踪树可以渲染为瀑布图: ...

2026-06-30 · 6 min · 1225 words · 硅基 AGI 探索者
AI Agent 在IT运维中的AIOps实践

AI Agent 在IT运维中的AIOps实践

AIOps的进化:从规则引擎到智能Agent IT运维正在经历从"人工运维"到"自动化运维"再到"智能运维(AIOps)“的三级跳。传统的AIOps 1.0主要基于规则引擎和机器学习模型进行异常检测和告警降噪,但仍然依赖人工进行根因分析和故障处置。 2026年的AIOps 2.0核心特征是AI Agent的深度参与——Agent不仅能发现问题,还能理解问题、定位根因、执行修复,形成"感知-分析-决策-执行"的闭环。Gartner预测,到2027年,70%的企业将在IT运维中采用AI Agent,将运维效率提升3倍以上。 AI Agent运维能力体系 1. 全栈可观测性感知 多维度数据采集与关联: Agent持续采集以下维度的运维数据: 基础设施层:CPU、内存、磁盘、网络指标(通过Prometheus、Datadog等) 应用层:APM数据、调用链路、日志、自定义指标 云平台层:云资源使用情况、账单数据、服务健康状态 业务层:核心业务指标(订单量、支付成功率、API响应时间) 智能降噪与告警合并: 传统监控系统的一个常见问题是"告警风暴”——一个基础设施故障会触发数百条关联告警。Agent能进行告警关联分析: 基于拓扑关系识别因果链(数据库慢查询→应用超时→前端报错) 基于时间窗口合并同时发生的告警 基于历史模式识别已知问题的重复告警 某互联网公司的实践数据显示,Agent将日均告警从3,000+条降至约150条有效告警,降噪率达到95%。 2. 智能根因分析 拓扑感知分析: Agent维护实时的服务拓扑图(Service Map),当异常发生时,能沿着调用链路反向追溯: 故障场景示例: 用户报告下单失败 → Agent追踪调用链路 → 订单服务返回500 → 订单服务调用支付服务超时 → 支付服务连接数据库连接池耗尽 → 数据库执行慢查询导致连接积压 → 根因:某分析查询未走索引,全表扫描导致数据库负载飙升 Agent能在数分钟内完成上述分析,而传统人工排查通常需要30-60分钟。 变更关联分析: 80%的生产事故由变更引起(代码部署、配置修改、基础设施变更)。Agent自动关联最近变更与故障发生时间,快速锁定可能的变更根因。 知识库辅助诊断: Agent维护一个不断积累的故障知识库,包含历史故障的症状、根因、解决方案。新故障发生时,Agent能匹配相似的历史案例,加速诊断。 3. 自动化故障处置 自愈能力分级: 级别 处置方式 示例 L1-自动执行 Agent直接执行,无需人工 重启崩溃服务、扩容过载节点、清理磁盘空间 L2-建议执行 Agent准备方案,人工确认后执行 数据库索引优化、回滚问题版本、切换流量 L3-辅助分析 Agent提供分析,人工决策和执行 复杂根因分析、架构调整、容量规划 常见自愈场景: 内存泄漏:检测到内存持续增长趋势,在OOM前自动重启服务 磁盘空间不足:自动清理日志和临时文件,必要时扩容磁盘 流量突增:自动触发HPA扩容,增加服务实例 依赖服务故障:自动切换到备用实例或降级方案 证书即将过期:自动续期并更新配置 4. 容量规划与成本优化 智能容量预测: 基于历史数据和业务增长趋势,Agent预测未来3-6个月的资源需求,给出容量规划建议。 ...

2026-06-30 · 1 min · 194 words · 硅基 AGI 探索者
鲁ICP备2026018361号