鍵.png)
MCP協(xié)議詳解:復(fù)刻Manus全靠它,為什么說MCP是Agent進(jìn)化的一大步?
要求:
python -m pip install pymysql flask
讓kimi給我生成一個(gè)文章表,并且插入10條數(shù)據(jù),我們可以告訴kimi,文章長(zhǎng)度多大,這樣內(nèi)容可以豐富些。
直接讓kimi生成一個(gè)暴露接口查數(shù)據(jù)庫(kù)的服務(wù),有簡(jiǎn)單的優(yōu)化了下,將下面的內(nèi)容放入到server.py
文件中
from flask import Flask, request, jsonify
import pymysql
app = Flask(__name__)
# 數(shù)據(jù)庫(kù)配置
DATABASE_CONFIG = {
'host': '', # 自己的數(shù)據(jù)庫(kù)地址
'user': '', # 自己數(shù)據(jù)庫(kù)的賬戶
'password': '', #自己數(shù)據(jù)庫(kù)的密碼
'db': 'demo', # 自己數(shù)據(jù)庫(kù)的庫(kù)名
'charset': 'utf8mb4',
'cursorclass': pymysql.cursors.DictCursor
}
@app.route('/query', methods=['POST'])
def query_database():
print("接收到請(qǐng)求")
# 獲取關(guān)鍵字
keyword = request.json.get('keyword')
print("keyword為:"+keyword)
ifnot keyword:
return jsonify({"error": "Keyword is required"}), 400
# 參數(shù)化查詢,避免 SQL 注入,修改成自己的庫(kù)
query = "SELECT * FROM articles WHERE content LIKE %s"
params = ('%' + keyword + '%',)
try:
# 建立數(shù)據(jù)庫(kù)連接
connection = pymysql.connect(**DATABASE_CONFIG)
with connection.cursor() as cursor:
# 執(zhí)行查詢
cursor.execute(query, params)
result = cursor.fetchall()
connection.commit()
connection.close()
ifnot result:
return"未查詢到有效數(shù)據(jù)", 400
# 生成 Markdown 表格
markdown_table = generate_markdown_table(result)
return markdown_table, 200
except Exception as e:
return str(e), 500
def generate_markdown_table(results):
""" 生成 Markdown 表格 """
ifnot results:
return""
# 獲取列名
columns = results[0].keys()
# 表頭
table_md = "| " + " | ".join([col for col in columns]) + " |\n"
# 分隔線
table_md += "| " + " --- |" * len(columns) + "\n"
# 表格內(nèi)容
for row in results:
table_md += "| " + " | ".join([str(cell) for cell in row.values()]) + " |\n"
return table_md
if __name__ == '__main__':
# 注意這里綁定本機(jī)的內(nèi)容ip,省事點(diǎn),就0.0.0.0即可。不要綁定127.0.0.1,docke內(nèi)訪問不到
app.run(host='10.1.0.65', port=8000)
啟動(dòng)服務(wù)
python .\server.py
創(chuàng)建一個(gè)空白應(yīng)用。
在開始節(jié)點(diǎn)添加一個(gè)輸入字段context
添加一個(gè)LLM,把開始節(jié)點(diǎn)設(shè)置的context
字段作為上下文傳入,并設(shè)置提示詞提取關(guān)鍵詞。
添加一個(gè)http請(qǐng)求節(jié)點(diǎn),把我們?cè)诮涌陂_發(fā)里的地址和接口名填寫進(jìn)去2
,然后把大模型的輸出作為關(guān)鍵詞填寫到請(qǐng)求body里3
,我們關(guān)閉重試機(jī)制4
。
這里要注意下:json的引號(hào)是中文的,最好在外面寫好校驗(yàn)過了再放進(jìn)去。
在HTTP請(qǐng)求的輸出變量里,我們只關(guān)注status_code 響應(yīng)狀態(tài)碼和響應(yīng)內(nèi)容即可。
添加一個(gè)條件分支1
,然后設(shè)置HTTP響應(yīng)碼為200的時(shí)候,連接到大模型。其他直接結(jié)束。
添加大模型,將HTTP請(qǐng)求的響應(yīng)體作為上下文給大模型,輸入提示詞,讓大模型根據(jù)知識(shí),驗(yàn)證,并進(jìn)行合理性的驗(yàn)證,最后結(jié)構(gòu)化返回。
在結(jié)束節(jié)點(diǎn)中,我們把大模型整理的內(nèi)容輸出。
試運(yùn)行效果。
由于difysandbox的安全限制
官方也有了對(duì)應(yīng)的說明,見文檔。 https://github.com/langgenius/dify-sandbox/blob/main/FAQ.mdss
一定要使用linux環(huán)境
、一定要使用linux環(huán)境
一定要使用linux環(huán)境
我從github上拉下代碼以后,搜索“syscalls_amd64.go
一共有4個(gè)文件,
我用python,不是arm架構(gòu)的,鏡像都是linux的。
我們直接問kimi即可。
ps:這個(gè)問題丟給了ds和chatgpt都是瞎回答
一步步的問kimi,最后告訴我要添加哪些。整理以后添加到代碼里。
var ALLOW_SYSCALLS = []int{
// file io
syscall.SYS_NEWFSTATAT, syscall.SYS_IOCTL, syscall.SYS_LSEEK, syscall.SYS_GETDENTS64,
syscall.SYS_WRITE, syscall.SYS_CLOSE, syscall.SYS_OPENAT, syscall.SYS_READ,
// thread
syscall.SYS_FUTEX,
// memory
syscall.SYS_MMAP, syscall.SYS_BRK, syscall.SYS_MPROTECT, syscall.SYS_MUNMAP, syscall.SYS_RT_SIGRETURN,
syscall.SYS_MREMAP,
// user/group
syscall.SYS_SETUID, syscall.SYS_SETGID, syscall.SYS_GETUID,
// process
syscall.SYS_GETPID, syscall.SYS_GETPPID, syscall.SYS_GETTID,
syscall.SYS_EXIT, syscall.SYS_EXIT_GROUP,
syscall.SYS_TGKILL, syscall.SYS_RT_SIGACTION, syscall.SYS_IOCTL,
syscall.SYS_SCHED_YIELD,
syscall.SYS_SET_ROBUST_LIST, syscall.SYS_GET_ROBUST_LIST, SYS_RSEQ,
// time
syscall.SYS_CLOCK_GETTIME, syscall.SYS_GETTIMEOFDAY, syscall.SYS_NANOSLEEP,
syscall.SYS_EPOLL_CREATE1,
syscall.SYS_EPOLL_CTL, syscall.SYS_CLOCK_NANOSLEEP, syscall.SYS_PSELECT6,
syscall.SYS_TIME,
syscall.SYS_RT_SIGPROCMASK, syscall.SYS_SIGALTSTACK, SYS_GETRANDOM,
//新增
5, 6, 7, 21, 41, 42, 44, 45, 51, 54, 55, 107, 137, 204, 281,
}
既然我們要操作在沙箱里操作mysql,那我們得在對(duì)應(yīng)的環(huán)境中預(yù)裝下mysql客戶端。
在1
對(duì)應(yīng)的文件中添加2
對(duì)應(yīng)的pymysql==1.1.1
,我直接安裝最新版。
在readme中有操作步驟
### Steps
1. Clone the repository using git clone https://github.com/langgenius/dify-sandbox
and navigate to the project directory.
2. Run ./install.sh to install the necessary dependencies.
3. Run ./build/build_[amd64|arm64].sh to build the sandbox binary.
4. Run ./main to start the server.
編譯成功以后,打包鏡像。因?yàn)槲覜]有環(huán)境,直接模擬了下創(chuàng)建了一個(gè)main和env
目錄
然后模擬打包鏡像。在根目錄中執(zhí)行下面的命令
docker build -f docker/amd64/dockerfile -t dify-sandbox:local .
我在win上打包報(bào)了一堆錯(cuò),都扔給kimi,一步步的解決。最后成功。
在我們的安裝dify的的時(shí)候,有個(gè)dify/docker/ssrf_proxy
目錄,找到squid.conf.template
在這里,你可以設(shè)置允許訪問的網(wǎng)絡(luò),允許訪問的端口,生產(chǎn)一定要最小權(quán)限
acl devnet src 10.1.0.0/24
acl devnet src 10.255.200.0/24
acl Safe_ports port 3306 # MySQL
acl Safe_ports port 5432 # Postgres
acl Safe_ports port 27017 # MongoDB
acl Safe_ports port 6379 # Redis
http_access allow devnet
devnet
為定義的規(guī)則集名稱,后面跟自己的ip段設(shè)置,表示:10.255.200.1
到 10.255.200.254
–acl Safe_ports port
允許訪問的端口http_access allow devnet
允許訪問的規(guī)則集在dify的的docker目錄中修改docker-compose.yaml
文件sandbox使用本地鏡像。
sandbox:
#image: langgenius/dify-sandbox:0.2.10
image: dify-sandbox:local
restart: always
environment:
將image
由langgenius/dify-sandbox:0.2.10
改為了dify-sandbox:local
在docker目錄下執(zhí)行以下命令
# 銷毀
docker compose down
# 重新部署
docker compose up -d
使用kimi生成了一個(gè)python代碼
import sys
import pymysql
import os
def connect_to_database():
""" 連接到數(shù)據(jù)庫(kù),配置都從環(huán)境變量里取 """
try:
# 從環(huán)境變量或配置文件中獲取數(shù)據(jù)庫(kù)參數(shù)
host = os.getenv("DB_HOST", "localhost")
user = os.getenv("DB_USER", "root")
password = os.getenv("DB_PASSWORD", "password")
database = os.getenv("DB_NAME", "database_name")
conn = pymysql.connect(
host=host,
user=user,
password=password,
database=database,
charset='utf8mb4',
cursorclass=pymysql.cursors.DictCursor # 使用字典游標(biāo)
)
return conn
except pymysql.MySQLError as err:
print(f"Error connecting to database: {err}")
returnNone
def execute_query(conn, query, params=None):
""" 執(zhí)行 SQL 查詢,并支持參數(shù)化查詢 """
cursor = conn.cursor()
try:
if params:
cursor.execute(query, params)
else:
cursor.execute(query)
return cursor.fetchall()
except pymysql.MySQLError as err:
print(f"Error executing query: {err}")
returnNone
finally:
cursor.close()
def generate_markdown_table(results):
""" 生成 Markdown 表格 """
ifnot results:
return""
# 獲取列名
columns = results[0].keys()
# 表頭
table_md = "| " + " | ".join([col for col in columns]) + " |\n"
# 分隔線
table_md += "| " + " --- |" * len(columns) + "\n"
# 表格內(nèi)容
for row in results:
table_md += "| " + " | ".join([str(cell) for cell in row.values()]) + " |\n"
return table_md
def main(arg1: str) -> dict:
# 參數(shù)化查詢,避免 SQL 注入
query = "SELECT * FROM table_name WHERE column LIKE %s"
params = ('%' + arg1 + '%',)
# 連接到數(shù)據(jù)庫(kù)
conn = connect_to_database()
ifnot conn:
sys.exit(1)
try:
# 執(zhí)行查詢
result = execute_query(conn, query, params)
if result isNone:
return {"result": [], "markdown": ""}
# 生成 Markdown 表格
markdown_table = generate_markdown_table(result)
return {
"result": result,
"markdown": markdown_table
}
except Exception as e:
print(f"Unexpected error: {e}")
return {"result": [], "markdown": ""}
finally:
# 確保數(shù)據(jù)庫(kù)連接關(guān)閉
conn.close()
這兩種方式,不管哪種都能實(shí)現(xiàn)查詢數(shù)據(jù)庫(kù),但是有個(gè)問題,數(shù)據(jù)量小的時(shí)候性能還行,數(shù)據(jù)量大了,你查詢一次就得耗時(shí)好久。
如果知識(shí)固定,也可以前置設(shè)置一個(gè)知識(shí)庫(kù)把關(guān)鍵詞和文章映射出來,這樣大模型整理的時(shí)候,盡量的去往對(duì)應(yīng)的關(guān)鍵詞上靠。
本文轉(zhuǎn)載自公眾號(hào)@5ycode
對(duì)比大模型API的內(nèi)容創(chuàng)意新穎性、情感共鳴力、商業(yè)轉(zhuǎn)化潛力
一鍵對(duì)比試用API 限時(shí)免費(fèi)