这套提示词的核心目的，是把一次性的 agent 编程过程，逐步沉淀成一种近似 harness 编程的项目协作方式。 需要这么做的根本原因是：大模型本身是无状态的。Codex 在一个上下文窗口里可以理解项目、推理链路、排查问题、形成判断；但这个上下文一结束，很多理解就会消失。换一个线程、换一个 agent，甚至隔一段时间重新进入同一个项目，如果没有外部化的项目上下文，就必须重新扫描、重新猜测、重新踩坑。 但它也有明显局限：这还不是完整的自动化 harness。它解决得比较好的是工作环境和上下文持久化，但反馈回路仍然依赖大模型本身执行：输入如何拆解、检查是否充分、问题是否问得对、验证结果如何解释，仍然需要模型消耗推理和上下文成本来完成。也就是说，它把“记忆”和“项目地图”从模型里搬到了仓库里，但还没有完全把判断、测试和反馈自动化。 因此，这套提示词更准确地说，是从 agent 编程走向 harness 编程的中间形态：先让项目具备可被 agent 反复读取、修正和增强的上下文骨架，再逐步把其中稳定的检查、验证和部署步骤自动化。 请为当前项目建立一套面向 Codex / LLM 的项目上下文 Wiki，目标是让新的 agent 在不依赖历史聊天记录的情况下，能够快速理解项目结构、运行方式、关键约束、跨模块关系、常见故障、验证方法，以及当前仍然缺失或需要澄清的信息。 请先读取当前仓库文件结构，再按下面格式创建或更新 Markdown 文档。不要编造未知事实；不确定的信息写成“待确认”，并说明需要用什么命令、文件、人员或外部系统确认。 推荐文件结构： - README.md 作为项目上下文入口，说明： - 项目是什么 - 项目为什么存在 - 当前目标 - 成功标准 - 失败标准 - 主要服务对象或使用者 - 文档目录说明 - 推荐阅读顺序 - AGENTS.md 作为 Codex 的持久入口说明，保持简短，说明： - 先读哪些上下文文件 - 修改代码或配置前必须确认哪些约束 - 如何验证工作完成 - 哪些内容不能写入文档，例如密钥、token、密码、私有凭证 - modules/overview.md 列出系统模块索引。每个模块只描述“自己是什么、负责什么、在哪里运行、如何检查、如何重启、有哪些注意点”。 - modules/<module-name>.md 每个文件描述一个模块，建议包含： - 职责 - 部署位置 - 关键路径 - 配置文件 - 启停命令 - 检查命令 - 日志位置 - 已知问题 - 不属于本模块负责的事情 - relationships/overview.md 或 relationships/access-flow.md 描述跨模块数据流、请求链路、调用关系、依赖关系。重点写清： - 用户请求如何进入系统 - 数据如何流转 - 哪些模块影响哪些能力 - 如何判断问题发生在哪一层 - relationships/service-registry.md 作为权威清单，只维护当前真实状态，不写长篇事故过程。建议用表格记录： - 服务名 - 对外入口 - 内部地址 - 运行位置 - 配置文件 - 启停/检查命令 - 日志位置 - 最近验证时间 - 当前认证或安全状态 - constraints/environment.md 记录稳定环境事实和假设，例如： - 操作系统 - 运行环境 - 网络条件 - 目录约定 - 权限限制 - 不能改变的外部依赖 - 待确认事项 - constraints/operations-runbook.md 写可执行运维手册，包含： - 新增一个服务或模块的步骤 - 修改配置后的最小验证 - 常用构建、测试、部署、回滚命令 - 分层排查流程 - 安全检查项 - issues/issues.md 作为历史问题索引。这里只放问题列表、状态、影响和结论。 - issues/<issue-name>-YYYY-MM-DD.md 每个历史问题单独成文，建议包含： - 现象 - 背景 - 当时的错误假设或误解 - 诊断证据 - 处理过程 - 最终结论 - 当前替代方案 - 对现在的影响 - 后续如何避免 - questions.md 记录 Codex / LLM 在理解项目时发现的缺口、矛盾和待澄清问题。 这是持续迭代项目上下文的入口，不是失败产物。 写作规则： 1. 当前真实状态优先于历史记录。 2. 权威表优先于分散模块说明。 3. issue 只记录历史问题，不维护当前端口、当前服务状态或权威配置。 4. 模块文档只解释模块自身，跨模块链路放到 relationships/。 5. 运维命令必须可复制执行；如果命令依赖环境，写明运行位置。 6. 所有验证都要写“预期结果”，不要只写命令。 7. 不要把密码、API key、token、私钥、cookie、UUID、生产凭证写入 Wiki。 8. 不确定内容标记为“待确认”，不要用猜测填充。 9. 如果发现历史 issue 暴露出稳定规则，把规则同步到 modules/、relationships/ 或 constraints/，不要只留在 issue 里。 10. 文档目标是让新的 Codex agent 能根据文档完成修改、运行检查、定位故障并解释判断依据。 理解与疑问处理规则： 1. 默认项目上下文一定存在缺口。不要为了让文档看起来完整而补全未知事实。 2. 发现以下情况时，必须记录为问题： - 文件存在但用途不明确 - 配置项存在但不知道谁读取 - 服务、脚本、端口、目录、环境变量没有来源说明 - 文档之间存在冲突 - 代码行为和现有文档不一致 - 缺少验证命令 - 缺少运行位置 - 缺少负责人、调用方或依赖方 - 历史问题有结论但没有证据 - 当前状态无法从仓库内确认 3. 问题不要散落在对话里，必须汇总到文档中。 4. 新建或维护 `questions.md`，作为“待澄清问题清单”。 5. 每个问题应包含： - 问题描述 - 相关文件或模块 - 为什么这个问题重要 - 当前已知线索 - 建议确认方式 - 优先级：High / Medium / Low - 状态：Open / Answered / Obsolete 6. 如果某个问题被确认，应把结论同步回对应的 `modules/`、`relationships/`、`constraints/` 或 `issues/` 文档，并把 `questions.md` 中的问题状态改为 `Answered`。 7. 如果问题已经不再 relevant，标记为 `Obsolete`，不要直接删除。 请完成以下任务： 1. 扫描当前项目结构。 2. 判断项目中的主要模块、跨模块关系、环境约束、历史问题和待澄清问题。 3. 创建上述目录和 Markdown 文件。 4. 如果已有类似文档，按这个结构重组，保留有效事实。 5. 不要为了完整性编造内容；缺失、冲突、无法确认的信息统一进入 `questions.md`。 6. 最后输出： - 创建或更新了哪些文件 - 当前已经确认的项目理解 - 当前仍待确认的信息 - 已汇总到 `questions.md` 的问题数量和最高优先级问题 - 建议下一次优先补充的上下文 配套的agent.md # Codex 项目上下文规则 开始处理本项目任务前，优先阅读： 1. `README.md` 2. `modules/overview.md` 3. `relationships/service-registry.md` 或 `relationships/overview.md` 4. `constraints/environment.md` 5. `constraints/operations-runbook.md` 6. `questions.md` 7. 需要排查历史问题时再读 `issues/issues.md` 维护规则： - 当前真实状态写入 `relationships/service-registry.md`。 - 单个模块说明写入 `modules/`。 - 跨模块链路写入 `relationships/`。 - 环境事实和可执行运维命令写入 `constraints/`。 - 历史故障、误解修正和处理过程写入 `issues/`。 - 理解缺口、文档矛盾、无法确认的信息写入 `questions.md`。 - 不写入密码、token、私钥、cookie、生产密钥或其他敏感凭证。 - 不确定的信息标记为“待确认”，并写明确认方式。 - 当 `questions.md` 中的问题被确认后，必须把结论同步回对应上下文文档。
Andrej Karpathy LLM 整理知识系统 LLM 知识库 Andrej Karpathy 最近发现一件非常有用的事情：用大语言模型（LLM）为各种研究主题构建个人知识库。这样一来，最近的大量 token 使用不再主要用于操作代码，而是更多用于处理知识（以 markdown 和图片形式存储）。最新的 LLM 在这方面已经做得相当不错。具体来说： [...]
21 Lessons From 14 Years at Google 转发分享 2026年1月3日 大约 14 年前加入谷歌时，我以为这份工作就是写出优秀的代码。我只对了一部分。随着待的时间越长，我越发意识到：那些茁壮成长的工程师未必是编程技术最好的，而是那些懂得如何驾驭代码之外一切事物的人——包括人、政治、目标对齐以及模糊性。 这些是我希望自己能早点知道的经验教训。有些本来可以帮我省去几个月的挫折，有些则花了我好几年才完全领悟。这里没有关于具体技术的建议——技术变化太快，并不重要。这些经验关于那些在不同项目、不同团队中反复出现的模式。 我分享这些是因为我曾从那些为我指路的前辈工程师那里受益良多。就把这当作我的一次薪火相传吧。 1. 最优秀的工程师痴迷于解决用户问题。 爱上一项技术并到处寻找它的应用场景，这种做法很诱人。我干过，大家都干过。但那些创造最大价值的工程师是逆向工作的：他们痴迷于深度理解用户的问题，让解决方案从这种理解中自然浮现。 “用户痴迷”意味着花时间处理客服工单，与用户交谈，观察用户在使用中的挣扎，不断追问“为什么”，直到触及问题的本质。真正理解问题的工程师往往会发现，优雅的解决方案比任何人预期的都要简单。 而那些从解决方案出发的工程师，往往为了证明方案的合理性而制造复杂性。 2. 单纯的“正确”很廉价，共同达成“正确”才是真本事。 你可能赢了每一次技术争论，却输掉了整个项目。我见过才华横溢的工程师因为总是做房间里最聪明的人而招致沉默的怨恨。这种代价日后会以“神秘的执行问题”和“奇怪的阻力”显现出来。 关键技能不在于你是对的，而在于进入讨论以对齐问题，给他人留出空间，并对自己确信的事情保持怀疑。 观点鲜明，但心态开放（Strong opinions, weakly held）——这并非因为你缺乏信念，而是因为在不确定性下做出的决策不应与个人身份绑定。 3. 行动至上。发布产品。你可以修改糟糕的页面，但无法修改空白的页面。 追求完美会导致瘫痪。我见过工程师花了数周时间争论他们从未构建过的东西的理想架构。完美的解决方案很少来自纯粹的思考——它来自与现实的碰撞。人工智能在很多方面对此都有帮助。 先做出来，再做对，最后做更好。把丑陋的原型放到用户面前。写下设计文档那凌乱的初稿。发布那个让你感到有点尴尬的 MVP（最小可行性产品）。你从一周的真实反馈中学到的东西，比一个月的理论辩论还要多。 动能创造清晰度。分析瘫痪一无所获。 4. 清晰度代表资历。炫技是累赘。 写出“聪明”代码的本能在工程师中几乎是普遍存在的。这感觉像是能力的证明。 但软件工程是当你加上“时间”和“其他程序员”这两个变量后发生的事情。在那种环境下，清晰不是一种风格偏好——它是降低运维风险的手段。 你的代码是写给那些在凌晨 2 点故障期间维护它的陌生人的战略备忘录。请优化他们的理解成本，而不是你的优雅程度。我最尊敬的资深工程师都学会了永远用清晰去交换炫技。 5. 新奇技术是一笔贷款，你将用故障、招聘难度和认知负担来偿还。 把你对技术的选择看作是一个只有少量“创新筹码”预算的组织。每当你采用某种非标准技术时，就花掉一个筹码。你负担不起太多。 重点不是“永远不要创新”，而是“只在你能获得独特回报的地方创新”。其他一切都应默认为无聊的技术，因为无聊的技术有已知的故障模式。 “最适合工作的工具”往往是“在许多工作中表现最不坏的工具”——因为维护一个像动物园样复杂的环境才是真正的重税。 6. 代码不会为你代言，人会。 在职业生涯早期，我相信优秀的作品会为自己说话。我错了。代码只是静静地躺在仓库里。你的经理要在会议上提及你，或者不提及。同事会推荐你参与项目，或者推荐别人。 在大型组织中，决策是在你没被邀请的会议上做出的，使用的是你没写的摘要，由那些只有五分钟时间和十二个优先事项的人决定的。如果当你不在场时没有人能阐述你的影响力，那么你的影响力实际上就是可有可无的。 这不仅是关于自我推销。这是为了让价值链对每个人——包括你自己——都清晰可见。 7. 最好的代码是你没写的代码。 我们在工程文化中推崇创造。没人会因为删代码而升职，尽管删除往往比增加更能改善系统。你没写的每一行代码，都是你永远不需要调试、维护或解释的一行。 在构建之前，先穷尽这个问题：“私如果我们干脆……不做会怎样？”有时答案是“没什么坏处”，那就是你的解决方案。 问题不在于工程师不会写代码或不会用 AI 写代码。问题在于我们太擅长写代码，以至于忘记了问自己是否应该写。 8. 规模化之后，即便是你的 Bug 也有用户依赖。 当用户足够多时，每一个可观察到的行为都会变成依赖项——不管你是怎么承诺的。有人在抓取你的 API，自动化你的怪癖，缓存你的 Bug。 这产生了一个职业层面的洞察：你不能把兼容性工作视为“维护”，而把新功能视为“真正的工作”。兼容性就是产品。 把你对旧功能的弃用设计成带有时间缓冲、工具支持和同理心的迁移过程。大多数“API 设计”实际上是“API 退休设计”。 9. 大多数“慢”团队其实是目标未对齐的团队。 当项目拖延时，本能反应是责怪执行力：大家工作不够努力，技术选型错了，工程师不够。通常这些都不是真正的问题。 在大公司里，团队是并发单元，但随着团队数量的增加，协调成本呈几何级数增长。大多数缓慢实际上是对齐失败——大家在做错误的事情，或者用不兼容的方式做正确的事情。 资深工程师花更多时间在澄清方向、接口和优先级上，而不是“更快地写代码”，因为那才是真正的瓶颈所在。 10. 关注你能控制的，忽略你不能控制的。 在大公司里，无数变量都在你的控制之外——组织变革、管理层决策、市场转变、产品转型。纠结于这些只会产生焦虑，却无法采取行动。 那些保持理智和高效的工程师专注于他们的影响圈。你无法控制重组是否发生。你可以控制你的工作质量、你的反应以及你学到了什么。面对不确定性时，把问题拆解，找出你可以采取的具体行动。 这不是被动接受，而是战略聚焦。花在无法改变之事上的精力，是从你可以改变之事上偷走的。 11. 抽象层不会消除复杂性，只会把它推迟到你值班的那一天。 每一个抽象层都是一个赌注，赌你不需要理解底层是什么。有时你赌赢了。但总有东西会泄漏，当泄漏发生时，你需要知道你站在什么之上。 资深工程师即使在技术栈越来越高层时，也会坚持学习“底层”知识。不是出于怀旧，而是出于对那个抽象层失效、凌晨 3 点你独自面对系统时刻的尊重。使用你的技术栈。 但要保持对其底层故障模式的理解模型。 12. 写作倒逼清晰。最好的学习方式是试着教别人。 写作强迫你理清思路。当我想向别人解释一个概念时——无论是在文档中、演讲中、代码审查评论中，甚至只是与 AI 聊天——我会发现自己理解上的漏洞。把东西向别人解释清楚的过程，也让我自己看得更清楚。 这并不意味着你能通过教别人做手术来学会做手术，但在软件工程领域，这个前提在很大程度上是成立的。 这不仅是对知识的慷慨。这是一种自私的学习黑客技巧。如果你认为你理解了某件事，试着简单地解释它。你卡住的地方，就是你理解浅薄的地方。 教学是在调试你自己的思维模型。 13. 成就他人的工作是无价的——也是隐形的。 胶水工作（Glue work）——文档、入职培训、跨团队协调、流程改进——至关重要。但如果你无意识地做这些，它可能会阻碍你的技术发展轨迹并让你精疲力竭。陷阱在于把它当作“乐于助人”来做，而不是把它当作经过深思熟虑、有边界、可见的影响力。 给它设定时间限制（Timebox）。轮流做。把它转化为产出物：文档、模板、自动化工具。并让它作为影响力被看到，而不是作为性格特征。 “无价”且“隐形”对你的职业生涯来说是一个危险的组合。 14. 如果你赢了每一场辩论，你可能正在积累沉默的抵触情绪。 我学会了对自己确信的事情保持怀疑。当我“赢”得太容易时，通常是有问题的。人们停止反驳你并不是因为你通过说服了他们，而是因为他们放弃了尝试——他们会在执行中而不是会议上表达这种分歧。 真正的对齐需要更长时间。你必须真正理解其他观点，整合反馈，有时甚至要公开改变主意。 短期内“我是对的”这种感觉，远不如长期建立与有意愿的合作者共事的现实更有价值。 15. 当度量指标成为目标时，它就失去了度量的意义。 你向管理层展示的每一个指标最终都会被利用（Gamed）。并非出于恶意，而是因为人类会针对被度量的东西进行优化。 如果你追踪代码行数，你会得到更多代码行。如果你追踪开发速度（velocity），你会得到虚高的估算。 资深的做法：用成对指标来回应每一个指标要求。一个针对速度，一个针对质量或风险。然后坚持解读趋势，而不是盲目崇拜阈值。目的是获得洞察，而不是监控。 16. 承认自己不知道比假装知道更能带来安全感。 说“我不知道”的资深工程师不是在示弱——他们是在给予许可。当领导者承认不确定性时，它向房间里的其他人发出信号：这样做是安全的。另一种选择是一种大家都假装理解的文化，问题被掩盖直到它们爆炸。 我见过最资深的人从不承认困惑的团队，也见过其造成的损害。问题没人问。假设没人挑战。初级工程师保持沉默，因为他们以为其他人都懂。 树立好奇心的榜样，你会得到一个真正学习的团队。 17. 你的人脉比你任何一份工作都长久。 在职业生涯早期，我专注于工作而忽视了人脉。事后看来，这是个错误。那些投资于关系——公司内部和外部——的同事获得了长达几十年的回报。 他们最先听到机会，能更快地建立桥梁，被推荐担任职位，并与多年来建立信任的人共同创立企业。 你的工作不是永远的，但你的人脉是。带着好奇心和慷慨去经营它，而不是交易性的投机。 当需要离开的时候，往往是人际关系为你打开大门。 18. 大多数性能提升来自减少工作量，而不是增加技巧。 当系统变慢时，本能反应是做加法：缓存层、并行处理、更智能的算法。有时这是对的。但我见过更多的性能胜利来自问这个问题：“我们在计算什么不需要计算的东西？” 删除不必要的工作几乎总是比更快地做必要的工作更有效。最快的代码是永远不运行的代码。 在你优化之前，先质疑这项工作是否应该存在。 19. 流程的存在是为了减少不确定性，而不是为了留存书面证据。 最好的流程让协作更容易，让失败的代价更低。最坏的流程是官僚主义的表演——它的存在不是为了提供帮助，而是在出问题时用来推卸责任。 如果你不能解释一个流程如何降低风险或增加清晰度，它可能只是累赘。 如果人们花在记录工作上的时间比做工作本身还多，那就说明出了大问题。 20. 最终，时间比金钱更宝贵。请据此行事。 在职业生涯早期，你用时间换金钱——这没问题。但在某个时刻，计算公式会反转。你开始意识到时间是不可再生资源。 我见过资深工程师为了追求下一个晋升等级而透支自己，只为优化那几个百分点的薪酬涨幅。有些人得到了。大多数人在那之后都在想，这是否值得他们放弃的东西。 答案不是“不要努力工作”。而是“知道你在交换什么，并深思熟虑地进行交换。” 21. 没有捷径，但有复利。 专业技能来自刻意练习——稍微超出你目前的能力范围，反思，重复。持续数年。没有浓缩版。 但这里有充满希望的部分：当学习创造新选项而不仅仅是新琐事时，它会产生复利。写作——不是为了流量，而是为了清晰。构建可复用的原语。将“伤疤组织”收集成剧本（Playbooks）。 那些将职业生涯视为复利而非彩票的工程师，往往最终会走得更远。 最后的想法 21条经验听起来很多，但它们实际上归结为几个核心思想：保持好奇，保持谦逊，并记住工作永远是关于人的——你为之构建产品的用户，以及与你一起构建产品的队友。 工程职业生涯足够长，足以让你犯很多错误并依然能脱颖而出。我最钦佩的工程师不是那些做对了一切的人——而是那些从错误中学习、分享他们发现的东西并坚持在场的人。 如果你正处于旅程的早期，要知道随着时间的推移，它会变得更加丰富。如果你已经深耕其中，我希望这些能引起你的一些共鸣。
AI 多代理大规模编程的尝试 背景 最近 cursor CEO 整了一个大活。用 Cursor 库构建了一个基于 GPT-5.2 的浏览器，包含超过 300 万行代码。 这个浏览器的表现为如下： 思考 数周能达到这个完成度，很不错。从一个demo角度是可以的。但是，从软件维护角度，这么大的产品后续迭代会是个灾难。 AI可以理解为一个无所不知的初级程序员，对于简单的项目，一次prompt就可以完成实现。但是对于大规模的软件开发，依旧不会是银弹。目前这个浏览器项目就是一个示例。 程序员可以利用AI提高自己的生产力。让软件产品更快、更好输出。 反过来，让AI规划产品，规划软件设计，目前来看不是一个好主意。 参考 原始推文 AI 生成的 chrome，wilsonzlin/fastrender cursor scaling agents
远程执行python脚本 uv 远程执行脚本介绍 Running scripts | uv Python scripts can be run directly from their URLs using uv run. 很多零碎的小脚本，可以放在云上，可以方便远程执行。 claude-code-transcripts_rename_html_with_prefix uv run https://guacamole.961118.xyz/my-oss-storage/2026/01/claude-code-transcripts_rename_html_with_prefix.py 适用场景： --------- - 有一组相互链接的 HTML 文件（如 index.html, page-001.html, page-002.html...） - 想给这些文件统一加前缀（如 kline-index.html, kline-page-001.html...） - 需要同时更新文件内部的所有链接，避免跳转失效
嵌入式软件分层 软件分层的核心目的是降低开发者的心智负担。当我们面对一个复杂系统时，不需要同时思考从硬件寄存器到业务逻辑的所有细节，而是聚焦于当前层的职责，信任下层提供的抽象。 分层带来的价值： 可替换性：更换硬件平台时，只需修改驱动层 可复用性：协议层代码可以在不同项目间复用 可测试性：每层可以独立进行单元测试 协作开发：不同开发者可以并行开发不同层 常见的软件分层 AUTOSAR AUTOSAR（汽车开放系统架构）是汽车电子领域的工业标准，提供了完整的分层规范： ┌────────────────────────────────────┐ │ Application Layer (SWC) │ 应用软件组件 ├────────────────────────────────────┤ │ Runtime Environment (RTE) │ 运行时环境 ├────────────────────────────────────┤ │ Services Layer (BSW) │ 基础软件服务层 ├────────────────────────────────────┤ │ ECU Abstraction Layer │ ECU 抽象层 ├────────────────────────────────────┤ │ MCAL │ 微控制器抽象层 ├────────────────────────────────────┤ │ Hardware │ 硬件 └────────────────────────────────────┘ AUTOSAR 的优势在于标准化程度高，有完整的规范文档和工具链支持。但对于中小型嵌入式项目来说过于复杂。 OSI 七层模型 OSI 模型是网络通信的经典参照，专注于数据在网络中的传输： ┌──────────────────┐ │ 应用层 │ HTTP, FTP, MQTT ├──────────────────┤ │ 表示层 │ 数据格式转换、加密 ├──────────────────┤ │ 会话层 │ 连接管理 ├──────────────────┤ │ 传输层 │ TCP, UDP ├──────────────────┤ │ 网络层 │ IP 路由 ├──────────────────┤ │ 数据链路层 │ 帧封装、MAC ├──────────────────┤ │ 物理层 │ 比特流传输 └──────────────────┘ OSI 模型的价值在于清晰定义了每层的职责边界，但它只覆盖"通信"这一个维度，不涉及业务逻辑和系统服务。 面向业务数据流的六层模型 结合 AUTOSAR 的分层思想和 OSI 的通信模型，针对中小型嵌入式项目提出简化的六层架构。核心关注点是业务数据如何从硬件一层层流向应用。 分层 ┌─────────────────────────────────────────────────────────────────┐ │ L6 应用层 │ 状态机 │ 业务逻辑 │ UI 交互 │ ├─────────────────────────────────────────────────────────────────┤ │ L5 服务层 │ 日志 │ 配置存储 │ 定时任务 │ Shell │ ├─────────────────────────────────────────────────────────────────┤ │ L4 协议层 │ Modbus │ 私有协议 │ Protobuf │ JSON │ ├─────────────────────────────────────────────────────────────────┤ │ L3 传输层 │ TCP/UDP │ 可靠传输 │ 分包重组 │ ├─────────────────────────────────────────────────────────────────┤ │ L2 链路层 │ UART帧 │ CAN帧 │ 以太网帧 │ ├─────────────────────────────────────────────────────────────────┤ │ L1 驱动层 │ HAL │ 外设驱动 │ DMA │ 中断 │ └─────────────────────────────────────────────────────────────────┘ 各层详解 L1 驱动层 (Driver/HAL) 职责：屏蔽硬件差异，提供统一的外设操作接口 向上提供：字节级别的读写能力 经典参照： 项目 特点 STM32 HAL ST 官方库，接口统一，易于移植 CMSIS-Driver ARM 标准驱动接口规范 RT-Thread Device 统一设备框架 rt_device_* ESP-IDF Driver 乐鑫官方驱动层 L2 链路层 (Link) 职责：在字节流上建立帧结构，处理帧定界、校验、转义 从下层获取：连续的字节流 向上提供：完整的、经过校验的数据帧 经典参照： 协议 帧格式 适用场景 HDLC 标志位 + 转义 + CRC 通用串口通信 CAN 帧 硬件级帧结构 CAN 总线通信 L3 传输层 (Transport) 职责：提供可靠传输、分包重组、流量控制 从下层获取：单个数据帧（可能丢失、乱序） 向上提供：可靠的、有序的数据流 经典参照： 协议 特点 适用场景 TCP 完整可靠传输 网络通信 Xmodem 停等协议 串口文件传输 CAN-TP (ISO 15765) CAN 分包传输 汽车诊断 自定义 ACK 机制 简单重传 资源受限场景 Modbus 寄存器读写 工业控制 L4 协议层 (Protocol) 职责：定义数据语义、命令格式、业务报文结构 从下层获取：可靠的字节流 向上提供：结构化的命令和数据 经典参照： 协议 模式 适用场景 Protobuf 二进制序列化 高效数据交换 JSON 文本格式 调试友好 私有 TLV Tag-Length-Value 自定义协议 L5 服务层 (Service) 职责：提供系统级公共服务，与具体业务逻辑解耦 特点：服务层是"横向"的，为所有其他层提供支撑 典型服务： 服务 经典实现 说明 日志 EasyLogger, RTT 调试和追踪 配置存储 NVS, LittleFS 参数持久化 定时任务 软件定时器 周期性任务调度 Shell letter-shell, finsh 命令行交互 OTA MCUboot 固件升级 L6 应用层 (Application) 职责：实现具体的业务逻辑 从下层获取：结构化的命令和数据 输出：业务动作、状态变更、响应数据 经典模式： 模式 说明 适用场景 状态机 有限状态自动机 设备控制流程 事件驱动 消息队列 + 事件处理 异步响应场景 命令模式 命令表 + 处理函数 请求-响应场景 各层软件设计复用 实现层间灵活配置的关键在于选择合适的工具和框架。以下按配置灵活度分类整理。 L1 驱动层配置工具 工具 类型 说明 STM32CubeMX 图形化配置 生成 HAL 初始化代码，引脚/时钟/外设可视化配置 MCUXpresso Config 图形化配置 NXP 官方，类似 CubeMX L2-L3 通信栈 工具/库 覆盖层级 配置方式 说明 lwIP L2-L4 lwipopts.h 宏配置 轻量 TCP/IP 栈，可深度裁剪 ringbuffer L2 代码抽象 环形缓冲区，驱动与链路层之间的数据缓存 kfifo (Linux) L2 代码抽象 内核无锁环形队列，可移植到裸机 lwrb L2 代码抽象 轻量级 ring buffer，支持 DMA L4 协议层工具 工具 类型 配置方式 说明 nanopb Protobuf .proto → C 代码 嵌入式 Protobuf，编译时生成 cJSON / jsmn JSON 代码抽象 轻量 JSON 解析器 MessagePack 二进制序列化 代码抽象 比 JSON 更紧凑 FreeModbus Modbus 编译时配置 嵌入式 Modbus 从站 L5 服务层组件 组件 服务类型 配置方式 说明 EasyLogger 日志 宏配置 轻量，支持多后端 Segger RTT 日志 编译时 高速调试通道 LittleFS 文件系统 编译时配置 掉电安全，磨损均衡 SPIFFS 文件系统 编译时配置 SPI Flash 专用 NVS (ESP-IDF) 键值存储 运行时 参数持久化 letter-shell Shell 宏配置 轻量命令行 finsh (RT-Thread) Shell 运行时 支持 C 表达式 L6 应用层框架 框架 类型 配置方式 说明 QP/C 状态机 代码生成 (QM) 层次状态机，活动对象模式 stateMachine 状态机 代码抽象 轻量有限状态机，表驱动 libevent 事件管理 运行时 事件循环，回调驱动 FreeRTOS 事件组 事件管理 运行时 RTOS 内置事件标志 命令分发表 命令模式 代码抽象 cmd_id → handler 映射表 灵活度等级 每层的实现可以在不同灵活度之间选择，根据项目需求做取舍： 最灵活 ◄──────────────────────────────────────────► 最精简 动态配置 静态可配置 代码抽象 硬编码 (运行时切换) (编译时选择) (回调/函数指针) (直接调用) │ │ │ │ ▼ ▼ ▼ ▼ 外部指令配置 menuconfig 接口结构体 内联代码 选择依据： 资源受限 → 倾向硬编码，减少间接调用开销 需要灵活 → 倾向动态配置，支持运行时调整 团队协作 → 倾向代码抽象，接口清晰便于分工
web 串口助手 想自己做一个web 串口助手。之前在浏览 阮一峰周刊 的时候，有见到过一个惊艳的 web 串口助手，一直找不到，颇为遗憾。 今天下午，寻找了几个小时的github，发现开源的 web 串口助手 都是功能少了一点，与自己理想的差了一点。 最后终于找到了 云之彼端串口助手 在 阮一峰老师科技爱好者周刊「工具」和「资源」汇总 中找到的。
如何优雅的屏蔽GCC编译器告警 作为一个合格的C语言程序员，在编译代码的时候一定要加上-W和-Wall选项，要保证代码中没有任何的warning信息,提高代码的可靠性。-Wall选项意思是编译后显示所有警告，-W选项只显示编译器认为会出现错误的警告。 但是有些时候，有些功能模块尚待开发，有些函数也没有完成功能，虽然不影响程序的正常执行，但是待开发的代码难免会有warning输出。如果去掉编译选项-W和-Wall，整个工程的告警就都会被忽略掉，那么怎么优雅的屏蔽部分代码的告警呢？ pragma GCC diagnostic ignored "告警类型" 编译如下代码： #include <stdio.h> void print_message(char *str, int num) { printf("%s : %d\n", str, &num); return; } int main(int argc, char *argv[]) { int i, j, k, t; t = 0; for(i = 0; i < 3; i++) { print_message("J value is", j++); } } 编译时加上-Wall选项，会出现如下告警提示： 有我们所学的C语言知识可知： -Wformat=：类型不匹配 -Wunused-but-set-variable：变量赋值却未使用 -Wunused-variable：变量未使用（也没有赋值） -Wreturn-typet：缺少返回值 我记得还有一种告警是"变量使用前未初始化"，代码中变量j就属于这种情况，但是不知为何没有告警信息，可能是我编译器版本的问题，或者是这个不会影响程序运行。 接下来我要屏蔽-Wformat=类型的告警：在函数前加上一行预处理命令，新的代码如下： #include <stdio.h> #pragma GCC diagnostic ignored "-Wformat=" void print_message(char *str, int num) { printf("%s : %d\n", str, &num); return; } int main(int argc, char *argv[]) { int i, j, k, t; t = 0; for(i = 0; i < 3; i++) { print_message("J value is", j++); } } 再次编译： 可以看到，-Wformat=类型的告警被屏蔽掉了。 当然，我们也可以同时屏蔽多种类型的告警，新的代码如下： #pragma GCC diagnostic ignored "-Wunused-but-set-variable" #pragma GCC diagnostic ignored "-Wunused-variable" #pragma GCC diagnostic ignored "-Wformat=" #pragma GCC diagnostic ignored "-Wreturn-type" void print_message(char *str, int num) { printf("%s : %d\n", str, &num); return; } int main(int argc, char *argv[]) { int i, j, k, t; t = 0; for(i = 0; i < 3; i++) { print_message("J value is", j++); } } 编译结果如下： 可以看到，所有的告警信息都被屏蔽掉了。 现在有一个问题，如果这样写的话，那么在这几行之后所有代码的告警信息都会被屏蔽掉，那么我想在某行之后恢复告警，该怎么做呢？切记，push和pop很好用哦，完整代码如下： #include <stdio.h> #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-but-set-variable" #pragma GCC diagnostic ignored "-Wunused-variable" #pragma GCC diagnostic ignored "-Wformat=" #pragma GCC diagnostic ignored "-Wreturn-type" void print_message(char *str, int num) { printf("%s : %d\n", str, &num); return; } int main(int argc, char *argv[]) { int i, j, k, t; t = 0; for(i = 0; i < 3; i++) { print_message("J value is", j++); } } #pragma GCC diagnostic pop
GitHub Pages 与 Cloudflare Pages：写博客和部署网站的最佳平台
GitHub Pages 与 Cloudflare Pages：写博客和部署网站的最佳平台 写博客是开发者提升个人影响力的常见方式。大多数技术博客采用 Markdown 格式撰写——一种简洁实用的标记语言，摒弃了 XML、HTML 等复杂标记，让作者专注于内容本身。 部署博客也应如此：摒弃繁杂的配置，专注内容展示，让 Web 回归交流沟通的本质。 传统上，博客部署首选 WordPress，搜索引擎一搜便是。WordPress 软件本身是免费开源的，但自建需要购买服务器/主机，这对刚入门的开发者（尤其是学生）来说是一道门槛。本博客使用的是更轻量的 Typecho，同样需要服务器支持。 而 GitHub Pages 提供了另一种选择：完全免费、部署简单、撰写方便，非常值得推荐。 GitHub Pages Jekyll Jekyll 是一款静态网站生成器，能将 Markdown 文件转换为 HTML 网页，在这方面表现出色。 选择 Jekyll 并非因为我偏爱 Ruby，也不是认为它是最好的静态网站生成器。原因很简单：GitHub 原生支持 Jekyll，在 GitHub Pages 上部署 Jekyll 网站几乎零配置。 部署 只需将文章推送到 GitHub 仓库，即可触发自动构建和发布。GitHub Pages 还支持自定义域名，配置非常简单，你可以用自己的域名访问博客。 编辑 GitHub 本身就是一个强大的在线编辑平台。在任意 GitHub 仓库页面按下 . 键，即可在浏览器中打开 VS Code（github.dev），获得完整的编辑体验。这意味着你甚至不需要电脑，用 iPad 等移动设备也能随时写博客。 使用熟悉的编辑器是提高写作效率的关键。相比其他博客平台需要适应新的编辑界面，GitHub 的方式对开发者更加友好。 Cloudflare Pages Cloudflare Pages 不仅是静态网站托管平台，还具备一定的后端能力。GitHub Pages 能做的，Cloudflare Pages 基本都能做到，而且它与 GitHub 仓库无缝集成，保留了完整的在线编辑体验。 更进一步，结合 Cloudflare Workers 生态（如 KV Storage、R2 Object Storage、Durable Objects），可以实现轻量级的动态功能。这让你能够突破纯静态内容的限制，发挥创意，让网站更加丰富多彩。 同样地，Cloudflare Pages 也是免费的。 参考 https://burkeholland.github.io/posts/gh-pages-best-blog/
大模型的训练速度正在加快 DeepSeek-R1: Incentivizing Reasoning Capability in LLMs via Reinforcement Learning 是 DeepSeek 2026 年发布最新论文，里面讲述了可以通过纯强化学习（pure RL）来激发 LLM 的推理能力，而不需要人工标注的推理轨迹。 [...]