Java+Python智能化网盘【Day8-2】
LLM之Agent智能体和Tool工具
大模型Agent智能体简介和应用场景
什么是Agent?
- 他是一种具备自主决策能力的Ai系统,通过感知环境、分析信息、调用工具、执行动作的闭环过程完成任务
- 智能体 = LLM + Tools + Memory 【工具其实就是函数和接口】
- 核心架构
应用场景:复杂任务自动化,思考分析,调用工具去完成任务。【eg:联网搜索、天气、金融走势等等这些实时的消息能够被获取得到】
大模型痛点
其实通过对上方的一个Agent的了解以及他的构成我们可以知道,LLM它知识基于训练的数据中的内容进行一个输出,缺乏实时信息的检索输出和精确的数学计算能力。即使是用上RAG知识检索,这方面的弊端还是很严重!所以就有了下方的Tool工具去和LLM组合使用来帮助LLM去与外部世界有了交互的接口
LangChain中的Tool
-
@Tool工具定义:API、函数、数据库
-
@tool装饰器:用来定义一个简单的工具函数,可以直接给函数加上这个装饰器,让函数成为可调用的工具
- 简单定义,需加上文档字符串注释描述,AI才知道工具用途(这是标准化,必须写)
from langchain_core.tools import tool@tool # 加上这个注解其实就是让大模型能够去扫描到从而获得这个函数的信息
def multiply(a: int, b: int) -> int:"""把两个参数相乘并返回"""return a * bprint(f"工具名称:{multiply.name}")
print(f"工具描述:{multiply.description}")
print(f"工具参数:{multiply.args}")
print(f"工具返回值:{multiply.return_direct}")
print(f"工具详细的schema:",multiply.args_schema.model_json_schema())
print(f"工具调用:{multiply.invoke({"a" : 2, "b" : 3 })}")
- pydantic进一步去约束tool,来给LLM更多的信息
from langchain_core.tools import tool
from pydantic import BaseModel, Fieldclass CalculatorInput(BaseModel):a : int = Field(description="第一个参数")b : int = Field(description="第二个参数")# tool中的description优先级更高对于对象的工具描述而言
@tool("multiplication-tool",args_schema=CalculatorInput, return_direct=True,description="计算两个数相乘V2")
def multiply(a : int, b : int) -> int:"""两数相乘"""return a * b
- StructuredTool介绍
- 是LangChain中用于定义结构化参数工具的基类,相比普通的tool装饰器
特性 | 普通@tool装饰器 | StructuredTool |
---|---|---|
参数定义 | 简单参数(单个字符串或字典) | 基于Pydantic模型的严格参数模式 |
参数校验 | 弱校验(依赖代码逻辑) | 强校验(自动类型检查和格式验证) |
多参数支持 | 需手动解析字典参数 | 直接映射多个命名参数 |
使用复杂度 | 快速定义简单工具 | 适合复杂业务逻辑工具 |
from langchain_core.tools import tool,StructuredTool
from pydantic import BaseModel, Fieldclass CalculatorInput(BaseModel):a : int = Field(description="第一个参数")b : int = Field(description="第二个参数")def multiply(a : int, b : int) -> int:"""两数相乘"""return a * b# 使用StructuredTool结构性创建工具
calculator = StructuredTool.from_function(func=multiply,name="multiplication-tool",description="计算两个数相乘",args_schema=CalculatorInput,return_direct=True,
)print(f"工具名称:{calculator.name}")
print(f"工具描述:{calculator.description}")
print(f"工具参数:{calculator.args}")
print(f"工具返回值:{calculator.return_direct}")
print(f"工具详细的schema:",calculator.args_schema.model_json_schema())
print(f"工具调用:{calculator.invoke({"a" : 2, "b" : 3 })}")
- 继承于BaseTool
from langchain_core.tools import tool,StructuredTool, BaseTool
from pydantic import BaseModel, Field
from typing import Typeclass CalculatorInput(BaseModel):a : int = Field(description="第一个参数")b : int = Field(description="第二个参数")class CustomCalculator(BaseTool):name : str = "calculator"description : str = "用于计算两个数字的和"args_schema: Type[BaseModel] = CalculatorInputreturn_direct : bool = Truedef _run(self,a: int, b: int)-> str:"""计算两个数字的和"""return str(a + b)calculator = CustomCalculator()print(f"工具名称:{calculator.name}")
print(f"工具描述:{calculator.description}")
print(f"工具参数:{calculator.args}")
print(f"工具返回值:{calculator.return_direct}")
print(f"工具详细的schema:",calculator.args_schema.model_json_schema())
print(f"工具调用:{calculator.invoke({"a" : 2, "b" : 3 })}")
大模型绑定工具
注意:不是所有的大模型都是支持绑定工具的
主要核心是LangChain的ChatOpenAi中有.bind_tools()函数,直接传入工具列表就行了,示例代码如下图所示
tools = [add,multiply]
llm = ChatOpenAI(model="gpt4o")
llm_with_tools = llm.bind_tools(tools)
query = "What is 3 * 12"
llm_with_tools.invoke(query)
工具调用
- 第一步
- 大模型如果需要调用工具,则生成响应里面包括了工具调用信息,本身的content内容为空
- 大模型响应的消息 或消息块 作为工具调用对象的列表,位于.tool_calls 属性中。
- 聊天模型可以同时调用多个工具, 包含 工具名称、参数值字典和(可选)标识符的类型字典。
- 没有工具调用的消息 默认将此属性设置为空列表
#使用绑定工具的模型处理用户查询
ai_msg =llm_with_tools.invoke(messages)
# 打印ai msg对象的tool calls属性,显示AI消息中包含的工具调用信息
print(ai_msg.tool_calls)
-
第二步
- 提取大模型响应信息里面的选择工具,代码编写选择对应的工具进行执行
# 遍历AI消息中的工具调用 for tool_call in ai_msg.tool_calls:#根据工具调用的名称选择对应的工具函数selected_tool = {"add" : add, "multiply" : multiply}[tool_call["name"].lower()]print(f"selected_tool:{selected_tool}")#调用选择的工具函数并获取结果tool_msg = selected_tool.invoke(tool_call)print(f"tool_msg:{tool_msg}")# 将工具调用结果增加到messages列表中messages.append(tool_msg)
- invoke()执行后,会自动生成执行结果对象ToolMessage,包括与模型生成的原始工具调用中的id匹配的tool_call_id
ToolMessage(content='36', name='multiply', tool_call_id='call_131923124321342')
-
第三步
- 将工具调用的结果添加到消息Messages列表中,在传递给大模型,大模型会重新执行,组织对应的语言并返回
案例<( ̄︶ ̄)↗[GO!]
from langchain_core.tools import tool,StructuredTool, BaseTool
from langchain_core.messages import HumanMessage # 新增导入
from pydantic import BaseModel, Field
from typing import Type
from langchain_openai import ChatOpenAI@tool
def multiply(a: int, b: int) -> int:"""Multiply two numbers together."""return a * b@tool
def add (a: int, b: int) -> int:"""Add two numbers together."""return a + b# 定义大模型
llm = ChatOpenAI(model_name="qwen-plus", base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",api_key="sk-XX",temperature=0.7,
)# 绑定工具
llm_with_tools = llm.bind_tools(tools=[multiply, add]
)# 定义问题
query = "请计算 13 * 21232"#
messages = [HumanMessage(content=query)
]# 使用绑定工具大模型ju的模型进行推理
ai_message = llm_with_tools.invoke(messages)
print(f"工具调用之后的content:{ai_message.content}")print(f"工具调用之后的tool_calls: {ai_message.tool_calls}")messages.append(ai_message)# 遍历AI消息中工具调用
for tool_call in ai_message.tool_calls:#根据工具调用的名称选择对应的工具函数selected_tool = {"add" : add, "multiply" : multiply}[tool_call["name"].lower()]print(f"selected_tool:{selected_tool}")#调用选择的工具函数并获取结果tool_msg = selected_tool.invoke(tool_call)print(f"tool_msg:{tool_msg}")# 将工具调用结果增加到messages列表中messages.append(tool_msg)print(f"最后的messages:{messages}")result = llm_with_tools.invoke(messages)
print(f"最终回复的计算结果:{result.content}")
这块是通过逻辑遍历去遍历tool_calls中的属性去判定用了哪些工具,后续LangChain框架的话他会自动的选择工具不需要这样子繁琐了,它有封装好的方法。
LangChain内置工具包
- 所有的工具都是BaseTool的子类,且工具是Runnabel可运行的组件,支持invoke和stream等方法
- 也可以通过name、description、args、return_direct等属性来获取得到工具的相关信息
- 如果内置工具包不满足既可以自定义工具
具体可以上LangChain官网上看
如何使用内置工具包【联网搜索为例子】
- 选择对应的工具->安装依赖包->编写代码
- 自己选择个search公司去注册获取api-key
from langchain_community.utilities import SearchApiAPIWrappersearch = SearchApiAPIWrapper(searchapi_api_key="XXX",engine="bing",
)result = search.run("今天日本的核污水排放怎么样了?")# search.result() 提取到的是元数据不是整理完之后的数据的
print(result)
总结
哇咔咔,可以说今天算是效率比较低的了,但是不算太低,明天把整个的RAG再总结过一遍,今天就先学到这个块工具绑定LLM吧,其实学到这块的话也是大致了解了Agent的一个大致路线,对于后续的开发和模型微调其实有了个雏形了在脑子里。明天也是要开始学校sb的小学期了,真不理解这个有鸡毛用,我看其他班上课老师jib毛不讲,就直接在前面玩手机,学生在底下玩手机电脑,就是提交一个大作业就行了,我真的无语死了,你tm的什么都不教,你还非要上这个课,老师你tm还要拿这个钱,我上早八!好了,明天我和老师说下吧,我知道老师应该也知道纯tm浪费时间,我说下我都会到时间交个作业,看看这样子可不可以把,真不想去浪费时间,还要打乱我的生物钟,而且自己的笔记本说实话,真没有我们学校的香,4080 Super 16G 版本的。拜拜了