Python調(diào)用DeepSeek API查詢ClickHouse的流程步驟
調(diào)用 DeepSeek API,并通過 MCP (Model Context Protocol) 協(xié)議接入 mcp-clickhouse,從而讓 DeepSeek 能夠查詢 ClickHouse 數(shù)據(jù)庫來回答用戶問題。
- stdio 模式
前置準(zhǔn)備
在運(yùn)行代碼之前,你需要確保環(huán)境中有以下依賴:
安裝 Python 庫:
pip install mcp openai
安裝 uv (因?yàn)槟愕呐渲弥惺褂昧?uv 來運(yùn)行 mcp-clickhouse):
pip install uv
獲取 DeepSeek API Key:你需要一個有效的 DeepSeek API 密鑰。
Python 代碼 (main.py)
請將代碼中的 <YOUR_DEEPSEEK_API_KEY> 替換為你的實(shí)際 Key,并確保 <clickhouse-host> 等配置已填入正確的值。
import asyncio
import os
import json
import sys
from typing import List, Dict, Any, Optional
# 導(dǎo)入 MCP 相關(guān)庫
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
import mcp.types as types
# 導(dǎo)入 OpenAI SDK (DeepSeek 兼容 OpenAI 格式)
from openai import AsyncOpenAI
# ================= 配置部分 =================
# DeepSeek API 配置
DEEPSEEK_API_KEY = os.getenv("DEEPSEEK_API_KEY", "<YOUR_DEEPSEEK_API_KEY>")
DEEPSEEK_BASE_URL = "https://api.deepseek.com"
MODEL_NAME = "deepseek-chat" # 或者 "deepseek-reasoner" (R1)
# MCP ClickHouse Server 配置 (來自你的 JSON)
MCP_CLICKHOUSE_CONFIG = {
"command": "uv",
"args": [
"run",
"--with",
"mcp-clickhouse",
"--python",
"3.10",
"mcp-clickhouse"
],
"env": {
"CLICKHOUSE_HOST": "<clickhouse-host>",
"CLICKHOUSE_PORT": "<clickhouse-port>",
"CLICKHOUSE_USER": "<clickhouse-user>",
"CLICKHOUSE_PASSWORD": "<clickhouse-password>",
"CLICKHOUSE_ROLE": "<clickhouse-role>",
"CLICKHOUSE_SECURE": "true",
"CLICKHOUSE_VERIFY": "true",
"CLICKHOUSE_CONNECT_TIMEOUT": "30",
"CLICKHOUSE_SEND_RECEIVE_TIMEOUT": "30"
}
}
# ================= 工具函數(shù) =================
def convert_mcp_tool_to_openai(mcp_tool: types.Tool) -> Dict[str, Any]:
"""
將 MCP 工具定義轉(zhuǎn)換為 OpenAI/DeepSeek 支持的 Function Calling 格式。
"""
return {
"type": "function",
"function": {
"name": mcp_tool.name,
"description": mcp_tool.description,
"parameters": mcp_tool.inputSchema
}
}
# ================= 主邏輯 =================
async def run_chat_loop():
# 1. 初始化 DeepSeek 客戶端
client = AsyncOpenAI(api_key=DEEPSEEK_API_KEY, base_url=DEEPSEEK_BASE_URL)
# 2. 準(zhǔn)備 MCP Server 參數(shù)
server_params = StdioServerParameters(
command=MCP_CLICKHOUSE_CONFIG["command"],
args=MCP_CLICKHOUSE_CONFIG["args"],
env={**os.environ, **MCP_CLICKHOUSE_CONFIG["env"]} # 合并當(dāng)前環(huán)境變量
)
print(f"正在啟動 MCP Server: {MCP_CLICKHOUSE_CONFIG['command']}...")
# 3. 連接 MCP Server 并開始對話循環(huán)
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
# 初始化連接
await session.initialize()
# 獲取 MCP Server 提供的工具列表
mcp_tools_list = await session.list_tools()
openai_tools = [convert_mcp_tool_to_openai(tool) for tool in mcp_tools_list.tools]
print(f"\n已連接 MCP Server,加載了 {len(openai_tools)} 個工具: {[t['function']['name'] for t in openai_tools]}")
print("-" * 50)
print("你可以開始詢問關(guān)于 ClickHouse 的問題了 (輸入 'quit' 退出)。")
messages = [
{"role": "system", "content": "你是一個智能助手,可以利用工具查詢 ClickHouse 數(shù)據(jù)庫來回答用戶問題。"}
]
while True:
user_input = input("\n用戶: ")
if user_input.lower() in ["quit", "exit"]:
break
messages.append({"role": "user", "content": user_input})
# 第一輪調(diào)用:發(fā)送用戶問題 + 工具定義給 DeepSeek
try:
response = await client.chat.completions.create(
model=MODEL_NAME,
messages=messages,
tools=openai_tools,
)
except Exception as e:
print(f"API 調(diào)用錯誤: {e}")
continue
assistant_msg = response.choices[0].message
messages.append(assistant_msg)
# 檢查 DeepSeek 是否想調(diào)用工具
if assistant_msg.tool_calls:
print(f"\n[思考] 模型決定調(diào)用工具...")
for tool_call in assistant_msg.tool_calls:
tool_name = tool_call.function.name
tool_args = json.loads(tool_call.function.arguments)
print(f" -> 調(diào)用工具: {tool_name}, 參數(shù): {tool_args}")
# 執(zhí)行 MCP 工具
try:
mcp_result = await session.call_tool(tool_name, arguments=tool_args)
# 獲取文本結(jié)果 (ClickHouse MCP 通常返回文本或 JSON 文本)
tool_output = ""
if mcp_result.content:
for content in mcp_result.content:
if content.type == "text":
tool_output += content.text
print(f" <- 工具返回結(jié)果 (前100字符): {tool_output[:100]}...")
# 將工具結(jié)果添加回對話歷史
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": tool_output
})
except Exception as e:
error_msg = f"工具執(zhí)行出錯: {str(e)}"
print(f" ! {error_msg}")
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": error_msg
})
# 第二輪調(diào)用:將工具結(jié)果發(fā)送回 DeepSeek 獲取最終回答
final_response = await client.chat.completions.create(
model=MODEL_NAME,
messages=messages,
# 這里依然傳入 tools,以防模型需要繼續(xù)多步調(diào)用
tools=openai_tools,
)
final_content = final_response.choices[0].message.content
print(f"\nDeepSeek: {final_content}")
messages.append(final_response.choices[0].message)
else:
# 如果不需要調(diào)用工具,直接輸出結(jié)果
print(f"\nDeepSeek: {assistant_msg.content}")
if __name__ == "__main__":
# Windows 下通常需要這個策略
if sys.platform.startswith('win'):
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
asyncio.run(run_chat_loop())
代碼邏輯解釋
MCP 連接 (stdio_client):
- 代碼使用
uv run ...命令啟動mcp-clickhouse的子進(jìn)程。 - 通過標(biāo)準(zhǔn)輸入/輸出 (stdio) 與該進(jìn)程建立通信通道。
CLICKHOUSE_HOST等敏感信息通過環(huán)境變量 (env) 傳遞給子進(jìn)程,保證安全性。
工具發(fā)現(xiàn)與轉(zhuǎn)換 (convert_mcp_tool_to_openai):
session.list_tools()從 mcp-clickhouse 獲取可用的工具(例如執(zhí)行 SQL 查詢的工具)。- 由于 MCP 的工具定義格式與 OpenAI/DeepSeek 的 Function Calling 格式略有不同(主要在于外層結(jié)構(gòu)),代碼中定義了一個轉(zhuǎn)換函數(shù)將其適配。
對話循環(huán) (Chat Loop):
- User Input: 接收你的問題。
- First API Call: 將問題和轉(zhuǎn)換后的工具列表發(fā)送給 DeepSeek。
- Tool Execution: 如果 DeepSeek 返回
tool_calls(例如它生成了一個 SQL 語句來查詢數(shù)據(jù)),Python 代碼會攔截這個請求,通過session.call_tool在本地的 mcp-clickhouse 服務(wù)中執(zhí)行該 SQL。 - Second API Call: 將 ClickHouse 返回的查詢結(jié)果(數(shù)據(jù))作為
tool類型的消息發(fā)回給 DeepSeek。 - Final Answer: DeepSeek 根據(jù)查詢結(jié)果生成最終的自然語言回答。
運(yùn)行示例
假設(shè)你問:“查詢 users 表里有多少行數(shù)據(jù)?”
- DeepSeek 分析意圖,返回
tool_calls,調(diào)用query_sql工具,參數(shù)為SELECT count() FROM users。 - Python 腳本通過 MCP 執(zhí)行該 SQL。
- ClickHouse 返回
105。 - Python 腳本將
105發(fā)給 DeepSeek。 - DeepSeek 回答:“users 表里共有 105 行數(shù)據(jù)。”
到此這篇關(guān)于Python調(diào)用DeepSeek API查詢ClickHouse的流程步驟的文章就介紹到這了,更多相關(guān)Python DeepSeek API查詢ClickHouse內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python提取JSON格式數(shù)據(jù)實(shí)戰(zhàn)案例
這篇文章主要給大家介紹了關(guān)于Python提取JSON格式數(shù)據(jù)的相關(guān)資料, Python提供了內(nèi)置的json模塊,用于處理JSON數(shù)據(jù),文中給出了詳細(xì)的代碼示例,需要的朋友可以參考下2023-07-07
Pandas創(chuàng)建DataFrame提示:type?object?'object'?has?n
Pandas數(shù)據(jù)幀(DataFrame)是二維數(shù)據(jù)結(jié)構(gòu),它包含一組有序的列,每列可以是不同的數(shù)據(jù)類型,這篇文章主要給大家介紹了關(guān)于Pandas創(chuàng)建DataFrame提示:type?object?‘object‘?has?no?attribute?‘dtype‘的解決方案,需要的朋友可以參考下2023-02-02
Python的Flask框架標(biāo)配模板引擎Jinja2的使用教程
Jinja2是Python世界的一款高人氣template engine,是許多開源Web框架的選擇,包括Flask這樣的明星級項(xiàng)目,這里我們就來共同學(xué)習(xí)Python的Flask框架標(biāo)配模板引擎Jinja2的使用教程2016-07-07
Scrapy框架基本命令與settings.py設(shè)置
這篇文章主要介紹了Scrapy框架基本命令與settings.py設(shè)置,結(jié)合實(shí)例形式分析了創(chuàng)建爬蟲項(xiàng)目、創(chuàng)建爬蟲文件、存儲、打開網(wǎng)頁及settings.py設(shè)置等相關(guān)操作技巧,需要的朋友可以參考下2020-02-02
django連接mysql數(shù)據(jù)庫及建表操作實(shí)例詳解
這篇文章主要介紹了django連接mysql數(shù)據(jù)庫及建表操作,結(jié)合實(shí)例形式詳細(xì)分析了Django框架連接mysql數(shù)據(jù)庫、創(chuàng)建與查詢數(shù)據(jù)表相關(guān)操作實(shí)現(xiàn)技巧,需要的朋友可以參考下2019-12-12
Windows上安裝tensorflow 詳細(xì)教程(圖文詳解)
這篇文章主要介紹了Windows上安裝TENSORFLOW 詳細(xì)教程,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下2020-02-02
Python3 關(guān)于pycharm自動導(dǎo)入包快捷設(shè)置的方法
今天小編就為大家分享一篇Python3 關(guān)于pycharm自動導(dǎo)入包快捷設(shè)置的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-01-01

