
本文字数:12221;估计阅读时间:31 分钟
作者:Dale McDiarmid & Lionel Palacin

在过去两年里,LLM(大语言模型)可观测性迅速成为热门话题,围绕这一领域的工具生态系统不断壮大,帮助开发者更好地理解与优化 AI 驱动的应用。从 LangChain 内置的 ClickHouse 集成,到各大 AI 工具包对 OpenTelemetry 的原生支持,关于模型行为、使用情况以及成本的透明度需求从未如此迫切。
ClickHouse 以其在高性能 LLM 分析领域的卓越表现而闻名[https://clickhouse.com/blog/langchain-why-we-choose-clickhouse-to-power-langchain],最近又推出了基于 ClickHouse 的开源可观测性栈——ClickStack。基于此背景,我们希望探索:利用 ClickStack 构建 LLM 可观测性到底有多容易。
本文将以 LibreChat 为例,介绍如何通过 OpenTelemetry(OTel)对这个集成了 MCP 服务器的 LLM 聊天界面进行埋点接入。我们的目标是:在尽量少改动代码的前提下,捕获有价值的追踪与指标,并评估基于 ClickStack 的方案在 LLM 应用的可观测性上能做到什么程度。
为什么这件事重要?在生产环境中,LLM 因 Token 消耗带来的成本往往十分可观。缺乏可观测性,团队就如同在盲飞——既无法洞察使用模式,也难以及时发现性能瓶颈或评估成本效益。可观测性不仅是“锦上添花”,更是成本管理、用户体验(UX)优化,以及投资回报率(ROI)验证的基础。接下来就让我们一探究竟。


LibreChat 是一个 AI 聊天平台,汇集了来自 OpenAI、Anthropic、Google 等提供商的模型,统一呈现在一个界面中。它被设计为 ChatGPT 或 Claude Desktop 的强大开源替代品,支持丰富的自定义选项、插件集成以及多语言访问。凭借简洁易用的界面和模块化架构,LibreChat 让自托管、功能扩展以及个性化定制的 AI 聊天体验变得轻而易举。

MCP 正快速成为 LLM 集成的默认标准,它提供了一种轻量且与编程语言无关的服务访问接口。今年早些时候,我们发布了 mcp-clickhouse 服务器,让 ClickHouse 能够被任何 MCP 客户端无缝调用。
MCP 的价值在于它赋予 LLM 更强的能力——不再只是被动回答,而是充当实时系统的主动接口。这样,模型不仅能查询数据库,还能触发操作,或通过自然对话的方式挖掘洞察。在这些 AI 智能体工作流中,响应速度和交互体验尤为关键。ClickHouse 在此类场景中尤为擅长,凭借其低延迟的分析引擎,可以在对话的几秒钟内给出响应,而无需等待数小时。MCP 正是促成这种连接的桥梁。
在本示例中,我们将把 ClickHouse MCP 服务器连接到 LibreChat。与此同时,以下的埋点接入过程同样适用于任何基于 FastMCP 框架的实现(ClickHouse MCP 便是基于此开发)。我们的 MCP 服务器会进一步连接到演示环境 sql.clickhouse.com[http://sql.clickhouse.com/],该环境包含 35 个以上的数据集,可用于回答用户的各类问题。

LibreChat 提供了一个 docker compose 文件[https://github.com/danny-avila/LibreChat/blob/main/docker-compose.yml],能够帮助用户轻松启动并运行所有相关组件。本节将介绍我们是如何在此基础上扩展 docker compose 文件,实现对 LibreChat 和 ClickHouse MCP Server 的埋点接入。完整的示例代码已发布在这个 Github 仓库[https://github.com/ClickHouse/examples/tree/main/clickstack/librechat-llm-observability]。

LibreChat 开箱即用支持 MCP,官方文档中提供了多种集成 MCP 服务器的示例[https://www.librechat.ai/docs/features/mcp#basic-configuration]。在本示例中,我们会将 ClickHouse MCP Server 作为独立服务部署,LibreChat 则通过 SSE 协议与其通信[https://en.wikipedia.org/wiki/Server-sent_events]。
ClickHouse MCP Server 提供了官方 Docker 镜像[https://hub.docker.com/r/mcp/clickhouse],方便我们在部署时实现独立运行。
下方展示了用于将 ClickHouse MCP Server 作为独立服务部署的 Docker Compose 配置,可直接追加到 LibreChat 官方提供的 docker compose 文件中[https://github.com/danny-avila/LibreChat/blob/main/docker-compose.yml]。
mcp-clickhouse:image: mcp/clickhousecontainer_name: mcp-clickhouseports:- 8001:8000extra_hosts:- "host.docker.internal:host-gateway"environment:- CLICKHOUSE_HOST=sql-clickhouse.clickhouse.com- CLICKHOUSE_USER=demo- CLICKHOUSE_PASSWORD=- CLICKHOUSE_MCP_SERVER_TRANSPORT=sse- CLICKHOUSE_MCP_BIND_HOST=0.0.0.0
在 LibreChat 的配置文件 librechat.yml 中,MCP 客户端配置为通过 SSE 协议连接 MCP 服务器。
mcpServers:clickhouse-playground:type: sseurl: http://host.docker.internal:8001/sse

我们的 LLM 可观测性方案的核心组件是 ClickStack——一套基于 ClickHouse 的可观测性栈。ClickStack 由三部分组成:HyperDX UI、OpenTelemetry collector,以及 ClickHouse(支持单独部署与配置)。在本次演示中,我们采用了最便捷的部署方式——通过 docker compose 实现的集成部署方案[https://clickhouse.com/docs/use-cases/observability/clickstack/deployment/all-in-one]。
只需执行以下命令,即可在本地启动 ClickStack。
docker run -p 8080:8080 -p 4317:4317 -p 4318:4318 -p 9000:9000 docker.hyperdx.io/hyperdx/hyperdx-all-in-one
启动完成后,HyperDX UI 可通过 http://localhost:8080 访问。首次访问时需要注册账号。
ClickStack 中的 OpenTelemetry collector 默认会开放 OTLP 端口,用于接收遥测数据,但该接口需要安全的 API 密钥。API 密钥会在 ClickStack 启动时自动生成,用户可在 HyperDX UI 的 Team Settings 菜单中查看。本文档后续将用 CLICKSTACK_API_KEY 来代指该密钥。


LibreChat 是一个基于 Node.js 构建、前端使用 React 的应用。ClickStack 提供了简单便捷的方案[https://clickhouse.com/docs/use-cases/observability/clickstack/sdks/nodejs],只需极少的代码改动即可为 Node.js 应用接入监控埋点。
为了引入所需的 Node.js 依赖,我们可以在 LibreChat 的 Docker 镜像基础上进行扩展。
# Use the existing image as baseFROM ghcr.io/danny-avila/librechat-dev:latest# Optional: switch to root if needed to install globallyUSER rootRUN apk add --no-cache git build-base python3-dev# Install OpenTelemetry CLIRUN npm install @hyperdx/node-opentelemetry# Switch back to the node user if neededUSER nodeEXPOSE 3080# Replace CMD with OpenTelemetry-instrumented version# Redirect stdout and stderr to a fileCMD sh -c "NODE_ENV=production \HDX_NODE_ADVANCED_NETWORK_CAPTURE=true \OTEL_EXPORTER_OTLP_ENDPOINT=,[object Object], \HYPERDX_API_KEY=,[object Object], \OTEL_SERVICE_NAME=librechat-api \npx opentelemetry-instrument api/server/index.js \>> app/api/logs/console.log 2>&1"
通过 opentelemetry-instrument 启动 Node.js 进程,便能完成监控接入,将应用的追踪数据发送到 ClickStack。注意,这里我们通过环境变量传入 CLICKSTACK_API_KEY,用于与 ClickStack 部署的 OpenTelemetry collector 认证对接。
应用的日志会写入本地文件 console.log,后续由 OTel collector 统一采集,具体可参考日志采集部分。
值得一提的是,我们将日志重定向至 console.log。虽然 LibreChat 内置了日志功能,但并不支持结构化的 JSON 格式输出,这对于 OTel collector 的日志解析至关重要。为此,我们通过设置环境变量 CONSOLE_JSON=true 和 DEBUG_CONSOLE=true,将日志级别调整为 debug,并启用结构化日志格式。

ClickHouse MCP Server 采用 Python 编写,因此我们可以直接通过 OpenTelemetry 的 Python 自动埋点功能[https://opentelemetry.io/docs/zero-code/python/],快速完成监控接入。
以下是如何基于官方 ClickHouse MCP Docker 镜像进行扩展。
FROM mcp/clickhouseRUN python3 -m pip install --no-cache-dir --break-system-packages \opentelemetry-distroRUN python3 -m pip install --no-cache-dir --break-system-packages \opentelemetry-exporter-otlpRUN opentelemetry-bootstrap -a install# Fix issue with urllib3 and OpenTelemetryRUN python3 -m pip uninstall -y pip_system_certsRUN mkdir -p app/logs# Redirect stdout and stderr to a fileCMD sh -c "OTEL_EXPORTER_OTLP_HEADERS='authorization=,[object Object],' opentelemetry-instrument python3 -m mcp_clickhouse.main >> app/logs/mcp.log 2>&1"
在本文撰写时,ClickStack 提供的 Python 埋点功能存在一些兼容性问题[https://clickhouse.com/docs/use-cases/observability/clickstack/sdks/python]。但我们依然可以使用标准的 OpenTelemetry 埋点方式完成集成。关键在于确保通过 OTEL_EXPORTER_OTLP_HEADERS='authorization=$CLICKSTACK_API_KEY' 将 API 认证密钥加入请求头。
与 LibreChat 类似,MCP Server 的日志也会写入本地文件,并通过 OTel collector 进行收集,具体细节可参见日志采集部分。

应用程序日志已被写入本地文件,我们通过在独立的 Docker 容器中部署单独的 OTel collector,来完成日志的收集。通过挂载共享卷,应用容器与 collector 容器可以共享同一日志文件,collector 利用 filelog receiver 读取日志内容[https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/filelogreceiver]。
该 collector 独立于 ClickStack 自带的 collector,我们通过 OTLP 协议将其与 ClickStack collector 连接。
此外,LibreChat 在 8000 端口还暴露了应用指标。我们通过 Prometheus receiver 采集这些指标[https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/prometheusreceiver],并统一转发到 ClickStack。
以下是我们部署的 OTel collector 的完整配置:
receivers:filelog:include:- var/log/librechat/console.log- var/log/librechat/mcp-clickhouse/mcp.logstart_at: beginningoperators:- type: json_parserid: parse_json_logon_error: send_quiettimestamp:parse_from: attributes.timestamplayout_type: gotimelayout: '2006-01-02T15:04:05.000Z'severity:parse_from: attributes.level- type: trace_parsertrace_id:parse_from: attributes.trace_idspan_id:parse_from: attributes.span_id- type: moveid: promote_messagefrom: attributes.messageto: bodyif: 'attributes.message != nil'- type: regex_parserid: extract_conversation_id# look in the body line for conversationIdparse_from: bodyregex: "conversationId: (?P[0-9a-fA-F-]+)"on_error: send_quietprometheus:config:scrape_configs:- job_name: 'librechat_metrics'scrape_interval: 15sstatic_configs:- targets: ['host.docker.internal:8000']processors:transform:error_mode: ignorelog_statements:- set(resource.attributes["service.name"], "librechat-api") where log.attributes["log.file.name"] == "console.log"- set(resource.attributes["service.name"], "mcp-clickhouse") where log.attributes["log.file.name"] == "mcp.log"resource:attributes:- key: service.namevalue: librechat-apiaction: upsertexporters:otlp:endpoint: http://host.docker.internal:4317headers:authorization: ${CLICKSTACK_API_KEY}tls:insecure: trueservice:pipelines:logs:receivers: [filelog]processors: [resource, transform]exporters: [otlp]metrics:receivers: [prometheus]processors: [resource]exporters: [otlp]

至此,我们已经定制了 LibreChat 和 ClickHouse MCP Server 的 Docker 镜像,同时通过独立的 OTel collector 服务实现日志采集。我们的最终数据采集与监控架构如下:

我们可以通过扩展 LibreChat 官方的 docker compose 文件,将所有组件集成在一起。完整的包含埋点配置的 docker compose 文件可在此获取[https://github.com/ClickHouse/examples/blob/96b55c02cf6c673b6700b5516717e4a2f09414e8/clickstack/librechat-llm-observability/docker-compose.yaml]。
要启动应用,只需执行 docker compose up。
LibreChat 启动后,可通过 http://localhost:3080 访问。首次访问需注册账号。为验证配置是否生效,登录后选择对应 API key 的 LLM 模型,并在聊天框下方选中 ClickHouse MCP Server。
下图展示了 LibreChat 成功配置 MCP Server 后的界面,输入框下方列出了 MCP server:


应用运行并完成埋点后,我们就可以基于收集到的可观测性数据,深入分析 LibreChat、LLM 与 MCP Server 之间的交互。例如,重点关注 LLM 模型与 MCP server 通信的频率,以及这些交互中 Token 的消耗量。
部分 LLM 交互统计,如会话数量、Token 使用等,已由默认的 LibreChat 组件内置的 MongoDB 实例记录(实际上,我们还可以通过 ClickHouse 的 MongoDB 表函数直接读取这些数据)。尽管这足以支持 LibreChat 的基础监控,但通过 ClickStack 观察 LLM 应用的方案更加灵活,支持大规模分析。无论应用本身是否集成 MCP 工具,这种方案都同样适用。
简单提示测试
为了验证 MCP Server 是否正常工作,以及 LLM 是否能与之交互,我们可以从一个简单的提示开始。
试用以下提示,获取 ClickHouse playground 中有哪些数据库:
"What databases do you have access to?"

在 LibreChat 界面中,我们可以看到 MCP 工具仅发起了一次请求来检索数据库列表。
接着,我们进入 HyperDX UI,查看已捕获的可观测性数据。默认情况下,日志数据源会展示来自 LibreChat(librechat-api)与 ClickHouse MCP Server(mcp-clickhouse)的日志信息:

为了定位交互的起点,我们可以用提示文本作为筛选条件。LibreChat 会自动将用户输入的提示作为 text 属性记录在日志中。
可以通过 SQL 语法设置筛选:LogAttributes['text'] LIKE '%What databases do you have access to%'
此外,我们在结果表中添加了两列:LogAttributes['text'] 用于展示提示文本,TraceId 则用来跟踪单次完整的交互过程。需要注意的是,每当用户向 LLM 提交提示,系统就会生成一条新的 trace,并赋予唯一的 TraceId。

接下来,我们按 TraceId 进一步筛选。点击某条日志后,点击 TraceId 字段旁的 Add to Filter。

在采集 LibreChat 日志的同时,还捕获了不少元数据。可以通过配置结果表来展示这些信息:
Timestamp,ServiceName,LogAttributes['conversationId'] AS cId, TraceId AS tId,LogAttributes['completionTokens'] as ct, LogAttributes['tokenCount'] as tc, LogAttributes['promptTokens'] as pt,LogAttributes['text'] as prompt, Body
这些属性中,有几项对于我们的分析尤其重要,以下是简要说明。需要说明的是,部分 token 相关属性的定义基于经验推断,因为目前缺乏权威文档:
conversationId:LibreChat 每次开启新会话时生成的唯一 ID。 TraceId:每次在会话内发起新的交互时生成的唯一追踪 ID。 completionTokens:LLM 生成响应内容时消耗的 Token 数。 promptTokens:LLM 处理提示时产生的 Token 数。 tokenCount:用户提交的提示消耗的 Token 数。 text:用户输入的实际提示内容。

通过 TraceId 过滤日志后,我们就能看到完整的交互过程。但实际上,涉及 LLM 的日志只有少数几条,这些记录中包含 completionTokens 或 promptTokens,代表 LLM 已经参与了响应。
验证数据
为了验证 Token 统计的准确性,我们首先通过 SQL 查询,统计某次会话中的 completionTokens 与 promptTokens 总和。然后将这个总数与 OpenAI 控制台的 Token 使用量进行比对。我们专门为对比测试申请了一个新的 API key。
下图是 OpenAI 控制台的使用情况截图,显示该 API key 共消耗了 1008 个 Token,其中 790 个为输入 Token,218 个为输出 Token。

接下来,我们用 ClickStack 中的统计结果与之对比。ClickHouse 的完整 SQL 支持让它相比普通可观测性工具,能支持更深入的分析。通过 ClickHouse 后端直接运行 SQL,不仅能精准计算 Token 数量,还能执行更丰富的数据分析——得益于所有数据按宽事件存储[https://clickhouse.com/blog/clickstack-a-high-performance-oss-observability-stack-on-clickhouse]。
ClickStack 的 Docker 镜像开放了 9000 端口,因此我们可以通过 clickhouse-client 直接连接到 ClickHouse 实例[https://clickhouse.com/docs/interfaces/cli]。
我们针对会话 ID 为 9a94bc9a-6e22-46d5-bffc-024cfc01223d 的交互,执行 SQL 查询以汇总 Token 数量。
SELECTLogAttributes['conversationId'] AS conversationId,LogAttributes['trace_id'] AS trace_id,sum(toUInt32OrZero(LogAttributes['completionTokens'])) AS completionTokens,sum(toUInt32OrZero(LogAttributes['tokenCount'])) AS tokenCount,sum(toUInt32OrZero(LogAttributes['promptTokens'])) AS promptTokens,anyIf(LogAttributes['text'], (LogAttributes['text']) != '') AS promptFROM otel_logsWHERE conversationId = '9a94bc9a-6e22-46d5-bffc-024cfc01223d'GROUP BYconversationId,trace_id
查询结果显示:

completionTokens 累计 218,与 OpenAI 控制台的输出 Token 数完全一致。promptTokens 累计 790,同样与输入 Token 数一致。
这让我们对 ClickStack 统计 Token 的准确性有了充分的信心。
追踪更复杂的提示
在简单提示验证成功后,我们继续用更贴近真实用户场景的提问进行测试。
下一次实验我们使用的提示是:“How is the USD related to the GBP?”
这次,模型需要频繁与 MCP server 交互——先探索数据是否有助于解答,再通过多次 SQL 查询获取更完整的答案细节。
下图是 LibreChat 中完整回答该问题的界面,可以看到 MCP 工具被多次调用,从 ClickHouse 查询数据。

回到 HyperDX UI,查看这次提问产生的日志。由于日志数量较多,我们通过筛选包含 completionTokens 或 tokenCount 的日志,聚焦查看 Token 相关的交互。
has(LogAttributes, 'completionTokens') OR has(LogAttributes, 'tokenCount')
这样便可以专注跟踪 LLM 的交互过程,以及每次交互的 Token 输入与输出数量。

我们还可以查看 trace,深入了解各个组件的交互链路。点击任意日志,进入 Trace 标签页,下滑找到 mcp-clickhouse trace,就可以看到 ClickHouse 的调用。

此外,ClickStack 还采集了丰富的监控指标,通过 Prometheus exporter 暴露[https://github.com/virtUOS/librechat_exporter/],并由 OTel collector 收集[https://github.com/ClickHouse/examples/blob/96b55c02cf6c673b6700b5516717e4a2f09414e8/clickstack/librechat-llm-observability/otel-file-collector.yaml#L36]。可用指标种类丰富,具体列表可在官方文档中查看。
例如,librechat_messages_total 用于统计 LibreChat 中的总消息数,并可以直观展示在监控图表上。


LLM 可观测性在生产环境尤其关键,尤其是针对智能体应用以及频繁借助 MCP 工具与 LLM 交互的场景。通过监控性能、使用情况与成本,帮助团队确保系统在规模化场景下依然稳定高效。ClickStack 支持设置阈值与自动告警[https://clickhouse.com/docs/use-cases/observability/clickstack/alerts],帮助团队在成本或延迟异常前,及时采取措施。
本文介绍了如何通过 ClickStack 以极简配置实现完整的监控与可观测性,部署方式易于复用,并已在真实环境中验证可行。借助 ClickHouse 的强大能力,ClickStack 还能轻松扩展,应对大规模的日志、追踪与指标数据。
除了监控,团队还可以基于这些数据与 HyperDX 对关键指标设置告警,例如标记消耗异常高的交互、请求量异常的高峰,或预付费 Token 接近耗尽的风险。
为了帮助大家快速上手,我们已在 GitHub 分享了完整的可运行示例,能够为构建复杂 LLM 工作流的可观测性提供一套简洁且实用的参考方案。
/END/
试用阿里云 ClickHouse企业版
轻松节省30%云资源成本?阿里云数据库ClickHouse 云原生架构全新升级,首次购买ClickHouse企业版计算和存储资源组合,首月消费不超过99.58元(包含最大16CCU+450G OSS用量)了解详情:https://t.aliyun.com/Kz5Z0q9G


征稿启示
面向社区长期正文,文章内容包括但不限于关于 ClickHouse 的技术研究、项目实践和创新做法等。建议行文风格干货输出&图文并茂。质量合格的文章将会发布在本公众号,优秀者也有机会推荐到 ClickHouse 官网。请将文章稿件的 WORD 版本发邮件至:Tracy.Wang@clickhouse.com






