智能体开发-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

相关推荐
T1mzhou12 小时前
ARM64 Linux 6.10 内核驱动(12):dd.c:probe/ remove、延迟 probe
linux·服务器·c语言·arm开发·arm
Doraemomo13 小时前
IMX6ULL裸机开发——系统主频和时钟配置
arm开发·嵌入式硬件·makefile·imx6ull
T1mzhou16 小时前
ARM64 平台安全学习记录
linux·服务器·arm开发·arm
云栖梦泽18 小时前
网络设备驱动(1)
linux·arm开发·嵌入式硬件
零依赖极客2 天前
Day 9·1 KV 也量化——q8 KV 把缓存与 decode 带宽压到一半
c语言·开发语言·arm开发·人工智能·缓存·矩阵
secondyoung2 天前
I2C通信协议详解
arm开发·驱动开发·stm32·单片机·嵌入式硬件·mcu·51单片机
奔跑的架构师2 天前
[A-50]ARMv9/v8-DVFS系统架构
linux·arm开发·架构·系统架构·arm
零依赖极客3 天前
Day 8·1 自注意力机制:Q·K^T/softmax/V的在线计算
c语言·arm开发·人工智能·llama
T1mzhou3 天前
ARM64 Linux 6.10 内核驱动(14):drivers/base/platform.c:板级设备主战场
linux·c语言·开发语言·arm开发
零依赖极客4 天前
《30 天手搓 ARM 架构零依赖纯 C 推理引擎》课程介绍与大纲
c语言·开发语言·arm开发·人工智能·嵌入式硬件·ai编程