最小 .NET LLM 可观测性:在 15 分钟内复现超时并进行排查

发布: (2026年3月2日 GMT+8 15:30)
10 分钟阅读
原文: Dev.to

Source: Dev.to

如果你的 LLM 接口出现超时,仅靠仪表盘往往帮不上忙。你需要的是一条从症状到原因的快速通道。

本文展示了一个小型 .NET 实验室,你可以在其中强制触发受控的 504 超时,并通过可重复的 metrics → trace → logs 工作流进行调试。技术栈包括 ASP.NET Core、Blazor、.NET Aspire、Ollama 和 OpenTelemetry,目标非常务实:在发布之前缩短诊断时间。

核心理念是:可观测性 不是 仪表盘,而是 诊断所需的时间

我之所以构建这个实验,是因为我已经在没有可靠方式关联日志、追踪和指标的情况下,浪费了太多时间盯着日志看。本文中的 “LLM 工作负载” 指的是一个接口,其中尾部延迟和故障通常来源于模型调用以及提示词或工具的变更,而不仅仅是你的 HTTP 处理程序。

本文 以代码仓库为先,直接使用配套的仓库:

仓库:

  • 包含一个 Blazor UI,可触发健康、延迟、超时以及真实模型调用等场景。

一分钟了解技术栈

ComponentDescription
ASP.NET Core API一个小的请求入口,我可以对其进行端到端的仪表化,而不会产生噪音。
Blazor Web UI一键健康检查、延迟、超时以及真实模型调用场景。
.NET Aspire AppHost本地编排加上 Aspire Dashboard,实现快速切换。
Ollama (ollama/ollama:0.16.3)真实的本地模型调用行为,无需云端令牌费用。
OpenTelemetry日志告诉我 什么,追踪告诉我 哪里,指标告诉我 频率

为什么 LLM 超时感觉不同

  • Prompt 变化相当于部署:代码可能保持不变,但延迟和失败模式可能会改变。
  • 模型和运行时的变化会影响尾部延迟。
  • 工具或依赖调用会放大方差——一次慢调用可能导致超时。

最小关联字段

为了保持快速的故障排查,我希望在所有地方都有几个字段:

字段目的
run_id跟踪单个请求的生命周期
trace_id跨跨度和服务跟踪执行
prompt_version将行为关联到提示的更改
tool_version将故障关联到集成的更改

关联应如何呈现

POST /ask → trace_id in the trace span → run_id + trace_id in logs → timeout metric increases

我使用的命名约定

  • snake_case 在日志和 JSON 中:run_idtrace_idprompt_versiontool_version
  • camelCase 在 C# 变量中:runIdtraceIdpromptVersiontoolVersion

示例日志行

timeout during /ask run_id=9f0f2f3a6fdd4f5f9e9a1f4d8f6c6f3e trace_id=4c4f3b2e86d4d6a6b1f69a0d9d0d9f0a prompt_version=v1 tool_version=local-llm-v1

如果该链中的任意一个环节缺失,故障排查会立即变慢。

调试流程是什么样的

在实际操作中,步骤如下:

  1. 在 Web UI 中点击 Simulated Timeout (504)
  2. 打开 Aspire Metrics,确认 llm_timeouts_total 已增加。
  3. 跳转到 Traces,打开失败的 llm.run
  4. 复制 trace_id,然后切换到日志并按 trace_idrun_id 进行过滤。
  5. 检查失败是否与特定的 prompt_versiontool_version 对应。

这正是实验的核心:通过几个有目的的步骤,从超时症状快速定位可能的原因,而不是盲目猜测。

前置条件

  • 已安装并运行 Docker Desktop 或 Docker Engine
  • 已安装仓库 global.json 中指定的 .NET SDK 版本
  • Aspire 工作负载(如果你的设置需要)
dotnet workload install aspire
  • 本地可用端口(或调整启动设置):188881888911434
  • 如果使用稳定的 API 端口附录,还需要确保 17100 端口空闲

第 1 步 — 克隆并运行仓库

git clone https://github.com/ovnecron/minimal-llm-observability.git
cd minimal-llm-observability
dotnet run --project LLMObservabilityLab.AppHost/LLMObservabilityLab.AppHost.csproj

打开终端中打印的 Aspire Dashboard URL。如果出现身份验证提示,使用终端中提供的一次性 URL。

已修复的本地 HTTP 启动设置

  • Aspire Dashboard:http://localhost:18888
  • OTLP 端点(Aspire Dashboard):http://localhost:18889
  • Web UI(LLMObservabilityLab.Web):从 Aspire Dashboard 资源列表中打开

在 AppHost 启动配置文件中已通过 ASPIRE_ALLOW_UNSECURED_TRANSPORT=true 启用不安全的本地传输。

如果你已经在本地的 11434 端口运行了 Ollama,请停止它或在 AppHost 中更改容器端口映射。

如果 Real Ollama Call 返回 “model not found”,请在运行中的容器中拉取默认模型:

docker exec -it "$(docker ps --filter "name=local-llm" --format "{{.Names}}" | head -n 1)" \
  ollama pull llama3.2:1b

第2步 — 在 Web UI 中触发场景

  1. 打开 Aspire Dashboard → Resources → 点击 web-ui 端点

  2. LLMObservabilityLab.Web 的根页面提供一键操作:

    • Healthy Run
    • Simulate Delay
    • Real Ollama Call
    • Simulated Timeout (504)

    每次运行会显示:

    • run_id
    • trace_id
    • 状态
    • 耗时
  3. Web UI 还包含 /drill,提供固定的 15 分钟故障排查清单。

第 3 步 — 生成健康基线(可选)

在 Web UI 中点击 Healthy Run 大约 20 次。这会为您提供以下指标的快速基线:

  • llm_runs_total
  • llm_success_total

随后您可以将后续的失败运行与此基线进行比较。

第4步 — 强制超时并进行排查

  1. 在 Web UI 中点击 Simulated Timeout (504)
  2. 立即打开 Aspire Dashboard。

按钮会返回受控的 504,以便您按需演练可观测性管道。

我的排查循环(目标:约 15 分钟)

阶段操作
SpotMetrics 中检查 llm_timeouts_total
Drill打开失败的 llm.run trace
Pivottrace_idrun_id 过滤日志
Inspect对比 prompt_versiontool_version
Mitigate首先应用最小的安全修复
Verify重新运行超时场景并确认恢复

简单的流程指南

  • Metrics → 检查 llm_latency_ms 是否出现峰值
  • Traces → 过滤 scenario=simulate_timeout → 打开失败的 llm.run

我用于快速决策的最小信号

直接由此仓库发出

  • llm_runs_total
  • llm_success_total
  • llm_timeouts_total
  • llm_errors_total
  • llm_latency_ms

派生指标

task_success_rate = llm_success_total / llm_runs_total * 100

启动警报启发式

(这些是种子——请根据你的基线进行调优。)

  • task_success_rate 在 30 分钟内下降 > 5 pp
  • 延迟分位数(源自 llm_latency_ms)相较基线上升 > 30 %
  • 工具版本范围的成功率(标记为 tool_version 的运行)下降 < 90 %

故障排除

症状解决办法
端口 11434 已被占用停止本地 Ollama 实例或更改 AppHost 端口映射
没有追踪或指标确认 Aspire Dashboard 正在运行且 OTLP 端点可访问
未找到模型在容器内部运行 ollama pull …
CLI 或 API 调用失败从 Aspire Dashboard 复制准确的 API 端点(llm‑api → Endpoints

已验证 vs. 观点

可观测性建议常常把硬性事实和个人工作流混在一起。

已验证(在此仓库可复现)

  • 场景(健康、延迟、超时、真实调用)均通过 Web UI 触发。
  • 关联链路完整:指标计数器 → llm.run 跟踪 → 带有 run_idtrace_id 的日志。

观点(对我有效,需自行调节)

  • “15 分钟”目标循环。
  • 上述告警阈值(作为起始种子,而非普遍真理)。
  • 恰好四个关联字段(如系统需要可自行添加更多)。

最后思考

目标不是完美的仪表盘,而是缩短 time‑to‑diagnosis
如果你无法从超时快速定位到确切的跟踪和日志行,你仍然在猜测。

我使用这个实验室找到了适合自己的工作流,希望它能帮助你构建适合自己的可观测性流水线。

如果你遇到问题,打开 GitHub issue,我很乐意提供帮助。

参考文献

0 浏览
Back to Blog

相关文章

阅读更多 »

当工作成为心理健康风险时

markdown !Ravi Mishrahttps://media2.dev.to/dynamic/image/width=50,height=50,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fu...