智能体开发1-智能体工具调用
智能体开发1-智能体工具调用
本教程先简要介绍智能体开发,在通过一个代码,实现智能体自动调用3个工具:
- 1.智能体根据需要自动读取网页数据并总结
- 2.智能体可以读取本地表格数据并总结
- 3.智能体会自己调用api读取股价数据并保存到本地
本文具体代码和数据在:https://github.com/disanda/Agent_Development
1.什么是智能体开发?
智能体开发是大模型应用的框架技术,从IT发展看技术变迁:
- 互联网技术:java web
- 智能手机技术(移动互联网):安卓系统
- AI人工智能:大模型-智能体
这也伴随着开发语言的变迁(JAVA->Python),以及开发工具的变化(IDE -> 命令行脚本)
本教程通过金融数据为载体,介绍智能体开发技术,主要有两个,这里上官方原文介绍(英文):
1.1 Langchain
LangChain is a framework for building agents and LLM-powered applications.
It helps you chain together interoperable components and third-party integrations to simplify AI application development
– all while future-proofing decisions as the underlying technology evolves.
大意是通过各种创建各种组件,将LLM包装为智能体,以完成复杂任务
1.2 MCP (Model Context Protocol)
MCP (Model Context Protocol) is an open-source standard for connecting AI applications to external systems.
Using MCP, AI applications like Claude or ChatGPT can connect to:
- data sources (e.g. local files, databases),
- tools (e.g. search engines, calculators)
- workflows (e.g. specialized prompts)
—enabling them to access key information and perform tasks.
Think of MCP like a USB-C port for AI applications. Just as USB-C provides a standardized way to connect electronic devices, MCP provides a standardized way to connect AI applications to external systems.
大意是 将LLM与数据(文件)、工具(函数)、工作流(通过提示词) 三大要素建立链接,使得大模型更容易使用(即成为智能体)
2.调用工具(函数)
工具有两种方式:
- tool:LangChain 框架原生的、传统的定义工具的方式
- mcp.tool: 一套独立于框架的MCP通信协议
具体区别如下:
| 特性 | LangChain @tool | MCP (Model Context Protocol) |
|---|---|---|
| 本质 | 一个 Python 装饰器,将函数包装成 LangChain 对象。 | 一套标准化的 客户端-服务器 (Client-Server) 协议。 |
| 运行位置 | 运行在你的 LangChain 应用进程内部。 | 通常运行在独立的 MCP Server 进程中。 |
| 通用性 | 只能在 LangChain 框架内直接使用。 | 可以在 Claude Desktop、LangChain、LlamaIndex 等任何支持 MCP 的客户端使用。 |
| 连接方式 | 直接代码调用。 | 以 HTTP 端口监听,通过 JSON-RPC 进行服务器跨进程通信。 |
2.1 调用方式
2 种工具调用的方式transport:
服务器(http端口监听): LLM ↔ JSON-RPC ↔ Server ↔ Tool
Direct Tool (langchain): LLM ↔ Python Function
2.2 代码实现
通过函数实现,需要
- 装饰器修饰 (Decorator)
- 变量类型提示 (Type Hints)
- 文档字描述字符串(Docstrings)
2.2.1 装饰器修饰
装饰器(Decorator)是面向对象编程(OOP)的一个概念:
在不修改原代码的情况下,给函数 / 方法 / 类 添加额外功能
这就避免通过继承来扩展功能,由于继承是静态的(在编译时决定),而装饰器是动态的(在运行时包装),这样会比继承更灵活。
装饰器本质是一个创建一个接收函数,接收需要成为工具的函数,并返回新函数(tool化的函数)
- langchain实现
fromlangchain.toolsimporttool@tooldeffunction(prm1:type1,…)->return_type:“””Description “”” …return- mcp实现
fromfastmcpimportFastMCP mcp=FastMCP("TradeTools")@mcp.tool()defbuy(prm1:type1,…)->eturn_type:“”” Description “””2.2.2 变量类型提示
包括参数类型和返回值类型检查(Type Hints),
其是Python 增强提案(Python Enhancement Proposals),PEP 484的一部分,是一个标准化规定。
具体如下:
| 提案 | 角色 | 贡献 |
|---|---|---|
| PEP 3107 (2006年) | 语法提供者 | 引入了函数注解的语法(即允许你写 : str 和 -> str),但当时官方并没有规定这些注解该怎么用,它们只是存储在annotations里的元数据。 |
| PEP 484 (2014年) | 标准制定者 | 正式引入了 Type Hints(类型提示)的概念。它规定了如何利用 PEP 3107 的语法进行静态类型检查,并引入了 typing 模块(如 List, Dict, Any)。 |
2.2.3 函数描述
其在PEP 257提出,专门针对 Docstrings 的语义和结构制定的标准,规定:
- 位置:必须在函数定义后的第一行。
- 格式:使用三引号 “”“内容”“”。
- 结构:一行描述应该是简短摘要(以句号结尾),多行则是详细说明,则在摘要后空一行再写。
3.测试代码
本例实现一个金融案例,假设大模型是一个会开发的金融工程师,以LangChain Tool实现以下三个工具:
read_url: 根据提示词中所需访问的网址,读取网址内容
analyze_csv:根据提示词中所需访问的csv文件,读取里面的数据
download_stock_price:根据提示词中的股票代码等信息,自动调取api下载相关股票数据,并保存到本地
3.1 函数实现
- read_url
# ========================= Tool 1: URL 内容读取 =========================@tooldefread_url(url:str,max_chars:int=1500)->str:"""Read and return text content from a web page."""r=requests.get(url,timeout=10)r.raise_for_status()text=r.text.replace("\n"," ")returntext[:max_chars]- analyze_csv
# ========================= Tool 2: CSV 分析 =========================@tooldefanalyze_csv(file_path:str,max_rows:int=5)->str:"""Analyze a local CSV file."""ifnotos.path.exists(file_path):returnf"File not found:{file_path}"df=pd.read_csv(file_path)return(f"Shape:{df.shape}\n"f"Columns:{list(df.columns)}\n\n"f"Head:\n{df.head(max_rows).to_string(index=False)}")- download_stock_price
# ========================= Tool 3: tushare 行情 =========================@tooldefdownload_stock_price(Ashare_code:str,end_date:str,days:int=10,file_path:str="data",file_name:str="stock_data.csv")->str:""" Download last N trading days of stock price using Tushare, save to CSV in specified folder with specified file name. Parameters: - Ashare_code: Stock code, e.g., '600519.SH' - end_date: End date in 'YYYYMMDD', e.g., '20251217' - days: Number of trading days to download - file_path: Folder to save CSV, default './data' - file_name: CSV file name, e.g., '600519.csv' Returns: - str: Saved file path or error message """ifnotTuShare_API:return"TUSHARE_TOKEN not set."# 初始化 Tusharets.set_token(TuShare_API)pro=ts.pro_api()# 下载数据try:df=pro.daily(ts_code=Ashare_code,end_date=end_date,limit=days)exceptExceptionase:returnf"Error downloading data:{e}"ifdf.empty:return"No data returned."# 按交易日期排序df=df.sort_values("trade_date")# 只保留指定列df=df[["trade_date","open","high","low","close","vol"]]# 创建保存目录os.makedirs(file_path,exist_ok=True)save_path=os.path.join(file_path,file_name)try:df.to_csv(save_path,index=False)exceptExceptionase:returnf"Error saving file:{e}"returnf"Data saved to{save_path}"3.2 运行方式
通过main函数执行:
- 创建llm对象
- 用llm对象创建agent
- 定义prompt,并送进agent执行等待输出
# ========================= Agent 初始化 =========================defmain():llm=ChatOpenAI(model="glm-4.5-air",api_key=OPENAI_API_KEY,base_url=OPENAI_API_BASE,temperature=0,)agent=create_agent(tools=[read_url,analyze_csv,download_stock_price],model=llm,system_prompt="你是一个会编程的金融分析专家,在必要的时候可以使用为你提供的tools",)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" """result=agent.invoke({"messages":[{"role":"user","content":prompt}]})print("\n===== FINAL OUTPUT =====\n")print(result)if__name__=="__main__":main()4. 模型输出结果分析
LangChain Agent 将执行结果以json字段的形式返回输出,
其输出包含一个完整的 Agent 执行轨迹(Execution Trace),
每次执行包含一类消息,是json字典的key。
4.1 消息类别
消息有三类:
| 类名 | 角色 | 信息含义 |
|---|---|---|
| HumanMessage | 用户 | 用户的原始指令或输入。 |
| AIMessage | AI 智能体(用llm构造) | AI 的思考、文本回复或发出的工具调用请求。 |
| ToolMessage | 工具/系统 | 工具执行后的返回结果。 |
4.2 HumanMessage
content: 消息的实际文本内容。如果是 ToolMessage,这就是工具输出的数据。
id: 消息在 LangChain 追踪系统中的唯一标识符。
response_metadata: 存放模型厂商返回的原始信息(如 Token 消耗、模型名称、停止原因、扩展参数如多模态函数调用等)。
usage_metadata: LangChain 统一封装后的 Token 统计,方便跨模型对比。
4.3 AIMessage
包含一些关键的非文本字段,这是 Agent 运行的核心,可分为以下四个部分:
4.3.1 文本反馈层 (User Interaction)
content:这是模型生成的直接对话文本。由于接下来要调用工具,它通常比较简短,起到承上启下的作用。
additional_kwargs:这是厂商特定的额外参数。下文案例中 “refusal: None” 表示模型没有拒绝回答你的问题(未触犯安全策略)。
4.3.2 模型元数据层 (Response Metadata)
包含以下字段:
additional_kwargs
response_metadata
- token_usage’,
- model_provider’: ‘openai’,
- ‘model_name’: ‘glm-4.5-air’,
- ‘system_fingerprint’: None, 模型后端配置指纹,用于排查模型微调或版本变更导致的输出差异。
- ‘id’: ‘2025121722523930d0575385154de9’,
- ‘finish_reason’: ‘tool_calls’, 表示模型stop 结束回答,并要去调工具。
- ‘logprobs’: None, 每个 token 的概率分布,用于研究 / 不确定性评估,默认关闭
id=‘lc_run–019b2ccc-807d-72b2-89c6-90158576be4a-0’,
4.3.3 执行决策层 (Tool Calls)
- tool_calls: 一个列表,包含模型想要执行的三个函数。
- name: 工具名称(对应你代码中 @tool 定义的函数名)。
- args: 模型从用户prompt中抽取的参数(如 URL、股票代码、结束日期等)。
- id: 本次调用的唯一指纹。注意这三个任务的 id 不同,它们将与后面的 ToolMessage 一一对应。
- type: 为 ‘tool_call’,标记这是一个函数调用请求。
案例:
- tool_calls
- ‘name’: ‘read_url’,
- ‘args’: {‘url’: ‘https://finance.eastmoney.com/a/202512173594061460.html’,
‘max_chars’: 1500},
‘id’: ‘call_-8059702116734984142’,
‘type’: ‘tool_call’}, - ‘id’: ‘call_-8059702116734984141’,
- ‘type’: ‘tool_call’},
4.3.4 消耗统计层 (Usage & Tokens)
调用api很多是根据token消耗收费的,这里有两次token统计信息,
包括模型response_metadata的token_usage (原始统计) 与 usage_metadata (LangChain 标准统计):
response_metadata={'token_usage':{'completion_tokens':422,'prompt_tokens':600,'total_tokens':1022,…,}usage_metadata={'input_tokens':600,'output_tokens':422,'total_tokens':1022,'input_token_details':{'cache_read':40},'output_token_details':{}}),字段含义如下:
| 字段 | 含义 |
|---|---|
| input_tokens/prompt_tokens | 输入给模型的 token 数(总字符量) |
| output_tokens/completion_tokens | 模型生成的 token 数,包含生成的思考文本 + JSON 格式的工具参数。 |
| total_tokens | 总消耗 |
| cached_tokens | 命中缓存的 token数,说明这部分 Prompt 之前处理过(不重复计费或低价) |
| audio_tokens | 语音相关(此处未用) |
4.4 ToolMessage
这里就三个字段:
- content:这是工具函数的返回值,在 Python 中定义的 @tool 函数执行完毕后,return 的字符串就被封装在这里。
- id:这条消息在 LangChain 运行历史中的唯一 ID,主要用于链路追踪(Tracing)和调试。
- tool_call_id: 这是关联性验证ID,它必须与前一步 AIMessage 中 tool_calls 列表对应的 id 完全一致。
4.5 输出原文
这里做了简要的整理:
=====FINAL OUTPUT====={'messages':[HumanMessage(content='\n 有三个任务:\n1.用100字的内容总结网页:https://finance.eastmoney.com/a/202512173594061460.html\n2.用100字的分析CSVfile:./data/daily_prices_sse_50.csv\n3.下载20251217之前20天的股票数据到当前路径的data文件夹,股票代码600519.SH,保存文件命名为:"股票代码_最后日期.CSV"\n ',additional_kwargs={},response_metadata={},id='612ba1c0-3fcf-4e9b-ae73-4868c3415d3c'),AIMessage(content='\n我来帮您完成这三个任务。\n',additional_kwargs={'refusal':None},response_metadata={'token_usage':{'completion_tokens':422,'prompt_tokens':600,'total_tokens':1022,'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':'2025121722523930d0575385154de9','finish_reason':'tool_calls','logprobs':None},id='lc_run--019b2ccc-807d-72b2-89c6-90158576be4a-0',tool_calls=[{'name':'read_url','args':{'url':'https://finance.eastmoney.com/a/202512173594061460.html','max_chars':1500},'id':'call_-8059702116734984142','type':'tool_call'},{'name':'analyze_csv','args':{'file_path':'./data/daily_prices_sse_50.csv','max_rows':5},'id':'call_-8059702116734984141','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_-8059702116734984140','type':'tool_call'}],usage_metadata={'input_tokens':600,'output_tokens':422,'total_tokens':1022,'input_token_details':{'cache_read':40},'output_token_details':{}}),ToolMessage(content='\r \r<!DOCTYPE html>\r<!--published at2025/12/1722:52:25by finance.eastmoney.com server-xml ZP NEWS18-->\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<styletype="text/css">\r.em_xuangu{display:block !important;}\r</style>\r<scripttype="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='71aed1f9-7e19-4223-9847-4c21b1c0f517',tool_call_id='call_-8059702116734984142'),ToolMessage(content="Shape:(11568,11)\n Columns:['ts_code','trade_date','open','high','low','close','pre_close','change','pct_chg','vol','amount']\n\nHead:\n ts_code trade_dateopenhigh low close pre_close change pct_chg vol amount\n600028.SH202501026.676.736.526.566.68-0.12-1.79641719786.771136783.089\n600030.SH2025010228.9829.0027.1727.4529.17-1.72-5.89652828487.337898902.462\n600031.SH2025010216.4816.4815.6915.7716.48-0.71-4.3083853894.281368558.133\n600036.SH2025010239.3539.5038.3438.5139.30-0.79-2.0102642000.702493694.677\n600048.SH202501028.848.988.618.688.86-0.18-2.03161273310.731121639.098",name='analyze_csv',id='f2a8bdf6-56d2-4735-8716-a5644d25b62b',tool_call_id='call_-8059702116734984141'),ToolMessage(content='Data saved to data/600519_20251217.CSV',name='download_stock_price',id='0ca6749e-e554-4e8a-a36d-8b23633524c6',tool_call_id='call_-8059702116734984140'),AIMessage(content='\n## 任务完成情况:\n\n### 1. 网页总结(100字):\n沐曦股份科创板上市成为近十年最赚钱新股,单签盈利达36万元。自2014年初新股恢复发行以来,累计上市超2900只新股,沐曦股份凭借这一盈利表现创下纪录,显示新股市场投资回报潜力巨大。\n\n### 2. CSV文件分析(100字):\n该文件包含11568条股票交易记录,涵盖11个字段:股票代码、交易日期、价格数据(开盘、最高、最低、收盘)、涨跌信息、成交量及成交额。数据格式规范,时间跨度较长,适合进行股票价格走势、波动性和交易量分析。\n\n### 3. 股票数据下载:\n已成功下载600519.SH股票20251217日前20天的交易数据,保存至data/600519_20251217.CSV文件。',additional_kwargs={'refusal':None},response_metadata={'token_usage':{'completion_tokens':439,'prompt_tokens':1700,'total_tokens':2139,'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':'20251217225243c0ef35d0a82948a5','finish_reason':'stop','logprobs':None},id='lc_run--019b2ccc-9287-7d71-a967-8d40200112c4-0',usage_metadata={'input_tokens':1700,'output_tokens':439,'total_tokens':2139,'input_token_details':{'cache_read':40},'output_token_details':{}})]}5.Ref
- https://github.com/langchain-ai/langchain
- https://reference.langchain.com/python/
- https://modelcontextprotocol.io/docs/getting-started/intro
