2025年终总结

还记得去年的总结是在高烧中迷迷糊糊完成的,谁能想到,今年开始动笔时,我又发烧了。 年终序言:这会是最后一篇年终总结吗? 去年使用各类 AI 工具时,新鲜中还夹杂着对不可控与等待焦虑的不确定性,但随着 DeepSeek 在年初的重磅更新引爆全球,中美各大科技巨头纷纷加注,砸下大量资源对 AI 进行超饱和式投入。这一年,随着产品端爆发式迭代,用户对 AI 产品的接受度也在迅速提高。 这一年,随着产品形态更多从 assistant 向 agent 转向,AI 智能体的交互形态和数量都在迅猛膨胀,而随着中心化 ReAct 架构的迅速衰落,多智能体方案伴随着持久记忆、生成式 UI 等技术手段与创新,开始走向主流,助力 AI 成为真正能上岗干活的智能助手。 随着时代革命的加速迭代,从国家层面战略部署、城市发展与治理被 AI 重构,再到企业间竞相内卷大模型能力,仿佛不踩上这趟车,就会被时代彻底抛下。而这份宏大的冲击,从日常新闻报道中,也顺着行业脉络、公司运营,渗透进了每个人的日常生活。AI 除了在疯狂迭代中对各行各业产生颠覆性“冲击”,也在以肉眼可见的速度击穿宏观与微观的边界。不论 AI 最终发展成什么样,毫无疑问,当前 AI 已演变成一场裹挟所有人无法回避的浪潮。 兴奋与恐慌持续共存,而这一年也悄悄来到尾声。不知再过多久,AI 的认知与思考能力会超过我,但至少当下,我最真实的感受还需要通过控制大脑,从这一年的见闻中挑挑拣拣,以形成这篇年终总结。 躺在投资舒适区,迎向迷茫和充满风险的未来 近几年的年度总结,似乎总是从投资复盘开篇,不过今年这部分会相对轻松些。尽管这一年依旧不太平——地缘政治冲突持续、中美谈判几经反复,但美联储降息预期逐步落地,国内也多措并举稳内需、促经济,整体仍是平稳的一年。 资本市场在这一年走出了回升行情,只要不追涨杀跌,不在高频交易中损耗成本,大概率都能像我一样,在宽基指数与行业指数的布局中有所收获。不过,即便今年的交易难度有所降低,仍有不少美中不足:比如仍趴在地板上的医药和白酒,以及在我看来远没触底的房地产板块。 展望明年,AI 在资本的饱和式供给下正迎来“龙卷风式”的迭代,这股浪潮不仅在革新各行各业,更在深刻影响未来的职场格局、企业需求及订单结构。眼下,由于资本仍热情高涨,市场也未充分计价风险,我们尚难判定这场 AI 热潮究竟是颠覆性的技术变革,还是即将破灭的资本泡沫。但多重复杂因素交织之下,明年的资本市场无疑会充满更多不确定性。 从最终结果来看,我今年的投资收益算得上差强人意。但遗憾的是,过去一年各类杂事填满了生活,我在投资学习上几乎是全然荒废。全年的投资操作,更多依赖长期持有与被动调仓,主动投研和持仓深度分析的环节,几乎是一片空白。投资本就是一门需要终生钻研的学问,依赖市场势能或许能让人 “躺平” 一时,但长此以往,终将被市场淘汰。明年务必要补齐这块短板。 除了股票与基金投资,今年我还花了不少心思研究稳健理财。从曾经的刚性兑付,到如今全面净值化转型,再到多项不合规计价方式被明令禁止,稳健理财早已渐渐褪去了 “稳健” 的标签,而我也到了该离开的时候了。年中时,我梳理了手头的稳健理财持仓,决定逐步将资金分流至其他资产类别。不过这些调整,暂时还未体现在投资收益率的提升上。往后等时机成熟,我或许可以写一篇文章来分享这段心路历程。 当职业生涯被 AI 击穿,很多事情开始模糊起来 以前说到转型,我们往往会将牺牲品锁定在被机器和技术替代的基础服务行业,不太会担心自己。相比可以被替代的体力,我们曾认为程序员的思考与编码能力难以模拟。但随着行业中到处 All in AI 的战略落地,不论大模型技术还是各类 AI 应用都入雨后春笋般涌现,不断地迭代正使得 AI 能完成一定复杂度工作的能力被认可,各类 AI 工具已渗透进我们的日常工作中,“经验优势”和“技能壁垒”正在加速瓦解,不可替代性已成为假命题。 程序本身,作为高度可判断和可推断的特性,在 AI 替代列表中首当其中。AI 创新没有带来温和的转向,而是让“平庸层”在迅速消失,不同工种之间的界限也逐渐变得模糊,市场上不再需要那么多“写代码的人”,总体岗位需求正在不断湮灭。 以前,我曾一直自嘲没有核心竞争力、随时要下岗,那时还很笃定自己的生产与创造力,但直到今年,在“无所不能”的 AI 面前,我第一次真正感受到职业生涯的明显缩减。 平平无奇的一年,从热闹工作开始、以忙碌焦虑收尾 今年的我,工作上是平平无奇的。一度忙碌到兼任产品、研发、设计等多个角色,但突然戛然而止,又干回前端,几个月后却又在迎面迷雾中转向全栈与 AI。这一年里,体验了冲一把的刺激,在一些项目尝试中有了跨越边界的收获,但更多的是,在大环境裹挟下日复一日品尝着身不由己的无趣。我曾经以为,工作要么快乐时斗志向前,要么气愤时转向窗外,却没想到还有一种带着忧虑和迷茫的无趣感。 虽说无趣,但我一直相信,每个时代都有属于每个时代的机会。在 AI 带来职业冲击的同时,虽然不知胜算几何,但我还是做了不少尝试,从个人 Context Coding 到 Agent 与 workflow 开发,很多事情虽然不一定有结果,但至少没有坐进观天、原地踏步。 虽然我仍没有想清前路,但就像在之前一篇文章中所说,首先,不论有没有 AI,很多工程技术的发展在这几年就已经大幅放缓了,这受制于市场需求和经济基础;其次,不止前端,客户端、服务端等主要靠通过人类来弥合用户需求与机器实现之间 gap 的工种,都在消亡。 在焦虑中,用一句话总结下今年的工作经历,仿佛是在激情蹦迪后,又跳回了原地。 年度健康 Keywords:全麻手术、健身退步、重拾烟火气 回过头才发现,我的忍耐力还挺高。我那不安分的阑尾在最近三年发作了三次,但每次我都忍了两天才去就医。之前因为担心影响工作,我都选择了保守治疗。由于多次发作,医生担心反复保守治疗会留下囊肿和粘连等后遗症,在医生的反复劝说下,一咬牙,我就把这个没什么用却充满负担的小器官切了。第一次做全麻手术,第一次需要家人陪着住院。手术本身并不难受,但陌生的环境加上术后插着个引流管,我的身体和精神都有明显的不适应症。 由于身体条件不允许,住院期间我实在没法工作,但在肢体被限制期间,我在病房里荡悠,在护士站闲聊,在病床上闭眼静养,在休息区和其他病号闲聊,收获很多生动故事的同时,内心默默给“健康”在人生排位上提升了很大的优先级。 我仍在坚持运动,但因为手术及恢复期间断过两个月,再加上今年频繁搬家,游泳这项运动也一度中断,运动量大大退步,这对于“努力健身却毫无痕迹”的我来说,更是雪上加霜。明年务必要补回来。 今年的我在医疗健康问题上一改往日拖沓作风,但另一方面,在按时作息、高效利用时间上,仍旧不合格。但关于饮食健康上,我很自豪的一点是“重归烟火气”。从往日看着食谱慌忙做出四不像菜肴,到跟着爸妈指导依葫芦画瓢,再到独自一人尝试新品、开拓新口味……这一年里,我的厨艺有非常明显的进步。我会担心在厨房呆久了成了“黄脸婆”,但更多的还是开心。刨根问底,我发现自己开火带给我的最大收获不仅是食材安全和健康可控,更多在于自己可以在从买到做的整个过程中放空自己,远离忧虑与压力,尽情享受没有杂念的创意设计过程。 藏在生活碎片里的快乐片段与遗憾插曲 今年的生活一波三折,比如我签过三个合同、搬了两次家。作为一个嫌麻烦且犹豫不决的人,没想到因为一些变故,有了第一次租房违约,压床底的收纳箱在短短半年里派上了两次用场。 然而,就是在这过程中,我开始践行真正意义上的断舍离。那些之前可能几年完全没用过的一些物品,大到床垫,小到杯子,我一个个将他们摆好,给他们拍上好看的“身份照”,然后编辑文字发贴。就在这些东西卖出去的那一刻,我发现自己也感受到了快乐,这快乐不仅来自于我从中回了些本,更在于这些物品在流转中,寻来了真正需要他们的主人。从某种意义上说,这非常契合我的性价比和实用主义观念。 记得我在公众号开始输出时,第一篇文章的名字就叫重振香港,但当时我其实没去过粤港澳大湾区。今年,我第一次去了香港。在准备行程时,才发现港澳通行证已经过期。很多证件都以十年为一个周期,但就在一切备齐时,最终也没促成行程。这一次,算是弥补了过去十年的遗憾。这次去香港,从蹲点太平山顶的烟花展到漫步西贡码头,从看不懂的 M+ 到 Hotel ICON 的榴莲自助,在快速感受这个城市的律动同时,我也攒下了足够很长一段时间回忆的美好碎片。一路上,遇到的人和事,除了让我开心快乐外,也真正让我慢下来思考。也是从今年起,我开始考虑长期规划的变数,我正式取消了在北京安家置业的打算,而开始向更适合的职业发展机会倾斜,去哪个城市、做什么工种,更多只是需要考虑的配套罢了,并不 key。 旅行是快乐的,于是就会想着再多尝试几次,获得更多快乐。以前,每逢假期景点爆满的新闻总会让我焦虑,于是我更喜欢通过大家的朋友圈“云游四方”。但人生嘛,重在体验,也不用一成不变的固守一处。随着性子,以后遇到假期,还是可以有些不同的尝试。 今年,我还想从分享文字转向视频输出,也就是当一个 up 主,但遗憾的是,这件事情迟迟没有落地,本来半年结束时,我在反思自己不够快乐时有过这个想法,但生活琐事交织在一起,这里处理一下那里处理一下,就来到了年底,而我还没有真正开始动手。今年还有个小成就,就是带家人逛了北京、天津和上海这几个城市,在纯粹的陪伴中,我感到自己是被需要的,再加上全程都是我一手操办,想想就很开心。 磨平棱角,中庸其实是个中性词 人到中年,我发现自己越来越倾向中庸之道。在我看来,这是一个中性词,生活里、工作中、感情上,很多事情没有绝对的对错,只是是否匹配或者合适,所以我也不再用 YES or NO 来回答,取而代之的是带着前因后果与个人思考的阐述,希望为回答提供更多上下文,让“读者”能更明白我的所思所想。事实上确实如此,“你过了 35 工作怎么办?”、“买这个能赚钱吗?”、“AI 到底能提效多少?”,这些问题怎么可能会有直接的答案呢,但事实证明,更多的补充与不直接回应,很少换来感同身受,反而会被推诿成不直面问题、犹豫不决、能力不足等等。 但好在,相比年轻气盛时,我已不太在意他人眼光了。不再需要证明自己就是对的,不再需要频繁得到他人肯定,我认可人本质上还是孤独的,开始用更多的时间来探索与自己、与世界的相处之道。倒不是说不需要恋爱、家庭,不需要工作、生活,或者不需要与外界接触和反思,只是说在特定事情上的处理方式开始频繁向内追求自洽,寻求内心平静罢了。如果一个事按照符合心意的方式发展,能在沟通中获得他人的共鸣,自然会很欣慰、会开心,但如果事与愿违,或得不到别人的理解,那么在一声叹息后,虽有遗憾,也会放下继续前行。 磨平棱角后,在权衡利弊中不再勇敢和不顾一切,好处是终于可以舒服地在社会上生存下去,但这样真的好吗?理性可以让很多事情的解法可量化、可计算,走向确定性,但还有很多时候,拥抱天马行空时,为了那微不足道的可能性想冲一把,仍需要上头瞬间的感性。 虽然走向中庸,但如何平衡理性和感性的配比,仍是新的一年我要继续学习的课题。 写在最后 今年的总结有太多和 AI 相关的笔墨,这既是生活经历的写照,也是真实的职业焦虑。但回过头来,或许并不需像上文般如此焦虑。以人类的草台程度,AI 的全面替代还要在很多年后。我有很多新的想法并没写下,但我认为对 AI 能力更切实的描述应该是,一个可以辅助人类生产、生活变化的革命,在其中,AI 既提升生产力效率,也可以拉高创造力上限,但要做到端到端全场景智能,还太过完美化,我们到现在连人类大脑都还没完全摸清楚呢。 退一万步说,或许 AI 能做很多事,AI 也确实能在某一天完全替代我们,但你我存在的意义并不需要过多去外界寻求价值锚点。平淡或是精彩,我们认真生活的每一天,都是独一无二的,而这些组成我们的情感、经历、思想,这就是我们,直到最后、最坚定的人类信念。 如果感到焦虑时,可以停止快速滑动手机屏幕,走出门外,大口呼吸新鲜空气,感受阳光洒在身上时,你注视眼前那些烟火气的认真瞬间。今年没怎么分享我的年度 TODO 完成情况,但在那些没有太多被说道的琐事瞬间里,我仍在认真生活。新的一年,希望大家平安健康,我也要好好加油。希望突破现状,希望有所收获。 新年快乐。

2025/12/20
articleCard.readMore

提示工程最佳实践:如何与 AI 更好地对话

Claude 最近新发了一篇关于提示工程最佳实践的文章,其中提到了诸多如何更好的写好提示词以利用 AI 帮助大家精准解决问题的思路,太长不看可以直接拿走这份思维导图。以下正文会详细给大家分享一下我认为文章还不错的很多精华部分。 什么是提示工程?其本质是修改传递给大语言模型(LLM)的查询,核心是在实际请求前添加 “正确的信息”。提示工程的核心价值在于: 提示工程是构建指令以从AI模型获得更优输出的技巧,包括表述查询、指定风格、提供上下文和引导模型行为等方面。 模糊指令与精心设计的提示差异显著:前者可能需要多次沟通澄清意图,后者可一次性达成目标。 提示工程是上下文工程的核心组成部分,与对话历史、附加文件和系统指令协同作用,共同优化AI输出结果。 一个合适的学习路径应该是先掌握基础习惯,再逐步应用复杂项目的高级方法。 一、核心基础技术 1. 指令明确清晰 核心原则:直接告知模型期望的结果,不假设模型能推断需求,使用简洁无歧义的语言。 最佳实践 以直接的动作动词开头(如“撰写”、“分析”、“生成”、“创建”)。 跳过开场白,直接切入请求核心。 明确输出应包含的内容,而非仅说明处理对象。 具体说明对质量和深度的期望。 示例对比 模糊表述:“创建一个分析仪表板” 明确表述:“创建一个分析仪表板,包含尽可能多的相关功能和交互,超越基础要求,实现功能完备的方案” 2. 提供上下文与动机 核心价值:解释需求背后的原因,帮助AI理解核心目标,生成更具针对性的响应(对能推理潜在目标的新型模型尤为有效)。 适用场景 说明输出的用途或受众。 解释特定约束存在的原因。 描述输出的使用方式。 指明要解决的具体问题。 示例对比 效果较差:“绝不要使用项目符号” 效果更佳:“我偏好自然段落形式的响应而非项目符号,因为流畅的散文更易阅读且更具对话感,项目符号对我的轻松学习风格而言过于正式和列表化” 3. 指令具体化 核心要求:通过明确的指导方针和要求构建指令,具体程度越高,结果越优。 需包含的关键要素 明确约束(字数、格式、时间线)。 相关上下文(受众、目标)。 期望的输出结构(表格、列表、段落)。 任何要求或限制(饮食需求、预算限制、技术约束)。 示例对比 模糊表述:“创建地中海饮食的膳食计划” 具体表述:“设计一份用于糖尿病前期管理的地中海饮食膳食计划,每日1800卡路里,重点关注低血糖指数食物,包含早餐、午餐、晚餐和一份加餐,并提供完整的营养成分分析” 4. 使用示例(单样本/少样本提示) 核心作用:通过示例直观展示期望的格式、语气或模式,比纯描述更易澄清复杂需求。 注意事项:现代模型(如Claude 4.x)会密切关注示例细节,需确保示例与期望行为一致,避免传递不良模式。 适用场景 期望格式难以用文字描述。 需要特定语气或风格。 任务涉及微妙模式或惯例。 简单指令无法产生一致结果。 实用技巧 先尝试1个示例(单样本),仅在输出不符合需求时添加更多示例(少样本)。 示例对比 无示例:“总结这篇文章” 带示例:“以下是我想要的总结风格示例:文章:[AI监管相关文章链接] 总结:欧盟通过全面的《人工智能法案》,针对高风险系统,核心条款包括透明度要求和人类监督规定,2026年生效。 现在按相同风格总结这篇文章:[新文章链接]” 5. 允许AI表达不确定性 核心目的:减少模型的幻觉(虚构信息),提高响应的可靠性。 示例 分析这份财务数据并识别趋势,若数据不足以得出结论,请直接说明,不要猜测 二、高级复杂场景技术 1. 预填充AI响应 核心作用:提前启动AI的响应内容,引导输出的格式、语气或结构。 适用场景 需要输出JSON、XML等结构化格式。 希望跳过对话开场白,直接获取核心内容。 需维持特定语气或角色。 要控制AI的响应开头方式。 2. 思维链提示(CoT) 定义:要求AI在给出答案前进行分步推理,适用于复杂分析任务。 适用场景 无“扩展思考”功能可用。 需要可审查的透明推理过程。 任务涉及多步分析。 需确保AI考虑特定因素。 三种常见实现方式 基础思维链:在指令中添加“分步思考”。示例:“为Care for Kids项目撰写个性化捐赠请求邮件,先分步思考再动笔”。 引导式思维链:指定具体推理阶段。示例:“撰写邮件前先思考:1. 根据捐赠者历史,哪些信息可能吸引他们;2. Care for Kids项目的哪些方面能引起共鸣;3. 基于分析撰写个性化邮件”。 结构化思维链:用标签分隔推理过程与最终答案。示例:“用<thinking>标签记录思考过程(分析吸引捐赠者的信息、项目相关亮点),用<email>标签呈现最终邮件”。 注意事项:“扩展思考”与手动CoT可互补使用,复杂任务中结合使用效果更佳。 3. 控制输出格式 核心原则:通过正向引导、风格匹配和明确要求实现格式控制。 三种有效方法 正向指令优先:不说“不要做什么”,而说“要做什么”。示例:不说“不要使用Markdown”,而说“响应应采用流畅的散文段落”。 提示风格与输出风格匹配:若希望输出少用Markdown,自身提示中也应减少Markdown使用。 明确格式偏好:详细说明格式要求。示例:“撰写报告时使用完整段落和标准分段,Markdown仅用于行内代码、代码块和简单标题;非必要不使用有序/无序列表,将内容自然融入句子中”。 4. 提示链 定义:将复杂任务拆分为多个连续步骤,每个步骤用单独提示处理,前一步输出作为后一步输入。 核心优势:以增加延迟为代价,提高每个子任务的准确性,适合需要迭代优化或中间验证的场景。 适用场景: 复杂请求需拆分步骤。 需要迭代优化输出。 多阶段分析任务。 中间验证能提升最终质量。 单条提示输出结果不一致。 示例(研究总结): 第一条提示:“总结这篇医学论文,涵盖方法、发现和临床意义”。 第二条提示:“审查上述总结的准确性、清晰度和完整性,提供分级反馈”。 第三条提示:“根据以下反馈优化总结:[第二步的反馈内容]”。 三、技术整合使用提示 1. 尝试通过多技术组合达到目的 从这份季度报告中提取关键财务指标,以JSON格式呈现。该数据用于自动化处理,因此响应必须仅包含有效JSON,无开场白或解释。使用以下结构:{\"revenue\":\"带单位的值\",\"profit_margin\":\"百分比\",\"growth_rate\":\"百分比\"}。若报告中未明确说明某指标,用null表示,不要猜测。响应以左大括号开头:{ 2. 技术选择决策框架 基础判断步骤 需求是否清晰明确?若否,优先优化清晰度。 任务是否简单?是则仅使用核心技术(明确、具体、提供上下文)。 是否需要特定格式?使用示例、预填充或明确格式指令。 任务是否复杂?考虑拆分任务(提示链)。 是否需要推理?使用“扩展思考”(若可用)或思维链。 技术-需求匹配表 需求场景 推荐技术 特定输出格式 示例、预填充、明确格式指令 分步推理 扩展思考(Claude 4.x)、思维链 复杂多阶段任务 提示链 透明推理过程 带结构化输出的思维链 防止幻觉 允许AI说“不知道” 3. 常见问题故障排除 问题现象 解决方案 输出过于通用 增加特异性描述、提供示例、明确要求“超越基础内容” 输出偏离主题或未击中要点 更明确地说明核心目标,提供需求背后的上下文 输出格式不一致 添加示例(少样本)或使用预填充控制响应开头 任务复杂导致结果不可靠 拆分为多个提示(提示链),每个提示专注单一任务 AI添加不必要的开场白 使用预填充或明确要求“跳过开场白,直接给出答案” AI虚构信息(幻觉) 明确允许AI在不确定时说明“不知道” 期望执行操作,AI却仅提供建议 明确动作指令(如“修改此函数”而非“你能建议修改吗?”) 4. 实用技巧 从简单提示开始,仅在需要时添加复杂技术。 每次添加技术后测试效果,确认是否真的提升输出质量。 四、常见错误与避坑指南 过度设计:更长、更复杂的提示不一定更好。 忽视基础:核心提示模糊不清时,高级技术无法弥补。 假设AI能“读心”:不明确的需求会导致AI误解,需具体化所有要求。 滥用技术:无需同时使用所有技术,仅选择解决特定问题的方法。 不迭代优化:首次提示极少完美,需测试并调整。 依赖过时技术:XML标签和过度角色提示对现代模型必要性低,优先使用明确指令。 五、最终建议 核心定位:提示工程本质是“沟通”,即用AI能清晰理解的语言表达意图。 学习路径:先熟练掌握核心技术,形成习惯后,仅在解决特定问题时添加高级技术。 优质提示的关键:并非最长或最复杂,而是能以最少的结构可靠达成目标。 与上下文工程的关系:提示工程是上下文工程的基础,每一个优质提示都是塑造AI行为的重要组成部分。 参考 原文:Best practices for prompt engineering

2025/11/26
articleCard.readMore

2024年终总结

前些天还有很大冲动要赶紧忙完手头事给这个年更节目预留时间,但真腾出空来打算下笔时,迟疑了很久,不知从何说起。打开相册从 1 月翻到 12 月,各种平淡无奇的片段一闪而过,要说这一年都干了些什么,貌似除了继续“熬”着并没有什么让我印象深刻,但真当想放弃时,又觉得该为他记录些什么。此刻的我扁桃体发炎加高烧不退,最终能写下啥文字,有几分可读性也不再清楚,但年更节目不能断更。 在投资中感受人性的贪婪与恐惧 要说这些年的“熬”收获了什么,我首先想到的是对贪婪与恐惧的人性有了更深的认知。在每一轮行情中,除了感受市场冷暖,自己的贪婪与恐惧也随之不断辗转。 今年初,A 股在急跌后迎来了一波转瞬即逝的疯狂反弹,就当大家还没回过神来,随着经济数据陆续出炉,市场情绪迅速冷却,一路阴跌到 9 月缩量到每天 6000 亿左右。熬到熊市第三年,加仓的间隔与金额在每次计算时都显得更加谨慎,虽然心知肚明,市场不可能一直跌下去,但在经济下行的背景下,不论是宏观行业还是微观个体的经济状况,都在不断恶化,我也早已没了从前的自信。 就在市场绝望之际,9 月底重磅会议突然加场,给政策转向定调,市场情绪直接被点燃。你说这半个月不到的时间里,有实体经济变化了吗?丝毫没有。但上证指数就直接旱地拔葱式的从 2700 直接跳到将近 3700,“信心比黄金重要“。甚至,一位从不投资的同事,也在国庆期间信誓旦旦跟我预测:指数月底必上 6000,年底 10000 不是梦。当然,没人能猜到市场怎么走,一路狂欢的暴涨行情在国庆后也戛然而止。直至今日,A 股的震荡行情已持续三个月了。 不仅要有目标,还要有清晰的执行计划 你可能会好奇,在今年市场最疯狂的那半个月,我做了什么?市场突然转向,几乎没给我太多时间思考行动方案,但却给我带来了巨大的焦虑。这种急涨行情明显不可持续,我频繁问自己是否需要撤出一些已盈利仓位;与此同时,更让我不安的是随着行情从火热变得火爆,因为手头还有闲钱在活期,我也开始担心错过。 即便不知道击鼓传花最终停在谁手中,但我仍会觉得自己不是那最后一个,于是我开始谨慎增加了短期仓位,并开始沉迷于每天不停地刷新软件。从结果上看,没动长期仓位以及通过短期网格使我不仅享受了完整行情也额外赚到几波零花钱,多少算个小股神,但只有我知道,当时的我可不是这个状态。 直到现在,我仍会设想另一条不曾发生过的场景:如果行情快速跌回到 2 月?如果因为担心过早撤出了大量仓位,而后又上头追涨了进去?人终归是动物,贪婪与恐惧的情绪在投资上会被极大放大,如果没有清晰的执行计划,那么就只能依靠不可靠、充满情绪的大脑。 市场上赚钱翻倍的机会数不胜数,但只需要亏一次就可以净值归零。提前做好计划,不预测,只应对。新的一年,要把完善的执行计划补齐。 不用等到一切都就绪才开始 很多时候,我都会倾向一件事情在大体上就绪才开始,因为,太多的不确定性会给我一种”失控感“。我曾经从中受益良多,从竞赛获奖到推免保送,从校招斩获众多 offer 到依据自身规划跳槽晋升加薪,这些大多都是在有了足够准备和充分练习后,奋力发起一击的结果。但凡事没有银弹,并不是所有事情都适用这种方式,也不是所有事情都有足够的时间等得起你的准备。 还记得两年前就和朋友约定好,我们要互相监督努力发展副业,但两年过去了从没行动起来。反省起自身,也不算是个拖延症的性格,但就是一直没开始,源头还是因为我真的没准备好。我还需要想清楚,但如果一直不能想清楚呢? 我们今年做出了改变,先从稳定的输出开始。不论是生活、技术还是商业、社会,不用过多的关注行文段落和措辞,但要输出鲜明的观点。我还记得逼迫自己将第一篇文章选题香港时,逼迫自己在半小时内完成搜索、阅读、学习以及将文章发表出来当时争分夺秒的紧迫感。随后的大半年时间里,我利用下班、周末、健身的间隙记录些思路关键词,并通过其他空余时间将其扩写成文章。期间不仅越写越顺畅,还结识了不少朋友。 你要问我现在准备好了吗?我会说并没有,也许永远都准备不好,因为永远都会有值得琢磨与优化的空间,但他已经不影响我行动起来。在行动的过程中,不断地审视与回顾,使自己对要做的事情也有了更加清晰的认知。可能最初我定的目标是向东走,而后发现应该转向东南,但这都不重要,重要的是行动起来。行动的过程,也是在梳理思路、发现自己的过程。 留出时间,与自己对话 这些年经济下行压力很大。各行各业都受此影响。本以为熬一熬就能看到光明,但实际等来的却是起落落落。每个你我都承受了很多,这在日常工作上体现为”不停的内卷“。当增量市场没了空间,就只能从存量市场中抢蛋糕。当自己行业的蛋糕不够吃,便开始觊觎跨行业的蛋糕。一个直观的数据来源,从统计局统计的人均每周工作时长在不断提升。 我们都知道卷不好,但更不好的是他的副作用。我经常听到一些朋友的声音,他们说,再熬一熬,忍一忍就好了。但就像今年 9 月的闪电行情一般,如果我们只是一味的熬,而不思变,那等行情真正来临时,我们如何反击?一味的内卷,既是对当下生活的麻木应对,也占用我们用于思考的时间。 我今年坚持下来的几个习惯,都源自留出的时间。即便工作再忙,我都留出时间写作、健身与复盘。游泳吐气之余,思考自己昨天做的事还有哪些改进措施可以做得更好;坚持输出观点之余,与自己对话,为不断学习、不断收获的自己喝彩;坚持投资复盘之余,找到自己的弱点、补齐短期计划并实施。每个人都是一个独立个体,世上能真正与我们感同身受的只会有我们自己。懂的自己的希望与迷茫,快乐与悲伤,才能知道自己想要向哪走,以及如何走。 享受结果的同时也享受过程 今年的世界变得太快了,不论是世界政局变化还是国内经济发展,很多人都认为未来不会再好了。既然如此,那也不用熬了,直接躺平。躺平是一种生活选择,无关对错,不过我有另一个看法。 你不会说,当我想要收养一只小猫时,我发现猫是有寿命的,最终仍会离开这个世界,那我就不好好对它了。因为,在它陪伴你的每一天,那些美好的时光和片段,就会是最大的享受。另一方面,通过你的悉心照料,小动物可能会拥有稍长的快乐生活时光,而这个是你可以掌控的。 我们虽然希望享受结果,但过程一样重要。 保持好奇心与观察力 我读书期间去过国外一段时间,当时回国前,一位老师对我说,”Keeping curious“,随后我将那天的照片放在博客,直到今天。我的好奇心与观察力似乎一如往常,而如果我有机会再遇到他,我想好好的感谢他对我的鼓励。 不知道有没有人像我一样,会因为小区晚上更加明亮而发现物业更换了一批更节能的路灯,发现平日上班的小道被市政凿开重新铺了砖块,也会发现航班上的小桌板不再每次都保持干净,发现外出就餐时餐厅工作人员变少以及更多的引导我们自助扫码点单。我们工作时,大家不再考虑我们一起做出一款卓越的产品,而是更多考虑这个功能的投入产出比以及是否有用户需求。当我们购买电子设备时,导购员也不再无脑鼓吹你下单,也会给你提供一些优惠券的领取建议。 世界还是我们从小到大的那个世界,但似乎又在细微之处变了许多模样。充满好奇心,对周边事物持续观察,我仍享受着由此带来的乐趣与自由。此刻的我即将踏上再次前往上海的旅途,而我记忆深刻的仍是年初在上海的打车日记以及年中去上海与网约车师傅的一路交谈。 这一年我还做了些什么 三月份,达成了一个人做手术的顶级单身成就。我在手术当天提前到医院候着,在护士的引导下换上病服,但刚走进手术室便开始犯嘀咕了,”这手术室简陋的怎么跟电视剧里演的不一样呢?“ 这一年,除了几次去医院以及附随的康复期,我几乎每天都坚持到健身房打卡。自从去年同事鼓励我尝试器械锻炼后,我便一直坚持了下来。虽然没有健身房那些霸榜大哥的爆炸肌肉,但更有型一些的身材以及每次拳击时挥洒汗水的快乐,已经让我快乐满满。 虽然没有明确的出游计划,但今年因为各类事情的凑巧,还是逛了不少地方,也攒下了不少游客照。而”读万卷书,行万里路“里的读也仍在状态。 在公交车上,在地铁里,在商场等号就餐间隙,在上下班路上,对着那个电子屏幕,不断地翻页,不停地阅读。c除了书籍外,年初我还定了一个目标,即追更完今年所有的《财新周刊》,除了当下因为发烧无法继续的最后两期,我几乎坚持了下来。从财经、商业、宏观世界到人文落地,这份稳定且有质量的信息源,很好的扩充了我的世界观与从信息中攫取价值的能力。 今年,也并不都是美好。我坚持了多年的居家做饭习惯,中断了。一方面是享受做饭准备时的放空感,另一方面是真正尝到自己动手成果的自豪感,这难免不让我觉得遗憾,希望明年能拾起这中华民族自古以来的”优良传统“。 写在最后 这一年,不能说没有遗憾,但能够更坦然的应对失误、不纠结当下,我的世界观与认知明显正在变得更加完整,这让我感到充实、自由。虽然这可能不是我努力的结果,而是岁数到了。 轻舟已过万重山。新的一年,要加油。

2024/12/31
articleCard.readMore

车里的微光

刚到虹桥 下了飞机,我沿着通往停车场的道路走去,同时打开手机叫网约车。每次在机场叫车,貌似都需要跟司机沟通一番确认上车地点,软件的上车指引貌似只是一纸友好但过期的提示,并不具备实际参考价值。没过多久就有司机接单,很快一个电话打来,司机让我到另一层等他,我毫不犹豫地答应,径直朝向约定地点走去。当车到达,我把行李放入后备箱,像往常一样打开后座门坐了上去。 “师傅,不走高速哈,其他随意”,我说。 “好的,这一路没有高速,只有些高架”,他回答,“如果你在浦东叫车,那边可能有”。 “浦东啊,我前几个月来过一次,当时是从浦东机场出发的,那边可远了”,我抱怨道,“后来,我都注意选到虹桥机场了”。 我沉默了一会,继续说道:“浦东的客流是不是比虹桥少一些,毕竟远离中心市区嘛”。 “其实也不少,我们也能接到不少单。那边虽然远,但我更愿意接,赚的会更多一些”。 “是的,路途远价格就会高些”,想着师傅这么晚接我的单,于是我鼓励到:“师傅,你这么晚还跑车,家人肯定也挺心疼你吧”。 “就我一个人在这边,家人都在老家呢。对了,等你回去的时候可要注意,从哪个机场出发,别走错了,不然可就麻烦了”。 “好的”。 激烈的竞争 平时外出,我都会主动给家里报平安。在给家人回复完消息后,我又主动与师傅搭话:“上海的高架桥挺多呢,还有地道,车开着也不会堵吧,感觉比北京要好很多,经济也比北京有活力”。 “是啊,这里的路,建设的很好,到哪都方便”,他说道,“北京是首都嘛,上海还是比较多搞经济的人儿。但是啊,这两年也没以前好了啊。社会上那么多公司,又是裁员又是降工资的。就拿我们自己说,这半年赚到的也比原来少了很多”。 我说:“确实,我也有听说,好像滴滴提升了不少抽成比例吧?” “是的,比如平常你付 100 块钱的单,我们能拿到 80 块,今年可能就只有 70 喽,尤其今年过完年之后,这不就是压榨我们司机嘛”,从话语中能听到师傅对现实的无奈,但他仍在坚持。 “经济不好,大家就都卷起来了,同行互相卷,平台卷司机”,由于聊的比较投机,我继续说到,“现在,不仅滴滴抽成,你们内部也有危机感吧。前段时间新闻不是提到萝卜快跑嘛,也会抢走大家一些饭碗吧”。 “是啊,那萝卜在武汉多火啊,抖音上天天刷到。不过说回来现在道路这么复杂,你说我们都开不明白,他机器还能开明白咯”,师傅继续说道,“你看新闻不是也说两个萝卜在转弯的时候互相卡住了嘛,一动不动,给路上堵得哦。“ 师傅继续,“人还能听交警的话,那萝卜哪会听啊?路上要都是萝卜,那得乱套了。我看啊不太行,这开车还是需要人”。 电车与保险 “但现在电车真的很便宜,你觉得呢”,师傅谈兴正浓,开始饶有兴趣地给我介绍车市行情:“你看前阵子,比亚迪那车一出降价消息,价格就低了不少!依我看,其他车企啊都得跟着降。电车以后肯定会越来越便宜,大家都能买得起车”。 我突然有个疑问,便向师傅问道,”师傅,你说这路上跑的有多少是新能源车呢?” “一百辆里,至少得有五、六十辆吧”。 “那还挺多的。北京虽然也有新能源车,倒没这么多。可能因为天气冷吧,电池不经扛?” “是的,天气冷,电池掉电起来非常快,电车还是南方多些“。 我继续追问师傅:“话说,电车你考虑过蔚小理吗?相比比亚迪,他们的车型应该会更便宜些吧,性价比更高?” “比亚迪也不贵呢,而且质量多好呀。你看这次他们降价,又便宜了不少“,说到这,师傅扭了下身子,继续说道,“要说贵啊,还得是保险”。 “我之前倒是有了解过,好像是因为新能源车更容易出事故,再加上发展起来时间还太短,所以保险定价也比较困难?” “事故确实多,发生得也快啊。就像上一次我在路上开车,眼看着前方一辆车冒烟了,就开一会到跟前的功夫,那车已经全部烧起来了,你说这多严重啊!” 我紧握着收集,听着师傅的描述,仿佛能看到那些惊心动魄的场景在眼前一幕幕上演。 师傅似乎还有很多经验继续分享,“不仅是容易着火,平时啊你一个不注意,保费都会往上涨点。我去年续保费用涨了 20%,当时业务员也很纳闷,后面一查发现是违章、扣分啊这些,影响最终的价格”。 “但这保费啊,就算再涨也得买呀。这年头,你要不上保险,哪敢开车往路上跑啊。万一撞到人,误工费、住院费、治疗费这些各种算在一起,哪赔的起啊“,他说着说着有些激动,”你知道我们最怕什么吗?” 我摇摇头,表示不知道。 “最怕那些跟你耗着的。遇到个事故,就算不是你的责任,人家是弱势群体,你都得搭进去好些时间和精力,还有赔偿。就说去年那会吧,我的车直接被交警扣押了一周多”。 我问道,“你当时遇到什么事了吗?” 师傅说:“当时在小区里,我开的很慢,突然不知道从哪个缝里窜出一辆电瓶车,‘咣’地一下撞到我车上。你说明明是他没看路撞上来,检查后也没发现什么大问题,但他就是躺着不肯走。最后没办法,我只能报警。警察来了后,了解了一下情况,直接把我车拖走。后面赔了钱,才把我的车拿回来。” 我又疑惑道,“按理说,这事故也不是你的责任啊,为什么交警要扣你的车?” “不管谁的问题,你们之间没有协商好,交警就会先把车拖走,权当个抵押物吧”,他带着些许抱怨的语气说道,“必须等到双方协商好签完字,才能把车拿走。要是没法达成协议,对方还可以让你的车继续往后拖个十天八天的。车扣一天,我就少赚一天的钱,我在上海也要生活下去啊。你说,我哪拖得起呀?” 我安慰道:“有人就故意碰瓷,没事也说有事”。 “是啊,但你保不准会遇到什么样的人。现在买保险了,遇到事故就交给保险公司去处理了”,他说道。 她还在坚持 “还好有保险”,我感慨道。 “有了保险,也没太多改善啊,一样攒不下钱”,师傅感慨道,“你就说,我这一年跑车下来,也能赚个十几万不少了,要是在老家干活,一个月也就三四千,但还是攒不到钱啊”。 此时,路程已经好一会了,窗外的风景在多个高架桥和隧地道之间切换,一会明亮,一会阴暗,快速切换的光景让我时而可以放空发呆,给大脑一阵小憩。 车辆向前,貌似不再有地道了,具有经典上海街景的马路映入眼帘,两边整齐排列精致且小巧的楼房,在外饰灯光的映衬下还挺好看。即便如此,我还是感觉有些不对,说不上哪来的一股隐隐压抑感,突然,我想到,是对师傅印象的那种忸怩与割裂感,对的,就是这种不太真实的割裂感。 一个深夜这么努力跑车赚钱的师傅,对乘客出行给出热心建议,对新能源车行业也有自己的学习与了解,对激烈的市场和经济不好的大环境有所提防,同时还不忘配置保险保障家庭,怎么还会感慨攒不到钱呢。他的热情、努力与那份真实感,怎么都让我无法将他与那种赚到钱就去大手大脚消费、月光的人联系在一起。我心里犯着嘀咕, 而此刻,师傅开始主动搭话。 “我平时除了睡觉、跑车,也没啥开销,赚到的钱都往家里寄。你知道,我 88 年的,活到现在这个岁数,养家糊口啊开销很大,我这生活啊已经不是为自己而活了“。 我突然明白,原来师傅的钱都用在了家人身上,那确实花钱。还记得同事经常说,养娃就是个无底洞,师傅将花销都花在了孩子身上,那想必也是幸福的烦恼吧,我一阵释然。 师傅继续说道:“上有老下有小的,今天女儿要上个补习班,明天儿子要去学个兴趣课程,到处都花钱,就跟流水一样”。 我轻松应答道:“是啊,养孩子嘛,为了孩子定位茁壮成长,还有上学,都很花钱的”。 师傅继续:“小时候,我就在读书上吃过亏,现在不想他们再吃亏了,我多跑车,让他们可以多学一些吧”。 “可怜天下父母心啊,孩子长大后会明白你的好的”,我说道。 “倒不奢求他们将来如何回报我们,现在社会上那么多不孝顺的新闻,见怪不怪了。为他们付出了这么多,要真等我老了,他们不管我了,我也不能怎么办”,师傅补充道。 “是啊,这就是单纯的付出与爱,是不求回报的”,此刻的我由于对亲子教育没有太多经验,也不太想聊,于是借着上有老下有小的话题,我开始向「上有老」延伸,但没想到接下来引出了非常沉重的话题。 我对师傅说道,”孩子嘛,至少还有个盼头,就是不求他们孝顺回报,但这么一天天看着他们长大,也算有所慰藉。但是家里的老人啊,这事就不那么好处理了“。 听了我的话,师傅似乎没有那么主动想接话,由于我对父母养老这个话题也很敏感,所以每当有机会,我都会拉着人一起聊聊,于是我继续说下去,”父母啊随着年龄增长,不管是生病还是养老陪护,都需要花精力、花钱,有的时候这些事情才让人烦恼“。 师傅向前挺了挺身子,然后回复到,“可不是嘛,父母这一病,不停地吃药、治疗,每个月那么多钱,压力很大“。 师傅的声音突然低沉下来,他紧紧握住方向盘,一字一句的吐露着:“我妈每天都在吃药,每个月花很多钱在买药上,但依旧在病痛中度过,已经很久了。花费这么多,但还是没法好,而我们也不能多做些什么,除了多赚些钱“。 “她得了癌症,熬到现在有三年了”,他补充道。 我的转过头,看着窗外快速略过的夜景,试图平复自己的情绪,但师傅的话语却像一根针,深深地刺入我心底。昏暗的夜晚,只能靠着不断来往的车辆折射的灯光,隐约看到师傅的身影,此刻,我透过后视镜扫了师傅几眼,发现他的眼眶已有些湿润,闪着微光。此刻,我想安慰他,却发现任何言语都显得是那么的苍白无力。 尽力而为 只见师傅眼眶越来越红,他深吸一口气,仿佛在平复自己的情绪,然后继续说道:”你说做子女的哪能不管呢,但这三年来,不停地检查、更换治疗方案、换药治疗,花了很多,她每次忍着病痛的样子,让我看到真是如刀割一样。但我们已经尽力了“。 “是啊”,我憋出两个字回应师傅。 师傅继续说道:“我们家,我到上海来赚得多些,我爸在家打工,我老婆也在家打工,为了孩子和我妈,不停地攒钱,又哗哗的花出去,你说哪攒的下钱呐”。 “三年前她刚确诊癌症,当时每个月的钱还少些,但每隔两个月旧的检查一次,一次六七千,还要不断地买药。刚开始药便宜,后来药不管用了,医生就让我们换药吃,不断的换药,价格也不断上涨。上个月医生又跟我说之前的药不管用了,要换另一种药试试,一个月一两万。药越来越贵,也得继续吃着啊,她治疗着痛苦,但治不好,我们也难受。“ 这时我想起了医保,于是忙问师傅:“你妈有买医保或者农村保险之类的东西吗,那个应该可以分担一些支出费用?” “买啦。早几年,有个上门卖保险的,当时就给他们买了,赔了七八万吧,但要早知道,当时就该多买些,那样可以赔得更多。医保嘛,期初还能报一些,但后来不断加药、换药,那些进口药都不在里面,是不能报销的”,师傅一口气说了很多,但明显还没说完,他清了清嗓子,继续说道:“我妈是真遭罪,就这么一直扛着,扛了三年了,不知道还能撑多久了。我们真的尽力了”。 看到师傅的眼眶明显有些红润,我平静的说道:“你尽力了”,我不知道自己的表述是否恰当,于是停顿了一会,才继续说道:“可能努力改变不了结果,但至少让自己不留遗憾吧”。 ”你说尽孝吧,我们也一直在努力,但就没个希望。过个一阵,就听到医生说这个药效没啥效果了,需要换新的药。你说就我们县城,大家都是一个月三四千的收入,我在上海还能赚不少钱,这要换其他家里可能早就放弃了“,师傅的声音开始颤抖,”我朋友经常说我太拼了,为了父母,为了孩子,我也得继续拼搏啊!” “尽力而为,不留遗憾”,我说道。 “生活就是这样啊,但不还得继续努力嘛,总不能就这么放弃了。我妈都那么坚强,我也要继续努力。话说回来,我还是挺喜欢上海的,我能在这赚不少,让他们活的好些……” 车快到酒店了,司机放慢了开车速度,直到把车停在酒店大厅旁。他还在说,似乎没有喊我下车的意思,我也就继续听着。 “还是要买保险啊,有机会多了解些,这还是很有用的”,“多谢师傅,加油!” 这是我跟师傅最后的对话,此后我便下车,径直走向酒店。师傅也开车离去,继续他的人生旅程。放下行李后,我直奔健身房。跑了半小时步,我的心情好似才没有那么堵了,多亏运动帮我发泄一番。 尾声 就是这么一次再普通不过的打车经历,两个青年相互交换了各自生活中一个又一个的故事,这是每个普通人都会遇到的日常,也是每个普通家庭都可能会面对的生活难题。 虽然他口口声声说不再为自己而活,但我仍能感受出,他对自己奋斗目标的在意与上心,对平淡、幸福生活的向往。我跟师傅这辈子可能也不再会有机会见面,不知道他的家庭生活未来会去向何方,他的母亲病情会如何发展,他的两个孩子长大会做什么工作。 但我想,我应早已知道这些答案。这样一个个真实而努力的身影,每天都在我们周围发生,他正是千千万万个普通人的缩影。 为了赚钱补贴家用深夜跑滴滴的司机; 不论刮风下雨仍坚守岗位的建设工人; 牺牲自己睡眠坚守夜班以保障城市基本运转的服务人员; 起个大早为了路面清洁的环卫工人; 精心备菜在食堂为大家准备放心食物的厨师; 以及,每一个为生活努力的你我。 为每一个认真生活、奋斗拼搏的身影加油,愿每一个像他般努力、坚持且热爱生活的人,都能幸福。

2024/7/25
articleCard.readMore

来简单聊聊 AI Gateway

写在最开始 在当今科技领域,大型语言模型(LLM)和生成式人工智能(AIGC)已成为引领潮流的热门话题。它们的出现不仅颠覆了我们对传统人工智能的认知,还为各行各业带来了前所未有的变革。然而,随着这些技术的广泛应用,如何有效地将这些强大的 AI 模型集成到实际应用场景中,成为了一个亟待解决的问题。在如此背景下,一个名为 AI Gateway 的概念近期被大家所了解,作为一种连接 AI 技术与各类应用的关键平台,它又为当前火热的 AIGC 带来了什么? 本文将详细介绍 AI Gateway 的概念、功能,并通过丰富的应用场景展示其在实际应用中的巨大潜力。通过阅读本文,相信你会对 AI Gateway 有一个全新的认识,并为你在广阔的 AI 世界中探索工具箱增添一个新的技术,那么我们就开始吧。 说说什么是 AI Gateway 提及工业界的实践,要追溯到 Cloudflare 在去年 11 月推出的 AI Gateway 测试版了,Cloudflare 在发布时表示,AI Gateway 可以使 AI 应用更具可监测性、更可靠、可扩展性更强。所以我们首先来回答这个问题,什么是 AI Gateway 呢? AI Gateway 也被称为大模型网关、AI 网关,是一个用于部署和管理人工智能(AI)模型的平台,在开源社区有对应技术实现。它为用户提供了一种方便的方式来部署和管理 AI 模型,无论这些模型是预训练的模型,还是用户自己开发的模型。AI Gateway 还提供了一种方式,让用户能够在需要的时候轻松地调用这些模型,例如在进行数据分析或开发新的 AI 应用程序时。此外,AI Gateway 还提供了各种工具,可以帮助用户监控模型的性能,以及进行模型的优化。 当然,除了上述功能外,AI Gateway 的特点不仅限于些,它还提供了高度的灵活性和可扩展性,用户可以根据自己的需求选择部署模型的规模,以满足各种业务需求。用户也可以根据自己的需求,调整模型的参数,以满足特定需求。 此外,由于具有对模型的权限管理及实时监控功能,加上可以缓存、重试、调整模型调用优先级等优化措施,AI Gateway 还可以保护数据隐私,稳定、高负载、安全的运行。 AI Gateway 的优势及对比 AI Gateway 和 Gateway 虽然两者不如雷锋和雷峰塔之间的巨大区别,但除了都是某种形式的关卡外,两者在服务对象、应用场景以及主要功能上,都存在不少差异。 如上文所描述,AI Gateway 是一个 AIOps 类平台,作为服务和推理提供者之间的代理,无论模型位于何处,为管理和扩展生成式 AI 工作负载提供了统一的接口。相比之下,Gateway,即传统网关,则更多地用于网络连接和数据传输,是网络连接到另一个网络的“关口”,实现网络互连,是最复杂的网络互连设备。 简单来说,AI Gateway 专注于 AI 模型的集成和管理,而传统网关则侧重于网络连接和数据传输。 AI Gateway 与直接使用大模型 大部分朋友接触 AIGC 应该都是从 chatGPT 开始的,因此,当了解到 AI Gateway 之后,难免不产生疑问,为什么我不直接用大模型呢,还要多走你调用一层?当然,chatGPT 作为一个人工智能对话程序,能够借助自然语言实现人机对话,对终端消费者已经够用了,然而,AI Gateway 作为一个 AI 模型的集成于管理平台,对于开发 chatGPT 这类服务的开发者来说,可能更具吸引力。 AI Gateway 和直接使用大模型之间的主要区别也在于 AI Gateway 提供了一种集中化的接口管理机制,使得应用程序能够更高效、安全地调用多种大语言模型,而直接使用大模型则涉及到与模型的直接交互,会涉及更多的技术细节和复杂性。此外,AI Gateway 还有以下几方面的特点,使得其相比直接使用大模型更具优势。 首先,AI Gateway 作为连接服务和推理提供者之间的代理,无论模型位于何处,为管理和扩展生成式 AI 工作负载提供了统一的接口,这便允许我们通过统一的调用方式,根据自身需要在多个大语言模型之间切换调用,以获得我们的需要。 其次,缓存 API 调用让 AI 应用开发成本更加可控与便捷。通过 AI Gateway,可以对 API 调用进行缓存,这在行业高速发展期,面对 API 调用次数快速增长的背景下,可以快速地节省成本开销以控制研发成本。 AI Gateway 也可以组合一系列技术和策略确保数据隐私,包括加密、访问控制、审计日志等,以保护用户数据不被未授权访问或滥用,达到保护数据隐私的目的。 此外,还有一些 AI Gateway 实现可以通过严格的用户认证和基于角色的访问控制(RBAC)系统,确保只有经过授权的用户才能访问和修改数据模型。这种访问控制机制是防止未经授权人员访问 AI 数据模型的关键。 应用场景与发展趋势 AI Gateway 的应用场景广泛,适用于多种人工智能应用场景,包括自然语言处理、文本生成、语音识别等,无论是个人开发者还是企业级应用,都可以从中受益。相比之下,AI Gateway 可以帮助开发者更好的管理 AI 应用及监控,同时更便捷、高效的实现对多种大语言模型的有效整合与调用,从而满足用户在各类 AI 场景下对于模型选择、策略配置以及数据安全等方面的专业需求。 作为仍在快速发展期的一项 AI 技术平台,AI Gateway 的未来仍有很多可能: 技术创新:AI Gateway 需要在技术底层,继续在提高性能和扩展性方面进行创新,以适应不断增长的 AI 模型和服务需求; 支持更多模型和服务:随着 AI 技术的进步,AI Gateway 也需要不断适配更多先进模型和服务,以满足用户对 AI 体验的更丰富的需求; 增强的安全性和可靠性:AI Gateway 需要加强安全性和可靠性功能,以保护用户数据和模型安全,同时确保服务的稳定运行; 融合更多行业方案:通过与物联网、大数据领域的融合,开拓出更多可以落地具体行业场景的 AI 应用; 写在最后 AI Gateway 在连接 AI 与各类应用中起着至关重要的作用。作为一个崭新的技术平台,它不仅提供了一种简便、高效的方式来集成和管理 AI 模型,同时也在实现 AI 技术与各类应用的无缝对接上发挥了巨大的作用。无论是自然语言处理、图像识别,还是语音合成和推荐系统等各种场景,AI Gateway都能大大提高 AI 技术的应用效率和便利性,从而推动 AI 技术的广泛应用和快速发展。 面向未来,不论是更大范围的 LLM 支持、更精细的查询加速与缓存机制建设、更全面的应用监控与安全防护策略,还是应用层更便捷的操作和低使用门槛,都是 AI Gateway 可以继续努力的方向。 参考 https://blog.cloudflare.com/zh-cn/announcing-ai-gateway-zh-cn https://github.com/Portkey-AI/gateway

2024/6/27
articleCard.readMore

冬日打车日记

今晚打车,司机停在一个靠近上车点拐弯口的路边,一直没开进来,期间他一直跟我站内信确认“出来了吗”,我和往常一样,快速回复说我就在定位点等他。回复完,貌似司机也没有动弹。 过了一阵他发来消息,问我能不能出去找他。他给我的理由是门口不让他开车进来。由于天气特别冷,我不太想动,于是文字回复他,“车子需要绕商场一圈才能进来,入口那是单行道”。回复完,对话框又陷入了沉默。 其实没有啥事,但我就是有点急,于是主动问他,到底是我出去找他还是他开进来,我说我可以出去,让他告诉我上车点。隔了一阵,他回复我,“我进来找你”。 由于绕行进来的这段路在下班点很堵,于是我又回到了室内大厅,那里会暖和点。期间我还在跟家人打电话,聊天过程中我带着一丝抱怨的语气提到,今天这师傅感觉对路不熟使我在外面等了很久,冷死了。 / 我期间也有一丝疑惑,司机跟我文字沟通这么多,为什么没直接打电话直接问我呢。过了好一会,车终于来了,我照常报了一下手机尾号,就全程沉默,直到快下车。 我发现临近目的地,司机还没有要停的意思,于是我赶紧说已经到了,但他似乎没听到,车仍旧向前多开了一会儿。 收拾好行李,正当我开门下车时,我发现他半侧着转过身来,双手合十,面带微笑,反复对我点头示意。 啊,我才反应过来,原来他是一个聋哑人。 / 在互联网企业工作久了,貌似自己的耐心都被削弱了不少,针对一些看似不寻常、不高效的事情,我甚至会在缺少观察和理解的前提下,直接下意识的设定立场与抱怨,不知道司机师傅有没有感觉到我的不耐烦。 从防止资本无序扩张、加速信息茧房、奶头乐理论到拉大贫富差距,互联网企业这些年一直没落得个好名声。但我想,他确实通过不断推出创新产品,给人们的生活带来便捷,从线上聊天、手机购物、扫码支付到方方面面,这都在深切的改变着我们的生活。线上打车不就给予了先天残障人士另一种更体面、适当、不风吹日晒的赚钱方式吗? 所以,互联网还是挺好的。

2024/1/27
articleCard.readMore

基于一次应用卡死问题所做的前端性能评估与优化尝试

问题背景 在上个月,由于客户反馈客户端卡死现象但我们远程却难以复现此现象,于是我们组织了一次现场上门故障排查,并希望基于此次观察与优化,为客户端开发提供一些整体的优化升级。当然,在尝试过程中,也发现了不少适用于通用前端项目开发的一些故障排查与性能评估的手段,于是总结此文,希望可以对读者有所帮助。 需要注意,在本文中所指的客户端均指通过 electron 开发出来的客户端应用,所以本质上还是属于前端应用开发范畴,关于 electron 框架的介绍可以参考 https://www.electronjs.org/ 现象复现 在客户那边,反馈过来的现象表现为“系统 CPU 资源未被占满,但客户端在操作一段时间后便卡死无法响应”。起初,我们根据用户的描述尝试在本地复现,但却没有收获;此外,由于客户的网络限制,也不方便频繁的远程连接以方便我们查看现场现象。 考虑到可能是机器部分配置较差(比如显卡)或者网络、机器自身运行软件过多等原因,而我们的开发机器由于要支持本地编译与调试,一般都是顶配机器,于是我们尝试让本机变慢,以模拟复现其现象,简单来看,存在如下几个思路: 卡死/卡顿复现:最好在虚拟机中操作,虚拟机本身分配资源相对主机较少,再加上 chrome devtools 配置增加延时 throttle 时长,比如500ms;电脑中再开启几个占用 CPU 性能的软件,比如 vscode,firefox 等等,可以一定程度上模拟卡顿现象,不一定稳定复现卡死现象; 操作卡顿复现:通过频繁的交互操作,制造同时多个请求并发发出的现象,加上 performance 录制,可以一定程度加重渲染进程的负担,以模拟操作卡顿现象; 定位问题 来到客户现场,作为首要尝试,当然是通过 top 、netstat 或者 cat /proc/cpuinfo 等命令来查看系统的 CPU、内存与网络的运行状态,但不出所料,这些信息在当前看来并没有太大异常。 由于从系统本身的一些状态上没能找到突破口,我们将目光转向客户端本身,希望在更小的范围内定位问题所在。通过 devtools 查看 netowork、performance 以及 DOM 渲染状态,我们只能发现貌似有些响应耗时过长的接口调用以及较长时长的 long task 任务,这当然需要我们进一步排查。 说到调试排查,首推的当然是 console.log 大法,为了让 log 打印复用,一个简单的技巧是写一个 HOC,以节省在每个地方都写一遍 debug log 的代码: export const debugRender = <T=any>(BaseComponent: FC<T>) => (props:any) => { console.log(`Rendering ${BaseComponent.name} at ${performance.now()}`); return <BaseComponent {...props} />; } 通过添加一些基于经验的断点信息打印,我们发现一些 Modal/Drawer 的显示/隐藏会较为明显的加重页面卡顿甚至到卡死现象上,通过排查代码实现以及查看对应 UI 库的 API 实现,会发现其中 Modal/Drawer 等组件上在隐藏时触发了其对应 DOM 节点的卸载,而在显示时又会重新渲染与插入,由于这些任务都需要在浏览器的渲染进程执行,而当 DOM 节点过多时频繁的节点装载与卸载便会对页面渲染效率产生影响。 于是,第一步便是定位到主要的几个组件,避免其在隐藏时执行 DOM 卸载(保留节点),通过这一步改变,我们直接消除了卡死现象。 部分优化尝试 为了更好的模拟卡顿现象,我们可以通过 chrome devtools 中 performance tab 中的 CPU throttling 配置来模拟卡顿: 在 Windows 高配版机器上,我们先将 CPU 降低配置 4x 情况,然后录制一段操作,从下图中可以看出有明显的任务执行耗时过长 & CPU 占用过高的现象: 以耗时最长的任务中占用时间最长的活动为例,我们搜索一下该关键词可以查到一个讨论 https://stackoverflow.com/questions/39916356/reacterrorutils-invokeguardedcallback-in-react-fires-event-repeatedly-in-ie-brow,简单来说,我们可以尝试优化点击事件不进行冒泡来减少事件的触发,例如: event.stopPropagation(); 通过优化该事件,我们可以一定程度上对事件在 DOM 上的传递 & 调用进行优化,但说到交互事件模型,我们在实际优化尝试时,也需要对 Web API 有些了解,以防用错 Web API 而南辕北辙,比如一个常见的面试题就是对比 Event 上暴露的两个 API stoppropagation 与 stopimmediatepropagation 的用途区别,可别用错了。关于此细节可以参考回答 https://stackoverflow.com/questions/5299740/stoppropagation-vs-stopimmediatepropagation 但假如我们需要针对不同事件切换不同的 API 该怎么办呢,这里可以简单写个函数封装一下,再加个类型守卫来实现,比如如下的伪代码通过传入一个点击回调事件,而后在实际事件触发时通过判断 Event 类型从而调用不同 API 以达到优化效果: const isMouseEvent = (event: Event | MouseEvent): event is MouseEvent => 'stopImmediatePropagation' in event export const stopPropagationWrapper = (handleClick: Func) => (event: Event | MouseEvent) => { if (isMouseEvent(event)) { event.stopImmediatePropagation(); } else { event.stopPropagation(); } handleClick(event); }; 我们继续针对卡顿问题的调用情况进行梳理。从录制的执行队列中选取较长的一个 long task 进行分析,可以看到在模拟卡顿时排名靠前四的调用任务分别如下: 其中 fsync 函数调用时间占第一,而拆分 fsync 的活动调用可以看到主要调用了 fsyncSync: 此处未对 fsync 进一步分析以确定优化策略,但对于 fsync 的作用可以参考如下一段描述: fsync 函数只对由文件描述符 filedes 指定的单一文件起作用,并且等待写磁盘操作结束,然后返回。fsync 可用于数据库这样的应用程序,这种应用程序需要确保将修改过的块立即写到磁盘上。 这说明应用中有可能有数据库读写操作,也可能有文件读写操作,所以如果要进一步优化的话可以从这个方面展开,囿于时间限制,我们继续探索可行的快捷优化方案。 在最初解决卡死问题时,我们看到了过多的 DOM 卸载/挂载现象,但回到前端框架本身,我们也可以用一些常规的手段来减少组件不必要的 rerender,这些方案通常通过仔细阅读 React 文档便可以略知一二,比如在必要的地方增加 memo 以减少不必要的渲染执行,一个示例代码如下: import { FC, memo, } from 'react'; const Detail: FC = ({}) => { return ( <div>Detail</div> ); } export default memo(Detail); 此外,还有什么写法可能会影响 Web 应用的性能呢?闭包。 我们检查了客户端代码仓库里的两个列表文件,发现其中组件包含过多闭包变量,大多数写法是在一些函数定义中直接从上层作用域引用了一些变量进行操作,而不是通过参数传入函数,这样的数据/函数在使用后无法及时释放内存空间,可能会对内存存在持续占用的现象,因此,这也是优化的方向之一。 后续可能的优化空间 在一些 long task 任务的分析中,我们还可以具体定位到代码来进行优化,这里再举一个例子。 通过录制卡死情况下的堆栈调用情况,可以发现有一个 2.7s 任务中包含很多活动,如 Minor GC、react event、fsync、ReactElement 等等,其中 mergeProps 函数调用耗时250+ms。 针对这些函数调用,有些可能是 React 内部实现 API,有些可能是 UI 库 API,所以要想一一优化,也需要逐个分析,看是优化代码的调用与响应方式,还是合并组件 props 的传递与调用。 此外,通过监控 layers 变化情况,也会发现一些 slow scroll rects,这在 chrome 中都会通过红色区域以标注出来,通过定位这些在滚动中可能会造成缓慢的区域并检查代码,也有提升应用性能的可能性,因此,也是优化方向之一。 比如针对我们的场景,通过调整 layer 布局,可以看到虽然 layer 层级很多,但是主要的 slow scroll rects 区域还是集中在主内容区,即分页列表本身。 Electron 注意事项 本来,为了可以针对这些数据进行持续的分析,想从 performance 中将数据下载下来,以便之后有空时继续调试,但由于 Electron 的某些限制或者说是错误,我们目前无法保存 performance tab 下的性能数据到本地以便进行更深入的分析和查看。如果有涉及到 electron 开发的场景,需要注意下这个问题。问题现象详见 issue https://github.com/electron/electron/issues/39818 优化效果 为了提高客户端的性能和用户体验,我们进行了一系列的优化措施。首先,我们分析了卡死现象,包括客户端出现卡死时的 CPU 占用率/JS 堆栈/DOM 节点数情况、虚拟机运行状态等。然后,我们尝试了一些优化措施,如去除Modal/Drawer的 unmountOnExit 配置等。接下来,我们梳理了卡顿问题调用情况,分析了排名靠前的四个调用任务。为了减少组件不必要的rerender,我们在必要的地方增加了 memo。此外,我们还提到了组件中包含过多闭包的问题,以及右键菜单卡顿问题的排查。 由于客户端需求迭代过快,在前端技术上没有做较多的数据监控、性能评估等建设,这都对我们评估用户体验与定位问题产生了影响;此外,由于生产工具链的不完善,在生产环境进行定位与调试都给我们带来了比较大的挑战与时间消耗,这也会是我们持续要跟进与解决的一些开发链路的效率提升工作之一。 通过这些优化,我们希望能够解决客户端卡死问题并改善卡顿现象,并提高用户的使用体验。当然,从具体效果上来看,我们确实在如下两个方面进行了改善: 交互性能上,问题页面在切换时,即便将 CPU 降低配置 4x 情况下也再无出现卡死现象,卡顿现象有减轻趋势; 渲染效率上,从数据上看,频繁出现的 500ms-700ms long task 已减为当前观察范围内没有超过 300ms 的 long task,代码执行效率上有较大提升; 以下为优化后效果采样图: 简要总结 通过分析与优化尝试,我们解决了客户端卡死问题,并改善了卡顿现象,但其中暴露出一些编程规范与用法不够优雅的问题还需要在日常中持续完善,这也是这次优化未尽事宜,需要在未来不断排期以彻底解决。 当然,此中涉及到的一些调试与问题定位方法,也不仅局限于客户端的问题排查,而是通用 Web 应用性能评估时调试可以用到的手段,而更深入的研究则要开始涉猎到框架代码等内部函数调用的地方了,这也是本文未涉及部分,有待后续继续研究与定位。

2024/1/3
articleCard.readMore

2023年终总结

这一年里充满了各种变化,也有不少东西值得记录,比如令人满意的健身打卡,逐步调整的投资仓位,以及通过阅读学习和出行游玩收获的喜悦。 但当我准备动笔记录今天的忙碌故事时,却突然感到思绪断片,不知从何说起。他们就像一段段孤立的片段,突然间收起了各自本该伸出的突触,毫无关联。让我努力编织下,希望可以拼凑出一个完整的年度回忆。 一顿操作猛如虎,最后像个二百五 虽然本就没几年经验,但在我的投资生涯里,很早便认可了“投资是自我认知的变现”这一投资信条。面对年复一年地亏损,我一直保有谦逊的态度,认为这是我对事物认知不够的结果,也是我所需要交的学费。年复一年,而我却越挫越勇。每当我收到工资时,我首先想到的是”我有钱可以增加投资了”,直到钱花光,然后我又开始努力工作,等待下个月的薪资。不断地增加投资,不断触及新低,让我不禁感叹,我自己就是那个最健康、拥有永续现金流的优质资产(在中年危机被裁员之前)。 在不断学习的过程中,我尝试过使用美林时钟来辅助我在当前世界的变化中调整不同资产的投资比例;通过关注恐惧贪婪指数、北上资金动向以及全市场成交量来控制我的资金进出节奏;还构建了自己的价值评分系统,用于评估购买资产和确定应对策略。可惜,直到最后都逃不过“一顿操作猛如虎,最后像个二百五”。 但这并没有阻止我对投资越来越沉迷。今年,在各种空闲时间里,我仍然花了大量时间阅读书籍、观看纪录片与调整资金进入策略,也主要补齐了对2008年金融危机及欧债危机期间世界各国发生的事情与各大央行的应对策略,而对这些历史事件的了解,也让我对当前发生的许多时事有了更敏锐的感触。当然,最深刻的印象仍然是通过真金白银的投入去理解和观察这个世界究竟是如何运行的。 投资是生活的投影 尤记得刚接触投资不久,我便困惑于两个问题,他们是如此明显但我却找不到答案,以至于我开始怀疑自己的信息检索能力。 “为什么有很多关于价值投资的声音都在介绍通过定投降低风险与长期持有,但却很少提及何时卖出与落袋为安?”,这让我很不解,涨的再多,没有在合适的时机卖出,也没法落袋为安啊。而后来,随着“核心资产”泡沫的狂欢在2021年春节后戛然而止,伴随着飞流直下三千尺式的暴跌,那些宣扬十年定投赚十倍之类的响亮声音也从市场上消失了。我逐渐开始明白,这并不是因为市场没有这类声音,而是我一直追逐的都是“跟风”和“主流”,而不是真正的“价值”。 另一个问题,从我开始规律地研究公募基金定期报告以来,无论是谈到跨过刘易斯拐点带来的挑战,漫长的三年疫情带来的创伤,还是面对欧美的科技封锁与孤立,基金经理们貌似都一直坚定地看好中国。我很好奇,这个国度究竟有什么是世界上其他国家所无法企及与不可替代的吗?后来我发现,原来股市是不可以做空的。 再后来,我所遇到的问题也越来越多,但一个个也在不断的探索与学习中得到了解答。虽然我相信权益类资产在长期来看会是最有吸引力的投资标的,但离钱越近的地方聪明人也就越多,这就意味着我需要长期投入、学习与进步。投资就如同生活的投影,预设目标,不断努力、尝试,达到目标、总结与规划,如此反复,而这也是他一直吸引我的原因所在。 为了前方的未知与愉悦,直到最后一页 一本书可能很厚,但一纸书页很薄。每一次翻页都如同一程短暂的摆渡、一场微小的跋涉,身后欧律狄刻的目光仍未消散,远望伊西斯的面纱已然显影。 这是在今年世界读书日,给读者推送我的书摘时,从豆瓣上摘抄的一句话。以前,不论是地铁通勤,还是周末进城,抑或是出远门见朋友,我都时常手捧一个 iPad 会看上几页,就这么零零星星地,每年能看上几十本书。但今年因为运动打卡挤占了原有的时间,加上工作强度增加,以及频繁跑医院,少了很多碎片时间,分配给读书的时间也有所减少。有鉴于此,周末没事时,我时常花上整个整个的半天,用来阅读。期间去过几次图书馆,一呆就是一个下午,除了接水也不起身。安安静静的,啥也不做,就盯着屏幕,希望从字里行间收获快乐。 虽然从时间上相比去年有明显减少,但今年的收获仿佛更加实在,说说几个比较贴切的例子吧。想起年初去医院看病,为了治疗痤疮,前后一共吃了好几个月的药。后来,在阅读《皮肤的秘密》时,我对许多现象以及对待皮肤问题的方式有了新的领悟。当我们的皮肤状况变差时,真的需要那么多昂贵的护肤品来挽救吗?也许不是,也许只需要一些药膏就能解决大部分问题。当然,更重要的是我们不要过度清洁皮肤,保持规律的作息习惯。 当然,由于对身体机理运作以及病菌原理感兴趣,我又淘到了一本《我们为什么生病》。在阅读时,不仅有“疾病不是因为我们弱,而是这个世界有些东西变化太快了”的感慨,还在豆瓣偶遇到张一鸣同学的书评“其实进化论强调:你看到的是结果”。阅读之后,虽然对于癌症、衰老、过敏以及身体机理应对自然变化的机制有了更多了解,但更现实的是,我逐步认识到了时间对世间万物的一视同仁:不论君王庶民,我们都无法与之对抗。在时间面前,我们无论做些什么都无法避免衰老、死亡,而这引发我对生命存在的意义更具象的追求。 经济类书籍每年都必不可少。对经济危机与大萧条研究颇深的伯南克在《行动的勇气》中详细描述了自己在美联储工作的那段经历,从房地产泡沫破裂到雷曼兄弟的大坝决堤,及其引发的全球金融系统崩溃等事件,事无巨细,同时也花了很大篇幅揭示他与保尔森、盖特纳一起协力、果断扑火的各种努力。从全球合作到最终退出量化宽松政策,伯南克感慨到自己还是做了不少努力并卓有成效,他最后为美联储在危机之后所作的努力总结道: 我意识到金融冲击往往是不可预测的,因此还鼓励幕僚们寻找金融体系的结构性弱点,想办法使它更有弹性。这个想法已经体现在了我们的许多改革中,比如要求更高的银行资本充足率,提高银行体系吸收损失的能力。 每当阅读此类书籍,都会让我对世界上各种复杂、高级别的组织更加了解,而满足这些好奇心也是促使我坚持阅读的一大动力。为了前方的未知与愉悦,直到最后一页。 怀旧、养生与散步,是提前步入老年生活的主旋律 作为一个准奔三青年,我仿佛变得越来越怀旧了。还记得从上大学之后开始就再也没看过快乐大本营这类综艺节目了,但今年却一股劲又盯上了很多芒果台的综艺,而且还是反复观看。从时光音乐会到声生不息,从宝岛季到家年华,我发现我非常偏爱音乐类节目。很多耳熟能详的老歌,再配上我“听歌很少关注歌词,而只享受旋律”的习惯,当那一阵阵旋律响起时,仿佛把我又拉回到那些历历在目而有印象深刻的故事中。 今年养成的习性不仅怀旧,而且养老。今年我还尤其喜欢逛公园,奥森、颐和园、北海公园、圆明园、什刹海以及各色大大小小的北京园子都被我逛了个遍,一是趁着天气晴好看看应季花景,再者也是与许久未见的朋友散心聊天、联络感情。 当然,除了养老之外,我还异常养生。我跟朋友说起我每天的生活时,他们都觉得我已经是个新时代的合格健康老头了。每天上班第一件事便是到茶水间泡一杯热茶,按时吃饭,以及没有意外时会规律的去健身房转转练练,晚上也尽量避免熬夜,一有点啥问题也会跑到医院抓个医生问个究竟。周末呢,要没啥事,就到楼下超市买个菜回来做饭,虽然不是什么复杂菜品,但那些健康而平淡的家常味道,已经让我感到非常满足。 刚说到今年经常跑医院,如何形容这个经常呢,我统计了一下截止今天的医保支出,一年23000+,这还是在没有什么大病的基础上的花费。仿佛年龄越大,就越怕死,今年的我,时常因为一些小毛病而频频往医院跑。虽然确实有一些值得一看的小病,在遵循专业医师的建议与处方下,也让自己变得稍微健康一些、好看一些了,但不可否认,还是有一批是来自“怕死焦虑”的变现。上个月我刚体检完,报告上标红了五六项,我辗转反侧,无法理解为什么坚持锻炼的我还有这么多毛病,于是,几个三甲医院一顿约,主任副主任医师一起抢,我一定要搞出个究竟来。不过到头来,好几个科室的医生面对来自我“如果这不是问题,那为什么我有别人没有”的有罪推论式发问,都不耐烦的回复“不要过度焦虑,这些只是个人差异,而不是病症”,终究还是让我宽心了不少。 说到健身,最让我自豪的便是今年里在大部分时间我都持续着高强度的锻炼节奏。从每天游泳打卡,到下班后跑步,以及在同事的辅导下开始器械训练,年末时也参加了几节团课训练。每次运动完,都能明显的感觉自己的状态好了一些,而要不了多久,便又开始期待下一次的健身打卡及其带来的快乐。想起前几天看到一位投资者面对记者采访时说到,因为自己前一天熬夜状态不好,希望摄影师用一些“手段”将自己拍的更得体与优雅些,“一个好的状态与形象,既是对自己、也是对观众的交待”,这是他给的理由。逐渐沉溺于健身的我,非常认同这番话(当然,只是自己长得丑,和他不像而已)。取悦自己,找到自己愿意去做的事情,仿佛是一个奔三青年眼前最重要的事。 冲破黑白灰的人生单色调 今年的我不仅变得异常怕死,同时也希望对自己查漏补缺。今年,我预约过几场心理咨询,也从中获得不少收获。探寻自己在家庭沟通上的一些失控情绪表达,找到内心潜在的一些心理缺陷并尝试修复,而这些都是我以前不曾涉足的领域。 我从原生家庭继承了一些执念,而时常又不自觉将这些执念寄托回他们身上。由于自己的认知仍在不断拓宽,一些强行灌输给他们的想法,在没有得到妥善处理时,便引发了不可避免的矛盾,这通常体现为我的大声说话与争吵。今年看的一本书《原生家庭》,帮助我对亲密关系以及性格缺陷有了更本质的一些理解,虽不至像书中一些案例一样中毒过深,但自己的成长或许也有从原生家庭习惯中隐性的吸到一些“毒气”。他们可能在生活的一些方面上具有闪光点,但却因为用力过猛而导致在其他一些方面上造成失控。与好几个朋友聊天时,他们对我都有相似的形容——能在工作上所向披靡,但回归生活发现很多事情都没有规划和过多想法。而在心理咨询后,我的这种行为被具象成了“由于无法得到满足,而对某些关系进行转移与嫁接”这样的标签。 年中出差成都,约了一个从小玩到大的朋友见面,我们聊了很久直到深夜,差不多绕着成都的高新区转了半个圈,期间探讨了很多事情,包括工作、未来发展、定居以及生活的方方面面,但在最后,他给我了一个标签,“你确实活得非常自律、严谨,就像个机器人,仿佛你的生活里只有黑白灰这三种颜色”。 我一时不知怎么接话,因为他说的确实在理,我只能笑笑,随意找了个借口回应道:“我确实没有什么物欲啊,很多人喜欢通过花钱来达到满足感,但对我不太适用;当然,投资亏钱除外。至于为什么要赚钱,一方面是为了‘安全感’,另一方面呢,也算是一种获胜的姿态吧,可以满足我的好胜心”。 就是这么一个黑白灰人格,既对亲人如此关心甚至到有些焦虑,而又对自己无欲无求、活得过于机械化,这也成为我要在新的一年去努力攻克的课题之一。 写在最后 今年因为经常挂到医院一大早的号而早起,但也因此看到很多往常不曾见到的风景。阳光从树梢穿过,零星撒向地面;骑着单车,听到林间鸟叫、看到小区晨起锻炼的人儿;迎面与一个个充满朝气的少年相遇,从他们眼里真的能看到光。这是令人向往的风景,便也为此努力奋斗。 一点一滴,日积月累,这既是果实,也是漫漫人生。季节更替、时间流转,也望诸君可以缓慢而坚定地前进,去做自己能做的事情。新的一年,好好吃饭,好好锻炼,好好生活。

2023/12/24
articleCard.readMore

结合 React Fiber 结构与 chrome 插件,谈谈无侵入自动化表单的技术尝试

本文亦有分享 Slides,详见 https://hijiangtao.github.io/slides/s-Common/Technical-Attempt-of-Non-intrusive-Automated-Forms-with-React-Fiber-and-chrome-plugins.pdf 或扫二维码查看。 前言 作为一名前端工程师,不论你处于什么业务方向,肯定都与表单打过交道,当然如果你是服务端、产品、测试同学,想必也早已接触过表单这类场景。让我们试想一下,如果研发需求的功能测试依赖一个复杂表单的填写而得以继续,那么频繁的表单填写在研发自测和 QA 验证过程中就会占用过多碎片化的时间,此类需要频繁执行以生成测试数据或推进执行流程的事情,简单一想貌似规则可循、可以被工具替代。既然可以自动化来实现,那为什么还要我们一个个手动点呢? 不要着急,这篇文章的目的,就是想与大家分享一下这样一个自驱型技术产品的诞生故事。这其中既包括技术与实现细节,同时也涵盖这个产品的设计过程。 问题初探:表单场景究竟麻烦在哪 首先,让我们来看看表单,到底麻烦在哪了。 从前端开发者视角看去,表单是由一个表单组件包裹多个表单控件组成,用 JSX 语法层层嵌套实现,当需求开发完成后需要自测时,最直接且简便的用法当属用 initialValue 属性或者 form 实例上提供的 API 方法(比如 setFieldsValue API)来赋值;但是等代码部署到开发/测试环境,想要这么灵活的变更初始数据就不太可能了,频繁的发布部署流程会让变更测试成本直线上升。 另一方面,在产品测试等同学的眼中,表单并不涉及到代码形态,只是一个有很多输入项的丰富 UI 页面,通过点击、输入、选择等操作,来完成数据的输入,是一个需要消耗一定时间的流程。而当表单项很多时,花费的时间也直线上升。 通过抽象,我们可以列举几个从前端角度观察到的例子,以方便我们更熟悉填写表单时涉及到的各类复杂场景: 对接完产品需求,终于把字段与各类逻辑组装进表单,想自测看看交互效果,简单来做,可以代码写一些 mock 拦截来实现 功能提测后,为了测试新功能,需要先填一遍复杂表单,造数据,但这个时候 Form 里嵌套 FormList,完成功能开发就用了很久了,现在造数据还需要再来一遍 每次填写表单,由于某个字段是存储主键,每次填写不能完全一致,即在特定规则下随机生成一些字符串,可能是年龄、中文姓名或者邮箱等 登陆态过期太频繁,一过期就要重新输入用户名密码再点击按钮登陆一遍,当然,现有的工具中我们可以通过 chrome 的记住密码来实现,但我们仍然需要在填充完成后点击确定按钮进行登录操作 总结来看,以上这些场景按照用途可以汇总成以下几类: 研发功能开发自测 测试数据构造 符合规则的个性化填写 日常操作,比如登陆 技术调研:开源社区与插件是市场的已有技术实现 在明确了需求之后,在是否需要动手之前,我们需要先调研看看有没有现有技术或者工具可以帮助我们达到目的,毕竟,反复造轮子在哪里都是被抵触的。开发工具的目的是为了解决问题,如果问题已经有了解决方案,我们就不需要自己去实现了。 回顾一下表单需求,仔细想想,可能存在几种解决思路呢?首先是辅助工具,比如浏览器插件这种,作为业务开发无感知,无接入成本(无侵入式)的技术方案,其特征也显而易见: 不依赖 UI 框架,通用性强 无需具体业务感知,对业务代码无侵入,接入成本低 识别与填充成功率低,支持控件有限,尤其在当下很多 UI 库针对不同表单控件会有自己的实现(以及事件拦截),只能支持简单的 input 框以及一些 radio 场景 随机 mock 数据能力有限,在自定义规则集中生成 不支持页面上表单与事件连续操作,比如派发表单填充后的点击行为 既然无侵入式方案能力有限,那么做些侵入式改造是不是会更加有用呢?比如,通过约定 url 传参或者业务代码内嵌入开关,来允许用户显式控制代码的执行逻辑,这样用户可以在打开页面时对表单做指定的赋值操作,对实际点击行为后触发的回调函数进行调用,这是一个大概的实现思路,其特点罗列如下: 基于具体表单结构定制,通用性弱 完美填充,支持全部表单控件 不支持页面上表单与事件连续操作 填充数据变更时需重新打包,成本高昂 由于辅助工具和侵入式改造都或多或少有些缺陷,熟悉自动化测试的同学肯定会说,这些要做的事情,自动化测试方案不是早就覆盖了吗?是的,自动化测试方案是一个完美的解决方案,基于 puppeteer 或者 e2e 框架,不仅方案通用性强,填充也很准确,但是从开发者以及使用者的便利性角度来看,基于这类方案用户在上手使用时存在成本,研发要实现对应功能成本也相对较高。还记得初衷么,我们是希望有一个可以解决表单场景的工具,我们既希望他能解决一些复杂场景的问题,同时也希望他简单易用成本低。 回顾一下,我们调研过的几个实现思路,能不能把无侵入式改造与高识别率结合?即“取其精华,取其糟粕”。 需求拆解:我们究竟需要一个怎样的工具 做完现有技术调研后,我们来将需求做拆解,从远期来看,我们当然希望有一个不侵入用户代码,却可辅助用户自动化识别页面内存在表单、支持用户自定义 mock 规则生成表单数据进行填充的工具,来帮助我们在各类表单场景中提效。 具体来看,我们将需求细化,希望覆盖这么几个场景: 接入零成本:开发者不用对当前业务代码做任何改造,零代码侵入便可使用 表单准确填充:当下很多方案基于 DOM 解析与处理进行实现,通过这类方案进行表单填充,会因为组件库自身实现做了事件拦截或者托管,而导致表单填充很多情况无法生效的情况,而用户在意的大多数字段却无法触发 表单准确识别:准确获取与开发者完全一致的表单结构,防止 DOM 解析不准确的情况,大多数工具只能解析简单的 input、radio 等场景 填充内容自定义:支持 mockjs 类语法对填充数据进行自定义构造 支持事件派发:在登陆场景下,一般除了填充表单外,还可以直接替用户点击「确定」进行登录操作,工具支持增加事件派发,将表单填充和点击等事件一体化流程处理 拆解了需求,就可以规划一步步来实现,将产品需求做成一期、二期不断迭代的交付节奏,我们在这一块遵循和正常产品研发相同的节奏。第一步,当然是识别表单结构,因为只有准确识别到表单,后续的数据构造、表单填充、事件派发才有意义。 技术方案:如何准确识别表单 怎么识别才准确呢?侵入式的方式肯定是最准确的,但我不能每个组件都包一个 wrapper 吧,如果一个项目有100处表单的调用,那我就需要做100次改造,而且从前面的调研来看,我们还是希望从无侵入方案入手,因此,如何提高无侵入识别方案的准确性,成了一个需要攻克的难题。这个时候,让我们先来看看一个面试常被问到的点,从 React Fiber 说起。 我们都知道,Virtual DOM 是对真实 DOM 的模拟,也是一棵树,通过 Diffing 算法和老树对比,得到差值,再同步给视图要修改哪些部分。Fiber 是对 React 核心算法的重构,Fiber 对象是一个用于保存「组件状态」、「组件对应的 DOM 的信息」、以及「工作任务 (work)」的数据结构,Fiber node 是 Fiber 对象的实例。 先不看 React Fiber 树的实现方式,如果我们自己来实现一遍,大抵会想到两种思路:数组或者链表。数组的组织方式可能更符合我们的直觉,但是想一想在这个树如果我们要查找遍历、调整结构(分割、替换节点)或者随时重建新树,链表的方式似乎更加灵活,事实上,React 也是这么做的。 Fiber 树的组织与遍历 我们先整体来看一下遍历过程。Fiber 树的遍历需要一个指针指向当前遍历到的节点,workInProgress 就是这个指针,进一步是 performUnitOfWork 的 next 指针,遍历在指针为 null 的时候结束。 next 先从 beginWork 获取,如果有则直接将当前遍历的指针 workInProgress 指向 next;如果没有,就到 completeUnitOfWork 中进一步处理。这里 beginWork 是“递”,即不停向下找到当前分支最深叶子节点的过程;completeUnitOfWork 是“归”,即结束这个分支,向右或向上的过程。 关于 performUnitOfWork 的更完整代码详见 https://github.com/facebook/react/blob/c1d414d75851aee7f25f69c1b6fda6a14198ba24/packages/react-reconciler/src/ReactFiberWorkLoop.new.js#L2051-L2077 在递归过程中,beginWork 过程比较简单,大体上是在深度优先搜索中,对遍历到的节点进行 component 更新处理,然后返回第一个字节点,这里就不介绍,我们看看 performUnitOfWork 的具体逻辑。 在“归”的过程中,我们需要避免遍历造成死循环,即若我们向下遍历时遇到的节点,在向上过程中出现时,我们不应该让其再次进入 beginWork。 completeUnitOfWork 内部又创建了一层循环,搭配一个向上的新指针 completeWork,然后循环该指针节点,如果有兄弟节点就更新当前遍历到的节点指针,返回交还给外层循环;没有就向上到父节点继续循环,直到新指针为空(即已经到达根节点);最后再处理标记最顶层的根节点处理状态。 关于 completeUnitOfWork 的更完整代码详见 https://github.com/facebook/react/blob/c1d414d75851aee7f25f69c1b6fda6a14198ba24/packages/react-reconciler/src/ReactFiberWorkLoop.new.js#L2173-L2271 整个遍历流程示意图可以参考《如何理解 React Fiber 架构? - 几木的回答》中的贴图 Fiber 树的构建与 Diffing Fiber 树是边创建边遍历的,每个节点都经历了「创建、Diffing、收集副作用(要改哪些节点)」的过程。其中,创建、Diffing要自上而下,因为有父才有子;收集副作用要自下而上最终收集到根节点。—— https://www.zhihu.com/question/49496872/answer/2517859568 在 React 中,同时最多会存在两颗树,一个是当前被渲染出来的 Fiber 树,称为 current,另一个是正在构建的 Fiber 树,称为 workInProgress,上文中提到的遍历均在后者身上进行。 找到两棵任意的树之间的最小的差异是一个复杂度为 O(n3) 的问题,React Diff 算法通过一些假设,最终达到了接近 O(n) 的复杂度。 这里提到的假设主要包含以下几点: 假设一:不同类型的两个元素将产生不同的树,遇此情况时 React 会拆卸原有节点并且建立新的节点(触发重建流程)。 假设二:默认情况下,在 DOM 节点的子节点上递归时,React 只会同时遍历两个子节点列表,并在存在差异时生成一个更新操作。 假设三:用户给每个子节点提供一个 key,标记它们“是同一个”,在有 key 的情况下能保证二者都复用仅做移动,但无 key 就会造成两个不必要的卸载重建。 副作用与收集过程 Fiber 树的构建以及 Diffing 都是同时进行的,不是说构建完 Fiber 树之后再开始 Diffing 寻找差距。同样的,两棵树 Diffing 的过程中,就已经决定了哪些旧节点需要复用、删除、移动,哪些新节点需要创建,这些操作会以 Effect 的形式挂到节点上,他们随着 Diffing 过程同步完成收集。 由于需要保证所有后代节点的副作用信息,副作用的收集有两个约定: 副作用是向上收集的,每次在 completeUnitOfWork 中循环经过一个节点时,会同时合并后代节点的 effectList 以及自己的 effectList; 副作用同样采用链表的方式存储,并通过 fisrtEffect —> nextEffect —> lastEffect 的关系串联起来,但此链表与 Fiber 树的链表结构没有关系; 关于副作用以及 Host 实例更新的更多细节,本文不再深入,此时,让我们重新回到最初的目标,即识别表单上来。 利用 Fiber 识别表单 关于 React Fiber 相关的知识补充,我们就讲到这里。接下来,我们看看如果利用 Fiber 来识别表单,这主要分为三步: 从 DOM 中找到目标 form 元素 获取有效的 Fiber 实例 读取目标属性值,解析表单结构 下方代码解释了我们如果从指定 form 元素中提取 Fiber 实例的过程。 /** * 获取 Fiber 实例 * @param dom * @param traverseUp */ function getFiberInstance(dom: HTMLElement, traverseUp = 0) { if (!dom) { return null } const key = Object.keys(dom).find((key) => { return ( key.startsWith("__reactFiber$") || // react 17+ key.startsWith("__reactInternalInstance$") ) // react <17 }) const domFiber = dom[key] if (domFiber == null) return null // react <16 if (domFiber._currentElement) { let compFiber = domFiber._currentElement._owner for (let i = 0; i < traverseUp; i++) { compFiber = compFiber._currentElement._owner } return compFiber._instance } // react 16+ const getCompFiber = (fiber) => { let parentFiber = fiber.return while (typeof parentFiber.type == "string") { parentFiber = parentFiber.return } return parentFiber } let compFiber = getCompFiber(domFiber) for (let i = 0; i < traverseUp; i++) { compFiber = getCompFiber(compFiber) } return compFiber } 当我们拿到 Fiber 实例后,那么 UI 库的部分属性就可以通过 Fiber 实例暴露出来,比如 setFieldsValue 等,此时,我们即可以轻松的拿到表单本身的结构,此部分暂略。 工具完善:构造数据与表单填充 我们再来回顾一下,对于表单来说,我们都需要构造些什么数据来作为填充数据: 固定取值:填入,每次填入相同值即可,无需特殊处理 规则取值:每次填入的字段都需要取一个符合相同规则但取值不同的数值 指定集合:针对单选、多选等场景,需要从指定选项中随机选取一个填入 时间取值:在有效的时间范围内随机生成一个时间串 布尔取值:checkbox、radio 等组件实际取值为 true/false 二选一 …… 让人开心的是,除了基于已知选项集合的数据和固定值外,其他类型数据都可以通过类似 mock.js 的规则来描述生成规则,而固定值和已知集合,我们暂且先让用户自己手动填写就好了。 需要注意的是,除了表单填充外,我们最开始还提到希望在表单完成填充后能够辅助用户对按钮进行点击操作,即事件派发能力,所以在表单填充上,我们至少要解决这两个问题: 多步操作:表单存在字段之间的联动,无法一次完成赋值 填充与事件组合:表单填充完下一步可能就是点击事件 关于这一部分,更多是在产品功能完善上的思考,而非技术调研上的难点,下面贴一张流程图来解释工具的工作流程: 工程开发:功能集成与插件开发 在完成了需求收集、技术调研以及分步骤拆解实现后,貌似大部分难题我们都获得了答案,接下来要做的便是另一方面,在一个单独的工具中将这些功能集成,当下最合适的方式应该是通过浏览器插件来实现它,插件形式上小巧,但借助 chrome API 以及共享 DOM,我们又能拥有强大的能力。 现代化的插件开发体验 开发过浏览器插件的同学,想必都感受过 chrome 开发文档与当下现代开发方式格格不入的开发体验,手写 JavaScript、HTML 以及 manifest 声明文件,貌似开发流程还停留在刀耕火种的时代,作为一名开发者,我不仅希望我的产品体验良好,也希望开发流程更加现代化,具体来说,对于插件开发,开发工作流至少得满足如下几个方面吧: 代码构建打包 TypeScript + React 支持 插件声明 manifest.json 自动生成 跨 script 持久化存储 不同 script 间 (content script / background / popup) 通信 幸运的是,我们也不用完全从头改造插件的开发工作流,当下已经有开源框架在做相关的事情了,我们可以直接用上,比如 plasmo,他使得我们可以像开发 React 项目那样开发一个 chrome 插件。 当然,我们确实需要额外关注几点,考虑到工具开发过程中遇到的几个难点,我这里着重强调下插件通信以及插件安全。 插件通信方案简介 通信是这个工具绕不开的一个功能点。举几个例子,比如 popup UI 和 content script 之间需要通信,以控制 content UI 的展示与否;比如插件脚本与 MAIN 的通信,以控制在页面内执行特定的脚本以收集一些信息;比如 content script 与 background script 之间的通信,以控制插件在后台需要做的一些计算处理逻辑等等。 为了实现这些功能,需要选择合适的通信方案。好在大多数 Web 通信方案都可以直接用在插件上,此外,插件还可以额外调用一些 chrome API 来触发特定的通信事件,简单来说,存在这么几种方案: 通用的通信机制,通过 postMessage 广播消息 非广播传递,MessageChannel 传递消息 通过 chrome API 进行消息通信 chrome.devtools. inspectedWindow.eval chrome.tabs.sendMessage chrome.tabs.connect chrome.extension.getBackgroundPage …… 其中,关于跨线程通信相关的技术方案,我在《Service Worker 实践指南》一文中有详细介绍,感兴趣的同学可以查阅 https://hijiangtao.github.io/2021/04/13/Service-Worker-Practical-Notes/ 插件安全问题汇总 由于浏览器对插件安全的设计,插件虽然可以通过 HTML/JavaScript/CSS 来编码开发,但其在运行上还存在一些安全限制,从我的开发过程来看,具体有这么三个方面值得注意: 插件权限:chrome 插件在运行中涉及到的权限调用需要在 manifest permissions 中声明 script 对 chrome API 权限:content scripts 中只允许如下几类 chrome.***.api 调用 chrome.extension(getURL , inIncognitoContext , lastError , onRequest , sendRequest) chrome.i18n chrome.runtime(connect , getManifest , getURL , id , onConnect , onMessage , sendMessage) chrome.storage 共享 DOM 权限:content scripts UI 部分不支持针对 DOM 的 Expando 属性的共享 工具功能集成 解决完插件开发的问题后,我们接下来需要做的便是,作为一个产品经理,去思考我们的产品在面世之前需要完成哪些功能的集成,比如: 支持表单自定义 mock 规则生成填充数据 不同规则适配不同页面地址 配置数据的导入与导出 表单识别后的规则提取与拆分 支持自定义事件组合 …… 总结 表单类形态在开发场景中非常常见,如果研发需求的功能测试依赖一个复杂表单的填写而得以继续,那么频繁的表单填写在研发自测和 QA 测试中就会占用过多碎片化的时间,此类需要频繁执行(以生成测试数据或推进执行流程)但规则可循的场景如果可以被工具替代,那么将可以极大的提升产研研发效率。 从远期目标来看,我们需要有一个不侵入用户代码,但可辅助用户自动化识别页面内存在表单,并支持用户自定义 mock 规则生成表单数据进行填充的工具,涵盖各类表单场景。 相比现有社区的方案中,有几个明显的优势/改善点,使得该类工具具有广泛的应用场景: 不依赖代码侵入,对开发人员无接入成本; 识别准确率高,理论情况下可以达到100%,不受前端框架以及 UI 开源库的选型影响; 数据构造灵活,可以完全自定义规则,生成中英文、数字、日期等各类数据,做到随机+灵活; 支持事件派发,支持多步骤表单填充,拥有组合能力; 使用者无需额外的软件安装,通过浏览器插件的方式使用,简单易用,成本低; 但从当下做起,通过技术调研,我们发现当下社区中并不存在一个低成本、无侵入且高准确性的工具,于是借助 React Fiber 结构以及浏览器插件的能力,我们先期实现了一个无侵入式、高准确性的表单识别和填充工具,更多功能会在后续迭代中不断完善。 参考 https://xyy94813.gitbook.io/x-note/fe/react/react-diff-algorithm https://www.zhihu.com/question/49496872/answer/2517859568

2023/11/30
articleCard.readMore

拔牙日记

上两周去拔牙,遇到一个操作非常仔细的医生,不仅细心交待,还给我分析牙齿生长情况,以及可能存在的术后问题。 好景不长,拔完不到5小时,嘴中开始大量渗血,浑身疼痛,在吐了几大口鲜红的液体后,急忙请假赶到医院,找到了上午给我看病的大夫。 谁能想到呢,接下来医生在我嘴里简单捅了几刀,我就开始血流不止了。医生没有过多考虑,便开始给我止血,直到材料塞满了嘴巴,等到开始缝针才想起没有给我打麻药,而我已经疼到有点晕厥,旁边的护士姐姐还提醒道:“要不让他喝了这葡萄糖吧,我看他脸色不好”。 但医生本着专业素养,在动完刀后,立马把自己的老师叫来验收成果,老师看着我满眼的泪珠,语重心长的说:“你这没打麻药,小伙子受不了吧”,我听闻后赶忙应和点点头,随后他叮嘱该医生,以后一定记得先打麻药再…… 随后,医生还留了我一会,本以为是要叮嘱些注意事项,没想到是想在病历上把这突如其来的遭遇仔仔细细记录一番。我明明已说不出话了,但为了记录下这个“疑难杂症”,他还是让我努力说一说,最后促成了一大段文字描述作为补充病情???能看出来,这是一位非常好学的医生。 接下来,由于嘴巴塞满材料且无法闭合,我跟粥汤以及水饺度过了两周,肉眼可见的瘦了。由于担心过久没让医生观察我的牙齿情况,于是我提前约定时间两天加挂了号,同时也做好了准备让医生拆线。果不其然,就在医生给我拆完线之后,又继续血流不止了。 医生紧急给我止血,往我嘴里塞了些材料,还让我继续咬着纱布呆上半小时观察,期间那种疼痛感仿佛又回来了…… 临走前记得医生说要等塞入的胶原蛋白棉片自行溶解在牙槽内,可能要持续一到两周,但,好景不长,第二天吃饭的时候,也不知道是不是太饿了,直接一咕噜,整个棉片随着一口汤全给我吞到肚子里去了。 这苦涩的人生啊。 虽拔牙遇到插曲,但仍然感激医生们的辛勤付出,希望大家都健健康康,远离病痛。

2023/11/11
articleCard.readMore