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; 创…...
3大核心功能构建学术研究知识库:Obsidian科研模板实战指南
3大核心功能构建学术研究知识库:Obsidian科研模板实战指南 【免费下载链接】obsidian_vault_template_for_researcher This is an vault template for researchers using obsidian. 项目地址: https://gitcode.com/gh_mirrors/ob/obsidian_vault_template_for_res…...
小程序制作平台哪个好,新手好用开发工具推荐
小程序制作平台终极对决:码云数智、有赞、微盟,谁才是你的命定之选?2026年的小程序赛道,早已不是"一招鲜吃遍天"的时代。当数字化转型成为每一个商家的必答题,选平台就不再是选一个工具,而是选一…...
从《GPU Gems》到实战:次表面散射(SSS)的四种“平替”方案全解析(含代码对比)
从《GPU Gems》到实战:次表面散射(SSS)的四种“平替”方案全解析(含代码对比) 在实时渲染领域,次表面散射(Subsurface Scattering,简称SSS)一直是提升材质真实感的关键技…...
别再让烙铁头‘烧死’了!手把手教你电烙铁日常保养与复活术(附温度设置建议)
电烙铁头养护全攻略:从氧化原理到实战修复技巧 1. 烙铁头氧化背后的科学原理 烙铁头氧化并非单纯由高温引起,而是高温与氧气共同作用的结果。当烙铁头暴露在空气中时,高温会加速金属表面与氧气的化学反应,形成一层致密的氧化层。这…...
CBAM注意力机制:为什么它比SENet更胜一筹?深入对比通道与空间注意力设计
CBAM注意力机制:通道与空间双重视角下的性能突破 在计算机视觉领域,注意力机制已经成为提升卷积神经网络性能的关键技术之一。当我们面对ImageNet分类、目标检测等复杂任务时,网络需要学会"看重点"——自动识别图像中最相关的区域和…...
2026届必备的六大AI辅助论文方案实际效果
Ai论文网站排名(开题报告、文献综述、降aigc率、降重综合对比) TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 处在信息爆炸的当下之时段,内容创作成为了个人以及企业的核心竞争力所在。针对广…...
别再只用BLAST了!试试MAFFT+HMMER这套组合拳,挖掘基因家族新成员更精准
基因家族分析进阶指南:MAFFT与HMMER的高效组合策略 在基因组学研究领域,识别基因家族成员是一项基础而关键的工作。传统方法如BLAST虽然广为人知,但在面对远缘同源基因或高度分化的基因家族时,其灵敏度往往不尽如人意。这时&#…...
CTF夺旗赛利器:手把手教你用GitHack挖掘.git泄露背后的Web漏洞
CTF夺旗赛利器:手把手教你用GitHack挖掘.git泄露背后的Web漏洞 在CTF竞赛和实战渗透测试中,.git目录泄露一直是Web安全领域的经典漏洞场景。这种看似简单的配置错误,往往能成为攻击者打开系统后门的金钥匙。本文将带您深入探索如何利用GitHac…...
探索Artisan:用开源软件解码咖啡烘焙的数据科学
探索Artisan:用开源软件解码咖啡烘焙的数据科学 【免费下载链接】artisan artisan: the worlds most trusted roasting software 项目地址: https://gitcode.com/gh_mirrors/ar/artisan 在咖啡烘焙的世界里,每一次烘焙都是一次精确的化学反应。从…...
Tauri 无边框窗口避坑指南:解决`data-tauri-drag-region`在多层嵌套div中失效的完整方案
Tauri 无边框窗口拖拽区域深度解析:从失效原理到工程化解决方案 当你在Tauri应用中精心设计了无边框窗口的拖拽区域,却发现data-tauri-drag-region属性在多层嵌套的DOM结构中神秘失效时,这绝不仅仅是一个简单的API使用问题。本文将带你深入浏…...
