mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
1162 字
3 分钟
Agent 可观测性:日志、追踪与调试
2025-04-06

前言#

Agent 系统由多步骤组成,出问题时定位根因困难。可观测性是生产 Agent 的必备能力。本章将从可观测性三支柱出发,详细介绍 LangSmith、LangFuse、Phoenix 等工具的集成方式,以及结构化日志、OpenTelemetry 接入和常见故障排查方法。

一、可观测性三支柱#

1.1 三大支柱#

支柱说明工具
日志 (Logs)文本记录Langfuse, LangSmith
追踪 (Traces)请求级追踪OpenTelemetry, Langtrace
指标 (Metrics)数值监控Prometheus, Datadog

1.2 Trace 结构#

graph TB A["User Request"] --> B["Orchestrator"] B --> C["Research Agent"] B --> D["Coding Agent"] C --> E["Tool: Search"] D --> F["Tool: Execute"]

1.3 为什么 Agent 需要特殊的可观测性#

传统的 Web 服务监控关注请求延迟和错误率。Agent 系统有更多需要追踪的维度:

维度传统服务Agent 系统
请求追踪单次调用多轮 Thought-Action-Obs
Token 消耗核心成本指标
工具调用链决策质量的关键证据
Prompt 内容调试和优化的依据
幻觉检测质量保障手段
多 Agent 协作状态通信和同步问题排查

二、LangSmith 追踪#

2.1 基础集成#

from langsmith import traceable
@traceable(project_name="my-agent")
async def research_agent(query: str):
# 每次调用自动追踪
result = await llm.complete(query)
return result

2.2 自定义追踪事件#

from opentelemetry import trace
tracer = trace.get_tracer(__name__)
@traceable
async def agent_with_spans(query: str):
with tracer.start_as_current_span("route") as span:
span.set_attribute("query_length", len(query))
decision = await route(query)
span.set_attribute("route_decision", decision)
with tracer.start_as_current_span("execute"):
result = await execute(decision)
return result

2.3 LangSmith 完整集成方案#

LangSmith 提供了最完整的 Agent 追踪方案,包括运行追踪、Prompt 版本管理和评估:

import os
from langsmith import Client, traceable, trace
from langsmith.run_helpers import get_run_tree
# 初始化
os.environ["LANGCHAIN_API_KEY"] = "your-api-key"
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_PROJECT"] = "production-agent"
client = Client()
class TracedAgent:
"""带完整追踪的 Agent"""
@traceable(name="agent.think", run_type="llm")
async def think(self, query: str, context: str) -> str:
"""思考阶段追踪"""
run = get_run_tree()
if run:
run.add_metadata({"query_tokens": count_tokens(query)})
thought = await llm.complete(
f"Context: {context}\nQuery: {query}\nThink step by step."
)
return thought
@traceable(name="agent.act", run_type="tool")
async def act(self, tool_name: str, tool_input: dict) -> str:
"""行动阶段追踪"""
run = get_run_tree()
if run:
run.add_metadata({"tool": tool_name, "input": tool_input})
result = await execute_tool(tool_name, tool_input)
if run:
run.add_metadata({"result_length": len(str(result))})
return result
@traceable(name="agent.run", run_type="chain")
async def run(self, query: str) -> str:
"""完整 Agent 运行"""
context = ""
for step in range(MAX_STEPS):
thought = await self.think(query, context)
action = parse_action(thought)
if action.type == "final_answer":
return action.answer
result = await self.act(action.tool, action.input)
context += f"\nThought: {thought}\nAction: {action}\nObservation: {result}"
return "达到最大步数"

2.4 LangSmith 的 Prompt 版本管理#

from langsmith import Client
client = Client()
# 创建 Prompt 版本
prompt = client.push_prompt(
"research-agent-system",
object={
"type": "chat",
"messages": [
{
"role": "system",
"content": "你是一个专业的研究助手,擅长搜索和分析信息。"
}
],
},
metadata={"version": "2.1", "change": "增加了事实核查要求"},
)
# 拉取特定版本的 Prompt
prompt_v2 = client.pull_prompt("research-agent-system", metadata={"version": "2.0"})

三、Langfuse 自托管#

3.1 优势#

特性LangfuseLangSmith
部署自托管云服务
数据主权完全控制第三方
成本服务器费用按量收费
定制完全可定制受限

3.2 Langfuse 集成#

from langfuse import Langfuse
langfuse = Langfuse()
@langfuse.trace()
def agent_step(tool_name: str, input_data: dict):
# Langfuse 自动记录
result = execute_tool(tool_name, input_data)
langfuse.flush()
return result

3.3 Langfuse 完整集成方案#

Langfuse 是开源替代方案,适合对数据主权有要求的企业:

from langfuse import Langfuse
from langfuse.decorators import langfuse_context, observe
# 初始化(自托管地址)
langfuse = Langfuse(
public_key="pk-xxx",
secret_key="sk-xxx",
host="http://localhost:3000", # 自托管地址
)
class LangfuseAgent:
"""使用 Langfuse 追踪的 Agent"""
@observe(name="agent.run", capture_input=True, capture_output=True)
async def run(self, query: str, user_id: str = None) -> str:
"""Agent 主入口"""
# 获取当前 trace
trace = langfuse_context.get_current_trace()
if trace:
trace.update(
user_id=user_id,
metadata={"query_length": len(query)},
tags=["production"],
)
# 思考
thought = await self._think(query)
# 行动
result = await self._act(thought)
# 记录评分(供后续评估用)
langfuse_context.get_current_span().update(
output=result,
metadata={"steps_taken": thought.step_count},
)
return result
@observe(name="agent.think")
async def _think(self, query: str) -> dict:
response = await llm.complete(query)
return parse_thought(response)
@observe(name="agent.act", kind="tool")
async def _act(self, thought: dict) -> str:
tool_name = thought["tool"]
tool_input = thought["input"]
result = await execute_tool(tool_name, tool_input)
# 记录工具调用的详细信息
span = langfuse_context.get_current_span()
span.update(
metadata={
"tool_name": tool_name,
"input_tokens": count_tokens(str(tool_input)),
"output_tokens": count_tokens(result),
}
)
return result

3.4 Langfuse Docker 自托管部署#

docker-compose.yml
version: "3"
services:
langfuse:
image: langfuse/langfuse:latest
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgresql://postgres:password@db:5432/langfuse
- NEXTAUTH_SECRET=your-secret-key
- SALT=your-salt
depends_on:
- db
db:
image: postgres:15
environment:
- POSTGRES_PASSWORD=password
- POSTGRES_DB=langfuse
volumes:
- pgdata:/var/lib/postgresql/data
# 可选:ClickHouse 用于大规模分析
clickhouse:
image: clickhouse/clickhouse-server:latest
ports:
- "8123:8123"
volumes:
- chdata:/var/lib/clickhouse
volumes:
pgdata:
chdata:

四、Arize Phoenix 追踪#

4.1 Phoenix 简介#

Arize Phoenix 是另一个开源的 LLM 可观测性工具,特点是本地优先、零配置启动:

特性PhoenixLangfuseLangSmith
开源
部署方式本地/自托管自托管云服务
启动难度极低
LLM 评估内置支持支持
嵌入可视化内置

4.2 Phoenix 快速集成#

# 安装: pip install arize-phoenix
import phoenix as px
from phoenix.trace.langchain import LangChainInstrumentor
# 启动 Phoenix(本地)
session = px.launch_app()
# 自动追踪 LangChain 调用
LangChainInstrumentor().instrument()
# 现在所有 LangChain 调用都会被追踪
agent = create_react_agent(llm, tools, prompt)
result = agent.invoke({"input": "查询天气"})

4.3 Phoenix 的嵌入分析#

Phoenix 独特的功能是可视化 Embedding 空间,帮助发现数据漂移和聚类问题:

from phoenix.experimental.evals import HallucinationEvaluator
# 使用 Phoenix 内置的幻觉评估器
evaluator = HallucinationEvaluator(model=llm)
# 评估 Agent 的回答
eval_results = []
for trace in session.get_traces():
for span in trace.spans:
if span.span_kind == "llm":
result = evaluator.evaluate(
input=span.input,
output=span.output,
reference=span.metadata.get("reference", ""),
)
eval_results.append(result)

五、结构化日志#

5.1 Agent 专用的日志格式#

Agent 的日志需要记录完整的推理过程,传统文本日志不够用。以下是推荐的结构化日志格式:

import structlog
from datetime import datetime
# 配置 structlog
structlog.configure(
processors=[
structlog.contextvars.merge_contextvars,
structlog.processors.add_log_level,
structlog.processors.JSONRenderer(),
],
)
logger = structlog.get_logger()
class AgentLogger:
"""Agent 专用结构化日志"""
def log_thought(self, trace_id: str, step: int, thought: str):
logger.info(
"agent.thought",
trace_id=trace_id,
step=step,
phase="thought",
content=thought[:200], # 截断防止日志过大
timestamp=datetime.now().isoformat(),
)
def log_action(self, trace_id: str, step: int, tool: str, params: dict):
logger.info(
"agent.action",
trace_id=trace_id,
step=step,
phase="action",
tool=tool,
params=_sanitize_params(params), # 脱敏
timestamp=datetime.now().isoformat(),
)
def log_observation(self, trace_id: str, step: int, observation: str):
logger.info(
"agent.observation",
trace_id=trace_id,
step=step,
phase="observation",
content_length=len(observation),
content_preview=observation[:100],
timestamp=datetime.now().isoformat(),
)
def log_error(self, trace_id: str, step: int, error: Exception):
logger.error(
"agent.error",
trace_id=trace_id,
step=step,
error_type=type(error).__name__,
error_message=str(error),
timestamp=datetime.now().isoformat(),
)
def log_token_usage(self, trace_id: str, model: str, prompt_tokens: int,
completion_tokens: int, cost_usd: float):
logger.info(
"agent.token_usage",
trace_id=trace_id,
model=model,
prompt_tokens=prompt_tokens,
completion_tokens=completion_tokens,
total_tokens=prompt_tokens + completion_tokens,
cost_usd=cost_usd,
timestamp=datetime.now().isoformat(),
)
def _sanitize_params(params: dict) -> dict:
"""参数脱敏:隐藏 API Key、密码等敏感信息"""
sensitive_keys = {"api_key", "password", "token", "secret", "credential"}
sanitized = {}
for k, v in params.items():
if any(s in k.lower() for s in sensitive_keys):
sanitized[k] = "***REDACTED***"
else:
sanitized[k] = v
return sanitized

5.2 日志输出示例#

{"event": "agent.thought", "trace_id": "t-001", "step": 1, "phase": "thought", "content": "用户询问北京天气,需要调用天气API获取实时数据", "timestamp": "2026-03-22T10:30:00"}
{"event": "agent.action", "trace_id": "t-001", "step": 1, "phase": "action", "tool": "get_weather", "params": {"city": "北京"}, "timestamp": "2026-03-22T10:30:01"}
{"event": "agent.observation", "trace_id": "t-001", "step": 1, "phase": "observation", "content_length": 85, "content_preview": "北京,晴,温度22°C,湿度45%,北风3级", "timestamp": "2026-03-22T10:30:02"}
{"event": "agent.token_usage", "trace_id": "t-001", "model": "gpt-4o", "prompt_tokens": 150, "completion_tokens": 80, "total_tokens": 230, "cost_usd": 0.00115, "timestamp": "2026-03-22T10:30:02"}

六、OpenTelemetry 集成#

6.1 OpenTelemetry Agent 追踪标准#

OpenTelemetry 为分布式追踪提供了统一标准。Agent 系统可以复用这套体系:

flowchart TB A["OTel Collector"] --> B["Jaeger<br/>链路追踪"] A --> C["Prometheus<br/>指标"] A --> D["ELK<br/>日志"] E["Agent Service"] -->|"OTLP"| A F["Tool Service"] -->|"OTLP"| A G["LLM Provider"] -->|"OTLP"| A

6.2 OpenTelemetry 完整集成#

from opentelemetry import trace, metrics
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.metrics import MeterProvider
from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader
from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import OTLPMetricExporter
# 配置 Tracer
trace.set_tracer_provider(TracerProvider())
tracer = trace.get_tracer(__name__)
trace.get_tracer_provider().add_span_processor(
BatchSpanProcessor(OTLPSpanExporter(endpoint="http://localhost:4317"))
)
# 配置 Meter
meter = metrics.get_meter(__name__)
metrics.set_meter_provider(MeterProvider(metric_readers=[
PeriodicExportingMetricReader(
OTLPMetricExporter(endpoint="http://localhost:4317")
)
]))
# 定义指标
task_counter = meter.create_counter(
name="agent.tasks.total",
description="Total number of agent tasks",
unit="1",
)
token_histogram = meter.create_histogram(
name="agent.tokens.usage",
description="Token usage per request",
unit="tokens",
)
latency_histogram = meter.create_histogram(
name="agent.request.latency",
description="Request latency",
unit="ms",
)
class OpenTelemetryAgent:
"""OpenTelemetry 追踪的 Agent"""
async def run(self, query: str) -> str:
with tracer.start_as_current_span("agent.run") as span:
span.set_attribute("query", query[:100])
span.set_attribute("query_length", len(query))
start_time = time.time()
try:
result = await self._execute(query)
task_counter.add(1, {"status": "success"})
span.set_attribute("status", "success")
return result
except Exception as e:
task_counter.add(1, {"status": "error", "error_type": type(e).__name__})
span.set_attribute("status", "error")
span.record_exception(e)
raise
finally:
elapsed = (time.time() - start_time) * 1000
latency_histogram.record(elapsed)
async def _execute(self, query: str) -> str:
with tracer.start_as_current_span("agent.think") as span:
thought = await llm.complete(query)
span.set_attribute("thought_length", len(thought))
return thought
def record_token_usage(self, model: str, prompt_tokens: int, completion_tokens: int):
token_histogram.record(
prompt_tokens + completion_tokens,
{"model": model, "type": "total"},
)

6.3 自定义 Span 属性标准#

为 Agent 追踪定义统一的 Span 属性命名规范:

属性名称类型说明
agent.querystring用户原始查询
agent.tool.namestring调用的工具名称
agent.tool.inputstring工具输入参数
agent.llm.modelstring使用的模型
agent.llm.prompt_tokensint输入 Token 数
agent.llm.completion_tokensint输出 Token 数
agent.step.numberint当前步骤编号
agent.step.typestringthought/action/observation
agent.decisionstring路由或分叉决策

七、调试技巧#

7.1 常见问题#

问题原因调试方法
Agent 循环缺少终止条件添加 max_iterations
工具调用失败参数错误/API 限流重试+错误日志
幻觉上下文不足添加 RAG 证据
响应过长Token 限制截断+摘要

7.2 调试工具#

# 添加详细日志
import logging
logging.basicConfig(level=logging.DEBUG)
@traceable
async def debug_agent(query: str):
logger.debug(f"输入: {query}")
thought = await think(query)
logger.debug(f"思考: {thought}")
action = await act(thought)
logger.debug(f"行动: {action}")
return action

7.3 可视化调试#

from langchain.debug import visualize_chains
# 开启可视化追踪
visualize_chains(agent_chain, visualization_dir="debug_output")

7.4 常见 Agent 故障模式与排查#

模式一:无限循环#

Agent 一直在相同的 Thought-Action-Observation 循环中打转:

class LoopDetector:
"""循环检测器"""
def __init__(self, max_similarity: float = 0.9, max_repeats: int = 3):
self.history: list[str] = []
self.max_similarity = max_similarity
self.max_repeats = max_repeats
def check(self, action: str) -> bool:
"""检查是否进入循环,返回 True 表示检测到循环"""
self.history.append(action)
# 计算与最近 N 个动作的相似度
recent = self.history[-self.max_repeats:]
if len(recent) < self.max_repeats:
return False
similarities = [
compute_similarity(recent[-1], recent[i])
for i in range(len(recent) - 1)
]
if all(s > self.max_similarity for s in similarities):
logger.warning(
f"检测到循环: 最近 {self.max_repeats} 个动作高度相似",
extra={"actions": recent}
)
return True
return False
# 在 Agent 循环中使用
loop_detector = LoopDetector()
for step in range(MAX_STEPS):
action = await agent.decide(observation)
if loop_detector.check(str(action)):
logger.warning("Agent 陷入循环,强制终止")
break
observation = await execute(action)

模式二:工具调用失败静默#

Agent 调用工具失败但没有正确处理,导致后续推理基于空结果:

class ToolCallMonitor:
"""工具调用监控"""
def __init__(self):
self.call_history: list[dict] = []
def record(self, tool_name: str, params: dict, result: Any, error: Exception | None):
self.call_history.append({
"tool": tool_name,
"params": params,
"success": error is None,
"result_type": type(result).__name__,
"error": str(error) if error else None,
})
def check_health(self) -> dict:
"""检查工具调用健康状况"""
total = len(self.call_history)
if total == 0:
return {"status": "no_data"}
failures = [c for c in self.call_history if not c["success"]]
failure_rate = len(failures) / total
# 按工具分组统计
by_tool = {}
for c in self.call_history:
tool = c["tool"]
if tool not in by_tool:
by_tool[tool] = {"total": 0, "failures": 0}
by_tool[tool]["total"] += 1
if not c["success"]:
by_tool[tool]["failures"] += 1
return {
"status": "unhealthy" if failure_rate > 0.3 else "healthy",
"total_calls": total,
"failure_rate": failure_rate,
"by_tool": by_tool,
}

模式三:上下文窗口溢出#

Agent 的对话历史过长,导致 Token 超出模型限制:

class ContextWindowMonitor:
"""上下文窗口监控"""
def __init__(self, max_tokens: int, warning_threshold: float = 0.8):
self.max_tokens = max_tokens
self.warning_threshold = warning_threshold
def check(self, messages: list[dict]) -> dict:
current_tokens = count_tokens(messages)
utilization = current_tokens / self.max_tokens
result = {
"current_tokens": current_tokens,
"max_tokens": self.max_tokens,
"utilization": utilization,
"status": "ok",
}
if utilization > 1.0:
result["status"] = "overflow"
logger.error(f"上下文溢出! {current_tokens}/{self.max_tokens}")
elif utilization > self.warning_threshold:
result["status"] = "warning"
logger.warning(f"上下文接近上限: {utilization:.1%}")
return result

7.5 调试流程图#

flowchart TD A["Agent 输出异常"] --> B{"追踪记录中能否复现?"} B -->|"能"| C["检查 LLM 输入输出"] B -->|"不能"| D["添加更多日志"] C --> E{"LLM 输入是否正确?"} E -->|"否"| F["检查 Prompt 构造"] E -->|"是"| G{"LLM 输出是否正确?"} G -->|"否"| H["优化 Prompt / 换模型"] G -->|"是"| I{"工具调用是否正确?"} I -->|"否"| J["检查工具参数和逻辑"] I -->|"是"| K["检查结果解析"]

八、成本追踪与 Token 监控#

8.1 Token 用量追踪#

class TokenUsageTracker:
"""Token 用量追踪器"""
def __init__(self):
self.usage_by_model: dict[str, list[dict]] = {}
self.usage_by_agent: dict[str, list[dict]] = {}
def record(self, agent_name: str, model: str, usage: dict):
record = {
"timestamp": datetime.now().isoformat(),
"prompt_tokens": usage.get("prompt_tokens", 0),
"completion_tokens": usage.get("completion_tokens", 0),
"total_tokens": usage.get("total_tokens", 0),
}
self.usage_by_model.setdefault(model, []).append(record)
self.usage_by_agent.setdefault(agent_name, []).append(record)
def get_summary(self, group_by: str = "model") -> dict:
"""获取用量汇总"""
data = self.usage_by_model if group_by == "model" else self.usage_by_agent
summary = {}
for key, records in data.items():
total_prompt = sum(r["prompt_tokens"] for r in records)
total_completion = sum(r["completion_tokens"] for r in records)
summary[key] = {
"total_prompt_tokens": total_prompt,
"total_completion_tokens": total_completion,
"total_tokens": total_prompt + total_completion,
"request_count": len(records),
"avg_tokens_per_request": (total_prompt + total_completion) / len(records),
}
return summary

8.2 实时成本仪表板#

class CostDashboard:
"""实时成本仪表板"""
def __init__(self):
self.tracker = TokenUsageTracker()
self.prices = MODEL_PRICING # 参考前文的模型定价表
def get_realtime_metrics(self) -> dict:
summary = self.tracker.get_summary(group_by="model")
total_cost = 0
details = {}
for model, stats in summary.items():
if model in self.prices:
cost = (
stats["total_prompt_tokens"] * self.prices[model]["input"] / 1_000_000
+ stats["total_completion_tokens"] * self.prices[model]["output"] / 1_000_000
)
else:
cost = 0
total_cost += cost
details[model] = {**stats, "cost_usd": cost}
return {
"total_cost_usd": total_cost,
"by_model": details,
"timestamp": datetime.now().isoformat(),
}
def check_budget(self, budget_usd: float) -> dict:
metrics = self.get_realtime_metrics()
remaining = budget_usd - metrics["total_cost_usd"]
usage_pct = metrics["total_cost_usd"] / budget_usd
alert = None
if usage_pct > 0.9:
alert = "CRITICAL: 已使用 90% 以上预算"
elif usage_pct > 0.7:
alert = "WARNING: 已使用 70% 以上预算"
return {
"budget_usd": budget_usd,
"used_usd": metrics["total_cost_usd"],
"remaining_usd": remaining,
"usage_pct": usage_pct,
"alert": alert,
}

九、生产环境监控#

9.1 关键指标#

# Prometheus 指标
agent_tasks_total{status="completed", agent="research"} 1000
agent_tasks_total{status="failed", agent="research"} 5
agent_latency_seconds{agent="research"} 2.5
agent_cost_tokens{agent="research"} 500000

9.2 告警配置#

# alerting rules
groups:
- name: agent
rules:
- alert: HighFailureRate
expr: rate(agent_tasks_failed / agent_tasks_total) > 0.1
for: 5m
labels:
severity: warning

9.3 完整的 Grafana 监控面板#

# Grafana Dashboard 配置建议
DASHBOARD_PANELS = {
"row_1": [
{"title": "请求成功率", "type": "stat", "query": 'sum(rate(agent_tasks_total{status="success"}[5m])) / sum(rate(agent_tasks_total[5m]))'},
{"title": "平均延迟 (ms)", "type": "gauge", "query": "histogram_quantile(0.5, agent_latency_seconds)"},
{"title": "P99 延迟 (ms)", "type": "gauge", "query": "histogram_quantile(0.99, agent_latency_seconds)"},
{"title": "每小时成本 ($)", "type": "stat", "query": 'sum(rate(agent_cost_usd[1h]))'},
],
"row_2": [
{"title": "Token 使用趋势", "type": "timeseries", "query": "sum by (model) (rate(agent_tokens_total[5m]))"},
{"title": "工具调用成功率", "type": "bar_chart", "query": "sum by (tool) (rate(agent_tool_calls{status='success'}[5m]))"},
{"title": "错误分布", "type": "pie_chart", "query": "sum by (error_type) (rate(agent_errors_total[5m]))"},
],
"row_3": [
{"title": "Agent 循环检测", "type": "stat", "query": 'sum(rate(agent_loop_detected_total[5m]))'},
{"title": "上下文利用率", "type": "gauge", "query": "avg(agent_context_utilization)"},
{"title": "缓存命中率", "type": "stat", "query": 'sum(rate(agent_cache_hits[5m])) / sum(rate(agent_cache_requests[5m]))'},
],
}

十、总结#

维度工具用途
追踪LangSmith/Langfuse请求级追踪
日志ELK/Loki问题排查
指标Prometheus/Datadog业务指标
调试LangServe/Debug UI开发调试

10.1 可观测性实施清单#

  • 基础:接入 LangSmith 或 Langfuse,自动追踪 LLM 调用链
  • 进阶:添加结构化日志,覆盖 Thought-Action-Observation 全过程
  • 高级:接入 OpenTelemetry,统一 Agent 系统与传统微服务的可观测性
  • 生产:搭建 Grafana 面板,配置告警规则,实现成本实时监控

可观测性是生产 Agent 系统的基础!

参考资料#

支持与分享

如果这篇文章对你有帮助,欢迎支持作者或分享给更多人

Agent 可观测性:日志、追踪与调试
https://blog.souloss.com/posts/machine-learning/agent-guide/agent-observability-and-debugging/
作者
Souloss
发布于
2025-04-06
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时