智能体开发-2-MCP

智能体开发-2-MCP

本文介绍MCP,一种server式工具调用方法,适合多智能体多工具开发:

MCP: 让 LLM 像调用远程 API 一样调用工具的标准协议

本文涉及的基础知识包括:

  • 操作系统
  • 计算机网络

1.网络编程

MCP是一种协议,是基于HTTP协议的网络编程技术, 具体如下:

python 复制代码
Client --POST--> /mcp (create session)
Client <======> Server (双向流) , 消息格式是 JSON-RPC

HTTP
 └── streamable-http协议 
     └── JSON-RPC 2.0
         └── tool list / call 

由于建立了session,其可以实现并发操作,即多个client通过网络协议访问server:

1.1 并发单元

要理解并发,需要了解操作系统的几个基本概念:

概念 定义 MCP / Agent 场景例子
进程(Process) 操作系统调度的最小独立运行单元,拥有独立物理内存空间 每启动一个 MCP Server,就有一个进程
线程(Thread) 进程里的执行单元,多个线程共享进程内存,属于进程内调度 MCP Server 可以在内部用线程处理 HTTP 请求
协程(Coroutine) Python 层的轻量执行单元,通过 async/await 调度 MCP Client / Session 用 asyncio 调度协程,单线程多协程
Session MCP 在TCP/HTTP 层面的一次会话,表示客户端和 Server 的一次连接,其不等于进程,也不等于线程 ClientSession 管理一个到 MCP Server 的连接(读写通道)

总结:

层次 MCP Server Session Thread Coroutine
归属 OS 进程 Server & Client 的逻辑关系 进程内部 线程内部
数量 1 个 / 多进程可扩展 多个 1~N 多个
并发 多进程并行 async 并发 CPU 并行 协作式并发
内存 独立 共用进程内存 共用进程内存 共用线程栈

举例:一个 MCP Server

  • 通常是 一个进程
  • 内部会开多个线程Thread(处理 HTTP / Streamable-HTTP)
  • 处理多个客户端连接session

1.2 异步编程 (Asynchronous Programming)

程序需要等待网络请求、数据库查询或文件读写时,异步编程允许程序利用这段等待时间去处理其他任务,而不是停在那里。

Python实现异步编程需要三个关键字:async / await / asyncio

  • asyncio: 调度器(单线程内的多协程并发,即io并发,通过事件循环Event Loop管理调度)
  • async: 协程函数声明 (Coroutine),表示该函数存在被挂起的操作,通常是有耗时的等待操作。
  • await: 是等待声明,只能在async函数内部使用,用于声明较为耗时的函数(如网络请求),程序先暂停在这个位置,把控制权交还给 asyncio,等函数结果出来,再回到这里继续往下执行。

2. MCP交互方式

整个交互的过程,tool与llm都是通过http协议完成的:

javascript 复制代码
┌───────────────────────┐
1.创建 llm (ChatOpenAI) 					   
2.创建 client (与server的链接session )
└─────────┬─────────────┘
					│
					▼
┌───────────────────────┐
3.从client 获取 tools (await)
4.将 tools 信息提供给 LLM 以创建 agent
└─────────┬─────────────┘
					│
					▼
┌────────────────────┐
5. agent通过 await ainvoke(), 收到 prompt
6. LLM 内部 reasoning: 判断是否使用工具
└─────────┬──────────┘
          │
          ▼
┌────────────────────┐
7.LLM (ChatOpenAI) 根据 prompt + 已知 tools 描述进行推理
8.得到 Tool Decision (tool_call JSON)   
└─────────┬──────────┘
          │ 
          ▼
┌────────────────────┐
9.将tool_call (JSON)转化为 StructuredTool (MCP Adapter) 
10. HTTP POST将 StructuredTool 传递至 /mcp,
└─────────┬──────────┘
          │
          ▼
┌─────────────────────────────┐
11. MCP Server 完成工具解析,包括:
	- 从 注册表(tool registry) 找到对应的工具对象
  - 用schema验证参数合法性   
12. MCP Server 根据 tool_name 找到对应的函数引用
  - 通过注册表里每个工具通常绑定一个 Python函数 (或者一个 外部 API 调用)
  - 通过 Python 调用异步函数,同事传入参数
└─────────┬───────────────────┘
          │
          ▼
┌────────────────────┐
13. MCP Server 收到 函数的 Return,将其封装成标准 JSON 返回给 Agent
14.  Agent / LLM 根据Return 完成后续 reasoning
└───────── ──────────┘

3.MCP执行步骤

3.1 工具定义

python 复制代码
@mcp.tool()
def download_stock_price(...):
    ...
  • 函数被注册为 MCP Tool
  • 自动生成 JSON Schema
  • 工具被挂到 MCP Server 的 /mcp endpoint

3.2 服务器启动

python 复制代码
mcp.run(transport="streamable_http", port=8000)
# POST http://localhost:8000/mcp
  • 列出工具(schema)
  • 接收 tool_call
  • 返回 tool_result

3.3 MCP Client 连接 Server(Agent 端)

py 复制代码
client = MultiServerMCPClient(mcp_config)
tools = await client.get_tools()
  • HTTP 请求 /mcp
    → initialize,建立sse_client()
    → 保存 session_id
    → list_tools
  • 拉取 tool schema
  • 把 MCP tool → 转成 StructuredTool

3.4 Tool 变成 LLM 可理解的能力

  • langchain

    Python function

    JSON Schema

    StructuredTool

    tool description

最终 LLM "看到"的是类似:

json 复制代码
[
  StructuredTool
  (
    name='read_url', 
    description='Read and return text content from a web page.', 
    args_schema={'properties': {'url': {'type': 'string'}, 
                                'max_chars': {'default': 1500, 'type': 'integer'}}, 
                 'required': ['url'], 'type': 'object'}, 
    metadata={'_meta': {'_fastmcp': {'tags': []}}}, 
    response_format='content_and_artifact', 
    coroutine=<function convert_mcp_tool_to_langchain_tool.<locals>.call_tool at 0x116b56c20>), 
  
  StructuredTool(
    name='analyze_csv', 
    description='Analyze a local CSV file.',
    args_schema={'properties': {'file_path': {'type': 'string'}, 
                                'max_rows': {'default': 5, 'type': 'integer'}}, 
                 'required': ['file_path'], 'type': 'object'}, 
    metadata={'_meta': {'_fastmcp': {'tags': []}}}, 
    response_format='content_and_artifact', 
    coroutine=<function convert_mcp_tool_to_langchain_tool.<locals>.call_tool at 0x116b1f400>), 
  
  StructuredTool
  (
    name='download_stock_price', 
    description="Download last N trading days of stock price using Tushare,\nsave to CSV in specified folder with specified file name.\n\nParameters:\n- Ashare_code: Stock code, e.g., '600519.SH'\n- end_date: End date in 'YYYYMMDD', e.g., '20251217'\n- days: Number of trading days to download\n- file_path: Folder to save CSV, default './data'\n- file_name: CSV file name, e.g., '600519.csv'\n\nReturns:\n- str: Saved file path or error message", 
    args_schema={'properties': {'Ashare_code': {'type': 'string'}, 
                                'end_date': {'type': 'string'}, 
                                'days': {'default': 10, 'type': 'integer'}, 
                                'file_path': {'default': 'data', 'type': 'string'}, 
                                'file_name': {'default': 'stock_data.csv', 'type': 'string'}, 
                                'TuShare_API': {'default': 'xxx', 'type': 'string'}}, 
                 'required': ['Ashare_code', 'end_date'], 'type': 'object'}, 
    metadata={'_meta': {'_fastmcp': {'tags': []}}}, 
    response_format='content_and_artifact', 
    coroutine=<function convert_mcp_tool_to_langchain_tool.<locals>.call_tool at 0x116b1f370>)]

3.5 Agent 推理

复制代码
result = await agent.ainvoke({"messages": [...]})
  • "我能直接回答吗?"

  • "不行,需要下载股票数据"

  • "我有一个叫 download_stock_price 的 tool"

3.6 调用工具

agent会输出调用工具所需 tool_call

复制代码
{
  "name": "download_stock_price",
  "arguments": {
    "ts_code": "600519.SH",
    "end_date": "20251217",
    "days": 20
  }
}

3.7 MCP Client → MCP Server 执行工具

  • 通过 MCP Client会将tool_call送到服务器

    StructuredTool

    HTTP POST

    /mcp

  • MCP Server 做:

    接收 tool_call

    调用 Python 函数

    执行 IO / API / 文件写入

3.8 Tool 返回结果

服务器将结果返回给 Agent

"Data saved to data/600519.SH_20251217.csv"

Agent把结果作为 tool_message, 注入对话上下文, 返回给LLM推理

最终将推理结果返回给用户

4. 代码案例

本文提供1个上述的代码案例,

4.1 启动服务器

首先需要在命令行运行server:

sudo python tools_server.py

运行成功后如图:

4.2 启动客服端

再开一个命令行终端,运行:

python mcp_client.py

此时开始MCP交互, 服务器终端显示交互信息如下:

4.3 智能体执行

我们设置如下Prompt:

复制代码
    prompt = """
    有三个任务:
    1. 用100字的内容总结网页: https://finance.eastmoney.com/a/202512173594061460.html
    2. 用100字的分析CSV file: ./data/daily_prices_sse_50.csv
    3. 下载20251217之前20天的股票数据到当前路径的data文件夹,股票代码600519.SH,保存文件命名为: "{股票代码}_{最后日期}.CSV"
    """

正确运行时,智能体会执行工具调用,并通过jsonl格式返回mcp交互信息,返回的具体内容如下:

json 复制代码
===== FINAL OUTPUT =====

{'messages': [

HumanMessage(
		content='\n    
						有三个任务:\n    
						1. 用100字的内容总结网页: https://finance.eastmoney.com/a/202512173594061460.html\n    
						2. 用100字的分析CSV file: ./data/daily_prices_sse_50.csv\n    
						3. 下载20251217之前20天的股票数据到当前路径的data文件夹,股票代码600519.SH,保存文件命名为: "{股票代码}_{最后日期}.CSV"\n    ', 		additional_kwargs={}, 
		response_metadata={}, 
		id='8e7bc69b-d5f2-400d-becc-bafcedd597c8'), 
		
AIMessage(
	content='\n我来帮您完成这三个任务。\n', 
	additional_kwargs={'refusal': None}, 
	response_metadata={
				'token_usage': {'completion_tokens': 515, 'prompt_tokens': 653, 'total_tokens': 1168, 
				'completion_tokens_details': None, 
				'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 43}}, 
				'model_provider': 'openai', 
				'model_name': 'glm-4.5-air', 
				'system_fingerprint': None, 
				'id': '202512261309470b33d315004c4aa0', 
				'finish_reason': 'tool_calls', 
				'logprobs': None}, 
	id='lc_run--019b5910-1e84-7f52-897b-957c39208cc1-0', 
	tool_calls=[
         {'name': 'read_url', 
          'args': {'url': 'https://finance.eastmoney.com/a/202512173594061460.html'}, 
          'id': 'call_-8035953936850336800', 
          'type': 'tool_call'}, 
         {'name': 'analyze_csv', 
          'args': {'file_path': './data/daily_prices_sse_50.csv'}, 
          'id': 'call_-8035953936850336799', 
          'type': 'tool_call'}, 
         {'name': 'download_stock_price', 
          'args': {'Ashare_code': '600519.SH', 'end_date': '20251217', 'days': 20, 'file_path': 'data', 'file_name': '600519_20251217.CSV'}, 
          'id': 'call_-8035953936850336798', 
          'type': 'tool_call'}
				 ], 
	usage_metadata={
				 	'input_tokens': 653, 
				 	'output_tokens': 515, 
				 	'total_tokens': 1168, 
				 	'input_token_details': {'cache_read': 43}, 
				 	'output_token_details': {}}), 
				 	
ToolMessage(
		content='\r \r <!DOCTYPE html>\r <!--published at 2025/12/26 13:10:03 by finance.eastmoney.com server-xml ZP NEWS 163-->\r <html lang="en">\r <head>\r     <meta charset="UTF-8">\r         <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />\r     <meta name="renderer" content="webkit" />\r     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />\r     <meta name="viewport" content="width=device-width, initial-scale=1.0">\r     <meta name="mobile-agent" content="format=html5; url=https://wap.eastmoney.com/a/202512173594061460.html">\r         <title>中一签36万!沐曦股份科创板上市 成近十年最赚钱新股 _ 东方财富网</title>\r         <meta name="keywords" content="沐曦股份,摩尔线程,盘中,600,733,科创板,新股,上市,赚钱,公司" />\r         <meta name="description" content="【中一签36万!沐曦股份科创板上市 成近十年最赚钱新股】自2014年初新股恢复发行以来累计上市了超2900只新股,沐曦股份凭借36万元的单签盈利成为期间最赚钱新股。" />\r     <meta name="referrer" content="always">\r     <style type="text/css">\r         .em_xuangu{display:block !important;}\r     </style>\r     <script type="text/javascript">\r         var __allow_likes_state= "0";\r         var __IsBeforeLoad = false;\r         var __WAPURL = "https://wap.eastmoney.com/a/202512173594061460.html";\r         var _NewsId = \'202512173594061460\';\r         var _us_zixun_Id = \'202512173594061460\';\r         var __VideoAdvSwitch = \'0\';\r         var _HideAdID = "202211302575026175,202211302575032853,202211302575017963,202212012576416386";\r         var _CMSHJ = \'prod\';\r         var _YM = \'finance\';\r         var _NewsTag = \'\';\r         var _ISComment = true;\r', 
		name='read_url', 
		id='f6206cc6-57da-44a4-90ac-c58bb7b0c647', 
		tool_call_id='call_-8035953936850336800'), 
		
ToolMessage(
		content="Shape: (11568, 11)\nColumns: ['ts_code', 'trade_date', 'open', 'high', 'low', 'close', 'pre_close', 'change', 'pct_chg', 'vol', 'amount']\n\nHead:\n  ts_code  trade_date  open  high   low  close  pre_close  change  pct_chg        vol      amount\n600028.SH    20250102  6.67  6.73  6.52   6.56       6.68   -0.12  -1.7964 1719786.77 1136783.089\n600030.SH    20250102 28.98 29.00 27.17  27.45      29.17   -1.72  -5.8965 2828487.33 7898902.462\n600031.SH    20250102 16.48 16.48 15.69  15.77      16.48   -0.71  -4.3083  853894.28 1368558.133\n600036.SH    20250102 39.35 39.50 38.34  38.51      39.30   -0.79  -2.0102  642000.70 2493694.677\n600048.SH    20250102  8.84  8.98  8.61   8.68       8.86   -0.18  -2.0316 1273310.73 1121639.098", 
		name='analyze_csv', 
		id='6f8ec1af-ddd0-4bcf-a8ac-ba203fe2a100', 
		tool_call_id='call_-8035953936850336799'), 
		
ToolMessage(
		content='Data saved to data/600519_20251217.CSV', 
		name='download_stock_price', 
		id='ba7a1312-c282-4296-b305-f18b7911ac07', 
		tool_call_id='call_-8035953936850336798'), 
		
AIMessage(
	content='\n', 
	additional_kwargs={'refusal': None}, 
	response_metadata={'token_usage': {
												'completion_tokens': 196, 
												'prompt_tokens': 1732, 
												'total_tokens': 1928, 
												'completion_tokens_details': None, 
												'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 655}}, 
												'model_provider': 'openai', 
												'model_name': 'glm-4.5-air', 
												'system_fingerprint': None, 
												'id': '20251226131004173b69a11b294d50', 
												'finish_reason': 'tool_calls', 'logprobs': None}, 
												id='lc_run--019b5910-5f82-7be1-9a0b-966c790db26a-0', 
												tool_calls=[
													{'name': 'read_url', 
													 'args': {'url': 'https://finance.eastmoney.com/a/202512173594061460.html', 'max_chars': 3000}, 
													 'id': 'call_-8035955242520293276', 
													 'type': 'tool_call'}], 
													 usage_metadata={'input_tokens': 1732, 
													 								 'output_tokens': 196, 
													 								 'total_tokens': 1928, 
													 								 'input_token_details': {'cache_read': 655}, 
													 								 'output_token_details': {}}), 
ToolMessage(
	content='\r \r <!DOCTYPE html>\r <!--published at 2025/12/26 13:10:03 by finance.eastmoney.com server-xml ZP NEWS 163-->\r <html lang="en">\r <head>\r     <meta charset="UTF-8">\r         <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />\r     <meta name="renderer" content="webkit" />\r     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />\r     <meta name="viewport" content="width=device-width, initial-scale=1.0">\r     <meta name="mobile-agent" content="format=html5; url=https://wap.eastmoney.com/a/202512173594061460.html">\r         <title>中一签36万!沐曦股份科创板上市 成近十年最赚钱新股 _ 东方财富网</title>\r         <meta name="keywords" content="沐曦股份,摩尔线程,盘中,600,733,科创板,新股,上市,赚钱,公司" />\r         <meta name="description" content="【中一签36万!沐曦股份科创板上市 成近十年最赚钱新股】自2014年初新股恢复发行以来累计上市了超2900只新股,沐曦股份凭借36万元的单签盈利成为期间最赚钱新股。" />\r     <meta name="referrer" content="always">\r     <style type="text/css">\r         .em_xuangu{display:block !important;}\r     </style>\r     <script type="text/javascript">\r         var __allow_likes_state= "0";\r         var __IsBeforeLoad = false;\r         var __WAPURL = "https://wap.eastmoney.com/a/202512173594061460.html";\r         var _NewsId = \'202512173594061460\';\r         var _us_zixun_Id = \'202512173594061460\';\r         var __VideoAdvSwitch = \'0\';\r         var _HideAdID = "202211302575026175,202211302575032853,202211302575017963,202212012576416386";\r         var _CMSHJ = \'prod\';\r         var _YM = \'finance\';\r         var _NewsTag = \'\';\r         var _ISComment = true;\r         function getQueryString(name) {\r             var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");\r             var r = window.location.search.substr(1).match(reg);\r             if (r != null) return unescape(r[2]);\r             return null;\r         }\r         function isMobile() {\r             try {\r                 if(getQueryString("has_jump_to_web") == "true"){\r                     return false;//需要展示web,不做后面的wap端验证\r                 }\r             } catch (err) { }\r \r             var ua = navigator.userAgent.toLowerCase();\r             var res = false;\r             var ipad = ua.match(/(ipad).*os\\s([\\d_]+)/),\r                 isIphone = !ipad && ua.match(/(iphone)/),\r                 isAndroid = ua.match(/(android)/) && ua.match(/(mobile)/),\r                 isAndroidHarmonyOS = ua.match(/(android)/) && ua.match(/(harmonyos)/),\r                 isOpenHarmony = ua.match(/(openharmony)/) && ua.match(/(mobile)/),\r                 isHuaWeiWeChat = navigator.userAgent.indexOf(\'MicroMessenger\') > -1 && navigator.userAgent.indexOf(\'HUAWEI\') > -1 && screen.width < screen.height,\r                 isMobile = isIphone || isAndroid || isAndroidHarmonyOS || isOpenHarmony || isHuaWeiWeChat;\r             if (isMobile) {\r                 res = true;\r             } else {\r                 res = false;\r             }\r             return res;\r         }\r         if (isMobile()) {\r             location.href = __WAPURL;\r         }\r     </script>\r     <link rel="stylesheet" hr', 
	name='read_url', 
	id='cebdce85-ec98-4de2-a630-bd5ecaaab8f1', 
	tool_call_id='call_-8035955242520293276'), 
		
AIMessage(
	content='\n', 
	additional_kwargs={'refusal': None}, 
	response_metadata={'token_usage': {'completion_tokens': 76, 'prompt_tokens': 2704, 'total_tokens': 2780, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 44}}, 
	'model_provider': 'openai', 'model_name': 'glm-4.5-air', 
	'system_fingerprint': None, 
	'id': '20251226131010135e81e3d084445d', 
	'finish_reason': 'tool_calls', 
	'logprobs': None}, 
	id='lc_run--019b5910-76cd-71d3-8a0e-14bb90d4acdb-0', 
	tool_calls=[{
			'name': 'read_url', 
			'args': {'url': 'https://finance.eastmoney.com/a/202512173594061460.html', 'max_chars': 5000}, 
			'id': 'call_-8035886179444499478', 
			'type': 'tool_call'}], 
	usage_metadata={'input_tokens': 2704, 
									'output_tokens': 76, 
									'total_tokens': 2780, 
									'input_token_details': {'cache_read': 44}, 
									'output_token_details': {}}), 

ToolMessage(
	content='\r \r <!DOCTYPE html>\r <!--published at 2025/12/26 13:10:03 by finance.eastmoney.com server-xml ZP NEWS 163-->\r <html lang="en">\r <head>\r     <meta charset="UTF-8">\r         <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />\r     <meta name="renderer" content="webkit" />\r     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />\r     <meta name="viewport" content="width=device-width, initial-scale=1.0">\r     <meta name="mobile-agent" content="format=html5; url=https://wap.eastmoney.com/a/202512173594061460.html">\r         <title>中一签36万!沐曦股份科创板上市 成近十年最赚钱新股 _ 东方财富网</title>\r         <meta name="keywords" content="沐曦股份,摩尔线程,盘中,600,733,科创板,新股,上市,赚钱,公司" />\r         <meta name="description" content="【中一签36万!沐曦股份科创板上市 成近十年最赚钱新股】自2014年初新股恢复发行以来累计上市了超2900只新股,沐曦股份凭借36万元的单签盈利成为期间最赚钱新股。" />\r     <meta name="referrer" content="always">\r     <style type="text/css">\r         .em_xuangu{display:block !important;}\r     </style>\r     <script type="text/javascript">\r         var __allow_likes_state= "0";\r         var __IsBeforeLoad = false;\r         var __WAPURL = "https://wap.eastmoney.com/a/202512173594061460.html";\r         var _NewsId = \'202512173594061460\';\r         var _us_zixun_Id = \'202512173594061460\';\r         var __VideoAdvSwitch = \'0\';\r         var _HideAdID = "202211302575026175,202211302575032853,202211302575017963,202212012576416386";\r         var _CMSHJ = \'prod\';\r         var _YM = \'finance\';\r         var _NewsTag = \'\';\r         var _ISComment = true;\r         function getQueryString(name) {\r             var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");\r             var r = window.location.search.substr(1).match(reg);\r             if (r != null) return unescape(r[2]);\r             return null;\r         }\r         function isMobile() {\r             try {\r                 if(getQueryString("has_jump_to_web") == "true"){\r                     return false;//需要展示web,不做后面的wap端验证\r                 }\r             } catch (err) { }\r \r             var ua = navigator.userAgent.toLowerCase();\r             var res = false;\r             var ipad = ua.match(/(ipad).*os\\s([\\d_]+)/),\r                 isIphone = !ipad && ua.match(/(iphone)/),\r                 isAndroid = ua.match(/(android)/) && ua.match(/(mobile)/),\r                 isAndroidHarmonyOS = ua.match(/(android)/) && ua.match(/(harmonyos)/),\r                 isOpenHarmony = ua.match(/(openharmony)/) && ua.match(/(mobile)/),\r                 isHuaWeiWeChat = navigator.userAgent.indexOf(\'MicroMessenger\') > -1 && navigator.userAgent.indexOf(\'HUAWEI\') > -1 && screen.width < screen.height,\r                 isMobile = isIphone || isAndroid || isAndroidHarmonyOS || isOpenHarmony || isHuaWeiWeChat;\r             if (isMobile) {\r                 res = true;\r             } else {\r                 res = false;\r             }\r             return res;\r         }\r         if (isMobile()) {\r             location.href = __WAPURL;\r         }\r     </script>\r     <link rel="stylesheet" href="emres/css/unitynews.css?v=2025.12.26.13.04.19">\r     <style type="text/css">.hotbox .hotnewsbox {width: calc(100% - 80px) !important;}.emshare2020_weixin_popup {display: none !important;}\r     </style>\r     <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />\r     <base target="_blank" />\r </head>\r <body style="background-color:#fff;width:1000px;margin:33px auto 0;">\r     <div class="main">\r         <!-- 头部 -->\r         <div class="headwrap">\r             \r \r <!-- 全局导航 -->\r <div class="globalNav">\r     <ul>\r                             <li class="first ">\r                                 <a target="_blank" href="http://finance.eastmoney.com/">财经</a>\r                             </li>\r                             <li class="">\r                                 <a target="_blank" href="http://finance.eastmoney.com/yaowen.html">焦点</a>\r                             </li>\r                             <li class="">\r                                 <a target="_blank" href="http://stock.eastmoney.com/">股票</a>\r                             </li>\r                             <li class="red">\r                                 <a target="_blank" href="http://stock.eastmoney.com/newstock.html">新股</a>\r                             </li>\r                             <li class="">\r                                 <a target="_blank" href="http://stock.eastmoney.com/gzqh.html">期指</a>\r                             </li>\r                             <li class="">\r                                 <a target="_blank" href="http://option.eastmoney.com/">期权</a>\r                             </li>\r                             <li class="red">\r                                 <a target="_blank" href="http://quote.eastmoney.com/flash/sz300059.html">行情</a>\r                             </li>\r                             <li class="">\r                                 <a target="_blank" href="http://data.eastmoney.com/">数据</a>\r                             </li>\r                       ', 
	name='read_url', 
	id='3b965c9d-ec7d-4285-8724-6cef543fe5c9',
  tool_call_id='call_-8035886179444499478'), 
	
AIMessage(
	content='\n根据三个任务的结果,我来为您完成总结:\n\n## 
							1. 网页总结(100字)\n沐曦股份科创板上市成为近十年最赚钱新股,单签盈利达36万元。自2014年初新股恢复发行以来,累计上市超2900只新股,沐曦股份凭借这一盈利表现创下纪录,成为期间盈利最高的新股,体现了科创板的投资价值。\n\n## 
							2. CSV文件分析(100字)\n该CSV文件包含上证50指数成分股的日度交易数据,共11568条记录,涵盖11个字段:股票代码、交易日期、开盘价、最高价、最低价、收盘价、前收盘价、涨跌额、涨跌幅、成交量、成交额。数据时间跨度较长,为分析上证50成分股的历史表现提供了全面的数据支持。\n\n## 
							3. 股票数据下载\n已成功下载600519.SH(贵州茅台)20251217之前20天的股票数据,保存至data/600519_20251217.CSV文件。', 
	additional_kwargs={'refusal': None}, 
	response_metadata={
										'token_usage': {'completion_tokens': 553, 
																		'prompt_tokens': 4145, 
											 							'total_tokens': 4698, 
											 							'completion_tokens_details': None, 
											 							'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 40}}, 
										 'model_provider': 'openai', 
										 'model_name': 'glm-4.5-air', 
										 'system_fingerprint': None, 
										 'id': '20251226131012b0306e0a295c4704', 
										 'finish_reason': 'stop', 
										 'logprobs': None
										 }, 
	id='lc_run--019b5910-7f5c-7141-91e3-58b9d69dd48f-0', 
	usage_metadata={'input_tokens': 4145, 
									'output_tokens': 553, 
									'total_tokens': 4698, 
									'input_token_details': {'cache_read': 40}, 
									'output_token_details': {}})
]}

以上信息大致过程如下:

复制代码
1.HumanMessage: 给出 3 个任务。

2.AIMessage (Round 1): 启动 3 个工具(读URL、分析CSV、下载股票)。

3.Tool ToolMessage Output: 3 个工具都返回了结果。 此时,CSV 和 下载任务已经完成了。但是 URL 任务返回的结果 AI 不满意。

4.AIMessage (Round 2): 再次请求 read_url (参数调整为 3000字)。

5. Tool ToolMessage Output: 返回结果。

6. AIMessage (Round 3): 再次请求 read_url (参数调整为 5000字)。

7. Tool ToolMessage Output: 返回结果。

8. AIMessage (Final): 拿到所有满意的结果,汇总输出最终答案。

5.本文代码

本文代码参见:https://github.com/disanda/Agent_Development

相关推荐
黑猫学长呀12 小时前
【嵌入式系统科普】第2篇:什么是uboot/kernel/根文件系统/BootLoader/操作系统/bios/设备树
linux·arm开发·单片机·嵌入式硬件·arm
风之子npu13 小时前
AXI 原子访问
arm开发·笔记·学习
番茄灭世神1 天前
使用VScode开发ARM核芯片通用配置
arm开发·vscode·mcu·cmake·clangd·llvm·ninja
ArrebolJiuZhou1 天前
arm指令集(一)
linux·运维·arm开发
切糕师学AI1 天前
ARM 汇编指令:UBFX
汇编·arm开发
ShiMetaPi2 天前
GM-3568JHF丨ARM+FPGA异构开发板系列教程:外设教程 07 音频
arm开发·fpga开发·音视频·fpga·rk3568
切糕师学AI2 天前
ARM 汇编指令:STP\LDP
汇编·arm开发
管理大亨2 天前
Linux vs Windows:五大维度深度对决
linux·arm开发·windows
XXYBMOOO2 天前
理解 C++ 中的字节序转换函数 `swapEndian`
开发语言·arm开发·c++