普通视图

发现新文章,点击刷新页面。
今天 — 2026年4月20日首页

泰国寻求三家美国半导体企业赴泰投资

2026年4月20日 13:18
泰国投资促进委员会在一份声明中表示,在泰国财政部长埃克尼蒂・尼蒂坦帕帕斯出访美国之后,泰国正加大力度对接孚诺尼克、格芯、泰瑞达三家美国头部企业,吸引美国半导体产业赴本国投资。(新浪财经)

海南:提升航天产业全链条技术服务

2026年4月20日 13:12
36氪获悉,近日,《海南省“十五五”服务业发展规划(征求意见稿)》公开征求意见。其中提到,提升航天产业全链条技术服务。壮大火箭链、卫星链及数据链,完善“发射+服务+制造+应用”一体化商用航天产业体系。支持绿色推进剂、火箭发射与回收、低轨通信卫星星座一体化等关键技术的应用转化,探索电磁发射等前沿技术方向,提升关键航天技术服务能力。建设文昌国际航天城科技创新公共平台、国际星箭协同研发中心、国际卫星先进制造中心,以技术创新推动航天产业成为新的经济增长点。

海南:扩大岛内居民免税购物种类,推动免税商品通过跨境电商拓展至岛外

2026年4月20日 13:12
36氪获悉,近日,《海南省“十五五”服务业发展规划(征求意见稿)》公开征求意见。其中提到,做大做强免税消费。扩大针对岛内居民的“限值、限品种”免税购物种类,动态调整日用消费品“零关税”正面清单。支持重点旅游城市增设免税店,探索“线上展示+快速配送”等新零售模式。吸引更多境外人员入境消费,有序扩大单方面免签国家范围,优化完善区域性入境免签政策,为更多符合条件的人员签发5年多次签证。推动免税商品通过跨境电商平台拓展至岛外及海外市场,支持开设跨境电商线上线下体验店,有序构建“离岛免税+岛内居民日消品免税+跨境电商”多层次供给格局。“十五五”期间,每年招引高端品牌直营免税运营中心2—3家,国际顶级免税集团分销中心1家,国内免税集团国际免税中转集拼部、国潮事业部以及特色商品免税部等2—3家。

宇树科技机器狗外观设计专利获授权

2026年4月20日 13:10
36氪获悉,爱企查App显示,近日,宇树科技股份有限公司申请的“机器狗”外观设计专利获授权。摘要显示,本外观设计产品用于服务、搜救、陪护、巡检、教育、导航、摄像、玩具、智能交互、娱乐互动、执行特定任务,设计要点在于形状。

IDC:2030年全球人形机器人出货量将突破51万台,年复合增长率近95%

2026年4月20日 13:03
36氪获悉,IDC最新报告预测,2030年全球人形机器人出货量将突破51万台,年复合增长率近95%。其中,轮式人形机器人于2025年应用起步,凭借更高的稳定性与可靠性可快速适配并运行于室内及半结构化环境,预计到2030年实现年复合增长率约120%的快速发展;全尺寸双足人形机器人依托全方位的灵活性实现更广泛场景落地,年复合增长率预计超95%。

36氪首发 | 首创“玩偶+主机”模式,多智能体儿童AI玩具品牌获数千万元融资

2026年4月20日 12:56

作者 | 乔钰杰

编辑 | 袁斯来

硬氪获悉,北京灵机天赐科技有限责任公司(下称“灵机天赐”)于过去一年内完成两轮数千万元人民币融资,天使轮由德联资本领投,小恐龙基金和瑞昇基金跟投,Pre-A轮由Implic Capital领投,两轮融资均由探奇资本担任公司独家财务顾问。

灵机天赐CEO杨冰长期从事儿童内容与智能硬件产品的定义及运营。接受硬氪采访时,杨冰表示,“AI时代,让孩子直接和一个虚拟人物聊天,这个产品定义其实很难成立。孩子无法快速和一个纯虚拟角色建立真实的物理连接。只有把世界观、人设和场景都构建出来,他们才会有交流的可能性。”

为了实现这种“可信的互动”,灵机天赐旗下品牌“Jollybubu”首创了“主机+玩偶”的智能体硬件交互系统。

每一个Jolly实体玩偶都对应独立的智能体(Agent),拥有各自的世界观、知识库和人格模型。当孩子将玩偶放置在主机底座上,即可激活对应角色的故事内容,并随时打断、提问,与玩偶进行角色化的互动对话。与此同时,主机bubu更像整个系统的中枢,持续沉淀孩子的提问、探索路径与互动偏好,进而实现个性化引导。

(图源/企业)

基于内置的世界观、知识库,每个实体玩偶都代表了一种思维方式和学科方向,杨冰介绍称“我们发现,当孩子提出一个问题,比如‘天为什么是蓝色’时,并不一定想要一个科学的答案,所以我们的玩偶也会根据自己的世界观和上下文做出各种不同的回答,可能是艺术的、可能是文学的、也可能是科学的。”当孩子使用不同的玩偶提问、互动,本身也是在不断拓展自己的认知路径和表达方式。

为实现这一效果,技术层面,每一个玩偶都是一个独立的智能体,由语音识别(ASR)、语音合成(TTS)、角色音色系统与大模型能力共同支撑。由于一次互动中可能涉及多个角色的连续响应与协同,后台系统需要同时处理多智能体之间的低延迟联动,并保持不同角色稳定输出各自鲜明的人格特征。

“这是我们独立摸索和开发出来的一套系统。”杨冰解释,“既要在多个角色切换和互动的情况下,把整体延迟控制到接近单轮大模型对话的水平,又要让每个角色持续保持鲜明且稳定的个性,这个难度很高。”

(图源/企业)

进一步的差异化在于,这套系统并非只是“陪聊”。

通过放置两个玩偶,孩子可以主动让它们基于不同世界观进行辩论,或者赋予技能让它们对战。“AI时代,输出与输入同样重要。”杨冰表示,“我们更想做的是一个能够发现孩子天赋、帮助孩子成长的伙伴系统,而不只是一个聊天工具。获取信息并不是唯一重要的能力,表达、提问、辩论和共创同样关键。”

硬件之外,灵机天赐还开发了配套小程序。孩子的交互数据(如记忆、情绪、操作等)会转化为一只不断成长变化的虚拟宠物。小程序首页即是宠物的展示界面,动态的“脑图”会记录孩子近段时间在哪些话题上表现出敏感与兴趣,为家长提供一种理解孩子情绪的“温度计”,也为家长观察孩子阶段性兴趣变化提供了更直观的窗口。

商业模式上,灵机天赐选择以硬件销售为主,不以订阅付费作为核心门槛。相较于持续订阅,团队更看好通过新玩偶、新角色和新内容的持续扩展,建立复购机制。

长期来看,灵机天赐希望构建一个“共生的AI智能体生态”。公司不仅会提供原创IP和合作IP,更会开放共创机制,允许家长、孩子、KOC甚至B端版权方(如图书内容)通过其平台分发和训练自己的IP。“我们鼓励孩子成为共创者,”

杨冰称,“他们可以找到自己的IP和内容,通过3D打印与我们的系统结合进行训练。让玩偶不只是承载内容的硬件,而成为持续生长的角色入口。”

据了解,Jollybubu将于今年5月底正式发售。

以下为访谈节选:

硬氪:为什么一定要做实体玩偶?

杨冰:不同的IP代表孩子在不同关系里——与自己、与社会,与自然,与未来,与世界。我们把原本枯燥抽象的关系,具象化为实物的玩偶,孩子可以真实地把玩在手里。如果没有完整的内容设定、角色关系和实体化场景,孩子很难真正进入并持续使用这样的产品。很多产品只做了一项对话功能,很难被被孩子持续使用,这是主要原因。

硬氪:如何解决孩子在使用上“长期留存”的问题?

杨冰:首先,我们不是做一个聊天工具,而是做一个“伙伴工具”。孩子每买一个新玩偶,就拓展了一个知识领域——神话、探案、自然……每个玩偶都有稳定的人格设定、表达方式和价值取向。主机上的宠物更像整个系统的陪伴中枢,会随着孩子的互动逐步成长和演化。孩子会发现,他与这个系统是共同成长的,知识库不断扩大,宠物也会随着交互数据变化、长大。其次,我们鼓励孩子成为共创者,他们可以创造自己的IP内容,甚至通过3D打印与我们的系统结合进行训练。新的玩偶加入就意味着新玩法、新任务、新社交链条的开始,当孩子能成为这个故事世界的一部分,留存也就会自然发生。

Mythos引发网络攻防新焦虑,新加坡金管局要求银行补上安全漏洞

2026年4月20日 12:53
随着对Anthropic PBC最新人工智能(AI)模型Mythos的担忧蔓延至亚洲,新加坡金融监管机构正敦促银行堵上网络安全漏洞。新加坡金融管理局发言人在回应关于Mythos所带来风险的询问时表示,金管局正与该国网络安全机构协调,加强包括银行在内的关键基础设施运营方的防御能力。Mythos是Anthropic推出的一款新AI模型,该公司认为该模型“过于危险”,不宜广泛发布。(新浪财经)

地产一哥业绩“大洗澡”,舍利润稳保现金流

2026年4月20日 12:47

地产行业持续下行,即使第一梯队阵营也承受了巨大压力。从销售巅峰期连续下降五年之后,连龙头上市房企,也必须在“保利润”和“保现金流”之间二选一。

4月17日晚间,连续三年销售额稳居行业第一的保利发展公布了2025年成绩单:

  • 全年销售额2530亿元,连续三年稳居行业第一;
  • 营业收入3081.44亿元,同比微降1.13%;
  • 归母净利润大幅下滑79.31%,仅剩10.35亿元;
  • 经营现金流净额151.91亿元,同比暴增142.74%;
  • 在手现金1229亿元,现金短债比1.74倍;
  • 综合融资成本降至2.72%,历史最低。

一边是利润“腰斩再腰斩”,一边是现金流充裕、融资成本创纪录。很显然,保利主动给自己“动了一次大手术”,在经营策略中优先选择了保现金流。

数据来源:保利发展2025年年报

01 净利润大幅下滑

保利发展2024年的归母净利润为50.01亿元,2025年忽然骤降至10.35亿元。扣非归母净利润更是同比下滑84.52%,降至6.59亿元,成为年报中最受关注的焦点。

保利发展解释称,报告期内,受行业和市场波动影响,公司房地产项目结转毛利率同比下降。公司在房地产销售行业的收入同比减少1.19%,毛利率也减少了0.99个百分点。

保利发展的毛利率水平虽低于中海、招商蛇口等同行,但在企业利润均大幅下滑的背景下,仍处于合理区间.

全国不同区域拉开巨大差距在保利的年报中也有体现。保利五大区域中,营收正增长的只有华东地区,北方地区下滑幅度最大,为33.84%。毛利率方面,华东、北方、中部三个区域同比上年增长,华南、西部区域分别减少4.66、5.63个百分点。

此外,合联营投资收益恶化,也是保利净利率下滑的主要原因之一。受部分合作项目销售不及预期影响,保利发展的合联营投资收益从2024年的12.2亿元降至2025年的-1.4亿元,减少13.6亿元,进一步侵蚀了归母净利润。同时,少数股东损益占比大幅提升,从2024年的48.7%上升至2025年的84.5%,使得归属于母公司股东的净利润进一步缩水。

数据来源:保利发展2025年年报

近两年,上市房企大幅计提资产减值,主动减少净利润,提前出清风险、减少分红,成为常规的应对市场压力的方式。这一次保利也进行了同样的“技术操作”。

2025年,保利发展一口气计提资产减值准备69.58亿元,直接吞掉归母净利润44.47亿元,成为拖累利润的最主要因素。从减值构成来看,存货跌价准备占比最高,达54.42亿元,占总减值金额的78.2%,主要涉及佛山保利中交大都汇、温州滨江云谷、常州保利天汇等去化困难、预期收益下降的项目;长期股权投资减值准备10.15亿元,占比14.6%,主要针对上海华辕实业、天津睿沣置业等合作企业;其他应收款减值准备5.01亿元,占比7.2%,主要为关联公司及合作方应收款项减值。

对于本次大幅计提减值,立信会计师事务所为公司出具了标准无保留意见的审计报告。业内人士认为这是保利主动清理历史包袱,为未来轻装上阵做准备。

02 库存压力仍然较大

以销售额为标准,保利发展已经连续三年位居行业第一。2025年,保利实现销售签约金额2530亿元,同比上一年下降21.67%,降幅大于行业平均,并且已经连续两年降幅超20%。这意味着保利感受到的销售下滑压力比同行更大。

为了减缓业绩下滑,保利在持续加大核心城市的土储占比。2025年,保利全年拓展总地价791亿元,其中一二线城市拓展总地价占比超过90%,核心城市拓展占比99%,其中北京、上海、广州三地占比约48%。

押注一二线城市,是为了对冲地产高峰期在三四线城市留下的难以消化的“老库存”。

从库存结构来看,百里发展的待售面积主要集中在核心城市,去化周期合理。但同时,保利的库存仍存在结构型压力:一是竣工物业规模持续增长,较期初增长7.2%至2137.7亿元,占存货总额的比例提升至28.1%,去化压力有所加大;二是存量项目占比偏高,特别是2022年以前获取的存量待售项目,部分高价地项目去化难度较大;三是三四线城市仍有大量库存,去化压力突出。

为了加快去化,保利采取了一系列操作:

  • “老盘新作”:对存量项目调规优化、产品升级,让旧盘焕新颜;
  • “以销定产”:新开工面积同比下滑40%,减少新增库存;
  • 灵活定价:降价促销、团购优惠,牺牲毛利率换流速。

效果如何?2025年,保利的存量项目贡献签约额为953亿元,在总签约额中占比约38%,库存去化初见成效,但仍任重道远。

保利发布财报之后,开源证券分析预计,2026年保利短期利润仍然承压,毛利率会在2026年筑底,2027年获得恢复,但PE倍数在未来三年内持续下降。

行业洗牌期,剩者为王。保利发展在努力用发债优势、融资成本优势、销售运营优势力保现金流,以“稳”争胜。

欣旺达动力在广州成立低空产业发展公司

2026年4月20日 12:44
36氪获悉,爱企查App显示,近日,广州欣旺达动力低空产业发展有限公司成立,法定代表人为盛建斌,注册资本100万元人民币,经营范围包括电池销售、蓄电池租赁、电池零配件销售、电子元器件与机电组件设备销售等。股东信息显示,该公司由欣旺达动力科技股份有限公司全资持股。

一季度海南离境退税金额增长8.5倍

2026年4月20日 12:36
海口海关日前发布统计数据,今年一季度该关共验核离境退税申请单8300份、申请单金额2339.4万元、退税金额290.8万元,同比分别增加16.8倍、8.3倍、8.5倍。(海南日报)

前端请求三部曲:Ajax / Fetch / Axios 演进与 Vue 工程化封装

作者 忆往wu前
2026年4月20日 12:33

从 Ajax → Fetch → Axios:前端网络请求演进史与工程化封装

前言

本篇是 Vue项目实战三板斧系列第一篇,专门聊聊前端最基础的网络请求。

不少同学上来就用 axios,会写但不太明白它到底是怎么来的。 这篇我就带大家简单走一遍进化路线:从最原始的 Ajax,到原生 Fetch,再到我们现在常用的 Axios,一步步看清它们的优缺点,最后一起封装一套简洁、好维护的工程化请求方案。 不求花里胡哨,只求看完能真正理解“我们为什么要这么写请求”。  

一、最原始的网络请求:原生 XMLHttpRequest

要说网络请求,老祖宗必须是 XMLHttpRequest,也就是我们常说的 Ajax。 它实现了页面不刷新就能拿数据,在当年简直是黑科技。

1.1 原生手写 Ajax(最底层写法)

// 1. 创建一个 ajax 实例
const xhr = new XMLHttpRequest();

// 2. 配置请求:请求方式、地址、异步(true)
xhr.open('GET','/api/data',true);

// 3. 监听请求状态变化(旧版常用写法)
xhr.onreadystatechange = function(){
  // readyState === 4 表示请求完成
  if(xhr.readyState === 4){
    // status 200~299 代表请求成功
    if(xhr.status >= 200 && xhr.status < 300){
      // 把后端返回的 JSON 字符串转成对象
      const result = JSON.parse(xhr.responseText);
      console.log('请求成功',result)
    }else{
      console.log('请求失败',xhr.status);
    }
  }
}

// 网络异常、跨域失败时触发
xhr.onerror = function(){
  console.log('网络异常或跨域错误')
}

// 4. 发送请求
xhr.send()

1.2 简单封装一下 Ajax

原生写法太啰嗦,我们简单封装一版,方便复用。

// 封装一个自己的 ajax 函数
function myajax(options) {
  // 1. 创建请求实例
  const xhr = new XMLHttpRequest()

  // 2. 解构配置参数,给默认值
  const {
    method = 'GET',  // 默认 GET 请求
    url,             // 请求地址
    data = null,     // 参数(这里演示无参)
    success,         // 成功回调
    error            // 失败回调
  } = options

  // 3. 初始化请求,转大写防止小写出错
  xhr.open(method.toUpperCase(), url, true)

  /*
    旧写法:onreadystatechange 需要判断 readyState
    新写法:onload 等价于 readyState=4,直接用更简单
  */
  xhr.onload = function () {
    // 判断 HTTP 状态码是否成功
    if (xhr.status >= 200 && xhr.status < 300) {
      // 解析后端返回的 JSON
      const res = JSON.parse(xhr.responseText)
      // 有成功回调就执行
      success && success(res)
    } else {
      // 失败把状态码抛出去
      error && error(xhr.status)
    }
  }

  // 网络异常触发
  xhr.onerror = function () {
    error && error('网络异常或跨域')
  }

  // 发送请求(这里不传参数,避免 GET 报错)
  xhr.send()
}

1.3 Ajax 的缺点(为啥我们不用它了)

缺点一:配置繁琐,全手动判断

详细解释:每发送一个请求,都要重复创建 XMLHttpRequest 实例、调用 open 配置请求、监听状态/错误、调用 send 发送请求,步骤多且冗余。而且要手动判断 readyState 请求状态、手动判断 status HTTP状态码、手动执行 JSON.parse 解析后端返回的字符串,没有任何自动处理逻辑,代码量极大,每写一个请求都要重复大量代码。

缺点二:回调一多直接回调地狱

详细解释: Ajax基于回调函数处理结果,一旦遇到连续多个依赖请求(比如先获取用户ID,再用ID获取详情,再用详情获取订单),就需要在success回调里嵌套下一个myajax请求。代码会层层嵌套、缩进不断加深,可读性极差,后期根本无法维护和修改,这就是典型的回调地狱问题。

  
// 回调地狱示例
myajax({
  url:'/api/user',
  success(res){
    // 第一层回调
    myajax({
      url:`/api/detail?id=${res.id}`,
      success(res){
        // 第二层回调
        myajax({
          url:`/api/order?did=${res.detailId}`,
          success(res){
            // 第三层回调,代码彻底混乱
          }
        })
      }
    })
  }
})
缺点三:没有拦截器、没有超时、没有统一处理

详细解释: 原生XHR没有全局请求/响应拦截机制,每个请求都要单独写错误处理、单独加请求头、单独处理返回结果。比如要给所有接口加token,必须在每个 xhr.open 之后,手动写 setRequestHeader ;想要设置请求超时,需要额外写定时器手动中断请求,无法做到一处配置、全局生效。

缺点四:不支持 Promise

详细解释: 原生Ajax不支持Promise语法,无法使用 async/await 、 then/catch 这种现代化异步写法,只能用传统回调函数。异步流程完全不可控,代码书写不优雅,也无法和现代前端的异步语法接轨,和后续的Fetch、Axios生态完全脱节。

总结:理解底层即可,真实项目没人直接写原生 Ajax。

 

二、现代浏览器原生:Fetch API

时代在进步,浏览器终于看不下去了,推出了Fetch。基于 Promise,告别回调,写法清爽多了。不用从头开始造,省时省力。

2.1 GET 请求(带参数拼接)

// 定义参数
const params = {
  id: 123,
  name: "text"
}

// 把对象转成 ?id=123&name=text 这种格式
const query = new URLSearchParams(params).toString();

// 发送请求
fetch(`/api/user?${query}`)
  .then(res => {
    // fetch 很坑:只有网络失败才 reject,404/500 依然走 then
    if (!res.ok) throw new Error("请求失败:" + res.status)
    // 解析 JSON
    return res.json()
  })
  .then(data => {
    console.log("获取数据成功", data)
  })
  .catch(err => {
    console.error("请求异常", err)
  })

2.2 POST 请求

// fetch 的 post 请求
fetch("/api/user", {
  method: "POST",
  headers: {
    // 必须声明传递 JSON 格式
    "Content-Type": "application/json"
  },
  // 对象转 JSON 字符串
  body: JSON.stringify({
    username: "admin",
    password: "123456"
  })
})
  .then(res => {
    if (!res.ok) throw new Error(res.status)
    return res.json()
  })
  .then(data => {
    console.log("请求成功", data)
  })
  .catch(err => {
    console.error("请求失败", err)
  }) 

2.3 async/await 语法糖更香

// 用 async/await 让代码看起来像同步
async function fetchData() {
  try {
    // 请求参数
    const postData = {
      username: "zhangsan",
      password: "123456"
    }

    // 发送请求
    const response = await fetch("/api/login", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(postData)
    })

    // 判断请求是否成功
    if (!response.ok) {
      throw new Error("请求失败,状态码:" + response.status)
    }

    // 解析数据
    const result = await response.json()
    console.log("请求成功", result)
  } catch (error) {
    // 统一捕获错误
    console.error("请求错误", error)
  }
}

// 执行
fetchData();

2.4 简单封装一版 Fetch

// 封装一个通用的 fetch 请求函数
async function request(url, options = {}) {
  // 解构参数
  const { method = 'GET', data, headers = {}, ...rest } = options;
  // 方法转大写
  const upperMethod = method.toUpperCase();
  // 最终请求地址
  let fetchUrl = url;

  // 配置 fetch 参数
  let fetchOptions = {
    method,
    headers,
    ...rest
  }

  // GET 请求:参数拼接到地址栏
  if (upperMethod === 'GET' && data) {
    const queryStr = new URLSearchParams(data).toString()
    fetchUrl += `?${queryStr}`
  }

  // POST/PUT/DELETE 处理 JSON 格式
  if (['POST', 'PUT', 'DELETE'].includes(upperMethod) && data) {
    // 设置请求头
    fetchOptions.headers['Content-Type'] = 'application/json';
    // 转 JSON 字符串
    fetchOptions.body = JSON.stringify(data)
  }

  try {
    // 发送请求
    const res = await fetch(fetchUrl, fetchOptions)
    // 判断状态
    if (!res.ok) { throw new Error(`请求错误:${res.status}`) }
    // 解析并返回数据
    return await res.json()
  } catch (err) {
    // 打印并抛出异常,外部可以继续 catch
    console.error('请求失败', err)
    throw err
  }
}

2.5 Fetch 有哪些硬伤?

硬伤一:网络错误才 reject,404 / 500 依然走 then,必须手动判断

详细解释: Fetch 的“成功”只看网络是否发出去,只要浏览器收到了 HTTP 响应,哪怕是 401、404、500 错误, fetch  依然认为请求“成功”,会走进  then  而不是  catch 。 所以你必须每次手动判断  res.ok ,否则会把错误当正常数据处理,导致页面报错。

// 不写这句,404/500 不会进 catch
if (!res.ok) throw new Error("请求失败")
硬伤二:没有请求、响应拦截器,所有逻辑必须手写重复

详细解释: Fetch 原生不支持拦截器。如果你想给所有接口加 token、加请求头、统一处理返回值、统一报错,每个 fetch 都要写一遍,无法像 axios 那样全局配置一次到处生效。

// 每个请求都要重复写一遍
headers: {
  "Content-Type": "application/json",
  Authorization: "Bearer " + token
}

 

硬伤三:无法取消请求,没有 abort 方案(必须额外用 AbortController)

详细解释: 原生 fetch 自身不支持取消请求。想要取消必须手动搭配  AbortController ,写一堆额外代码,切换页面、重复请求时无法自动中断,容易造成内存泄漏、重复请求、旧数据覆盖新数据等问题。

硬伤四:没有自带超时处理,超时要自己写定时器包装

详细解释: Axios 直接配置  timeout: 5000  就可以自动超时中断。Fetch 没有超时配置,想实现超时必须自己包一层  Promise.race  +  setTimeout ,每个请求都要重复造轮子,非常麻烦。

硬伤五:请求 body 不会自动处理,必须手动 JSON.stringify

详细解释: Axios 会自动帮你把对象转成 JSON、自动加  Content-Type: application/json 。 Fetch 完全不处理,你必须手动:

body: JSON.stringify(data)
headers: { "Content-Type": "application/json" }

少一句后端就收不到数据,非常容易漏写。

硬伤六:无法监听请求进度(上传/下载进度很难实现)

详细解释: Axios 自带  onUploadProgress  可以直接监听上传进度做进度条。 Fetch 原生不支持,只能通过  ReadableStream  自己手动解析流,实现复杂、成本极高,普通项目基本没法用。

结论:小 demo 能用,中大型项目顶不住。

三、项目主流方案:Axios 全面上手

前面我们了解了:

  • 最底层:XMLHttpRequest,功能强但写起来巨麻烦
  • 现代原生:Fetch,语法好看,但能力残缺

那有没有一个东西,既保留 XHR 的强大能力,又拥有 Fetch 的 Promise 优雅语法,还把所有坑都填了?

它就是我们现在前端项目的事实标准 —— Axios。

重点来了: Axios 并不是什么新底层技术,它本质上就是对原生 XMLHttpRequest 再次封装、增强、Promise 化之后的终极工具库。 相当于把我们刚才手写的简陋 myajax、简陋 fetch 封装,做到了工业级极致。

它解决了所有痛点:支持 Promise、自动处理 JSON、拦截器、取消请求、超时、进度监听…… 所以现在 Vue、React、小程序、Node 项目里,大家几乎都默认用 Axios。

3.1 基础使用

import axios from 'axios'

// 完整写法
axios({
  method: 'get',
  url: '/user',
  params: { id: 10 }
})
  .then(res => {
    // axios 自动帮你解析了 JSON,直接拿 data
    console.log(res.data)
  })
  .catch(err => {
    console.log('请求失败', err)
  }) 

3.2 简写 GET / POST

// 简写 GET
axios.get('/user', {
  params: { id: 10 }
}).catch(err => {
  console.log(err)
})

// 简写 POST(自动处理 JSON,不用自己 stringify)
axios.post('/login', {
  username: 'admin',
  password: '123456'
}).catch(err => {
  console.log(err)
})

3.3 async/await 优雅版

// 登录请求
async function login() {
  try {
    const res = await axios.post('/login', {
      username: 'admin',
      password: '123456'
    })
    console.log(res.data)
  } catch (err) {
    // 请求失败、状态码错误都会进这里
    console.log('请求失败', err)
  }
}

 

四、工程化核心:Axios 二次封装(重点)

真实项目里,我们不会到处直接写 axios.get, 必须封装一次,统一处理:token、超时、状态码、错误提示。

4.1 封装 request.js

import axios from 'axios'

// 创建 axios 实例
const request = axios.create({
  baseURL: '/api',    // 统一接口前缀
  timeout: 5000       // 超时时间 5 秒
})

// =================== 请求拦截器 ===================
request.interceptors.request.use(config => {
  // 从本地拿到 token
  const token = localStorage.getItem('token')
  // 如果有 token,就加到请求头里
  if (token) {
    config.headers.Authorization = `Bearer ${token}`
  }
  // 必须 return config
  return config
})

// =================== 响应拦截器 ===================
request.interceptors.response.use(
  res => {
    // 直接返回后端数据,页面不用再 .data
    return res.data
  },
  err => {
    // 统一错误提示
    console.log('请求出错', err)
    // 抛出异常,让页面可以自己 catch 处理
    return Promise.reject(err)
  }
)

// 导出实例,页面引入使用
export default request

这一封装,好处直接拉满:

- 统一 baseURL,后期改地址只改一处

- 所有接口自动带 token,不用每个请求写

- 统一错误处理,不用每个接口 catch

- 响应直接返回 data,代码更干净

 

五、接口模块化管理(真正工程化)

封装完 axios 还不够,工程化必须接口模块化。

5.1 按业务拆分文件

src/
└── api/
    ├── request.js   # axios 封装
    ├── user.js      # 用户相关接口
    ├── goods.js     # 商品相关接口
    └── order.js     # 订单相关接口

5.2 user.js 示例

import request from './request'

// 登录接口
export function loginApi(data) {
  return request({
    url: '/login',
    method: 'post',
    data
  })
}

// 获取用户信息
export function getUserInfo() {
  return request({
    url: '/user/info',
    method: 'get'
  })
}

5.3 组件中使用

import { loginApi } from '@/api/user'

async function login() {
  try {
    const res = await loginApi({
      username: 'admin',
      password: '123456'
    })
    console.log('登录成功', res)
  } catch (err) {
    console.log('登录失败')
  }
}

优点:

- 接口统一管理,便于维护

- 页面逻辑更干净

- 方便 mock、方便重复调用

六、在 Vue3 组件中实战使用

Vue

<template>
  <div>
    <button @click="getUser">获取用户信息</button>
  </div>
</template>

<script setup>
import { getUserInfo } from '@/api/user'
import { ref } from 'vue'

const userInfo = ref({})

// 获取数据
const getUser = async () => {
  try {
    const res = await getUserInfo()
    userInfo.value = res
  } catch (err) {
    console.log('请求失败')
  }
}
</script>

可以看到,组件中已经完全看不到底层的  axios  调用,只需要调用封装好的接口方法即可完成数据请求。代码更加简洁清晰,职责更加单一,真体现了前端工程化低耦合、高复用、易维护的优势。

七、总结

这一篇我们完整走完了前端请求进化之路:

1. Ajax(XMLHttpRequest):底层基石,所有请求的根

2. Fetch:浏览器原生 Promise 方案,但能力有限

3. Axios:基于 XHR 深度封装,现代前端工程化最佳实践

工具一直在变,但核心思路没变:

从繁琐难用,到语法简化,再到功能完善。 Axios 之所以成为主流,正是因为它在原生 XHR 的基础上做了大量贴心封装,让我们不用再重复处理各种细节。

而封装和工程化的意义,也远不止“省事”这么简单:

统一的配置、统一的错误处理、按模块拆分接口,本质上都是为了让代码更简洁、更好维护、更容易协作。 一个项目是否规范,往往从请求层就能看出来。

搞懂这些来龙去脉,以后再写接口、做封装,就不再是机械复制代码,而是真正知道自己在做什么、为什么这么做。

这也是 Vue 项目工程化的第一步。 下一篇我们继续三板斧第二篇:VueRouter 路由与路由守卫,配合今天的 token 实现登录鉴权。

万达电影实体店将继续使用“万达影城”名称

2026年4月20日 12:28
4月20日,在万达电影正式更名为“儒意电影娱乐股份有限公司”之后,儒意电影董事长兼总裁陈祉希发布了一封全员信。据了解,万达电影实体店将继续使用“万达影城”名称,“万达影城”仍会是儒意电影旗下重要的院线品牌之一,未来会根据市场变化和用户需求规划新品牌。(澎湃)

越南计划将电动汽车税收优惠政策延长至2030年

2026年4月20日 12:26
越南国会办公厅周末发布消息称,越南计划将电动汽车特别消费税减免政策延长近4年,至2030年底,以此提振电动汽车销量、减少碳排放。越南于2022年3月下调了电动汽车特别消费税,由原先的4%~11%降至1%~3%,原减税政策将于2027年2月到期。(新浪财经)

“五一”临近航班遭取消?航空公司:优先签转,保障旅客顺利成行

2026年4月20日 12:14
“五一”假期临近,不少人正在规划出游。近期,受燃油价格暴涨、供应紧缺等因素影响,全球多家航空公司运力出现不同程度缩减,直接导致了航班大规模取消的情况。中国航空运输协会理事长助理朱耀春表示,所有受航班调整影响的旅客,退改签全程不收取任何手续费、服务费。航空公司要通过短信、官方公众号、客服热线等多渠道,第一时间把航班调整原因、替代方案、办理流程推送给每一位受影响旅客,确保大家提前知晓、调整行程。(央视新闻)

恒指午间休盘涨0.82%,恒生科技指数涨0.78%

2026年4月20日 12:02
36氪获悉,恒指午间休盘涨0.82%,恒生科技指数涨0.78%;GEO、光伏概念领涨,智谱涨超10%,信义光能涨超6%,MINIMAX-WP涨超3%;煤炭、石油股跌幅居前,中国石油股份、中煤能源跌超2%;南向资金净买入5.47亿港元。

为什么我不建议普通前端盲目卷全栈?

作者 ErpanOmer
2026年4月20日 12:00

Gemini_Generated_Image_s62j8ys62j8ys62j (1).png

周末,一个半年前从我们组离职去当 独立开发者 的小伙子,突然约我出来喝了顿大酒。

半年前他提离职的时候,眼里是有光的。当时他手里拿着一个用 Next.js + Node + MongoDB 拼凑出来的 AI 翻译 SaaS 雏形,满脸兴奋地跟我说,现在有了 AI 辅助,前端搞全栈简直易如反掌,他马上就要去赚美金、做数字游民了😊。

半年后的饭桌上,他头发肉眼可见地稀疏了,整个人透着一股被掏空的疲惫😢。

我问他产品跑得怎么样? 他倒了一堆苦水: 上线第二周,因为忘了配置 MongoDB 的白名单,数据库被黑产端了,留了个比特币勒索地址; 换了云数据库后,上个月被海外羊毛党用并发脚本刷爆了注册接口,由于 Node.js 端没做事务锁和限流,AI 服务的 Token 余额一夜之间被刷欠费了两千多刀。

他长叹一口气:老大,写后端真他妈不是人干的活😖😖😖。

这两年,前端圈有一股极其狂热的风气,大厂在逼着前端转全栈,各类博主在教你怎么用 Cursor 一键生成后端 API,似乎只要会写几句 JS,连上个数据库,你就能凭一己之力抗下整个商业闭环。

但作为一个写了 9 年代码、搞过出海独立站、也无数次给新人擦过屁股的老兵,我今天必须把这层窗户纸捅破: 绝大多数普通前端理解的全栈,根本就是个一戳就破的纸老虎。我不建议你盲目去卷全栈🤷‍♂️。


你以为的全栈,只是在写玩具后端

很多前端对后端的认知,还停留在用 Express 或者 NestJS 写一个 router.get('/api/user'),然后调用一下 ORM 查查数据库。代码能跑通,能返回 JSON,就觉得自己是全栈了。

这是巨大的错觉。

真实的后端工程,最难的从来不是业务逻辑(CRUD),而是高并发下的数据一致性、资源隔离与灾备防御。

举个最经典的例子。很多刚转全栈的前端,在处理 用户消耗积分调用 AI 这个逻辑时,代码往往是这么写的:

// 前端思维写出来的后端代码
app.post('/api/generate', async (req, res) => {
  const user = await User.findById(req.userId);
  
  // 判断余额
  if (user.points < 1) {
    return res.status(403).send('积分不足');
  }
  
  // 扣减积分并保存
  user.points -= 1;
  await user.save();
  
  // 调用 AI 接口...
});

本地单步调试,毫无问题。 但只要把它扔到线上,稍微遇到点网络延迟,或者有黑客同时发来 10 个并发请求。这 10 个请求会同时读到 user.points === 1,然后各自往下执行,最终用户的 1 个积分被成功扣减了 1 次,但你的 AI 接口被免费调用了 10 次。

在真正的后端视野里,这叫竞态条件(Race Condition)。解法是利用数据库层面的原子更新(比如 MongoDB$inc),或者是加分布式锁。

但很多前端根本不懂什么是事务隔离级别,什么是乐观锁悲观锁,什么是慢查询引发的连接池打满。他们拿着一套写 UI 的心智模型去搞后端,最后搭出来的系统,防得住正人君子,防不住任何一次稍微猛烈的流量冲击。


2026 年独立开发者真实生存状况

现在的年轻人动不动就想搞独立 SaaS,觉得有个好点子就能变现。 我带你看一眼 2026 年前端做独立开发者的真实时间线:

Gemini_Generated_Image_xi8phxi8phxi8phx.png

第一周: 激情澎湃,花 5 天时间用 Tailwind CSS 把落地页的动效调得丝滑无比,深色模式完美适配,觉得自己真是个产品天才。

第二周: 开始搭后端环境。在 Docker、Nginx 配置、SSL 证书续签里痛苦挣扎。为了省几十块钱服务器钱,买了个廉价 VPS,每天提心吊胆怕宕机。

第四周: 产品终于上线了。发到 Product HuntV2EX 上,迎来了 500 个独立访客。

第五周: 被俄罗斯或者印度的 Bot 盯上了。恶意脚本疯狂轰炸你的登录接口,你那单节点的 Node.js 进程直接 CPU 飙到 100% OOM 死机。你大半夜爬起来看日志,临时去搜 Node.js 怎么做 IP 频控。

第二个月: 热情耗尽,服务器吃灰,域名到期不续费🤷‍♂️。。。

这才是赤裸裸的真相。 很多前端做独立开发,90% 的精力消耗在了配环境、查后端 Bug、修服务器配置上,真正花在打磨核心产品功能和做营销推广上的时间,连 10% 都不到。

你以为你是产品 CEO,其实你只是个免费的初级兼职运维。


普通前端该怎么破局?学会借力,而不是造轮子

说了这么多,难道前端就只能老老实实切图,彻底告别独立开发和全栈了吗?

错❌❌❌。

我的核心观点是:放弃传统后端的玩法,拥抱 Serverless 和 BaaS(后端即服务)。

2026 年了,前端的护城河绝对不是去学怎么配置 K8s 集群,也不是去死磕如何调优 MySQL 索引。你的核心价值是 极速交付业务逻辑

要做全栈,就把脏活累活全甩给成熟的云基础设施。 比如这两年我在搞出海项目时,几乎抛弃了所有传统的自建 Node 服务器部署 (比如 Render, fly.io),全盘转向了 Cloudflare Workers + D1(Serverless SQLite) 或者 Supabase

不用管服务器运维,不用管 Nginx 负载均衡,自带企业级防 DDOS,把代码推到边缘节点(Edge),全球毫秒级生效。

给你看一眼在 Cloudflare Workers 里,如何用极简的代码实现极其硬核的 IP 频控(Rate Limit),这在传统后端里要搭一套 Redis 才能搞定:

// 基于 Cloudflare 的现代前端全栈玩法
export default {
  async fetch(request, env) {
    const ip = request.headers.get('cf-connecting-ip');
    
    // 调用平台自带的限流服务,一行代码解决防刷问题
    const { success } = await env.RATE_LIMITER.limit({ key: ip });
    if (!success) {
      return new Response('请求过于频繁,请稍后再试', { status: 429 });
    }

    // 处理核心业务逻辑...
    return new Response('业务处理成功');
  }
};

发现了吗?这种工程维度的跨越,才是前端走向全栈的正确姿势。 你不需要去理解底层的流量网关是怎么实现的,你只需要站在巨人的肩膀上,把 API 串起来,把精力留在如何优化用户的产品体验上。


别被技术焦虑绑架

很多技术社区都在制造焦虑,好像你不懂点微服务、不懂点高并发,你就不配做一个现代的前端。

但真实的世界是:没有任何一个商业项目,是因为用了多牛逼的后端架构才成功的;绝大部分死掉的项目,都是因为产品根本没人用,或者在早期就被无意义的基础设施消耗拖垮了团队🤔。

如果你是一个前端,有极强的业务嗅觉,想自己做点东西。 那就用熟你手里的 VueReact,用好 Tailwind 快速构建 UI,把后端托管给 Supabase 或者 Firebase,把边缘逻辑交给 Cloudflare。用两周时间把 MVP(最小可行性产品)跑通,直接推向市场验证🫡。

不要去盲目卷传统后端。 把时间留给产品,留给用户,留给真正的商业闭环。这才是 2026 年,一个有独立思考能力的前端老兵,最该具备的技术品味。

你们说是不是?😊

Suggestion (2).gif

手搓你的 AI 外置记忆,连接飞书体验直接脚踢龙虾

作者 imoo
2026年4月20日 11:54

前言

在做这套东西前,我一直是有个疑虑的。ai 这些持续的习惯、记忆积累是否是无用功,会不会刚做的差不多,这个工具就过时了,又要花时间切一套新的重新积累(比如之前的 cursor)。而且多设备的记忆并不同步,做这件事的性价比可能并不高。

但最近我有了另一条思路:可以将记忆做成一个完整的项目,给不同的平台做不同的适配方案。这样一来,切换工具时只需要让 ai 处理一下适配层即可,可以放心的存储记忆或者迁移。

并且同样的,你的 skills、agents 乃至于临时搓的工具脚本,都可以纳入这个架构下。切换设备时,只需要你把这个仓库 clone 下来,就能拥有和之前完全相同的能力了。

原理

  1. claude code、codex 等工具,一定是有一个记忆文件的,用于存储你强调的习惯

在 claude code 中为:根目录/.claude/CLAUDE.md

在 codex 中为:.codex/AGENTS.md

我们可以利用这个机制,将这些入口,都软链至我们的记忆项目,这样一来,无论在哪个平台运行 ai,都能进入到这个项目的入口中,载入我们的记忆。

  1. 渐进式披露上下文

渐进加载是指,claude 会开始对话时,会自动读取 文件,将其加入上下文并开始对话。随后每读取文件夹时,都会尝试加载该文件夹下的 claude.md 并加入上下文中。

我们可以将记忆项目进行合理的规划与分层,使记忆结构更加有条理,方便管理

渐进机制仅在 claude code 存在,在非 claude 平台,比如 codex,就只能靠提示词进行约束了,例如:

##claude.md 规则

进入目录时,必须先读取当前目录下对应 claude.md

原则:先读 claude.md,再读写具体文件 — 没有例外,违反此规则 = 任务失败

不过目前看下来效果还不错,codex 能完全遵守该规则去读文件

项目结构

  • src/brain 负责记忆层
  • src/config 负责工具层
  • src/projects 负责业务层
  • src/temp 用于存储一些临时文件

外层的作用是引入各类工具文件,比如 node_modules、husky、.gitgnore 等,不引入这一层的话, 这些文件会和上述核心层同级,占据额外的上下文。

实现思路

记忆层

当前的 brain 层,主要是结合了分享会上的长期记忆方案以及 claude 的渐进加载机制。我们只需要在入口增加这样的说明,它就会自动进到 brain 层:

---

## Session Init(读取规则)

**新会话启动时,按顺序读取:**

1. **必选**`/Users/imoo/work/data/project/ai-config/src/brain/claude.md`
2. **必选**`/Users/imoo/work/data/project/ai-config/src/brain/memory/claude.md` + `/Users/imoo/work/data/project/ai-config/src/brain/knowledge/claude.md`
3. **条件**`/Users/imoo/work/data/project/ai-config/src/brain/memory/YYYY-MM-DD.md`(今日)
4. **条件**`/Users/imoo/work/data/project/ai-config/src/config/skills/claude.md`(技能索引)
5. **按需**:根据 Index Tags 读取 `/Users/imoo/work/data/project/ai-config/src/brain/knowledge/<topic>.md`
6. **写入前必读**:新增或改写 `knowledge/*.md` 前,先读取 `/Users/imoo/work/data/project/ai-config/src/brain/knowledge/knowledge-format.md`


→ 完成后回复:`记忆系统已加载`

---

brain 层里有两部分是核心:

  • knowledge:存放关键规则,可以手动维护

  • memory:存放每次对话的一些关键记录,有点像日记本

knowledge 和 memory 层,会有对应的 claude.md 及每天的日期文件,通过 claude 的自动读取机制,能很方便的读到对当前层级设定的规则。如

# Memo Index

| Date  | Summary | Tags |
|-------|---------|------|

---
**说明:**
- 每日 memory 存放在 `memory/YYYY-MM-DD.md`
- `checkpoint` 时若未更新当日 `memory`,视为 `checkpoint` 未完成
- memory 只记录今日完成的工作清单(Done),不含反思或经验
- 每条 Done 尽量写结果,不写流水账式命令记录
- 若某条结论未来可复用,应拆到 knowledge,并在 memory 中只保留简述
- Index 用于快速检索,不加载全部 memory

# Knowledge Index

| Usage | File | Summary | Tags |
|-------|------|---------|------|

---
**说明:**
- knowledge 存放可复用的稳定结论、方法论、用户偏好
- Agent 启动时只加载 `claude.md` 索引
- 新增或改写 knowledge 前,先读取 `knowledge-format.md`
- `Usage` 记录 knowledge 文件被读取和实际使用的次数,默认按次数降序排序
- 每次 checkpoint 时,基于本轮实际读取过的 knowledge 文件更新 `Usage`
- 只收录稳定规则、用户偏好、项目长期结论
- 避免记录仅对单次会话有价值的过程细节
- 需要某个主题时,按 Tags 匹配到对应文件再读取

---

记忆层的设计其实相当简单,于我而言这两块即可应对大部分情况,可根据需要进行拓展。不过过于复杂的设计,很可能导致模型上下文庞大时更新知识流程出错。

有同学可能发现了,这里只介绍了如何让 agent 读取记忆,写入记忆单独放在了后文,先介绍大致层级。

工具层

  • skill 和 agents 层其实就是做个迁移。
  • tools 层则是各种封装好的工具

这里介绍几个例子:

  1. bb-browser:也就是 ai 操控浏览器的一个浏览器插件 + cli。

  这个工具可以让 agent 直接操纵你现在浏览器,从而跳过鉴权等操作,我将使用说明置入到了 skill 中。这里会有一个很好的开发体验,在当前架构下, ai 可以同时读取插件内容、cli 内容、skill 内容,一旦出现变更,可以同步处理这三端的代码与上下文

  1. 飞书中转能力:也就是龙虾的将飞书消息与 claude 打通的能力。

  这里实际上需要本地起一个 ws 服务,用于持续让 bot 的接收飞书发来的消息,并起一个 claude 进行处理。这一步需要你提前去建好飞书应用,并且开通以下权限才能正常。

{
  "scopes": {
    "tenant": [
      "contact:user.employee_id:readonly",
      "docs:doc",
      "docs:permission.member:create",
      "docs:permission.member:delete",
      "docs:permission.member:retrieve",
      "docx:document",
      "im:chat",
      "im:chat:read",
      "im:chat:update",
      "im:message",
      "im:message.group_at_msg:readonly",
      "im:message.group_msg",
      "im:message.p2p_msg:readonly",
      "im:resource"
    ],
    "user": []
  }
}

projects 层

负责链接你的各种业务项目,能让模型获得充分的上下文

image.png

每个项目我切了两层,work 放需求级别的文件夹,code 则是放项目源码。这里我的 code 基本是软链过来的,因为我的工作目录划分了不同的文件夹,不太好直接扔到这里来。

另外我也不希望子项目的改动直接带到我的记忆系统的改动中,最多留个需求文档供复盘,所以这里的 git 我是直接忽略了 code 层。

这里涉及到了比较多的规则,还有频繁使用的软链接、需求写法等,所以我直接封装了一个 project-work 的 skill 来处理这件事,也避免给 agent 带来噪音,所有需求通用类的要求会被收敛到一起

这一层值得一提的是,由于记忆系统的存在,就算你只开了某个子项目,你也能直接在子项目的 ai 终端中读取到其他项目的上下文。

temp 层

这层就放各类的临时文件了,比如我的计划、报告、临时 git 仓库等,没有说明放置位置的文件都会被收到这里,用日期进行划分,这里只临时存放,所以也同样会被 git 忽略。

关于知识增长

上文中谈到了记忆层的读取,这里则着重于记忆层的写入。

理想情况下,我们需要大模型每次被纠错 / 了解了我们的新习惯时,都自动写入记忆到知识层

但随着上下文的增长,自动处理会逐渐跑偏甚至失效,所以我们要两手准备,即自动和手动。

手动记录

我增加了一个 checkpoint skill,当我完成当前任务,并且觉得此次对话有价值时,会发送 checkpoint 给 ai,由于在 claude.md 中约定了这个规范,ai 会自动执行该 skill

---

## Checkpoint

用户输入 "checkpoint" 时,使用 `checkpoint` skill 执行。

---

该 skill 就是一个工作流:

---
name: checkpoint workflow
 description: checkpoint 总流程 - 先沉淀 memory 与 knowledge,再更新索引,最后执行 add/commit/push
---

# Checkpoint Workflow

## 结论

- `checkpoint` 只在用户明确输入 `checkpoint` 时触发,不能按“收尾”“结束 session”等语义自动推断。
- checkpoint 的顺序固定为:回顾本轮内容 -> 写 memory -> 写 knowledge -> 更新索引 -> 自检 -> `git add` -> `git commit` -> `git push`- 不写 memory,checkpoint 不完整;没有完成知识沉淀,checkpoint 也不完整;未完成 `push`,checkpoint 也不完整。
- 用户明确输入 `checkpoint` 后,先运行 `git status`,识别已有脏改动和本轮工作范围。
- `git add` / `git commit` / `git push` 必须放在沉淀完成之后统一执行,提交前再运行一次 `git status`,确认没有遗漏文件。

## 适用规则

- 执行前先读取:
  - `src/brain/memory/claude.md`
  - `src/brain/knowledge/claude.md`
  - `src/brain/knowledge/knowledge-format.md`
  - `src/brain/knowledge/reinforced-rules.md`
- 如需补充用户偏好或错误模式,再按索引读取相关 `prefer-*.md` / `error-*.md` 文件。
- 如本轮涉及 `temp/` 写入,再读取 `src/temp/claude.md`- 写入 `memory/YYYY-MM-DD.md` 时只写 Done,不混入偏好、规则、反思。
- 写入 knowledge 时区分三类目标:
  - `knowledge/<topic>.md`:稳定结论、方法论、排查结论
  - `prefer-*.md`:稳定协作偏好
  - `reinforced-rules.md`:反复犯错且需要强制检查的规则
- 更新完内容后同步更新对应索引:
  - 新增或改写 knowledge 时,更新 `src/brain/knowledge/claude.md`
  - 更新当日 memory 时,更新 `src/brain/memory/claude.md`
- 更新 `src/brain/knowledge/claude.md` 时,同步把本轮实际读取过的 knowledge 文件 `Usage` 加一,并按 `Usage` 降序重排。
- 如果 checkpoint 开始时已存在与本轮无关的改动,先识别边界,不把无关文件误纳入提交。
- 若改动包含 `src/projects/`,不能直接提交,必须先展示 `git diff` 并等待用户确认。
- `git push` 默认属于 checkpoint 标准流程,除非用户明确说这次只提交不推送,或远端/网络阻塞导致无法完成。
- 完成后报告:
  - memory 写入位置
  - 更新过的 knowledge 文件
  - 更新过的索引
  - 执行的 git 流程
  - 若未提交,说明阻塞原因

其中,根据本轮对话更新 knowledge 与 memory 是核心,也是 agent 能持续成长的关键。

利用 checkpoint 新增的 commit,前缀我规定为了 cp-,这是为了防止跟自己手动更新的部分产生混淆,另外后续也需要根据这个标识,进行一些特殊的处理

这里 checkpoint 用其他的词也行,不过如果太常见可能容易令模型歧义

自动记录

自动记录是高频触发项,需要记录的点主要是 knowledge,此类约束需要在每次对话中都用到,所以需要加到我们的入口文件 claude.md 里

## 记忆系统(Memory Protocol)

**核心原则**:所有工作过程必须沉淀到记忆系统,不写 memory 或者知识没正确积累都视为任务未完成

| 类型 | 位置 | 要求 |
|------|------|------|
| **memory** | `memory/YYYY-MM-DD.md` | 今日完成的工作清单(Done) |
| **knowledge** | `knowledge/<topic>.md` | 可复用的稳定结论、用户偏好、方法论 |

**即时沉淀:**
- 如果在对话过程中被用户纠正,或已经确认形成了可复用的稳定结论,必须先更新对应 knowledge,再继续当前工作
- 不要等到 checkpoint 才补记这类内容,避免遗漏或表述失真
- 写入时只记录稳定结论本身,不把一次性上下文和命令过程塞进 knowledge

合理性评估

脚本侧约束

众所周知,模型的幻觉是相当严重的,在知识增长的时候很容易写错文件,比如我们已经指定了 src/brain 为记忆层的情况,它仍然可能写到外层的 /brain。

这种情况其实在项目开发中是挺常见的,比如【git 分支命名规范不对的时候,直接拦截,不允许提交】,和这个其实是类似的情况,所以理所当然的请出了我们的 husky

husky 主要负责在 git 提交过程中加入钩子,在这里的应用就是拦截不合规范的提交

我在外层的 /script 中增加了一个脚本,并配有白名单机制,只允许设置好的文件类型、目录等被提交

如此一来,模型即使出了幻觉,也会在 checkpoint 提交时被卡住,返回的错误会让 ai 重新去读取当前设置的文件规则,从而在大体架构上约束住模型。

模型侧评估

根据上面的 husky 拦截原理,我们还可以再加入一个评估 agent,用于整体评估该 checkpoint 是否符合预期。它会按照以下步骤执行:

  1. 新开一个空白的 agent,避免给自己生成的结果开后门
  2. 收集当前对话的完整流程,git diff 作为上下文
  3. 根据设定好的评估规则进行评估

评估若拒绝,则 commit 会被打断,并且将错误抛回给主流程继续处理

关于飞书豪华加强版

不得不吹的一点,当你舍弃了龙虾这些封装的好的库,你将得到无穷的灵活度。

case1: 当到饭点的时候,你的 claude code 只跑了一半,这时候就可以用手机接过该对话,放心去吃饭,原理是使用 session id 进行对话同步。

此处应该有图片,但是飞书有水印,遂放弃,看下文字版本吧。首先是 /list 指令

(我发送)/list 
(agent 开始回复)最近 5 条本地会话:  


1.  ai-config | 04-20 11:13  
    提问:好像如果 /load 回复太多的时候, 会弹出来一大串消息, 有点影响正常使用, 将这一串消息合成一条吧, 不过注意飞书消息一次最多18000…  
    回答:已经改了。 `/load` 现在会优先把“已加载对话 + 最后一个提问 + 回放内容”合成一条消息发送;只有合并后超过飞书单条 18000 字…

2.  fe-monorepo | 04-20 10:57  
    提问:先改一下我看看  
    回答:我先给你落了一版最小改动…


3.  fe-monorepo | 04-17 20:50  
    提问:是说 website 模式下  
    回答:对,website 模式下这两个接口分工是这样的…


4.  ai-config | 04-17 16:32  
    提问:你得写全, 可以自己运行看看有哪些, 并且给我补上中文介绍  
    回答:已经补完,README 现在是基于我本地实际运行 `gws --help`、`gws --help`、`gws schem…

5.  ai-config | 04-17 16:28  
    提问:apps.googleusercontent.co…  
    回答:已经写进项目了: - 新增 [`.env`](/Users/imoo/work/data/project/ai-config/src/temp…

使用 `/load <序号>` 加载指定对话。

接着是 /load 加载

(我发送)/load 2
(agent 开始回复)已加载对话 fe-monorepo | 04-20 10:57  
最后一个提问: 先改一下我看看  
后续在这个话题里的普通消息会基于这条上下文继续。  
  
我先按最小改动做一版,只碰... (这里是完整的,不过不占用篇幅了)

还有的同学会说,会不会像龙虾一样停不下来,所以我这里还提供了一个 /abort 功能,供你写错或者它理解错的时候直接终止。

case2: 当群里某个话题下讨论的热火朝天,需要用 agent 排查时,能直接 @ 介入并自动读取上下文,原理是话题 id 可以拉到完整消息

消息1:你好,现在几点

消息2:我忘了 @你

消息3:@claude200


claude200:我先按仓库规则完成会话初始化,读取必需的记忆与目录说明文件,再基于线程上下文继续回复用户。

claude200:记忆系统已加载,我补一下线程里漏掉的回复,先取当前时间,然后按飞书对话语气续上。

claude200:现在是 2026-04-20 11:34:47(CST,上海时区)。你刚才忘了 `@` 我也没事,这里补上回复。

case3:通过 mcp 直接读取飞书文档

这个倒是挺常见的,让 agent 直接读业务文档。

新增的好处则是让他记录了一下,当 mcp 授权过期时,它会直接提醒你去哪个链接再点一下,省去了查路径的问题。

case4:当你遇到新功能还需要加新特性时

比如说最近在改造对话功能时,想让他读取到对话,就先贴一个小表情。

这个功能能让我知道它正在正常工作,我直接一句话发给了它,它库库改造完成后,自动进行了服务重启。这样一来我想要什么新功能,只需要直接告诉它即可,灵活度极高,而且处理成本极低。

总之用起来一个字,爽!

screenshot-20260420-115324.png

总结

本文有两个关键点:

  1. 用一个简单的方式搭建记忆管理系统,并将记忆这部分做成不依赖平台、可迁移的方式
  2. 手搓一个链接飞书的方式,体验绝对远高于龙虾的飞书

就是这些,感谢阅读~

半日主力资金加仓电子板块 抛售房地产板块

2026年4月20日 11:52
主力资金早间净流入电子、国防军工、计算机等板块,仅净流出房地产、农林牧渔板块。具体到个股来看,浪潮信息、中天科技、中国卫星获净流入30.10亿元、28.98亿元、27.35亿元。净流出方面,新易盛、长光华芯、太辰光遭抛售8.87亿元、6.43亿元、5.58亿元。(第一财经)
❌
❌