本文已收錄在Github,關(guān)注我,緊跟本系列專欄文章,咱們下篇再續(xù)!
- ?? 魔都架構(gòu)師 | 全網(wǎng)30W技術(shù)追隨者
- ?? 大廠分布式系統(tǒng)/數(shù)據(jù)中臺實(shí)戰(zhàn)專家
- ?? 主導(dǎo)交易系統(tǒng)百萬級流量調(diào)優(yōu) & 車聯(lián)網(wǎng)平臺架構(gòu)
- ?? AIGC應(yīng)用開發(fā)先行者 | 區(qū)塊鏈落地實(shí)踐者
- ?? 以技術(shù)驅(qū)動創(chuàng)新,我們的征途是改變世界!
- ?? 實(shí)戰(zhàn)干貨:編程嚴(yán)選網(wǎng)
0 前言
LangChain4j 支持模型上下文協(xié)議(MCP),用于與符合 MCP 標(biāo)準(zhǔn)的服務(wù)器通信,從而調(diào)用并執(zhí)行工具。
該協(xié)議支持兩種通信方式,LangChain4j 均已支持:
- HTTP 模式:客戶端通過 SSE 通道接收服務(wù)端事件,并通過 HTTP POST 請求發(fā)指令
- stdio 模式:客戶端可將 MCP 服務(wù)器作為本地子進(jìn)程運(yùn)行,并通過標(biāo)準(zhǔn)輸入/輸出與其通信
想讓聊天模型或 AI 服務(wù)使用 MCP 服務(wù)器提供的工具,先得創(chuàng)建一個 MCP 工具提供者實(shí)例。
1 創(chuàng)建 MCP 工具提供者(MCP tool provider)
1.1 MCP通信方式
先要構(gòu)建一個 MCP 通信方式的實(shí)例。
① stdio
以本地啟動 NPM 包為例:
McpTransport transport = new StdioMcpTransport.Builder()
.command(List.of("/usr/bin/npm", "exec", "@modelcontextprotocol/server-everything@0.6.2"))
.logEvents(true) // 開啟日志記錄(可選)
.build();
② HTTP
需要兩個 URL:
- 一個用于啟動 SSE channel
- 另一個用于通過 POST 提交命令:
McpTransport transport = new HttpMcpTransport.Builder()
.sseUrl("http://localhost:3001/sse") // SSE 事件channel地址
.logRequests(true) // 開啟請求日志
.logResponses(true) // 開啟響應(yīng)日志
.build();
1.2 創(chuàng)建 MCP 客戶端
代表可以通過給定的傳輸協(xié)議,使用服務(wù)器檢索和執(zhí)行工具的客戶端,該客戶端可以與MCP服務(wù)器通信。
使用 transport 實(shí)例創(chuàng)建 MCP 客戶端:
McpClient mcpClient = new DefaultMcpClient.Builder()
.transport(transport)
.build();
1.3 創(chuàng)建 MCP 工具提供者
工具提供者。每次調(diào)用AI服務(wù)并為該特定調(diào)用提供工具時,都會調(diào)用它。 toolproviderresult中返回的工具將包含在對LLM的請求中。
使用 MCP 客戶端創(chuàng)建工具提供者:
ToolProvider toolProvider = McpToolProvider.builder()
.mcpClients(List.of(mcpClient))
.build();
一個 MCP 工具提供者可同時用多個 MCP 客戶端。如需自定義在連接某個服務(wù)器失敗時行為,可 builder.failIfOneServerFails(boolean)
設(shè)置:
- 默認(rèn)
false
:忽略單個服務(wù)器失敗,繼續(xù)使用其他服務(wù)器 - 若置
true
:任一服務(wù)器失敗都會導(dǎo)致整個工具提供者拋異常
將工具提供者綁定到 AI 服務(wù)中,只需在構(gòu)建 AI 服務(wù)時傳入:
Bot bot = AiServices.builder(Bot.class)
.chatModel(model)
.toolProvider(toolProvider)
.build();
2 日志功能
MCP 協(xié)議支持服務(wù)端向客戶端發(fā)送日志消息。默認(rèn),客戶端會將這些日志轉(zhuǎn)為 SLF4J 格式輸出。如想自定義日志處理邏輯,可實(shí)現(xiàn) dev.langchain4j.mcp.client.logging.McpLogMessageHandler
接口,并傳入客戶端構(gòu)造器:
McpClient mcpClient = new DefaultMcpClient.Builder()
.transport(transport)
.logMessageHandler(new MyLogMessageHandler()) // 自定義日志處理器
.build();
3 資源操作
獲取服務(wù)器上的 MCP 資源,使用:
- client.listResources():返回
McpResource
列表,包含資源元數(shù)據(jù)及 URI - client.listResourceTemplates():獲取資源模板
獲取資源具體內(nèi)容時,用client.readResource(uri),傳入資源 URI,返回 McpReadResourceResult
,其中包含一個或多個 McpResourceContents
:
-
McpBlobResourceContents
:二進(jìn)制資源 -
McpTextResourceContents
:文本資源
4 提示詞操作(Prompts)
獲取服務(wù)器上定義的MCP 提示詞,用:
-
client.listPrompts()
:返回提示詞McpPrompt
列表,包含名稱和參數(shù)信息 -
client.getPrompt(name, arguments)
:渲染具體提示詞內(nèi)容,返回一組McpPromptMessage
,包含角色(如user
、assistant
)和消息內(nèi)容
當(dāng)前支持的消息內(nèi)容類型包括:
-
McpTextContent
:文本 -
McpImageContent
:圖像 -
McpEmbeddedResource
:嵌入資源
提示詞消息可用 McpPromptMessage.toChatMessage()
轉(zhuǎn)為通用的 LangChain4j 消息類型 ChatMessage
,但需滿足:
-
role
為assistant
時,內(nèi)容須是文本,否則會拋異常 - 包含二進(jìn)制內(nèi)容的消息無法轉(zhuǎn)換
5 使用 Docker 運(yùn)行 GitHub MCP 服務(wù)器
看一個通過 MCP 協(xié)議連接 GitHub 的示例。目標(biāo)是用 LangChain4j 和 MCP 客戶端獲取并總結(jié) GitHub 上公開倉庫的最新提交信息。
通過 MCP 提供的 GitHub 服務(wù)器實(shí)現(xiàn)(見 MCP GitHub 倉庫),通過 Docker 本地運(yùn)行。
構(gòu)建 Docker 鏡像
先克隆或下載 MCP GitHub 服務(wù)器源碼,進(jìn)入根目錄,執(zhí)行以下命令構(gòu)建鏡像:
docker build -t mcp/github -f Dockerfile .
構(gòu)建完成后,本地會生成 mcp/github
鏡像:
docker image ls
REPOSITORY TAG IMAGE ID SIZE
mcp/github latest b141704170b1 173MB
6 開發(fā)工具提供者代碼示例
創(chuàng)建 Java 類 McpGithubToolsExample
,使用 LangChain4j 連接 GitHub MCP 服務(wù)器,執(zhí)行以下操作:
- 啟動 Docker 容器運(yùn)行 GitHub MCP 服務(wù)器
- 使用 stdio 通信方式連接 MCP 服務(wù)器
- 使用語言模型總結(jié) LangChain4j 倉庫最近 3 次提交信息
?? 提示:下面代碼中通過環(huán)境變量
GITHUB_PERSONAL_ACCESS_TOKEN
傳入 GitHub Token,訪問公共倉庫時可選。
獲取GITHUB_PERSONAL_ACCESS_TOKEN
直達(dá):https://github.com/settings/personal-access-tokens/new:
自己保存好:
構(gòu)建好的鏡像:
docker run --rm -d \
--name mcp-github-server \
-e GITHUB_PERSONAL_ACCESS_TOKEN=token \
mcp/github
啟動成功:
public static void main(String[] args) throws Exception {
ChatLanguageModel model = OllamaChatModel.builder()
.baseUrl("http://localhost:11434") // Ollama 默認(rèn)本地服務(wù)地址
.modelName("llama3-groq-tool-use:8b") // 你本地 Ollama 拉取的模型名稱
.logRequests(true)
.logResponses(true)
.build();
McpTransport transport = new StdioMcpTransport.Builder()
.command(List.of("/usr/local/bin/docker", "run", "-e", "GITHUB_PERSONAL_ACCESS_TOKEN", "-i", "mcp/github"))
.logEvents(true)
.build();
McpClient mcpClient = new DefaultMcpClient.Builder()
.transport(transport)
.build();
ToolProvider toolProvider = McpToolProvider.builder()
.mcpClients(List.of(mcpClient))
.build();
Bot bot = AiServices.builder(Bot.class)
.chatModel(model)
.toolProvider(toolProvider)
.build();
try {
String response = bot.chat("Summarize the last 3 commits of the LangChain4j GitHub repository");
System.out.println("RESPONSE: " + response);
} finally {
mcpClient.close();
}
}
7 執(zhí)行示例代碼
運(yùn)行 Java 應(yīng)用后,收到類似輸出,總結(jié) LangChain4j 倉庫最近 3 次提交內(nèi)容:
以下是 LangChain4j GitHub 倉庫最近三次提交的摘要:
1. **提交 [36951f9](https://github.com/langchain4j/langchain4j/commit/36951f9649c1beacd8b9fc2d910a2e23223e0d93)**(時間:2025-02-05)
- **作者:** Dmytro Liubarskyi
- **信息:** 更新至 `upload-pages-artifact@v3`
- **詳情:** 此提交將上傳頁面資源的 GitHub Action 升級至版本 3。
2. **提交 [6fcd19f](https://github.com/langchain4j/langchain4j/commit/6fcd19f50c8393729a0878d6125b0bb1967ac055)**(時間:2025-02-05)
- **作者:** Dmytro Liubarskyi
- **信息:** 更新至 `checkout@v4`、`deploy-pages@v4` 和 `upload-pages-artifact@v4`
- **詳情:** 此提交升級了多個 GitHub Action 到版本 4。
3. **提交 [2e74049](https://github.com/langchain4j/langchain4j/commit/2e740495d2aa0f16ef1c05cfcc76f91aef6f6599)**(時間:2025-02-05)
- **作者:** Dmytro Liubarskyi
- **信息:** 更新至 `setup-node@v4` 和 `configure-pages@v4`
- **詳情:** 此提交將相關(guān) GitHub Action 升級至版本 4。
這三次提交都由 Dmytro Liubarskyi 完成,時間相同,主要內(nèi)容為將 GitHub Actions 升級至新版。
本文由博客一文多發(fā)平臺 OpenWrite 發(fā)布!