尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Vue3 组合查询条件树组件:递归渲染、序列化与校验实践
简介面向 Vue.js 前端开发者的一份组合查询条件示例源码适合正在实现多字段筛选、动态查询参数拼装与结果联动更新的初中级开发者参考。代码围绕组件化查询表单展开输入框、下拉选择、日期等字段各自独立封装借助计算属性与侦听器组合查询参数并用 Vuex 集中管理查询条件与结果状态配合 axios 发起请求、Vue Router 管理结果页路由较完整地呈现了从表单绑定到数据回显的响应式链路对理解查询条件如何驱动视图更新、请求参数如何分层组织尤其有帮助。压缩包共 32 个文件约 139KB以 14 个 js 脚本、4 个 vue 单文件组件和 5 个 xml 配置为主另含 json、html、png 等工程与说明文件目录涵盖 src、router、store、build、config 等模块结构清晰便于按层阅读。目前已有 1278 人学习下载可作为搭建后台列表筛选功能时的结构参照与排错对照。1. 从一张越堆越长的筛选面板说起vue 组合查询条件源码值不值得拆运营后台的筛选区大概是最容易被低估的地方。一开始只是「用户名 状态下拉」三个月后变成「注册时间区间、来源渠道多选、订单数大于、标签包含任意一个、手机号模糊匹配」模板里塞满了v-if每加一个字段就要改一次页面、发一次版。把这份 vue 组合查询条件源码拆完最直接的感受是筛选不该写成模板应该写成数据结构——字段是一份配置条件是用户点出来的一棵树页面只负责把这棵树画出来。这份资源给的就是一整套条件树组件、操作符字典、序列化与校验逻辑适合正在做中后台、低代码表单、报表查询页的开发者尤其适合那种「筛选条件由产品随时改」的项目。2. 目录与技术选型这份 vue 组合查询条件源码的骨架长什么样先看骨架再谈实现。整套东西是 Vue 3 script setup写的构建工具用 Vite样式基本裸写、不绑定组件库输入控件那层留了插槽和映射表所以你可以接 Element Plus、Ant Design Vue也可以纯原生input。这个选择挺务实查询构造器这种东西一旦和某个 UI 库绑死换库就得重写而它真正有价值的部分是数据模型和序列化不是按钮长什么样。2.1 目录结构与每个文件的职责src/ ├── components/ │ ├── QueryBuilder.vue # 对外入口布局、操作按钮、校验结果汇总 │ ├── ConditionGroup.vue # 递归节点渲染一组 AND/OR 子条件自己嵌套自己 │ ├── ConditionRow.vue # 单条条件字段选择 / 操作符选择 / 值输入 │ └── ValueInput.vue # 按字段类型动态切换输入控件文本框、下拉、日期区间 ├── composables/ │ ├── useConditionTree.js # 树的增删改、路径查找、节点 id 生成 │ └── useOperator.js # 操作符与字段类型的匹配、操作符元信息查询 ├── core/ │ ├── operators.js # 操作符字典eq/like/between/in… │ ├── serialize.js # 条件树 → JSON DSL / SQL 片段双出口 │ └── validate.js # 递归校验返回错误路径 ├── presets/ │ └── fields.js # 字段元数据示例用户名、注册时间、渠道、订单数 └── App.vue # 演示页接一份假的列表数据这个划分的关键点是core目录不 import 任何 Vue 的东西。serialize.js和validate.js是纯函数输入一个普通对象输出一个普通对象。这个约束看着不起眼实际很救命——后端同学要对照 DSL 结构时你可以直接把core丢给他跑单测不用起一个 Vue 环境将来要做「查询条件保存为常用视图」序列化逻辑也能直接搬到 Node 侧复用。文件是否依赖 Vue主要职责改造频率QueryBuilder.vue是入口、按钮、校验汇总低ConditionGroup.vue是递归渲染、组级操作中ConditionRow.vue是字段/操作符切换、值重置中ValueInput.vue是控件映射高换 UI 库时core/serialize.js否树 → DSL / SQL高对接后端时core/validate.js否递归校验低presets/fields.js否业务字段配置最高每个项目都改2.2 数据模型为什么是树不是扁平数组扁平数组[{field, op, value}, ...]只能表达「全部 AND」一旦产品说「渠道是 A 或 B并且订单数大于 3」扁平结构就塌了只能在字段值里塞数组做特殊处理越写越玄学。树形结构把「组」和「条件」区分开逻辑关系挂在组上表达能力立刻够了{ id: g_root, type: group, logic: AND, children: [ { id: c_1, type: condition, field: channel, operator: in, value: [a, b] }, { id: g_2, type: group, logic: OR, children: [ { id: c_2, type: condition, field: orderCount, operator: gt, value: 3 }, { id: c_3, type: condition, field: orderCount, operator: between, value: [10, 20] } ] } ] }几个字段的含义type只有group和condition两种递归时靠它分流logic只出现在组节点上取值为AND/ORid用于v-for的 key 和路径定位必须全局唯一别用索引——索引做 key在中间插入或删除节点时会触发复用错乱输入框里的值会「跳到」另一行去这个坑我在别的列表组件里踩过不止一次。value的形状跟着操作符走in和between是数组其余是标量。这套约定要提前和后端对齐别一边传[1,2]一边传1,2联调时能吵半天。2.3 依赖与启动三条命令把 demo 跑起来依赖极简Vue 3 是硬依赖其余都是可选的。核心依赖大致是这样{ name: vue-query-builder, scripts: { dev: vite, build: vite build, preview: vite preview }, dependencies: { vue: ^3.4.0 }, devDependencies: { vite: ^5.0.0, vitejs/plugin-vue: ^5.0.0 } }如果你打算用现成的下拉和日期控件再加一行element-plus或ant-design-vue然后在ValueInput.vue的映射表里换掉原生标签就行组件逻辑不用动。启动流程没什么花样# 装依赖 npm install # 起开发服务器默认 http://localhost:5173 npm run dev # 生产构建产物在 dist/ npm run build跑起来之后页面上是一个默认带两三条条件的面板可以点「 条件」加一行点「 条件组」加一个嵌套组组头部的下拉能在「且 / 或」之间切。打开控制台点提交时能看到serialize打印出的 DSL 结构——先看这个结构比读代码更快建立对整棵树的直觉。提示如果你的宿主项目还是 Vue 2别急着照搬script setup。Vue 2.7 已经支持 Composition API把setup语法换成setup()函数返回即可递归组件的name选项必须显式写上这个后面会细说。3. 递归渲染链路条件树是怎么一层层变成可操作面板的组件里唯一有难度的地方就是递归。ConditionGroup渲染自己ConditionRow渲染叶子ValueInput负责最终那个输入框。三层各管一段边界清楚改起来才不会一改全崩。这里我把每个文件的核心逻辑拆开讲你可以直接对着抄。3.1 ConditionGroup递归节点与组级操作组节点要做三件事渲染组头逻辑切换 增删按钮、渲染本组内的条件行、渲染子组并把自己再调一次。!-- ConditionGroup.vue -- script setup import { computed } from vue import ConditionRow from ./ConditionRow.vue const props defineProps({ node: { type: Object, required: true }, // 当前组 { id, type:group, logic, children } fields: { type: Array, default: () [] }, // 字段元数据原样往下传 depth: { type: Number, default: 0 } // 嵌套层级控制缩进与最大深度 }) const emit defineEmits([add-row, add-group, remove-node, update-logic, change-row]) // 硬限制三层且嵌套或再嵌套且之上基本没人看得懂也没人维护得了 const canNest computed(() props.depth 3) const rows computed(() props.node.children.filter(c c.type condition)) const groups computed(() props.node.children.filter(c c.type group)) /script template div classqb-group :class{ qb-group--nested: depth 0 } div classqb-group__head select :valuenode.logic changeemit(update-logic, node.id, $event.target.value) option valueAND且/option option valueOR或/option /select button typebutton clickemit(add-row, node.id) 条件/button button v-ifcanNest typebutton clickemit(add-group, node.id) 条件组/button button v-ifdepth 0 typebutton clickemit(remove-node, node.id)删除组/button /div !-- 叶子条件 -- ConditionRow v-forchild in rows :keychild.id :nodechild :fieldsfields change(patch) emit(change-row, child.id, patch) removeemit(remove-node, child.id) / !-- 递归自己子组继续走同一套渲染 -- ConditionGroup v-forchild in groups :keychild.id :nodechild :fieldsfields :depthdepth 1 add-rowemit(add-row, $event) add-groupemit(add-group, $event) remove-nodeemit(remove-node, $event) update-logic(id, logic) emit(update-logic, id, logic) change-row(id, patch) emit(change-row, id, patch) / /div /template参数说明node是当前子树组件不持有任何副本纯靠 props 往下传depth从 0 开始每递归一层加 1同时用于缩进和canNest判断fields是字段元数据一路透传保证每一个叶子节点都能拿到完整的字段清单。事件全部往上抛组件自身不修改props.node这是 Vue 单向数据流的硬要求也是后面「删了没反应」那个坑的根源。为什么用事件冒泡而不是provide/inject直接操作因为树的写操作集中到最顶层一个 composable 里做不可变更新更好排查任何一次改动都会产生一棵新树把前后两棵树打印出来对比问题基本就锁定了。provide/inject少写几行但出问题时改动的来源满天飞。3.2 ConditionRow字段一换值和操作符都得重置这一行看着简单实际是 bug 高发区。用户先选了「注册时间」配了日期区间又改成「用户名」如果只更新field而不管value输入框会拿着一个数组去渲染文本框页面上出现[object Object]甚至直接报错。!-- ConditionRow.vue -- script setup import { computed } from vue import ValueInput from ./ValueInput.vue const props defineProps({ node: { type: Object, required: true }, // { id, type:condition, field, operator, value } fields: { type: Array, default: () [] } }) const emit defineEmits([change, remove]) const currentField computed(() props.fields.find(f f.key props.node.field)) const operators computed(() currentField.value?.operators || [eq]) // 切字段操作符回落到该字段合法的第一个值按新字段的形态重置 function onFieldChange(key) { const field props.fields.find(f f.key key) emit(change, { field: key, operator: field?.operators?.[0] || eq, value: field?.valueType array ? [] : }) } // 切操作符只在形态变化时重置比如 eq - between 要从标量变数组 function onOperatorChange(op) { const needArray op between || op in const isArray Array.isArray(props.node.value) emit(change, { operator: op, value: needArray isArray ? props.node.value : (needArray ? [] : ) }) } /scriptvalueType是字段元数据里自己定的约定取值string/number/array/date它决定了新条件初始值的形态。onOperatorChange里那个needArray isArray判断是个小技巧形态没变就别动值用户从gt切到gte时输过的数字应该留着别一刀切清空那种体验很烦人。注意emit(change, patch)传的是补丁对象而不是完整节点由顶层合并。这样快速连续切换时不会因为拿到的props.node是旧快照而互相覆盖。3.3 ValueInput一张映射表搞定所有控件类型值输入这一层最容易写成一堆v-if。写在模板里加一种类型就多一个分支半年后没人敢动。改成映射表的思路是字段元数据里用widget声明该用哪种控件组件只负责把widget映射到具体组件。!-- ValueInput.vue -- script setup import { computed } from vue const props defineProps({ field: { type: Object, default: () ({}) }, modelValue: { type: [String, Number, Array, Date, null], default: } }) const emit defineEmits([update:modelValue]) const widget computed(() props.field?.widget || input) const options computed(() props.field?.options || []) function update(v) { emit(update:modelValue, v) } /script template !-- 文本框eq / like / ne 这类单值操作符默认走这里 -- input v-ifwidget input :valuemodelValue inputupdate($event.target.value) / !-- 数字框注意转 Number后端拿到字符串会报类型错 -- input v-else-ifwidget number typenumber :valuemodelValue inputupdate($event.target.value ? : Number($event.target.value)) / !-- 下拉单选或多选由字段的 multiple 决定 -- select v-else-ifwidget select :multiplefield.multiple :valuemodelValue changeupdate( field.multiple ? Array.from($event.target.selectedOptions).map(o o.value) : $event.target.value ) option v-foropt in options :keyopt.value :valueopt.value{{ opt.label }}/option /select !-- 日期区间输出固定为 [start, end] 两元素数组 -- span v-else-ifwidget daterange input typedate :valuemodelValue?.[0] || changeupdate([$event.target.value, modelValue?.[1] || ]) / input typedate :valuemodelValue?.[1] || changeupdate([modelValue?.[0] || , $event.target.value]) / /span /templatewidget支持input/number/select/daterange四种够覆盖中后台八成场景剩下的用插槽扩展。这里特意把数字框做了Number()转换——原生input的value永远是字符串orderCount 3传给后端变成3很多 ORM 会做隐式转换但一旦碰上严格类型校验就直接 400属于典型的联调翻车点。同理日期控件输出的2024-05-01这种字符串要不要转时间戳最好在序列化层统一处理而不是散落在各个控件里。4. 序列化与校验把条件树翻译成后端接口认的参数树画出来了接下来是把它变成后端能吃的东西。这一步决定了整套组件是「好看但没用」还是「真能落地」。平时我会准备两个出口一个结构化 JSON DSL交给后端自己解析一个带占位符的 SQL 片段给那些只接受原生条件的查询接口用。前者是主流后者是兜底。4.1 serialize空节点剪枝与单子节点扁平化序列化最容易忽略的不是拼接是「清理」。用户点了「 条件组」但没填任何东西直接提交后端收到一个空 children 的组解析出来就是AND ()语法错误。所以serialize的第一职责是丢垃圾。// core/serialize.js // 单条条件是否有效字段必须有值不能是空字符串 / null / 空数组 function isValidCondition(node) { if (!node.field) return false const v node.value if (v || v null || v undefined) return false if (Array.isArray(v) (v.length 0 || v.some(x x || x null))) return false return true } /** * 条件树 - JSON DSL * param {Object} node 组节点或条件节点 * returns {Object|null} null 表示该分支整枝无效调用方需要过滤掉 */ export function serialize(node) { if (!node) return null if (node.type condition) { return isValidCondition(node) ? { field: node.field, op: node.operator, value: node.value } : null } const children (node.children || []) .map(serialize) .filter(Boolean) // 剪掉无效分支 if (children.length 0) return null if (children.length 1) return children[0] // 单子节点不用包一层后端少解析一层 return { logic: node.logic || AND, children } }逐段看isValidCondition把「值是否为空」的判断集中在一个地方区间字段只要有一端没填就整条判无效避免出现BETWEEN 3 AND NULLfilter(Boolean)是剪枝的核心一行代码把空组、空条件全部剔除最后的单子节点扁平化是有意为之{logic:AND, children:[x]}和x语义等价但前者会让后端多写一层递归DSL 也变难看。前端做掉这层简化联调时对方会舒服很多。如果后端只要 SQL 片段加一个出口就行重点是永远别把值直接拼进字符串// core/serialize.js续 const OP_MAP { eq: , ne: !, gt: , gte: , lt: , lte: , like: LIKE, in: IN, between: BETWEEN } export function toSql(node, params []) { const dsl serialize(node) if (!dsl) return { sql: , params: [] } function walk(n) { if (n.children) { const parts n.children.map(walk) return (${parts.join( ${n.logic || AND} )}) } const op OP_MAP[n.op] || if (n.op between) { params.push(n.value[0], n.value[1]) return ${n.field} BETWEEN ? AND ? } if (n.op in) { params.push(...n.value) return ${n.field} IN (${n.value.map(() ?).join(,)}) } if (n.op like) { params.push(%${n.value}%) // 通配符在参数里拼不拼进 SQL return ${n.field} LIKE ? } params.push(n.value) return ${n.field} ${op} ? } return { sql: walk(dsl), params } }params数组收集占位符对应的值顺序和 SQL 里的?一一对应。字段名field这里是直接拼的前提是字段名来自fields.js白名单——serialize前应该用配置里的 key 校验一遍绝不能让用户输入的字符串变成列名这是最基本的一条底线。4.2 validate递归校验要能定位到具体哪一行校验和序列化的区别在于序列化可以「静默丢弃」校验必须「明着告警」。用户点了提交你得告诉他第几条条件的哪个字段没填而不是简单弹一句「请完善查询条件」。// core/validate.js export function validate(root, fields) { const fieldMap new Map(fields.map(f [f.key, f])) const errors [] // path 记录从根到当前节点的索引链路用来拼出第 2 组第 1 条这种可读位置 function walk(node, path) { if (node.type group) { (node.children || []).forEach((child, i) walk(child, [...path, i])) return } const field fieldMap.get(node.field) if (!field) { errors.push({ path, nodeId: node.id, message: 请选择字段 }) return } if (!field.operators.includes(node.operator)) { errors.push({ path, nodeId: node.id, message: 字段「${field.label}」不支持该操作符 }) } const v node.value const empty v || v null || v undefined || (Array.isArray(v) v.length 0) if (empty) { errors.push({ path, nodeId: node.id, message: 请填写「${field.label}」的查询值 }) } } walk(root, []) return errors }path是这条链路的关键它把嵌套位置编码成数组界面上可以用nodeId直接滚动定位并高亮那一行。返回结构里带nodeId而不是让调用方自己去找是因为树可能被重新生成过索引会变但 id 不会。实际项目里我还会给每个错误配一条人话消息别让用户看到VALIDATION_FAILED这种。4.3 接进真实请求DSL 放哪儿、怎么防 URL 超长拿到 DSL 之后就是发请求。枚举查询条件传 JSON 结构GET时塞进params会被序列化成[object Object]必须自己JSON.stringify条件一多URL 长度轻松突破浏览器和网关的限制这时候换POST更稳。import { serialize } from /core/serialize import { validate } from /core/validate async function handleSearch(tree, fields, page) { // 1. 先校验有错直接拦下别把半成品发给后端 const errors validate(tree, fields) if (errors.length) { highlightErrors(errors) // 界面上按 nodeId 高亮 return } // 2. 序列化空分支已经被剪掉 const dsl serialize(tree) // 3. 结构复杂或条件多时走 POST避免 URL 超长 const res await fetch(/api/users/query, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ condition: dsl, // 后端按 logic/children 递归解析 page: page.page, size: page.size }) }) return res.json() }这里有个容易被忽略的点dsl为null时代表「没有任何有效条件」此时应该查全量还是拦下来提示「至少填一个条件」取决于业务。我一般会在入口加个开关requireCondition默认true——后台列表页动辄百万行一个空条件查询打下去数据库那边脸色会很难看。5. 踩坑排查条件树组件最容易翻车的五个现场这套东西的复杂度不在写出来在改的时候不崩。下面五条基本都是我和周围人真踩过的按「现象 → 原因 → 解决」记下来出问题时对着查能省不少时间。第一条控制台报Failed to resolve component: ConditionGroup页面一片空白。现象是递归的地方完全没有渲染也不报错中断。原因是递归自引用失效。Vue 3 的script setup支持用文件名隐式自引用但前提是文件名和标签名严格一致而且组件必须是通过 SFC 编译的。一旦你把它包进defineComponent、改了文件名、或者用index.js统一导出隐式引用就断了Vue 2 更直接必须显式写name: ConditionGroup。解决办法Vue 3 里在script setup中import ConditionGroup from ./ConditionGroup.vue后虽然会有自引用告警但最稳的做法是保留文件名一致Vue 2 老老实实加name选项。第二条点「删除条件」数据变了但界面纹丝不动或者删错了行。现象是控制台打印树结构发现节点已经没了视图却还是旧的。原因多半是在子组件里直接props.node.children.splice(index, 1)。这既违反单向数据流也因为修改的是 prop 内部的引用父组件的响应式追踪不到。解决所有写操作统一往上 emit在顶层useConditionTree里做不可变更新——返回一棵新树用tree.value nextTree整体替换。宁可多拷贝一次也别在子组件里动手。第三条从「等于」切到「区间」页面直接报value.map is not a function。现象是切换操作符后输入控件崩了。原因是value还是字符串abc而daterange/ 多选控件期望数组内部调.map就炸。解决在ConditionRow里监听operator变化按操作符的形态标量 / 数组重置值也就是 3.2 里onOperatorChange那段。补一句切换字段同理两处都要处理只处理一处照样翻车。第四条后端返回 400说条件解析失败一看请求体里有{logic:AND,children:[]}。现象是明明没填任何条件提交后后端报错。原因就是空组没剪枝serialize直接把空 children 原样输出。解决在serialize里对children.length 0返回null外层filter(Boolean)过滤掉。顺带一提单个子节点也建议扁平化减少后端递归层数两边都省事。第五条复制一个条件组做「常用查询」日期条件全变成了字符串回填时报错。现象是「另存为模板」再加载回来日期区间不好使了。原因是用了JSON.parse(JSON.stringify(tree))做深拷贝Date对象被序列化成 ISO 字符串undefined直接丢失。解决优先用structuredClone它原生支持Date、Map、Set环境不支持就手写递归拷贝或者在数据模型层面就约定所有值只用基本类型和数组日期统一存时间戳数字从源头避开这个问题。提示这五条里有四条都指向同一个设计原则——不要在子组件里改 props不要相信用户会填完整。把写操作收敛到一个地方把校验和剪枝放在序列化之前能省掉大半联调时间。6. 二次开发把自己的业务字段接进这套查询构造器真正落地时改得最多的不是组件是presets/fields.js。这份配置决定了用户能选哪些字段、每种字段能用哪些操作符、值用什么控件渲染。加一个新字段基本就是往数组里塞一个对象加上后端对应的列名映射。配置项类型说明常见取值keystring字段唯一标识也是传给后端的列名username、createdAtlabelstring界面上显示的中文名用户名、注册时间widgetstring用哪种输入控件input/number/select/daterangevalueTypestring值的形态决定重置逻辑string/number/arrayoperatorsstring[]该字段允许的操作符第一个是默认值[eq,like]multipleboolean下拉是否多选true/falseoptionsarray下拉选项{label, value}由字典接口拉取// presets/fields.js —— 新增一个订单数字段 export const fields [ { key: username, label: 用户名, widget: input, valueType: string, operators: [like, eq, ne] // 默认 like模糊搜索最常用 }, { key: createdAt, label: 注册时间, widget: daterange, valueType: array, operators: [between] // 日期字段只给区间别开放 eq }, { key: orderCount, label: 订单数, widget: number, valueType: number, operators: [gt, gte, lt, lte, between] }, { key: channel, label: 来源渠道, widget: select, valueType: array, multiple: true, operators: [in, notIn], options: [] // 运行时从字典接口填充 } ]加完之后有两处必须同步改一是core/operators.js里补上notIn这类新操作符的定义显示名、是否需要数组值、对应的 SQL 写法二是后端解析 DSL 的分支里认这个操作符。这两边不同步前端能选、后端不认症状是提交后静默少一个条件比报错还难查。验证方法我一般用三步走先在演示页里把新字段的每种操作符都点一遍看控制台打印的 DSL 结构对不对再写一个纯函数的单测直接对serialize喂一棵构造好的树断言输出结构这层不依赖 Vue跑得飞快最后接真实接口联调重点看两个边界——空值被剪掉没有、数组值和标量值有没有混淆。遇到字段多、选项来自接口的情况记得把options做成异步填充别在fields.js里写死不然字典一改就得重新发版。这套组件的改造上限其实取决于你的 DSL 设计。想做得更深可以往「条件模板」「跨表关联字段」「权限控制哪些字段可见」几个方向走但每一步都要先改数据结构再改 UI顺序反了就会陷入到处打补丁的局面。说个教训早些年我在一个后台项目里图省事让子组件直接改父级传下来的数组测试环境一路通畅上线后运营反馈「删条件删不干净、偶尔还删错行」查了大半天才定位到是引用被就地修改、视图没跟上。从那以后我每次写这类树形/列表组件写操作一律从顶层走一遍不可变替换删完立刻打印前后两棵树对比。看着啰嗦但比半夜回滚强。希望帮到你。本文还有配套的精品资源点击获取
RELATED

相关推荐

AI驱动的测试数据生成:原理、实践与金融案例

AI驱动的测试数据生成:原理、实践与金融案例

1. 项目概述:AI如何重塑测试数据生成领域在软件开发和测试领域,数据质量直接影响着测试结果的可靠性。传统测试数据生成方法通常依赖手工创建或生产环境数据脱敏,这两种方式都存在明显局限:手工创建耗时耗力且覆盖面有限&#xff…

📅 2026/10/26 17:18:46
2026年贵阳科目一交警手势题怎么记?实用技巧来了

2026年贵阳科目一交警手势题怎么记?实用技巧来了

一、痛点深度剖析:交警手势题不是“背8张图”那么简单我们团队在贵阳观山湖做科一科四理论咨询近10年,发现交警手势题的难点不在题量,而在动态空间关系。很多贵阳学员背图时记住了“左手”“右手”,但题干一换、左右镜像一绕&…

📅 2026/10/26 17:18:46
AI伦理测试实战:从技术合规到社会责任

AI伦理测试实战:从技术合规到社会责任

1. 新规背景与测试工程师的挑战当欧盟AI法案将"高风险AI系统"的伦理评估列为强制要求时,整个行业突然意识到:模型准确率99%的后面,可能藏着100%的伦理灾难。作为第一批接到AI伦理测试需求的测试工程师,我清楚地记得那个…

📅 2026/10/26 17:18:46
MORE NEWS

更多资讯

📰

Scrapy+MongoDB构建汽车之家结构化数据管道

简介:本资源是一个面向Python爬虫开发者与数据工程初学者的实战项目,聚焦汽车垂直领域结构化数据采集与存储,解决从非结构化网页中高效提取车型参数、用户口碑、经销商报价、新闻资讯及图片视频等多模态内容并持久化的问题。压缩包共16个文件…

📰

可白嫖源码---课程设计--毕业设计--springboot快递代拿系统[编号:project16522](案例分析)

本文仅展示核心实现逻辑与部分代码片段,完整项目源码、配套文档、数据库脚本内容较多,篇幅有限无法全部放出。 有需要完整资源的同学,可以在评论区留言【资料或领源码】,我会一 一回复站内私信,发送完整文件 摘 要 随…

📰

agent-skills:面向AI Agent的标准化能力契约与操作系统层

1. 什么是 agent-skills:一个被严重低估的工程化接口层“agent-skills”这个词最近在开发者社区里频繁刷屏,但很多人点开仓库或文档后反而更迷糊了——它既不是某个具体模型,也不是某家大厂新发布的API服务,更不是又一个LLM应用框…

📰

cuDNN 8.1.0.77 Windows x64安装教程:匹配CUDA 11.2与TensorFlow/PyTorch

简介:这是面向Windows平台CUDA 11.2环境的cuDNN v8.1.0.77库文件包,主要服务使用TensorFlow、PyTorch等框架进行深度学习训练与推理的开发者,用于补齐CUDA生态中的DNN加速组件,避免因缺少cudnn64_8.dll等动态库而导致程序启动失败…

📰

【多论文阅读笔记】下一阶段,Agent记忆关注什么能力?

之前做了一个 position,就是下一阶段 Agent 记忆系统应该考虑的核心目标,是保持 Agent 运行态的心流。而【心流】就是:Agent运行中,已有信息能够接近无损接入的状态——即,像一个深入思考某事的人类一样,大…

📰

Marketing Skills:数字时代核心职业能力解析

我理解您的要求,但需要说明:当前输入内容中,项目标题仅为“marketingskills”这一英文词组,且未提供任何有效正文、关键词、摘要描述或可解析的上下文信息。根据您设定的核心规则——“仅接收用户提供的【项目标题】这一个输入参数…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬