JavaSE-线程池(5)- 建议使用的方式
JavaSE-线程池(5)- 建议使用的方式
虽然JDK Executors 工具类提供了默认的创建线程池的方法,但一般建议自定义线程池参数,下面是阿里巴巴开发手册给出的理由:
另外Spring也提供了线程池的实现,比如 ThreadPoolExecutor
ThreadPoolExecutor
如下,初始化一个核心线程数为 2 ,最大线程数为 4,队列长度为 2 的线程池,其中 initialize 为线程池具体初始化方法
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import java.util.concurrent.ThreadPoolExecutor;public class ThreadPoolTaskExecutorTest {static class MyTask implements Runnable {private int i;public MyTask(int i) {this.i = i;}@Overridepublic void run() {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread() + " " + i);}}public static void main(String[] args) {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();//设置核心线程数executor.setCorePoolSize(2);//设置最大线程数executor.setMaxPoolSize(4);//设置线程被回收的空闲时长executor.setKeepAliveSeconds(6);//设置队列容量executor.setQueueCapacity(2);//设置线程前缀executor.setThreadNamePrefix("t-");//设置拒绝策略executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());//初始化线程池executor.initialize();for (int i = 1; i <= 8; i++) {try {executor.execute(new MyTask(i));} catch (Exception e) {e.printStackTrace();}}}
}
由打印结果可以看出7,8任务由于线程数达到 maxPoolSize,且队列也填充满,线程池执行了拒绝策略
18:47:12.134 [main] INFO org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor - Initializing ExecutorService
org.springframework.core.task.TaskRejectedException: Executor [java.util.concurrent.ThreadPoolExecutor@63e2203c[Running, pool size = 4, active threads = 4, queued tasks = 2, completed tasks = 0]] did not accept task: com.hs.example.base.multithread.threadpool.ThreadPoolTaskExecutorTest$MyTask@3224f60bat org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor.execute(ThreadPoolTaskExecutor.java:317)at com.hs.example.base.multithread.threadpool.ThreadPoolTaskExecutorTest.main(ThreadPoolTaskExecutorTest.java:39)
Caused by: java.util.concurrent.RejectedExecutionException: Task com.hs.example.base.multithread.threadpool.ThreadPoolTaskExecutorTest$MyTask@3224f60b rejected from java.util.concurrent.ThreadPoolExecutor@63e2203c[Running, pool size = 4, active threads = 4, queued tasks = 2, completed tasks = 0]at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047)at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823)at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369)at org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor.execute(ThreadPoolTaskExecutor.java:314)... 1 more
org.springframework.core.task.TaskRejectedException: Executor [java.util.concurrent.ThreadPoolExecutor@63e2203c[Running, pool size = 4, active threads = 4, queued tasks = 2, completed tasks = 0]] did not accept task: com.hs.example.base.multithread.threadpool.ThreadPoolTaskExecutorTest$MyTask@4bbfb90aat org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor.execute(ThreadPoolTaskExecutor.java:317)at com.hs.example.base.multithread.threadpool.ThreadPoolTaskExecutorTest.main(ThreadPoolTaskExecutorTest.java:39)
Caused by: java.util.concurrent.RejectedExecutionException: Task com.hs.example.base.multithread.threadpool.ThreadPoolTaskExecutorTest$MyTask@4bbfb90a rejected from java.util.concurrent.ThreadPoolExecutor@63e2203c[Running, pool size = 4, active threads = 4, queued tasks = 2, completed tasks = 0]at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047)at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823)at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369)at org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor.execute(ThreadPoolTaskExecutor.java:314)... 1 more
Thread[t-4,5,main] 6
Thread[t-1,5,main] 1
Thread[t-3,5,main] 5
Thread[t-2,5,main] 2
Thread[t-3,5,main] 3
Thread[t-4,5,main] 4
ThreadPoolTaskExecutor initialize 方法
在上述例子中,initialize 方法是线程池初始化的具体实现,源码如下:
public void initialize() {if (this.logger.isInfoEnabled()) {this.logger.info("Initializing ExecutorService" + (this.beanName != null ? " '" + this.beanName + "'" : ""));}if (!this.threadNamePrefixSet && this.beanName != null) {this.setThreadNamePrefix(this.beanName + "-");}。;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;this.executor = this.initializeExecutor(this.threadFactory, this.rejectedExecutionHandler);
}
由以下代码可以看出 ThreadPoolExecutor 是对 ThreadPoolExecutor 的封装,其中 this.threadFactory即为 ThreadPoolExecutor 本身,由下面的类结构图可以看出 ThreadPoolExecutor 继承自 ExecutorConfigurationSupport,而ExecutorConfigurationSupport实现了 ThreadFactory 接口
protected ExecutorService initializeExecutor(ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {BlockingQueue<Runnable> queue = this.createQueue(this.queueCapacity);ThreadPoolExecutor executor;if (this.taskDecorator != null) {executor = new ThreadPoolExecutor(this.corePoolSize, this.maxPoolSize, (long)this.keepAliveSeconds, TimeUnit.SECONDS, queue, threadFactory, rejectedExecutionHandler) {public void execute(Runnable command) {Runnable decorated = ThreadPoolTaskExecutor.this.taskDecorator.decorate(command);if (decorated != command) {ThreadPoolTaskExecutor.this.decoratedTaskMap.put(decorated, command);}super.execute(decorated);}};} else {executor = new ThreadPoolExecutor(this.corePoolSize, this.maxPoolSize, (long)this.keepAliveSeconds, TimeUnit.SECONDS, queue, threadFactory, rejectedExecutionHandler);}if (this.allowCoreThreadTimeOut) {executor.allowCoreThreadTimeOut(true);}this.threadPoolExecutor = executor;return executor;
}
ThreadPoolTaskExecutor 类结构图:

直接注入ThreadPoolTaskExecutor
除了手动实例化 ThreadPoolTaskExecutor 外,也可以直接注入 ThreadPoolTaskExecutor ,如下例:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.test.context.junit4.SpringRunner;import java.util.concurrent.CountDownLatch;@RunWith(SpringRunner.class)
@SpringBootTest
public class ThreadPoolTaskExecutorTests {static class MyTask implements Runnable {private int i;private CountDownLatch countDownLatch;public MyTask(int i, CountDownLatch countDownLatch) {this.i = i;this.countDownLatch = countDownLatch;}@Overridepublic void run() {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread() + " " + i);countDownLatch.countDown();}}@Autowiredprivate ThreadPoolTaskExecutor taskExecutor;@Testpublic void contextLoads() {CountDownLatch countDownLatch = new CountDownLatch(8);long start = System.currentTimeMillis();for (int i = 1; i <= 8; i++) {try {taskExecutor.execute(new MyTask(i, countDownLatch));} catch (Exception e) {e.printStackTrace();}}try {countDownLatch.await();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("耗时:" + (System.currentTimeMillis() - start));}}
2023-02-19 21:25:15.219 INFO 123964 --- [ main] c.h.e.aop.ThreadPoolTaskExecutorTests : Starting ThreadPoolTaskExecutorTests on 0IZV69K0AKR0ELX with PID 123964 (started by Administrator in D:\workspace\idea_workspace\idea-test\example\2-aop)
2023-02-19 21:25:15.220 INFO 123964 --- [ main] c.h.e.aop.ThreadPoolTaskExecutorTests : No active profile set, falling back to default profiles: default
2023-02-19 21:25:16.349 INFO 123964 --- [ main] c.h.e.aop.ThreadPoolTaskExecutorTests : Started ThreadPoolTaskExecutorTests in 1.571 seconds (JVM running for 3.269)
2023-02-19 21:25:16.382 INFO 123964 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
Thread[task-8,5,main] 8
Thread[task-6,5,main] 6
Thread[task-4,5,main] 4
Thread[task-2,5,main] 2
Thread[task-3,5,main] 3
Thread[task-5,5,main] 5
Thread[task-7,5,main] 7
Thread[task-1,5,main] 1
耗时:1005
2023-02-19 21:25:17.637 INFO 123964 --- [ Thread-2] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
之所以可以直接使用 ThreadPoolTaskExecutor ,是因为SpringBoot自动注入了此类,具体看
org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration:
package org.springframework.boot.autoconfigure.task;import java.util.concurrent.Executor;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.task.TaskExecutionProperties.Pool;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.task.TaskExecutorBuilder;
import org.springframework.boot.task.TaskExecutorCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.task.TaskDecorator;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;@ConditionalOnClass({ThreadPoolTaskExecutor.class})
@Configuration
@EnableConfigurationProperties({TaskExecutionProperties.class})
public class TaskExecutionAutoConfiguration {public static final String APPLICATION_TASK_EXECUTOR_BEAN_NAME = "applicationTaskExecutor";private final TaskExecutionProperties properties;private final ObjectProvider<TaskExecutorCustomizer> taskExecutorCustomizers;private final ObjectProvider<TaskDecorator> taskDecorator;public TaskExecutionAutoConfiguration(TaskExecutionProperties properties, ObjectProvider<TaskExecutorCustomizer> taskExecutorCustomizers, ObjectProvider<TaskDecorator> taskDecorator) {this.properties = properties;this.taskExecutorCustomizers = taskExecutorCustomizers;this.taskDecorator = taskDecorator;}@Bean@ConditionalOnMissingBeanpublic TaskExecutorBuilder taskExecutorBuilder() {Pool pool = this.properties.getPool();TaskExecutorBuilder builder = new TaskExecutorBuilder();builder = builder.queueCapacity(pool.getQueueCapacity());builder = builder.corePoolSize(pool.getCoreSize());builder = builder.maxPoolSize(pool.getMaxSize());builder = builder.allowCoreThreadTimeOut(pool.isAllowCoreThreadTimeout());builder = builder.keepAlive(pool.getKeepAlive());builder = builder.threadNamePrefix(this.properties.getThreadNamePrefix());builder = builder.customizers(this.taskExecutorCustomizers);builder = builder.taskDecorator((TaskDecorator)this.taskDecorator.getIfUnique());return builder;}//实例化 ThreadPoolTaskExecutor @Lazy@Bean(name = {"applicationTaskExecutor", "taskExecutor"})@ConditionalOnMissingBean({Executor.class})public ThreadPoolTaskExecutor applicationTaskExecutor(TaskExecutorBuilder builder) {return builder.build();}
}
默认配置 TaskExecutionProperties :
@ConfigurationProperties("spring.task.execution")
public class TaskExecutionProperties {private final TaskExecutionProperties.Pool pool = new TaskExecutionProperties.Pool();private String threadNamePrefix = "task-";public TaskExecutionProperties() {}public TaskExecutionProperties.Pool getPool() {return this.pool;}public String getThreadNamePrefix() {return this.threadNamePrefix;}public void setThreadNamePrefix(String threadNamePrefix) {this.threadNamePrefix = threadNamePrefix;}public static class Pool {private int queueCapacity = 2147483647;private int coreSize = 8;private int maxSize = 2147483647;private boolean allowCoreThreadTimeout = true;private Duration keepAlive = Duration.ofSeconds(60L);public Pool() {}public int getQueueCapacity() {return this.queueCapacity;}public void setQueueCapacity(int queueCapacity) {this.queueCapacity = queueCapacity;}public int getCoreSize() {return this.coreSize;}public void setCoreSize(int coreSize) {this.coreSize = coreSize;}public int getMaxSize() {return this.maxSize;}public void setMaxSize(int maxSize) {this.maxSize = maxSize;}public boolean isAllowCoreThreadTimeout() {return this.allowCoreThreadTimeout;}public void setAllowCoreThreadTimeout(boolean allowCoreThreadTimeout) {this.allowCoreThreadTimeout = allowCoreThreadTimeout;}public Duration getKeepAlive() {return this.keepAlive;}public void setKeepAlive(Duration keepAlive) {this.keepAlive = keepAlive;}}
}
相关文章:
JavaSE-线程池(5)- 建议使用的方式
JavaSE-线程池(5)- 建议使用的方式 虽然JDK Executors 工具类提供了默认的创建线程池的方法,但一般建议自定义线程池参数,下面是阿里巴巴开发手册给出的理由: 另外Spring也提供了线程池的实现,比如 Thread…...
城市轨道交通供电系统研究(Matlab代码实现)
👨🎓个人主页:研学社的博客💥💥💞💞欢迎来到本博客❤️❤️💥💥🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密…...
什么是 RESTful 风格?
一、什么是 REST ? REST即表述性状态传递(英文:Representational State Transfer,简称REST)是Roy Thomas Fielding博士在2000年他的博士论文中提出来的一种软件架构风格。它是一种针对网络应用的设计和开发方式&#…...
从业6年,对敏捷和自动化测试的一点心得
不久前,参加Thoughtworks组织的一场自动化测试的分享,同事由于出差国外不能参加,特意嘱托我提问两个问题: 在互联网这个将“敏捷”与“持续集成”进行积极实践的环境里,“敏捷测试”与“自动化测试”成了一个大家经常…...
ThreeJS 之界面控制
文章目录参考描述界面自适应问题resize 事件修改画布大小修改视锥体的宽高比全屏显示dblclick 事件检测全屏显示状态进入全屏显示状态退出全屏显示状态尾声参考 项目描述ThreeJS官方文档哔哩哔哩老陈打码搜索引擎BingMDN 文档document.mozFullScreenElementMDN 文档Element.re…...
【查找算法】解析学习四大常用的计算机查找算法 | C++
第二十二章 四大查找算法 目录 第二十二章 四大查找算法 ●前言 ●查找算法 ●一、顺序查找法 1.什么是顺序查找法? 2.案例实现 ●二、二分查找法 1.什么是二分查找法? 2.案例实现 ●三、插值查找法 1.什么是插值查找法? 2…...
Android实例仿真之一
目录 零 开局三问 第一问:为什么要有这一章? 第二问:Android算不算是一个嵌入式系统? 第三问:用什么方法来分析Android这个大系统? 一 讨论Android的流行 二 深入浅出Android 零 开局三问 在正式开始…...
软考高级-信息系统管理师之重要工具和技术的口语化表示(最新版)
重要工具和技术的口语化表示 本文主要介绍重要工具和技术的口语化解释 1、 模板、表格和标准:就是用之前的项目的模版、表格、标准,结合本项目进行了修改,在编制一些计划、方案的时候就可以采用这个工具和技术。可以拿来就用的,节约时间、提高质量的。 2、 产品分析:通过一…...
基于springboot+vue的个人健康信息服务平台
基于springbootvue的个人健康信息服务平台 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取项目下载方式🍅 一、项目背…...
SpringBoot2.x实战专题——SpringBoot2 多配置文件【开发环境、测试环境、生产环境】
SpringBoot2.x实战专题——SpringBoot2 多配置文件【开发环境、测试环境、生产环境】 目录SpringBoot2.x实战专题——SpringBoot2 多配置文件【开发环境、测试环境、生产环境】一、创建一个SpringBoot项目二、修改pom.xml中SpringBoot的版本三、配置文件3.1 application-dev.ym…...
测试2:编写测试用例的方法
2.编写测试用例的方法 7种 测试常用的方法:code review 代码静态分析、CI/CD CI–持续集成–开发成员经常集成它们的工作,尽快发现集成错误 CD–持续部署–将集成后的代码部署到更贴近真实运行的环境 2.1 测试用例的描述: 用例编号 用例…...
docker安装配置镜像加速器-拉取创建Mysql容器示例
List item docker 常见命令大全docker安装docker拉取创建Mysql容器docker 安装 1、安装链接:https://blog.csdn.net/BThinker/article/details/123358697 ; 2、安装完成需要配置docker镜像加速器 3、docker 镜像加速器推荐使用阿里云的: 编…...
WSL1和WSL2相互转换以及安装路径迁移相关问题
目录 1.从WSL 1如何切换到WSL 2? 2.从WSL 2如何切换回WSL 1? 3.WSL1转换为WSL2后,WSL1里面安装的程序和库需要重装吗? 4.WSL2转换为WSL1后,WSL2里面安装的程序和库需要重装吗? 5.如何备份WSL2…...
系统分析*
文章目录系统分析分析的任务结构化方法OO的方法的任务常用的详细调查方法有哪些?系统分析的建模TFD业务流程图DFDDD数据流图用例模型(重点用例图)用例图的内容:用例之间的关系:对象模型(类图)时…...
【redis】持久化:RDB和AOF
redis的持久化指将数据写入可靠内存中,如ssd。Redis提供了4种持久化策略 RDB:Redis Database,周期性的将某个时间点的数据集快照持久化AOF:Append Only File,每次redis服务接收到写操作(修改内存的操作),都…...
2023Python接口自动化测试实战教程,附视频实战讲解
这两天一直在找直接用python做接口自动化的方法,在网上也搜了一些博客参考,今天自己动手试了一下。 一、整体结构 上图是项目的目录结构,下面主要介绍下每个目录的作用。 Common:公共方法:主要放置公共的操作的类,比如数据库sql…...
【原创】java+swing+sqlserver药品管理系统设计与实现
之前数据库都是用的mysql,今天我们使用sqlserver在配合swing来开发一个药品管理系统。方便医院工作人员进行药品的管理,基础功能基本都是一些增删改查操作。 功能分析: 药品管理系统主要提供给管理员和员工使用,功能如下&#x…...
软考高级信息系统项目管理师系列之二十七:信息文档管理与配置管理
软考高级信息系统项目管理师系列之二十七:信息文档管理与配置管理 一、信息文档管理与配置管理内容整理二、信息系统文档管理1.信息系统文档概念2.软件文档分类与质量等级三、配置管理1.配置管理2.典型配置项3.配置项4.配置项操作权限5.配置项状态6.配置项版本号7.配置项版本管…...
软考高级-信息系统管理师之项目管理基础(最新版)
项目管理基础 项目管理特点战略管理三个过程IT项目特点项目管理概念项目管理特点软技能PRINCE2的四个要素组织结构职能型组织优缺点职能型组织优点同时,职能型组织也存在着如下缺点:项目型组织优缺点项目型组织优点项目型组织也存在着如下缺点:矩阵型组织优缺点矩阵型组织的优…...
leetcode240+Search a 2D Matrix II+从右上角开始
链接 class Solution { public:bool searchMatrix(vector<vector<int>>& matrix, int target) {if(matrix.size()0 || matrix[0].size()0) return false;int i0, jmatrix[0].size()-1; //从右上角开始while (i<matrix.size()&&j>0) {int x mat…...
树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法
树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作,无需更改相机配置。但是,一…...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...
遍历 Map 类型集合的方法汇总
1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...
8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
蓝桥杯 2024 15届国赛 A组 儿童节快乐
P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡,轻快的音乐在耳边持续回荡,小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下,六一来了。 今天是六一儿童节,小蓝老师为了让大家在节…...
BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...
.Net Framework 4/C# 关键字(非常用,持续更新...)
一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...
使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...
