新闻详情

新闻详情

首页 / 资讯中心 / 详情

SpringBoot集成Activiti 7工作流引擎:架构变化、配置实践与生产排障

发布时间:2026/9/28 15:03:59来源:尧图网络
SpringBoot集成Activiti 7工作流引擎:架构变化、配置实践与生产排障
上周帮一个团队把审批中心从 if-else 硬编码改造成工作流引擎驱动我选了 Activiti 7。这里说句实话如果不是已经在一个 SpringBoot 项目里做了两年多流程相关功能我可能也会被网上那些过时教程带偏——Activiti 7 和你在老博客里刷到的 Activiti 5/6 集成方式已经是两种不同的东西。这篇文章把我从项目搭建、流程部署、任务流转到生产排障的完整过程整理出来给准备在 SpringBoot 项目中接入 Activiti 7 工作流引擎的同学做个参考。文章不写废话每个配置、每段代码都是跑过验证的。1. 集成之前必须先认清Activiti 7的架构变化1.1 与Activiti 5/6最大的不同集成方式与安全体系老版本的 Activiti5.x、6.x集成 Spring Boot核心思路是引入一个 starter然后自己配 ProcessEngine、包扫描、服务注册社区里大量教程都停在这个年代。到了 Activiti 7架构做了大调整引擎本身被拆成了多个模块Spring Boot 集成变成了官方主推的一等公民starter 里默认带上 Spring Security 依赖认证方式也从以前自己写拦截器变成了直接吃 SecurityContext 里的用户信息。这个变化直接影响你写代码的方式。比如Activiti 7 中任务办理接口拿到当前操作人走的是org.activiti.api.runtime.shared.security.SecurityManager它内部从 Spring Security 的 Authentication 里取用户名。如果项目里没有引入 Spring Security或者引入了但没做好认证上下文那你调用 TaskRuntime、ProcessRuntime 这些新 API 时会拿到一个空用户或者直接报 401。这是很多第一次用 Activiti 7 的人最容易栽跟头的地方。另一个变化是版本号。Activiti 7 的正式版本长期停留在里程碑版本比如7.1.0.M6。网上有人看到 M 后缀就不敢用其实实际项目里跑一两年没问题的案例不少关键是依赖锁定好别混合版本。1.2 为什么不直接选Flowable同源分流的现实取舍聊 Activiti 7 的时候绕不开 Flowable因为两者同源。Activiti 5/6 时代一部分核心代码被 fork 出去成了后来的 Flowable。现在去搜流程引擎方案Flowable 因为迭代节奏更快在社区里声音也更大。但我的选择逻辑很直接团队里没人深入研究过 Flowable而 Activiti 的资料、示例、书籍更多招人也好招。Flowable 和 Activiti 的表结构确实相似BPMN 2.0 规范也都是同一套关键能力比如会签、驳回、多实例、定时器都是齐的。如果你不是遇到 Activiti 确实搞不定的需求不建议为了“更新”而换 Flowable换来换去反而多踩一遍坑。把 Activiti 7 在 SpringBoot 里吃透换成 Flowable 的迁移成本也不会太高因为 API 结构非常接近。2. 依赖引入与配置文件版本匹配是第一道坎2.1 依赖清单官方starter还不够必须引入BOM新建一个 SpringBoot 项目后第一步不是直接抄一个 starter 进 pom.xml而是先把 Activiti 的 BOM 引入依赖管理。不然你后面会遇到各种传递依赖版本冲突尤其是 Spring Security 相关 jar。我实际项目里的 pom 关键部分是这样配的dependencyManagement dependencies dependency groupIdorg.activiti.dependencies/groupId artifactIdactiviti-dependencies/artifactId version7.1.0.M6/version typepom/type scopeimport/scope /dependency /dependencies /dependencyManagement dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.activiti/groupId artifactIdactiviti-spring-boot-starter/artifactId /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency /dependencies注意这里没有手动写 Activiti 的 version交给 BOM 管理。否则你要是单独写个7.1.0.M6很容易和 Spring Boot 的 spring-boot-starter-parent 里的依赖版本打架尤其是在 spring-security 上。Spring Boot 版本这边我的实测结论是Spring Boot 2.5.x 和 Activiti 7.1.0.M6 最稳。用 Spring Boot 2.7.x 也能跑但一旦你的项目里还有其它和 Spring Security 强相关的组件比如 springdoc、oauth2 资源服务器启动时经常出现NoSuchMethodError。这不是你代码写错了纯粹是 jar 包版本不对齐下面第 5 章我会讲一个具体的排查案例。2.2 application.yml里的那些关键开关配置文件里很多人只抄了spring.datasource和spring.activiti.database-schema-update结果启动后要么自动部署不生效要么历史数据查不到。我把自己验证过的一套配置贴出来spring: datasource: url: jdbc:mysql://localhost:3306/workflow?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghainullCatalogMeansCurrenttrue username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver activiti: database-schema-update: true db-history-used: true history-level: full process-definition-location-prefix: classpath:/processes/ check-process-definitions: true async-executor-activate: false逐项解释一下为什么这么配database-schema-update: true表示启动时自动建表或升级表结构开发环境非常方便。但生产环境必须改成false或者用true配合受控发布窗口否则引擎会在启动时偷偷改表结构DBA 根本来不及 review。db-history-used: true配合history-level: full保证流程实例、任务、活动、变量的历史全部落库。你后面做流程轨迹回放、统计报表全靠这两项。history-level如果写audit部分变量变化记录会缺失排查问题时会很痛苦。async-executor-activate: false是我的习惯。Activiti 有独立的定时任务线程池处理定时器、异步延续等。如果你的流程定义里没有定时器场景没必要启动它省一点无用线程开销。等真的需要时再改成 true。process-definition-location-prefix: classpath:/processes/是固定约定Activiti 启动时会扫描这个目录下的.bpmn20.xml或者.bpmn文件做自动部署。2.3 数据源与数据库准备自动建表不是万能的Activiti 7 需要至少 5 张核心表实际会生成差不多 40 多张表名前缀是ACT_开头分成ACT_RE_流程定义、模型、部署、ACT_RU_运行时数据、ACT_HI_历史数据、ACT_GE_通用数据。数据库连接串里我加了nullCatalogMeansCurrenttrue这个参数主要解决 MySQL 8 下的一些 catalog 兼容问题。如果你用的是 MySQL 8.0驱动必须是com.mysql.cj.jdbc.Driver老驱动com.mysql.jdbc.Driver会直接报连接异常。还有字符集的问题建库语句最好显式指定CREATE DATABASE workflow DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;utf8mb4 比 utf8 更稳妥因为流程变量里可能存表情字符比如审批备注里带个 emoji普通 utf8 在某些字符集排序规则下会报 “Incorrect string value”。3. 从BPMN文件到流程实例核心API这样用3.1 一个可复用的请假审批流程BPMN模板Activiti 执行的最小单位是 BPMN 2.0 文件。我先给一个可以直接部署的请假流程它麻雀虽小五脏俱全开始事件、用户任务、排他网关、结束事件还带条件表达式。?xml version1.0 encodingUTF-8? definitions xmlnshttp://www.omg.org/spec/BPMN/20100524/MODEL xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xmlns:activitihttp://activiti.org/bpmn targetNamespacehttp://www.example.com/process process idleaveProcess name请假审批流程 isExecutabletrue startEvent idstartEvent name开始/ userTask idapplyTask name填写请假单 activiti:assignee${applyUser}/ userTask idmanagerTask name部门经理审批 activiti:assignee${managerUser}/ exclusiveGateway iddaysGateway name天数判断/ userTask idhrTask name人事备案 activiti:assignee${hrUser}/ endEvent idendEvent name结束/ sequenceFlow idflow1 sourceRefstartEvent targetRefapplyTask/ sequenceFlow idflow2 sourceRefapplyTask targetRefmanagerTask/ sequenceFlow idflow3 sourceRefmanagerTask targetRefdaysGateway/ sequenceFlow idflow4 sourceRefdaysGateway targetRefhrTask conditionExpression xsi:typetFormalExpression![CDATA[${days 3}]]/conditionExpression /sequenceFlow sequenceFlow idflow5 sourceRefdaysGateway targetRefendEvent conditionExpression xsi:typetFormalExpression![CDATA[${days 3}]]/conditionExpression /sequenceFlow sequenceFlow idflow6 sourceRefhrTask targetRefendEvent/ /process /definitions这个文件放在src/main/resources/processes/leave-process.bpmn20.xml。注意文件名后缀必须是.bpmn20.xml或者.bpmnActiviti 自动部署时靠后缀识别。流程 ID 是leaveProcess后面启动流程、查询流程定义都用这个 key不能乱改。3.2 RepositoryService部署与版本管理流程文件放好后一般不需要手动部署因为配置了check-process-definitions启动时引擎会自动扫目录。但如果你们流程文件是从数据库读取的或者需要做灰度发布那必须手动用RepositoryService部署Autowired private RepositoryService repositoryService; public String deployProcess(InputStream inputStream, String name) { Deployment deployment repositoryService.createDeployment() .name(name) .addInputStream(leave-process.bpmn20.xml, inputStream) .category(oa) .deploy(); return deployment.getId(); }部署之后同一个流程 ID 的新版本会生成新的ACT_RE_PROCDEF记录版本号递增。每次启动新流程实例时默认使用最新版本。查询所有版本可以这样ListProcessDefinition definitions repositoryService.createProcessDefinitionQuery() .processDefinitionKey(leaveProcess) .orderByProcessDefinitionVersion() .desc() .list();这里有一个容易被忽略的点旧版本流程已经启动的实例在流转过程中默认还是按旧版本的 BPMN 走。也就是说你改了流程定义不影响已经跑了一半的流程只是新起流程时用新版本。这是引擎的标准行为不用慌。3.3 RuntimeService启动实例并向流程传参启动一个流程实例对应业务上就是“张三发起一个请假申请”。需要把流程变量一并传进去尤其注意 BPMN 里用到的${applyUser}、${managerUser}、${days}这些变量引擎在走到对应节点时会实时读取。Autowired private RuntimeService runtimeService; public ProcessInstance startLeaveProcess(String applicant, String manager, int days) { MapString, Object variables new HashMap(); variables.put(applyUser, applicant); variables.put(managerUser, manager); variables.put(days, days); // 这里第二个参数是业务key方便业务系统关联 return runtimeService.startProcessInstanceByKey(leaveProcess, variables); }有一个高频翻车点${applyUser}如果没传流程不会在启动时立刻报错而是当执行到“填写请假单”这个任务时引擎尝试解析表达式applyUser发现没有这个变量直接抛ActivitiException或者流程卡住。所以流程变量的完整性要在启动前用代码做校验不要依赖引擎自动兜底。启动成功后返回的ProcessInstance对象里有processInstanceId这个 ID 是后面查询任务、回滚、查看历史的通行证记得存到业务表。3.4 TaskService查询待办与完成任务TaskService 是日常代码里调用最频繁的接口。查询张三的待办任务Autowired private TaskService taskService; public ListTask getTodoTasks(String assignee) { return taskService.createTaskQuery() .taskAssignee(assignee) .processDefinitionKey(leaveProcess) .active() .orderByTaskCreateTime() .desc() .list(); }需要注意这里.active()过滤掉挂起任务.taskAssignee()是精确匹配“指定人”。如果你用候选组或者候选人模式查询方式不一样。最简单粗暴的做法就是给每个任务节点指定具体审批人适合中小团队如果要做角色组审批就用taskCandidateGroup(manager)后面再说。完成任务时可以同时传流程变量或者局部变量public void completeTask(String taskId, boolean approved, String comment) { Task task taskService.createTaskQuery().taskId(taskId).singleResult(); if (task null) { throw new RuntimeException(任务不存在或已被办理); } MapString, Object vars new HashMap(); vars.put(approve, approved); vars.put(comment, comment); taskService.addComment(taskId, task.getProcessInstanceId(), comment); taskService.complete(taskId, vars); }这里我习惯在 complete 前先 addComment把审批意见落到引擎的ACT_HI_COMMENT表后面追溯时能直接查。complete传入的vars默认是流程实例级变量会直接影响后面网关条件的判断所以要看清你传的变量名和 BPMN 里的条件表达式是否一致。4. 审批场景里的“驳回”和“会签”到底怎么实现4.1 驳回没有现成API但有三条常见路子很多第一次用 Activiti 的人会问“引擎有没有内置驳回接口”。答案是没有“一键驳回”这种 API。Activiti 只提供流程实例推进的标准动作驳回本质上是“流程跳转”要靠流程模型设计或底层 API 实现。我在实际项目里用过三种方案按推荐程度排序第一种最推荐在 BPMN 里设计回退网关。在经理审批节点后面加一个排他网关根据审批结果决定是回退到申请节点还是继续往下走。流程定义大概长这样exclusiveGateway idresultGateway name审批结果判断/ sequenceFlow idrejectFlow sourceRefresultGateway targetRefapplyTask conditionExpression xsi:typetFormalExpression![CDATA[${approved false}]]/conditionExpression /sequenceFlow sequenceFlow idapproveFlow sourceRefresultGateway targetRefdaysGateway conditionExpression xsi:typetFormalExpression![CDATA[${approved true}]]/conditionExpression /sequenceFlow经理审批时 complete 传入approvedfalse流程会自动回到 “填写请假单” 节点申请节点重新生成一个新任务。这个方案的可控性最强业务规则一眼可见。第二种使用RuntimeService的ChangeActivityStateBuilder适合动态跳转场景runtimeService.createChangeActivityStateBuilder() .processInstanceId(processInstanceId) .moveActivityIdTo(managerTask, applyTask) .changeState();这个 API 比较底层它会把当前活动节点 managerTask 迁移到 applyTask删掉当前活动重新生成目标活动。复杂流程里如果多个分支并行很容易迁错我只在极少数动态会签场景里用日常建议走第一种。第三种是打补丁式把流程实例挂起手动改ACT_RU_TASK表任务节点再激活。这种我强烈不建议碰数据库里改完经常出现执行实例和任务状态对不上排查成本极高。4.2 会签/或签多实例节点的XML配置会签是审批流程里的高频需求。比如采购金额大于一定阈值需要三名部门经理全部同意才通过或者是签只要一个人同意就通过。Activiti 用multiInstanceLoopCharacteristics实现。userTask idcountersignTask name会签审批 activiti:assignee${assigneeUser} multiInstanceLoopCharacteristics isSequentialfalse activiti:collection${countersignUsers} activiti:elementVariableassigneeUser completionCondition${nrOfCompletedInstances 2}/completionCondition /multiInstanceLoopCharacteristics /userTask这段配置的含义是集合变量countersignUsers里有多少人就并行生成多少个待办任务每个任务指派给assigneeUser即集合里的每一个人。等完成数量达到 2 个整个会签节点就提前流转。如果去掉completionCondition默认是集合里所有人都完成才流转。启动流程时需要传集合变量MapString, Object vars new HashMap(); vars.put(countersignUsers, Arrays.asList(userA, userB, userC)); vars.put(applyUser, zhangsan); runtimeService.startProcessInstanceByKey(leaveProcess, vars);办理每一个人任务时还是走taskService.complete(taskId, variables)。这里有个小技巧如果想记录每个人在会签中的独立意见用局部变量不要用流程级变量。taskService.setVariableLocal(taskId, opinion, 同意); taskService.complete(taskId);这样每个子任务的局部变量互不影响历史表里能清楚看到谁签了什么意见。等completionCondition触发后nrOfCompletedInstances会带着所有子任务的结果一起汇总。4.3 流程变量作用域很多人在这里翻车流程变量有三种常见作用域流程实例级、执行实例级、任务级。简单记setVariable是流程实例级全局可见setVariableLocal是当前执行实例或任务级局部可见。最开始带我的老师傅说过一句让我印象很深的话“流程变量不是你放在 HashMap 里就能随便读的变量作用域理解错了等于把钥匙藏在别人兜里。” 实操中我在会签节点踩过一个坑用setVariableLocal存了审批意见结果在会签完成后的排他网关里读不到因为网关是在父执行实例上求值读的是流程实例级变量。正确做法是影响流程走向的数据统一用setVariable存流程实例级只有各节点内部处理用的临时数据才用局部变量。5. 我在实际项目中踩过的几个坑5.1 启动报NoSuchMethodErrorjar包冲突排查链路我接手的那个项目Spring Boot 版本是 2.7.18引入 Activiti 7.1.0.M6 后应用启动直接报java.lang.NoSuchMethodError: org.springframework.security.web.SecurityFilterChain这个问题最可恨的点在于报错信息和你的业务代码毫无关系完全看不出来是谁触发的。我当时的排查链路分享给你第一步看完整堆栈找到第一个出现Caused by的位置确认是 Spring Security 相关类加载冲突。第二步跑mvn dependency:tree -Dincludesorg.springframework.security看到 activiti-spring-boot-starter 传递进来的 spring-security-web 版本是 5.3.x而 Spring Boot 2.7.18 期望的 SecurityFilterChain 是 5.7.x 的 API两个版本在SecurityFilterChain的接口定义上发生了二进制不兼容。第三步解决方案有两条路把 Spring Boot 降到 2.5.5 左右或者用 dependencyManagement 手动锁定 spring-security 版本。我当时选择了把 Spring Boot 从 2.7.18 降到 2.5.5问题消失整个项目不再出现类似冲突。这里我要强调一个观念SpringBoot 版本不是越新越好要看你集成的中间件支持到什么版本。Activiti 7 官方支持矩阵当时主要对齐 Boot 2.x 的中期版本你硬上 Boot 2.7 就是给自己找事。5.2 流程图中文乱码字体文件缺失流程部署后在流程跟踪页面看流程图节点名称的中文全部变成方框。一开始我怀疑是数据库字符集问题检查了一圈发现 BPMN 文件是 UTF-8表也是 utf8mb4数据库没问题。后来才定位到Activiti 7 生成流程图时用的是 Java 的图形库默认字体是 Dialog这种字体在 Linux 服务器上不包含中文字形画图时中文就变成方块。解决办法是给 ProcessEngineConfiguration 指定中文字体Bean public ProcessEngineConfigurationConfigurer processEngineConfigurationConfigurer() { return config - { config.setActivityFontName(宋体); config.setLabelFontName(宋体); config.setAnnotationFontName(宋体); }; }如果你用的 Docker 镜像比较精简可能连宋体都没装那还要在镜像里装fonts-wqy-microhei之类的中文字体包。这个问题在本地 Windows 开发环境不一定能复现到 Linux 环境才爆所以别用“我本地正常”来推断服务器行为。5.3 Spring Security拦截导致流程接口401Activiti 7 的 starter 自带 spring-boot-starter-security 依赖项目启动后控制台会打印 “Using generated security password: xxxx”然后你所有工作流接口都是 401。这个问题本质上是 Activiti 7 希望你提供认证用户。如果你项目里本身有登录系统就把你已有的登录逻辑接入 Spring Security让请求带着认证信息进来。如果只是内部管理系统演示可以直接配置放行所有请求Configuration public class ActivitiSecurityConfig { Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests() .anyRequest().permitAll() .and() .httpBasic(); return http.build(); } }但注意这里只是解决了接口访问权限问题。如果你用了 ProcessRuntime 这类新 API它内部还是要从 SecurityContextHolder 拿用户名拿不到会报InsufficientAuthenticationException。所以从业务角度看还是应该把当前登录用户塞进 SecurityContext或者尽量用老牌的 RuntimeService、TaskService它们不受 SecurityContext 强制约束。5.4 查不到历史数据history相关配置被漏掉项目上线两周后业务方要拉一个“所有已完成请假流程”的报表结果HistoryService查出来是空的但 ACT_RU_* 表有数据。我们查了半天最后发现application.yml里只配了spring.activiti.database-schema-update: true没配db-history-used和history-level默认值没有把完整历史记录下来。把配置补齐后重启新产生的流程实例历史数据就正常了。注意已经产生但没记录完整历史的流程实例不会自动补数据只能存量数据做清洗或者按业务表信息手工补录。所以历史配置一定要在项目早期就定好。6. 生产级经验监控、清理与性能优化6.1 核心表结构速记排查问题先看哪张表工作流引擎出问题时不要一根筋查代码先看表。我把常用表整理成一张表排查时按图索骥表名归属作用ACT_RE_DEPLOYMENT仓库部署记录一个部署对应一个文件包ACT_RE_PROCDEF仓库流程定义一个流程ID会有多个版本ACT_RU_EXECUTION运行时执行实例核心流程跳转状态ACT_RU_TASK运行时待办任务当前谁在处理ACT_RU_VARIABLE运行时流程变量当前运行中的变量值ACT_HI_PROCINST历史历史流程实例流程生命周期ACT_HI_TASKINST历史历史任务实例所有任务创建和完成时间ACT_HI_ACTINST历史历史活动实例每个节点的执行记录ACT_HI_VARINST历史历史变量流程变量变化后的最终值ACT_HI_COMMENT历史审批意见和备注举个例子一个流程实例卡在“部门经理审批”没有流转你可以先去 ACT_RU_TASK 看 assignee、create_time再去 ACT_RU_EXECUTION 看当前活动节点如果 ACT_RU_TASK 为空而 ACT_RU_EXECUTION 还有记录说明执行实例卡在某个非用户节点上典型的场景是排他网关没有匹配条件流程没有可走的出口。这种问题在 BPMN 设计器里看不出来跑起来才发现。6.2 数据膨胀历史表清理与归档策略Activiti 的 ACT_HI_ACTINST 表增长速度吓人一次流程流转经过五六个节点就会产生五六个活动实例记录。半年下来表轻松百万级数据查询历史开始变慢。不要等到卡了再后悔。我在项目里留了一个定时任务按季度把三个月前的历史数据搬到历史库Scheduled(cron 0 0 2 1 * ?) public void archiveHistory() { Date threshold DateUtils.addMonths(new Date(), -3); ListHistoricProcessInstance oldInstances historyService.createHistoricProcessInstanceQuery() .finishedBefore(threshold) .list(); for (HistoricProcessInstance instance : oldInstances) { historyService.deleteHistoricProcessInstance(instance.getId()); } }这里用deleteHistoricProcessInstance会级联删除该实例的历史活动、历史任务、历史变量比较彻底。但如果业务需要保留审计轨迹就不能这样删应该把数据同步到归档表或者冷存储再从引擎表物理删除。大批量删除时ACT_HI_ACTINST 表还会涉及关联外键建议一次删 5000 条左右循环处理不要一次性删几十万行会把 InnoDB 锁持有时间拉长影响在线业务。6.3 异步执行器与缓存参数调整Activiti 7 引擎在启动时会初始化一个异步定时执行器如果你流程里没有定时器、异步延续之类的需求把它关掉最简单spring.activiti.async-executor-activate: false。流程定义缓存方面默认情况下引擎会把最近用到的流程定义缓存到内存避免每次任务都重新解析 BPMN。如果你的系统中有大量不同的流程定义可以配置缓存上限防止内存被顶爆spring: activiti: process-definition-cache-limit: 128另外数据库层面ACT_HI_ACTINST、ACT_HI_TASKINST 这种大表的查询很依赖索引。Activiti 建表脚本自带了一部分索引但实际查询条件可能和默认索引对不上比如你要按PROC_INST_ID_ START_TIME_查历史活动建议自己补一个组合索引。ALTER TABLE ACT_HI_ACTINST ADD INDEX idx_proc_start_time (PROC_INST_ID_, START_TIME_);建完后用EXPLAIN验证一下执行计划别盲目建一堆冗余索引写入性能也会受影响。最后再分享一个小技巧如果你们的流程定义文件频繁改动调试时想让探索环境自动重部署可以写一个监听器监听本地文件变更后调用repositoryService.createDeployment()重新部署并且在 BPMN 里给流程定义加一个版本后缀比如leaveProcess_v2这样新老流程都能在引擎上共存不会影响正在跑的旧流程实例。这个习惯我一直沿用到生产大大降低了流程变更的上线风险。我个人的体会是Activiti 7 本身不复杂复杂的是你所在业务系统里那些边界条件——审批人怎么定、超时怎么提醒、驳回能不能限制次数、会签通过率怎么算。先用透这篇文章里的基础链路再把边界一个一个补上流程引擎才能真正变成你业务的中枢而不是另一个需要人维护的“复杂系统”。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

TP9932换XS9922C实战:车载视频解码芯片替代的引脚与配置全解析 2026/9/28 15:53:30

TP9932换XS9922C实战:车载视频解码芯片替代的引脚与配置全解析

做车载摄像头的同行应该对TP9932这颗芯片不陌生,尤其是做360环视、ADAS、DMS后装方案的工程师,前几年大量方案都是围绕它做的。最近我这边接到一个项目,客户明确要求把原方案里的TP9932替换成芯昇的XS9922C,说是成本、供货和交期方…

阅读更多 →
TP9932到XS9922C:车载模拟高清解码芯片国产替代实战指南 2026/9/28 15:53:30

TP9932到XS9922C:车载模拟高清解码芯片国产替代实战指南

做车载环视和安防 DVR 开发的老朋友,对 TP9932 这颗料应该都不陌生。它作为多路模拟高清解码芯片,在 AHD/TVI/CVI 混用时代几乎是方案标配,负责把四路模拟摄像头信号统一解码,再转成 SoC 能直接吃的 MIPI 或 BT656 数据。最近这两…

阅读更多 →
Steam评论情感分析:Python爬虫+hanlp分词+pyecharts可视化 2026/9/28 15:53:30

Steam评论情感分析:Python爬虫+hanlp分词+pyecharts可视化

简介:基于哈工大语言平台的蒸汽平台评论爬取情感分析可视化源码,是一份可直接运行的课程设计与期末大作业方案,面向需要完成数据分析类项目的学习者。项目完整覆盖评论采集、文本清洗、情感判断与图表展示等环节,从接口请求到数据…

阅读更多 →
RAG实战:从朴素向量检索到混合检索+重排序的完整改造指南 2026/9/28 15:53:30

RAG实战:从朴素向量检索到混合检索+重排序的完整改造指南

1. 为什么朴素向量检索会翻车:一次险些上线的业务事故先讲个真实经历。早前接了一个内部知识库问答项目,文档量不大,也就几千篇,内容覆盖公司制度、产品手册、技术规范。第一版我图省事,直接走了最标准的朴素RAG路线&a…

阅读更多 →
微信开源知识库项目:企业级RAG问答系统部署与调优实践 2026/9/28 15:53:30

微信开源知识库项目:企业级RAG问答系统部署与调优实践

手里囤了几十个知识库项目,个人博客也折腾过不少,但最近看到“微信开源了一个神级知识库项目”这个话题被反复刷屏时,我还是没忍住,连夜翻文档、搭环境、导入文档、跑通了完整的知识库问答链路。说实话,这几年开源知识…

阅读更多 →
AI Agent操作在线表格:Univer开源SDK架构与实战解析 2026/9/28 15:53:23

AI Agent操作在线表格:Univer开源SDK架构与实战解析

1. 为什么 AI Agent 需要自己的办公“底座”:Univer 的生态位AI Agent 圈子里最近讨论最多的,已经不再是“能不能多轮对话”,而是“能不能把对话变成文档、表格、演示文稿”。原因很简单:企业办公里真正产生价值的产物&#xff0c…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉