MCP 实战:打造股票分析助手系统

图片来源网络,侵权联系删。

文章目录

  • [1. 引言](#1. 引言)
  • [2. MCP 核心机制与 Web 技术栈的深度映射](#2. MCP 核心机制与 Web 技术栈的深度映射)
    • [2.1 MCP 工作流程(Mermaid)](#2.1 MCP 工作流程(Mermaid))
  • [3. 系统设计:基于 MCP 的股票分析助手架构](#3. 系统设计:基于 MCP 的股票分析助手架构)
    • [3.1 功能需求](#3.1 功能需求)
    • [3.2 工具定义(MCP Tool Schema)](#3.2 工具定义(MCP Tool Schema))
  • [4. 工程实现:Java 后端 + Vue 前端全栈开发](#4. 工程实现:Java 后端 + Vue 前端全栈开发)
    • [4.1 后端:Spring Boot 实现 MCP Agent 编排器](#4.1 后端:Spring Boot 实现 MCP Agent 编排器)
    • [4.2 前端:Vue 3 展示分析结果](#4.2 前端:Vue 3 展示分析结果)
  • [5. 生产级优化:提升可靠性、性能与安全性](#5. 生产级优化:提升可靠性、性能与安全性)
    • [5.1 防幻觉:强制数据驱动回答](#5.1 防幻觉:强制数据驱动回答)
    • [5.2 性能优化](#5.2 性能优化)
    • [5.3 安全性](#5.3 安全性)
  • [6. 总结与延伸:从股票助手到通用 MCP 平台](#6. 总结与延伸:从股票助手到通用 MCP 平台)

1. 引言

在 Web 开发中,我们早已习惯通过 API 获取数据、处理逻辑、渲染界面。而 MCP(Model Context Protocol)正是将这一范式扩展到 AI Agent 领域的标准协议------它让 LLM 能像调用 RESTful 接口一样,安全、可靠地使用外部工具。

对于有 Java/Node.js + Vue/React 经验的开发者来说,构建一个生产级股票分析助手不再是"AI 黑魔法",而是一次熟悉的全栈工程实践:

  • 用户提问 → Agent 理解意图 → 调用金融 API → 分析数据 → 生成结构化报告 → 前端可视化

本文将基于 MCP 思想,手把手带你从零实现一个支持多工具调用、上下文记忆、防幻觉输出的股票分析系统,并提供完整可运行的代码示例。


2. MCP 核心机制与 Web 技术栈的深度映射

MCP 的本质是为 LLM 提供标准化的"操作系统接口",其三大核心组件与 Web 开发高度对应:

MCP 概念 Web 开发类比 作用
Context(上下文) HTTP Session / JWT Payload 存储用户身份、对话历史、临时状态
Tool(工具) RESTful API / gRPC 服务 封装外部能力(如查股价、读新闻)
Protocol(协议) OpenAPI Spec / JSON Schema 定义工具输入/输出格式,确保类型安全

关键优势:Web 开发者无需学习新范式,只需将现有工程经验迁移到 Agent 场景。

2.1 MCP 工作流程(Mermaid)

News_API Financial_API MCP_Agent Backend Frontend User News_API Financial_API MCP_Agent Backend Frontend User "特斯拉最近一周表现如何?" POST /analyze { query: "...", sessionId: "abc" } 初始化上下文 + 注册工具 解析意图 → 需调用 get_stock_price & get_news GET /price?symbol=TSLA&days=7 返回股价数据 GET /news?symbol=TSLA&limit=3 返回新闻列表 基于数据生成结构化分析 { "summary": "...", "trend": "up", "confidence": 0.85 } 返回 JSON 渲染图表 + 文字结论


3. 系统设计:基于 MCP 的股票分析助手架构

3.1 功能需求

支持以下自然语言查询:

  • "苹果公司最近股价走势?"
  • "比较英伟达和 AMD 的基本面"
  • "特斯拉有负面新闻吗?"

系统需具备:

  • 实时股价获取(Alpha Vantage)
  • 新闻情感分析(NewsAPI + LLM)
  • 防幻觉机制(仅基于数据回答)
  • 结构化输出(前端可直接解析)

3.2 工具定义(MCP Tool Schema)

json 复制代码
// tools/stock_tools.json
[
  {
    "name": "get_stock_price_history",
    "description": "获取某股票过去N天的收盘价",
    "input_schema": {
      "type": "object",
      "properties": {
        "symbol": { "type": "string", "description": "股票代码,如 AAPL" },
        "days": { "type": "integer", "default": 7, "minimum": 1, "maximum": 30 }
      },
      "required": ["symbol"]
    },
    "output_schema": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "date": { "type": "string", "format": "date" },
          "close": { "type": "number" }
        }
      }
    }
  },
  {
    "name": "get_company_news_with_sentiment",
    "description": "获取某公司最近新闻及其情感倾向",
    "input_schema": {
      "type": "object",
      "properties": {
        "symbol": { "type": "string" },
        "limit": { "type": "integer", "default": 5 }
      },
      "required": ["symbol"]
    },
    "output_schema": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "title": { "type": "string" },
          "url": { "type": "string", "format": "uri" },
          "sentiment": { "type": "string", "enum": ["positive", "neutral", "negative"] }
        }
      }
    }
  }
]

🔍 这相当于 Web 后端的 OpenAPI 文档,Agent 会据此安全调用工具。


4. 工程实现:Java 后端 + Vue 前端全栈开发

4.1 后端:Spring Boot 实现 MCP Agent 编排器

java 复制代码
// McpAgentService.java
@Service
public class McpAgentService {

    private final RestTemplate restTemplate;
    private final OpenAiService openAiService; // 使用官方 SDK 或 LangChain4j

    public StockAnalysisResponse analyze(String sessionId, String userQuery) {
        // 1. 加载上下文(含历史对话)
        McpContext context = contextStore.load(sessionId);
        context.addUserMessage(userQuery);

        // 2. 注册工具(实际项目中可动态加载)
        context.registerTool("get_stock_price_history", this::fetchStockPrice);
        context.registerTool("get_company_news_with_sentiment", this::fetchNewsWithSentiment);

        // 3. 构建系统提示词(含工具说明)
        String systemPrompt = """
        你是一名专业金融分析师,请严格遵守:
        - 仅基于工具返回的数据回答
        - 若数据不足,回答"信息不足"
        - 输出必须为以下 JSON 格式:
        {"summary":"...","recommendation":"hold","confidence":0.8}
        """ + context.getToolDescriptions();

        // 4. 调用 LLM(启用 function calling)
        ChatCompletionResult result = openAiService.createChatCompletion(
            ChatCompletionRequest.builder()
                .model("gpt-4o")
                .messages(context.getMessagesForLLM(systemPrompt))
                .tools(context.getOpenAIToolDefinitions())
                .toolChoice("auto")
                .build()
        );

        // 5. 执行工具调用(如有)
        if (result.hasToolCalls()) {
            for (ToolCall call : result.getToolCalls()) {
                Object output = context.executeTool(call);
                context.addToolResponse(call.getId(), output);
            }
            // 二次调用生成最终回答
            result = openAiService.createChatCompletion(...); // 传入更新后的上下文
        }

        // 6. 保存上下文并返回结构化结果
        contextStore.save(sessionId, context);
        return parseJsonToResponse(result.getMessage().getContent());
    }

    private Object fetchStockPrice(Map<String, Object> args) {
        String symbol = (String) args.get("symbol");
        int days = (int) args.getOrDefault("days", 7);
        // 调用 Alpha Vantage API
        String url = "https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=%s&apikey=%s"
                     .formatted(symbol, apiKey);
        JsonNode response = restTemplate.getForObject(url, JsonNode.class);
        // 解析并返回最近 days 天的数据(略)
        return extractedData;
    }
}

4.2 前端:Vue 3 展示分析结果

vue 复制代码
<!-- StockAnalyzer.vue -->
<template>
  <div class="analyzer">
    <input v-model="query" @keyup.enter="analyze" placeholder="例如:英伟达值得投资吗?" />
    <button @click="analyze">分析</button>

    <div v-if="result" class="result">
      <h2>分析摘要</h2>
      <p>{{ result.summary }}</p>

      <div class="metrics">
        <span class="recommendation" :class="result.recommendation">
          {{ result.recommendation.toUpperCase() }}
        </span>
        <span class="confidence">置信度: {{ (result.confidence * 100).toFixed(0) }}%</span>
      </div>

      <h3>相关新闻</h3>
      <ul class="news-list">
        <li v-for="news in result.news" :key="news.url">
          <a :href="news.url" target="_blank">{{ news.title }}</a>
          <span class="sentiment" :class="news.sentiment">{{ news.sentiment }}</span>
        </li>
      </ul>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import axios from 'axios'

const query = ref('')
const result = ref(null)
const sessionId = localStorage.getItem('session') || (localStorage.setItem('session', Date.now().toString()), Date.now().toString())

const analyze = async () => {
  const res = await axios.post('/api/stock/analyze', { 
    query: query.value, 
    sessionId 
  })
  result.value = res.data // 包含 summary, recommendation, confidence, news
}
</script>

<style scoped>
.recommendation.buy { color: green; font-weight: bold; }
.recommendation.sell { color: red; font-weight: bold; }
.recommendation.hold { color: orange; }
.sentiment.positive { color: green; }
.sentiment.negative { color: red; }
</style>

5. 生产级优化:提升可靠性、性能与安全性

5.1 防幻觉:强制数据驱动回答

在系统提示词中明确约束:

"你必须仅基于工具返回的数据生成回答。禁止猜测、编造或引用外部知识。若工具未返回有效数据,请回答'当前无足够信息进行分析'。"

5.2 性能优化

  • 缓存 :使用 Redis 缓存 get_stock_price_history(AAPL, 7),TTL=5分钟
  • 限流:对高频用户限制每分钟 3 次分析请求(类似 Web API 限流)
  • 异步:复杂分析可转为后台任务,前端轮询结果

5.3 安全性

  • 输入校验 :后端校验 symbol 是否为合法股票代码(正则:^[A-Z]{1,5}$
  • API Key 隔离:金融 API Key 不暴露给前端,由后端代理调用
  • 日志脱敏:记录日志时移除敏感用户信息

6. 总结与延伸:从股票助手到通用 MCP 平台

通过本次实战,我们验证了:

MCP 是 Web 开发者构建 Agent 的理想范式

股票分析助手 = 微服务 + 智能路由 + 结构化输出

工程化思维 > AI 理论深度

下一步建议

  1. 扩展工具集:接入财报 PDF 解析(LLM + PyPDF)、技术指标计算(TA-Lib)
  2. 支持多 Agent 协作:一个负责数据,一个负责风险评估,一个生成报告
  3. 部署到生产环境:使用 Docker + Kubernetes + Prometheus 监控

推荐资源

🌟 记住:你不是在"做 AI 项目",而是在"用 AI 升级你的 Web 工程能力"。

相关推荐
亓才孓4 小时前
继承父类和接口,又冲突的变量名怎么解决
java·开发语言
七夜zippoe4 小时前
Spring WebFlux核心原理-对比Servlet与响应式模型
java·spring·servlet·长连接·webflux·短连接
猫头虎4 小时前
如何解决pip报错 import pandas as pd ModuleNotFoundError: No module named ‘pandas‘问题
java·python·scrapy·beautifulsoup·pandas·pip·scipy
indexsunny4 小时前
互联网大厂Java求职面试实战:Spring Boot与微服务在电商场景中的应用解析
java·数据库·spring boot·微服务·面试·消息队列·电商
廋到被风吹走4 小时前
【Java】【JVM】内存模型
java·开发语言·jvm
talenteddriver4 小时前
java: JAVA静态方法细节
java·前端·apache
indexsunny4 小时前
互联网大厂Java面试实录:从Spring Boot到微服务实战解析
java·spring boot·spring cloud·kafka·microservices·java interview·software development
小宇的天下4 小时前
【caibre】快速查看缓存库文件(8)
java·后端·spring
Wpa.wk4 小时前
接口自动化 - 接口组合业务练习(CRUD组合)-REST-assure(Java版)
java·运维·经验分享·测试工具·自动化·接口自动化