正文
(
'请输入:'
),
"role"
:
"user"
}
]
print
(
"-"
*
60
)
i =
1
first_response = get_response(messages)
assistant_output = first_response[
'choices'
][
0
][
'message'
]
print
(
f"\n第
{i}
轮大模型输出信息:
{first_response}
\n"
)
if
assistant_output[
'content'
]
is
None
:
assistant_output[
'content'
] =
""
messages.append(assistant_output)
if
assistant_output[
'tool_calls'
] ==
None
:
print
(
f"无需调用工具,我可以直接回复:
{assistant_output[
'content'
]}
"
)
return
while
assistant_output[
'tool_calls'
] !=
None
:
if
assistant_output[
'tool_calls'
][
0
][
'function'
][
'name'
] ==
'get_current_weather'
:
tool_info = {
"name"
:
"get_current_weather"
,
"role"
:
"tool"
}
location = json.loads(assistant_output[
'tool_calls'
][
0
][
'function'
][
'arguments'
])[
'location'
]
tool_info[
'content'
] = get_current_weather(location)
elif
assistant_output[
'tool_calls'
][
0
][
'function'
][
'name'
] ==
'get_current_time'
:
tool_info = {
"name"
:
"get_current_time"
,
"role"
:
"tool"
}
tool_info[
'content'
] = get_current_time()
print
(
f"工具输出信息:
{tool_info[
'content'
]}
\n"
)
print
(
"-"
*
60
)
messages.append(tool_info)
assistant_output = get_response(messages)[
'choices'
][
0
][
'message'
]
if
assistant_output[
'content'
]
is
None
:
assistant_output[
'content'
] =
""
messages.append(assistant_output)
i +=
1
print
(
f"第
{i}
轮大模型输出信息:
{assistant_output}
\n"
)
print
(
f"最终答案:
{assistant_output[
'content'
]}
"
)
注意:需要注意的是这里的大模型判断的时候可能会识别到需要多个tools,所以才会需要用到循环,这个也是通过这个进行MCP的Client编写。
从结构、扩展性、性能、可维护性等角度对 Agent + Function Call 与 MCP 进行对比。
2.3.1 结构对比
在结构设计方面,Agent + Function Call 通常采用单体式模式,即大语言模型直接在推理过程中,基于预定义的 tool list,动态判断并调用外部函数。这种方式强调轻量、快速,如 OpenAI 在其 Function Calling 文档中所述,模型在每轮对话中,可以基于工具描述(如 name、description 和 parameters)直接生成调用请求[2]。而 MCP 则采用了严格的 Client-Server 架构,将工具管理、数据上下文提供与模型推理解耦开来。根据 MCP 官方介绍,Host(如 LLM 应用)通过 Client 与 Server 建立连接,Server 统一管理各种工具、数据源和提示词资源[1]。结构上,MCP 更加标准化和模块化,天然适配大型系统的分布式部署与演进需求[6]。
2.3.2 扩展性对比
扩展性是衡量智能体系统可持续发展的重要指标。Agent + Function Call 由于本地 tightly-coupled(紧耦合)工具列表的特性,每增加或修改一个工具,都需同步更新模型侧的工具定义,维护成本较高。不同模型平台(如 OpenAI、Anthropic、通义千问)在 Function Call 支持的格式上也存在差异,跨模型迁移时需要额外适配[7]。相比之下,MCP 在设计上强调工具与模型的解耦。Server 端可独立发布、更新、下线工具,不需要重新训练或重启模型推理链路。MCP 也支持多种数据源(本地文件、数据库、远程 API 等)统一接入[2],极大提升了系统的扩展灵活性和多源融合能力。
这种松耦合设计被认为是未来智能系统发展的必然趋势,并有助于通过统一的访问控制和最小化授权来降低安全风险[8]。
2.3.3 性能对比
在性能方面,Agent + Function Call 因调用链条短(模型直接调用本地或小范围工具函数),在单次任务响应延迟上具有明显优势。特别是在低并发、轻量任务场景下,如简单的天气查询、汇率换算,能够提供极快的响应体验[2][3]。然而,随着任务复杂度提升,特别是涉及多轮调用、复杂工作流编排时,Agent 本地调度可能出现瓶颈。而 MCP 架构虽然引入了 Client-Server 的通信开销,但其 Server 可通过分布式部署、异步处理、负载均衡等手段优化整体性能表现[1]。相关研究也指出,在复杂任务密集型场景下,微服务式架构(如 MCP)在系统稳定性和高可用性方面优于单体式设计[9]。
2.3.4 可维护性对比
系统可维护性直接关系到长周期系统演进与运营成本。Agent + Function Call 由于将工具描述、调用逻辑与模型 tightly bundled,在实际维护中,若工具数量庞大、版本频繁更新,容易导致接口变更混乱,且缺乏统一的调用日志和监控体系[7]。MCP 在这一点上具有显著优势。根据 MCP 官方文档,Client 和 Server 均能独立记录调用日志,支持细粒度的性能监控、故障排查和审计[1]。此外,MCP Server 层可以独立设置访问权限、安全策略,实现数据与工具访问的最小化授权(principle of least privilege)[8]。在企业级应用环境下,MCP 更易满足合规性、审计与安全隔离要求。
针对搬栈 AI 化的业务需求,分别基于 MCP 协议和 Agent + Function Call 两种方式进行了实践探索与效果验证,旨在评估不同方案在多轮任务调度场景下的适配性与应用优势。
本节介绍 MCP(Model Context Protocol)在实际项目中的应用方式与配置过程。
针对搬栈 AI 化的业务需求,进行了 MCP 场景的实施探索。整体采用本地部署方式,严格遵循官方文档指引,并结合实际环境进行了适配与改写,实现了完整的 MCP 接入链路。
通过实践可以明确,基于 MCP 协议的系统搭建主要包含两个关键组成部分:
基于通义模型,具体搭建流程如下:
1.搭建 Client
Client 侧基于标准的 MCP 客户端框架(例如调用 DashScope 等服务),配置 LLM 模型、连接 Server,并在推理过程中实现工具调度与调用链路闭环。
client部分代码--大模型选择tools
client = OpenAI(
api_key=os.getenv("DASHSCOPE_API_KEY"),
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
completion = client.chat.completions.create(
model="qwen-plus",
messages=messages,
tools=self.tools,
)
response = completion.model_dump_json()
print(response)
assistant_output = json.loads(response)['choices'][0]['message']
print(f"assistant_output{assistant_output}")
client部分代码--大模型确定tools后的调用模型
if assistant_output['content']:
final_text.append(assistant_output['content'])
while assistant_output['tool_calls'] != None:
print(f"tool_name{assistant_output['tool_calls']}")
tool_name = assistant_output['tool_calls'][0]['function']['name']
tool_args = assistant_output['tool_calls'][0]['function']['arguments']
tool_args = json.loads(tool_args)
tool_result = await self.session.call_tool(tool_name, tool_args)
final_text.append(
f"[Calling tool {tool_name} with args {tool_args}]")
messages.append({
"role": "assistant",
"content": assistant_output['content'],
"tool_calls": assistant_output['tool_calls']
})
client部分代码--大模型把query+tools信息+大模型回复整合后进行再输出
prompt = "不需要改变原结构,输出原来的结构,除了产品信息,前后都要用中文"
messages.append({
"role": "tool",
"content": tool_result.content[0].text,
"tool_call_id": completion.choices[0].message.tool_calls[0].id,
"prompt":prompt
})
completion = client.chat.completions.create(
model="qwen-plus",
messages=messages
)
assistant_output = completion.model_dump()['choices'][0]['message']
if assistant_output['content'] is None:
assistant_output['content'] = ""
messages.append(assistant_output)
final_text.append(completion.choices[0].message.content)
2.搭建 Server
Server 侧需实现符合 MCP 规范的服务端逻辑,注册可供调用的工具资源。每个工具以标准的 function schema 方式对外暴露,支持参数定义、调用路径和返回格式规范化管理。
tool举例--查询阿里云某个产品对应模块信息
@mcp.tool()
async def descirbe_pricing_modules(owner_id: int = None,
product_code: str = None,
product_type: str = None,
subscription_type: str = None,) -> str:
"""查询阿里云某个产品对应模块信息(DescribePricingModule),product_code 和 subscription_type订阅类型是必选项。"""
await ensure_connected()
def sync_call():
req = bss_models.DescribePricingModuleRequest(
product_code=product_code,
product_type=product_type,
subscription_type=subscription_type
)
runtime = util_models.RuntimeOptions()
return client.describe_pricing_module_with_options(req, runtime)