[{"content":"为什么需要检查清单 AI 功能很容易在演示阶段看起来不错，但上线后遇到长尾输入、成本波动、上下文缺失和不可复现问题。上线前需要把这些风险尽量显性化。\n数据和上下文 先确认模型能看到完成任务所需的信息：\n数据来源是否可靠 上下文是否过长或过少 用户隐私和敏感信息是否被保护 引用或检索结果是否可追溯 评测和日志 至少准备一组代表性样例，覆盖正常输入、边界输入和失败输入。日志要能回答：用了什么提示词、传了什么上下文、模型返回了什么、最终是否被用户接受。\n失败兜底 AI 功能必须允许失败。失败时应该给出可理解的提示，必要时回退到人工处理、传统规则或安全默认值。\n小结 AI 工程化的重点不是让模型永远正确，而是让系统在模型不稳定时仍然可诊断、可回退、可持续改进。\n","date":"2026-05-18T12:20:00+08:00","permalink":"/ai/ai-engineering/ai-feature-checklist/","title":"AI 功能上线前检查清单"},{"content":"为什么需要结构 提示词不是越长越好，而是越清楚越好。一个稳定的提示词应该让模型知道要完成什么、依据什么、不能做什么，以及结果如何判断。\n最小模板 可以从这个结构开始：\n目标： 上下文： 输入： 约束： 输出格式： 验收标准： 如果任务需要多轮完成，还可以补充“先做什么、后做什么、什么时候停下来问问题”。\n约束比鼓励更重要 “请认真一点”这类表达很难约束行为。更有效的是明确边界，例如不要修改无关文件、必须引用来源、先运行测试、输出必须包含失败原因。\n小结 好的提示词像一份小型任务说明。它不替代判断，但能显著减少误解和返工。\n","date":"2026-05-18T12:10:00+08:00","permalink":"/ai/prompt-agents/prompt-structure/","title":"提示词结构的最小模板"},{"content":"不同任务需要不同模型 选择 AI 模型时，不要只看模型名字或排行榜。真正重要的是任务需要什么能力：理解长上下文、写代码、总结资料、调用工具、推理规划，还是快速生成草稿。\n一个简单的判断方式是先区分任务类型：\n简单改写和摘要：优先速度和成本 代码修改和调试：优先上下文理解和可靠性 多步骤研究：优先推理能力和工具使用能力 大量批处理：优先稳定性、成本和吞吐 看上下文而不是只看输入长度 上下文窗口越大，不代表效果一定越好。长上下文任务要关注模型能否抓住关键约束，以及是否会忽略早期信息。\n对于长文档或代码库，最好先组织结构化上下文，再让模型执行具体任务。\n评估要贴近真实任务 模型选择应该用自己的任务做小型评估。比如博客写作可以比较标题、结构、事实准确性和可读性；代码任务可以比较测试通过率、改动范围和解释质量。\n小结 模型选择不是一次性决定。随着任务、成本和工具链变化，模型策略也应该定期复盘。\n","date":"2026-05-18T12:00:00+08:00","permalink":"/ai/model-basics/model-selection-notes/","title":"AI 模型选择笔记"},{"content":"为什么做周复盘 研究任务经常是开放问题，如果只记录最终结果，中间的判断依据很容易丢失。周复盘的目标是留下阶段证据，让下一周知道该继续、收缩还是换方向。\n推荐结构 可以固定写这几项：\n本周目标： 完成进展： 关键证据： 遇到的问题： 判断变化： 下周计划： 需要求助： 这个结构不复杂，但能覆盖研究推进最重要的信息。\n关键证据 复盘里最值得保留的是证据，而不是情绪化结论。证据可以是实验结果、日志、图表、论文结论、对比数据或失败复现记录。\n如果某个判断改变了，要写清楚是哪个证据让判断改变。\n下周计划 下周计划最好具体到可以执行：\n复现某篇论文的一个实验 补齐一个数据处理脚本 比较两个基线方法 写完相关工作的一小节 小结 周复盘不是额外负担，而是研究过程的导航。它能帮助我们避免在模糊问题里原地打转。\n","date":"2026-05-18T11:50:00+08:00","permalink":"/research/writing-review/research-weekly-review/","title":"研究课题周复盘模板"},{"content":"审查目标 C 代码审查不是挑风格问题，而是提前发现运行时成本最高的问题：内存错误、资源泄漏、接口歧义、错误路径遗漏和不可测试的全局状态。\n接口语义 先看函数接口是否清楚：\n参数能否为 NULL 返回值如何表达错误 调用方是否负责释放资源 输出参数失败时是否有效 函数是否修改传入缓冲区 接口语义不清楚时，后续实现再漂亮也容易出问题。\n内存和边界 重点检查长度、容量和生命周期：\n字符串空间是否包含 \\0 memcpy、snprintf、数组下标是否有边界 释放路径是否覆盖所有失败分支 指针释放后是否还会被访问 错误路径 C 项目里很多 bug 只在异常路径出现。审查时要刻意走失败分支：申请失败、文件打开失败、设备不存在、协议字段不合法、部分初始化后返回错误。\n小结 好的代码审查清单能把经验固化下来。每次发现新问题，都应该把它变成下一次能提前检查的条目。\n","date":"2026-05-18T11:40:00+08:00","permalink":"/c-language/debug-quality/code-review-checklist/","title":"C 代码审查清单"},{"content":"先保留现场 Kernel panic 出现时，第一件事不是立刻改代码，而是把现场保存下来。串口完整日志、内核版本、设备树版本、启动参数、复现步骤和最近改动都应该保留。\n最小记录清单：\npanic 完整日志 bootargs Kernel commit 或版本号 DTB 来源 根文件系统版本 外设连接状态 看最后一个有效栈 panic 日志里最有价值的是调用栈和触发点。先找到 Call trace，再判断是空指针、非法地址、BUG_ON、oops 还是 watchdog。\n如果地址已经符号化，可以直接看函数名；如果没有符号，需要保留未裁剪的 vmlinux，配合 addr2line 定位源码行。\n区分必现和偶现 必现问题优先缩小配置和输入。偶现问题要关注并发、时序、内存越界、栈溢出和硬件状态。\n对于偶现问题，日志要尽量包含时间戳，并在关键路径加轻量日志，避免日志本身改变时序太多。\n复盘问题来源 定位后还要记录根因类型：\n设备树配置错误 驱动资源申请失败后清理不完整 中断上下文误用阻塞接口 DMA buffer 或 cache 同步问题 用户态输入触发内核边界缺陷 小结 Kernel panic 排查的关键是保留证据、定位栈、区分复现类型，再把根因沉淀成可检查的清单。\n","date":"2026-05-18T11:30:00+08:00","permalink":"/embedded-linux/debug-performance/kernel-panic-debugging/","title":"Kernel panic 排查记录模板"},{"content":"实验记录的价值 实验记录不是流水账，而是为了让未来的自己能够复现当时的判断。好的实验记录应该能回答：为什么做这个实验，怎么做的，结果是什么，是否支持原假设。\n推荐字段 可以固定记录这些字段：\n实验日期： 实验目标： 假设： 环境： 输入数据： 操作步骤： 关键参数： 结果： 异常： 结论： 下一步： 字段不一定每次都写满，但假设、环境、结果和结论最好保留。\n环境记录 环境包括硬件、系统版本、依赖版本、编译参数和数据版本。很多复现失败不是方法错了，而是环境差异没有记录。\n嵌入式相关实验还要记录板卡型号、内核版本、设备树版本、启动参数和外设连接状态。\n异常也要记录 失败实验同样有价值。异常日志、错误输入和失败条件能帮助排除路径，也能避免之后重复踩同一个问题。\n小结 实验记录的目标是支持复盘和复现。只要能让结论有证据、有上下文、有下一步，它就是有效记录。\n","date":"2026-05-18T11:20:00+08:00","permalink":"/research/experiment-reproduction/experiment-log-template/","title":"实验记录应该写什么"},{"content":"为什么要固定模板 论文读多以后，如果每篇只留下零散划线，很难回头比较。固定模板能帮助我们把论文放到同一张表里看：它解决什么问题，用什么方法，证据是否充分，能否复现。\n基本信息 先记录最基础的信息：\n标题： 作者： 年份： 会议/期刊： 代码/数据： 关键词： 这些信息方便之后检索和引用。\n核心问题 用自己的话写出论文试图解决的问题。不要直接复制摘要，而是回答：\n以前的方法哪里不够 作者具体改进了什么 这个问题为什么重要 方法和实验 方法部分记录主要流程、关键假设和实现细节。实验部分记录数据集、基线、指标和消融实验。\n如果论文有代码，最好记录运行环境、依赖版本和复现步骤。\n读后判断 最后写一段自己的判断：\n这篇论文最有价值的点是什么 哪些结论还需要进一步验证 对当前课题有什么启发 小结 论文阅读不是把内容搬进笔记，而是把论文转化为自己的问题地图。模板的作用，是让每次阅读都有可比较的结构。\n","date":"2026-05-18T11:10:00+08:00","permalink":"/research/topic-literature/literature-reading-notes/","title":"论文阅读笔记模板"},{"content":"好课题的几个特征 一个合适的研究课题不只是“有意思”，还需要能被验证、能在资源约束内推进，并且有清晰产出。\n可以从四个维度初筛：\n问题是否真实存在 是否有明确评价指标 当前资源能否支撑实验 最终能形成什么产出 问题价值 问题价值来自实际需求、理论缺口或工程瓶颈。选题时要能说清楚：如果这个问题被解决，会带来什么变化。\n如果只能说“这个方向很热门”，还不够。\n可验证性 研究问题要能转化为可验证假设。例如“优化系统性能”太宽，可以进一步拆成“在给定负载下，降低任务切换带来的平均延迟”。\n可验证性越强，实验设计越容易落地。\n资源约束 资源包括时间、设备、数据、算力、工具链和已有知识。一个好课题不是越大越好，而是能在当前条件下持续推进。\n小结 选题不是一次性决定，而是不断收缩问题边界。先找到真实问题，再把它改写成可验证、可推进、可复盘的计划。\n","date":"2026-05-18T11:00:00+08:00","permalink":"/research/topic-literature/topic-selection-framework/","title":"研究课题选题框架"},{"content":"常见现象 C 内存问题经常表现得很绕：崩溃点不一定是出错点，今天能复现的问题明天可能消失，打开日志后问题也可能变化。\n常见类型包括：\n数组或缓冲区越界 使用已经释放的指针 重复释放 未初始化读取 资源泄漏 先缩小范围 不要一开始就盯着崩溃现场。先确认最近改动、输入数据规模、线程数量、编译优化级别和是否只在特定平台出现。\n如果问题能稳定复现，优先构造最小复现用例。\n检查边界 内存越界通常和长度计算有关。重点检查：\n缓冲区大小是否包含结尾 \\0 memcpy 长度是否来自可信来源 循环边界是否使用 \u0026lt; 而不是误用 \u0026lt;= 结构体长度和协议字段是否一致 检查生命周期 悬空指针来自对象生命周期结束后继续访问。释放后可以把指针置为 NULL，但这只能减少部分误用，不能替代清晰的所有权设计。\n小结 排查内存问题要有耐心，也要有方法。先稳定复现，再缩小范围，最后回到边界、生命周期和错误路径。\n","date":"2026-05-18T10:50:00+08:00","permalink":"/c-language/debug-quality/debugging-memory-bugs/","title":"C 内存问题排查清单"},{"content":"模块边界 C 项目变大以后，真正难维护的往往不是语法，而是模块边界。好的模块接口应该让调用方知道能做什么，不需要知道内部怎么做。\n常见做法是把结构体定义隐藏在 .c 文件里，只在头文件暴露不透明类型。\nstruct logger; struct logger *logger_create(const char *path); void logger_destroy(struct logger *log); int logger_write(struct logger *log, const char *message); 调用方不能直接访问内部字段，模块就有空间调整实现。\n资源成对管理 创建和销毁函数要成对出现，命名保持一致。这样调用方一眼能看出资源生命周期。\ninit/deinit create/destroy open/close alloc/free 不要让调用方猜一个对象应该用 free、close 还是自定义函数释放。\n错误处理 C 语言没有异常，接口必须明确错误返回。常见方式是返回 0 表示成功，负数或非零表示错误。\n更重要的是：失败时资源状态要可预测。函数要么完全成功，要么保持原状态，不能留下半初始化对象。\n减少全局状态 全局变量会让测试、并发和复用都变困难。能通过上下文对象传递的状态，就尽量放进上下文对象。\n小结 C 模块接口的目标是降低调用方心智负担。接口越稳定、语义越明确，后续维护成本越低。\n","date":"2026-05-18T10:40:00+08:00","permalink":"/c-language/module-interface/module-interface-design/","title":"C 模块接口设计的几个原则"},{"content":"指针问题的本质 C 语言不会替我们记录对象归谁所有、什么时候释放、还能不能访问。很多指针 bug 表面是野指针、重复释放或内存泄漏，背后都是所有权边界不清楚。\n写 C 代码时，可以主动给指针加上三类语义：\n拥有：负责释放资源 借用：只临时使用，不释放 输出：函数负责写入结果 拥有型指针 拥有型指针通常来自 malloc、资源打开函数或创建函数。谁拥有它，谁就负责释放。\n命名上可以用 create/free、open/close 成对出现：\nstruct buffer *buffer_create(size_t size); void buffer_destroy(struct buffer *buf); 这种接口比让调用者猜释放方式更稳。\n借用型指针 借用型指针不应该被释放，也不应该长期保存到超过对象生命周期的地方。\n函数参数里常见的 const char *name 多数是借用。加上 const 能明确函数不会修改传入内容。\n输出参数 C 语言里常用输出参数返回多个结果。输出参数要说明是否允许为 NULL，以及失败时是否会被修改。\nint sensor_read(struct sensor *dev, int *value); 这个接口至少需要约定：dev 和 value 是否能为空，返回非零时 value 是否有效。\n小结 指针本身只是地址。真正决定代码可靠性的，是所有权、生命周期和错误路径是否写清楚。\n","date":"2026-05-18T10:30:00+08:00","permalink":"/c-language/pointer-memory/pointer-and-ownership/","title":"C 语言指针与所有权笔记"},{"content":"根文件系统承担什么 Kernel 启动后需要挂载根文件系统，并运行第一个用户态进程。根文件系统里至少要有基础目录、初始化程序、命令工具、动态库、配置文件和设备节点。\n最小系统常见目录包括：\n/bin /sbin /etc /lib /dev /proc /sys /tmp /var init Kernel 默认会尝试运行 /sbin/init、/etc/init、/bin/init 或 /bin/sh。如果这些路径都不存在，系统会 panic。\n调试时可以临时在 bootargs 里指定：\ninit=/bin/sh 这样能绕过复杂启动脚本，先确认根文件系统能否进入用户态。\n动态库 如果应用或 BusyBox 是动态链接，需要把对应 C 运行库和动态加载器放进根文件系统。缺库时，常见现象是文件明明存在，却提示 not found。\n可以用交叉工具链的 readelf 或 ldd 替代方案检查依赖。\n虚拟文件系统 启动脚本通常需要挂载：\nmount -t proc proc /proc mount -t sysfs sysfs /sys mount -t devtmpfs devtmpfs /dev 缺少这些挂载会影响进程信息、设备节点和驱动状态查看。\n小结 根文件系统问题要从两个角度看：Kernel 是否成功挂载它，用户态程序是否能在里面正常运行。先确认最小 shell 可用，再逐步恢复完整启动脚本。\n","date":"2026-05-18T10:20:00+08:00","permalink":"/embedded-linux/boot-system/rootfs-build-notes/","title":"根文件系统构建笔记"},{"content":"为什么设备树容易出问题 设备树描述硬件，但它本身不会证明硬件真的可用。一个节点看起来完整，也可能因为地址、时钟、中断、复位或引脚复用配置错误而导致驱动 probe 失败。\n调试设备树时，可以先围绕几个高频字段检查。\ncompatible compatible 决定设备节点能否匹配到驱动。驱动侧通常通过 of_device_id 表匹配字符串。\n如果驱动没有 probe，先检查：\n字符串是否拼写一致 驱动是否编进内核或模块已加载 节点 status 是否为 okay reg 和 ranges reg 描述寄存器地址和长度。地址单元数量受父节点的 #address-cells 和 #size-cells 影响。\n如果寄存器读写异常，要确认物理地址、长度和父总线地址映射是否正确。\npinctrl、clock 和 reset 很多外设 probe 成功但不能工作，问题往往在 pinctrl、clock 或 reset。\n常见检查项：\n引脚复用是否切到外设功能 上拉、下拉、驱动能力是否符合硬件 时钟是否被正确打开 reset 是否释放 interrupt 中断问题通常表现为驱动正常加载，但事件没有响应。需要确认中断号、触发方式和中断控制器引用是否正确。\n小结 设备树调试要同时看 DTS、驱动匹配表、内核日志和硬件原理图。只看一个文件很容易误判。\n","date":"2026-05-18T10:10:00+08:00","permalink":"/embedded-linux/drivers-dts/device-tree-debugging/","title":"设备树调试的几个检查点"},{"content":"启动主线 嵌入式 Linux 的启动过程可以先抓住一条主线：硬件上电后，Boot ROM 找到第一阶段启动程序，随后加载 U-Boot，再由 U-Boot 加载 Linux Kernel、设备树和根文件系统。\n完整路径通常是：\nPower On -\u0026gt; Boot ROM -\u0026gt; SPL/TPL -\u0026gt; U-Boot -\u0026gt; Kernel -\u0026gt; init -\u0026gt; user space 不同芯片的细节会变化，但定位问题时先把当前卡在哪一段确认清楚，排查效率会高很多。\nBoot ROM Boot ROM 是芯片内部固化代码，负责根据启动引脚或熔丝配置选择启动介质，例如 eMMC、SD 卡、SPI NOR、NAND 或 USB 下载模式。\n这一阶段常见问题包括启动介质不可读、镜像偏移不对、签名校验失败、供电和时钟没有满足芯片要求。\nU-Boot U-Boot 负责初始化更多硬件，并准备 Kernel 运行环境。常见动作包括初始化 DRAM、加载镜像、传递启动参数、加载设备树和设置 bootargs。\n调试时优先确认：\n串口是否有输出 DRAM 大小是否识别正确 Kernel、DTB、rootfs 地址是否正确 bootcmd 和 bootargs 是否符合当前启动介质 Kernel Kernel 接管后会解压、初始化内核子系统、解析设备树、挂载根文件系统并启动第一个用户态进程。\n如果 Kernel 已经打印日志但最终 panic，重点看 panic 前的最后几行。根文件系统挂载失败时，常见原因是驱动缺失、设备节点不匹配、文件系统类型不支持或 root= 参数错误。\n小结 启动问题不要一开始就陷入全部日志。先判断卡在 Boot ROM、U-Boot、Kernel 还是用户态，再按阶段收集证据，问题会清楚很多。\n","date":"2026-05-18T10:00:00+08:00","permalink":"/embedded-linux/boot-system/linux-boot-flow/","title":"嵌入式 Linux 启动流程速记"},{"content":"配置检查 部署前先确认 hugo.toml 中的站点地址、语言、标题和分页配置。baseURL 会影响线上资源路径，尤其是样式和图片。\n如果使用 GitHub Pages 的用户站点，常见地址是：\nbaseURL = \u0026#34;https://username.github.io/\u0026#34; 如果使用项目站点，则通常需要带上仓库名。\n内容检查 发布前至少检查这些内容：\n首页能说明博客主题 About 页面不是空白 至少有几篇正式文章 文章 draft = false 日期不是未来时间 图片路径大小写一致 没有提交私钥、邮箱明文或私人照片 Actions 检查 GitHub 仓库的 Pages Source 需要选择 GitHub Actions。工作流构建时要安装 Hugo Extended，并上传 public 目录作为 Pages artifact。\n常用构建命令是：\nhugo --gc --minify 小结 部署问题通常不是 Hugo 本身复杂，而是路径、草稿状态、Actions 权限和 Pages 设置容易漏。上线前做一次清单检查，可以省掉很多排查时间。\n","date":"2026-05-18T09:20:00+08:00","permalink":"/posts/github-pages-deploy-checklist/","title":"GitHub Pages 部署前检查清单"},{"content":"为什么需要流程 技术文章很容易变成命令堆砌。写之前先想清楚读者、问题和结果，文章会更容易读，也更方便未来的自己回看。\n五步写作法 第一步是选题。选题可以来自今天解决的问题、刚学会的工具、项目里的坑，或者一段值得保留的思考。\n第二步是列提纲。提纲不需要复杂，只要回答三个问题：背景是什么，问题是什么，最后得到什么结果。\n第三步是写初稿。初稿阶段先追求完整，不急着打磨句子。\n第四步是本地预览。Hugo 的本地预览可以及时发现标题层级、代码块、图片路径和链接问题。\n第五步是校对和发布。发布前检查草稿状态、日期、标签、图片、链接和隐私信息。\n文章模板 ## 背景 ## 问题 ## 过程 ## 结果 ## 总结 这个模板很朴素，但足够覆盖大多数学习笔记和项目复盘。\n小结 写作流程的价值不是限制表达，而是减少启动成本。每次都从同一套结构开始，长期会更容易坚持。\n","date":"2026-05-18T09:10:00+08:00","permalink":"/posts/markdown-writing-workflow/","title":"一套简单的 Markdown 写作流程"},{"content":"背景 我希望博客能长期维护，文章源文件可以直接用 Git 管理，部署流程尽量简单，所以选择了 Hugo、Markdown 和 GitHub Pages。\n这一套方案的核心好处是：文章就是普通 Markdown 文件，构建结果是静态页面，不依赖数据库，也方便以后迁移。\n第一版目标 第一版不追求复杂功能，先完成几个基础能力：\n可以本地预览文章 可以用 Markdown 写作 有首页、文章列表、关于页和项目页 推送到 GitHub 后能自动部署 站点结构清晰，后续容易扩展 项目结构 当前项目采用 Hugo 标准结构：\ncontent/ # 页面和文章 layouts/ # 自定义模板 assets/ # Hugo 处理的 CSS static/ # 原样复制的图片和图标 没有引入外部主题，主要是为了减少初始依赖。等站点稳定后，再决定是否接入主题或继续维护自定义模板。\n发布流程 写文章时先使用草稿状态：\nhugo new content posts/my-new-post.md hugo server -D 确认内容、图片、链接和排版都没问题后，再把 draft 改为 false，提交并推送到 GitHub。\n小结 个人博客最重要的不是功能复杂，而是能稳定写、稳定发布、稳定维护。先让系统跑起来，再逐步加入搜索、评论、统计和自定义域名。\n","date":"2026-05-18T09:00:00+08:00","permalink":"/posts/hugo-blog-setup/","title":"用 Hugo 搭建个人博客的第一步"}]