<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>vibe coding on 向叔记事簿</title>
        <link>https://ttf248.life/tags/vibe-coding/</link>
        <description>Recent content in vibe coding on 向叔记事簿</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>zh-cn</language><atom:link href="https://ttf248.life/tags/vibe-coding/index.xml" rel="self" type="application/rss+xml" /><item>
        <title>给编码模型几个代码锚点</title>
        <link>https://ttf248.life/p/code-anchors-for-llm-requirements/</link>
        <pubDate>Sun, 05 Jul 2026 23:04:15 +0800</pubDate>
        
        <guid>https://ttf248.life/p/code-anchors-for-llm-requirements/</guid>
        <description>&lt;p&gt;给编码模型写需求时，我越来越倾向于顺手带上几个能在仓库里搜到的名字：函数名、组件名、CSS 类名，或者接口路径。少了这些词，模型未必做不了，但它经常要先花一轮时间猜“这句话对应哪段代码”。&lt;/p&gt;
&lt;p&gt;比如只写：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;调整登录按钮的禁用状态，提交中不要重复点击，样式也要变灰。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;人能借助页面印象理解“登录按钮”在哪，编码模型面对的却可能是几十个按钮、多个登录入口，以及散落在组件、状态管理和样式文件里的实现。它首先要把自然语言中的“登录按钮”映射到仓库里的具体符号，然后才能判断该改事件处理、状态变量，还是 CSS。&lt;/p&gt;
&lt;p&gt;如果需求改成下面这样，搜索空间会小很多：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;调整 &lt;code&gt;LoginForm&lt;/code&gt; 中 &lt;code&gt;handleSubmit&lt;/code&gt; 的提交状态。提交期间禁用 &lt;code&gt;.login-submit&lt;/code&gt;，避免重复请求；现有错误提示行为不变。验收：请求未结束时再次点击不会发出第二个请求，按钮呈禁用样式，请求结束后恢复。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这里真正有用的不是提示词变长，而是多了几枚可以落到代码上的锚点。&lt;/p&gt;
&lt;h2 id=&#34;模型在预测代理还要先找代码&#34;&gt;模型在预测，代理还要先找代码
&lt;/h2&gt;&lt;p&gt;当前主流大语言模型通常把输入切成 token，根据已有上下文逐步预测后续 token。Transformer 的自注意力机制让序列中的 token 能彼此建立联系；经过大规模预训练和后续对齐，模型可以遵循指令、解释代码，并生成修改方案。但“能根据上下文生成”不等于“天然知道你当前仓库里登录按钮放在哪”。&lt;/p&gt;
&lt;p&gt;编码代理还多了一层工作：它会调用文件搜索、文本检索、读取和测试工具，把仓库里的相关代码放进模型上下文。函数名 &lt;code&gt;handleSubmit&lt;/code&gt; 和类名 &lt;code&gt;.login-submit&lt;/code&gt; 在这个阶段有双重作用。&lt;/p&gt;
&lt;p&gt;第一重是&lt;strong&gt;检索锚点&lt;/strong&gt;。自然语言里的“登录按钮”可能匹配文案、注释、测试和多个组件；精确符号可以直接交给文本搜索工具，较快找到定义、引用和相邻测试。少读几个无关文件，不只节省时间和 token，也减少无关代码干扰判断。&lt;/p&gt;
&lt;p&gt;第二重是&lt;strong&gt;语义约束&lt;/strong&gt;。&lt;code&gt;handleSubmit&lt;/code&gt; 暗示改动与提交链路有关，&lt;code&gt;.login-submit&lt;/code&gt; 把视觉状态限定到一个具体选择器，&lt;code&gt;LoginForm&lt;/code&gt; 又给出了组件边界。它们共同降低了“按钮究竟是哪一个、状态应该放在哪一层”的歧义。模型仍在做概率生成，但可选解释少了，下一步更容易沿着正确代码路径展开。&lt;/p&gt;
&lt;p&gt;这也是为什么我更愿意把这种写法叫“提供坐标”，而不是“提示词技巧”。它同时帮助了模型和模型外面的工具链。哪怕换成另一个编码模型，只要它也需要检索仓库，这些坐标仍然有价值。&lt;/p&gt;
&lt;h2 id=&#34;好需求不只是一串关键词&#34;&gt;好需求不只是一串关键词
&lt;/h2&gt;&lt;p&gt;只有符号名也不够。下面这种写法虽然容易搜索，仍然不知道要改成什么：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;LoginForm&lt;/code&gt;、&lt;code&gt;handleSubmit&lt;/code&gt;、&lt;code&gt;.login-submit&lt;/code&gt;，优化一下。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我现在更常用的写法包含四类信息：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;信息&lt;/th&gt;
					&lt;th&gt;作用&lt;/th&gt;
					&lt;th&gt;示例&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;代码锚点&lt;/td&gt;
					&lt;td&gt;缩小检索范围&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;LoginForm&lt;/code&gt;、&lt;code&gt;handleSubmit&lt;/code&gt;、&lt;code&gt;.login-submit&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;目标行为&lt;/td&gt;
					&lt;td&gt;说明改完发生什么&lt;/td&gt;
					&lt;td&gt;提交期间禁止重复请求&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;保持项&lt;/td&gt;
					&lt;td&gt;防止顺手改坏邻接行为&lt;/td&gt;
					&lt;td&gt;现有错误提示不变&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;验收条件&lt;/td&gt;
					&lt;td&gt;给实现和测试一个终点&lt;/td&gt;
					&lt;td&gt;第二次点击不发请求，请求结束后恢复&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;文件路径、测试名、接口名和报错文本也能充当锚点。优先给自己确认过、辨识度高的名字，不必为了显得具体而堆满所有相关符号。通常一两个入口函数、一个组件或样式名，已经足够让代理开始检索；剩余调用关系应该让它从代码里验证，而不是由需求编写者凭记忆补全。&lt;/p&gt;
&lt;p&gt;还要警惕错误坐标。函数已经重命名、类名在多处复用，或者需求指向的其实是另一个页面时，精确但错误的关键词会让模型更快地走错路。稳妥的表达可以加一句“名称可能已调整，请先搜索确认”，或者同时给出页面行为和可见文案，让代理交叉验证。&lt;/p&gt;
&lt;p&gt;所以更实用的结论不是“需求里多塞关键词”，而是：&lt;strong&gt;把人的页面印象翻译成仓库可检索的坐标，再用行为和验收条件约束修改结果。&lt;/strong&gt; 前者减少寻找代码的成本，后者减少写错代码的空间。两部分同时存在，编码模型的效率提升才更稳定。&lt;/p&gt;
&lt;h2 id=&#34;参考资料&#34;&gt;参考资料
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://arxiv.org/abs/1706.03762&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Attention Is All You Need&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://arxiv.org/abs/2005.14165&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Language Models are Few-Shot Learners&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://openai.com/academy/what-is-ai/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;OpenAI Academy：AI fundamentals&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://openai.com/index/why-language-models-hallucinate/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;OpenAI：Why language models hallucinate&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;details class=&#34;article-notes&#34;&gt;
    &lt;summary&gt;写作附记&lt;/summary&gt;
    &lt;div class=&#34;article-notes__content&#34;&gt;
        &lt;h3 id=&#34;原始提示词&#34;&gt;原始提示词
&lt;/h3&gt;&lt;blockquote&gt;
&lt;p&gt;大模型编码写需求的时候，如果能带上一些关键词，比如：关联的函数名称、前端关联的样式名称，能让模型的效率更高，稍微讲解下 LLM 的原来，当前大模型的原理，解释下我这样做为什么更好&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这篇保留了“函数名、样式名能提高编码效率”的现场判断，并补上语言模型生成与编码代理检索之间的区别。压掉了完整 Transformer 教程、模型代际比较和泛化的提示词清单，避免机制介绍抢走工程问题的主线。&lt;/p&gt;

    &lt;/div&gt;
&lt;/details&gt;</description>
        </item>
        <item>
        <title>Loop engineering 把人挪到检查点</title>
        <link>https://ttf248.life/p/loop-engineering-human-checkpoints/</link>
        <pubDate>Sun, 14 Jun 2026 07:35:00 +0800</pubDate>
        
        <guid>https://ttf248.life/p/loop-engineering-human-checkpoints/</guid>
        <description>&lt;p&gt;昨天参加 MiniMax 线下开发者大会，回来以后有个词一直没绕过去：loop engineering。&lt;/p&gt;
&lt;p&gt;我一开始以为它只是把 agent 多跑几轮。这个理解太浅了。真正让我卡住的地方是，AI 写代码的速度已经比人审核代码的速度快太多，如果人的参与还停在“每一步都看、每一步都拍板”，那生产力最后会被人的检查速度锁住。&lt;/p&gt;
&lt;p&gt;这和我最近用 Codex 的感受能接上。之前写 &lt;a class=&#34;link&#34; href=&#34;https://ttf248.life/p/codex-goal-command-explained/&#34; &gt;那篇 goal 文章&lt;/a&gt; 时，我更多关注的是“完成条件”这件事：目标是什么，边界在哪里，用什么验证，什么时候算完成。&lt;/p&gt;
&lt;p&gt;大会以后再回头看，goal 只是 loop engineering 里很小但很关键的一块。它解决的是单次任务怎么不靠人反复提醒也能往前走。更大的问题是：哪些任务值得交给循环，哪些检查点必须留给人，哪些判断可以提前写进系统，哪些责任不能推给 AI。&lt;/p&gt;
&lt;p&gt;我现在觉得最契合的场景有两个。&lt;/p&gt;
&lt;p&gt;一个是性能优化。它天然有指标，最好还能自动复测。你告诉 agent：接口 P95 要降到多少，首屏要控制在多少毫秒，包体要降到多少 KB，回归测试不能挂。它每改一轮就跑一次 benchmark、profile 或压测，没达标就继续找瓶颈。这里人的价值不是每次看它改了哪一行，而是先给出可验收的指标，再在关键节点判断“这个优化有没有改变业务语义”。&lt;/p&gt;
&lt;p&gt;另一个是 UI 重构。前提是要有明确设计稿，最好能做到 1:1 还原。没有设计稿时，人会不断被拉回“这个边距不对”“这个颜色不舒服”“这个交互不像”的琐碎判断里；有了设计稿，AI 的循环就可以围着截图、DOM、样式和视觉差异来收敛。人不必跟着每一次 CSS 调整跑，但要对最终界面负责。&lt;/p&gt;
&lt;p&gt;这两个场景的共同点是，验收物不是一句“做得好一点”。性能优化有数字，UI 重构有设计稿。循环能跑起来，不是因为 AI 更听话，而是因为任务本身有可比较的目标。&lt;/p&gt;
&lt;h2 id=&#34;multica-像一块协作板&#34;&gt;Multica 像一块协作板
&lt;/h2&gt;&lt;p&gt;大会现场还碰到开源圈的人介绍项目，其中 Multica 挺有意思。我回来查了一下，它不是一个新的单体 coding agent，而是把 Claude Code、Codex、GitHub Copilot CLI、OpenCode、Gemini、Kimi、Cursor Agent 等工具接进同一个任务协作层。&lt;/p&gt;
&lt;p&gt;它的 README 里把 agent 写成 teammate：可以被分配 issue，会汇报 blocker，会更新状态，也会出现在看板、评论和任务生命周期里。文档里更具体一点：agent 是 workspace 的一等成员，可以被 assign issue、在评论里发言、被 &lt;code&gt;@&lt;/code&gt; 提及；创建 agent 时可以选择背后的 AI coding tool，并配置 instructions、model、环境变量、CLI 参数、可见性和并发限制。&lt;/p&gt;
&lt;p&gt;这就把“用哪个模型”从一次 prompt 里的临时选择，变成了团队协作里的角色配置。&lt;/p&gt;
&lt;p&gt;它最有意思的地方，不是“多代理”这个词，而是可以给不同 agent 配不同身份。比如一个 agent 用便宜模型做重复修复，一个 agent 用更强模型做架构判断，一个 agent 只做 review，不改代码；再配合 Squad 这种机制，由 leader agent 根据 issue 内容把任务路由给合适成员。&lt;/p&gt;
&lt;p&gt;我没有完整跑一遍 Multica，所以这里只能把它当作一个公开资料可核对的样本看。但这个设计方向和 loop engineering 是同一类问题：不是让一个 AI 把所有事干完，而是把任务、角色、模型、审核和状态流转放进同一个循环里。&lt;/p&gt;
&lt;p&gt;如果公司真要落地 AI 写代码，这个差别很重要。&lt;/p&gt;
&lt;p&gt;现在模型价格不一样，能力边界也不一样。所有任务都用最贵的闭源模型，成本不一定扛得住；所有任务都用便宜模型，返工和漏审又可能把成本搬到后面。更现实的做法是分层：低风险、重复、边界清楚的活交给便宜模型先跑；关键变更、架构取舍和最终审核，留给更强的模型或人。&lt;/p&gt;
&lt;p&gt;闭源强模型用来做审核，我觉得是一个不错的位置。审核不只是“挑语法错误”，它要看需求有没有被改坏，边界有没有被越过，测试是不是只覆盖了表面，提交说明是不是掩盖了风险。这类任务对判断力要求更高，但调用频次未必像实现阶段那么大，成本账更容易接受。&lt;/p&gt;
&lt;h2 id=&#34;人少参与不等于人不负责&#34;&gt;人少参与，不等于人不负责
&lt;/h2&gt;&lt;p&gt;圆桌讨论里有个观点我很认同：代码是 AI 写的，但代码是人类提交的。&lt;/p&gt;
&lt;p&gt;这句话听起来像责任提醒，其实也是流程设计原则。AI 可以写代码、改代码、跑测试、生成 PR 说明，甚至可以让另一个模型先审一轮。但最后把代码合进主干的人，不能说“这是 AI 写的，和我没关系”。&lt;/p&gt;
&lt;p&gt;公司里要的不是谁在键盘上敲字符，而是谁对结果负责。你提交了，就表示你愿意为这次变更的业务语义、风险边界、测试证据和回滚预案负责。AI 参与得越深，这件事越不能含糊。&lt;/p&gt;
&lt;p&gt;所以 loop engineering 不是把人彻底从流程里删掉。它更像是重新安排人的位置：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;任务开始前，人写清目标、边界和验收条件。&lt;/li&gt;
&lt;li&gt;循环运行时，系统和 agent 自己处理重复尝试、测试、修复和状态同步。&lt;/li&gt;
&lt;li&gt;关键节点上，人看证据、看差异、看风险，而不是逐行追着 AI 的产出跑。&lt;/li&gt;
&lt;li&gt;提交代码时，人承担结果责任，不能把 AI 当免责理由。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这也是我为什么会把 goal、性能指标、设计稿、Multica 这几个看似分散的东西连在一起。它们都在把人的判断提前、外显、结构化。人参与得少一点，但参与的位置更关键。&lt;/p&gt;
&lt;p&gt;这件事如果做不好，就会变成另一种低效：AI 产出很多，人审不过来，最后团队靠“感觉上差不多”合代码；出了问题以后，又把锅甩给 AI。那不是工程化，只是把混乱换了个生产者。&lt;/p&gt;
&lt;p&gt;真正值得追的循环，不是让 AI 一直写，而是让每一轮写作、修改、测试和审核都能回到同一张验收单上。人的工作从“盯着它写”变成“定义什么算好、检查证据够不够、为提交负责”。这可能才是 loop engineering 这个词让我一直想的地方。&lt;/p&gt;
&lt;h2 id=&#34;参考资料&#34;&gt;参考资料
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/multica-ai/multica&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Multica GitHub README&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://multica.ai/docs/agents&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Multica Docs: Agents&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://multica.ai/docs/agents-create&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Multica Docs: Create and configure an agent&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://multica.ai/docs/providers&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Multica Docs: AI coding tools matrix&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://multica.ai/docs/squads&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Multica Docs: Squads&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;details class=&#34;article-notes&#34;&gt;
    &lt;summary&gt;写作附记&lt;/summary&gt;
    &lt;div class=&#34;article-notes__content&#34;&gt;
        &lt;h3 id=&#34;原始提示词&#34;&gt;原始提示词
&lt;/h3&gt;&lt;blockquote&gt;
&lt;p&gt;$blog-writer 昨天参加 Minimax 线下开发者大会，有个东西一直没绕过去，loop engineering，近期在用 codex 代码开发，也喜欢用 goal，也写过关于 goal 的文章，发现两个场景，最契合，性能优化，直接给出我要求的性能指标、UI 重构，提供设计稿，要求 1:1 还原。回到开始说的 loop engineering，AI 时代的编程，由于 AI 的生产力远超人类，人类审核的速度，完全无法追平，AI 产出的速度，但是现在的 vibe coding，很多决策还是需要人类参与的，人的参与变多了以后，整个流程就不容易完全自动化。loop engineering 的理念，更多就是降低人类的参与程度。还碰到了开源圈的人来宣讲他们的项目，有一个项目比较有意思，Multica，你查下相关资料，简单的介绍下，除开他的设计理念，最有意思的地方在，不同给的模型，给不同的身份，能有效的利用各家的大模型，毕竟现在模型价格不一样，闭源模型来做审核是个不错的思路。关于 AI 代码在公司落地，圆桌讨论的时候，有个观点也是一致的，代码是 AI 写的，但是代码是人类提交的，你需要对你提交的代码负责，这表现的是你的责任心、你做事情的态度。你不能说这是AI写的，和你没关系。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;写作思路摘要&#34;&gt;写作思路摘要
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;保留 2026-06-13 参加 MiniMax 线下开发者大会这个现场触发点，没有把它扩写成大会报道。&lt;/li&gt;
&lt;li&gt;把主线收束在“人的参与位置怎么变”，而不是逐条解释 loop engineering、goal、Multica 和公司责任。&lt;/li&gt;
&lt;li&gt;Multica 部分只写公开资料能支撑的能力，并把“闭源模型做审核”明确放在作者判断里。&lt;/li&gt;
&lt;li&gt;压掉了对具体模型价格、公司管理制度和代码审查流程的展开，避免文章从工作流观察跑成管理制度建议。&lt;/li&gt;
&lt;/ul&gt;
    &lt;/div&gt;
&lt;/details&gt;</description>
        </item>
        <item>
        <title>Codex 写界面扑街之后，让 ChatGPT 画 UI</title>
        <link>https://ttf248.life/p/codex-chatgpt-ui-mockup-workflow/</link>
        <pubDate>Sun, 14 Jun 2026 05:14:22 +0800</pubDate>
        
        <guid>https://ttf248.life/p/codex-chatgpt-ui-mockup-workflow/</guid>
        <description>&lt;p&gt;最开始我以为只是前端还没来得及收拾。&lt;code&gt;strategy_studio&lt;/code&gt; 的业务逻辑一直在往前走：行情同步、PostgreSQL、异步回测、报告落库和研究工作台都陆续接上了，但页面看起来越来越像“功能先上车，界面后补票”。等我想让 Codex 直接破坏性重构 UI 时，问题才真正露出来：提示词越写越狠，界面还是像在旧格子里重新挪组件。&lt;/p&gt;
&lt;p&gt;这不是第一次用 Codex 改代码。后端链路、API 对接、测试修复、报告生成这类任务，我通常直接把目标扔进去，让它读文件、改代码、跑验证、提交。问题出在前端重构这里：我没有先做 UI 稿，前面又已经把业务结构铺开了。旧界面一旦存在，模型看到的就不只是需求，还有现成组件、现成路由、现成样式和一堆历史惯性。&lt;/p&gt;
&lt;p&gt;我一开始的反应也很普通：继续加提示词。允许破坏性重构，重新设计 UI 和交互逻辑，元素不要太密集，适配 24 寸和 32 寸显示器，聚焦核心功能，不要保守。每句话单独看都对，但合在一起仍然缺一个东西：最后到底应该长什么样。&lt;/p&gt;
&lt;h2 id=&#34;卡住的不是按钮颜色&#34;&gt;卡住的不是按钮颜色
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;strategy_studio&lt;/code&gt; 不是一个只有两三个按钮的小工具。README 里对它的定位已经是中文优先的策略研究平台：Next.js 前端、FastAPI API、PostgreSQL、Worker、Scheduler 和 Yahoo 同步链路一起跑。前端 README 又把页面收敛成一个研究工作台：样本准备、实验配置、任务跟踪、结果复盘、模板维护，还有报告详情和运行维护入口。&lt;/p&gt;
&lt;p&gt;这种项目的前端问题，表面上是“不够好看”，实际是信息秩序没定下来。用户先看行情，还是先看回测任务？报告详情里曲线、指标、输入参数和重跑按钮谁更重要？首页是导航页，还是工作台？大屏上是铺满，还是留出呼吸感？&lt;/p&gt;
&lt;p&gt;这些判断只用文字描述，Codex 很容易理解成“在现有页面里优化一下”。它会改组件、调间距、换颜色，但仍然沿着旧结构走。允许破坏性重构也不够，因为破坏性重构解决的是“能不能大改代码”，不是“有没有一个可验收的视觉目标”。&lt;/p&gt;
&lt;p&gt;我白天出去一趟，晚上突然想到，别继续让 Codex 猜 UI 了。先在 ChatGPT 网页端把 UI 设计稿画出来，再把图交给 Codex 还原。&lt;/p&gt;
&lt;p&gt;当时用的提示词很直接：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;https://github.com/ttf248/strategy_studio 分析当前项目的前端代码，理解业务逻辑，作为专业的UI设计师、交互设计师，帮我重新设计一套前端页面，每个页面单独出图，记得适配 24寸、32寸显示器，元素不要太密集，方便用户使用聚焦核心功能。
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这一步出来的效果，比我继续在 Codex 里堆形容词要稳定得多。它先给了一个可见的目标：页面怎么排、模块比例怎么分、视觉中心在哪里、留白大概到什么程度。Codex 后面再接手时，任务就从“凭审美重设计”变成了“按图理解业务并还原代码”。&lt;/p&gt;
&lt;h2 id=&#34;配色也要先变成材料&#34;&gt;配色也要先变成材料
&lt;/h2&gt;&lt;p&gt;第一轮图已经解决了版面问题，但默认配色还是常规后台系统的蓝白，不太符合我的审美。如果这个时候再把“不喜欢蓝白，换个高级点的配色”丢给 Codex，本质上还是让它猜。&lt;/p&gt;
&lt;p&gt;这张就是最初那版蓝白配色。它已经能说明页面结构，但气质仍然偏普通管理后台。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://ttf248.life/p/codex-chatgpt-ui-mockup-workflow/strategy-studio-white-blue-blog.webp&#34;
	width=&#34;1200&#34;
	height=&#34;675&#34;
	
	loading=&#34;lazy&#34;
	
		alt=&#34;Strategy Studio 初版蓝白 UI 稿&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;后面我换了做法：先在 ChatGPT 网页端沟通配色方向，把底色、强调色、卡片层级和研究工具感说清楚，再让图像模型按这个方向出示意图。它不等于正式 Figma，也不是完整设计系统，但已经足够把前端重构最容易漂移的东西固定下来。&lt;/p&gt;
&lt;p&gt;最后拿到的不是一张“大而全首页”，而是按页面拆开的设计稿：首页、行情研究、回测实验、报告中心、报告详情、策略模板、运行维护。这个拆法很关键。&lt;code&gt;strategy_studio&lt;/code&gt; 的前端不是营销页，而是研究工具；首页、行情页和报告详情页承担的阅读任务不一样，不能都塞进同一套卡片网格。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://ttf248.life/p/codex-chatgpt-ui-mockup-workflow/strategy-studio-home-blog.webp&#34;
	width=&#34;1200&#34;
	height=&#34;675&#34;
	
	loading=&#34;lazy&#34;
	
		alt=&#34;Strategy Studio 首页设计稿&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://ttf248.life/p/codex-chatgpt-ui-mockup-workflow/strategy-studio-report-detail-blog.webp&#34;
	width=&#34;1200&#34;
	height=&#34;675&#34;
	
	loading=&#34;lazy&#34;
	
		alt=&#34;Strategy Studio 报告详情设计稿&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;177&#34;
		data-flex-basis=&#34;426px&#34;
	
&gt;&lt;/p&gt;
&lt;p&gt;图出来以后，Codex 的角色就清楚了。它不是从零当 UI 设计师，而是读现有业务逻辑、拆组件、调布局、对齐交互状态、跑 lint/build，再把旧前端重构到接近设计稿的目标状态。&lt;/p&gt;
&lt;h2 id=&#34;不是简单的网页版更聪明&#34;&gt;不是简单的“网页版更聪明”
&lt;/h2&gt;&lt;p&gt;后来我又查了一圈官方资料，想确认这件事能不能解释成“不同渠道的 ChatGPT 智力能力不一样”，或者“Codex 直接使用时功能被阉割”。这个说法太粗。&lt;/p&gt;
&lt;p&gt;OpenAI 对 Codex CLI 的描述，是本地终端里的 coding agent：它能在当前目录里读代码、改代码、运行命令。Codex web 则是在云端环境里处理代码任务。OpenAI 讲 Codex agent loop 时，重点也不是“模型凭空想出所有东西”，而是模型推理、上下文管理、工具调用、文件读写和命令执行一起构成软件任务。&lt;/p&gt;
&lt;p&gt;ChatGPT Images 是另一种入口。OpenAI Help 里对 Images in ChatGPT 的说明，是用户可以在对话里创建和编辑图片，也可以做 mockup 或创意视觉。这个产品形态天然更适合先探索视觉目标，因为它的交付物就是图，而不是马上动代码。&lt;/p&gt;
&lt;p&gt;所以这次差异，不是“谁更聪明”，而是任务形态不同。把“重新设计 UI”直接交给 Codex，它会站在代码仓库里思考：哪些文件要改、哪些组件不能破坏、怎么让构建通过。把同样的业务背景先交给 ChatGPT Images，它会先把抽象的审美和信息层级压成一张可见的目标图。&lt;/p&gt;
&lt;p&gt;这也解释了为什么后来 Codex 反而更好用。不是设计稿绕开了 Codex，而是设计稿给 Codex 补了上下文和验收标准。官方 Codex prompting 文档也强调，要给 Codex 相关文件、图片和清楚的完成标准。没有图时，“元素不要太密集”只是形容词；有图以后，它才变成可还原的布局约束。&lt;/p&gt;
&lt;h2 id=&#34;更顺的链路&#34;&gt;更顺的链路
&lt;/h2&gt;&lt;p&gt;这次之后，我会把这类前端重构拆成三段。&lt;/p&gt;
&lt;p&gt;第一段，先做视觉探索。让 ChatGPT 网页端读仓库、理解业务、按页面出图，再围绕配色、密度、大屏适配和视觉层级来回调。这个阶段的产物不是代码，而是目标图。&lt;/p&gt;
&lt;p&gt;第二段，把目标图和工程约束交给 Codex。提示词不要停在“重新设计 UI”，而要写清楚：以哪些图片为目标，哪些业务逻辑不能破坏，哪些页面允许破坏性重构，哪些测试和构建必须通过。&lt;/p&gt;
&lt;p&gt;第三段，进入工程还原。这里才适合让 Codex 开 goal 或连续任务模式：先读前端结构，再按页面拆分实施，每个页面完成后跑验证，最后统一检查交互和响应式。&lt;/p&gt;
&lt;p&gt;我以前容易把“提示词写得更狠”当成解决办法。现在看，前端重构里更有用的不是狠，而是把缺失的中间产物补上。没有 UI 稿时，破坏性重构只是拆得更大；有了 UI 稿以后，破坏性重构才有方向。&lt;/p&gt;
&lt;p&gt;这套流程也不是只适合 &lt;code&gt;strategy_studio&lt;/code&gt;。任何已经有业务逻辑、但前端长期靠边做边补的个人项目，都可以这么处理：先让图像模型把界面目标画出来，再让 Codex 把目标变成代码。模型之间不是谁替代谁，而是各自接自己更像工种的那一段。&lt;/p&gt;
&lt;h2 id=&#34;参考资料&#34;&gt;参考资料
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/ttf248/strategy_studio&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;ttf248/strategy_studio GitHub 仓库&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/ttf248/strategy_studio/blob/main/README.md&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Strategy Studio README&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/ttf248/strategy_studio/blob/main/frontend/README.md&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Strategy Studio Frontend README&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/ttf248/strategy_studio/tree/main/ui&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Strategy Studio UI 设计稿目录&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://help.openai.com/en/articles/11084440-images-in-chatgpt&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;OpenAI Help：Images in ChatGPT&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://help.openai.com/en/articles/9260256-chatgpt-capabilities-overview&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;OpenAI Help：ChatGPT Capabilities Overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://developers.openai.com/codex/cli&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;OpenAI Developers：Codex CLI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://developers.openai.com/codex/cloud&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;OpenAI Developers：Codex web&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://developers.openai.com/codex/prompting&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;OpenAI Developers：Codex prompting&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://openai.com/index/unrolling-the-codex-agent-loop/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;OpenAI：Unrolling the Codex agent loop&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;details class=&#34;article-notes&#34;&gt;
    &lt;summary&gt;写作附记&lt;/summary&gt;
    &lt;div class=&#34;article-notes__content&#34;&gt;
        &lt;h3 id=&#34;原始提示词&#34;&gt;原始提示词
&lt;/h3&gt;&lt;blockquote&gt;
&lt;p&gt;$blog-writer 日常使用 codex 调用 ChatGPT 模型进行代码，开源项目 &lt;a class=&#34;link&#34; href=&#34;https://github.com/ttf248/strategy_studio&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://github.com/ttf248/strategy_studio&lt;/a&gt; 开发的时候，开始没做 UI 稿，直接进行业务逻辑开发，导致前端界面没有规划，尝试直接在 codex 里面写提示词：允许破坏性重构，重新设计 UI、交互逻辑，怎么调整效果都不太行。这个时候，还没怀疑 codex 的问题，白天出去一趟，晚上灵光闪现，我是不是能在网页版，调用 image2 出一组 UI 设计稿，然后交付给 codex 开启 goal 模型进行还原开发，简单尝试下，没有任何问题，这是用到的提示词: &lt;a class=&#34;link&#34; href=&#34;https://github.com/ttf248/strategy_studio&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://github.com/ttf248/strategy_studio&lt;/a&gt; 分析当前项目的前端代码，理解业务逻辑，作为专业的UI设计师、交互设计师，帮我重新设计一套前端页面，每个页面单独出图，记得适配 24寸、32寸显示器，元素不要太密集，方便用户使用聚焦核心功能。此时已经效果不错了，但是这个默认的配色，常规的蓝白色，不符合我的审美，继续调整方案，我们先在网页沟通一组合适的配色，然后 image 根据配色，出个演示图，再用配色方案，结合前面的提示词，我们就能拿到：https://github.com/ttf248/strategy_studio/tree/main/ui。我写的内容很多，你整理下，用一篇稿子写完，我有疑惑的地方，你自己联网查资料，提供的 &lt;a class=&#34;link&#34; href=&#34;https://github.com/ttf248/strategy_studio/tree/main/ui&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://github.com/ttf248/strategy_studio/tree/main/ui&lt;/a&gt; 里面有很多图片，随便抽两张贴到博客里面。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;写作思路摘要&#34;&gt;写作思路摘要
&lt;/h3&gt;&lt;p&gt;这次重写保留了原文的判断和材料，但把开头从“先给完整答案”改成“先进入前端重构卡住的现场”。文章压掉了泛化模型评测，只写这次工作流里真正有效的转向：先把视觉目标变成图，再让 Codex 做工程还原。&lt;/p&gt;

    &lt;/div&gt;
&lt;/details&gt;</description>
        </item>
        <item>
        <title>Codex goal 把完成标准交给任务本身</title>
        <link>https://ttf248.life/p/codex-goal-command-explained/</link>
        <pubDate>Wed, 27 May 2026 20:11:41 +0800</pubDate>
        
        <guid>https://ttf248.life/p/codex-goal-command-explained/</guid>
        <description>&lt;p&gt;&lt;code&gt;/goal&lt;/code&gt; 最容易被误解成一条“让 agent 多干一会儿”的命令。&lt;/p&gt;
&lt;p&gt;这当然是它的表象。你给 Codex 一个目标，它可以围着这个目标持续推进，不是一轮回答完就停。但真正值得注意的不是“跑得久”，而是它把“做到什么算完”从一句临时提醒，变成了任务本身的一部分。&lt;/p&gt;
&lt;p&gt;普通 prompt 说的是下一步要做什么。&lt;code&gt;goal&lt;/code&gt; 更像给 agent 挂了一张验收单：目标是什么，边界在哪里，哪些验证必须通过，满足什么条件才可以收工。&lt;/p&gt;
&lt;h2 id=&#34;goal-不是继续按钮&#34;&gt;goal 不是继续按钮
&lt;/h2&gt;&lt;p&gt;如果只看命令形态，&lt;code&gt;/goal&lt;/code&gt; 很像一句增强版的“继续做，直到完成”。但这会把重点带偏。&lt;/p&gt;
&lt;p&gt;长任务最麻烦的地方，不是模型愿不愿意继续，而是每一轮结束以后，谁来判断还要不要继续。&lt;/p&gt;
&lt;p&gt;你让 agent 迁移一个前端项目，它可能改了路由就觉得完成了；你让它修一个测试，它可能让当前失败用例通过就停了；你让它重写一批文章，它可能改了几篇高风险稿就认为已经处理了重点。&lt;/p&gt;
&lt;p&gt;这些停点不一定是错的，但它们经常和人的验收口径不一样。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;goal&lt;/code&gt; 要解决的就是这件事：把验收口径提前写清楚，让后续每一轮都能围着它判断。&lt;/p&gt;
&lt;p&gt;一个松散目标是这样的：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/goal 帮我把前端迁到 Next.js
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;它的问题不是短，而是没有停机条件。Codex 可以迁几页，可以顺手重构组件，也可以一直补它认为该补的东西。&lt;/p&gt;
&lt;p&gt;更可用的写法应该接近这样：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/goal 把订单后台从 React Router 迁到 Next.js App Router。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;登录页、订单列表、订单详情和下单页的视觉行为要和旧版一致。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;不要改 API 合约和数据库 schema。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;每完成一批页面都跑 npm run build、npm test 和 Playwright 关键路径。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;只有这些验证都通过，才算完成。
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这段话多出来的不是废话，而是四个控制面：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;要素&lt;/th&gt;
					&lt;th&gt;作用&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;目标&lt;/td&gt;
					&lt;td&gt;最终要出现什么结果&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;边界&lt;/td&gt;
					&lt;td&gt;哪些接口、数据、文件或行为不能顺手动&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;验证&lt;/td&gt;
					&lt;td&gt;用什么证据证明它真的完成&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;停机&lt;/td&gt;
					&lt;td&gt;满足哪些条件以后才可以停&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;goal&lt;/code&gt; 抬高的就是这四件事。&lt;/p&gt;
&lt;h2 id=&#34;为什么它能跑很久&#34;&gt;为什么它能跑很久
&lt;/h2&gt;&lt;p&gt;Codex 能在 goal 下持续推进，不是因为一次回答被拉长了。&lt;/p&gt;
&lt;p&gt;真正的工作方式更接近一个循环：计划、执行、观察工具结果、修正，再决定是否继续。构建失败、测试失败、截图不一致、lint 报错、评估样本没过，都会把任务拉回下一轮。&lt;/p&gt;
&lt;p&gt;如果目标里写了验证方式，agent 就不只是凭感觉说“应该好了”。它需要拿到证据。证据没有回来，就继续查；证据失败，就继续修；证据都通过，才有资格收工。&lt;/p&gt;
&lt;p&gt;这就是为什么 &lt;code&gt;goal&lt;/code&gt; 适合迁移、重构、批量改稿、prompt eval、长链路排障这类任务。它们共同的特点是：一轮做不完，而且完成不能只靠主观判断。&lt;/p&gt;
&lt;p&gt;反过来，这样的目标就很危险：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/goal 想一个更高级的产品方案
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;它没有边界、没有验证，也没有停机条件。agent 可能跑很久，但跑久不等于有用。至少要写清楚产出几套方案、覆盖哪些约束、用什么标准筛掉、什么时候停。&lt;/p&gt;
&lt;h2 id=&#34;claude-code-也在处理同一件事&#34;&gt;Claude Code 也在处理同一件事
&lt;/h2&gt;&lt;p&gt;Claude Code 也有 &lt;code&gt;/goal&lt;/code&gt;，官方文档的说法更直白：用户设置 completion condition，Claude 会跨 turn 持续工作，直到条件满足。&lt;/p&gt;
&lt;p&gt;Claude Code 文档还提到，每一轮结束后会检查完成条件是否成立；如果不成立，就继续下一轮。这一点很关键，因为它把“继续”从模型自己的主观收尾里拿出来，变成一个额外的条件判断。&lt;/p&gt;
&lt;p&gt;两家的具体实现细节不必强行等同，但方向是一致的：终端 agent 开始从“执行下一条指令”，走向“围绕可验证目标持续推进”。&lt;/p&gt;
&lt;p&gt;可以简单分一下：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;能力&lt;/th&gt;
					&lt;th&gt;更像在解决什么问题&lt;/th&gt;
					&lt;th&gt;适合场景&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;/goal&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;明确完成条件，跨轮推进到可验证结果&lt;/td&gt;
					&lt;td&gt;迁移、重构、批量修复、长任务&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;/loop&lt;/code&gt; 或循环类能力&lt;/td&gt;
					&lt;td&gt;让同一任务按次数或条件反复执行&lt;/td&gt;
					&lt;td&gt;重试、生成候选、批量探索&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;hooks&lt;/td&gt;
					&lt;td&gt;在固定事件上自动执行规则&lt;/td&gt;
					&lt;td&gt;格式化、测试、通知、日志&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;子代理/多代理视图&lt;/td&gt;
					&lt;td&gt;把任务拆给不同工作线程观察和推进&lt;/td&gt;
					&lt;td&gt;并行分析、分模块实现、长期后台任务&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;记忆/项目说明文件&lt;/td&gt;
					&lt;td&gt;固化长期约束和仓库规则&lt;/td&gt;
					&lt;td&gt;团队规范、代码风格、工具入口&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;这张表里，&lt;code&gt;goal&lt;/code&gt; 的位置很清楚：它不是替代 hooks，也不是替代记忆。它管的是“这次任务做到什么程度算完成”。&lt;/p&gt;
&lt;h2 id=&#34;好-goal-要写得像验收条件&#34;&gt;好 goal 要写得像验收条件
&lt;/h2&gt;&lt;p&gt;我现在会把一个 goal 写成四行：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;目标：最终要出现什么用户可见结果。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;边界：哪些文件、接口、数据、视觉或行为不能乱动。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;验证：用哪些命令、测试、截图、评测或人工检查作为证据。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;停机：全部满足时停止；遇到哪些权限、事实、产品判断时暂停。
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这和普通 prompt 的区别很大。&lt;/p&gt;
&lt;p&gt;普通 prompt 更像下一步动作，goal 更像完成口径。它不是让人从流程里消失，而是把人的判断提前放进去。你不再每一轮提醒它“这个不算完成”，而是在一开始就把“什么算完成”写成后续必须服从的条件。&lt;/p&gt;
&lt;p&gt;所以，越想让 agent 自己跑，越要把目标写窄。&lt;/p&gt;
&lt;p&gt;越想少盯过程，越要把验证写实。&lt;/p&gt;
&lt;p&gt;越不想它跑偏，越要把边界写清楚。&lt;/p&gt;
&lt;p&gt;这才是 &lt;code&gt;goal&lt;/code&gt; 真正值得关注的地方。不是多一条命令，不是可以跑多久，而是终端 agent 开始把“谁来判断做完”这件事抬到台面上。&lt;/p&gt;
&lt;h2 id=&#34;参考资料&#34;&gt;参考资料
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://developers.openai.com/codex/use-cases/follow-goals&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Follow a goal | Codex use cases&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://developers.openai.com/codex/cli/slash-commands&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Slash commands in Codex CLI | OpenAI Developers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://developers.openai.com/blog/run-long-horizon-tasks-with-codex&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Run long horizon tasks with Codex | OpenAI Developers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://code.claude.com/docs/en/goal&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Keep Claude working toward a goal | Claude Code Docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;details class=&#34;article-notes&#34;&gt;
    &lt;summary&gt;写作附记&lt;/summary&gt;
    &lt;div class=&#34;article-notes__content&#34;&gt;
        &lt;h3 id=&#34;原始提示词&#34;&gt;原始提示词
&lt;/h3&gt;&lt;blockquote&gt;
&lt;p&gt;$blog-writer 详解 codex 新出的 goal 命令，工作原理是什么，为什么持续工作很长的时间，官方提供的案例是什么。claude code 有没有类似的命名，顺带整理近期 两家终端新出的，好用的、受欢迎的功能，整理为表格。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;写作思路摘要&#34;&gt;写作思路摘要
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;保留原文主判断：&lt;code&gt;goal&lt;/code&gt; 的核心不是命令名，而是完成条件。&lt;/li&gt;
&lt;li&gt;补回原始提示词里要求的 Claude Code 对比和终端功能表格。&lt;/li&gt;
&lt;li&gt;压掉“官方文档复述”，把重点放在如何写一个可用的 goal。&lt;/li&gt;
&lt;/ul&gt;
    &lt;/div&gt;
&lt;/details&gt;</description>
        </item>
        <item>
        <title>AI 会写代码后，新人的练级路线变了</title>
        <link>https://ttf248.life/p/when-ai-writes-code-how-juniors-level-up/</link>
        <pubDate>Mon, 27 Apr 2026 23:18:36 +0800</pubDate>
        
        <guid>https://ttf248.life/p/when-ai-writes-code-how-juniors-level-up/</guid>
        <description>&lt;p&gt;这几个月用 Claude、Codex 写代码，我最强烈的感受不是“程序员要没了”。&lt;/p&gt;
&lt;p&gt;更准确的说法是，很多以前会丢给新人练手的活，现在 AI 能先打一版了。脚手架、小功能、测试、文档、边角 bug，以前这些活不算高级，但很适合把一个人从“会语法”磨到“知道工程怎么回事”。&lt;/p&gt;
&lt;p&gt;对老手来说，AI 是提效工具。对新人来说，它更像把新手村拆短了。门没有关，但从入口走到能独立负责事情，中间能慢慢摔跤的地方变少了。&lt;/p&gt;
&lt;h2 id=&#34;被压缩的是练手机会&#34;&gt;被压缩的是练手机会
&lt;/h2&gt;&lt;p&gt;以前团队带新人，很多时候靠的不是精心设计的培训，而是一堆低风险任务。&lt;/p&gt;
&lt;p&gt;改一个页面，接一个接口，补几个 CRUD，修一个日志里能看出来的小 bug。活不大，也不体面，但它们有价值。新人会在这些任务里学会：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;需求怎么落到代码；&lt;/li&gt;
&lt;li&gt;接口怎么和数据对上；&lt;/li&gt;
&lt;li&gt;日志怎么读；&lt;/li&gt;
&lt;li&gt;测试为什么不能只看通过；&lt;/li&gt;
&lt;li&gt;线上系统为什么和本地 Demo 不一样。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;现在最容易被 AI 吃掉的，恰好就是这类活。&lt;/p&gt;
&lt;p&gt;企业当然会算账。一个有经验的人带着 AI，先让模型出草稿，再人工审一遍，可能比安排新人慢慢磨更快。尤其在预算收紧、交付压力大的时候，“先不补初级岗”会变成一个很自然的选择。&lt;/p&gt;
&lt;p&gt;所以问题不只是裁员。更隐蔽的问题是，不再补人。&lt;/p&gt;
&lt;p&gt;岗位还在，需求也还在，但原来那条“从小活开始练”的路径变窄了。&lt;/p&gt;
&lt;h2 id=&#34;老手为什么更吃红利&#34;&gt;老手为什么更吃红利
&lt;/h2&gt;&lt;p&gt;AI 写代码以后，老手反而更容易受益，这件事看起来有点反直觉。&lt;/p&gt;
&lt;p&gt;原因不复杂：老手知道什么时候该不信。&lt;/p&gt;
&lt;p&gt;模型生成一段代码，能不能编译只是第一层。真正麻烦的是后面几层：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;抽象是不是过早；&lt;/li&gt;
&lt;li&gt;错误是不是被吞掉；&lt;/li&gt;
&lt;li&gt;测试是不是只是在糊弄 CI；&lt;/li&gt;
&lt;li&gt;接口是不是破坏了隐含约定；&lt;/li&gt;
&lt;li&gt;这段改动下周还好不好维护。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些判断不靠打字速度，靠踩坑经验。&lt;/p&gt;
&lt;p&gt;Anthropic、METR、BLS、ILO 这些报告从不同角度都在指向类似的现实：AI 会改变任务结构，但不是把整份工作一次性抹掉。软件开发仍然需要人，只是“重复性编码”和“低判断力执行”的价值变薄了。&lt;/p&gt;
&lt;p&gt;这对老手是红利。因为 AI 把体力活压短以后，老手可以把更多时间放到设计、审查、边界和验证上。&lt;/p&gt;
&lt;p&gt;但对新人就尴尬了。你本来需要靠那些体力活长出判断力，现在这些活先被 AI 接走了一半。公司又希望你一上来就会审 AI、会拆需求、会判断质量。&lt;/p&gt;
&lt;p&gt;这像是要求新人跳过训练关，直接开始打中段 boss。&lt;/p&gt;
&lt;h2 id=&#34;新人要练的东西变了&#34;&gt;新人要练的东西变了
&lt;/h2&gt;&lt;p&gt;我不觉得新入行的人没路了。&lt;/p&gt;
&lt;p&gt;软件需求还在，系统越来越多，业务也不会因为 AI 会写代码就自动变简单。真正变的是入场能力。&lt;/p&gt;
&lt;p&gt;以前新人最重要的是“能把需求写成代码”。以后可能要多两层：&lt;/p&gt;
&lt;p&gt;第一，能把需求拆成 AI 能做的小任务。&lt;/p&gt;
&lt;p&gt;不是一句“帮我做个后台”，而是能说清楚当前目标、边界、输入输出、不能动哪些文件、完成后怎么验证。&lt;/p&gt;
&lt;p&gt;第二，能审 AI 的结果。&lt;/p&gt;
&lt;p&gt;这比写 prompt 难。审代码需要知道项目上下文，知道语言和框架的坑，也知道业务里哪些东西不能省。你要能指出“不对在哪里”，而不是只说“感觉不太好”。&lt;/p&gt;
&lt;p&gt;所以新人不能只练“让 AI 写”。还要练：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;自己从零写一遍小功能；&lt;/li&gt;
&lt;li&gt;读懂 AI 写的每一行；&lt;/li&gt;
&lt;li&gt;把模型输出拆成可验证的小步；&lt;/li&gt;
&lt;li&gt;让测试和日志告诉自己哪里错；&lt;/li&gt;
&lt;li&gt;复盘为什么第一版看起来对，后来又错了。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AI 可以加速，但不能替你完成这部分判断力训练。&lt;/p&gt;
&lt;h2 id=&#34;新手村还在只是要自己搭&#34;&gt;新手村还在，只是要自己搭
&lt;/h2&gt;&lt;p&gt;如果我是刚入行的人，我会刻意给自己留一些“低效率练习”。&lt;/p&gt;
&lt;p&gt;比如同一个小功能，先不用 AI 手写一版，再让 AI 写一版，对比差异。或者让 AI 写完以后，自己逐行解释，解释不出来就当作没学会。再或者故意把任务拆得很小，每轮只允许模型过一个检查点，不让它一口气把项目铺满。&lt;/p&gt;
&lt;p&gt;这听起来比“AI 帮我全写了”慢。&lt;/p&gt;
&lt;p&gt;但新人真正缺的不是代码产量，而是判断力的来源。你不亲自经历几个“看起来能跑，后来发现设计错了”的坑，就很难知道 AI 什么时候也在犯同样的错。&lt;/p&gt;
&lt;p&gt;老一辈所谓“古法编程”的价值，不是怀旧。它只是让人见过足够多的错误形态。见过以后，AI 给你一段代码，你才知道哪些地方要追问，哪些地方要加测试，哪些地方不能轻易信。&lt;/p&gt;
&lt;p&gt;所以新人不是不能用 AI，而是不能只用 AI。&lt;/p&gt;
&lt;p&gt;门没有关。只是以前团队和项目自然提供的新手村，正在被效率工具压缩。以后想进门的人，可能得自己搭一部分训练场。&lt;/p&gt;
&lt;p&gt;这不公平，但很现实。&lt;/p&gt;
&lt;h2 id=&#34;参考资料&#34;&gt;参考资料
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://www.weforum.org/reports/the-future-of-jobs-report-2025/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;The Future of Jobs Report 2025&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://www.bls.gov/ooh/computer-and-information-technology/software-developers.htm&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Software Developers, Quality Assurance Analysts, and Testers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://www.bls.gov/ooh/computer-and-information-technology/computer-programmers.htm&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Computer Programmers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://www.bls.gov/opub/mlr/2025/article/ai-impacts-in-bls-employment-projections.htm&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;AI impacts in BLS employment projections&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://www.anthropic.com/research/anthropic-economic-index-january-2026-report&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Anthropic Economic Index: Insights from the Latest Data&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://www.anthropic.com/research/economic-index-primitives&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Anthropic Economic Index: Tracking AI Use Across Work and Life&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://metr.org/blog/2025-07-10-early-2025-ai-experienced-os-dev-study/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Measuring the Impact of Early-2025 AI on Experienced Open-Source Developer Productivity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://www.ilo.org/publications/generative-ai-and-jobs-refined-global-index-occupational-exposure&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Generative AI and Jobs: A Refined Global Index of Occupational Exposure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://siepr.stanford.edu/publications/working-paper/generative-ai-work&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Generative AI at Work&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;details class=&#34;article-notes&#34;&gt;
    &lt;summary&gt;写作附记&lt;/summary&gt;
    &lt;div class=&#34;article-notes__content&#34;&gt;
        &lt;h3 id=&#34;原始提示词&#34;&gt;原始提示词
&lt;/h3&gt;&lt;blockquote&gt;
&lt;p&gt;AI 编程的一些思考，刚毕业的应届生，编码能力肯定是不如 claude、codex，对于老手，AI 能提效，但是 AI 导致企业大幅削减了初级程序员的岗位，本人毕业已经十年，经历了新人到老人的爬坑阶段，以后，但是新入行的呢，他们会怎么样？老一辈算是经历过古法编程，说白了，能识别出来AI写的是好的，还是不好的，毕竟当前阶段的AI还是会犯错。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;写作思路摘要&#34;&gt;写作思路摘要
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;保留原文核心问题：AI 提效老手，但压缩新人练手机会。&lt;/li&gt;
&lt;li&gt;把旧稿中过密的报告材料降级为支撑，把主线放回“新手村变窄”。&lt;/li&gt;
&lt;li&gt;不写求职鸡汤，只给出新人需要主动搭训练场的判断。&lt;/li&gt;
&lt;/ul&gt;
    &lt;/div&gt;
&lt;/details&gt;</description>
        </item>
        <item>
        <title>让 AI 写 Demo，检查点要比代码更小</title>
        <link>https://ttf248.life/p/ai-demo-fast-rework-faster/</link>
        <pubDate>Fri, 10 Apr 2026 15:39:51 +0800</pubDate>
        
        <guid>https://ttf248.life/p/ai-demo-fast-rework-faster/</guid>
        <description>&lt;p&gt;AI 写 C++ 小项目，最吓人的地方不是它写不出来，而是它太快写出来了。&lt;/p&gt;
&lt;p&gt;你只是想起一个最小 Demo，它三分钟给你铺好目录，接好三方库，补上日志、配置、异常和几个看起来很专业的类。项目甚至能跑。问题是，等你开始认真接业务，才发现自己还没搞清楚新库支持什么、构建链路怎么走、哪些抽象是必要的，返工已经排着队来了。&lt;/p&gt;
&lt;p&gt;我现在对 AI 编程的态度反而更保守：不是少用 AI，而是每一轮都把检查点压小。尤其 C++ 这种没有统一脚手架兜底的语言，前面让 AI 多做一点，后面就可能多还几步。&lt;/p&gt;
&lt;h2 id=&#34;快不是问题失去节奏才是问题&#34;&gt;快不是问题，失去节奏才是问题
&lt;/h2&gt;&lt;p&gt;人工写一个 C++ 小项目，常见节奏其实很土：&lt;/p&gt;
&lt;p&gt;先写 &lt;code&gt;main.cpp&lt;/code&gt;，让它能编。再加一小段业务逻辑，让它能跑。接着才考虑日志、配置、目录拆分和测试。每一步都不优雅，但每一步都知道自己换来了什么。&lt;/p&gt;
&lt;p&gt;AI 容易破坏这个节奏。&lt;/p&gt;
&lt;p&gt;它看到“写一个日志扫描工具”，可能顺手就给你：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;src/&lt;/code&gt;、&lt;code&gt;include/&lt;/code&gt;、&lt;code&gt;tests/&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fmt&lt;/code&gt;、&lt;code&gt;spdlog&lt;/code&gt;、&lt;code&gt;toml++&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;配置类、日志类、扫描类；&lt;/li&gt;
&lt;li&gt;错误处理、帮助信息、输出格式；&lt;/li&gt;
&lt;li&gt;甚至还会补一个 README。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些东西单看都不坏。真正的问题是，你的认知没有跟上项目展开速度。一个三方库引进来以后，安装方式、编译目标、异常模型、线程安全、平台差异，都可能变成后面的约束。你不理解这些约束，Demo 越完整，返工范围越大。&lt;/p&gt;
&lt;p&gt;所以 AI 编程里最该练的能力，不是让模型一次生成更多，而是让它每次只跨过一个你能验收的检查点。&lt;/p&gt;
&lt;h2 id=&#34;一个够用的小练习&#34;&gt;一个够用的小练习
&lt;/h2&gt;&lt;p&gt;我觉得可以拿一个很小的 C++ 工具练手：&lt;code&gt;logscan&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;它只做一件事：扫描一个目录里的日志文件，统计 &lt;code&gt;error&lt;/code&gt; 和 &lt;code&gt;warn&lt;/code&gt; 的数量，然后打印结果。&lt;/p&gt;
&lt;p&gt;题目不复杂，但刚好能覆盖小项目常见的几块：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;命令行入口；&lt;/li&gt;
&lt;li&gt;输出格式化；&lt;/li&gt;
&lt;li&gt;日志；&lt;/li&gt;
&lt;li&gt;配置文件；&lt;/li&gt;
&lt;li&gt;简单业务模块。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;关键是，不要让 AI 一口气做完。把它切成四轮。&lt;/p&gt;
&lt;h2 id=&#34;第一轮只接-fmt&#34;&gt;第一轮只接 fmt
&lt;/h2&gt;&lt;p&gt;第一轮只做输出。&lt;/p&gt;
&lt;p&gt;目标很小：根目录有一个 &lt;code&gt;CMakeLists.txt&lt;/code&gt;，有一个 &lt;code&gt;main.cpp&lt;/code&gt;，能用 &lt;code&gt;fmt&lt;/code&gt; 打印扫描目录和统计结果。业务扫描可以先是假数据。&lt;/p&gt;
&lt;p&gt;这一步的 prompt 可以写得很死：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;当前只完成一个检查点：项目能编译，main.cpp 能用 fmt 打印目录和统计结果。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;不要新增日志模块、配置模块、测试框架或复杂目录结构。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;先说明修改哪些文件，再给代码。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;完成后给出构建命令和预期输出。
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里不是不让 AI 发挥，而是先确认一件事：依赖怎么接进来，项目怎么编译，输出是否符合预期。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;fmt&lt;/code&gt; 有清楚的 CMake 用法，CMake 的 &lt;code&gt;FetchContent&lt;/code&gt; 也适合小项目起步。你可以让 AI 按其中一种方式做，但不要让它一轮里同时尝试 &lt;code&gt;find_package&lt;/code&gt;、手拷源码、&lt;code&gt;add_subdirectory&lt;/code&gt; 和包管理器。&lt;/p&gt;
&lt;p&gt;第一轮的目标不是“架构好看”，而是把构建链路钉住。&lt;/p&gt;
&lt;h2 id=&#34;第二轮再加日志&#34;&gt;第二轮再加日志
&lt;/h2&gt;&lt;p&gt;等第一轮能稳定编译，再上 &lt;code&gt;spdlog&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;这一步也要压住范围。不要一开始就让 AI 做滚动日志、按天切分、全局 logger 工厂和配置驱动。先只做控制台日志，最多再加一个简单文件日志。&lt;/p&gt;
&lt;p&gt;这一轮真正要确认的是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;日志初始化放在哪里；&lt;/li&gt;
&lt;li&gt;业务逻辑怎么拿 logger；&lt;/li&gt;
&lt;li&gt;正常输出和调试日志怎么分工；&lt;/li&gt;
&lt;li&gt;失败时日志里能看到什么。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;spdlog&lt;/code&gt; 能做很多事，但练习的重点不是把它所有能力都接上。重点是确认你的项目真的需要哪些能力。&lt;/p&gt;
&lt;p&gt;AI 很容易把“库支持”误写成“项目需要”。这一步要拦住它。&lt;/p&gt;
&lt;h2 id=&#34;第三轮才读配置&#34;&gt;第三轮才读配置
&lt;/h2&gt;&lt;p&gt;配置文件最容易膨胀。&lt;/p&gt;
&lt;p&gt;一个小工具本来只需要三个配置：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;扫描目录；&lt;/li&gt;
&lt;li&gt;关键字列表；&lt;/li&gt;
&lt;li&gt;是否输出到文件。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AI 可能会顺手写成配置中心、热更新、环境变量覆盖、默认值合并、校验层、错误码体系。不是这些东西没用，而是你还没证明现在需要它们。&lt;/p&gt;
&lt;p&gt;如果用 &lt;code&gt;toml++&lt;/code&gt;，这一轮只读一个 &lt;code&gt;config.toml&lt;/code&gt;，解析成一个很薄的 &lt;code&gt;AppConfig&lt;/code&gt; 结构体就够了。&lt;/p&gt;
&lt;p&gt;不要让配置层先于业务长大。配置只是服务当前工具，不是给未来所有想象中的版本做平台。&lt;/p&gt;
&lt;h2 id=&#34;第四轮再拆模块&#34;&gt;第四轮再拆模块
&lt;/h2&gt;&lt;p&gt;等输出、日志、配置都跑过，再拆业务模块。&lt;/p&gt;
&lt;p&gt;这时候可以收成几个文件：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;main.cpp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;app_config.h / app_config.cpp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;logger.h / logger.cpp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;log_scanner.h / log_scanner.cpp
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意顺序：是先跑通，再拆。&lt;/p&gt;
&lt;p&gt;第一步就把目录排得很漂亮，不一定让项目更清楚。很多时候只是视觉上完整，问题来源反而更难追。等每个依赖和职责都实际跑过一轮，再让 AI 帮你整理，返工成本会低很多。&lt;/p&gt;
&lt;h2 id=&#34;我现在只留三条规则&#34;&gt;我现在只留三条规则
&lt;/h2&gt;&lt;p&gt;网上 AI 编程规范很多，复杂到最后很难执行。我自己现在只保留三条。&lt;/p&gt;
&lt;p&gt;第一，每次引库前，先写一张“引库卡”：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;这个库解决什么问题；&lt;/li&gt;
&lt;li&gt;这次只用哪一两个能力；&lt;/li&gt;
&lt;li&gt;它会给构建、部署或运行带来什么约束；&lt;/li&gt;
&lt;li&gt;如果不用它，最小替代方案是什么。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;第二，每轮只过一个检查点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;能编译；&lt;/li&gt;
&lt;li&gt;能运行；&lt;/li&gt;
&lt;li&gt;能看到预期输出；&lt;/li&gt;
&lt;li&gt;能通过当前测试。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不要在同一轮里同时“顺手重构”“顺手补配置”“顺手引日志”。C++ 里最怕顺手，因为顺手会把问题来源弄脏。&lt;/p&gt;
&lt;p&gt;第三，每轮都要能回滚：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;这一步改了哪些文件；&lt;/li&gt;
&lt;li&gt;错了以后删哪里；&lt;/li&gt;
&lt;li&gt;回到上一步项目还能不能编。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这三条看起来不像什么新方法，甚至有点笨。但笨办法抗返工。AI 已经足够快了，人要补上的不是更快，而是把它的快切成能验收的小段。&lt;/p&gt;
&lt;h2 id=&#34;参考资料&#34;&gt;参考资料
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.anthropic.com/en/docs/claude-code/common-workflows&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Anthropic, Claude Code Common Workflows&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.anthropic.com/en/docs/claude-code/overview&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Anthropic, Claude Code Overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.github.com/en/copilot/tutorials/cloud-agent/get-the-best-results&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;GitHub Docs, Best practices for using GitHub Copilot to work on tasks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://cmake.org/cmake/help/latest/module/FetchContent.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;CMake Docs, FetchContent&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://fmt.dev/latest/get-started/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;{fmt} Get Started&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/gabime/spdlog&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;gabime/spdlog README&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/gabime/spdlog/wiki/Sinks&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;gabime/spdlog Wiki: Sinks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/marzer/tomlplusplus&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;marzer/tomlplusplus README&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;details class=&#34;article-notes&#34;&gt;
    &lt;summary&gt;写作附记&lt;/summary&gt;
    &lt;div class=&#34;article-notes__content&#34;&gt;
        &lt;h3 id=&#34;原始提示词&#34;&gt;原始提示词
&lt;/h3&gt;&lt;blockquote&gt;
&lt;p&gt;提示词：人工写项目，针对 C++ 这种不用手脚架的语言，第一个弄个 框架，从 main 开始拓展逻辑，逐步增加模块，比如配置文件、日志模块、迭代业务模块。我的习惯是每次都能确保编译，逐步重构，可能一开始不是最优解。AI 编程，现在很多时候，跳过了步骤，前期思考的太少，特别是引入新的三方库，AI 是能快速出个 Demo，但是由于我不清楚新引入三方库的细节，支持哪些功能，相关逻辑的返工率明显高于人工开发。有没有好的实战案例，让我学下，我知道网上有很多复杂的 AI 编程规范，我想要简单一些的，能快速落地的。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;写作思路摘要&#34;&gt;写作思路摘要
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;保留原始提示词里的 C++ 小项目、逐步编译、逐步重构和三方库返工问题。&lt;/li&gt;
&lt;li&gt;把旧稿的步骤教程压成一个练习路径，重点放在“每轮只过一个检查点”。&lt;/li&gt;
&lt;li&gt;删除泛泛的 AI 编程规范感，保留能立刻执行的三条规则。&lt;/li&gt;
&lt;/ul&gt;
    &lt;/div&gt;
&lt;/details&gt;</description>
        </item>
        <item>
        <title>VS Code 调 C&#43;&#43;，CMake 和 GDB Printer 要一起配</title>
        <link>https://ttf248.life/p/vscode-cpp-debug-prelaunch-cmake-gdb-printer/</link>
        <pubDate>Thu, 09 Apr 2026 19:21:36 +0800</pubDate>
        
        <guid>https://ttf248.life/p/vscode-cpp-debug-prelaunch-cmake-gdb-printer/</guid>
        <description>&lt;p&gt;以前我在 VS Code 里调 C++，配置基本就停在 &lt;code&gt;launch.json&lt;/code&gt;，最多再加一句 GDB。&lt;/p&gt;
&lt;p&gt;把 &lt;code&gt;program&lt;/code&gt; 填好，把 &lt;code&gt;gdb&lt;/code&gt; 填好，把断点打好。然后呢？然后每次调试前，自己去终端里 &lt;code&gt;cmake --build&lt;/code&gt; 一下。&lt;/p&gt;
&lt;p&gt;更烦的是，自定义的价格、合约、订单类型断下来以后，VS Code 调试窗口经常只能看到一堆内部字段。数据是对的，但是不说人话。&lt;/p&gt;
&lt;p&gt;这事离谱的地方在于，我以前看过的一些教程也差不多就写到 &lt;code&gt;launch.json&lt;/code&gt; 为止。直到最近让 AI 配一个新项目，它顺手加了 &lt;code&gt;preLaunchTask&lt;/code&gt; 和 &lt;code&gt;gdb_printers.py&lt;/code&gt;，我才反应过来：VS Code 调 C++，不只是把 GDB 启起来。调试前可以自动触发 CMake 编译，断点停住以后，也可以让 GDB 加载 Python 脚本，把业务类型处理成自己看得懂的样子。&lt;/p&gt;
&lt;p&gt;说实话，这不是什么黑科技。&lt;/p&gt;
&lt;p&gt;但是它刚好补上了 C++ 日常调试里两块很烦的空白：&lt;strong&gt;启动前构建&lt;/strong&gt;，以及&lt;strong&gt;断点后的变量展示&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id=&#34;以前只配了一半&#34;&gt;以前只配了一半
&lt;/h2&gt;&lt;p&gt;很多教程里的 &lt;code&gt;.vscode/launch.json&lt;/code&gt;，大概是这个意思：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;version&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;0.2.0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;configurations&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Debug with GDB&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;cppdbg&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;request&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;launch&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;program&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;${workspaceFolder}/build/debug/bin/vscode_cpp_debug_demo&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;args&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;stopAtEntry&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;cwd&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;${workspaceFolder}&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;MIMode&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;gdb&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;miDebuggerPath&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;/usr/bin/gdb&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;setupCommands&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;nt&#34;&gt;&amp;#34;description&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Enable pretty-printing for gdb&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;nt&#34;&gt;&amp;#34;text&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;-enable-pretty-printing&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;nt&#34;&gt;&amp;#34;ignoreFailures&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这段不能说错。&lt;/p&gt;
&lt;p&gt;VS Code 官方的 C++ 示例里，也是类似这一套结构：&lt;code&gt;type&lt;/code&gt; 用 &lt;code&gt;cppdbg&lt;/code&gt;，&lt;code&gt;MIMode&lt;/code&gt; 用 &lt;code&gt;gdb&lt;/code&gt;，&lt;code&gt;setupCommands&lt;/code&gt; 里打开 pretty-printing。&lt;/p&gt;
&lt;p&gt;但是少了一个关键动作。&lt;/p&gt;
&lt;p&gt;你点 F5 的时候，它会去启动 &lt;code&gt;program&lt;/code&gt; 指向的那个可执行文件。问题是，这个文件是不是刚刚编出来的？&lt;/p&gt;
&lt;p&gt;如果不是，那你调的就是上一次的旧程序。&lt;/p&gt;
&lt;p&gt;我以前就经常干这种蠢事。代码改了，断点也打了，调半天发现行为不对，最后才想起来：哦，刚刚没重新编译。&lt;/p&gt;
&lt;h2 id=&#34;prelaunchtask-才是那个钩子&#34;&gt;preLaunchTask 才是那个钩子
&lt;/h2&gt;&lt;p&gt;VS Code 的 Tasks，本质上就是把外部命令挂进编辑器。&lt;/p&gt;
&lt;p&gt;编译、测试、打包，原来要在终端敲，现在可以写到 &lt;code&gt;.vscode/tasks.json&lt;/code&gt;。然后 &lt;code&gt;launch.json&lt;/code&gt; 里的 &lt;code&gt;preLaunchTask&lt;/code&gt;，再按 label 去找那一个 task。&lt;/p&gt;
&lt;p&gt;一个最小的 CMake 项目，可以这么放：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── .vscode/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   ├── launch.json
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   └── tasks.json
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── CMakeLists.txt
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── src/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   └── main.cpp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;└── tools/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    └── gdb_printers.py
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;CMakeLists.txt&lt;/code&gt; 先写到够用：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cmake&#34; data-lang=&#34;cmake&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cmake_minimum_required&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;VERSION&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;3.16&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;project&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;vscode_cpp_debug_demo&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;LANGUAGES&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;CXX&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;CMAKE_CXX_STANDARD&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;20&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;CMAKE_CXX_STANDARD_REQUIRED&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;ON&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;CMAKE_RUNTIME_OUTPUT_DIRECTORY&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;CMAKE_BINARY_DIR&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;/bin&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;add_executable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;vscode_cpp_debug_demo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s&#34;&gt;src/main.cpp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后是 &lt;code&gt;.vscode/tasks.json&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;version&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;2.0.0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;tasks&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;label&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;cmake: configure debug&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;process&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;command&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;cmake&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;args&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;s2&#34;&gt;&amp;#34;-S&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;${workspaceFolder}&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;s2&#34;&gt;&amp;#34;-B&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;${workspaceFolder}/build/debug&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;s2&#34;&gt;&amp;#34;-DCMAKE_BUILD_TYPE=Debug&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;problemMatcher&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;label&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;cmake: build debug&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;process&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;command&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;cmake&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;args&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;s2&#34;&gt;&amp;#34;--build&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;${workspaceFolder}/build/debug&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;s2&#34;&gt;&amp;#34;--parallel&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;dependsOn&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;cmake: configure debug&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;group&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;kind&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;build&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;isDefault&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;problemMatcher&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;$gcc&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意这里的 &lt;code&gt;cmake --build&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;CMake 官方给的构建入口就是这个形式：&lt;code&gt;cmake --build &amp;lt;dir&amp;gt;&lt;/code&gt;。它会去调用背后的原生构建工具，比如 Make、Ninja、MSBuild 这一类。&lt;/p&gt;
&lt;p&gt;也就是说，VS Code 不需要知道你的项目到底该敲 &lt;code&gt;make&lt;/code&gt; 还是 &lt;code&gt;ninja&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;这件事交给 CMake。&lt;/p&gt;
&lt;h2 id=&#34;f5-之前先编译&#34;&gt;F5 之前，先编译
&lt;/h2&gt;&lt;p&gt;然后回到 &lt;code&gt;.vscode/launch.json&lt;/code&gt;，把 &lt;code&gt;preLaunchTask&lt;/code&gt; 补进去：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;version&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;0.2.0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;configurations&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;CMake Debug with GDB&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;cppdbg&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;request&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;launch&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;program&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;${workspaceFolder}/build/debug/bin/vscode_cpp_debug_demo&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;args&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;stopAtEntry&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;cwd&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;${workspaceFolder}&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;environment&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;externalConsole&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;MIMode&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;gdb&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;miDebuggerPath&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;/usr/bin/gdb&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;setupCommands&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;nt&#34;&gt;&amp;#34;description&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Enable pretty-printing for gdb&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;nt&#34;&gt;&amp;#34;text&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;-enable-pretty-printing&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;nt&#34;&gt;&amp;#34;ignoreFailures&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nt&#34;&gt;&amp;#34;preLaunchTask&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;cmake: build debug&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这一行才是重点：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;preLaunchTask&amp;#34;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;cmake: build debug&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;按 F5 的链路就变成了：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;launch.json
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  -&amp;gt; preLaunchTask
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    -&amp;gt; tasks.json: cmake: build debug
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      -&amp;gt; dependsOn: cmake: configure debug
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        -&amp;gt; cmake -S ... -B ...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      -&amp;gt; cmake --build ...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  -&amp;gt; gdb 启动最新的 program
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果是 Windows + MinGW，&lt;code&gt;program&lt;/code&gt; 大概率要改成带 &lt;code&gt;.exe&lt;/code&gt; 的路径，&lt;code&gt;miDebuggerPath&lt;/code&gt; 也要指到自己的 &lt;code&gt;gdb.exe&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;如果是 Visual Studio Generator 那种多配置生成器，构建参数通常还要加 &lt;code&gt;--config Debug&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;但是主线不变。&lt;/p&gt;
&lt;p&gt;调试前让 VS Code 先跑一次构建任务，别靠自己脑子记。&lt;/p&gt;
&lt;h2 id=&#34;还有一个痛点自定义类型看不懂&#34;&gt;还有一个痛点：自定义类型看不懂
&lt;/h2&gt;&lt;p&gt;只把编译链路打通，还不够。&lt;/p&gt;
&lt;p&gt;C++ 代码里稍微封装一点业务类型，VS Code 左边那个变量窗口就开始变得难看。&lt;/p&gt;
&lt;p&gt;比如下面这个例子。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;src/main.cpp&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;cstdint&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;string_view&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#include&lt;/span&gt; &lt;span class=&#34;cpf&#34;&gt;&amp;lt;vector&amp;gt;&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;namespace&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;market&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;Price&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int64_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;raw&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Price&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;from_double&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;double&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Price&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;static_cast&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int64_t&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;value&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;10000&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;double&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;to_double&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;static_cast&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;double&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raw&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;10000.0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;Instrument&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;symbol&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;16&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]{};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;Price&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;last&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Instrument&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;make_instrument&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;string_view&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;symbol&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;double&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;price&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;Instrument&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;instrument&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;snprintf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;instrument&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;symbol&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;instrument&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;symbol&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;%s&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;symbol&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;());&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;instrument&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;last&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Price&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;from_double&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;price&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;instrument&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// namespace market
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vector&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;market&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Instrument&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;watchlist&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;market&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;make_instrument&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;IF2406&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;3578.6&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;market&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;make_instrument&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;IH2406&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;2468.2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;market&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Price&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;limit&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;market&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Price&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;from_double&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;3600.5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 在这里打断点，观察 watchlist 和 limit。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;watchlist&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;empty&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;limit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raw&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;market::Price&lt;/code&gt; 在业务里是价格。&lt;/p&gt;
&lt;p&gt;但是调试器默认看到的可能只有：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;limit = {raw = 36005000}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;没错，数据是对的。&lt;/p&gt;
&lt;p&gt;但是我脑子里还要自己把 &lt;code&gt;36005000&lt;/code&gt; 换算成 &lt;code&gt;3600.5000&lt;/code&gt;。如果项目里有一堆 &lt;code&gt;Price&lt;/code&gt;、&lt;code&gt;Quantity&lt;/code&gt;、&lt;code&gt;OrderId&lt;/code&gt;、&lt;code&gt;Instrument&lt;/code&gt;、&lt;code&gt;AlgoState&lt;/code&gt;，调试窗口很快就变成结构体坟场。&lt;/p&gt;
&lt;p&gt;这个时候就该上 GDB pretty-printer 了。&lt;/p&gt;
&lt;p&gt;GDB 官方手册说得很直接：它提供了一套机制，可以用 Python 代码 pretty-print 值，而且这个机制同时适用于 MI 和命令行。&lt;/p&gt;
&lt;p&gt;VS Code 的 C++ 调试刚好走的就是 GDB/MI 这条路。&lt;/p&gt;
&lt;h2 id=&#34;给业务类型写一个-python-展示层&#34;&gt;给业务类型写一个 Python 展示层
&lt;/h2&gt;&lt;p&gt;新建 &lt;code&gt;tools/gdb_printers.py&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;gdb&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;gdb.printing&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;PricePrinter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;fm&#34;&gt;__init__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;val&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;val&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;val&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;to_string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;raw&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;val&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;raw&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;sa&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;raw&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;10000.0&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;.4f&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;InstrumentPrinter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;fm&#34;&gt;__init__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;val&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;val&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;val&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;to_string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;symbol&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;val&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;symbol&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;price_raw&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;bp&#34;&gt;self&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;val&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;last&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;][&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;raw&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;price&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;price_raw&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;10000.0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;sa&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;symbol&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; last=&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;price&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;.4f&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;build_pretty_printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;printer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;gdb&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;printing&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;RegexpCollectionPrettyPrinter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;market&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;add_printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Price&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;^market::Price$&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;PricePrinter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;printer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;add_printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Instrument&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;^market::Instrument$&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;InstrumentPrinter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;printer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;gdb&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;printing&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;register_pretty_printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;gdb&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;current_objfile&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;build_pretty_printer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;replace&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;True&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后在 &lt;code&gt;launch.json&lt;/code&gt; 的 &lt;code&gt;setupCommands&lt;/code&gt; 里把它 source 进去：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;setupCommands&amp;#34;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;description&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Enable pretty-printing for gdb&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;text&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;-enable-pretty-printing&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;ignoreFailures&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;description&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Load project pretty-printers&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;text&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;-interpreter-exec console \&amp;#34;source ${workspaceFolder}/tools/gdb_printers.py\&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;ignoreFailures&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;重新 F5。&lt;/p&gt;
&lt;p&gt;这时候再看调试窗口，&lt;code&gt;Price&lt;/code&gt; 的展示就应该接近：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;limit = 3600.5000
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;Instrument&lt;/code&gt; 也会从一坨数组、结构体，变成更接近业务的：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;IF2406 last=3578.6000
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里我故意说“接近”，因为 pretty-printer 要和编译器、类型名字、真实字段布局匹配。&lt;/p&gt;
&lt;p&gt;如果你的业务类型里面又套了 &lt;code&gt;std::vector&lt;/code&gt;、&lt;code&gt;std::array&lt;/code&gt;、智能指针，Python 脚本里访问的字段可能还要继续调。不要指望一个脚本通吃所有项目。&lt;/p&gt;
&lt;p&gt;但是思路是稳的。&lt;/p&gt;
&lt;p&gt;把“调试时人想看的样子”，单独写成一层 Python 展示逻辑。&lt;/p&gt;
&lt;h2 id=&#34;别把-launchjson-当成全部&#34;&gt;别把 launch.json 当成全部
&lt;/h2&gt;&lt;p&gt;现在再看这套配置，我觉得至少有三层。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;.vscode/launch.json&lt;/code&gt; 负责“怎么启动调试器”。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;.vscode/tasks.json&lt;/code&gt; 负责“启动调试器之前，先把项目编出来”。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;tools/gdb_printers.py&lt;/code&gt; 负责“断住以后，变量用人能看懂的方式展示”。&lt;/p&gt;
&lt;p&gt;以前我只配第一层。&lt;/p&gt;
&lt;p&gt;能用，但是很毛坯。&lt;/p&gt;
&lt;p&gt;真正顺手的 C++ 调试，不应该是“我先去终端编译一下，再回来按 F5，再在变量窗口里心算字段含义”。&lt;/p&gt;
&lt;p&gt;更舒服的链路应该是：按 F5，VS Code 自动跑 CMake，GDB 自动加载项目的 Python printer，断点停下来以后，调试窗口直接说业务语言。&lt;/p&gt;
&lt;p&gt;AI 这次帮我配项目，最有价值的地方倒不是生成了多少 C++ 代码。&lt;/p&gt;
&lt;p&gt;而是它把这些老工具之间的胶水也补上了。&lt;/p&gt;
&lt;p&gt;我以前不是不知道 CMake，也不是不知道 GDB。&lt;/p&gt;
&lt;p&gt;只是少配了中间那几个钩子。&lt;/p&gt;
&lt;h2 id=&#34;参考资料&#34;&gt;参考资料
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://code.visualstudio.com/docs/cpp/config-linux&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Using C++ on Linux in VS Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://code.visualstudio.com/docs/debugtest/tasks&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;VS Code: Integrate with External Tools via Tasks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://cmake.org/cmake/help/latest/manual/cmake.1.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;CMake cmake(1) manual&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://sourceware.org/gdb/current/onlinedocs/gdb.html/Pretty-Printing.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;GDB Manual: Pretty Printing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://sourceware.org/gdb/current/onlinedocs/gdb.html/Writing-a-Pretty_002dPrinter.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;GDB Manual: Writing a Pretty-Printer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;details class=&#34;article-notes&#34;&gt;
    &lt;summary&gt;写作附记&lt;/summary&gt;
    &lt;div class=&#34;article-notes__content&#34;&gt;
        &lt;h3 id=&#34;原始提示词&#34;&gt;原始提示词
&lt;/h3&gt;&lt;blockquote&gt;
&lt;p&gt;提示词：$blog-writer vscode 进行 C++ 开发，以前查看的教程，都只是简单的配置了 launch.json 里面的 gdb 调试信息，都没提到配置 preLaunchTask，能做到自动触发 cmake 编译，这还是 AI 配置新项目发现的好东西；如果代码有很多自定义的数据类型，vscode 调试窗口无法直接展示，可以引入 python 脚本进行预处理，这样都能展示了。针对上面的内容，都需要提供实际的代码案例。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;写作思路摘要&#34;&gt;写作思路摘要
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;主线放在“以前只配 launch.json，其实少了调试前构建和调试时展示两层胶水”。&lt;/li&gt;
&lt;li&gt;保留用户给出的触发点：AI 配新项目时发现 &lt;code&gt;preLaunchTask&lt;/code&gt; 可以自动触发 CMake 编译。&lt;/li&gt;
&lt;li&gt;代码案例按一个最小 CMake 项目组织，包含 &lt;code&gt;CMakeLists.txt&lt;/code&gt;、&lt;code&gt;tasks.json&lt;/code&gt;、&lt;code&gt;launch.json&lt;/code&gt;、C++ 自定义类型和 GDB Python pretty-printer。&lt;/li&gt;
&lt;li&gt;事实核验优先看 VS Code、CMake、GDB 官方文档；正文不翻译文档，只保留和这条调试链路有关的事实。&lt;/li&gt;
&lt;li&gt;对 pretty-printer 的边界做了提醒：类型名、标准库实现、字段布局会影响 Python 脚本，项目里要按自己的类型改。&lt;/li&gt;
&lt;/ul&gt;
    &lt;/div&gt;
&lt;/details&gt;</description>
        </item>
        <item>
        <title>AI 博客工程（三）：本地、在线和 MiniMax 怎么分工</title>
        <link>https://ttf248.life/p/how-i-split-local-online-and-minimax-models/</link>
        <pubDate>Fri, 03 Apr 2026 21:06:02 +0800</pubDate>
        
        <guid>https://ttf248.life/p/how-i-split-local-online-and-minimax-models/</guid>
        <description>&lt;p&gt;翻了一圈现在仓库里的配置，我反而更确定一件事：这套东西最后拼的不是单个模型有多强，而是每一层到底该让谁来承担成本。&lt;/p&gt;
&lt;p&gt;最明显的一个信号就是，当前生效的 &lt;code&gt;published.runtime.json&lt;/code&gt; 还是 2026 年 4 月 2 日生成的 &lt;code&gt;minimax-m2&lt;/code&gt;，但 2026 年 4 月 3 日 16:38 的 &lt;code&gt;5f17088&lt;/code&gt; 已经把 &lt;code&gt;blog-style-suite&lt;/code&gt; 的默认 provider 切到了本地 &lt;code&gt;LM Studio&lt;/code&gt; 里的 &lt;code&gt;gemma-4-26b-a4b&lt;/code&gt;。这看起来像前后不一致，其实不是，它恰好说明了这条流水线开始有了分工。&lt;/p&gt;
&lt;p&gt;这组文章到这里，前两篇已经把边界铺开了。&lt;a class=&#34;link&#34; href=&#34;https://ttf248.life/p/why-blog-writer-had-to-exist/&#34; &gt;第一篇&lt;/a&gt; 讲的是 &lt;code&gt;blog-writer&lt;/code&gt; 为什么会长出来，&lt;a class=&#34;link&#34; href=&#34;https://ttf248.life/p/how-blog-style-suite-split-style-and-token-cost/&#34; &gt;第二篇&lt;/a&gt; 讲的是 &lt;code&gt;blog-style-suite&lt;/code&gt; 怎么把风格学习和 token 成本拆开。最后这一篇，就收在最现实的问题上：本地模型、在线模型、&lt;code&gt;Minimax&lt;/code&gt;，到底该放在哪个工位上。&lt;/p&gt;
&lt;h2 id=&#34;训练风格数据不值得每一步都烧在线模型&#34;&gt;训练风格数据，不值得每一步都烧在线模型
&lt;/h2&gt;&lt;p&gt;风格数据这件事，一旦开始认真做，token 很快就会变成现实问题。&lt;/p&gt;
&lt;p&gt;不是你想不想省，而是你如果不分工，这套东西根本跑不久。&lt;/p&gt;
&lt;p&gt;以前最容易出现的误区，就是让一个在线模型把所有活都包了。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;扫历史文章&lt;/li&gt;
&lt;li&gt;做筛选&lt;/li&gt;
&lt;li&gt;做归类&lt;/li&gt;
&lt;li&gt;评分&lt;/li&gt;
&lt;li&gt;抽样本&lt;/li&gt;
&lt;li&gt;压风格&lt;/li&gt;
&lt;li&gt;最后再去写稿&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这么干的最大问题，不是“模型不够强”，而是每一步都在烧同一档成本。&lt;/p&gt;
&lt;p&gt;反过来想，哪些步骤必须在线，哪些步骤其实应该尽量本地化，哪些步骤甚至根本不该交给模型。&lt;/p&gt;
&lt;p&gt;只要这个边界不清楚，再强的模型进来，最后也只是在帮你重复做一堆本来能预处理掉的活。&lt;/p&gt;
&lt;h2 id=&#34;本地模型更适合脏活重活和反复试错&#34;&gt;本地模型更适合脏活、重活和反复试错
&lt;/h2&gt;&lt;p&gt;我现在越来越愿意把本地模型定义成生产侧的体力层。&lt;/p&gt;
&lt;p&gt;它不一定最强，也不一定每次都最漂亮，但它特别适合承担这些事情：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;反复试跑的构建&lt;/li&gt;
&lt;li&gt;风格数据的多轮压缩实验&lt;/li&gt;
&lt;li&gt;配置改动后的重新扫描&lt;/li&gt;
&lt;li&gt;对已有结构做低风险重算&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这类活的共同点很明显。&lt;/p&gt;
&lt;p&gt;不是单次价值极高，而是要反复跑、能容忍试错、并且最好别每一轮都重新付高价。&lt;/p&gt;
&lt;p&gt;当前 &lt;code&gt;scripts/blog-style-suite/config.json&lt;/code&gt; 已经切到了 &lt;code&gt;lm-studio-gemma4&lt;/code&gt;，这本身就说明判断在变。不是说本地 &lt;code&gt;gemma&lt;/code&gt; 一定比在线模型更强，而是生产侧这条链路，终于开始优先考虑“跑得起、跑得勤、能反复改”。&lt;/p&gt;
&lt;p&gt;这一点，其实和我前面写过的 &lt;a class=&#34;link&#34; href=&#34;https://ttf248.life/p/weaker-models-shouldnt-do-frontier-work/&#34; &gt;弱模型别硬上强活&lt;/a&gt; 是同一个逻辑。&lt;/p&gt;
&lt;p&gt;本地模型不一定适合总包复杂写稿，但很适合接那些脏活、重活、批量活。风格数据的预处理，本来就更像这一类任务。&lt;/p&gt;
&lt;h2 id=&#34;在线模型更适合收口不适合包办一切&#34;&gt;在线模型更适合收口，不适合包办一切
&lt;/h2&gt;&lt;p&gt;说本地模型适合生产侧，不等于在线模型就没价值了。&lt;/p&gt;
&lt;p&gt;在线模型真正值钱的地方，恰恰是最后那一下收口。&lt;/p&gt;
&lt;p&gt;比如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;根据最新资料补事实&lt;/li&gt;
&lt;li&gt;在更大上下文里整理论证&lt;/li&gt;
&lt;li&gt;处理需要联网核验的时间敏感信息&lt;/li&gt;
&lt;li&gt;把已经准备好的结构化风格资产，转成一篇能发出来的文章&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些动作对表达质量、事实整合、上下文理解要求更高，在线模型放在这里更值。&lt;/p&gt;
&lt;p&gt;也就是说，强模型更像总装线最后那几道工序。它不是不可以往前多干点，但如果你让它从头扫到尾，整个成本结构很快就会走形。&lt;/p&gt;
&lt;p&gt;这也是为什么 &lt;code&gt;blog-writer&lt;/code&gt; 在设计上只读发布位 &lt;code&gt;published.runtime.json&lt;/code&gt;，而不是写稿时再去切 provider、再去回扫 suite 目录。消费侧越轻，越适合让更强的模型专心把文章收好。&lt;/p&gt;
&lt;h2 id=&#34;minimax-的意义不只是多接了一个-provider&#34;&gt;Minimax 的意义，不只是多接了一个 provider
&lt;/h2&gt;&lt;p&gt;很多人看到 &lt;code&gt;Minimax&lt;/code&gt;，第一反应可能是：无非又多接了一个模型。&lt;/p&gt;
&lt;p&gt;我觉得不是。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Minimax&lt;/code&gt; 真正有价值的地方，是它把“多 provider 输出，同一发布契约消费”这条路走通了。&lt;/p&gt;
&lt;p&gt;2026 年 4 月 2 日 10:18 的 &lt;code&gt;9f15199&lt;/code&gt; 把 &lt;code&gt;blog-style-suite&lt;/code&gt; 改成了多模型配置，输出按 provider 隔离。后面 README 和 runtime 结构也一直在强调一件事：suite 可以生成很多份结果，但真正生效的只有人工挑出来的 &lt;code&gt;published.runtime.json&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;这个边界特别重要。&lt;/p&gt;
&lt;p&gt;因为一旦边界明确了，&lt;code&gt;Minimax&lt;/code&gt; 的角色就不再是“必须绑定在写稿流程里”，而变成了：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;它可以参与生产侧的对比&lt;/li&gt;
&lt;li&gt;可以用来生成一版 runtime&lt;/li&gt;
&lt;li&gt;可以和本地模型产物横向比较&lt;/li&gt;
&lt;li&gt;最后由人工决定哪一版发布&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这就把 provider 从“系统依赖”变成了“可替换部件”。&lt;/p&gt;
&lt;p&gt;我觉得这是 &lt;code&gt;Minimax&lt;/code&gt; 在这套工程里最有意思的意义。它不是来统治整条链路的，它是来验证这条链路到底有没有把接口收干净。&lt;/p&gt;
&lt;h2 id=&#34;真正的分工不是按模型强弱分是按任务类型分&#34;&gt;真正的分工，不是按模型强弱分，是按任务类型分
&lt;/h2&gt;&lt;p&gt;我现在更认同一种很土，但很管用的划分法。&lt;/p&gt;
&lt;h3 id=&#34;规则和硬约束&#34;&gt;规则和硬约束
&lt;/h3&gt;&lt;p&gt;交给本地脚本。&lt;/p&gt;
&lt;p&gt;能用 &lt;code&gt;scanner.py&lt;/code&gt;、&lt;code&gt;write_post.py&lt;/code&gt;、&lt;code&gt;write_post_series.py&lt;/code&gt; 这种确定性工具解决的，就别让模型掺和。&lt;/p&gt;
&lt;h3 id=&#34;风格数据生产&#34;&gt;风格数据生产
&lt;/h3&gt;&lt;p&gt;优先交给本地模型或成本更低的 provider。&lt;/p&gt;
&lt;p&gt;因为这里最重要的是可重复、可试错、可缓存，不是单次输出必须最华丽。&lt;/p&gt;
&lt;h3 id=&#34;最终写稿和事实收口&#34;&gt;最终写稿和事实收口
&lt;/h3&gt;&lt;p&gt;交给更适合长上下文整合、表达收束、联网补事实的模型。&lt;/p&gt;
&lt;p&gt;这一层才是在线模型最值得花钱的地方。&lt;/p&gt;
&lt;p&gt;这么一拆，很多原来纠结的问题反而没那么复杂了。你不需要每天争论“到底哪个模型最强”，你只需要问一句：这个任务属于哪一层。&lt;/p&gt;
&lt;h2 id=&#34;到最后最值钱的不是模型而是边界清楚&#34;&gt;到最后，最值钱的不是模型，而是边界清楚
&lt;/h2&gt;&lt;p&gt;第三篇我就收在这里。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;blog-writer&lt;/code&gt; 和 &lt;code&gt;blog-style-suite&lt;/code&gt; 这套东西一路演化下来，我觉得最值钱的，不是又接了谁、又换了谁、又试了哪个 provider。&lt;/p&gt;
&lt;p&gt;最值钱的是边界终于越来越清楚了。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;blog-writer&lt;/code&gt; 管消费侧&lt;/li&gt;
&lt;li&gt;&lt;code&gt;blog-style-suite&lt;/code&gt; 管生产侧&lt;/li&gt;
&lt;li&gt;&lt;code&gt;published.runtime.json&lt;/code&gt; 是发布位&lt;/li&gt;
&lt;li&gt;本地模型更适合反复跑的脏活和重活&lt;/li&gt;
&lt;li&gt;在线模型更适合最后的收口&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Minimax&lt;/code&gt; 这类在线 provider 更像可替换部件，而不是系统中枢&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;边界一清楚，整个工作流就顺了。&lt;/p&gt;
&lt;p&gt;你不会再指望一个模型包打天下，也不会再把每一步都堆到最贵那一层去做。到最后，这件事看起来是在选模型，实际上是在给不同类型的任务安排工位。&lt;/p&gt;
&lt;p&gt;说白了，单点更强当然好。&lt;/p&gt;
&lt;p&gt;但长期跑下来，边界清楚，往往比单点更强更重要。&lt;/p&gt;
&lt;h2 id=&#34;参考资料&#34;&gt;参考资料
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;仓库提交：&lt;a class=&#34;link&#34; href=&#34;https://github.com/ttf248/notebook/commit/9f1519967981c5eef7bd1eb407b0406ac542ebd0&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;&lt;code&gt;9f1519967981c5eef7bd1eb407b0406ac542ebd0&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库提交：&lt;a class=&#34;link&#34; href=&#34;https://github.com/ttf248/notebook/commit/5f17088391ee858b88fc50df884bc0103ff0b3c1&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;&lt;code&gt;5f17088391ee858b88fc50df884bc0103ff0b3c1&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库文件：&lt;code&gt;scripts/blog-style-suite/config.json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;生效运行时：&lt;code&gt;.agents/data/blog-writing/published.runtime.json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;相关旧文：&lt;a class=&#34;link&#34; href=&#34;https://ttf248.life/p/a-long-period-of-deep-ai-programming/&#34; &gt;重度AI编程的一段日子&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;相关旧文：&lt;a class=&#34;link&#34; href=&#34;https://ttf248.life/p/ultimately-its-returning-to-domestic-models/&#34; &gt;终归还是回到国产模型&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;相关旧文：&lt;a class=&#34;link&#34; href=&#34;https://ttf248.life/p/weaker-models-shouldnt-do-frontier-work/&#34; &gt;弱模型别硬上强活&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;details class=&#34;article-notes&#34;&gt;
    &lt;summary&gt;写作附记&lt;/summary&gt;
    &lt;div class=&#34;article-notes__content&#34;&gt;
        &lt;h3 id=&#34;原始提示词&#34;&gt;原始提示词
&lt;/h3&gt;&lt;blockquote&gt;
&lt;p&gt;$blog-writer 本次的内容比较多，拆分成系列文章：去年就有很多稿子是通过大模型写的，那会是自己写个大纲或者问题清单，然后AI出稿子，复制内容到本地 md 文档，填写头信息，标签信息、发布文章；近期 codex 用了很多，发现 codex 里面的联网搜索能力很强，那我是不是能写个 skill，将这些事情自动化，此时诞生了 skill blog-writer 的第一稿，我还想着让 AI 学习我以前文章的风格，这就导致 blog-writer 运行的时候，很费 token，后续我针对 blog-writer 进行了多个版本的优化，拆分了 数据模块，数据生成的模块，原本数据生成的模块还是独立的 skill，写着写着，我就发现，更适合做成 Python 项目，此时就有了 blog-style-suite，然后我又发现，训练风格数据，也是比较费 token，我就想着用本地的大模型，对接了本地的大模型，我又想到了对比下本地大模型和在线版本的区别，又对接了 minimax；blog-style-suite 和 blog-writer 的演化历史可以分析的 git 提价记录。顺带基于本地 blog-writer、blog-style-suite 的代码，可以讲讲里面的设计思路，是如何做到了节约 token，数据结构是如何设计的，核心的设计思路。Token 富裕完全能生吃历史文章，预处理能节约很多 token&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;写作思路摘要&#34;&gt;写作思路摘要
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;第三篇不再重复讲架构，而是把“模型分工”这个现实问题单独收口。&lt;/li&gt;
&lt;li&gt;直接用当前仓库里 &lt;code&gt;published.runtime.json&lt;/code&gt; 还是 &lt;code&gt;minimax-m2&lt;/code&gt;、&lt;code&gt;config.json&lt;/code&gt; 已切到本地 &lt;code&gt;gemma4&lt;/code&gt; 这个事实开篇，减少空话。&lt;/li&gt;
&lt;li&gt;重点不是证明谁更强，而是说明为什么不同任务该由不同成本层来承担。&lt;/li&gt;
&lt;li&gt;把 &lt;code&gt;Minimax&lt;/code&gt; 放在“可替换 provider”这个位置上讲，是为了把它的意义拉回工程边界，而不是模型榜单。&lt;/li&gt;
&lt;li&gt;结尾回到“边界清楚比单点更强更重要”这个总判断，作为整组文章的收口。&lt;/li&gt;
&lt;/ul&gt;
    &lt;/div&gt;
&lt;/details&gt;</description>
        </item>
        <item>
        <title>AI 博客工程（二）：把风格学习和 token 成本拆开</title>
        <link>https://ttf248.life/p/how-blog-style-suite-split-style-and-token-cost/</link>
        <pubDate>Fri, 03 Apr 2026 21:02:02 +0800</pubDate>
        
        <guid>https://ttf248.life/p/how-blog-style-suite-split-style-and-token-cost/</guid>
        <description>&lt;p&gt;如果 token 足够，最省脑子的办法其实很粗暴：把历史文章直接塞给模型，让它自己学。&lt;/p&gt;
&lt;p&gt;问题在于，这种办法只适合偶尔来一篇，不适合反复写。你要是真把博客写作当成长期工作流来做，生吃历史文章这条路，很快就会从“简单直接”变成“又贵又乱”。&lt;/p&gt;
&lt;p&gt;这组文章讲到这里，主线已经变了。上一篇 &lt;a class=&#34;link&#34; href=&#34;https://ttf248.life/p/why-blog-writer-had-to-exist/&#34; &gt;AI 写博客这件事，后来还是得做成工程（一）：blog-writer 为什么会长出来&lt;/a&gt; 讲的是消费侧的自动化；这一篇开始讲生产侧，也就是风格数据怎么生成、怎么压缩、怎么别把 token 白白烧掉；下一篇会接着收在 &lt;a class=&#34;link&#34; href=&#34;https://ttf248.life/p/how-i-split-local-online-and-minimax-models/&#34; &gt;AI 写博客这件事，后来还是得做成工程（三）：本地模型、在线模型和 Minimax 最后怎么分工&lt;/a&gt;。&lt;/p&gt;
&lt;h2 id=&#34;一开始最自然的想法就是直接喂历史文章&#34;&gt;一开始最自然的想法，就是直接喂历史文章
&lt;/h2&gt;&lt;p&gt;这条路真的太自然了。&lt;/p&gt;
&lt;p&gt;你既然想让模型学会你的写法，那最直观的办法当然就是把旧文章喂给它。最好把历史博客里写得最像自己的那些都塞进去，让它自己总结。&lt;/p&gt;
&lt;p&gt;单看一次任务，这么干没什么毛病。&lt;/p&gt;
&lt;p&gt;甚至很多时候效果还不错。上下文够长，模型够强，历史文章够多，风格确实能被带出来。&lt;/p&gt;
&lt;p&gt;但问题不是“这一篇能不能写成”，问题是“下一篇、下下篇，还要不要再来一遍”。&lt;/p&gt;
&lt;p&gt;每次都重新喂一批旧文章，会带来几个很现实的副作用：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;同一批材料反复占上下文&lt;/li&gt;
&lt;li&gt;token 开销和写稿次数近乎线性增长&lt;/li&gt;
&lt;li&gt;模型看到的噪音越来越多，真正有用的信号反而被稀释&lt;/li&gt;
&lt;li&gt;写稿动作和风格维护动作彻底绑死，谁都轻不下来&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;也就是说，token 富裕的时候，生吃当然能吃。但工程上不能老这么吃。&lt;/p&gt;
&lt;h2 id=&#34;这也是为什么数据模块和数据生成模块必须拆开&#34;&gt;这也是为什么数据模块和数据生成模块必须拆开
&lt;/h2&gt;&lt;p&gt;我后来把这件事想明白，核心就一句话：消费侧和生产侧得分开。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;blog-writer&lt;/code&gt; 负责的是消费侧。它只管读一份已经发布好的 runtime，然后把文章按固定契约写出来。&lt;/p&gt;
&lt;p&gt;而风格数据的扫描、筛选、评分、压缩、provider 对比，这些都应该放到另一条生产侧流水线里。也就是后来长出来的 &lt;code&gt;blog-style-suite&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;从 git 记录看，这个转折很清楚。&lt;/p&gt;
&lt;p&gt;2026 年 4 月 1 日 21:47 的 &lt;code&gt;84a06b5&lt;/code&gt;，已经明确把原来的 &lt;code&gt;blog-style-maintainer&lt;/code&gt; skill 换成了仓库级 CLI 工具。这个动作很说明问题，因为一旦你有了 &lt;code&gt;scan/build/rebuild&lt;/code&gt;、有了输出目录、有了恢复机制，事情就已经不像一个 skill 了，更像一个正常的 Python 项目。&lt;/p&gt;
&lt;p&gt;再到 2026 年 4 月 1 日 23:05 的 &lt;code&gt;9e92b8e&lt;/code&gt;，&lt;code&gt;blog-style-suite&lt;/code&gt; 继续被拆成 &lt;code&gt;scanner.py&lt;/code&gt;、&lt;code&gt;builder.py&lt;/code&gt;、&lt;code&gt;compressor.py&lt;/code&gt; 这些模块。到这一步，思路其实已经非常工程化了：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;scanner.py&lt;/code&gt; 负责把文章从磁盘里扫出来，提取结构化特征&lt;/li&gt;
&lt;li&gt;&lt;code&gt;builder.py&lt;/code&gt; 负责评分、精选、缓存、运行时装配&lt;/li&gt;
&lt;li&gt;&lt;code&gt;compressor.py&lt;/code&gt; 负责该让模型参与的那几步压缩&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这和单纯写一段超级 prompt，已经是两种完全不同的思路了。&lt;/p&gt;
&lt;h2 id=&#34;省-token不靠玄学靠的是预处理和批量化&#34;&gt;省 token，不靠玄学，靠的是预处理和批量化
&lt;/h2&gt;&lt;p&gt;2026 年 4 月 2 日 19:41 的 &lt;code&gt;bc4b950&lt;/code&gt; 是关键的一次提交。&lt;/p&gt;
&lt;p&gt;那次提交把话说得很直白，AI 调用从大约 &lt;code&gt;2000&lt;/code&gt; 次，直接降到了每个 provider 最多 &lt;code&gt;5&lt;/code&gt; 次。&lt;/p&gt;
&lt;p&gt;怎么做到的？&lt;/p&gt;
&lt;p&gt;不是靠“把 prompt 改得更聪明”，而是靠把该预处理的东西提前做掉。&lt;/p&gt;
&lt;p&gt;现在 &lt;code&gt;blog-style-suite&lt;/code&gt; 的流程，已经很清楚了：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;scan&lt;/code&gt; 阶段纯启发式，0 次 AI 调用&lt;/li&gt;
&lt;li&gt;&lt;code&gt;build&lt;/code&gt; 阶段先做启发式评分，还是 0 次 AI 调用&lt;/li&gt;
&lt;li&gt;再按 &lt;code&gt;technical / finance / essay / tooling&lt;/code&gt; 四个 lane 各做 1 次批量精选和打标签&lt;/li&gt;
&lt;li&gt;最后再做 1 次作者风格压缩&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这样算下来，冷启动最多也就是 5 次调用。&lt;/p&gt;
&lt;p&gt;更关键的是，这 5 次不是分散在每一篇文章上，而是集中在已经被预处理过的、高价值的摘要材料上。&lt;/p&gt;
&lt;p&gt;这就是预处理真正省 token 的地方。不是少省几个字，而是从“按文章逐篇调用”改成“按阶段集中调用”。&lt;/p&gt;
&lt;p&gt;再往后，缓存也补上了。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;builder.py&lt;/code&gt; 里有 lane 的 batch fingerprint，有 provider checkpoint 恢复，有 &lt;code&gt;review_pool_per_lane = 12&lt;/code&gt; 这种为了本地模型上下文做的收缩。你要改一小部分数据，不会整条流水线重跑。&lt;/p&gt;
&lt;p&gt;这类设计看起来都不炫，但每一个都很实用。因为它们解决的都是“别让同一批 token 反复烧第二次”。&lt;/p&gt;
&lt;h2 id=&#34;现在这套数据结构本质上就是在压缩真正有用的信号&#34;&gt;现在这套数据结构，本质上就是在压缩真正有用的信号
&lt;/h2&gt;&lt;p&gt;这一套拆完以后，数据结构也就顺了。&lt;/p&gt;
&lt;p&gt;我现在更愿意把它理解成三层。&lt;/p&gt;
&lt;h3 id=&#34;第一层scanjson&#34;&gt;第一层：&lt;code&gt;scan.json&lt;/code&gt;
&lt;/h3&gt;&lt;p&gt;这是共享原料。&lt;/p&gt;
&lt;p&gt;里面放的是文章路径、标题、日期、分类、标签、开头段落、closing stub、headings、screening 结果、lane 归类这些结构化信号。&lt;/p&gt;
&lt;p&gt;它不是给 &lt;code&gt;blog-writer&lt;/code&gt; 直接吃的，它是给生产侧继续往下加工的。&lt;/p&gt;
&lt;h3 id=&#34;第二层providersourcejson&#34;&gt;第二层：&lt;code&gt;{provider}.source.json&lt;/code&gt;
&lt;/h3&gt;&lt;p&gt;这是 provider 级 checkpoint。&lt;/p&gt;
&lt;p&gt;在共享原料的基础上，多了评分结果、lane selection、fingerprint、cache status 这些中间态。也就是说，它更像“加工过程中的半成品”，重点是可恢复、可复用、可中断继续。&lt;/p&gt;
&lt;h3 id=&#34;第三层providerruntimejson-和-publishedruntimejson&#34;&gt;第三层：&lt;code&gt;{provider}.runtime.json&lt;/code&gt; 和 &lt;code&gt;published.runtime.json&lt;/code&gt;
&lt;/h3&gt;&lt;p&gt;这才是消费侧真正关心的成品。&lt;/p&gt;
&lt;p&gt;里面保留的是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;author_style&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lanes&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;samples&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;writer_guide&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;也就是把原来一大堆历史文章，压成一份可直接消费的运行时风格资产。&lt;/p&gt;
&lt;p&gt;尤其是 &lt;code&gt;published.runtime.json&lt;/code&gt; 这个发布位很关键。&lt;code&gt;blog-writer&lt;/code&gt; 只读这一份，不回头去扫 &lt;code&gt;content/post&lt;/code&gt;，也不关心 suite 目录下所有 provider 的完整镜像。&lt;/p&gt;
&lt;p&gt;这个边界一旦立住，消费侧就轻了。写稿模型看到的，不再是一堆原始旧文，而是一份已经预处理好的高密度信号。&lt;/p&gt;
&lt;h2 id=&#34;不是所有事情都该让模型做&#34;&gt;不是所有事情都该让模型做
&lt;/h2&gt;&lt;p&gt;我现在越来越认同一个判断：其实不是“多接几个模型”，而是“别把不该让模型做的事也扔给模型”。&lt;/p&gt;
&lt;p&gt;像这些事情，就很适合本地规则先做掉：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;frontmatter 解析&lt;/li&gt;
&lt;li&gt;开头段落提取&lt;/li&gt;
&lt;li&gt;headings 抽取&lt;/li&gt;
&lt;li&gt;本人/转载/模型署名判断&lt;/li&gt;
&lt;li&gt;blockquote 比例检测&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;!--more--&amp;gt;&lt;/code&gt;、嵌入 prompt、正文长度这类硬规则筛掉&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些动作让模型来做，不是不行，是浪费。&lt;/p&gt;
&lt;p&gt;模型更适合做的，是那些带模糊性、带取舍的部分。比如一个 lane 里哪几篇更能代表当前声音，或者从高分文章里提炼作者风格标签。&lt;/p&gt;
&lt;p&gt;所以 &lt;code&gt;blog-style-suite&lt;/code&gt; 真正值钱的，不只是“省 token”，而是它把人、规则、模型三者各自该干的活重新分了一次。&lt;/p&gt;
&lt;h2 id=&#34;预处理不是为了省一点-token是为了让写稿这件事可持续&#34;&gt;预处理不是为了省一点 token，是为了让写稿这件事可持续
&lt;/h2&gt;&lt;p&gt;第二篇的结论，我想压得更直接一点。&lt;/p&gt;
&lt;p&gt;token 富裕的时候，生吃历史文章当然没问题。甚至你真只写一两篇，可能还更省脑子。&lt;/p&gt;
&lt;p&gt;但只要你想把这件事做成长期工作流，预处理就不是可选项了。因为你不做预处理，写稿模型每次都得重复看旧材料，风格维护和文章生成也永远搅在一起。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;blog-style-suite&lt;/code&gt; 的意义，就是把这一团东西拆开。&lt;/p&gt;
&lt;p&gt;不是为了显得系统，不是为了多一个项目名，而是为了让 &lt;code&gt;blog-writer&lt;/code&gt; 保持轻，保持稳，保持“只干写稿这一个动作”。&lt;/p&gt;
&lt;p&gt;到了这里，下一步的问题也就顺理成章了。&lt;/p&gt;
&lt;p&gt;既然生产侧已经独立出来了，那到底该让什么模型来承担这部分成本？本地模型、在线模型、&lt;code&gt;Minimax&lt;/code&gt;，分别该站在哪个工位上？这件事，留到下一篇 &lt;a class=&#34;link&#34; href=&#34;https://ttf248.life/p/how-i-split-local-online-and-minimax-models/&#34; &gt;AI 写博客这件事，后来还是得做成工程（三）：本地模型、在线模型和 Minimax 最后怎么分工&lt;/a&gt;。&lt;/p&gt;
&lt;h2 id=&#34;参考资料&#34;&gt;参考资料
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;仓库提交：&lt;a class=&#34;link&#34; href=&#34;https://github.com/ttf248/notebook/commit/84a06b5dc743f2e9bc6e788d53496a1261bc63ae&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;&lt;code&gt;84a06b5dc743f2e9bc6e788d53496a1261bc63ae&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库提交：&lt;a class=&#34;link&#34; href=&#34;https://github.com/ttf248/notebook/commit/9e92b8e6a15d03e6392aff7f3b2dcb0992fe5043&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;&lt;code&gt;9e92b8e6a15d03e6392aff7f3b2dcb0992fe5043&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库提交：&lt;a class=&#34;link&#34; href=&#34;https://github.com/ttf248/notebook/commit/bc4b950cbb13e37d1fdb16a9d23325cfefa6f90e&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;&lt;code&gt;bc4b950cbb13e37d1fdb16a9d23325cfefa6f90e&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库文件：&lt;code&gt;scripts/blog-style-suite/README.md&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;仓库文件：&lt;code&gt;scripts/blog-style-suite/style_pipeline/scanner.py&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;仓库文件：&lt;code&gt;scripts/blog-style-suite/style_pipeline/builder.py&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;仓库文件：&lt;code&gt;scripts/blog-style-suite/style_pipeline/compressor.py&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;生效运行时：&lt;code&gt;.agents/data/blog-writing/published.runtime.json&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;details class=&#34;article-notes&#34;&gt;
    &lt;summary&gt;写作附记&lt;/summary&gt;
    &lt;div class=&#34;article-notes__content&#34;&gt;
        &lt;h3 id=&#34;原始提示词&#34;&gt;原始提示词
&lt;/h3&gt;&lt;blockquote&gt;
&lt;p&gt;$blog-writer 本次的内容比较多，拆分成系列文章：去年就有很多稿子是通过大模型写的，那会是自己写个大纲或者问题清单，然后AI出稿子，复制内容到本地 md 文档，填写头信息，标签信息、发布文章；近期 codex 用了很多，发现 codex 里面的联网搜索能力很强，那我是不是能写个 skill，将这些事情自动化，此时诞生了 skill blog-writer 的第一稿，我还想着让 AI 学习我以前文章的风格，这就导致 blog-writer 运行的时候，很费 token，后续我针对 blog-writer 进行了多个版本的优化，拆分了 数据模块，数据生成的模块，原本数据生成的模块还是独立的 skill，写着写着，我就发现，更适合做成 Python 项目，此时就有了 blog-style-suite，然后我又发现，训练风格数据，也是比较费 token，我就想着用本地的大模型，对接了本地的大模型，我又想到了对比下本地大模型和在线版本的区别，又对接了 minimax；blog-style-suite 和 blog-writer 的演化历史可以分析的 git 提价记录。顺带基于本地 blog-writer、blog-style-suite 的代码，可以讲讲里面的设计思路，是如何做到了节约 token，数据结构是如何设计的，核心的设计思路。Token 富裕完全能生吃历史文章，预处理能节约很多 token&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;写作思路摘要&#34;&gt;写作思路摘要
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;这一篇把重点从写稿动作切到数据工程，核心回答“为什么必须拆模块”。&lt;/li&gt;
&lt;li&gt;开头直接承认“生吃历史文章能用”，这样后面的拆分理由才更有说服力。&lt;/li&gt;
&lt;li&gt;重点展开了 &lt;code&gt;scan.json&lt;/code&gt;、&lt;code&gt;source.json&lt;/code&gt;、&lt;code&gt;runtime.json&lt;/code&gt; 这三层结构，避免空讲架构。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bc4b950&lt;/code&gt; 被放在中间当转折点，因为“从约 2000 次到 5 次”最能说明预处理的价值。&lt;/li&gt;
&lt;li&gt;结尾把消费侧和生产侧重新分开，为第三篇的模型分工做铺垫。&lt;/li&gt;
&lt;/ul&gt;
    &lt;/div&gt;
&lt;/details&gt;</description>
        </item>
        <item>
        <title>AI 博客工程（一）：blog-writer 为什么会长出来</title>
        <link>https://ttf248.life/p/why-blog-writer-had-to-exist/</link>
        <pubDate>Fri, 03 Apr 2026 20:58:02 +0800</pubDate>
        
        <guid>https://ttf248.life/p/why-blog-writer-had-to-exist/</guid>
        <description>&lt;p&gt;去年写了不少 AI 稿子，那会最土的流程就是，自己先整理个大纲或者问题清单，让大模型把正文吐出来，然后再把内容复制到本地 &lt;code&gt;md&lt;/code&gt; 文档里，补 frontmatter、标签、分类、标题，最后再发布。&lt;/p&gt;
&lt;p&gt;这套流程不是不能用，是很烦。真正费时间的地方，不是正文，而是正文外面那一圈重复劳动。尤其是最近 &lt;code&gt;Codex&lt;/code&gt; 用多了以后，这种别扭感更强了。它能读仓库、能改文件、能补资料、还能直接把文章写进目录里，我要是还手工复制来复制去，反而像是人把工具的腿绑住了。&lt;/p&gt;
&lt;p&gt;这组文章其实就想讲一件事，AI 写博客到了后面，不能再只靠一段 prompt 硬顶。当前这一篇先讲 &lt;code&gt;blog-writer&lt;/code&gt; 为什么会长出来；下一篇会接着写 &lt;a class=&#34;link&#34; href=&#34;https://ttf248.life/p/how-blog-style-suite-split-style-and-token-cost/&#34; &gt;AI 写博客这件事，后来还是得做成工程（二）：blog-style-suite 怎么把风格学习和 token 成本拆开&lt;/a&gt;；最后一篇收在 &lt;a class=&#34;link&#34; href=&#34;https://ttf248.life/p/how-i-split-local-online-and-minimax-models/&#34; &gt;AI 写博客这件事，后来还是得做成工程（三）：本地模型、在线模型和 Minimax 最后怎么分工&lt;/a&gt;。&lt;/p&gt;
&lt;h2 id=&#34;真正烦人的不是写稿是那一串机械动作&#34;&gt;真正烦人的，不是写稿，是那一串机械动作
&lt;/h2&gt;&lt;p&gt;早期那套流程，说穿了很像外包流水线。&lt;/p&gt;
&lt;p&gt;我自己先把问题列清楚，或者先搭个大纲。模型负责把正文铺出来。然后人再回来补齐剩下的发布动作。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;复制到本地 &lt;code&gt;md&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;补 &lt;code&gt;title&lt;/code&gt;、&lt;code&gt;date&lt;/code&gt;、&lt;code&gt;slug&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;填标签和分类&lt;/li&gt;
&lt;li&gt;补 &lt;code&gt;&amp;lt;!--more--&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;整理参考资料&lt;/li&gt;
&lt;li&gt;再决定落到哪个目录&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这一串活，单看每一步都不难，连起来就很烦。烦的不是技术难度，烦的是它们都很机械，但又不能不做。&lt;/p&gt;
&lt;p&gt;这也是为什么我后来越来越觉得，&lt;a class=&#34;link&#34; href=&#34;https://ttf248.life/p/command-line-ai-coding-interaction/&#34; &gt;基于命令行的AI编码交互&lt;/a&gt; 这类变化，不只是“换了个入口”。当 AI 已经能直接在仓库里读写文件的时候，博客写作如果还停在“复制正文到本地文档”这一层，整个工作流其实已经落后了。&lt;/p&gt;
&lt;h2 id=&#34;blog-writer-第一层价值不是文风是把契约写死&#34;&gt;blog-writer 第一层价值，不是文风，是把契约写死
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;blog-writer&lt;/code&gt; 最早的那个节点，是 2026 年 4 月 1 日 17:00 的 &lt;code&gt;991536a&lt;/code&gt;。从 git 提交记录看，这一版已经把 &lt;code&gt;SKILL.md&lt;/code&gt;、&lt;code&gt;write_post.py&lt;/code&gt; 和一套最初的风格材料一起放进来了。&lt;/p&gt;
&lt;p&gt;但我后来回头看，这一稿最值钱的地方，不是“AI 学会了我的文风”，而是先把写稿契约写死了。&lt;/p&gt;
&lt;p&gt;什么叫契约写死？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;输入里至少要有大纲和事实锚点&lt;/li&gt;
&lt;li&gt;输出必须是完整 Markdown，不是半成品&lt;/li&gt;
&lt;li&gt;frontmatter 不能再靠人补&lt;/li&gt;
&lt;li&gt;文章不能只停在聊天窗口里，得直接落到 &lt;code&gt;content/post&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这件事很重要，因为 prompt 本身不稳定。你今天说一句“帮我像以前那样写”，它可能理解成语气像一点；明天你再说一遍，它可能只学到表面句式。可一旦写成 &lt;code&gt;Skill&lt;/code&gt;，规则就从“临场发挥”变成“固定工序”了。&lt;/p&gt;
&lt;p&gt;后面的几个节点，其实都在继续补这个契约。&lt;/p&gt;
&lt;p&gt;2026 年 4 月 2 日 22:54 的 &lt;code&gt;8eb735a&lt;/code&gt;，把作者字段、写作附记、原始提示词这些东西都固定下来了。到这一步，博客成稿已经不是“正文写完就算完”，而是连元信息、可追溯性、公开附记都一起标准化了。&lt;/p&gt;
&lt;p&gt;所以 &lt;code&gt;blog-writer&lt;/code&gt; 的第一层价值，从来不是让模型显得更会写，而是让写稿这件事终于有了可重复执行的边界。&lt;/p&gt;
&lt;h2 id=&#34;系列模式其实也是写作契约往前走了一步&#34;&gt;系列模式，其实也是写作契约往前走了一步
&lt;/h2&gt;&lt;p&gt;单篇写稳了以后，下一个问题很快就冒出来了。&lt;/p&gt;
&lt;p&gt;有些题目根本不适合挤在一篇里。你如果硬塞，最后往往会变成一篇信息很多、主线很散、每个点都讲不透的长文。&lt;/p&gt;
&lt;p&gt;这也是为什么 2026 年 4 月 2 日 23:55 的 &lt;code&gt;1a5604e&lt;/code&gt; 很关键。那次直接把系列模式和 &lt;code&gt;write_post_series.py&lt;/code&gt; 一起补进来了，文章之间用 &lt;code&gt;relref&lt;/code&gt; 串起来，批量写入时再统一替换。&lt;/p&gt;
&lt;p&gt;这看起来像是个写文件脚本的小升级，实际上不是。&lt;/p&gt;
&lt;p&gt;它说明一件事：写作工程化已经不再只考虑“这一篇怎么生成”，而是开始考虑“这一组内容怎么稳定落盘、怎么保证顺序、怎么在站点里互相跳转”。&lt;/p&gt;
&lt;p&gt;第二天 2026 年 4 月 3 日 09:29 的 &lt;code&gt;04dccb9&lt;/code&gt; 继续把这件事往前推了一步。系列文章时间戳按分钟递增，不再共用一个时间。这个改动很小，但很有工程味，因为它解决的是 Hugo 列表页、上一篇下一篇、系列顺序这些真实问题。&lt;/p&gt;
&lt;p&gt;说白了，系列模式不是为了显得高级，而是为了让“多篇一起发”这件事别再靠手工兜底。&lt;/p&gt;
&lt;h2 id=&#34;但只靠一个-skill后面还是会撞到-token-墙&#34;&gt;但只靠一个 skill，后面还是会撞到 token 墙
&lt;/h2&gt;&lt;p&gt;一旦开始认真折腾文风学习，&lt;code&gt;blog-writer&lt;/code&gt; 的上下文会很快变胖。你不但要让它会写，还想让它像你以前那样写。那最自然的办法，就是把历史文章也一股脑塞进去。&lt;/p&gt;
&lt;p&gt;这么干，单次当然能跑。&lt;/p&gt;
&lt;p&gt;但只要你不是偶尔写一篇，而是想把它变成长期工作流，问题马上就来了：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;token 花销高&lt;/li&gt;
&lt;li&gt;每次都重复喂同一批旧文章&lt;/li&gt;
&lt;li&gt;模型注意力被旧材料稀释&lt;/li&gt;
&lt;li&gt;写稿和风格维护缠在一起，谁都不轻&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;也就是从这里开始，我慢慢意识到，&lt;code&gt;blog-writer&lt;/code&gt; 更适合当消费侧，而不是把所有事情都塞给它做。&lt;/p&gt;
&lt;p&gt;写稿这个动作，应该尽量轻，尽量直接，尽量只读生效版本。至于风格数据怎么生成、怎么筛、怎么压缩，那是另一条生产侧流水线的事。这个判断，最后才把我推到了下一步，也就是 &lt;a class=&#34;link&#34; href=&#34;https://ttf248.life/p/how-blog-style-suite-split-style-and-token-cost/&#34; &gt;AI 写博客这件事，后来还是得做成工程（二）：blog-style-suite 怎么把风格学习和 token 成本拆开&lt;/a&gt;。&lt;/p&gt;
&lt;h2 id=&#34;先把流程做稳后面才有资格谈风格和模型&#34;&gt;先把流程做稳，后面才有资格谈风格和模型
&lt;/h2&gt;&lt;p&gt;现在回头看，&lt;code&gt;blog-writer&lt;/code&gt; 长出来，不是因为我忽然很想做一个博客写作助手。&lt;/p&gt;
&lt;p&gt;更像是因为原来那套流程已经开始不配合新的工作方式了。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Codex&lt;/code&gt; 这种工具一旦能联网补资料、能在仓库里读写、能直接调用脚本，写博客这件事就不该再停在“复制正文到本地文档”那一步。你不把这部分自动化，它反而会变成整条链路里最笨的一环。&lt;/p&gt;
&lt;p&gt;所以第一篇的结论我就放这。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;blog-writer&lt;/code&gt; 先解决的，不是文风，而是发布动作的重复劳动。没有这层契约，后面谈 token、谈数据结构、谈本地模型，其实都站不住。&lt;/p&gt;
&lt;h2 id=&#34;参考资料&#34;&gt;参考资料
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;仓库提交：&lt;a class=&#34;link&#34; href=&#34;https://github.com/ttf248/notebook/commit/991536a237d04aba7c44dec501b3d98c644040c8&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;&lt;code&gt;991536a237d04aba7c44dec501b3d98c644040c8&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库提交：&lt;a class=&#34;link&#34; href=&#34;https://github.com/ttf248/notebook/commit/8eb735aa8448c97deb2af1ea46b86772008fa9e3&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;&lt;code&gt;8eb735aa8448c97deb2af1ea46b86772008fa9e3&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库提交：&lt;a class=&#34;link&#34; href=&#34;https://github.com/ttf248/notebook/commit/1a5604e7e6ce0a13f260fcbb8c2c1d964cdd0892&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;&lt;code&gt;1a5604e7e6ce0a13f260fcbb8c2c1d964cdd0892&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库提交：&lt;a class=&#34;link&#34; href=&#34;https://github.com/ttf248/notebook/commit/04dccb98c55a6ea3b81408012b33a6219cf8ab77&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;&lt;code&gt;04dccb98c55a6ea3b81408012b33a6219cf8ab77&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库文件：&lt;code&gt;.agents/skills/blog-writer/SKILL.md&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;仓库文件：&lt;code&gt;.agents/skills/blog-writer/scripts/write_post.py&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;仓库文件：&lt;code&gt;.agents/skills/blog-writer/scripts/write_post_series.py&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;details class=&#34;article-notes&#34;&gt;
    &lt;summary&gt;写作附记&lt;/summary&gt;
    &lt;div class=&#34;article-notes__content&#34;&gt;
        &lt;h3 id=&#34;原始提示词&#34;&gt;原始提示词
&lt;/h3&gt;&lt;blockquote&gt;
&lt;p&gt;$blog-writer 本次的内容比较多，拆分成系列文章：去年就有很多稿子是通过大模型写的，那会是自己写个大纲或者问题清单，然后AI出稿子，复制内容到本地 md 文档，填写头信息，标签信息、发布文章；近期 codex 用了很多，发现 codex 里面的联网搜索能力很强，那我是不是能写个 skill，将这些事情自动化，此时诞生了 skill blog-writer 的第一稿，我还想着让 AI 学习我以前文章的风格，这就导致 blog-writer 运行的时候，很费 token，后续我针对 blog-writer 进行了多个版本的优化，拆分了 数据模块，数据生成的模块，原本数据生成的模块还是独立的 skill，写着写着，我就发现，更适合做成 Python 项目，此时就有了 blog-style-suite，然后我又发现，训练风格数据，也是比较费 token，我就想着用本地的大模型，对接了本地的大模型，我又想到了对比下本地大模型和在线版本的区别，又对接了 minimax；blog-style-suite 和 blog-writer 的演化历史可以分析的 git 提价记录。顺带基于本地 blog-writer、blog-style-suite 的代码，可以讲讲里面的设计思路，是如何做到了节约 token，数据结构是如何设计的，核心的设计思路。Token 富裕完全能生吃历史文章，预处理能节约很多 token&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;写作思路摘要&#34;&gt;写作思路摘要
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;第一篇先收在工作流触发点，不急着展开 token 和模型分工，避免三篇一起抢主线。&lt;/li&gt;
&lt;li&gt;重点保留了“正文不难，麻烦的是发布前后那串机械动作”这个判断。&lt;/li&gt;
&lt;li&gt;通过 &lt;code&gt;991536a&lt;/code&gt;、&lt;code&gt;8eb735a&lt;/code&gt;、&lt;code&gt;1a5604e&lt;/code&gt;、&lt;code&gt;04dccb9&lt;/code&gt; 这些节点，把“流程契约化”落到真实 git 演化上。&lt;/li&gt;
&lt;li&gt;系列模式放在这一篇讲，是为了说明博客写作已经从单篇生成走到了整组落盘。&lt;/li&gt;
&lt;li&gt;结尾故意把问题引到 token 墙，为第二篇的数据工程和预处理做铺垫。&lt;/li&gt;
&lt;/ul&gt;
    &lt;/div&gt;
&lt;/details&gt;</description>
        </item>
        <item>
        <title>Skill 更像 agent 的工种手册</title>
        <link>https://ttf248.life/p/skill-is-an-agent-handbook/</link>
        <pubDate>Thu, 02 Apr 2026 22:43:16 +0800</pubDate>
        
        <guid>https://ttf248.life/p/skill-is-an-agent-handbook/</guid>
        <description>&lt;p&gt;这几天看 AI 编程，前脚大家还在聊 &lt;code&gt;MCP&lt;/code&gt;，后脚又开始聊 &lt;code&gt;Skill&lt;/code&gt;。这两个词放在一起，最容易让人误会成又多了一个协议，或者又多了一种高级提示词。&lt;/p&gt;
&lt;p&gt;真正的区别其实更朴素：&lt;code&gt;MCP&lt;/code&gt; 解决的是 agent 怎么接上外部工具和数据，&lt;code&gt;Skill&lt;/code&gt; 解决的是接上以后按什么顺序把活干稳。一个偏连接，一个偏流程。&lt;/p&gt;
&lt;p&gt;所以 &lt;code&gt;Skill&lt;/code&gt; 最有价值的场景，不是模型完全不会做，而是模型每次做法不稳。它像一份工种手册，把触发条件、步骤、边界、参考资料和必要脚本放在一起，让 agent 少靠临场发挥。&lt;/p&gt;
&lt;h2 id=&#34;它先解决做法不稳&#34;&gt;它先解决“做法不稳”
&lt;/h2&gt;&lt;p&gt;如果用最通俗的话来解释，我会这么说：你把一个老员工脑子里的熟练做法，整理成一份能复用、能触发、能落地的说明书，这东西就是 &lt;code&gt;Skill&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;OpenAI 官方文档的定义也很直接，&lt;code&gt;Skill&lt;/code&gt; 是一类面向特定任务的能力包，里面可以放指令、参考资料，以及可选的脚本。目的不是让模型“更聪明”，而是让它在某一类任务上，按固定工作流稳定输出。&lt;/p&gt;
&lt;p&gt;它不像普通 prompt，因为它不是一次性说两句就完了；也不像 &lt;code&gt;MCP&lt;/code&gt;，因为它不负责连工具和数据源；更不像 &lt;code&gt;AGENTS.md&lt;/code&gt;，因为它不是全仓库通用规矩。它更像专项 SOP，或者说工种手册。&lt;/p&gt;
&lt;p&gt;比如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;处理 GitHub PR 评论时，先看哪些评论要处理，再问用户处理哪几条，再改代码，再反馈结果&lt;/li&gt;
&lt;li&gt;排查 CI 失败时，先拉取 GitHub Actions 日志，再提炼失败片段，再给修复计划，批准后才动手&lt;/li&gt;
&lt;li&gt;写博客时，先按固定文风生成标题，再补事实，再补 frontmatter，再落盘&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些事的共同点都不是“模型不知道怎么回答”，而是“模型每次做法都不一样，很容易跑偏”。这时候，&lt;code&gt;Skill&lt;/code&gt; 的价值就出来了：把会反复发生的偏差，提前写进流程里。&lt;/p&gt;
&lt;h2 id=&#34;mcp-接世界skill-定流程&#34;&gt;MCP 接世界，Skill 定流程
&lt;/h2&gt;&lt;p&gt;这事还是得放回真实工作流里看，不然很容易讲飘。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;MCP&lt;/code&gt; 像接口层。&lt;/p&gt;
&lt;p&gt;官方对 &lt;code&gt;MCP&lt;/code&gt; 的定义，是把 AI 应用连接到外部系统的开放标准。文件、本地数据库、搜索引擎、设计稿、第三方服务，这些都可以通过 &lt;code&gt;MCP&lt;/code&gt; 接进来。所以它解决的是“接进去”。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Skill&lt;/code&gt; 像流程层。&lt;/p&gt;
&lt;p&gt;OpenAI 的 &lt;code&gt;Agent Skills&lt;/code&gt; 文档里写得很清楚，&lt;code&gt;Skill&lt;/code&gt; 是可复用工作流的编写格式。一个 &lt;code&gt;Skill&lt;/code&gt; 至少要有一个 &lt;code&gt;SKILL.md&lt;/code&gt;，还可以带 &lt;code&gt;scripts/&lt;/code&gt;、&lt;code&gt;references/&lt;/code&gt;、&lt;code&gt;assets/&lt;/code&gt;。Codex 会先读取它的 &lt;code&gt;name&lt;/code&gt; 和 &lt;code&gt;description&lt;/code&gt;，只有在判断要用的时候，才把完整说明载入上下文。这就是官方说的 &lt;code&gt;progressive disclosure&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;所以这两者的分工很清楚：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;MCP&lt;/code&gt;：把能力接进来&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Skill&lt;/code&gt;：把做事顺序定下来&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;拿一个很直观的例子来说，Figma 转代码这种事，如果 agent 根本读不到设计稿，那你先补的是 &lt;code&gt;MCP&lt;/code&gt;。但如果它已经能读设计稿了，只是每次都乱写，今天先写组件，明天先切页面，后天又忘了做视觉检查，那你补的就该是 &lt;code&gt;Skill&lt;/code&gt;。&lt;/p&gt;
&lt;h2 id=&#34;开发-skill先找重复偏差&#34;&gt;开发 Skill，先找重复偏差
&lt;/h2&gt;&lt;p&gt;这东西真没想象中那么重。&lt;/p&gt;
&lt;p&gt;OpenAI 官方建议先用内置的 &lt;code&gt;$skill-creator&lt;/code&gt;，让它帮你把触发条件、范围、是否需要脚本这些骨架先搭出来。默认优先是 instruction-only，也就是先别急着上脚本，先把说明写清楚。&lt;/p&gt;
&lt;p&gt;如果手工写，最小结构也很简单：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;my-skill/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── SKILL.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── scripts/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;├── references/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;└── assets/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中真正必需的，只有 &lt;code&gt;SKILL.md&lt;/code&gt;。并且这个文件至少要有两项元数据：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nn&#34;&gt;---&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;skill-name&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;description&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;Explain exactly when this skill should and should not trigger.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nn&#34;&gt;---&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;真正要避免的，是把 Skill 写成“我希望模型更聪明”的愿望清单。它应该回答的是更具体的问题：哪类任务会反复出现，哪一步总跑偏，哪些资料只有在这类任务里才需要加载，哪些动作必须用脚本保证确定性。&lt;/p&gt;
&lt;h3 id=&#34;1-先找重复出现的偏差&#34;&gt;1. 先找“重复出现的偏差”
&lt;/h3&gt;&lt;p&gt;不是所有任务都值得做成 &lt;code&gt;Skill&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;如果你只是偶尔让 agent 干一次活，普通 prompt 就够了。真正适合抽成 &lt;code&gt;Skill&lt;/code&gt; 的，通常是这种情况：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;你已经反复说过很多次同样的话&lt;/li&gt;
&lt;li&gt;agent 明明有能力，但执行顺序总变&lt;/li&gt;
&lt;li&gt;每次出错的位置都差不多&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;说白了，不是“能力不够”，而是“套路不稳”。&lt;/p&gt;
&lt;h3 id=&#34;2-把-description-写成触发条件&#34;&gt;2. 把 &lt;code&gt;description&lt;/code&gt; 写成触发条件
&lt;/h3&gt;&lt;p&gt;这一步非常关键。&lt;/p&gt;
&lt;p&gt;官方文档专门强调，Codex 是否会隐式调用一个 &lt;code&gt;Skill&lt;/code&gt;，很依赖 &lt;code&gt;description&lt;/code&gt;。所以别写“这是一个很好用的技能”，要写“什么时候该用，什么时候不该用”。&lt;/p&gt;
&lt;p&gt;比如 &lt;code&gt;gh-fix-ci&lt;/code&gt; 官方技能的描述就很清楚：当用户要你调试或修复 GitHub PR 检查失败时使用；重点是检查日志、总结失败原因、给出修复计划，并且在得到明确批准后再实施。你一看就知道它的边界在哪里。&lt;/p&gt;
&lt;h3 id=&#34;3-能靠说明搞定就先别写脚本&#34;&gt;3. 能靠说明搞定，就先别写脚本
&lt;/h3&gt;&lt;p&gt;OpenAI 文档的建议也很务实，除非你明确需要确定性行为或者外部工具，不然优先用说明，不要一上来就脚本化。&lt;/p&gt;
&lt;p&gt;为什么？因为脚本一多，维护成本就上来了。&lt;/p&gt;
&lt;p&gt;很多 &lt;code&gt;Skill&lt;/code&gt; 一开始只需要把步骤讲明白：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;先做什么&lt;/li&gt;
&lt;li&gt;再做什么&lt;/li&gt;
&lt;li&gt;输出格式是什么&lt;/li&gt;
&lt;li&gt;哪些情况要停下来问用户&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这已经能解决大半问题。&lt;/p&gt;
&lt;p&gt;只有当某一步特别稳定、特别机械、特别适合自动化时，再把它下沉到 &lt;code&gt;scripts/&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id=&#34;4-把资料模版和资源拆出去&#34;&gt;4. 把资料、模版和资源拆出去
&lt;/h3&gt;&lt;p&gt;&lt;code&gt;Skill&lt;/code&gt; 写着写着，很容易变成一坨超长说明文。这时候就该拆。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;SKILL.md&lt;/code&gt; 负责讲规则和顺序&lt;/li&gt;
&lt;li&gt;&lt;code&gt;references/&lt;/code&gt; 放背景文档和查阅材料&lt;/li&gt;
&lt;li&gt;&lt;code&gt;assets/&lt;/code&gt; 放模版、图标、样例&lt;/li&gt;
&lt;li&gt;&lt;code&gt;scripts/&lt;/code&gt; 放能稳定执行的动作&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这样做有两个好处。&lt;/p&gt;
&lt;p&gt;第一，主文件不会越来越臃肿。第二，模型只有在需要时才加载细节，符合 &lt;code&gt;progressive disclosure&lt;/code&gt; 这套思路。&lt;/p&gt;
&lt;h3 id=&#34;5-本地先用跨项目再分发&#34;&gt;5. 本地先用，跨项目再分发
&lt;/h3&gt;&lt;p&gt;官方文档把这件事也分得很清楚。&lt;/p&gt;
&lt;p&gt;如果你只是给自己当前仓库用，放在 &lt;code&gt;.agents/skills/&lt;/code&gt; 就够了。Codex 会从仓库、用户、系统这些位置扫描技能目录。&lt;/p&gt;
&lt;p&gt;如果你已经发现这套东西不只一个仓库能用，或者想把多个技能一起打包分发，那就别只停在 skill folder 这一层了，应该考虑 &lt;code&gt;plugin&lt;/code&gt;。OpenAI 官方文档的原话也很明确，&lt;code&gt;Skill&lt;/code&gt; 是工作流本身，&lt;code&gt;plugin&lt;/code&gt; 才是更适合安装和分发的单位。&lt;/p&gt;
&lt;h2 id=&#34;哪些场景适合&#34;&gt;哪些场景适合
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;Skill&lt;/code&gt; 不是越多越好，它最适合的是下面几类活。&lt;/p&gt;
&lt;h3 id=&#34;高频重复任务&#34;&gt;高频重复任务
&lt;/h3&gt;&lt;p&gt;你每周都会做，而且每次顺序都差不多。&lt;/p&gt;
&lt;p&gt;比如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;处理 PR review 评论&lt;/li&gt;
&lt;li&gt;写博客并补 frontmatter&lt;/li&gt;
&lt;li&gt;排查 CI 失败&lt;/li&gt;
&lt;li&gt;做发布前检查&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这类活，最怕的不是模型不会，而是每次都要重新讲一遍。&lt;/p&gt;
&lt;h3 id=&#34;有固定流程的任务&#34;&gt;有固定流程的任务
&lt;/h3&gt;&lt;p&gt;某件事就是天然有先后顺序。&lt;/p&gt;
&lt;p&gt;比如排查问题，你就应该先看日志，再收敛范围，再提计划，再改。这个时候，&lt;code&gt;Skill&lt;/code&gt; 特别合适，因为它能把顺序写死，减少模型临场发挥。&lt;/p&gt;
&lt;h3 id=&#34;需要绑定专业语境的任务&#34;&gt;需要绑定专业语境的任务
&lt;/h3&gt;&lt;p&gt;有些任务不只是步骤固定，还带强约束。&lt;/p&gt;
&lt;p&gt;比如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;只能查官方文档&lt;/li&gt;
&lt;li&gt;必须按某个审查格式输出&lt;/li&gt;
&lt;li&gt;必须保留团队里的既有术语&lt;/li&gt;
&lt;li&gt;必须遵守某个仓库的写作或开发规范&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这类活，如果你每次都只靠 prompt 临时说，很容易漏。&lt;/p&gt;
&lt;h3 id=&#34;工具和流程要一起用的任务&#34;&gt;工具和流程要一起用的任务
&lt;/h3&gt;&lt;p&gt;这个场景特别典型。&lt;/p&gt;
&lt;p&gt;不是单纯“连上 GitHub”就完了，而是连上以后，还得按某种方法去看日志、归纳问题、决定要不要修改、最后怎么反馈。也就是说，外部连接和内部流程必须一起工作。&lt;/p&gt;
&lt;p&gt;这时候常常就是 &lt;code&gt;MCP + Skill&lt;/code&gt; 联合出场。&lt;/p&gt;
&lt;h2 id=&#34;哪些场景不必上&#34;&gt;哪些场景不必上
&lt;/h2&gt;&lt;p&gt;反过来也要说清楚，不然很容易什么都想做成 &lt;code&gt;Skill&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id=&#34;一次性的随口任务&#34;&gt;一次性的随口任务
&lt;/h3&gt;&lt;p&gt;用户临时问一句，普通 prompt 往往就够了。&lt;/p&gt;
&lt;h3 id=&#34;你只是想接一个外部系统&#34;&gt;你只是想“接一个外部系统”
&lt;/h3&gt;&lt;p&gt;那优先考虑 &lt;code&gt;MCP&lt;/code&gt;，不是 &lt;code&gt;Skill&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id=&#34;你想约束整个仓库的长期行为&#34;&gt;你想约束整个仓库的长期行为
&lt;/h3&gt;&lt;p&gt;这更像 &lt;code&gt;AGENTS.md&lt;/code&gt; 的活，不是 &lt;code&gt;Skill&lt;/code&gt; 的活。&lt;/p&gt;
&lt;p&gt;所以简单总结一下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;缺连接，用 &lt;code&gt;MCP&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;缺流程，用 &lt;code&gt;Skill&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;缺全局规矩，用 &lt;code&gt;AGENTS.md&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;看几个案例就够了&#34;&gt;看几个案例就够了
&lt;/h2&gt;&lt;p&gt;概念讲再多，不如看几个真的案例。&lt;/p&gt;
&lt;h3 id=&#34;1-roll-dice最小可用的入门案例&#34;&gt;1. &lt;code&gt;roll-dice&lt;/code&gt;：最小可用的入门案例
&lt;/h3&gt;&lt;p&gt;这个案例来自 OpenAI 官方 &lt;code&gt;Agent Skills&lt;/code&gt; 文档。&lt;/p&gt;
&lt;p&gt;它非常小，目录里几乎只有一个 &lt;code&gt;SKILL.md&lt;/code&gt;，让 agent 在用户要求掷骰子时，调用 PowerShell 的随机数命令。&lt;/p&gt;
&lt;p&gt;为什么这个例子好？&lt;/p&gt;
&lt;p&gt;因为它把 &lt;code&gt;Skill&lt;/code&gt; 最核心的那层骨架直接露出来了：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;有明确触发条件&lt;/li&gt;
&lt;li&gt;有明确执行方式&lt;/li&gt;
&lt;li&gt;有明确边界&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;它说明了一件事，&lt;code&gt;Skill&lt;/code&gt; 不一定非得很大。只要某件事会重复发生，而且你不希望模型瞎发挥，就可以做成 &lt;code&gt;Skill&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id=&#34;2-gh-address-comments处理-github-评论的流程案例&#34;&gt;2. &lt;code&gt;gh-address-comments&lt;/code&gt;：处理 GitHub 评论的流程案例
&lt;/h3&gt;&lt;p&gt;这个案例来自 OpenAI 官方的 &lt;a class=&#34;link&#34; href=&#34;https://github.com/openai/skills&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;&lt;code&gt;openai/skills&lt;/code&gt;&lt;/a&gt; 仓库。&lt;/p&gt;
&lt;p&gt;它的目标不是“连 GitHub”，而是把“处理当前分支 PR 的评论”这件事固化下来。官方版本里的步骤就很典型：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;先确认 &lt;code&gt;gh&lt;/code&gt; 是否已经认证&lt;/li&gt;
&lt;li&gt;再拉出当前 PR 的评论和 review threads&lt;/li&gt;
&lt;li&gt;编号并总结这些评论&lt;/li&gt;
&lt;li&gt;让用户明确选择要处理哪几条&lt;/li&gt;
&lt;li&gt;然后才开始修&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这个例子特别能说明 &lt;code&gt;Skill&lt;/code&gt; 的价值。&lt;/p&gt;
&lt;p&gt;很多工程任务，难点根本不在“模型知不知道 GitHub 是什么”，而在“它会不会按对的顺序处理事情”。&lt;code&gt;gh-address-comments&lt;/code&gt; 解决的，就是这类顺序问题。&lt;/p&gt;
&lt;h3 id=&#34;3-gh-fix-ci排查-ci-失败的工程案例&#34;&gt;3. &lt;code&gt;gh-fix-ci&lt;/code&gt;：排查 CI 失败的工程案例
&lt;/h3&gt;&lt;p&gt;这也是 &lt;code&gt;openai/skills&lt;/code&gt; 仓库里的官方技能。&lt;/p&gt;
&lt;p&gt;它针对的是另一种很典型的工程任务：PR 检查挂了，要不要修，怎么修。&lt;/p&gt;
&lt;p&gt;这个 &lt;code&gt;Skill&lt;/code&gt; 里定义的流程也很有代表性：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;先确认 &lt;code&gt;gh&lt;/code&gt; 登录状态&lt;/li&gt;
&lt;li&gt;找到当前 PR&lt;/li&gt;
&lt;li&gt;拉 GitHub Actions 的失败检查和日志&lt;/li&gt;
&lt;li&gt;提炼失败片段&lt;/li&gt;
&lt;li&gt;先给修复计划&lt;/li&gt;
&lt;li&gt;得到批准后才动手&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这就不是“帮我看看 CI 为什么挂了”一句 prompt 能稳定搞定的场景了。因为它里面有权限、日志、外部工具、审批边界、执行顺序，这些都需要定下来。&lt;/p&gt;
&lt;h3 id=&#34;4-仓库私有-skill把团队自己的套路沉淀下来&#34;&gt;4. 仓库私有 Skill：把团队自己的套路沉淀下来
&lt;/h3&gt;&lt;p&gt;除了官方案例，我觉得 &lt;code&gt;Skill&lt;/code&gt; 更大的价值，其实是在私有仓库里。&lt;/p&gt;
&lt;p&gt;比如眼前这个博客仓库里的 &lt;code&gt;blog-writer&lt;/code&gt;，本质上就是一个很典型的 repo-scoped skill。它不负责“让模型学会写中文”，而是把这个仓库已经固定下来的文风、结构、事实核验、输出路径、落盘格式都写成工作流。&lt;/p&gt;
&lt;p&gt;这类 &lt;code&gt;Skill&lt;/code&gt; 往往最有现实价值。因为它不是面向所有人，而是专门解决“你这个仓库里，哪类活总在重复出现，而且总容易跑偏”。&lt;/p&gt;
&lt;h2 id=&#34;什么时候该认真做&#34;&gt;什么时候该认真做
&lt;/h2&gt;&lt;p&gt;所以最后还是回到最实际的问题，什么时候你应该认真做一个 &lt;code&gt;Skill&lt;/code&gt;？&lt;/p&gt;
&lt;p&gt;我的答案是：&lt;/p&gt;
&lt;p&gt;当你发现问题已经不再是“模型能力不够”，而是“它每次做法都不稳”的时候。&lt;/p&gt;
&lt;p&gt;这时候继续堆 prompt，收益通常越来越低。你今天补一句，明天再补一句，最后 prompt 长得像流水账，模型还是会漏。&lt;/p&gt;
&lt;p&gt;反而是把它整理成 &lt;code&gt;Skill&lt;/code&gt;，把触发条件、步骤、边界、脚本、资料分开管理，效果更稳，也更能复用。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;MCP&lt;/code&gt; 把外部世界接进来，&lt;code&gt;Skill&lt;/code&gt; 把内部套路固化下来。&lt;/p&gt;
&lt;p&gt;前者解决“能不能做”，后者解决“怎么稳定地做”。&lt;/p&gt;
&lt;p&gt;这就是我现在理解的 &lt;code&gt;Skill&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;它不是新提示词，也不是新协议。它更像是给 agent 配工种手册：少一点临场发挥，多一点可复用的做事顺序。&lt;/p&gt;
&lt;h2 id=&#34;参考资料&#34;&gt;参考资料
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://developers.openai.com/codex/skills&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Agent Skills - Codex | OpenAI Developers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://developers.openai.com/blog/skills-agents-sdk&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Using skills to accelerate OSS maintenance | OpenAI Developers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://modelcontextprotocol.io/docs/getting-started/intro&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;What is the Model Context Protocol (MCP)? | Model Context Protocol&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/openai/skills&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;openai/skills | GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/openai/skills/blob/main/skills/.curated/gh-address-comments/SKILL.md&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;gh-address-comments/SKILL.md | openai/skills&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/openai/skills/blob/main/skills/.curated/gh-fix-ci/SKILL.md&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;gh-fix-ci/SKILL.md | openai/skills&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;details class=&#34;article-notes&#34;&gt;
    &lt;summary&gt;写作附记&lt;/summary&gt;
    &lt;div class=&#34;article-notes__content&#34;&gt;
        &lt;h3 id=&#34;原始提示词&#34;&gt;原始提示词
&lt;/h3&gt;&lt;blockquote&gt;
&lt;p&gt;提示词：AI 大模型编程，先是出现了 MCP，然后是 Skill，用通俗的写法，解释下 Skill 是什么，如何开发 Skill，什么场景适用 Skill，分别出处具体的，有代表性的案例&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;写作思路摘要&#34;&gt;写作思路摘要
&lt;/h3&gt;&lt;p&gt;这次重写保留了原稿里的官方定义、&lt;code&gt;MCP&lt;/code&gt; 边界、开发结构和官方案例，但把文章主线从“概念综述”改成“Skill 解决做法不稳”。压缩了定义式段落，强化了触发条件、重复偏差和流程边界。&lt;/p&gt;

    &lt;/div&gt;
&lt;/details&gt;</description>
        </item>
        <item>
        <title>重度AI编程的一段日子</title>
        <link>https://ttf248.life/p/a-long-period-of-deep-ai-programming/</link>
        <pubDate>Mon, 16 Mar 2026 20:44:42 +0800</pubDate>
        
        <guid>https://ttf248.life/p/a-long-period-of-deep-ai-programming/</guid>
        <description>&lt;p&gt;近期在项目中，重度使用 AI 编程，应该是最近三年，AI 在工作中融合度最高的一个项目。记录的笔记不成体系，想到什么说什么。&lt;/p&gt;
&lt;h2 id=&#34;背景&#34;&gt;背景
&lt;/h2&gt;&lt;p&gt;linux 环境，后端服务开发，不涉及 UI 开发等前端内容。&lt;/p&gt;
&lt;h2 id=&#34;模型&#34;&gt;模型
&lt;/h2&gt;&lt;p&gt;国内的 minimax、glm、kimi 三剑客都上手试过了，kimi 的效果最好。&lt;code&gt;claude 面对大需求，能有效进行拆解，codex 最适用于生产环境，它异常谨慎&lt;/code&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Claude 最全能的选手，目前编程赛道，没人能打败它，就是&lt;strong&gt;贵&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Minimax 性价比最高，速度足够快，速度稳定 &amp;ndash; 龙虾浪潮下受益者&lt;/li&gt;
&lt;li&gt;Codex 大部分时候都挺好的，但是有些任务，他指令遵循度不够，老是想着帮我优化，提高性能，实际上我不需要，单元测试的时候，我就希望有一些啰嗦答案，能直观的看懂案例&lt;/li&gt;
&lt;li&gt;Kimi 指定遵循度很高，国内用起来最顺手的模型&lt;/li&gt;
&lt;li&gt;GLM 节前还算正常，节后算力严重不足，弃用了&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;定位&#34;&gt;定位
&lt;/h2&gt;&lt;p&gt;AI 的脑容量是远超个人的，有些模块的设计，和 AI 进行方案讨论，能有效的拓展思维链路，找到更合理的设计方案。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;高级的导师、能干的助手。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;你有不懂的可以问他，你有清晰的开发任务，可以交付给它执行，相当于你带了很能干的小弟。&lt;/p&gt;
&lt;h2 id=&#34;问题&#34;&gt;问题
&lt;/h2&gt;&lt;p&gt;国内的模型，在春节回来以后，出现大面积的算力不足，输出太慢了。虽说便宜有性价比，但是输出太慢，在实际工作中，很影响交互的的效率。智谱还在春节搞出来幺蛾子事件，背刺开发者，乱改套餐的价格。最后事情闹大了，大年初五发布道歉信，内部流程也有点混乱，在我申请退款以后，节后把历史的套餐全部都给我退款了。本来公告说的是仅退款升级的部分，保留老套餐的权益。&lt;/p&gt;
&lt;p&gt;周限额，最初的智谱没有这个东西，现在购买都有了，也是平台低估了用户薅羊毛的能力。全额退款，导致我也不能继续薅羊毛了。glm-4.7 能力上和 kimi-2.5 差不多，指令遵循度足够。&lt;/p&gt;
&lt;p&gt;无论哪个模型，目前都是需要人工进行审核。&lt;/p&gt;
&lt;h2 id=&#34;单元测试&#34;&gt;单元测试
&lt;/h2&gt;&lt;p&gt;项目设计初期，各个模块的设计都是能独立进行单元测试。开发到了后期，发现大模型自己写的代码，然后自己写单元测试案例，大部分场景都是能全部通过的，由于不是测试驱动开发，单元测试工作的作用，在于后期的业务迭代、重构阶段，便于审核 ai 修改的代码是否破坏了原来的功能。&lt;/p&gt;
&lt;h2 id=&#34;性能测试&#34;&gt;性能测试
&lt;/h2&gt;&lt;p&gt;如果没有 AI 针对部分核心函数，大概率是懒得进行性能测试的编码开发。有了 AI 那就顺带做一份，看看数据怎么样。&lt;/p&gt;
&lt;h2 id=&#34;文档&#34;&gt;文档
&lt;/h2&gt;&lt;p&gt;维护文档是个费力的事情，ai 不一样，他能在修改代码的同时，帮你维护文档，同步更新相关的文档到最新的代码分支。&lt;/p&gt;
&lt;h2 id=&#34;新能分析&#34;&gt;新能分析
&lt;/h2&gt;&lt;p&gt;尝试用了 codex 进行服务的性能优化，授权以后，能自动调用 perf 进行性能分析，但是不够聪明，它分析到了是频繁的申请内存导致效率太低，但是没有理解是由于循环次数太多导致的频繁申请内存，属于代码的不合理，有个很大的临时变量在循环内部，每次都执行了构造、析构。&lt;/p&gt;
&lt;h2 id=&#34;流程&#34;&gt;流程
&lt;/h2&gt;&lt;p&gt;AI 项目的维护，人工介入，按照模块、函数来迭代开发，不指望 AI 能持续的维护新功能，每次编写提示词，相当于人工编写一个小的开发方案，涉及的模块有什么、在哪里修改最合适。&lt;/p&gt;
&lt;p&gt;网上传的很多流程，在我这里并没有进行尝试，流程上比较传统，用起来也是最顺手的。&lt;/p&gt;</description>
        </item>
        <item>
        <title>AI 变“笨”了吗？揭秘参数精度与推理成本的博弈</title>
        <link>https://ttf248.life/p/is-ai-getting-dumber-uncovering-the-game-between-parameter-precision-and-inference-costs/</link>
        <pubDate>Thu, 04 Dec 2025 21:58:09 +0800</pubDate>
        
        <guid>https://ttf248.life/p/is-ai-getting-dumber-uncovering-the-game-between-parameter-precision-and-inference-costs/</guid>
        <description>&lt;p&gt;近期混迹在各个编程大模型的交流圈，模型降智是大家吐槽最多的事情。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;本地台式机部署的都是量化以后的模型，可以说是降智后的版本&lt;/li&gt;
&lt;li&gt;vibe coding 这么热门，有没有可能当前大模型输出的内容，代码是最值钱的产物？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本轮的提示词有过一次优化，刚好是模型降智，大模型给的方案是优化提示词，更详细的任务规划、更明确的输出要求&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;针对这个问题，给出合适的提示词：现在很多大厂都提供了大模型服务，偶尔会有用户反馈模型降智问题；从专业角度，参数的精度、推理的成本出发，编写文章；科普文，不要太长。&lt;/p&gt;
&lt;p&gt;优化后的版本：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;你是一位资深的 AI 行业技术专栏作家。你的目标是撰写一篇针对普通读者但内容专业的中文科普文章。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;请一步一步思考并撰写：
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;1. 大纲制定：首先，请拟定一个清晰的三段式文章结构大纲（例如：引言、精度分析、成本与架构分析、结论）。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;2. 内容聚焦：文章必须深入浅出地解释用户反馈的“模型降智”现象，核心分析点必须围绕 **参数精度（量化）** 和 **推理的运营成本** 展开。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;3. 字数与格式：最终文章长度必须控制在 &lt;span class=&#34;m&#34;&gt;600&lt;/span&gt; 字以内。请使用清晰的 &lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;##` 标题 来划分段落，并使用 **粗体** 来强调文中的关键专业术语（如：量化、MoE、FP16）。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;引言&#34;&gt;引言
&lt;/h2&gt;&lt;p&gt;为了确保逻辑清晰且符合科普要求，我制定了以下结构：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;引言：&lt;/strong&gt; 确认用户感知的真实性，引出核心矛盾——在用户规模激增的背景下，服务商必须在“智力巅峰”与“服务可用性”之间做平衡。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;精度分析（核心点1）：&lt;/strong&gt; 解释&lt;strong&gt;参数&lt;/strong&gt;与&lt;strong&gt;精度&lt;/strong&gt;的关系。通过对比 &lt;strong&gt;FP16&lt;/strong&gt; 与 &lt;strong&gt;量化&lt;/strong&gt;（INT8/INT4），用“图片压缩”的类比来说明为什么精度下降会导致逻辑变差。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;成本与架构（核心点2）：&lt;/strong&gt; 剖析&lt;strong&gt;推理成本&lt;/strong&gt;。介绍 &lt;strong&gt;MoE&lt;/strong&gt; 架构与&lt;strong&gt;稀疏激活&lt;/strong&gt;机制，解释为了省钱和加速，模型是如何“偷懒”的。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;结论：&lt;/strong&gt; 总结这种“降智”是商业化普及的必经之路（不可能三角）。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;文章正文&#34;&gt;文章正文
&lt;/h2&gt;&lt;p&gt;近期，不少用户反馈大模型似乎没有以前“聪明”了：逻辑变简单、指令遵循变差，甚至出现车轱辘话。这并非全是错觉。从技术视角看，这种“降智”现象往往是大厂在面对海量用户时，为了平衡&lt;strong&gt;推理成本&lt;/strong&gt;与服务速度而做出的技术妥协。&lt;/p&gt;
&lt;h2 id=&#34;精度缩水从-4k-到-720p-的代价&#34;&gt;精度“缩水”：从 4K 到 720P 的代价
&lt;/h2&gt;&lt;p&gt;大模型的“智商”主要存储在数千亿个&lt;strong&gt;参数&lt;/strong&gt;中。在理想状态下，这些参数以高精度的 &lt;strong&gt;FP16&lt;/strong&gt;（16位浮点数）格式运行，能捕捉极细微的语义差别。但这种高精度意味着巨大的&lt;strong&gt;显存&lt;/strong&gt;占用和缓慢的计算速度。&lt;/p&gt;
&lt;p&gt;为了让数亿用户都能流畅使用，服务商普遍采用了&lt;strong&gt;量化&lt;/strong&gt;（Quantization）技术。这是一种将参数精度从 &lt;strong&gt;FP16&lt;/strong&gt; 压缩到 &lt;strong&gt;INT8&lt;/strong&gt; 甚至 &lt;strong&gt;INT4&lt;/strong&gt; 的手段。&lt;/p&gt;
&lt;p&gt;这就好比将一部 4K 高清电影压缩成 720P 流媒体：虽然剧情（大体逻辑）没变，但画面细节（微小的逻辑关联、复杂指令的执行细节）却丢失了。这种“有损压缩”直接导致模型在处理复杂任务时表现力下降，给用户一种“变笨”的体感。&lt;/p&gt;
&lt;h2 id=&#34;成本压力让大脑部分休息&#34;&gt;成本压力：让大脑“部分休息”
&lt;/h2&gt;&lt;p&gt;除了精度，&lt;strong&gt;推理的运营成本&lt;/strong&gt;是另一大核心因素。每次你向 AI 提问，服务器都要进行庞大的矩阵运算，电费和硬件损耗惊人。&lt;/p&gt;
&lt;p&gt;为了降低成本，现代大模型多采用 &lt;strong&gt;MoE&lt;/strong&gt;（Mixture of Experts，混合专家模型）架构。与传统模型每次都激活所有神经元不同，&lt;strong&gt;MoE&lt;/strong&gt; 采用&lt;strong&gt;稀疏激活&lt;/strong&gt;策略：针对你的问题，系统只唤醒模型中一小部分相关的“专家”网络，其余部分保持休眠。&lt;/p&gt;
&lt;p&gt;虽然这极大降低了计算量，但如果&lt;strong&gt;路由算法&lt;/strong&gt;（Router）为了负载均衡或节省算力，将你的复杂数学问题派发给了“文学专家”，或者为了速度牺牲了专家的调用数量，输出质量自然就会出现波动和下滑。&lt;/p&gt;
&lt;h2 id=&#34;结论&#34;&gt;结论
&lt;/h2&gt;&lt;p&gt;因此，所谓的“降智”，本质上是 AI 从实验室走向大规模商业化时的必然阵痛。在&lt;strong&gt;参数精度&lt;/strong&gt;上的克制和&lt;strong&gt;模型架构&lt;/strong&gt;上的精打细算，是厂商为了让每个人都能用得起 AI，而在“绝对聪明”与“成本效率”之间寻找的微妙平衡。&lt;/p&gt;</description>
        </item>
        <item>
        <title>claude code 常用操作指南</title>
        <link>https://ttf248.life/p/claude-code-frequently-asked-operations-guide/</link>
        <pubDate>Sat, 08 Nov 2025 17:09:24 +0800</pubDate>
        
        <guid>https://ttf248.life/p/claude-code-frequently-asked-operations-guide/</guid>
        <description>&lt;p&gt;cc 提供的命令那么多，好用的都有哪些，抖音找个了视频学习一波，简单的记录下我认为有用的。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;生成规范化 git 日志，默认会带上版权信息，但是国内已经不用他家的模型了，对接的都是国内大模型，git 日志里面的版权也就没必要加上了（github 会展示 cc 为合作开发者）&lt;/p&gt;
&lt;p&gt;找到用户配置文件，添加配置项 &lt;code&gt;&amp;quot;includeCoAuthoredBy&amp;quot;: false&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;/init 分析分析当前文件夹生成一份概要，方便大模型更好的理解项目&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/compact /clear&lt;/code&gt; 日常命令，不解释&lt;/p&gt;
&lt;p&gt;&lt;code&gt;claude --dangerously-skip-permissions&lt;/code&gt; 慎用，上篇稿子的 null 文件就是这样弄出来的，cc windows 上有很多小问题&lt;/p&gt;
&lt;p&gt;&lt;code&gt;#&lt;/code&gt; 进入记忆模式，项目级别用的比较少，我常用在用户级别，常用项目要求写到里面&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/ide&lt;/code&gt; 能感知到 vscode 当前选中的文本数据，trae 里面，经常交互的时候，我是提供很多相关文件的函数片段，切换到命令行，一直没找到类似的功能，主要是很多时候项目的文件很多，制定参考的函数，能有效提供生成代码的准确率&lt;/p&gt;
&lt;p&gt;mcp ？一直没怎么尝试此类型的工具，后续有需要再来尝试，老觉得用起来有点麻烦&lt;/p&gt;
&lt;p&gt;自定义命令 没需求，用户级别的能替代之前写的 git 规范化递交&lt;/p&gt;
&lt;p&gt;&lt;code&gt;-r&lt;/code&gt; 关闭项目后重启找到之前的对话，对于复杂的项目，用处不大，国内的模型，上下文 200k，很容易就满了&lt;/p&gt;</description>
        </item>
        <item>
        <title>基于命令行的AI编码交互</title>
        <link>https://ttf248.life/p/command-line-ai-coding-interaction/</link>
        <pubDate>Wed, 05 Nov 2025 10:12:46 +0800</pubDate>
        
        <guid>https://ttf248.life/p/command-line-ai-coding-interaction/</guid>
        <description>&lt;p&gt;惯例打开 Trae 准备开始搞搞代码，通知栏收到消息：claude 模型下线了，不能用，后续大概率也无法恢复，官方给了补偿方案，使用次数增加 300（截止到一月份）。&lt;/p&gt;
&lt;p&gt;查了下，不出预料，anthropic 公司按照美国的要求，禁止国内的公司继续使用 claude 系列模型。混入 trae discord 社群，看到不少人吐槽 claude 模型的下线，毕竟大部分人都是冲着 claude 来的。早在 claude 4.5 模型没有在  trae 同步上线，这事就已经有了苗头。&lt;/p&gt;
&lt;h2 id=&#34;尝试&#34;&gt;尝试
&lt;/h2&gt;&lt;p&gt;抱着最后试试的心态，体验了还支持的其他模型，包括 openai 的 gpt-3.5-turbo、gpt-4、google 的 gemini pro。&lt;/p&gt;
&lt;p&gt;怎么说呢，效果都不太理想，不知道 trae 境外团队怎么开发的，按理说，不会有那么大的差距。测试用的提示词，还是以前练手项目：小蓝书，以前的文章有写过。&lt;/p&gt;
&lt;p&gt;叠加对于 Trae IDE 本身就有不满意，遂发了邮件给 Trae 团队，申请退款。&lt;/p&gt;
&lt;h2 id=&#34;改变&#34;&gt;改变
&lt;/h2&gt;&lt;p&gt;没记错应该是谷歌先发布的，基于终端交互的 ai 编程，相对 ide，日常的智能提示没有了，但是更通用了，开发人员可以继续使用原来的开发环境。&lt;/p&gt;
&lt;p&gt;OpenAI 和 Anthropic 这两家公司，分别发布了 claude code、codex，工具和模型并没有彻底绑定，通过修改配置文件，也能接入其他模型。&lt;/p&gt;
&lt;p&gt;discord 社群中，有人提到了 minimax m2 和 glm4，这俩都是国内的模型，还是小蓝书项目，体验了前者，还不错。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;安装需要科学上网，不同模型的切换，推荐：&lt;a class=&#34;link&#34; href=&#34;https://github.com/farion1231/cc-switch&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://github.com/farion1231/cc-switch&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;claude-code&#34;&gt;claude code
&lt;/h2&gt;&lt;p&gt;依赖 node js，命令：npm install -g @anthropic-ai/claude-code&lt;/p&gt;
&lt;p&gt;常用的命令：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用 /clear 清除聊天上下文，避免累积过多历史信息影响效率&lt;/li&gt;
&lt;li&gt;claude &amp;ndash;dangerously-skip-permissions，执行这个之后，Claude 会自动跳过所有权限确认&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;╭─── Claude Code v2.0.33 ────────────────────────────────────────────────────────────────────────────────╮
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│                                    │ Tips &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; getting started                                          │
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│            Welcome back!           │ Run /init to create a CLAUDE.md file with instructions &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; Claude │
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│                                    │ ───────────────────────────────────────────────────────────────── │
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│               ▐▛███▜▌              │ Recent activity                                                   │
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│              ▝▜█████▛▘             │ No recent activity                                                │
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│                ▘▘ ▝▝               │                                                                   │
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│                                    │                                                                   │
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│   minimax-m2 · API Usage Billing   │                                                                   │
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│          F:&lt;span class=&#34;se&#34;&gt;\d&lt;/span&gt;ev&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;otebook           │                                                                   │
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;╰────────────────────────────────────────────────────────────────────────────────────────────────────────╯
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;gt; Try &lt;span class=&#34;s2&#34;&gt;&amp;#34;create a util logging.py that...&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  ! &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; bash mode       double tap esc to clear input      ctrl + _ to undo
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  / &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; commands        alt + m to auto-accept edits       alt + v to paste images
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  @ &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; file paths      ctrl + o &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; verbose output
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;# to memorize         ctrl + t to show todos&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                        tab to toggle thinking
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                        backslash &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\)&lt;/span&gt; + &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;⏎&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                        newline
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;切换到 vscode 再也不能白嫖 trae 提供的免费 git 日志功能，测试期间发现个小惊喜：生成规范 git 递交日志。生成的递交日志比以前更加详细，还包含了文件修改列表。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;✅ 规范 Git 提交日志已生成完成！
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  📋 提交摘要
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  提交哈希： 612ea2a
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  提交类型： feat - 新功能
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  影响范围： waterfall - 瀑布流组件
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  提交标题：
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  feat&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;waterfall&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: 重新设计瀑布流布局实现错落有致视觉效果
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  📊 提交统计
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - &lt;span class=&#34;m&#34;&gt;6&lt;/span&gt; 个文件被修改
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - &lt;span class=&#34;m&#34;&gt;331&lt;/span&gt; 行新增
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - &lt;span class=&#34;m&#34;&gt;7&lt;/span&gt; 行删除
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  🎯 主要更改点
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  ✅ 添加 react-masonry-css 依赖
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  ✅ 实现 &lt;span class=&#34;m&#34;&gt;5&lt;/span&gt; 种卡片类型渲染逻辑
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  ✅ 使用 Masonry 布局替代 CSS columns
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  ✅ 添加 PostType 类型定义
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  ✅ 实现随机标签系统
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  ✅ 优化响应式断点配置
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  🏗️ 重构文件列表
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - src/store/useStore.ts - 类型定义
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - src/data/mockData.ts - 数据生成
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - src/components/WaterfallGrid.tsx - 布局组件
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - src/components/PostCard.tsx - 卡片渲染
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - package.json - 依赖管理
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  提交消息遵循 https://www.conventionalcommits.org/ 规范，包含清晰的变更说明和详细的文件修改列表。
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;codex&#34;&gt;codex
&lt;/h2&gt;&lt;p&gt;暂未体验，参考资料：&lt;a class=&#34;link&#34; href=&#34;https://platform.minimaxi.com/docs/guides/text-ai-coding-tools#%E5%9C%A8-codex-cli-%E4%B8%AD%E4%BD%BF%E7%94%A8-minimax-m2&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://platform.minimaxi.com/docs/guides/text-ai-coding-tools#%E5%9C%A8-codex-cli-%E4%B8%AD%E4%BD%BF%E7%94%A8-minimax-m2&lt;/a&gt;&lt;/p&gt;</description>
        </item>
        <item>
        <title>字节AI编码新范式 SOLO</title>
        <link>https://ttf248.life/p/bytedance-ais-solo-encoding-new-paradigm/</link>
        <pubDate>Thu, 14 Aug 2025 21:49:06 +0800</pubDate>
        
        <guid>https://ttf248.life/p/bytedance-ais-solo-encoding-new-paradigm/</guid>
        <description>&lt;p&gt;以前用的产品，在进行代码开发的时候，大差不差，但是字节的SOLO，在代码开发的时候，就有了很大的不同。最开始通过邀请码参与内测，现在是提交邮箱，等待审核，审核通过后，就可以使用了。忘记什么时候进行的申请，今天打开 Trae 收到了审核通过的消息。&lt;/p&gt;
&lt;h2 id=&#34;字节solo的优势&#34;&gt;字节SOLO的优势
&lt;/h2&gt;&lt;p&gt;仿照正常项目开发的流程，引入了UI设计、需求分析、功能设计、技术方案实现，最后才是代码的开发。怎么说的，整体的交互逻辑对于小白是更加友好的，如果是复杂的项目，还是老的模式更加好用，AI作为辅助工具，进行代码的修改优化。&lt;/p&gt;
&lt;h2 id=&#34;港美股app开发&#34;&gt;港美股APP开发
&lt;/h2&gt;&lt;p&gt;没错，标题就是我写的 Prompt 语句，没有任何额外的描述。在 SOLO 模式下面，先输出了需求文档、技术架构文档，用户如果确认没有问题，就会进行代码的开发。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/ttf248/ai-coding-trae-solo/blob/master/.trae/documents/%E6%B8%AF%E7%BE%8E%E8%82%A1APP%E4%BA%A7%E5%93%81%E9%9C%80%E6%B1%82%E6%96%87%E6%A1%A3.md&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;需求文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/ttf248/ai-coding-trae-solo/blob/master/.trae/documents/%E6%B8%AF%E7%BE%8E%E8%82%A1APP%E6%8A%80%E6%9C%AF%E6%9E%B6%E6%9E%84%E6%96%87%E6%A1%A3.md&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;技术架构文档&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;怎么说呢，不说设计的特别完美，当成初稿用完全是可以的。由于本人并没有 UI 的设计经验，没有测试 Figma 导入设计稿的功能。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;代码构建的过程中，也发现一些文档，SOLO 模式下面，AI 会尝试自行处理一切存在的问题，比如说，数据库在我本地，需要调增数据库的字段设计，会先生成对应的脚本，然后编写 js 脚本执行数据库脚本。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;也有开始看资料没发现的亮点，任务拆解功能，港美股那会的资料没有截图，这里用了以前的漫画阅读器项目。字节也是不差钱，一次请求，能执行一堆任务，但是这个场景实际也不多，新项目才会大量的消耗 token，当用户有了依赖性，这里才是赚钱的地方。&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://ttf248.life/p/bytedance-ais-solo-encoding-new-paradigm/20250814215722.png&#34;
	width=&#34;571&#34;
	height=&#34;236&#34;
	
	loading=&#34;lazy&#34;
	
		alt=&#34;任务拆解功能&#34;
	
	
		class=&#34;gallery-image&#34; 
		data-flex-grow=&#34;241&#34;
		data-flex-basis=&#34;580px&#34;
	
&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;上面的都是优势，也有一个不足的地方，测试的项目都是生成的 web 网页，没有详细测试原生客户端的开发是否好用，比如：安卓原生、C# 客户端。&lt;/p&gt;</description>
        </item>
        <item>
        <title>日常碎碎念：开源项目、投资复盘</title>
        <link>https://ttf248.life/p/daily-musings/</link>
        <pubDate>Thu, 19 Jun 2025 19:07:33 +0800</pubDate>
        
        <guid>https://ttf248.life/p/daily-musings/</guid>
        <description>&lt;p&gt;AI已经融入到日常开发的工作流、投资最近切换了思路，从场外基金，切换到了场内的股票和ETF。&lt;/p&gt;
&lt;h2 id=&#34;开源项目&#34;&gt;开源项目
&lt;/h2&gt;&lt;h3 id=&#34;项目记录&#34;&gt;项目记录
&lt;/h3&gt;&lt;p&gt;上周无聊时尝试获取 Github 勋章，开始使用 Issue 模块。以前写代码时，总想找个地方记录每次 AI 改动的内容，但单独弄个文档记录显得杂乱。现在有了 Issue 模块，打上标签区分 bug、feature、enhancement 等，记录变得清晰且高效。即使以后可能用不到，记录下来也是一种积累。&lt;/p&gt;
&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/ttf248/comic-reader/issues?q=is%3Aissue&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;查看 Issue 列表&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;版本发布&#34;&gt;版本发布
&lt;/h3&gt;&lt;p&gt;版本发布记录，找到最近相关的提交，由于都是AI生成的提交记录，从网页端，复制近期所有的提交记录，扔给AI让它整理下，就是一份不错的发布记录。&lt;/p&gt;
&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/ttf248/comic-reader/releases/tag/v1.9.0&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://github.com/ttf248/comic-reader/releases/tag/v1.9.0&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;活跃度&#34;&gt;活跃度
&lt;/h3&gt;&lt;p&gt;那次整上了Github的个人主页，被动的提高了写代码的积极性，毕竟数据可视化了，有些东西，就是那么奇妙，简单的正反馈，能让人有持续下去的动力。&lt;/p&gt;
&lt;h3 id=&#34;trae&#34;&gt;Trae
&lt;/h3&gt;&lt;p&gt;付费买了首月体验，怎么说呢，在 Vscode 里面也是用的 Claude4 模型，字节的 IDE 体验上还是更好，实战的效果也是更好，有时候同样的问题，Trae 能给出更好的答案，后续要不要买个年费呢？按照现在瞎搞的频率，Trae 次数可能不够用，不用想那么多，等用完再说，字节应该还有另外的的付费方案，购买更多的调用次数。&lt;/p&gt;
&lt;p&gt;&lt;del&gt;简单的小问题，用微软的，github copilot 各个模型也能都能调用。&lt;/del&gt;&lt;/p&gt;
&lt;p&gt;计划夭折，github copilot 也开始限制调用次数，&lt;a class=&#34;link&#34; href=&#34;https://docs.github.com/zh/copilot/about-github-copilot/plans-for-github-copilot#models&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;618 开启限制次数&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;如何查看&lt;a class=&#34;link&#34; href=&#34;https://docs.github.com/zh/copilot/managing-copilot/understanding-and-managing-copilot-usage/monitoring-your-copilot-usage-and-entitlements#downloading-a-monthly-usage-report&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;当前使用量&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;投资&#34;&gt;投资
&lt;/h2&gt;&lt;p&gt;终归还是没忍住，自从开通了港股通，还没在港股交易过，想着小米要发布新车，买了点小米，涨了点就卖了，跌了又买回来，来回操作几次，还没等到新车发布，股票上小赚。&lt;/p&gt;
&lt;p&gt;这个时候没事看什么跨境通的资金流，看着美团都是资金的净流入，跟风买进去，成功当上了股东，忘记看总的资金流，国内买入的资金，只是一部分，港股还有很多外资。这次刚好实践下，蓝筹股，慢慢持有最后的收益会怎么样。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;仓位的控制和亏损，&lt;strong&gt;反人性的东西&lt;/strong&gt;，慢慢来，慢慢来，不能急。小米如果新车不太行，到底要不要卖掉呢？这是个问题。投资的认知还是不够，还是要多看书，多学习。美联储不准备降息，港股大跌一波，建仓的时候如果再晚一些？也不对，如果传出来的消息是降息，港股大涨怎么办？这就是投资，考验人性。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;常念叨的一句话，买的是国运，但自己好像不太信国运。&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;抛开国运的信仰问题，&lt;strong&gt;另外一个就是注意力&lt;/strong&gt;，既然是要做长线，频繁看盘是没意义，每天早上十分钟，收盘十分钟差不多了。最终预期的收益率是多少？还没一个明确的止盈位置。&lt;/p&gt;
&lt;p&gt;除开止盈的问题，配置部分股票，还是老脑子里面有个固有的观念，资产配置需要一部分股票。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;市场大跌的时候，腾讯还是香饽饽，资金扎堆&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;代码&lt;/th&gt;
					&lt;th&gt;名称&lt;/th&gt;
					&lt;th&gt;最新价&lt;/th&gt;
					&lt;th&gt;成交额&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;00700&lt;/td&gt;
					&lt;td&gt;腾讯控股&lt;/td&gt;
					&lt;td&gt;498.600&lt;/td&gt;
					&lt;td&gt;80.08亿&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;03690&lt;/td&gt;
					&lt;td&gt;美团-W&lt;/td&gt;
					&lt;td&gt;128.100&lt;/td&gt;
					&lt;td&gt;68.81亿&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;09992&lt;/td&gt;
					&lt;td&gt;泡泡玛特&lt;/td&gt;
					&lt;td&gt;247.200&lt;/td&gt;
					&lt;td&gt;57.03亿&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;09988&lt;/td&gt;
					&lt;td&gt;阿里巴巴-W&lt;/td&gt;
					&lt;td&gt;109.800&lt;/td&gt;
					&lt;td&gt;53.22亿&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;01810&lt;/td&gt;
					&lt;td&gt;小米集团-W&lt;/td&gt;
					&lt;td&gt;53.050&lt;/td&gt;
					&lt;td&gt;41.05亿&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;p&gt;这段是好几天后更新的，港股一波大涨，那天跌下去的基本都涨回来了。脑子突然想到去年亏损的恒生电子，怎么说呢，从老东家走了，就是对未来的预期不看好，选择买入恒生碰到下跌，心理就会拿不住。两波节奏，股价彻底涨回去，一个是去年的牛市，还有一个就是过年那会的杭州六小龙概念。今年的稳定币也算一个？&lt;/p&gt;
&lt;p&gt;从哪里跌到从哪里爬起来是没错，短时间没机会重新建仓恒生电子了。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;update 20250625&lt;/p&gt;
&lt;p&gt;小米发布会还没开始，上次清空场内ETF，券商这两天大涨，还是没做到长期持有，中间随意变仓了，要买小米，也不应该动券商ETF的资金。&lt;/p&gt;</description>
        </item>
        <item>
        <title>博客翻译项目碎碎念：文化传播、AI编程</title>
        <link>https://ttf248.life/p/blog-translation-project-musings-cultural-transmission-ai-programming/</link>
        <pubDate>Mon, 02 Jun 2025 21:41:00 +0800</pubDate>
        
        <guid>https://ttf248.life/p/blog-translation-project-musings-cultural-transmission-ai-programming/</guid>
        <description>&lt;p&gt;文化传播：意识形态上的影响，潜移默化。
AI编程：不做软件设计，返工很多&lt;/p&gt;
&lt;h2 id=&#34;文化传播&#34;&gt;文化传播
&lt;/h2&gt;&lt;p&gt;起初项目仅仅支持了英语、日语、韩语三种语言，后面想着反正都是AI翻译，何不多支持几种语言呢？于是又增加了法语、俄罗斯语、印度语。此时还没发现问题，程序执行翻译的时候，由于历史的代码存在问题，翻译出来的格式不对，存档的文章需要重新翻译。&lt;/p&gt;
&lt;p&gt;统计耗时提醒，全部翻译完成需要将近20小时，毕竟是本地部署的大模型，那会还是用 12b 参数的大模型。想着干掉几个不常用的语言，减少翻译时间。于是删除了法语、俄罗斯语、印度语。这时候感觉到了不对劲，为什么开始的语言里面，我会选择韩语、日语。&lt;/p&gt;
&lt;p&gt;按照全球人口的分布，这两个语言的受众人群并不多，尤其是韩语，全球使用人数大概只有8000万左右。日语稍微多一点，大概1.2亿人。相比之下，法语、俄罗斯语、印度语的使用人数都在1亿以上。&lt;/p&gt;
&lt;p&gt;这时候才意识到，韩语、日语的受众人群并不是因为语言使用人数多，而是因为文化传播的影响。韩国和日本的文化在全球范围内有着广泛的影响力，尤其是在亚洲地区。K-pop、动漫、影视剧等文化产品吸引了大量粉丝，这些粉丝自然也会对相关语言产生兴趣。&lt;/p&gt;
&lt;p&gt;回顾成长的历程，小时经常看日本的动漫、漫画，长大了看了很多韩国的电影、电视剧。导致我在项目设置初始语言的时候，下意识的选择了这两个熟悉的语言。&lt;/p&gt;
&lt;h3 id=&#34;软件设计与ai编程&#34;&gt;软件设计与AI编程
&lt;/h3&gt;&lt;p&gt;翻译助手最初只是一个简单的小工具，但在体验了 Claude4 的编码能力后，逐渐扩展了功能，增加了文章翻译、标签翻译等模块。随着功能的增加，代码复杂度也随之提升。虽然 AI 重构代码后目录结构显得更清晰，但在扩展新功能或修复缺陷时，AI生成的代码常常存在重复问题。&lt;/p&gt;
&lt;p&gt;AI在生成代码时，缺乏对整体结构和设计理念的理解。它通常基于已有代码进行修改和扩展，却未能有效复用已有模块，导致代码冗余。每次都需要手动清理重复代码，这无形中增加了开发成本。&lt;/p&gt;
&lt;p&gt;此外，AI生成的代码虽然语法正确，但在逻辑和设计上往往存在问题。例如，在另一个项目中稍微调整提示词后，生成的网页结构完全不同，缺乏一致性。这反映了项目初期缺乏合理设计，功能的增加更多是随意堆砌，导致代码结构混乱。&lt;/p&gt;
&lt;p&gt;这也提醒我们，软件工程的核心经验仍然不可忽视。合理的设计不仅能减少返工，还能提升代码的可维护性和扩展性。AI虽然是强大的工具，但它无法替代人类对系统设计的深刻理解和规划。&lt;/p&gt;</description>
        </item>
        <item>
        <title>不写代码，设计开发自选股模块</title>
        <link>https://ttf248.life/p/design-develop-custom-stock-module-no-code/</link>
        <pubDate>Thu, 27 Feb 2025 23:20:39 +0800</pubDate>
        
        <guid>https://ttf248.life/p/design-develop-custom-stock-module-no-code/</guid>
        <description>&lt;p&gt;上个月我们试用了 cursor，但是由于免费额度的限制，并没有做太复杂的功能开发，只是简单的测试了一下。那会就发现，字节也发布了类似的产品，两者底层调用的大模型一样，都是 Claude-3.5。&lt;/p&gt;
&lt;p&gt;字节产品叫做 Trae，先发布的 mac 版本，今年二月份，终于发布了 windows 版本。大厂的东西就是好，能免费白嫖，不用掏钱，无限量使用 Claude-3.5，这个模型的效果还是很不错的。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;最终卡在了K线图的开发上，由于本人基本不懂 react，所以只能放弃了。想要继续开发，需要笔者补充一些前端的基础知识，将任务拆分的更细，而不是直接给一个大任务：开发K线图。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;发现的问题&#34;&gt;发现的问题
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;由于使用国外的 AI 模型，Vue3 + Element-Plus 的训练数据不足，因此选择了 React 作为前端框架&lt;/li&gt;
&lt;li&gt;可能存在偶发的语法错误，需要人工修复&lt;/li&gt;
&lt;li&gt;部分复杂问题的解决方案需要人工指引&lt;/li&gt;
&lt;li&gt;代码结构优化需要人工指导&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其中耗时最多的地方，打包前端代码到容器中，由于笔者零基础 &lt;code&gt;.env.production&lt;/code&gt; &lt;code&gt;tsconfig.json&lt;/code&gt;，完全是没有概念的，这些还是中途求助豆包，才捋顺对应的逻辑。前端开发 dev 模式和 build 模式，对于代码的检查，差异很大。后端数据库和服务的容器脚本，合计五分钟就搞定了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AI 目前更多的提高开发的效率，你有基础是最好的，并不是 AI 会帮你解决所有的问题&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id=&#34;仓库地址&#34;&gt;仓库地址
&lt;/h2&gt;&lt;p&gt;正如标题说的，我们这次是能不写就不动手，和AI硬聊，设计开发自选股模块。看最终能做出来什么效果。&lt;/p&gt;
&lt;p&gt;仓库地址：&lt;a class=&#34;link&#34; href=&#34;https://github.com/ttf248/trae-demo&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://github.com/ttf248/trae-demo&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;详细的使用方法，可以看仓库的 README.md 文件。&lt;/p&gt;
&lt;p&gt;仓库包含很多递交记录，大部分都是我和 Trae 的对话记录，以及我对 Trae 的一些功能的测试，备注了是否人工干预来实现对应的功能。&lt;/p&gt;
&lt;h2 id=&#34;prompt&#34;&gt;Prompt
&lt;/h2&gt;&lt;p&gt;项目是从零开始创建，下面是项目的 Prompt：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;基于项目原型图，开发功能：自选股，需要支持合约的新增、删除、修改、查询。自选股界面需要展示基础的行情数据。支持多个不同的市场切换。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;前端：react
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;后端：golang gin gorm
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;数据库：PostgreSQL
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;服务端需要支持跨域请求，同时需要考虑数据的校验和错误处理，如果后端服务不可用，前端需要告警提示。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;后端需要展示请求和应答的日志；前端也打印通讯的日志，方便排查问题。
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;ui和交互优化&#34;&gt;UI和交互优化
&lt;/h2&gt;&lt;p&gt;前端界面的设计完全依赖的 Grok，我们首先在 Trae 里面做出来产物的雏形，但是没有审美，由于使用的模型，代码能力很强，但是其他能力比较弱，所以我们需要使用 Grok 来优化前端的 UI。&lt;/p&gt;
&lt;p&gt;通过将当前的界面截图，上传到 Grok 里面，然后让它帮我们优化 UI，可能一次性拿到很多的优化建议，我们人工评估，然后拷贝到 Trae 中执行，观察优化的效果。&lt;/p&gt;
&lt;h3 id=&#34;技术栈&#34;&gt;技术栈
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;前端：React + TypeScript&lt;/li&gt;
&lt;li&gt;后端：Golang + Gin + GORM&lt;/li&gt;
&lt;li&gt;数据库：PostgreSQL 17&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;系统架构&#34;&gt;系统架构
&lt;/h2&gt;&lt;h2 id=&#34;后端架构&#34;&gt;后端架构
&lt;/h2&gt;&lt;p&gt;后端采用 Golang 的 Gin 框架实现 RESTful API，主要模块包括：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;数据库模块&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用 GORM 作为 ORM 框架&lt;/li&gt;
&lt;li&gt;支持环境变量配置数据库连接&lt;/li&gt;
&lt;li&gt;自动进行数据库表迁移&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;路由模块&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;RESTful API 设计&lt;/li&gt;
&lt;li&gt;统一的错误处理机制&lt;/li&gt;
&lt;li&gt;内置请求日志记录&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;跨域处理&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;支持本地开发环境跨域&lt;/li&gt;
&lt;li&gt;可配置的 CORS 策略&lt;/li&gt;
&lt;li&gt;支持 Cookie 跨域&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;前端架构&#34;&gt;前端架构
&lt;/h2&gt;&lt;p&gt;前端使用 React + TypeScript 构建，实现了：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;股票列表展示&lt;/li&gt;
&lt;li&gt;自选股管理&lt;/li&gt;
&lt;li&gt;行情数据展示&lt;/li&gt;
&lt;li&gt;错误提示机制&lt;/li&gt;
&lt;/ul&gt;</description>
        </item>
        <item>
        <title>Cursor AI 编程 IDE 试用</title>
        <link>https://ttf248.life/p/cursor-ai-programming-ide-trial/</link>
        <pubDate>Thu, 23 Jan 2025 19:30:13 +0800</pubDate>
        
        <guid>https://ttf248.life/p/cursor-ai-programming-ide-trial/</guid>
        <description>&lt;p&gt;转眼又是一年过去了，工作上的最大的变动，还是AI参与度明显提高了，相当以往来说，不同的开发语言之间切换，需要开发者熟悉的各种语言不同的 api 接口，现在这些基础代码都可以通过 AI 生成代码了，对于开发者来说，就是一个很大的福音。&lt;/p&gt;
&lt;h2 id=&#34;chatgpt&#34;&gt;ChatGPT
&lt;/h2&gt;&lt;p&gt;早在 23 年的时候，整过两篇简单的入门介绍，转眼已经到了 25 年，怎么说呢，并没有感知到显著的进步，还是需要开发有自己的认知，能合理的拆分任务，当然，最重要的是识别 AI 生成的代码是否存在 bug。&lt;/p&gt;
&lt;h2 id=&#34;github-copilot&#34;&gt;Github copilot
&lt;/h2&gt;&lt;p&gt;忘记是是哪天了，看到资料说新加坡部署了服务器，国内使用，再也不用长期挂梯子，当然，登录的时候，还是需要挂个梯子，不过这个梯子只需要登录的时候用一下，之后就可以关闭了。&lt;/p&gt;
&lt;p&gt;日常用的更多的也是 Github copilot，这个插件，可以直接在 vscode、visual studio 中直接使用。不用两个软件之间切换。相对于 ChatGPT，Github copilot 对于项目的支持更好，交互上更友好，能你能选择部分本地的文件投喂，&lt;strong&gt;“训练”AI&lt;/strong&gt;，这样生成的代码更符合你的项目。&lt;/p&gt;
&lt;h2 id=&#34;cursor-ai&#34;&gt;Cursor AI
&lt;/h2&gt;&lt;p&gt;最近看到了一个新的 AI 编程 IDE，Cursor AI，这个 IDE 也是基于 Github copilot 的，不过这个 IDE 更加的智能，可以帮你直接创建文件。&lt;/p&gt;
&lt;p&gt;简单的用了一下，感觉还是不错的，不过对于现有项目的理解还是不够，本地项目文件多的时候，大的重构优化调整，还是需要&lt;strong&gt;开发者拆分任务&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;附上一个例子：切换到 curso 的工程模式，输入内容：新建个人简历网页，支持多个不同风格切换，记得填充一些个人信息用于数据展示。&lt;/p&gt;
&lt;p&gt;经过几次来回的&lt;strong&gt;拉扯&lt;/strong&gt;，你就能拿到如下的网页，当然，这个网页还是比较简单的，不过对于新手来说，还是很不错的。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;目前注册用户能免费试用 150 次高级 api，付费用户限制 5000 次高级 api&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://ttf248.life/cursor/index.html&#34; &gt;个人简历&lt;/a&gt;&lt;/p&gt;</description>
        </item>
        <item>
        <title>AI编程和任务拆解</title>
        <link>https://ttf248.life/p/ai-programming-and-task-decomposition/</link>
        <pubDate>Fri, 22 Dec 2023 08:44:26 +0800</pubDate>
        
        <guid>https://ttf248.life/p/ai-programming-and-task-decomposition/</guid>
        <description>&lt;p&gt;两年前给站点添加代码区域的拷贝功能，前后折腾了小半天，最终渲染效果有点不如意，作为半吊子前端开发，也没想着改进，能用就行，今年用&lt;code&gt;AI&lt;/code&gt;开发了小程序，对于前端的开发也更加熟悉了，重构一波（AI重新设计）。&lt;/p&gt;
&lt;p&gt;悟道：任务拆解开，很多小任务，&lt;code&gt;AI&lt;/code&gt;开发起来还是顺手的。已经倒闭的小程序，&lt;code&gt;75%&lt;/code&gt;代码由&lt;code&gt;AI&lt;/code&gt;提供，拆解了多个任务交付，人工进行项目代码的&lt;code&gt;组装&lt;/code&gt;。&lt;/p&gt;
&lt;h2 id=&#34;前文&#34;&gt;前文
&lt;/h2&gt;&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://ttf248.github.io/post/2022/001-%E4%BB%A5%E4%B8%BA%E5%BE%88%E7%AE%80%E5%8D%95%E7%9A%84%E4%BA%8B%E6%83%85%E5%A2%9E%E5%8A%A0%E4%B8%80%E4%B8%AA%E4%BB%A3%E7%A0%81%E5%A4%8D%E5%88%B6%E6%8C%89%E9%92%AE/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;以为很简单的事情，增加一个代码复制按钮&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;正文&#34;&gt;正文
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;promot&lt;/strong&gt;: 设计 css 和 JavaScript 代码，定位网页元素 class=&amp;ldquo;highlight&amp;rdquo;，这个元素的容器内，添加一个 复制按钮，实现复制代码的功能&lt;/p&gt;
&lt;p&gt;给的第一稿代码一眼看上去就有问题，重新生成一稿，基本可用，复制的内容不对，有冗余的文字，再次引导优化，人工指定核心的颜色设计，包含哪些特效&lt;/p&gt;
&lt;p&gt;了解到您对按钮的尺寸和颜色有特定的要求，我们可以重新设计按钮的样式以适应这些要求。以下是一个调整后的 CSS 样式，其中包括了您提供的颜色方案，并对按钮的尺寸进行了优化：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-css&#34; data-lang=&#34;css&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;copy-btn&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;position&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;absolute&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;top&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;px&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c&#34;&gt;/* 调整位置 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;right&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;px&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;padding&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;px&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;px&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c&#34;&gt;/* 缩小尺寸 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;font-size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;12&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;px&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c&#34;&gt;/* 减小字体大小 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;background-color&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;#8FD1E1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c&#34;&gt;/* 按钮背景色 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;color&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;#272822&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c&#34;&gt;/* 文字颜色 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;border&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;px&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;solid&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;#272822&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c&#34;&gt;/* 边框颜色 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;border-radius&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;px&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c&#34;&gt;/* 圆角 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;cursor&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;pointer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;opacity&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;0.7&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c&#34;&gt;/* 默认半透明 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;transition&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;opacity&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;0.3&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;s&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;ease&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;background-color&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;0.3&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;s&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;ease&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c&#34;&gt;/* 平滑过渡效果 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;copy-btn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;hover&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;opacity&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c&#34;&gt;/* 鼠标悬停时不透明 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;background-color&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;#A3D4E5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c&#34;&gt;/* 鼠标悬停时的背景色 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;highlight&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;position&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;relative&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在这个样式中，我减小了按钮的尺寸和字体大小，使其更加精致。同时，按钮的默认状态是半透明的，当鼠标悬停在按钮上时，它会变为不透明，并且背景色会变得稍微亮一些，以提供视觉反馈。这样的设计既符合您的颜色要求，又保持了现代化和用户友好的特点。&lt;/p&gt;
&lt;p&gt;对应的提供了一份更简单的 &lt;code&gt;JavaScript&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-JavaScript&#34; data-lang=&#34;JavaScript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;document&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;addEventListener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;DOMContentLoaded&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// 查找所有 .highlight 元素
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;highlights&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;document&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;querySelectorAll&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;.highlight&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;highlights&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;forEach&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;highlight&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 创建复制按钮
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;copyBtn&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;document&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;createElement&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;button&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;copyBtn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;textContent&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;复制&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;copyBtn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;classList&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;add&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;copy-btn&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 将按钮添加到每个 .highlight 元素中
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;highlight&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;appendChild&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;copyBtn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 添加点击事件监听器
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;copyBtn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;addEventListener&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;click&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;c1&#34;&gt;// 假设 .highlight 下的第一个 &amp;lt;code&amp;gt; 元素包含要复制的代码
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;code&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;highlight&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;querySelector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;code&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;?&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;highlight&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;querySelector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;code&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;textContent&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;navigator&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;clipboard&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;writeText&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;code&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;then&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// 显示复制成功信息
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;copyBtn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;textContent&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;已复制!&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;setTimeout&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;nx&#34;&gt;copyBtn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;textContent&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;复制&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2000&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;}).&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;catch&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;复制失败: &amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;后记&#34;&gt;后记
&lt;/h2&gt;&lt;p&gt;虽说我更期望在代码区域的右上角，顶部区域新增复制按钮，由于对前端不够了解，无法基于关键词准确描述功能，和&lt;code&gt;AI&lt;/code&gt;来回折腾几个回合也没有达到预期。&lt;/p&gt;
&lt;p&gt;就是不知道随着时间的发展，&lt;code&gt;AI&lt;/code&gt;对于程序开发会有多大的影响。&lt;/p&gt;</description>
        </item>
        <item>
        <title>Prompt 工程师</title>
        <link>https://ttf248.life/p/prompt-engineer/</link>
        <pubDate>Sun, 26 Mar 2023 20:46:53 +0800</pubDate>
        
        <guid>https://ttf248.life/p/prompt-engineer/</guid>
        <description>&lt;p&gt;就如当年学习搜索引擎的技巧，我们也需要学习一些和&lt;code&gt;AI&lt;/code&gt;沟通的技巧，给出合理且充分的限定条件，高效的获取需要的答案。&lt;/p&gt;
&lt;p&gt;如果你换个角度呢，当前的&lt;code&gt;AI&lt;/code&gt;属于一个记忆力很好的小孩子，它拥有过目不忘的能力，有抄作业的能力。我们需要做的是学会如何正确、有效的和&lt;code&gt;AI&lt;/code&gt;沟通，精准的描述需求，帮助&lt;code&gt;AI&lt;/code&gt;生成预期的结果。&lt;/p&gt;
&lt;h2 id=&#34;科普&#34;&gt;科普
&lt;/h2&gt;&lt;p&gt;火出天际的&lt;code&gt;AI&lt;/code&gt;确切的说&lt;code&gt;Generative Pre-Training&lt;/code&gt;，直译过来就是生成式的预训练。它是一种基于互联网可用数据训练的文本生成深度学习模型，用于问答、文本摘要生成、机器翻译、分类、代码生成和对话 AI 等任务。目前已经有 GPT-1、GPT-2、GPT-3 和 GPT-4 等不同版本的模型，每个版本都比前一个版本更大、更强大。&lt;/p&gt;
&lt;h2 id=&#34;到底有没有智能&#34;&gt;到底有没有智能
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;相似度足够高，准确率也就越高&lt;/li&gt;
&lt;li&gt;基础的、重复性的工作，进过特定训练，不再需要人工的介入&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;生成式AI是一种利用现有的文本、音频、图像等数据来创建新内容的技术。它可以用于文本生成、语音合成、图像生成、对话系统等多种任务。生成式AI的逻辑性取决于它的训练数据和模型结构。一般来说，生成式AI可以在一定程度上遵循语法、逻辑和常识，但也可能出现错误、偏差或不真实的内容。因此，生成式AI的输出需要人类的判断和验证，不能盲目相信或使用。&lt;/p&gt;
&lt;h2 id=&#34;prompt-工程师&#34;&gt;Prompt 工程师
&lt;/h2&gt;&lt;p&gt;时间河流不会逆流，人需要学会适应潮流。你可以认为&lt;code&gt;AI&lt;/code&gt;不智能，没有逻辑性，它经常写出来不能用的代码。&lt;/p&gt;
&lt;p&gt;如果你换个角度呢，当前的&lt;code&gt;AI&lt;/code&gt;属于一个记忆力很好的小孩子，它拥有过目不忘的能力，有抄作业的能力。我们需要做的是学会如何正确、有效的和&lt;code&gt;AI&lt;/code&gt;沟通，精准的描述需求，帮助&lt;code&gt;AI&lt;/code&gt;生成预期的结果。&lt;/p&gt;
&lt;h2 id=&#34;对话模式&#34;&gt;对话模式
&lt;/h2&gt;&lt;p&gt;两年前&lt;code&gt;Github Copilot&lt;/code&gt;发布，谁也想不到两年后，&lt;code&gt;OpenAI&lt;/code&gt;横空出世，让人类认知到了大语言模型的能力。&lt;/p&gt;
&lt;p&gt;基于&lt;strong&gt;基于注释的编程&lt;/strong&gt;和&lt;strong&gt;基于对话的编程&lt;/strong&gt;，交互逻辑上完全不同，对话的模式，小白用户的交互体验友好，此处必须提到&lt;code&gt;NewBing&lt;/code&gt;在每个问题之后，给出的追问提示，微软在尝试引导用户，获取&lt;code&gt;AI&lt;/code&gt;知识库里面，更多的内容。&lt;/p&gt;
&lt;h2 id=&#34;举个栗子&#34;&gt;举个栗子
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;场景&lt;/strong&gt;：高铁旅途时间漫漫，编码是个不错的选择。流量有限的情况下，处理几个图片，获取了图片素材，下载软件处理图片稍微有点奢侈，网络条件也不允许。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;需求&lt;/strong&gt;：有一批图片素材，带透明背景图，用来作为小程序的导航栏，选中的状态是彩色的，没选中的状态是黑白的，素材都是彩色的，需要预处理一下。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prompt&lt;/strong&gt;：编写一段 python 代码，从一个文件夹中读取所有的图片，将图片转换成黑白，维持透明背景，保存图片的时候，优化图片的质量，减少文件体积，同时在控制台展示，优化前后的文件体积大小对比&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 导入必要的库&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;os&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;PIL&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;PIL&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Image&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 定义一个函数，将图片转换成黑白，维持透明背景，保存图片，并返回文件体积&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;convert_and_save&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 打开图片&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;image&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Image&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;open&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 获取图片的模式，如果是 RGBA 模式，说明有透明背景&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;mode&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mode&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mode&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;RGBA&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;# 创建一个和图片大小一致的白色背景图片&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;background&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Image&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;RGB&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;255&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;255&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;255&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;# 将原图片粘贴到白色背景上，忽略透明像素&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;background&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;paste&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mask&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;split&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;# 将合成的图片转换成灰度模式&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;gray_image&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;background&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;convert&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;L&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;# 将灰度图片再转换成 RGBA 模式，以便保留透明背景&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;final_image&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;gray_image&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;convert&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;RGBA&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;# 如果不是 RGBA 模式，直接将图片转换成灰度模式&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;final_image&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;convert&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;L&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 获取原图片的文件名和扩展名&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;file_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file_ext&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;splitext&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 定义新图片的文件名，添加 _bw 后缀表示黑白&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;new_file_name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file_name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;_bw&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file_ext&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 保存新图片，并优化质量，减少文件体积&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;final_image&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;save&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new_file_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;optimize&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;True&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 获取原图片和新图片的文件体积，并返回&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;old_size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;getsize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;new_size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;getsize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new_file_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;old_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;new_size&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 定义一个文件夹路径，存放所有的图片&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;folder_path&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;images&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 遍历文件夹中的所有文件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listdir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;folder_path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 拼接完整的文件路径&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;file_path&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;join&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;folder_path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 判断是否是图片文件，根据扩展名判断，可以根据需要添加或修改扩展名&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file_path&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;endswith&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;.png&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;.jpg&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;.jpeg&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;.gif&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;# 调用函数，转换并保存图片，并获取文件体积&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;old_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;new_size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;convert_and_save&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;file_path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;# 在控制台展示优化前后的文件体积大小对比&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nb&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;sa&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;: &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;old_size&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; bytes -&amp;gt; &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new_size&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; bytes&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;AI&lt;/code&gt;迅速给出了答案，看着很漂亮，用起来也没问题，经验丰富的程序源，会觉得下面的代码不够通用，也没法上生产环境：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;参数固定了&lt;/li&gt;
&lt;li&gt;没有日志文件，信息都打印在控制台&lt;/li&gt;
&lt;li&gt;图片处理的任务，适合多线程模型&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;NewBing&lt;/code&gt;登场，依据提示，选择了一个问题：&lt;strong&gt;这段代码有什么可以改进的地方吗&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这次给的答案，实话，完全超出了预期，一般程序员能想到的优化措施，&lt;code&gt;AI&lt;/code&gt;都给出对应的建议&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;这段代码可能还有一些可以改进的地方，比如：
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;可以使用 argparse 库，让用户可以通过命令行参数指定文件夹路径和扩展名，而不是写死在代码里。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;可以使用 logging 库，记录程序的运行情况，而不是直接打印到控制台。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;可以使用 try-except 语句，捕获可能出现的异常，比如文件打开失败，图片转换失败等，并做相应的处理。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;可以使用 multiprocessing 库，利用多核处理器，加速图片的转换和保存过程。
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;很友好的应答，考虑到部署的环境存在差异，允许不支持多进程&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;当然，我很乐意帮你修改一下代码。我尝试添加了 argparse, logging 和 try-except 语句，但没有添加 multiprocessing 库，因为我不确定你的电脑是否支持多核处理。修改后的代码如下：
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 导入必要的库&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;argparse&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;logging&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;multiprocessing&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;os&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;PIL&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Image&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 定义一个函数，将图片转换成黑白，维持透明背景，保存图片，并返回文件体积&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;convert_and_save&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 打开图片&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;try&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;image&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Image&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;open&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;except&lt;/span&gt; &lt;span class=&#34;ne&#34;&gt;Exception&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;e&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;logging&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;sa&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Failed to open &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_file&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;: &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;e&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;None&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 获取图片的模式，如果是 RGBA 模式，说明有透明背景&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;mode&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mode&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mode&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;RGBA&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;# 创建一个和图片大小一致的白色背景图片&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;background&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Image&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;RGB&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;255&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;255&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;255&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;# 将原图片粘贴到白色背景上，忽略透明像素&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;background&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;paste&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mask&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;split&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;# 将合成的图片转换成灰度模式&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;gray_image&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;background&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;convert&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;L&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;# 将灰度图片再转换成 RGBA 模式，以便保留透明背景&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;final_image&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;gray_image&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;convert&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;RGBA&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;# 如果不是 RGBA 模式，直接将图片转换成灰度模式&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;final_image&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;image&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;convert&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;L&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 获取原图片的文件名和扩展名&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;file_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file_ext&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;splitext&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 定义新图片的文件名，添加 _bw 后缀表示黑白&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;new_file_name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file_name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;_bw&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file_ext&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 保存新图片，并优化质量，减少文件体积&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;try&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;final_image&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;save&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new_file_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;optimize&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;True&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;except&lt;/span&gt; &lt;span class=&#34;ne&#34;&gt;Exception&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;e&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;logging&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;sa&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Failed to save &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new_file_name&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;: &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;e&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;None&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 获取原图片和新图片的文件体积，并返回&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;old_size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;getsize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;image_file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;new_size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;getsize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new_file_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;old_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;new_size&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 定义一个函数，解析命令行参数，并返回文件夹路径和扩展名列表&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;parse_args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 创建一个解析器对象&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;parser&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;argparse&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ArgumentParser&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;description&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Convert images to black and white and optimize quality.&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 添加一个必选的位置参数，表示文件夹路径&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;parser&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;add_argument&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;folder_path&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;help&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;The path of the folder that contains the images.&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 添加一个可选的参数，表示扩展名列表，默认为 png, jpg, jpeg 和 gif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;parser&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;add_argument&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;-e&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;--extensions&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;nargs&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;+&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;.png&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;.jpg&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;.jpeg&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;.gif&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;help&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;The extensions of the image files.&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 解析命令行参数，并返回结果对象&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;args&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;parser&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;parse_args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;folder_path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;extensions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 定义一个函数，打印优化前后的文件体积大小对比&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;print_result&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;result&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 如果结果不为空，说明转换和保存成功&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;result&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;# 解包结果为文件名和文件体积元组&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;result&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;old_size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;new_size&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;result&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;c1&#34;&gt;# 在控制台展示优化前后的文件体积大小对比&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;logging&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;sa&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;: &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;old_size&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; bytes -&amp;gt; &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new_size&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; bytes&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;logging&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;sa&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;result&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 配置日志记录器，将日志输出到控制台和文件中，设置日志等级为 INFO&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;logging&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;basicConfig&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;level&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;logging&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;INFO&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &lt;span class=&#34;nb&#34;&gt;format&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;%(asctime)s&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;%(levelname)s&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;%(message)s&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &lt;span class=&#34;n&#34;&gt;handlers&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;logging&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;StreamHandler&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                              &lt;span class=&#34;n&#34;&gt;logging&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;FileHandler&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;log.txt&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 调用函数，获取文件夹路径和扩展名列表&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;folder_path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;extensions&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;parse_args&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;vm&#34;&gt;__name__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;__main__&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# Windows 需要这个函数的原因是 Windows 缺乏 fork() 函数（这不完全正确）。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 因此，在 Windows 上，fork() 是通过创建一个新的进程来模拟的，这个新的进程中运行的代码，在 Linux 上是在子进程中运行的。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 由于这些代码要在技术上无关的进程中运行，所以它必须在运行之前被传递到那里。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 传递的方式是先将它们序列化，然后通过管道从原始进程发送到新的进程。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 另外，这个新的进程被通知它必须运行通过管道传递的代码，通过向它传递 --multiprocessing-fork 命令行参数。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 如果你看一下 freeze_support() 函数的实现，它的任务是检查它运行在哪个进程中，是否应该运行通过管道传递的代码&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;multiprocessing&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;freeze_support&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 创建一个进程池，根据电脑的核心数自动分配进程&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;pool&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;multiprocessing&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Pool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 创建一个空列表，用于存放异步任务的结果对象&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;results&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 遍历文件夹中的所有文件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;listdir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;folder_path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;# 拼接完整的文件路径&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;file_path&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;join&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;folder_path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;# 判断是否是图片文件，根据扩展名判断，可以根据需要修改扩展名列表&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;any&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;file_path&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;endswith&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ext&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ext&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;extensions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;c1&#34;&gt;# 调用函数，转换并保存图片，并获取文件体积，使用异步方式，不阻塞主进程&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;result&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;pool&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;apply_async&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;convert_and_save&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;args&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;file_path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,),&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;callback&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;print_result&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;c1&#34;&gt;# 将结果对象添加到列表中&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;results&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;append&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;result&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 关闭进程池，不再接受新的任务&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;pool&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# 等待所有的任务完成&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;pool&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;join&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;后记&#34;&gt;后记
&lt;/h2&gt;&lt;p&gt;由于本地开发是&lt;code&gt;windows&lt;/code&gt;系统，&lt;code&gt;AI&lt;/code&gt;第一次给出的答案，并没有加上&lt;code&gt;main&lt;/code&gt;函数，也没有&lt;code&gt;multiprocessing.freeze_support&lt;/code&gt;。通过追问发生的报错，修复了代码。&lt;/p&gt;
&lt;p&gt;就如当年学习搜索引擎的技巧，我们也需要学习一些和&lt;code&gt;AI&lt;/code&gt;沟通的技巧，给出合理且充分的限定条件，高效的获取需要的答案。&lt;/p&gt;
&lt;p&gt;注意：&lt;strong&gt;如果你是个编程新手，基于给出的注释，还有看不懂的地方，可以继续追问相关代码&lt;/strong&gt;&lt;/p&gt;</description>
        </item>
        <item>
        <title>AI辅助编程，生产力的进化</title>
        <link>https://ttf248.life/p/ai-assisted-programming-productivity-evolution/</link>
        <pubDate>Tue, 28 Feb 2023 17:05:17 +0800</pubDate>
        
        <guid>https://ttf248.life/p/ai-assisted-programming-productivity-evolution/</guid>
        <description>&lt;p&gt;&lt;code&gt;GitHub Copilot&lt;/code&gt; 发布也不到两年时间，&lt;code&gt;ChatGPT&lt;/code&gt; 问世了，不是很懂背后的原理，都用了一段时间。两个工具的辅助层面完全不同，但是都做到了大幅提高生产力。&lt;/p&gt;
&lt;p&gt;太复杂的事情，&lt;code&gt;AI&lt;/code&gt;还做不到，毕竟他们没有逻辑，有套路的或者说范式固定的事情，训练的语料足够，&lt;code&gt;AI&lt;/code&gt;的效果能打个九分。&lt;/p&gt;
&lt;h2 id=&#34;github-copilot&#34;&gt;github copilot
&lt;/h2&gt;&lt;p&gt;发布的时候，看着官网的介绍&lt;code&gt;demo&lt;/code&gt;，不是很智能，试用了一下，不是很好用，放弃了。&lt;/p&gt;
&lt;p&gt;2022年前，闲来无事，切换到新版本体验一下，效果已经不错了，就是国内的速度有点慢，大概率是网络的原因。&lt;code&gt;Python&lt;/code&gt;之类的语言，依据注释写出来的代码都还不错，比我自己查资料然后编写的速度快了很多。&lt;/p&gt;
&lt;h2 id=&#34;chatgpt&#34;&gt;ChatGPT
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;Github Copilot&lt;/code&gt;还停留在程序员，也就是开发的角度来设计产品，你需要懂的如何编程，慢慢的通过注释来引导AI辅助编程。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ChatGPT&lt;/code&gt; 走到了下一个层面，&lt;strong&gt;让外行人也能迅速上手&lt;/strong&gt;。对话聊天交互式的设计，你完全可以提出问题，描述需求，不懂的地方，继续提问。&lt;/p&gt;
&lt;p&gt;简单来个例子，知道分词的概念，但是不知道如何编码，想要计算字符串的相似度：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Python 分词计算 維天運通 LOGORY 和 合肥維天運通信息科技股份有限公司 两个字符串的相似度；
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;比较前，统一处理字符串，英文转换为小写；
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;第二个字符中如果能找到第一个字符的首字符，将第二个字符串截位，截位的长度为第一个字符串的长度
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;你好，这是Bing。😊&lt;/p&gt;
&lt;p&gt;根据网上的信息123，Python 分词计算可以使用 jieba 库来实现。jieba 库支持三种分词模式：精确模式、全模式和搜索引擎模式。你可以根据你的需求选择合适的模式。&lt;/p&gt;
&lt;p&gt;为了比较两个字符串的相似度，你需要先对它们进行分词，然后计算它们的词向量或者编辑距离等指标。你可以使用 numpy 或者 scipy 等库来进行数学运算。&lt;/p&gt;
&lt;p&gt;为了统一处理字符串，英文转换为小写，你可以使用 Python 的内置函数 lower() 来实现。&lt;/p&gt;
&lt;p&gt;为了截取第二个字符串，你可以使用 Python 的切片操作符 [ ] 来实现。&lt;/p&gt;
&lt;p&gt;以下是一个可能的代码示例：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;jieba&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;numpy&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;np&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;scipy.spatial.distance&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cosine&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 定义两个字符串&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;str1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;維天運通 LOGORY&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;str2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;合肥維天運通信息科技股份有限公司&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 统一处理字符串，英文转换为小写&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;str1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;str1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;lower&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;str2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;str2&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;lower&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 找到第二个字符串中第一个字符的位置&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;index&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;str2&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;find&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;str1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 如果找到了，截取第二个字符串&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;index&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;str2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;str2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;index&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;str1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 使用 jieba 库进行分词&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;words1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;jieba&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cut&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;str1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;words2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;jieba&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cut&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;str2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 计算两个字符串的词向量（以词频作为权重）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;vector1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;np&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;zeros&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;words1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;vector2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;np&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;zeros&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;words1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;word&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;enumerate&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;words1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;vector1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;# 统计第一个字符串中每个词出现的次数&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;word&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;words2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;vector2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;# 统计第二个字符串中每个词出现的次数&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 计算两个字符串的相似度（以余弦距离作为指标）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;similarity&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cosine&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vector1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;vector2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;两个字符串的相似度是：&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;similarity&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;更进一步，咨询运行的结果，恭喜你，发现问题了，结果是瞎编的，它并没有实际运行代码，但是会给你一个不错的结果&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&#34;栗子&#34;&gt;栗子
&lt;/h3&gt;&lt;p&gt;提问：sql 语句，查出产品代码表中，产品代码在这个区间 80000-89999 的记录&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;你好，这是 Bing。😊
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;根据搜索结果12，你可以使用 SQL BETWEEN 运算符来选择给定区间内的值。BETWEEN 运算符包含了开始和结束的值。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;你需要先指定要查询的表名和列名，然后在 WHERE 子句中使用 BETWEEN 运算符和区间值。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;例如，如果你要查询产品代码表中，产品代码在 80000 到 89999 之间的记录，你可以使用以下语句：
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SELECT * FROM product_code
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;WHERE code BETWEEN 80000 AND 89999;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;这里，* 表示选择所有列3。如果你只想选择特定的列，比如产品名称和价格，你可以用逗号分隔它们，如下：
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SELECT name, price FROM product_code
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;WHERE code BETWEEN 80000 AND 89999;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;希望这能帮助到你。
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;继续提问，否定它：产品代码是字符串，你的代码错了&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;抱歉，我没有注意到产品代码是字符串。如果是这样的话，你需要在区间值两边加上单引号，如下：
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SELECT * FROM product_code
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;WHERE code BETWEEN &amp;#39;80000&amp;#39; AND &amp;#39;89999&amp;#39;;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;请原谅我的错误。🙏
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;恭喜你，它会认错的。&lt;/p&gt;</description>
        </item>
        
    </channel>
</rss>
