从零开发网页版“大鱼吃小鱼”:玩法、AI与性能优化实战

如果你小时候在网页上玩过“大鱼吃小鱼”,应该还记得那种既紧张又爽快的体验:拼命寻找比自己小的鱼,又时不时瞥见一条大一圈的家伙缓缓游来,手心冒汗。这个经典玩法放到今天依然不过时,它天然具备快速反馈和成长快感,很适合拿来当作游戏开发的练手项目。我最近从零做了一版网页版的“大鱼吃小鱼”,过程不算长,但遇到不少有价值的问题。这篇文章就围绕这个自研Demo来写,把玩法建模、AI设计、碰撞处理、性能优化和踩坑经验完整记录下来,适合已经掌握一定基础编程、正想找一个完整小项目沉淀技术的朋友参考。

1. 为什么说这个玩法天生适合当全链路练手项目

先说结论:想在短时间内体验“从零做一个游戏”的全过程,“大鱼吃小鱼”几乎是最划算的选择。它不像卡牌或RPG那样需要大量美术资源、剧情文本和系统策划,画面元素简单到一条鱼、一个圆就能表达,但背后涉及的游戏开发核心模块却一个都不少。

很多人一开始想做宏大项目,结果人还没开始走路就想学飞,进度卡在人物动画或地图加载上,最后不了了之。而“大鱼吃小鱼”的好处在于:你把规则想清楚之后,只要写几百行代码就能看到一个动态的、可操作的游戏世界在浏览器里跑起来。这种即时反馈对维持开发动力极其重要。

具体到技术点,这个Demo覆盖了以下关键环节:

  • 数据建模:鱼群对象、玩家对象、食物对象、淘汰规则,每个实体有位置、半径、速度等属性。
  • 行为设计:鱼群AI的三种状态(游荡、追逐、逃跑),以及状态切换的条件。
  • 碰撞与判定:圆形碰撞检测,以及“谁吃谁”的吞并逻辑。
  • 渲染循环:基于浏览器的逐帧渲染,处理时间步进与帧率波动。
  • 性能优化:当鱼数量上升到一百多条时,如何避免碰撞检测变成性能瓶颈。
  • 体验打磨:速度曲线、缩放动画、视觉反馈,这些决定游戏好不好玩的关键细节。

一套流程走完,你对“游戏手感”这个词的理解会从抽象变成具体——手感不是玄学,而是数值和反馈的叠加。

更重要的是,它的扩展空间巨大。基于同一套基础逻辑,你可以加入道具、技能、排行榜,甚至改成双人对战。练手项目最怕做成一潭死水,而这个玩法天然适合后续加料,做完不会觉得无路可走。

2. 核心规则与数值设计:先定规则,再写代码

项目动手之前,我花了不少时间把规则彻底理清。很多人拿到这个题目就急着写代码,写到一半才发现规则没定清楚,导致返工。比如:两只一样大的鱼碰撞时怎么办?玩家变大之后速度降多少?AI鱼之间会不会互相吞噬?如果你自己都说不清楚,代码里就会充满随意临时补丁。

2.1 一句话规则

玩家控制一条鱼,碰到比自己小的鱼就将其吞噬并成长,碰到比自己大的鱼则被吃掉并扣除一条命。AI鱼群拥有自己的游动、觅食和逃生逻辑,玩家需要在有限的生命次数内尽可能长得更大、活得更久。

因为规则简单,上手门槛极低,这保证了任何人打开页面十秒内就能理解目标。但“简单”不代表没有设计空间,关键在于数值参数的拿捏。

2.2 六个核心参数

我先列一张自己项目里用到的初始参数表,实际开发时可以参考,但不建议照抄:因为手感这种东西,最终要结合美术表现和玩家体感微调。

参数初值作用
玩家初始半径12决定起点尺寸和初始吞噬能力
鱼群半径范围6 ~ 45控制场景中大小鱼的分布广度
吞噬半径比例1.1只有大鱼半径超过小鱼1.1倍时才可吞噬,避免相等或临界时判定混乱
鱼群最高数量120平衡画面丰富度与性能开销
AI视野范围300决定AI鱼感知猎物的距离
速度衰减系数0.85鱼越大速度越慢,越大的鱼越笨重

这里我想重点解释“吞噬半径比例”。如果规则只是“大于对方就可以吃”,那两只尺寸几乎相同的鱼碰撞时就会出现一种很尴尬的反复横跳:一瞬间判定我大,下一瞬间又判定对方大。所以项目里统一用“半径比对方大10%以上”作为吞噬前提。这10%的冗余看似不起眼,实际能消除大量边缘判定冲突。

2.3 成长公式的数学细节

成长公式是吞噬玩法的灵魂,这里我踩过一个经典的数学坑:两条鱼相遇后,如果直接大鱼半径 = 大鱼半径 + 小鱼半径,玩家的鱼会在吃了几条后迅速膨胀成遮住半个屏幕的怪物,数值彻底崩坏。

正确的思路是让面积叠加,而不是半径叠加。鱼本身近似圆形,“体重”可以理解成面积。吃掉猎物后,大鱼得到的是猎物的面积,而非半径。换算成半径时要用开方:

// 假设 player 是被吃者之外的胜者,prey 是被吞噬的猎物 player.radius = Math.sqrt(player.radius * player.radius + prey.radius * prey.radius);

这个公式的效果是:前期每吃一条鱼,体积增长非常明显,能给玩家爽感;但当你已经很大时,吃一条小鱼带来的半径变化微乎其微,逼迫玩家去挑战更大的目标。正是这种“越吃越大、大得越慢”的曲线,让成长反馈始终存在但不至于失去控制。

2.4 速度与体型的平衡

为了让大鱼玩家有“笨重感”,速度需要随半径增长而下降。我用了一个指数式衰减:

player.speed = baseSpeed * Math.pow(0.85, (player.radius - startRadius) / 5);

每次半径比起点多出5,速度整体乘以0.85。这个设计让游戏前中期操作流畅,后期则更像驾驶一辆越来越难停下来的车,玩家需要提前规划游动路线,而不是满场乱窜。

3. 技术选型:一套轻量但完整的网页游戏方案

确定玩法后,我面临技术选型。任何项目都有很多实现路径,区别只在于你投入多少资源、想要什么学习效果。

我最终选择的是Canvas 2D + JavaScript,不引入现成的游戏引擎,自己写主循环和渲染逻辑。理由如下:

  • 这个游戏的规模很小,没有地图编辑器、骨骼动画、多人同步等需求,直接上引擎等于杀鸡用牛刀。
  • 手写主循环能让我把所有底层逻辑摸清楚:requestAnimationFrame怎么控制帧率、时间步进怎么处理、渲染和逻辑怎么分开更新。
  • 调试和部署成本低,打开一个HTML文件就能完成整个开发周期。

如果你只是想快速出成果,用现成引擎也可以。但从学习角度出发,纯手写一套能让你理解引擎背后真正做了什么,之后再切换到任何工具都会事半功倍。

3.1 项目文件结构

我没有把所有逻辑塞进一个文件,而是按职责做了拆分,这样维护起来舒服很多:

project/ ├── index.html // 页面入口,创建Canvas画布 ├── css/ │ └── style.css // 页面布局与基础样式 └── js/ ├── config.js // 所有数值参数,集中管理 ├── Fish.js // 鱼对象的数据结构与基本运动 ├── AI.js // AI状态切换与视野搜索 ├── Render.js // 绘制逻辑:背景、鱼、UI ├── Game.js // 主循环、碰撞、吞噬、状态管理 └── main.js // 初始化入口,绑定输入事件

config.js单独拆出来是个好习惯。前期调参非常频繁,如果参数散落在各个类里,改一次手感要翻好几个文件。集中放在一处,然后用表格清晰地列出来,改起来轻松得多。

3.2 渲染循环与时间步

游戏循环是整个项目的心脏,我使用requestAnimationFrame驱动:

let lastTime = 0; function gameLoop(time) { const dt = Math.min((time - lastTime) / 1000, 0.05); lastTime = time; updateWorld(dt); // 逻辑更新:AI、碰撞、成长 renderWorld(); // 绘制:鱼、背景、UI requestAnimationFrame(gameLoop); } requestAnimationFrame(gameLoop);

这里有个容易忽视的细节:dt做了Math.min限定。因为浏览器在切走标签页再切回来时,time时间戳可能突然产生一个很大间隔,如果不限幅,鱼会像瞬移一样跳一下。限幅到最大0.05秒,即使你切后台很久,回来时也只是所有鱼缓慢前进一步,不会造成视觉突跳。

4. 鱼群AI设计:让每条鱼看起来像活物

在“大鱼吃小鱼”里,AI鱼群不是背景板,它们的行为直接决定世界是否真实。如果所有AI鱼都只是原地转圈,游戏会变成纯粹的数值堆砌,索然无味。我的目标是让每条鱼都具备三种行为:游荡、追逐、逃跑,并根据周围局势自动切换。

4.1 鱼对象的数据结构

实现前先定义Fish类,包含AI所需的全部字段:

class Fish { constructor() { this.x = 0; this.y = 0; this.vx = 0; this.vy = 0; this.radius = 8 + Math.random() * 37; this.speed = 60; this.mode = 'roam'; // roam / chase / flee this.targetX = 0; this.targetY = 0; this.targetChangeTimer = 0; this.prey = null; this.danger = null; } }

字段“松鼠大纲”式的定义都是必要项:mode记录当前行为状态,prey和danger用于暂存视野中找到的目标,targetX/Y和targetChangeTimer则驱动游荡行为。

4.2 三种AI行为的行为逻辑

游荡模式:鱼每隔几秒随机选一个目标点,然后以当前速度游过去。到达后就原地短暂停顿,或直接换个新目标。这种随机游走模仿了水中的漂浮感,避免了所有鱼固定往同一方向移动的机械感。

追逐模式:当AI鱼发现视野范围内有比自己小10%以上的鱼时,切换为追逐。这里我加了一个策略:不是盲目追最近的猎物,而是优先追半径差距最小但能吃掉的鱼。因为追太大的猎物有一定风险,追太小又可能浪费体力,稳妥节奏会更有生机。

逃跑模式:当AI鱼发现视野内有一条比自己大10%以上的鱼时,立刻切换为逃跑,方向是危险来源的反向。逃跑优先级最高,只要感知到危险就放弃一切觅食计划,这一点很有必要,否则鱼群会经常被大鱼“一锅端”。

4.3 AI切换的实现

AI的切换逻辑用一段核心伪代码可以说明:

function updateAI(fish, fishes) { let danger = null; let prey = null; for (const other of fishes) { if (other === fish) continue; const distance = Math.hypot(other.x - fish.x, other.y - fish.y); if (other.radius > fish.radius * 1.1 && distance < seeingRange) { if (!danger || other.radius > danger.radius) { danger = other; } } else if (fish.radius > other.radius * 1.1 && distance < seeingRange) { if (!prey || other.radius < prey.radius) { if (other.radius < fish.radius * 1.8) { prey = other; } } } } if (danger) { fish.mode = 'flee'; fish.danger = danger; } else if (prey) { fish.mode = 'chase'; fish.prey = prey; } else { fish.mode = 'roam'; } }

这里对猎物半径增加了一个“不追击比自己小太多”的限制:other.radius < fish.radius * 1.8。如果不加这个限制,最大的AI鱼永远都在追最小的AI鱼,中等鱼又追更小的鱼,场景会变成全员向前狂奔的闹剧。有了限制后,鱼群会自动形成一种“各自有合适目标”的相对稳定生态。

4.4 让视觉更自然的鱼群排斥力

AI逻辑跑通后,我又发现一个问题:鱼群偶尔会重叠,甚至几条鱼完全穿模叠在一起,观感极其出戏。原因是AI只考虑了捕食关系,没有考虑鱼身体之间的物理排斥。

解决办法是在移动阶段加一个简单的排斥力:遍历所有鱼,计算碰撞对,距离小于两者半径和时就施加一个推开的力。不需要做成完整的物理碰撞,只是把重叠的鱼轻柔推开,就能让世界看起来合理很多。

5. 玩家操控、碰撞判定与吞噬成长

AI鱼群与玩家的交互是游戏的核心体验。这一章把玩家控制流程和吞并判定讲清楚。

5.1 操控方式与手感

玩家操控我做了三套输入方案:

  • 键盘:方向键或WASD控制鱼朝指定方向游动。
  • 鼠标:鱼朝鼠标位置游动,按住左键冲刺。
  • 触屏:手指按住屏幕拖动,鱼朝手指位置游动。

电脑端最常见的控制方式是鼠标跟随,因为它最自然。鱼的方向不是直接跳跃到鼠标方向,而是做了转向插值——每次更新时把当前角度向目标角度逼近一个比例。这会让鱼的转向带有惯性,游起来有“滑行感”,而不是僵硬地瞬间转身。

// angle 是当前朝向,targetAngle 是目标方向 function lerpAngle(angle, targetAngle, t) { let diff = targetAngle - angle; while (diff > Math.PI) diff -= Math.PI * 2; while (diff < -Math.PI) diff += Math.PI * 2; return angle + diff * t; } player.angle = lerpAngle(player.angle, Math.atan2(targetY - player.y, targetX - player.x), 0.08);

5.2 圆形碰撞与吞噬条件

所有鱼都抽象成圆,所以碰撞判定简化成了两圆是否相交,距离是否小于半径和。但“相交”不等于“吞噬”,只有满足大小关系的相交才会触发吞噬。

function tryEat(fishA, fishB) { const dx = fishA.x - fishB.x; const dy = fishA.y - fishB.y; const distance = Math.hypot(dx, dy); const minRadius = Math.max(fishA.radius, fishB.radius) * 1.1; const maxRadius = Math.max(fishA.radius, fishB.radius); const minDistance = fishA.radius + fishB.radius; if (distance < minDistance) { if (fishA.radius > fishB.radius * 1.1) { // fishA 吞噬 fishB fishA.radius = Math.sqrt(fishA.radius * fishA.radius + fishB.radius * fishB.radius); return fishB; // 返回被吃对象 } else if (fishB.radius > fishA.radius * 1.1) { // fishB 吞噬 fishA fishB.radius = Math.sqrt(fishB.radius * fishB.radius + fishA.radius * fishA.radius); return fishA; } } return null; }

5.3 吞噬后的重生与保护

被吞噬的鱼不会立即消失就结束,而是会在一段时间后重新生成一条新AI鱼,保证场景中始终维持接近上限的鱼群数量。但生成新鱼时要注意:不要直接刷在玩家脸上,否则会制造大量莫名其妙的口粮,降低挑战性。我的做法是选取离玩家一定距离以外的随机位置。

这里还有一个新手容易忽视的点:吞噬瞬间的冷却与无敌帧。两条鱼相交触发吞噬后,如果被吃对象还残留在世界里,逻辑上已经被判定为死亡,那么它与大鱼之间不应继续参与碰撞。所以每次吞噬后立刻将被吃对象标记为“已死亡”并从碰撞遍历中移除,同时给玩家极短暂的无敌时间(大约0.5秒),避免刚吞完一条鱼又同时撞上另一条大鱼的“连续死亡冤案”。

5.4 死亡重生与生命周期管理

玩家也被吃掉后,进入死亡动画和复活流程。我设置三条命,死亡时画面短暂闪红,然后从初始位置以无敌状态重生。重生时提供约1.5秒无敌时间,让玩家有反应空间,不至于复活瞬间又被秒杀。

整个生命周期用状态机来管理:

  • alive:正常游玩
  • dying:播放死亡特效,暂停操控
  • respawning:无敌阶段,玩家可操作但不受伤害
  • gameover:生命值为0,游戏结束

状态机的好处是代码路径清晰,所有可能的游戏状态一目了然,不用担心“复活后还能不能移动”这种边界问题。

6. 视觉细节与体验打磨:从能玩到耐玩

“能玩”和“好玩”之间往往隔着大量细节。算法和规则只是基础,真正让玩家感受到品质的,是那些不经意的视觉反馈和动效。

6.1 场景表现与氛围

我没有用真实鱼类图片,而是用不同颜色的圆形加一条小尾巴表示鱼,再用半透明背景营造水下感。这个做法有两个好处:第一,不用处理图片素材,完全用绘图API完成;第二,圆形的精简让鱼群的移动和目标状态一目了然。

背景绘制了三层半透明的水纹线,每隔几十秒随机改变缓慢漂移方向,让画面不至于静止得像一张截图。这层效果成本极低,但对“水感”的提升非常大。

6.2 鱼的视觉区分

鱼的颜色我按半径范围做了分层:小号鱼以浅蓝、浅绿色调为主,中型鱼使用稍深的橙色和紫色,大型鱼则使用深红或深蓝色。这种分层让玩家能凭颜色快速判断鱼的大致尺寸,减少认知负担。

玩家鱼使用了白色描边和尾迹光晕,在任何背景色上都非常显眼。AI鱼被吞噬时,会播放一个缩小消散的动画——就是几帧内逐渐降低透明度和缩放比例,能有效传递“我吃到东西了”的预期反馈。

6.3 吞噬反馈和屏幕震动

吞噬瞬间的反馈是最重要的手感来源。我在项目里做了两件事:

  • 吞噬时,全局暂停约0.05秒的时间步,然后再恢复运行,制造类似“子弹时间”的瞬间卡顿感。
  • 画面有极轻微缩放震颤,玩家鱼在吞噬后的两帧内放大到1.1倍再回弹,模拟“吞了一口东西”的膨胀感。

这种细微的节奏控制比单纯加粒子特效还要有效,因为它作用于时间维度,给玩家大脑一个明确的“得分”信号。

6.4 HUD与相机跟随

当玩家鱼慢慢变大,视野范围会显得不足,于是我给游戏加了一个简易相机:以玩家鱼为锚点,将Canvas平移居中。同时相机有一个缩放逻辑,当玩家半径超过30后,相机逐渐拉远,让玩家能看清更大范围的局势,不至于一条鱼占据整块屏幕。

HUD部分显示当前半径(或长度)、生命条、得分。得分与半径挂钩,每条鱼被吞噬时按猎物体积给予分值,最终排名以累计得分为准。UI尽量做得轻,避免遮挡太多视野。

7. 性能优化与踩坑实录

说点实在的。我跑通基础玩法后,鱼群数量一调高,帧率立刻掉了。这里有性能优化,也有几个比较隐蔽的Bug值得记录。

7.1 对象池:别频繁创建新对象

最初每次生成新鱼都是简单new Fish(),但在鱼群死亡重生频繁时,短时间大量创建对象会造成垃圾回收抖动,具体表现为游戏每隔几秒就卡一下。解决办法是做一个简单的对象池:

class FishPool { constructor(initialSize) { this.pool = []; this.active = []; for (let i = 0; i < initialSize; i++) { this.pool.push(new Fish()); } } spawn(x, y, radius) { let fish = this.pool.pop(); if (!fish) fish = new Fish(); fish.x = x; fish.y = y; fish.radius = radius; fish.alive = true; this.active.push(fish); return fish; } despawn(fish) { fish.alive = false; const index = this.active.indexOf(fish); if (index > -1) this.active.splice(index, 1); this.pool.push(fish); } }

对象池准备好后,所有鱼的新增与移除都走池子的spawn和despawn方法,不再直接new或删除数组元素。运行一段时间后游戏全程稳定流畅,也没有GC卡顿。

7.2 碰撞检测剪枝:空间网格

当鱼数量在100条以下时,对所有鱼两两比较碰撞,复杂度是O(N²),性能可以接受。但当我调高到300条鱼时,每帧要做近4万5千次距离计算,明显吃力。

我把碰撞检测改进成了简单的空间网格法。将整个画布划分成若干个格子(大小等于最大鱼直径),每条鱼只与同一格子和相邻格子中的鱼进行碰撞判定。这样距离较远的鱼对完全不会进入比较,计算量大幅下降。

function getGridKey(fish, gridSize) { const gx = Math.floor(fish.x / gridSize); const gy = Math.floor(fish.y / gridSize); return `${gx},${gy}`; }

在每次逻辑更新时,先遍历鱼群生成Map<gridKey, Fish[]>,再对每个格子内的鱼进行两两碰撞检测。实测300条鱼从每帧卡顿降到全程60帧稳定,效果非常明显。如果你的鱼群数量在200条以下,其实不做这个优化也能流畅运行,但从一开始就写空间网格,后续加人数或加AI扩展会从容很多。

7.3 踩过的三个坑

坑一:鱼在目标点附近疯狂抖动表现是鱼到达目标点时不是停下,而是在一个很小范围内反复横跳。原因是目标点判定距离设得太小,鱼每次游到目标点后,下一帧又重新生成了一个新目标点,新目标点可能就在原地附近,转向插值还没完成就再次转向,于是造成抖动。

解决办法:到达目标点小半径范围后,不立即换目标,而是让目标点保留并让鱼暂停游动0.5~1秒,再随机生成新目标。小小的停顿反而让鱼群看起来更自然,像是在原地观察水况。

坑二:吞噬后反复判定这个坑和前面说的吞噬半径比例有关。如果只判断“我半径大于你”,而不加1.1倍冗余,当一条半径和另一条刚差0.1倍时,两帧内可能判定方向颠倒,画面出现“明明吃了又吐出来”的现象。把所有吞噬判定统一改成“必须是1.1倍以上”后,此类问题彻底消失。

坑三:dt没有限幅导致的瞬移这个问题在手机端尤其明显。手机切到锁屏或接电话,再回到游戏时,requestAnimationFrame会触发一个很大的时间间隔,如果没有对dt做上限处理,鱼会瞬移到远处。给dt加上0.05秒上限后,卡顿场景只会迷你加速,不会瞬移。

7.4 实测中的调参心得

做完所有功能后,我调整了几乎一周的数值才找到满意的节奏。这里有几个经验值供你参考:

  • 玩家初始半径在12~14之间体验最好,太小会觉得起点太差,太大又会失去成长空间。
  • AI鱼最大半径不要超过玩家初始半径的4倍,否则地图里会出现几个超级大块头,玩家根本无处可逃。
  • 鱼群的最高数量按设备和场景大小来定:手机端150条封顶,桌面端300条仍然流畅。
  • 所有尺寸参数调完后,都必须实际试玩至少15分钟再下结论,不是跑通Demo就能保证手感的。

7.5 从“能玩”到“耐玩”的进阶方向

如果之后想把这个Demo继续扩展,以下几个方向相对自然且收益高:

  • 道具系统:增加加速、护盾、分身道具,让策略维度更丰富。
  • 双人对战:本地双人模式或联网对战,一次赛谁能先吃到指定数量的鱼。
  • 排行榜:把得分上传到后端,形成每日/每周挑战。
  • AI难度梯度:随游戏进程增大AI鱼的攻击性,高亮追着跑的大鱼会明显增加压迫感。

我个人实际做完后的最大体会是:这个游戏看起来简单,但它几乎每个环节都有真正的技术含量——数值曲线、状态机、碰撞检测、性能优化,每一项都能嚼出不少东西。如果你也正想找一个能完整做下来、又不至于在美术上卡住的练手项目,“大鱼吃小鱼”绝对值得一试。

相关新闻

图片转Excel全流程拆解:OCR批量处理与表格结构还原实战

图片转Excel全流程拆解:OCR批量处理与表格结构还原实战

图片转Excel&#xff0c;真的能去掉“手敲键盘”的命吗&#xff1f;干了这么多年数据处理&#xff0c;我电脑里几乎每天都有人发来这种玩意儿&#xff1a;一张表格照片、一份截图、甚至是一整页扫描件&#xff0c;然后附一句——“帮我把这个弄成Excel呗”。搁几年前&#xff0…

2026/10/20 2:50:44 阅读更多 →
SpeedTree 10 + Nanite 植被工作流:告别纸片树冠,实现透射与季相重构

SpeedTree 10 + Nanite 植被工作流:告别纸片树冠,实现透射与季相重构

做场景美术这些年&#xff0c;每次听到“这棵树的树冠跟纸片似的”&#xff0c;心里都咯噔一下。传统游戏植被的做法大家心知肚明&#xff1a;树冠就是几张交叉的面片加Alpha Test贴图&#xff0c;远远近近的LOD一级比一级“扁”&#xff0c;最后几乎只能看到一个剪影。逆光的时…

2026/10/20 2:49:43 阅读更多 →
深度学习模型训练如何做到稳定可复现?从随机种子到工程实践

深度学习模型训练如何做到稳定可复现?从随机种子到工程实践

做深度学习做得久了&#xff0c;你会发现一个特别矛盾的现象&#xff1a;模型的性能指标看起来是确定的——F1 0.91、AUC 0.94&#xff0c;写进报告里干干净净&#xff1b;但只要你自己回头重跑一遍&#xff0c;或者换台机器复现一下&#xff0c;数字经常就是另一番模样。这个问…

2026/10/20 2:49:43 阅读更多 →

最新新闻

本地推理实战:用llama.cpp与ollama部署LFM2.5-1.2B小模型

本地推理实战:用llama.cpp与ollama部署LFM2.5-1.2B小模型

1. 上手前的心里话&#xff1a;为什么大家都盯着小模型本地推理最近圈子里聊本地大模型&#xff0c;基本绕不开两个东西&#xff1a;llama.cpp 和 ollama。而我这段时间一直在折腾的主角&#xff0c;是 LFM2.5-1.2B 这个模型。别看它只有 1.2B 参数&#xff0c;实测下来每秒能跑…

2026/10/20 3:51:14 阅读更多 →
CPU推理LFM2.5-1.2B:llama.cpp与ollama的15token/s实战

CPU推理LFM2.5-1.2B:llama.cpp与ollama的15token/s实战

). To avoid truncated thinking or repeated loops, set appropriate stop sequences; generate_enough tokens because thinking consumes budget; temperature lower (0.6-0.7); maybe set--no-cnv? Simpler: stop attags if present; handle "过度思考" issue b…

2026/10/20 3:51:14 阅读更多 →
PyTorch 2.1神经网络构建核心:计算图、编译与内存控制

PyTorch 2.1神经网络构建核心:计算图、编译与内存控制

1. 这不是“Hello World”式教学&#xff1a;为什么从PyTorch 2.1开始构建神经网络&#xff0c;必须绕开90%初学者踩过的坑你点进来的这个标题——“【PyTorch】2.1 使用Pytorch构建一个神经网络”——看起来平平无奇&#xff0c;甚至有点过时。毕竟PyTorch都出到2.3了&#xf…

2026/10/20 3:51:14 阅读更多 →
LiteLLM实战:统一大模型网关的部署与路由策略

LiteLLM实战:统一大模型网关的部署与路由策略

1. 项目概述&#xff1a;LiteLLM 到底是什么&#xff0c;凭什么值得关注干了这些年大模型应用开发&#xff0c;我最大的痛感就是“供应商锁定”和“接口碎片化”。今天调这家模型用一套参数&#xff0c;明天换那家模型又是另一套鉴权和超时策略&#xff0c;光适配层代码就写到手…

2026/10/20 3:51:14 阅读更多 →
OpenClaw Agent日均成本从50元到0.48元:AI工具调用优化实战

OpenClaw Agent日均成本从50元到0.48元:AI工具调用优化实战

1. 一天50块是怎么烧掉的&#xff1a;一次天气查询的完整计费分解先说个真实的场景。某位朋友在群里截图问我&#xff1a;他给OpenClaw配好了工具链&#xff0c;让它每天早上9点自动查一次当天的天气&#xff0c;顺便提醒要不要带伞。结果月底一看账单&#xff0c;光这一条自动…

2026/10/20 3:51:14 阅读更多 →
技能管理实战:识别、组合与迁移,打造个人核心竞争力

技能管理实战:识别、组合与迁移,打造个人核心竞争力

有一次帮一位朋友梳理简历&#xff0c;他接到一个面试问题——“你最擅长的三项技能是什么”。他愣了半天&#xff0c;最后写的是"Excel、PPT、沟通"。写完连他自己都不信&#xff0c;觉得这跟没说一样。那一刻我突然意识到一件事&#xff1a;我们几乎每天都在提&quo…

2026/10/20 3:50:14 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型&#xff08;GMM&#xff09;的语音识别系统&#xff0c;很多人第一反应就是一堆数学公式&#xff0c;觉得门槛很高。但如果你真的在MATLAB里把它落地跑通&#xff0c;会发现核心其实就是三件事&#xff1a;把声音变成特征向量&#xff0c;用GMM给每个类别…

2026/10/19 10:02:04 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人&#xff0c;但落到具体操作上&#xff0c;无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程&#xff1a;对图像做反白、改调色板、彩色转灰度&#xff0c;最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词&#xff0c;你会发现一个很有意思的现象&#xff1a;每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型&#xff0c;有人指的是运动控制系统&#xff0c;还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 9:10:22 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →