LangGraph 源码分析 | BaseTool 模板类
文章目录
- BaseTool 源码分析
- 核心属性
- 以 `TavilySearchResults(BaseTool)` 为例
- name
- description
- args_schema
- response_format
- 查询选项属性
- 需要子类实现的抽象方法
- 以 `TavilySearchResults(BaseTool)` 为例
- 核心方法
- `arun()`:`run()`的异步执行版本
- `invoke()`和`ainvoke()`
BaseTool 源码分析
BaseTool 是 LangChain 框架中定义 tools 的模板类
核心属性
name
:表示 tool 唯一名称的字符串(用于识别)description
:对如何 / 何时 / 为何使用该 tool 的描述,帮助模型决定什么时候调用该 toolargs_schema
:验证工具输入参数的 Pydantic model 或 schemareturn_direct
:如果为True
,则立即返回 tool 的输出responcse_format
:定义 tool 的响应格式
以 TavilySearchResults(BaseTool)
为例
name
name: str = "tavily_search_results_json"
description
description: str = ("A search engine optimized for comprehensive, accurate, and trusted results. ""Useful for when you need to answer questions about current events. ""Input should be a search query.")
args_schema
class TavilyInput(BaseModel):"""Input for the Tavily tool."""query: str = Field(description="search query to look up")# 输入将遵循 TavilyInput 类中定义的架构规则
# 同时args_schema的值必须是BaseModel派生类
args_schema: Type[BaseModel] = TavilyInput
- 按照
TavilyInput
的规则,如果输入没有提供query
值,将抛出一个验证错误 Field
函数用于向字段添加元数据(描述)
response_format
response_format: Literal["content_and_artifact"] = "content_and_artifact"
- 使用 Literal 来确保某些值被限制为特定文字
@_LiteralSpecialForm
@_tp_cache(typed=True)
def Literal(self, *parameters):"""Special typing form to define literal types (a.k.a. value types).This form can be used to indicate to type checkers that the correspondingvariable or function parameter has a value equivalent to the providedliteral (or one of several literals):def validate_simple(data: Any) -> Literal[True]: # always returns True...MODE = Literal['r', 'rb', 'w', 'wb']def open_helper(file: str, mode: MODE) -> str:...open_helper('/some/path', 'r') # Passes type checkopen_helper('/other/path', 'typo') # Error in type checkerLiteral[...] cannot be subclassed. At runtime, an arbitrary valueis allowed as type argument to Literal[...], but type checkers mayimpose restrictions."""# There is no '_type_check' call because arguments to Literal[...] are# values, not types.parameters = _flatten_literal_params(parameters)try:parameters = tuple(p for p, _ in _deduplicate(list(_value_and_type_iter(parameters))))except TypeError: # unhashable parameterspassreturn _LiteralGenericAlias(self, parameters)
查询选项属性
**max_results
:返回的最大结果数量,默认为 5。**search_depth
:查询的深度,可以是"basic"
或"advanced"
,默认是"advanced"
。**include_domains
:一个包含在结果中的域名列表(默认为空,即包含所有域名)。exclude_domains
:一个排除在结果之外的域名列表。include_answer
:是否在结果中包含简短答案,默认值为False
。include_raw_content
:是否返回 HTML 原始内容的解析结果(默认关闭)。include_images
:是否在结果中包含相关图片,默认值为False
。
需要子类实现的抽象方法
@abstractmethoddef _run(self, *args: Any, **kwargs: Any) -> Any:"""Use the tool.Add run_manager: Optional[CallbackManagerForToolRun] = Noneto child implementations to enable tracing."""
以 TavilySearchResults(BaseTool)
为例
api_wrapper: TavilySearchAPIWrapper = Field(default_factory=TavilySearchAPIWrapper) # type: ignore[arg-type]
api_wrapper
是一个TavilySearchAPIWrapper
实例,用于封装 API 调用的细节
class TavilySearchAPIWrapper(BaseModel):"""Wrapper for Tavily Search API."""tavily_api_key: SecretStrmodel_config = ConfigDict(extra="forbid",)@model_validator(mode="before")@classmethoddef validate_environment(cls, values: Dict) -> Any:"""Validate that api key and endpoint exists in environment."""tavily_api_key = get_from_dict_or_env(values, "tavily_api_key", "TAVILY_API_KEY")values["tavily_api_key"] = tavily_api_keyreturn valuesdef raw_results(self,query: str,max_results: Optional[int] = 5,search_depth: Optional[str] = "advanced",include_domains: Optional[List[str]] = [],exclude_domains: Optional[List[str]] = [],include_answer: Optional[bool] = False,include_raw_content: Optional[bool] = False,include_images: Optional[bool] = False,) -> Dict:params = {"api_key": self.tavily_api_key.get_secret_value(),"query": query,"max_results": max_results,"search_depth": search_depth,"include_domains": include_domains,"exclude_domains": exclude_domains,"include_answer": include_answer,"include_raw_content": include_raw_content,"include_images": include_images,}response = requests.post(# type: ignoref"{TAVILY_API_URL}/search",json=params,)response.raise_for_status()return response.json()def results(self,query: str,max_results: Optional[int] = 5,search_depth: Optional[str] = "advanced",include_domains: Optional[List[str]] = [],exclude_domains: Optional[List[str]] = [],include_answer: Optional[bool] = False,include_raw_content: Optional[bool] = False,include_images: Optional[bool] = False,) -> List[Dict]:"""Run query through Tavily Search and return metadata.Args:query: The query to search for.max_results: The maximum number of results to return.search_depth: The depth of the search. Can be "basic" or "advanced".include_domains: A list of domains to include in the search.exclude_domains: A list of domains to exclude from the search.include_answer: Whether to include the answer in the results.include_raw_content: Whether to include the raw content in the results.include_images: Whether to include images in the results.Returns:query: The query that was searched for.follow_up_questions: A list of follow up questions.response_time: The response time of the query.answer: The answer to the query.images: A list of images.results: A list of dictionaries containing the results:title: The title of the result.url: The url of the result.content: The content of the result.score: The score of the result.raw_content: The raw content of the result."""raw_search_results = self.raw_results(query,max_results=max_results,search_depth=search_depth,include_domains=include_domains,exclude_domains=exclude_domains,include_answer=include_answer,include_raw_content=include_raw_content,include_images=include_images,)return self.clean_results(raw_search_results["results"])async def raw_results_async(self,query: str,max_results: Optional[int] = 5,search_depth: Optional[str] = "advanced",include_domains: Optional[List[str]] = [],exclude_domains: Optional[List[str]] = [],include_answer: Optional[bool] = False,include_raw_content: Optional[bool] = False,include_images: Optional[bool] = False,) -> Dict:"""Get results from the Tavily Search API asynchronously."""# Function to perform the API callasync def fetch() -> str:params = {"api_key": self.tavily_api_key.get_secret_value(),"query": query,"max_results": max_results,"search_depth": search_depth,"include_domains": include_domains,"exclude_domains": exclude_domains,"include_answer": include_answer,"include_raw_content": include_raw_content,"include_images": include_images,}async with aiohttp.ClientSession() as session:async with session.post(f"{TAVILY_API_URL}/search", json=params) as res:if res.status == 200:data = await res.text()return dataelse:raise Exception(f"Error {res.status}: {res.reason}")results_json_str = await fetch()return json.loads(results_json_str)async def results_async(self,query: str,max_results: Optional[int] = 5,search_depth: Optional[str] = "advanced",include_domains: Optional[List[str]] = [],exclude_domains: Optional[List[str]] = [],include_answer: Optional[bool] = False,include_raw_content: Optional[bool] = False,include_images: Optional[bool] = False,) -> List[Dict]:results_json = await self.raw_results_async(query=query,max_results=max_results,search_depth=search_depth,include_domains=include_domains,exclude_domains=exclude_domains,include_answer=include_answer,include_raw_content=include_raw_content,include_images=include_images,)return self.clean_results(results_json["results"])def clean_results(self, results: List[Dict]) -> List[Dict]:"""Clean results from Tavily Search API."""clean_results = []for result in results:clean_results.append({"url": result["url"],"content": result["content"],})return clean_results
raw_results()
:同步调用 API。raw_results_async()
:异步调用 API。clean_results()
:清理和格式化查询结果。
def _run(self,query: str,run_manager: Optional[CallbackManagerForToolRun] = None,) -> Tuple[Union[List[Dict[str, str]], str], Dict]:"""Use the tool."""# TODO: remove try/except, should be handled by BaseTooltry:raw_results = self.api_wrapper.raw_results(query,self.max_results,self.search_depth,self.include_domains,self.exclude_domains,self.include_answer,self.include_raw_content,self.include_images,)except Exception as e:return repr(e), {}return self.api_wrapper.clean_results(raw_results["results"]), raw_results
- 传入查询参数,调用 TavilySearchAPIWrapper 来获取结果。
- 如果查询失败,则返回错误信息。
核心方法
arun()
:run()
的异步执行版本
async def _arun(self, *args: Any, **kwargs: Any) -> Any:"""Use the tool asynchronously.Add run_manager: Optional[AsyncCallbackManagerForToolRun] = Noneto child implementations to enable tracing."""if kwargs.get("run_manager") and signature(self._run).parameters.get("run_manager"):kwargs["run_manager"] = kwargs["run_manager"].get_sync()return await run_in_executor(None, self._run, *args, **kwargs)
- 若具有
run_manager
参数,则转换为同步版本,然后使用默认执行器异步运行self._run
方法 run_in_executor
是一个异步执行器,它允许你在不同的执行器中运行同步代码,而不会阻塞当前的事件循环
invoke()
和ainvoke()
def invoke(self,input: Union[str, dict, ToolCall],config: Optional[RunnableConfig] = None,**kwargs: Any,
) -> Any:tool_input, kwargs = _prep_run_args(input, config, **kwargs)return self.run(tool_input, **kwargs)async def ainvoke(self,input: Union[str, dict, ToolCall],config: Optional[RunnableConfig] = None,**kwargs: Any,
) -> Any:tool_input, kwargs = _prep_run_args(input, config, **kwargs)return await self.arun(tool_input, **kwargs)
- 充当执行工具逻辑的入口点
- 准备输入参数,并在内部调用
run()
或arun()
相关文章:
LangGraph 源码分析 | BaseTool 模板类
文章目录 BaseTool 源码分析核心属性以 TavilySearchResults(BaseTool) 为例namedescriptionargs_schemaresponse_format查询选项属性 需要子类实现的抽象方法以 TavilySearchResults(BaseTool) 为例 核心方法arun():run()的异步执行版本invoke()和ainvoke() BaseTo…...

vulnhub靶场之JOY
一.环境搭建 1.靶场描述 Does penetration testing spark joy? If it does, this machine is for you. This machine is full of services, full of fun, but how many ways are there to align the stars? Perhaps, just like the child in all of us, we may find joy in …...

intel和AMD突然联姻,这操作给我看傻了
要说现在的显卡一哥,那肯定非 NVIDIA 莫属,不仅仅是在 AI 领域是赚的盆满钵满,更是在游戏显卡领域把红蓝两家打的节节败退。 在 6000 系列尚能与之一战的 AMD 也认清了现实,在最近宣布了下一代 8000 系列显卡放弃高端显卡战争&…...

yolo_face_pose-DataBall 人脸关键点数据集 >> DataBall
数据集下载地址:ultralyticsyolo训练自定义人脸关键点训练和验证数据集资源-CSDN文库 数据集定义: ultralytics yolo 训练自定义人脸关键点训练和验证数据集 数据集格式:yolo 训练集数量:3295 验证集数量:120 类别&a…...

Unity 山水树木
本章节内容 1. Unity对3D游戏物体的简单操作; 2. 构建山水树木的场景 1. Unity 简易操作 1.1 新建3D游戏场景 1. 打开Unity Hub,点击 New Project (新建项目)按键,选择第二项 3D(Built-In Render Pipeline)…...

Redis 性能优化选择:Pika 的配置与使用详解
引言 在我们日常开发中 redis是我们开发业务场景中不可缺少的部分。Redis 凭借其内存存储和快速响应的特点,广泛应用于缓存、消息队列等各种业务场景。然而,随着数据量的不断增长,单节点的 Redis 因为内存限制和并发能力的局限,逐…...

【某农业大学计算机网络实验报告】实验三 IP数据报发送和转发流程
实验目的: (1)掌握基本的网络配置方法。 (2)观察 IP 数据报的发送和转发流程,掌握 IP 转发分组的原理。 实验器材: 一台Windows操作系统的PC机。 实验准备: 1.配置…...
Android13 添加运行时权限
在一些场景下,需要给app 添加运行时权限,这样就不需要在使用的时候再去点击授权。 直接上代码: --- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.javab/services/core/java/com/android/server/pm…...

官方操刀占用仅6G,Win 11 LTSC详细安装、优化教程来了
前段时间微软发布 Win 11 年度重磅更新 24H2,顺便也带来了备受期待的 Win 11 2024 官方精简 LTSC(老坛酸菜)版。 Win 11 重磅更新发布,老坛酸菜版成了配角! 简单来说,Win 11 LTSC 是微软针对企业用户推出…...

【论文精读】RELIEF: Reinforcement Learning Empowered Graph Feature Prompt Tuning
RELIEF: Reinforcement Learning Empowered Graph Feature Prompt Tuning 前言AbstractMotivationSolutionRELIEFIncorporating Feature Prompts as MDPAction SpaceState TransitionReward Function Policy Network ArchitectureDiscrete ActorContinuous ActorCritic Overall…...

2023-06 GESP C++三级试卷
2023-06 GESP C三级试卷 (满分:100 分 考试时间:90 分钟) PDF试卷及答案回复:GESPC2023063 一、单选题(每题 2 分,共 30 分) 1 高级语言编写的程序需要经过以下( )操…...

Maven--简略
简介 Apache旗下的一款开源项目,用来进行项目构建,帮助开发者管理项目中的jar及jar包之间的依赖,还拥有项目编译、测试、打包的功能。 管理方式 统一建立一个jar仓库,把jar上传至统一的仓库,使用时,配置…...
leetcode 刷题day44动态规划Part13( 647. 回文子串、516.最长回文子序列)
647. 回文子串 动规五部曲: 1、确定dp数组(dp table)以及下标的含义 按照之前做题的惯性,定义dp数组的时候很自然就会想题目求什么,就如何定义dp数组。但是对于本题来说,这样定义很难得到递推关系&#x…...
华为OD机试真题---关联子串
华为OD机试中的“关联子串”题目是一个考察字符串处理和算法理解的经典问题。以下是对该题目的详细解析: 一、题目描述 给定两个字符串str1 和 str2,如果字符串 str1 中的字符, 经过排列组合后的字符串中只要有一个是 str2 的子串ÿ…...

【OpenAI】第二节(Token)什么是Token?如何计算ChatGPT的Token?
深入解析:GPT如何计算Token数?让你轻松掌握自然语言处理的核心概念!🚀 在当今的人工智能领域,GPT(Generative Pre-trained Transformer)无疑是最受关注的技术之一。无论是在文本生成、对话系统…...
GraphRAG + Ollama + Groq 构建知识库 续篇 利用neo4j显示知识库
GraphRAG Ollama Groq 构建知识库 在上一篇文章中,我们详细介绍了如何创建一个知识库。尽管知识库已经建立,但其内容的可视化展示尚未实现。我们无法直接看到知识库中的数据,也就无法判断这些数据是否符合我们的预期。为了解决这个问题&…...

工业以太网之战:EtherCAT是如何杀出重围的?
前言 EtherCAT 是一种开放的实时工业以太网协议,由德国倍福公司开发并在 2003 年 4 月的汉诺威工业博览会上首次亮相,目前由 EtherCAT 技术协会(ETG)进行维护和推广。经过 21 年的不断发展,EtherCAT 显示出极强的生命…...

轻量级可视化数据分析报表,分组汇总表!
什么是可视化分组汇总表? 可视化分组汇总表,是一种结合了数据分组、聚合计算与视觉呈现功能的数据分析展示功能。它能够按照指定的维度(如时间、地区、产品类型等)对数据进行分组,还能自动计算各组的统计指标…...

初始Python篇(4)—— 元组、字典
找往期文章包括但不限于本期文章中不懂的知识点: 个人主页:我要学编程(ಥ_ಥ)-CSDN博客 所属专栏: Python 目录 元组 相关概念 元组的创建与删除 元组的遍历 元组生成式 字典 相关概念 字典的创建与删除 字典的遍历与访问 字典…...
C#中正则表达式
在C#中,正则表达式由 System.Text.RegularExpressions 命名空间提供,可以使用 Regex 类来处理正则表达式。以下是一些常见的用法及示例。 C# 中使用正则表达式的步骤: 引入命名空间: using System.Text.RegularExpressions; 创…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...
变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析
一、变量声明设计:let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性,这种设计体现了语言的核心哲学。以下是深度解析: 1.1 设计理念剖析 安全优先原则:默认不可变强制开发者明确声明意图 let x 5; …...

7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...

深入理解JavaScript设计模式之单例模式
目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式(Singleton Pattern&#…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面
代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http…...

从零实现STL哈希容器:unordered_map/unordered_set封装详解
本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说,直接开始吧! 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...

c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...
大数据学习(132)-HIve数据分析
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言Ǵ…...

GruntJS-前端自动化任务运行器从入门到实战
Grunt 完全指南:从入门到实战 一、Grunt 是什么? Grunt是一个基于 Node.js 的前端自动化任务运行器,主要用于自动化执行项目开发中重复性高的任务,例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...