微信利用垄断地位作恶
在微信的小程序里有 4.72 元余额,是通过微信充值进去的。
退款时,小程序申称退款了,微信却申称没有收到。
我投诉小程序,被微信私自关闭,要我私下打电话和小程序商量,我的钱我要去商量很奇怪,我去联系小程序,又被推给微信,说钱给了微信,
我又去联系微信,微信说钱给到了小程序,不管他们的事。
就这样我的钱进入了规则黑洞,不可见了。
xiaohack博客专注前沿科技动态与实用技术干货分享,涵盖 AI 代理、大模型应用、编程工具、文档解析、SEO 实战、自动化部署等内容,提供开源项目教程、科技资讯日报、工具使用指南,助力开发者、AI 爱好者获取前沿技术与实战经验。
在微信的小程序里有 4.72 元余额,是通过微信充值进去的。
退款时,小程序申称退款了,微信却申称没有收到。
我投诉小程序,被微信私自关闭,要我私下打电话和小程序商量,我的钱我要去商量很奇怪,我去联系小程序,又被推给微信,说钱给了微信,
我又去联系微信,微信说钱给到了小程序,不管他们的事。
就这样我的钱进入了规则黑洞,不可见了。
昨日 V 友努力,Opus4.6 消耗了近 10 亿 token

我也紧盯报错日志,修复了不少问题(其中包括一些其他收费中转站也报错的问题。得益于自研的负载均衡报错转移逻辑,目前暂无太明显的中转站问题)

已听劝。
为了让 V 友在周末休闲时间 vibe coding 用得爽,暂时关闭 CF 小黄云,上线临时日本 IP 将延迟降低至 100ms 以下。

请允许我打个小广告:各位用得爽的 V 友可以给同事推荐一下,网站需要流量。谢谢🙏
一个免费不限量 Claude API 公益服务,请作为兜底使用。支持 OpenAI 和 Anthropic 格式。
不用注册 免费 不限量 真模型 自己服务不能用了再用这个作为兜底,别做主力使用,不保证稳定性,只保用到的模型是真的模型。
网址自行解码:aHR0cHM6Ly9vbmVkYXlhaS5hdXRvY29kZS5zcGFjZS8=
🙏赛博活佛🙏
现在奶茶店琳琅满目。太多种类了
但是真的健康吗。里面的牛奶是真的牛奶吗。珍珠啥的都健康吗
还有奶茶店的食材工商管理或者食品安全部门会检查吗
不求喝了能延年益寿。起码没什么致癌或者心脑血管的成分吧
开发者朋友们大家好: 这里是 「RTE 开发者日报」 ,每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE(Real-Time Engagement) 领域内「有话题的技术」、「有亮点的产品」、「有思考的文章」、「有态度的观点」、「有看点的活动」,但内容仅代表编辑的个人观点,欢迎大家留言、跟帖、讨论。 本期编辑:@瓒an、@鲍勃 1、Mistral AI 发布 Voxtral Transcribe 2 系列语音转文字模型:延迟降至 200ms 以下,Realtime 模型权重开源 法国 AI 初创公司 Mistral AI 发布新一代语音转文字系列模型「Voxtral Transcribe 2」,包含实时流式模型「Voxtral Realtime」与离线批处理模型「Voxtral Mini Transcribe V2」。该系列在大幅降低推理延迟的同时,通过 $0.003/分钟的定价策略挑战现有的语音 API 市场,并对实时模型实行 Apache 2.0 协议开源。 「Voxtral Mini Transcribe V2」已通过 API 上线,定价 $0.003/min;「Voxtral Realtime」API 定价 $0.006/min,其模型权重已在 Hugging Face 开放下载。 HuggingFace: ( @Mistral AI Blog) 2、Sarvam AI 发布「Sarvam Vision」视觉语言模型:基于 3B 参数 SSM 架构,主打 22 种印度语种文档解析 印度 AI 初创公司 Sarvam AI 推出 3B 参数的视觉语言模型「Sarvam Vision」。该模型采用 State-space 架构,旨在解决印度 22 种官方语言在文档智能领域的精度瓶颈,实现从扫描件、历史档案及复杂图表中进行端到端的知识提取。 API 已正式上线。2026 年 2 月全月,「Sarvam AI」 平台提供免费无限量使用。 相关链接: ( @Sarvam AI Blog) 1、库克官宣苹果进军 AI 硬件,首款 AI 眼镜有望今年发布 科技媒体 Cult of Mac 今天发布博文,报道称在苹果本周召开的全员会议上,公司首席执行官蒂姆 · 库克首次确认,正积极筹备一系列由 AI 驱动的全新产品类别。 库克并未在会议上展示具体原型机,但向员工强调了 AI 为苹果带来的全新机遇。该媒体认为这一表态证实了业界长期的猜测:苹果正试图通过人工智能技术,重新定义用户与设备的交互方式,逐步摆脱对传统触摸屏的依赖。 在 AI 设备方面,基于目前相关爆料,目前至少有 AI 眼镜和 AI 胸针两款产品。 该媒体报道称苹果内部正加速研发 AI 智能眼镜,被视为接替 iPhone 的关键设备之一。首代产品预计不配备显示屏,而是通过集成摄像头、麦克风和扬声器,实现电话接听、音乐播放、实时翻译及逐向导航等功能。 消息称苹果会在 2026 年年底前展示该产品的初版概念,然后在 2027 年发售。至于带有显示屏的第二代版本,则可能要等到 2028 年才会问世。 在 AI 胸针方面,其尺寸类似 AirTag,混合铝合金与玻璃外壳材质,计划最早于 2027 年发布。设备正面集成了两颗摄像头(标准镜头与广角镜头),不仅能拍摄照片,还能实时捕捉用户周边的视频信息。 (@IT 之家) 2、金融科技初创公司 Veritus 获 1010 万美元种子轮融资,深耕贷款领域语音 AI 智能体 据 FinTech Futures 独家报道,美国金融科技初创公司 Veritus 已成功完成 1010 万美元的种子轮融资。本轮融资由 Crosslink 和 Threshold 领投,Emergence Capital、Surge Point、Cedar Capital 及 Rebel Fund 等机构参投。 Veritus 由 Joshua March 与前 Divvy Homes 工程师 David Schlesinger、Joey Stein 于去年共同创立,并入选了 Y Combinator 2025 年夏季批次。该公司总部位于旧金山,专门为消费贷款行业提供 AI 智能体平台。其核心技术是语音优先的智能体,能够与借款人进行符合监管要求的对话,同时支持短信、电子邮件和实时聊天。 该平台通过与贷款管理系统及记录系统集成来访问客户数据,运行全渠道的入站和出站业务。目前的部署重点集中在两个领域: Veritus 采用双智能体架构处理复杂对话,如困境计划、费用减免及结算。在此模式下,一名 AI 智能体负责与客户沟通,另一名则在后台监测对话并向主智能体提供评估建议。 在安全性方面,Veritus 在创立之初即确立了银行级控制标准。平台具备实时个人敏感信息脱敏和令牌化功能,目前已获得 PCI、HIPAA、ISO 及 SOC Type II 等相关合规认证。 公司已上线运营五个月,客户涵盖金融科技公司、大型服务商及一家英国银行。随着种子轮融资完成,Veritus 计划通过扩充团队来加速市场扩张。其核心成员包括来自 Best Egg、高盛 Marcus 及 Robinhood 等知名机构的资深专家。CEO Joshua March 表示,市场正意识到智能体 AI 带来的运营效益,公司目标是迅速满足增长的需求,并将在业务起飞后适时启动 A 轮融资。 ( @FinTech Futures) 3、AI 视频数字人平台 Synthesia 融资 2 亿美元,将打造员工技能培训 AI 总部位于伦敦的 AI 视频数字人平台 Synthesia Ltd。 宣布完成 2 亿美元的 E 轮融资,公司估值因此达到 40 亿美元。本轮融资由现有投资者 Google Ventures 领投,Evantic 和 Hedosophia 参投。包括 NVentures、Accel、Kleiner Perkins、New Enterprise Associates 等在内的多位现有投资者也参与了本轮跟投。该消息证实了去年 10 月关于由 Google Ventures 领投该轮融资的报道。 Synthesia 成立于 2017 年,主要提供利用生成式 AI 制作逼真、栩栩如生的人物视频虚拟形象的平台。公司计划利用新资金,通过其专业的视频 AI 产品重新定义员工的学习方式。其核心工具具备以下特点: 公司联合创始人兼首席执行官 Victor Riparbelli 表示,本轮融资将用于扩展公司的愿景,即利用 AI 将内容创作成本降至零,并为组织提供更具吸引力的沟通与学习方式。Synthesia 认为,未来十年内容形式将从静态的单向内容转变为由 AI 代理驱动的交互式体验,例如在自助服务终端或移动设备上实现类似视频通话的互动。 针对企业面临的员工技能提升挑战,Synthesia 将重点放在设计用于教育和技能提升的对话代理上。早期客户反馈显示,基于代理的新产品比传统格式带来了更高的参与度。鉴于此,Synthesia 表示将把教育代理作为核心战略重点,同时继续投资现有平台的功能开发。 相关链接: ( @SiliconANGLE) 4、一句指令安排全家日程:Nori 登顶生产力榜,探索家庭语音交互新形态 Domus Next 旗下的 AI 产品 Nori 近期在美国市场表现抢眼,仅凭为期一个月的内测便渗透进超 10 万家庭,发布首日更在 App 生产力榜单上一度超越 Google Calendar。该团队核心成员来自字节跳动和三星,试图将 AI 的关注点从专业工具回归大众生活,解决家庭场景中信息分散、协作低效的痛点。 Nori 将共享日历、任务管理、菜谱规划等功能整合,并提供了显著的 AI 入口。用户可通过文字、语音或拍照等多种方式与 AI 交互。在实际体验中,语音成为了高效处理琐事的利器: 尽管「简单好用」是其核心标签,但用户反馈也暴露了纯软件形态在语音交互上的局限。许多用户抱怨手机锁屏状态下无法唤醒 AI,导致厨房里随口一句「牛奶快没了」或客厅关于周末计划的闲聊无法被即时捕捉。这种对手机硬件的依赖,使得 Nori 难以获取散落在环境中的非正式信息,也阻碍了部分不习惯使用 App 的家庭成员参与协作。 针对这一瓶颈,Domus Next 正探索软硬件协同的路线。未来的硬件设备被视为一个始终在线的物理载体,它能像「耳朵」一样常驻家庭公共空间,解决手机交互的割裂问题。通过捕捉持续的、环境化的语音上下文,AI 有望从单一工具进化为真正理解家庭真实运作机制的智能体。 ( @Z Potentials) 1、ElevenLabs CEO:语音是人工智能的下一个交互界面 ElevenLabs 联合创始人兼 CEO Mati Staniszewski 在多哈 Web Summit 峰会上指出,语音正演变为人工智能的下一代主流交互界面。随着模型突破文本与屏幕的限制,语音将成为人类操控机器的核心方式。 Staniszewski 表示,ElevenLabs 开发的语音模型已不仅限于模拟情感与语调,而是开始与大语言模型的推理能力深度结合。他预见在未来几年,手机将回归口袋,人们得以便捷地沉浸于现实世界,通过语音机制直接掌控各项技术。 这一愿景已获得行业资本与巨头的广泛认可。本周,ElevenLabs 完成 5 亿美元融资,估值攀升至 110 亿美元。目前,语音交互已成为 AI 竞争的关键战场: 针对技术演进,Staniszewski 强调了「智能体化」的趋势。未来的语音系统将不再依赖逐条指令,而是通过积累持久记忆与上下文,使交互过程更趋自然。 为支持耳机等可穿戴硬件,ElevenLabs 正开发云端与本地处理相结合的混合架构,使语音成为持久伴随的工具。目前,该公司已与 Meta 展开合作,将其技术应用于 Instagram 及 Horizon Worlds,并有意探讨在 Ray-Ban 智能眼镜上的合作可能。 然而,随着语音系统更深入地嵌入日常生活,关于隐私、监控及个人数据存储的风险也随之增加,这成为该领域必须面对的严峻挑战。 ( @TechCrunch) 阅读更多 Voice Agent 学习笔记:了解最懂 AI 语音的头脑都在思考什么 写在最后: 我们欢迎更多的小伙伴参与 「RTE 开发者日报」 内容的共创,感兴趣的朋友请通过开发者社区或公众号留言联系,记得报暗号「共创」。 对于任何反馈(包括但不限于内容上、形式上)我们不胜感激、并有小惊喜回馈,例如你希望从日报中看到哪些内容;自己推荐的信源、项目、话题、活动等;或者列举几个你喜欢看、平时常看的内容渠道;内容排版或呈现形式上有哪些可以改进的地方等。 作者提示: 个人观点,仅供参考
01 有话题的技术

https://huggingface.co/mistralai/Voxtral-Mini-4B-Realtime-2602

https://dashboard.sarvam.ai/02 有亮点的产品




03 有态度的观点




大家好!今天想给大家分享一个我最近用 Vue 开发的实用小工具——BMI计算器。 BMI(Body Mass Index,身体质量指数)是国际上常用的衡量人体胖瘦程度以及是否健康的一个标准。无论你是在健身、减肥,还是单纯关注身体健康,了解自己的 BMI 值都是非常重要的第一步。 虽然网上有很多计算器,但我发现很多体验并不好,要么广告满天飞,要么界面陈旧。作为一个程序员,我决定自己动手,用 Vue.js 开发一个纯净、快速、好用的在线 BMI 计算器。 使用非常简单,只需要三步: 工具会自动算出你的 BMI 指数,并用不同颜色的卡片直观展示你的健康状态。比如,绿色代表健康,橙色或红色则提示需要注意了。 这个工具是基于 Vue.js 框架构建的。利用 Vue 的响应式特性,实现了数据的实时处理和界面的动态更新。UI 方面使用了现代化的设计语言,确保视觉上的舒适感。所有的计算逻辑都在前端完成,保护你的隐私,数据不会被上传。 希望这个小工具能帮助大家更好地管理自己的健康!如果你觉得好用,欢迎分享给身边的朋友。BMI计算器 在线工具分享
在线工具网址:https://see-tool.com/bmi-calculator
什么是 BMI?
为什么开发这个工具?
工具亮点
如何使用?
技术实现
用 Claude Code 写代码时最大的痛点:离开电脑就失联了。各种手机终端软件交互也不友好
所以做了 CCBot , 一个 Telegram Bot ,让你用手机无缝接管终端里的 Claude Code 会话。
它不封装 SDK ,只是通过 tmux 启动 Claude 进程,然后服务和 tmux 进行交互:读 tmux 的输出、发按键给 tmux 等等。使用 tmux attach 又可以继续在电脑操作了,完整的上下文都在。

京东好像好取消了客服电话,现在整个 APP 都找不到客服电话了。
现在只有 web 在线客服,但是这些在线客服整体业务和素质都不如当初的。
其实我们不必回避看完书就忘的问题,因为大多数人看书都是会忘的。其实人类的大脑就是这么设计的,它会过滤掉大部分不重要的信息,只保留下重要的信息。如果真的想要记住一本书重要的知识,需要反复阅读,反复思考,反复练习。
在前 AI 时代,做读书笔记是一件非常耗费精力的事情,但是有大模型之后,我们可以在做笔记这件事上偷偷懒。
注意:做笔记可以偷懒,但是思考和反复回看是绝对不能偷懒的。
那么有什么好用的工具呢?朋友们,有的!欢迎使用 ebook-to-mindmap!简单来说,你可以通过 ebook-to-mindmap 把 pdf 或 epub 格式的电子书转换为分章节的思维导图或者文字总结。

点击这里即可立即体验。整个网页应用功能比较简洁,大家可以直接上手,当然,下面我也会比较详细地介绍一下这个应用的使用方法🤗
使用 ebook-to-mindmap 的第一步是配置模型。它和很多 AI 应用一样,都是选择 byok( Bring Your Own Key )的模式,你可以在这里配置你自己的大模型。
这里还是要强调一下,在 ebook-to-mindmap 填写 Key 时不必担心 Key 泄露,因为 Key 只是保存在你自己的浏览器里,请求也是直接从你的浏览器发送到大模型提供商的服务器的。你可以在浏览器的开发者工具里查看网络请求,确认这一点。同时,ebook-to-mindmap 作为一个开源项目你可以随时检视它的代码,还可以自己部署一个属于你的 ebook-to-mindmap 。
说回模型的选择,可能很多人会担心使用 ebook-to-mindmap 的花费太高,其实倒也不必,毕竟现阶段还是能找到很多免费或者低价的大模型。我的首推还是 openrouter,你只需要充值 10 刀,就能获得一个较大的免费模型(其中包括一些 deepseek 变体、最近小米的新模型、之前一段时间还有 grok )使用额度,基本上一天让它处理好几本书都没问题了。其他详细推荐可以参考免费和付费 AI API 选择指南。

在获取到 Key 后如上图填写信息即可。
你还可以配置多个模型,点击左侧的星星后会成为默认模型,后续处理时默认使用星标的模型:

配置模型后,在主页选择电子书即可。之后 ebook-to-mindmap 会自动识别电子书的格式,然后开始识别章节:

提示:如果 epub 无法获取到章节,可以在设置里勾选使用 Spine 获取章节
章节识别成功后,选择你需要总结的章节,或者使用分组功能(可以使用快捷键 Ctrl + G )把零碎的章节组合成分组一起发送给 AI 处理。
一切准备好后,点击开始解释按钮即可开始生成笔记。
默认情况下,ebook-to-mindmap 会生成思维导图,你也可以点击小齿轮切换到文字总结模式:

虽然有整书思维导图生成功能,但是如果书的内容比较长,AI 可能吃不下这么长的上下文,所以建议还是分章节生成,最后系统会自动拼接
生成笔记如果想要中途取消,放心点取消就好,之前处于完成状态的章节会被缓存,不用担心之后需要再浪费 Token 重新生成。
举个例子吧,你在提示词列表里添加一个“小·红书风格”提示词,在生成环节选择这个提示词,就能直接生成小红书风格的笔记。

不止小红书风格,你也可以让 AI 只简单地提取该章节最重要的 5 个观点,帮助你对整本书的主要内容有一个简要的了解。
你还可以使用“反论法”提示词:
选取本章的核心论点或思想,并探索它的对立面。如果作者要为相反的观点辩护,他们需要证明什么?文本中是否有无意间支持反面观点的蛛丝马迹?
参考分享几条有意思的 NotebookLM 提示词这篇文章,里面有几个有趣的提示词,或许能让你眼前一亮。
ebook-to-mindmap 充满了下载按钮,是的,你生成的数据必须还是属于你的!你可以很轻易地把数据拿出来!
导出的文字内容可能是 markdown 文件或是思维导图 json 文件。
markdown 文件可以直接阅读,或者导入到 Obsidian 、Notion 等笔记软件再细化修改。
思维导图 json 文件可以使用 mind-elixir-core 等前端库渲染,当然,如果你是技术人员,理解 json 数据的结构你也可以随意修改和渲染。
思维导图亦可导出为图片,点击思维导图页面右上角的下载按钮即可。
最后谈谈电子书格式的问题,ebook-to-mindmap 支持 pdf 和 epub 格式的电子书,但是这两种格式如何选择呢?
或许大家都会比较喜欢看 pdf ,因为看起来比较工整,但是使用 ebook-to-mindmap ,我还是比较推荐 epub 格式的电子书。
稍微讲一下 pdf 和 epub 的原理吧。
pdf 的特点是在任何设备上看起来都一样,这就很容易想到,其实 pdf 的排版是非常固定的,而且更重要的是,pdf 的排版是没有语义的。也就是说,人类能看到一个标题是加粗黑字,但是 pdf 本身并不知道这是一个标题,它只是知道这一块区域的文字是加粗黑字的。
更严重的问题是 pdf 如果有一些复杂的排版,例如在角落嵌入一段文字,在解释的时候就很难理解那段文字的意义。所以,大模型理解 pdf 的难度会比较大。
而 epub 格式就不一样,它更像是一张网页,有语义,有结构,有层次,就跟 HTML 差不多。但缺点就是人类看来这样的排版有点粗糙,在不同的阅读器上显示效果也不同。在某些落后的 epub 阅读器上阅读时可能会觉得排版很有年代感。但是大模型不在乎排版,有清晰的结构就能得到好的输出结果。
总的来说,ebook-to-mindmap 是一个能帮你快速复习或者把书本变薄的工具。在这个信息爆炸的时代,高效地获取和整理知识变得越来越重要。希望这个小工具能成为你阅读路上的得力助手,让你把更多的时间花在深度思考和理解上,而不是机械地摘抄。
如果你觉得这个项目对你有帮助,欢迎在 GitHub 上点个 Star ⭐️ 支持一下!如果你有任何建议或发现了 bug ,也欢迎提 Issue 或者加入讨论。
Happy Reading!
其实我们不必回避看完书就忘的问题,因为大多数人看书都是会忘的。其实人类的大脑就是这么设计的,它会过滤掉大部分不重要的信息,只保留下重要的信息。如果真的想要记住一本书重要的知识,需要反复阅读,反复思考,反复练习。
在前 AI 时代,做读书笔记是一件非常耗费精力的事情,但是有大模型之后,我们可以在做笔记这件事上偷偷懒。
注意:做笔记可以偷懒,但是思考和反复回看是绝对不能偷懒的。
那么有什么好用的工具呢?朋友们,有的!欢迎使用 ebook-to-mindmap!简单来说,你可以通过 ebook-to-mindmap 把 pdf 或 epub 格式的电子书转换为分章节的思维导图或者文字总结。

点击这里即可立即体验。整个网页应用功能比较简洁,大家可以直接上手,当然,下面我也会比较详细地介绍一下这个应用的使用方法🤗
使用 ebook-to-mindmap 的第一步是配置模型。它和很多 AI 应用一样,都是选择 byok( Bring Your Own Key )的模式,你可以在这里配置你自己的大模型。
这里还是要强调一下,在 ebook-to-mindmap 填写 Key 时不必担心 Key 泄露,因为 Key 只是保存在你自己的浏览器里,请求也是直接从你的浏览器发送到大模型提供商的服务器的。你可以在浏览器的开发者工具里查看网络请求,确认这一点。同时,ebook-to-mindmap 作为一个开源项目你可以随时检视它的代码,还可以自己部署一个属于你的 ebook-to-mindmap 。
说回模型的选择,可能很多人会担心使用 ebook-to-mindmap 的花费太高,其实倒也不必,毕竟现阶段还是能找到很多免费或者低价的大模型。我的首推还是 openrouter,你只需要充值 10 刀,就能获得一个较大的免费模型(其中包括一些 deepseek 变体、最近小米的新模型、之前一段时间还有 grok )使用额度,基本上一天让它处理好几本书都没问题了。其他详细推荐可以参考免费和付费 AI API 选择指南。

在获取到 Key 后如上图填写信息即可。
你还可以配置多个模型,点击左侧的星星后会成为默认模型,后续处理时默认使用星标的模型:

配置模型后,在主页选择电子书即可。之后 ebook-to-mindmap 会自动识别电子书的格式,然后开始识别章节:

提示:如果 epub 无法获取到章节,可以在设置里勾选使用 Spine 获取章节
章节识别成功后,选择你需要总结的章节,或者使用分组功能(可以使用快捷键 Ctrl + G )把零碎的章节组合成分组一起发送给 AI 处理。
一切准备好后,点击开始解释按钮即可开始生成笔记。
默认情况下,ebook-to-mindmap 会生成思维导图,你也可以点击小齿轮切换到文字总结模式:

虽然有整书思维导图生成功能,但是如果书的内容比较长,AI 可能吃不下这么长的上下文,所以建议还是分章节生成,最后系统会自动拼接
生成笔记如果想要中途取消,放心点取消就好,之前处于完成状态的章节会被缓存,不用担心之后需要再浪费 Token 重新生成。
举个例子吧,你在提示词列表里添加一个“小·红书风格”提示词,在生成环节选择这个提示词,就能直接生成小红书风格的笔记。

不止小红书风格,你也可以让 AI 只简单地提取该章节最重要的 5 个观点,帮助你对整本书的主要内容有一个简要的了解。
你还可以使用“反论法”提示词:
选取本章的核心论点或思想,并探索它的对立面。如果作者要为相反的观点辩护,他们需要证明什么?文本中是否有无意间支持反面观点的蛛丝马迹?
参考分享几条有意思的 NotebookLM 提示词这篇文章,里面有几个有趣的提示词,或许能让你眼前一亮。
ebook-to-mindmap 充满了下载按钮,是的,你生成的数据必须还是属于你的!你可以很轻易地把数据拿出来!
导出的文字内容可能是 markdown 文件或是思维导图 json 文件。
markdown 文件可以直接阅读,或者导入到 Obsidian 、Notion 等笔记软件再细化修改。
思维导图 json 文件可以使用 mind-elixir-core 等前端库渲染,当然,如果你是技术人员,理解 json 数据的结构你也可以随意修改和渲染。
思维导图亦可导出为图片,点击思维导图页面右上角的下载按钮即可。
最后谈谈电子书格式的问题,ebook-to-mindmap 支持 pdf 和 epub 格式的电子书,但是这两种格式如何选择呢?
或许大家都会比较喜欢看 pdf ,因为看起来比较工整,但是使用 ebook-to-mindmap ,我还是比较推荐 epub 格式的电子书。
稍微讲一下 pdf 和 epub 的原理吧。
pdf 的特点是在任何设备上看起来都一样,这就很容易想到,其实 pdf 的排版是非常固定的,而且更重要的是,pdf 的排版是没有语义的。也就是说,人类能看到一个标题是加粗黑字,但是 pdf 本身并不知道这是一个标题,它只是知道这一块区域的文字是加粗黑字的。
更严重的问题是 pdf 如果有一些复杂的排版,例如在角落嵌入一段文字,在解释的时候就很难理解那段文字的意义。所以,大模型理解 pdf 的难度会比较大。
而 epub 格式就不一样,它更像是一张网页,有语义,有结构,有层次,就跟 HTML 差不多。但缺点就是人类看来这样的排版有点粗糙,在不同的阅读器上显示效果也不同。在某些落后的 epub 阅读器上阅读时可能会觉得排版很有年代感。但是大模型不在乎排版,有清晰的结构就能得到好的输出结果。
总的来说,ebook-to-mindmap 是一个能帮你快速复习或者把书本变薄的工具。在这个信息爆炸的时代,高效地获取和整理知识变得越来越重要。希望这个小工具能成为你阅读路上的得力助手,让你把更多的时间花在深度思考和理解上,而不是机械地摘抄。
如果你觉得这个项目对你有帮助,欢迎在 GitHub 上点个 Star ⭐️ 支持一下!如果你有任何建议或发现了 bug ,也欢迎提 Issue 或者加入讨论。
Happy Reading!
我买过 3 个不同品牌的 rtl8126 网卡,全都不支持 uefi 模式下的 pxe 启动,我想把 Realtek 官方的"UEFI UNDI Driver (X64/ARM)"驱动(下载解压后会得到 RtkUndiDxe.efi )刷入网卡的 rom ,但不知道怎么操作,ai 给的方法试了都不管用,也搜不到靠谱的教程,有有这方面经验的 v 友能指导一下吗?
目前我通过一种变通的方式实现了 rtl8126 网卡的 pxe 启动,步骤如下:
在 u 盘上创建一个 efi 分区,把 fedora 的 edk2-shell-x64 包的 /usr/share/edk2/ovmf/Shell.efi 文件拷贝到 efi 分区的 EFI/Boot 目录并且重命名为 bootx64.efi ,然后在 efi 分区的根目录创建 startup.nsh 文件自动加载 RtkUndiDxe.efi ,再通过主板板载的 rtl8125 网卡的 pxe 功能从 tftp 服务器加载 ipxe.efi ,然后就可以通过 ipxe 来从 rtl8126 网卡把 Fedora 系统安装在 iscsi 存储上并从 iscsi 存储上启动。
这么搞相比直接支持 pxe 启动的网卡来说太麻烦了,我知道新出的 rtl8127 网卡是支持 uefi 模式下的 pxe 启动的,但价格是 rtl8126 的 3 倍多,对我来说 5G 速率的网卡就够我用了,不想多花钱上 rtl8127 网卡,我目前已经把 rtl8126 的网卡的 rom 提取出来了,用如下命令:
d@d-macbookair:~/Downloads$ EfiRom -f 0x10EC -i 0x8126 -e RtkUndiDxe.efi
d@d-macbookair:~/Downloads$
d@d-macbookair:~/Downloads$ rom-parser RtkUndiDxe.rom
Valid ROM signature found @0h, PCIR offset 1ch
PCIR: type 3 (EFI), vendor: 10ec, device: 8126, class: 000000
PCIR: revision 3, vendor revision: 0
EFI: Signature Valid, Subsystem: Boot, Machine: X64
Last image
d@d-macbookair:~/Downloads$
但就是不知道如何把 RtkUndiDxe.rom 刷入网卡的 rom
编码是机器学习流程里最容易被低估的环节之一,模型没办法直接处理文本形式的分类数据,尺寸(Small/Medium/Large)、颜色(Red/Blue/Green)、城市、支付方式等都是典型的分类特征,必须转成数值才能输入到模型中。 那么问题来了:为什么不直接把 Red 编成 1,Blue 编成 2?这个做法看起来简单粗暴,但其实藏着大坑。下面用一个小数据集来说明。 Ordinal Encoding 思路很简单:给每个类别分配一个数字,但是模型会把这些数字当作有序的。 假设对 做编码:Cash = 1,PayPal = 2。模型会认为 Cash < PayPal,仿佛 PayPal 比 Cash "更好" 或 "更大"。但支付方式之间根本没有这种大小关系因为它们只是不同的选项而已。 什么时候 Ordinal Encoding 才合适?当数据本身就存在真实的顺序关系时。比如 :High School < Associate < Bachelor's < Master's < PhD。这是客观存在的递进关系,用数字表示完全没问题,模型的理解也是对的。 所以 Ordinal Encoding 的使用场景很明确:只用于那些排名确实有意义的特征。 One-Hot Encoding 换了个思路:不用数字而是给每个类别创建一列。 有 4 个值,就变成 4 列,每行只有一个位置是 1,其余全是 0。 这样做的好处是消除了虚假的顺序关系,所有类别被平等对待和线性模型配合得也很好。 那么代价是什么?维度会膨胀。 和 各 4 个值,合起来就是 8 列。如果遇到城市这种特征,50 多个类别直接炸成 50 多列,维度灾难就来了。 面对高基数特征(比如 City 有 50 多个值)One-Hot Encoding 会把特征空间撑得太大,Target Encoding 的做法是:用每个类别对应的目标变量均值来替换。也叫 Mean Encoding。 举个例子,目标变量是 (Yes = 1,No = 0): 计算每个城市的目标均值:Austin → (1 + 1) / 2 = 1.0,New York → (1 + 0 + 0 + 0 + 1) / 5 = 0.4,这样得到的编码结果就是: 这里有一个坑,Austin 只出现了 2 次而且刚好都是正例,编码值直接变成 1.0。模型可能会 "学到" 一个规律:看到 Austin 就预测 will_return = Yes。 但这个 "规律" 完全是数据量不足造成的假象。样本太少均值就很不可靠。 Smoothing 的思路是把类别均值往全局均值方向 "拉" 一拉。公式: 其中 Category Mean 是该类别的目标均值Global Mean 是整个数据集的目标均值,w 是一个和样本量相关的权重。样本越少w 越小,编码值就越接近全局均值;样本越多类别自己的均值就越占主导。这能有效抑制小样本带来的过拟合。 另一个问题就是 Data Leakage。如果用全量数据计算编码值再把这个编码喂给模型,模型等于直接 "看到了" 答案的统计信息。比如模型发现 City = 0.34 对应的样本大概率是 will_return = Yes,那它干脆走捷径,不从其他特征里学东西了。 所以就要引入交叉验证,以 5 折为例:把数据分成 5 份,对第 1 份的数据,用第 2 到第 5 份来计算编码;对第 2 份的数据,用第 1、3、4、5 份来计算编码;以此类推。每个样本的编码值都来自于它 "没见过" 的数据,泄露就切断了。 但是副作用是同一个城市在不同折里的编码值会略有差异:New York 在 Fold 1 里可能是 0.50,在 Fold 2 里是 0.45。但这反而是好事,这样可以让模型被迫学习更一般化的模式而不是死记某个精确数值。 Target Encoding 的优点:避免维度爆炸,适合高基数特征,还能把目标变量的统计信息编进去。 但用的时候得小心:必须加 Smoothing 防止小样本过拟合,必须用交叉验证防止数据泄露。 三种编码方法各有适用场景,选择取决于特征本身的性质。 实际操作中可以这样判断:特征有天然顺序就用 Ordinal Encoding;没有顺序、类别数量也不多就用 One-Hot Encoding;类别太多就上 Target Encoding,记得配合 Smoothing 和交叉验证。 真实项目里,一个数据集往往会同时用到这三种方法。 https://avoid.overfit.cn/post/eeabb03fba684a88a6ccce132f4852b0 作者: adham ayman
数据集概述
Feature | Description
-------------------|----------------------------------------------------------
customer_id | Unique customer identifier
gender | Male or Female
education_level | High School → Associate → Bachelor's → Master's → PhD
employment_status | Full-time, Part-time, Self-employed, Unemployed
city | Customer's city (50+ US cities)
product_category | Electronics, Clothing, Books, Sports, Home & Garden, Beauty, Food & Beverage
payment_method | Credit Card, Debit Card, PayPal, Cash
customer_tier | Bronze → Silver → Gold → Platinum
satisfaction_level | Dissatisfied → Neutral → Satisfied → Very Satisfied
credit_score_range | Poor → Fair → Good → Very Good → Excellent
purchase_amount | Purchase amount in USD
will_return | Yes or No (target variable)Ordinal Encoding
payment_methodeducation_level from sklearn.preprocessing import OrdinalEncoder
ordEnc = OrdinalEncoder()
print(ordEnc.fit_transform(data[["education_level"]])[:5])
# Output
"""
[[1.]
[2.]
[3.]
[4.]
[2.]]
"""One-Hot Encoding
payment_method | payment_cash | payment_credit_card | payment_debit_card | payment_paypal |
|--------------|---------------------|--------------------|----------------|
| 1 | 0 | 0 | 0 |
| 0 | 1 | 0 | 0 |
| 0 | 0 | 1 | 0 |
| 0 | 0 | 0 | 1 |customer_tierpayment_method from sklearn.preprocessing import OneHotEncoder
oneEnc = OneHotEncoder()
print(oneEnc.fit_transform(data[["customer_tier", "payment_method"]]).toarray()[:5])
[#output](#output)
"""
[[0. 1. 0. 0. 0. 1. 0. 0.]
[0. 0. 0. 1. 0. 0. 1. 0.]
[0. 0. 1. 0. 0. 0. 0. 1.]
[0. 1. 0. 0. 0. 1. 0. 0.]
[1. 0. 0. 0. 1. 0. 0. 0.]]
"""Target Encoding
will_return | City | will_return |
|-----------|-------------|
| Austin | 1 |
| Austin | 1 |
| New York | 1 |
| New York | 0 |
| New York | 0 |
| New York | 0 |
| New York | 1 | | City | Encoded Value |
|----------|----------------|
| Austin | 1.0 |
| New York | 0.4 | Encoded Value = (w * Category Mean) + ((1 - w) * Global Mean) from sklearn.preprocessing import TargetEncoder
data["will_return_int"] = data["will_return"].map({"Yes": 1, "No": 0})
tarEnc = TargetEncoder(smooth="auto", cv=5) # Those are the default value
print(data[["city"]][:5])
print(tarEnc.fit_transform(data[["city"]], data["will_return_int"])[:5])
"""
city
0 Houston
1 Phoenix
2 Chicago
3 Phoenix
4 Phoenix
[[0.85364466]
[0.69074308]
[0.65024828]
[0.74928653]
[0.81359495]]
"""总结
Protobuf 中明确界定的字段取值范围,可能因序列化过程的类型信息丢失,导致非法数据流入核心业务逻辑;嵌套结构的层级变更未被及时感知,进而引发数据解析的连锁异常,排查时需追溯整条数据链路,消耗大量时间成本。核心矛盾在于,Protobuf 的类型契约未能穿透至动态语言的运行时环境,形成“定义与执行两张皮”的现状。如何让静态契约成为动态执行的“语义核心”,实现从结构定义到运行时校验的无缝衔接,既保留动态语言的开发灵活性,又复刻静态类型语言的安全壁垒,成为跨服务协同场景中亟待破解的关键命题。这一探索并非对现有工具的简单拼接,而是对类型系统本质的深度拆解与重构,通过重新设计契约传递的链路,让类型安全从编译阶段延伸至数据流转的全生命周期,为动态语言的跨服务通信构建坚实的安全底座。 实现无缝转换的核心前提,是让 Protobuf 的定义突破“单纯结构描述”的局限,升级为承载完整语义约束的“类型元数据载体”。传统的 Protobuf 定义多聚焦于字段名称、基础类型与层级关系,却忽略了运行时校验必需的核心信息,如字段约束规则、关联逻辑、默认行为与容错策略,导致动态语言在解析时仅能获取表层结构,无法复现完整的类型契约。真正具备落地价值的定义增强,需要在完全兼容现有 Protobuf 语法的基础上,嵌入可被机器精准解析的语义注解:例如为数值字段标注合法区间、步长约束与精度要求,为字符串字段定义格式校验规则(如正则匹配、长度限制)与字符集约束,为嵌套结构明确必选层级、关联依赖与解析顺序,为枚举类型添加业务含义映射与非法值容错规则,甚至为整个消息类型定义版本兼容策略。这些语义注解并非冗余信息,而是连接静态定义与动态执行的“翻译字典”,让 Protobuf 定义从“告知机器数据的结构”,升级为“告知机器数据该如何被校验、使用、容错与适配”。在实践过程中,这种语义增强无需修改 Protobuf 的核心语法规范,而是通过官方支持的扩展注解机制实现,既保证了与现有系统的完全兼容,又为后续的类型转换提供了充足的语义支撑,让每一份 Protobuf 定义都自带完整的“安全执行说明书”,为全链路类型安全奠定基础。 连接静态定义与动态运行时的关键,是构建一套“双向语义对齐”的中间层适配机制,而非简单的单向解析或一次性代码生成工具。这一中间层的核心使命,是将 Protobuf 中增强后的语义元数据,精准转化为 TypeScript 可识别的类型描述与运行时校验逻辑,同时反向确保动态语言中的类型变更能同步反馈至契约定义,形成闭环。其运作逻辑可拆解为三个深度关联的关键环节:首先是元数据提取环节,中间层需深度解析 Protobuf 定义文件,包括处理 import 依赖、嵌套消息、枚举类型与扩展注解,全面梳理出字段类型、约束规则、默认值、容错策略、版本信息等完整数据,形成标准化、结构化的语义模型,确保无任何语义信息丢失;其次是类型映射环节,需根据 TypeScript 的类型系统特性,将 Protobuf 的原生类型(如整型、浮点型、消息类型、枚举类型)精准转化为对应的语言内置类型或自定义类型,同时建立语义约束与类型描述的关联映射,例如将 Protobuf 的 required 字段映射为 TypeScript 的必选属性,并关联对应的存在性校验规则;最后是校验逻辑注入环节,将语义模型中的各类约束规则,转化为 TypeScript 可执行的校验函数,包括字段存在性校验、类型一致性校验、业务规则校验(如数值区间、字符串格式)、版本兼容性校验等,且这些校验逻辑并非独立于类型系统之外,而是与类型注解深度融合,形成“类型声明即校验规则”的一体化结构。这一中间层的核心价值在于其动态同步能力,当 Protobuf 定义发生更新时,中间层能自动感知变更内容,并同步更新对应的类型描述与校验逻辑,从根源上避免静态定义与动态执行的不一致,彻底解决传统开发中“文档更新、代码未更”的顽疾。 运行时类型安全的落地,关键在于实现“无感知校验”与“精准容错”的动态平衡,让类型校验自然融入数据流转过程,既不增加额外的开发负担,也不造成明显的性能损耗。在动态语言的跨服务通信中,数据的序列化与反序列化是类型契约最容易失效的环节,也是校验逻辑的核心触发点。通过中间层注入的校验逻辑,需在数据进入业务逻辑前自动执行,形成“校验前置”的安全屏障:当从网络接收 Protobuf 序列化数据后,解析过程将与校验逻辑同步进行,若存在类型不匹配、必填字段缺失、非法取值、格式错误等问题,将立即返回包含错误类型、字段路径、具体原因的结构化错误信息,方便开发者快速定位问题,而非让错误流入业务逻辑引发连锁异常;当业务逻辑生成数据准备序列化发送时,同样先通过校验逻辑确保数据完全符合 Protobuf 契约,避免非法数据被发送至其他服务,保障整个服务生态的数据一致性。更重要的是,校验逻辑需支持“精准容错”策略,根据语义注解中的配置,对不同类型的异常采取差异化处理:对于非核心字段的缺失,可根据定义中的默认值规则自动补全,确保业务逻辑能正常执行;对于格式轻微偏差但不影响核心逻辑的数据(如字符串首尾空格、数值类型的轻微精度差异),可通过容错注解允许兼容处理,同时记录偏差日志便于后续优化;对于核心字段错误或严重违规数据,则直接阻断流程并返回错误。这种“校验前置、容错分级”的模式,既保证了运行时的类型安全,又避免了过度校验导致的灵活性丧失,让动态语言在享受类型安全保障的同时,不丢失其原生的开发效率与适配能力。 复杂场景的适配能力,直接决定了转换方案的实用价值,尤其在嵌套结构、联合类型、版本兼容等高频复杂场景中,需要构建“渐进式类型增强”的应对策略,确保类型安全的全面覆盖。针对嵌套结构,核心挑战在于层级依赖的校验传递与错误定位,例如某一层级的字段缺失可能导致后续所有解析失败,此时中间层需支持“深度校验”机制,递归遍历整个数据结构,不仅要检测出所有异常,还要精准定位错误所在的层级与字段路径,返回详细的错误链信息,而非仅提示顶层错误,大幅降低问题排查难度;同时,嵌套结构的校验需支持“懒加载”模式,仅在访问某一层级数据时才执行该层级的校验,避免因嵌套过深导致的性能浪费。针对联合类型(Protobuf 中通过 oneof 实现),需突破原生类型的限制,通过语义注解明确联合类型的构成与判别规则,让中间层能根据实际数据自动匹配对应的类型分支,并执行该分支的专属校验逻辑,确保联合类型的每一种可能都能得到精准校验。版本兼容是跨服务场景的核心诉求,当 Protobuf 定义发生迭代(如新增字段、废弃字段、类型变更),中间层需支持“向前兼容”与“向后兼容”的双向适配:对于旧版本服务发送的数据,能自动忽略新增字段、兼容废弃字段的默认处理逻辑,确保解析不报错;对于新版本服务发送的数据,能让旧版本服务识别核心字段并正常处理,同时忽略未定义的新增字段;对于类型变更的字段,可通过语义注解配置兼容转换规则(如整型与字符串的互转),实现平滑过渡。这些复杂场景的解决方案,并非依赖硬性的校验规则,而是通过语义元数据的精细化定义,让中间层具备智能适配能力,实现“契约迭代、适配自动同步”的动态兼容效果。 实践落地的优化方向,在于将转换方案深度融入开发全链路,实现“类型安全左移”与“工具链协同”,让类型约束从运行时提前至编码阶段,从被动校验升级为主动引导,同时确保运行时的高效执行。在编码阶段,通过中间层生成的类型描述,可与 IDE 的智能提示功能深度集成,开发者在编写代码时,能实时获取字段名称、类型约束、取值范围、默认值等关键信息提示,避免因记忆偏差或文档遗漏导致的类型错误;同时,结合静态代码检查工具,可在编译阶段提前发现潜在的类型不匹配、字段使用错误等问题,将部分运行时校验的风险前置,进一步降低线上异常概率。在测试阶段,基于 Protobuf 的语义元数据,可自动生成覆盖所有类型约束的测试用例,包括合法数据场景、边界值场景、非法数据场景、版本兼容场景等,确保校验逻辑的完整性与准确性,同时减少测试用例的编写成本。
客户端SDK的开发往往需要手动对接接口文档,不同端侧的开发人员对同一文档的理解存在差异,导致各端SDK的接口调用逻辑、异常处理方式出现不一致,后续的版本维护也需要多端同步推进,产生大量的重复劳动。这些日常开发中反复出现的问题,让我开始深入探索接口协同的本质问题:若能让API文档跳出传统“参考性文档”的定位,摆脱自然语言描述的模糊性与滞后性,使其成为整个接口生态中唯一的信息锚点,即“单一可信源”,是否能反向驱动客户端SDK、模拟服务器与集成测试用例手册的自动化生成,让所有开发环节都基于同一套标准化的接口契约展开,从而从根源上消除信息协同偏差,构建起设计到验证的全链路自动化协同体系。这一探索并非理论层面的空想,而是源于对多端协同开发流程的长期打磨与优化,在经历了无数次因文档与实际实现脱节导致的联调困境后,以API文档为可信源的全链路自动化工具链构想,逐渐从零散的思路整合为可落地的技术实践方向。 要让API文档真正成为全链路的“单一可信源”,其核心要义并非单纯提升文档的详尽程度,也不是简单对文档格式进行标准化规范,而是要赋予API文档结构化的契约属性与可被机器精准解析的语义能力,让文档从“面向人类的描述文件”转变为“面向人类与机器的双重契约载体”。传统API文档多以自然语言为主要描述方式,即便辅以简单的格式划分,也难以规避表述模糊、边界条件缺失、语义歧义等问题,比如仅描述“某参数为可选参数”,却未明确参数为空时的接口处理逻辑;仅标注返回值的数据类型,却未定义字段的业务含义与关联约束,这类模糊化的描述人类开发者尚可结合经验进行判断,但机器却无法精准解读,自然也无法基于此生成具备实际可用性的开发产物。而具备“单一可信源”特质的API文档,需要建立一套完整的语义映射体系,将接口的全部核心契约以机器可识别的结构化方式进行定义,这其中不仅包括请求方法、参数名称、数据类型、返回值结构、状态码映射等基础信息,更要涵盖参数的校验约束、异常场景的触发条件、接口的认证规则、返回值字段的关联逻辑、不同场景下的接口行为差异等深层的行为契约。比如针对数值型参数,不仅要标注取值范围,还要明确超出范围时接口的具体响应方式;针对接口的分页参数,不仅要定义参数含义,还要说明分页逻辑的实现规则与边界情况。在实际实践中发现,只有当API文档能够精准、完整地承载这些语义信息时,自动化工具才能基于此生成符合实际开发需求的产物,否则只会陷入“文档与生成结果脱节”的新困境。这也要求API文档的编写者彻底转变角色定位,从单纯的“接口描述者”转变为“接口契约的定义者”,在编写文档的过程中,不仅要兼顾人类开发者的可读性,更要严格遵循语义化的定义规范,让每一处描述都成为可被机器解析的契约节点,最终形成“一次契约定义,多端全链路复用”的核心锚点,让后端、前端、测试等所有参与方,以及所有自动化工具,都基于同一套契约展开工作,从根源上保证信息的一致性。 客户端SDK的自动化生成,是API文档作为“单一可信源”最直接、最具落地价值的应用场景,其核心价值在于彻底消除手动编写SDK带来的契约偏差与多端重复劳动,让SDK成为精准对接接口契约的标准化调用载体。在传统的开发模式中,客户端SDK的开发完全依赖开发者对API文档的人工解读与手动编码,不同端侧如iOS、Android、跨平台框架等,需要各自组建开发团队完成SDK的开发工作,不仅消耗大量的人力与工时,还极易因开发者对文档的理解偏差、编码习惯差异,导致各端SDK在接口调用逻辑、参数序列化方式、返回值解析规则、异常处理策略等方面出现不一致,比如同一接口的参数校验逻辑,在iOS端做了空值校验,而在Android端却未做处理,最终在实际使用中出现端侧适配问题。更关键的是,当后端接口发生迭代后,各端SDK需要同步进行修改与更新,开发团队需要反复沟通接口变更点,逐个端侧调整代码,不仅更新效率低下,还容易出现变更遗漏,导致SDK版本与接口契约脱节。而基于“单一可信源”API文档的SDK自动化生成,本质是将文档中定义的结构化语义契约,通过解析工具转化为各端侧可直接执行的原生调用逻辑,这一过程并非简单的代码模板填充,而是工具对文档语义的深度解析与端侧适配。比如工具会根据文档中定义的参数必填标识,自动为各端SDK添加对应的原生校验逻辑;根据返回值的结构化定义,自动生成各端侧的数据模型与解析工具;根据接口的认证规则,自动集成对应的签名、token验证机制;根据文档中定义的异常场景,自动生成标准化的异常捕获与处理逻辑。在实践中,为了让自动化生成的SDK具备足够的灵活性与可扩展性,还需要在API文档的语义定义中嵌入端侧适配的扩展规则,比如指定各端侧的参数绑定方式、返回值的解析策略,预留自定义的拦截器、缓存策略扩展点,让开发者能够在自动化生成的SDK基础上,根据业务需求进行个性化的二次开发,既保证了SDK与接口契约的绝对一致性,又避免了自动化生成产物的“僵化性”,让SDK真正成为连接各端侧与后端接口的可靠桥梁,实现“文档更新,SDK同步自动生成”的高效开发模式。 模拟服务器的自动化构建,是API文档作为“单一可信源”赋能多端并行开发的关键环节,其核心作用在于打破传统开发流程中“前端等后端、测试等开发”的协作壁垒,构建起基于接口契约的并行开发体系,让多端开发工作能够在后端接口实际实现前有序开展。在传统的开发流程中,前端与测试工作往往需要等待后端接口开发完成并部署至测试环境后才能推进,在这一等待周期内,前端开发者只能通过手动编写简单的Mock数据模拟接口响应,而这类手动Mock数据往往仅能覆盖正常的业务场景,无法模拟接口的异常场景、边界条件、流量控制策略等,导致前端开发完成后,在与实际接口联调时,频繁出现因异常处理逻辑缺失、参数校验不规范导致的适配问题,不得不返工修改;测试人员也无法提前开展测试用例的设计与执行,只能在接口开发完成后仓促开展测试工作,影响测试的深度与覆盖率。而基于“单一可信源”API文档自动化构建的模拟服务器,并非简单的Mock数据服务,而是能够精准复刻文档中定义的全部接口行为的“虚拟服务镜像”,其不仅能根据文档定义返回符合格式要求的正常响应,还能完整模拟接口的各类异常场景、参数校验逻辑、边界条件处理方式,甚至能模拟接口的流量特性如限流、超时、重试等。比如根据文档中定义的参数约束条件,模拟服务器会自动对接收的请求参数进行校验,对非法参数返回对应的错误状态码与提示信息;根据文档中定义的限流规则,模拟服务器会在请求次数达到阈值时返回限流响应;根据文档中定义的异常场景,模拟服务器能精准触发对应的异常响应。在实践中,模拟服务器的价值远不止于支撑前端并行开发,还能作为接口契约的“自动化校验器”,与后端的实际接口开发形成联动:后端开发者基于API文档的契约定义完成接口开发后,可通过契约校验工具,将实际接口与模拟服务器的接口行为进行自动化对比,快速检测出实际接口与契约定义不一致的地方,比如返回值字段缺失、状态码映射错误、参数处理逻辑偏差等,实现接口开发的早期问题发现,大幅降低联调阶段的问题排查成本。这种以模拟服务器为核心的并行开发模式,让API文档从静态的契约描述文件转变为动态的协作工具,彻底重构了多端协同的开发流程,极大提升了整体的开发效率与质量。 集成测试用例手册的自动化生成,是API文档作为“单一可信源”构建全链路自动化闭环的最后一环,其核心在于将文档中定义的接口契约,精准转化为可执行、可落地的集成测试用例,让测试工作能够紧跟接口契约的迭代步伐,实现测试用例与接口契约的同步更新,从根本上提升集成测试的覆盖率与效率。传统的集成测试用例编写工作,完全依赖测试人员对API文档的人工解读与逐点提取,测试人员需要花费大量时间逐行阅读文档,梳理接口的核心测试点,设计对应的测试场景,这一过程不仅耗时耗力,还极易因人工疏忽遗漏关键的测试场景,尤其是参数的边界条件、异常处理逻辑、多参数组合的场景等,导致测试用例的覆盖率不足,无法全面验证接口的正确性。更关键的是,当后端接口契约发生迭代后,测试用例需要测试人员手动进行修改与补充,不仅更新效率低下,还容易出现测试用例与接口契约脱节的问题,导致后续的测试工作失去实际意义。而基于“单一可信源”API文档自动化生成的集成测试用例手册,是工具对文档中结构化语义契约的深度提取与转化,工具会自动从文档中提取所有的校验元数据,包括参数的取值范围、必填项约束、返回值结构要求、异常场景定义、状态码映射规则等,进而组合成覆盖全面、逻辑严谨的结构化测试用例。这些测试用例并非简单的场景罗列,而是包含明确的测试目标、输入参数、预期结果、校验规则与执行步骤,比如针对每个数值型参数,工具会自动生成正常值、最大值、最小值、临界值、非法值等多维度的测试用例;针对每个异常状态码,工具会自动生成对应的触发场景与校验标准;针对多参数组合的接口,工具会自动生成合理的参数组合测试用例。在实践中,为了让自动化生成的测试用例手册具备更强的实用性与落地性,还会根据接口的业务重要性对测试用例进行优先级划分,核心业务接口的测试用例实现全场景覆盖,次要接口则侧重核心场景与高频场景,同时将测试用例手册与模拟服务器、实际测试环境进行联动,测试人员可以直接基于手册中的测试用例,在模拟服务器上开展前期的契约验证测试,后端接口开发完成后,再在实际测试环境中执行相同的测试用例,实现测试工作的一致性与连贯性。此外,当API文档的契约发生更新时,测试用例手册会自动同步完成更新,并清晰标注新增、修改、删除的测试用例,让测试人员能够快速聚焦接口的变更点,开展针对性的测试工作,大幅降低测试用例的编写与维护成本,提升集成测试的效率与质量。 以API文档为“单一可信源”驱动全链路自动化的落地实践,并非一蹴而就的技术改造,而是需要在契约标准化、工具链适配、团队协作模式重构等多个层面进行持续的优化与打磨,其中每一个层面的挑战,都需要结合实际开发场景找到贴合需求的解决方案。这一实践过程中,最核心的挑战并非技术层面的工具开发,而是API文档语义描述的准确性与长期的维护成本——如果文档的语义描述存在模糊性、歧义性或完整性缺失,自动化工具生成的SDK、模拟服务器与测试用例手册都会出现相应的偏差,反而会增加开发成本;而如果文档的维护责任未明确界定,接口契约迭代后文档未及时同步更新,API文档就会失去“可信源”的核心价值,进而导致整个全链路自动化体系的崩塌。
本文主要是基于windows平台,基于claude desktop ,让他(自己给自己)写了一个pyhon实现的可获取到本地pc电脑配置的信息,细节之处包括python多环境管理配置、claude config的添加。 mcp的本质是协议层的约定。统一各大ai厂商的底层协议。这篇文章是ai写出了整体的代码,我这里记录下。 注意我以上的文件目录位置为 claude descktop配置文件位置 注意是增加 相关核心代码
1.test_hardware_info.py
#!/usr/bin/env python3
"""
硬件信息 MCP Server
提供读取电脑硬件配置信息的工具
"""
from mcp.server import Server
from mcp.types import Tool, TextContent
import mcp.server.stdio
import platform
import psutil
import socket
from datetime import datetime
import json
# 创建 MCP server 实例
server = Server("hardware-info-server")
def get_cpu_info() -> dict:
"""获取CPU信息"""
cpu_freq = psutil.cpu_freq()
return {
"处理器": platform.processor(),
"架构": platform.machine(),
"物理核心数": psutil.cpu_count(logical=False),
"逻辑核心数": psutil.cpu_count(logical=True),
"当前频率_MHz": round(cpu_freq.current, 2) if cpu_freq else "N/A",
"最大频率_MHz": round(cpu_freq.max, 2) if cpu_freq else "N/A",
"最小频率_MHz": round(cpu_freq.min, 2) if cpu_freq else "N/A",
"CPU使用率_%": psutil.cpu_percent(interval=1, percpu=False)
}
def get_memory_info() -> dict:
"""获取内存信息"""
mem = psutil.virtual_memory()
swap = psutil.swap_memory()
def bytes_to_gb(bytes_value):
return round(bytes_value / (1024**3), 2)
return {
"物理内存": {
"总量_GB": bytes_to_gb(mem.total),
"已用_GB": bytes_to_gb(mem.used),
"可用_GB": bytes_to_gb(mem.available),
"使用率_%": mem.percent
},
"交换内存": {
"总量_GB": bytes_to_gb(swap.total),
"已用_GB": bytes_to_gb(swap.used),
"空闲_GB": bytes_to_gb(swap.free),
"使用率_%": swap.percent
}
}
def get_disk_info() -> dict:
"""获取磁盘信息"""
partitions = psutil.disk_partitions()
disk_info = {}
def bytes_to_gb(bytes_value):
return round(bytes_value / (1024**3), 2)
for partition in partitions:
try:
usage = psutil.disk_usage(partition.mountpoint)
disk_info[partition.device] = {
"挂载点": partition.mountpoint,
"文件系统": partition.fstype,
"总容量_GB": bytes_to_gb(usage.total),
"已用_GB": bytes_to_gb(usage.used),
"空闲_GB": bytes_to_gb(usage.free),
"使用率_%": usage.percent
}
except PermissionError:
disk_info[partition.device] = {
"挂载点": partition.mountpoint,
"状态": "无访问权限"
}
return disk_info
def get_network_info() -> dict:
"""获取网络接口信息"""
net_if_addrs = psutil.net_if_addrs()
net_if_stats = psutil.net_if_stats()
network_info = {}
for interface_name, addresses in net_if_addrs.items():
interface_info = {
"地址列表": [],
"状态": "未知"
}
if interface_name in net_if_stats:
stats = net_if_stats[interface_name]
interface_info["状态"] = "启用" if stats.isup else "禁用"
interface_info["速度_Mbps"] = stats.speed
for addr in addresses:
addr_info = {
"地址族": str(addr.family),
"地址": addr.address
}
if addr.netmask:
addr_info["子网掩码"] = addr.netmask
if addr.broadcast:
addr_info["广播地址"] = addr.broadcast
interface_info["地址列表"].append(addr_info)
network_info[interface_name] = interface_info
return network_info
def get_system_info() -> dict:
"""获取系统基本信息"""
boot_time = datetime.fromtimestamp(psutil.boot_time())
return {
"系统": platform.system(),
"系统版本": platform.version(),
"系统发行版": platform.release(),
"主机名": socket.gethostname(),
"Python版本": platform.python_version(),
"开机时间": boot_time.strftime("%Y-%m-%d %H:%M:%S"),
"运行时长_小时": round((datetime.now() - boot_time).total_seconds() / 3600, 2)
}
def get_gpu_info() -> dict:
"""获取GPU信息"""
try:
import GPUtil
gpus = GPUtil.getGPUs()
if not gpus:
return {"消息": "未检测到GPU或无法访问GPU信息"}
gpu_info = {}
for i, gpu in enumerate(gpus):
gpu_info[f"GPU_{i}"] = {
"名称": gpu.name,
"显存总量_MB": gpu.memoryTotal,
"显存已用_MB": gpu.memoryUsed,
"显存空闲_MB": gpu.memoryFree,
"GPU负载_%": gpu.load * 100,
"温度_C": gpu.temperature
}
return gpu_info
except ImportError:
return {
"消息": "未安装GPUtil库",
"提示": "运行 'pip install gputil' 来获取GPU信息"
}
except Exception as e:
return {
"消息": "无法获取GPU信息",
"错误": str(e)
}
def get_battery_info() -> dict:
"""获取电池信息"""
if not hasattr(psutil, "sensors_battery"):
return {"消息": "当前平台不支持电池信息查询"}
battery = psutil.sensors_battery()
if battery is None:
return {"消息": "未检测到电池(可能是台式机)"}
return {
"电量_%": battery.percent,
"充电中": battery.power_plugged,
"剩余时间_分钟": round(battery.secsleft / 60, 2) if battery.secsleft != psutil.POWER_TIME_UNLIMITED else "充电中或无限"
}
def get_all_hardware_info() -> dict:
"""获取所有硬件信息的汇总"""
return {
"系统信息": get_system_info(),
"CPU信息": get_cpu_info(),
"内存信息": get_memory_info(),
"磁盘信息": get_disk_info(),
"网络信息": get_network_info(),
"GPU信息": get_gpu_info(),
"电池信息": get_battery_info()
}
@server.list_tools()
async def list_tools() -> list[Tool]:
"""列出所有可用工具"""
return [
Tool(
name="get_cpu_info",
description="获取CPU信息,包括核心数、频率、使用率等",
inputSchema={
"type": "object",
"properties": {},
"required": []
}
),
Tool(
name="get_memory_info",
description="获取内存信息,包括物理内存和交换内存的使用情况",
inputSchema={
"type": "object",
"properties": {},
"required": []
}
),
Tool(
name="get_disk_info",
description="获取磁盘信息,包括所有分区的容量和使用情况",
inputSchema={
"type": "object",
"properties": {},
"required": []
}
),
Tool(
name="get_network_info",
description="获取网络接口信息,包括IP地址、MAC地址等",
inputSchema={
"type": "object",
"properties": {},
"required": []
}
),
Tool(
name="get_system_info",
description="获取系统基本信息,包括操作系统、主机名、运行时长等",
inputSchema={
"type": "object",
"properties": {},
"required": []
}
),
Tool(
name="get_gpu_info",
description="获取GPU信息,包括显存、负载、温度等(需要NVIDIA GPU)",
inputSchema={
"type": "object",
"properties": {},
"required": []
}
),
Tool(
name="get_battery_info",
description="获取电池信息,包括电量、充电状态等(仅笔记本)",
inputSchema={
"type": "object",
"properties": {},
"required": []
}
),
Tool(
name="get_all_hardware_info",
description="获取所有硬件信息的完整汇总",
inputSchema={
"type": "object",
"properties": {},
"required": []
}
),
]
@server.call_tool()
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
"""执行工具调用"""
# 工具函数映射
tool_functions = {
"get_cpu_info": get_cpu_info,
"get_memory_info": get_memory_info,
"get_disk_info": get_disk_info,
"get_network_info": get_network_info,
"get_system_info": get_system_info,
"get_gpu_info": get_gpu_info,
"get_battery_info": get_battery_info,
"get_all_hardware_info": get_all_hardware_info,
}
if name not in tool_functions:
raise ValueError(f"未知工具: {name}")
try:
result = tool_functions[name]()
return [
TextContent(
type="text",
text=json.dumps(result, ensure_ascii=False, indent=2)
)
]
except Exception as e:
return [
TextContent(
type="text",
text=json.dumps({"错误": str(e)}, ensure_ascii=False)
)
]
async def main():
"""运行服务器"""
async with mcp.server.stdio.stdio_server() as (read_stream, write_stream):
await server.run(
read_stream,
write_stream,
server.create_initialization_options()
)
if __name__ == "__main__":
import asyncio
asyncio.run(main())
"@ | Out-File -FilePath hardware_info_server.py -Encoding utf82.依赖配置requirements.txt
mcp>=1.0.0
psutil>=5.9.0
gputil>=1.4.0安装步骤
1.创建虚拟环境
python -m venv venv
# 激活虚拟环境
# Windows:
venv\Scripts\activate
# macOS/Linux:
source venv/bin/activate
# 安装依赖
pip install -r requirements.txt2. 配置文件更改
C:\Users\volvo\Downloads
windows为 C:\Users\volvo\AppData\Roaming\Claude,通用配置文件:%APPDATA%\Claude\claude_desktop_config.jsonmcpServers 字段配置{
"mcpServers": {
"hardware-info": {
"command": "C:\\Users\\volvo\\Downloads\\venv\\Scripts\\python.exe",
"args": [
"C:\\Users\\volvo\\Downloads\\hardware_info_server.py"
]
}
},
"preferences": {
"coworkScheduledTasksEnabled": false,
"sidebarMode": "chat"
}
}注意事项
node版本不能太低
(venv) PS C:\Users\volvo\Downloads> nvm list
22.12.0
18.18.2
16.20.2
16.18.0
* 14.15.0 (Currently using 64-bit executable)
(venv) PS C:\Users\volvo\Downloads> nvm use 22.12.0
Now using node v22.12.0 (64-bit)
(venv) PS C:\Users\volvo\Downloads> npx @modelcontextprotocol/inspector python hardware_info_server.py
Need to install the following packages:
@modelcontextprotocol/inspector@0.19.0
Ok to proceed? (y) y
npm warn deprecated node-domexception@1.0.0: Use your platform's native DOMException instead
Starting MCP inspector...
⚙️ Proxy server listening on localhost:6277
🔑 Session token: 6f5e50390c183e0382b034b144bf806ffe2a33caf18e44bcbb0167c3bb6b1ade
Use this token to authenticate requests or set DANGEROUSLY_OMIT_AUTH=true to disable auth
🚀 MCP Inspector is up and running at:
http://localhost:6274/?MCP_PROXY_AUTH_TOKEN=6f5e50390c183e0382b034b144bf806ffe2a33caf18e44bcbb0167c3bb6b1ade
🌐 Opening browser...
New STDIO connection request
Query parameters: {"command":"python","args":"hardware_info_server.py","env":"{\"APPDATA\":\"C:\\\\Users\\\\volvo\\\\AppData\\\\Roaming\",\"HOMEDRIVE\":\"C:\",\"HOMEPATH\":\"\\\\Users\\\\volvo\",\"LOCALAPPDATA\":\"C:\\\\Users\\\\volvo\\\\AppData\\\\Local\",\"PATH\":\"C:\\\\Users\\\\volvo\\\\AppData\\\\Local\\\\npm-cache\\\\_npx\\\\5a9d879542beca3a\\\\node_modules\\\\.bin;C:\\\\Users\\\\volvo\\\\Downloads\\\\node_modules\\\\.bin;C:\\\\Users\\\\volvo\\\\node_modules\\\\.bin;C:\\\\Users\\\\node_modules\\\\.bin;C:\\\\node_modules\\\\.bin;C:\\\\Users\\\\volvo\\\\AppData\\\\Local\\\\nvm\\\\v22.12.0\\\\node_modules\\\\npm\\\\node_modules\\\\@npmcli\\\\run-script\\\\lib\\\\node-gyp-bin;C:\\\\Users\\\\volvo\\\\Downloads\\\\venv\\\\Scripts;D:\\\\go\\\\bin;C:\\\\Python313\\\\Scripts\\\\;C:\\\\Python313\\\\;C:\\\\Program Files\\\\Eclipse Adoptium\\\\jdk-8.0.442.6-hotspot\\\\bin;C:\\\\Program Files\\\\Python310\\\\Scripts\\\\;C:\\\\Program Files\\\\Python310\\\\;C:\\\\Program Files (x86)\\\\Intel\\\\iCLS Client\\\\;C:\\\\Program Files\\\\Intel\\\\iCLS Client\\\\;C:\\\\Windows\\\\system32;C:\\\\Windows;C:\\\\Windows\\\\System32\\\\Wbem;C:\\\\Windows\\\\System32\\\\WindowsPowerShell\\\\v1.0\\\\;C:\\\\Program Files (x86)\\\\Intel\\\\Intel(R) Management Engine Components\\\\DAL;C:\\\\Program Files\\\\Intel\\\\Intel(R) Management Engine Components\\\\DAL;C:\\\\Program Files (x86)\\\\Intel\\\\Intel(R) Management Engine Components\\\\IPT;C:\\\\Program Files\\\\Intel\\\\Intel(R) Management Engine Components\\\\IPT;C:\\\\Program Files (x86)\\\\NVIDIA Corporation\\\\PhysX\\\\Common;C:\\\\Program Files\\\\Intel\\\\WiFi\\\\bin\\\\;C:\\\\Program Files\\\\Common Files\\\\Intel\\\\WirelessCommon\\\\;C:\\\\WINDOWS\\\\system32;C:\\\\WINDOWS;C:\\\\WINDOWS\\\\System32\\\\Wbem;C:\\\\WINDOWS\\\\System32\\\\WindowsPowerShell\\\\v1.0\\\\;C:\\\\WINDOWS\\\\System32\\\\OpenSSH\\\\;C:\\\\Program Files\\\\Git\\\\cmd;C:\\\\Program Files\\\\NVIDIA Corporation\\\\NVIDIA NvDLISR;C:\\\\phpstudy_pro\\\\Extensions\\\\php\\\\php7.3.4nts;C:\\\\Program Files;C:\\\\Program Files (x86)\\\\NetSarang\\\\Xshell 8\\\\;C:\\\\ProgramData\\\\ComposerSetup\\\\bin;D:\\\\softInstall\\\\mcpuvx;c:\\\\Program Files\\\\TraeInternational\\\\bin;C:\\\\Program Files\\\\platform-tools;C:\\\\Users\\\\volvo\\\\AppData\\\\Local\\\\pnpm;C:\\\\Users\\\\volvo\\\\AppData\\\\Local\\\\Microsoft\\\\WindowsApps;C:\\\\Program Files\\\\Go\\\\bin;C:\\\\Users\\\\volvo\\\\AppData\\\\Roaming\\\\nvm;C:\\\\Users\\\\volvo\\\\AppData\\\\Local\\\\Microsoft\\\\WinGet\\\\Links;C:\\\\Users\\\\volvo\\\\AppData\\\\Local\\\\Microsoft\\\\WinGet\\\\Packages\\\\Schniz.fnm_Microsoft.Winget.Source_8wekyb3d8bbwe;C:\\\\Users\\\\volvo\\\\AppData\\\\Roaming\\\\Composer\\\\vendor\\\\bin;C:\\\\Users\\\\volvo\\\\.dotnet\\\\tools;C:\\\\Program Files (x86)\\\\GnuWin32\\\\bin;C:\\\\Users\\\\volvo\\\\Desktop\\\\infoSetUp\\\\soft\\\\1011\\\\platformTool;C:\\\\devENV\\\\apache-maven-3.9.9-bin\\\\apache-maven-3.9.9\\\\bin;C:\\\\Users\\\\volvo\\\\.dotnet\\\\tools;C:\\\\Users\\\\volvo\\\\AppData\\\\Roaming\\\\npm;C:\\\\Users\\\\volvo\\\\AppData\\\\Local\\\\nvm;C:\\\\nvm4w\\\\nodejs;D:\\\\softpath\\\\adbtools\\\\1011\\\\platformTool;C:\\\\Users\\\\volvo\\\\Desktop\\\\beetercall\\\\v1\\\\infoSetUp\\\\adb\\\\1011\\\\platformTool;D:\\\\softInstall\\\\networkCatch\\\\Fiddler\",\"PROCESSOR_ARCHITECTURE\":\"AMD64\",\"SYSTEMDRIVE\":\"C:\",\"SYSTEMROOT\":\"C:\\\\WINDOWS\",\"TEMP\":\"C:\\\\Users\\\\volvo\\\\AppData\\\\Local\\\\Temp\",\"USERNAME\":\"volvo\",\"USERPROFILE\":\"C:\\\\Users\\\\volvo\",\"PROGRAMFILES\":\"C:\\\\Program Files\"}","transportType":"stdio"}
STDIO transport: command=C:\Users\volvo\Downloads\venv\Scripts\python.exe, args=hardware_info_server.py
Created client transport
Created server transport
Received POST message for sessionId 55ac8b56-f912-4243-81d6-ae2c56e5a92d
New STDIO connection request
Query parameters: {"command":"python","args":"hardware_info_server.py","env":"{\"APPDATA\":\"C:\\\\Users\\\\volvo\\\\AppData\\\\Roaming\",\"HOMEDRIVE\":\"C:\",\"HOMEPATH\":\"\\\\Users\\\\volvo\",\"LOCALAPPDATA\":\"C:\\\\Users\\\\volvo\\\\AppData\\\\Local\",\"PATH\":\"C:\\\\Users\\\\volvo\\\\AppData\\\\Local\\\\npm-cache\\\\_npx\\\\5a9d879542beca3a\\\\node_modules\\\\.bin;C:\\\\Users\\\\volvo\\\\Downloads\\\\node_modules\\\\.bin;C:\\\\Users\\\\volvo\\\\node_modules\\\\.bin;C:\\\\Users\\\\node_modules\\\\.bin;C:\\\\node_modules\\\\.bin;C:\\\\Users\\\\volvo\\\\AppData\\\\Local\\\\nvm\\\\v22.12.0\\\\node_modules\\\\npm\\\\node_modules\\\\@npmcli\\\\run-script\\\\lib\\\\node-gyp-bin;C:\\\\Users\\\\volvo\\\\Downloads\\\\venv\\\\Scripts;D:\\\\go\\\\bin;C:\\\\Python313\\\\Scripts\\\\;C:\\\\Python313\\\\;C:\\\\Program Files\\\\Eclipse Adoptium\\\\jdk-8.0.442.6-hotspot\\\\bin;C:\\\\Program Files\\\\Python310\\\\Scripts\\\\;C:\\\\Program Files\\\\Python310\\\\;C:\\\\Program Files (x86)\\\\Intel\\\\iCLS Client\\\\;C:\\\\Program Files\\\\Intel\\\\iCLS Client\\\\;C:\\\\Windows\\\\system32;C:\\\\Windows;C:\\\\Windows\\\\System32\\\\Wbem;C:\\\\Windows\\\\System32\\\\WindowsPowerShell\\\\v1.0\\\\;C:\\\\Program Files (x86)\\\\Intel\\\\Intel(R) Management Engine Components\\\\DAL;C:\\\\Program Files\\\\Intel\\\\Intel(R) Management Engine Components\\\\DAL;C:\\\\Program Files (x86)\\\\Intel\\\\Intel(R) Management Engine Components\\\\IPT;C:\\\\Program Files\\\\Intel\\\\Intel(R) Management Engine Components\\\\IPT;C:\\\\Program Files (x86)\\\\NVIDIA Corporation\\\\PhysX\\\\Common;C:\\\\Program Files\\\\Intel\\\\WiFi\\\\bin\\\\;C:\\\\Program Files\\\\Common Files\\\\Intel\\\\WirelessCommon\\\\;C:\\\\WINDOWS\\\\system32;C:\\\\WINDOWS;C:\\\\WINDOWS\\\\System32\\\\Wbem;C:\\\\WINDOWS\\\\System32\\\\WindowsPowerShell\\\\v1.0\\\\;C:\\\\WINDOWS\\\\System32\\\\OpenSSH\\\\;C:\\\\Program Files\\\\Git\\\\cmd;C:\\\\Program Files\\\\NVIDIA Corporation\\\\NVIDIA NvDLISR;C:\\\\phpstudy_pro\\\\Extensions\\\\php\\\\php7.3.4nts;C:\\\\Program Files;C:\\\\Program Files (x86)\\\\NetSarang\\\\Xshell 8\\\\;C:\\\\ProgramData\\\\ComposerSetup\\\\bin;D:\\\\softInstall\\\\mcpuvx;c:\\\\Program Files\\\\TraeInternational\\\\bin;C:\\\\Program Files\\\\platform-tools;C:\\\\Users\\\\volvo\\\\AppData\\\\Local\\\\pnpm;C:\\\\Users\\\\volvo\\\\AppData\\\\Local\\\\Microsoft\\\\WindowsApps;C:\\\\Program Files\\\\Go\\\\bin;C:\\\\Users\\\\volvo\\\\AppData\\\\Roaming\\\\nvm;C:\\\\Users\\\\volvo\\\\AppData\\\\Local\\\\Microsoft\\\\WinGet\\\\Links;C:\\\\Users\\\\volvo\\\\AppData\\\\Local\\\\Microsoft\\\\WinGet\\\\Packages\\\\Schniz.fnm_Microsoft.Winget.Source_8wekyb3d8bbwe;C:\\\\Users\\\\volvo\\\\AppData\\\\Roaming\\\\Composer\\\\vendor\\\\bin;C:\\\\Users\\\\volvo\\\\.dotnet\\\\tools;C:\\\\Program Files (x86)\\\\GnuWin32\\\\bin;C:\\\\Users\\\\volvo\\\\Desktop\\\\infoSetUp\\\\soft\\\\1011\\\\platformTool;C:\\\\devENV\\\\apache-maven-3.9.9-bin\\\\apache-maven-3.9.9\\\\bin;C:\\\\Users\\\\volvo\\\\.dotnet\\\\tools;C:\\\\Users\\\\volvo\\\\AppData\\\\Roaming\\\\npm;C:\\\\Users\\\\volvo\\\\AppData\\\\Local\\\\nvm;C:\\\\nvm4w\\\\nodejs;D:\\\\softpath\\\\adbtools\\\\1011\\\\platformTool;C:\\\\Users\\\\volvo\\\\Desktop\\\\beetercall\\\\v1\\\\infoSetUp\\\\adb\\\\1011\\\\platformTool;D:\\\\softInstall\\\\networkCatch\\\\Fiddler\",\"PROCESSOR_ARCHITECTURE\":\"AMD64\",\"SYSTEMDRIVE\":\"C:\",\"SYSTEMROOT\":\"C:\\\\WINDOWS\",\"TEMP\":\"C:\\\\Users\\\\volvo\\\\AppData\\\\Local\\\\Temp\",\"USERNAME\":\"volvo\",\"USERPROFILE\":\"C:\\\\Users\\\\volvo\",\"PROGRAMFILES\":\"C:\\\\Program Files\"}","transportType":"stdio"}
STDIO transport: command=C:\Users\volvo\Downloads\venv\Scripts\python.exe, args=hardware_info_server.py
Created client transport
Created server transport
Received POST message for sessionId 6e8c342f-e65d-4c83-bf7f-e1da6c8afc76
Received POST message for sessionId 55ac8b56-f912-4243-81d6-ae2c56e5a92d
Received POST message for sessionId 6e8c342f-e65d-4c83-bf7f-e1da6c8afc76
Received POST message for sessionId 6e8c342f-e65d-4c83-bf7f-e1da6c8afc76
Received POST message for sessionId 6e8c342f-e65d-4c83-bf7f-e1da6c8afc76
Received POST message for sessionId 6e8c342f-e65d-4c83-bf7f-e1da6c8afc76
Starting MCP inspector...
⚙️ Proxy server listening on localhost:6277
🔑 Session token: 72a7e06967c2e25056a4e58a3743d6eee509eacbbb6754744a74142f999c0d90
Use this token to authenticate requests or set DANGEROUSLY_OMIT_AUTH=true to disable auth
🚀 MCP Inspector is up and running at:
http://localhost:6274/?MCP_PROXY_AUTH_TOKEN=72a7e06967c2e25056a4e58a3743d6eee509eacbbb6754744a74142f999c0d90
🌐 Opening browser...本地会有一个mcp inspector

相关文档
相关配置图片
配置好claude的config.json后就可以看到这个mcp

然后就可以让agent调用ai,让ai发命令去读取基于mcp 实现的tool,需要授权

可以看到调用成功了

必须是在 IPFS 上的音乐。127.0.0.1:5001 API 需要打开
https://k51qzi5uqu5dkf2cme54lajnbp178zt690qggilw5pl6md5j3jewkmy32libra.ipns.gateway.v2ex.pro/
VITE-SHADCN 是一个基于 仓库地址:https://github.com/yluiop123/vite-shadcn 项目访问地址:https://yluiop123.github.io/vite-shadcn 我将为您更新表格,添加说明列: 项目默认使用 以下是常用的环境变量配置及其说明: 路由配置包含四个核心参数: 2.国家化文件中配置title中的key 3.增加页面 src\pages\component\general\index.tsx 注意必须在index.tsx下。 4.mock权限增加 下面这段模拟的是获取当前用户权限,需要在这段代码里增加新增菜单的权限。 对应的function 是getPermissionList 后端返回的权限字段 前端权限字段 项目使用 MSW 模拟数据,msw的引入代码如下 mock数据的入口在如下文件,如果要新增mock的话,参照如下代码新增一个handlers就行了 用户权限从userInfo中获取 系统权限管理包含以下概念: 系统支持多角色管理模式。当用户选择"全部角色"时,系统将整合用户权限与所有角色权限的并集作为当前权限集,实现灵活的权限控制策略。 1.新增主题色在src\themes下 2.新增主题色后,需要导入 下面可以配置主题色,Color的字符串颜色和src\themes中的一致vite-shadcn
Shadcn , Vite , React,Zustand,React-Router 等构建的项目 。已经参照ant-design扩展组件扩展了shadcn大量shadcn缺少的组件。并且实现了各种大屏以及可视化方案。



快速开始
1)环境
2)技术栈
3)安装启动
# 克隆项目
git clone https://github.com/yluiop123/vite-shadcn.git
cd <项目目录>
# 安装依赖
pnpm install
# 本地开发启动
pnpm dev
#项目启动后访问 http://localhost:3000/ 4)命令行
命令 描述 说明 dev vite 启动开发服务器,支持热重载和实时编译 build tsc -b && vite build 构建生产版本,先进行 TypeScript 类型检查,再打包项目 build:github tsc -b && vite build --mode github 构建 GitHub 部署版本,使用特定的构建配置 lint eslint . 运行 ESLint 检查代码质量,识别潜在问题 preview vite preview 预览生产构建的项目,用于本地测试构建结果 preview:github vite preview --mode github 预览 GitHub 部署版本的构建结果 analyze cross-env ANALYZE=true vite build 分析打包结果,生成 bundle 分析报告 5)环境变量
.env 文件作为环境变量配置。当通过 --mode 参数指定特定模式时,Vite 会自动加载对应的环境变量文件。例如,build:github 命令会加载 .env.github 文件中的配置。VITE_BASE=/ # 项目部署的相对路径,用于指定应用的基础 URL
VITE_ROUTE=browserRouter # 路由类型,决定应用使用的路由策略
VITE_MOCK_ENABLE=true # 是否启用 Mock 数据服务,用于开发和测试
VITE_BASE_API=/api/ # API 请求的统一前缀,用于后端接口调用
VITE_CESIUM_TOKEN=### # Cesium 地图服务的认证令牌
目录结构
vite-shadcn
├── .github/ # GitHub 配置文件
│ ├── workflows/
│ │ └── main.yml # CI/CD 工作流配置
│ ├── copilot-instructions.md # Copilot 指令
├── .trae/ # Trae IDE 规则
│ └── rules/
├── public/ # 静态资源目录
├── src/ # 源代码目录
│ ├── assets/ # 静态资源
│ ├── components/ # 通用组件
│ │ ├── ext/ # 扩展组件
│ │ ├── ui/ # Shadcn UI 基础组件
│ │ ├── app-sidebar.tsx # 应用侧边栏
│ │ ├── chart-area-interactive.tsx # 交互式面积图
│ │ ├── color-switcher.tsx # 颜色切换器
│ │ ├── dialog-form.tsx # 表单对话框
│ │ ├── group-tree-select.tsx # 分组树选择器
│ │ ├── nav-main.tsx # 主导航
│ │ ├── nav-user.tsx # 用户导航
│ │ ├── permission-tree-select.tsx # 权限树选择器
│ │ ├── permission-tree-single-select.tsx # 权限单选树
│ │ ├── permission-type.tsx # 权限类型
│ │ ├── role-select.tsx # 角色选择器
│ │ ├── section-cards.tsx # 区域卡片
│ │ ├── sidebar-menutree.tsx # 侧边栏菜单树
│ │ ├── site-header.tsx # 站点头部
│ │ └── ... # 更多组件
│ ├── hooks/ # React Hooks
│ │ └── use-mobile.ts # 移动端检测 Hook
│ ├── lib/ # 工具库
│ │ ├── axios.ts # Axios 配置
│ │ ├── dict.ts # 字典工具
│ │ ├── fixLeafletIcon.ts # Leaflet 图标修复
│ │ ├── notify.ts # 通知工具
│ │ └── utils.ts # 通用工具函数
│ ├── locale/ # 国际化
│ │ ├── en-US.ts # 英文翻译
│ │ └── zh-CN.ts # 中文翻译
│ ├── mock/ # Mock 数据
│ ├── pages/ # 页面组件
│ │ ├── chart/ # 图表页面
│ │ ├── component/ # 组件示例页面
│ │ ├── dashboard/ # 仪表板页面
│ │ ├── system/ # 系统管理页面
│ ├── store/ # 状态管理
│ ├── themes/ # 主题色文件
│ ├── App.tsx # 应用根组件
│ ├── index.css # 全局样式
│ ├── layout.tsx # 应用布局
│ └── main.tsx # 应用入口
├── .env # 环境变量
├── .env.github # GitHub 环境变量
├── .gitignore # Git 忽略文件
├── .hintrc # Webhint 配置
├── CODE_OF_CONDUCT.md # 行为准则
├── LICENSE # 许可证
├── components.json # 组件配置
└── package.json # 项目配置
路由与菜单
路由示例(React Router v7):
//src\routes.ts
const routeSetting: NavItem[] = [
{
key: "dashboard",
title: "menu.dashboard",
icon: LayoutDashboard,
children: [
{ key: "normal", title: "menu.dashboard.normal", icon: Gauge },
],
},
];如下,是其中一个页面的配置示例:
//src\routes.ts
const routeSetting: NavItem[] = [
{
key: "dashboard",
title: "menu.dashboard",
icon: LayoutDashboard,
children: [
{ key: "normal", title: "menu.dashboard.normal", icon: Gauge },
],
},
];//src\locale\en-US.ts
export default {
'menu.dashboard': 'Dashboard',
'menu.dashboard.normal': 'Normal',
};//src\locale\zh-CN.ts
export default {
'menu.dashboard': '仪表盘',
'menu.dashboard.normal': '普通仪表盘',
};//src\mock\system\permission.ts
http.get<{ id: string }>(
"/api/system/permissions/detail/:id",//src\mock\system\permission.ts
function getPermissionList(locale: string) {
const dataArray: Permission[] = [
//supper menu permissions
{id: '0000', parentId:'',order: 0, path: "/dashboard",type: "directory",name:localeMap[locale]['menu.dashboard'] },
{id: '0001', parentId:'',order: 1, path: "/component", type: "menu",name:localeMap[locale]['menu.component'] },
{id: '000100', parentId:'0001',order: 0, path: "/component/general", type: "menu",name:localeMap[locale]['menu.component.general'] },component/general 页面对应的权限标识为 id: '000100',其中 type 字段表示权限类型://src\mock\components\permission.ts
type Permission = {
name: string//权限名称,用于显示在菜单或权限列表中
id: string//权限ID,用于唯一标识权限
path: string//权限路径,用于标识具体的资源或操作
type: string//权限类型,指示权限的具体作用(如目录:directory、菜单:menu、操作:action、功能:function、接口:api)
action?: string//type=action时才会有,操作名称,进一步细化权限的具体操作(如读取、写入、执行等)
status?: "0" | "1"//权限状态,0表示禁用,1表示启用
create?: string,//创建时间,记录权限创建的时间
parentId?: string//父权限ID,用于构建权限树结构
order: number//排序顺序,用于在菜单或权限列表中排序显示,后端自动生成
}//src\store\user.ts
type Permission = {
path: string;//权限路径,用于标识具体的资源或操作
role: string;//角色名称,指定该权限所属的角色
type: string;
//权限类型,指示权限的具体作用(如目录:directory、菜单:menu、操作:action、功能:function、接口:api)
/**
* 权限类型,指示权限的具体作用(如目录:directory、菜单:menu、操作:action、功能:function、接口:api)
* - directory: 目录权限,包含该目录下所有子菜单的访问权限
* - menu: 菜单项权限,仅控制当前菜单项的访问权限
* - action: 表示菜单下的具体动作(如读取、写入、执行等)
* - function: 功能权限,用于执行特定的系统功能
* - api: 接口权限,用于访问后端提供的API接口
*/
action: string;//操作名称,进一步细化权限的具体操作(如读取、写入、执行等)
};国际化
配置示例(react-intl):
//src\locale\en-US.ts
export default {
'menu.dashboard': 'Dashboard',
};//src\locale\zh-CN.ts
export default {
'menu.dashboard': '仪表盘',
};页面使用示例:
import { useIntl } from "react-intl";
const { formatMessage } = useIntl();
<div>{formatMessage({ id: "menu.dashboard", defaultMessage: "Dashboard" })}</div>模拟数据
//src\main.tsx
const mockEnable = (import.meta.env.VITE_MOCK_ENABLE||'true')=='true';
if(mockEnable){
initMSW().then(()=>{
createRootElement();
})
}else{
createRootElement();
}//src\mock\index.ts
import { setupWorker } from "msw/browser";
import groupHandlers from "./components/group";
import permissionHandlers from "./components/permission";
import loginUserHandlers from "./login/user";
import systemGroupHandlers from "./system/group";
import systemPermissionHandlers from "./system/permission";
import systemRoleHandlers from "./system/role";
import systemUserHandlers from "./system/user";
const mockHandlers = [
...loginUserHandlers,
...groupHandlers,
...permissionHandlers,
...systemUserHandlers,
...systemRoleHandlers,
...systemGroupHandlers,
...systemPermissionHandlers
];
let worker: ReturnType<typeof setupWorker> | null = null;
export default async function initMSW() {
if (worker) return worker;
worker = setupWorker(...mockHandlers);
// 启动 MSW
await worker.start({
serviceWorker: {
url: `${import.meta.env.BASE_URL}mockServiceWorker.js`,
options: { type: 'module', updateViaCache: 'none' },
},
onUnhandledRequest: (req) => {
if (!req.url.startsWith('/api')) {
return // 直接跳过,不拦截
}
},
});
return worker;
}权限控制
import { useUserStore } from '@/store';
const { userInfo} = useUserStore();主题
//src\index.css
@import "@/themes/blue.css";
@import "@/themes/green.css";
@import "@/themes/orange.css";
@import "@/themes/red.css";
@import "@/themes/rose.css";
@import "@/themes/violet.css";
@import "@/themes/yellow.css";//src\store\theme.ts
export type Color =
| "default"
| "blue"
| "green"
| "orange"
| "red"
| "rose"
| "violet"
| "yellow";import {useThemeStore } from '@/store/index';
const {color,setColor} = useThemeStore();
setColor('blue')
写在前面,本人目前处于求职中,如有合适内推岗位,请加:lpshiyue 感谢。 在掌握了Hadoop三大核心组件的基础原理后,我们面临一个更加实际的问题:如何在这个分布式基础架构上构建高效、易用的数据仓库体系?Hive作为Hadoop生态中最早出现的数据仓库工具,通过SQL化接口将MapReduce的复杂性封装起来,使得传统数据人员也能利用大数据平台进行数据分析。本文将深入探讨Hive在离线数据仓库中的分层建模方法论、分区与分桶的技术取舍,以及优化查询代价的实战策略。 Hive诞生于Facebook的数据困境时代,当时该公司每天需要处理超过10TB的新增数据,直接使用MapReduce开发分析任务效率极低。Hive的创新在于将SQL接口与Hadoop分布式计算相结合,使得数据分析师能够使用熟悉的SQL语言进行大数据分析。 Hive的核心设计哲学是"一次学习,处处编写",它通过将SQL查询转换为MapReduce任务(现在也支持Tez、Spark等引擎),在保持易用性的同时继承了Hadoop的扩展性和容错性。值得注意的是,Hive并非关系型数据库,其读时模式设计与传统数据库的写时模式有本质区别,这决定了它在数据仓库场景而非事务处理场景的适用性。 离线数据仓库的核心价值在于将原始操作数据转化为分析就绪数据,为企业决策提供统一、一致的数据视图。据行业统计,优秀的分层数据仓库设计能将数据团队的分析效率提升40%以上,同时降低30%的数据计算成本。 离线处理的特征决定了其适合以下场景: 数据仓库分层的本质是复杂性问题分解,通过将数据处理流程拆分为多个专注的层次,降低整体系统的复杂度。标准的分层架构包括ODS、DWD、DWS和ADS四层,每层有明确的职责边界。 数据仓库分层表示例 不同业务场景需要差异化的分层策略,一刀切的分层设计往往导致过度工程或支持能力不足。 电商交易型数仓需要强调数据一致性和事务准确性,适合采用维度建模中的星型模型,围绕订单、用户等核心实体构建宽表。 日志分析型数仓通常数据量极大但更新较少,适合采用流水线模型,注重数据压缩率和查询性能,可适当合并DWD和DWS层。 混合业务数仓需要平衡灵活性和性能,采用星座模型,多个事实表共享维度表,既保持扩展性又避免过度冗余。 分层架构的成功依赖数据可追溯性和质量保障机制。完善的血缘关系追踪能快速定位数据问题影响范围,而分层质量检查点确保异常数据不会污染下游。 质量检查策略应当在每个层级间建立: 某大型电商通过建立分层数据质量体系,将数据问题发现时间从平准4小时缩短到30分钟以内,数据信任度显著提升。 分区本质上是粗粒度索引,通过将数据按特定维度(通常是时间)组织到不同目录中,使查询能快速跳过无关数据。Hive分区对应HDFS的目录结构,当查询条件包含分区字段时,Hive只需扫描相关分区,大幅减少IO量。 分区策略的选择需要平衡查询效率和管理成本: 分区表创建与数据插入 分区粒度的选择是查询效率与元数据压力的权衡。分区过细会导致小文件问题,NameNode压力增大;分区过粗则无法有效剪裁数据。 分区粒度参考标准: 实践表明,按日期分区是最通用有效的策略,结合业务特点可增加第二级分区(如业务类型、地区等)。某大型互联网公司的日志表按天分区后,查询性能提升5-8倍,而管理成本增加有限。 分区表需要定期维护以保证性能,包括过期数据清理、分区统计信息收集、小文件合并等。 分区维护脚本示例: 分区表维护操作 分区优化策略还包括分区裁剪(避免全表扫描)、动态分区(简化数据加载)和分区索引(加速点查询)等。 分桶是通过哈希散列将数据均匀分布到多个文件中的技术,它为Hive提供了细粒度数据组织能力。与分区的目录级隔离不同,分桶是文件级别的数据分布,适合在分区内进一步优化。 分桶的核心价值体现在: 分桶表创建与优化连接 分桶数量的选择需要综合考虑数据量、查询模式和集群资源。过多的分桶会产生小文件问题,过少则无法发挥并行优势。 分桶数决策公式(经验法则): 其中块大小通常为128MB-256MB,分桶数最好是2的幂次方,便于哈希分布。 某电商用户画像表通过合理分桶(256个桶),JOIN查询性能提升3倍,同时避免了小文件问题。 分区和分桶不是互斥技术,而是协同工作的关系。常见模式是先分区后分桶,在时间分区内再按业务键分桶。 协同设计示例: 分区与分桶协同设计 设计原则: 每种数据组织技术都带来不同的存储开销和管理成本: 分层存储代价: 分区存储代价: 分桶存储代价: 不同的数据组织方式对查询性能有显著影响,需要根据查询模式进行针对性优化。 点查询性能(=条件): 范围查询性能(BETWEEN条件): JOIN查询性能: 实际系统中,通常采用组合策略,如先按时间分区,再按JOIN键分桶,在分区内利用分桶优化连接操作。 理解Hive查询执行计划是优化的基础,通过EXPLAIN命令可查看查询的完整执行流程。 执行计划关键元素: 执行计划分析示例 数据倾斜是Hive性能的"头号杀手",表现为个别Reduce任务处理数据量远大于其他任务。 倾斜检测与处理: 数据倾斜检测与处理 常见倾斜处理策略: 合理的资源参数配置能显著提升查询性能,主要从内存管理和并行度控制两方面入手。 内存优化参数: 内存参数优化 并行度控制参数: 并行度优化参数 Hive不再局限于MapReduce,支持Tez和Spark等现代执行引擎,显著提升性能。 执行引擎对比: 执行引擎配置 列式存储(ORC/Parquet)结合高效压缩(Snappy/Zlib)是现代数仓的标准配置。 ORC格式优势: ORC格式优化 完善的数据治理体系确保数仓的长期健康度,包括元数据管理、数据质量、血缘追踪和生命周期管理。 生命周期管理策略: 某金融企业通过完善的生命周期管理,在数据量年增长200%的情况下,存储成本仅增加30%。 Hive离线数据仓库的建设是一个系统性工程,需要平衡架构规范、技术选型和性能优化。优秀的数据仓库不是技术的堆砌,而是与业务深度结合的有机体系。 核心设计原则: 未来演进方向: 随着数据技术的不断发展,Hive在云原生、实时计算等场景下面临新的挑战和机遇,但其作为大数据入口的历史地位和分层建模的思想精华仍将持续影响数据仓库的发展方向。 📚 下篇预告 点击关注,解锁Spark高性能计算的秘密! 今日行动建议:优秀的离线数据仓库不是数据的简单堆积,而是分层架构、分区策略与分桶技术精密平衡的艺术品
1 Hive的定位与离线数仓的核心价值
1.1 从MapReduce到Hive的技术演进
1.2 离线数仓的架构价值
2 数据分层建模:离线数仓的架构基石
2.1 分层架构的设计哲学
-- ODS层表示例:保持原始数据格式
CREATE TABLE ods_user_behavior (
user_id BIGINT,
action STRING,
log_time STRING
) PARTITIONED BY (dt STRING) STORED AS ORC;
-- DWD层表示例:数据清洗和标准化
CREATE TABLE dwd_user_behavior (
user_id BIGINT,
action STRING,
log_time TIMESTAMP,
normalized_action STRING
) PARTITIONED BY (dt STRING) STORED AS ORC;
-- DWS层表示例:轻度聚合
CREATE TABLE dws_user_daily_behavior (
user_id BIGINT,
dt STRING,
pv_count BIGINT,
unique_actions BIGINT
) STORED AS ORC;
-- ADS层表示例:应用就绪数据
CREATE TABLE ads_user_retention_monthly (
dt STRING,
month_active_users BIGINT,
retained_users BIGINT,
retention_rate DECIMAL(10,4)
) STORED AS ORC;2.2 分层模型的业务适配策略
2.3 数据血缘与质量保障
3 分区策略:数据检索的加速器
3.1 分区的本质与适用场景
-- 按日期单级分区(最常见)
CREATE TABLE logs (
log_id BIGINT,
user_id BIGINT,
action STRING
) PARTITIONED BY (dt STRING); -- 格式:yyyy-MM-dd
-- 多级分区(日期+类型)
CREATE TABLE logs (
log_id BIGINT,
user_id BIGINT
) PARTITIONED BY (dt STRING, action STRING);
-- 动态分区插入
INSERT INTO TABLE logs PARTITION (dt, action)
SELECT log_id, user_id, action, dt, action
FROM raw_logs;3.2 分区粒度的权衡艺术
3.3 分区维护与优化策略
-- 过期分区清理(保留最近90天)
ALTER TABLE logs DROP PARTITION (dt < '20230101');
-- 收集分区统计信息(优化查询计划)
ANALYZE TABLE logs PARTITION (dt) COMPUTE STATISTICS;
-- 分区修复(元数据与实际数据同步)
MSCK REPAIR TABLE logs;4 分桶技术:数据分布的精细控制
4.1 分桶的原理与价值
-- 分桶表示例
CREATE TABLE user_behavior_bucketed (
user_id BIGINT,
action STRING,
log_time TIMESTAMP
) CLUSTERED BY (user_id) INTO 32 BUCKETS
STORED AS ORC;
-- 分桶表连接优化
SET hive.optimize.bucketmapjoin=true;
SET hive.input.format=org.apache.hadoop.hive.ql.io.BucketizedHiveInputFormat;
SELECT /*+ MAPJOIN(b) */ a.user_id, a.action, b.user_name
FROM user_behavior_bucketed a JOIN user_info_bucketed b
ON a.user_id = b.user_id;4.2 分桶数决策模型
分桶数 ≈ 数据总量 / (块大小 * 2)4.3 分桶与分区的协同设计
-- 分区+分桶协同设计
CREATE TABLE user_behavior (
user_id BIGINT,
action STRING,
device STRING
) PARTITIONED BY (dt STRING)
CLUSTERED BY (user_id) SORTED BY (log_time) INTO 64 BUCKETS
STORED AS ORC;
-- 这种设计支持高效的多维度查询
SELECT user_id, COUNT(*)
FROM user_behavior
WHERE dt = '20230115' AND user_id IN (1001, 1002, 1003)
GROUP BY user_id;5 分层、分区、分桶的代价权衡
5.1 存储代价分析
5.2 查询性能权衡
6 Hive查询优化实战策略
6.1 执行计划分析与优化
-- 查看执行计划
EXPLAIN
SELECT u.user_id, COUNT(o.order_id) as order_count
FROM dwd_users u JOIN dwd_orders o ON u.user_id = o.user_id
WHERE o.dt = '20230115' AND u.region = 'Beijing'
GROUP BY u.user_id
HAVING order_count > 5;6.2 数据倾斜处理方案
-- 检测倾斜:查看key分布
SELECT user_id, COUNT(*) as cnt
FROM orders WHERE dt = '20230115'
GROUP BY user_id
ORDER BY cnt DESC LIMIT 10;
-- 处理倾斜:随机前缀扩散
SELECT user_id, order_id,
CONCAT(CAST(user_id AS STRING), '_', CAST(rand()*10 AS INT)) as user_prefix
FROM orders WHERE dt = '20230115';set hive.map.aggr=trueset hive.optimize.skewjoin=trueset hive.groupby.skewindata=true6.3 资源参数调优
-- Map内存设置
set mapreduce.map.memory.mb=4096;
set mapreduce.map.java.opts=-Xmx3072m;
-- Reduce内存设置
set mapreduce.reduce.memory.mb=8192;
set mapreduce.reduce.java.opts=-Xmx6144m;
-- 容器内存上限
set yarn.scheduler.maximum-allocation-mb=16384;-- Reduce数量自动推断
set hive.exec.reducers.bytes.per.reducer=256000000; -- 每个Reduce处理256MB
set hive.exec.reducers.max=999; -- 最大Reduce数
-- 并行执行
set hive.exec.parallel=true;
set hive.exec.parallel.thread.number=8; -- 并行线程数7 现代Hive生态的演进与最佳实践
7.1 执行引擎的演进选择
-- 切换执行引擎
SET hive.execution.engine=tez;
-- Tez优化参数
SET tez.am.resource.memory.mb=4096;
SET tez.task.resource.memory.mb=2048;7.2 存储格式与压缩优化
-- 创建ORC表
CREATE TABLE orc_table (
id BIGINT,
name STRING
) STORED AS ORC
TBLPROPERTIES ("orc.compress"="SNAPPY");
-- 启用谓词下推
SET hive.optimize.ppd=true;7.3 数仓治理与数据生命周期
总结
《Spark批处理认知——RDD与DataFrame的差异、Shuffle与资源利用》—— 我们将深入探讨: