当前位置: 首页 > news >正文

360牛盾JS逆向与人类轨迹模拟实战指南

1. 这不是“验证码识别”而是对一套动态防御体系的逆向解构你点开360牛盾的登录页鼠标还没动页面就弹出一个滑块验证你拖动滑块刚到终点又跳出来一个点选文字的挑战你填完文字后台却返回“行为异常”。这不是运气差是牛盾在用一套实时演化的JS逻辑对你每一次鼠标移动、键盘敲击、甚至页面加载时序都做着毫秒级的打分。我第一次接触这个需求时客户给的原始描述只有两行“要绕过360牛盾的滑块验证”“必须能跑通自动化登录”。但实操三天后我才意识到所谓“破解验证码”本质是逆向一整套前端风控SDK——它不只校验你最终拖到了哪个位置更在暗处记录你从页面加载开始的每一帧鼠标轨迹、每一次setTimeout的执行延迟、甚至window.performance.memory的使用峰值。关键词里“JS逆向”“轨迹模拟”这两个词恰恰点破了问题的核心矛盾牛盾的验证不是静态图像识别问题而是一个动态行为建模问题。它的服务端不信任任何客户端传来的“坐标值”只信任由它自己注入的JS引擎所生成的、带有完整执行上下文的加密签名。这个签名里封装了时间戳序列、DOM操作链、Canvas绘图路径、WebGL指纹甚至包括你浏览器是否启用了navigator.permissions.query。所以用OpenCV去识别滑块缺口、用Tesseract去OCR点选文字从一开始就是南辕北辙——你识别得再准传上去的坐标值也会被服务端直接拒绝因为缺少那个唯一的、由牛盾JS运行时生成的token。这篇文章面向三类人一是正在被牛盾卡住、反复403的爬虫工程师二是想系统性提升JS逆向能力的前端安全学习者三是需要评估某套风控方案实际对抗成本的技术负责人。它不提供“一键破解”的黑盒脚本而是带你亲手拆解牛盾v2.8.7当前主流版本的加密流程还原其轨迹采样机制构建可复现、可调试、可长期维护的模拟方案。我会把整个过程拆成四步先定位牛盾JS的加载与初始化入口再逆向其核心加密函数_a1b2c3()的调用链接着重点解析它如何将鼠标移动转化为加密轨迹数据最后给出一套稳定可用的PuppeteerPlaywright双引擎模拟方案。所有代码、参数、调试技巧都来自我过去半年在6个不同业务线上的真实落地经验。2. 定位牛盾JS加载链从Network面板到AST语法树的三级穿透很多新手一上来就对着/api/verify接口发请求试图伪造参数结果连第一道门都进不去。牛盾的防御设计非常狡猾它把最关键的加密逻辑藏在了比接口调用更早的页面加载阶段。你必须先让牛盾的JS成功执行拿到它生成的token和session_id后续的验证请求才可能被受理。所以逆向的第一步永远不是看接口而是看JS。2.1 Network面板中的“伪装者”识别牛盾的真实资源打开Chrome DevTools切到Network标签页强制刷新页面CtrlF5然后过滤js类型资源。你会看到一堆以/static/js/开头的文件比如main.1a2b3c.js、vendor.d4e5f6.js。但牛盾的JS通常不会这么直白地命名。它有三个典型特征域名特征牛盾的JS资源往往托管在dn-static.360.cn或cdn.360.com子域下且路径中包含antifraud、shield、guard等关键词响应头特征查看Response Headers牛盾JS的Content-Type通常是application/javascript; charsetutf-8但关键在于X-Content-Type-Options: nosniff和X-Frame-Options: DENY这两个头这是其SDK的标配内容特征在Preview或Response中搜索字符串360、antifraud、shield如果某个JS文件里高频出现window._$a、document.getElementById(nc_1__wrap)、nc_token等变量名基本可以锁定。我遇到过最隐蔽的一次牛盾JS被拆成了三段第一段在/static/js/core.js里定义了全局window.NC对象第二段通过fetch动态加载了/api/antifraud/config?rxxx返回一个JSON配置其中js_url字段指向真正的加密逻辑第三段才是那个/static/js/encrypt_v2.8.7.min.js。如果你只盯着Network里初始加载的JS就会错过第二段的动态加载请求导致永远找不到入口。2.2 Sources面板中的“活体”动态断点与执行栈追踪一旦定位到疑似牛盾JS文件不要急着格式化Pretty Print。牛盾的代码经过高度混淆格式化后反而会丢失关键线索。正确的做法是在Sources面板中右键该JS文件 → “Add source map”如果页面提供了sourcemap这是最省力的方式如果没有sourcemap就在文件顶部搜索function _、var a、!function(等混淆函数的常见开头找到第一个大型IIFE立即执行函数表达式在IIFE的入口处下断点比如!function(e,t){...}(window,document)的第一行然后刷新页面。这时执行会停在JS加载的最起点。按F10单步执行观察Call Stack调用栈的变化。牛盾的初始化流程通常遵循一个固定模式init()→loadConfig()→renderWidget()→bindEvents()。重点关注bindEvents()函数它内部一定会注册mousedown、mousemove、mouseup事件监听器。这些监听器的回调函数就是轨迹采集的源头。提示牛盾v2.8.x版本中bindEvents函数内部会调用一个名为_trackMouse的私有方法该方法接收event.clientX和event.clientY并将其推入一个名为_mousePath的数组。这个数组就是我们后续模拟轨迹的原始数据源。2.3 AST语法树中的“真相”用esbuild反混淆关键函数当动态调试遇到障碍比如代码被eval包裹、或存在debugger反调试就需要上静态分析。我推荐用esbuild配合自定义插件来反混淆。核心思路是牛盾的加密函数名虽然被混淆为_a1b2c3、_xYz789但其函数体结构是稳定的。它必然包含以下元素对_mousePath数组的遍历对每个坐标点进行Math.sin()、Math.cos()等三角函数运算将运算结果与一个硬编码的key如360antifraud2024进行异或XOR或AES加密最终拼接成一个base64字符串作为token。你可以写一个简单的esbuild插件在transform钩子中匹配function _[a-z0-9]{5,}正则然后提取其函数体用acorn解析为AST再遍历CallExpression节点找出所有对Math.*的调用。我实测下来对牛盾v2.8.7其核心加密函数_a1b2c3的AST中body.body[0].expression.arguments[0].callee.object.name Math且callee.property.name sin的节点恰好有7个这与官方文档中提到的“7维轨迹特征”完全吻合。3. 逆向核心加密函数从混淆变量名到可读算法的完整还原定位到_a1b2c3函数只是开始真正耗时的是理解它每一步在做什么。牛盾的加密不是简单的哈希而是一套基于物理运动模型的特征提取。它把你的鼠标移动当成一个质点在二维平面上的运动然后计算其加速度、曲率、 jerk加加速度等物理量并将这些量编码进最终的token。3.1 混淆变量名的“字典”建立本地映射表牛盾v2.8.7的_a1b2c3函数体约1200行其中充斥着var e[],t[],n[],i[],r[],o[],u[];这样的声明。这些字母变量绝非随意命名而是有严格对应关系的。通过在_trackMouse中打印console.log(_mousePath)我获取了真实的轨迹数据样本_mousePath [ {x: 100, y: 200, t: 1687654321000}, {x: 102, y: 201, t: 1687654321012}, {x: 105, y: 203, t: 1687654321025}, // ... 共127个点 ]然后我在_a1b2c3函数的开头插入console.log(arguments)发现它接收两个参数arguments[0]是_mousePath数组arguments[1]是一个长度为16的Uint8Array即AES密钥。此时再结合AST分析就能建立变量映射混淆名真实含义数据类型来源e原始坐标点数组Array{x,y,t}arguments[0]t归一化后的x坐标数组number[]e[i].x / window.innerWidthn归一化后的y坐标数组number[]e[i].y / window.innerHeighti时间间隔数组毫秒number[]e[i].t - e[i-1].tr速度数组像素/毫秒number[]Math.sqrt((t[i]-t[i-1])**2 (n[i]-n[i-1])**2) / i[i]o加速度数组number[](r[i] - r[i-1]) / i[i]u曲率数组number[]Math.abs((n[i1]-n[i])*(t[i]-t[i-1]) - (t[i1]-t[i])*(n[i]-n[i-1])) / Math.pow(..., 1.5)这个映射表是我花了两天时间逐行对比10组不同轨迹样本的输出结果才确认下来的。它不是靠猜而是靠“输入-输出”对照实验。比如我把_mousePath中所有t时间戳统一加1000毫秒再运行_a1b2c3发现输出的token完全改变但改变的规律只影响i数组和r数组的计算从而反推出i和r的含义。3.2 物理模型的“校验”用真实运动学公式验证算法牛盾的曲率计算公式初看非常复杂u[i] Math.abs((n[i1]-n[i])*(t[i]-t[i-1]) - (t[i1]-t[i])*(n[i]-n[i-1])) / Math.pow(Math.pow(t[i]-t[i-1],2)Math.pow(n[i]-n[i-1],2),1.5);这其实是二维平面运动学中离散点序列的曲率近似公式。它的数学原型是$$ \kappa \frac{|xy - xy|}{(x^2 y^2)^{3/2}} $$其中x和y是一阶导数即速度x和y是二阶导数即加速度。牛盾用前后三点的差分来近似导数完全符合数值计算的常规做法。我用Python写了一个小脚本对同一组轨迹数据分别用牛盾JS和NumPy计算曲率结果误差小于1e-10这证明了其算法的严谨性。注意牛盾v2.8.x的曲率计算只对i从1到e.length-2有效。这意味着它会自动丢弃轨迹的首尾各一个点。所以你在模拟时如果只生成100个点最终参与加密的只有98个。这个细节90%的教程都会忽略导致模拟token始终校验失败。3.3 加密流程的“流水线”七步特征提取与AES封装_a1b2c3函数的主体就是一个标准的特征工程流水线。它不直接加密坐标而是先提取7个维度的特征再拼接、加密起始点归一化t[0]和n[0]首点x,y占屏比终点归一化t[t.length-1]和n[n.length-1]末点x,y占屏比平均速度r.reduce((a,b)ab,0)/r.length最大加速度Math.max(...o)曲率标准差u数组的标准差轨迹总长度r.reduce((a,b)ab,0)时间总耗时e[e.length-1].t - e[0].t。这7个数值被转换为字符串用|连接形成一个明文特征串例如0.123|0.456|0.002|1.23|0.05|127.8|1250。然后牛盾用AES-CBC模式以arguments[1]为密钥、一个固定的IV360antifraudIV123进行加密最后base64编码得到最终的token。我用Node.js的crypto模块完全复现了这个流程代码如下const crypto require(crypto); function encryptFeature(features, key) { const iv Buffer.from(360antifraudIV123); const cipher crypto.createCipheriv(aes-128-cbc, key, iv); let encrypted cipher.update(features, utf8, base64); encrypted cipher.final(base64); return encrypted; } // features 0.123|0.456|0.002|1.23|0.05|127.8|1250 // key Uint8Array [51, 54, 48, 97, 110, 116, 105, 102, 114, 97, 117, 100, 50, 48, 50, 52]实测表明只要输入的features字符串和key完全一致此Node.js函数输出的token与牛盾JS原生输出的token100%相同。4. 轨迹模拟的“灵魂”从贝塞尔曲线到人类行为建模的深度实践破解了加密算法只是完成了50%的工作。剩下50%是如何生成一条能让牛盾“信以为真”的鼠标轨迹。很多人以为只要把_mousePath数组里的点用page.mouse.move(x, y)依次执行就行。但这样生成的轨迹在牛盾眼里就是一条完美的、机械的、毫无生命感的直线——它会被立刻标记为“机器人行为”。4.1 为什么简单线性插值必然失败牛盾的“抖动检测”机制牛盾在_trackMouse函数中除了记录clientX/clientY还会记录screenX/screenY和movementX/movementY。后者是两次mousemove事件之间的像素偏移量。一个真实的人类其movementX和movementY的分布是高度随机的服从某种特定的概率分布经我统计接近对数正态分布。而用for (let i0; i100; i) { page.mouse.move(startX i*dx, startY i*dy) }生成的轨迹其movementX恒为dxmovementY恒为dy这种完美规律性是牛盾最敏感的红线。我在一次测试中故意将movementX设为一个常数2其他参数全按真实数据模拟结果token虽然能通过基础校验但在服务端二次验证时返回{code:403,msg:behavior suspicious}。通过抓包发现服务端会额外校验一个_jerk_score字段该字段正是由movementX和movementY的方差计算而来。方差越小_jerk_score越高风险等级就越高。4.2 贝塞尔曲线的“欺骗性”用三次样条拟合人类手部运动人类拖动鼠标时手部肌肉并非匀速运动而是存在启动加速、中途匀速、末端减速的过程。这恰好符合三次贝塞尔曲线的运动特性。牛盾的前端SDK其内部轨迹绘制就是用Canvas的bezierCurveTo()实现的。所以我们的模拟也必须用同样的数学工具。核心思想是给定起点P0、终点P3以及两个控制点P1、P2贝塞尔曲线的参数方程为$$ B(t) (1-t)^3P_0 3(1-t)^2tP_1 3(1-t)t^2P_2 t^3P_3 $$其中t从0到1。P1和P2的位置决定了曲线的弯曲程度。我通过分析1000条真实用户滑块轨迹发现P1通常位于P0到P3连线的左上方P2位于右下方且距离连线的垂直偏移量约为连线长度的15%-25%。以下是一个生产环境可用的贝塞尔轨迹生成器TypeScriptinterface Point { x: number; y: number; } interface TrajectoryPoint extends Point { t: number; } function generateBezierTrajectory( p0: Point, p3: Point, durationMs: number 1200, pointsCount: number 120 ): TrajectoryPoint[] { // 计算控制点模拟人类手部的自然弯曲 const dx p3.x - p0.x; const dy p3.y - p0.y; const dist Math.sqrt(dx * dx dy * dy); // P1: 左上方偏移量为距离的20% const p1: Point { x: p0.x dx * 0.3 - dy * 0.2, y: p0.y dy * 0.3 dx * 0.2 }; // P2: 右下方偏移量为距离的20% const p2: Point { x: p0.x dx * 0.7 dy * 0.2, y: p0.y dy * 0.7 - dx * 0.2 }; const trajectory: TrajectoryPoint[] []; const startTime Date.now(); for (let i 0; i pointsCount; i) { const t i / pointsCount; // 贝塞尔插值 const x Math.pow(1 - t, 3) * p0.x 3 * Math.pow(1 - t, 2) * t * p1.x 3 * (1 - t) * Math.pow(t, 2) * p2.x Math.pow(t, 3) * p3.x; const y Math.pow(1 - t, 3) * p0.y 3 * Math.pow(1 - t, 2) * t * p1.y 3 * (1 - t) * Math.pow(t, 2) * p2.y Math.pow(t, 3) * p3.y; // 添加微小抖动模拟肌肉震颤 const jitterX (Math.random() - 0.5) * 2; const jitterY (Math.random() - 0.5) * 2; trajectory.push({ x: Math.round(x jitterX), y: Math.round(y jitterY), t: startTime Math.round(t * durationMs) }); } return trajectory; }这段代码的关键在于p1和p2的计算方式。它不是凭空捏造而是基于对真实数据的统计回归得出的。jitterX和jitterY的加入是为了模拟人类手部无法避免的细微震颤其幅度控制在±1像素这与真实生物信号的信噪比完全一致。4.3 行为建模的“终极武器”引入时间维度的非线性变速贝塞尔曲线解决了空间上的“弯曲”但还不够。真实的人类其拖动速度是随时间非线性变化的。牛盾的_trackMouse函数中有一个隐藏的_speedProfile数组它记录了每个点的瞬时速度。我通过大量采样发现这个速度曲线完美契合Sigmoid函数的形状$$ v(t) \frac{v_{max}}{1 e^{-k(t - t_{mid})}} $$其中v_max是最大速度t_mid是达到半速的时间点k是陡峭度。对于一个1200ms的滑块t_mid通常在650ms左右k约为0.012。因此最终的轨迹生成器必须将贝塞尔空间插值与Sigmoid时间插值结合起来。这意味着我们不能简单地让t从0到1均匀递增而要让t本身按照Sigmoid函数的反函数来采样。这确保了前30%的路程耗时占总时间的50%中间40%的路程耗时占30%最后30%的路程耗时占20%。这种“慢-快-慢”的节奏才是人类行为的精髓。我将这个逻辑封装进了generateRealisticTrajectory函数并在生产环境中稳定运行了三个月日均调用量超20万次通过率稳定在99.2%以上。其核心伪代码如下1. 用Sigmoid反函数生成一个非均匀的时间点数组 T[0..N]满足 T[i1] - T[i] 符合 Sigmoid 导数。 2. 对每个 T[i]计算对应的贝塞尔参数 t_i T[i] / totalDuration。 3. 用 t_i 代入贝塞尔方程计算出该时刻的空间坐标 (x_i, y_i)。 4. 在 (x_i, y_i) 处添加符合高斯分布的微小抖动。 5. 将所有 (x_i, y_i, T[i]) 组合成 _mousePath 数组。这套方案已经超越了“模拟”进入了“建模”的范畴。它不再试图欺骗牛盾而是以一种尊重其设计逻辑的方式提供它所期望的、符合人类生理极限的数据。5. 可落地的双引擎方案Puppeteer与Playwright的协同作战理论再完美最终也要落地到代码。我不会给你一个“复制粘贴就能用”的黑盒脚本因为牛盾的更新频率很高平均每月一个小版本任何硬编码的selector或函数名都可能在下次更新后失效。我提供的是一个可维护、可调试、可扩展的双引擎框架。5.1 Puppeteer方案适合深度调试与快速验证Puppeteer的优势在于其无与伦比的调试能力。你可以随时在page.evaluate()中插入debugger直接在Chrome DevTools里单步执行牛盾JS。这对于逆向分析阶段是不可替代的。以下是一个最小可行的Puppeteer脚本骨架const puppeteer require(puppeteer); (async () { const browser await puppeteer.launch({ headless: false, devtools: true }); const page await browser.newPage(); // 1. 注入一个全局变量用于接收牛盾的加密结果 await page.exposeFunction(receiveToken, (token) { console.log(Received token from JS:, token); }); // 2. 监听页面加载等待牛盾JS就绪 await page.goto(https://example.com/login, { waitUntil: networkidle2 }); await page.waitForFunction(() typeof window.NC ! undefined); // 3. 获取牛盾的加密函数和密钥 const { encryptFunc, key } await page.evaluate(() { // 这里执行我们之前逆向出的逻辑从牛盾JS中提取 _a1b2c3 和 key return { encryptFunc: window._a1b2c3.toString(), key: new Uint8Array([/* 从牛盾config中提取的16字节key */]) }; }); // 4. 生成真实轨迹 const trajectory generateRealisticTrajectory( {x: 100, y: 300}, {x: 400, y: 300}, 1200, 120 ); // 5. 在页面上下文中执行加密 const token await page.evaluate((traj, key, encryptStr) { // 将加密函数字符串转为可执行函数 const encrypt eval((${encryptStr})); return encrypt(traj, key); }, trajectory, key, encryptFunc); console.log(Final token:, token); // 6. 提交验证 await page.evaluate((tk) { fetch(/api/verify, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ token: tk }) }); }, token); await browser.close(); })();这个脚本的价值不在于它能直接跑通而在于它展示了如何将逆向成果无缝嵌入到自动化流程中。exposeFunction让你能从JS上下文向Node.js传递数据waitForFunction确保了执行时机evaluate的沙箱隔离保证了牛盾JS的纯净运行环境。5.2 Playwright方案适合高并发与长期稳定运行当项目进入生产阶段Puppeteer的调试优势就变成了性能负担。Playwright的架构更轻量API更现代且对多浏览器Chromium, Firefox, WebKit的支持更好。更重要的是它的page.route()拦截功能可以让我们在不修改页面JS的情况下“劫持”牛盾的加密调用。核心技巧是用page.route()拦截所有对牛盾JS的请求然后返回一个我们自己构造的、已注入了monkey patch的JS文件。import { chromium, Page } from playwright-core; async function setupAntiFraud(page: Page) { // 拦截牛盾JS请求 await page.route(**/antifraud/**.js, async (route) { const response await route.fetch(); const body await response.text(); // 在原始JS末尾注入我们的patch const patchedBody body // 重写 _a1b2c3 函数使其接受我们传入的轨迹 const originalEncrypt window._a1b2c3; window._a1b2c3 function(mousePath, key) { // 我们可以在这里做任何事比如记录日志、修改输入 console.log(Encrypting with custom path of length:, mousePath.length); return originalEncrypt(mousePath, key); }; // 暴露一个全局函数供外部调用 window.encryptForExternal function(path, k) { return originalEncrypt(path, k); }; ; await route.fulfill({ status: 200, contentType: application/javascript, body: patchedBody }); }); } // 使用时 const browser await chromium.launch(); const page await browser.newPage(); await setupAntiFraud(page); await page.goto(https://example.com/login); // 后续逻辑同Puppeteer...这个方案将“逆向”与“运行”彻底解耦。你可以在本地开发一个独立的encrypt.ts模块专门负责轨迹生成和加密然后通过page.evaluate调用window.encryptForExternal来获取token。这样当牛盾更新时你只需要更新encrypt.ts而无需改动任何Playwright的胶水代码。5.3 关键参数的“黄金组合”一份经过千次验证的配置清单最后分享一份我在6个不同客户项目中反复验证、调整、最终沉淀下来的“黄金参数”清单。这些参数不是理论最优而是在通过率、速度、稳定性三者间取得的最佳平衡点参数推荐值说明调整建议pointsCount120轨迹点总数少于100曲率计算不稳多于150服务端解析超时durationMs1200总耗时毫秒必须在1000-1500之间低于1000易被判定为“过快”高于1500易被判定为“犹豫”jitterAmplitude±1.5抖动幅度像素固定值不可为0超过±2轨迹过于毛糙像鼠标故障sigmoidK0.012Sigmoid陡峭度牛盾v2.8.x的硬编码值不可更改controlPointOffset20%控制点偏移比例在15%-25%间浮动20%是均值最稳妥keyRefreshInterval30分钟AES密钥有效期牛盾密钥每30分钟轮换一次必须定时刷新这份清单是我踩过无数坑之后用血泪写就的。比如曾经有个客户坚持要用durationMs800来追求极致速度结果通过率暴跌至60%。我用Wireshark抓包分析发现服务端返回的X-RateLimit-Remaining头在800ms请求下数值衰减速度是1200ms下的3倍——原来牛盾的限流策略是和行为时间强绑定的。我在实际使用中发现最可靠的保障不是追求100%的通过率而是建立一套完整的失败熔断与降级机制。当连续3次token校验失败时系统应自动切换到备用方案比如暂停自动化触发人工审核流程或者降级为截图OCR的混合方案。技术的高明不在于它永不失败而在于它失败时有尊严、有预案、有退路。
http://www.zskr.cn/news/1375157.html

相关文章:

  • Fiddler HTTPS抓包失败根因:证书信任链修复实战
  • UE5 C++开发环境配置避坑指南:VS2022兼容性与UBT编译链路校准
  • Unity蒙皮性能优化:SkinnedMeshRenderer CPU瓶颈与GPU Skinning实战
  • 预测性基准测试效度评估:从实验室分数到真实世界决策的避坑指南
  • AngularJS 控制器详解
  • Unity新手第一课:从创建立方体理解场景驱动开发
  • Playwright 5种性能配置基准对比与选型指南
  • Unity入门:从创建立方体理解组件化三维工作流
  • SkyWalking SQL注入漏洞深度解析与实战加固指南
  • Keil µVision内存窗口地址保存问题解决方案
  • 融合链上数据与市场情绪的以太坊Gas价格预测模型实践
  • 别再死记硬背GBDT公式了!用Python手写一个回归预测模型(附完整代码)
  • Unity2023+Vuforia10.17.4安卓二次唤醒崩溃根因与修复
  • 力学引导机器学习:构建土壤液化地理空间预测新范式
  • Unity UI性能优化实战:UGUI Canvas重建与FGUI渲染控制深度解析
  • 天辛大师谈山东爱济南文化,AI赋能后的泉城文学序列
  • 告别依赖地狱!在Ubuntu 20.04上丝滑安装ROS2 Foxy与Gazebo Garden(保姆级排错指南)
  • 机器学习势能面构建实战:从量子化学数据到高精度分子模拟
  • 鲁棒非参数回归理论:重尾噪声下Huber损失与预测误差分析
  • Keil MDK Middleware TCP发送性能问题分析与优化
  • 鲟龙科技获IPO备案:靠卖鱼子酱年营收7.7亿 刚派息1.39亿
  • 睿触机器人获IPO备案:拟港交所上市
  • 机器学习气候模拟器与极值分析:估算万年一遇极端天气的新范式
  • Armv8-A架构扩展特性解析:安全、虚拟化与性能优化
  • 仅剩237份|ChatGPT绘画提示词生成专家级训练集(含12类细分领域·2187组带标注正负样本+Prompt熵值评估模型)
  • ChatGPT记忆功能怎么用:资深Prompt工程师压箱底的6条黄金规则,第4条让响应准确率提升41.7%
  • 天辛大师浅谈湖湘文化传承,AI赋能考古记之高庙文化真实研究(五)
  • 2026年比较好的贵州月嫂培训/贵州月嫂全网热门推荐 - 行业平台推荐
  • 扩散模型量化技术:挑战、突破与实战指南
  • 中介核对对账