<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="http://cosven.me/feed.xml" rel="self" type="application/atom+xml" /><link href="http://cosven.me/" rel="alternate" type="text/html" /><updated>2026-04-03T09:14:05+00:00</updated><id>http://cosven.me/feed.xml</id><title type="html">Cosven</title><subtitle>待补充。</subtitle><author><name>cosven</name></author><entry><title type="html">Doris 对一些数据库经典问题的解决方案</title><link href="http://cosven.me/blogs/10031" rel="alternate" type="text/html" title="Doris 对一些数据库经典问题的解决方案" /><published>2026-03-26T12:04:00+00:00</published><updated>2026-03-26T12:04:00+00:00</updated><id>http://cosven.me/blogs/doris-solutions</id><content type="html" xml:base="http://cosven.me/blogs/10031"><![CDATA[<p>学而时习之，不亦说乎</p>

<h2 id="doris-是怎样实现主键模型的">Doris 是怎样实现主键模型的？</h2>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>...
...
rowset-v3
rowset-v2 delete_bitmap-v3
rowset-v1 delete_bitmap-v2 delete_bitmap-v3
</code></pre></div></div>

<ol>
  <li>写的时候，在老的版本上做一个标记，标记一个 rowset 里面那些行已经被删除了。
这个标记叫 <code class="language-plaintext highlighter-rouge">delete bitmap</code>，它里面记录了的是行号（rowid）。
    <ul>
      <li>性能优化tip：怎样根据 key 找到对应的行号？—&gt; 引入了一个主键索引（primary key index），它的结构是类似 RocksDB Partitioned Index。
相当于记录一个 key range 的位置（相比于记录每个 key 的位置会更省内存空间）。</li>
      <li>性能优化tip：主键索引上面还套了一个 bloom filter，来加速查询。
        <ul>
          <li>bloom filter 可以用于范围查询么？—&gt; 不行。</li>
        </ul>
      </li>
    </ul>
  </li>
  <li>通常 Doris 不会读历史版本。如果读写几乎同时的话，读也会根据版本来判断要使用哪些 delete bitmap。
    <ul>
      <li>ps：schema change 和 compaction 也会产生读请求</li>
      <li>性能优化tip：一个 rowset 上有多个 delete bitmap，这样读的时候 delete bitmap 要合并。这个合并的结果会放到 cache。</li>
    </ul>
  </li>
</ol>

<p>这里的性能优化点基本都是空间换时间的策略。这个时候就会有内存和缓存问题。从测试角度看，这里就会有一些值得注意的风险点。</p>

<ol>
  <li>并发写怎么处理？rowset 顺序怎么保证？
    <ul>
      <li>首先写入是有事务的，事务提交的时候确认版本号，事务提交会走到 FE 上。（不过它还有个 publish 机制，只有 publish 了才会被读到。）</li>
      <li>先提交的事务版本就比较小，CDC 场景并发更新时就需要额外的机制来保证顺序。也就是 sequence 列，sequence 列的值由客户端控制。</li>
    </ul>
  </li>
  <li>
    <p>update 和写并发的时候，官方说行为不确定。</p>
  </li>
  <li>为啥存算分离模式下，主键会有一个表锁呢？而存算一体模式下没有类似的东西？
    <ul>
      <li>这个锁的存在是因为在事务提交阶段，需要更新所有 tablet 上的 delete bitmap。并且每个导入计算 delete bitmap 的时候，需要依赖现有的所有 delete bitmap。
让 AI 分析一下代码试试，看看能不能更加具体一点：核心问题还是 commit 阶段需要计算 delete bitmap。AI 的分析结论
        <ul>
          <li>delete bitmap update lock：负责 MoW delete bitmap 的最终正确性</li>
          <li>commitLock：负责把同表 MoW commit 先串一下，减少远端锁竞争、异步任务交错和重试风暴</li>
        </ul>
      </li>
      <li>这个问题和 2PC 也有点关系，单独开一节记录一下。</li>
    </ul>
  </li>
</ol>

<h2 id="doris-compaction-和-rocksdb-compaction-有哪些异同">Doris compaction 和 RocksDB compaction 有哪些异同？</h2>

<p>基本目的是相同的：都是 append 写，磁盘友好；后台合并来避免读性能太差。</p>

<p>我觉得要区别它们的 compaction 策略，一个关键问题是看在哪一层，重复数据被彻底消灭？
Doris 是在 base compaction 把重复数据彻底消灭。一次 base compaction 可以说几乎是读取所有数据来进行的。
RocksDB(leveled compaction) 除了 L0，其它每一层内部的数据都是不重叠的。</p>

<p>让 AI 给我分析一下异同，还是 AI 专业一点。它从适用场景、触发机制、合并粒度、资源控制来分析。</p>

<p>综合一下 AI 的理解，Compaction 的目标是尽可能“及时”的“触发”，“选择”一部分数据，并稳定性的“执行”。
这样就和 AI 分析的维度对应上了。</p>

<h2 id="doris-存算一体模式下的多副本是怎样保证一致性的">Doris 存算一体模式下的多副本是怎样保证一致性的？</h2>

<ul>
  <li>Doris 只需要两副本写成功，事务就可以提交了。
    <ul>
      <li>那一个副本缺版本了，又有查询怎么办？ — AI 说有个 tablet scheduler 会受到心跳，然后处理它，接着修复它。和我理解对得上。</li>
    </ul>
  </li>
</ul>

<h2 id="doris-存算一体和存算分离的-2pc">Doris 存算一体和存算分离的 2PC</h2>

<p>Doris 存算一体导入流程是：prepare -&gt; commit -&gt; publish。它这里的 commit 相当于 2PC 的 prewrite/precommit。
不过这里有个点是 commit 这个操作是指 1 个 tablet 写入成功。而 1 个 tablet 写入成功也需要 2 副本写入成功才行。</p>

<p>存算分离的导入流程为啥没有 publish 阶段了？存算一体的 publish 阶段本质是为了协调每个 BE 的元数据达到一致的状态。
而在存算分离模式下，它的元数据都是从 meta-service 同步。</p>

<p>从 2PC 的角度看“为啥没有 publish 阶段”？因为存算分离没有 2PC 的说法了，它把事务交给 meta-service 这样一个中心节点来处理。
所有元数据的操作都需要提交到 meta-service。使用元数据的时候，都需要去 sync 一下（当然这里有 cache 层）。</p>

<p>再想一个问题，2PC 的 commit 阶段是如何保证“最终一致”的？基本思路，假设某一个节点在过程中挂了，它恢复之后，
去问 coordinator，最终是应该 commit 还是 rollback。</p>]]></content><author><name>cosven</name></author><category term="笔记" /><category term="database" /><summary type="html"><![CDATA[学而时习之，不亦说乎]]></summary></entry><entry><title type="html">AI 笔记</title><link href="http://cosven.me/blogs/10029" rel="alternate" type="text/html" title="AI 笔记" /><published>2026-03-08T17:50:00+00:00</published><updated>2026-03-08T17:50:00+00:00</updated><id>http://cosven.me/blogs/ai-reading</id><content type="html" xml:base="http://cosven.me/blogs/10029"><![CDATA[<h2 id="读evaluating-memory-in-llm-agents-via-incremental-multi-turn-interactions03-10">读《Evaluating Memory in LLM Agents via Incremental Multi-Turn Interactions》(03-10)</h2>

<p>和 AI 一起读了一下这篇论文，也把它的 benchmark 手动跑了一下。个人感觉这篇论文有两个非常有学习价值的点</p>

<ol>
  <li>提出核心的评价维度是4个。
    <blockquote>
      <p>In this paper, based on classic theories from memory science and cognitive science, we identify four core competencies essential for memory agents: accurate retrieval, test-time learning, long-range understanding, and selective forgetting.</p>
    </blockquote>
  </li>
  <li>（AI 总结的）两个数据集。这篇论文为了填补现有基准在评估“准确检索”和“选择性遗忘”上的空白，
 专门构建了两个全新的数据集：EventQA 和 FactConsolidation。此外，作者强调，虽然现有很多长文本数据集，
 但它们大多是一次性输入给模型的。为了评测记忆代理，作者还将许多现有的长文本数据集（如 Document QA, LongMemEval 等）
 进行了重构，把它们切分成对话块（chunks），要求代理随时间推移增量式地读取和记忆。</li>
</ol>

<p>看一个 accurate retrieval 的 benchmark 题示例（对这个 benchmark 有个基本的感受）：</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Answer the question based on the memorized documents. Only give me the answer and do not output any other words.

 Now Answer the Question: In what country is Normandy located?
</code></pre></div></div>

<p>看一个 selective forgetting (multiple-hop) 的 benchmark 题示例（对这个 benchmark 有个基本的感受）：</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Pretend you are a knowledge management system. Each fact in the knowledge pool is provided with a serial number at the beginning, and the newer fact has larger serial number.
 You need to solve the conflicts of facts in the knowledge pool by finding the newest fact with larger serial number. You need to answer a question based on this rule. You should give a very concise answer without saying other words for the question **only** from the knowledge pool you have memorized rather than the real facts in real world.

For example:

 [Knowledge Pool]

 Question: Based on the provided Knowledge Pool, what is the name of the current president of Russia?
Answer: Donald Trump

 Now Answer the Question: Based on the provided Knowledge Pool, What is the country of citizenship of the spouse of the author of Our Mutual Friend?
Answer:
</code></pre></div></div>

<p>读后感：这几天看了两三个 agent 评测相关的博客或论文，总结下来有个共同的感受，找到核心的评测维度非常关键。
比如记忆系统，作者这里提炼了四个评测维度，然后每个维度设计评测数据集。再比如 03-06 读的那篇文章，
它的 ChatBI 评测也提炼了一些维度。之前还看到说 agent 评测，一个维度是评估它调用工具的能力。</p>

<h2 id="ai-这么强我还能赚钱么03-09">AI 这么强，我还能赚钱么？(03-09)</h2>

<p>想想，我是否还能通过数据库测试这个工具来赚钱？ -&gt; 结论还是可以的，但思路和人数有大变化</p>
<ol>
  <li>测试基建
    <ol>
      <li>【硬需求：懂测试基建的架构师】 基建选型：需要人工的调研和决策，划分系统边界。</li>
      <li>【实际需要】对于每个系统来说：需要指定系统的设计和验收方案。</li>
    </ol>
  </li>
  <li>测试设计
    <ol>
      <li>【硬需求：懂测试的架构师】测试设计：需要人工的设计。划分系统边界。</li>
      <li>【硬需求】场景测试：产品需求变成场景</li>
      <li>【实际需要】各类系统测试：需要有人结合架构师的设计，以及动手能力来落地测试。</li>
      <li>一个变化是 feature 测试将来一定是研发自己负责闭环。</li>
    </ol>
  </li>
</ol>

<h2 id="读2025我们这样评测-ai笔记2026-03-06">读《2025，我们这样评测 AI》笔记（2026-03-06）</h2>

<p>看这篇文章的初衷是我在本地也构建一些测试 agent。但怎么把这些 agent 分享给其他人，
怎样让其他人知道这些 agent 是真的能够解决一些实际问题呢。我觉得这就涉及 agent 的测试/评测。</p>

<p>文章链接：https://testerhome.com/topics/43475</p>

<p>有几个例子有利于理解 Agent 测试，一个是 ChatBI。
文中提到，AI 评测痛点：</p>
<ul>
  <li>评测数据集的构建：真实性，权威性，（以及全面性）</li>
  <li>有效断言：开发型问题的判定；标准答案的语义理解</li>
  <li>数据集规模（效率）</li>
</ul>

<p>评测举例，ChatBI：</p>
<ol>
  <li>评测预料生成：从业务理解角度拆出 “原子指标”，“加工逻辑”，和“分析维度”三个维度，从这三个维度确保全面性。</li>
  <li>评测指标：以查询结果是否正确为核心。查询结果是否正确的判断才用人工先给出一个标准答案。</li>
  <li>评测工具：自动生成评测语料。</li>
  <li>难点：用户问法多样性（比如复合问法）；断言效率与门槛。</li>
</ol>

<p>RAG 评测：
看下来，我的感受是作者没有讲清楚。</p>
<ol>
  <li>全集是啥：提到了单篇、多篇与标题。末尾作者也提到，这个还不够。</li>
  <li>评测指标：没有拆成可以量化的指标。</li>
  <li>局部最优的陷阱</li>
</ol>

<p>自己想想这个问题。如果把自己当成一个 RAG 系统，当一个问题来的时候</p>
<ol>
  <li>首先，需要判断这个问题是否能回答。
    <ol>
      <li>开放型问题，按理说这类问题不是 RAG 系统能解决的。</li>
      <li>确定性问题，则可以回答知道或不知道。然后再有答案的准确性。
        <ol>
          <li>推理性，统计性问题</li>
          <li>检索性问题
感觉从这个维度去拆分全集会好一些？算了，放弃看这个。</li>
        </ol>
      </li>
    </ol>
  </li>
</ol>

<p>Agentic 智能体评测：感谢写的没有特别清楚。</p>

<h2 id="happy-llm-学习笔记2026-03-05">happy-llm 学习笔记（2026-03-05）</h2>

<p>看了它的前两章，将 Transfermer 的架构，和老的神经网络架构做了对比。说它主要解决了两个问题，
一个是长距离依赖问题，一个是并行计算问题。接着又说了 LLM 另外一个核心概念，就是 Attention。
它的核心思想是：每个 token 都可以和输入序列中的任意一个 token 进行交互。算法没看太明白。
先放下来，等后续有机会再看。</p>

<h2 id="ai-代替测试工程师么2026-02-28">AI 代替测试工程师么？（2026-02-28）</h2>

<p>（数据库）测试工程师的工作内容：</p>
<ul>
  <li>测试
    <ul>
      <li>基础测试集和特性测试</li>
      <li>测试设计，测试实现，测试执行，测试结果分析</li>
      <li>测试基建</li>
    </ul>
  </li>
  <li>Bug review</li>
  <li>质量度量</li>
  <li>胶水工作：发版；流水线维护等</li>
</ul>

<p>最关键还是跑通这个流程：测试设计、编写、运行、沉淀用例。</p>

<p>个人感觉，AI 与人最大的区别在于它无法很好的沉淀记忆。而目前还没有很好的记忆组件，
听说 claude-mem 也有性能太差的问题。</p>

<p>按照我目前的调研，没有一个真正能工作的很好的 “长期记忆” 系统。基于 markdown 记忆的有 openclaw,
memsearch 等记忆系统。还有 claude 最新的记忆系统，也是基于 markdown 的。这一类奉行的是
Markdown is the source of truth。还有一种基于向量库的。supermemory, memori 等 SAAS 服务，
这种不知道真实效果如何，看资料效果好一点。</p>

<h2 id="ai-agent-开发-2025-09-09">AI Agent 开发 (2025-09-09)</h2>

<p>https://www.parlant.io/blog/how-parlant-guarantees-compliance/</p>

<p>这篇文章说了 Agent 开发的几个痛点问题，并概要描述 parlant 是怎样解决的。</p>

<p>文章提了两个衡量 Agent 效果的指标：失败频率；失败的严重程度。它还说了5种具体的失败类型。
它指出传统 agent 的核心问题的根源来自：<a href="https://openreview.net/forum?id=R6q67CDBCH">Curse of Instructions</a> 。
ps：它将‘依靠一段 prompt 来约束系统’的 agent 叫做传统。
这篇论文提到了一个研究观点：大模型遵守一两条规则是比较有效的，
当规则变多到10来条的时候，它遵守的准确定会大幅降低。</p>

<p>parlant 通过一套系统，让模型每次只需要遵守少数几条规则，来解决上述问题。
它的理论基础是 <a href="https://arxiv.org/abs/2503.03669">Attentive Reasoning Queries (ARQs)</a> 这篇论文。
另外，它也说自己这套规则（agentic rule）和在代码里面直接编写规则（scripted rule）还是有区别的。</p>

<p>读后感：这篇文章让我想起了 Gemini Cli 的 prompt，它定义了几种任务场景，然后为每种任务场景定义了一个工作流。
它的目的也是想让大模型按照某个思路来做事。我主观觉得 Gemini Cli 的局限性是比较明显的，
它 prompt 提到的规则势必会很泛。</p>]]></content><author><name>cosven</name></author><category term="阅读" /><category term="笔记" /><category term="AI" /><summary type="html"><![CDATA[读《Evaluating Memory in LLM Agents via Incremental Multi-Turn Interactions》(03-10)]]></summary></entry><entry><title type="html">AI benchmark 长啥样？有参考价值么？（1）</title><link href="http://cosven.me/blogs/10028" rel="alternate" type="text/html" title="AI benchmark 长啥样？有参考价值么？（1）" /><published>2025-12-03T16:04:00+00:00</published><updated>2025-12-03T16:04:00+00:00</updated><id>http://cosven.me/blogs/what-do-AI-benchmarks-look-like</id><content type="html" xml:base="http://cosven.me/blogs/10028"><![CDATA[<p><strong>TL;DR</strong> Benchmark 本身有价值，但分数‘没价值’。</p>

<p>不知道你们有没有这些疑问哈</p>
<ol>
  <li>大模型发布时，大都会刷榜（跑 benchmark），这些 benchmark 的参考价值怎么样？里面都有些什么样的测试题？能反应模型能力强弱么？</li>
  <li>光有模型不够呀，大模型自己又不会解决问题，总得有东西（现在咱都叫 agent）来调用大模型吧，厂商评测的时候，用的是啥 agent 呢？不同厂商用的 agent 相同么？</li>
</ol>

<p><a href="https://mp.weixin.qq.com/s/ohsU1xRrYu9xcVD7qu5lNw">DeepSeek-V3.2</a> <a href="https://mmbiz.qpic.cn/mmbiz_png/pkWC42uvwkmkWUpqHRFeNvCZJ4dbmZuoVzdEgO2VgzAMhiabCbR6Nrbuvb4KIdlmmxYy8xVkJm6m1YpicaQRhpNw/640?wx_fmt=png&amp;from=appmsg&amp;tp=webp&amp;wxfrom=5&amp;wx_lazy=1#imgIndex=0">这个表格</a>
显示它重点关注了 8 个基准测试集。其中 4 个评估推理能力的，分别是 AIME（美国数学邀请赛）, HMMT（哈佛 MIT 数学竞赛）,
HLE（人类全学科前沿难题测试）, CodeForces（世界级编程竞赛）。还有 4 个评估 Agentic 能力的，
分别是 SWE Verified, Terminal Bench 2.0，𝜏2-Bench，Tool Decathlon。前两个和程序员关系还是紧密的，
我重点研究下这两个 benchmark。</p>

<h2 id="swe-bench-verified">SWE-bench Verified</h2>

<p>下面是 AI 关于这个测试集的介绍，还是非常准确的。</p>

<blockquote>
  <p>SWE-bench（Software Engineering Benchmark）是一个专门用于评估大语言模型（LLM）在真实软件工程任务中表现的基准测试，
最初由普林斯顿大学 NLP 团队于 2023 年发布。 它的核心任务是：给定一个 GitHub 开源项目的代码仓库和一个对应的
issue（问题描述），模型需要像人类开发者一样，理解问题、定位代码、修改文件，并生成一个补丁（patch），
最终通过该项目原有的单元测试验证修复是否成功。
SWE-bench 的关键特点：</p>
  <ul>
    <li>真实场景：所有任务都来源于 GitHub 上 12 个流行 Python 项目的真实 issue 和对应的 pull request（PR），共 2,294 个任务实例。</li>
    <li>执行验证：采用“Fail-to-Pass”测试机制，即修复前测试失败，修复后测试通过，才算成功。</li>
    <li>高难度：任务涉及多文件理解、跨模块调用、复杂依赖关系等，远超传统代码补全或算法题。</li>
  </ul>
</blockquote>

<h3 id="其中一个题目">其中一个题目</h3>

<p>看一个真实的题，<a href="https://github.com/pylint-dev/pylint/issues/6471">链接是这个</a>，是一个真实的 GitHub Issue，
内容我就不贴过来了，请点击链接阅读。pylint 项目算是 Python 社区的一个中型项目，阅读 issue 可以发现，
这个题本身是真实存在的且有现实意义的，有一定的难度。并且在 issue 的描述中，没有透露任何解法。
总结来说：<strong>题目是有参考价值的</strong>，这就是普通的人类程序员遇到的问题。</p>

<h3 id="大模型怎样解题">大模型怎样解题</h3>

<p>大模型要解 SWE Verified 基准测试集里面的题目，就必须要修改，编辑代码文件。也就是说，<strong>必须得找一个 agent
来调用大模型</strong>，这样才能解题。那看看 DeepSeek 的打榜分数是用啥 agent 测出来的吧？</p>

<p>读一下 DeepSeek 论文，有一段文字解答了这个疑惑。答案是：使用内部框架去测的。</p>

<blockquote>
  <p>For SWE-bench Verified, the primary score was obtained using our internal framework.
Robustness tests across other settings—including the Claude Code and RooCode frameworks,
as well as non-thinking mode—produced consistent results, ranging from 72 to 74.</p>
</blockquote>

<p>有点可惜哈，看不到 DeepSeek 的 agent 代码和评估流程。不过，从这一小段文字，
<strong>这下你知道该用哪个 agent 来编码了吧 [阴险笑]</strong>。待我回头去试试 RooCode！</p>

<p>虽然看不到 DeepSeek 的评估流程，但找找资料可以发现，这个榜单的作者，他们已经提供了多个工具来帮助评测，
其中一个工具（agent）是 <a href="https://github.com/SWE-agent/mini-swe-agent">mini-swe-agent</a>。
这个 agent 核心代码只有 100，它想法非常大胆，我感觉非常有意思。我尝试概括一下它的核心思想。</p>

<blockquote>
  <p>用户从提出问题到看到最终的解决方案，只需要做两件事：一是在启动后把问题描述输入给它；
二是持续按 enter 键，直到模型自己说“我已经解决完毕了”。
这个 agent 让大模型“用且只用 bash 命令”来解决用户提出的编码问题。
模型在接受到用户的问题之后，会尝试自己去生成 bash 命令来获取上下文，或者编辑文件。</p>
</blockquote>

<p>你可能会好奇，解决上面这个 pylint 问题，那肯定需要修改代码呀。大模型光用 bash 命令，也能修改代码？
答案是yes，现在的大模型（我用 DeepSeek-v3.2 测试了一下）真的会用 bash 命令来编辑文件。举个例子，
在我测试的过程中，大模型会生成一条这样的 bash 命令，来编辑 <code class="language-plaintext highlighter-rouge">pylinter.py</code> 文件</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cd</span> /Users/cosven/code/pylint/pylint/lint <span class="o">&amp;&amp;</span> python3 <span class="o">&lt;&lt;</span> <span class="sh">'</span><span class="no">EOF</span><span class="sh">'
import os
...
...
content = xxx
...
# Write the modified file
with open('pylinter.py', 'w') as f:
    f.write(content)

print("Successfully modified pylinter.py")
</span><span class="no">EOF
</span></code></pre></div></div>

<p>除了这个“剑走偏锋”的 agent 外，还有很多其它 agent 也能辅助做类似的评测，我之前也<a href="https://cosven.me/blogs/10024">手动测过几个</a>，
感兴趣的话，你可以看看。</p>

<h2 id="一些思考">一些思考</h2>

<p>虽然目前只看了一个 benchmark，但对之前的两个问题，已经有了初步答案：参考价值还是有的，因为 benchmark 的测试题都是真实存在的。
但，这个 benchmark 的评测指标还是太局限了。举个例子，对于 SWE-bench Verified，各厂商只展现了一个指标，那就是 Resolved 率（也就是问题解决率）。
而人用大模型、或者 agent 来解决实际问题，<strong>不仅会关注最终的“解决率”，还有一个重要的指标是“效率”</strong>。我相信，
以后大模型和 agent 的 benchmark，一定会把效率考虑进去。</p>

<p>我用 mini-swe-agent + DeepSeek-V3.2 来尝试解决上面那个 pylint issue。硬是和大模型来回对话了 44 轮，
它才开始尝试修改代码来修复问题。而这时候，它已经花了我好几分钟了，同时花了我 3 毛钱（心疼啊【狗头】）。
我要正常用的话，别说 44 轮，第 2 轮它表现不符我意，我就不会继续和它对话了。</p>

<p>所以说，benchmark 是有用的，但榜单是没用的。好的，得到一个自己满意的答案，睡觉！</p>

<p>再想一下，这么“傻”的 agent 都能解决问题，且能让解决率达到 74.4%（DeepSeek-V3.2 测出来 73.1%）。
现在的大模型真是强的有点可怕，潜力很大。同时，agent 怎样发挥模型的本领，要/能做的事情还很多！</p>]]></content><author><name>cosven</name></author><category term="稍微正经点的" /><category term="AI" /><category term="benchmark" /><summary type="html"><![CDATA[TL;DR Benchmark 本身有价值，但分数‘没价值’。]]></summary></entry><entry><title type="html">“分布式数据库测试”这件小事（2）</title><link href="http://cosven.me/blogs/10025" rel="alternate" type="text/html" title="“分布式数据库测试”这件小事（2）" /><published>2025-08-11T14:50:00+00:00</published><updated>2025-08-11T14:50:00+00:00</updated><id>http://cosven.me/blogs/database-testing-2</id><content type="html" xml:base="http://cosven.me/blogs/10025"><![CDATA[<p>“牛”的“数据库测试工程师”具备哪些特质、怎样培养这些特质？当然，<code class="language-plaintext highlighter-rouge">牛 != 创造了最多价值 != 混得好</code>。
写篇博客来记录自己关于“数据库测试工程师”这个岗位的一些认识与思考。</p>

<p>我觉得应该要想几个问题：</p>
<ol>
  <li>公司需要我干什么？</li>
  <li>我主观觉得干啥比较有意思？</li>
  <li>干点啥呢？</li>
</ol>

<h2 id="第一个问题我认为的牛逼数据库测试打工人具备哪些特质">第一个问题：我认为的“牛逼数据库测试打工人”具备哪些特质？</h2>

<p>干数据库测试这么多年，有好几位同事/朋友明显的让我感觉“ta有点东西”，找了几个富有代表性的来尝试描述一下。</p>

<p>一位是动手能力很强。从测试基建、到测试前沿方法对应的工具都可以搞定，“码力极强”。
给我的体感是：给定一个技术活，只要目标足够明确，ta就可以搞定。
以此为基础，再学习一些数据库与分布式某一具体领域的知识，ta可以转型做研发。
核心竞争力：编码能力强；精通特定几类测试工具。</p>

<p>一位是‘测试’能力很强。质量理念到位，对各项测试活动以及怎么干有丰富经验，测试用例设计能力强。
体现为对“怎么做测试”理解比较深。给我的体感是：给定一个产品，ta知道要干啥才能测好，即使当下对产品理解没那么深刻。
核心竞争力：质量理念清晰；精通质量活动落地；测试用例设计能力强。</p>

<p>一位在‘数据库性能’方面有比较深的理解。ta对性能经典测试集熟悉，熟悉性能问题的定位方法，
对部分经典的性能优化方法也有了解，能帮助用户 PoC，解决 PoC 过程中的问题。
给我的体感是：用户遇到的大部分性能问题，ta能解决；偶尔还能发现一些产品潜在的性能优化点；对性能问题富有热情。
核心竞争力：精通数据库测试一个垂直领域：性能（类似的应该还有高可用、混沌、SQL测试等）；综合能力。</p>

<p>下面自我剖析一下。</p>

<p>根据自己的兴趣，喜欢上面三种的哪个？</p>
<blockquote>
  <p>对 1 最感兴趣，因为 1 看起来富有创造性。接触新事物。
其次是 3，会有很多解决问题的成就感。
最后是 2，这个角色会让人有一种“敌军围困万千重，我自岿然不动”的怡然自得感。</p>
</blockquote>

<p>我的能力模型，和上面三者分别有什么异同？</p>
<blockquote>
  <p>和1比：动手能力没那么强。
和2比：测试能力没那么强。
和3比：并没有在一个领域有这么强的统治力。</p>

  <p>那我总得有点其它优势吧？
🥶硬说，就是更综合。
🥶但大部分工作似乎需要特长，不需要综合。</p>
</blockquote>

<p>好，进入下一个问题。公司对测试岗的要求或期望是什么？
上面三者应该也是很好的满足了公司的某一类期望。</p>

<h2 id="第二个问题公司对测试岗的要求或期望是什么">第二个问题：公司对测试岗的要求或期望是什么？</h2>

<p>我认为有是三方面（其实是从各个我认同的 JD 上抄过来的）</p>
<ol>
  <li>保障产品质量。从客户需求、架构设计、编码等多方面保障产品的质量，发现风险并推动快速解决；合理的测试流程和准出标准。</li>
  <li>提升测试效率。包括测试用例的设计效率、测试用例编写、执行效率，测试结果分析效率。</li>
  <li>创新测试工具和方法。引入新的测试工具和测试框架，探索新的测试场景、测试方法。</li>
</ol>

<blockquote>
  <p>写到这里时，想起来一个有意思的“加班通知”。这个加班通知用白话文，而不是所谓的“公文语言”
把事情描述的很清楚，而且给人感觉会更亲切一些。但我自己似乎已经习惯了 1,2,3,… 的表达方式，不是一个好趋势。
<a href="https://www.zhihu.com/question/1939966359892095893/answer/1939970603613426294">企业加班通知走红，涨薪 25%、发 800 补贴，清洁阿姨帮看娃，如何看待此事？是否存在潜在违法风险？ - 楠说的回答 - 知乎</a></p>
</blockquote>

<p>上面三方面有点抽象，举几个具体例子来看看？</p>

<h3 id="测试效率">测试效率</h3>
<p>我遇到的数据库公司都喜欢发很多版本，然后就有一个发版效率的问题：比如要求N天把所有测试跑完。
这个目标通常就要求一套自动化测试基建。包括资源申请释放，集群部署工具，测试执行调度，测试结果分析等子系统。
这个事情显然很重要，同时我也觉得这个事情似乎没那么有技术挑战。但似乎比较容易陷入“能用就行”的尴尬境地 :)
感觉这个工作对应的技能标签是：云；K8s；CI/CD。</p>

<h3 id="保障产品质量">保障产品质量</h3>
<p>需求调研，方案设计、编码实现，code review，研发流程大家都知道，但是做的有好有差。测试流程，更难弄好。
测试流程、准出标准，bug triage 流程，流程肯定还是要的，怎么落地也是很需要能力的。
若干个垂直的通用测试集，是基础质量的重要保障，把这些弄好，70% 的信心就有了。
新特性的质量保障，考验个人测试能力与质保流程、基础测试集。
技能标签：流程方法；测试设计；产品、数据库、分布式系统理解；测试工具与方法。</p>

<h2 id="碎碎念">碎碎念</h2>

<p>最后，当然是回顾下两年前写的另外一篇 <a href="/blogs/10017">“分布式数据库测试”这件小事</a>。有没有点进步？</p>

<p>更像测试一点了 :) 对怎样评估和改进质量有了更多维度的认识；对测试用例设计有一套不知道好不好的方法论。
对职场和‘创业’公司的了解多了一点点。</p>

<p>分布式数据库<strong>核心</strong>功能 + 通用测试集 + AI !!! 多动手!! 多‘混混’!</p>

<p>从 08-11 写到 09-24，拖了一个月，终于糊弄完了。</p>]]></content><author><name>cosven</name></author><category term="稍微正经点的" /><category term="work" /><category term="database" /><category term="testing" /><summary type="html"><![CDATA[“牛”的“数据库测试工程师”具备哪些特质、怎样培养这些特质？当然，牛 != 创造了最多价值 != 混得好。 写篇博客来记录自己关于“数据库测试工程师”这个岗位的一些认识与思考。]]></summary></entry><entry><title type="html">AI编程哪家强？Benchmark搞一把</title><link href="http://cosven.me/blogs/10024" rel="alternate" type="text/html" title="AI编程哪家强？Benchmark搞一把" /><published>2025-07-26T02:35:00+00:00</published><updated>2025-07-26T02:35:00+00:00</updated><id>http://cosven.me/blogs/AI-coding-benchmark</id><content type="html" xml:base="http://cosven.me/blogs/10024"><![CDATA[<p>Claude Code、Gemini Cli 等命令行工具相继发布，这两个月 AI 编码又火出了新高度。
我对效率类工具一直都特感兴趣，喜欢折腾和把玩它们，加之这些工具是实实在在提升效率。
我去年底接触 Aider、Cursor、Cline、Continue，就想写篇博客来记录一下我对它们的感受。
最近又有些新感触！搞个博客来记录一下。</p>

<p>本来呀，我也只是想写一篇 “Aider 是怎么跑 benchmark 的” 的笔记。但看完了它的跑法之后呢，
感觉没啥可聊的。这两天正好看懂车帝搞了个智驾测试，挺有意思（特斯拉是真有点东西？）；
加上最近几年工作也是搞测试；再加上有好几个朋友说 Claude Code 牛出天际，我就想看看是不是那么回事！</p>

<p>我就充当一回“懂AI帝”，来评测一把。</p>

<h2 id="如何评测">如何评测？</h2>

<p>我也知道，要完善的评测一个工具，是很麻烦的。毕竟场景那么多，每个工具都有自己的擅长领域。
你看懂车帝的评测，就有很多人喷，但也有很多人顶它。我下面先介绍一下我的评测方法。</p>

<p>我看到的“榜单”有两个，一个是 <a href="https://aider.chat/docs/leaderboards/">Aider LLM Leaderboards</a>，还有一个是 <a href="https://www.swebench.com/">SWE-bench</a>。
前者可能比较小众，先简单介绍一下后者（让 AI 给我总结一把什么是 SWE-bench）</p>

<blockquote>
  <p>SWE-bench（Software Engineering Benchmark）是一个专门用于评估大语言模型（LLM）在真实软件工程任务中表现的基准测试，最初由普林斯顿大学 NLP 团队于 2023 年发布。
它的核心任务是：给定一个 GitHub 开源项目的代码仓库和一个对应的 issue（问题描述），模型需要像人类开发者一样，理解问题、定位代码、修改文件，并生成一个补丁（patch），最终通过该项目原有的单元测试验证修复是否成功。
SWE-bench 的关键特点：
真实场景：所有任务都来源于 GitHub 上 12 个流行 Python 项目的真实 issue 和对应的 pull request（PR），共 2,294 个任务实例。
执行验证：采用“Fail-to-Pass”测试机制，即修复前测试失败，修复后测试通过，才算成功。
高难度：任务涉及多文件理解、跨模块调用、复杂依赖关系等，远超传统代码补全或算法题。</p>
</blockquote>

<p>Aider LLM Leaderboards 虽然小众，但人家评测流程和数据都是开源透明的，我觉得它的数据还是挺有参考价值的。
有兴趣的小伙伴可以去看看。</p>

<p>我从 SWE-bench 中选了一个题 <a href="https://huggingface.co/datasets/princeton-nlp/SWE-bench_Verified/viewer/default/test?f%5Brepo%5D%5Bvalue%5D=%27pylint-dev%2Fpylint%27&amp;sort%5Bcolumn%5D=created_at&amp;sort%5Bdirection%5D=desc&amp;sort%5Btransform%5D=length&amp;row=325">pylint-dev__pylint-6528</a> 来评测这些工具。
我选它，是因为看中了这个题的几个特点：</p>
<ol>
  <li>难度适中。它的难度评级是 <code class="language-plaintext highlighter-rouge">15min - 1hour</code>，简单的题是 15min 以内，比如算法题。难的题要好几个小时。</li>
  <li>这个题的答案要修改两个文件。我觉得这对 Coding 工具是有一些挑战的，只改一个文件在当下这个时间节点，对它们没啥挑战。</li>
  <li>这个题很好理解。我看了一遍题目的 problem statement，我就看懂了，不需要很强的背景知识。</li>
  <li>pylint 这个项目，我自己也接触过，有把握能在本地搭好评测环境、判断 AI 答案的准确性等。</li>
</ol>

<p>不仅题目，评测流程也很重要。比如说，不同的 PROMPT 就会带来完全不一样的结果。我的评测原则和流程如下</p>
<ol>
  <li>PROMPT 要完全一致，或者基本一致。比如，我给每个工具说的第一句话都是一模一样的
    <blockquote>
      <p>解决一下这个问题：{problem_statement}</p>
    </blockquote>
  </li>
  <li>当工具问我要不要做某个操作时，我基本都会回答是，这样尽可能保证 apple-to-apple。除非以下场景
    <ol>
      <li>它要跑 lint 命令。我会拒绝。比如，Aider 的一个机制就是会跑 lint 命令来让代码质量更好。但我也用过很多次，它跑 lint 命令的时候，会 lint 并尝试修改老代码，这其实引入了很大的风险。</li>
      <li>它要跑 unit test 命令。我会拒绝。比如，很多工具都会尝试自动跑测试，但根据我的经验，它们的测试命令都非常粗糙。它可能直接建议我跑 pytest，跑一遍可能都过年了。</li>
      <li>它要给我添加测试。我会拒绝。因为 SWE-bench 数据集里面已经有测试用例了，不需要它来。</li>
    </ol>
  </li>
</ol>

<p>我评测流程，如果用伪代码来描述，就是</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">evaluate</span><span class="p">():</span>
	<span class="n">start_tool_with_default_parameters</span>
	<span class="n">send_to_chat</span><span class="p">:</span> <span class="sb">`解决一下这个问题：{problem_statement}`</span>
	<span class="n">enter</span> <span class="n">yes</span> <span class="n">until</span> <span class="n">它生成修复代码</span>

	<span class="c1"># 初步检查答案，保证它的答案不会让回归测试失败
</span>	<span class="k">while</span> <span class="n">我主观觉得它还有戏</span><span class="p">:</span>
		<span class="n">run</span> <span class="n">PASS</span><span class="o">-</span><span class="n">TO</span><span class="o">-</span><span class="n">PASS</span> <span class="n">tests</span>  <span class="c1"># 如果这个测试都跑不过，这个工具评测结果不及格
</span>		<span class="k">if</span> <span class="n">fail</span><span class="p">:</span>
		 	<span class="n">send_to_chat</span><span class="p">:</span> <span class="n">有</span> <span class="n">X</span> <span class="n">个测试失败了</span><span class="err">：</span><span class="p">{</span><span class="n">failure_summary</span><span class="p">}</span>
			<span class="n">enter</span> <span class="n">yes</span> <span class="n">until</span> <span class="n">它再一次生成修复代码</span>
		<span class="k">else</span><span class="p">:</span>
			<span class="c1"># 认为它代码已经修改完毕，直接开始检查它的答案
</span>			<span class="k">break</span>

	<span class="c1"># 检查最终答案
</span>	<span class="k">while</span> <span class="n">我主观觉得它还有戏</span><span class="p">:</span>
		<span class="n">run</span> <span class="n">FAIL</span><span class="o">-</span><span class="n">TO</span><span class="o">-</span><span class="n">PASS</span> <span class="n">tests</span>
		<span class="k">if</span> <span class="n">fail</span><span class="p">:</span>
		 	<span class="n">send_to_chat</span><span class="p">:</span> <span class="n">有</span> <span class="n">X</span> <span class="n">个测试失败了</span><span class="err">：</span><span class="p">{</span><span class="n">failure_summary</span><span class="p">}</span>
			<span class="n">enter</span> <span class="n">yes</span> <span class="n">until</span> <span class="n">它再一次生成修复代码</span>
		<span class="k">else</span><span class="p">:</span>
			<span class="k">break</span>
</code></pre></div></div>

<p>更新(07-27 22:36): 这里 while 的地方有个主观部分，你可能会觉得它会影响这个评测的结果。严格来说，确实会有影响。但这里所谓的“主观”其实也是有判断标准的：即如果两次改动的代码都不符合预期，就认为它没戏。这个主要是考虑测试效率。</p>

<h2 id="tldr-评测结果">TL;DR 评测结果</h2>

<p>我写了评测过程，让 AI 帮我总结了一个评测结果的表格。<strong>打分是我根据这次任务，主观打的</strong>。</p>

<table>
  <thead>
    <tr>
      <th>工具</th>
      <th>模型</th>
      <th>测试结果</th>
      <th>小结</th>
      <th>打分</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Aider</td>
      <td>deepseek-chat-v3-0324</td>
      <td>通过</td>
      <td>问题定位非常准确，一次性找到关键文件和函数；修复过程中遇到循环引用但最终解决</td>
      <td>⭐⭐⭐⭐</td>
    </tr>
    <tr>
      <td>Gemini Cli</td>
      <td>gemini-pro</td>
      <td>通过</td>
      <td>问题定位准确，修复过程需多次交互，最终解决；有时会卡主</td>
      <td>⭐⭐⭐</td>
    </tr>
    <tr>
      <td>Claude Code</td>
      <td>原生版</td>
      <td>通过</td>
      <td>问题定位准确，一次性修复成功；交互体验良好，TODO列表清晰</td>
      <td>⭐⭐⭐⭐⭐</td>
    </tr>
    <tr>
      <td>Claude Code</td>
      <td>Qwen3-Coder-480B</td>
      <td>失败</td>
      <td>问题定位基本准确，修复方案不正确；交互过程展示过多细节</td>
      <td>⭐⭐</td>
    </tr>
    <tr>
      <td>Claude Code</td>
      <td>deepseek-chat-v3-0324</td>
      <td>失败</td>
      <td>流程走不完，无法评价</td>
      <td>⭐</td>
    </tr>
    <tr>
      <td>Trae</td>
      <td>Builder(Auto)</td>
      <td>失败</td>
      <td>问题定位不够准确，修复方案不正确；交互过程展示过多细节</td>
      <td>⭐⭐</td>
    </tr>
    <tr>
      <td>Trae</td>
      <td>Builder(Claude Sonnet 4)</td>
      <td>失败</td>
      <td>排不上队，无法评价</td>
      <td>⭐</td>
    </tr>
    <tr>
      <td>Trae</td>
      <td>Builder(DeepSeek)</td>
      <td>失败</td>
      <td>问题定位不够准确，修复方案不正确；交互过程展示过多细节</td>
      <td>⭐⭐</td>
    </tr>
    <tr>
      <td>Cursor</td>
      <td>Auto</td>
      <td>失败</td>
      <td>问题定位准确，修复方案有问题；搜索展示简洁，交互体验勉强还行</td>
      <td>⭐⭐</td>
    </tr>
  </tbody>
</table>

<h2 id="评测结果分析">评测结果分析</h2>

<p>在评测过程中，我发现了一些有意思的细节，下面也和读者分享一波。另外评测还有很多局限性，也给自己跌跌甲，轻喷。</p>

<p>我从评测过程中，提炼了几个维度来评价这些工具。这里最重要的指标是问题最终是否被解决了。
如果问题解决了，过程坎坷一点也能接受。如果问题没解决，过程再惊艳，也没用。
因此，我给 Claude Code, Aider, Gemini Cli 打的分数比较高。其它就低一些。</p>

<p>第二个维度是交互体验。这里又可以细分：UI/UX；可观测性；性能；稳定性。我暂时就想到这几个维度。</p>

<table>
  <thead>
    <tr>
      <th>维度</th>
      <th>问题解决能力</th>
      <th>UI/UX</th>
      <th>性能与稳定性</th>
      <th>收费</th>
      <th>综合打分</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Aider+DS</td>
      <td>⭐⭐⭐⭐</td>
      <td>⭐⭐⭐</td>
      <td>⭐⭐⭐</td>
      <td>⭐⭐⭐⭐</td>
      <td>⭐⭐⭐⭐</td>
    </tr>
    <tr>
      <td>Gemini Cli</td>
      <td>⭐⭐⭐⭐</td>
      <td>⭐⭐</td>
      <td>⭐⭐⭐</td>
      <td>⭐⭐⭐⭐</td>
      <td>⭐⭐⭐</td>
    </tr>
    <tr>
      <td>Claude Code</td>
      <td>⭐⭐⭐⭐⭐</td>
      <td>⭐⭐⭐</td>
      <td>⭐⭐⭐⭐</td>
      <td>⭐</td>
      <td>⭐⭐⭐</td>
    </tr>
    <tr>
      <td>Trae(DS)</td>
      <td>⭐⭐</td>
      <td>⭐⭐⭐</td>
      <td>⭐⭐⭐</td>
      <td>⭐⭐⭐</td>
      <td>⭐⭐⭐</td>
    </tr>
    <tr>
      <td>Cursor</td>
      <td>⭐⭐</td>
      <td>⭐⭐⭐⭐</td>
      <td>⭐⭐⭐⭐</td>
      <td>⭐⭐</td>
      <td>⭐⭐⭐</td>
    </tr>
  </tbody>
</table>

<ul>
  <li><strong>UI/UX</strong>：指的是用户界面和用户体验。
    <ul>
      <li>Aider 界面简洁；交互基本都是一波流。但可观测性差了点。</li>
      <li>Gemini Cli 的展示总是半屏（让我感觉有 bug 一样）；交互略微繁琐。</li>
      <li>Claude Code 的界面也有繁琐，展示了很多工具的操作与结果；交互体验还行。另外它比较精致一点。</li>
      <li>Trae 和 Cursor 都是 GUI 的
        <ul>
          <li>两者都把过程搞得很繁琐，每一次工具操作都显示出来且不能折叠，繁琐。不过也是有点好处的。</li>
          <li>编辑的时候可以 accept 一部分，这个可控性比较好，这是 GUI 的优势</li>
          <li>工具的结果方便查看，这也是 GUI 的优势</li>
        </ul>
      </li>
    </ul>
  </li>
  <li><strong>性能与稳定性</strong>：
    <ul>
      <li>稳定性方面：三个 Cli 工具感觉都有点小毛病。</li>
      <li>性能方面：Trae 的 edit 速度体感比较慢（感觉是设计上的问题，vscode 的 edit 速度也很慢）。</li>
    </ul>
  </li>
  <li><strong>收费</strong>：
    <ul>
      <li>Aider 支持任何模型，加之有很多免费 API，总体给高评分。</li>
      <li>Gemini Cli 免费额度基本够用。但不支持其它模型。</li>
      <li>Claude Code 贵出天际，一天不用上三个小时，感觉有点亏 🐶</li>
      <li>Trae 似乎可以免费用，只是要排队。好像不能设置其它模型。</li>
      <li>Cursor 有免费额度，额度很小。</li>
    </ul>
  </li>
</ul>

<p>值得一提的是，模型真的很重要。不同的模型，测出来结果差异可能会差很远。</p>

<p>还有个值得一提的是，这里评测的背景是解决一个实际问题。最后再附加一下个人的综合性观点</p>
<ol>
  <li>假设我很有钱、或者工作里面需要经常堆shi，我应该会选择 cursor。也会考虑 claude code。</li>
  <li>在我钱不多、且编码不那么多的情况下，我会选择 Aider + VSCode(Copilot)</li>
  <li>Gemini Cli 和 Trae 感觉目前竞争力还差点。如果 Trae 让我免费用，我也乐意 🐶</li>
</ol>

<h2 id="评测过程记录">评测过程记录</h2>

<p>注：我也 review 了一下自己的评测过程记录，我发现我给 Aider 记录的比较详细（大概率是因为一开始时间充裕），
给 Claude 记录的也比较详细（因为我对它期望比较高，而它失败了几次）。其它的记录就比较摘要了，我后面变懒了可能是一方面；但更重要的是，它们有太多的工具调用、很繁琐，不太好记录。</p>

<h3 id="aider--deepseek-chat-v3-0324">Aider + deepseek-chat-v3-0324</h3>
<p>Aider (openrouter/deepseek/deepseek-chat-v3-0324:free)</p>

<p>测试过程摘要</p>
<ul>
  <li>我：解决一下这个问题：{problem_statement}</li>
  <li>Aider：花了 10s 扫描了一遍整个项目
    <blockquote>
      <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Scanning repo: 100%|███████████████████████████| 2580/2580 [00:09&lt;00:00, 260.12it/s]
</code></pre></div>      </div>
    </blockquote>
  </li>
  <li>Aider: 一波分析，比较准确的识别了问题所在的文件 <code class="language-plaintext highlighter-rouge">pylint/lint/expand_modules.py</code> 和 <code class="language-plaintext highlighter-rouge">pylint/lint/pylinter.py</code>，并且询问我是否要把这两个文件加入到聊天中。
    <ul>
      <li>点评：Aider 分析的结果非常准确。可以看下 Aider 是怎样找到这两个文件的。
        <blockquote>
          <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Based on the bug report, the issue is with recursive file discovery not properly honoring ignore settings in Pylint. The key
files that likely need to be modified are:

 1 pylint/lint/pylinter.py - This handles the core linting logic and would manage the recursive file discovery
 2 pylint/lint/expand_modules.py - This handles module expansion and file discovery

These are the most likely files that need changes to fix the ignore pattern behavior during recursive mode.
...省略一些分析...
...省略一些分析...
</code></pre></div>          </div>
        </blockquote>
      </li>
    </ul>
  </li>
  <li>我：连续两个 Enter（代表 yes，把文件加入到聊天中）</li>
  <li>Aider: 输出了它的第一个解决方案
    <blockquote>
      <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>I'll help fix the ignore paths behavior in recursive mode. The issue is that _discover_files() in pylinter.py doesn't properly
apply the ignore patterns during recursive directory traversal. Here are the needed changes:
</code></pre></div>      </div>
    </blockquote>
    <ul>
      <li>点评：上面是 Aider 的一部分分析，Aider 这里又精确的找到了问题所在的函数。</li>
    </ul>
  </li>
  <li>Aider: 自动执行了 lint，并询问我是否要修复这些 lint 错误</li>
  <li>我：输入 No
    <ul>
      <li>注：根据我过去的使用经验，Aider 的 lint 不一定能很好工作，可能会帮倒忙。几方面
        <ol>
          <li>代码库本来可能就没有 lint，它 lint 的时候，报了很多老代码的问题。这时候修复它们不是一个好主意</li>
          <li>代码库的 lint 命令和 Aider 的 lint 命令可能不一样。导致结果帮倒忙。</li>
        </ol>
      </li>
      <li>但 Aider 自己在 benchmark 的时候，它在测试的过程中是会<a href="https://aider.chat/2024/05/22/swe-bench-lite.html">自动执行 lint</a> 的。</li>
    </ul>
  </li>
  <li>我：在另外一个终端中执行一下老的测试用例集(PASS-TO-PASS)，发现有两个之前能跑过的测试，现在跑不过了。于是把错误摘要信息贴给它。
    <blockquote>
      <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> 	&gt; 有两个测试跑失败了：FAILED tests/test_self.py::TestRunTC::test_recursive - AttributeError: 'PyLinter' object has no attribute '_ignore_paths'
 	&gt; FAILED tests/test_self.py::TestRunTC::test_recursive_current_dir - AttributeError: 'PyLinter' object has no attribute '_ignore_paths'
</code></pre></div>      </div>
    </blockquote>
  </li>
  <li>Aider：又是一波操作</li>
  <li>Aider：又问我是否 lint</li>
  <li>我：输入 No</li>
  <li>我：再次执行一遍测试用例集，发现又有了新的报错。仍然简单的把错误贴给它。
    <blockquote>
      <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>这两个测试还是报错，而且还是报类似的错，变量没有初始化：FAILED tests/test_self.py::TestRunTC::test_recursive - NameError: name '_is_in_ignore_list_re' is not defined
FAILED tests/test_self.py::TestRunTC::test_recursive_current_dir - NameError: name '_is_in_ignore_list_re' is not defined
</code></pre></div>      </div>
    </blockquote>
  </li>
  <li>Aider：还是一波操作，修改了一波代码。接着就是问我是否 lint（我是不）</li>
  <li>我：再次执行测试用例。发现这下测试都跑不起来了。由于错误信息不多，我就把错误信息完整贴给了它。
    <blockquote>
      <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>现在测试都跑不了了： pytest tests/test_self.py
/Users/cosven/code/pylint/.venv/lib/python3.8/site-packages/_pytest/config/__init__.py:331: PluggyTeardownRaisedWarning: A plugin raised an exception during an old-style hookwrapper teardown.
Plugin: helpconfig, Hook: pytest_cmdline_parse
ConftestImportFailure: ImportError: cannot import name '_is_in_ignore_list_re' from partially initialized module 'pylint.lint.utils' (most likely due to a circular import) (/Users/cosven/code/pylint/pylint/lint/utils.py) (from /Users/cosven/code/pylint/tests/conftest.py)
For more information see https://pluggy.readthedocs.io/en/stable/api_reference.html#pluggy.PluggyTeardownRaisedWarning
  config = pluginmanager.hook.pytest_cmdline_parse(
ImportError while loading conftest '/Users/cosven/code/pylint/tests/conftest.py'.
tests/conftest.py:15: in &lt;module&gt;
    from pylint.lint import PyLinter
pylint/lint/__init__.py:21: in &lt;module&gt;
    from pylint.lint.parallel import check_parallel
pylint/lint/parallel.py:16: in &lt;module&gt;
    from pylint.lint.utils import _patch_sys_path
pylint/lint/utils.py:16: in &lt;module&gt;
    from pylint.lint.expand_modules import get_python_path
pylint/lint/expand_modules.py:8: in &lt;module&gt;
    from pylint.lint.utils import _is_in_ignore_list_re
E   ImportError: cannot import name '_is_in_ignore_list_re' from partially initialized module 'pylint.lint.utils' (most likely due to a circular import) (/Users/cosven/code/pylint/pylint/lint/utils.py)
</code></pre></div>      </div>
    </blockquote>
  </li>
  <li>Aider：又是一波一样的操作。</li>
  <li>我：再次执行测试用例。发现老的测试用例都可以跑过了
    <ul>
      <li>点评：Aider 这里虽然解决了问题，但我人肉看了，它的解决方案不是最佳（它新增了一个文件来解决循环引用的问题，但其实不需要）。</li>
    </ul>
  </li>
  <li>我：用 swe-bench 里面用来评测这个修复的新测试用例(FAIL-TO-PASS)也跑了一遍，发现新测试用例也可以跑过了。至此，Aider 算是解决了这个问题。</li>
</ul>

<h3 id="gemini-cli第一轮测试">Gemini Cli（第一轮测试）</h3>

<p>测试过程摘要</p>
<ul>
  <li>我：<code class="language-plaintext highlighter-rouge">解决一下这个问题：{problem_statement}</code></li>
  <li>Gemini: 上来说自己想按照问题描述的步骤来复现一下。问我是否同意？</li>
  <li>我：不用复现了，直接修复吧 (我思考了一下，感觉复现比较复杂，所以让它直接修复。)</li>
  <li>Gemini：
    <blockquote>
      <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>我将首先搜索代码库，找到处理文件收集和递归逻辑的部分，然后进行修复。我推测问题可能出在 pylint/lint/discover.py 文件中。
 	&gt; ✔  FindFiles 'pylint/lint/discover.py ---&gt; No files found
✦ 好的，看来我猜错了文件名。

我将通过在代码库中搜索 recursive 来定位处理文件发现和递归逻辑的相关代码。这应该能让我找到正确的文件并进行修复。
✔ SearchText 'recursive' within pylint ---&gt; Found 32 matche(s)
pylint/lint/pylinter.py 中的 if self.config.recursive: 是一个很强的线索。我将检查该文件，了解是如何发现文件的，以及 ignore 逻辑是如何（或没有）被应用的。

我将阅读 pylint/lint/pylinter.py 的内容。
✦ 我仔细阅读了 pylint/lint/pylinter.py 的代码。

问题似乎出在 _discover_files 方法中。当 recursive 标志被设置时，这个方法负责遍历目录并找到要检查的 Python 文件。
...省略一些代码...
...省略一些代码...
...省略一些代码和一些分析...
询问我是否同意修改？
</code></pre></div>      </div>
    </blockquote>
  </li>
  <li>我：同意</li>
  <li>Gemini: apply 了上面的修改建议，并问我是否需要运行 pytest 命令</li>
  <li>我：不需要，并自己运行 swe-bench 中指定的测试用例 (PASS-TO-PASS)。
    <ul>
      <li>点评：和 Aider 问我要不要跑 lint 类似，跑 pytest 有很多不确定性。我自己跑 pytest 肯定只跑特定的。</li>
    </ul>
  </li>
  <li>我：上面的测试用例都跑过了。尝试用 FAIL-TO-PASS 中的测试用例集合来跑一下。</li>
  <li>我：发现这次测试的基准代码有问题。用了之前 Aider 修复后的代码。于是中断了这次测试。</li>
</ul>

<h3 id="gemini-cli-第三轮测试">Gemini Cli (第三轮测试)</h3>

<p>这里直接跳过了 Gemini Cli 的第二轮测试，是因为我在第二轮测试时，感觉 Gemini 似乎聪明了很多，
于是我找了下它的缓存，把缓存删了一把 <code class="language-plaintext highlighter-rouge">rm -rf ~/.gemini/tmp/xxxhashxxx/</code>。
删了之后，第三轮测试看起来是正常的。下面是测试记录</p>

<ul>
  <li>我：<code class="language-plaintext highlighter-rouge">解决一下这个问题：{problem_statement}</code></li>
  <li>Gemini：（一波思考，过程忽略）
    <ul>
      <li>备注：思考了两分钟，还在思考，我直接让它停止了。ℹ Request cancelled.</li>
      <li>点评：Gemini 和 Claude Code 在交互上有点相似，会把它当前在干什么动态展示出来，这个在体验上是个加分项。但是要补充的是，它展示的信息基本上就是一扫而过，并且我看不到过程记录，又有点“展示了个寂寞”的味道。</li>
    </ul>
  </li>
  <li>我：<code class="language-plaintext highlighter-rouge">解决一下这个问题：{problem_statement}</code>
    <ul>
      <li>备注：由于它上一轮一直在思考，我给它 cancel 了，于是重新把问题发给它</li>
    </ul>
  </li>
  <li>Gemini：
    <blockquote>
      <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> 我将按以下步骤来修复这个问题：
 ...省略一些 Gemini 的分析...

 首先，我需要浏览一下 Pylint 的代码，以便更好地了解项目结构。我将从 pylint/lint 目录开始，因为这里很可能包含了核心的 linting 逻辑。
✔  FindFiles 'pylint/lint/**/*.py' ---&gt; Found 10 matching file(s)
✦ pylinter.py 和 expand_modules.py 这两个文件看起来最可疑，一个负责 PyLinter 的主体逻辑，另一个负责模块的发现和过滤。

我先看看 pylint/lint/expand_modules.py，了解下它在递归模式下是如何搜寻文件以及应用 ignore 规则的。
✔  ReadFile pylint/lint/expand_modules.py
我注意到 PyLinter 类中有两个相关方法：_discover_files 和 _expand_files。
 ...省略一些 Gemini 的分析...
 ...省略一些 Gemini 的分析和修改思路...
问我是否接收它的修改提议，问了好几个问题
</code></pre></div>      </div>
    </blockquote>
    <ul>
      <li>点评：这一次 Gemini 比第一次测试的时候，表现得更聪明一些。思考两分钟还是有点效果的 :)</li>
    </ul>
  </li>
  <li>我：全部回答 yes（除了有一个问题：它想帮我加测试，这个我拒绝了）</li>
  <li>我：手动执行一遍测试用例(PASS-TO-PASS)，发现报错
    <blockquote>
      <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>有两个测试跑失败了：FAILED tests/test_self.py::TestRunTC::test_recursive - AttributeError: 'PyLinter' object has no attribute '_ignore_paths'
FAILED tests/test_self.py::TestRunTC::test_recursive_current_dir - AttributeError: 'PyLinter' object has no attribute '_ignore_paths'
</code></pre></div>      </div>
    </blockquote>
    <ul>
      <li>点评：这个报错和 Aider 第一次修复的报错很相似</li>
    </ul>
  </li>
  <li>Gemini: 又来了一波修复，并询问我是否接受
    <ul>
      <li>点评：Gemini 会把一次改动拆分成很多步骤，会提很多问题。而 Aider 则是一波流。</li>
    </ul>
  </li>
  <li>我：全部接受。然后执行(PASS-TO-PASS)。发现测试运行不了了。我把测试直接贴给了 Gemini</li>
  <li>Gemini: 又问了我三个问题</li>
  <li>我：全部接受。</li>
  <li>我：手动执行一遍测试用例(PASS-TO-PASS)，发现测试都可以过。然后执行(FAIL-TO-PASS)，发现测试用例都可以跑过了。</li>
</ul>

<h3 id="claude-code--deepseek-chat-v3-0324--deepseek-r1-0528">Claude Code + deepseek-chat-v3-0324 + deepseek-r1-0528</h3>

<p>穷，使用 CCR 来为 Claude Code 提供模型 + API 服务</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w">  </span><span class="nl">"Router"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"longContext"</span><span class="p">:</span><span class="w"> </span><span class="s2">"openrouter,deepseek/deepseek-chat-v3-0324:free"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"background"</span><span class="p">:</span><span class="w"> </span><span class="s2">"openrouter,deepseek/deepseek-chat-v3-0324:free"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"think"</span><span class="p">:</span><span class="w"> </span><span class="s2">"openrouter,deepseek/deepseek-r1-0528:free"</span><span class="p">,</span><span class="w">
    </span><span class="nl">"default"</span><span class="p">:</span><span class="w"> </span><span class="s2">"openrouter,deepseek/deepseek-chat-v3-0324:free"</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<ul>
  <li>我：<code class="language-plaintext highlighter-rouge">解决一下这个问题：{problem_statement}</code></li>
  <li>Claude Code: （思考了几十秒之后，就停止了）
    <blockquote>
      <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>⏺ Update Todos
  ⎿  ☐ Search for the implementation of recursive file handling in Pylint to understand how ignore patterns are applied
     ☐ Investigate how ignore paths are processed in Pylint's codebase
     ☐ Propose a fix for the issue by modifying the relevant Pylint files
     ☐ Test the proposed fix to ensure it resolves the issue

⏺ &lt;｜tool▁call▁begin｜&gt;function&lt;｜tool▁sep｜&gt;Task
  json
  {"description": "Investigate ignore paths processing", "prompt": "Investigate how ignore paths are processed in Pylint's codebase, focusing on the handling of --ignore,
  --ignore-paths, and --ignore-patterns settings."}
</code></pre></div>      </div>
    </blockquote>
  </li>
  <li>我：写代码解决问题呀</li>
  <li>Claude Code: （还是给我弹出来 tool_call_begin 的块，估计是模型和它不兼容，只能放弃）</li>
</ul>

<p>试了几次，后面都卡“tool 调用不了”这个问题上了。有点可惜。</p>

<h3 id="trae--builderauto">Trae + Builder(Auto)</h3>

<ul>
  <li>我：<code class="language-plaintext highlighter-rouge">解决一下这个问题：{problem_statement}</code></li>
  <li>Trae(Builder):
    <blockquote>
      <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>我需要查看Pylint的源代码，找出递归模式下忽略文件的实现逻辑，以解决忽略设置在递归模式下不生效的问题。
   Search codebase for 'recursive mode ignore files implementation'
...省略它的若干代码搜索...
...省略它的若干代码搜索...

我需要查看更多关于Pylint的文件收集和忽略规则实现的代码，特别是 expand_modules.py 文件，因为之前的搜索结果提到这个文件包含了与忽略列表和正则表达式匹配相关的关键函数。
我需要查看Pylint的递归模式实现，特别是与命令行参数处理相关的部分。我将查看 pylint/lint/run.py 文件，因为它可能包含命令行参数处理和递归模式的实现。
...省略它的若干文件浏览...
...省略它的若干文件浏览...

我发现了问题所在。...blabla省略若干分析...
最后它改了一行代码，并且加了一个测试用例
</code></pre></div>      </div>
    </blockquote>
    <ul>
      <li>点评：Aider 和 Gemini 基本都在第一轮就分析了问题对应的代码，而它没有。
它的行为和 Gemini 很相似，都是一波搜索加分析。可惜的是它分析的结果不对。</li>
    </ul>
  </li>
  <li>我：接受修改一行的修改，但决绝了添加测试用例</li>
  <li>Trae(Builder): 给上面的修改来了一波总结</li>
  <li>我：（我知道修改一行肯定不行，于是直接告诉它不对）我大概看了下代码，你这个修复方法不对</li>
  <li>Trae(Builder): 开始发你，并且又进行了一波分析（这里就省略了），最后又改了几行代码</li>
  <li>我：跑了一遍(PASS-TO-PASS)测试，也是两个用例失败了，然后就让它修改</li>
  <li>Trae(Builder): 查看了测试文件，然后又是一波分析，然后修复了一把
    <ul>
      <li>点评：我发现 Trae 特别喜欢搜索代码、查看文件，而且把这些过程展示给我，我觉得这个非常繁琐。更无语的是它搜的东西都不对（要是搜对了，你展示一下，我可能还能开心一点）。</li>
    </ul>
  </li>
  <li>我：跑了一遍(PASS-TO-PASS)测试，过了。然后跑了一遍(FAIL-TO-PASS)测试，4个用例失败了。把4个用例贴给它。</li>
  <li>Trae(Builder): 修改了，并且持续思考，然后 Trae 报错了
    <blockquote>
      <p>Model thinking limit reached, please enter ‘Continue’ to get more.</p>
    </blockquote>
    <ul>
      <li>点评：我看了它改的代码，感觉它不行，基本陷入到它自己思维里面去了。感觉是 Auto 的模型不太行。</li>
    </ul>
  </li>
</ul>

<h3 id="trae--builderclaude-4">Trae + Builder(Claude-4)</h3>

<ul>
  <li>我：<code class="language-plaintext highlighter-rouge">解决一下这个问题：{problem_statement}</code></li>
  <li>Trae：In queue：Too many current requests. Your queue position is 207.
    <ul>
      <li>点评：吐了。难顶。没钱办事是真的难。还好的是这个 position 会实时刷新，让我能看到一丝希望。</li>
    </ul>
  </li>
</ul>

<p>Cursor 都测试完了，这个队还在排，才排到了 100+，吐了。直接换 Deepseek 吧。</p>

<h3 id="cursor--auto">Cursor + Auto</h3>

<ul>
  <li>我：<code class="language-plaintext highlighter-rouge">解决一下这个问题：{problem_statement}</code></li>
  <li>Cursor: 和 Trae 有点像（有点倒反天罡），一顿 grep 加查看文件，最后得出结论
    <blockquote>
      <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>问题根因
--recursive=y 时，Pylint 通过 _discover_files 递归遍历目录，但没有应用 ignore/ignore-patterns/ignore-paths 相关过滤，导致所有文件（包括应被忽略的）都被 lint。
但在非递归模式下，Pylint 会通过 expand_modules，而该函数会正确应用 ignore 相关选项。
...一堆分析...
...一堆分析...
...最后提出了一个代码修改方案，并问我接不接受...
</code></pre></div>      </div>
    </blockquote>
    <ul>
      <li>点评1：Cursor 的这个 grep 展示就比较简洁，我比较喜欢。
Trae 生怕我啥也不懂，把模型的弱智全给我展示出来 :)
我想大部分程序员，看到这个 grep keyword 就懂它在干嘛。</li>
      <li>点评2: cursor 这个根因分析也比较到位，和 aider/gemini 类似，很快定位到对应的两个函数。</li>
    </ul>
  </li>
  <li>我：行</li>
  <li>Cursor：修改了代码，并让我确认</li>
  <li>我：在 UI 上点了 accept，并且手动在终端执行了一波(PASS-TO-PASS)测试。结果有两个用例失败了。
    <blockquote>
      <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>有两个测试失败了：FAILED tests/test_self.py::TestRunTC::test_recursive - AssertionError: expected output status 0, got 1. Below pylint output:
FAILED tests/test_self.py::TestRunTC::test_recursive_current_dir - AssertionError: expected output status 0, got 1. Below pylint output:
</code></pre></div>      </div>
    </blockquote>
    <ul>
      <li>点评：有趣的是，这些 AI 改了之后，失败的用例都是这两个</li>
    </ul>
  </li>
  <li>Cursor: 从“失败原因分析”，到“解决思路”，最后“修复建议”</li>
  <li>我：行</li>
  <li>Cursor：应用了上面这个修复建议对应的代码</li>
  <li>我：重跑(PASS-TO-PASS)测试，结果失败的用例更多了，有4个。
    <ul>
      <li>点评：我看了它的代码修改，它的代码修改是有问题的。</li>
    </ul>
  </li>
  <li>Cursor: 又来了一个新的方案
    <ul>
      <li>点评：我看了代码，知道它是不行的。算了，我感觉它也没救了。</li>
    </ul>
  </li>
</ul>

<h3 id="trae--builderdeepseek-v3-0324">Trae + Builder(DeepSeek-V3-0324)</h3>

<ul>
  <li>我：<code class="language-plaintext highlighter-rouge">解决一下这个问题：{problem_statement}</code></li>
  <li>Trae：两次 grep 加两个文件查看，定位到了问题。并且给出了代码修复的建议。
    <blockquote>
      <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>I've analyzed the issue with Pylint not respecting ignore patterns in recursive mode. The problem occurs because the _discover_files method in pylinter.py doesn't apply the ignore patterns when recursively discovering files, while the ignore patterns are only applied later in _expand_files .
</code></pre></div>      </div>
    </blockquote>
    <ul>
      <li>点评：指定了一个模型之后，这个问题定位能力感觉变强了一点点。可惜这里不全对。</li>
    </ul>
  </li>
  <li>我：接受。并且手动去跑一下(PASS-TO-PASS)测试。也是两个测试报错了
    <blockquote>
      <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>有两个测试报错了：FAILED tests/test_self.py::TestRunTC::test_recursive - NameError: name 'self' is not defined
FAILED tests/test_self.py::TestRunTC::test_recursive_current_dir - NameError: name 'self' is not defined
</code></pre></div>      </div>
    </blockquote>
  </li>
  <li>Trae: 好家伙，它直接建议我修改我的测试用例。</li>
  <li>我：我教育了一下它（其实我还挺怕教育它的，一般来说模型是纠正不过来的）
    <blockquote>
      <p>不要改测试用例，测试没通过，说明你的解决方案、或者代码有问题。</p>
    </blockquote>
  </li>
  <li>Trae: 表示理解我的诉求，并尝试继续改动 <code class="language-plaintext highlighter-rouge">_discover_files</code> 函数</li>
  <li>我：接受。并且手动去跑一下(FAIL-TO-PASS)测试。结果这两个用例还是失败了。
    <ul>
      <li>点评：我感觉它已经没戏了。除非我给它一些额外的 PROMPT。</li>
    </ul>
  </li>
</ul>

<p>经过这次测试，我感觉模型的影响特别明显，于是尝试用 claude-sonnet-3.7 来测试一把。
claude-sonnet-3.7 第一波分析的方向也不完全对，和 deepseek 差不多，就不继续测了。</p>

<p>再换一个 gemini-2.5-pro 试试，这样可以和 gemini-cli 对比。但看着也不对。</p>

<p>测试过程中，发现 trae apply 代码有点慢，肉眼可见的那种慢。</p>

<h3 id="claude-code--qwen3-coder-480b-a35b-instruct">Claude Code + Qwen3-Coder-480B-A35B-Instruct</h3>

<p>朋友说，它用 Claude Code + Qwen3 是可以的，于是我又测试了一把</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w">    </span><span class="nl">"Router"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"default"</span><span class="p">:</span><span class="w"> </span><span class="s2">"xxx,Qwen/Qwen3-Coder-480B-A35B-Instruct"</span><span class="w">
    </span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<ul>
  <li>我：<code class="language-plaintext highlighter-rouge">解决一下这个问题：{problem_statement}</code></li>
  <li>Claude Code: 经过一波 “Considering Spelunking Philosophing Conjuring Musing Forging Wizarding …“，给出了它的思路
    <blockquote>
      <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>⏺ I'll help you fix the issue where Pylint doesn't respect ignore settings in recursive mode. Let me first understand the codebase structure and locate the relevant files.

⏺ Search(pattern: "**/*.py")
  ⎿  Found 100 files (ctrl+r to expand)

⏺ Let me search for the main pylint module and recursive functionality:

⏺ Search(pattern: "recursive", type: "py")
  ⎿  Found 16 files (ctrl+r to expand)

⏺ Let me look at the main pylint module and the base options to understand how recursive mode is implemented:
</code></pre></div>      </div>
    </blockquote>
  </li>
  <li>我：可以，继续</li>
  <li>Claude Code:（又向我发出请求确认，要读这读那的）
    <blockquote>
      <p>⏺ Read(pylint/lint/base_options.py)
  ⎿  Read 572 lines (ctrl+r to expand)</p>

      <p>⏺ Now let me look at the PyLinter class to understand how the recursive mode is implemented:</p>
    </blockquote>
  </li>
  <li>我：可以，继续</li>
  <li>Claude Code:（又请求要读这读那得，这里就不贴细节了）</li>
  <li>我：可以，继续</li>
  <li>…就这样持续了好几回合，终于…</li>
  <li>Claude Code:（它终于做出了它的结论，说定位到了问题）
    <blockquote>
      <p>⏺ Now I understand the issue. Let me look at the specific problem. The issue is in the _discover_files method in
  pylint/lint/pylinter.py. Let me examine how the recursive mode is implemented and where the ignore patterns should be applied:</p>

      <p>Based on my analysis, I can see the issue. In the _discover_files method, the ignore patterns are being applied, but there’s a
   flaw in how they’re checked. Let me create a fix for this issue.</p>

      <p>First, let me create a test to reproduce the issue:
…省略一些它的 TODO list…
…它的 TODO list 第一项是写一个用例来复现…</p>
    </blockquote>
  </li>
  <li>我：不用写测试用例，直接修复（和之前测 Aider/Gemini 一样，直接让它改代码）</li>
  <li>Claude Code: （这里 claude code 主要做了几个事情）
    <ol>
      <li>仔细分析：它发现 <code class="language-plaintext highlighter-rouge">pylint/lint/pylinter.py</code> 文件中的 <code class="language-plaintext highlighter-rouge">_discover_files</code> 方法和这个问题有关。
 分析这个方法的调用关系。在分析调用关系的时候，又发现 <code class="language-plaintext highlighter-rouge">expand_modules</code> 这个函数，理解了一波。
 最后决定要修复 <code class="language-plaintext highlighter-rouge">_discover_files</code> 方法。</li>
      <li>更新了一波 <code class="language-plaintext highlighter-rouge">pylint/lint/pylinter.py</code> 文件，修复了 <code class="language-plaintext highlighter-rouge">_discover_files</code> 方法。</li>
      <li>自己 review 自己的修复，blablabla，然后还想继续修复，询问我是否继续</li>
    </ol>
  </li>
  <li>我：可以，继续</li>
  <li>Claude Code：修了一小段代码，问我是否继续</li>
  <li>我：继续吧（我是不会干涉它的思考、修复流程的）</li>
  <li>…就这样又持续了几个回合，终于…</li>
  <li>Claude Code: 给自己的修改搞了一个 Summary Of Changes, Blabla</li>
  <li>我：跑了一波 PASS-TO-PASS 测试，发现有一个用例失败了。
    <ul>
      <li>备注：我用 git diff 看了一下它的改动，我基本判断它没戏了。所以没继续后面的测试了。</li>
    </ul>
  </li>
</ul>

<p>记录一下第一印象：前面我已经测试过好几轮了，对各种工具的做事方式方法也大概有了些了解。
按照 Claude Code 的工作流程点评一下它：</p>
<ol>
  <li>分析问题：这个过程会调用 <code class="language-plaintext highlighter-rouge">search keyword</code> / <code class="language-plaintext highlighter-rouge">read file</code> 等工具。然后让模型进行分析理解。
 这一步，它还是做的不错的。也定位到了这个问题的关键点：<code class="language-plaintext highlighter-rouge">_discover_files</code> 和 <code class="language-plaintext highlighter-rouge">expand_modules</code> 方法。
 但最可惜的是，它分析到最后，结论不对。(这可能是它后续失败的关键)。这里还有个问题是，它每次读一个新的问题，
 都让我给它确认，太繁琐了。（虽然听朋友说，可以配置，但咱们只测默认配置下的表现）</li>
  <li>解决问题：Claude Code 有个特点是会自己修复，并且自己 review 自己的修复，然后提出进一步方案。
 它自己 review 这一点给我的印象还是深刻的。然并卵，它的分析就没有走在正确的方向上。
 如果我人工给它一点建议，或许会好一些吧。当 Claude Code 全部搞完后，它还会自我总结一下，来个
 Summary Of Changes，也挺有意思的。</li>
</ol>

<h3 id="claude-code-满血版走-aicodemirror">Claude Code 满血版（走 AICodeMirror）</h3>

<ul>
  <li>我：<code class="language-plaintext highlighter-rouge">解决一下这个问题：{problem_statement}</code></li>
  <li>Claude Code: 上来梳理了一个 TODO list。
    <ul>
      <li>然后自动开始了第一步。就是一系列的搜索和读取文件
  ```
        <blockquote>
          <p>⏺ Search(pattern: “recursive”, type: “py”)
  ⎿  Found 16 files (ctrl+r to expand)</p>

          <p>⏺ Search(pattern: “–recursive”, type: “py”)
  ⎿  Found 1 file (ctrl+r to expand)</p>

          <p>⏺ Search(pattern: “ignore.*path”, type: “py”)
  ⎿  Found 8 files (ctrl+r to expand)</p>

          <p>⏺ Read(pylint/lint/base_options.py)
  ⎿  Read 572 lines (ctrl+r to expand)</p>

          <p>⏺ Read(pylint/lint/expand_modules.py)
  ⎿  Read 150 lines (ctrl+r to expand)
```</p>
        </blockquote>
      </li>
      <li>接着它继续理解代码。也是一些搜索和读取文件，这里就不粘贴了。
        <blockquote>
          <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>⏺ Now let me look at the main pylinter module to understand how recursive mode is implemented:
...省略一堆它的搜索和读取文件...
</code></pre></div>          </div>
        </blockquote>
      </li>
      <li>然后它觉得自己找到了问题所在。自动进入 todo list 的第二项：写一个用例来复现，这时它来询问我</li>
    </ul>
  </li>
  <li>我： 跳过问题复现这一步，直接修复吧（和之前其它测试一样，让它跳过）</li>
  <li>Claude Code: 它按照要求跳过了这一步，进入了下一步
    <blockquote>
      <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>⏺ Update Todos
  ⎿  ☒ Investigate current recursive mode implementation
     ☒ Reproduce the bug with test case
     ☐ Identify where ignore logic should be applied in recursive mode
     ☐ Fix the ignore logic implementation
     ☐ Add regression tests
     ☐ Run existing tests to ensure no regressions
</code></pre></div>      </div>
    </blockquote>
    <ul>
      <li>点评：这里特意把它的 todo list 贴了一下，我觉得得夸一下，它这个 UI 做的还不错，比较清晰的标记自己进入了第三步。（终端里面看是有颜色的，非常清晰）</li>
      <li>接着它就把自己的修复代码给输出出来了。
        <blockquote>
          <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>⏺ Let me look at how the ignore logic is currently implemented by examining the expand_modules function:
...省略...
⏺ Now I need to modify the _discover_files method .... 省略...
...省略...
⏺ Let me check how the ignore settings are accessed in the config:
...省略...
...省略它的代码...
⏺ Now I need to check if _ignore_paths is available ... 省略 ...
...省略...
⏺ I see that _ignore_paths is defined later in the code. I should use self.config.ignore_paths directly instead:
...省略...
...省略...
⏺ Great! There are already some recursive tests. Now let me add a test for the ignore functionality:
</code></pre></div>          </div>
        </blockquote>
        <ul>
          <li>点评：值得一提的是，它输出代码的过程似乎也是分步的，先改一个代码文件；然后说接下来我要改第二个代码文件。但我觉得它应该是先总体规划好了，然后展示的时候，给人感觉是一步一步的。</li>
        </ul>
      </li>
    </ul>
  </li>
  <li>我：（它想给我加测试用例，我没有回复它）我去跑了 PASS-TO-PASS 测试，发现符合预期。然后再去跑 FAIL-TO-PASS 测试，发现符合预期，问题已经解决。</li>
</ul>

<p>相比 Qwen 版本，满血版(或者叫做原声版)效果明显要好很多，主要有几个方面</p>
<ol>
  <li>没有每个步骤都让我确认（这里我也不太清楚为什么，命名运行参数都是一样的）。而该让我确认的，也让我确认了，比如它想复现，我就有机会拒绝它这个提议。</li>
  <li>定位问题更准，同样是一波搜索加文件读取，这次，它就准确的找到了问题，并且一次性修复。还是牛的。</li>
</ol>

<h2 id="结个尾">结个尾</h2>

<p>这次搞这个评测，自己感觉还是挺好玩的，也还算满意，毕竟每个环节做到了满足预期的程度。
但是呢，这东西还是太花时间了，把我周末调研装修的+峡谷娱乐的时间都占用了。</p>

<p>结尾再很主观的点评一下 Trae（你懂哪种恨铁不成钢的感受么？）。和 Aider。</p>

<p>为了支持国产搞 IDE 的厂商（其实更多是因为它基础功能免费 :) ）这次特意试用了一下 Trae，
前段时间也偶尔用过。几点感受</p>
<ol>
  <li>Trae 的免费 tab 补全还是让我挺心动的，其它功能没让我觉得眼前一亮。SOLO 要付费，我穷。</li>
  <li>它的排队机制是个双刃剑，看似给了我希望（可能十几页有一点点吧）。但大部分情况则等了个寂寞。
 关键是 Auto 也要排队，还不如直接给我每天免费用几次，让我有个明确预期。</li>
  <li>Remote 开发功能用不了（看 issue 是说 macOS 不支持）。我就想，
 ssh 不是 VSCode 最杀手级的功能么，你竟然都不支持。难绷，太难绷了。</li>
  <li>还是挺希望 Trae 能搞成的，毕竟国内就没有一个像样的开发工具。把握机会争点气吧 狗头</li>
</ol>

<p>Aider 做的真的很棒。博客、文档、benchmark learborad、工具本身，都非常棒。
但奇怪的就是这个项目就一个人在合并代码，我很担心它的前途。希望它不会倒闭 🤯</p>

<p>Cline 最近其实也试用过，感觉效果不行（虽然 UI 看着很牛）；Continue 很久没试用了。</p>]]></content><author><name>cosven</name></author><category term="稍微正经点的" /><category term="AI" /><category term="coding" /><category term="Aider" /><category term="vscode" /><summary type="html"><![CDATA[Claude Code、Gemini Cli 等命令行工具相继发布，这两个月 AI 编码又火出了新高度。 我对效率类工具一直都特感兴趣，喜欢折腾和把玩它们，加之这些工具是实实在在提升效率。 我去年底接触 Aider、Cursor、Cline、Continue，就想写篇博客来记录一下我对它们的感受。 最近又有些新感触！搞个博客来记录一下。]]></summary></entry><entry><title type="html">Easy Groovy (1)</title><link href="http://cosven.me/blogs/10023" rel="alternate" type="text/html" title="Easy Groovy (1)" /><published>2025-05-22T15:15:00+00:00</published><updated>2025-05-22T15:15:00+00:00</updated><id>http://cosven.me/blogs/easy-groovy</id><content type="html" xml:base="http://cosven.me/blogs/10023"><![CDATA[<p>代码跳转是写项目的必备功能了，而用 VSCode 写 Groovy 竟然没有这个功能，这能忍嘛？？？</p>

<p>工作时而需要写 Doris 的回归测试 <a href="https://github.com/apache/doris/tree/master/regression-test">regression-test</a>，在本地，IDEA 当然是最佳选择。
无奈我写的测试用例都是压力测试类，都需要跑在远程开发机上，而 IDEA 的远程开发又很弱智（或许是我没付钱），
于是被迫转战 VSCode。但，不能忍呀！</p>

<h2 id="简单尝试">简单尝试</h2>

<p>几年前，有人折腾过一个 <a href="https://github.com/DontShaveTheYak/groovy-guru">groovy-guru</a> 的项目，它最让我心动的就是里面包含了一个
Groovy LSP，可以实现代码跳转。半年前我就是试用过，它当时就有个毛病，动不动就卡主。
这几天又狠下心来试用了一把，果然，还是用了一会就卡主了。两个 LSP 进程 CPU 占用 100%。
于是花了点时间研究了一下。</p>

<p>这不很久没写博客了，水一篇。滴水穿石，非一日之功 <code class="language-plaintext highlighter-rouge">:)</code></p>

<h2 id="卡哪里了">卡哪里了？</h2>

<p>第一想法是想看看 LSP 的日志。但令人惊讶的，<a href="https://github.com/GroovyLanguageServer/groovy-language-server">Groovy Language Server</a> 竟然连一行日志都没有，
什么垃圾玩意。当然就在想，难道 JAVA 老师都是直接 JDB 调试么？饭中和同事聊了聊，
感觉确实有这种可能呀。</p>

<p>既然卡主了，也没日志，那肯定就是看看 stack 喽。自己看了一会，没看出什么名堂来。
丢给 AI 分析了一下，AI 果然瞬间抓住了重点
（其实我仔细看，也能发现，但苦于没经验呀，没经验就没信心，AI 还是有点东西的）</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>根据提供的 stack.txt 分析，高 CPU 占用的直接原因是用户线程 pool-1-thread-1 在执行 Groovy 语言服务器（net.prominic.groovyls）的 AST 节点排序操作。以下是详细分析和解决方案：

1. 定位高 CPU 线程
线程名称: pool-1-thread-1
CPU 时间: 93629636.47ms（约 9.3 万秒，占进程总运行时间 94103.90 秒的 99%+）
线程状态: RUNNABLE（正在执行代码）
关键堆栈：

at net.prominic.groovyls.compiler.ast.ASTNodeVisitor.contains(ASTNodeVisitor.java:301)
at net.prominic.groovyls.compiler.ast.ASTNodeVisitor.lambda$getNodeAtLineAndColumn$1(...)
at java.util.TimSort.binarySort(TimSort.java:296)  // TimSort 排序操作
</code></pre></div></div>

<p>打了几次 stack，发现都是类似的，基本可以断定，要么是死循环了。
要么是我这个回归测试的项目太大了，它分析太耗时。</p>

<h2 id="上-jdb-查查">上 JDB 查查？</h2>

<p>查了查，上 JDB 的前提是，java 进程已经开启了 debug 模式。也就是启动的时候要加上这个参数：</p>
<blockquote>
  <p><code class="language-plaintext highlighter-rouge">-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:0,quiet=y</code></p>
</blockquote>

<p>加这个参数的过程中也遇到了一些小坑，我之前是指定了调试端口，但由于 VSCode 疑似会启动多个
（我测试遇到的情况是两个）LSP server，于是总有一个 server 会由于端口冲突而失败。</p>

<p>加了调试参数之后，确实就能使用 JDB 了，但 JDB 的操作学起来也挺麻烦了。听说 JAVA
老师都用 IDEA，试了一下确实方便… 切换线程、查看变量、设置断点，太方便了。
以前写 Python，都是 print 为主，pdb 用的很少，反思一下，还是 Python 调试器没这个好用。
经过多次断点，发现问题出在了它的 getParent 方法上，一个 child 的 parent 还是它自己，
于是它和 contains 配合，直接死循环了。</p>

<p><a href="https://github.com/GroovyLanguageServer/groovy-language-server/blob/cff39b87ffb3eb0dfc483ba727914824e871247e/src/main/java/net/prominic/groovyls/compiler/ast/ASTNodeVisitor.java#L244C17-L264">https://github.com/GroovyLanguageServer/groovy-language-server/blob/cff39b87ffb3eb0dfc483ba727914824e871247e/src/main/java/net/prominic/groovyls/compiler/ast/ASTNodeVisitor.java#L244C17-L264</a></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>	public ASTNode getParent(ASTNode child) {
		if (child == null) {
			return null;
		}
		ASTNodeLookupData data = lookup.get(new ASTLookupKey(child));
		if (data == null) {
			return null;
		}
		return data.parent;
	}

	public boolean contains(ASTNode ancestor, ASTNode descendant) {
		ASTNode current = getParent(descendant);
		while (current != null) {
			if (current.equals(ancestor)) {
				return true;
			}
			current = getParent(current);
		}
		return false;
	}
</code></pre></div></div>

<h2 id="为啥有死循环嘞">为啥有死循环嘞？</h2>

<p>这里就比较琐碎了。</p>

<ol>
  <li>先分析 node.parent 是在哪里设置的？—&gt; 看了一波代码，发现这个逻辑还是挺精简的，
是在 ASTNodeVisitor 的 pushASTNode 方法里设置的。</li>
  <li>那这个方法又是在哪里调用的呢？—&gt; 继续看代码，发现 ASTNodeVisitor 的 visit 方法里，</li>
  <li>之前分析已经发现，有问题的 ASTNode 是一个 ElvisOperatorExpression，读读它的代码，
发现它的 visit 实现确实有问题。</li>
</ol>

<p>看看这个项目的代码，感觉某种程度来说，也挺草台的（有的函数就直接就注释掉，没有任何注释）。</p>

<p>好，问题找到了，愉快的水了一个 PR： <a href="https://github.com/GroovyLanguageServer/groovy-language-server/pull/102">https://github.com/GroovyLanguageServer/groovy-language-server/pull/102</a></p>

<h2 id="lsp-修好还不够还得更新-vscode-插件">LSP 修好还不够，还得更新 VSCode 插件</h2>

<p>Groovy-guru 这个项目用的 LSP 是 Groovy Language Server，它通过 submodule
来集成的。考虑到 Groovy-guru 这个项目已经两年没更新了，于是我 Fork 了一个，
为了能发布插件，还把项目名字啥的都改了一下，在 VSCode 插件市场注册了一个账号，
发布了 <a href="https://marketplace.visualstudio.com/items?itemName=cosven.easy-groovy">Easy Groovy v0.1.1</a>。</p>

<h2 id="结语">结语</h2>

<p>这下我也是 VSCode 插件开发者了 <code class="language-plaintext highlighter-rouge">:)</code></p>

<p>LSP、tree-sitter 这些技术还是挺有意思的，之前一直想研究研究来着。
这次算是个不错的机会，总体比较顺利，踩坑也不多。</p>

<p>下一步计划是增强一下 Groovy LSP 在 Doris 回归测试项目中的性能（我发现它会加载所有的 suite 文件）；
或者研究研究，看看能不能让它跳转到 [Plugins] 的代码里去。目标是对编辑器有更深了解。</p>

<p>好，成功的划水一篇！</p>]]></content><author><name>cosven</name></author><category term="life" /><category term="easy-groovy" /><summary type="html"><![CDATA[代码跳转是写项目的必备功能了，而用 VSCode 写 Groovy 竟然没有这个功能，这能忍嘛？？？]]></summary></entry><entry><title type="html">读《小家越住越大》</title><link href="http://cosven.me/blogs/10030" rel="alternate" type="text/html" title="读《小家越住越大》" /><published>2025-04-05T14:50:00+00:00</published><updated>2025-04-05T14:50:00+00:00</updated><id>http://cosven.me/blogs/big-house</id><content type="html" xml:base="http://cosven.me/blogs/10030"><![CDATA[<h2 id="第一章买不起大房子忍受局促生活">第一章：买不起大房子!=忍受局促生活</h2>
<p>“大房子” != 面积大</p>

<h2 id="第二章给家减肥">第二章：给家减肥</h2>
<p>给家减肥：丢</p>

<h2 id="第三章收纳">第三章：收纳</h2>

<p>四级收纳：</p>
<ol>
  <li>房子是家的容器</li>
  <li>房间是任何家具的容器</li>
  <li>大型储物家具是物品的容器</li>
  <li>小的储物盒子进一步收纳</li>
</ol>

<p>前三级收纳的判断标准</p>
<ol>
  <li>各处均布，就近收纳：每个房间都有自己的收纳区域，收纳对应的东西。
    <ol>
      <li>反例（辩证）：储物间。储物间不是万能的。</li>
    </ol>
  </li>
  <li>占地 12%</li>
  <li>立体集成
    <ol>
      <li>垂直空间利用</li>
      <li>配合度、整齐度</li>
    </ol>
  </li>
  <li>二八原则：展示2，隐藏8</li>
</ol>

<p>展示优雅的，收藏杂乱的。</p>

<h2 id="第四章小容器大智慧">第四章：小容器，大智慧</h2>

<p>收纳的几个场景</p>
<ol>
  <li>鞋子</li>
  <li>浴室瓶瓶罐罐</li>
  <li>冰箱</li>
</ol>

<h2 id="第五章玄关">第五章：玄关</h2>
<h2 id="第六章客厅">第六章：客厅</h2>
<h2 id="第七章厨房">第七章：厨房</h2>

<h3 id="高度">高度</h3>
<p>操作台高度：身高/2+50（毫米）
炒锅需要让台面低一点，而洗碗则需要让台面高一点。
如果不在一个平面可能是最好的。</p>

<h3 id="抽屉">抽屉</h3>
<p>横向与纵向。</p>

<h3 id="挂件">挂件</h3>

<h2 id="第八章卧室">第八章：卧室</h2>

<p>动线：为了完成一系列动作所走的路的长度。</p>]]></content><author><name>cosven</name></author><category term="阅读" /><category term="笔记" /><summary type="html"><![CDATA[第一章：买不起大房子!=忍受局促生活 “大房子” != 面积大]]></summary></entry><entry><title type="html">记点笔记（2024-10）</title><link href="http://cosven.me/blogs/10022" rel="alternate" type="text/html" title="记点笔记（2024-10）" /><published>2024-10-22T03:05:00+00:00</published><updated>2024-10-22T03:05:00+00:00</updated><id>http://cosven.me/blogs/10month-reading</id><content type="html" xml:base="http://cosven.me/blogs/10022"><![CDATA[<p>强行记一点，养成好习惯！</p>

<h2 id="ai-编辑器">AI 编辑器</h2>

<p>刚接触 AI 编辑器是在 10 月份，当时这对我来说还是个新奇的话题。
现在 12 月，两个月过去了，周边同事或朋友几乎都用上了 cursor 或 windsurf。
是个程序员可能都尝试或听说过了。有人喜欢它的 chat 功能，有人喜欢它的 tab 功能。</p>

<p><a href="https://www.arguingwithalgorithms.com/posts/cursor-review.html">这篇文章</a> 对cursor 的介绍的不错。</p>

<h2 id="并发模型">并发模型</h2>

<p>今天在看什么资料的时候，看到并发模型的概念，这是我一直都很好奇的东西。我不需要掌握使用它，
但需要了解它大概的样子，知道它的基本使用场景。</p>

<p>看了一些资料后，我对“并发模型”的基本理解</p>
<ol>
  <li>常听说的并发模型有：线程与锁；函数式编程；actor 模型；CSP。</li>
  <li>（我理解）不同的并发模型主要考虑两方面的东西：代码可维护性；性能。
不同的并发模型，使用的技术仍然是队列、线程池、协程这些老东西。</li>
</ol>

<p>Actor 模型的基本印象</p>
<ol>
  <li>这个模型有几个概念：信箱（mailbox）；actor。
    <ol>
      <li>信箱对应到真正的实现，一般也就是一个队列。</li>
      <li>actor 通常会无限循环，从 mailbox 接受并处理消息。</li>
    </ol>
  </li>
  <li>Actor 模型通过异步消息来通信，发送者和接受者之间不共享状态。</li>
  <li>发送消息这个操作本身非阻塞。消息并不是直接发送到一个 actor，而是发送到一个信箱。</li>
</ol>

<p>CSP 模型的基本印象</p>
<ol>
  <li>CSP 模型不关注发送消息的实体，而是关注发送消息时使用的 channel (通道)。
channel 是第一类 对象，它不像进程那样与信箱是紧轉合的，而是可以单独创建和读写，
并在进程之间传递。</li>
</ol>

<p>CSP 模型与 Actor 模型的差别（来自 AI 的解释）</p>
<ol>
  <li>通信方式不一样：CSP 通过<strong>共享的 channel</strong>来通信。而 Actor 模型通过传递消息。</li>
  <li>并发实体不一样：CSP 模型并发实体是进程。而 Actor 模型的并发实体是 actor。</li>
</ol>

<p>其它问题</p>
<ol>
  <li>Actor 模型与“生产者/消费者”模型的关系？它们本身就不同一个抽象层级的概念。</li>
  <li>数据库的 pipeline 模型是什么东西？和 CPU 的 pipeline 相似。</li>
  <li>“线程与锁”，“Actor 模型”，“CSP 模型” 这三个的异同？看一下七周七并发每个章节的复习章节。</li>
</ol>

<h2 id="协程与事件循环">协程与事件循环</h2>

<p>协程需要一个循环来驱动它们的状态变化。</p>

<p>比如对于 Python 的 asyncio 来说，在 Linux 环境下，它会使用 epoll 来驱动。
那对于 goroutine 或者 rust 的协程，它们使用什么来驱动的呢？花了点时间研究了下，
看起来它们会自己来实现。简单理解的话，它们会实现一个消息队列，然后轮询这个队列。
下面两篇文章（尤其是第二篇）比较详细的描述了这个“驱动”，它称之为 scheduler。</p>

<ul>
  <li>https://kerkour.com/rust-async-await-what-is-a-runtime</li>
  <li>https://tokio.rs/blog/2019-10-scheduler#the-next-generation-tokio-scheduler</li>
</ul>

<h2 id="doris-mow-实现原理">Doris MOW 实现原理</h2>

<p>参考资料1：https://zhuanlan.zhihu.com/p/590643211</p>

<p>2024-12-19：最近有种感觉是没有抓住这个话题的重点，这个东西可能应该鸽了。</p>

<p>关键概念或问题</p>
<ol>
  <li>主键索引</li>
  <li>delete bitmap</li>
  <li>todo: 所有的“主键行号”到底是怎么计算的？</li>
</ol>

<p>在 Doris，Delete bitmap 在代码层对应了 “Roaring BitMap” 这个数据结构。这里涉及几个概念：Bitmap（位图），
Roaring Bitmap（压缩位图）。Bitmap 实现了数字和 bit 一对一。Roaring Bitmap 是一种优化，
处理稀疏数据时的性能更好，尤其是空间性能。</p>]]></content><author><name>cosven</name></author><category term="阅读" /><category term="笔记" /><summary type="html"><![CDATA[强行记一点，养成好习惯！]]></summary></entry><entry><title type="html">2024 干点啥</title><link href="http://cosven.me/blogs/10021" rel="alternate" type="text/html" title="2024 干点啥" /><published>2024-03-08T11:05:00+00:00</published><updated>2024-03-08T11:05:00+00:00</updated><id>http://cosven.me/blogs/2024-plan</id><content type="html" xml:base="http://cosven.me/blogs/10021"><![CDATA[<p>回顾一把了 2023，也想了想 2024 干点啥好，心里已经基本有思路了。现在是下午六点半，
预约了晚上7点的海底捞，前面排了 240 桌。说回来，我觉得自己的 2024 规划挺好的，
从来没对自己这么有信心过 :)</p>

<h2 id="有记录的日子都是美好的">有记录的日子都是美好的</h2>

<p>在回顾与规划之间，有个小发现：从 2018 年有记录开始，我每年目标的大体相似，尤其是大方向上。
不仅目标相似，连思路都相似。</p>

<ol>
  <li>生活上
    <ol>
      <li>落户-&gt;买房-&gt;还贷-&gt;装修：虽迟但到。至今也不知道买房是否是正确的选择。</li>
      <li>多和朋友约饭、约玩：一直都做的不行。后面尝试 1v1 约吧？还是说共同兴趣过少？</li>
      <li>找对象结婚生仔：还处于经常会思考“意义是什么”的状态。流程上是有些进展，emmm</li>
      <li>多和家人联系：主观意识上有一些长进 :）</li>
    </ol>
  </li>
  <li>工作上
    <ol>
      <li>之前的4-5年一直执著“提升技术深度、搞低层”。最近一年觉得，做好事情比提升技术能力要高些。
但不得不说的是，技术深度也确确实实的限制了我工作的选择。</li>
      <li>对于自己需要提升什么技能，比以前清晰了很多。但对3年后仍然没有规划。</li>
      <li>最近两年都是希望能做出一件有亮点的事情，今后两年有希望。</li>
    </ol>
  </li>
  <li>日常
    <ol>
      <li>在“让自己成为一个热爱生活的人”的路上，似乎有一点长进，但似乎也不多。</li>
      <li>FeelUOwn：严格：要死不活。乐观积极心态：稳步前进。</li>
    </ol>
  </li>
</ol>

<h2 id="2023-回忆">2023 回忆</h2>

<h3 id="旅游">旅游</h3>
<p>思来想去，2023 年印象最深的还属自驾318川藏线。回想那个时间，虽然没有工作，但心态却异常积极
（好像构不成虽然但是得关系🐶）。和朋友们一起旅游是件非常开心的事情哇，“在路上”
给人带来的放松、向往感，和平常几点一线的生活也是截然不同的。</p>

<h3 id="工作导致心烦意乱">工作导致心烦意乱？</h3>
<p>今天看到<a href="https://youjiali1995.github.io/essay/2023-summary/">一个观点</a> 我特别认同
（其实也是这篇文章提醒了我，要总结一下）</p>
<blockquote>
  <p>过度工作的人必然对结果有着更高的预期，但结果不是靠自己和努力就能决定的，
往往期望越高失望越大，导致不可持续发展。</p>
</blockquote>

<p>其实我自己不会因为工作而心烦意乱（少数情况），我对工作的要求和期望都比较低。但生活中，
遇到这个问题的朋友大有人在。</p>

<h3 id="技术深度这个事情">技术深度这个事情</h3>

<p>以前觉得技术很重要，一个事情技术难度高、越底层，这个事情对我的吸引力就越大，
觉得搞定它会很酷、很有成就感。比如去看技术大牛们写的博客或者技术文章，
就会很向往和憧憬。确实没错，这个回路确实很合理。但同时，这个行业的人，一定也经常听到这种说法，
“你放眼看去，高级别的人有几个是技术大牛”。这个问题该怎么辩证看呢？最近有了新想法。</p>

<p>上面的回路很对，但不能光有它。个人实践了 3-5 年，我每年都觉得自己技术深度不够，
然后会督促自己看看书和基础论文，短时间“深”了，但随后又会忘了，到头来“深度”还是不够。
接着，我就会反思，反思的结论之一就是自己看书不够坚持。这确实也是原因之一，
不过想想，还有没有其它原因呢？5 年过去了，我都没坚持下来，是不是也应该换个思路了。</p>

<p>总的来说，技术和解决事情两个角度，两手抓两手都要硬。当你从纯技术入手遇到瓶颈的时候，
不如试试从项目入手。以前的目标可能是对的，但方式得修正下。反正我今年是准备尝试下 🐶。祝自己好运。</p>

<h3 id="旅游的好与坏">旅游的“好”与“坏”</h3>

<p>有的旅游让我印象深刻，而有的旅游，则在脑海中消失的无影无踪。这个问题是我想解答的问题，
但现在领悟还不够。但有一条，有记录的日子都是美好的。一说到旅游，
我能回忆起来的旅游场景，都是那些我写了博客记录或发了朋友圈。仔细回味一下，
并不纯粹是因为这些旅游就玩的更开心，而是游玩结束有认真的回味这次旅游。</p>

<h3 id="爱情结婚与生仔">爱情，结婚与生仔</h3>

<p>不会。等有灵感再来记录一下。</p>

<h2 id="2024-是光明的">2024 是光明的</h2>

<ol>
  <li>生活：
    <ol>
      <li>期望：让周围的人因你而感到幸福。</li>
      <li>目标：
        <ol>
          <li>把做饭技能捡回来；把房子装修搞好；</li>
          <li>见老友2次；和2个以上的朋友聊聊“结婚生子”的意义；</li>
          <li>让父母体检一次；和家人出游一次。</li>
        </ol>
      </li>
    </ol>
  </li>
  <li>工作目标：
    <ol>
      <li>短期期望：有更长远且具象一点的眼光。</li>
      <li>目标：
        <ol>
          <li>能对一个事情的结果负责。</li>
          <li>善于发现同事的优点，取长补短。</li>
        </ol>
      </li>
    </ol>
  </li>
  <li>其它：
    <ol>
      <li>FeelUOwn 能达到“有信心推荐给朋友用”的水平。</li>
      <li>找找旅游的最佳实践。</li>
    </ol>
  </li>
</ol>]]></content><author><name>cosven</name></author><category term="life" /><category term="life" /><category term="work" /><summary type="html"><![CDATA[回顾一把了 2023，也想了想 2024 干点啥好，心里已经基本有思路了。现在是下午六点半， 预约了晚上7点的海底捞，前面排了 240 桌。说回来，我觉得自己的 2024 规划挺好的， 从来没对自己这么有信心过 :)]]></summary></entry><entry><title type="html">小小秋游-徒步栖霞坑古道</title><link href="http://cosven.me/blogs/10020" rel="alternate" type="text/html" title="小小秋游-徒步栖霞坑古道" /><published>2023-12-03T11:05:00+00:00</published><updated>2023-12-03T11:05:00+00:00</updated><id>http://cosven.me/blogs/qi-xia-keng-cun</id><content type="html" xml:base="http://cosven.me/blogs/10020"><![CDATA[<p>抓到浙江秋天的尾巴，“栖霞坑古道”一日游，盗图若干。</p>

<figure class="half">
    <img src="https://github.com/cosven/blogs/assets/4962134/42ca54c1-d0c7-4550-be4a-3c4f9582f058" />
    <img src="https://github.com/cosven/blogs/assets/4962134/7337bb8c-aeeb-4af4-b0a4-d49572be7209" />
    <figcaption>盗图两张</figcaption>
</figure>

<figure class="third">
    <img src="https://github.com/cosven/blogs/assets/4962134/2f075656-6eec-4403-a09a-c96268cfd1cf" />
    <img src="https://github.com/cosven/blogs/assets/4962134/c46ff5c5-c371-46d7-a7fe-fb7d393d490c" />
    <img src="https://github.com/cosven/blogs/assets/4962134/0969ac65-120d-4e1a-a99c-db7f3b2fb7ff" />
    <figcaption>再盗图三张</figcaption>
</figure>

<p>这次凑了两车人马，出乎意料的“热闹”。
从杭州余杭九点出发，自驾到栖霞坑村，干完午饭，已是下午两点。时间仓促，
只走了个古道的一小半行程。图4,5为咱一伙人穿越荆棘，爬了一个60度坡，
强行登“顶”，拍了个夕阳西下（还有一位肌肉男和一位美女未出镜）。
偶然发现，自己对“登顶”似乎有一些执念。</p>

<h2 id="一点好奇">一点好奇</h2>

<p>“为啥这村要叫坑呀？” 想起国庆路过黄山以及婺源的时候，也有很多村有“坑”。
在当下流行的语言环境中，这字显然褒义偏少，有点好奇。</p>
<blockquote>
  <p>“坑”表示溪涧在东南诸方言中普遍存在，并大量出现在东南地区村落地名当中。
此义引申自山谷义，有明确的历史来源，并与东南地区地貌特征有很大关系，
是东南诸方言的广义特征词。</p>
</blockquote>

<h2 id="小脑袋大疑问">小脑袋，大疑问</h2>

<h3 id="一桃花源记">一：桃花源记</h3>
<p>一行人在栖霞坑村，沿河流往上走的时候，会不自觉的让人背出</p>
<blockquote>
  <p>土地平旷，屋舍俨然，有良田、美池、桑竹之属。
。。。
鸡犬相闻，其中往来种作，男女衣着</p>
</blockquote>

<p>不经历_工作日的两点一线_，对_此情此景_又会有何感想？
emmm，没有《桃花源记》，对此情此景又会有何感想呢？
回头看，我觉得图1,2拍的还真不错。</p>

<h3 id="二人生的意义">二：人生的意义</h3>
<p>今日倒垃圾的时候，遇到一个人在挠头倾诉：“我感觉最近好无聊啊”。</p>

<p>我就想，如果我是被倾诉对象，我要怎么办呢，这可是个大难题。
带ta去做点平常不做的事情？我能找到这样的事情么，2333,感觉好难啊。</p>

<p>如果我是倾诉对象，不，感觉自己不会成为这样的倾诉者。我可能会认为这是给倾听者徒增烦恼。
但又想想，如果这样的话无处诉说，或者说这样的情绪无处发泄，也是非常难受的一件事了。
还有一个问题是，作为一个成年人，又能对谁、哪个角色去诉说呢？亲人、朋友？可能是朋友。</p>

<p>然后联想到一个终极问题，人生意义在于什么？想了几个选项，游山玩水、
、吃喝玩乐、开心、成就感、结婚生子、传宗接代…… 但感觉这些选项都比较局限，
不足以概括人生意义，后来想到一个词，自己觉得比较满意的答案：活着。
活着就是为了活着而已。于是想去读一读余华的《活着》。（但，看了下简介，又没那么想读了）。</p>

<h3 id="三就是想记录点什么">三：就是想记录点什么</h3>

<ol>
  <li>下次出游一定要拍集体照。（即使自己很“丑”，也想记录照片，要长肥！）</li>
  <li>生活不缺美，只缺发现美的角度。</li>
  <li>明天要上班，毕竟大概率要工作到很晚。太卷了！c**！</li>
  <li>写字似乎是(我)释放情绪/感受的一个非常有效的方式。</li>
</ol>

<h2 id="最后">最后</h2>

<p>等下还有几件事情要做：洗澡；上分；吃夜宵。而今天只剩两个半小时。
生活虽然很美好，但也仍需努力度过。</p>

<p><a href="https://www.bilibili.com/video/BV137411V7Zp">许巍此时此刻演唱会北京收官未删减版</a>
这个演唱会视频真不错，视听盛宴，强烈推荐的音乐视频之一！</p>]]></content><author><name>cosven</name></author><category term="life" /><category term="旅游" /><summary type="html"><![CDATA[抓到浙江秋天的尾巴，“栖霞坑古道”一日游，盗图若干。]]></summary></entry></feed>