使用说明
📱 三星Galaxy S系列——人工智能购物助手
比较亚马逊、Flipkart、三星和Croma的三星Galaxy手机,然后通过AP2协议安全购买
由...驱动 春季AI + MCP(模型上下文协议) + AP2(代理支付协议) + 奥拉马LLM
📖 目录
- 这是什么?
- 关键技术概念(为初学者讲解)
- 架构概述
- 完成请求流(逐步)
- MCP协议详细信息
- AP2安全支付流
- 聊天记忆系统
- 产品数据
- 项目结构
- 每个文件的作用
- 入门指南
- API终点
- 配置参考
- 故障排除
- 技术栈
🎯 这是什么?
一款基于人工智能的购物助手,让您 搜索、比较和购买 三星Galaxy手机通过自然对话。问以下问题 “比较所有平台的S24 Ultra价格” --LLM自动搜索4个电子商务平台,比较价格,推荐购买地点,并通过谷歌的 AP2(代理支付协议) 通过加密授权验证。
主要特点
- 🔍 4平台搜索 --亚马逊印度、Flipkart、Samsung.com印度、Croma
- 📊 并排比较 --价格、MRP、折扣%、银行优惠、EMI、赠品、交货、保修
- 🔒 AP2安全支付 --三步加密授权链(意图→ Cart → 付款)
- 💬 会话记忆 --具有上下文保留功能的多回合对话(最后20条消息)
- 🎨 高级暗聊天用户界面 --打字指示器、建议芯片、响应式设计
- 🤖 完全本地化 --无需云API,完全在使用Ollama的机器上运行
你能说什么
• "Compare S24 Ultra prices" → Searches all 4 platforms
• "Search on Amazon for S24" → Searches Amazon only
• "What's on Flipkart?" → Searches Flipkart
• "Details for FK-S24U-256" → Gets full product specs
• "Buy the Flipkart S24 Ultra" → Starts AP2 payment flow
📚 关键技术概念(为初学者讲解)
什么是LLM?
LLM(大型语言模型) 是一个基于大量文本数据训练的人工智能模型。它可以理解自然语言(比如“在S24 Ultra上为我找到最好的交易”),并产生类似人类的反应。在这个项目中,我们使用 奥拉玛 运行 llama3.2:3b 模型 本地在您的计算机上 -不需要互联网或API密钥。
示例:当您键入“Compare S24 Ultra prices”时,LLM知道您想要进行价格比较,并决定调用 comparePrices 工具。
Ollama是什么?
奥拉玛 是一个允许您在自己的计算机上运行LLM(如Llama、Mistral等)的应用程序。将其视为本地ChatGPT。它在上公开了一个API http://localhost:11434 我们的Java应用程序与之对话。
# Install Ollama from https://ollama.com
# Then download the model:
ollama pull llama3.2:3b # Downloads a 2GB model
ollama serve # Starts the API server
什么是Spring AI?
春季AI 是一个框架(Spring生态系统的一部分),可以轻松地将AI/LLM功能集成到Java应用程序中。它提供:
ChatClient--向LLM(Ollama、OpenAI等)发送提示的Java客户端- 工具调用 --让LLM在需要数据时调用Java方法
- 聊天记忆 --记住对话中以前的消息
- MCP集成 --连接到MCP服务器以查找工具
// Example: Send a message to the LLM with tools
String response = chatClient.prompt()
.user("Compare S24 Ultra prices") // User's question
.call() // Send to Ollama
.content(); // Get the response text
什么是MCP(模型上下文协议)?
MCP(模型上下文协议) 是LLM的标准化协议↔ 工具通信。把它想象成 “用于AI工具的USB” --通用即插即用标准。
我们为什么需要它? LLM可以理解语言,但他们不能自己访问数据库、调用API或搜索网络。MCP允许他们“调用工具”——获取真实数据的Java方法。
它是如何工作的:
- MCP服务器 公开工具(Java方法注释为
@Tool) - MCP客户端 连接到服务器,发现可用工具
- 当 LLM 需要数据,它告诉客户端“使用这些参数调用此工具”
- 这 客户端 将请求发送到服务器,获取结果,并将其传递回LLM
运输: 在这个项目中,MCP使用 SSE(服务器发送事件) 传输--客户端连接到 http://localhost:8081/sse 以建立用于实时通信的持久连接。
MCP Client ──SSE──→ MCP Server
(port 8080) (port 8081)
什么是AP2(代理支付协议)?
AP2(代理支付协议) 是谷歌用于安全人工智能代理主导支付的开放协议。传统的支付流程假设人类点击“购买”。但当人工智能代理代表您进行购买时,我们需要额外的安全保障:
- 授权 --证明用户允许代理人花钱
- 真实性 --确保订单符合用户的实际需求
- 问责 --如果出现问题,创建审计跟踪
AP2通过一个 三步加密授权链 (详细解释 在......下面).
什么是工具(在AI环境中)?
A. 工具 是LLM可以调用以获取真实世界数据的函数。LLM不直接执行该工具,它生成一个 工具调用请求 (“请致电 searchAmazon 有争论 S24 Ultra),框架(Spring AI)实际执行Java方法并将结果反馈给LLM。
@Tool(description = "Search for Samsung phones on Amazon India")
public String searchAmazon(@ToolParam(description = "Phone name") String productName) {
// This method runs on the MCP Server when the LLM calls it
List<Product> products = mockDataProvider.searchAmazon(productName);
return formatResults(products);
}
什么是SSE(服务器发送事件)?
上海证券交易所 是一种web技术,允许服务器通过单个HTTP连接将数据推送到客户端。与常规HTTP(请求→ SSE保持连接打开以进行连续通信。MCP使用SSE,因此客户端可以有效地接收工具响应。
什么是JSON-RPC?
JSON-RPC 是一种用于调用远程函数的轻量级协议。MCP对所有工具调用使用JSON-RPC 2.0格式:
{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "searchAmazon",
"arguments": { "productName": "S24 Ultra" }
}
}
🏗️ 架构概述
应用程序以如下方式运行 3个单独的过程 它们相互通信:
┌────────────────────────────────────────────────────────────────────┐
│ BROWSER (index.html) │
│ Dark-themed chat UI with suggestion cards │
│ Sends user messages via POST /api/shop │
└─────────────────┬──────────────────────────────────────────────────┘
│ POST /api/shop {message, conversationId}
│ (Standard REST/JSON)
▼
┌────────────────────────────────────────────────────────────────────┐
│ MCP CLIENT (port 8080) — The Orchestrator │
│ │
│ ShoppingController ─→ ShoppingAssistant ─→ Ollama LLM │
│ (REST API) (ChatClient + (llama3.2:3b │
│ Memory + Tools) localhost:11434) │
│ │
│ What it does: │
│ 1. Receives user messages via REST API │
│ 2. Injects system prompt (Samsung expert persona) │
│ 3. Loads conversation history (last 20 messages) │
│ 4. Sends prompt + tool definitions to LLM │
│ 5. When LLM requests a tool call → routes it via MCP to server │
│ 6. Feeds tool result back to LLM │
│ 7. Returns LLM's final response to browser │
└─────────────────┬──────────────────────────────────────────────────┘
│ MCP (SSE Transport)
│ JSON-RPC 2.0 over SSE at /sse
▼
┌────────────────────────────────────────────────────────────────────┐
│ MCP SERVER (port 8081) — The Tool Provider │
│ │
│ ┌─────────────┬──────────────┬──────────────┬──────────────┐ │
│ │ AmazonTool │ FlipkartTool │ SamsungStore │ CromaTool │ │
│ │ │ │ Tool │ │ │
│ ├─────────────┼──────────────┼──────────────┴──────────────┤ │
│ │ PriceCompar │ OrderTool │ AP2PaymentTool │ │
│ │ ator │ (details, │ (intent, cart, payment) │ │
│ │ │ status) │ │ │
│ ├─────────────┴──────────────┴─────────────────────────────┤ │
│ │ McpToolConfig (registers all 10 tools explicitly) │ │
│ ├──────────────────────────────────────────────────────────┤ │
│ │ MockDataProvider (28 products) │ PaymentService (AP2 PSP)│ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ What it does: │
│ • Exposes @Tool methods over MCP (SSE transport) │
│ • Searches mock product data across 4 platforms │
│ • Compares prices with grouping and sorting │
│ • Manages AP2 mandate chain for secure payments │
│ • Returns formatted text results to the LLM │
└────────────────────────────────────────────────────────────────────┘
流程总结
| 进程 | 端口 | 角色 |
|---|---|---|
| 奥拉玛 | 11434 | 跑步 llama3.2:3b LLM本地。决定调用哪些工具。生成自然语言响应。 |
| MCP服务器 | 8081 | 通过MCP公开产品搜索+AP2支付工具。这里没有LLM,只有Java方法。 |
| MCP客户端 | 8080 | 编排器:桥接用户↔ LLM↔ MCP工具。将聊天UI提供给浏览器。 |
他们如何相互交谈
Browser ──HTTP/JSON──→ MCP Client ──HTTP──→ Ollama (LLM)
│
└──SSE/JSON-RPC──→ MCP Server (Tools)
- 浏览器→ MCP客户端:标准REST(POST
/api/shopJSON正文) - MCP客户端→ 奥拉玛:HTTP到
/api/chat(Spring AI会自动处理此问题) - MCP客户端→ MCP服务器:基于SSE传输的MCP协议(Spring AI也处理此问题)
🔄 完成请求流(逐步)
流程1:产品搜索和比较
当用户键入 “比较S24 Ultra价格”,具体情况如下:
第一步——浏览器→ 控制器
POST http://localhost:8080/api/shop
{"message": "Compare S24 Ultra prices", "conversationId": "session-abc123"}
ShoppingController 接收此信息,提取 message 和 conversationId,呼叫 shoppingAssistant.chat().
步骤2——ShoppingAssistant构建LLM提示
组装了三件事:
- 系统提示 --“你是三星Galaxy S系列购物助理…”(定义角色和指导方针)
- 对话历史 --来自的最后20条消息
MessageWindowChatMemory(所以LLM会记住之前的回合) - 用户消息 --“比较S24 Ultra价格”
另外: 10工具定义 (名称、描述、参数模式)被发送给Ollama,以便LLM知道它可以调用哪些工具。
步骤3--向Ollama LLM发送提示
完整提示转到 http://localhost:11434/api/chat (Ollama的API)。LLM读取用户的意图并决定调用工具。它返回:
{
"tool_calls": [{
"function": {
"name": "spring_ai_mcp_client_s_comparePrices",
"arguments": {"productName": "S24 Ultra"}
}
}]
}
重要提示: LLM不执行任何操作,它只决定调用哪个工具以及使用什么参数。Spring AI处理实际执行。
关于工具名称的说明: Spring AI添加前缀
spring_ai_mcp_client_s_所有MCP工具名称。这s来源于中的MCP连接名称application.yml此前缀对用户不可见,但对刀具布线很重要。
步骤4-Spring AI将工具调用路由到MCP服务器
Spring AI拦截 tool_calls,抬头看 comparePrices 并通过SSE向MCP服务器发送JSON-RPC请求:
{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "comparePrices",
"arguments": {"productName": "S24 Ultra"}
}
}
步骤5-MCP服务器执行该工具
PriceComparator.comparePrices("S24 Ultra") 在服务器上运行:
- 呼叫
mockDataProvider.searchAllPlatforms("S24 Ultra") - 从每个平台获取2个产品(256GB+512GB)=总共8个
- 按型号+存储进行分组,以便进行公平比较
- 按价格对每组进行排序(最便宜的先)
- 格式化一个丰富的比较,显示每个平台的价格、MRP、折扣%、报价、交付、保修
- 返回格式化字符串(≈5000个字符的比较数据)
步骤6——工具结果返回LLM
Spring AI将工具输出作为 tool_response 消息。LLM现在拥有真实的产品数据,并生成自然语言摘要:
Based on the comparison, here's the best deal for Samsung Galaxy S24 Ultra:
**Best Price:** ₹127,999 (MRP: ₹149,999, 15% off) on Flipkart
with ₹8,000 off on Axis Bank Card + ₹1,000 off with SuperCoins
Other Options:
• Amazon India: ₹129,999 (13% off)
• Croma: ₹129,999 (13% off)
• Samsung.com India: ₹131,999 (12% off)
Would you like to buy from Flipkart?
步骤7——响应返回给用户
LLM响应→ ChatClient 保存到内存→ ShoppingAssistant 返回字符串→ ShoppingController 用JSON封装→ 浏览器在聊天UI中呈现它。
流程2:AP2安全支付
当用户决定购买时 AP2(代理支付协议) 开始。请参阅专用部分 在......下面.
🔗 MCP协议详细信息
MCP做什么
MCP(模型上下文协议) 是LLM的标准化协议↔ 工具通信。没有MCP,您需要为每个工具编写自定义集成代码。使用MCP,可以通过标准协议发现和调用工具。
传输:SSE(服务器发送事件)
此项目使用 SSE运输。客户端连接到 http://localhost:8081/sse 以建立持久连接。所有工具调用和响应都通过此连接进行。
# Client configuration (application.yml)
spring.ai.mcp.client:
type: SYNC
sse:
connections:
s: # Short name → keeps tool name prefixes short
url: http://localhost:8081 # MCP Server address
为什么连接名称只是
s? Spring AI在所有工具名称前加上spring_ai_mcp_client_{connection-name}_一个简短的名字,比如s产生较短的工具名称(例如。,spring_ai_mcp_client_s_searchAmazon),这有助于小型LLM可靠地处理工具调用。长名字会让小模特感到困惑。
工具发现(启动时)
- MCP客户端连接到
http://localhost:8081/sse - 发送
initialize然后握手tools/list请求 - 服务器以全部10个响应
@Tool-带注释的方法——参数的名称、描述和JSON模式 - 客户端将它们包装为
SyncMcpToolCallback对象并将其注册到ChatClient
工具执行(聊天期间)
- LLM决定致电
searchFlipkart("S24 Ultra") - Spring AI发送
tools/callJSON-RPC通过SSE连接到MCP服务器 - 服务器执行
FlipkartTool.searchFlipkart("S24 Ultra") - 通过JSON-RPC响应返回格式化的结果字符串
- Spring AI将结果作为工具响应消息传递回LLM
工具注册:McpToolConfig
Spring AI @Tool 注释本身并不能在MCP服务器上自动注册工具。我们需要…… 明确注册 所有使用工具bean MethodToolCallbackProvider:
@Configuration
public class McpToolConfig {
@Bean
public ToolCallbackProvider toolCallbackProvider(
AmazonTool amazonTool, FlipkartTool flipkartTool, /* ... */) {
return MethodToolCallbackProvider.builder()
.toolObjects(amazonTool, flipkartTool, cromaTool, samsungStoreTool,
priceComparator, orderTool, ap2PaymentTool)
.build();
}
}
这个类很关键——没有它,MCP服务器报告0个工具,一切都不起作用。
全部10个注册工具
| # | 工具 | 类 | 参数 | 用途 |
|---|---|---|---|---|
| 1 | searchAmazon |
AmazonTool |
productName |
在亚马逊印度搜索三星手机 |
| 2 | searchFlipkart |
FlipkartTool |
productName |
在Flipkart上搜索三星手机 |
| 3 | searchSamsungStore |
SamsungStoreTool |
productName |
搜索Samsung.com印度 |
| 4 | searchCroma |
CromaTool |
productName |
Search Croma(塔塔集团所有) |
| 5 | comparePrices |
PriceComparator |
productName |
同时比较所有4个平台 |
| 6 | getProductDetails |
OrderTool |
productId |
按ID获取特定产品的完整详细信息 |
| 7 | checkOrderStatus |
OrderTool |
orderId |
检查订单或AP2交易的状态 |
| 8 | createIntentMandate |
AP2PaymentTool |
intent, budget, platform |
AP2步骤1:捕捉用户意图 |
| 9 | createCartMandate |
AP2PaymentTool |
intentId, productId, qty |
AP2第二步:锁车 |
| 10 | processPayment |
AP2PaymentTool |
cartId, method, name, addr |
AP2步骤3:处理付款 |
🔒 AP2安全支付流
为什么选择AP2?
传统支付假设人为点击“购买”。随着人工智能代理进行购买,我们需要额外的保障措施:
- 授权 --证明用户允许代理人花钱
- 真实性 --确保订单符合用户的真实意图
- 问责 --如果出现问题,请维护加密审计跟踪
三步授权链
每一步都会创建一个 加密签名记录 与前一步骤相关联,形成一条牢不可破的链:
User says: "Buy the Flipkart S24 Ultra 256GB"
┌─────────────────────────────────────────────────────────────┐
│ STEP 1: createIntentMandate │
│ │
│ What: Captures user's shopping intent + budget │
│ Input: intent="Buy Galaxy S24 Ultra from Flipkart" │
│ maxBudget=150000, platform="Flipkart" │
│ Output: IM-A1B2C3D4 (SHA-256 signed, timestamped) │
│ │
│ Why: Creates verifiable proof that the user │
│ authorized this purchase with these constraints │
└──────────────────────────┬──────────────────────────────────┘
│ links to
┌──────────────────────────▼──────────────────────────────────┐
│ STEP 2: createCartMandate │
│ │
│ What: Locks EXACT product, price, quantity │
│ Input: intentMandateId="IM-A1B2C3D4" │
│ productId="FK-S24U-256", quantity=1 │
│ Validates: │
│ ✅ Intent mandate exists and is valid │
│ ✅ Product exists and is in stock │
│ ✅ Total (₹127,999) doesn't exceed budget (₹150,000) │
│ Output: CM-E5F6G7H8 (SHA-256 signed, linked to IM) │
│ │
│ Why: "What you see is what you pay for" │
│ Price is locked — can't be changed later │
└──────────────────────────┬──────────────────────────────────┘
│ links to
┌──────────────────────────▼──────────────────────────────────┐
│ STEP 3: processPayment │
│ │
│ What: Validates full chain + processes payment │
│ Input: cartMandateId="CM-E5F6G7H8" │
│ paymentMethod="UPI", name, address │
│ Validates: │
│ ✅ Cart mandate exists │
│ ✅ Intent mandate chain is unbroken │
│ ✅ Payment method is valid (UPI/Card/Wallet/NetBanking) │
│ Output: TXN-X1Y2Z3A4B5C6 (COMPLETED, full audit trail) │
│ │
│ Audit Trail: │
│ IM-A1B2C3D4 → CM-E5F6G7H8 → TXN-X1Y2Z3A4B5C6 │
│ (intent) (cart) (payment) │
│ All cryptographically signed ✅ │
└─────────────────────────────────────────────────────────────┘
AP2输入消毒
小型LLM有时会传递额外的格式化字符(换行符、方框图字符,如 ├─)在授权ID中。这 AP2PaymentTool 包括a sanitizeId() 使用正则表达式提取干净ID的方法(例如。, IM-A1B2C3D4 从 IM-A1B2C3D4\n├─ ...).
AP2对话示例
User: "I want to buy the S24 Ultra from Flipkart, 256GB"
Bot: 🔒 Intent Mandate created: IM-A1B2C3D4
Intent: "Buy Galaxy S24 Ultra 256GB from Flipkart"
Budget: ₹150,000 | Signature: 4f8a2b1c... ✅
🛒 Cart locked: CM-E5F6G7H8
Product: Samsung Galaxy S24 Ultra (Titanium Gray, 256GB)
Platform: Flipkart | Price: ₹127,999
Intent Link: IM-A1B2C3D4 ✅
Please confirm and tell me:
• Payment method: UPI / Credit Card / Debit Card
• Your full name
• Delivery address with pincode
User: "Confirm. UPI, Harsh Gupta, Bangalore 560001"
Bot: ✅ PAYMENT SUCCESSFUL (AP2)
Transaction ID: TXN-X1Y2Z3A4B5C6
Product: Samsung Galaxy S24 Ultra (256GB)
Platform: Flipkart | Amount: ₹127,999 | Via: UPI
🔐 AP2 Audit Trail:
Intent: IM-A1B2C3D4 ✅
Cart: CM-E5F6G7H8 ✅
Payment: 7c3d9e... ✅
🧠 聊天记忆系统
运作原理
// Sliding window — keeps the last 20 messages per conversation
MessageWindowChatMemory.builder().maxMessages(20).build();
- 在每次LLM呼叫之前,
MessageChatMemoryAdvisor加载给定消息的最后20条消息conversationId - 这些消息作为对话历史记录注入到提示符中
- 法学硕士可以“记住”前面讨论的内容
- LLM响应后,用户消息和AI响应都会保存到内存中
多回合对话示例
Turn 1: "Compare S24 Ultra prices" → LLM calls comparePrices, gets data
Turn 2: "Buy the Flipkart one" → LLM remembers Flipkart had the best price, starts AP2
Turn 3: "UPI, Harsh, Bangalore 560001" → LLM remembers the cart, processes payment
对话隔离
每个浏览器会话都有一个唯一的 conversationId (自动生成的UUID)。不同的用户不共享内存。您可以通过以下方式清除内存:
POST http://localhost:8080/api/clear
{"conversationId": "session-abc123"}
📊 产品数据
所有产品数据 嘲笑 (对电子商务网站没有真正的API调用)。这使得演示具有自包含性和可重复性。
28个产品(7部手机×4个平台)
| 型号 | 存储 | 关键规格 |
|---|---|---|
| Galaxy S24 Ultra | 256GB、512GB | 骁龙8代3,200MP,S笔,6.8英寸QHD+ |
| Galaxy S24+ | 256GB | Exynos 2400,50MP,6.7英寸FHD+ |
| Galaxy S24 | 128GB、256GB | Exynos 2400、50MP、6.2英寸FHD+ |
| Galaxy S23 FE | 128GB、256GB | Exynos 2200、50MP、6.4英寸FHD+ |
每个产品字段(27)
| 类别 | 字段 |
|---|---|
| 身份 | id, name, platform, category |
| 变体 | color, storage, ram |
| 规格 | processor, display, camera, battery, os |
| 定价 | price, mrp,自动计算 discountPercent() |
| 优惠 | offers, emiOption, exchangeValue, freebie |
| 交付 | deliverySpeed, deliveryDate, deliveryCharge, codAvailable, deliveryPartner |
| 信任 | seller, rating, reviewCount, warranty, returnPolicy, inStock, stockCount |
平台定价和差异
| 平台 | S24 Ultra 256GB | 独特优惠 | 交货 | COD |
|---|---|---|---|---|
| 亚马逊 | ₹129,999(13%折扣) | HDFC/SBI/IICII卡折扣 | 1-3天 | ✅ |
| Flipkart | ₹127,999(15%折扣) | 安讯士银行₹8K off+超级硬币 | 第二天! | ✅ |
| 三星网 | ₹131,999(12%折扣) | 免费Galaxy Buds2 Pro+三星护理+ | 3-5天 | ❌ |
| 八分音符 | ₹129,999(13%折扣) | HDFC+Croma奖励,店内兑换 | 2-3天 | ❌ |
📁 项目结构
spring-ai-mcp-demo/
├── pom.xml # Parent POM (multi-module Maven project)
│
├── mcp-server/ # PORT 8081 — MCP Tool Server
│ ├── pom.xml # Server dependencies + maven-compiler-plugin with -parameters
│ └── src/main/java/.../mcpserver/
│ ├── McpServerApplication.java # Spring Boot entry point
│ ├── McpToolConfig.java # ★ Explicitly registers all 10 tools via MethodToolCallbackProvider
│ ├── model/
│ │ └── Product.java # 27-field product model (Lombok @Builder)
│ ├── mock/
│ │ └── MockDataProvider.java # 28 products, search logic, orders
│ ├── ap2/ # ★ AP2 Protocol Implementation
│ │ ├── IntentMandate.java # Step 1: signed user intent (Java record)
│ │ ├── CartMandate.java # Step 2: signed locked cart (Java record)
│ │ ├── PaymentResult.java # Step 3: transaction receipt + audit trail (Java record)
│ │ └── PaymentService.java # Mock PSP with mandate chain validation
│ └── tools/
│ ├── AmazonTool.java # @Tool: searchAmazon
│ ├── FlipkartTool.java # @Tool: searchFlipkart
│ ├── SamsungStoreTool.java # @Tool: searchSamsungStore
│ ├── CromaTool.java # @Tool: searchCroma
│ ├── PriceComparator.java # @Tool: comparePrices (searches all 4 platforms)
│ ├── OrderTool.java # @Tool: getProductDetails, checkOrderStatus
│ ├── AP2PaymentTool.java # @Tool: createIntentMandate, createCartMandate, processPayment
│ └── ToolOutputHelper.java # Shared formatting utility for product results
│
└── mcp-client/ # PORT 8080 — User-facing App
├── pom.xml # Client dependencies (Spring AI Ollama + MCP Client)
└── src/main/
├── resources/
│ ├── application.yml # Ollama + MCP client config
│ └── static/index.html # Chat UI (dark theme, suggestion chips)
└── java/.../mcpclient/
├── McpClientApplication.java
├── controller/
│ └── ShoppingController.java # REST: /api/shop, /api/clear, /api/health
└── service/
└── ShoppingAssistant.java # ChatClient + Memory + System Prompt + MCP Tools
📋 每个文件的作用
MCP客户端(端口8080)
| 文件 | 它的作用 |
|---|---|
ShoppingController.java |
REST API-接收 /api/shop POST请求,委托 ShoppingAssistant,返回JSON响应。提供 /api/clear (重置对话)和 /api/health (服务器状态)。日志请求计时。 |
ShoppingAssistant.java |
核心服务——构建 ChatClient 具有:(1)系统提示定义助手的角色,(2)MCP工具通过 SyncMcpToolCallbackProvider, (3) MessageWindowChatMemory 对话历史。向Ollama发送提示并返回响应。 |
application.yml |
配置--Ollama URL(localhost:11434),型号(llama3.2:3b),上下文窗口(num-ctx: 8192),MCP客户端SSE连接到 localhost:8081. |
index.html |
聊天UI——深色主题、打字指示器、建议芯片、markdown渲染。向发送获取请求 /api/shop。自动生成对话ID。 |
MCP服务器(端口8081)
| 文件 | 它的作用 |
|---|---|
McpToolConfig.java |
关键配置 --使用以下命令显式注册所有7个toolbean类 MethodToolCallbackProvider如果没有这个,MCP服务器将暴露0个工具。 |
Product.java |
数据模型——27个字段,涵盖身份、变体、规格、定价、报价、交付、信任。使用龙目岛 @Builder.有 toDetailedCard() 丰富的格式。 |
MockDataProvider.java |
内存数据库——28个产品(7部手机×4个平台),按搜索词索引。模糊搜索匹配:精确→ 子字符串→ 产品名称。还管理订单记录。 |
ToolOutputHelper.java |
共享格式化程序——为所有4个平台工具使用的产品列表生成一致的富文本输出。显示规格、MRP/折扣定价、优惠、交货详情。 |
AmazonTool.java |
MCP工具-- searchAmazon(productName) → 搜索亚马逊模拟数据→ 返回格式化的结果。 |
FlipkartTool.java |
MCP工具-- searchFlipkart(productName) → Flipkart的模式相同。 |
SamsungStoreTool.java |
MCP工具-- searchSamsungStore(productName) → Samsung.com印度。 |
CromaTool.java |
MCP工具-- searchCroma(productName) → 克罗玛。 |
PriceComparator.java |
MCP工具-- comparePrices(productName) → 搜索所有4个平台,按型号+存储进行分组,按价格排序,显示价格差异和每组的最佳交易。 |
OrderTool.java |
MCP工具-- getProductDetails(productId) 返回完整的产品卡。 checkOrderStatus(orderId) 查找订单或AP2交易。 |
AP2PaymentTool.java |
MCP工具——3个AP2工具: createIntentMandate, createCartMandate, processPayment。包括 sanitizeId() 以处理授权ID中的LLM格式化工件。 |
IntentMandate.java |
AP2记录——捕获用户意图(查询、预算、平台)。生成模拟SHA-256签名。不可变Java记录。 |
CartMandate.java |
AP2记录——锁定产品/价格/数量,链接到意向授权。SHA-256签名。根据意图验证预算。 |
PaymentResult.java |
AP2记录——具有完整审计跟踪的交易收据(意图→ Cart → 付款签名)。 |
PaymentService.java |
模拟支付服务提供商(PSP)——管理授权商店(ConcurrentHashMap),在每一步验证链的完整性,处理付款。记录AP2流的每一步。 |
🚀 入门指南
先决条件
- Java 17+ --检查:
java -version - 奥拉玛 --从以下位置安装 ollama.com
设置和运行
# 1. Install the LLM model (2GB download, one-time)
ollama pull llama3.2:3b
# 2. Make sure Ollama is running
ollama serve
# 3. Clone the project
git clone <repo-url>
cd spring-ai-mcp-demo
# 4. Start the MCP Server (port 8081) — opens a new terminal
cd mcp-server && ../mvnw spring-boot:run
# 5. Start the MCP Client (port 8080) — in another terminal
cd mcp-client && ../mvnw spring-boot:run
# 6. Open the chat UI in your browser
open http://localhost:8080
验证它是否正常工作
您应该看到这些日志:
MCP服务器:
🔧 [CONFIG] Registering MCP tools...
→ AmazonTool: searchAmazon
→ FlipkartTool: searchFlipkart
...
= 10 tools total
Registered tools: 10
Started McpServerApplication on port 8081
MCP客户端:
🔧 [SERVICE] MCP tool provider resolved 10 tool callbacks:
📌 Tool: spring_ai_mcp_client_s_searchAmazon
📌 Tool: spring_ai_mcp_client_s_comparePrices
...
✅ [SERVICE] ShoppingAssistant ready!
Started McpClientApplication on port 8080
📡 API终点
与助手聊天
curl -X POST http://localhost:8080/api/shop \
-H "Content-Type: application/json" \
-d '{"message": "Compare S24 Ultra prices", "conversationId": "test-1"}'
答复:
{
"response": "Here are the best deals for Samsung Galaxy S24 Ultra:\n\n**Best Price:** ₹127,999 on Flipkart...",
"conversationId": "test-1"
}
健康检查
curl http://localhost:8080/api/health
清除对话记忆
curl -X POST http://localhost:8080/api/clear \
-H "Content-Type: application/json" \
-d '{"conversationId": "test-1"}'
⚙️ 配置参考
客户端配置(mcp-client/src/main/resources/application.yml)
server:
port: 8080 # Client web server port
spring:
application:
name: mcp-shopping-client
ai:
ollama:
base-url: http://localhost:11434 # Ollama API endpoint
chat:
model: llama3.2:3b # LLM model to use
options:
temperature: 0.7 # Creativity level (0=deterministic, 1=creative)
num-ctx: 8192 # Context window size (tokens). Must be large
# enough to fit system prompt + 10 tool definitions
# + conversation history + user message
mcp:
client:
type: SYNC # Synchronous MCP client
sse:
connections:
s: # ★ Connection name — keep SHORT!
url: http://localhost:8081 # MCP Server URL
⚠️ 重要提示: 连接名称(
s)成为发送到LLM的每个工具名称的一部分:spring_ai_mcp_client_{name}_toolName。保持简短(1-3个字符),以便小LLM可以正确处理工具调用。
服务器配置(mcp-server/src/main/resources/application.yml)
server:
port: 8081 # MCP Server port
spring:
application:
name: mcp-shopping-server
ai:
mcp:
server:
name: shopping-tools-server # Server identity in MCP handshake
version: 1.0.0
type: SYNC # Synchronous MCP server
Maven编译器配置(mcp-server/pom.xml)
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<parameters>true</parameters> <!-- ★ Preserves parameter names at runtime -->
</configuration> <!-- Without this, @ToolParam args become arg0, arg1 -->
</plugin>
⚠️ 严重: 这
-parameters旗帜是必不可少的。没有它,Java会编译掉参数名,Spring AI无法正确映射工具参数,导致NullPointerException.
🔧 故障排除
常见问题
| 问题 | 原因 | 修复 |
|---|---|---|
| MCP服务器:“已注册0个工具” | @Tool 未自动发现方法 |
确保 McpToolConfig.java 通过以下方式存在并注册所有工具bean MethodToolCallbackProvider |
| 客户端:404 on/mcp | 错误的MCP传输类型 | 使用 sse 客户端传输 application.yml,不 streamable-http |
| 服务器:工具参数上出现NullPointerException | Java擦除参数名称 | 添加 <parameters>true</parameters> 到 maven-compiler-plugin 在服务器中 pom.xml |
| LLM输出原始JSON而不是调用工具 | 工具名称前缀太长 | 缩短MCP连接名称(例如。, shopping-server → s).还要确保 num-ctx 足够大(8192+) |
| AP2:“未找到购物车授权” | LLM在授权ID中传递了额外的格式化字符 | sanitizeId() 在 AP2PaymentTool 处理这个。如果仍然失败,请清除对话记忆并重试 |
| Ollama:“找不到模型” | 模型未下载 | 运行 ollama pull llama3.2:3b |
| Ollama:连接被拒绝 | Ollama不跑 ollama serve |
调试提示
-
检查服务器日志 --两台服务器都使用表情符号记录每次工具调用,以便于扫描:
🛒 [MCP TOOL] searchAmazon called with: 'S24 Ultra'🔒 [AP2] Intent Mandate created: IM-A1B2C3D4✅ [AP2] Payment COMPLETED! Transaction: TXN-...
-
检查刀具分辨率 --客户端在启动时记录所有10个工具:
🔧 [SERVICE] MCP tool provider resolved 10 tool callbacks: 📌 Tool: spring_ai_mcp_client_s_searchAmazon -
直接测试Olama -如果LLM没有调用工具,请测试Ollama的API:
curl http://localhost:11434/api/chat -d '{ "model": "llama3.2:3b", "messages": [{"role": "user", "content": "Search for S24 Ultra"}], "tools": [{"type":"function","function":{"name":"searchAmazon","description":"Search Amazon","parameters":{"type":"object","properties":{"productName":{"type":"string"}}}}}], "stream": false }'
🛡️ 技术栈
| 组件 | 技术 | 为什么 |
|---|---|---|
| 语言 | Java 17 | Spring生态系统、记录类型、模式匹配 |
| 框架 | Spring Boot 3.4.1 | 自动配置、依赖注入、嵌入式Tomcat |
| 人工智能框架 | Spring AI 1.0.0-SNAPSHOT | 聊天客户端、工具调用、MCP客户端/服务器集成 |
| LLM | Ollama(llama3.2:3b) | 本地、免费、私有-无API密钥或云依赖性 |
| MCP传输 | SSE(服务器发送事件) | 通过HTTP进行实时双向通信 |
| 支付协议 | AP2(代理支付协议) | 通过加密授权实现安全的代理主导支付 |
| 前端 | 普通HTML/CSS/JS | 单文件,无构建步骤,深色主题聊天UI |
| 构建 | Maven(多模块) | 服务器+客户端作为单独的模块, -parameters 旗帜 |
| 数据 | 内存模拟数据 | 4个平台上的28个产品,没有外部数据库 |
关键依赖关系
<!-- MCP Server -->
spring-boot-starter-web <!-- REST endpoints + Tomcat -->
spring-ai-starter-mcp-server-webmvc <!-- MCP server with SSE transport -->
lombok <!-- @Builder, @Getter for Product model -->
<!-- MCP Client -->
spring-boot-starter-web <!-- REST endpoints + Tomcat -->
spring-ai-starter-mcp-client <!-- MCP client with SSE support -->
spring-ai-ollama-spring-boot-starter <!-- Ollama LLM integration -->
📄 许可证
该项目用于示范和教育目的。