
MCP協議詳解:復刻Manus全靠它,為什么說MCP是Agent進化的一大步?
要求:
python -m pip install pymysql flask
讓kimi給我生成一個文章表,并且插入10條數據,我們可以告訴kimi,文章長度多大,這樣內容可以豐富些。
直接讓kimi生成一個暴露接口查數據庫的服務,有簡單的優化了下,將下面的內容放入到server.py
文件中
from flask import Flask, request, jsonify
import pymysql
app = Flask(__name__)
# 數據庫配置
DATABASE_CONFIG = {
'host': '', # 自己的數據庫地址
'user': '', # 自己數據庫的賬戶
'password': '', #自己數據庫的密碼
'db': 'demo', # 自己數據庫的庫名
'charset': 'utf8mb4',
'cursorclass': pymysql.cursors.DictCursor
}
@app.route('/query', methods=['POST'])
def query_database():
print("接收到請求")
# 獲取關鍵字
keyword = request.json.get('keyword')
print("keyword為:"+keyword)
ifnot keyword:
return jsonify({"error": "Keyword is required"}), 400
# 參數化查詢,避免 SQL 注入,修改成自己的庫
query = "SELECT * FROM articles WHERE content LIKE %s"
params = ('%' + keyword + '%',)
try:
# 建立數據庫連接
connection = pymysql.connect(**DATABASE_CONFIG)
with connection.cursor() as cursor:
# 執行查詢
cursor.execute(query, params)
result = cursor.fetchall()
connection.commit()
connection.close()
ifnot result:
return"未查詢到有效數據", 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"
# 表格內容
for row in results:
table_md += "| " + " | ".join([str(cell) for cell in row.values()]) + " |\n"
return table_md
if __name__ == '__main__':
# 注意這里綁定本機的內容ip,省事點,就0.0.0.0即可。不要綁定127.0.0.1,docke內訪問不到
app.run(host='10.1.0.65', port=8000)
啟動服務
python .\server.py
創建一個空白應用。
在開始節點添加一個輸入字段context
添加一個LLM,把開始節點設置的context
字段作為上下文傳入,并設置提示詞提取關鍵詞。
添加一個http請求節點,把我們在接口開發里的地址和接口名填寫進去2
,然后把大模型的輸出作為關鍵詞填寫到請求body里3
,我們關閉重試機制4
。
這里要注意下:json的引號是中文的,最好在外面寫好校驗過了再放進去。
在HTTP請求的輸出變量里,我們只關注status_code 響應狀態碼和響應內容即可。
添加一個條件分支1
,然后設置HTTP響應碼為200的時候,連接到大模型。其他直接結束。
添加大模型,將HTTP請求的響應體作為上下文給大模型,輸入提示詞,讓大模型根據知識,驗證,并進行合理性的驗證,最后結構化返回。
在結束節點中,我們把大模型整理的內容輸出。
試運行效果。
由于difysandbox的安全限制
官方也有了對應的說明,見文檔。 https://github.com/langgenius/dify-sandbox/blob/main/FAQ.mdss
一定要使用linux環境
、一定要使用linux環境
一定要使用linux環境
我從github上拉下代碼以后,搜索“syscalls_amd64.go
一共有4個文件,
我用python,不是arm架構的,鏡像都是linux的。
我們直接問kimi即可。
ps:這個問題丟給了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,那我們得在對應的環境中預裝下mysql客戶端。
在1
對應的文件中添加2
對應的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.
編譯成功以后,打包鏡像。因為我沒有環境,直接模擬了下創建了一個main和env
目錄
然后模擬打包鏡像。在根目錄中執行下面的命令
docker build -f docker/amd64/dockerfile -t dify-sandbox:local .
我在win上打包報了一堆錯,都扔給kimi,一步步的解決。最后成功。
在我們的安裝dify的的時候,有個dify/docker/ssrf_proxy
目錄,找到squid.conf.template
在這里,你可以設置允許訪問的網絡,允許訪問的端口,生產一定要最小權限
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
為定義的規則集名稱,后面跟自己的ip段設置,表示:10.255.200.1
到 10.255.200.254
–acl Safe_ports port
允許訪問的端口http_access allow devnet
允許訪問的規則集在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目錄下執行以下命令
# 銷毀
docker compose down
# 重新部署
docker compose up -d
使用kimi生成了一個python代碼
import sys
import pymysql
import os
def connect_to_database():
""" 連接到數據庫,配置都從環境變量里取 """
try:
# 從環境變量或配置文件中獲取數據庫參數
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 # 使用字典游標
)
return conn
except pymysql.MySQLError as err:
print(f"Error connecting to database: {err}")
returnNone
def execute_query(conn, query, params=None):
""" 執行 SQL 查詢,并支持參數化查詢 """
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"
# 表格內容
for row in results:
table_md += "| " + " | ".join([str(cell) for cell in row.values()]) + " |\n"
return table_md
def main(arg1: str) -> dict:
# 參數化查詢,避免 SQL 注入
query = "SELECT * FROM table_name WHERE column LIKE %s"
params = ('%' + arg1 + '%',)
# 連接到數據庫
conn = connect_to_database()
ifnot conn:
sys.exit(1)
try:
# 執行查詢
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:
# 確保數據庫連接關閉
conn.close()
這兩種方式,不管哪種都能實現查詢數據庫,但是有個問題,數據量小的時候性能還行,數據量大了,你查詢一次就得耗時好久。
如果知識固定,也可以前置設置一個知識庫把關鍵詞和文章映射出來,這樣大模型整理的時候,盡量的去往對應的關鍵詞上靠。
本文轉載自公眾號@5ycode