本文字数:7143;估计阅读时间:18 分钟
作者:Lionel Palacin
本文在公众号【ClickHouseInc】首发
假设你正在找新房,想了解某个社区近几年的房价走势。与其反复点开图表、调整筛选条件,你能不能直接问一句:
“展示过去十年曼彻斯特的房价变化。”
然后系统立刻生成图表,附带解释,甚至还能继续提出后续问题。
这就是智能 AI 应用(Agentic 应用)的魅力所在。借助大语言模型(Large Language Model,LLM)的强大能力,它不仅能理解复杂的请求,还能自动调用 API,基于单个用户指令完成整套流程,带来真正智能、交互式的使用体验。
你可以点击文末原文观看我们客户小组的视频,了解 MCP 在实时分析类应用中的强大潜力。
在本文中,我们将教你如何构建这样一个智能应用。我们会基于 ClickHouse MCP Server 和 CopilotKit,开发一个可自定义的英国房产市场分析仪表板。前端使用 React 和 Next.js 构建,但你也可以将相同方法应用到任何现代应用框架中。
智能应用的核心组件
我们先来看看构建这样一个应用所需的关键组成部分。
大语言模型(LLM)
任何智能应用的核心都是大语言模型。它负责理解用户的输入、识别上下文、生成响应内容,并决定下一步该做什么。
为了确保用户体验流畅、响应及时,选用一款性能强大、上下文窗口足够大的模型非常关键。智能应用通常涉及复杂的任务、与外部工具的交互,以及处理来自第三方系统的数据。随着上下文信息越来越多,模型必须具备高效的处理和快速响应能力,才能让最终用户获得自然、流畅的交互体验。
在本示例中,我们使用的是 Anthropic 提供的 Claude Sonnet 3.7 模型。截至本文撰写时,该模型在 TAU-bench 基准测试中,在航空和零售行业场景下表现出色。这个基准测试主要评估各类 LLM 在与用户交互以及遵循专业规则方面的能力。
ClickHouse MCP Server:连接数据与智能的桥梁
我们的智能应用将通过构建用户自定义的仪表板,帮助大家分析英国房地产市场数据。虽然这些数据本身是公开的,模型在训练过程中也可能接触过,但这些信息存储在模型的参数中,并不是逐条记录。换句话说,即使模型曾见过这类数据,当我们询问英国某地的房价时,它依然可能“凭空想象”出一些数字。因此,在很多场景下,模型必须访问实时或专有的数据源,才能输出准确、有价值的结果。
这正是模型上下文协议(Model Context Protocol,MCP)服务器诞生的背景。MCP 是一个开放标准,帮助开发者在自有数据源与 AI 工具之间建立安全、双向的连接。
ClickHouse MCP Server 让开发者可以在智能应用中无缝集成 ClickHouse,使模型能够直接发起查询,获取实时数据支持。
CopilotKit:简化智能应用开发的 UI 框架
在整个架构中,CopilotKit 是第三个核心组件。它是一个专为 Agentic 应用设计的 UI 框架,极大地简化了开发流程。
我之所以选择 CopilotKit,是因为它帮我屏蔽了很多底层的复杂细节。它内置聊天界面支持、可轻松接入不同的大语言模型,还能自动处理模型触发的各种工具调用和 UI 动作。
接下来我们就来看一下,这些组件是如何协同工作的。
整体架构:从用户请求到可视化图表
我们以一个用户输入为例,展示整个流程如何运转。这个流程展示了各个组件如何协作,将自然语言请求转换为一张图表结果。
-
用户输入请求:“展示过去十年曼彻斯特的房价变化。”
-
该请求与当前应用状态和可用操作项一起,被发送至 CopilotKit 的运行时。
-
CopilotKit 将 MCP 资源列表加入提示中,并将其转发给大语言模型(LLM)。LLM 分析提示内容与当前资源,判断需要查询数据,并生成一条针对 ClickHouse 的 SQL 查询语句。
-
CopilotKit 运行时通过 MCP 客户端发起查询请求。
-
MCP 客户端调用 ClickHouse MCP Server,根据生成的 SQL 查询获取曼彻斯特近十年的房价数据。
-
数据与上下文信息一起返回给 LLM,模型识别出预定义的 generateChart 动作,并按照图表要求对数据进行格式化,生成最终响应。最终,图表被呈现在用户界面中
这个流程充分展现了智能应用背后各组件的紧密配合:模型理解用户意图,通过 ClickHouse 获取实时数据,再结合 CopilotKit 调用 UI 动作,将结果以图表形式反馈给用户。
如何搭建智能应用(Agentic Application)
在上一部分中我们已经了解了整个应用的高层架构,接下来我们将一步一步讲解如何从头开始构建它。
本节将重点展示实现过程中的关键步骤。如需查看完整可运行的示例,请访问我们的 Github 仓库获取参考代码。【https://github.com/ClickHouse/examples/tree/main/ai/mcp/copilotkit】
初始化应用
首先,我们需要创建一个全新的 React 应用,并使用 CopilotKit 框架进行初始化。使用 npx 命令可以快速生成项目。在提示如何与大语言模型交互时,请选择 MCP 作为连接方式。
npx create-next-app@latest
cd agentic-app
npx copilotkit@latest init
接入你自己的大语言模型
CopilotKit 默认使用的是 OpenAI 模型。但你也可以根据需要切换为其他支持的模型,具体支持列表可参考官方文档。【https://docs.copilotkit.ai/guides/bring-your-own-llm】
模型连接通常在服务端完成。CopilotKit 默认会暴露一个用于与大语言模型通信的 API 路由,前端通过这个接口与模型进行交互。
你可以编辑文件 ./app/api/copilotkit/routes.ts 来更换所使用的模型。
import { AnthropicAdapter } from "@copilotkit/runtime";
// const serviceAdapter = new OpenAIAdapter()
const serviceAdapter = new AnthropicAdapter({model: "claude-3-7-sonnet-latest"});
同时,别忘了通过环境变量的方式提供 API 密钥(如:ANTHROPIC_API_KEY)。
部署 ClickHouse MCP Server
在这个示例中,我们选择在本地部署 ClickHouse MCP Server。当然,你也可以将其部署到远程服务器,并让多个 MCP 客户端连接到同一个服务。
未来,ClickHouse Cloud 将支持远程 MCP Server 作为默认接口。这意味着,无需本地部署,任何 MCP 客户端都能直接连接到你的云端 ClickHouse 实例。
如果你希望抢先体验这项功能,可以前往 clickhouse.ai 注册 AI 功能的候补名单。【https://clickhouse.com/ai】
# Clone the ClickHouse MCP Server repository
git clone https://github.com/ClickHouse/mcp-clickhouse
# Install dependencies
python3 -m venv .venv && source .venv/bin/activate && uv sync && uv add fastmcp
# Configure connection to ClickHouse database
export CLICKHOUSE_HOST="sql-clickhouse.clickhouse.com"
export CLICKHOUSE_USER="demo"
export CLICKHOUSE_SECURE="true"
export CLICKHOUSE_PORT="8443"
# Run the MCP server and expose SSE transport protocol
fastmcp run mcp_clickhouse/mcp_server.py:mcp --transport sse
本次演示中我们使用的是 ClickHouse SQL Playground,它包含了英国房产市场的数据集。
最后,我们通过 fastmcp 命令启动 MCP Server,并使用 SSE(Server-Sent Events)作为默认传输方式,监听端口为 8000。
配置 MCP 客户端
CopilotKit 内置支持 MCP 客户端,我们只需配置服务器连接地址即可完成对接。
打开并编辑 ./app/copilotkit/page.tsx 文件,添加 ClickHouse MCP Server 的连接信息即可。
useEffect(() => {
setMcpServers([
{ endpoint: "http://localhost:8000/sse" },
]);
}, []);
定义智能体的操作逻辑
Agentic 应用最核心的特性之一,就是它能够根据与用户的对话自动执行操作。
在本项目中,我们希望应用能够根据用户的描述动态生成图表。这就是我们需要告诉大语言模型(LLM)该如何执行的操作。
我们使用 CopilotKit 提供的 useCopilotAction Hook 来实现这一功能。通过这个 Hook,开发者可以定义一组可由模型调用的自定义操作。在我们的示例中,该操作就是向状态中添加一条新的图表配置。
此外,我们还会用到另一个 Hook:useCopilotReadable,它允许我们将某个状态变量(例如图表配置数组)暴露给模型,以便它在推理过程中能使用这些信息。
要完成设置,你需要编辑文件 ./app/copilotkit/page.tsx,在其中定义好动作逻辑,并将图表的状态变量共享给模型。
// Chart configuration array
const [charts, setCharts] = useState<Chart[]>([]);
// Share the charts state variable with LLM
useCopilotReadable({
description: "These are all the charts props",
value: charts,
});
// Create a new action generateChart that will be used by the LLM to create the correct chart configuration and add it to the state variable.
useCopilotAction({
name: "generateChart",
description: "Generate a chart based on the provided data. Make sure to provide the data in the correct format and specify what field should be used a x-axis.",
parameters: [
{
name: "data",
type: "object[]",
description: "Data to be used for the chart. The data should be an array of objects, where each object represents a data point.",
},
{
name: "chartType",
type: "string",
description: "Type of chart to be generated. Lets use bar, line, area, or pie.",
},
{
name: "title",
type: "string",
description: "Title of the chart. Cant be more than 30 characters.",
},
{ name: "xAxis", type: "string", description: "x-axis label" }
],
handler: async ({ data, chartType, title, xAxis }) => {
const newChart = {
data,
chartType,
title,
xAxis
};
setCharts((charts) => [...charts, newChart] );
},
render: "Adding chart...",
});
接下来,我们添加一个 DynamicGrid 组件,用来遍历图表配置数组,并为每一项渲染一个图表。
function DynamicGrid({ charts }: { charts: Chart[] }) {
return (
charts.map((chart, index) => (
<div className="flex flex-col gap-4" key={index}>
<p className="text-white whitespace-nowrap overflow-hidden text-overflow-ellipsis text-xl leading-[150%] font-bold font-inter">{chart.title}</p>
<GenericChart {...chart} />
</div>
))
)
}
图表本身由 GenericChart 组件实现,它基于 ECharts 的 React 版本。当然,你也可以自由更换成自己喜欢的图表库。GenericChart 的源码可以在这里查看。【https://github.com/ClickHouse/examples/blob/copilotkit/ai/mcp/copilotkit/components/GenericChart.tsx】
最终效果展示
我们已经完成了整个实现的核心逻辑。接下来的工作主要是美化界面,为应用添加一些样式细节,让整体更具视觉吸引力。完整代码已托管在 Github 上,欢迎参考。【https://github.com/ClickHouse/examples/tree/main/ai/mcp/copilotkit】
在智能应用中使用 ClickHouse 的优势
实时分析数据库的强大能力
对于这类需要动态响应和实时推理的智能应用,选择一款实时分析型数据库至关重要。ClickHouse 正是这方面的理想选择。
实时分析数据库具备一系列适配 Agentic 应用场景的特性。首先,它支持近实时数据处理,可以让系统在信息刚产生时就立刻用于推理与响应。这对于需要及时辅助用户做决策的 AI 智能体至关重要。
其次,这类数据库天生适合执行复杂的数据分析任务,例如多维聚合、趋势挖掘和异常检测等。它们不像传统事务型数据库那样只关注数据的读写,而是专注于挖掘和提取洞察。
最后,它们还能支持高频率、高并发的交互式查询,无论是在对话过程中生成图表,还是执行多轮数据探索分析,都能保持稳定的性能,带来更加丝滑、即时的用户体验。
细粒度权限与配额控制
构建智能应用的一大挑战,是如何控制大语言模型(LLM)在代表用户操作时的权限范围。尤其是在模型可以通过 MCP Server 直接访问生产数据库的场景下,权限管理就显得尤为关键。
好在 ClickHouse 提供了非常灵活的权限机制与配额(quota)设置,让我们可以精准控制 MCP Server 向模型开放的数据与操作权限。
在本示例中,我们通过 SQL Playground 托管了英国房地产市场的数据集,并将 MCP Server 配置为以 demo 用户的身份进行身份验证。你可以在对应链接中查看该用户的具体配置方式。【https://github.com/ClickHouse/sql.clickhouse.com/blob/main/setup.sql】
demo 用户被限制为只读权限,且只能访问特定数据库。这种限制确保了模型只能查询我们允许的数据。在此基础上,我们还为该用户设置了配额限制,并分配了一个受限权限的用户配置文件,防止模型发起过多或资源开销过大的查询操作。通过这样的设置,我们可以在操作范围和资源消耗两方面实现精细化(fine-grained)控制。
总结
在这篇博客中,我们详细介绍了如何使用 ClickHouse MCP Server 与 CopilotKit 构建一款智能应用。
借助大语言模型的能力,用户可以自由构建基于英国市场数据的分析仪表板,实现个性化的数据洞察体验。
而像 ClickHouse 这样的高速、可扩展、具备安全机制的分析型数据库,是实现这种应用高效、稳定运行的关键所在。这种新型架构为 AI 工具的构建打开了全新思路,让我们能够为用户提供更深入的分析能力和更出色的使用体验。
征稿启示
面向社区长期正文,文章内容包括但不限于关于 ClickHouse 的技术研究、项目实践和创新做法等。建议行文风格干货输出&图文并茂。质量合格的文章将会发布在本公众号,优秀者也有机会推荐到 ClickHouse 官网。请将文章稿件的 WORD 版本发邮件至:Tracy.Wang@clickhouse.com