「前言」读完本文你将收获:
- 工程角度上对ai聊天的完全理解
- 对Function Call与MCP的清晰认知
对话历史构建---消息类型
与大模型的对话消息可分为三类:
System
- role: "system"
- 设定AI的行为和角色
- 定义回答的风格、限制,ai会始终遵循
- 一般不展示给用户
- 例如:你是一名专业的客服助手,回答要简洁,态度友好,不要透露用户个人信息
User
- role: "user"
- 用户发送的问题或指令
- 例如:我想找一个100元以内的手机,拍照要清晰
Assistant
- role: "assistant"
- AI回复的内容,根据System指令 + 历史上下文生成
- 例如:在100以内,没有拍照清晰的手机...
Tips
应用开发时,后端请求ai接口,对话历史需要包含System、User和Assistant等所有类型的消息,但前端UI中一般不展示System类型的消息
模型对话api对接
文本型
(即一次性对话。用户问,模型回答,对话结束)
向大模型供应商发出请求:
js
// 伪代码
const response = await fetch(
'https://api.openai.com/v1/chat/completions',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${API_KEY}`
},
body: JSON.stringify({
model: 'gpt-3.5.turbo',
messages: [
{ role: 'user', content: userMessage }
]
})
}
)
// 或SDK
import OpenAI from 'openai';
const openai = new OpenAI({
appKey: process.env.OPENAI_API_KEY
})
async function chatWithAI(userMessage) {
const completion = await openai.chat.completions.create({
model: 'gpt-3.5.turbo',
message: [
{ role: 'user', content: userMessage }
]
})
return completion.choices[0].message.content;
}
对话型
(包含对话历史。模型的回复基于用户与模型的所有对话上下文)
在应用中维护对话历史
js
let concersationHistory = [];
async function chat(userMessage) {
// 添加用户消息至历史
concersationHistory.push({
role: 'user',
content: userMessage
})
// 发送整个对话历史至ai接口
const response = await openai.chat.completions.create({
model: 'gpt-3.5.turbo',
messages: concersationHistory
})
// 添加AI消息到历史
const aiMessage = response.choices[0].message;
concersationHistory.push(aiMessage);
return aiMessage.content;
}
api调用对话的瓶颈
举例
若用户询问:帮我查询北京今天的天气,ai知识滞后(不联网),所以无法做到这个查询
又比如一些专业领域的知识,但模型仅靠文本生成算法无法很好的解决此类问题
解决方案一、提示词工程
使用提示词来规范模型的输出,服务端对接这些格式化的输出,最终触发外部工具调用来解决问题
例如,输入system消息:
你可以访问天气,当你需要获取天气信息时,请你返回合法的JSON格式的模拟结果,必须包含如下示例中的字段。我会查询后告诉你结果,你再回复用户。示例:
json
{
"action": "getWeather",
"parameters": {
"city": "地点名称",
"date": "遵循日期格式(比如2025-03-16)"
}
}
缺点:
- 存在不可靠性:AI可能不遵循提示词,JSON不可控,一旦内容非法或者语法错误,都会影响正常运行
解决方案二、Function Calling
2023,openAi发布Function Calling功能
Function Calling本质上即支持在ai接口层面,声明可用的工具列表
js
import OpenAI from 'openai';
const openai = new OpenAI({
appKey: process.env.OPENAI_API_KEY
})
async function chatWithFunctionCalling(userMessage) {
// 1. 定义可用的函数
const functions = [
{
name: 'getWeather',
description: '获取指定城市的天气信息',
parameters: {
type: 'object',
properties: {
location: {
type: 'string',
description: '城市名称'
}
},
required: ['location']
}
}
];
// 2. 传参functions & function_call: 'auto'
const response = await openai.chat.completions.create({
model: 'gpt-3.5.turbo',
message: [ { role: 'user', content: userMessage } ],
functions,
function_call: 'auto' // 让AI决定是否调用函数
})
const message = response.choices[0].message;
// 3. 检查是否调用函数
if(message.function_call) {
// 4. 获取函数调用详情
const functionName = message.function_call.name;
const args = JSON.parse(message.function_call.arguments)
// 5. 函数(工具)调用
if(functionName === 'getWeather') {
const weatherData = await getWeatherApi(args.location);
// 6. 手动总结返回用户(或让ai总结后返回,好处在于ai回复语言更生动)
return `${args.location}的天气:${weatherData.condition},温度${weatherData.temperature}`
}
}
}
示意图如下,与提示词工程的区别只有红色部分
ChatGPT插件
ChatGPT插件是Function Calling发展衍生出来的方向,本质上是借助开源社区丰富ChatGPT客户端的function,打造生态。
基于Function Calling,用户在与openai客户端聊天时,每支持一种工具,都需要openai自己的客户端和服务端进行工具适配工作,为了让适配工作开源给社区,打造生态系统,故推出ChatGPT插件:
- 由第三方提供
- 仅仅服务于ChatGPT的web端(不服务于自己的app)
- 工具执行于非chatGpt的服务端
本质上,ChatGPT插件的核心即提供function calling清单与工具具体的实现(实现的请求地址),例如:
- 创建manifeat.json描述文件,重点关注api.url配置项,指定一个yaml配置文件,文件内包含function calling相关配置
json
{
"schema_version": "v1",
"name_for_human": "天气查询",
"name_for_model": "weather",
"description_for_human": "获取全球天气预报",
"description_for_model": "获取城市天气信息,包括温度、湿度等",
"auth": {
"type": "none"
},
"api": {
"type": "openai",
"url": "https://example.com/openapi.yaml"
},
"logo_url": "https://example.com/logo.png",
"contact_email": "[email protected]"
}
- openapi.yaml如下,创建OpenAPI规范描述。重点关注配置项servers与paths,即具体工具的实现(url地址)
yaml
openapi: 3.0.1
info:
title: 天气查询插件
description: 一个可以获取全球天气预报的API服务
version: v1
servers:
- url: https://weather-api.example.com
paths:
/weather:
get:
operationId: getCurrentWeather
summary: 获取当前天气预报
description_for_model: 获取城市天气信息,包括温度、湿度等
parameters:
- name: city
in: query
description: 城市名称或地区
required: true
schema:
type: string
- name: date
# ...
MCP
MCP是什么?
借用上文在Funciton Call章节提到的让AI查询天气的例子,基于MCP如何实现:functions列表不再写死在接口调用里,请求外部API不再由appServer自身去做,而是把所有工具调用、资源访问相关的事情都交由一个独立的服务器来完成,也就是MCP服务器(这个服务器遵循Model Context Protocol协议进行开发)。MCP服务器可能是appClient,也可能是appServer去跟MCP服务器直接通信。
示意图如下:
理解上述过程,可以总结:基于MCP协议实现的MCP服务器,抽取了ai外部工具调用的逻辑,以客户端为中介与ai服务通信。
Function Call为一切的基石,本质上是让ai能够结构化的输出JSON格式来调用函数,并且几乎所有的大模型都支持Function call接口规范:
scss
Function Call(基石) => ChatGPT插件(OpenAIWeb专用) => MCP协议(通用标准)
MCP就是对Function Call流程规范化:
-
MCP服务器的tools/list接口,提供可调用的工具列表,即提供functions参数
-
MCP服务器的tools/call接口,完成具体的工具的调用
-
resources/list:获取可用资源、resources/read:读取资源内容、prompts/list:获取可用提示等等都是对ai访问外部资源这个流程的动作拆分与规范化实现
-
除了Function Call,MCP还拓展更多的高级功能,如核心三大功能:
-
工具(Tools):让AI能执行具体操作,如发送邮件、查天气、执行命令、调用API,如调用一些公司内网提供的服务,本质上是借助MCP服务器去代理调用
底层使用Function Call实现,与OpenAI格式兼容
-
资源(Resources):给AI提供参考信息,如文件内容,数据库记录、系统状态等
MCP独有,Function Call没有此功能
-
提示(Prompts):预设的对话模版,如快捷命令、标准工作流、指导性提示等
MCP独有,Function Call没有
-