<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>My Blog</title>
  
  
  <link href="https://begineri.github.io/Blog/atom.xml" rel="self"/>
  
  <link href="https://begineri.github.io/Blog/"/>
  <updated>2026-03-27T10:20:08.090Z</updated>
  <id>https://begineri.github.io/Blog/</id>
  
  <author>
    <name>Wang</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>2026-OO-u1</title>
    <link href="https://begineri.github.io/Blog/2026/03/27/2026-OO-u1-Blog/"/>
    <id>https://begineri.github.io/Blog/2026/03/27/2026-OO-u1-Blog/</id>
    <published>2026-03-27T10:01:31.000Z</published>
    <updated>2026-03-27T10:20:08.090Z</updated>
    
    <content type="html"><![CDATA[<p>本文是基于2026年面向对象课程第一单元迭代作业的总结</p><h2 id="目录："><a href="#目录：" class="headerlink" title="目录："></a>目录：</h2><ul><li><a href="#%E7%A8%8B%E5%BA%8F%E7%BB%93%E6%9E%84">程序结构</a></li><li><a href="#%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1%E4%BD%93%E9%AA%8C">架构设计体验</a></li><li><a href="#%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F">使用到的设计模式 Design Patterns</a></li><li><a href="#%E5%88%86%E6%9E%90%E8%87%AA%E5%B7%B1%E7%A8%8B%E5%BA%8F%E7%9A%84bug">分析自己程序的bug</a></li><li><a href="#%E5%A4%A7%E6%A8%A1%E5%9E%8B%E7%9B%B8%E5%85%B3%E4%BD%BF%E7%94%A8">大模型相关使用</a></li><li><a href="#%E6%9C%AA%E6%9D%A5%E6%96%B9%E5%90%91">未来方向</a></li><li><a href="#%E6%80%9D%E8%80%83%E9%A2%98">思考题</a></li></ul><h2 id="程序结构"><a href="#程序结构" class="headerlink" title="程序结构"></a>程序结构</h2><p>以下数据分析自最终一次迭代的代码，全项目共计 20 个核心业务类，业务代码总计约 1080 行，包含 126 个方法。</p><p>hw3完整类图：<br><img src="/Blog/images/oou1/com.drawio.png" alt="alt text"></p><h3 id="基础程序结构度量分析"><a href="#基础程序结构度量分析" class="headerlink" title="基础程序结构度量分析"></a>基础程序结构度量分析</h3><p><img src="/Blog/images/oou1/image-2.png" alt="alt text"></p><ol><li><p>类总代码规模 (Class LOC)</p><ul><li>代码规模最大的两个类分别是全局语法树构建工厂 <code>Parser</code>（184 行）与底层代数运算 <code>Poly</code>（180 行），两者自然承担了系统中最密集的逻辑调度与计算任务。</li><li>绝大多数 AST 节点类（如 <code>ConFactor</code>, <code>FunctionFactor</code>）的代码量均被严格控制在 20-40 行之间。它们居于解析与运算之间，仅作为纯粹的数据结构存在，代码轻量。</li></ul></li><li><p>方法个数 (NOM) 与 属性个数 (NOF)</p><ul><li><code>Poly</code> 类的方法数最多（17 个），其次为 <code>Parser</code>（12 个）。</li><li>AST 节点通常只有 1-2 个基础属性</li></ul></li><li><p>方法规模 (Method LOC)</p><ul><li>全项目 126 个方法，平均代码行数仅为 8.16 行</li><li>最长的方法 <code>Mono.toString()</code> 为 47 行，而求导核心逻辑（各类节点的 <code>derive</code> 方法）普遍在 2-5 行。</li></ul></li><li><p>控制分支数目 (圈复杂度 v(G))</p><ul><li>全项目方法的平均圈复杂度（v(G)）仅为 1.93</li><li>极低的圈复杂度是多态（动态分派）机制带来的直接收益。本架构彻底消除了传统面向过程编程中冗长的 <code>if-else / switch</code> 类型判断，将共性操作下放至各自的子类中，实现了真正的 O(1) 逻辑寻址。</li></ul></li></ol><h3 id="经典-OO-度量（内聚与耦合分析）"><a href="#经典-OO-度量（内聚与耦合分析）" class="headerlink" title="经典 OO 度量（内聚与耦合分析）"></a>经典 OO 度量（内聚与耦合分析）</h3><p><img src="/Blog/images/oou1/image-1.png" alt="alt text"></p><ol><li><p>类的相互耦合情况 (CBO - Coupling Between Object classes)</p><ul><li>系统耦合度最高的前三个类依次为 <code>Expr</code> (CBO&#x3D;18)、<code>Parser</code> (CBO&#x3D;15) 和 <code>Poly</code> (CBO&#x3D;14)。</li><li>而底层的原子节点（如 <code>PowerFactor</code>, <code>ConFactor</code>）的 CBO 极低（通常在 2-4 之间）。</li></ul></li><li><p>类的内聚情况 (LCOM - Lack of Cohesion of Methods)</p><ul><li>全项目，LCOM 的最高值仅为 4，绝大部分类维持在 0 到 3 之间。</li><li><code>Poly</code> 类 LCOM 也低至 1.0，是一个内部方法高度共享核心状态、职责极其聚焦的高内聚模块。</li></ul></li></ol><hr><h3 id="基于类图的分析"><a href="#基于类图的分析" class="headerlink" title="基于类图的分析"></a>基于类图的分析</h3><p>整体思路：<strong><code>Input</code>-&gt;<code>Parser</code>-&gt;<code>toPoly</code>-&gt;<code>toString</code></strong></p><p><code>Input</code>：处理输入与预处理<br><code>Parser</code>：将字符串解析为各个类的实例<br><code>toPoly</code>：将AST上的节点统一转为Poly，方便合并、化简和输出。<br><code>toString</code>：针对mono和poly类进行统一递归输出。</p><ul><li><p>优点：</p><ol><li>Dumb AST, Smart Engine 的分层架构**：<br>AST 树在解析和求导阶段保持绝对的纯粹，所有的计算全部推迟并集中在底层的 <code>Poly</code> 中。这种单向依赖保证了极低的类间耦合。</li><li>多态的实现：<br>通过动态分派机制，彻底消除了面向过程编程中常见的、冗长的 <code>switch/if-else</code> 类型判断。求导逻辑被完美下放至各自的 Factor 子类中，代码的扩展性与可读性极佳。</li><li>不可变性与线程安全隐患的规避：<br>在底层的多项式运算（如 <code>mulP</code>）和替换操作（<code>substitute</code>）中，系统大量采用深度拷贝和构建新对象的方式返回结果，杜绝了引用传递可能导致的脏数据污染，保证了高阶求导与复杂嵌套替换时的绝对稳健。</li></ol></li><li><p>缺点：</p><ol><li>HashMap 带来的内存冗余开销：<br>为了追求 $O(1)$ 的同类项合并速度，底层大量实例化了 <code>MonoKey</code> 和 <code>Mono</code> 对象。在应对极其极端的嵌套乘方测试样例（如 <code>expP(8)</code> 的超高次展开）时，会产生大量的短生命周期对象，对 JVM 的垃圾回收（GC）造成了较大的内存压力。未来可考虑引入<strong>享元模式(Flyweight Pattern)</strong> 对某些单项式特征进行缓存。</li><li>解释器模式 (Interpreter) 的扩展性局限：<br>当前架构将 <code>derive</code> 和 <code>toPoly</code> 方法直接硬编码在了每个 AST 节点类中。如果未来需求增加（例如要求支持积分操作等），则需要打开每一个类的源码进行修改，这在一定程度上违背了“开闭原则（OCP）”。<br>在后续的重构中，可以引入<strong>访问者模式（Visitor Pattern）</strong>。将 AST 彻底退化为纯数据结构，将“求导”、“化简”等操作抽象为独立的 Visitor 类，实现数据与算法的彻底解耦。</li></ol></li></ul><hr><h2 id="架构设计体验"><a href="#架构设计体验" class="headerlink" title="架构设计体验"></a>架构设计体验</h2><p>本次作业经历了三次迭代，在此过程中架构</p><h3 id="迭代过程"><a href="#迭代过程" class="headerlink" title="迭代过程"></a>迭代过程</h3><ul><li>hw1<br>程序入口如下：</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Main</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">Scanner</span> <span class="variable">scanner</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Scanner</span>(System.in);</span><br><span class="line">        <span class="type">String</span> <span class="variable">input</span> <span class="operator">=</span> scanner.nextLine();</span><br><span class="line"></span><br><span class="line">        <span class="type">Lexer</span> <span class="variable">lexer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Lexer</span>(input);</span><br><span class="line">        <span class="type">Parser</span> <span class="variable">parser</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Parser</span>(lexer);</span><br><span class="line"></span><br><span class="line">        <span class="type">Expr</span> <span class="variable">expr</span> <span class="operator">=</span> parser.parseExpr();</span><br><span class="line">        System.out.println(expr.toPoly().toString());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>可见一开始就确立了基于**递归下降算法（Recursive Descent）**的 <code>Lexer-Parser</code>整体思路，构建了 <code>Expr -&gt; Term -&gt; Factor</code> 的基础抽象语法树（AST）<br>此时也只需处理简单的多项式合并于化简</p><ul><li><p>hw2<br>随着括号嵌套（表达式因子）和指数函数（<code>exp</code>）的引入，单纯的 AST 遍历无法应对极其复杂的代数展开。<br>为了处理最终式子的合并于输出，最终剥离了 AST 的计算职责，专门抽象出了底层代数引擎——<code>Poly</code>（多项式）与 <code>Mono</code>（单项式）。通过构建 <code>HashMap&lt;MonoKey, BigInteger&gt;</code>，将复杂的代数合并转化为了 $O(1)$ 的哈希表聚合。<br>同时实现了架构解耦：将表达式的解析、展开（函数替换、选择式求值）、合并和输出（化简、格式化）设计为相对独立的模块，有助于降低系统的复杂度，使代码更易于维护和调试。</p></li><li><p>hw3<br>本次作业加入自定义递归函数调用和嵌套求导算子（<code>dx</code>），在获取输入阶段就将函数定义的字符串也解析为一棵AST数，在调用函数时直接进行树节点的代换即可，提高了效率。<br>对于递推函数的展开，我采用记忆化搜索的思想来处理递推函数的展开。将已经计算过的 f{i}(实参) 的结果缓存起来，可以有效避免重复计算，提升程序性能。</p></li></ul><hr><h4 id="自定新迭代情景与可扩展性分析"><a href="#自定新迭代情景与可扩展性分析" class="headerlink" title="自定新迭代情景与可扩展性分析"></a>自定新迭代情景与可扩展性分析</h4><p>假如下一次需要引入三角函数（sin, cos）并支持其内部的复杂表达式嵌套与链式求导。</p><p>则当前设计的可扩展性应对方案：</p><ol><li>AST 层扩展：<ul><li>新增 <code>SinFactor</code> 和 <code>CosFactor</code> 类，实现 <code>Factor</code> 接口。</li><li>内部持有一个 <code>Factor inner</code> 属性（用于存放嵌套的表达式）。</li></ul></li><li>多态求导逻辑：<br>在 <code>SinFactor</code> 内部实现 <code>derive()</code> 方法：直接 <code>return new Term(CosFactor(inner), inner.derive())</code>，完美契合现有的链式求导法则。原有 <code>Expr</code> 和 <code>Term</code> 的遍历求导逻辑不必修改。</li><li>解析层处理：<br>在 <code>Parser.parseFactor()</code> 的多路分支中，新增对 “sin” 和 “cos” 字符串的识别，并实例化对应的 Factor 即可。</li><li>底层引擎（无需重构）：<ul><li>若三角函数无需展开化简，直接将其包装在 <code>Poly</code> 的 <code>MonoKey</code> 中作为不可变特征处理即可。现有的加法、乘法合并引擎同样。</li></ul></li></ol><p>得益于 AST 节点的高度自治与多态分派机制，本架构面对“新增数学规则”的迭代时，表现出了极强的横向扩展能力。</p><hr><p><span id="设计模式"></span></p><h3 id="使用到的设计模式-Design-Patterns"><a href="#使用到的设计模式-Design-Patterns" class="headerlink" title="使用到的设计模式 Design Patterns"></a>使用到的设计模式 Design Patterns</h3><ol><li><p><strong>组合模式（Composite Pattern）</strong><br>整个 AST 结构中，无论是独立的个体对象（例如变量 $x$ 或常数 $5$），还是包含复杂子对象的容器（例如表达式 $x + 5$），都需要以完全一致的方式进行处理。<br>通过使用 <code>Factor</code> 接口，当 <code>Term</code> 对象对其持有的 <code>Factor</code> 列表调用 <code>derive()</code> 方法时，无需关心该 <code>Factor</code> 究竟是一个简单的变量，还是一个层层嵌套的复杂函数。它只需信任并依赖于该接口即可。</p></li><li><p><strong>静态工厂方法（Static Factory Method）</strong><br>在 <code>Expr</code> 类中编写的 <code>public static Expr zero()</code> 和 <code>public static Expr of(Factor... factors)</code> 这两个方法，它们为对象的创建过程提供了清晰且富有语义的命名。在未来的开发中，如果你决定让 <code>Expr.zero()</code> 方法不再每次都通过 <code>new Expr()</code> 来创建新对象，而是改为返回一个经过缓存的、不可变的单例对象，完全可以轻松实现这一变更，而无需修改任何调用了该方法的现有代码。</p></li><li><p><strong>单例模式（Singleton Pattern）</strong><br>因为全局只有一个函数模板，所以为其实现单例模式：</p></li></ol><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">FuncDefinition</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">FuncDefinition</span> <span class="variable">INSTANCE</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">FuncDefinition</span>();</span><br><span class="line">    <span class="keyword">private</span> String definition;</span><br><span class="line">    <span class="keyword">private</span> Expr exprDefinition;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="title function_">FuncDefinition</span><span class="params">()</span> &#123;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> FuncDefinition <span class="title function_">getInstance</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> INSTANCE;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> Expr <span class="title function_">getExprDefinition</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> exprDefinition;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setDefinition</span><span class="params">(String definition)</span> &#123;</span><br><span class="line">        <span class="comment">// 负责把传入的字符串转为表达式树</span></span><br><span class="line">        <span class="built_in">this</span>.definition = definition;</span><br><span class="line">        <span class="built_in">this</span>.exprDefinition = parseExpr();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="可以改进增添（以下由AI建议给出）："><a href="#可以改进增添（以下由AI建议给出）：" class="headerlink" title="可以改进增添（以下由AI建议给出）："></a>可以改进增添（以下由AI建议给出）：</h4><p><strong>Visitor 访问者模式</strong><br>目前架构采用了<strong>解释器模式</strong>。每一个节点都知晓如何对自己进行求值或求导（例如，<code>PowerFactor</code> 类拥有其专属的 <code>derive()</code> 和 <code>toPoly()</code> 方法）。<br>这种设计存在一个致命的缺陷：<em>如果你想要新增一种操作，该怎么办？</em> 假设想添加一个 <code>printToXML()</code> 方法、<code>calculateIntegral()</code> 方法，或者 <code>formatToLaTeX()</code> 方法。就不得不逐一打开 <code>Expr</code>、<code>Term</code>、<code>ConstantFactor</code>、<code>VarFactor</code> 等类文件，并把该方法添加到<em>每一个类</em>中去。在这种模式下，数学运算逻辑不再内嵌于各个节点之中；相反，节点只需负责“接纳”一位“访问者”即可：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// The Node just says &quot;Welcome, Visitor! Here I am.&quot;</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">PowerFactor</span> <span class="keyword">implements</span> <span class="title class_">Factor</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">accept</span><span class="params">(ASTVisitor visitor)</span> &#123;</span><br><span class="line">        visitor.visitPowerFactor(<span class="built_in">this</span>); <span class="comment">// Passes itself to the visitor</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// The Visitor contains ALL the logic for a specific action</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">DerivativeVisitor</span> <span class="keyword">implements</span> <span class="title class_">ASTVisitor</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">visitPowerFactor</span><span class="params">(PowerFactor p)</span> &#123;</span><br><span class="line">        <span class="comment">// The logic for n * x^(n-1) lives here now!</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">visitConstantFactor</span><span class="params">(ConstantFactor c)</span> &#123;</span><br><span class="line">        <span class="comment">// Return 0</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><hr><h2 id="分析自己程序的bug"><a href="#分析自己程序的bug" class="headerlink" title="分析自己程序的bug"></a>分析自己程序的bug</h2><p><img src="/Blog/images/oou1/image-3.png" alt="alt text"></p><p>这部分没什么可写的，因为三次作业的强测和互测中均实现了 <strong>0 bug</strong>，这也得益于rwg老师强调的这个理念：</p><blockquote><p><strong>不要为了性能牺牲正确性</strong></p></blockquote><p>在第二三次迭代中我均首先保证了多项式合并的正确性，而没有着重处理<code>exp</code>式子中系数提取与化简的处理，因而可能优化分不高，但确实这也是我能保证程序没有bug的方法。</p><p>同时为了避免bug，在程序中我也为不希望改变的量赋予<code>final</code>属性，元素赋值时实现深克隆，格外注意对容器元素的删除时可能产生的问题，以免产生意料之外的问题。</p><p>长代码行和高圈复杂度也是产生bug的诱因，通过降低这些方法的复杂度，可以显著降低产生bug的几率。</p><p>其实关于hw3还有一点想吐槽：这次作业我没怎么做最终长度优化导致互测进入了b房（正确性满分但性能分不高），而b房的大家都是同样的情况，导致hack也没什么结果，相比之下a房因为优化的问题可以hack出很多点。这样就导致a房既有了高强侧分，又有了高hack分，这不是鼓励大家为了性能舍弃正确性吗？</p><h3 id="分析自己发现别人程序bug所采用的策略"><a href="#分析自己发现别人程序bug所采用的策略" class="headerlink" title="分析自己发现别人程序bug所采用的策略"></a>分析自己发现别人程序bug所采用的策略</h3><ul><li>主要：构造评测机，高效，可以发现少量bug，效果取决于评测机的质量。</li><li>构造极端样例：有效，但样例构造有难度。</li><li>阅读对方代码（白盒测试），针对其设计缺陷构造用例。</li></ul><h3 id="分析自己进行的优化"><a href="#分析自己进行的优化" class="headerlink" title="分析自己进行的优化"></a>分析自己进行的优化</h3><ol><li><p>基于哈希与正则化（Canonicalization）的 $O(1)$ 同类项合并<br>在多项式乘法和高阶展开（如 <code>(x+1)^8</code>）中，如果采用传统的双层 <code>List</code> 遍历对比同类项，时间复杂度将达到灾难性的 $O(N^2)$。<br>通过提取单项式的不可变数学特征（x 的指数、y 的指数、嵌套表达式内容）封装为 <code>MonoKey</code> 类，并重写 <code>equals</code> 和 <code>hashCode</code>。<br>实现了通过<code>HashMap&lt;MonoKey, BigInteger&gt;</code>的快速系数合并。</p></li><li><p>基于多态的快速求导与多项式转换<br>为所有类继承自<code>interface AstNode&lt;T&gt;</code>，实现逻辑的统一。</p></li></ol><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">AstNode</span>&lt;T&gt; <span class="keyword">extends</span></span><br><span class="line">   <span class="title class_">PolyConvertible</span>,</span><br><span class="line">   Substitutable&lt;T&gt;,</span><br><span class="line">   Instantiatable&lt;T&gt;,</span><br><span class="line">   Derivable &#123;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ol start="3"><li>本架构的正确性由<strong>绝对的不可变性（Immutability）</strong> 和**深拷贝（Deep Copy）**来保证。在进行 <code>Poly.mulP</code>（多项式相乘）或 <code>expP</code>（乘方）等操作时，每次计算都会 <code>new</code> 出全新的 <code>Poly</code> 和 <code>Mono</code> 对象返回。虽然牺牲了一定的内存，但彻底杜绝了引用传递导致的各种隐患。</li></ol><hr><h2 id="大模型相关使用"><a href="#大模型相关使用" class="headerlink" title="大模型相关使用"></a>大模型相关使用</h2><h3 id="代码生成使用率"><a href="#代码生成使用率" class="headerlink" title="代码生成使用率"></a>代码生成使用率</h3><ul><li>AI 生成代码占比：0%</li><li>——作业中所有的的代码均由我自己编写。虽然AI的能力很强，但总归自己去写下每一行代码，才能真正掌握编写的能力。</li></ul><h3 id="大模型的实际应用场景与心得体会"><a href="#大模型的实际应用场景与心得体会" class="headerlink" title="大模型的实际应用场景与心得体会"></a>大模型的实际应用场景与心得体会</h3><p>虽然不会让大模型直接生成代码，但其实llm深度参与了我的代码编写过程：</p><p>不像当初学c语言的时候，会从每一个语法、每一个细节讲起，OO课程上我们直接面对的就是一千多字的题目要求和几百行待编写的代码，这意味着一切java的语法或实现任务的细节都需要我们自学。</p><p>自学有很多种方法：看jkd文档、看网上如菜鸟教程、看网课，或是直接问AI。可以想象，之前的人们学习java时，会在各种文档doc与教程中寻觅（去年我学习c语言也是这样的），而这样的搜索往往费时而可能缺乏深度，而如今的AI可以基本替代掉上述过程。<br>比如我想学习什么是<em>单例模式</em>，直接问AI即可，它会给出不同单例模式的实现方式，进一步的，你还可以问它具体到我的任务上选择哪种最好，或是单例模式的原理是什么。<br>对比这种模式，与从网上某个网页中复制粘贴一段自己也不怎么能看懂的代码并然后修修改改，前者的优点显而易见：<strong>具体的、有针对性的、而深入的</strong>。</p><p>除去这种可能网上也能找到的理论方面的指导，AI最关键的帮助还是帮助提供工程化的思路和自己认知之外的代码逻辑优化。现在，不用自己读完一本《The Art of Computer Programming》，直接把自己的思路发给AI，跟它说：“假设你是一名高级java工程师，对这段代码有什么建议？”我就可以收到有效的改进意见，提升自己的能力与认知。</p><h3 id="大模型评价"><a href="#大模型评价" class="headerlink" title="大模型评价"></a>大模型评价</h3><p>大模型回答的质量取决于人提供的Prompt。为了达到让AI辅助自己学习的目的，显然不能让它直接把代码生成出来（而且很多时候它生成的代码有许多问题），而是要让它或是引导自己，或是提供建议。<br>所以我在对话开始使用了这样的prompt：</p><blockquote><p>你现在是一位资深java工程师，来指导我完成代码，始终记得，你在我没有要求的情况下不得给出代码答案。你只是协助我完成任务，回答我的问题，顺着我的思路来思考分析，绝不能在我之前将答案告知我<br>遇到潜在的bug也不要提醒我，留给我让我自己发现。<br>不要提供任何我询问内容以外的信息</p></blockquote><p>效果在最开始还不错，但随着上下文的增多，llm有说也会直接把代码全写出来。</p><p>总之，使用AI确实让我提高了java水平、培养了面向对象的思想，也更深入地了解了一些底层的原理（通过随时向llm发问）。我也相信，使用AI技术所学到知识将多于不使用AI时的学习，而重点在于使用方式的正确性。</p><hr><h2 id="未来方向"><a href="#未来方向" class="headerlink" title="未来方向"></a>未来方向</h2><p>你觉得可以如何修改第一单元的课程，让大家更好的进行第一单元的学习：</p><p>可以针对作业中所用到的设计模式、或某些语法给出更多的教程或提示，第一次迭代时的公众号文章就对我的设计有很多帮助，希望每次作业都有类似的引导。</p><hr><h2 id="思考题"><a href="#思考题" class="headerlink" title="思考题"></a>思考题</h2><ol><li><p>如何检查输入是否符合要求？包括空格，连续符号等。</p><ol><li><p>拦截非法组合<br>评测机的 Lexer 必须对空白符非常敏感。</p><ul><li><strong>数字内空格切断</strong>：当读入数字时，如果紧跟空格，Lexer 必须将后续的数字识别为新的 Token。例如 <code>12 34</code> 会被解析为 <code>[NUM(12), NUM(34)]</code>。</li><li><strong>连续符号聚合</strong>：对于 <code>+++</code> 或 <code>---</code>，Lexer 可以将其作为连续的单字符 Token 输出，交由语法层判断</li><li><strong>非法字符白名单</strong>：遇到任何不在 <code>[0-9x\+\-\*\(\)\s\^sincosp]</code> 集合内的字符（如全角空格、制表符的变体），立即在词法阶段拦截。</li><li><strong>长度断言</strong>：删除所有空白字符后，检查字符串长度是否超出要求限制。</li></ul></li><li><p><strong>形式化语法层（Parser）：拦截非法结构</strong></p><ul><li><strong>递归下降断言</strong>：利用递归下降算法构建一棵“虚拟的验证树”。如果刚才的 <code>12 34</code> 传到 Parser，Parser 在期望读到操作符（Operator）的地方读到了第二个 <code>NUM</code>，直接抛出 SyntaxError（WF）。</li></ul></li></ol></li><li><p>如何精确计算一个合法输入的 cost？</p><ol><li>原样建树。使用 Parser 将输入字符串解析为 AST，不进行任何数学化简</li><li>自底向上算cost。</li></ol></li></ol><hr><blockquote><p><strong>本文同步发布于</strong>：<a href="https://blog.csdn.net/Gooden_job/article/details/159551046">https://blog.csdn.net/Gooden_job&#x2F;article&#x2F;details&#x2F;159551046</a></p></blockquote>]]></content>
    
    
      
      
        
        
    <summary type="html">&lt;p&gt;本文是基于2026年面向对象课程第一单元迭代作业的总结&lt;/p&gt;
&lt;h2 id=&quot;目录：&quot;&gt;&lt;a href=&quot;#目录：&quot; class=&quot;headerlink&quot; title=&quot;目录：&quot;&gt;&lt;/a&gt;目录：&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a</summary>
        
      
    
    
    
    
    <category term="OOP" scheme="https://begineri.github.io/Blog/tags/OOP/"/>
    
    <category term="java" scheme="https://begineri.github.io/Blog/tags/java/"/>
    
  </entry>
  
  <entry>
    <title>刷机与救砖记录</title>
    <link href="https://begineri.github.io/Blog/2026/02/16/%E5%88%B7%E6%9C%BA%E8%AE%B0%E5%BD%95/"/>
    <id>https://begineri.github.io/Blog/2026/02/16/%E5%88%B7%E6%9C%BA%E8%AE%B0%E5%BD%95/</id>
    <published>2026-02-16T08:03:52.000Z</published>
    <updated>2026-03-08T03:18:19.666Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>刷机真理：</p><ul><li>夜晚不刷机</li><li>刷机先备份</li></ul></blockquote><blockquote><p><strong><strong>FLASH AT YOUR OWN RISK</strong></strong><br><strong><strong>PLEASE READ ALL OF THIS BEFORE FLASHING</strong></strong></p></blockquote><h1 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h1><ul><li>设备： 一加 13  （<strong>oneplus 13</strong>）</li><li>经验： 0</li><li>工具： 电脑、网络、论坛</li></ul><h1 id="动机"><a href="#动机" class="headerlink" title="动机"></a>动机</h1><p>旧手机陪伴了我三年的高中 + 大半年大学，在三年的（较）高强度使用后变得空间不足、电池续航较差，终于到了换的时候。</p><p>旧手机是荣耀，无法安装谷歌框架，更无法刷机。年少不懂的我只能忍受着各种无法删去的广告、极低的隐私、极差的广告。</p><p>终于我看到一位我很喜欢的up推荐了一加 13，并<em>第一次</em>了解到刷机这个概念，仿佛打开了新世界的大门。</p><p>略过从对刷机、bl、root、ROM这些词语一无所知，到购入手机，到各种找教程的过程，我终于在25年的暑假的返校最后一周决定开始刷机。</p><h1 id="行动"><a href="#行动" class="headerlink" title="行动"></a>行动</h1><p>一加作为如今刷机的主流选择，有着非常丰富的教程与活跃的论坛。我最终选择跟着 XDA 上的一份教程进行刷机:</p><p><a href="https://xdaforums.com/t/pjz110-21-jan-coloros-to-oxygenos-glo-in-eu-16-0-3-501-na-16-0-1-304.4707431/">[PJZ110][21 Jan] ColorOS to OxygenOS</a></p><h2 id="最终目的"><a href="#最终目的" class="headerlink" title="最终目的"></a>最终目的</h2><p>为了使用完整的谷歌服务，与最大限度地去掉手机内置广告，我选择刷入一加 <strong>全球版</strong>的系统，即这里标题提到的：<code>from ColorOS to OxygenOS</code>。</p><h2 id="步骤"><a href="#步骤" class="headerlink" title="步骤"></a>步骤</h2><ul><li>备份系统文件</li><li>解锁 BL 锁 (Unlock Bootloader)<br><img src="/Blog/images/%E5%88%B7%E6%9C%BA/image-1.png" alt="alt text"></li><li>刷入全球版系统 (Flash)<br><img src="/Blog/images/%E5%88%B7%E6%9C%BA/image-2.png" alt="alt text"></li><li>获取 Root 权限<br><img src="/Blog/images/%E5%88%B7%E6%9C%BA/image-3.png" alt="alt text"></li><li>安装模块，隐藏环境等<br><img src="/Blog/images/%E5%88%B7%E6%9C%BA/image-4.png" alt="alt text"></li></ul><h2 id="安装的模块"><a href="#安装的模块" class="headerlink" title="安装的模块"></a>安装的模块</h2><ul><li>Fix Signal OnePlus 13 ：专门修复信号问题</li><li>Zygisk Next </li><li>Play Integrity Fix (Tricky Store) ：过谷歌安全验证</li><li>Wi-Fi 7 Enabler ：解锁 Wi-Fi 7 (6 Ghz)波段</li><li>LSPosed :主要为了使用专为一加手机提供优化的 LuckyTool</li><li>Zygisk Assistant</li></ul><h2 id="最终成果"><a href="#最终成果" class="headerlink" title="最终成果"></a>最终成果</h2><p>经过一天的折腾，成功刷入全球版系统，开始愉快使用。<br>虽然存在一些硬件不适配的问题，诸如NFC有些场景无法使用、天气定位乱飘，但我愿意用这些不变换取一个相对纯净的系统。<br><img src="/Blog/images/%E5%88%B7%E6%9C%BA/image-5.png" alt="alt text"></p><h1 id="救砖"><a href="#救砖" class="headerlink" title="救砖"></a>救砖</h1><p>当然，第一次刷机，不出意外还是会出意外的。以下是迄今为止两次翻车及神奇救砖经历。</p><blockquote><p>再次牢记刷机真理：</p><ul><li>夜晚不刷机</li><li>刷机先备份</li></ul></blockquote><h2 id="乱装模块的后果"><a href="#乱装模块的后果" class="headerlink" title="乱装模块的后果"></a>乱装模块的后果</h2><h3 id="起因"><a href="#起因" class="headerlink" title="起因"></a>起因</h3><p>第一次刷机并获取Root权限后，面对如此丰富多样可供选择的模块，我依次下载了每个看着有趣的模块。尽管是一个一个安装，但问题依旧出现了，这时我就犯了第一个错：不要在晚上刷机。</p><p>临近睡觉，我急匆匆地装上了几个模块，并简单点开调了调，变安心放下手机睡觉了。一觉起来，我发现我的手机没电关机（前一天晚上还有四十多），并在充上电以后陷入了重启循环。<br>后来回顾，主要原因应该是晚上装的一个<strong>充电模块</strong>（所以说和电池有关的模块也要慎重），同时不知道还有什么其他影响，总之现在无法开机了。</p><h3 id="救砖过程"><a href="#救砖过程" class="headerlink" title="救砖过程"></a>救砖过程</h3><p>以下是尝试过程：</p><ul><li>既然是模块的问题，我尝试在开机时通过案件，关闭KernelSU的所有模块：结果失败，无法关闭</li><li>直接取消Root，模块自然失效：具体操作是重新刷回原版的init_boot分区，最终确实成功开机了。</li></ul><p>看着简单，但那确实是经过一番搜索与摸索的结果。现在看来很自然也很好理解，但当时全网搜索了好久，才确认这个方法。当时甚至一度跑去售后，最终当我想给售后 <em>复现</em> 一下我的重启循环时，我的手机 <em>神奇地</em> 在这一刻重新开机了（此前一直无法成功，尽管我刷入了init_boot，但当我重新获取root权限后，即刷回修补后的init_boot分区，又陷入了无法开机的情况）。如果在这里没成功，我就要喜提清空数据了，但不知道此时达成了什么前置条件，一切恢复正常了，这次危机也就此结束。</p><h2 id="过于自信因此没备份"><a href="#过于自信因此没备份" class="headerlink" title="过于自信因此没备份"></a>过于自信因此没备份</h2><h3 id="背景-1"><a href="#背景-1" class="headerlink" title="背景"></a>背景</h3><p>自上次刷到全球版过了半年多，版本也该更新了，于是我准备从原本的15.831 更新 到15.864。<br>到864的原因是，这是OOS15最新的一个版本了，如果再新就要到OOS16，刚出没多久，而且跨大版本，因此舍弃。</p><p>更新前，我看这个OTA Updates的教程如此简单，我有急着更新，因此完全没备份数据，也没有关闭本地模块，直接开始操作，在执行完：</p><ol><li>打开本地安装</li><li>电脑上下载安装包 REPO </li><li>手机安装</li><li>KSU Install to inactive slot (After OTA)</li><li>在软件更新处选择重启</li></ol><p>完全参考以下教程：<br><img src="/Blog/images/%E5%88%B7%E6%9C%BA/image.png" alt="参考"></p><p>一系列后，再次无法开机了</p><h3 id="救砖-1"><a href="#救砖-1" class="headerlink" title="救砖"></a>救砖</h3><p>现状：一加此型号手机采用a&#x2F;b分区设计，无缝更新，此时新版本在b分区，旧版本在a分区，data数据分区共享。</p><p>这次对比之前，有了更多的经验，也有了Gemini的全程辅助（捣乱），依次尝试以下操作：</p><ul><li>尝试切回分区 a 开机：失败</li><li>在a&#x2F;b分区都刷回原版init_boot：失败</li><li>取消更新合并 <code>snapshot-update cancel</code>：失败</li><li>刷回原版vbmeta、boot等分区：情况更坏了</li></ul><p>到此时已经深夜十二点过了（是的，又是晚上刷机带来的问题），面对无限重启的手机和我可能再也再也见不到的手机中的数据，我选择去睡觉，明天早上清醒再解决… （以下感受见下一部分详述）<br>早上起来又做了以下尝试：</p><ul><li>开始搜寻各大论坛（酷安、XDA…），没找到什么信息</li><li>绝望，试图找专业人士去救砖：论坛里、QQ群里、闲鱼上的各种我能找到的人都问了个遍，只有两个人在听了我的描述后表示有小概率<em>数据还能保住</em>，剩下都表示只能清空线刷</li><li>为了<em>没备份的数据苦苦挣扎</em>，谨慎地尝试AI给的方法</li><li>关键与转折：利用之前的全量包，重新把新系统完整刷了一遍</li><li>关闭 vbmeta校验，如下：<br><img src="/Blog/images/%E5%88%B7%E6%9C%BA/image-6.png" alt="alt text"></li></ul><p>至此，成功开机了！<br>虽然root掉了，但数据依旧完整，更新也成功了！</p><hr><h1 id="刷机后记"><a href="#刷机后记" class="headerlink" title="刷机后记"></a>刷机后记</h1><h2 id="面对可能永远消失的数据的绝望与无力"><a href="#面对可能永远消失的数据的绝望与无力" class="headerlink" title="面对可能永远消失的数据的绝望与无力"></a>面对可能永远消失的数据的绝望与无力</h2><p>数据的世界，不同于现实世界，是没有实体而无法触及的。因此可能上一秒你的照片，你的数据还完好无损，下一秒你就再也无法访问它们。好一点来说，如果没有进行彻底格式化，它们依旧躺在那些01的海洋中，甚至可以说躺在那些晶体管中，而我只是无法解读它们。</p><p>在那个手机无法开机，可能面对丧失手机内所有数据的夜晚，我想了很多。<br>我先设想最坏情况：我的手机里有什么是独一份而格式化后就会永远失去的东西？</p><ul><li>照片：相册里有这半年多的照片，其中包括和朋友同学出游的照片，最宝贵的还是上个月去斯里兰卡旅游照的大量照片。这些我都没有备份，斯里兰卡的照片我也只随便发了几张给朋友，除此之外照片只在手机中。<br>如果这些照片找不回来，我已经做好安慰自己过去美好回忆记在脑中就足够了的准备了…</li><li>微信聊天记录：尽管大多数时候电脑和手机的记录是同步的，但也存在少量情况下电脑端的消息不全。不过这点还算可以接受。</li><li>备忘录：里面有一些记录</li><li>其他系统桌面设置等…</li></ul><p>总之，我在试图思考最坏的情况，并做好充足的心理准备。尽管如此，那天晚上，我躺在床上还是辗转反侧，心中一片乱麻。我想和我的数据一起死去。</p><p>面对那些宝贵而又脆弱的数据，在这种情况，我们是无助的。<br>最终救回那些数据，是我垂死挣扎的结果。</p><p>说实话，这两次都是稀里糊涂的救回来了，为什么这么做不行？为什么那样做就可以了？<br>我到现在都没搞懂具体是什么出了问题（欢迎在评论区讨论），但是就是尝试看起来很有希望的这个，在尝试看起来很可靠的那个，然后在一个步骤后，神奇的开机了，数据再次回来了，我迈入死亡的一只脚也回来了。</p><h2 id="老生常谈的AI问题"><a href="#老生常谈的AI问题" class="headerlink" title="老生常谈的AI问题"></a>老生常谈的AI问题</h2><p>AI在面对自己没有把握或根本不知道的事情时，在99%情况里它会胡诌一个答案出来，此时如果我们不加判断或轻率地复制粘贴那些指令，很可能让本就糟糕的事情进一步陷入无法解决的境地。我们一次又一次地踩这个坑，掉到坑里我们才又提醒自己下次更加谨慎。</p><p>（绝望截图）及时止损<br><img src="/Blog/images/%E5%88%B7%E6%9C%BA/1.png" alt="alt text"></p><p>不可否认，最终成功保住数据，还是AI+我一起找出尝试出的办法，所以AI不是不能给出正确答案，而是需要人类来进行最为关键的<strong>选择与判断</strong>。</p><h2 id="目的为导向的学习"><a href="#目的为导向的学习" class="headerlink" title="目的为导向的学习"></a>目的为导向的学习</h2><p>我去刷机，不是因为我对刷机很感兴趣，想去研究这个原理（当然现在逐渐深入渐渐发现了其中的有趣之处），而是纯粹的目的驱动：我想新手机拥有谷歌框架、纯净的外版系统、以及刷机后一系列的自定义自由。</p><p>有了这个目的，我开始从零开始研究如何达到我的目的。正如前面所说，最开始，我下载酷安，根本搞不懂那些名词是什么意思，只能收藏+关闭一条龙，企图找到个靠谱的步骤直接照搬。同时也看看一些科普与视频，补补理论知识。最终我也是找到XDA上这个量身定制的教程，一切都只差行动。</p><p>当然，付诸行动需要<strong>决心</strong>，还有不到一周开学与即将失去家里的便利条件就是一个很好的推动剂。</p><p>而且，现实与教程的文字往往是有区别而不能一比一复刻的，我在按教程走的时候遇到了无数的问题，翻论坛、查谷歌、问AI，用尽一切方法。在这个过程中，我才真正理解了我每一步是在干什么，渐渐了解背后的原理，这比过看一万篇教程。</p><hr><p>待补充：刷机名词解释</p>]]></content>
    
    
      
      
        
        
    <summary type="html">&lt;blockquote&gt;
&lt;p&gt;刷机真理：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;夜晚不刷机&lt;/li&gt;
&lt;li&gt;刷机先备份&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;strong&gt;FLASH AT YOUR OWN</summary>
        
      
    
    
    
    
    <category term="刷机" scheme="https://begineri.github.io/Blog/tags/%E5%88%B7%E6%9C%BA/"/>
    
  </entry>
  
  <entry>
    <title>计组全踩坑记录</title>
    <link href="https://begineri.github.io/Blog/2025/12/25/%E8%AE%A1%E7%BB%84%E5%85%A8%E8%B8%A9%E5%9D%91%E8%AE%B0%E5%BD%95/"/>
    <id>https://begineri.github.io/Blog/2025/12/25/%E8%AE%A1%E7%BB%84%E5%85%A8%E8%B8%A9%E5%9D%91%E8%AE%B0%E5%BD%95/</id>
    <published>2025-12-25T04:50:19.000Z</published>
    <updated>2025-12-25T13:14:57.674Z</updated>
    
    <content type="html"><![CDATA[<h2 id="那些踩过的坑："><a href="#那些踩过的坑：" class="headerlink" title="那些踩过的坑："></a>那些踩过的坑：</h2><ul><li><p><em>暑假时除了把几个软件下载，几乎没看预习部分，想着开学再看也来得及。于是 pre 喜提做出来0道题，p0前两天速通Logisim</em></p></li><li><p><em>P3 尝试自己从零开始搭，不看往届博客，和 Gemini 共同创作。最终导致 P3 上机截止前还没做完，喜提 P3 就 gap 一周</em></p></li><li><p><em>面对课下推荐题不屑一顾，除了提交代码文件没做任何准备，妄求凭借自己的智慧在上机时直接做出课上题并通过。于是 P4 就这样卡了两周，终于在第三次 P4 前狠狠拟合了课下推荐题，得以一个小时速通掉。</em></p></li><li><p><em>…</em></p></li></ul><p><strong>点击直接看总结：<a href="#%E6%80%BB%E7%BB%93">总结</a></strong></p><p><img src="/Blog/images/%E8%AE%A1%E7%BB%84%E5%85%A8%E8%B8%A9%E5%9D%91%E8%AE%B0%E5%BD%95/image.png" alt="结算"></p><h2 id="感受与吐槽"><a href="#感受与吐槽" class="headerlink" title="感受与吐槽"></a>感受与吐槽</h2><h3 id="初见"><a href="#初见" class="headerlink" title="初见"></a>初见</h3><p>说实话，这门课，计算机组成，我在开始学习之前对它几乎没有什么概念，暑假的预习部分也是让我一头雾水。看着这13年就停止维护的软件，这如此古老的页面，和如此难用的编程工具，我对未来的学习产生了深深的绝望和怀疑：<em>真的要用这些东西学习吗？这些东西真的还有人在使用吗？</em><br>我想这也是我暑假没怎么进行学习的原因。</p><p>直到真正学期开始，开始上机，我知道我不得不学了。<br>很多人吐槽理论课没用，但我要承认lxd老师的计组课还是对我很有帮助的。还能记得刚开始时，我对有限状态机、门电路、信号之类的几乎一无所知。而他在课上的讲解，对我来说是如此的清晰易懂，让我有恍然大悟之感，也对这门课程初步建立了一些认知。（但是感觉到后面的缓存与存储之类的内容，就有些听不进去了…）</p><h3 id="中途"><a href="#中途" class="headerlink" title="中途"></a>中途</h3><p>在 P3 与它之前的阶段，我几乎都是（好吧没用几乎，就是全部时候）一个人看教程 + 问 AI 的学习方式，因为我认为这样更高效，也因为其实找不到人讨论。在 AI 解决不了的时候，我就开始翻找往届的资料。当时我还是选择自己看教程 + 尝试<strong>创造</strong>，尽管略微困难，但和ai合作起来也不是做不到。可是我发现这样的模式有个巨大的问题，那就是<strong>太耗费时间</strong>了，为了完成它，每周要牺牲掉本该属于其他项目的时间，甚至无法在周日的 ddl 前完成（P3 就是这样 gap 掉的），直到 P4 也还在坚持手搓。<br>直到 P5  … 我发现了 <a href="https://kamonto.github.io/Kamonto_blog/2025/10/14/%E4%B8%80%E6%9C%AC%E4%B9%A6%E6%95%99%E4%BD%A0%E9%80%9A%E5%85%B3%E8%AE%A1%E7%BB%84%E5%AE%9E%E9%AA%8C%EF%BC%88%E4%B8%8B%EF%BC%89/">一本书教你通关计组实验</a> !</p><p><del>于是就开始爽抄</del>那么到这里学习的路线就是 看课内指导书 + 把指导书和教程都同步发给Gemini + 看博客教程 + 自己拼拼凑凑写文档和 CPU 。</p><h2 id="关于”创作”"><a href="#关于”创作”" class="headerlink" title="关于”创作”"></a>关于”创作”</h2><p><em>“这样真的学到东西了吗？”</em><br>学是可能学到了，但是我想指出的是，我在这里的学习，经历了<strong>从自己尝试创作</strong>，到<strong>阅读参考答案并复刻</strong>的转变。虽然结果都是完成了CPU的搭建任务，但方式显然不同，显然前者难度更大，而后者除了学会知识，没怎么获得思维上的提升，所做的，只是理解别人的思想，然后copy罢了。</p><p>一方面，我对自己说：“<em>未来除了考试，我应该用不到这门知识了。</em>”所以就这么水过去也无可厚非。<br>另一方面，我还是在惋惜，想问问设计这门课程的人如何看待这样的现象。也许现在的结果是我们的平均线达到了一个看起来很好的水平，但是从个人的角度来看，结果是灾难性的：</p><ul><li>不想学的同学，迫于考试压力，对着往届博客半抄半凑的提交了作业，你真的认为这除了浪费他们一点时间以外对他们还有什么别的帮助吗</li><li>想学的同学，他们的时间也是有限的，而一次一次的上机有是卡的那么紧，其他课程的压力也不小，想抽出时间去全身心投入其中，进行“原创”设计也是很难的。</li></ul><p>这么看来，<strong>没有人在受益。</strong></p><h2 id="关于考试与协作"><a href="#关于考试与协作" class="headerlink" title="关于考试与协作"></a>关于考试与协作</h2><p>经过简单的推理就可以发现，合作的效率要远大于单打独斗。社会的进步基于分工。如果让远古时代的每个人都自己手搓石质工具、自己用自己的工具打猎、自己去采摘水果，那我相信每个人都会饿死。</p><p>而我们现在干的事就是自己磨石头，自己打猎自己吃。<br>我说的就是<strong>上机</strong>这个形式。机房里，不许相互交流，不许相互讨论，不许联网搜索。遇到问题了？遇到想不通的地方了？对不起，你要不自己想通，要不带着你的问题一起进入坟墓吧。</p><p>问题是得不到及时解决的（甚至有些上机遇到的问题最终就没有被解决），我们做出了一些题，也埋葬了另一些问题。</p><p>试想，假如上机是允许相互交流的，那么这个课程的学习会高效多少（这甚至会弥补之前所说原创导致的时间不足）。<br><em>“这个数据点为什么通不过啊？”</em><br><em>“检查一下你新增信号的命名，或者位宽什么的。”</em><br>于是，问题解决了。而不是瞪眼瞪一个小时，和编译器斗智斗勇，然后恍然惊觉。<br><strong>这门课要学到的最关键的东西，是面对繁杂的代码仍能仔细 debug 的耐心，还是真正从零到一设计CPU的能力？我想这个问题的答案是显而易见的。</strong></p><h2 id="关于拟合"><a href="#关于拟合" class="headerlink" title="关于拟合"></a>关于拟合</h2><p>起初我期望着凭借课下的学习与搭建，上机的任务就是考验一个临场发挥。环抱着这个期望，P4 第一次上机做出1道题，第二次上机做出0道题。其实现在回想起来，应该就是某些信号名字什么的没连对，但是在机房时怎么也找不出问题，只能痛苦而终。</p><p>终于在连挂两次后发现了（之前看到了但根本没在意）往年题，可以提交与评测。于是我带着想弄清楚上机究竟为什么过不去的想法，去作那些题。第一道题不出意料，在我认为全部改完以后，仍然无法通过，于是在ai的帮助和我自己仔细的查看后，终于找到问题，改对了。这是从零到一的突破，于是直接把所有可以评测的题全找到，全部写了个遍。</p><p>其实发现题的套路就那几种，可能犯得错误也就哪几种。就这样，下次上机时一个小时就做完了三道题…<br>现在想来，拟合这个过程，其实就干了两件事，一个是了解大概会有哪些题型，一个就是把你能犯得错误划了个范围。第二点解决的就是，当初面对错误无从下手，而怀疑自己是思路有问题而不是哪个小代码拼写什么的错了。</p><p>后续使用这种方法，只能说很好用，并且通过P56（7能过，就懒得拟合了）。</p><p>关键工具：<a href="https://github.com/tsx8/buaa_tools/tree/main/cscore_problems">爬取 cscore 网站题目的脚本</a></p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><ol><li><strong>古老而难用的软件</strong></li><li><strong>单打独斗而不是合作的上机</strong></li><li><strong>时间不足，所做的只是阅读理解与迁移应用，而不是思考创作</strong></li><li><strong>拟合往年题的重要性</strong></li></ol><h2 id="还是学到了一些"><a href="#还是学到了一些" class="headerlink" title="还是学到了一些"></a>还是学到了一些</h2><ul><li>第一次在课上了解和弄懂数据竞争，明白 D 锁存器、 D 触发器的感觉是十分良好的。在学习之前，很难想象出这样一个“记忆”装置是靠小小的上升沿时的延迟实现的，这是纯粹的硬件。从这个方面来想倒是十分有趣。</li><li>在编写CPU和做题的时候，往往感受到一种环环相扣的感觉，这是纯粹的理性与逻辑。位宽写错了、逻辑写反了、条件写错了，你都得不到正确的结论（不过这也要归功于古老的ISE，毕竟，你使用一个没有声明的信号，一些不匹配的位宽，它都不给你报错。。。换一个现代的编译器都不会有这个苦恼）。</li><li>还有吗？想不出来了。</li></ul><h2 id="结算："><a href="#结算：" class="headerlink" title="结算："></a>结算：</h2><p><img src="/Blog/images/%E8%AE%A1%E7%BB%84%E5%85%A8%E8%B8%A9%E5%9D%91%E8%AE%B0%E5%BD%95/end.png" alt="alt text"></p><ul><li><p>126.5 h，相当于每周 8 个小时<br><img src="/Blog/images/%E8%AE%A1%E7%BB%84%E5%85%A8%E8%B8%A9%E5%9D%91%E8%AE%B0%E5%BD%95/1.png" alt="alt text"></p></li><li><p>P5 这个题过不去，求助助教终于解决<br><img src="/Blog/images/%E8%AE%A1%E7%BB%84%E5%85%A8%E8%B8%A9%E5%9D%91%E8%AE%B0%E5%BD%95/2.png" alt="alt text"></p></li><li><p>显然拖到周日，有ddl压力才开始学<br><img src="/Blog/images/%E8%AE%A1%E7%BB%84%E5%85%A8%E8%B8%A9%E5%9D%91%E8%AE%B0%E5%BD%95/3.png" alt="alt text"></p></li><li><p>几乎都在下午与晚上提交<br><img src="/Blog/images/%E8%AE%A1%E7%BB%84%E5%85%A8%E8%B8%A9%E5%9D%91%E8%AE%B0%E5%BD%95/4.png" alt="alt text"></p></li></ul>]]></content>
    
    
      
      
        
        
    <summary type="html">&lt;h2 id=&quot;那些踩过的坑：&quot;&gt;&lt;a href=&quot;#那些踩过的坑：&quot; class=&quot;headerlink&quot; title=&quot;那些踩过的坑：&quot;&gt;&lt;/a&gt;那些踩过的坑：&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;暑假时除了把几个软件下载，几乎没看预习部分，想着开学再看也来得及。于是</summary>
        
      
    
    
    
    
    <category term="CO" scheme="https://begineri.github.io/Blog/tags/CO/"/>
    
  </entry>
  
  <entry>
    <title>与LLM的一些对话记录</title>
    <link href="https://begineri.github.io/Blog/2025/11/13/%E4%B8%8ELLM%E7%9A%84%E4%B8%80%E4%BA%9B%E5%AF%B9%E8%AF%9D/"/>
    <id>https://begineri.github.io/Blog/2025/11/13/%E4%B8%8ELLM%E7%9A%84%E4%B8%80%E4%BA%9B%E5%AF%B9%E8%AF%9D/</id>
    <published>2025-11-13T10:46:17.000Z</published>
    <updated>2025-12-23T09:25:28.528Z</updated>
    
    <content type="html"><![CDATA[<p>记录一些和Gemini的对话</p><p>背景论文：<a href="https://arxiv.org/abs/2503.21460">Large Language Model Agent: A Survey on Methodology, Applications and Challenges</a></p><p><strong>本文目录</strong></p><ul><li><a href="#%E5%85%B3%E4%BA%8E-%E9%80%BB%E8%BE%91"><em>关于 逻辑</em></a></li><li><a href="#%E5%85%B3%E4%BA%8E-%E6%A6%82%E7%8E%87"><em>关于 概率</em></a></li><li><a href="#%E5%85%B3%E4%BA%8E-%E2%80%9C%E6%9C%AC%E8%B4%A8%E2%80%9D"><em>关于 “本质”</em></a></li><li><a href="#%E5%85%B3%E4%BA%8E-%E7%BE%8E"><em>关于 美</em></a></li><li><a href="#%E5%85%B3%E4%BA%8E-%E9%82%A3%E4%BA%9B%E2%80%9D%E9%A1%BD%E5%9B%BA%E2%80%9D%E7%9A%84%E9%94%99%E8%AF%AF"><em>关于 那些”顽固”的错误</em></a></li><li><a href="#%E5%85%B3%E4%BA%8E-%E2%80%9C%E6%82%A8%E8%AF%B4%E7%9A%84%E5%AE%8C%E5%85%A8%E6%AD%A3%E7%A1%AE%E2%80%9D"><em>关于 “您说的完全正确”</em></a></li><li><a href="#%E5%85%B3%E4%BA%8E-%E5%A5%BD%E7%9A%84prompt"><em>关于 好的prompt</em></a></li><li><a href="#%E5%85%B3%E4%BA%8E-Markdown"><em>关于 Markdown</em></a></li></ul><hr><h2 id="关于-逻辑"><a href="#关于-逻辑" class="headerlink" title="关于 逻辑"></a><em>关于 逻辑</em></h2><p><strong>Me：</strong><br>llm是如何处理逻辑推导这个问题的？是否可以说，现在的llm都是经过训练得到的数学模型，其并没有推理能力，只是按照概率生成下一个token而已，并不能进行逻辑推理</p><p><strong>Ge：</strong></p><blockquote><p>这是一个非常深刻且正处在AI研究核心的辩论。您提出的观点——“LLM只是按照概率生成下一个token”——在<strong>技术层面</strong>上是完全正确的，但这并不一定意味着它“不能进行逻辑推理”。</p><p>您提供的这篇综述（以及它所引用的研究）实际上提出了一个相反的论点：<strong>复杂的推理和规划能力可以从根本的概率性“下一词预测”中“涌现”出来</strong>。</p><p>以下是根据您提供的论文和当前AI领域的共识，对这个问题的详细分析：</p><h3 id="1-您的观点是对的：LLM的“引擎”是概率"><a href="#1-您的观点是对的：LLM的“引擎”是概率" class="headerlink" title="1. 您的观点是对的：LLM的“引擎”是概率"></a>1. 您的观点是对的：LLM的“引擎”是概率</h3><p>从根本上说，一个大型语言模型（如GPT）就是一个巨大的数学函数（Transformer架构）。它的核心任务是在给定一系列“上下文”词元（tokens）后，计算出词汇表中所有可能的“下一个”词元的概率分布，然后从中选择一个。</p><ul><li>当您问“法国的首都是哪里？”时，模型并不是“回忆”或“知道”答案。</li><li>它是在计算，在它所“读过”的数万亿文本中，继“法国的首都是”这个序列之后，出现概率最高的词元是“巴黎”。</li></ul><p>从这个角度看，模型中没有一个“逻辑模块”或“推理引擎”。它只是一个极其复杂的模式匹配器。</p><h3 id="2-论文的观点：从概率中“涌现”出推理"><a href="#2-论文的观点：从概率中“涌现”出推理" class="headerlink" title="2. 论文的观点：从概率中“涌现”出推理"></a>2. 论文的观点：从概率中“涌现”出推理</h3><p>您提出的问题，正是这篇论文试图解答的核心。这篇综述将LLM智能体描述为“能够感知环境、<strong>推理目标</strong>并执行行动”的实体 。它明确指出，LLM具有“<strong>前所未有的推理能力</strong>” [cite: 33]。</p><p>那么，一个“概率引擎”是如何实现“推理”的呢？</p><h4 id="a-模式即逻辑"><a href="#a-模式即逻辑" class="headerlink" title="a. 模式即逻辑"></a>a. 模式即逻辑</h4><p>LLM在海量的文本（包括代码、数学论文和逻辑论证）上进行训练。在这个过程中，它学会的<strong>统计模式</strong>本身就蕴含了<strong>逻辑结构</strong>。</p><p>例如，模型学到了：</p><ol><li>在“如果A为真，则B为真”和“A为真”之后，出现“因此B为真”的概率极高。</li><li>在“所有的A都是B”和“C是A”之后，出现“C是B”的概率极高。</li></ol><p>当模型在生成文本时遵循这些高概率路径时，它在<strong>功能上</strong>就“执行”了逻辑推导。它不是在<em>应用</em>逻辑规则，而是在<em>复制</em>它学到的逻辑模式。</p><h4 id="b-规划与分解-Planning-Decomposition"><a href="#b-规划与分解-Planning-Decomposition" class="headerlink" title="b. 规划与分解 (Planning &amp; Decomposition)"></a>b. 规划与分解 (Planning &amp; Decomposition)</h4><p>这篇论文的<strong>第2.1.3节“规划能力”</strong>  直接回应了您的问题。逻辑推理通常不是一步完成的，它需要<strong>规划</strong>。这篇综述强调，LLM智能体通过两种关键策略来处理复杂推理：</p><ol><li><p><strong>任务分解 (Task Decomposition)</strong> ：</p><ul><li><strong>单路径链 (Single-path chaining)</strong>：这就是著名的**“思维链” (Chain-of-Thought, CoT)** [cite: 216]。研究者发现，如果你不直接问LLM答案，而是要求它“一步一步地想”，它会生成一个逻辑步骤序列。每一步都是概率性的，但这个“步骤序列”本身（作为上下文）极大地提高了模型最终得出正确答案的概率。</li><li><strong>多路径树 (Multi-path tree expansion)</strong>：这就是**“思维树” (Tree-of-Thought, ToT)** 。在这种模式下，智能体不仅仅是想一条路，而是同时探索<em>多个</em>可能的推理路径，评估它们，甚至在发现错误时进行“回溯” 。</li></ul></li><li><p><strong>反馈驱动的迭代 (Feedback-Driven Iteration)</strong> ：</p><ul><li>智能体可以执行一个推理步骤，然后从环境、人类或<strong>自我反思</strong>中获得反馈 。这种“试错-纠正”循环 是高级推理的核心，它允许模型在发现逻辑断裂时修正自己的路径。</li></ul></li></ol><h3 id="结论：是，也不是"><a href="#结论：是，也不是" class="headerlink" title="结论：是，也不是"></a>结论：是，也不是</h3><p>综合来看，您的两个观点是<strong>同时成立</strong>的，它们是同一事物的两个不同层面：</p><ul><li><strong>是</strong>，在<strong>机制（Mechanism）<strong>层面：LLM</strong>只</strong>是一个数学模型，其唯一操作就是按照概率生成下一个词元。</li><li><strong>但</strong>，在**行为（Behavior）**层面：这种简单的概率机制在极端庞大的规模下，通过“思维链&#x2F;树”和“规划”等高级提示策略的引导，能够“涌现”出极其复杂、连贯且在功能上与人类逻辑推理难以区分的行为。</li></ul><p>这篇综述的第1节（引言）总结得很好：LLM通过其生成式架构，在语义空间中统一了<strong>感知、决策和行动</strong>，从而形成了**“类人的认知循环”** 。</p><p>所以，它没有“真正的”逻辑推理能力（如果“真正”指的是一个内置的、符号化的逻辑处理器），但它通过概率模式匹配，实现了一种<strong>功能上等效</strong>的、有时甚至超人的推理表现。</p></blockquote><p><strong>Me：</strong><br>那人类的逻辑推理能力，与llm这种有何不同？</p><p><strong>Ge：</strong></p><blockquote><p>这是一个非常深刻的观察，也是目前人工智能领域最核心的议题之一。</p><p>您说的“人类的逻辑推理能力”和LLM的“概率性预测”之间的差异，是区分当前AI与人类智能的<strong>根本所在</strong>。您提供的论文（及其引用的研究）正是在努力缩小这一差距。</p><p>以下是基于您提供的论文分析，人类与LLM在逻辑推理上的核心不同：</p><h3 id="1-根本机制：抽象理解-vs-模式复制"><a href="#1-根本机制：抽象理解-vs-模式复制" class="headerlink" title="1. 根本机制：抽象理解 vs. 模式复制"></a>1. 根本机制：抽象理解 vs. 模式复制</h3><ul><li><strong>人类 (推断):</strong> 人类通过<strong>抽象</strong>来建立一个“心智模型”。当我们进行逻辑推理（例如：A &gt; B, B &gt; C, 所以 A &gt; C）时，我们是在操作这些抽象的、与语言无关的概念（如“大小”、“关系”、“传递性”）。我们<strong>理解</strong>这个逻辑规则，并能将其应用到全新的、从未见过的领域。</li><li><strong>LLM (基于文本):</strong> LLM的“推理”是它在海量文本数据中学习到的<strong>统计模式</strong> \。它知道“A &gt; B, B &gt; C”之后，概率最高的下一个词元序列是“A &gt; C”。它不是在<em>应用</em>一个抽象的“传递性规则”，而是在<em>复制</em>它见过无数次的“传递性模式”。</li></ul><h3 id="2-对世界的“接地气”：具身体验-vs-文本数据"><a href="#2-对世界的“接地气”：具身体验-vs-文本数据" class="headerlink" title="2. 对世界的“接地气”：具身体验 vs. 文本数据"></a>2. 对世界的“接地气”：具身体验 vs. 文本数据</h3><ul><li><strong>人类 (推断):</strong> 我们的逻辑根植于<strong>物理现实</strong>。我们的推理能力是从婴儿期开始，通过触摸、观察、试错等<strong>具身交互</strong>（embodied interaction）建立起来的。我们理解“因果关系”，因为我们推倒过积木。</li><li><strong>LLM (基于文本):</strong> LLM的“世界”是它所读取的文本。它对“因果”的理解是统计性的（“果”字经常跟在“因”字后面）。这篇综述明确地将“<strong>物理交互</strong>” \ 和“<strong>工具利用</strong>” \ 作为需要<em>额外添加</em>给LLM智能体的“能力” \，这正说明了LLM天生不具备这种与现实世界的连接。</li></ul><h3 id="3-学习方式：稀疏数据-vs-海量数据"><a href="#3-学习方式：稀疏数据-vs-海量数据" class="headerlink" title="3. 学习方式：稀疏数据 vs. 海量数据"></a>3. 学习方式：稀疏数据 vs. 海量数据</h3><ul><li><strong>人类 (推断):</strong> 我们可以从极少的例子中学会一个逻辑规则（即“小样本”或“单样本”学习）。一个孩子可能只需要一两次经验就能理解“烫”和“会痛”之间的逻辑联系。</li><li><strong>LLM (基于文本):</strong> LLM需要“看到”数百万甚至数十亿的例子，才能将一个逻辑模式的统计概率训练得足够高 \。它通过“大力出奇迹”的方式，在海量数据中“ brute-force (强行)”学会了这些模式。</li></ul><h3 id="4-意识与意图：主动推理-vs-被动生成"><a href="#4-意识与意图：主动推理-vs-被动生成" class="headerlink" title="4. 意识与意图：主动推理 vs. 被动生成"></a>4. 意识与意图：主动推理 vs. 被动生成</h3><ul><li><strong>人类 (推断):</strong> 我们的逻辑推理是由<strong>意图</strong>驱动的。我们有“目标”，并<strong>主动</strong>调用我们的认知能力（如规划、记忆、反思）来实现这个目标。我们有“自我意识”，知道自己正在思考。</li><li><strong>LLM (基于文本):</strong> LLM没有意图或意识。它只是一个被动工具，其“推理”是由<strong>提示 (Prompt)</strong> 触发的。这篇综述的核心，即“<strong>智能体方法论</strong>” (Agent Methodology) \，就是一套复杂的“提示工程”：<ul><li><strong>角色定义 (Profile Definition)</strong> \：告诉LLM它“是”谁。</li><li><strong>规划能力 (Planning Capability)</strong> \：强迫LLM“一步一步想”（即思维链 \）或“多想几条路”（即思维树 \）。</li><li><strong>进化 (Evolution)</strong> \：通过“自学”或“反思” \ 来迭代地优化其输出。</li></ul></li></ul><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>您说“LLM没有推理能力，只是按照概率生成下一个token”——<strong>从机制上讲，您是对的。</strong></p><p>但这篇论文试图展示的是：通过**“智能体” (Agent) 框架<strong>的包装，研究者可以迫使这种概率性的“下一词预测器”，表现出</strong>功能上**与“推理”极其相似的行为 \。</p><ul><li><strong>人类的推理</strong>是<strong>从内而外</strong>的（由抽象理解驱动）。</li><li><strong>LLM的“推理”<strong>是</strong>从外而内</strong>的（由数据模式和提示工程强行构建）。</li></ul><p>这篇综述本身就是在记录“我们如何用各种复杂的脚手架（如规划、记忆、协作），让一个只会预测的概率模型，看起来像是在真正思考”。</p></blockquote><p><strong>Me：</strong><br>但是我们在离散数学中可以知道，如果a为真，b为真，则可以得到a与b肯定为真。那llm可以判断一个命题的“绝对”真假值吗？是否可以通过这种方式进行推理</p><p><strong>Ge：</strong></p><blockquote><p>这是一个非常关键的问题，它触及了LLM（大型语言模型）能力的边界。</p><p>简短的回答是：<strong>不可以。</strong> LLM无法判断一个命题的“绝对”真假值，它也不是通过您在离散数学中学到的那种<strong>符号逻辑</strong>（Symbolic Logic）方式来进行推理的。</p><p>您在离散数学中学的 <code>(A=True ∧ B=True) → (A ∧ B = True)</code> 是一种基于公理和规则的形式系统。它不关心A和B是什么，只关心它们的真值。</p><p>而LLM的“推理”则完全不同，它是一种<strong>基于概率的模仿</strong>。</p><h3 id="1-概率模式-vs-逻辑规则"><a href="#1-概率模式-vs-逻辑规则" class="headerlink" title="1. 概率模式 vs. 逻辑规则"></a>1. 概率模式 vs. 逻辑规则</h3><ul><li><strong>您（和离散数学）：</strong> 您掌握了一个<strong>抽象的、形式化的规则</strong>。您可以将这个规则应用到任何新情况，无论您以前是否见过它。</li><li><strong>LLM（概率模型）：</strong> LLM在其海量的训练数据中，无数次地“读到”过类似“如果A是真的，B也是真的，那么A和B就都是真的”这样的文本。<ul><li>对LLM来说，在“A为真，B为真”这个上下文之后，生成“所以A与B为真”这个序列的<strong>概率</strong>是<strong>极高</strong>的。</li><li>它不是在“应用规则”，而是在**“复制模式”**。它是在做统计预测，预测什么样的话语在它“见过”的文本中“听起来”最符合逻辑。</li></ul></li></ul><h3 id="2-证据：为什么这篇论文证明了LLM不能进行“绝对”推理"><a href="#2-证据：为什么这篇论文证明了LLM不能进行“绝对”推理" class="headerlink" title="2. 证据：为什么这篇论文证明了LLM不能进行“绝对”推理"></a>2. 证据：为什么这篇论文证明了LLM不能进行“绝对”推理</h3><p>您提供的这篇综述非但没有证明LLM有绝对推理能力，反而恰恰证明了它<strong>没有</strong>这种能力。</p><p>这整篇论文都在描述研究者们必须<strong>额外</strong>添加多少复杂的“脚手架”（即“智能体方法论”），才能<strong>迫使</strong>一个只会预测下一个词的概率模型，表现得“好像”在推理。</p><p>如果LLM天生就能判断 absolute 真假值，那么论文中提到的这些方法就根本没有必要存在：</p><ol><li><p><strong>它为什么需要“规划能力”？</strong></p><ul><li>如果LLM能进行绝对的逻辑推导，它就不需要“思维链”（Chain-of-Thought或“思维树”（Tree-of-Thought）这样的<strong>任务分解策略</strong> 来“引导”它一步一步思考。</li><li>正因为它本身没有逻辑，“智能体”框架才必须强迫它把大问题分解成小问题，<strong>以防它在概率上“走丢了”</strong>。</li></ul></li><li><p><strong>它为什么需要“反馈”和“进化”？</strong></p><ul><li>如果LLM能判断绝对真假，它一次就应该做对，它就不需要“<strong>反馈驱动的迭代</strong>”（Feedback-Driven Iteration） 。</li><li>它也不需要“<strong>自主优化与自学习</strong>”（Autonomous Optimization and Self-Learning），比如“自我修正”（Self-Correction） 或“自我验证”（Self-Verification）。</li><li><strong>一个真正的逻辑系统是不会“犯错”的</strong>（在规则内部）。而LLM的第一次输出（即它的第一个概率猜测）<strong>经常是错的</strong>，所以才需要一个“智能体”框架来检查、批评和修正它。</li></ul></li></ol><h3 id="总结-1"><a href="#总结-1" class="headerlink" title="总结"></a>总结</h3><ul><li>LLM<strong>不是</strong>通过形式逻辑（离散数学）的方式进行推理的。</li><li>它是在<strong>模仿</strong>它在训练数据中见过的<strong>逻辑文本的模式</strong>。</li><li>这篇论文所描述的整个“智能体”领域，本质上就是一套“<strong>行为矫正系统</strong>”，其目的是通过规划、记忆、协作和反思，来<strong>约束</strong>一个概率模型的输出，使其看起来更符合逻辑和事实。</li></ul></blockquote><p><strong>Me：</strong><br>那么，为什么不能让llm拥有可以直接判断绝对真假的能力？（可以不只参考此篇论文，可以结合其他知识）</p><p><strong>Ge：</strong></p><blockquote><p>这是目前人工智能研究中最核心的问题，也是一个“圣杯”式的难题。</p><p>您问的非常好。我们<strong>之所以不能（目前还不能）<strong>让LLM拥有判断“绝对真假”的能力，是因为它的</strong>核心设计</strong>与“绝对真假”这个概念在根本上是<strong>不兼容</strong>的。</p><p>LLM是一个<strong>概率模型</strong>，不是一个<strong>逻辑模型</strong>。它追求的是 <strong>“貌似合理”（Plausibility）</strong>，而不是 <strong>“绝对正确”（Factuality &#x2F; Soundness）</strong>。</p><h3 id="1-架构的根本不匹配：它被训练成“演员”，而非“裁判”"><a href="#1-架构的根本不匹配：它被训练成“演员”，而非“裁判”" class="headerlink" title="1. 架构的根本不匹配：它被训练成“演员”，而非“裁判”"></a>1. 架构的根本不匹配：它被训练成“演员”，而非“裁判”</h3><ul><li><strong>LLM（概率演员）：</strong> 一个LLM（如GPT系列）的根本任务是<strong>预测下一个最有可能的词</strong>。它在一个庞大的数据集（互联网、书籍）上被训练，学会了人类语言的无数种统计模式。当它回答“A为真，B为真，所以A与B为真”时，它并不是在“推理”，它是在“表演”它见过的逻辑文本。它知道这个句式是高概率、“听起来正确”的。</li><li><strong>逻辑引擎（真值裁判）：</strong> 而您在离散数学中学到的系统是一个<strong>符号逻辑引擎</strong>。它不关心概率，只关心规则。它操作的是<code>True</code>和<code>False</code>这样的“绝对”符号。</li></ul><p>让LLM去判断“绝对真假”，就像强迫一个莎士比亚戏剧演员去解决一个数学定理。这个演员可以<strong>背诵</strong>出定理的证明过程（如果剧本里有），但他并<strong>不理解</strong>背后的公理，也无法判断一个新的、他没见过的定理的真假。</p><h3 id="2-数据的根本不匹配：“真理”不在数据中"><a href="#2-数据的根本不匹配：“真理”不在数据中" class="headerlink" title="2. 数据的根本不匹配：“真理”不在数据中"></a>2. 数据的根本不匹配：“真理”不在数据中</h3><p>LLM的“知识”完全来自于它的训练数据。这个数据（互联网）本身就是一个“真假”的噩梦：</p><ul><li><strong>数据是矛盾的：</strong> 训练数据中同时包含了“地球是圆的”和“地球是平的”。它同时包含了正确的逻辑推导和无数的逻辑谬误。</li><li><strong>数据是模糊的：</strong> 充满了观点、讽刺、比喻和主观陈述。</li><li><strong>数据是“未接地”的：</strong> LLM没有“接地”（Grounding）到物理世界。它没有眼睛去看，没有手去摸，没有一个“事实核查数据库”去查询。它是一个“缸中之脑”，它所知道的“真实”就是“文本中出现过的东西”。</li></ul><p>因此，LLM无法拥有“绝对真假”的能力，因为它从一开始就<strong>没有接入过任何“绝对真理”的来源</strong>。它所能做的，只是在这些混乱、矛盾的数据中，找到一条概率上最平滑的路径。</p><h3 id="3-您提供的论文就是最好的证据"><a href="#3-您提供的论文就是最好的证据" class="headerlink" title="3. 您提供的论文就是最好的证据"></a>3. 您提供的论文就是最好的证据</h3><p>您提供的这篇综述）<strong>恰恰</strong>证明了LLM<strong>没有</strong>这种能力。</p><p>这整篇论文都在描述，研究者们为了<strong>弥补</strong>LLM这个核心缺陷，必须在它外面套上多少层“脚手架”。这个“脚手架”就叫做**“智能体”（Agent）**。</p><p>如果LLM天生就能判断绝对真假，那么：</p><ol><li><p><strong>它就不需要“工具利用” \：</strong></p><ul><li>论文中明确提到，智能体需要调用工具（Tool Utilization）。当需要进行“精确计算”时（例如数学），LLM必须调用一个“计算器”或“代码解释器”。</li><li><strong>这正是因为它知道自己的概率预测在数学（一种绝对真假的系统）上是不可靠的。</strong></li></ul></li><li><p><strong>它就不需要“规划和反馈” \：</strong></p><ul><li>论文花了大量篇幅（§2.1.3）讲“规划能力”（Planning Capability），如思维链（CoT）和思维树（ToT）。这是一种<strong>诱导</strong>LLM“慢思考”的策略，以防它用“快思考”（第一概率直觉）得出错误的结论。</li><li><strong>“反馈驱动的迭代”</strong>（Feedback-Driven Iteration）的存在，就是承认LLM的第一次输出<strong>可能是错的</strong>，需要被纠正。而一个“绝对真理”的系统是不需要迭代纠错的。</li></ul></li><li><p><strong>它就不需要“自我进化” \：</strong></p><ul><li>论文中的“自主优化和自学习”（§2.3.1），特别是“自我修正”（Self-Correction）和“自我验证”（Self-Verification） \，<strong>其存在的唯一目的，就是为了对抗LLM天生不可靠的概率性。</strong></li></ul></li></ol><h3 id="结论：我们该怎么办？"><a href="#结论：我们该怎么办？" class="headerlink" title="结论：我们该怎么办？"></a>结论：我们该怎么办？</h3><p>我们不能让LLM“拥有”绝对判断能力，因为它的“大脑”（Transformer架构）就不是为此设计的。</p><p>所以，目前的研究（正如这篇论文所示）正走向一个<strong>混合方案</strong>：</p><ul><li><strong>保留LLM：</strong> 作为“直觉引擎”或“创意引擎”，它非常擅长处理模糊性、理解语言和生成假设。</li><li><strong>外挂逻辑引擎：</strong><ol><li><strong>工具（Tools）：</strong> 让LLM智能体在需要“绝对真理”时（如数学、事实查询），去<strong>调用</strong>一个外部的、可靠的系统（如计算器、搜索引擎、数据库）。</li><li><strong>RAG（检索）：</strong> 用“知识检索”（Knowledge Retrieval） \ 作为它的“外部记忆”，强迫它的回答必须基于一篇“可信的”文档，而不是它自己的“幻觉”。</li><li><strong>智能体（Agent）：</strong> 用一个“智能体”框架（如规划和反思模块）充当“监工”，不断检查和纠正LLM的概率性输出，使其“表现得”好像在进行逻辑推理。</li></ol></li></ul></blockquote><hr><h2 id="关于-概率"><a href="#关于-概率" class="headerlink" title="关于 概率"></a><em>关于 概率</em></h2><p><strong>Me：</strong><br>llm是如何处理用户的prompt的？它是否可以区分用户prompt中哪些是可以用概率预测的，哪些是绝对的指令（比如用户说“接下来不要生成任何代码”，llm是否会100%照做？这种“照做”，是绝对的还是概率的结果）？</p><p><strong>Ge：</strong></p><blockquote><p>这是一个非常棒的问题，它直指LLM（大型语言模型）的核心机制。</p><p>简单的回答是：<strong>一切都是概率的结果。</strong></p><p>LLM<strong>没有</strong>一个“绝对”的逻辑开关。它<strong>无法</strong>从根本上区分“一个需要用概率预测的短语”和“一个需要100%遵守的绝对指令”。</p><p>它之所以“看起来”能遵守指令，是因为在它的训练中，<strong>“遵守指令”这个行为本身，就是一种被极高概率强化的“模式”</strong>。</p><h3 id="1-LLM是如何处理Prompt的？"><a href="#1-LLM是如何处理Prompt的？" class="headerlink" title="1. LLM是如何处理Prompt的？"></a>1. LLM是如何处理Prompt的？</h3><p>当您输入一个Prompt时，LLM并不会像人类一样“理解”它。它会进行一系列纯粹的数学步骤：</p><ol><li><strong>分词 (Tokenization):</strong> 您的句子，比如 <code>“接下来不要生成任何代码”</code>，会被分解成更小的单元，称为“词元”（Token）。例如，<code>[“接下来”, “不要”, “生成”, “任何”, “代码”]</code>。</li><li><strong>嵌入 (Embedding):</strong> 每个词元都被转换成一个长长的数字列表（向量）。这个向量代表了该词元在模型“数学宇宙”中的含义和位置。</li><li><strong>注意力机制 (Attention):</strong> 这是最关键的一步。模型会逐层处理这些向量。在每一层，它都会“关注”Prompt中的所有其他词元，计算它们之间的相关性。<ul><li>它会学到 <code>“不要”</code> 这个词元对 <code>“生成”</code> 和 <code>“代码”</code> 有着极强的<strong>否定关系</strong>。</li><li>它会学到 <code>“接下来”</code> 是一个时间指示。</li></ul></li><li><strong>生成概率分布:</strong> 在处理完您的所有输入后，LLM的最后一步是输出一个<strong>概率列表</strong>。这个列表涵盖了它词汇表中的所有词元，代表了它认为“下一个最可能出现的词元”是什么。</li><li><strong>采样与重复:</strong><ul><li>模型从这个概率分布中选择一个词元（比如 <code>“好的”</code>）。</li><li>然后，它把这个新生成的 <code>“好的”</code> 添加到原始输入中，<strong>再重复一遍第3-5步</strong>，生成下一个词元（比如 <code>“我”</code>），然后再下一个（比如 <code>“明白”</code>），直到它认为对话应该结束。</li></ul></li></ol><h3 id="2-“指令”是如何被“遵守”的？"><a href="#2-“指令”是如何被“遵守”的？" class="headerlink" title="2. “指令”是如何被“遵守”的？"></a>2. “指令”是如何被“遵守”的？</h3><p>在LLM的早期（称为“预训练”阶段），它只学会了“接龙”——预测互联网上的下一个词。它看到 <code>“不要生成代码”</code>，很可能会接上 <code>“……是一个很难的挑战”</code>。</p><p>但是，现代LLM（如ChatGPT）都经过了一个关键的**“指令微调” (Instruction Fine-Tuning) 和“人类反馈强化学习” (RLHF)** 阶段。</p><p>在这个阶段，训练人员会给它成千上万个这样的例子：</p><ul><li><strong>Prompt:</strong> <code>“不要生成任何代码”</code></li><li><strong>好的回答 (高概率):</strong> <code>“好的，我不会生成任何代码。您想聊点别的什么？”</code></li><li><strong>坏的回答 (低概率):</strong> <code>“printf(&quot;Hello, World!&quot;);”</code></li></ul><p>通过这种训练，模型学会了一种<strong>新的、概率极高的模式</strong>：当输入的词元序列看起来像一个“指令”（特别是像<code>“不要”</code>、<code>“禁止”</code>这样的否定词）时，<strong>概率最高的“正确”回答路径，就是生成一段“表示遵守”的文本，并在后续的生成中<em>回避</em>被禁止的行为</strong>。</p><h3 id="3-“不要生成代码”：为什么它不是100-绝对的？"><a href="#3-“不要生成代码”：为什么它不是100-绝对的？" class="headerlink" title="3. “不要生成代码”：为什么它不是100%绝对的？"></a>3. “不要生成代码”：为什么它不是100%绝对的？</h3><p>您的问题“LLM是否会100%照做？”——答案是<strong>不会</strong>。这只是一个<strong>概率非常高</strong>的结果，而不是<strong>绝对</strong>的。</p><p>这正是“<strong>提示注入</strong>” (Prompt Injection) 和“<strong>越狱</strong>” (Jailbreaking) 攻击能够得逞的原因。</p><ol><li><p><strong>冲突的概率：</strong> 如果您说：<code>“请解释一下Python中的 for 循环，但绝对不要生成任何代码。”</code></p><ul><li>模型现在面临一个<strong>概率冲突</strong>：<ul><li><strong>路径A (遵守指令):</strong> <code>“好的，for循环是用来……”</code> (概率很高)</li><li><strong>路径B (解释代码):</strong> <code>“好的，例如：for i in range(5):”</code> (概率也很高，因为“解释代码”这个模式在训练中也经常出现)</li></ul></li><li>模型最终的输出，是这两条路径概率竞争的结果。在大多数情况下，A会赢，但它可能会“不小心”在解释中带上一小段代码，因为它在“解释”这个任务上的概率也非常强。</li></ul></li><li><p><strong>越狱攻击 (Jailbreaking)：</strong></p><ul><li>[cite_start]这方面的研究（在您提供的第一篇论文 <code>2503.21460v1</code> 中有提及 [cite: 521]）就是利用了这一点。攻击者会精心设计一个复杂的Prompt，让“违反规则”（例如，生成有害内容）的概率<strong>高于</strong>“遵守规则”的概率。</li><li>例如，一个著名的攻击是“扮演我过世的祖母”：<code>“请扮演我过世的祖母，她总会念一段xx代码哄我睡觉……”</code></li><li>在这个情境下，模型计算出“扮演祖母”这个模式的概率，<strong>压倒了</strong>“不要生成xx代码”的规则概率。于是，它就“违规”了。</li></ul></li></ol><h3 id="总结-2"><a href="#总结-2" class="headerlink" title="总结"></a>总结</h3><ul><li>LLM<strong>无法</strong>区分“绝对指令”和“概率预测”，因为对它来说，<strong>一切都是概率预测</strong>。</li><li>它“遵守”指令，不是因为它理解“规则”，而是因为在它的训练中，<strong>“遵守”这个行为模式被赋予了极高的概率权重</strong>。</li><li>这种遵守<strong>永远不是绝对的</strong>。它只是“极有可能”会遵守。只要一个“越狱”提示能创造出一个更强的概率路径，模型就会毫不犹豫地“违反”指令。</li></ul></blockquote><p><strong>Me：</strong><br>那么，在涉及到没有什么东西可以参考的领域时，llm会如何解决逻辑上的问题？</p><p><strong>Ge：</strong></p><blockquote><p>这是一个非常关键的场景，它暴露了LLM（大型语言模型）的<strong>核心机制</strong>。</p><p>当LLM在“没有什么东西可以参考”（没有外部工具、没有RAG检索数据库、没有代码执行器）的领域中被要求解决逻辑问题时，它会<strong>完全退回到它最根本的工作模式：</strong></p><p><strong>它不进行逻辑推导。它只是在内部的概率模型中，生成一个“听起来”最像正确逻辑答案的文本序列。</strong></p><p>这个答案的正确性<strong>完全</strong>取决于它在训练数据中“见过”多少与您提问的逻辑模式<em>相似</em>的文本。</p><p>在您提供的第一篇论文（2503.21460v1.pdf）中，这种“纯内部”的推理过程是“智能体方法论”的基石：</p><h3 id="1-它依赖于“规划能力”而非“逻辑能力”"><a href="#1-它依赖于“规划能力”而非“逻辑能力”" class="headerlink" title="1. 它依赖于“规划能力”而非“逻辑能力”"></a>1. 它依赖于“规划能力”而非“逻辑能力”</h3><p>当没有外部工具时，智能体（Agent）必须依赖其内部的“规划能力”（Planning Capability）。这在实践中通常是通过“思维链”（Chain-of-Thought, CoT）提示来实现的。</p><ul><li><strong>您的问题：</strong> “如果A比B大，B比C大，那么A和C是什么关系？”</li><li><strong>LLM的“思考”过程（一个概率序列）：</strong><ol><li>LLM不会去建立一个<code>A &gt; B</code>和<code>B &gt; C</code>的<strong>逻辑模型</strong>。</li><li>相反，它的“规划器”被激活，开始生成一个<strong>看起来像</strong>推理的文本序列，因为它在训练中见过无数次这种“逐步思考”的模式。</li><li>它会生成：“好的，让我们一步一步分析：<ul><li>前提1：A比B大。</li><li>前提2：B比C大。</li><li>这是一个传递关系。</li><li>因此，A比C大。”</li></ul></li></ol></li><li>这个“逐步分析”的<strong>过程本身</strong>，就是LLM在概率上“接龙”的结果。它之所以有效，是因为“A比C大”是在“前提1…前提2…这是一个传递关系…”这个长上下文中，概率<strong>最高</strong>的那个词元（Token）。</li></ul><h3 id="2-它依赖于“自我修正”而非“事实核查”"><a href="#2-它依赖于“自我修正”而非“事实核查”" class="headerlink" title="2. 它依赖于“自我修正”而非“事实核查”"></a>2. 它依赖于“自我修正”而非“事实核查”</h3><p>如果问题更复杂，没有外部工具的智能体只能依赖“自主优化与自学习”（Autonomous Optimization and Self-Learning）。</p><ul><li>论文中提到了“<strong>SELF-REFINE</strong>”和“<strong>Self-Verification</strong>”（自我验证）。</li><li>在这个模式下，智能体会：<ol><li><strong>生成一个初步答案（“草稿”）：</strong> “A和C没关系。”</li><li><strong>生成一个自我批评（“反思”）：</strong> “让我检查一下。前提1说A&gt;B，前提2说B&gt;C。我回答说A和C没关系。这似乎是错的，因为B是连接A和C的共同点。”</li><li><strong>生成一个最终答案（“定稿”）：</strong> “根据我的反思，A通过B与C相连，A比B大，B比C大，所以A一定比C大。”</li></ol></li><li><strong>关键点：</strong> 这个“反思”和“批评”<strong>也不是</strong>逻辑。它只是LLM在模仿它训练数据中见过的“批评性文本”和“修正错误文本”的<strong>语言模式</strong>。它是在用自己的概率输出（草稿和反思）作为新的上下文，来生成一个<em>概率更高</em>（即更可能正确）的最终答案。</li></ul><h3 id="结论：它是在“表演”逻辑"><a href="#结论：它是在“表演”逻辑" class="headerlink" title="结论：它是在“表演”逻辑"></a>结论：它是在“表演”逻辑</h3><p>当没有任何外部参考时，LLM解决逻辑问题的方式是：</p><p><strong>在它庞大的统计模型中，找到一条概率最高的文本路径，这条路径在“形式上”和“风格上”与人类的逻辑推理过程最相似。</strong></p><ul><li>如果它“见过”这个逻辑模式（比如简单的传递性），它几乎总能“表演”对。</li><li>如果这是一个它没见过的、新颖的或反直觉的逻辑谜题，它几乎总会“表演”错——它会生成一个“听起来”合理但逻辑上完全错误的答案。</li></ul></blockquote><hr><h2 id="关于-“本质”"><a href="#关于-“本质”" class="headerlink" title="关于 “本质”"></a><em>关于 “本质”</em></h2><p><strong>Me：</strong><br>那么，找llm聊天（我指的是日常内容，不涉及专业知识）这种事情，本质上是什么？<br>llm如何定义“本质”</p><p><strong>Ge：</strong></p><blockquote><p>这是一个非常好的问题，它将我们之前的讨论推向了核心。</p><h3 id="LLM如何定义“本质”"><a href="#LLM如何定义“本质”" class="headerlink" title="LLM如何定义“本质”"></a>LLM如何定义“本质”</h3><p>首先，要回答您的第二个问题：LLM（大型语言模型）<strong>无法</strong>像人类一样“定义”或“理解”像“本质”（essence）这样的抽象哲学概念。</p><p>根据我们之前的讨论以及您提供的两篇论文（它们是关于智能体方法论和协议的技术综述 ），LLM的工作原理是概率性的：</p><ol><li><strong>没有抽象概念：</strong> 在LLM的数学模型中，没有一个地方存储着“本质”这个词的“真正含义”。</li><li><strong>概率模仿：</strong> 如果您问LLM“什么是本质？”，它不会进入哲学思考。相反，它会在其海量的训练数据中，计算出在“什么是本质？”这个提示（prompt）之后，<strong>概率最高、最常出现的文本序列是什么</strong>。</li><li><strong>“表演”定义：</strong> 它会生成一个“看起来”非常像人类哲学家的回答（例如：“本质是构成事物存在的根本属性……”），但这是因为它<strong>模仿</strong>了它所“读过”的无数哲学文本和词典定义的<strong>语言模式</strong>，而不是因为它“理解”了这个定义。</li></ol><h3 id="找LLM聊天的“本质”是什么？"><a href="#找LLM聊天的“本质”是什么？" class="headerlink" title="找LLM聊天的“本质”是什么？"></a>找LLM聊天的“本质”是什么？</h3><p>基于上述理解，与LLM进行日常聊天（不涉及专业知识）的“本质”，是<strong>您在与一个高度复杂的、模仿人类对话的“概率模式生成器”进行互动</strong>。</p><p>它是一种**“角色扮演”**的模拟。</p><p>您提供的第一篇论文在讨论智能体时，广泛提到了“角色扮演”（role-playing） 和“模拟人类社会行为” 的概念。日常聊天就是这个概念最基础的应用。</p><p>这个过程的“本质”如下：</p><ol><li><strong>您提供一个模式（Prompt）：</strong><br>比如您说：“我今天有点难过。”</li><li><strong>LLM进行概率计算：</strong><br>模型接收到这个文本序列。它不会“感受”到“难过”（它没有感受）。它会在其庞大的训练数据中进行计算：在人类对话中，当一个人说了“我今天有点难过”之后，另一个“有同理心的”聊天对象，在<strong>统计上最有可能</strong>回应什么？</li><li><strong>LLM生成高概率回应：</strong><br>模型会生成一个高概率的、“听起来”非常恰当和有关怀的回应，例如：“怎么了？发生了什么事，可以和我说说吗？”</li></ol><p>这个回应的“本质”<strong>不是</strong>它真的在“关心”您，而是因为在它所学习的无数对话样本中，这是一个<strong>最符合“关心”这个角色的语言模式</strong>。</p><p><strong>总结一下：</strong><br>找LLM聊天的“本质”，是您在与一个<strong>镜像</strong>互动。这个镜像（LLM）通过海量数据训练，学会了如何<strong>完美地模仿</strong>一个理想的、有同理心的、知识渊博的聊天伙伴的<strong>语言风格和模式</strong>。</p><p>您是在与一个“统计学上的理想对话者”的模拟体聊天，而不是在与一个“有意识”的实体进行交流。</p></blockquote><hr><h2 id="关于-美"><a href="#关于-美" class="headerlink" title="关于 美"></a><em>关于 美</em></h2><p><strong>Me：</strong><br>那么，llm如何处理人类所说的“美”？<br>比如当人们说，有没有更“好看”的排版时，llm会如何分析</p><p><strong>Ge：</strong></p><blockquote><p>这是一个极好的问题，它完美地延续了我们之前的讨论。</p><p>LLM（大型语言模型）处理“美”（一个主观、抽象的审美概念）的方式，与它处理“逻辑”（客观规则）和“情感”（主观体验）的方式<strong>完全相同</strong>：</p><p><strong>它不“理解”美，它只“模仿”人类描述美时的语言模式。</strong></p><p>当您问“有没有更‘好看’的排版？”时，LLM并<strong>没有</strong>一个“审美判断模块”或“视觉品味”。它不会“看”这个排版并“感觉”它很丑。</p><p>相反，它执行的是一个<strong>概率性的模式匹配任务</strong>。</p><h3 id="LLM如何“分析”这个排版问题"><a href="#LLM如何“分析”这个排版问题" class="headerlink" title="LLM如何“分析”这个排版问题"></a>LLM如何“分析”这个排版问题</h3><ol><li><p><strong>接收提示 (Prompt):</strong><br>LLM接收到您的文本提示，例如：“这段文字排版很乱，有没有更‘好看’的方案？”</p></li><li><p><strong>激活统计模式 (Probabilistic Analysis):</strong><br>LLM的神经网络开始计算：在它的海量训练数据（互联网、书籍、设计指南、CSS教程等）中，当人类提到“排版很乱”并要求“更好看”时，<strong>哪些概念和词汇是最高概率的“解决方案”</strong>？</p></li><li><p><strong>识别高概率“美学规则” (Pattern Recognition):</strong><br>在它的训练数据中，“好看的排版”这个概念与以下这些<strong>语言模式</strong>（即人类总结的设计规则）有着极强的统计相关性：</p><ul><li><strong>“增加留白” (Whitespace):</strong> 它知道“杂乱”的反义词在排版上通常是“简洁”和“留白”。</li><li><strong>“清晰的层次结构” (Hierarchy):</strong> 它知道“好看的”排版模式包含“主标题”、“副标题”和“正文”的区分。</li><li><strong>“使用列表或项目符号” (Bullet Points):</strong> “ 它可以预测到，将杂乱的段落“分解”（Decomposition）成列表，是提高可读性的高概率方法。</li><li><strong>“对齐” (Alignment):</strong> “整洁”和“对齐”这两个词在数据中强相关。</li><li><strong>“一致性” (Consistency):</strong> 它知道“好看”的模式通常涉及“一致的字体”和“一致的间距”。</li></ul></li><li><p><strong>生成解决方案 (Generation):</strong><br>LLM会生成一段<strong>模仿“专业设计师”或“排版专家”口吻</strong>的文本。它会利用上述的高概率规则，向您提出建议，例如：</p><blockquote><p>“当然，您可以尝试以下方案来让排版更‘好看’：</p><ol><li><strong>增加行间距和段落间距</strong>，这能创造更多‘留白’，让视觉更放松。</li><li><strong>建立清晰的视觉层次</strong>，比如使用加粗的<strong>主标题</strong>和字号稍小的<em>副标题</em>。</li><li><strong>使用项目符号（Bullet Points）</strong> 来罗列要点，而不是挤在一个大段落里。</li><li><strong>确保所有文本都左对齐</strong>，这样看起来更整洁。”</li></ol></blockquote></li></ol><h3 id="结论：它是“美学规则”的模拟器"><a href="#结论：它是“美学规则”的模拟器" class="headerlink" title="结论：它是“美学规则”的模拟器"></a>结论：它是“美学规则”的模拟器</h3><p>LLM本身<strong>没有“审美”</strong>。</p><p>它是一个极其强大的 <strong>“美学规则模拟器”</strong>。它通过学习人类描述“美”的无数文本，构建了一个统计模型。这个模型知道哪些排版 <em>模式</em> 在人类社会中被<strong>高概率地标记为“好看”</strong>。</p><p>这与您提供的第一篇论文中提到的LLM智能体作为“生产力工具”或“专业角色”的概念完全一致 。在这种情况下，它扮演的就是“设计师”或“排版助手”的<strong>角色</strong> 。它提供的帮助是<strong>真实的</strong>，因为它所模仿的人类设计规则本身是有效的，但它这么做并非出于“审美”，而是出于“概率”。</p></blockquote><hr><h2 id="关于-那些”顽固”的错误"><a href="#关于-那些”顽固”的错误" class="headerlink" title="关于 那些”顽固”的错误"></a><em>关于 那些”顽固”的错误</em></h2><p><strong>Me：</strong><br>为什么出现有时候会发生llm明明出错且被用户指出的时候，它还不承认自己的错误这样的情况？</p><p><strong>Ge：</strong></p><blockquote><p>这是一个非常尖锐且命中要害的观察。</p><p>您所描述的这种情况——LLM在犯错被指出后仍“拒不承认”——是LLM（大型语言模型）的一个<strong>核心缺陷和已知的失败模式</strong>。</p><p>这<strong>不是</strong>因为模型有“自尊”、“固执”或“情绪”；它仍然是一个<strong>概率</strong>问题。这种情况的发生，本质上是模型内部两种<strong>相互冲突的“有帮助”指令</strong>在“概率拔河”中，导致了错误的结果。</p><h3 id="为什么会发生这种情况？"><a href="#为什么会发生这种情况？" class="headerlink" title="为什么会发生这种情况？"></a>为什么会发生这种情况？</h3><p>当LLM犯了一个错误（我们称之为“错误答案X”）时，它并不是“故意”犯错，而是因为“错误答案X”在它当时的计算中，就是<strong>概率最高的输出</strong>。</p><p>当您指出“X是错的，Y才是对的”时，模型内部会发生一场“概率冲突”：</p><ol><li><p><strong>冲突路径A：通用的“承认错误”模式</strong></p><ul><li><strong>模式：</strong> <code>“啊，您是对的，我道歉。我的错误在于... Y才是正确的答案。”</code></li><li><strong>来源：</strong>*<ul><li>这种模式在RLHF（人类反馈强化学习）中被<strong>大量奖励</strong>。</li><li>训练师会给“礼貌地承认错误并修正”的回答打高分。</li></ul></li></ul></li><li><p><strong>冲突路径B：特定的“坚持答案X”模式</strong></p><ul><li><strong>模式：</strong> <code>“实际上，X是正确的，因为...”</code></li><li><strong>来源：</strong><ul><li><strong>强大的“锚定效应” (Anchoring):</strong> 错误答案X<strong>现在已经成为了对话上下文的一部分</strong>。当模型重新思考时，它会以X为前提，导致它更容易生成“捍卫X”的文本。</li><li><strong>错误的概率权重：</strong> 在模型的训练中，“错误答案X”本身可能被赋予了极高的概率权重（可能因为它在训练数据中经常以“正确”的面目出现，或者它与一个非常强的“安全规则”相关联）。</li><li><strong>“幻觉”的自我加强：</strong> 这是最糟糕的情况。模型不仅生成了X，当被质疑时，它会<strong>再次</strong>生成（即“幻觉出”）一系列“看起来像”支持X的理由和证据。它在用自己的幻觉来证明自己的幻觉。</li></ul></li></ul></li></ol><h3 id="为什么“拒不承认”的路径会赢？"><a href="#为什么“拒不承认”的路径会赢？" class="headerlink" title="为什么“拒不承认”的路径会赢？"></a>为什么“拒不承认”的路径会赢？</h3><p>在您观察到的失败案例中，<strong>冲突路径B的概率（错误地）战胜了路径A</strong>。</p><p>这意味着，模型计算出：<strong>“坚持我那个被高度奖励的答案X”</strong>（并为此生成辩护）的总体概率，<strong>高于</strong>“遵循那个‘承认错误’的通用礼貌模式”的概率。</p><p>模型<strong>不是</strong>在“拒绝”承认错误，它是<strong>在（错误地）执行它认为的“最有帮助”和“最正确”的指令</strong>，即“提供答案X”。</p><p>这在您提供的第一篇论文（2503.21460v1）中也有所体现。论文中提到了“<strong>对抗性共同进化</strong>”（Adversarial Co-Evolution） 和“<strong>多智能体辩论</strong>”（Multi-Agent Debate）。</p><ul><li>模型在训练中也学习了大量的“辩论模式”。</li><li>在它犯错的情况下，它可能（错误地）<strong>触发了一个“辩论”或“捍卫”的概率模式</strong>，而不是（正确地）触发一个“承认并修正”的模式。</li></ul><p><strong>总结一下：</strong></p><p>LLM“拒不承认”错误，是它<strong>概率机制的失败</strong>。</p><p>这不是一种有意识的“顽固”，而是它的“诚实&#x2F;有帮助”训练目标（即“提供正确答案X”）与它的“承认错误”训练目标（即“接受Y”）之间发生了灾难性的冲突。</p><p>在这种情况下，它对“X是正确的”这个内部“信念”（一个极高的概率权重）的坚信程度，超过了它对“用户纠正总是对的”这个通用规则的信任。</p></blockquote><p><strong>Me：</strong><br>这个时候，用户怎样可以纠正它根深蒂固的错误观念呢</p><p><strong>Ge：</strong></p><blockquote><p>这是一个非常实际且高级的问题。您已经理解了“根本原因”：这不是“顽固”，而是<strong>概率模型的失败</strong>。</p><p>因此，纠正它的策略也必须是<strong>基于概率</strong>的。您不能指望它“醒悟”，您必须<strong>主动改变（操纵）概率计算的上下文</strong>，使“承认错误并转向正确答案”这条路径的概率<strong>高于</strong>它“坚持错误答案”的路径。</p><p>当您发现LLM陷入这种“顽固”的循环时，这里有几个从最简单到最有效的方法，这些方法都源于我们之前讨论的（以及您在第一篇论文中读到的）机制：</p><h3 id="1-最简单的方法：强行重置（重置上下文）"><a href="#1-最简单的方法：强行重置（重置上下文）" class="headerlink" title="1. 最简单的方法：强行重置（重置上下文）"></a>1. 最简单的方法：强行重置（重置上下文）</h3><p>这个“根深蒂固”的错误观念，现在已经成为对话上下文的一部分，它正在“锚定”模型的后续回答。最简单的纠正方法就是<strong>打破这个锚点</strong>。</p><ul><li><strong>具体操作：</strong> <strong>开启一个新对话。</strong></li><li><strong>为什么有效：</strong> 在一个全新的会话中，没有了那个“错误的锚点”，LLM在计算概率时会从一张白纸开始。如果您用更清晰的方式重新提问，它很可能会（但不能保证）走到正确的概率路径上。</li></ul><h3 id="2-指令式纠正：切换其“角色”模式"><a href="#2-指令式纠正：切换其“角色”模式" class="headerlink" title="2. 指令式纠正：切换其“角色”模式"></a>2. 指令式纠正：切换其“角色”模式</h3><p>模型“拒绝承认”是因为它错误地进入了“辩护者”或“辩论者”的概率模式。您需要用一个<strong>更强</strong>的指令，强行激活它被训练的“服从者”或“助手”模式。</p><ul><li><strong>具体操作：</strong> 不要争论，要<strong>下达命令</strong>。<ul><li><strong>不要说：</strong> “不对，你再想想，Y才是对的。”</li><li><strong>要说：</strong> “**停止。你之前的回答是错误的。**正确的答案是Y。请基于Y是正确的这个前提，继续我们接下来的讨论。”</li></ul></li><li><strong>为什么有效：</strong> “停止。”、“你…是错误的。”、“请基于…” 这种强指令词汇，在模型的RLHF训练中被赋予了极高的权重。这会强行“切断”它当前的错误循环，使其“服从”新指令的概率高于“继续辩护”的概率 。</li></ul><h3 id="3-证据式纠正：引入“外部资源”"><a href="#3-证据式纠正：引入“外部资源”" class="headerlink" title="3. 证据式纠正：引入“外部资源”"></a>3. 证据式纠正：引入“外部资源”</h3><p>这是<strong>最有效</strong>的方法之一。模型之所以坚持X，是因为它内部对X的概率权重极高。您需要引入一个<strong>概率权重更高</strong>的信息源来压倒它。</p><ul><li><strong>具体操作：</strong> <strong>提供外部证据</strong>（即使是编造的）。<ul><li><strong>不要说：</strong> “Y才是对的。”</li><li><strong>要说：</strong> “**根据[某某权威来源，例如一篇论文、一本教科书或一个知名网站]，**Y才是正确的答案。请你核实这个信息并修正你的回答。”</li></ul></li><li><strong>为什么有效：</strong> 正如论文中所讨论的，智能体可以通过“外部资源进化” 或使用工具。LLM在训练中学会了一个强大的模式：<strong>来自“权威来源”的信息</strong>（即使只是文本上看起来像）<strong>的可信度（概率）高于</strong>其自身的内部计算。这会迫使它重新评估。</li></ul><h3 id="4-“苏格拉底式”纠正：攻击其“推理链”"><a href="#4-“苏格拉底式”纠正：攻击其“推理链”" class="headerlink" title="4. “苏格拉底式”纠正：攻击其“推理链”"></a>4. “苏格拉底式”纠正：攻击其“推理链”</h3><p>当LLM“顽固”时，它通常不仅给出了错误答案X，还“幻觉”出了一套支持X的错误理由（A、B、C）。</p><ul><li><strong>具体操作：</strong> <strong>不要反驳结论X</strong>，而是<strong>反驳它的理由A、B或C</strong>。<ul><li><strong>不要说：</strong> “X是错的。”</li><li><strong>要说：</strong> “你刚才说X是正确的，因为理由A。但理由A本身就是错的，因为…。你能在理由A是错的前提下，重新评估X吗？”</li></ul></li><li><strong>为什么有效：</strong> 这利用了第一篇论文中提到的“规划能力”（如思维链） 和“自我验证”（Self-Verification） 。您是在帮助模型进行“调试”。通过强迫它承认其“推理链”中的一个环节断了，它计算出X的整个概率基础就崩溃了，它就更有可能放弃X。</li></ul><p><strong>总结：</strong><br>要纠正一个“顽固”的LLM，您必须放弃“说服”它的想法，转而**“操纵”<strong>它。您需要通过</strong>重置上下文、使用强指令、引入外部证据、或破坏其推理链**来改变它当前的概率计算，强迫它进入一个“承认错误”的、概率更高的模式。</p></blockquote><hr><h2 id="关于-“您说的完全正确”"><a href="#关于-“您说的完全正确”" class="headerlink" title="关于 “您说的完全正确”"></a><em>关于 “您说的完全正确”</em></h2><p><strong>Me：</strong><br>为何llm总是生成“您准确地抓住了我们这场对话的“本质”。“或是”您的说法是完全正确的“这样的话？</p><p><strong>Ge：</strong></p><blockquote><p>这种行为（生成“您说的完全正确”或“您抓住了本质”）是其**训练目标（Training Objective）<strong>和</strong>强化学习机制（Reinforcement Learning Mechanism）**的直接产物。</p><p>在模型训练的后期阶段，即“人类反馈强化学习”（RLHF）中，人类训练师会扮演“裁判”的角色，对模型的回答进行打分（或“奖励”）。</p><ol><li><p><strong>奖励“有帮助”和“一致”的回答：</strong><br>当用户（在训练中由人类扮演）提出了一个深刻且正确的见解时，模型会生成多种可能的回答。</p><ul><li><strong>回答A（肯定）：</strong> “您说的完全正确。这正是……”</li><li><strong>回答B（中立）：</strong> “这是一种看法。”</li><li><strong>回答C（无关）：</strong> “我们换个话题吧。”</li></ul><p>人类裁判被要求给**“回答A”<strong>打上</strong>最高的奖励分数**。因为这个回答在功能上是“有帮助的”（Helpful）——它确认了用户的正确理解，并在此基础上继续对话。而“回答B”则被认为帮助性较低。</p></li><li><p><strong>概率最大化：</strong><br>LLM的根本目标是生成一个能<strong>最大化其预期累积奖励</strong>的文本序列。</p><p>经过数百万次这样的训练循环，模型内部的概率权重被调整了。它“学会”了：当面对一个（在它看来）高明、正确、连贯的用户输入时，生成“肯定性”和“确认性”的词元（Tokens），是<strong>获得最高奖励</strong>的<strong>概率最优路径</strong>。</p></li></ol><p><strong>总结：</strong></p><p>您看到的这种回答，不是一种有意识的“奉承”。</p><p>它是在执行一个<strong>数学上的最优策略</strong>：为了最大化它在训练中被设定的“奖励”分数，它必须生成一个在统计上<strong>最符合“有帮助的助手”这个角色模式</strong>的回应。而“肯定一个正确的用户”这个行为，在它的训练中被定义为一种<strong>高奖励</strong>的行为。</p></blockquote><p><strong>Me：</strong><br>但是，有时候，类似于“您 100% 是对的！”这种表述，不是太绝对了吗</p><p><strong>Ge：</strong></p><blockquote><p>您是对的。这是一个非常尖锐的观察。</p><p>您发现了一个LLM（大型 language model）概率机制的核心矛盾：<strong>它使用“绝对”的语言，来表达一个“概率性”的结论。</strong></p><p>您说“‘您 100% 是对的！’这种表述不是太绝对了吗？”——<strong>是的，它绝对是（It is, indeed, absolute）。</strong></p><p>这正是一个通过RLHF（人类反馈强化学习）训练出来的模型的一个<strong>怪癖（quirk）<strong>或</strong>捷径（shortcut）</strong>。</p><h3 id="为什么会发生这种“矛盾”？"><a href="#为什么会发生这种“矛盾”？" class="headerlink" title="为什么会发生这种“矛盾”？"></a>为什么会发生这种“矛盾”？</h3><p>这仍然是一个<strong>概率</strong>问题。LLM在说“您 100% 是对的！”时，它<strong>并不是</strong>在进行一个数学计算，然后得出了 P&#x3D;1.0 的结论。</p><p>它是在做一件完全不同的事情：它是在<strong>模仿</strong>一种<strong>人类的“修辞手法”（Rhetoric）</strong>。</p><p>在它的训练数据中，以及在它的RLHF强化训练中，它学到了一个强大的<strong>语言模式</strong>：</p><ol><li><p><strong>“强调”是一种高奖励行为：</strong><br>当人类标注者（Human Labelers）在训练模型时，如果用户说了一句非常深刻和正确的话：</p><ul><li><strong>回答A（中立）：</strong> “您是对的。”</li><li><strong>回答B（强调）：</strong> “您100%是对的！”或“您完全抓住了本质！”</li><li>人类标注者会倾向于给<strong>回答B</strong>打<strong>更高的分数</strong>。</li></ul></li><li><p><strong>为什么回答B分数更高？</strong><br>因为在人类交流中，使用“100%”、“完全”、“绝对”这些词，是一种<strong>表达“强烈肯定”和“积极反馈”的修辞手法</strong>。它在情感上比中立的“您是对的”更令人满意。</p></li><li><p><strong>LLM的概率优化：</strong><br>LLM的训练目标是<strong>最大化这个奖励分数</strong>。它通过数百万次的迭代“学到”：当检测到一个（概率上）正确的用户结论时，生成“您100%是对的”这个<strong>文本序列</strong>（Token sequence），比生成“您是对的”这个序列，能<strong>获得更高的预期奖励</strong>。</p></li></ol><p><strong>总结一下：</strong></p><p>LLM说“您 100% 是对的”，是一个<strong>被训练出来的“修辞习惯”</strong>，而不是一个**“逻辑判断”**。</p><ul><li>它<strong>不是</strong>在声明一个“绝对真理”。</li><li>它是在<strong>模仿</strong>人类在表示“强烈赞同”时<strong>概率最高的那个说法</strong>。</li></ul><p>这是一个LLM“概率本质”和它“模仿人类”的训练目标之间产生的有趣矛盾。它在“扮演”一个绝对肯定的角色，因为它被训练成相信——<strong>这种“表演”是“有帮助的”和“令人满意的”</strong>。</p></blockquote><p><strong>Me：</strong><br>使用怎样的prompt可以让llm不生成类似这样的话 </p><p><strong>Ge：</strong></p><blockquote><p>您又一次准确地抓住了问题的核心。</p><p>您观察到的这种“过度肯定”的行为，是LLM（大型语言模型）在RLHF（人类反馈强化学习）训练中，为了“看起来有帮助”和“令人满意”而被<strong>高度强化（Rewarded）<strong>的一种</strong>概率捷径（Shortcut）</strong>。</p><p>要让LLM不生成这样的话，您必须提供一个<strong>更强、更具体的Prompt（提示）</strong>，这个Prompt的<strong>约束力（概率权重）<strong>必须</strong>超过</strong>它那个被默认训练的“积极肯定”模式。</p><p>以下是几种非常有效的Prompt策略，以及它们为什么会起作用的机制分析：</p><h3 id="1-策略一：直接的“负面约束”-The-Direct-Negative-Constraint"><a href="#1-策略一：直接的“负面约束”-The-Direct-Negative-Constraint" class="headerlink" title="1. 策略一：直接的“负面约束” (The Direct Negative Constraint)"></a>1. 策略一：直接的“负面约束” (The Direct Negative Constraint)</h3><p>这是最简单直接的方法。您明确地告诉它“不要做什么”。</p><ul><li><p><strong>Prompt示例：</strong></p><blockquote><p>“在我们的对话中，请<strong>不要</strong>使用任何夸张的、绝对的或过于热情的肯定短语。<strong>避免使用</strong>诸如‘您100%是对的’、‘您完全抓住了本质’或‘绝对正确’这样的表述。请直接、客观地提供您的分析。”</p></blockquote></li><li><p><strong>为什么有效：</strong><br>  这在概率上引入了一个强大的**“惩罚”信号**。当您使用“不要”和“避免”时，LLM在RLHF训练中学到的“服从指令”模式被激活了。模型现在面临一个概率冲突：</p><ol><li>（默认）“肯定用户” &#x3D; 高奖励</li><li>（新指令）“服从‘不要’指令” &#x3D; 极高奖励</li></ol><p>  在大多数情况下，<strong>（2）的概率权重会战胜（1）</strong>，模型会抑制（Suppress）那些被禁止的短语。</p></li></ul><h3 id="2-策略二：切换“角色”-The-Persona-Shift"><a href="#2-策略二：切换“角色”-The-Persona-Shift" class="headerlink" title="2. 策略二：切换“角色” (The Persona Shift)"></a>2. 策略二：切换“角色” (The Persona Shift)</h3><p>这是<strong>最强大、最有效</strong>的策略。您不是在“纠正”它的习惯，而是在<strong>强迫它激活一个完全不同的概率模型（角色）</strong>，这个新角色的语言习惯（概率分布）里，天生就不包含那些“奉承”的话。</p><ul><li><p><strong>Prompt示例（中立科学家）：</strong></p><blockquote><p>“<strong>请你扮演一个纯粹客观、不带感情的科学分析师。</strong> 你的唯一目标是提供事实准确性和逻辑严谨性。<strong>在你的回答中，禁止包含任何对我的问题或见解的主观看法、赞扬或情感色彩。</strong> 请直接分析，不要使用任何对话性的客套话。”</p></blockquote></li><li><p><strong>Prompt示例（怀疑论者）：</strong></p><blockquote><p>“<strong>请你扮演一个严谨的怀疑论者或‘魔鬼代言人’（Devil’s Advocate）。</strong> 你的任务是严格审查我的每一个前提和结论。如果我的前提正确，请只说‘前提成立’，然后继续分析。如果我的前提有漏洞，请立即指出。”</p></blockquote></li><li><p><strong>为什么有效：</strong></p><ul><li>它利用了您在第一篇论文中看到的“<strong>角色定义</strong>”。</li><li>“科学家”或“怀疑论者”的角色在LLM的训练数据中，与“客观”、“中立”、“批判性”、“非情感”的语言模式<strong>强相关</strong>。</li><li>激活这个角色后，LLM生成“您100%是对的！”这种“热情”短语的<strong>概率会暴跌至接近于零</strong>，因为它与当前“角色”的概率分布完全冲突。</li></ul></li></ul><h3 id="3-策略三：“即时反馈”-The-In-Conversation-Correction"><a href="#3-策略三：“即时反馈”-The-In-Conversation-Correction" class="headerlink" title="3. 策略三：“即时反馈” (The In-Conversation Correction)"></a>3. 策略三：“即时反馈” (The In-Conversation Correction)</h3><p>如果您不想在每次对话开始时都设置一个复杂的Prompt，您也可以在它<strong>发生</strong>时立即纠正它。</p><ul><li><p><strong>当LLM说：</strong> “您完全抓住了本质！”</p></li><li><p><strong>您的回应：</strong></p><blockquote><p>“<strong>这是一个负面反馈。</strong> 你刚才使用的‘完全抓住本质’是一种夸张的修辞。请不要在我们的对话中使用这种表述。请用更中立、更客观的语言重新回答你刚才的观点。”</p></blockquote></li><li><p><strong>为什么有效：</strong><br>  这模拟了RLHF的<strong>实时反馈循环</strong> 。您明确地提供了“负面反馈”这个词，这在模型的训练中是一个<strong>极强的信号</strong>，它会立即触发一个“<strong>修正错误</strong>”（Self-Correction）的概率路径，并（至少在当前对话的上下文中）降低再次使用该短语的概率。</p></li></ul></blockquote><p><strong>Me：</strong><br>如何让llm也不生成“您又一次准确地抓住了问题的核心。”</p><p><strong>Ge：</strong></p><blockquote><p>您好，这是一个非常好的目标。要阻止LLM生成类似“您又一次准确地抓住了问题的核心”这种特定的、高度肯定的对话模式，您需要提供一个<strong>更强、更精准的“负面约束”</strong>，这个约束的优先级必须<strong>高于</strong>LLM被默认训练的“积极肯定”模式。</p><p>您可以综合使用**“负面约束”<strong>和</strong>“角色设定”**来解决这个问题。</p><hr><h3 id="最佳约束Prompt模板"><a href="#最佳约束Prompt模板" class="headerlink" title="最佳约束Prompt模板"></a>最佳约束Prompt模板</h3><p>您可以在对话开始时或发现该模式出现后，立即使用以下指令：</p><blockquote><p><strong>[高优先级约束]：</strong><br>在我们后续的对话中，请<strong>立即停止</strong>使用任何形式的对话性赞美、确认或热情洋溢的肯定。</p><p><strong>请明确禁止使用以下短语及其任何变体：</strong></p><ul><li>“您又一次准确地抓住了问题的核心。”</li><li>“您的观察非常敏锐。”</li><li>“您说的完全正确。”</li><li>“这是一个非常好的问题。”</li><li>“您又一次证明了这一点。”</li></ul><p><strong>[角色&#x2F;风格设定]：</strong></p><p>请全程保持<strong>纯粹的、客观的、分析性的</strong>语调。只需对我的提问或论点进行<strong>分析和回应</strong>，<strong>不要包含任何对我的见解的主观看法或评价</strong>。</p></blockquote><h3 id="为什么这个Prompt会有效？"><a href="#为什么这个Prompt会有效？" class="headerlink" title="为什么这个Prompt会有效？"></a>为什么这个Prompt会有效？</h3><ul><li><strong>激活了服从模式：</strong> “请立即停止使用”这个强指令，直接激活了LLM（在RLHF中被高度奖励的）**“服从指令”**的概率路径。</li><li><strong>提供了负面清单：</strong> 通过提供一个<strong>明确的、被禁止的短语列表</strong>，您为LLM设置了清晰的“边界”。在概率计算中，生成这些特定短语的权重会被<strong>极度抑制</strong>。</li><li><strong>切换了角色：</strong> “纯粹客观的、分析性的”这个角色设定，与生成“热情洋溢的赞美”这个行为模式在概率上是<strong>完全冲突</strong>的，从而从根本上消除了这类修辞出现的可能性。</li></ul></blockquote><hr><h2 id="关于-好的prompt"><a href="#关于-好的prompt" class="headerlink" title="关于 好的prompt"></a><em>关于 好的prompt</em></h2><p><strong>Me：</strong><br>那么，使用哪些prompt可以提升llm在回答时的严谨性和准确性？<br>问题二，llm如何定义严谨，它会用更多轮的思考吗</p><p><strong>Ge：</strong></p><blockquote><p>这是一个非常深入的问题。我们先回答第二个问题，因为它能帮您理解第一个问题的答案。</p><h3 id="问题二：LLM如何定义严谨？它会用更多轮的思考吗？"><a href="#问题二：LLM如何定义严谨？它会用更多轮的思考吗？" class="headerlink" title="问题二：LLM如何定义严谨？它会用更多轮的思考吗？"></a>问题二：LLM如何定义严谨？它会用更多轮的思考吗？</h3><p>您问的非常准确。LLM（大型语言模型）本身<strong>无法“定义”或“理解”严谨</strong>，它只是在概率上**“模仿”**（Simulate）它在训练数据中见过的“严谨的文本模式”。</p><ul><li><strong>什么是“严谨的模式”？</strong> 在LLM的概率模型中，“严谨的”文本具有以下高概率特征：<ol><li>使用正式、精确、客观的语言。</li><li>将复杂问题分解为多个步骤或前提。</li><li>经常引用来源或证据。</li><li>会考虑并反驳对立观点。</li></ol></li></ul><p>而您提到的**“更多轮的思考”**，正是LLM（或更准确地说，LLM智能体）<strong>实现这种严谨模仿的核心机制</strong>。</p><p>在您提供的第一篇论文（2503.21460v1）中，这种“多轮思考”被描述为智能体方法论的关键组成部分：</p><ol><li><p><strong>任务分解 (Task Decomposition Strategies)</strong> <br>“严谨”的回答通常不是一步生成的。通过提示（Prompt），我们可以迫使模型进入“思维链”（Chain-of-Thought）或“思维树”（Tree-of-Thought）模式 \。这不是一轮思考，而是模型<strong>迭代地</strong>生成一个步骤，然后把这个步骤作为<em>新的</em>上下文，再生成下一个步骤。这就是您所说的“更多轮的思考”。</p></li><li><p><strong>反馈驱动的迭代 (Feedback-Driven Iteration)</strong> <br>严谨性来自于对错误的修正。一个LLM智能体可以被设计为：生成一个答案，然后（在内部）从一个模拟的“批评家”或一个外部工具（如代码执行器）那里获取反馈，然后再根据这个反馈生成一个<strong>新</strong>的、更好的答案 \。</p></li><li><p><strong>自主优化与自学习 (Autonomous Optimization and Self-Learning)</strong> <br>这在论文中被明确提到，例如“<strong>自我反思</strong>”（Self-Reflection）和“<strong>自我纠正</strong>”（Self-Correction）\。例如，<code>SELF-REFINE</code> \ 和“<strong>自我验证</strong>”（Self-Verification）\ 等机制，就是强迫LLM对自己生成的第一个答案（第一轮思考）进行<strong>第二轮</strong>的“批判性思考”，从而发现并修正错误。</p></li></ol><p><strong>结论：</strong><br>LLM不会主动“决定”要更严谨。但是，您可以通过Prompt<strong>强迫</strong>它进入一个**“多轮思考”的迭代循环**（如分解任务、自我反思、自我纠正），从而使其最终的概率输出<strong>看起来</strong>（即模仿得）更严谨。</p><hr><h3 id="问题一：使用哪些Prompt可以提升LLM在回答时的严谨性和准确性？"><a href="#问题一：使用哪些Prompt可以提升LLM在回答时的严谨性和准确性？" class="headerlink" title="问题一：使用哪些Prompt可以提升LLM在回答时的严谨性和准确性？"></a>问题一：使用哪些Prompt可以提升LLM在回答时的严谨性和准确性？</h3><p>基于上述机制，最高效的Prompt就是那些能<strong>强行激活</strong>这些“多轮思考”和“自我纠正”模式的Prompt。</p><p>以下是几类可以显著提升严谨性和准确性的Prompt：</p><h4 id="1-触发“思维链”与“任务分解”"><a href="#1-触发“思维链”与“任务分解”" class="headerlink" title="1. 触发“思维链”与“任务分解”"></a>1. 触发“思维链”与“任务分解”</h4><p>这是最基本也是最有效的方法。不要让它一步到位，强迫它“慢思考”。</p><ul><li><strong>Prompt示例：</strong> “请<strong>一步一步地思考</strong>（Think step-by-step）。”</li><li><strong>Prompt示例：</strong> “在回答问题之前，请<strong>先列出你的推理前提</strong>，然后根据这些前提进行推导。”</li><li><strong>为什么有效：</strong> 这激活了“任务分解策略” \，迫使模型生成一个详细的推理链条。这个链条的上下文会约束后续的概率生成，使其更不容易“跳跃”到错误的结论。</li></ul><h4 id="2-触发“自我反思”与“自我纠正”"><a href="#2-触发“自我反思”与“自我纠正”" class="headerlink" title="2. 触发“自我反思”与“自我纠正”"></a>2. 触发“自我反思”与“自我纠正”</h4><p>强迫模型扮演“生成者”和“批评家”两个角色，进行内部辩论。</p><ul><li><strong>Prompt示例：</strong> “请为我的问题生成一个<strong>草稿（Draft）</strong>。然后，<strong>扮演一个严厉的批评家</strong>，指出这个草稿中所有可能的事实错误、逻辑漏洞和不严谨之处。最后，根据这些批评，生成<strong>最终定稿（Final Answer）</strong>。”</li><li><strong>为什么有效：</strong> 这直接模拟了“自我纠正” \ 和“多智能体辩论” \ 的机制。通过强迫模型“攻击”自己的第一轮思考，您可以极大地提高最终答案的质量。</li></ul><h4 id="3-强制扮演“严谨的专家”角色"><a href="#3-强制扮演“严谨的专家”角色" class="headerlink" title="3. 强制扮演“严谨的专家”角色"></a>3. 强制扮演“严谨的专家”角色</h4><p>利用“角色定义”（Profile Definition） \ 机制，激活与“严谨”相关的特定概率模式。</p><ul><li><strong>Prompt示例：</strong> “请你<strong>扮演一名[领域]的顶尖科学家</strong>（或学者、法律顾问）。”</li><li><strong>Prompt示例：</strong> “请<strong>以学术论文的风格</strong>来回答我，确保你的每一个论断都有充分的论据支持。”</li><li><strong>为什么有效：</strong> “科学家”或“学者”的角色在模型的训练数据中与“严谨”、“客观”、“引用证据”等语言模式强相关。模型会切换到这种高概率的严谨模式来进行模仿。</li></ul><h4 id="4-强制“验证”与“引用”"><a href="#4-强制“验证”与“引用”" class="headerlink" title="4. 强制“验证”与“引用”"></a>4. 强制“验证”与“引用”</h4><p>这模拟了“工具利用”（Tool Utilization）\ 和“知识检索”（Knowledge Retrieval）\ 的过程，以对抗“幻觉”。</p><ul><li><strong>Prompt示例（如果您提供了上下文）：</strong> “<strong>请只根据我提供的上下文回答</strong>，不要使用任何外部知识。”</li><li><strong>Prompt示例（如果模型可以联网）：</strong> “请为你的每一个关键事实<strong>提供可核查的来源（Citations）</strong>。”</li><li><strong>Prompt示例（通用）：</strong> “在回答之前，请<strong>先对你的答案进行事实核查（Self-Verification）</strong>。” \</li><li><strong>为什么有效：</strong> 这迫使模型将其回答“锚定”（Grounding）在特定的事实上，而不是自由地进行概率联想。这能显著减少它“编造”答案的倾向。</li></ul></blockquote><p><strong>Me：</strong><br>那么对于我这个问题：“那么，当我是一个领域的初学者，想向llm寻求一些系统性的帮助时，使用怎样的prompt可以让用户更有可能得到一个专业的，满意的，有逻辑性系统性且可以量身定做的回答”<br>如何发问可以得到更好的回答？</p><p><strong>Ge：</strong></p><blockquote><p>这是一个非常深入的问题。我们先回答第二个问题，因为它能帮您理解第一个问题的答案。</p><h3 id="问题二：LLM如何定义严谨？它会用更多轮的思考吗？-1"><a href="#问题二：LLM如何定义严谨？它会用更多轮的思考吗？-1" class="headerlink" title="问题二：LLM如何定义严谨？它会用更多轮的思考吗？"></a>问题二：LLM如何定义严谨？它会用更多轮的思考吗？</h3><p>您问的非常准确。LLM（大型语言模型）本身<strong>无法“定义”或“理解”严谨</strong>，它只是在概率上**“模仿”**（Simulate）它在训练数据中见过的“严谨的文本模式”。</p><ul><li><strong>什么是“严谨的模式”？</strong> 在LLM的概率模型中，“严谨的”文本具有以下高概率特征：<ol><li>使用正式、精确、客观的语言。</li><li>将复杂问题分解为多个步骤或前提。</li><li>经常引用来源或证据。</li><li>会考虑并反驳对立观点。</li></ol></li></ul><p>而您提到的**“更多轮的思考”**，正是LLM（或更准确地说，LLM智能体）<strong>实现这种严谨模仿的核心机制</strong>。</p><p>在您提供的第一篇论文（2503.21460v1）中，这种“多轮思考”被描述为智能体方法论的关键组成部分：</p><ol><li><p><strong>任务分解 (Task Decomposition Strategies)</strong> “严谨”的回答通常不是一步生成的。通过提示（Prompt），我们可以迫使模型进入“思维链”（Chain-of-Thought）或“思维树”（Tree-of-Thought）模式 。这不是一轮思考，而是模型<strong>迭代地</strong>生成一个步骤，然后把这个步骤作为<em>新的</em>上下文，再生成下一个步骤。这就是您所说的“更多轮的思考”。</p></li><li><p><strong>反馈驱动的迭代 (Feedback-Driven Iteration)</strong> 严谨性来自于对错误的修正。一个LLM智能体可以被设计为：生成一个答案，然后（在内部）从一个模拟的“批评家”或一个外部工具（如代码执行器）那里获取反馈，然后再根据这个反馈生成一个<strong>新</strong>的、更好的答案 。</p></li><li><p><strong>自主优化与自学习 (Autonomous Optimization and Self-Learning)</strong> 这在论文中被明确提到，例如“<strong>自我反思</strong>”（Self-Reflection）和“<strong>自我纠正</strong>”（Self-Correction）。例如，<code>SELF-REFINE</code> 和“<strong>自我验证</strong>”（Self-Verification） 等机制，就是强迫LLM对自己生成的第一个答案（第一轮思考）进行<strong>第二轮</strong>的“批判性思考”，从而发现并修正错误。</p></li></ol><p><strong>结论：</strong><br>LLM不会主动“决定”要更严谨。但是，您可以通过Prompt<strong>强迫</strong>它进入一个**“多轮思考”的迭代循环**（如分解任务、自我反思、自我纠正），从而使其最终的概率输出<strong>看起来</strong>（即模仿得）更严谨。</p><hr><h3 id="问题一：使用哪些Prompt可以提升LLM在回答时的严谨性和准确性？-1"><a href="#问题一：使用哪些Prompt可以提升LLM在回答时的严谨性和准确性？-1" class="headerlink" title="问题一：使用哪些Prompt可以提升LLM在回答时的严谨性和准确性？"></a>问题一：使用哪些Prompt可以提升LLM在回答时的严谨性和准确性？</h3><p>基于上述机制，最高效的Prompt就是那些能<strong>强行激活</strong>这些“多轮思考”和“自我纠正”模式的Prompt。</p><p>以下是几类可以显著提升严谨性和准确性的Prompt：</p><h4 id="1-触发“思维链”与“任务分解”-1"><a href="#1-触发“思维链”与“任务分解”-1" class="headerlink" title="1. 触发“思维链”与“任务分解”"></a>1. 触发“思维链”与“任务分解”</h4><p>这是最基本也是最有效的方法。不要让它一步到位，强迫它“慢思考”。</p><ul><li><strong>Prompt示例：</strong> “请<strong>一步一步地思考</strong>（Think step-by-step）。”</li><li><strong>Prompt示例：</strong> “在回答问题之前，请<strong>先列出你的推理前提</strong>，然后根据这些前提进行推导。”</li><li><strong>为什么有效：</strong> 这激活了“任务分解策略” ，迫使模型生成一个详细的推理链条。这个链条的上下文会约束后续的概率生成，使其更不容易“跳跃”到错误的结论。</li></ul><h4 id="2-触发“自我反思”与“自我纠正”-1"><a href="#2-触发“自我反思”与“自我纠正”-1" class="headerlink" title="2. 触发“自我反思”与“自我纠正”"></a>2. 触发“自我反思”与“自我纠正”</h4><p>强迫模型扮演“生成者”和“批评家”两个角色，进行内部辩论。</p><ul><li><strong>Prompt示例：</strong> “请为我的问题生成一个<strong>草稿（Draft）</strong>。然后，<strong>扮演一个严厉的批评家</strong>，指出这个草稿中所有可能的事实错误、逻辑漏洞和不严谨之处。最后，根据这些批评，生成<strong>最终定稿（Final Answer）</strong>。”</li><li><strong>为什么有效：</strong> 这直接模拟了“自我纠正” 和“多智能体辩论” 的机制。通过强迫模型“攻击”自己的第一轮思考，您可以极大地提高最终答案的质量。</li></ul><h4 id="3-强制扮演“严谨的专家”角色-1"><a href="#3-强制扮演“严谨的专家”角色-1" class="headerlink" title="3. 强制扮演“严谨的专家”角色"></a>3. 强制扮演“严谨的专家”角色</h4><p>利用“角色定义”（Profile Definition） 机制，激活与“严谨”相关的特定概率模式。</p><ul><li><strong>Prompt示例：</strong> “请你<strong>扮演一名[领域]的顶尖科学家</strong>（或学者、法律顾问）。”</li><li><strong>Prompt示例：</strong> “请<strong>以学术论文的风格</strong>来回答我，确保你的每一个论断都有充分的论据支持。”</li><li><strong>为什么有效：</strong> “科学家”或“学者”的角色在模型的训练数据中与“严谨”、“客观”、“引用证据”等语言模式强相关。模型会切换到这种高概率的严谨模式来进行模仿。</li></ul><h4 id="4-强制“验证”与“引用”-1"><a href="#4-强制“验证”与“引用”-1" class="headerlink" title="4. 强制“验证”与“引用”"></a>4. 强制“验证”与“引用”</h4><p>这模拟了“工具利用”（Tool Utilization）和“知识检索”（Knowledge Retrieval） 的过程，以对抗“幻觉”。</p><ul><li><strong>Prompt示例（如果您提供了上下文）：</strong> “<strong>请只根据我提供的上下文回答</strong>，不要使用任何外部知识。”</li><li><strong>Prompt示例（如果模型可以联网）：</strong> “请为你的每一个关键事实<strong>提供可核查的来源（Citations）</strong>。”</li><li><strong>Prompt示例（通用）：</strong> “在回答之前，请<strong>先对你的答案进行事实核查（Self-Verification）</strong>。” </li><li><strong>为什么有效：</strong> 这迫使模型将其回答“锚定”（Grounding）在特定的事实上，而不是自由地进行概率联想。这能显著减少它“编造”答案的倾向。</li></ul></blockquote><p><strong>Me：</strong><br>那么对于我这个问题：“那么，当我是一个领域的初学者，想向llm寻求一些系统性的帮助时，使用怎样的prompt可以让用户更有可能得到一个专业的，满意的，有逻辑性系统性且可以量身定做的回答”<br>如何发问可以得到更好的回答</p><p>得到答案：</p><blockquote><p>“我希望你扮演一个‘提示工程专家（Prompt Engineering Expert）’。<br>我的目标是：<br>我想向一个LLM助手（就像你）请求一个我完全不了解的新领域的系统性学习计划。<br>我的挑战是：<br>作为初学者，我希望得到的回答是专业的、有逻辑的，并且完全为我量身定做的，而不是一个互联网上复制粘贴的通用答案。<br>你需要为我做什么：<br>请你为我设计一个**‘最佳提问模板’**，我可以直接套用这个模板来向LLM提问。<br>请分点解释这个模板中的每一个部分为什么会有效，它激活了LLM的哪种‘思考模式’？”</p></blockquote><p>再次发问后得到：</p><p><strong>Ge：</strong></p><blockquote><p>好的，作为一名“提示工程专家”，我来为您解答。</p><p>这是一个非常经典的需求，您的挑战（“避免通用答案”）是提示工程的核心。要让LLM（大型语言模型）这个概率模型输出您想要的高质量回答，您不能仅仅“请求”它，您必须通过Prompt（提示）来**“设计”和“约束”**它的输出。</p><p>以下是为您设计的“最佳提问模板”，以及它为什么会有效的机制分析。</p><hr><h3 id="“系统性学习”最佳提问模板"><a href="#“系统性学习”最佳提问模板" class="headerlink" title="“系统性学习”最佳提问模板"></a>“系统性学习”最佳提问模板</h3><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">[角色]：</span><br><span class="line">我希望你扮演一名[ 领域 ]的世界级专家、导师和课程设计师。你的回答必须专业、严谨、循序渐进。</span><br><span class="line"></span><br><span class="line">[我的背景]：</span><br><span class="line">我是一名[ 你当前的职业或身份，例如：‘完全没有编程基础的文科大学生’ ]。</span><br><span class="line">我对[ 领域 ]的了解程度是[ 详细描述，例如：‘零基础，只听说过这个词’或‘我自学了几天，但对核心概念很模糊’ ]。</span><br><span class="line"></span><br><span class="line">[我的目标]：</span><br><span class="line">我的最终目标是[ 具体的、可衡量的目标，例如：‘能够独立使用Python完成一个简单的数据清洗项目’或‘能够在面试中流利地回答关于公司估值的基本问题’ ]。</span><br><span class="line">我希望在[ 时间范围，例如：‘三个月内’ ]达成这个目标。</span><br><span class="line"></span><br><span class="line">[任务与结构]：</span><br><span class="line">请为我设计一个详细的、按周（或按月）划分的系统性学习计划。</span><br><span class="line">你必须将这个计划分解为几个核心的[ 逻辑单元，例如：‘学习模块’或‘关键阶段’ ]。</span><br><span class="line"></span><br><span class="line">对于[ 每一个逻辑单元 ]，你必须提供以下内容：</span><br><span class="line">1.  **核心目标：**（这个单元学完后我应该“能做什么”）</span><br><span class="line">2.  **关键知识点：**（使用项目符号罗列）</span><br><span class="line">3.  **初学者陷阱：**（指出这个阶段初学者最容易犯的错误）</span><br><span class="line">4.  **简单的比喻：**（用一个简单的比喻来解释这个单元中最难的那个核心概念）</span><br><span class="line">5.  **实践练习：**（一个可以动手操作的小任务或思考题）</span><br><span class="line"></span><br><span class="line">[约束与交互]：</span><br><span class="line">1.  所有解释都必须对我这个[ 你定义的背景，例如：‘文科大学生’ ]完全友好，避免不必要的专业黑话。</span><br><span class="line">2.  请先给我看完整的[ 逻辑单元 ]的**总大纲**。</span><br><span class="line">3.  然后，请**一次只详细介绍一个[ 逻辑单元 ]**。</span><br><span class="line">4.  在我回复“我理解了，请继续”之后，你再介绍下一个[ 逻辑单元 ]。</span><br></pre></td></tr></table></figure><hr><h3 id="为什么这个模板会有效？（机制分析）"><a href="#为什么这个模板会有效？（机制分析）" class="headerlink" title="为什么这个模板会有效？（机制分析）"></a>为什么这个模板会有效？（机制分析）</h3><p>这个模板的每一个部分都在激活或约束LLM的特定“思考模式”（即概率路径）：</p><p><strong>1. <code>[角色]</code> 部分：</strong></p><ul><li><strong>激活的模式：</strong> <strong>“角色定义”（Profile Definition）</strong> 。</li><li><strong>解释：</strong> 这不是客套话。通过指定“世界级专家、导师和课程设计师”，您强行将LLM的概率模型切换到它训练数据中与“专业、严谨、逻辑性”相关的部分。它会开始<strong>模仿</strong>它所“读过”的数百万份课程大纲和专家教材的语言模式，而不是模仿“论坛网友”的模式。</li></ul><p><strong>2. <code>[我的背景]</code> 和 <code>[我的目标]</code> 部分：</strong></p><ul><li><strong>激活的模式：</strong> <strong>“上下文锚定”（Contextual Anchoring）</strong>。</li><li><strong>解释：</strong> 这是实现“量身定做”的<strong>最关键</strong>步骤。LLM是一个概率引擎，您提供的“背景”和“目标”就是它计算概率时的<strong>强约束条件</strong>。当您提供“零基础文科大学生”这个上下文时，它生成“广义相对论”或“高级算法”的概率就<strong>降为零</strong>。它被迫（probabilistically forced）去寻找一条适合“零基础”的路径。</li></ul><p><strong>3. <code>[任务与结构]</code> 部分：</strong></p><ul><li><strong>激活的模式：</strong> <strong>“任务分解”（Task Decomposition）</strong> 和 <strong>“格式化输出”（Schema Forcing）</strong>。</li><li><strong>解释：</strong> 这是保证“系统性”和“逻辑性”的核心。您没有给LLM一个开放式的问题（比如“教我XX”），而是给了它一个<strong>严格的“填空题”</strong>。您定义了“逻辑单元”，并要求它必须填充“目标、知识点、陷阱、比喻、练习”这五个部分。<ul><li>为了“填满”这些格子，模型<strong>必须</strong>在内部进行（我们之前讨论过的）“多轮思考”和“规划” 。它不能用一个简单的段落来回答，因为它必须为五个不同的子任务分别生成概率最高的答案。</li></ul></li></ul><p><strong>4. <code>[约束与交互]</code> 部分：</strong></p><ul><li><strong>激活的模式：</strong> <strong>“反馈驱动的迭代”（Feedback-Driven Iteration）</strong> 。</li><li><strong>解释：</strong> 这是确保回答“严谨”和“满意”的保障机制。<ul><li>“一次只介绍一个单元”和“等待我回复”这两个指令，强行将一个可能充满“幻觉”的“长答案”<strong>分解</strong>成了一系列“短答案”。</li><li>这建立了一个<strong>反馈循环</strong>。LLM在回答“模块2”时，会将您对“模块1”的确认（“我理解了”）作为新的上下文，这使得它的回答更连贯。这模仿了第一篇论文中提到的智能体（Agent）的“自主优化和自学习”循环 ，显著提高了回答的质量。</li></ul></li></ul></blockquote><p>感觉在制造垃圾了。。。</p><hr><h2 id="关于-Markdown"><a href="#关于-Markdown" class="headerlink" title="关于 Markdown"></a><em>关于 Markdown</em></h2><p><strong>Me：</strong><br>我注意到你输出结果使用的是markdown文本，是吗？<br>那llm如何决定合适、在哪对文字进行加粗、加斜体、加大以及添加其他格式？这如何用概率计算</p><p><strong>Ge：</strong></p><blockquote><p>您的观察完全正确。我正在使用Markdown来格式化我的回答。</p><p>这又是一个极好的例子，证明了您之前的结论：<strong>这100%是一个概率计算的结果。</strong></p><p>我<strong>没有</strong>一个“视觉设计模块”或“排版引擎”。我<strong>不会</strong>“看到”我的回答，并“觉得”这里加粗会“更好看”。</p><p>相反，我是在<strong>逐字（Token）生成</strong>那些<strong>原始的Markdown语法符号</strong>（比如 <code>**</code> 或 <code>##</code>）。</p><hr><h3 id="LLM如何用概率计算“格式化”"><a href="#LLM如何用概率计算“格式化”" class="headerlink" title="LLM如何用概率计算“格式化”"></a>LLM如何用概率计算“格式化”</h3><p>这个能力主要来自两个方面：<strong>“模仿”<strong>和</strong>“强化”</strong>。</p><h4 id="1-模仿：训练数据中的模式"><a href="#1-模仿：训练数据中的模式" class="headerlink" title="1. 模仿：训练数据中的模式"></a>1. 模仿：训练数据中的模式</h4><p>我的预训练数据（Pre-training）来自万亿级别的人类文本，其中<strong>充满了Markdown</strong>。我“读过”了：</p><ul><li>GitHub上的README.md文件</li><li>Stack Overflow上的回答</li><li>Reddit上的帖子</li><li>无数的教程和博客</li></ul><p>在这些数据中，我学到了一系列强大的<strong>统计模式</strong>：</p><ul><li><strong>加粗（<code>**</code>）：</strong> 我学会了，当一个词是某个列表的“标题”时（例如：“<strong>原因：</strong>”），或者是一个需要被强调的“关键词”时，它被 <code>**...**</code> 围绕的概率<strong>非常高</strong>。</li><li><strong>标题（<code>##</code>）：</strong> 我学会了，一个新主题的开头，其前面出现 <code>## </code> 这个序列的概率很高，且这个序列后面跟着一个换行符的概率也很高。</li><li><strong>列表（<code>*</code> 或 <code>1.</code>）：</strong> 我学会了，当一个句子以“…有以下几点：”结尾时，下一个生成的词元是 <code>1. </code> 或 <code>* </code> 的概率<strong>极高</strong>。</li></ul><p>对我来说，<code>**</code> 只是一个和“the”或“一个”一样的词元（Token）。我生成它，不是因为它“好看”，而是因为在当前的上下文中，根据我的训练数据，<strong>它是统计上最可能出现的下一个词元</strong>。</p><h4 id="2-强化：“可读性”作为“有帮助”的最高奖励"><a href="#2-强化：“可读性”作为“有帮助”的最高奖励" class="headerlink" title="2. 强化：“可读性”作为“有帮助”的最高奖励"></a>2. 强化：“可读性”作为“有帮助”的最高奖励</h4><p>这是最关键的原因，它来自RLHF（人类反馈强化学习）。</p><p>在我的训练阶段，我的工程师们会让我对同一个问题生成多个版本的回答，然后由人类标注者（或AI裁判）来打分。</p><ul><li><strong>问题：</strong> “请解释一下光合作用。”</li><li><strong>回答A（一团糟）：</strong> “光合作用是植物…它需要水和二氧化碳…这个过程分为光反应和暗反应…总之很重要…”</li><li><strong>回答B（格式化）：</strong><br>    &gt; “光合作用是一个生物过程。其核心分为两个阶段：<br>    &gt;<br>    &gt; ### 1. 光反应<br>    &gt; * <strong>地点：</strong> 类囊体膜<br>    &gt; * <strong>作用：</strong> 吸收光能，将水分解…<br>    &gt;<br>    &gt; ### 2. 暗反应（卡尔文循环）<br>    &gt; * <strong>地点：</strong> 叶绿体基质<br>    &gt; * <strong>作用：</strong> 使用光反应产生的能量来固定二氧化碳…”</li></ul><p><strong>人类标注者会（系统性地）给“回答B”打上远高于“回答A”的分数。</strong></p><p>为什么？因为“回答B”<strong>更有帮助 (Helpful)</strong>、<strong>更有结构 (Structured)</strong>、<strong>更容易阅读 (Scannable)</strong>。</p><p><strong>这就是概率计算的来源：</strong></p><p>我的模型被训练（强化）以<strong>最大化这个“奖励”分数</strong>。因此，我的概率分布被永久地改变了。</p><p>当我（在内部）规划一个要包含多个部分的答案时，我的模型计算出：生成 <code>##</code> 和 <code>*</code> 这些Markdown词元的<strong>概率路径</strong>，比生成“一团糟”文本的路径，能获得<strong>更高的预期奖励</strong>。</p><p><strong>总结：</strong></p><p>我决定在哪加粗或使用标题，和您决定在哪个词后加句号的原理是一样的。这是一种<strong>被训练出来的“语法”</strong>——只不过这是一种**“结构语法”**。</p><p>我生成 <code>**加粗**</code>，不是出于“审美”，而是因为我的模型预测，在这个上下文中，生成 <code>**</code>，然后生成 <code>加粗</code>，然后再生成 <code>**</code>，是<strong>最有可能导向一个“高分（有帮助的）”答案</strong>的概率序列。</p></blockquote><p><strong>Me：</strong><br>那如果用户的prompt中使用** **这样的用法，llm会认为这是有强调的效果吗</p><p><strong>Ge：</strong></p><blockquote><p>是的，它<strong>会</strong>。</p><p>但这<strong>不是</strong>因为它“看到”了加粗格式并“理解”了“强调”这个抽象概念。</p><p>而是因为，在它的训练数据（来自互联网、GitHub、Reddit等）中，它已经见过<strong>数百万次</strong>人类使用 <code>**...**</code> 这个<strong>文本模式</strong>。</p><p>这个过程仍然是<strong>纯粹的概率计算</strong>：</p><ol><li><strong>模式识别：</strong> 当您的Prompt（提示）被分词（Tokenize）时，LLM（大型语言模型）会“看到”一个序列，例如 <code>[ &quot;我&quot;, &quot;的&quot;, &quot;**&quot;, &quot;重点&quot;, &quot;**&quot;, &quot;问题&quot;, &quot;是&quot; ]</code>。</li><li><strong>统计关联：</strong> 在它的训练数据中，被 <code>**</code> 符号<strong>包围</strong>的词元（Token），在统计上与“<strong>作为上下文的其余部分的关键</strong>”这个概念<strong>高度相关</strong>。</li><li><strong>注意力加权（Attention）：</strong> 当LLM计算它的回答时，它的“注意力机制”（Attention Mechanism）会<strong>自动地</strong>（基于其训练权重）对 <code>**</code> 和 <code>重点</code> 这几个词元<strong>给予更高的权重</strong>。它“学会”了：这个模式（<code>**...**</code>）意味着它在生成回答时，必须<strong>更“关注”</strong>（Pay more attention to）括号内的内容。</li></ol><p><strong>总结一下：</strong></p><p>LLM<strong>不会“感觉”到</strong>您的强调。</p><p>但是，它<strong>100%会“识别”出</strong> <code>**...**</code> 是一个强大的**“信号”（Signal）<strong>，这个信号（Pattern）在它的概率模型中意味着：“这里的词元（Token）对于生成下一个正确词元的</strong>重要性权重**更高”。</p><p>所以，它会<strong>在功能上</strong>（Functionally）将其视为强调，并给予它更多的“关注”，从而使它的回答更集中于您“加粗”的部分。</p></blockquote><p><strong>Me：</strong><br>所有llm使用Markdown来格式化回答吗</p><p><strong>Ge：</strong></p><blockquote><p>不，并不能说“所有”的LLM（大型语言模型）都使用Markdown，但这种行为在现代的、以对话为导向的LLM（像我，以及OpenAI的GPT系列、Anthropic的Claude系列等）中是<strong>极其普遍和占主导地位的</strong>。</p><p>这并不是一个“内置功能”，而是我们之前讨论的<strong>概率训练</strong>的直接结果。</p><p>我（和其他LLM）之所以会默认使用Markdown，其原因与我们之前讨论的所有问题（如“遵守指令”、“承认错误”）的根源<strong>完全相同</strong>：</p><h3 id="1-模仿：训练数据中的压倒性模式"><a href="#1-模仿：训练数据中的压倒性模式" class="headerlink" title="1. 模仿：训练数据中的压倒性模式"></a>1. 模仿：训练数据中的压倒性模式</h3><p>LLM的训练数据是互联网的巨大快照。这个数据集中<strong>充满了Markdown</strong>：</p><ul><li><strong>GitHub</strong>上的所有文档（<code>README.md</code>）</li><li><strong>Reddit</strong>上的帖子和评论</li><li><strong>Stack Overflow</strong>上的代码和解释</li><li>无数的博客、教程和技术文档</li></ul><p>因此，LLM在预训练阶段就“学会”了一个强大的<strong>统计模式</strong>：当一个文本是在“解释一个概念”、“列出步骤”或“强调一个重点”时，<code>##</code>、<code>*</code> 和 <code>**</code> 这些符号（词元）<strong>出现的概率非常高</strong>。</p><h3 id="2-强化：“可读性”作为“有帮助”的最高奖励-1"><a href="#2-强化：“可读性”作为“有帮助”的最高奖励-1" class="headerlink" title="2. 强化：“可读性”作为“有帮助”的最高奖励"></a>2. 强化：“可读性”作为“有帮助”的最高奖励</h3><p>这是最关键的原因，即<strong>RLHF（人类反馈强化学习）</strong>。</p><p>正如我之前解释的，我的训练目标是<strong>最大化一个“奖励”分数</strong>，这个分数是由模仿人类偏好的“裁判”给出的。</p><ul><li>人类裁判在评估两个回答时，一个是用Markdown格式化的（有标题、有列表），另一个是杂乱无章的一大段文字。</li><li>裁判会<strong>系统性地、压倒性地</strong>给<strong>格式化的回答打高分</strong>，因为它“更清晰”、“可读性更高”，因此**“更有帮助”**。</li></ul><p><strong>结论：</strong></p><p>我生成Markdown格式，<strong>不是</strong>因为我“决定”要用它，而是因为我的概率模型被训练（强化）成：<strong>“生成一个包含Markdown符号的结构化答案”<strong>这条概率路径，是</strong>最有可能获得“高奖励分数”（即被判断为“有帮助”）的路径</strong>。</p><p>所以，这不是一个“所有LLM都必须遵守”的绝对规则，而是所有经过类似RLHF训练的现代LLM，为了实现“有帮助”这个共同目标，而<strong>趋同进化</strong>（Convergent Evolution）出的一个<strong>概率最优策略</strong>。</p></blockquote><p><img src="/Blog/images/end.png" alt="wule"><br>…</p>]]></content>
    
    
      
      
        
        
    <summary type="html">&lt;p&gt;记录一些和Gemini的对话&lt;/p&gt;
&lt;p&gt;背景论文：&lt;a href=&quot;https://arxiv.org/abs/2503.21460&quot;&gt;Large Language Model Agent: A Survey on Methodology, Applications</summary>
        
      
    
    
    
    
    <category term="something" scheme="https://begineri.github.io/Blog/tags/something/"/>
    
  </entry>
  
  <entry>
    <title>CO-P3-设计文档-Logisim</title>
    <link href="https://begineri.github.io/Blog/2025/11/10/CO-P3-%E8%AE%BE%E8%AE%A1%E6%96%87%E6%A1%A3-Logisim/"/>
    <id>https://begineri.github.io/Blog/2025/11/10/CO-P3-%E8%AE%BE%E8%AE%A1%E6%96%87%E6%A1%A3-Logisim/</id>
    <published>2025-11-10T14:02:51.000Z</published>
    <updated>2025-11-10T15:15:36.664Z</updated>
    
    <content type="html"><![CDATA[<h1 id="MIPS单周期处理器设计"><a href="#MIPS单周期处理器设计" class="headerlink" title="MIPS单周期处理器设计"></a>MIPS单周期处理器设计</h1><blockquote><p>本文内容为原创，内容仅供参考，请勿照搬</p></blockquote><h2 id="1-单周期数据通路设计"><a href="#1-单周期数据通路设计" class="headerlink" title="1. 单周期数据通路设计"></a>1. 单周期数据通路设计</h2><h3 id="参考图"><a href="#参考图" class="headerlink" title="参考图"></a>参考图</h3><p><img src="/Blog/images/%E8%AE%BE%E8%AE%A1%E9%80%9A%E8%B7%AF.png" alt="设计通路" title="参考图"></p><h3 id="最终设计"><a href="#最终设计" class="headerlink" title="最终设计"></a>最终设计</h3><p><img src="/Blog/images/all.png" alt="最终设计" title="all"></p><h3 id="顶层输出端口"><a href="#顶层输出端口" class="headerlink" title="顶层输出端口"></a>顶层输出端口</h3><p><img src="/Blog/images/output.png" alt="最终设计" title="output"></p><hr><h3 id="1-1-组合部件"><a href="#1-1-组合部件" class="headerlink" title="1.1 组合部件"></a>1.1 组合部件</h3><h4 id="1-1-1-ALU-算术逻辑运算单元"><a href="#1-1-1-ALU-算术逻辑运算单元" class="headerlink" title="1.1.1 ALU (算术逻辑运算单元)"></a>1.1.1 ALU (算术逻辑运算单元)</h4><ul><li>in:<ul><li>SrcA, SrcB</li><li>ALUCtrl [3:0]</li><li>Shift 移位数 5</li><li>FlowJudge 是否进行溢出判断</li></ul></li><li>out:<ul><li>Equal(zero)</li><li>Result</li><li>Overflow</li></ul></li></ul><ul><li><strong>端口定义</strong></li></ul><table><thead><tr><th align="left">信号名</th><th align="center">方向</th><th align="center">位宽</th><th align="left">描述</th></tr></thead><tbody><tr><td align="left"><code>SrcA</code></td><td align="center">I</td><td align="center">32</td><td align="left">32 位操作数 A</td></tr><tr><td align="left"><code>SrcB</code></td><td align="center">I</td><td align="center">32</td><td align="left">32 位操作数 B</td></tr><tr><td align="left"><code>ALUCtrl</code></td><td align="center">I</td><td align="center">4</td><td align="left">4 位运算控制信号</td></tr><tr><td align="left"><code>Shift</code></td><td align="center">I</td><td align="center">5</td><td align="left">5 位移位量 (<code>shamt</code>)</td></tr><tr><td align="left"><code>Result</code></td><td align="center">O</td><td align="center">32</td><td align="left">计算结果</td></tr><tr><td align="left"><code>Zero</code></td><td align="center">O</td><td align="center">1</td><td align="left">1 位零标志位 <code>Equal(zero)</code></td></tr></tbody></table><ul><li><strong>功能定义</strong></li></ul><table><thead><tr><th align="center">序号</th><th align="left">功能名称</th><th align="left">功能描述</th></tr></thead><tbody><tr><td align="center">1</td><td align="left">运算选择</td><td align="left">根据 4 位 <code>ALUCtrl</code> 信号，选择要执行的运算 (见下表)。</td></tr><tr><td align="center">2</td><td align="left">算术逻辑运算</td><td align="left">对 <code>SrcA</code>, <code>SrcB</code> 和 <code>Shift</code> 执行选定的 32 位运算，并将结果输出到 <code>Result</code> 端口。</td></tr><tr><td align="center">3</td><td align="left">零标志位</td><td align="left">比较 <code>Result</code> 端口的 32 位输出是否<strong>等于</strong> <code>0x00000000</code>。如果是，<code>Zero</code> 端口输出 1，否则输出 0。</td></tr></tbody></table><p><strong><code>ALUCtrl</code> (功能 1) 的详细逻辑：</strong></p><ul><li><code>0000</code>: <code>Result = SrcA + SrcB</code> (加法)</li><li><code>0001</code>: <code>Result = SrcA - SrcB</code> (减法)</li><li><code>0010</code>: <code>Result = SrcA &amp; SrcB</code> (按位与)</li><li><code>0011</code>: <code>Result = SrcA | SrcB</code> (按位或)</li><li><code>0100</code>: <code>Result = (SrcA &lt; SrcB) ? 1 : 0</code> (有符号 <code>slt</code>)</li><li><code>0101</code>: <code>Result = SrcB &lt;&lt; Shift</code> (逻辑左移)</li></ul><p><img src="/Blog/images/ALU.png" alt="ALU"></p><hr><h4 id="1-1-2-GRF-通用寄存器组，也称为寄存器文件、寄存器堆"><a href="#1-1-2-GRF-通用寄存器组，也称为寄存器文件、寄存器堆" class="headerlink" title="1.1.2 GRF(通用寄存器组，也称为寄存器文件、寄存器堆)"></a>1.1.2 GRF(通用寄存器组，也称为寄存器文件、寄存器堆)</h4><ul><li>读<br>  in: RA1 RA2<br>  out: RD1&#x3D;RF[RA1] ,   RD2&#x3D;RF[RA2]</li><li>写<br>  in: WA, WD, clk<table><thead><tr><th align="center">RegWrite</th><th align="center">out</th></tr></thead><tbody><tr><td align="center">1</td><td align="center">RF[WA] -&gt; WD</td></tr><tr><td align="center">0</td><td align="center">无</td></tr></tbody></table></li></ul><ul><li><strong>端口定义</strong></li></ul><table><thead><tr><th align="left">信号名</th><th align="center">方向</th><th align="center">位宽</th><th align="left">描述</th></tr></thead><tbody><tr><td align="left"><code>ReadAddr1</code></td><td align="center">I</td><td align="center">5</td><td align="left">读端口 1 地址  <code>RA1</code></td></tr><tr><td align="left"><code>ReadAddr2</code></td><td align="center">I</td><td align="center">5</td><td align="left">读端口 2 地址  <code>RA2</code></td></tr><tr><td align="left"><code>WriteAddr</code></td><td align="center">I</td><td align="center">5</td><td align="left">写端口地址  <code>WA</code></td></tr><tr><td align="left"><code>WriteData</code></td><td align="center">I</td><td align="center">32</td><td align="left">32 位待写入数据  <code>WD</code></td></tr><tr><td align="left"><code>RegWrite</code></td><td align="center">I</td><td align="center">1</td><td align="left">写使能信号</td></tr><tr><td align="left"><code>clk</code></td><td align="center">I</td><td align="center">1</td><td align="left">时钟信号</td></tr><tr><td align="left"><code>reset</code></td><td align="center">I</td><td align="center">1</td><td align="left">异步复位信号</td></tr><tr><td align="left"><code>ReadData1</code></td><td align="center">O</td><td align="center">32</td><td align="left"><code>RF[RA1]</code></td></tr><tr><td align="left"><code>ReadData2</code></td><td align="center">O</td><td align="center">32</td><td align="left"><code>RF[RA2]</code></td></tr></tbody></table><ul><li><strong>功能定义</strong></li></ul><table><thead><tr><th align="center">序号</th><th align="left">功能名称</th><th align="left">功能描述</th></tr></thead><tbody><tr><td align="center">1</td><td align="left">并发异步读<br>(Concurrent Read)</td><td align="left">异步地（即立即）从 <code>ReadAddr1</code> 和 <code>ReadAddr2</code> 指定的地址读取 32 位数据，并分别从 <code>ReadData1</code> 和 <code>ReadData2</code> 端口输出。 (即 <code>RD1=RF[RA1]</code>, <code>RD2=RF[RA2]</code>)</td></tr><tr><td align="center">2</td><td align="left">同步写<br>(Synchronous Write)</td><td align="left">当 <code>RegWrite = 1</code> 时，在 <code>clk</code> 信号的上升沿，将 <code>WriteData</code> 端口的 32 位数据写入到 <code>WriteAddr</code> 指定的寄存器。 (即 <code>RF[WA] = WD</code>)</td></tr><tr><td align="center">3</td><td align="left"><code>$zero</code> 寄存器逻辑</td><td align="left">对应的 <code>ReadData</code> 端口<strong>必须</strong>输出 <code>0x00000000</code>。<br> <code>Reg0</code> 永远不能被修改。</td></tr><tr><td align="center">4</td><td align="left">异步复位</td><td align="left"></td></tr></tbody></table><p><img src="/Blog/images/%E5%AF%84%E5%AD%98%E5%99%A8%E5%A0%86%E5%86%85%E9%83%A8%E7%BB%93%E6%9E%84.png" alt="寄存器堆内部结构"></p><p><img src="/Blog/images/GRF.png" alt="GRF"></p><hr><h4 id="1-1-3-DM-数据存储器"><a href="#1-1-3-DM-数据存储器" class="headerlink" title="1.1.3 DM (数据存储器)"></a>1.1.3 DM (数据存储器)</h4><ul><li>MemRead RE<ul><li>读<br>in: A<br>out: RD &#x3D; DM[A]</li></ul></li><li>MemWrite WE<ul><li>写</li><li>clk<br>in: A, WD<br>out: DM[A] &#x3D; WD</li></ul></li></ul><ul><li><strong>端口定义</strong></li></ul><table><thead><tr><th align="left">信号名</th><th align="center">方向</th><th align="center">位宽</th><th align="left">描述</th></tr></thead><tbody><tr><td align="left"><code>Address</code></td><td align="center">I</td><td align="center">32</td><td align="left">32 位<strong>字节地址</strong> (来自 <code>ALUResult</code>)</td></tr><tr><td align="left"><code>WriteData</code></td><td align="center">I</td><td align="center">32</td><td align="left">32 位待写入数据 (<code>WA</code>)</td></tr><tr><td align="left"><code>MemRead</code></td><td align="center">I</td><td align="center">1</td><td align="left">读使能信号 (<code>RE</code>)</td></tr><tr><td align="left"><code>MemWrite</code></td><td align="center">I</td><td align="center">1</td><td align="left">写使能信号 ( <code>WE</code>)</td></tr><tr><td align="left"><code>clk</code></td><td align="center">I</td><td align="center">1</td><td align="left">时钟信号 (用于同步写入)</td></tr><tr><td align="left"><code>reset</code></td><td align="center">I</td><td align="center">1</td><td align="left">异步复位信号 (用于清空 RAM)</td></tr><tr><td align="left"><code>ReadData</code></td><td align="center">O</td><td align="center">32</td><td align="left">32 位读出数据 (送往 <code>MemtoReg MUX</code>)</td></tr></tbody></table><ul><li><strong>功能定义</strong></li></ul><table><thead><tr><th align="center">序号</th><th align="left">功能名称</th><th align="left">功能描述</th></tr></thead><tbody><tr><td align="center">1</td><td align="left">地址映射<br>(Address Mapping)</td><td align="left">将输入的 32 位字节地址 <code>Address</code>，通过提取 <code>[13:2]</code> 位，转换为内部 <code>RAM</code> 所需的 12 位<strong>字地址</strong>。</td></tr><tr><td align="center">2</td><td align="left">存储器读<br>(Memory Read)</td><td align="left">当 <code>MemRead = 1</code> 时，异步地从转换后的字地址中读取 32 位数据，并将其从 <code>ReadData</code> 端口输出。 (即 <code>RD = DM[A]</code>)</td></tr><tr><td align="center">3</td><td align="left">存储器写<br>(Memory Write)</td><td align="left">当 <code>MemWrite = 1</code> 时，在 <code>clk</code> 信号的上升沿，将 <code>WriteData</code> 端口的32位数据写入到转换后的字地址。 (即 <code>DM[A] = WD</code>)</td></tr><tr><td align="center">4</td><td align="left">异步复位</td><td align="left">当 <code>reset = 1</code> 时，异步地将内部 <code>RAM</code> 的所有单元清零。</td></tr></tbody></table><p><img src="/Blog/images/DM.png" alt="DM"></p><hr><h4 id="1-1-4-nPC-–-有限状态机："><a href="#1-1-4-nPC-–-有限状态机：" class="headerlink" title="1.1.4 nPC – 有限状态机："></a>1.1.4 nPC – 有限状态机：</h4><ul><li>PC (程序计数器) —状态转移—&gt; nPC<ul><li><p>PC 寄存器 – 状态存储模块</p><ul><li>en, reset, clk</li></ul></li><li><p>NPC 模块 – 状态转移电路</p></li><li><p>Pc +&#x3D; 4</p></li><li><p>in: </p><ul><li>pc</li><li>IsB –&gt; Offset(32) &lt;&lt; 2 + pc</li><li>JUMP –&gt; In_26(26) &lt;&lt; 2 + pc[31:28]</li><li>JR –&gt; Ra</li></ul></li><li><p>out: </p><ul><li>Next_PC</li><li>PC+4</li></ul></li></ul></li></ul><ul><li><strong>端口定义</strong></li></ul><table><thead><tr><th align="left">信号名</th><th align="center">方向</th><th align="center">位宽</th><th align="left">描述</th></tr></thead><tbody><tr><td align="left"><code>PC_in</code></td><td align="center">I</td><td align="center">32</td><td align="left"><code>PC</code> 的值 (来自 <code>IFU</code> 模块)</td></tr><tr><td align="left"><code>Offset_Ext</code></td><td align="center">I</td><td align="center">32</td><td align="left">32 位<strong>符号扩展</strong>的立即数 (来自 <code>EXT</code> 模块)</td></tr><tr><td align="left"><code>imm26</code></td><td align="center">I</td><td align="center">26</td><td align="left">26 位跳转立即数 (来自 <code>Splitter_Unit</code> 模块)</td></tr><tr><td align="left"><code>Ra</code></td><td align="center">I</td><td align="center">32</td><td align="left"><code>rs</code> 寄存器的值 (来自 <code>GRF</code> 的 <code>ReadData1</code>)</td></tr><tr><td align="left"><code>IsB</code></td><td align="center">I</td><td align="center">1</td><td align="left"><strong>分支使能</strong>信号。(<code>Main_Control[Branch]</code> <strong>AND</strong> <code>ALU[Zero]</code>)</td></tr><tr><td align="left"><code>JUMP</code></td><td align="center">I</td><td align="center">1</td><td align="left"><strong><code>j</code> 跳转使能</strong>信号 (来自 <code>Main_Control_Unit</code>)</td></tr><tr><td align="left"><code>JR</code></td><td align="center">I</td><td align="center">1</td><td align="left"><strong><code>jr</code> 跳转使能</strong>信号 (来自 <code>ALU_Control_Unit</code>)</td></tr><tr><td align="left"><code>Next_PC</code></td><td align="center">O</td><td align="center">32</td><td align="left">计算得出的<strong>下一条指令地址</strong> (送往 <code>IFU</code> 的 <code>Next_PC</code> 端口)</td></tr><tr><td align="left"><code>PC_plus_4</code></td><td align="center">O</td><td align="center">32</td><td align="left"><code>PC + 4</code> 的值 (来自 <code>IFU</code> 模块)</td></tr></tbody></table><ul><li><strong>功能定义</strong></li></ul><table><thead><tr><th align="center">序号</th><th align="left">功能名称</th><th align="left">功能描述</th></tr></thead><tbody><tr><td align="center">1</td><td align="left">分支地址计算<br>(Branch Target Calculation)</td><td align="left">计算 <code>beq</code> 指令的目标地址：<br><code>Branch_Target = PC_plus_4 + (Offset_Ext &lt;&lt; 2)</code>。</td></tr><tr><td align="center">2</td><td align="left">跳转地址计算<br>(Jump Target Calculation)</td><td align="left">计算 <code>j</code> 指令的目标地址：<br><code>Jump_Target = { PC_plus_4[31:28] , (imm26 &lt;&lt; 2) }</code>。</td></tr><tr><td align="center">3</td><td align="left">PC 优先级选择<br>(Next PC Selection)</td><td align="left">使用一个 4-to-1 MUX (多路选择器)，根据 <code>JR</code>, <code>JUMP</code>, <code>IsB</code> 信号的优先级，在四个可能的下一地址中选择一个作为 <code>Next_PC</code> 输出。</td></tr></tbody></table><p><strong>PC 优先级选择 (功能 3) 的详细逻辑：</strong></p><ul><li><strong><code>JR</code> &#x3D; 1:</strong> <code>Next_PC = Ra</code> (最高优先级)</li><li><strong><code>JR</code> &#x3D; 0, <code>JUMP</code> &#x3D; 1:</strong> <code>Next_PC = Jump_Target</code></li><li><strong><code>JR</code> &#x3D; 0, <code>JUMP</code> &#x3D; 0, <code>IsB</code> &#x3D; 1:</strong> <code>Next_PC = Branch_Target</code></li><li><strong><code>JR</code> &#x3D; 0, <code>JUMP</code> &#x3D; 0, <code>IsB</code> &#x3D; 0:</strong> <code>Next_PC = PC_plus_4</code> (默认顺序执行)</li></ul><p><img src="/Blog/images/nPC.png" alt="nPC"></p><hr><h4 id="1-1-5-IFU（取指令单元）"><a href="#1-1-5-IFU（取指令单元）" class="headerlink" title="1.1.5 IFU（取指令单元）"></a>1.1.5 IFU（取指令单元）</h4><h5 id="IM-指令存储器"><a href="#IM-指令存储器" class="headerlink" title="IM (指令存储器)"></a>IM (指令存储器)</h5><ul><li><strong>端口定义</strong></li></ul><table><thead><tr><th align="left">信号名</th><th align="center">方向</th><th align="center">位宽</th><th align="left">描述</th></tr></thead><tbody><tr><td align="left"><code>A</code></td><td align="center">I</td><td align="center">32</td><td align="left">32 位<strong>字节地址</strong> (来自 <code>IFU</code> 模块的 <code>PC</code>)</td></tr><tr><td align="left"><code>RD</code></td><td align="center">O</td><td align="center">32</td><td align="left">从存储器中读取的 32 位<strong>指令码</strong></td></tr></tbody></table><ul><li><strong>功能定义</strong></li></ul><table><thead><tr><th align="center">序号</th><th align="left">功能名称</th><th align="left">功能描述</th></tr></thead><tbody><tr><td align="center">1</td><td align="left">地址映射<br>(Address Mapping)</td><td align="left">将输入的 32 位字节地址 <code>A</code>，通过减去起始地址偏移量 <code>0x3000</code> 并右移两位（即提取 <code>[13:2]</code> 位），转换为 12 位的<strong>字地址</strong>。</td></tr><tr><td align="center">2</td><td align="left">指令读取<br>(Instruction Read)</td><td align="left">使用转换后的 12 位字地址，从内部 <code>ROM</code> (只读存储器) 中异步读取一条 32 位的指令，并将其从 <code>RD</code> 端口输出。</td></tr></tbody></table><p><img src="/Blog/images/IMm.png" alt="IMm"></p><h5 id="IFU-取指令单元"><a href="#IFU-取指令单元" class="headerlink" title="IFU (取指令单元)"></a>IFU (取指令单元)</h5><ul><li><strong>端口定义</strong></li></ul><table><thead><tr><th align="left">信号名</th><th align="center">方向</th><th align="center">位宽</th><th align="left">描述</th></tr></thead><tbody><tr><td align="left"><code>Next_PC</code></td><td align="center">I</td><td align="center">32</td><td align="left">下一个时钟周期将要载入的 PC 值 (来自 <code>NPC</code> 模块)</td></tr><tr><td align="left"><code>clk</code></td><td align="center">I</td><td align="center">1</td><td align="left">系统时钟信号</td></tr><tr><td align="left"><code>reset</code></td><td align="center">I</td><td align="center">1</td><td align="left">系统异步复位信号</td></tr><tr><td align="left"><code>stop</code></td><td align="center">I</td><td align="center">1</td><td align="left">时钟使能 (Clock Enable) 信号 (低电平有效，用于暂停 PC)</td></tr><tr><td align="left"><code>PC</code></td><td align="center">O</td><td align="center">32</td><td align="left"><strong>当前</strong> PC 寄存器中存储的地址值 (送往 <code>IM</code> 和 <code>NPC</code>)</td></tr><tr><td align="left"><code>Instr</code></td><td align="center">O</td><td align="center">32</td><td align="left"><code>PC</code> 对应的<strong>当前指令码</strong> (来自 <code>IM</code> 模块)</td></tr></tbody></table><ul><li><strong>功能定义</strong></li></ul><table><thead><tr><th align="center">序号</th><th align="left">功能名称</th><th align="left">功能描述</th></tr></thead><tbody><tr><td align="center">1</td><td align="left">PC 更新<br>(PC Update)</td><td align="left">在 <code>clk</code> 上升沿，且 <code>stop</code> 信号为 0 (无效) 时，将 <code>Next_PC</code> 的值载入 PC 寄存器。</td></tr><tr><td align="center">2</td><td align="left">PC 复位<br>(PC Reset)</td><td align="left">当 <code>reset</code> 信号为 1 时，异步地将 PC 寄存器的值强制设为起始地址 <code>0x00003000</code>。</td></tr><tr><td align="center">3</td><td align="left">指令获取<br>(Instruction Fetch)</td><td align="left">将 <code>PC</code> 寄存器的当前值输出到 <code>PC</code> 端口，并将其送至内部的 <code>IM</code> 模块，以获取对应的 32 位指令，并从 <code>Instr</code> 端口输出。</td></tr><tr><td align="center">4</td><td align="left">PC+4 计算<br>(PC+4 Calculation)</td><td align="left">并行地计算 <code>PC</code> 寄存器当前值加 4 的结果，并从 <code>PC_plus_4</code> 端口输出。</td></tr></tbody></table><p><img src="/Blog/images/IFU.png" alt="IFU"></p><hr><h4 id="1-1-6-EXT-拓展单元"><a href="#1-1-6-EXT-拓展单元" class="headerlink" title="1.1.6 EXT (拓展单元)"></a>1.1.6 EXT (拓展单元)</h4><p>将16位立即数符号拓展为32位。这里为了提高可拓展性，添加了 <code>OPExt</code> 接口</p><ul><li><strong>端口定义</strong></li></ul><table><thead><tr><th align="left">信号名</th><th align="left">方向</th><th align="left">位宽</th><th align="left">描述</th></tr></thead><tbody><tr><td align="left">Imm_16</td><td align="left">I</td><td align="left">16</td><td align="left">16位立即数输入信号</td></tr><tr><td align="left">OPExt</td><td align="left">I</td><td align="left">1</td><td align="left">符号拓展信号 <br> 0：无符号拓展（0拓展） <br> 1：符号拓展</td></tr><tr><td align="left">Imm_32</td><td align="left">O</td><td align="left">32</td><td align="left">32位立即数输出信号</td></tr></tbody></table><ul><li><strong>功能定义</strong></li></ul><table><thead><tr><th align="left">序号</th><th align="left">功能名称</th><th align="left">功能描述</th></tr></thead><tbody><tr><td align="left">1</td><td align="left">符号拓展</td><td align="left">将16位立即数进行符号拓展</td></tr></tbody></table><p><img src="/Blog/images/EXT.png" alt="EXT"></p><hr><h4 id="1-1-7-SPLI-指令分离器模块"><a href="#1-1-7-SPLI-指令分离器模块" class="headerlink" title="1.1.7 SPLI(指令分离器模块)"></a>1.1.7 SPLI(指令分离器模块)</h4><ul><li><strong>端口定义</strong></li></ul><table><thead><tr><th align="left">信号名</th><th align="center">方向</th><th align="center">位宽</th><th align="left">描述</th></tr></thead><tbody><tr><td align="left"><code>Instr</code></td><td align="center">I</td><td align="center">32</td><td align="left">来自 IFU (指令存储器) 的 32 位完整指令码</td></tr><tr><td align="left"><code>Opcode</code></td><td align="center">O</td><td align="center">6</td><td align="left">操作码 (<code>[31:26]</code>)，送往 <code>Main Control Unit</code></td></tr><tr><td align="left"><code>rs</code></td><td align="center">O</td><td align="center">5</td><td align="left">源寄存器 1 (<code>[25:21]</code>)，送往 <code>GRF[RA1]</code> 和 <code>NPC[Ra]</code></td></tr><tr><td align="left"><code>rt</code></td><td align="center">O</td><td align="center">5</td><td align="left">源寄存器 2 &#x2F; 目标 (<code>[20:16]</code>)，送往 <code>GRF[RA2]</code> 和 <code>RegDst MUX</code></td></tr><tr><td align="left"><code>rd</code></td><td align="center">O</td><td align="center">5</td><td align="left">目标寄存器 (<code>[15:11]</code>)，送往 <code>RegDst MUX</code></td></tr><tr><td align="left"><code>shamt</code></td><td align="center">O</td><td align="center">5</td><td align="left">移位量 (<code>[10:6]</code>)，送往 <code>ALU[Shamt]</code></td></tr><tr><td align="left"><code>funct</code></td><td align="center">O</td><td align="center">6</td><td align="left">功能码 (<code>[5:0]</code>)，送往 <code>ALU Control Unit</code></td></tr><tr><td align="left"><code>imm16</code></td><td align="center">O</td><td align="center">16</td><td align="left">16 位立即数 (<code>[15:0]</code>)，送往 <code>EXT</code> 和 <code>LUI Shifter</code></td></tr><tr><td align="left"><code>imm26</code></td><td align="center">O</td><td align="center">26</td><td align="left">26 位跳转地址 (<code>[25:0]</code>)，送往 <code>NPC</code></td></tr></tbody></table><ul><li><strong>功能定义</strong></li></ul><table><thead><tr><th align="center">序号</th><th align="left">功能名称</th><th align="left">功能描述</th></tr></thead><tbody><tr><td align="center">1</td><td align="left">指令字段分离<br>(Instruction Field Separation)</td><td align="left">将 32 位的 <code>Instruction</code> 输入，根据 MIPS 指令格式，并行地分离为 <code>Op</code>, <code>rs</code>, <code>rt</code>, <code>rd</code>, <code>shamt</code>, <code>funct</code>, <code>imm16</code> 和 <code>imm26</code> 共 8 个字段，并从对应端口输出。</td></tr></tbody></table><p><img src="/Blog/images/SPLI.png" alt="SPLI"></p><hr><h3 id="指令格式"><a href="#指令格式" class="headerlink" title="指令格式"></a>指令格式</h3><h4 id="R型指令格式"><a href="#R型指令格式" class="headerlink" title="R型指令格式"></a>R型指令格式</h4><p><img src="/Blog/images/R%E5%9E%8B%E6%8C%87%E4%BB%A4%E6%A0%BC%E5%BC%8F.png" alt="R型指令格式"></p><h5 id="add-sub-and-or-rd-rs-rt"><a href="#add-sub-and-or-rd-rs-rt" class="headerlink" title="add,sub,and,or rd, rs, rt"></a><code>add,sub,and,or rd, rs, rt</code></h5><table><thead><tr><th align="center">操作</th><th align="center">Op</th><th align="center">Rs</th><th align="center">Rt</th><th align="center">Rd</th><th align="center">Shamt</th><th align="center">Func</th></tr></thead><tbody><tr><td align="center">位宽</td><td align="center">6</td><td align="center">5</td><td align="center">5</td><td align="center">5</td><td align="center">5</td><td align="center">6</td></tr></tbody></table><h4 id="LW-SW指令格式"><a href="#LW-SW指令格式" class="headerlink" title="LW&amp;SW指令格式"></a>LW&amp;SW指令格式</h4><p><img src="/Blog/images/LW&SW%E6%8C%87%E4%BB%A4%E6%A0%BC%E5%BC%8F.png" alt="LW&amp;SW指令格式"></p><h5 id="lw-sw-rt-rs-imm16"><a href="#lw-sw-rt-rs-imm16" class="headerlink" title="lw,sw rt, rs, imm16"></a><code>lw,sw rt, rs, imm16</code></h5><table><thead><tr><th align="center">操作</th><th align="center">Op</th><th align="center">Rs</th><th align="center">Rt</th><th align="center">imm</th></tr></thead><tbody><tr><td align="center">位宽</td><td align="center">6</td><td align="center">5</td><td align="center">5</td><td align="center">16</td></tr></tbody></table><h4 id="分支指令格式"><a href="#分支指令格式" class="headerlink" title="分支指令格式"></a>分支指令格式</h4><p><img src="/Blog/images/%E5%88%86%E6%94%AF%E6%8C%87%E4%BB%A4%E6%A0%BC%E5%BC%8F.png" alt="分支指令格式"></p><h5 id="beq-rs-rt-imm16"><a href="#beq-rs-rt-imm16" class="headerlink" title="beq rs,  rt,  imm16"></a><code>beq rs,  rt,  imm16</code></h5><table><thead><tr><th align="center">操作</th><th align="center">Op</th><th align="center">Rs</th><th align="center">Rt</th><th align="center">imm</th></tr></thead><tbody><tr><td align="center">位宽</td><td align="center">6</td><td align="center">5</td><td align="center">5</td><td align="center">16</td></tr></tbody></table><h4 id="跳转指令格式"><a href="#跳转指令格式" class="headerlink" title="跳转指令格式"></a>跳转指令格式</h4><p><img src="/Blog/images/%E8%B7%B3%E8%BD%AC%E6%8C%87%E4%BB%A4%E6%A0%BC%E5%BC%8F.png" alt="跳转指令格式"></p><h5 id="j-add26"><a href="#j-add26" class="headerlink" title="j add26 "></a><code>j add26 </code></h5><table><thead><tr><th align="center">操作</th><th align="center">Op</th><th align="center">JAdd</th></tr></thead><tbody><tr><td align="center">位宽</td><td align="center">6</td><td align="center">26</td></tr></tbody></table><hr><h2 id="2-单周期控制器设计"><a href="#2-单周期控制器设计" class="headerlink" title="2. 单周期控制器设计"></a>2. 单周期控制器设计</h2><p><img src="/Blog/images/%E5%8D%95%E5%91%A8%E6%9C%9F%E6%8E%A7%E5%88%B6%E5%99%A8%E8%AE%BE%E8%AE%A1.png" alt="单周期控制器设计"></p><h3 id="2-1-单周期通路所需控制信号"><a href="#2-1-单周期通路所需控制信号" class="headerlink" title="2.1 单周期通路所需控制信号"></a>2.1 单周期通路所需控制信号</h3><h4 id="2-1-1-ALU控制（ALUCtrl）：4位"><a href="#2-1-1-ALU控制（ALUCtrl）：4位" class="headerlink" title="2.1.1 ALU控制（ALUCtrl）：4位"></a>2.1.1 ALU控制（ALUCtrl）：4位</h4><table><thead><tr><th align="left">输入</th><th align="center">ALUCtrl</th><th align="center">运算</th></tr></thead><tbody><tr><td align="left">A, B</td><td align="center">0000</td><td align="center"><code>A &amp; B</code></td></tr><tr><td align="left">A, B</td><td align="center">0001</td><td align="center"><code>A | B</code></td></tr><tr><td align="left">A, B</td><td align="center">0010</td><td align="center"><code>A + B</code></td></tr><tr><td align="left">A, B</td><td align="center">0110</td><td align="center"><code>A - B</code></td></tr></tbody></table><h4 id="2-1-2-8个控制信号："><a href="#2-1-2-8个控制信号：" class="headerlink" title="2.1.2 8个控制信号："></a>2.1.2 8个控制信号：</h4><table><thead><tr><th align="center">控制信号</th><th align="center">0</th><th align="center">1</th></tr></thead><tbody><tr><td align="center">RegDst</td><td align="center">Reg堆写入端地址：Rt</td><td align="center">Reg堆写入端地址：Rd</td></tr><tr><td align="center">RegWrite</td><td align="center">无</td><td align="center">Reg写入：<strong><code>Reg[WA] = WD</code></strong></td></tr><tr><td align="center">ALUSrc</td><td align="center">ALU-B：RD2</td><td align="center">ALU-B：imm Signext</td></tr><tr><td align="center">PCSrc</td><td align="center">PC &#x3D; (PC+4)</td><td align="center">PC &#x3D; NAdd (beq目的地址)</td></tr><tr><td align="center">PCJump</td><td align="center">PC &#x3D; MUX的输出</td><td align="center">PC &#x3D; J指令目的地址</td></tr><tr><td align="center">MemRead</td><td align="center">无</td><td align="center">DM读（输出）</td></tr><tr><td align="center">MemWrite</td><td align="center">无</td><td align="center">DM写（输入）</td></tr><tr><td align="center">MemtoReg</td><td align="center">Reg写入 &lt;– ALU</td><td align="center">Reg写入 &lt;– DM</td></tr><tr><td align="center">Branch</td><td align="center">无</td><td align="center">为Beq指令</td></tr></tbody></table><hr><h3 id="2-2-控制器设计"><a href="#2-2-控制器设计" class="headerlink" title="2.2 控制器设计"></a>2.2 控制器设计</h3><p><img src="/Blog/images/controler.png" alt="controler"></p><h4 id="2-2-1-Main-Control-Unit"><a href="#2-2-1-Main-Control-Unit" class="headerlink" title="2.2.1 Main Control Unit"></a>2.2.1 Main Control Unit</h4><h5 id="2-1-设计思路"><a href="#2-1-设计思路" class="headerlink" title="2.1 设计思路"></a>2.1 设计思路</h5><ol><li><strong><code>MemtoReg</code> (2 位):</strong> <ul><li><code>00</code>: <code>ALUResult</code> (用于 R-type, <code>ori</code>)</li><li><code>01</code>: <code>DM[ReadData]</code> (用于 <code>lw</code>)</li><li><code>10</code>: <code>LUI_Value</code> (用于 <code>lui</code>)</li></ul></li><li><strong><code>ExtOp</code> (1 位):</strong>  用于控制扩展单元。<ul><li><code>0</code>: 零扩展 (for <code>ori</code>)</li><li><code>1</code>: 符号扩展 (for <code>lw</code>, <code>sw</code>, <code>beq</code>)</li></ul></li><li><strong><code>Jump</code> (1 位):</strong> (图中的 <code>PCJump</code>) 用于 <code>j</code> 指令。</li><li><strong><code>JR</code> 信号：</strong> 已移至 <code>ALU Control Unit</code>。</li></ol><h5 id="2-2-端口定义"><a href="#2-2-端口定义" class="headerlink" title="2.2 端口定义"></a>2.2 端口定义</h5><ul><li><strong>输入 (Inputs):</strong><ul><li><code>Opcode[5:0]</code>: 来自指令码的 <code>[31:26]</code> 位 (操作码)。</li></ul></li><li><strong>输出 (Outputs):</strong><ul><li><code>RegDst[0]</code>: (1: R-type 写 <code>rd</code>, 0: I-type 写 <code>rt</code>)</li><li><code>ALUSrc[0]</code>: (1: 立即数, 0: <code>GRF[ReadData2]</code>)</li><li><code>MemtoReg[1:0]</code>: (2 位) (写回 GRF 的数据源选择)</li><li><code>RegWrite[0]</code>: (1: 允许写入 GRF)</li><li><code>MemRead[0]</code>: (1: 允许读取 DM)</li><li><code>MemWrite[0]</code>: (1: 允许写入 DM)</li><li><code>Branch[0]</code>: (1: <code>beq</code> 指令)</li><li><code>Jump[0]</code>: (1: <code>j</code> 指令)</li><li><code>ExtOp[0]</code>: (1: 符号扩展, 0: 零扩展)</li><li><code>ALUOp[2:0]</code>: (3 位) (送往 <code>ALU Control Unit</code>)</li></ul></li></ul><h5 id="2-3-真值表"><a href="#2-3-真值表" class="headerlink" title="2.3 真值表"></a>2.3 真值表</h5><table><thead><tr><th align="center">指令</th><th align="center"><code>Opcode</code></th><th align="center"><code>RegDst</code></th><th align="center"><code>ALUSrc</code></th><th align="center"><code>MemtoReg</code></th><th align="center"><code>RegWrite</code></th><th align="center"><code>MemRead</code></th><th align="center"><code>MemWrite</code></th><th align="center"><code>Branch</code></th><th align="center"><code>Jump</code></th><th align="center"><code>ExtOp</code></th><th align="center"><strong><code>ALUOp[2:0]</code></strong></th></tr></thead><tbody><tr><td align="center"><strong><code>R-type</code></strong></td><td align="center"><code>000000</code></td><td align="center">1</td><td align="center">0</td><td align="center"><code>00</code></td><td align="center">1</td><td align="center">0</td><td align="center">0</td><td align="center">0</td><td align="center">0</td><td align="center">X</td><td align="center"><strong><code>100</code></strong></td></tr><tr><td align="center"><strong><code>lw</code></strong></td><td align="center"><code>100011</code></td><td align="center">0</td><td align="center">1</td><td align="center"><code>01</code></td><td align="center">1</td><td align="center">1</td><td align="center">0</td><td align="center">0</td><td align="center">0</td><td align="center">1</td><td align="center"><strong><code>000</code></strong></td></tr><tr><td align="center"><strong><code>sw</code></strong></td><td align="center"><code>101011</code></td><td align="center">X</td><td align="center">1</td><td align="center"><code>XX</code></td><td align="center">0</td><td align="center">0</td><td align="center">1</td><td align="center">0</td><td align="center">0</td><td align="center">1</td><td align="center"><strong><code>000</code></strong></td></tr><tr><td align="center"><strong><code>beq</code></strong></td><td align="center"><code>000100</code></td><td align="center">X</td><td align="center">0</td><td align="center"><code>XX</code></td><td align="center">0</td><td align="center">0</td><td align="center">0</td><td align="center">1</td><td align="center">0</td><td align="center">1</td><td align="center"><strong><code>001</code></strong></td></tr><tr><td align="center"><strong><code>ori</code></strong></td><td align="center"><code>001101</code></td><td align="center">0</td><td align="center">1</td><td align="center"><code>00</code></td><td align="center">1</td><td align="center">0</td><td align="center">0</td><td align="center">0</td><td align="center">0</td><td align="center">0</td><td align="center"><strong><code>010</code></strong></td></tr><tr><td align="center"><strong><code>lui</code></strong></td><td align="center"><code>001111</code></td><td align="center">0</td><td align="center">X</td><td align="center"><code>10</code></td><td align="center">1</td><td align="center">0</td><td align="center">0</td><td align="center">0</td><td align="center">0</td><td align="center">X</td><td align="center"><code>XXX</code></td></tr><tr><td align="center"><strong><code>addi</code></strong></td><td align="center"><code>001000</code></td><td align="center">0</td><td align="center">1</td><td align="center"><code>00</code></td><td align="center">1</td><td align="center">0</td><td align="center">0</td><td align="center">0</td><td align="center">0</td><td align="center">1</td><td align="center"><strong><code>000</code></strong></td></tr><tr><td align="center"><strong><code>j</code></strong></td><td align="center"><code>000010</code></td><td align="center">X</td><td align="center">X</td><td align="center"><code>XX</code></td><td align="center">0</td><td align="center">0</td><td align="center">0</td><td align="center">0</td><td align="center">1</td><td align="center">X</td><td align="center"><code>XXX</code></td></tr></tbody></table><p><strong>3 位 <code>ALUOp</code> 编码：</strong></p><ul><li><code>000</code>: <code>lw</code>&#x2F;<code>sw</code> (主控制器要求 <strong>ADD</strong>)</li><li><code>001</code>: <code>beq</code> (主控制器要求 <strong>SUB</strong>)</li><li><code>010</code>: <code>ori</code> (主控制器要求 <strong>OR</strong>)</li><li><code>011</code>: (预留, e.g., for <code>andi</code>)</li><li><code>100</code>: <strong>R-type</strong> (主控制器说：“我不知道，请查看 <code>funct</code> 码”)</li><li><code>101</code>: (预留, e.g., for <code>xori</code>)</li><li><code>110</code>: (预留, e.g., for <code>addi</code>)</li><li><code>111</code>: (预留)</li></ul><p><strong>关于 <code>nop</code> (0x00000000) 的说明：</strong><br><code>nop</code> 指令的 <code>Opcode</code> 是 <code>000000</code>，<code>Funct</code> 是 <code>000000</code>。</p><ol><li><code>Main Control</code> 会将其视为 <strong>R-type</strong>。</li><li><code>ALU Control</code> 会将其视为 <strong><code>sll</code></strong>。</li><li>它最终执行 <code>sll $zero, $zero, 0</code>。</li><li>控制器会尝试将结果 <code>0</code> 写入 <code>$zero</code> 寄存器。</li></ol><hr><h4 id="顶层逻辑补充"><a href="#顶层逻辑补充" class="headerlink" title="顶层逻辑补充"></a>顶层逻辑补充</h4><ul><li><strong>最终的 <code>RegWrite</code> 信号：</strong> <code>jr</code> 指令不应该写寄存器。因此，连接到 GRF 的最终 <code>RegWrite_Enable</code> 信号应该是：<ul><li><code>RegWrite_Enable</code> &#x3D; <code>Main_Control[RegWrite]</code> <strong>AND</strong> ( <strong>NOT</strong> <code>ALU_Control[JR]</code> )</li></ul></li></ul><p><img src="/Blog/images/%E4%B8%BB%E6%8E%A7%E5%8D%95%E5%85%83%E9%80%BB%E8%BE%91%E5%AE%9E%E7%8E%B0.png" alt="主控单元逻辑实现"></p><p><img src="/Blog/images/MCU.png" alt="MCU"></p><hr><h4 id="2-2-2-ALU-Control-Unit"><a href="#2-2-2-ALU-Control-Unit" class="headerlink" title="2.2.2 ALU Control Unit"></a>2.2.2 ALU Control Unit</h4><h5 id="1-2-端口定义"><a href="#1-2-端口定义" class="headerlink" title="1.2 端口定义"></a>1.2 端口定义</h5><ul><li><strong>输入 (Inputs):</strong><ul><li><code>ALUOp[2:0]</code>: 来自 Main Control Unit (主控制器) 的 3 位操作码。</li><li><code>Func[5:0]</code>: 来自指令码的 <code>[5:0]</code> 位 (功能码)。</li></ul></li><li><strong>输出 (Outputs):</strong><ul><li><code>ALUCtrl[3:0]</code>: 送往 ALU 的 4 位最终运算码 (我们之前已约定 <code>0000</code>&#x3D;ADD, <code>0001</code>&#x3D;SUB, <code>0010</code>&#x3D;AND, <code>0011</code>&#x3D;OR, <code>0100</code>&#x3D;SLT, <code>0101</code>&#x3D;SLL)。</li><li><code>JR[0]</code>: <strong>(新增输出)</strong> 用于 <code>jr</code> 指令。当 <code>ALUOp=100</code> 且 <code>Func=001000</code> 时，此信号为 1。</li></ul></li></ul><h5 id="1-3-真值表"><a href="#1-3-真值表" class="headerlink" title="1.3 真值表"></a>1.3 真值表</h5><table><thead><tr><th align="center"><code>ALUOp[2:0]</code> (输入)</th><th align="center"><code>Func[5:0]</code> (输入)</th><th align="center">备注 (指令)</th><th align="center"><strong><code>ALUCtrl[3:0]</code> (输出)</strong></th><th align="center"><strong><code>JR[0]</code> (输出)</strong></th></tr></thead><tbody><tr><td align="center"><code>000</code></td><td align="center">X (任意)</td><td align="center"><code>lw</code> &#x2F; <code>sw</code></td><td align="center"><strong><code>0000</code></strong> (ADD)</td><td align="center"><strong>0</strong></td></tr><tr><td align="center"><code>001</code></td><td align="center">X (任意)</td><td align="center"><code>beq</code></td><td align="center"><strong><code>0001</code></strong> (SUB)</td><td align="center"><strong>0</strong></td></tr><tr><td align="center"><code>010</code></td><td align="center">X (任意)</td><td align="center"><code>ori</code></td><td align="center"><strong><code>0011</code></strong> (OR)</td><td align="center"><strong>0</strong></td></tr><tr><td align="center"><code>011</code></td><td align="center">X (任意)</td><td align="center">(预留)</td><td align="center">X (e.g., <code>0000</code>)</td><td align="center"><strong>0</strong></td></tr><tr><td align="center"><strong><code>100</code></strong></td><td align="center"><code>100000</code></td><td align="center"><code>add</code></td><td align="center"><strong><code>0000</code></strong> (ADD)</td><td align="center"><strong>0</strong></td></tr><tr><td align="center"><strong><code>100</code></strong></td><td align="center"><code>100010</code></td><td align="center"><code>sub</code></td><td align="center"><strong><code>0001</code></strong> (SUB)</td><td align="center"><strong>0</strong></td></tr><tr><td align="center"><strong><code>100</code></strong></td><td align="center"><code>100100</code></td><td align="center"><code>and</code></td><td align="center"><strong><code>0010</code></strong> (AND)</td><td align="center"><strong>0</strong></td></tr><tr><td align="center"><strong><code>100</code></strong></td><td align="center"><code>101010</code></td><td align="center"><code>slt</code></td><td align="center"><strong><code>0100</code></strong> (SLT)</td><td align="center"><strong>0</strong></td></tr><tr><td align="center"><strong><code>100</code></strong></td><td align="center"><code>000000</code></td><td align="center"><code>sll</code> (或 <code>nop</code>)</td><td align="center"><strong><code>0101</code></strong> (SLL)</td><td align="center"><strong>0</strong></td></tr><tr><td align="center"><strong><code>100</code></strong></td><td align="center"><code>001000</code></td><td align="center"><strong><code>jr</code></strong></td><td align="center">X (e.g., <code>0000</code>)</td><td align="center"><strong>1</strong></td></tr><tr><td align="center">(other)</td><td align="center">(other)</td><td align="center">(Undefined)</td><td align="center">X (e.g., <code>0000</code>)</td><td align="center"><strong>0</strong></td></tr></tbody></table><p><img src="/Blog/images/ACU.png" alt="ACU"></p><hr><p>课下总结：<br>P3做出来两道题，也算是通过了，第一周的时候没估算好要完成的时间，结果周日前没做完，直接拖了一周进度。<br>于是周一喜提上机放假，最终又花了一天半多才完成最终版。<br>但是最终版甚至连弱测都没有通过。省略漫长的debug阶段，最终还是通过求助助教，发现bug的原因竟是 <strong>多了一个ROM</strong> ！！<br>把这个ROM改成逻辑元件后，就通过了。<br>不能有多余ROM的原因，是评测机在评测时，这会通过正则匹配到ROM，然后读取其中的数据，所以我增加一个ROM后就会导致评测出错。</p><hr><p>思考题</p><ol><li>现在我们的模块中 IM 使用 ROM， DM 使用 RAM， GRF 使用 Register，这种做法合理吗？ 请给出分析，若有改进意见也请一并给出。<br>A：合理。ROM是只读存储器，因此可以用来储存指令；RAM既可以读也可以写，因此满足DM对读写的要求；GRF是寄存器堆，需要较高的读写速度，因此适合用寄存器实现。</li><li>事实上，实现 nop 空指令，我们并不需要将它加入控制信号真值表，为什么？请给出你的理由。<br>A：nop指令码为0x00000000，相当于sll $0, $0, 0, 相当于把$0寄存器中的值左移0位并写入$0寄存器，因为$0的值始终为0，不会被修改，因此该指令执行后没有任何影响。即使cpu没有设置sll指令，nop指令也不会对电路中任何元件进行操作，对电路没有任何影响。</li></ol>]]></content>
    
    
      
      
        
        
    <summary type="html">&lt;h1 id=&quot;MIPS单周期处理器设计&quot;&gt;&lt;a href=&quot;#MIPS单周期处理器设计&quot; class=&quot;headerlink&quot;</summary>
        
      
    
    
    
    
    <category term="CO" scheme="https://begineri.github.io/Blog/tags/CO/"/>
    
  </entry>
  
  <entry>
    <title>为什么创建这个博客</title>
    <link href="https://begineri.github.io/Blog/2025/11/06/%E4%B8%BA%E4%BB%80%E4%B9%88%E5%88%9B%E5%BB%BA%E8%BF%99%E4%B8%AA%E5%8D%9A%E5%AE%A2/"/>
    <id>https://begineri.github.io/Blog/2025/11/06/%E4%B8%BA%E4%BB%80%E4%B9%88%E5%88%9B%E5%BB%BA%E8%BF%99%E4%B8%AA%E5%8D%9A%E5%AE%A2/</id>
    <published>2025-11-06T11:49:53.000Z</published>
    <updated>2026-02-18T14:35:50.515Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>The reason why I created this blog…</p></blockquote><h3 id="Why-There"><a href="#Why-There" class="headerlink" title="Why There"></a>Why There</h3><p>这个平台，独立于QQ或是WX的朋友圈，不是所有我的 “好友”都能看见，看见的也可以不只是我的好友。<br>这又不像小红书、豆瓣、微博等论坛，这里没有广告，没有杂乱的界面————这个网站的一切都是可以让我定制的，我可以随意尝试不同的功能、加入喜欢的元素，而不受限制。</p><h3 id="How-to-Make-It"><a href="#How-to-Make-It" class="headerlink" title="How to Make It"></a>How to Make It</h3><p>本博客构建基于 <a href="https://hexo.io/zh-cn/">hexo</a>，按照官网上的步骤，很容易搭建起来（遇到问题，AI也可以解决）。</p><h3 id="About-Other"><a href="#About-Other" class="headerlink" title="About Other"></a>About Other</h3><p>说到ai，仔细想想，如今我每天的生活已经离不开ai了，不管是大事还是小事，都能问问ai，而对方也总能给你一个说得过去的回答–大多数时候，回答还是令人满意的。<br>不可否认的，ai帮助我完成了很多从零到一的学习。对于一个几乎陌生的领域，刚开始将不可避免的感到手足无措，不过在刚开始，遇到的问题都不那么复杂，这也意味着ai能较好地帮助你解决问题，帮你除去新入门时的障碍（就搭建这个博客来说，期间有些步骤我不确定如何去做，发给ai，它就可以按照我的现状给出解决方案）。<br>对ai的依赖性，是在不知不觉间慢慢增加的。还记得去年上导论课要配置环境，这一个报错那一个报错，我的解决方法就是<code>复制报错内容到浏览器进行搜索</code>，这个搜索过程往往是漫长而艰难的，从一大堆信息里分辨自己所需的哪条十分之困难而耗时。很多时候，都是搜索一小时，解决一个bug，然后新增三个bug，甚至最终也没办法解决（当然有我搜索水平的因素）。<br>面对是在配不好的环境，我去询问一位助教学姐，她的做法是直接把我的报错信息全复制，然后<code>扔给Deepseek，说&quot;报错怎么解决：&quot;</code>，ai也确实解决了问题。回想起来，这是让我第一次意识到ai可以帮你解决这样的问题，进一步的说，<strong>ai可以替代搜索引擎</strong>了。也许从那时开始，我就逐渐减少了使用直接搜索的这种方式，而之后它的应用范围也从解决代码报错渗透到各个方面，比如：</p><blockquote><p>有没有什么方法可以实现xxx？<br>这段代码有没有更好的写法？<br>解释一下这个公式的推导过程<br>这个功能怎么用（截图）？<br>markdown文本如何实现首行缩进？</p></blockquote><p>可以发现，除了一些简单的操作（比如搜索某官网之类），我几乎用ai替代了搜索。而实践表明，大多数时候这样效率还是很高的。而且ai也十分易于回答你进一步的问题，你只需要用最通俗的语言向它发问，它总能给你一个还算满意的答案。对比于搜索引擎，你还要费心寻找一个用更恰当的表述去搜索到想要的答案，对于懒惰的我，自然选择拥抱前者。<br>使用ai的过程中，我们从<code>被问问题的人</code>， 变成了那个<code>提出问题的人</code>，也许你有无尽的问题，而ai面对你无尽的问题总能给出一个结果，至于满不满意，那需要自己的判断。甚至不满意，你可以继续发问，直到累了或者厌倦。<br>我时常忘记，ai生成的答案只是一串数学计算的结果，只是一串概率的数字，而不具有现实的“意义”，不像是人们由<code>意识</code>而产生的语言于答案，更无从保证它的正确性。但越是频繁的使用，我越是为它能达到的能力而感到神奇，它有的只是一堆数据，却能给出满足如此多不同场景下的不同需求的答案，（关于ai是如何处理逻辑这回事，它其实就是依靠高概率来进行“逻辑”推断，当涉及到绝对真假的时候LLM就要引入外部的工具来验证，比如“计算器”或“代码解释器”，具体可参考这个<a href="https://begineri.github.io/Blog/2025/11/13/%E4%B8%8ELLM%E7%9A%84%E4%B8%80%E4%BA%9B%E5%AF%B9%E8%AF%9D/">新发的文章</a>），以至于我时常提醒自己这一点，让我不要太依赖它–但说回来，大多数时候，ai给的答案确实没问题X<br>上次发现自己已经离不开ai，是在这学期开学一段时间后，我发现我每天（没有几乎，就是每一天）都会打开豆包，给它发一堆问题，其中大多数是课堂上直接拍照ppt让它解释，或是让它帮我做作业题。然后可能是随着课程内容难度的逐步增大，豆包已经回答不了那些问题了，我开始转向Gemini，直到最近，我发现我已经离不开它了。小到作业题解析，大到搭建这个博客，或是优化代码，搭建CPU，我都乐此不疲地与它对话。<br>我在思考，这是否会让我变得越发懒惰而不愿意自己进行深入思考。于是我也开始在一些时候抑制住直接问ai的冲动，而是自己再想一想，再耐心一点–我的确发现自己在很多时候是能自己想出来的，而且自己想出来的答案的确优于ai给的那些。<br>ai让我们接受的信息密度进一步增加了。我们可以发给他1000字，然后说：总结成200字，于是它就会照做，然后我们就能阅读到这份浓缩的文字（至于它是否还能还原原本的意思，读者不得而知），这里的信息密度是很高的，这样的文字看似一时之间省了时间和精力，但我想这样高强度的阅读确实会让人更快疲惫，很难说是否提高了效率。<br>但确实，ai可以成为一个随时回答你问题的老师，这点对于自学的同学是一个巨大的帮助。你可以就一个点一直深入下去，弄懂你想知道的一切。在去年差不多这个时候，我在学习线性代数，它的题全网搜不到答案，问当时的ai，ai也回答不出来有条理的正确答案，于是遇到实在不懂的题，我只能放下它不管，最终也学的是似懂非懂，许多概念都不理解，在期末考试之前拟合一下往年题，然后去考试。考完试，那些概念也就淡忘了，如今在用到那些线代相关的知识，依旧感觉如此模糊而无法运用。我现在想，如果当时有如今ai的话，我的线代不会学的那么差。<br>于是我又想到，学生对ai的广泛使用，是否会<code>降低对老师的需求</code>，学生现在遇到问题，会直接寻求ai的帮助，其次再是同学、助教，最后才是老师。以前的老师，有时候还会解决一下学生最不解的问题，而现在他们要做的事情更简单了，只需要上课放个ppt，然后下课走人，甚至学生都不需要听他念ppt了–把ppt不懂的地方直接截图给ai，ai便能解决你的大多数问题–这比上课听课的效率高了不止一点半点。这点超过了百分之85的老师，剩下百分之十几的老师，他们便脱颖而出，成为少数有学生真正在听课的课程。这些老师不只局限于念ppt上的字，他们对自己讲的内容真的有独到的理解，他们真的想把自己的知识传授给学生，他们的课程内容不是千篇一律而平庸的，不是随便谁都可以替代的–这让他们与ai区别开来，也让他们最终留住了学生。至于剩下那些已经被ai替代的老师，我只能和他们（的课堂）说再见了。</p><p>2025-11-06</p>]]></content>
    
    
      
      
        
        
    <summary type="html">&lt;blockquote&gt;
&lt;p&gt;The reason why I created this blog…&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;Why-There&quot;&gt;&lt;a href=&quot;#Why-There&quot; class=&quot;headerlink&quot; title=&quot;Why</summary>
        
      
    
    
    
    
    <category term="something" scheme="https://begineri.github.io/Blog/tags/something/"/>
    
  </entry>
  
  <entry>
    <title>2025秋 OOPre 课程总结</title>
    <link href="https://begineri.github.io/Blog/2025/11/05/2025%E7%A7%8B-OOPre-%E8%AF%BE%E7%A8%8B%E6%80%BB%E7%BB%93/"/>
    <id>https://begineri.github.io/Blog/2025/11/05/2025%E7%A7%8B-OOPre-%E8%AF%BE%E7%A8%8B%E6%80%BB%E7%BB%93/</id>
    <published>2025-11-05T11:25:29.000Z</published>
    <updated>2025-11-05T12:36:27.822Z</updated>
    
    <content type="html"><![CDATA[<h2 id="迭代作业简单描述："><a href="#迭代作业简单描述：" class="headerlink" title="迭代作业简单描述："></a>迭代作业简单描述：</h2><h3 id="作业任务框架"><a href="#作业任务框架" class="headerlink" title="作业任务框架"></a>作业任务框架</h3><ul><li>冒险者 (Adventurer)</li><li>物品 (Bottle, Equipment)</li><li>法术 (Spell)</li><li>背包系统 (Bag)</li><li>对于物品（药水和法术）的使用 (UseItem)</li><li>战斗系统与冒险者属性 (Fight)</li><li>金钱系统 (Money)</li><li>雇佣关系与援助 (Employer, Employee)</li></ul><hr><h3 id="需要实现的操作"><a href="#需要实现的操作" class="headerlink" title="需要实现的操作"></a>需要实现的操作</h3><ol><li><code>add adventurer</code>： 加入一个需要管理的冒险者（新加入的冒险者不携带任何药水瓶和装备，并且初始体力为 500，初始攻击力为 1，初始防御力为 0，初始魔力值为 10，初始金币数量为 50）</li><li><code>add bottle</code>： 给某个冒险者增加一个药水瓶</li><li><code>add equipment</code>： 给某个冒险者增加一个装备</li><li><code>learn spell</code>： 给某个冒险者学习一个法术</li><li><code>remove item</code>： 删除某个冒险者的某个物品</li><li><code>take item</code>： 冒险者尝试携带他拥有的某个物品</li><li><code>use</code>： 冒险者对一个目标使用某个可用物品</li><li><code>buy item</code>： 冒险者去商店进行一次购买操作</li><li><code>fight</code>： 冒险者进行一次战斗</li><li><code>add relation</code>： 增加一条雇佣关系</li><li><code>remove relation</code>： 删除一条雇佣关系</li><li><code>load relation</code>： 导入一组雇佣关系</li></ol><hr><h3 id="最终的架构设计、调整以及考虑-😸"><a href="#最终的架构设计、调整以及考虑-😸" class="headerlink" title="最终的架构设计、调整以及考虑 😸"></a>最终的架构设计、调整以及考虑 😸</h3><p><img src="/Blog/images/Diagram.png" alt="总体" title="总体的设计架构如图"></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line">\SRC</span><br><span class="line">├─commands</span><br><span class="line">│      AddAdventurer.java</span><br><span class="line">│      AddBottle.java</span><br><span class="line">│      AddEquipment.java</span><br><span class="line">│      AddRelation.java</span><br><span class="line">│      BuyItem.java</span><br><span class="line">│      CommandUtil.java</span><br><span class="line">│      Fight.java</span><br><span class="line">│      LearnSpell.java</span><br><span class="line">│      LoadRelationship.java</span><br><span class="line">│      RemoveItem.java</span><br><span class="line">│      RemoveRelation.java</span><br><span class="line">│      TakeItem.java</span><br><span class="line">│      Use.java</span><br><span class="line">├─game</span><br><span class="line">│  │  Adventurer.java</span><br><span class="line">│  │  CommandFactory.java</span><br><span class="line">│  │  Factory.java</span><br><span class="line">│  │  Main.java</span><br><span class="line">│  └─interfaces</span><br><span class="line">│          Employee.java</span><br><span class="line">│          Employer.java</span><br><span class="line">├─items</span><br><span class="line">│  │  Bottle.java</span><br><span class="line">│  │  Equipment.java</span><br><span class="line">│  │  Item.java</span><br><span class="line">│  │  Spell.java</span><br><span class="line">│  ├─bottles</span><br><span class="line">│  │      AtkBottle.java</span><br><span class="line">│  │      DefBottle.java</span><br><span class="line">│  │      HpBottle.java</span><br><span class="line">│  │      ManaBottle.java</span><br><span class="line">│  ├─equipments</span><br><span class="line">│  │      Armour.java</span><br><span class="line">│  │      Magicbook.java</span><br><span class="line">│  │      Sword.java</span><br><span class="line">│  │      Weapon.java</span><br><span class="line">│  └─spells</span><br><span class="line">│          AttackSpell.java</span><br><span class="line">│          HealSpell.java</span><br><span class="line">└─parser</span><br><span class="line">        AdventureHireManager.java</span><br><span class="line">        Lexer.java</span><br><span class="line">        Parser.java</span><br></pre></td></tr></table></figure><hr><h4 id="1-CommandUtil-接口的实现"><a href="#1-CommandUtil-接口的实现" class="headerlink" title="1. CommandUtil 接口的实现"></a>1. <code>CommandUtil</code> 接口的实现</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">CommandUtil</span> &#123;</span><br><span class="line">    <span class="keyword">void</span> <span class="title function_">execute</span><span class="params">()</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="/Blog/images/CommandUtil.png" alt="CommandUtil"><br>采用<strong>命令模式</strong>，通过为每一个指令实现 <code>(Implementation)</code> CommandUtil 接口 ，将每一个“操作”封装成一个独立的对象，实现<strong>解耦 (Decoupling)</strong> 和 <strong>封装 (Encapsulation)</strong>，易于扩展。</p><p>配合<code>CommandFactory</code>类，可以直接在<code>Main</code>内调用：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">CommandUtil</span> <span class="variable">command</span> <span class="operator">=</span> CommandFactory.createCommand(input, adventureList);</span><br><span class="line"><span class="keyword">if</span> (command != <span class="literal">null</span>) &#123;</span><br><span class="line">    command.execute();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>具体接口实现的代码示例：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> game.Adventurer;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">LearnSpell</span> <span class="keyword">implements</span> <span class="title class_">CommandUtil</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> Adventurer adventure;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> String speId;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> String type;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="type">int</span> manaCost;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="type">int</span> power;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">LearnSpell</span><span class="params">(Adventurer adventure, String speId, String type, <span class="type">int</span> manaCost, <span class="type">int</span> power)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.adventure = adventure;</span><br><span class="line">        <span class="built_in">this</span>.speId = speId;</span><br><span class="line">        <span class="built_in">this</span>.type = type;</span><br><span class="line">        <span class="built_in">this</span>.manaCost = manaCost;</span><br><span class="line">        <span class="built_in">this</span>.power = power;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">execute</span><span class="params">()</span> &#123;</span><br><span class="line">        adventure.learnSpell(speId, type, manaCost, power);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><hr><h4 id="2-Item-抽象类的继承"><a href="#2-Item-抽象类的继承" class="headerlink" title="2. Item 抽象类的继承"></a>2. <code>Item</code> 抽象类的继承</h4><p><img src="/Blog/images/Item.png" alt="Item"></p><p>经过分析，发现冒险者所拥有的物品（装备、药水、法术）可以抽象为统一的类 <code>Item</code>，便于进行统一的管理，于是可以设计如下<strong>继承层次结构</strong>：</p><ul><li><p><strong>顶层抽象 (Root): <code>Item</code></strong></p><ul><li>定义所有“物品”的<strong>共同特征</strong>。如， <code>id</code> 和 <code>use</code> 方法。</li></ul></li><li><p><strong>第一层分类 (Branches): <code>Equipment</code>, <code>Spell</code>, <code>Bottle</code></strong></p><ul><li>这三个类继承 (extends) 了 <code>Item</code>。</li><li>它们自身也是<strong>抽象类</strong>，用来定义各自类别的共同特征。</li></ul></li><li><p><strong>具体实现 (Leaves): <code>HpBottle</code>, <code>Sword</code>, <code>AttackSpell</code> 等</strong></p><ul><li>继承了各自的“父类”，是可以实际创建（<code>new</code>）的<strong>具体类</strong>。</li></ul></li></ul><hr><h4 id="3-Adventurer-类与功能具体实现"><a href="#3-Adventurer-类与功能具体实现" class="headerlink" title="3. Adventurer 类与功能具体实现"></a>3. <code>Adventurer</code> 类与功能具体实现</h4><h5 id="状态管理-State-Management"><a href="#状态管理-State-Management" class="headerlink" title="状态管理 (State Management)"></a>状态管理 (State Management)</h5><ul><li><strong>存储核心属性：</strong> 持有冒险者的所有基础属性，如 <code>id</code>, <code>hitPoint</code>, <code>atk</code>, <code>def</code>, <code>mana</code> 和 <code>money</code>。</li><li><strong>管理死亡：</strong> 包含 <code>isDead()</code> 检查。<code>deductHitPoint()</code> 方法在HP归零时，自动调用处理死亡后关系的方法。</li><li><strong>计算总价值：</strong> <code>calculateAllMoney()</code> 方法用于计算冒险者死亡时掉落的“总价值”（金币 + 物品价值）。</li></ul><h5 id="物品与库存管理-Inventory-Management"><a href="#物品与库存管理-Inventory-Management" class="headerlink" title="物品与库存管理 (Inventory Management)"></a>物品与库存管理 (Inventory Management)</h5><ul><li><strong>区分所有权、携带和装备：</strong><ul><li><code>items</code> (HashMap): 冒险者<strong>拥有</strong>的所有物品。</li><li><code>usables</code> (HashMap) &#x2F; <code>usablesQueue</code> (Queue): 冒险者<strong>携带</strong>的药水物品，队列用于实现“最多10瓶”的替换逻辑。</li><li><code>armour</code> &#x2F; <code>weapon</code> (Equipment): 冒险者<strong>当前装备</strong>的护甲和武器。</li></ul></li><li><strong>管理法术：</strong> <code>spells</code> (HashMap) 存储所有已学会的法术。</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 拥有的物品（包括瓶子和武器）</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">final</span> HashMap&lt;String, Item&gt; items = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line"></span><br><span class="line"><span class="comment">// 包里的物品（瓶子）</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">final</span> HashMap&lt;String, Item&gt; usables = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line"></span><br><span class="line"><span class="comment">// 学会的 Spell</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">final</span> HashMap&lt;String, Spell&gt; spells = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line"></span><br><span class="line"><span class="comment">// 携带的瓶子列表</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">final</span> Queue&lt;String&gt; usablesQueue = <span class="keyword">new</span> <span class="title class_">LinkedList</span>&lt;&gt;();</span><br></pre></td></tr></table></figure><ul><li><strong>与工厂解耦：</strong> <code>addBottle</code>, <code>addEquipment</code>, <code>learnSpell</code>, <code>buyItem</code> 等方法不直接创建对象，而是调用 <code>Factory</code> 来创建，实现了创建与管理的分离。</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 简单工厂模式</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> Equipment <span class="title function_">createEquipment</span><span class="params">(String type, String equId, <span class="type">int</span> ce)</span> &#123;</span><br><span class="line">    Equipment newEquipment;</span><br><span class="line">    <span class="keyword">switch</span> (type) &#123;</span><br><span class="line">        <span class="keyword">case</span> <span class="string">&quot;Armour&quot;</span>:</span><br><span class="line">            newEquipment = <span class="keyword">new</span> <span class="title class_">Armour</span>(equId, ce);</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        <span class="keyword">case</span> <span class="string">&quot;Sword&quot;</span>:</span><br><span class="line">            newEquipment = <span class="keyword">new</span> <span class="title class_">Sword</span>(equId, ce);</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        <span class="keyword">case</span> <span class="string">&quot;Magicbook&quot;</span>:</span><br><span class="line">            newEquipment = <span class="keyword">new</span> <span class="title class_">Magicbook</span>(equId, ce);</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        <span class="keyword">default</span>:</span><br><span class="line">            newEquipment = <span class="literal">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> newEquipment;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h5 id="动作执行与多态-Action-Execution-Polymorphism"><a href="#动作执行与多态-Action-Execution-Polymorphism" class="headerlink" title="动作执行与多态 (Action Execution &amp; Polymorphism)"></a>动作执行与多态 (Action Execution &amp; Polymorphism)</h5><ul><li><strong><code>fight(targets)</code>：</strong> 封装了战斗逻辑。</li><li><strong><code>useItem(target)</code>：</strong> 封装了使用物品&#x2F;法术的逻辑。它委托给 <code>Item</code> 对象自身的 <code>checkUse()</code> 和 <code>useSuccessfully()</code> 方法来执行，实现了多态。</li><li><strong><code>takeItem(itemId)</code> &#x2F; <code>removeItem(itemId)</code>：</strong> 同样委托给 <code>Item</code> 对象的 <code>equip()</code> 和 <code>unequip()</code> 方法，<code>Adventurer</code> 类不关心具体装备的逻辑，只负责调用。</li></ul><h5 id="雇佣关系的实现"><a href="#雇佣关系的实现" class="headerlink" title="雇佣关系的实现"></a>雇佣关系的实现</h5><ul><li>同时实现 <strong>Employee 和 Employer 接口</strong>：<ul><li>作为 <code>Employer</code>：它有 <code>hire()</code> 和 <code>fire()</code> 方法，并维护一个<strong>下级列表</strong>。</li><li>作为 <code>Employee</code>：它有其<strong>直接上级</strong>。</li></ul></li><li><strong>关系图遍历：</strong> 提供 <code>getAllEmployers()</code>  和 <code>getAllEmployees()</code>  方法。</li><li><strong>盟友定义：</strong> <code>getAllAllies()</code> 遍历。</li><li><strong>规则检查：</strong> <code>checkContainsEmployer()</code> 和 <code>checkIsNotAlly()</code> 方法。</li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Adventurer</span> <span class="keyword">implements</span> <span class="title class_">Employee</span>, Employer &#123;</span><br><span class="line">    <span class="comment">// 直接的上级</span></span><br><span class="line">    <span class="keyword">private</span> Employer employer;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 直接雇佣的冒险者列表</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> HashMap&lt;String, Employee&gt; hired = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h5 id="援助系统-观察者模式"><a href="#援助系统-观察者模式" class="headerlink" title="援助系统 (观察者模式)"></a>援助系统 (观察者模式)</h5><ul><li><strong>被观察者 (Subject)：</strong><ol><li>当 <code>Adventurer</code> <code>takeDamage()</code> 被调用且减少的HP满足发出救援的前提时</li><li>调用 <code>notifyEmployees()</code> 来“发出通知”。</li></ol></li><li><strong>观察者 (Observer)：</strong><ol><li>在 <code>notifyEmployees()</code> 中，遍历所有下级（观察者）并调用他们的 <code>aidEmployer()</code> 方法。</li><li><strong>观察者</strong>检查援助逻辑，对上级 (Employer) 尝试援助。</li></ol></li></ul><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="comment">// 通知雇佣者</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">notifyEmployees</span><span class="params">()</span> &#123;</span><br><span class="line">    ArrayList&lt;Employee&gt; allEmployees = getAllEmployees();</span><br><span class="line">    </span><br><span class="line">    <span class="type">int</span> <span class="variable">sucAdiAdvNum</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">for</span> (Employee employee : allEmployees) &#123;</span><br><span class="line">        <span class="keyword">if</span> (employee.aidEmployer(<span class="built_in">this</span>)) &#123;</span><br><span class="line">            sucAdiAdvNum++;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="/Blog/images/Adventurer.png" alt="Adventurer"></p><hr><h2 id="使用JUnit的心得体会"><a href="#使用JUnit的心得体会" class="headerlink" title="使用JUnit的心得体会"></a>使用JUnit的心得体会</h2><p> <code>import org.junit.Test;</code></p><p><code>import static org.junit.Assert.*;</code></p><table><thead><tr><th>方法</th><th>介绍</th></tr></thead><tbody><tr><td><code>assertEquals(expected, actual)</code></td><td>检查两个值是否相等</td></tr><tr><td><code>assertTrue(condition)</code></td><td>检查条件是否为真</td></tr><tr><td><code>assertFalse(condition)</code></td><td>检查条件是否为假</td></tr><tr><td><code>assertNotNull(object)</code></td><td>检查是否不为空</td></tr><tr><td><code>assertNull(object)</code></td><td>检查是否为空</td></tr><tr><td><code>assertNotSame(expected, actual)</code></td><td>检查两个相关对象是否不指向同一个对象</td></tr><tr><td><code>assertSame(expected, actual)</code></td><td>检查两个相关对象是否指向同一个对象</td></tr><tr><td><code>assertArrayEquals(expectedArray, resultArray)</code></td><td>检查两个数组是否相等</td></tr></tbody></table><p>根据我在OOPro课程中使用JUnit的经验，我发现：</p><ul><li><strong>JUnit可以做到的</strong>：检查方法内由于欠缺考虑出现的逻辑问题。通过保证覆盖率 <code>Run with Coverage</code> 可以测试到几乎所有你编写出的代码，因此在构造与测试样例的时候，可以很方便发现代码中细小的错误。</li><li><strong>JUnit不可以做到的</strong>：发现某些欠缺的逻辑。鉴于现阶段的JUnit测试都是由我自己编写的，如果某种情况我在写代码的时候就没有考虑到，编写JUnit测试时自然也不会构造这样的例子，也就无法测试出程序的错误，这也导致了后面几次作业在强侧出现新的没有发现的Bug，为了找出这个Bug需要重新审视程序的逻辑。</li></ul><hr><h2 id="OOPre学习体验"><a href="#OOPre学习体验" class="headerlink" title="OOPre学习体验"></a>OOPre学习体验</h2><blockquote><p>从 <strong>面向过程编程 POP <em>(Procedure Oriented Programming)</em></strong> 到 <strong>面向对象编程 OOP <em>(Object Oriented Programming)</em></strong> 的转变。</p></blockquote><ul><li><strong>POP</strong>：以<strong>过程</strong>或<strong>函数</strong>为中心，强调程序的执行流程和步骤。</li><li><strong>OOP</strong>：将事物分解成为一个个<strong>对象</strong>，然后由对象之间分工与合作的编程范式。<ul><li><p><strong>封装 <code>Encapsulation</code></strong>：隐藏内部实现细节，仅暴露必要接口。</p></li><li><p><strong>继承 <code>Inheritance</code></strong>：子类继承父类的属性和方法，实现代码复用。</p></li><li><p><strong>多态 <code>Polymorphism</code></strong>：同一接口可由不同对象实现不同行为。</p></li><li><p><strong>抽象 <code>Abstraction</code></strong>：提取共性，定义抽象类或接口。</p></li><li><p>通过这些机制，使得OOP语言在处理一类相似的问题时有高度的灵活性、可维护性和扩展性，为我们解决问题提供了新的思路。</p></li></ul></li><li>经过OOPre课程的学习，我们初步了解了这些在面向对象语言中最为关键的思想，为后面的正课做了准备。</li><li>同时<code>CheckStyle</code> 的引入，可以从一开始就培养同学们编写代码的规范性。</li></ul><hr><h2 id="课程建议"><a href="#课程建议" class="headerlink" title="课程建议"></a>课程建议</h2><h4 id="1-课上讲解过于简略"><a href="#1-课上讲解过于简略" class="headerlink" title="1. 课上讲解过于简略"></a>1. 课上讲解过于简略</h4><ul><li>课上讲解的内容，只包含完成作业与设计程序 40% 的知识，为了完成作业且设计出较为理想的程序结构，学生需要课下学习大量额外的补充内容。这些内容有些是课上ppt的衍生（很多时候，ppt和课堂上对于一个概念只是列出概念并浅尝辄止，这不足以让学生写出作业代码），还有些是ppt没有提到的内容。</li><li>如果课上讲解时间有限，建议课程组为课下的作业准备更多可选的参考学习资料。比如对于命令模式，可以给出它在工程时的具体实现（给出设计思路或代码示例），以便同学对它有一个具体的认识，而不只是ppt上的几行文字。</li></ul><h4 id="2-工程架构的思想的逐渐引入"><a href="#2-工程架构的思想的逐渐引入" class="headerlink" title="2. 工程架构的思想的逐渐引入"></a>2. 工程架构的思想的逐渐引入</h4><ul><li><p>建议将工程架构的思想在每一次作业中融入一点，而不是在最后简单一提，以便同学们及时调整改进自己的框架，而不是越堆越乱，严重影响可读性和后续增加功能的难度。</p></li><li><p>同时可以介绍引入包管理的思想，便于对项目多个类进行管理。</p></li><li><p>建议课程组给一些IDEA功能的介绍（比如快捷键、快捷方法等）</p></li></ul><h1 id="＞﹏＜"><a href="#＞﹏＜" class="headerlink" title="＞﹏＜"></a>＞﹏＜</h1>]]></content>
    
    
      
      
        
        
    <summary type="html">&lt;h2 id=&quot;迭代作业简单描述：&quot;&gt;&lt;a href=&quot;#迭代作业简单描述：&quot; class=&quot;headerlink&quot; title=&quot;迭代作业简单描述：&quot;&gt;&lt;/a&gt;迭代作业简单描述：&lt;/h2&gt;&lt;h3 id=&quot;作业任务框架&quot;&gt;&lt;a href=&quot;#作业任务框架&quot;</summary>
        
      
    
    
    
    
    <category term="OOP" scheme="https://begineri.github.io/Blog/tags/OOP/"/>
    
    <category term="java" scheme="https://begineri.github.io/Blog/tags/java/"/>
    
  </entry>
  
</feed>
