AI Agent智能体与MCP Server开发实践
基础概念
模型调用
模型调用就是通过API接口与大语言模型对话,就像你在微信上跟朋友聊天一样。你发送消息,模型回复你
typescript
// 基础的大模型调用示例
const apiKey ='xxx'
async function callLLM(prompt: string) {
try {
const response = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${apiKey}`
},
body: JSON.stringify({
model: 'qwen-plus',
messages: [
{
role: 'system',
content: '你是一个有用的AI助手,请用中文回答用户的问题。'
},
{
role: 'user',
content: prompt
}
],
max_tokens: 1000,
temperature: 0.7,
response_format: { type: "json_object" } //指定返回为json
})
});
const data = await response.json();
return data.choices[0].message.content;
} catch (error) {
console.error('调用大模型失败:', error);
throw error;
}
}
// messages 中 role 的类型说明:
// 1. 'system': 系统角色,用于设定AI的行为、风格、能力等,通常放在对话开始
// 2. 'user': 用户角色,表示用户输入的消息
// 3. 'assistant': 助手角色,表示AI的回复消息
// 4. 'function': 函数角色,用于函数调用的特殊消息类型(某些模型支持)
// 5. 'tool': 工具角色,用于工具调用的消息类型(某些模型支持)
// 使用示例
const response = await callLLM('你好,请介绍一下人工智能');
console.log(response);
重要参数说明:max_tokens控制回复的最大长度,数字越大回复越长;temperature控制创造性程度,0-1之间,0最保守,1最有创意;model选择哪个模型,不同模型能力不同。
提示词编写技巧
提示词就是你给大模型的"指令",就像你告诉朋友"帮我写一篇文章"一样。好的提示词能让模型更准确地理解你的需求。提示词的核心原则包括明确性(说清楚要什么,不要模棱两可)、具体性(给出具体的例子和要求)、结构化(要求输出特定的格式)和角色定位(给模型设定明确的身份)。
结构化输出
大模型默认输出的是自然语言,结构化输出就是让大模型输出特定的格式,比如JSON,而不是自然语言。这样做的好处是程序可以直接解析使用,数据格式统一,便于后续程序化的处理,减少人工处理。
typescript
// 使用更严格的输出控制,确保获得可解析的数据
function createStrictPrompt(userCode: string): string {
return `
你是一个代码优化专家。请优化以下代码:
===code===
function calculateTotal(items) {
let total = 0;
for (let i = 0; i < items.length; i++) {
total += items[i].price;
}
return total;
}
===code===
要求:
1. 必须输出有效的JSON格式
2. 不要添加任何其他文字
3. 严格按照以下结构输出:
{
"originalCode": "这里返回原始代码",
"optimizedCode": "完整的优化后代码",
"changes": [
{
"type": "修改类型",
"description": "修改描述",
"before": "修改前",
"after": "修改后"
}
],
"summary": "优化总结",
"performance": "性能提升说明"
}
注意:JSON必须完全有效,不要有任何语法错误。
`;
}
const prompt = createStrictPrompt(userCode);
const response = await callLLM(prompt); // 大模型返回的是JSON格式的字符串
// 大模型返回的内容
/**
```json
{
"originalCode": "function calculateTotal(items) {\n let total = 0;\n for (let i = 0; i < items.length; i++) {\n total += items[i].price;\n }\n return total;\n}",
"optimizedCode": "function calculateTotal(items) {\n return items.reduce((total, item) => total + item.price, 0);\n}",
"changes": [
{
"type": "重构",
"description": "将传统的 for 循环替换为数组的 reduce 方法",
"before": "for (let i = 0; i < items.length; i++) {\n total += items[i].price;\n}",
"after": "return items.reduce((total, item) => total + item.price, 0);"
}
],
"summary": "使用 reduce 方法简化代码逻辑,提高可读性和简洁性。",
"performance": "减少手动循环控制,利用内置 reduce 方法提升执行效率,同时避免了显式索引管理和边界检查。"
}
```*/
**/
// 解析响应 - 将JSON字符串转换为JavaScript对象
console.log('大模型原始响应(字符串):', response);
try {
// 提取 ```json 和 ``` 之间的内容
const jsonBlockMatch = response.match(/```json\s*([\s\S]*?)\s*```/);
if (jsonBlockMatch) {
const jsonString = jsonBlockMatch[1].trim();
console.log('提取的JSON字符串:', jsonString);
const result = JSON.parse(jsonString);
console.log('解析成功!');
// 现在可以从解析后的对象中直接获取结构化数据
const optimizedCode = result.optimizedCode;
console.log('优化后的代码:', optimizedCode);
console.log('性能提升:', result.performance);
console.log('修改详情:', result.changes);
// 处理换行符
const formattedOriginalCode = result.originalCode.replace(/\\n/g, '\n');
const formattedOptimizedCode = result.optimizedCode.replace(/\\n/g, '\n');
console.log('格式化后的原始代码:');
console.log(formattedOriginalCode);
console.log('格式化后的优化代码:');
console.log(formattedOptimizedCode);
} else {
console.error('未找到JSON代码块');
}
} catch (error) {
console.error('JSON解析失败:', error);
console.log('原始响应:', response);
}
关键点说明:
- 大模型直接返回JSON: 通过明确的提示词要求,大模型会直接返回JSON格式的字符串
- 错误处理: 用 try-catch 处理JSON解析失败的情况
- 确保返回的是有效的JSON格式
- 减少解析错误的概率
提示词使用技巧
高级提示词技术能解决基础提示词效果不好的问题,比如模型理解不准确、输出格式不统一、回答质量不稳定、逻辑性不够强等。这些技术让模型输出更准确、更有用。
Chain of Thought (思维链)
思维链就是让模型像人一样,一步一步地思考问题,而不是直接给出答案。这样做的好处是思路更清晰,逻辑更完整,不容易遗漏,结果更可靠。适用场景包括复杂问题分析、需要详细推理、要求逻辑完整、避免跳跃性思维等。
typescript
const chainOfThoughtPrompt = `
请按照以下步骤分析这个购物决策问题:
1. 首先明确购物需求
2. 列出可选的产品选项
3. 分析每个选项的优缺点
4. 考虑预算和实际需求
5. 做出最终选择并说明理由
题目:小明想买一台笔记本电脑,预算5000元,主要用于办公和学习,偶尔看看视频。请帮他分析选择。
请按照上述步骤分析,每一步都要详细说明。
`;
使用思维链的技巧是步骤要具体明确,每一步都要有要求,避免过于复杂的步骤,适合需要分析的问题。
Few-Shot Learning (少样本学习)
少样本学习就是给模型几个例子,让它学会做类似的事情。这样做的好处是模型理解更准确,输出格式更统一,减少提示词长度,提高成功率。适用场景包括分类任务、格式转换、风格模仿、标准化输出等。
typescript
const fewShotPrompt = `
请根据以下示例,完成类似的文本分类任务:
示例1:
输入:这部电影真的很棒,演员表演出色,剧情引人入胜。
输出:正面评价
示例2:
输入:剧情拖沓,演员演技一般,特效也很差。
输出:负面评价
现在请分类以下文本:
输入:这部电影还可以,不算太差但也没什么亮点。
输出:
`;
使用少样本学习的技巧是例子要典型,格式要一致,例子数量适中(2-5个),避免过于复杂的例子。
Function Call
Function Call就是让大模型能够"打电话"给你的程序,调用你预先写好的函数。就像你告诉朋友"帮我查一下北京的天气",朋友不会查,但会告诉你"我可以帮你查,需要知道具体日期"。 Function Call让模型知道它能调用什么函数,以及怎么调用。这样做的好处是模型能做更多事情,可以获取实时数据,能执行具体操作,扩展性更强。
适用场景 工具调用: 需要执行特定功能的场景 API集成: 与外部服务交互 工作流自动化: 需要按步骤执行的任务 参数验证: 对输入参数有严格要求
typescript
// 定义可调用的函数
const availableFunctions = {
getWeather: {
description: "获取指定城市的天气信息",
parameters: {
type: "object",
properties: {
city: {
type: "string",
description: "城市名称"
},
date: {
type: "string",
description: "日期,格式:YYYY-MM-DD"
}
},
required: ["city"]
}
},
calculateDistance: {
description: "计算两个城市之间的距离",
parameters: {
type: "object",
properties: {
city1: {
type: "string",
description: "起始城市"
},
city2: {
type: "string",
description: "目标城市"
}
},
required: ["city1", "city2"]
}
}
};
// 调用大模型并处理 Function Call
async function callLLMWithFunctions(prompt: string, functions: any) {
const response = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.OPENAI_API_KEY}`
},
body: JSON.stringify({
model: 'gpt-3.5-turbo',
messages: [
{
role: 'user',
content: '帮我查询北京今天的天气'
}
],
functions: functions,
function_call: 'auto'
})
});
const data = await response.json();
const message = data.choices[0].message;
// 检查是否需要调用函数
if (message.function_call) {
const functionName = message.function_call.name;
const functionArgs = JSON.parse(message.function_call.arguments);
// 执行对应的函数
const result = await executeFunction(functionName, functionArgs);
// 将函数结果发送回模型
return await sendFunctionResult(message, result);
}
return message.content;
}
// 执行函数的示例
async function executeFunction(functionName: string, args: any) {
switch (functionName) {
case 'getWeather':
return await getWeatherData(args.city, args.date);
case 'calculateDistance':
return await calculateCityDistance(args.city1, args.city2);
default:
throw new Error(`未知函数: ${functionName}`);
}
}
Tool Call
Tool Call是Function Call的升级版本,让大模型能够调用多个工具,并且可以并行执行。
Function Call与MCP协议
技术演进关系
Function Call和MCP协议代表了AI工具调用技术的不同发展阶段,它们既有技术继承关系,又有根本性的差异。
发展时间线
scss
Function Call (2023年) → Tool Call (2024年) → MCP (2024年11月)
- Function Call:OpenAI在2023年推出的基础功能
- Tool Call:OpenAI在2024年对Function Call的升级
- MCP:Anthropic在2024年11月推出的标准化协议
技术继承关系
scss
Function Call (基础概念)
↓
Tool Call (功能扩展)
↓
MCP (协议标准化)
📊 功能对比分析
1. Function Call (OpenAI基础版)
typescript
// OpenAI Function Call示例
const functions = [
{
name: "get_weather",
description: "获取天气信息",
parameters: {
type: "object",
properties: {
city: { type: "string" }
},
required: ["city"]
}
}
];
// 调用方式
const response = await openai.chat.completions.create({
model: "gpt-4",
messages: [{ role: "user", content: "北京天气怎么样?" }],
functions: functions,
function_call: "auto"
});
特点:
- 只能调用一个函数
- 模型自动选择函数
- 简单的参数传递
- 基础的工具调用能力
2. Tool Call (OpenAI升级版)
typescript
// OpenAI Tool Call示例
const tools = [
{
type: "function",
function: {
name: "get_weather",
description: "获取天气信息",
parameters: {
type: "object",
properties: {
city: { type: "string" }
},
required: ["city"]
}
}
},
{
type: "function",
function: {
name: "get_news",
description: "获取新闻",
parameters: {
type: "object",
properties: {
topic: { type: "string" }
},
required: ["topic"]
}
}
}
];
// 调用方式
const response = await openai.chat.completions.create({
model: "gpt-4",
messages: [{ role: "user", content: "北京天气和科技新闻" }],
tools: tools,
tool_choice: "auto"
});
特点:
- 支持多个工具并行调用
- 更灵活的工具选择
- 增强的参数验证
- 更好的错误处理
3. MCP (Anthropic标准化协议)
typescript
// MCP协议示例
const mcpRequest = {
jsonrpc: "2.0",
id: 1,
method: "tools/call",
params: {
name: "get_weather",
arguments: {
city: "北京"
}
}
};
// 通过MCP客户端调用
const response = await mcpClient.callTool("get_weather", { city: "北京" });
特点:
- 完全标准化的协议
- 支持多种传输方式
- 丰富的工具类型
- 完整的生态系统
🔄 技术架构对比
1. Function Call架构
javascript
用户 → OpenAI API → Function → 结果
2. Tool Call架构
用户 → OpenAI API → Tools → 并行执行 → 结果
3. MCP架构
用户 → AI模型 → MCP客户端 → MCP服务器 → 工具 → 结果
核心差异分析
1. 标准化程度
Function Call/Tool Call:
- OpenAI专有技术
- 绑定OpenAI生态系统
- 协议不开放
- 厂商锁定风险
MCP:
- 完全开源标准
- 厂商无关
- 协议开放透明
- 避免厂商锁定
2. 功能范围
Function Call/Tool Call:
- 仅支持函数调用
- 功能相对简单
- 扩展性有限
- 主要针对OpenAI模型
MCP:
- 支持工具、资源、提示词
- 功能更加丰富
- 高度可扩展
- 支持多种AI模型
3. 生态系统
Function Call/Tool Call:
- OpenAI控制
- 工具相对集中
- 集成成本较高
- 依赖OpenAI基础设施
MCP:
- 社区驱动
- 工具生态丰富
- 集成成本较低
- 独立的基础设施
实际使用关系
1. 可以同时使用
typescript
class HybridAIAgent {
private openaiClient: OpenAIClient;
private mcpClient: MCPClient;
async handleUserRequest(userInput: string) {
// 1. 使用OpenAI Tool Call处理简单任务
if (this.isSimpleTask(userInput)) {
return await this.handleWithOpenAI(userInput);
}
// 2. 使用MCP处理复杂任务
if (this.isComplexTask(userInput)) {
return await this.handleWithMCP(userInput);
}
// 3. 混合使用
return await this.handleHybrid(userInput);
}
private async handleHybrid(userInput: string) {
// 先用OpenAI分析意图
const intent = await this.openaiClient.analyzeIntent(userInput);
// 再用MCP执行具体任务
const result = await this.mcpClient.callTool(intent.toolName, intent.params);
// 最后用OpenAI生成回复
return await this.openaiClient.generateResponse(result);
}
}
1. 使用Function Call/Tool Call的场景
- 项目完全基于OpenAI生态
- 只需要简单的函数调用
- 对标准化要求不高
- 快速原型开发
- 短期项目需求
2. 使用MCP的场景
- 需要跨平台兼容性
- 复杂的工具集成需求
- 长期项目维护
- 开源生态建设
- 避免厂商锁定
- 多模型支持需求
3. 混合使用的场景
- 渐进式迁移
- 多模型支持
- 复杂业务场景
📝 总结
Function Call和MCP协议的关系可以概括为:
- 技术演进:Function Call → Tool Call → MCP
- 标准化程度:专有技术 → 开放标准
- 功能范围:简单函数调用 → 完整工具生态
- 使用方式:可以独立使用,也可以混合使用
- 发展方向:MCP代表了更开放、更标准化的未来
建议:新项目优先考虑MCP,现有OpenAI项目可以逐步迁移,或者采用混合架构来获得最佳效果。MCP的开源特性和标准化设计使其成为AI工具集成的长期发展方向。
简单示例
typescript
// 定义两个简单的工具
const tools = [
{
type: "function",
function: {
name: "getWeather",
description: "获取天气信息",
parameters: {
type: "object",
properties: {
city: { type: "string", description: "城市名称" }
},
required: ["city"]
}
}
},
{
type: "function",
function: {
name: "getNews",
description: "获取新闻",
parameters: {
type: "object",
properties: {
topic: { type: "string", description: "新闻主题" }
},
required: ["topic"]
}
}
}
];
// 工具执行函数
async function executeTool(toolName: string, args: any) {
switch (toolName) {
case 'getWeather':
// 模拟天气API调用
return {
city: args.city,
temperature: '25°C',
condition: '晴天',
humidity: '60%'
};
case 'getNews':
// 模拟新闻API调用
return {
topic: args.topic,
news: [
{ title: `${args.topic}相关新闻1`, summary: '这是第一条新闻' },
{ title: `${args.topic}相关新闻2`, summary: '这是第二条新闻' }
]
};
default:
throw new Error(`未知工具: ${toolName}`);
}
}
// 调用API
const response = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.OPENAI_API_KEY}`
},
body: JSON.stringify({
model: 'gpt-4',
messages: [{ role: 'user', content: '北京今天天气怎么样?有什么科技新闻?' }],
tools: tools,
tool_choice: 'auto'
})
});
const data = await response.json();
const message = data.choices[0].message;
// 检查是否有工具调用
if (message.tool_calls) {
console.log('模型要调用工具:', message.tool_calls);
// 执行所有工具调用
const toolResults = await Promise.all(
message.tool_calls.map(async (toolCall) => {
const toolName = toolCall.function.name;
const toolArgs = JSON.parse(toolCall.function.arguments);
console.log(`执行工具: ${toolName},参数:`, toolArgs);
const result = await executeTool(toolName, toolArgs);
return {
tool_call_id: toolCall.id,
role: 'tool',
content: JSON.stringify(result)
};
})
);
// 将结果发送回模型获取最终回答
const finalResponse = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.OPENAI_API_KEY}`
},
body: JSON.stringify({
model: 'gpt-4',
messages: [
{ role: 'user', content: '北京今天天气怎么样?有什么科技新闻?' },
message,
...toolResults
]
})
});
const finalData = await finalResponse.json();
console.log('最终回答:', finalData.choices[0].message.content);
}
深入理解MCP服务
在本节中,我们将学习如何开发一个MCP服务,从MCP开发视角,来看如何搭建一个完整的AI智能体应用
📋 MCP协议介绍
MCP,即模型上下文协议(Model Context Protocol),是 Anthropic Claude 的一个开源开放协议,旨在建立 AI 模型和开发环境之间的统一上下文交互,通过提供标准化的上下文信息访问,使 AI 模型能够更好地理解和处理代码。就像给它们之间搭建了一座桥梁,使得开发者可以通过一套标准将 AI 应用和数据源连接起来
MCP能做什么?
-
调用工具:执行具体的任务(创建文档、发送邮件、查询数据)
-
读取资源:获取各种信息(文档内容、图片、数据库记录)
-
使用模板:基于预设的提示词生成内容(写报告、做总结)
-
标准化:所有MCP工具都遵循相同的通信规则
-
JSON格式:使用人类可读的JSON格式进行数据交换
-
RPC风格:采用请求-响应的通信模式,就像远程调用函数一样
-
类型安全:通过JSON Schema定义参数格式,确保数据正确性
核心组件架构
MCP系统有三个主要角色:
- MCP服务器:提供各种工具和资源的"商店"
- MCP客户端:AI智能体用来连接服务器的"连接器"
- MCP Host端:宿主运行环境。通常是指mcp的应用,比如AI智能体"
架构说明:
-
主机 (Host):AI智能体的核心控制器,负责:
- 分析用户意图
- 选择合适的客户端
- 协调各个组件的交互
-
客户端 (Clients):不同类型的MCP客户端,包括:
- 客户端1:连接本地文件系统和Git服务
- 客户端2:连接本地数据库服务
- 客户端3:连接外部互联网服务
-
MCP服务端: 开放的API能力对外提供,比如
- 文件务:管理文件操作
- 数据库服务:处理数据存储和查询
-
互联网服务:
- 外部API服务:集成第三方云服务和在线资源
-
资源层:
- 本地资源:文件系统、数据库等本地存储
- 远程资源:云数据库、在线文件存储等远程服务
通信流程
消息格式示例
1. 获取提示词模板列表
请求:
json
{
"jsonrpc": "2.0",
"id": 6,
"method": "prompts/list",
"params": {}
}
响应:
json
{
"jsonrpc": "2.0",
"id": 6,
"result": [
{
"name": "weather_report",
"description": "生成天气报告",
"arguments": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称"
},
"format": {
"type": "string",
"description": "报告格式",
"enum": ["简洁", "详细"]
}
},
"required": ["city"]
}
}
]
}
2. 执行提示词模板
请求:
json
{
"jsonrpc": "2.0",
"id": 7,
"method": "prompts/execute",
"params": {
"name": "weather_report",
"arguments": {
"city": "北京",
"format": "详细"
}
}
}
响应:
json
{
"jsonrpc": "2.0",
"id": 7,
"result": {
"content": [
{
"type": "text",
"text": "北京今日天气报告:\n\n当前温度:25°C\n天气状况:晴天\n湿度:60%\n风力:微风\n能见度:10km\n气压:1013hPa\n\n天气适宜外出活动,建议适当防晒。"
}
]
}
}
错误响应示例
当工具不存在时的错误响应:
json
{
"jsonrpc": "2.0",
"id": 3,
"error": {
"code": -1001,
"message": "工具不存在",
"data": {
"toolName": "get_weather"
}
}
}
完整的MCP交互流程示例
步骤1:建立连接
json
// 客户端发送初始化请求
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {
"tools": {},
"resources": {},
"prompts": {}
},
"clientInfo": {
"name": "ai-coder",
"version": "1.0.0"
}
}
}
// 服务器响应
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2024-11-05",
"capabilities": {
"tools": {
"listChanged": true
},
"resources": {
"listChanged": true
},
"prompts": {
"listChanged": true
}
},
"serverInfo": {
"name": "weather-service",
"version": "1.0.0"
}
}
}
步骤2:获取可用工具
json
// 客户端请求工具列表
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list",
"params": {}
}
// 服务器返回工具列表
{
"jsonrpc": "2.0",
"id": 2,
"result": [
{
"name": "get_weather",
"description": "获取指定城市的天气信息",
"inputSchema": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称"
}
},
"required": ["city"]
}
},
{
"name": "get_forecast",
"description": "获取指定城市的天气预报",
"inputSchema": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称"
},
"days": {
"type": "integer",
"description": "预报天数",
"minimum": 1,
"maximum": 7
}
},
"required": ["city"]
}
}
]
}
步骤3:调用具体工具
json
// 客户端调用天气工具
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "get_weather",
"arguments": {
"city": "北京"
}
}
}
// 服务器返回天气数据
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"city": "北京",
"temperature": "25°C",
"condition": "晴天",
"humidity": "60%",
"wind": "微风",
"visibility": "10km",
"pressure": "1013hPa"
}
}
步骤4:获取资源信息
json
// 客户端请求资源列表
{
"jsonrpc": "2.0",
"id": 4,
"method": "resources/list",
"params": {}
}
// 服务器返回资源列表
{
"jsonrpc": "2.0",
"id": 4,
"result": [
{
"uri": "mcp://weather-service/current/beijing",
"name": "北京当前天气",
"description": "北京地区的实时天气信息",
"mimeType": "application/json"
},
{
"uri": "mcp://weather-service/forecast/beijing",
"name": "北京天气预报",
"description": "北京地区的7天天气预报",
"mimeType": "application/json"
}
]
}
步骤5:读取具体资源
json
// 客户端读取天气资源
{
"jsonrpc": "2.0",
"id": 5,
"method": "resources/read",
"params": {
"uri": "mcp://weather-service/current/beijing"
}
}
// 服务器返回资源内容
{
"jsonrpc": "2.0",
"id": 5,
"result": {
"contents": [
{
"uri": "mcp://weather-service/current/beijing",
"mimeType": "application/json",
"text": "{\"city\":\"北京\",\"temperature\":\"25°C\",\"condition\":\"晴天\"}"
}
]
}
}
🛠️ MCP Server工具类型
MCP支持三种主要类型:
1. 工具 (Tools)
- 作用:执行具体的操作
- 例子:创建文档、发送邮件、查询天气
- 特点:有输入参数,返回执行结果
2. 资源 (Resources)
- 作用:提供各种信息
- 例子:文档内容、图片、数据库记录
- 特点:可以读取,但不能修改
3. 提示词模板 (Prompts)
- 作用:指导AI生成特定类型的内容
- 例子:写技术文档、做数据分析报告
- 特点:基于模板生成,格式统一
💡 实际应用场景
场景1:智能客服
- 用户问:"我的订单什么时候发货?"
- AI通过MCP调用订单查询工具
- 返回具体的发货时间和物流信息
场景2:技术文档助手
- 用户说:"帮我写一个React教程"
- AI通过MCP调用文档生成模板
- 生成结构化的React学习教程
🔧 开发MCP服务器的简单步骤
第1步:定义你的工具
typescript
// 定义一个简单的天气查询工具
const weatherTool = {
name: "get_weather",
description: "查询指定城市的天气信息",
inputSchema: {
type: "object",
properties: {
city: {
type: "string",
description: "城市名称"
}
},
required: ["city"]
}
};
第2步:实现工具功能
typescript
// 实现天气查询功能
async function getWeather(city: string) {
// 模拟天气数据
const weatherData = {
'北京': { temperature: '25°C', condition: '晴天', humidity: '60%' },
'上海': { temperature: '28°C', condition: '多云', humidity: '70%' },
'广州': { temperature: '30°C', condition: '小雨', humidity: '80%' }
};
return weatherData[city] || { temperature: '未知', condition: '未知', humidity: '未知' };
}
第3步:创建简单的MCP服务器
typescript
import express from 'express';
const app = express();
app.use(express.json());
// 存储工具
const tools = new Map();
// 注册工具
function registerTool(name: string, handler: Function, schema: any) {
tools.set(name, { handler, schema });
}
// 注册天气工具
registerTool('get_weather', getWeather, weatherTool.inputSchema);
// MCP工具列表接口
app.get('/tools', (req, res) => {
const toolsList = Array.from(tools.keys()).map(name => ({
name,
description: tools.get(name).schema.description || '',
inputSchema: tools.get(name).schema
}));
res.json(toolsList);
});
// MCP工具调用接口
app.post('/tools/call', async (req, res) => {
try {
const { name, arguments: args } = req.body;
if (!tools.has(name)) {
return res.status(400).json({ error: `工具不存在: ${name}` });
}
const tool = tools.get(name);
const result = await tool.handler(args.city);
res.json({
content: [
{
type: 'text',
text: `${args.city}天气:温度${result.temperature},${result.condition},湿度${result.humidity}`
}
]
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// 启动服务器
app.listen(3000, () => {
console.log('MCP服务器已启动: http://localhost:3000');
console.log('可用工具:', Array.from(tools.keys()));
});
📚 学习建议
初学者路径:
- 先理解MCP的基本概念(工具、资源、模板)
- 学习如何调用现成的MCP工具
- 尝试开发一个简单的MCP工具
- 逐步构建完整的MCP服务器
进阶方向:
- 深入学习MCP协议规范
- 开发复杂的工具和资源
- 优化性能和安全性
- 参与MCP生态建设
MCP client端
现在,我们来实现一个简单的MCP客户端,用于连接MCP服务器并调用其中的工具。
typescript
// MCP客户端配置
interface MCPClientConfig {
serverUrl: string;
apiKey: string;
timeout?: number;
}
// MCP工具调用请求
interface MCPToolCallRequest {
toolName: string;
parameters: Record<string, any>;
}
// MCP客户端类
class MCPClient {
private config: MCPClientConfig;
constructor(config: MCPClientConfig) {
this.config = config;
}
// 调用MCP工具的方法
async callTool(toolCallRequest: MCPToolCallRequest): Promise<any> {
try {
const response = await fetch(`${this.config.serverUrl}/api/tool/call`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(toolCallRequest),
timeout: this.config.timeout || 30000
});
if (!response.ok) {
throw new Error(`MCP调用失败: ${response.status} ${response.statusText}`);
}
return await response.json();
} catch (error) {
console.error('MCP工具调用错误:', error);
throw error;
}
}
// 列出可用的工具
async listAvailableTools(): Promise<any> {
try {
const response = await fetch(`${this.config.serverUrl}/api/tools`, {
method: 'GET',
headers: {
'Authorization': `Bearer ${this.config.apiKey}`
}
});
return await response.json();
} catch (error) {
console.error('获取工具列表失败:', error);
throw error;
}
}
}
// 使用MCP客户端处理请求
async function handleWithMCPClient(userQuery: string, toolName: string): Promise<string> {
// 创建MCP客户端实例
const mcpClient = new MCPClient({
serverUrl: 'https://mcp-server.example.com', // 替换为实际的MCP服务器地址
});
try {
// 解析用户查询,提取参数
const parameters = extractParameters(userQuery, toolName);
// 调用MCP工具
const result = await mcpClient.callTool({
toolName: toolName,
parameters: parameters,
});
// 格式化结果为友好的回复
return formatMCPResult(result, toolName);
} catch (error) {
console.error('MCP处理失败:', error);
// 失败时回退到直接使用大模型
return await callLLM(userQuery);
}
}
// 从用户查询中提取参数
function extractParameters(userQuery: string, toolName: string): Record<string, any> {
const params: Record<string, any> = {};
// 简单的参数提取逻辑
switch (toolName) {
case 'weather_tool':
// 提取城市名
const cityMatch = userQuery.match(/(北京|上海|广州|深圳|杭州|成都|武汉|西安|重庆|天津)/);
if (cityMatch) {
params.city = cityMatch[0];
} else {
params.city = '北京'; // 默认值
}
break;
case 'news_tool':
// 提取新闻主题
const topicMatch = userQuery.match(/(科技|体育|娱乐|财经|政治)/);
if (topicMatch) {
params.topic = topicMatch[0];
} else {
params.topic = '科技'; // 默认值
}
break;
}
return params;
}
// 格式化MCP结果
function formatMCPResult(result: any, toolName: string): string {
switch (toolName) {
case 'weather_tool':
return `\n当前${result.city}的天气情况:\n- 温度:${result.temperature}\n- 天气状况:${result.condition}\n- 湿度:${result.humidity}\n- 风力:${result.wind}`;
case 'news_tool':
let newsSummary = `\n最新${result.topic}新闻:\n`;
result.news.forEach((item: any, index: number) => {
newsSummary += `${index + 1}. ${item.title}\n ${item.summary}\n`;
});
return newsSummary;
default:
return JSON.stringify(result, null, 2);
}
}
完整智能体示例
下面是一个整合了以上所有功能的完整智能体示例:
typescript
// 完整的智能体应用
class SimpleAIAgent {
private mcpClient: MCPClient;
constructor(mcpConfig: MCPClientConfig) {
this.mcpClient = new MCPClient(mcpConfig);
}
// 启动智能体
async start() {
console.log('AI智能体已启动,等待用户输入...');
// 这里可以添加实际的用户界面或API接口
// 为了演示,我们使用几个测试问题
const testQueries = [
'北京今天天气怎么样?',
'有什么最新的科技新闻?',
'如何用JavaScript实现一个简单的计算器?',
'你能给我讲个笑话吗?'
];
// 处理每个测试问题
for (const query of testQueries) {
console.log(`\n用户问题: ${query}`);
const response = await this.handleUserQuery(query);
console.log(`智能体回复: ${response}`);
}
}
// 处理用户查询
async handleUserQuery(userQuery: string): Promise<string> {
// 1. 分析用户意图
const intent = await analyzeUserIntent(userQuery);
console.log(`识别到的意图: ${intent}`);
// 2. 根据意图选择处理方式
switch (intent) {
case 'weather_query':
return await this.handleWithMCPClient(userQuery, 'weather_tool');
case 'news_query':
return await this.handleWithMCPClient(userQuery, 'news_tool');
case 'code_help':
return await handleCodeHelp(userQuery);
default:
// 直接使用大模型回复
return await callLLM(userQuery);
}
}
// 使用MCP客户端处理请求
private async handleWithMCPClient(userQuery: string, toolName: string): Promise<string> {
try {
// 解析参数
const parameters = extractParameters(userQuery, toolName);
// 调用MCP工具
const result = await this.mcpClient.callTool({
toolName: toolName,
parameters: parameters,
});
// 格式化结果
return formatMCPResult(result, toolName);
} catch (error) {
console.error('MCP处理失败,回退到直接调用大模型:', error);
return await callLLM(userQuery);
}
}
}
// 使用示例
async function runExample() {
// 创建并启动智能体
const agent = new SimpleAIAgent({
serverUrl: 'https://mcp-server.example.com',
apiKey: 'your-mcp-api-key'
});
await agent.start();
}
// 运行示例
runExample().catch(console.error);
ai智能体工作流程
主流程图
- 分层调用: 不同阶段使用不同的 LLM 调用策略
- 上下文传递: 每次调用都会传递相关的上下文信息
- 工具类型区分: 明确区分Prompt模板和MCP工具的执行方式
- 结果缓存: 避免重复的 LLM 调用
- 降级处理: 当 LLM 调用失败时的备选方案
总结
通过本教程,我们学习了如何构建一个完整的AI智能体系统,包括:
- 基础概念: 模型调用、提示词编写、Function Call、Tool Call等
- MCP协议: 协议规范、服务器端实现、客户端开发
- 意图分析: 使用大模型进行智能意图识别
- 工具调用: 集成MCP工具和Prompt模板
- 流程设计: 多次LLM调用的优化策略
- 错误处理: 完善的降级和容错机制