【AI】十四.进阶LLM之Agent智能体和Tool工具实战 小滴课堂讲师 2025年09月19日 ai大模型, aigc 预计阅读 30 分钟 #### 大模型Agent智能体介绍和应用场景 ##### 什么是智能体Agent * 是一种**具备自主决策能力的AI系统**,通过感知环境、分析信息、调用工具、执行动作的闭环过程完成任务 * 智能体 = 大语言模型(LLM) + 工具(Tools) + 记忆(Memory) * 核心架构 ``` 用户输入 → 大模型推理 → 工具选择 → 执行工具 → 结果验证 → 输出响应 ↑ ↓ ↑ 记忆系统 ↔ 工具库 ↔ 知识库 ``` * 类比:一个具备自主决策能力的虚拟助手,能根据目标自主调用工具完成任务 * 与传统LLM的关键区别 | 维度 | 常规LLM | Agent | | :------: | :-----------: | :---------------: | | 交互方式 | 单轮问答 | 多轮决策链 | | 能力范围 | 文本生成 | 工具调用+环境交互 | | 记忆机制 | 短期上下文 | 长期记忆存储 | | 输出形式 | 自然语言 | 结构化动作序列 | | 应用场景 | 内容创作/问答 | 复杂任务自动化 | * 常规大模型和Agent案例场景对比 | 测试用例 | 传统模式响应 | Agent模式响应 | | :--------------: | :----------: | :---------------------------: | | "北京天气" | 温度数据 | "北京当前晴,12℃,建议穿外套" | | "明天需要带伞吗" | 无法处理 | 调用天气API分析降水概率 | | "上周三天气如何" | 报错 | 自动切换历史天气数据库工具 | ##### 典型应用场景 * 医疗行业 - 诊断辅助Agent * 传统系统痛点: * 基于固定规则的专家系统、无法处理复杂症状组合、知识更新依赖人工维护 * Agent方案关键能力 * 结合最新医学论文(通过工具实时检索,常规大模型没法获取最新数据) * 自动生成检查建议清单 * 保留患者完整诊疗历史 ```python medical_agent = AgentExecutor( tools=[ SymptomAnalyzerTool, MedicalLiteratureTool, LabTestRecommenderTool ], memory=PatientHistoryMemory() ) # 交互示例 response = medical_agent.invoke({ "input": "患者女35岁,持续低烧两周,伴有关节痛", "history": "既往有类风湿病史" }) # 输出:建议进行抗核抗体检测+推荐专科医生 ``` * 教育行业 - 个性化学习Agent * 传统在线教育 ```python // 固定学习路径 public class LearningService { public String getNextStep(String userId) { int score = db.getUserScore(userId); if (score < 60) { return "重新学习第三章"; } return "进入第四章"; } } ``` * Agent方案关键能力 * 动态调整学习路径(基于实时掌握程度) * 多模态教学内容推荐(视频/图文/交互实验) * 自动生成错题分析报告 ```python class TutorAgent: tools = [ KnowledgeGraphTool, ExerciseRecommenderTool, LearningStyleAnalyzerTool ] def guide_student(self, studentQuery): # 动态决策: # 1. 分析学生知识薄弱点 # 2. 根据学习风格推荐资料 # 3. 生成个性化练习计划 return self.agent_executor.invoke(studentQuery) ``` * Agent智能体案例(伪代码) ```python from langchain.agents import AgentExecutor, create_react_agent from langchain import hub # 定义工具集 tools = [ Tool( name="WeatherCheck", func=get_weather_api_data, description="查询实时天气数据" ), Tool( name="CalendarAccess", func=read_google_calendar, description="访问用户日历信息" ) ] # 构建Agent prompt = hub.pull("hwchase17/react") agent = create_react_agent( llm=ChatOpenAI(temperature=0), tools=tools, prompt=prompt ) # 执行示例 agent_executor = AgentExecutor(agent=agent, tools=tools) result = agent_executor.invoke({ "input": "帮我安排明天北京的户外会议,需要考虑天气情况" }) print(result["output"]) #典型输出示例 思考过程: 1. 需要确定明天北京的天气(调用WeatherCheck) 2. 查询明天下午2点的天气预报 3. 如果天气适宜,查找明天下午的空闲时段(调用CalendarAccess) 4. 综合结果建议会议时间 最终输出:建议将会议安排在明天下午15:00,天气预报显示晴,气温22℃。 ``` #### 大模型痛点和LangChain工具Tool实战 ##### 需求背景 * **大模型的短板**:虽然大语言模型(LLM)擅长文本生成,但缺乏: - 实时数据获取能力(如天气/股票)、精确数学计算能力 - 专业领域知识(如法律/医疗)、外部系统对接能力 * Tool工具就是解决这类问题的,通过Tool机制,好比给大模型插入翅膀 ##### 大模型的Tool工具 * Tool是LLM与外部世界交互的接口,让大模型能调用外部功能(如API、函数、数据库) * 核心 * 突破大模型静态知识库限制 * 实时获取外部数据(如天气/股票) * 执行复杂计算业务逻辑 * 连接现有软件系统(如CRM、各个系统API) * 工具生命周期 ``` 工具定义 → 2. Agent注册 → 3. 自动调用 → 4. 结果处理 ``` ##### LangChain里面创建工具 * @tool装饰器 * 通过简单的@tool装饰器或StructuredTool即可实现,适用于大多数用例, * @tool但不能同时有同步和异步的方法,只能单独使用 * LangChain Runnables * 接受字符串或字典输入的LangChain Runnables使用as_tool方法转换为工具 * 允许为参数指定名称、描述和其他模式信息; * 继承BaseTool类: * 通过从BaseTool进行子类化来定义自定义工具,提供了对工具定义的最大控制,但需要编写更多的代码。 ##### LangChain里面Tool实战 * **@tool 装饰器**:用来定义一个简单的工具函数,, 可以直接给函数加上这个装饰器,让函数成为可调用的工具 * 简单定义, **需要加上文档字符串注释描述,AI才知道工具的用途** ```python from langchain_core.tools import tool @tool def multiply(a: int, b: int) -> int: """把传递的两个参数相乘""" return a * b print("工具名称:", multiply.name) print("工具描述:", multiply.description) print("工具参数:", multiply.args) print("工具返回值:", multiply.return_direct) print("工具详细的schema:",multiply.args_schema.model_json_schema()) print(multiply.invoke({"a": 2, "b": 3})) #定义了一个 `multiply` 工具,用于两个数字相乘,并在调用时显示该工具的名称、描述和参数列表。 ``` * 配置参数 ```python from pydantic import BaseModel, Field from langchain_core.tools import tool class CalculatorInput(BaseModel): a: int = Field(description="第一个参数") b: int = Field(description="第二个参数") @tool("multiplication-tool", args_schema=CalculatorInput, return_direct=True) def multiply(a: int, b: int) -> int: """Multiply two numbers.""" return a * b # Let's inspect some of the attributes associated with the tool. print("工具名称:", multiply.name) print("工具描述:", multiply.description) print("工具参数:", multiply.args) print("工具返回值:", multiply.return_direct) print("工具详细的schema:",multiply.args_schema.model_json_schema()) ``` * 核心组件 | **组件** | **作用** | **示例** | | :---------------------------- | :--------------------------------------------------------- | :----------------------------- | | **名称(name)** | 工具唯一标识符,代理通过名称匹配调用工具 | `wikipedia`、`google_search` | | **描述(description)** | 工具功能的自然语言描述,代理根据描述决定是否调用工具 | "查询维基百科内容" | | **输入参数(args_schema)** | 定义工具的参数格式(Pydantic模型),用于参数校验与提示生成 | `query: str` | | **执行函数(func)** | 实际执行操作的函数(如调用API、运行Shell命令) | `def run(query: str): ...` | | **返回模式(return_direct)** | 若为`True`,代理直接返回工具结果,不再生成额外文本 | 适用于无需进一步推理的简单任务 | ##### StructuredTool 介绍 * 是LangChain中用于定义**结构化参数工具**的基类,相比普通`@tool`装饰器,它支持: - **严格的参数模式定义**(基于Pydantic模型) - **多参数输入校验** - **自动生成工具调用示例** * **适用场景**:需要多个输入参数或复杂参数类型的工具 | **特性** | **普通@tool装饰器** | **StructuredTool** | | :------------- | :--------------------------- | :------------------------------- | | **参数定义** | 简单参数(单个字符串或字典) | 基于Pydantic模型的严格参数模式 | | **参数校验** | 弱校验(依赖代码逻辑) | 强校验(自动类型检查和格式验证) | | **多参数支持** | 需手动解析字典参数 | 直接映射多个命名参数 | | **使用复杂度** | 快速定义简单工具 | 适合复杂业务逻辑的工具 | * 案例实战 ```python from pydantic import BaseModel, Field from langchain_core.tools import StructuredTool # 定义输入参数的数据结构 class CalculatorInput(BaseModel): a: int = Field(description="第一个数字") b: int = Field(description="第二个数字") # 定义计算函数 def multiply(a: int, b: int) -> int: """Multiply two numbers.""" return a * b # 封装工具 calculator = StructuredTool.from_function( func=multiply, name="Calculator", description="用于计算两个数字的乘积", args_schema=CalculatorInput, return_direct=True, ) print("工具名称:", calculator.name) print("工具描述:", calculator.description) print("工具参数:", calculator.args) print("工具返回值:", calculator.return_direct) print("工具详细的schema:",calculator.args_schema.model_json_schema()) # 调用工具 print("工具调用结果:", calculator.invoke({"a": 2, "b": 3})) ``` * 使用继承`BaseTool`子类进行创建工具 ```python from pydantic import BaseModel, Field from typing import Type from langchain_core.tools import BaseTool from pydantic import BaseModel class CalculatorInput(BaseModel): a: int = Field(description="第一个参数") b: int = Field(description="第二个参数") class CustomCalculatorTool(BaseTool): name: str = "Calculator" description: str = "当你需要计算数学问题时候使用" args_schema: Type[BaseModel] = CalculatorInput return_direct: bool = True def _run( self, a: int, b: int ) -> str: """使用工具.""" return a * b calculator = CustomCalculatorTool() print("工具名称:", calculator.name) print("工具描述:", calculator.description) print("工具参数:", calculator.args) print("工具返回值:", calculator.return_direct) print("工具详细的schema:",calculator.args_schema.model_json_schema()) print(calculator.invoke({"a": 2, "b": 3})) ``` #### LLM大模型绑定工具Tool案例实战 ##### 需求 * 定义了工具,需要把工具绑定给大模型, 大模型会在合适的时候,选择对应的工具函数 * **解决痛点**:如天气查询/股票数据/订单处理等需要实时数据的场景 * **类比理解**:给大模型装"手和脚",像钢铁侠的AI助手贾维斯可操作战甲 * 注意 * 虽然“工具调用”这个名称暗示模型直接执行某些操作,但实际上并非如此! * 模型仅生成工具的参数,实际运行工具(或不运行)取决于用户的需求 | 要素 | 作用 | 示例 | | :------: | :------------------------------: | :------------------------------: | | 工具描述 | 告诉模型工具的功能和使用方法 | 天气查询API的输入输出说明 | | 参数解析 | 从自然语言中提取结构化参数 | 提取"北京今天温度"中的城市和日期 | | 执行反馈 | 将工具返回结果重新组织成自然语言 | 把JSON天气数据转为口语化描述 | ##### 技术实现流程 ``` 用户输入 → 大模型分析意图 → 选择工具 → 提取参数 → 调用工具 → 结果格式化 → 最终回复 ``` ##### 大模型绑定工具api * 支持工具调用功能的聊天模型, 直接使用`.bind_tools( )`方法,传入工具列表即可 ```python def bind_tools( self, tools: Sequence[Union[Dict[str, Any], Type, Callable, BaseTool]], *, tool_choice: Optional[ Union[dict, str, Literal["auto", "none", "required", "any"], bool] ] = None, strict: Optional[bool] = None, parallel_tool_calls: Optional[bool] = None, **kwargs: Any, ) -> Runnable[LanguageModelInput, BaseMessage]: ``` * 注意:不是全部大模型都是支持绑定工具列表, * 大模型绑定工具的伪代码参考 ```python tools = [add, multiply] from langchain_openai import ChatOpenAI llm = ChatOpenAI(model="gpt-4o-mini") llm_with_tools = llm.bind_tools(tools) query = "What is 3 * 12?" resp = llm_with_tools.invoke(query) ``` ##### 工具调用 * 第一步 * 大模型如果需要调用工具,则生成响应里面包括了工具调用信息,本身的content内容为空 * 大模型响应的消息 或消息块 作为工具调用对象的列表,位于`.tool_calls`属性中。 * 聊天模型可以同时调用多个工具, 包含 工具名称、参数值字典和(可选)标识符的类型字典。 * 没有工具调用的消息 默认将此属性设置为空列表 ```python # 使用绑定工具的模型处理用户查询 ai_msg = llm_with_tools.invoke(messages) # 打印ai_msg对象的tool_calls属性,显示AI消息中包含的工具调用信息 print(ai_msg.tool_calls) {'tool_calls': [ { 'id': 'call_ea723d86cf804a088b946a', 'function': {'arguments': '{"a": 3, "b": 12}', 'name': 'multiply'}, 'type': 'function', 'index': 0} ] } ``` * 第二步 * 提取大模型响应信息里面的选择的工具,代码编写 选择对应的工具进行执行 ```python # 遍历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_1319a58494c54998842092')] ``` * 第三步 * 将工具调用的结果添加到消息messages列表中,再传递给大模型,大模型会重新进行执行,组织对应的语言返回 ```python # 再次使用绑定工具的模型处理更新后的messages列表 reslut = llm_with_tools.invoke(messages) # 打印最终结果 print(f"最终结果:{reslut}") 最终结果: content='3 乘以 12 的结果是 36。' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 16, 'prompt_tokens': 272, 'total_tokens': 288, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'qwen-plus', 'system_fingerprint': None, 'id': 'chatcmpl-b499cd0b-29d4-9d83-8473-e41d7214223d', 'finish_reason': 'stop', 'logprobs': None} id='run-8046aa25-091a-4df3-a49a-aa36811c8d44-0' usage_metadata={'input_tokens': 272, 'output_tokens': 16, 'total_tokens': 288, 'input_token_details': {'cache_read': 0}, 'output_token_details': {}} ```   ##### 完整案例实战 ```python from langchain_core.tools import tool from langchain_openai import ChatOpenAI from langchain_core.messages import HumanMessage # 定义一个加法工具函数 @tool def add(a: int, b: int) -> int: """Adds a and b.""" return a + b # 定义一个乘法工具函数 @tool def multiply(a: int, b: int) -> int: """Multiplies a and b.""" return a * b # 定义模型 llm = ChatOpenAI( model_name = "qwen-plus", base_url="https://dashscope.aliyuncs.com/compatible-mode/v1", api_key="sk-005c3c25f6d042848b29d75f2f020f08", temperature=0.7 ) # 将前面定义的工具函数整合到一个列表中 tools = [add, multiply] # 将工具函数绑定到语言模型 llm_with_tools = llm.bind_tools(tools) # 定义用户查询 query = "3 * 12 结果是多少" # 创建一个包含用户查询的messages列表 messages = [HumanMessage(query)] # 使用绑定工具的模型处理用户查询 ai_msg = llm_with_tools.invoke(messages) # 打印ai_msg对象,以便用户可以看到AI的消息响应 print(ai_msg) # 打印ai_msg对象的tool_calls属性,显示AI消息中包含的工具调用信息 print(ai_msg.tool_calls) # 将AI的消息添加到messages列表中 messages.append(ai_msg) # 遍历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) # 打印更新后的messages列表 print(f"打印更新后的messages列表:{messages}") # 再次使用绑定工具的模型处理更新后的messages列表 result = llm_with_tools.invoke(messages) # 打印最终结果 print(result) ``` #### LangChain内置工具包和联网搜索实战 ##### LangChain工具包 * 方便开发者快速使用各种主流工具,LangChain官方加入了很多内置工具,开箱即用 * 所有工具都是 BaseTool 的子类,且工具是 Runnable可运行组件,支持 invoke、stream 等方法进行调用 * 也可以通过 name、 description、args、 returu_direct 等属性来获取到工具的相关信息 * 如果内置工具包不满足,即可以自定义工具 * 地址(失效忽略即可):https://python.langchain.com/docs/integrations/tools/ ##### 如何使用内置工具包【联网搜索例子】 * 选择对应的工具->安装依赖包->编写代码实战 * 案例实战 * 搜索工具:选择 SearchApi,注册时100次免费搜索,注册账号获取 APIKEY * 编写代码 ```python # 导入操作系统接口模块,用于与环境变量交互 import os # 从langchain_community.utilities模块中导入SearchApiAPIWrapper类,用于封装搜索API from langchain_community.utilities import SearchApiAPIWrapper # 设置环境变量SEARCHAPI_API_KEY,用于认证搜索API的密钥 os.environ["SEARCHAPI_API_KEY"] = "qQBHMQo4Rk8SihmpJjCs7fML" # 实例化SearchApiAPIWrapper对象,用于调用搜索API search = SearchApiAPIWrapper() # 调用run方法执行搜索操作,参数为查询腾讯股价的中文字符串 result = search.run("今天腾讯的股价是多少") # 输出搜索结果 print(result) ``` * 拓展 * SearchApi 包装器可以自定义为使用不同的引擎,如 Google News、Google Jobs、Google Scholar * 其他可以在 SearchApi 文档中找到的引擎。执行查询时可以传递 SearchApi 支持的所有参数。 ``` search = SearchApiAPIWrapper(engine="google_jobs") ``` * 获取元数据 ```python result_meta = search.results("今天腾讯的股价是多少") print(result_meta) ``` #### 兜底降级-LangChain调用工具Tool异常处理 ##### 需求背景 * 智能体(Agent)在调用外部工具(如 API、数据库、搜索引擎)时,会遇到各种不可预知的错误 * 例如: - 网络请求失败(如 API 无响应) - 权限不足(如访问密钥失效) - 输入参数不合法(如格式错误) - 资源限制(如 API 调用次数超限) * 如果智能体不处理这些错误,会导致: * **程序崩溃**:直接抛出未捕获的异常。 * **用户困惑**:返回难以理解的错误堆栈信息。 * **无法恢复**:智能体无法根据错误调整策略(如重试或切换工具) ##### 解决方案 ToolException * 通过 ToolException 统一捕获和处理工具调用中的错误,使智能体具备容错能力和用户友好的错误反馈 * ToolException 的核心作用 * 统一错误格式:将不同工具的异常转换为标准格式,方便智能体解析。 * 错误上下文传递:保留错误原因、工具名称等关键信息。 * 使用场景举例 * **API 调用失败**:如天气查询接口超时。 * **权限校验失败**:如访问数据库的密钥过期。 * **输入参数校验**:如用户输入的城市名不存在。 * **资源限制**:如每日调用次数用尽。 ##### 案例实战 * 方式一:配置响应 `handle_tool_error=True` 默认是false ```python from langchain_core.tools import tool, ToolException, StructuredTool def search(query: str) -> str: """ 执行搜索查询 """ # 引发一个ToolException来模拟搜索结果为空的情况 raise ToolException(f"相关搜索结果为空:{query}") # 使用StructuredTool从函数创建一个工具实例 # handle_tool_error参数设置为True,表示工具将处理内部异常 search_tool = StructuredTool.from_function( func=search, name="search", description="搜索工具", handle_tool_error=True ) # 调用search_tool的invoke方法来执行搜索工具, 传递一个包含查询参数的字典 resp = search_tool.invoke({"query": "腾讯的股价多少"}) # 打印搜索工具的响应结果 print(resp) ``` * 方式二:配置响应 `handle_tool_error=”错误信息“` ```python from langchain_core.tools import tool, ToolException, StructuredTool def search(query: str) -> str: """ 执行搜索查询 """ # 引发一个ToolException来模拟搜索结果为空的情况 raise ToolException(f"相关搜索结果为空:{query}") # 使用StructuredTool从函数创建一个工具实例 # handle_tool_error参数设置为True,表示工具将处理内部异常 search_tool = StructuredTool.from_function( func=search, name="search", description="搜索工具", handle_tool_error="搜索结果失败,请重试" ) # 调用search_tool的invoke方法来执行搜索工具,传递一个包含查询参数的字典 resp = search_tool.invoke({"query": "腾讯的股价多少"}) # 打印搜索工具的响应结果 print(resp) ``` * 方式三:配置自定义处理函数-兜底降级 ```python from langchain_core.tools import tool, ToolException, StructuredTool def search(query: str) -> str: """ 执行搜索查询 """ # 引发一个ToolException来模拟搜索结果为空的情况 raise ToolException(f"相关搜索结果为空:{query}") #自定义异常处理函数 def _handle_tool_error(error: ToolException) -> str: """ 自定义异常处理函数 """ return f"搜索结果失败,自定义异常,请重试:{error}" # 使用StructuredTool从函数创建一个工具实例 # handle_tool_error参数设置为True,表示工具将处理内部异常 search_tool = StructuredTool.from_function( func=search, name="search", description="搜索工具", handle_tool_error=_handle_tool_error ) # 调用search_tool的invoke方法来执行搜索工具,传递一个包含查询参数的字典 resp = search_tool.invoke({"query": "腾讯的股价多少"}) # 打印搜索工具的响应结果 print(resp) ``` #### 插上翅膀-LLM增加联网搜索功能实 ##### 需求说明 * 实现了一个结合大语言模型(LLM)和工具调用的智能问答系统。 * 用户可以通过自然语言输入问题,系统会根据问题内容判断是否需要调用外部工具(如搜索引擎或计算工具),返回最终答案。 ##### 交互流程图 ##### 步骤思路 * 配置SearchAPI的API密钥, * 实例化`SearchApiAPIWrapper`对象,用于调用搜索API。 * 定义多个工具函数,供系统在回答问题时调用。 - **web_search**: 用于搜索实时信息、最新事件或未知领域知识。 - 输入参数:`query`(字符串类型,搜索关键词)。 - 返回值:搜索结果的标题和摘要。 - **multiply**: 用于计算两个整数的乘积。 - 输入参数:`a`和`b`(均为整数类型)。 - 返回值:两数相乘的结果。 * 初始化大语言模型(LLM),并将其与工具绑定,形成一个智能问答Agent。 - **关键点** - 使用`ChatOpenAI`类初始化LLM,指定模型名称、API密钥、温度等参数。 - 创建聊天提示模板(`ChatPromptTemplate`),定义系统角色和用户输入格式。 - 将工具列表与LLM绑定,具备工具调用能力的Agent。 * 构建运行链(`chain`),将用户输入传递给提示模板和Agent,生成响应。 - **关键点** - 用户输入通过`RunnablePassthrough`传递到提示模板。 - 提示模板生成的消息进一步传递给Agent处理。 * 根据据LLM生成的响应,判断是否要调用工具。如果需要调用工具并将结果合并到历史消息中,重新传递给LLM生成最终答案。 - **关键点** - 通过`resp.tool_calls`判断是否需要调用工具。 - 调用工具后,将结果以`ToolMessage`形式添加到历史消息中。 - 最终结果由LLM根据更新的历史消息生成。 ##### 案例代码实战 ```python # 基于LangChain 0.3.x的SearchApi工具实战(需安装依赖) # pip install langchain-core langchain-openai langchain-community from langchain_community.utilities import SearchApiAPIWrapper from langchain_core.tools import tool from langchain_openai import ChatOpenAI from langchain_core.messages import ToolMessage from langchain_core.runnables import RunnablePassthrough from langchain_core.prompts import ChatPromptTemplate import os from langchain_core.tools import tool from pydantic import Field # ====================== # 第一步:配置搜索工具 # ====================== # 注册SearchAPI获取密钥:https://www.searchapi.io/ # 设置SearchAPI的API密钥 os.environ["SEARCHAPI_API_KEY"] = "qQBHMQo4Rk8SihmpJjCs7fML" # 实例化SearchApiAPIWrapper对象,用于调用搜索API search = SearchApiAPIWrapper() # ====================== # 第二步:定义搜索工具 # ====================== @tool("web_search", return_direct=True) def web_search(query: str) -> str: """ 当需要获取实时信息、最新事件或未知领域知识时使用,输入应为搜索关键词 """ try: results = search.results(query) # 获取前3条结果 return "\n\n".join([ f"来源:{res['title']}\n内容:{res['snippet']}" for res in results['organic_results'] ]) except Exception as e: return f"搜索失败:{str(e)}" @tool("multiply") def multiply(a: int, b: int) -> int: """ 把传递的两个参数相乘 """ return a * b # ====================== # 第三步:绑定LLM创建Agent # ====================== # 初始化大模型 llm = ChatOpenAI( model_name = "qwen-plus", base_url="https://dashscope.aliyuncs.com/compatible-mode/v1", api_key="sk-005c3c25f6d042848b29d75f2f020f08", temperature=0.7 ) # 创建聊天提示模板 prompt = ChatPromptTemplate.from_messages( [ ("system", "你是一个AI助手,名称叫老王,请根据用户输入的查询问题,必要时可以调用工具帮用户解答"), ("human", "{query}"), ] ) # 定义工具字典 tool_dict = { "web_search": web_search, "multiply": multiply } # 从字典中提取工具列表 tools = [ tool_dict[tool_name] for tool_name in tool_dict ] # 绑定工具到大模型 llm_with_tools = llm.bind_tools(tools=tools) # 创建运行链 chain = {"query":RunnablePassthrough()} | prompt | llm_with_tools # 定义查询 query = "你是谁?" # 执行链并获取响应 resp = chain.invoke({"query":query}) print(resp) #判断是否需要调用工具 content=''不一定需要调用,根据tool_calls进行判断 ``` ##### 编码实战 ```python #判断是否需要调用工具 content=''不一定需要调用,根据tool_calls进行判断 # ====================== # 第四步:获取工具调用 # ====================== tool_calls = resp.tool_calls if len(tool_calls) <= 0: print(f"不需要调用工具:{resp.content}") else: #将历史消息合并,包括用户输入和AI输出 history_messages = prompt.invoke(query).to_messages() history_messages.append(resp) print(f"历史消息:{history_messages}") #循环调用工具 for tool_call in tool_calls: tool_name = tool_call.get("name") tool_args = tool_call.get("args") tool_resp = tool_dict[tool_name].invoke(tool_args) print(f"一次调用工具:{tool_name},参数:{tool_args},结果:{tool_resp}") #将工具调用结果添加到历史消息中 history_messages.append( ToolMessage( tool_call_id=tool_call.get("id"), name=tool_name, content=tool_resp ) ) print(f"历史消息:{history_messages}") resp = llm_with_tools.invoke(history_messages) print(f"最终结果:{resp}") print(f"调用工具后的结果:{resp.content}") ``` * 案例测试实战 ``` #query = "9*3是多少" #query = "今天是腾讯股价是多少" ``` * 扩展功能建议 - **多语言支持**:增加对多种语言的输入和输出支持。 - **更多工具集成**:集成更多类型的工具,如翻译工具、图像识别工具等。 - **用户反馈机制**:允许用户对系统生成的答案进行评价,优化模型性能。
评论区