<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <author>
    <name>Alessia</name>
  </author>
  <generator uri="https://hexo.io/">Hexo</generator>
  <id>https://liu-alessia.github.io/</id>
  <link href="https://liu-alessia.github.io/" rel="alternate"/>
  <link href="https://liu-alessia.github.io/atom.xml" rel="self"/>
  <rights>All rights reserved 2026, Alessia</rights>
  <subtitle>Alessia's funny place</subtitle>
  <title>Alessia's Blog</title>
  <updated>2026-08-13T16:00:00.000Z</updated>
  <entry>
    <author>
      <name>Alessia</name>
    </author>
    <category term="LLM知识体系搭建" scheme="https://liu-alessia.github.io/categories/LLM%E7%9F%A5%E8%AF%86%E4%BD%93%E7%B3%BB%E6%90%AD%E5%BB%BA/"/>
    <category term="学习资料" scheme="https://liu-alessia.github.io/tags/%E5%AD%A6%E4%B9%A0%E8%B5%84%E6%96%99/"/>
    <content>
      <![CDATA[<h1 id="RAG"><a href="#RAG" class="headerlink" title="RAG"></a>RAG</h1><p>Retrieval Augmented Generation</p><h2 id="基本步骤"><a href="#基本步骤" class="headerlink" title="基本步骤"></a>基本步骤</h2><p>RAG的整体流程<br>![[RAG的整体流程.png]]</p>]]>
    </content>
    <id>https://liu-alessia.github.io/2026/08/31/2026-08-14-day4-RAG/</id>
    <link href="https://liu-alessia.github.io/2026/08/31/2026-08-14-day4-RAG/"/>
    <published>2026-08-31T14:48:42.067Z</published>
    <summary>
      <![CDATA[<h1 id="RAG"><a href="#RAG" class="headerlink" title="RAG"></a>RAG</h1><p>Retrieval Augmented Generation</p>
<h2 id="基本步骤"><a href="#基本步骤" c]]>
    </summary>
    <title>day4-RAG</title>
    <updated>2026-08-13T16:00:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Alessia</name>
    </author>
    <category term="LLM知识体系搭建" scheme="https://liu-alessia.github.io/categories/LLM%E7%9F%A5%E8%AF%86%E4%BD%93%E7%B3%BB%E6%90%AD%E5%BB%BA/"/>
    <category term="学习资料" scheme="https://liu-alessia.github.io/tags/%E5%AD%A6%E4%B9%A0%E8%B5%84%E6%96%99/"/>
    <content>
      <![CDATA[<h1 id="ReAct"><a href="#ReAct" class="headerlink" title="ReAct"></a>ReAct</h1><p>Reasoning and Acting</p><h2 id="基本步骤"><a href="#基本步骤" class="headerlink" title="基本步骤"></a>基本步骤</h2><p>![[主流agent的技术架构.png]]</p>]]>
    </content>
    <id>https://liu-alessia.github.io/2026/08/31/2026-08-17-day5-ReAct/</id>
    <link href="https://liu-alessia.github.io/2026/08/31/2026-08-17-day5-ReAct/"/>
    <published>2026-08-31T14:48:42.067Z</published>
    <summary>
      <![CDATA[<h1 id="ReAct"><a href="#ReAct" class="headerlink" title="ReAct"></a>ReAct</h1><p>Reasoning and Acting</p>
<h2 id="基本步骤"><a href="#基本步骤" cla]]>
    </summary>
    <title>day5-ReAct</title>
    <updated>2026-08-17T16:00:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Alessia</name>
    </author>
    <category term="计算机基础" scheme="https://liu-alessia.github.io/categories/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/"/>
    <category term="随笔杂谈" scheme="https://liu-alessia.github.io/tags/%E9%9A%8F%E7%AC%94%E6%9D%82%E8%B0%88/"/>
    <content>
      <![CDATA[<h1 id="内存、固态硬盘与机械硬盘"><a href="#内存、固态硬盘与机械硬盘" class="headerlink" title="内存、固态硬盘与机械硬盘"></a>内存、固态硬盘与机械硬盘</h1><p>计算机中的“存储”大致分为两类：内存用于暂存正在运行的数据，断电后通常丢失；固态硬盘和机械硬盘用于长期保存数据，断电后仍能保留内容。三者在原理、接口和性能上各不相同。</p><h2 id="一、内存（RAM）"><a href="#一、内存（RAM）" class="headerlink" title="一、内存（RAM）"></a>一、内存（RAM）</h2><h3 id="原理"><a href="#原理" class="headerlink" title="原理"></a>原理</h3><p>内存是 CPU 直接访问的工作空间，主要使用 DRAM（动态随机存取存储器）。一个 DRAM 单元通常由一个电容和一个晶体管组成，电容是否带电表示 0 或 1。由于电荷会逐渐泄漏，DRAM 需要周期性刷新。</p><p>常见的 DDR SDRAM 在时钟信号的上升沿和下降沿都传输数据，因此可以在较低时钟频率下获得更高的数据传输率。内存具有较低延迟和较高带宽，但断电后数据会消失。</p><h3 id="接口"><a href="#接口" class="headerlink" title="接口"></a>接口</h3><ul><li><strong>DIMM</strong>：台式机常用的内存条接口。</li><li><strong>SO-DIMM</strong>：笔记本电脑常用的短尺寸接口。</li><li><strong>DDR 标准</strong>：DDR、DDR2、DDR3、DDR4、DDR5 逐代提高传输速率，并改善电压、容量和电源管理。</li><li><strong>内存总线</strong>：连接 CPU 内存控制器与内存模块，传输地址、数据和控制信号。</li></ul><h3 id="发展历史"><a href="#发展历史" class="headerlink" title="发展历史"></a>发展历史</h3><p>早期计算机使用磁芯存储器，后来逐渐发展为半导体 RAM。20 世纪 70 年代，DRAM 开始普及；随后 SDRAM、DDR SDRAM 相继成为个人计算机的主流。现代 DDR5 通过更高传输速率、分组结构和片上电源管理提升了带宽与能效。</p><h2 id="二、固态硬盘（SSD）"><a href="#二、固态硬盘（SSD）" class="headerlink" title="二、固态硬盘（SSD）"></a>二、固态硬盘（SSD）</h2><h3 id="原理-1"><a href="#原理-1" class="headerlink" title="原理"></a>原理</h3><p>SSD 使用 NAND Flash 闪存保存数据。闪存单元通过控制栅极中的电荷量表示数据，写入时改变电荷状态，读取时检测电压。它没有机械运动部件，因此访问延迟低、抗震性好。</p><p>SSD 不能像 RAM 一样直接覆盖任意位置。控制器需要进行地址映射、磨损均衡、垃圾回收和坏块管理；操作系统看到的逻辑地址，实际由闪存转换层映射到 NAND 物理位置。NAND 通常按页读写、按块擦除。</p><h3 id="接口-1"><a href="#接口-1" class="headerlink" title="接口"></a>接口</h3><ul><li><strong>SATA</strong>：常见于 2.5 英寸 SSD，使用 SATA 连接器，接口带宽限制了最高速度。</li><li><strong>M.2</strong>：一种外形规格，不等于某一种协议。M.2 SSD 可以使用 SATA，也可以使用 PCIe。</li><li><strong>PCIe + NVMe</strong>：NVMe 针对非易失性存储设计，利用 PCIe 通道并支持多队列，延迟和并发性能通常优于 SATA。</li><li><strong>U.2、U.3</strong>：主要用于服务器和企业级设备，通常也使用 PCIe&#x2F;NVMe 协议。</li></ul><h3 id="发展历史-1"><a href="#发展历史-1" class="headerlink" title="发展历史"></a>发展历史</h3><p>早期闪存主要用于数码相机、U 盘和嵌入式设备。随着 NAND Flash 成本下降，SSD 从高价产品逐渐进入个人电脑。接口也从 SATA 逐步发展到 PCIe，协议从传统 AHCI 转向 NVMe，性能瓶颈从接口带宽进一步转移到 NAND、控制器和散热。</p><h2 id="三、机械硬盘（HDD）"><a href="#三、机械硬盘（HDD）" class="headerlink" title="三、机械硬盘（HDD）"></a>三、机械硬盘（HDD）</h2><h3 id="原理-2"><a href="#原理-2" class="headerlink" title="原理"></a>原理</h3><p>HDD 使用高速旋转的磁盘片保存数据。磁头在盘片表面上方移动，通过改变磁性材料的磁化方向写入数据，再根据磁场变化读取数据。数据通常按照磁道和扇区组织。</p><p>HDD 的访问时间包括磁头寻道时间、盘片旋转等待时间和数据传输时间。由于存在电机和磁头等运动部件，它的随机访问延迟高于 SSD，但单位容量价格低，适合大容量归档和备份。</p><h3 id="接口-2"><a href="#接口-2" class="headerlink" title="接口"></a>接口</h3><ul><li><strong>IDE&#x2F;PATA</strong>：早期个人电脑常见的并行接口，排线较宽。</li><li><strong>SATA</strong>：目前个人电脑中最常见的 HDD 接口，使用串行传输。</li><li><strong>SAS</strong>：服务器和存储阵列常用接口，通常具有更好的可靠性和扩展能力。</li></ul><h3 id="发展历史-2"><a href="#发展历史-2" class="headerlink" title="发展历史"></a>发展历史</h3><p>1956 年，IBM 推出了世界上第一台磁盘存储系统 RAMAC。早期硬盘体积庞大、容量有限，后来随着磁记录密度提高，硬盘逐渐进入个人电脑和数据中心。垂直磁记录、叠瓦式磁记录等技术不断提高容量，但机械结构决定了其随机访问延迟难以达到 SSD 的水平。</p><h2 id="四、三者对比"><a href="#四、三者对比" class="headerlink" title="四、三者对比"></a>四、三者对比</h2><table><thead><tr><th>类型</th><th>主要用途</th><th>断电后数据</th><th>访问特点</th><th>常见接口</th></tr></thead><tbody><tr><td>内存（RAM）</td><td>运行程序、暂存数据</td><td>丢失</td><td>延迟低、带宽高</td><td>DIMM、SO-DIMM、DDR</td></tr><tr><td>SSD</td><td>系统盘、应用和文件存储</td><td>保留</td><td>随机访问快、无机械部件</td><td>SATA、M.2、PCIe&#x2F;NVMe</td></tr><tr><td>HDD</td><td>大容量存储、备份和归档</td><td>保留</td><td>顺序访问经济，随机访问较慢</td><td>SATA、SAS、PATA</td></tr></tbody></table><p>简单来说，内存解决“程序运行时放在哪里”，SSD 和 HDD 解决“数据长期保存在哪里”。SSD 速度快但成本较高，HDD 容量大且便宜；实际设备通常会组合使用三者，以平衡速度、容量和成本。</p>]]>
    </content>
    <id>https://liu-alessia.github.io/2026/08/16/2026-08-17-%E5%AD%98%E5%82%A8/</id>
    <link href="https://liu-alessia.github.io/2026/08/16/2026-08-17-%E5%AD%98%E5%82%A8/"/>
    <published>2026-08-16T16:00:00.000Z</published>
    <summary>
      <![CDATA[<h1 id="内存、固态硬盘与机械硬盘"><a href="#内存、固态硬盘与机械硬盘" class="headerlink" title="内存、固态硬盘与机械硬盘"></a>内存、固态硬盘与机械硬盘</h1><p>计算机中的“存储”大致分为两类：内存用于暂存正在运行的数据，]]>
    </summary>
    <title>存储</title>
    <updated>2026-08-31T14:48:42.068Z</updated>
  </entry>
  <entry>
    <author>
      <name>Alessia</name>
    </author>
    <category term="找工" scheme="https://liu-alessia.github.io/categories/%E6%89%BE%E5%B7%A5/"/>
    <category term="计算神经" scheme="https://liu-alessia.github.io/tags/%E8%AE%A1%E7%AE%97%E7%A5%9E%E7%BB%8F/"/>
    <category term="Agent" scheme="https://liu-alessia.github.io/tags/Agent/"/>
    <category term="强化学习" scheme="https://liu-alessia.github.io/tags/%E5%BC%BA%E5%8C%96%E5%AD%A6%E4%B9%A0/"/>
    <content>
      <![CDATA[<p><strong>路径积分与空间表征：</strong><br>基于 LSTM 处理线速度和角速度序列，预测位置细胞与头方向细胞编码，在隐层中涌现网格细胞、边界细胞等空间表征；采用 BPTT、RMSProp、Dropout 和梯度裁剪训练，训练后模型15秒定位误差由91cm降至16cm。</p><p><strong>强化学习导航架构：</strong><br>基于 CNN、Grid LSTM 和 A3C Actor-Critic 搭建端到端 Agent，融合视觉特征、当前&#x2F;目标网格编码、历史动作与奖励，实现稀疏奖励下的一次目标学习和向量导航。<br>![[gridcell-agent架构.png]]</p><p><strong>评测与可解释性分析：</strong><br>在开放场地、程序化多房间、随机门和捷径环境中训练，使用 Ridge Regression 解码目标距离与方向，并通过移除目标编码、屏蔽高 Gridness 单元等消融实验验证空间表征作用。</p><p><strong>项目成果</strong></p><p>l 网格样单元占比达 25.2%，100 次随机初始化实验中平均占比为 23% ± 2.8%。</p><p>l 在带噪速度、无真实坐标输入条件下，将 15 秒自定位误差由 88 cm 降至 12 cm。</p><p>l 导航性能超过 A3C、位置细胞 Agent、NavMemNet、DNC 等基线及人类专家，并可零微调泛化至更大地图、利用未见捷径完成最短路径规划。</p>]]>
    </content>
    <id>https://liu-alessia.github.io/2026/07/26/2026-07-27-%E5%9F%BA%E4%BA%8E%E7%BD%91%E6%A0%BC%E7%8A%B6%E7%BB%86%E8%83%9E%E7%9A%84%E7%9F%A2%E9%87%8F%E5%AF%BC%E8%88%AA/</id>
    <link href="https://liu-alessia.github.io/2026/07/26/2026-07-27-%E5%9F%BA%E4%BA%8E%E7%BD%91%E6%A0%BC%E7%8A%B6%E7%BB%86%E8%83%9E%E7%9A%84%E7%9F%A2%E9%87%8F%E5%AF%BC%E8%88%AA/"/>
    <published>2026-07-26T16:00:00.000Z</published>
    <summary>
      <![CDATA[<p><strong>路径积分与空间表征：</strong><br>基于 LSTM 处理线速度和角速度序列，预测位置细胞与头方向细胞编码，在隐层中涌现网格细胞、边界细胞等空间表征；采用 BPTT、RMSProp、Dropout 和梯度裁剪训练，训练后模型15秒定位误差由91cm降]]>
    </summary>
    <title>基于网格状细胞的矢量导航</title>
    <updated>2026-08-31T14:48:42.068Z</updated>
  </entry>
  <entry>
    <author>
      <name>Alessia</name>
    </author>
    <category term="技术实践" scheme="https://liu-alessia.github.io/categories/%E6%8A%80%E6%9C%AF%E5%AE%9E%E8%B7%B5/"/>
    <category term="技术随笔" scheme="https://liu-alessia.github.io/tags/%E6%8A%80%E6%9C%AF%E9%9A%8F%E7%AC%94/"/>
    <id>https://liu-alessia.github.io/2026/07/26/2026-07-27-google-analytics-tool/</id>
    <link href="https://liu-alessia.github.io/2026/07/26/2026-07-27-google-analytics-tool/"/>
    <published>2026-07-26T16:00:00.000Z</published>
    <title>google-analytics-tool</title>
    <updated>2026-08-31T14:48:42.068Z</updated>
  </entry>
  <entry>
    <author>
      <name>Alessia</name>
    </author>
    <category term="技术实践" scheme="https://liu-alessia.github.io/categories/%E6%8A%80%E6%9C%AF%E5%AE%9E%E8%B7%B5/"/>
    <category term="技术随笔" scheme="https://liu-alessia.github.io/tags/%E6%8A%80%E6%9C%AF%E9%9A%8F%E7%AC%94/"/>
    <content>
      <![CDATA[<p>参考<a href="https://effortlessacademic.com/connecting-zotero-and-obsidian-with-the-zotlit-plugin-templates/">使用 ZotLit 插件和模板连接 Zotero 和 Obsidian</a></p><h2 id="系统架构"><a href="#系统架构" class="headerlink" title="系统架构"></a>系统架构</h2><p><img src="/images/posts/zotero+obsidian/%E7%B3%BB%E7%BB%9F%E6%9E%B6%E6%9E%84.png" alt="系统架构"><br>已完成：</p><ul><li>AI读取PDF全文，一句指令生成结构化文献笔记并自动归类</li><li>文献量增长后仍能快速检索——自动索引按标签多维度筛选</li><li>写论文草稿时引用自己读过的文献，引用格式可直接编译为word&#x2F;pdf</li><li>文献之间自动建立关联网络，在obsidian图谱中可视化研究脉络</li><li>设计实验时结合已有文献给出具体参数建议</li></ul><p>待完成：</p><ul><li>文献收录在zotero，复制想要AI阅读的文献PDF到obsidian pdf目录下</li><li>AI根据关键字调研并获取文献</li></ul><h2 id="文件架构"><a href="#文件架构" class="headerlink" title="文件架构"></a>文件架构</h2><p><img src="/images/posts/zotero+obsidian/%E6%96%87%E4%BB%B6%E6%9E%B6%E6%9E%84.png" alt="文件架构"></p><h2 id="obsidian、zotero协同"><a href="#obsidian、zotero协同" class="headerlink" title="obsidian、zotero协同"></a>obsidian、zotero协同</h2><ol><li>在Zotero导入文献</li><li>PDF进入知识库</li><li>用obsidian生成笔记骨架</li><li>codex填充笔记内容</li><li>在obsidian里验证</li></ol><p>按类别访问</p><p>文献阅读标注在zotero，笔记&#x2F;AI解析在obsidian。那么PDF不能移动到zotero</p><p>zotero字段名用的<code>&#123;&#123;citekey&#125;&#125;-&#123;&#123;shortTitle&#125;&#125;</code></p>]]>
    </content>
    <id>https://liu-alessia.github.io/2026/07/20/2026-07-21-zotero+obsidian%E6%96%87%E7%8C%AE%E5%B7%A5%E4%BD%9C%E6%B5%81/</id>
    <link href="https://liu-alessia.github.io/2026/07/20/2026-07-21-zotero+obsidian%E6%96%87%E7%8C%AE%E5%B7%A5%E4%BD%9C%E6%B5%81/"/>
    <published>2026-07-20T16:00:00.000Z</published>
    <summary>
      <![CDATA[<p>参考<a href="https://effortlessacademic.com/connecting-zotero-and-obsidian-with-the-zotlit-plugin-templates/">使用 ZotLit 插件和模板连接 Zotero 和 Ob]]>
    </summary>
    <title>zotero+obsidian文献工作流</title>
    <updated>2026-08-31T14:48:42.068Z</updated>
  </entry>
  <entry>
    <author>
      <name>Alessia</name>
    </author>
    <category term="项目实践" scheme="https://liu-alessia.github.io/categories/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E8%B7%B5/"/>
    <category term="Agent" scheme="https://liu-alessia.github.io/tags/Agent/"/>
    <category term="MCP" scheme="https://liu-alessia.github.io/tags/MCP/"/>
    <category term="金融分析" scheme="https://liu-alessia.github.io/tags/%E9%87%91%E8%9E%8D%E5%88%86%E6%9E%90/"/>
    <category term="LangGraph" scheme="https://liu-alessia.github.io/tags/LangGraph/"/>
    <content>
      <![CDATA[<h2 id="项目运行"><a href="#项目运行" class="headerlink" title="项目运行"></a>项目运行</h2>]]>
    </content>
    <id>https://liu-alessia.github.io/2026/07/17/2026-07-18-%E8%82%A1%E7%A5%A8Agent%E5%AE%9E%E8%B7%B5/</id>
    <link href="https://liu-alessia.github.io/2026/07/17/2026-07-18-%E8%82%A1%E7%A5%A8Agent%E5%AE%9E%E8%B7%B5/"/>
    <published>2026-07-17T16:00:00.000Z</published>
    <summary>
      <![CDATA[<h2 id="项目运行"><a href="#项目运行" class="headerlink" title="项目运行"></a>项目运行</h2>]]>
    </summary>
    <title>股票Agent实践</title>
    <updated>2026-07-18T16:00:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Alessia</name>
    </author>
    <category term="LLM知识体系搭建" scheme="https://liu-alessia.github.io/categories/LLM%E7%9F%A5%E8%AF%86%E4%BD%93%E7%B3%BB%E6%90%AD%E5%BB%BA/"/>
    <category term="学习资料" scheme="https://liu-alessia.github.io/tags/%E5%AD%A6%E4%B9%A0%E8%B5%84%E6%96%99/"/>
    <content>
      <![CDATA[<p>此系列博客记录<a href="https://my.feishu.cn/docx/FAL3d7zlTo6fcCxQzXbcbY2Xnff">居丽叶的大模型自学计划表-算法岗速成版</a>的学习过程，主要参考资料<a href="https://my.feishu.cn/docx/AN61dRfiWoRUiRxhc6ucbmJwnGr">居里叶LLM知识体系搭建</a>。</p><h2 id="embedding"><a href="#embedding" class="headerlink" title="embedding"></a>embedding</h2><h2 id="encoder"><a href="#encoder" class="headerlink" title="encoder"></a>encoder</h2><h2 id="decoder"><a href="#decoder" class="headerlink" title="decoder"></a>decoder</h2><h2 id="pre-norm和post-norm"><a href="#pre-norm和post-norm" class="headerlink" title="pre-norm和post-norm"></a>pre-norm和post-norm</h2>]]>
    </content>
    <id>https://liu-alessia.github.io/2026/07/13/2026-07-14-day2-transformer/</id>
    <link href="https://liu-alessia.github.io/2026/07/13/2026-07-14-day2-transformer/"/>
    <published>2026-07-13T16:00:00.000Z</published>
    <summary>
      <![CDATA[<p>此系列博客记录<a href="https://my.feishu.cn/docx/FAL3d7zlTo6fcCxQzXbcbY2Xnff">居丽叶的大模型自学计划表-算法岗速成版</a>的学习过程，主要参考资料<a href="https://my.feishu.cn/d]]>
    </summary>
    <title>day2-transformer</title>
    <updated>2026-08-31T14:48:42.067Z</updated>
  </entry>
  <entry>
    <author>
      <name>Alessia</name>
    </author>
    <category term="LLM知识体系搭建" scheme="https://liu-alessia.github.io/categories/LLM%E7%9F%A5%E8%AF%86%E4%BD%93%E7%B3%BB%E6%90%AD%E5%BB%BA/"/>
    <category term="学习资料" scheme="https://liu-alessia.github.io/tags/%E5%AD%A6%E4%B9%A0%E8%B5%84%E6%96%99/"/>
    <content>
      <![CDATA[<p>此系列博客记录<a href="https://my.feishu.cn/docx/FAL3d7zlTo6fcCxQzXbcbY2Xnff">居丽叶的大模型自学计划表-算法岗速成版</a>的学习过程，主要参考资料<a href="https://my.feishu.cn/docx/AN61dRfiWoRUiRxhc6ucbmJwnGr">居里叶LLM知识体系搭建</a>。</p><h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p><a href="https://www.bilibili.com/video/BV1PvwYzxE9D/?spm_id_from=333.788.recommend_more_video.-1&trackid=web_related_0.router-related-2479604-tdxs9.1786885403228.791&vd_source=e829fda6ffe593dd9c2083114e4800c0">隔壁的程序员老王B站视频【什么是LoRA 大模型微调是怎么回事】</a></p><p>模型微调所需的显存并不比预训练的少</p><p><img src="/images/posts/LLM_QuickStart/%E6%A8%A1%E5%9E%8B%E5%BE%AE%E8%B0%83%E6%98%BE%E5%AD%98%E5%8D%A0%E7%94%A8%E5%88%86%E6%9E%90.png" alt="alt text"><br>以约 1.5B 参数模型为例，FP16 权重本身约占 3GB；推理时主要还需要 KV Cache 和临时激活，因此显存需求通常为“模型权重 + KV Cache + 激活”，其中 KV Cache 会随 batch size 和上下文长度增长。训练时除了模型权重外，还需要保存梯度、前向激活以及优化器状态；对于 AdamW，为了保证训练精度，必须保证 FP32 的训练精度，主权重、一阶动量和二阶动量，每项约 6GB，因此仅参数、梯度和优化器状态就可能达到约 24GB，实际训练还要叠加 activation 和临时 buffer。</p><h1 id="方法"><a href="#方法" class="headerlink" title="方法"></a>方法</h1><h2 id="LoRA"><a href="#LoRA" class="headerlink" title="LoRA"></a>LoRA</h2><p>Low Rank Adaption</p><p>论文主图<br><img src="/images/posts/LLM_QuickStart/LORA-%E9%87%8D%E5%8F%82%E6%95%B0%E5%8C%96%E4%B8%BB%E5%9B%BE.png" alt="LoRA 重参数化主图"></p>]]>
    </content>
    <id>https://liu-alessia.github.io/2026/07/13/2026-07-26-day3-%E6%A8%A1%E5%9E%8B%E5%BE%AE%E8%B0%83/</id>
    <link href="https://liu-alessia.github.io/2026/07/13/2026-07-26-day3-%E6%A8%A1%E5%9E%8B%E5%BE%AE%E8%B0%83/"/>
    <published>2026-07-13T16:00:00.000Z</published>
    <summary>
      <![CDATA[<p>此系列博客记录<a href="https://my.feishu.cn/docx/FAL3d7zlTo6fcCxQzXbcbY2Xnff">居丽叶的大模型自学计划表-算法岗速成版</a>的学习过程，主要参考资料<a href="https://my.feishu.cn/d]]>
    </summary>
    <title>day3-模型微调</title>
    <updated>2026-08-31T14:48:42.067Z</updated>
  </entry>
  <entry>
    <author>
      <name>Alessia</name>
    </author>
    <category term="LLM知识体系搭建" scheme="https://liu-alessia.github.io/categories/LLM%E7%9F%A5%E8%AF%86%E4%BD%93%E7%B3%BB%E6%90%AD%E5%BB%BA/"/>
    <category term="学习资料" scheme="https://liu-alessia.github.io/tags/%E5%AD%A6%E4%B9%A0%E8%B5%84%E6%96%99/"/>
    <content>
      <![CDATA[<p>此系列博客记录<a href="https://my.feishu.cn/docx/FAL3d7zlTo6fcCxQzXbcbY2Xnff">居丽叶的大模型自学计划表-算法岗速成版</a>的学习过程，主要参考资料<a href="https://my.feishu.cn/docx/AN61dRfiWoRUiRxhc6ucbmJwnGr">居里叶LLM知识体系搭建</a>。</p><h2 id="原理"><a href="#原理" class="headerlink" title="原理"></a>原理</h2><h2 id="改进"><a href="#改进" class="headerlink" title="改进"></a>改进</h2><h2 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h2><p>MHA&#x2F;MQA代码手撕</p><figure class="highlight python"><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><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> torch.nn <span class="hljs-keyword">as</span> nn<br><span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np<br><span class="hljs-keyword">import</span> torch<br><span class="hljs-keyword">import</span> math<br><br><span class="hljs-comment"># ====== 超参数（贯穿全文的形状参考）======</span><br><span class="hljs-comment"># batch=10, num_head=8, n_q=2, n_k=n_v=4</span><br><span class="hljs-comment"># dimension_q=dimension_k=128, dimension_v=64</span><br><span class="hljs-comment"># d_k=16, d_v=16, d_o=8</span><br><br><span class="hljs-comment"># ==================== 多头注意力 MHA ====================</span><br><span class="hljs-comment"># MHA：每个 head 有独立的 K、V 投影矩阵</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">MHA</span>(nn.Module):<br>    <span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, num_head, dimension_k, dimension_v, d_k, d_v, d_o</span>):<br>        <span class="hljs-comment"># d_k：每个 head 的 key/query 维度；d_k * num_head = 原始 embedding 长度</span><br>        <span class="hljs-built_in">super</span>().__init__()<br>        <span class="hljs-variable language_">self</span>.num_head = num_head<br>        <span class="hljs-variable language_">self</span>.d_k = d_k<br>        <span class="hljs-variable language_">self</span>.d_v = d_v<br>        <span class="hljs-variable language_">self</span>.d_o = d_o<br>        <span class="hljs-comment"># fc_q/fc_k：把输入 embedding 投影到 num_head 个 head 的拼接空间</span><br>        <span class="hljs-comment">#   输入 dimension_k=128 → 输出 num_head*d_k = 8*16 = 128</span><br>        <span class="hljs-variable language_">self</span>.fc_q = nn.Linear(dimension_k, num_head * d_k)<br>        <span class="hljs-variable language_">self</span>.fc_k = nn.Linear(dimension_k, num_head * d_k)<br>        <span class="hljs-comment"># fc_v：dimension_v=64 → num_head*d_v = 8*16 = 128</span><br>        <span class="hljs-variable language_">self</span>.fc_v = nn.Linear(dimension_v, num_head * d_v)<br>        <span class="hljs-comment"># fc_o：拼接后的多头输出 → 最终输出维度 d_o=8</span><br>        <span class="hljs-variable language_">self</span>.fc_o = nn.Linear(num_head * d_v, d_o)<br>        <span class="hljs-variable language_">self</span>.softmax = nn.Softmax(dim=<span class="hljs-number">2</span>)<br><br>    <span class="hljs-keyword">def</span> <span class="hljs-title function_">forward</span>(<span class="hljs-params">self, q, k, v, mask</span>):<br>        <span class="hljs-comment"># 输入形状：</span><br>        <span class="hljs-comment">#   q: (batch, n_q, dimension_q) = (10, 2, 128)</span><br>        <span class="hljs-comment">#   k: (batch, n_k, dimension_k) = (10, 4, 128)</span><br>        <span class="hljs-comment">#   v: (batch, n_v, dimension_v) = (10, 4, 64)</span><br>        batch, n_q, dimension_q = q.size()<br>        batch, n_k, dimension_k = k.size()<br>        batch, n_v, dimension_v = v.size()<br><br>        <span class="hljs-comment"># ---- 线性投影 ----</span><br>        q = <span class="hljs-variable language_">self</span>.fc_q(q)  <span class="hljs-comment"># (10, 2, 128) → (10, 2, 128)  即 (batch, n_q, num_head*d_k)</span><br>        k = <span class="hljs-variable language_">self</span>.fc_k(k)  <span class="hljs-comment"># (10, 4, 128) → (10, 4, 128)</span><br>        v = <span class="hljs-variable language_">self</span>.fc_v(v)  <span class="hljs-comment"># (10, 4,  64) → (10, 4, 128)  即 (batch, n_v, num_head*d_v)</span><br><br>        <span class="hljs-comment"># ---- 拆分多头并重排维度 ----</span><br>        <span class="hljs-comment"># 目标：把 num_head 维提到最前，batch 维合并进去，方便批量做矩阵乘法</span><br>        <span class="hljs-comment"># permute：交换矩阵维度位置</span><br>        <span class="hljs-comment"># q: (10,2,128) → view(10,2,8,16) → permute(2,0,1,3)=(8,10,2,16) → view(-1,2,16) = (80,2,16)</span><br>        q = q.view(batch, n_q, <span class="hljs-variable language_">self</span>.num_head, <span class="hljs-variable language_">self</span>.d_k).permute(<span class="hljs-number">2</span>, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">3</span>).contiguous().view(-<span class="hljs-number">1</span>, n_q, <span class="hljs-variable language_">self</span>.d_k)<br>        <span class="hljs-comment"># k: (10,4,128) → (8,10,4,16) → (80,4,16)</span><br>        k = k.view(batch, n_k, <span class="hljs-variable language_">self</span>.num_head, <span class="hljs-variable language_">self</span>.d_k).permute(<span class="hljs-number">2</span>, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">3</span>).contiguous().view(-<span class="hljs-number">1</span>, n_k, <span class="hljs-variable language_">self</span>.d_k)<br>        <span class="hljs-comment"># v: (10,4,128) → (8,10,4,16) → (80,4,16)</span><br>        v = v.view(batch, n_v, <span class="hljs-variable language_">self</span>.num_head, <span class="hljs-variable language_">self</span>.d_v).permute(<span class="hljs-number">2</span>, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">3</span>).contiguous().view(-<span class="hljs-number">1</span>, n_v, <span class="hljs-variable language_">self</span>.d_v)<br><br>        <span class="hljs-comment"># ---- 计算注意力分数 ----</span><br>        <span class="hljs-comment"># q: (80,2,16)  k.T: (80,16,4)  → attention: (80,2,4)</span><br>        attention = torch.matmul(q, k.transpose(-<span class="hljs-number">1</span>, -<span class="hljs-number">2</span>)) / math.sqrt(<span class="hljs-variable language_">self</span>.d_k)<br><br>        <span class="hljs-comment"># mask: (10,2,4) → repeat → (80,2,4)  上三角填 -inf，防止未来位置泄露</span><br>        mask = mask.repeat(<span class="hljs-variable language_">self</span>.num_head, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>)<br>        attention = attention + mask        <span class="hljs-comment"># (80,2,4)</span><br>        attention = <span class="hljs-variable language_">self</span>.softmax(attention) <span class="hljs-comment"># (80,2,4)，每行和为 1</span><br><br>        <span class="hljs-comment"># ---- 加权求和 ----</span><br>        <span class="hljs-comment"># attention: (80,2,4)  v: (80,4,16)  → output: (80,2,16)</span><br>        output = torch.matmul(attention, v)<br><br>        <span class="hljs-comment"># ---- 合并多头，还原 batch 维度 ----</span><br>        <span class="hljs-comment"># (80,2,16) → view(8,10,2,16) → permute(1,2,0,3)=(10,2,8,16) → view(10,2,-1)=(10,2,128)</span><br>        output = output.view(<span class="hljs-variable language_">self</span>.num_head, batch, n_q, <span class="hljs-variable language_">self</span>.d_v).permute(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">0</span>, <span class="hljs-number">3</span>).contiguous().view(batch, n_q, -<span class="hljs-number">1</span>)<br><br>        <span class="hljs-comment"># ---- 输出投影 ----</span><br>        <span class="hljs-comment"># (10,2,128) → fc_o → (10,2,8)  即 (batch, n_q, d_o)</span><br>        output = <span class="hljs-variable language_">self</span>.fc_o(output)<br>        <span class="hljs-keyword">return</span> attention, output  <span class="hljs-comment"># attention:(80,2,4)  output:(10,2,8)</span><br><br><br><span class="hljs-comment"># ==================== 多查询注意力 MQA ====================</span><br><span class="hljs-comment"># MQA：所有 head 共享同一组 K、V 投影矩阵，只有 Q 是多头的</span><br><span class="hljs-comment"># 好处：KV Cache 大幅减小，推理更快</span><br><span class="hljs-keyword">class</span> <span class="hljs-title class_">MQA</span>(nn.Module):<br>    <span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, num_head, dimension_k, dimension_v, d_k, d_v, d_o</span>):<br>        <span class="hljs-built_in">super</span>().__init__()<br>        <span class="hljs-variable language_">self</span>.num_head = num_head<br>        <span class="hljs-variable language_">self</span>.d_k = d_k<br>        <span class="hljs-variable language_">self</span>.d_v = d_v<br>        <span class="hljs-variable language_">self</span>.d_o = d_o<br>        <span class="hljs-comment"># Q 仍然多头：dimension_k=128 → num_head*d_k=128</span><br>        <span class="hljs-variable language_">self</span>.fc_q = nn.Linear(dimension_k, num_head * d_k)<br>        <span class="hljs-comment"># K/V 只投影到单头维度：dimension_k=128 → d_k=16；dimension_v=64 → d_v=16</span><br>        <span class="hljs-variable language_">self</span>.fc_k = nn.Linear(dimension_k, d_k)<br>        <span class="hljs-variable language_">self</span>.fc_v = nn.Linear(dimension_v, d_v)<br>        <span class="hljs-variable language_">self</span>.fc_o = nn.Linear(num_head * d_v, d_o)<br>        <span class="hljs-variable language_">self</span>.softmax = nn.Softmax(dim=<span class="hljs-number">2</span>)<br><br>    <span class="hljs-keyword">def</span> <span class="hljs-title function_">forward</span>(<span class="hljs-params">self, q, k, v, mask</span>):<br>        <span class="hljs-comment"># 输入形状：同 MHA</span><br>        <span class="hljs-comment">#   q: (10, 2, 128)  k: (10, 4, 128)  v: (10, 4, 64)</span><br>        batch, n_q, dimension_q = q.size()<br>        batch, n_k, dimension_k = k.size()<br>        batch, n_v, dimension_v = v.size()<br><br>        <span class="hljs-comment"># ---- 线性投影 ----</span><br>        q = <span class="hljs-variable language_">self</span>.fc_q(q)  <span class="hljs-comment"># (10, 2, 128) → (10, 2, 128)  多头</span><br>        k = <span class="hljs-variable language_">self</span>.fc_k(k)  <span class="hljs-comment"># (10, 4, 128) → (10, 4,  16)  单头</span><br>        v = <span class="hljs-variable language_">self</span>.fc_v(v)  <span class="hljs-comment"># (10, 4,  64) → (10, 4,  16)  单头</span><br><br>        <span class="hljs-comment"># ---- Q 拆分多头 ----</span><br>        <span class="hljs-comment"># (10,2,128) → view(10,2,8,16) → permute(2,0,1,3)=(8,10,2,16) → view(-1,2,16)=(80,2,16)</span><br>        q = q.view(batch, n_q, <span class="hljs-variable language_">self</span>.num_head, <span class="hljs-variable language_">self</span>.d_k).permute(<span class="hljs-number">2</span>, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">3</span>).contiguous().view(-<span class="hljs-number">1</span>, n_q, <span class="hljs-variable language_">self</span>.d_k)<br><br>        <span class="hljs-comment"># ---- K/V 复制 num_head 份，对齐 Q 的第0维 ----</span><br>        <span class="hljs-comment"># k: (10,4,16) → repeat(8,1,1) → (80,4,16)</span><br>        k = k.repeat(<span class="hljs-variable language_">self</span>.num_head, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>)<br>        <span class="hljs-comment"># v: (10,4,16) → repeat(8,1,1) → (80,4,16)</span><br>        v = v.repeat(<span class="hljs-variable language_">self</span>.num_head, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>)<br><br>        <span class="hljs-comment"># ---- 计算注意力（与 MHA 完全相同）----</span><br>        <span class="hljs-comment"># q:(80,2,16)  k.T:(80,16,4)  → attention:(80,2,4)</span><br>        attention = torch.matmul(q, k.transpose(-<span class="hljs-number">1</span>, -<span class="hljs-number">2</span>)) / math.sqrt(<span class="hljs-variable language_">self</span>.d_k)<br>        mask = mask.repeat(<span class="hljs-variable language_">self</span>.num_head, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>)  <span class="hljs-comment"># (10,2,4) → (80,2,4)</span><br>        attention = attention + mask<br>        attention = <span class="hljs-variable language_">self</span>.softmax(attention)       <span class="hljs-comment"># (80,2,4)</span><br><br>        <span class="hljs-comment"># ---- 加权求和 ----</span><br>        <span class="hljs-comment"># (80,2,4) @ (80,4,16) → output:(80,2,16)</span><br>        output = torch.matmul(attention, v)<br><br>        <span class="hljs-comment"># ---- 合并多头 ----</span><br>        <span class="hljs-comment"># (80,2,16) → view(8,10,2,16) → permute(1,2,0,3)=(10,2,8,16) → view(10,2,128)</span><br>        output = output.view(<span class="hljs-variable language_">self</span>.num_head, batch, n_q, <span class="hljs-variable language_">self</span>.d_v).permute(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">0</span>, <span class="hljs-number">3</span>).contiguous().view(batch, n_q, -<span class="hljs-number">1</span>)<br><br>        <span class="hljs-comment"># (10,2,128) → fc_o → (10,2,8)</span><br>        output = <span class="hljs-variable language_">self</span>.fc_o(output)<br>        <span class="hljs-keyword">return</span> attention, output  <span class="hljs-comment"># attention:(80,2,4)  output:(10,2,8)</span><br><br><br><span class="hljs-comment"># ==================== 测试 ====================</span><br>batch = <span class="hljs-number">10</span><br>num_head = <span class="hljs-number">8</span><br>n_q, n_k, n_v = <span class="hljs-number">2</span>, <span class="hljs-number">4</span>, <span class="hljs-number">4</span>   <span class="hljs-comment"># sequence 长度</span><br>dimension_q, dimension_k, dimension_v = <span class="hljs-number">128</span>, <span class="hljs-number">128</span>, <span class="hljs-number">64</span>  <span class="hljs-comment"># 输入 embedding 长度</span><br>d_k, d_v, d_o = <span class="hljs-number">16</span>, <span class="hljs-number">16</span>, <span class="hljs-number">8</span>  <span class="hljs-comment"># 单头维度 / 输出维度</span><br><br><span class="hljs-comment"># q:(10,2,128)  k:(10,4,128)  v:(10,4,64)</span><br>q = torch.randn(batch, n_q, dimension_q)<br>k = torch.randn(batch, n_k, dimension_k)<br>v = torch.randn(batch, n_v, dimension_v)<br><br><span class="hljs-comment"># mask:(10,2,4)，上三角为 -inf（因果掩码）</span><br>mask = torch.full((batch, n_q, n_k), -np.inf)<br>mask = torch.triu(mask, diagonal=<span class="hljs-number">1</span>)<br><br>mha = MHA(num_head, dimension_k, dimension_v, d_k, d_v, d_o)<br>attention, output = mha(q, k, v, mask)<br><span class="hljs-built_in">print</span>(attention.size(), output.size())  <span class="hljs-comment"># torch.Size([80, 2, 4]) torch.Size([10, 2, 8])</span><br><br>mqa = MQA(num_head, dimension_k, dimension_v, d_k, d_v, d_o)<br>attention, output = mqa(q, k, v, mask)<br><span class="hljs-built_in">print</span>(attention.size(), output.size())  <span class="hljs-comment"># torch.Size([80, 2, 4]) torch.Size([10, 2, 8])</span><br></code></pre></td></tr></table></figure><p>可参考博客</p><p><a href="https://hwcoder.top/Manual-Coding-1">https://hwcoder.top/Manual-Coding-1</a></p><p><a href="https://www.bilibili.com/video/BV19YbFeHETz/?spm_id_from=333.337.search-card.all.click&vd_source=1e761ed3a09f77601129e52e0099cad9">手写self-attention的四重境界</a></p>]]>
    </content>
    <id>https://liu-alessia.github.io/2026/07/12/2026-07-13-day1-self-attention/</id>
    <link href="https://liu-alessia.github.io/2026/07/12/2026-07-13-day1-self-attention/"/>
    <published>2026-07-12T16:00:00.000Z</published>
    <summary>
      <![CDATA[<p>此系列博客记录<a href="https://my.feishu.cn/docx/FAL3d7zlTo6fcCxQzXbcbY2Xnff">居丽叶的大模型自学计划表-算法岗速成版</a>的学习过程，主要参考资料<a href="https://my.feishu.cn/d]]>
    </summary>
    <title>day1-self-attention</title>
    <updated>2026-08-31T14:48:42.067Z</updated>
  </entry>
  <entry>
    <author>
      <name>Alessia</name>
    </author>
    <category term="项目实践" scheme="https://liu-alessia.github.io/categories/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E8%B7%B5/"/>
    <category term="Agent" scheme="https://liu-alessia.github.io/tags/Agent/"/>
    <category term="MCP" scheme="https://liu-alessia.github.io/tags/MCP/"/>
    <category term="金融分析" scheme="https://liu-alessia.github.io/tags/%E9%87%91%E8%9E%8D%E5%88%86%E6%9E%90/"/>
    <category term="LangGraph" scheme="https://liu-alessia.github.io/tags/LangGraph/"/>
    <content>
      <![CDATA[<h1 id="股票投资顾问Agent架构解析"><a href="#股票投资顾问Agent架构解析" class="headerlink" title="股票投资顾问Agent架构解析"></a>股票投资顾问Agent架构解析</h1><h2 id="项目概览"><a href="#项目概览" class="headerlink" title="项目概览"></a>项目概览</h2><p>这是一个基于多智能体协作和 MCP (Model Context Protocol) 的股票投资分析系统，由三个核心模块组成：</p><ol><li><strong>a-share-mcp-is-just-i-need</strong>: A股数据服务MCP服务器</li><li><strong>Financial-MCP-Agent</strong>: 多智能体金融分析系统</li><li><strong>模型训练与测试</strong>: 情感分析和风险评估模型</li></ol><hr><h2 id="整体架构"><a href="#整体架构" class="headerlink" title="整体架构"></a>整体架构</h2><figure class="highlight nix"><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><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><code class="hljs nix">Finance<span class="hljs-symbol">/</span><br>├── a-share-mcp-is-just-i-need<span class="hljs-symbol">/</span>      <span class="hljs-comment"># MCP数据服务层</span><br>│   ├── mcp_server.py                <span class="hljs-comment"># MCP服务器入口</span><br>│   └── src<span class="hljs-symbol">/</span><br>│       ├── data_source_interface.py <span class="hljs-comment"># 数据源抽象接口</span><br>│       ├── baostock_data_source.py  <span class="hljs-comment"># Baostock数据实现</span><br>│       ├── tools<span class="hljs-symbol">/</span>                   <span class="hljs-comment"># 各类金融数据工具</span><br>│       │   ├── stock_market.py      <span class="hljs-comment"># 股票行情</span><br>│       │   ├── financial_reports.py <span class="hljs-comment"># 财报数据</span><br>│       │   ├── indices.py           <span class="hljs-comment"># 指数数据</span><br>│       │   ├── market_overview.py   <span class="hljs-comment"># 市场概览</span><br>│       │   ├── macroeconomic.py     <span class="hljs-comment"># 宏观经济</span><br>│       │   ├── date_utils.py        <span class="hljs-comment"># 日期工具</span><br>│       │   ├── analysis.py          <span class="hljs-comment"># 分析工具</span><br>│       │   └── news_crawler.py      <span class="hljs-comment"># 新闻爬虫</span><br>│       └── formatting<span class="hljs-symbol">/</span><br>│           └── markdown_formatter.py <span class="hljs-comment"># Markdown格式化</span><br>│<br>├── Financial-MCP-Agent<span class="hljs-symbol">/</span>             <span class="hljs-comment"># 多智能体分析系统</span><br>│   ├── src<span class="hljs-symbol">/</span><br>│   │   ├── main.py                  <span class="hljs-comment"># 主程序入口</span><br>│   │   ├── agents<span class="hljs-symbol">/</span>                  <span class="hljs-comment"># 分析智能体</span><br>│   │   │   ├── fundamental_agent.py <span class="hljs-comment"># 基本面分析</span><br>│   │   │   ├── technical_agent.py   <span class="hljs-comment"># 技术分析</span><br>│   │   │   ├── value_agent.py       <span class="hljs-comment"># 估值分析</span><br>│   │   │   ├── news_agent.py        <span class="hljs-comment"># 新闻分析</span><br>│   │   │   └── summary_agent.py     <span class="hljs-comment"># 综合总结</span><br>│   │   ├── tools<span class="hljs-symbol">/</span><br>│   │   │   ├── mcp_client.py        <span class="hljs-comment"># MCP客户端</span><br>│   │   │   ├── mcp_config.py        <span class="hljs-comment"># MCP配置</span><br>│   │   │   └── openrouter_config.py <span class="hljs-comment"># OpenRouter配置</span><br>│   │   └── utils<span class="hljs-symbol">/</span><br>│   │       ├── state_definition.py  <span class="hljs-comment"># 状态定义</span><br>│   │       ├── execution_logger.py  <span class="hljs-comment"># 执行日志</span><br>│   │       ├── logging_config.py    <span class="hljs-comment"># 日志配置</span><br>│   │       └── llm_clients.py       <span class="hljs-comment"># LLM客户端</span><br>│   ├── logs<span class="hljs-symbol">/</span>                        <span class="hljs-comment"># 执行日志</span><br>│   └── reports<span class="hljs-symbol">/</span>                     <span class="hljs-comment"># 分析报告</span><br>│<br>├── 模型训练脚本                      <span class="hljs-comment"># 模型训练与测试</span><br>│   ├── train_qwen_sentiment.py      <span class="hljs-comment"># 情感分析模型训练</span><br>│   ├── train_qwen_risk.py           <span class="hljs-comment"># 风险评估模型训练</span><br>│   ├── test_qwen_sentiment.py       <span class="hljs-comment"># 情感模型测试</span><br>│   └── test_risk_model.py           <span class="hljs-comment"># 风险模型测试</span><br>│<br>├── 数据处理脚本<br>│   ├── data_process.py              <span class="hljs-comment"># 新闻去重处理</span><br>│   └── download.py                  <span class="hljs-comment"># 数据下载</span><br>│<br>├── 数据目录<br>│   ├── nasdaq_news_sentiment<span class="hljs-symbol">/</span>        <span class="hljs-comment"># 情感分析数据</span><br>│   └── risk_nasdaq<span class="hljs-symbol">/</span>                  <span class="hljs-comment"># 风险评估数据</span><br>│<br>└── requirements.txt                 <span class="hljs-comment"># 依赖管理</span><br></code></pre></td></tr></table></figure><hr><h2 id="核心架构解析"><a href="#核心架构解析" class="headerlink" title="核心架构解析"></a>核心架构解析</h2><h3 id="1-MCP数据服务层-a-share-mcp-is-just-i-need"><a href="#1-MCP数据服务层-a-share-mcp-is-just-i-need" class="headerlink" title="1. MCP数据服务层 (a-share-mcp-is-just-i-need)"></a>1. MCP数据服务层 (a-share-mcp-is-just-i-need)</h3><h4 id="设计理念"><a href="#设计理念" class="headerlink" title="设计理念"></a>设计理念</h4><p>采用 <strong>MCP协议</strong> 提供标准化的金融数据访问接口，通过抽象层实现数据源的可替换性。</p><h4 id="核心组件"><a href="#核心组件" class="headerlink" title="核心组件"></a>核心组件</h4><p><strong>数据源抽象接口</strong> (<code>FinancialDataSource</code>)</p><figure class="highlight python"><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><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">FinancialDataSource</span>(<span class="hljs-title class_ inherited__">ABC</span>):<br><span class="hljs-meta">    @abstractmethod</span><br>    <span class="hljs-keyword">def</span> <span class="hljs-title function_">get_historical_k_data</span>(<span class="hljs-params">...</span>) -&gt; pd.DataFrame<br>        <span class="hljs-string">&quot;&quot;&quot;获取历史K线数据&quot;&quot;&quot;</span><br>    <br><span class="hljs-meta">    @abstractmethod</span><br>    <span class="hljs-keyword">def</span> <span class="hljs-title function_">get_stock_basic_info</span>(<span class="hljs-params">...</span>) -&gt; pd.DataFrame<br>        <span class="hljs-string">&quot;&quot;&quot;获取股票基本信息&quot;&quot;&quot;</span><br>    <br><span class="hljs-meta">    @abstractmethod</span><br>    <span class="hljs-keyword">def</span> <span class="hljs-title function_">get_trade_dates</span>(<span class="hljs-params">...</span>) -&gt; pd.DataFrame<br>        <span class="hljs-string">&quot;&quot;&quot;获取交易日历&quot;&quot;&quot;</span><br></code></pre></td></tr></table></figure><p><strong>具体实现</strong> (<code>BaostockDataSource</code>)</p><ul><li>基于 baostock 库实现A股数据获取</li><li>支持K线、财报、指数、宏观数据</li><li>实现了完整的 <code>FinancialDataSource</code> 接口</li></ul><p><strong>工具模块注册</strong><br>每个工具模块通过 <code>register_*_tools()</code> 函数向MCP服务器注册功能：</p><ul><li><code>register_stock_market_tools()</code> - 股票行情工具</li><li><code>register_financial_report_tools()</code> - 财报分析工具</li><li><code>register_index_tools()</code> - 指数追踪工具</li><li><code>register_market_overview_tools()</code> - 市场概览工具</li><li><code>register_macroeconomic_tools()</code> - 宏观经济工具</li><li><code>register_date_utils_tools()</code> - 日期工具</li><li><code>register_analysis_tools()</code> - 分析工具</li><li><code>register_news_crawler_tools()</code> - 新闻爬虫工具</li></ul><h4 id="技术栈"><a href="#技术栈" class="headerlink" title="技术栈"></a>技术栈</h4><ul><li><strong>FastMCP</strong>: 现代化的MCP服务器框架</li><li><strong>baostock</strong>: 免费A股数据接口</li><li><strong>pandas</strong>: 数据处理</li></ul><hr><h3 id="2-多智能体分析系统-Financial-MCP-Agent"><a href="#2-多智能体分析系统-Financial-MCP-Agent" class="headerlink" title="2. 多智能体分析系统 (Financial-MCP-Agent)"></a>2. 多智能体分析系统 (Financial-MCP-Agent)</h3><h4 id="设计理念-1"><a href="#设计理念-1" class="headerlink" title="设计理念"></a>设计理念</h4><p>采用 <strong>LangGraph</strong> 构建并行智能体工作流，每个智能体专注于特定分析维度，最终由总结智能体整合结果。</p><h4 id="工作流架构"><a href="#工作流架构" class="headerlink" title="工作流架构"></a>工作流架构</h4><figure class="highlight scss"><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><code class="hljs scss">用户输入 (股票名称/代码)<br>    ↓<br>start_node (提取股票信息)<br>    ↓<br>    ├─→ fundamental_analyst (基本面分析)<br>    ├─→ technical_analyst (技术分析)<br>    ├─→ value_analyst (估值分析)<br>    └─→ news_analyst (新闻分析)<br>    ↓<br>summarizer (综合总结)<br>    ↓<br>生成分析报告<br></code></pre></td></tr></table></figure><h4 id="核心智能体"><a href="#核心智能体" class="headerlink" title="核心智能体"></a>核心智能体</h4><p><strong>1. 基本面分析智能体</strong> (<code>fundamental_agent.py</code>)</p><ul><li>分析财务状况（营收、利润、现金流）</li><li>评估盈利能力和成长性</li><li>行业地位对比</li><li>使用MCP工具获取财报数据</li><li>基于 ReAct Agent 框架实现</li></ul><p><strong>2. 技术分析智能体</strong> (<code>technical_agent.py</code>)</p><ul><li>价格趋势分析</li><li>技术指标计算（MA、MACD、RSI等）</li><li>成交量分析</li><li>支撑阻力位识别</li><li>基于 ReAct Agent 框架实现</li></ul><p><strong>3. 估值分析智能体</strong> (<code>value_agent.py</code>)</p><ul><li>市盈率、市净率分析</li><li>PEG、DCF等估值模型</li><li>行业估值对比</li><li>内在价值评估</li><li>基于 ReAct Agent 框架实现</li></ul><p><strong>4. 新闻分析智能体</strong> (<code>news_agent.py</code>)</p><ul><li>新闻情感分析</li><li>风险因素识别</li><li>重大事件影响评估</li><li>使用新闻爬虫工具获取最新新闻</li><li>基于 ReAct Agent 框架实现</li></ul><p><strong>5. 综合总结智能体</strong> (<code>summary_agent.py</code>)</p><ul><li>整合四个维度的分析结果</li><li>生成投资建议</li><li>风险提示</li><li>输出结构化报告</li><li>使用 Summary Agent 框架</li></ul><h4 id="状态管理"><a href="#状态管理" class="headerlink" title="状态管理"></a>状态管理</h4><p>使用 <code>AgentState</code> 实现智能体间的数据传递：</p><figure class="highlight python"><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><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">AgentState</span>(<span class="hljs-title class_ inherited__">TypedDict</span>):<br>    messages: Annotated[<span class="hljs-type">Sequence</span>[BaseMessage], operator.add]<br>    data: Annotated[<span class="hljs-type">Dict</span>[<span class="hljs-built_in">str</span>, <span class="hljs-type">Any</span>], merge_dicts]<br>    metadata: Annotated[<span class="hljs-type">Dict</span>[<span class="hljs-built_in">str</span>, <span class="hljs-type">Any</span>], merge_dicts]<br></code></pre></td></tr></table></figure><h4 id="自然语言处理"><a href="#自然语言处理" class="headerlink" title="自然语言处理"></a>自然语言处理</h4><p>主程序包含复杂的股票信息提取逻辑，支持多种查询格式：</p><ul><li>“分析嘉友国际”</li><li>“帮我看看比亚迪这只股票怎么样”</li><li>“603871 这个股票值得买吗？”</li><li>“茅台(600519)值得投资吗”</li></ul><p>提取模式包括20多种正则表达式模式：</p><ol><li>括号内的股票代码</li><li>直接的公司名称</li><li>股票代码+公司名组合</li><li>智能语义识别</li><li>复杂句式解析</li></ol><hr><h3 id="3-模型训练与测试模块"><a href="#3-模型训练与测试模块" class="headerlink" title="3. 模型训练与测试模块"></a>3. 模型训练与测试模块</h3><h4 id="3-1-情感分析模型训练-train-qwen-sentiment-py"><a href="#3-1-情感分析模型训练-train-qwen-sentiment-py" class="headerlink" title="3.1 情感分析模型训练 (train_qwen_sentiment.py)"></a>3.1 情感分析模型训练 (<code>train_qwen_sentiment.py</code>)</h4><p><strong>功能</strong>: 训练金融新闻情感分析模型</p><p><strong>技术架构</strong>:</p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs">数据加载 → 提示模板构建 → Tokenization → LoRA微调 → 模型保存<br></code></pre></td></tr></table></figure><p><strong>核心组件</strong>:</p><ol><li><p><strong>数据预处理</strong> (<code>load_and_preprocess_data</code>)</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs python">df = df[df[<span class="hljs-string">&#x27;Lsa_summary&#x27;</span>].notna() &amp; df[<span class="hljs-string">&#x27;sentiment_deepseek&#x27;</span>].notna()]<br>df = df[df[<span class="hljs-string">&#x27;sentiment_deepseek&#x27;</span>] != <span class="hljs-number">0</span>]  <span class="hljs-comment"># 移除无效标签</span><br></code></pre></td></tr></table></figure></li><li><p><strong>提示模板构建</strong> (<code>create_prompt_template</code>)</p><figure class="highlight python"><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></pre></td><td class="code"><pre><code class="hljs python">system_prompt = <span class="hljs-string">&quot;You are a financial expert... Score from 1 to 5...&quot;</span><br>conversation = <span class="hljs-string">f&quot;&quot;&quot;System: <span class="hljs-subst">&#123;system_prompt&#125;</span></span><br><span class="hljs-string"></span><br><span class="hljs-string">User: News to Stock Symbol -- AAPL: Apple (AAPL) increase 22%</span><br><span class="hljs-string">Assistant: 5</span><br><span class="hljs-string"></span><br><span class="hljs-string">User: <span class="hljs-subst">&#123;user_content&#125;</span></span><br><span class="hljs-string">Assistant: <span class="hljs-subst">&#123;sentiment&#125;</span>&quot;&quot;&quot;</span><br></code></pre></td></tr></table></figure></li><li><p><strong>数据集准备</strong> (<code>prepare_dataset</code>)</p><ul><li>训练集&#x2F;验证集分割 (80%&#x2F;20%)</li><li>Tokenization处理</li><li>智能损失计算（只对Assistant回答部分计算损失）</li></ul></li><li><p><strong>LoRA微调配置</strong></p><figure class="highlight python"><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></pre></td><td class="code"><pre><code class="hljs python">lora_config = LoraConfig(<br>    task_type=TaskType.CAUSAL_LM,<br>    r=<span class="hljs-number">16</span>,                          <span class="hljs-comment"># LoRA rank</span><br>    lora_alpha=<span class="hljs-number">32</span>,                  <span class="hljs-comment"># 缩放因子</span><br>    lora_dropout=<span class="hljs-number">0.1</span>,               <span class="hljs-comment"># Dropout</span><br>    target_modules=[<span class="hljs-string">&quot;q_proj&quot;</span>, <span class="hljs-string">&quot;v_proj&quot;</span>, <span class="hljs-string">&quot;k_proj&quot;</span>, <span class="hljs-string">&quot;o_proj&quot;</span>, <br>                    <span class="hljs-string">&quot;gate_proj&quot;</span>, <span class="hljs-string">&quot;up_proj&quot;</span>, <span class="hljs-string">&quot;down_proj&quot;</span>]<br>)<br></code></pre></td></tr></table></figure></li></ol><p><strong>评分标准</strong>:</p><ul><li>1: 负面</li><li>2: 轻微负面</li><li>3: 中性</li><li>4: 正面</li><li>5: 极正面</li></ul><p><strong>训练参数</strong>:</p><figure class="highlight python"><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><code class="hljs python">TrainingArguments(<br>    output_dir=<span class="hljs-string">&quot;./qwen_sentiment_model&quot;</span>,<br>    num_train_epochs=<span class="hljs-number">3</span>,<br>    per_device_train_batch_size=<span class="hljs-number">4</span>,<br>    gradient_accumulation_steps=<span class="hljs-number">4</span>,<br>    warmup_steps=<span class="hljs-number">100</span>,<br>    learning_rate=<span class="hljs-number">2e-5</span>,<br>    fp16=<span class="hljs-literal">True</span>,<br>    logging_steps=<span class="hljs-number">50</span>,<br>    save_steps=<span class="hljs-number">500</span>,<br>    eval_steps=<span class="hljs-number">500</span><br>)<br></code></pre></td></tr></table></figure><hr><h4 id="3-2-风险评估模型训练-train-qwen-risk-py"><a href="#3-2-风险评估模型训练-train-qwen-risk-py" class="headerlink" title="3.2 风险评估模型训练 (train_qwen_risk.py)"></a>3.2 风险评估模型训练 (<code>train_qwen_risk.py</code>)</h4><p><strong>功能</strong>: 训练股票风险评估模型</p><p><strong>技术架构</strong>: 与情感分析模型完全相同的架构，但专注于风险评估</p><p><strong>核心差异</strong>:</p><ol><li><p><strong>评分标准不同</strong>:</p><ul><li>1: 极低风险</li><li>2: 低风险</li><li>3: 中等风险（默认，无明显风险迹象）</li><li>4: 高风险</li><li>5: 极高风险</li></ul></li><li><p><strong>提示词不同</strong>:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs python">system_prompt = <span class="hljs-string">&quot;You are a financial expert specializing in risk assessment... </span><br><span class="hljs-string">Provide a risk score from 1 to 5...&quot;</span><br></code></pre></td></tr></table></figure></li><li><p><strong>示例不同</strong>:</p><figure class="highlight python"><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></pre></td><td class="code"><pre><code class="hljs python">User: Apple (AAPL) increases <span class="hljs-number">22</span>%<br>Assistant: <span class="hljs-number">3</span>  <span class="hljs-comment"># 涨幅较大但非风险事件</span><br><br>User: Apple (AAPL) price decreased <span class="hljs-number">30</span>%<br>Assistant: <span class="hljs-number">4</span>  <span class="hljs-comment"># 大幅下跌，高风险</span><br></code></pre></td></tr></table></figure></li></ol><p><strong>训练输出</strong>: 模型保存在 <code>./qwen_risk_model</code></p><hr><h4 id="3-3-情感模型测试-test-qwen-sentiment-py"><a href="#3-3-情感模型测试-test-qwen-sentiment-py" class="headerlink" title="3.3 情感模型测试 (test_qwen_sentiment.py)"></a>3.3 情感模型测试 (<code>test_qwen_sentiment.py</code>)</h4><p><strong>功能</strong>: 测试训练好的情感分析模型</p><p><strong>测试流程</strong>:</p><ol><li><p><strong>模型加载</strong></p><figure class="highlight python"><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></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">load_trained_sentiment_model</span>(<span class="hljs-params">model_path</span>):<br>    tokenizer = AutoTokenizer.from_pretrained(model_path)<br>    base_model = AutoModelForCausalLM.from_pretrained(<span class="hljs-string">&quot;/root/code/Finance/Qwen&quot;</span>, ...)<br>    model = PeftModel.from_pretrained(base_model, model_path)<br>    <span class="hljs-keyword">return</span> model, tokenizer<br></code></pre></td></tr></table></figure></li><li><p><strong>预测函数</strong></p><figure class="highlight python"><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></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">predict_sentiment</span>(<span class="hljs-params">model, tokenizer, text, stock_symbol</span>):<br>    prompt = create_sentiment_test_prompt(text, stock_symbol)<br>    inputs = tokenizer(prompt, return_tensors=<span class="hljs-string">&quot;pt&quot;</span>, truncation=<span class="hljs-literal">True</span>, max_length=<span class="hljs-number">512</span>)<br>    outputs = model.generate(**inputs, max_new_tokens=<span class="hljs-number">5</span>, do_sample=<span class="hljs-literal">False</span>)<br>    <span class="hljs-keyword">return</span> extract_score(outputs)<br></code></pre></td></tr></table></figure></li><li><p><strong>测试内容</strong>:</p><ul><li><strong>预设测试用例</strong>: 10个不同场景的新闻</li><li><strong>真实数据测试</strong>: 从CSV读取真实数据进行测试</li><li><strong>情感分布测试</strong>: 测试模型在5个类别上的表现</li></ul></li></ol><p><strong>测试输出示例</strong>:</p><figure class="highlight asciidoc"><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></pre></td><td class="code"><pre><code class="hljs asciidoc"><span class="hljs-section">=== 情感分析模型测试结果 ===</span><br><br>测试 1:<br>新闻: Apple reported strong quarterly earnings with revenue growth of 15%<br>股票: AAPL<br>预测情感: 4 (正面)<br><br>测试 2:<br>新闻: Apple faces supply chain disruptions and production delays<br>股票: AAPL<br>预测情感: 2 (轻微负面)<br><br>整体准确率: 8/10 = 80.0%<br></code></pre></td></tr></table></figure><hr><h4 id="3-4-风险模型测试-test-risk-model-py"><a href="#3-4-风险模型测试-test-risk-model-py" class="headerlink" title="3.4 风险模型测试 (test_risk_model.py)"></a>3.4 风险模型测试 (<code>test_risk_model.py</code>)</h4><p><strong>功能</strong>: 测试训练好的风险评估模型</p><p><strong>测试流程</strong>: 与情感模型测试类似，但专注于风险评分</p><p><strong>测试内容</strong>:</p><ul><li>预设测试用例（7个）</li><li>真实数据测试（3条）</li></ul><p><strong>测试输出示例</strong>:</p><figure class="highlight asciidoc"><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><code class="hljs asciidoc"><span class="hljs-section">=== 风险评估模型测试结果 ===</span><br><br>测试 1:<br>新闻: Apple reported strong quarterly earnings with revenue growth of 15%<br>股票: AAPL<br>预测风险: 2 (低风险)<br><br>测试 2:<br>新闻: Apple faces major supply chain disruptions and production delays<br>股票: AAPL<br>预测风险: 4 (高风险)<br></code></pre></td></tr></table></figure><hr><h3 id="4-数据处理模块-data-process-py"><a href="#4-数据处理模块-data-process-py" class="headerlink" title="4. 数据处理模块 (data_process.py)"></a>4. 数据处理模块 (<code>data_process.py</code>)</h3><p><strong>功能</strong>: 新闻去重和数据预处理</p><p><strong>核心组件</strong>:</p><figure class="highlight python"><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><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">NewsDeduplicator</span>:<br>    <span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self</span>):<br>        <span class="hljs-variable language_">self</span>.title_threshold = <span class="hljs-number">0.8</span>       <span class="hljs-comment"># 标题相似度阈值</span><br>        <span class="hljs-variable language_">self</span>.content_threshold = <span class="hljs-number">0.75</span>     <span class="hljs-comment"># 正文重合度阈值</span><br>        <span class="hljs-variable language_">self</span>.simhash_threshold = <span class="hljs-number">3</span>        <span class="hljs-comment"># 汉明距离阈值</span><br>        <span class="hljs-variable language_">self</span>.minhash_permutations = <span class="hljs-number">128</span>   <span class="hljs-comment"># MinHash排列数</span><br></code></pre></td></tr></table></figure><p><strong>关键算法</strong>:</p><ol><li><p><strong>标题相似度</strong> - 组合方法</p><figure class="highlight python"><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><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">title_similarity</span>(<span class="hljs-params">title1, title2</span>):<br>    edit_sim = <span class="hljs-variable language_">self</span>.edit_distance(title1, title2)      <span class="hljs-comment"># 编辑距离</span><br>    cos_sim = <span class="hljs-variable language_">self</span>.text_to_tfidf_vector([title1, title2])  <span class="hljs-comment"># TF-IDF余弦相似度</span><br>    <span class="hljs-keyword">return</span> (edit_sim + cos_sim) / <span class="hljs-number">2</span>  <span class="hljs-comment"># 平均</span><br></code></pre></td></tr></table></figure></li><li><p><strong>正文重合度</strong> - MinHash</p><figure class="highlight python"><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><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">content_overlap</span>(<span class="hljs-params">content1, content2</span>):<br>    shingles1 = <span class="hljs-variable language_">self</span>.get_shingles(content1)  <span class="hljs-comment"># 生成k-shingles</span><br>    shingles2 = <span class="hljs-variable language_">self</span>.get_shingles(content2)<br>    sig1 = <span class="hljs-variable language_">self</span>.minhash_signature(shingles1) <span class="hljs-comment"># 计算MinHash签名</span><br>    sig2 = <span class="hljs-variable language_">self</span>.minhash_signature(shingles2)<br>    <span class="hljs-keyword">return</span> <span class="hljs-variable language_">self</span>.jaccard_similarity_minhash(sig1, sig2)<br></code></pre></td></tr></table></figure></li><li><p><strong>语义相似度</strong> - SimHash</p><figure class="highlight python"><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><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">semantic_similarity</span>(<span class="hljs-params">content1, content2</span>):<br>    hash1 = <span class="hljs-variable language_">self</span>.simhash(content1)      <span class="hljs-comment"># 计算SimHash</span><br>    hash2 = <span class="hljs-variable language_">self</span>.simhash(content2)<br>    <span class="hljs-keyword">return</span> <span class="hljs-variable language_">self</span>.hamming_distance(hash1, hash2)  <span class="hljs-comment"># 汉明距离</span><br></code></pre></td></tr></table></figure></li><li><p><strong>去重判断</strong> - 三重阈值</p><figure class="highlight python"><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><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">is_duplicate</span>(<span class="hljs-params">item1, item2</span>):<br>    <span class="hljs-keyword">return</span> (<br>        <span class="hljs-variable language_">self</span>.title_similarity(title1, title2) &gt; <span class="hljs-number">0.8</span> <span class="hljs-keyword">and</span><br>        <span class="hljs-variable language_">self</span>.content_overlap(content1, content2) &gt; <span class="hljs-number">0.75</span> <span class="hljs-keyword">and</span><br>        <span class="hljs-variable language_">self</span>.semantic_similarity(content1, content2) &lt;= <span class="hljs-number">3</span><br>    )<br></code></pre></td></tr></table></figure></li></ol><p><strong>处理流程</strong>:</p><figure class="highlight excel"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs excel">CSV文件 → 加载数据 → <span class="hljs-built_in">Unicode</span>归一化 → 计算相似度 → <br>三重阈值判断 → 去重处理 → 保存JSONL<br></code></pre></td></tr></table></figure><hr><h3 id="5-完整程序架构图"><a href="#5-完整程序架构图" class="headerlink" title="5. 完整程序架构图"></a>5. 完整程序架构图</h3><figure class="highlight css"><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></pre></td><td class="code"><pre><code class="hljs css">┌─────────────────────────────────────────────────────────┐<br>│                    Finance Project                       │<br>└─────────────────────────────────────────────────────────┘<br>                            │<br>        ┌───────────────────┼───────────────────┐<br>        │                   │                   │<br>        ▼                   ▼                   ▼<br>┌──────────────┐   ┌──────────────┐   ┌──────────────┐<br>│ 数据处理层    │   │ 模型训练层    │   │ Agent应用层  │<br>├──────────────┤   ├──────────────┤   ├──────────────┤<br>│              │   │              │   │              │<br>│ data_process │   │ train_qwen_  │   │ Financial-   │<br>│              │   │ _sentiment   │   │ MCP-Agent    │<br>│ download<span class="hljs-selector-class">.py</span>  │   │              │   │              │<br>│              │   │ train_qwen_  │   │ <span class="hljs-selector-tag">main</span><span class="hljs-selector-class">.py</span>      │<br>│ NewsDedu-    │   │ _risk        │   │              │<br>│ plicator     │   │              │   │ agents/      │<br>│              │   │ test_qwen_   │   │              │<br>│ - 去重策略    │   │ _sentiment   │   │ - 基本面     │<br>│ - 相似度计算  │   │              │   │ - 技术面     │<br>│ - 数据清洗    │   │ test_risk_   │   │ - 估值面     │<br>│              │   │ _model       │   │ - 新闻面     │<br>└──────┬───────┘   └──────┬───────┘   └──────┬───────┘<br>       │                  │                  │<br>       │                  │                  │<br>       ▼                  ▼                  ▼<br>┌─────────────────────────────────────────────────────┐<br>│                   <span class="hljs-selector-tag">a</span>-share-mcp-server                 │<br>│                    (数据服务层)                       │<br>├─────────────────────────────────────────────────────┤<br>│ - stock_market      - financial_reports              │<br>│ - indices           - market_overview                │<br>│ - macroeconomic     - analysis                       │<br>│ - date_utils        - news_crawler                   │<br>└─────────────────────────────────────────────────────┘<br>       │<br>       ▼<br>┌─────────────────────────────────────────────────────┐<br>│                  Baostock API                        │<br>│                  (<span class="hljs-selector-tag">A</span>股数据源)                         │<br>└─────────────────────────────────────────────────────┘<br></code></pre></td></tr></table></figure><hr><h3 id="6-数据流程图"><a href="#6-数据流程图" class="headerlink" title="6. 数据流程图"></a>6. 数据流程图</h3><figure class="highlight nix"><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></pre></td><td class="code"><pre><code class="hljs nix">原始新闻数据 (CSV)<br>    ↓<br>data_process.py<br>    ├─ load_and_preprocess_data()  <span class="hljs-comment"># 加载和过滤</span><br>    ├─ unicode_normalize()          <span class="hljs-comment"># Unicode归一化</span><br>    ├─ title_similarity()           <span class="hljs-comment"># 标题相似度计算</span><br>    ├─ content_overlap()            <span class="hljs-comment"># 正文重合度计算</span><br>    ├─ semantic_similarity()        <span class="hljs-comment"># 语义相似度计算</span><br>    └─ deduplicate()                <span class="hljs-comment"># 去重处理</span><br>    ↓<br>清洗后的数据 (JSONL<span class="hljs-operator">/</span>CSV)<br>    ↓<br>训练集 <span class="hljs-symbol">/</span> 验证集 (<span class="hljs-number">80</span>%<span class="hljs-operator">/</span><span class="hljs-number">20</span>%)<br>    ↓<br>train_qwen_sentiment.py <span class="hljs-symbol">/</span> train_qwen_risk.py<br>    ├─ create_prompt_template()     <span class="hljs-comment"># 创建提示模板</span><br>    ├─ prepare_dataset()           <span class="hljs-comment"># 数据集准备</span><br>    ├─ tokenize_function()         <span class="hljs-comment"># Token化</span><br>    ├─ create_model_and_tokenizer() <span class="hljs-comment"># 创建模型</span><br>    ├─ LoRA微调                     <span class="hljs-comment"># 参数高效训练</span><br>    └─ save_model()                 <span class="hljs-comment"># 保存模型</span><br>    ↓<br>训练好的模型<br>    ↓<br>test_qwen_sentiment.py <span class="hljs-symbol">/</span> test_risk_model.py<br>    ├─ load_trained_model()         <span class="hljs-comment"># 加载模型</span><br>    ├─ predict()                    <span class="hljs-comment"># 预测</span><br>    └─ evaluate()                   <span class="hljs-comment"># 评估</span><br></code></pre></td></tr></table></figure><hr><h3 id="7-关键技术详解"><a href="#7-关键技术详解" class="headerlink" title="7. 关键技术详解"></a>7. 关键技术详解</h3><h4 id="7-1-损失计算策略"><a href="#7-1-损失计算策略" class="headerlink" title="7.1 损失计算策略"></a>7.1 损失计算策略</h4><p>在训练过程中，采用智能损失计算策略：</p><figure class="highlight python"><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></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">tokenize_function</span>(<span class="hljs-params">examples</span>):<br>    labels = tokenized[<span class="hljs-string">&#x27;input_ids&#x27;</span>].clone()<br>    <br>    <span class="hljs-keyword">for</span> i, text <span class="hljs-keyword">in</span> <span class="hljs-built_in">enumerate</span>(examples[<span class="hljs-string">&#x27;text&#x27;</span>]):<br>        <span class="hljs-comment"># 找到Assistant标记位置</span><br>        assistant_marker = <span class="hljs-string">&quot;Assistant: &quot;</span><br>        last_assistant_pos = text.rfind(assistant_marker)<br>        <br>        <span class="hljs-keyword">if</span> last_assistant_pos != -<span class="hljs-number">1</span>:<br>            <span class="hljs-comment"># 计算输入部分的token数量</span><br>            input_part = text[:last_assistant_pos + <span class="hljs-built_in">len</span>(assistant_marker)]<br>            input_part_tokens = tokenizer.encode(input_part, add_special_tokens=<span class="hljs-literal">False</span>)<br>            mask_length = <span class="hljs-built_in">len</span>(input_part_tokens)<br>            <br>            <span class="hljs-comment"># 将输入部分设置为-100（不计算损失）</span><br>            labels[i, :mask_length] = -<span class="hljs-number">100</span><br>            <br>            <span class="hljs-comment"># 确保padding部分也是-100</span><br>            actual_length = (input_ids != pad_token_id).<span class="hljs-built_in">sum</span>().item()<br>            <span class="hljs-keyword">if</span> actual_length &lt; <span class="hljs-built_in">len</span>(input_ids):<br>                labels[i, actual_length:] = -<span class="hljs-number">100</span><br>    <br>    tokenized[<span class="hljs-string">&#x27;labels&#x27;</span>] = labels<br>    <span class="hljs-keyword">return</span> tokenized<br></code></pre></td></tr></table></figure><p><strong>优势</strong>:</p><ul><li>只对模型生成部分计算损失</li><li>避免对System、User等固定部分计算损失</li><li>提高训练效率</li></ul><hr><h4 id="7-2-新闻去重算法"><a href="#7-2-新闻去重算法" class="headerlink" title="7.2 新闻去重算法"></a>7.2 新闻去重算法</h4><p><strong>三重阈值策略</strong>:</p><figure class="highlight python"><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><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">is_duplicate</span>(<span class="hljs-params">item1, item2</span>):<br>    <span class="hljs-comment"># 1. 标题相似度 &gt; 0.8</span><br>    title_sim = <span class="hljs-variable language_">self</span>.title_similarity(title1, title2)<br>    <br>    <span class="hljs-comment"># 2. 正文重合度 &gt; 0.75</span><br>    content_sim = <span class="hljs-variable language_">self</span>.content_overlap(content1, content2)<br>    <br>    <span class="hljs-comment"># 3. 语义距离 &lt;= 3</span><br>    semantic_dist = <span class="hljs-variable language_">self</span>.semantic_similarity(content1, content2)<br>    <br>    <span class="hljs-keyword">return</span> (title_sim &gt; <span class="hljs-number">0.8</span> <span class="hljs-keyword">and</span> content_sim &gt; <span class="hljs-number">0.75</span> <span class="hljs-keyword">and</span> semantic_dist &lt;= <span class="hljs-number">3</span>)<br></code></pre></td></tr></table></figure><p><strong>各算法特点</strong>:</p><ul><li><strong>编辑距离</strong>: 字符级别的相似度</li><li><strong>TF-IDF余弦相似度</strong>: 词向量级别的相似度</li><li><strong>MinHash</strong>: 快速估计Jaccard相似度</li><li><strong>SimHash</strong>: 语义级别的指纹匹配</li></ul><hr><h3 id="8-部署架构"><a href="#8-部署架构" class="headerlink" title="8. 部署架构"></a>8. 部署架构</h3><figure class="highlight sqf"><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></pre></td><td class="code"><pre><code class="hljs sqf">┌─────────────────────────────────────────┐<br>│         用户终端 (CLI)                    │<br>└────────────┬────────────────────────────┘<br>             │<br>             ↓<br>┌─────────────────────────────────────────┐<br>│      Financial-MCP-<span class="hljs-built_in">Agent</span>                 │<br>│  (多智能体工作流引擎)                      │<br>│                                          │<br>│  ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐   │<br>│  │基本面│ │技术面│ │估值面│ │新闻面│   │<br>│  │<span class="hljs-built_in">Agent</span> │ │<span class="hljs-built_in">Agent</span> │ │<span class="hljs-built_in">Agent</span> │ │<span class="hljs-built_in">Agent</span> │   │<br>│  └───┬──┘ └───┬──┘ └───┬──┘ └───┬──┘   │<br>│      └───────┴───────┴───────┴───────┘   │<br>│                   │                        │<br>│                   ↓                        │<br>│              总结<span class="hljs-built_in">Agent</span>                     │<br>└───────────────────┬───────────────────────┘<br>                    │ MCP Protocol<br>                    ↓<br>┌─────────────────────────────────────────┐<br>│    a-share-mcp-is-just-i-need            │<br>│         (MCP数据服务器)                   │<br>│                                          │<br>│  ┌──────────┐  ┌──────────┐              │<br>│  │数据接口层│  │工具注册器│              │<br>│  └────┬─────┘  └────┬─────┘              │<br>│       │             │                     │<br>│       ↓             ↓                     │<br>│  ┌────────────────────────┐              │<br>│  │  Baostock数据源        │              │<br>│  └────────────────────────┘              │<br>└───────────────────┬──────────────────────┘<br>                    │<br>                    ↓<br>           ┌────────────────┐<br>           │  Baostock API  │<br>           │  (免费A股数据)  │<br>           └────────────────┘<br></code></pre></td></tr></table></figure><hr><h3 id="9-依赖管理"><a href="#9-依赖管理" class="headerlink" title="9. 依赖管理"></a>9. 依赖管理</h3><h4 id="核心依赖"><a href="#核心依赖" class="headerlink" title="核心依赖"></a>核心依赖</h4><figure class="highlight txt"><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></pre></td><td class="code"><pre><code class="hljs txt"># 智能体工作流<br>langgraph==0.6.6              # 智能体工作流编排<br>python-dotenv==1.1.1          # 环境变量管理<br>langchain-openai==0.3.30      # OpenAI API集成<br>langchain-core==0.3.74        # LangChain核心<br>langchain-mcp-adapters==0.1.9 # MCP协议适配<br><br># 模型训练<br>transformers==4.51.3         # HuggingFace模型<br>peft==0.17.0                 # 参数高效微调 (LoRA)<br>huggingface-hub==0.34.4      # 模型仓库<br><br># 数据处理<br>baostock==0.9.1              # A股数据接口<br>pandas                       # 数据处理<br>numpy                        # 数值计算<br>scikit-learn                 # TF-IDF、余弦相似度<br>jieba                        # 中文分词<br><br># 其他<br>uv==0.8.12                   # 包管理器<br></code></pre></td></tr></table></figure><hr><h3 id="10-使用示例"><a href="#10-使用示例" class="headerlink" title="10. 使用示例"></a>10. 使用示例</h3><h4 id="命令行调用"><a href="#命令行调用" class="headerlink" title="命令行调用"></a>命令行调用</h4><figure class="highlight bash"><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><code class="hljs bash"><span class="hljs-comment"># 直接分析</span><br>python src/main.py --<span class="hljs-built_in">command</span> <span class="hljs-string">&quot;分析嘉友国际&quot;</span><br><br><span class="hljs-comment"># 交互式输入</span><br>python src/main.py<br><span class="hljs-comment"># 系统会提示输入查询内容</span><br></code></pre></td></tr></table></figure><h4 id="训练模型"><a href="#训练模型" class="headerlink" title="训练模型"></a>训练模型</h4><figure class="highlight bash"><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></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># 训练情感分析模型</span><br>python train_qwen_sentiment.py<br><br><span class="hljs-comment"># 训练风险评估模型</span><br>python train_qwen_risk.py<br></code></pre></td></tr></table></figure><h4 id="测试模型"><a href="#测试模型" class="headerlink" title="测试模型"></a>测试模型</h4><figure class="highlight bash"><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></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># 测试情感分析模型</span><br>python test_qwen_sentiment.py<br><br><span class="hljs-comment"># 测试风险评估模型</span><br>python test_risk_model.py<br></code></pre></td></tr></table></figure><h4 id="数据处理"><a href="#数据处理" class="headerlink" title="数据处理"></a>数据处理</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># 新闻去重处理</span><br>python data_process.py<br></code></pre></td></tr></table></figure><hr><h3 id="11-查询示例"><a href="#11-查询示例" class="headerlink" title="11. 查询示例"></a>11. 查询示例</h3><p>系统支持多种自然语言查询方式：</p><ul><li><strong>简单查询</strong>: “分析嘉友国际”</li><li><strong>描述性查询</strong>: “帮我看看比亚迪这只股票怎么样”</li><li><strong>代码查询</strong>: “603871 这个股票值得买吗？”</li><li><strong>格式化查询</strong>: “茅台(600519)值得投资吗”</li><li><strong>复杂查询</strong>: “我想了解一下腾讯的投资价值”</li><li><strong>细分查询</strong>: “给我分析一下宁德时代的财务状况”</li></ul><hr><h3 id="12-输出内容"><a href="#12-输出内容" class="headerlink" title="12. 输出内容"></a>12. 输出内容</h3><p>系统会生成结构化的分析报告，包含：</p><ol><li><strong>基本信息</strong> - 股票代码、公司名称、行业分类</li><li><strong>基本面分析</strong> - 财务指标、盈利能力、成长性</li><li><strong>技术面分析</strong> - 趋势判断、技术指标信号</li><li><strong>估值分析</strong> - 估值水平、投资价值</li><li><strong>新闻分析</strong> - 近期新闻、风险提示</li><li><strong>综合建议</strong> - 投资评级、风险提示</li></ol><p>报告保存在 <code>reports/</code> 目录，格式为 <code>report_&#123;公司名&#125;_&#123;代码&#125;_&#123;日期&#125;.md</code></p><hr><h3 id="13-扩展性设计"><a href="#13-扩展性设计" class="headerlink" title="13. 扩展性设计"></a>13. 扩展性设计</h3><h4 id="添加新的数据源"><a href="#添加新的数据源" class="headerlink" title="添加新的数据源"></a>添加新的数据源</h4><figure class="highlight python"><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></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">MyDataSource</span>(<span class="hljs-title class_ inherited__">FinancialDataSource</span>):<br>    <span class="hljs-comment"># 实现所有抽象方法</span><br>    <span class="hljs-keyword">def</span> <span class="hljs-title function_">get_historical_k_data</span>(<span class="hljs-params">self, ...</span>):<br>        <span class="hljs-comment"># 实现K线数据获取</span><br>        <span class="hljs-keyword">pass</span><br></code></pre></td></tr></table></figure><h4 id="添加新的分析智能体"><a href="#添加新的分析智能体" class="headerlink" title="添加新的分析智能体"></a>添加新的分析智能体</h4><figure class="highlight python"><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><code class="hljs python"><span class="hljs-keyword">from</span> langgraph.graph <span class="hljs-keyword">import</span> StateGraph, END<br><br><span class="hljs-comment"># 添加新节点</span><br>workflow.add_node(<span class="hljs-string">&quot;my_analyst&quot;</span>, my_agent)<br>workflow.add_edge(<span class="hljs-string">&quot;start_node&quot;</span>, <span class="hljs-string">&quot;my_analyst&quot;</span>)<br>workflow.add_edge(<span class="hljs-string">&quot;my_analyst&quot;</span>, <span class="hljs-string">&quot;summarizer&quot;</span>)<br></code></pre></td></tr></table></figure><h4 id="添加新的MCP工具"><a href="#添加新的MCP工具" class="headerlink" title="添加新的MCP工具"></a>添加新的MCP工具</h4><figure class="highlight python"><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></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-meta">@register_tool</span><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">my_tool</span>(<span class="hljs-params">param1: <span class="hljs-built_in">str</span></span>) -&gt; <span class="hljs-built_in">str</span>:<br>    <span class="hljs-string">&quot;&quot;&quot;工具描述&quot;&quot;&quot;</span><br>    <span class="hljs-comment"># 实现工具逻辑</span><br>    <span class="hljs-keyword">return</span> result<br></code></pre></td></tr></table></figure><hr><h2 id="局限性与改进方向"><a href="#局限性与改进方向" class="headerlink" title="局限性与改进方向"></a>局限性与改进方向</h2><h3 id="当前局限"><a href="#当前局限" class="headerlink" title="当前局限"></a>当前局限</h3><ol><li><strong>数据延迟</strong>: Baostock数据有1-2天延迟</li><li><strong>模型依赖</strong>: 分析质量依赖所选LLM</li><li><strong>计算资源</strong>: 并行执行需要足够的计算资源</li><li><strong>模型规模</strong>: Qwen模型较大，部署成本高</li><li><strong>数据量限制</strong>: 训练数据仅1000条，可能影响泛化能力</li></ol><h3 id="改进方向"><a href="#改进方向" class="headerlink" title="改进方向"></a>改进方向</h3><ol><li><strong>实时数据</strong>: 集成实时行情API</li><li><strong>多模型集成</strong>: 不同智能体使用不同模型</li><li><strong>缓存机制</strong>: 减少重复数据查询</li><li><strong>Web界面</strong>: 开发可视化前端</li><li><strong>回测系统</strong>: 添加策略回测功能</li><li><strong>模型优化</strong>: 使用更小更快的模型（如Qwen2.5-7B）</li><li><strong>数据增强</strong>: 扩充训练数据集，提升模型性能</li><li><strong>知识蒸馏</strong>: 将大模型知识蒸馏到小模型</li><li><strong>增量学习</strong>: 支持模型持续学习和更新</li></ol><hr><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>这个股票投资顾问Agent系统展示了现代AI在金融分析中的应用：</p><h3 id="核心优势"><a href="#核心优势" class="headerlink" title="核心优势"></a>核心优势</h3><ol><li><strong>架构清晰</strong>: MCP协议 + 多智能体工作流</li><li><strong>可扩展性</strong>: 模块化设计，易于扩展</li><li><strong>实用性</strong>: 提供全面的多维度分析</li><li><strong>标准化</strong>: 使用行业标准和协议</li><li><strong>完整性</strong>: 从数据处理、模型训练到应用部署的完整链路</li></ol><h3 id="技术亮点"><a href="#技术亮点" class="headerlink" title="技术亮点"></a>技术亮点</h3><ul><li>MCP协议的实践应用</li><li>LangGraph并行智能体编排</li><li>LoRA参数高效微调</li><li>三重阈值新闻去重算法</li><li>智能损失计算策略</li></ul><p>该项目为个人投资者提供了一个自动化、全面、易用的股票分析工具，同时也为金融AI应用开发提供了一个很好的参考架构。系统结合了传统金融分析方法和现代AI技术，为金融科技领域的发展提供了有价值的探索。</p>]]>
    </content>
    <id>https://liu-alessia.github.io/2026/07/12/2026-07-13-%E8%82%A1%E7%A5%A8%E6%8A%95%E8%B5%84%E9%A1%BE%E9%97%AEAgent/</id>
    <link href="https://liu-alessia.github.io/2026/07/12/2026-07-13-%E8%82%A1%E7%A5%A8%E6%8A%95%E8%B5%84%E9%A1%BE%E9%97%AEAgent/"/>
    <published>2026-07-12T16:00:00.000Z</published>
    <summary>
      <![CDATA[<h1 id="股票投资顾问Agent架构解析"><a href="#股票投资顾问Agent架构解析" class="headerlink" title="股票投资顾问Agent架构解析"></a>股票投资顾问Agent架构解析</h1><h2 id="项目概览"><a href]]>
    </summary>
    <title>股票投资顾问Agent架构解析</title>
    <updated>2026-07-16T16:00:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Alessia</name>
    </author>
    <category term="找工" scheme="https://liu-alessia.github.io/categories/%E6%89%BE%E5%B7%A5/"/>
    <category term="leetcode" scheme="https://liu-alessia.github.io/tags/leetcode/"/>
    <content>
      <![CDATA[<h1 id="字节"><a href="#字节" class="headerlink" title="字节"></a>字节</h1><h2 id="哈希"><a href="#哈希" class="headerlink" title="哈希"></a>哈希</h2><h3 id="REAL805-小红的区间删除"><a href="#REAL805-小红的区间删除" class="headerlink" title="REAL805 小红的区间删除"></a>REAL805 小红的区间删除</h3><p>乍一看以为是求最长不重复数组，其实更简单。只需遍历，放入哈希表，遇到重复的计算可删除长度i-hashTable[x]-1，不用更新哈希表</p>]]>
    </content>
    <id>https://liu-alessia.github.io/2026/06/18/2026-06-19-%E9%9D%A2%E8%AF%95%E6%89%8B%E6%92%95/</id>
    <link href="https://liu-alessia.github.io/2026/06/18/2026-06-19-%E9%9D%A2%E8%AF%95%E6%89%8B%E6%92%95/"/>
    <published>2026-06-18T16:00:00.000Z</published>
    <summary>
      <![CDATA[<h1 id="字节"><a href="#字节" class="headerlink" title="字节"></a>字节</h1><h2 id="哈希"><a href="#哈希" class="headerlink" title="哈希"></a>哈希</h2><h3 id]]>
    </summary>
    <title>面试手撕准备</title>
    <updated>2026-08-31T14:48:42.067Z</updated>
  </entry>
  <entry>
    <author>
      <name>Alessia</name>
    </author>
    <category term="力扣刷题日记" scheme="https://liu-alessia.github.io/categories/%E5%8A%9B%E6%89%A3%E5%88%B7%E9%A2%98%E6%97%A5%E8%AE%B0/"/>
    <category term="leetcode" scheme="https://liu-alessia.github.io/tags/leetcode/"/>
    <content>
      <![CDATA[<p>写此系列博客的榜样来自：<a href="https://books.halfrost.com/leetcode/">leetcode cookbook</a></p><h1 id="套路"><a href="#套路" class="headerlink" title="套路"></a>套路</h1><p>增量构建答案的过程，通常由递归实现</p><h2 id="回溯三问："><a href="#回溯三问：" class="headerlink" title="回溯三问："></a>回溯三问：</h2><ol><li>当前操作？枚举path[i]要填入的字母</li><li>子问题？</li><li>下一个子问题</li></ol><p>先写二叉树回溯,再做的通用回溯。二叉树型回溯和多叉树(通用型)回溯的区别就是 通用型要写for loop，而二叉树只有2个选择，所以没有for loop，直接执行dfs(node.left)和dfs(node.right).</p><p>从写代码的角度对比,几乎完全一样:</p><p>确定递归函数的意义：</p><p>1.1 def dfs(node):从上到下遍历树的每一个node<br>1.2 def dfs(i):从index 0开始构造这条路径</p><p>确定base case：</p><p>2.1 if node is None 所有该遍历的节点已经遍历完了(node是叶子节点的时候，就是最后一片要遍历的叶子）<br>2.2 if i &#x3D;&#x3D; n 这条路径已经被填满了(i&#x3D;n-1的时候，就是最后要处理的一个path格子)</p><p>确定单层递归的当前操作:</p><p>3.1 加入pathpath.append(str(node.val)) 且 进行下层递归dfs(node.left) dfs(node.right) 且恢复现场path.pop()<br>3.2 在for loop下加入path在for loop下: path.append(c) 且 进行下一层递归dfs(i + 1) 且恢复现场path.pop</p><h1 id="子集型回溯"><a href="#子集型回溯" class="headerlink" title="子集型回溯"></a>子集型回溯</h1><ol><li>当前操作？</li><li>子问题？</li><li>下一个子问题</li></ol><h1 id="组合型"><a href="#组合型" class="headerlink" title="组合型"></a>组合型</h1><h1 id="排列型"><a href="#排列型" class="headerlink" title="排列型"></a>排列型</h1>]]>
    </content>
    <id>https://liu-alessia.github.io/2026/05/14/2026-05-14-%E6%97%A5%E8%AE%B07-%E5%9B%9E%E6%BA%AF/</id>
    <link href="https://liu-alessia.github.io/2026/05/14/2026-05-14-%E6%97%A5%E8%AE%B07-%E5%9B%9E%E6%BA%AF/"/>
    <published>2026-05-14T16:00:00.000Z</published>
    <summary>
      <![CDATA[<p>写此系列博客的榜样来自：<a href="https://books.halfrost.com/leetcode/">leetcode cookbook</a></p>
<h1 id="套路"><a href="#套路" class="headerlink" title="]]>
    </summary>
    <title>回溯</title>
    <updated>2026-08-31T14:48:42.067Z</updated>
  </entry>
  <entry>
    <author>
      <name>Alessia</name>
    </author>
    <category term="力扣刷题日记" scheme="https://liu-alessia.github.io/categories/%E5%8A%9B%E6%89%A3%E5%88%B7%E9%A2%98%E6%97%A5%E8%AE%B0/"/>
    <category term="leetcode" scheme="https://liu-alessia.github.io/tags/leetcode/"/>
    <content>
      <![CDATA[<p>写此系列博客的榜样来自：<a href="https://books.halfrost.com/leetcode/">leetcode cookbook</a></p><h1 id="思考方式"><a href="#思考方式" class="headerlink" title="思考方式"></a>思考方式</h1><p>萌新三步：思考回溯怎么写；改成记忆化搜索；1：1翻译成递推。</p><p>以下以打家劫舍为例，说明思考方式</p><ol><li><p>回溯：<br><img src="/images/posts/leetcode/8-dp/%E6%89%93%E5%AE%B6%E5%8A%AB%E8%88%8D%E4%BA%8C%E5%8F%89%E6%A0%91.png" alt="alt text"></p></li><li><p>把递归的计算结果保存下来，<br><img src="/images/posts/leetcode/8-dp/%E8%AE%B0%E5%BF%86%E5%8C%96%E5%AD%98%E5%82%A8.png" alt="alt text"></p></li></ol><figure class="highlight python"><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><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">rob</span>():<br>    n=<span class="hljs-built_in">len</span>(nums)<br>    cache=[-<span class="hljs-number">1</span>]*n<br>    <span class="hljs-keyword">def</span> <span class="hljs-title function_">dfs</span>(<span class="hljs-params">i</span>):<br>        <span class="hljs-keyword">if</span> i&lt;<span class="hljs-number">0</span>:<br>            <span class="hljs-keyword">return</span> <span class="hljs-number">0</span><br>        <span class="hljs-keyword">if</span> cache[i]!=-<span class="hljs-number">1</span>:<br>            <span class="hljs-keyword">return</span> cache[i]<br>        res=<span class="hljs-built_in">max</span>(dfs(i-<span class="hljs-number">1</span>),dfs(i-<span class="hljs-number">2</span>)+nums[i])<br>        cache[i]=res<br>        <span class="hljs-keyword">return</span> res<br>    <span class="hljs-keyword">return</span> dfs(n-<span class="hljs-number">1</span>)<br></code></pre></td></tr></table></figure><ol start="3"><li>改为递推<br>自底向上计算<br><img src="/images/posts/leetcode/8-dp/%E9%80%92%E6%8E%A8%E5%92%8C%E7%A9%BA%E9%97%B4%E4%BC%98%E5%8C%96.png" alt="alt text"></li></ol><figure class="highlight python"><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></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">rob</span>():<br>    n=<span class="hljs-built_in">len</span>(nums)<br>    f=[<span class="hljs-number">0</span>]*(n+<span class="hljs-number">2</span>)<br>    <span class="hljs-keyword">for</span> i,x <span class="hljs-keyword">in</span> <span class="hljs-built_in">enumerate</span>(nums):<br>        f[i+<span class="hljs-number">2</span>]=<span class="hljs-built_in">max</span>(f[i+<span class="hljs-number">1</span>],f[i]+x)<br></code></pre></td></tr></table></figure><p>空间优化：</p><h1 id="背包问题"><a href="#背包问题" class="headerlink" title="背包问题"></a>背包问题</h1><h2 id="一般问题"><a href="#一般问题" class="headerlink" title="一般问题"></a>一般问题</h2><p>我们有 $n$ 件物品和一个容量（capacity）为 $C$ 的背包，记第 $i$ 件物品的重量（weight）为 $w_i$，价值（value）为 $v_i$，求将哪些物品装入背包可使价值总和最大。</p><blockquote><h3 id="0-1-背包"><a href="#0-1-背包" class="headerlink" title="0-1 背包"></a>0-1 背包</h3><p>如果限定每件物品最多只能选取 $1$ 次（即 $0$ 或 $1$ 次），则问题称为 <strong>0-1 背包问题</strong>。</p></blockquote><blockquote><h3 id="完全背包"><a href="#完全背包" class="headerlink" title="完全背包"></a>完全背包</h3><p>如果每件物品最多可以选取无限次，则问题称为 <strong>完全背包问题</strong>。</p></blockquote><p>假设放入背包中的物品 $i$ 的数目为 $k_i$，则上述背包问题在数学上可表达为：</p><p>$$<br>\max \sum_{i&#x3D;0}^{n-1} k_i \cdot v_i<br>$$</p><p>约束条件（subject to, s.t.）：</p><p>$$<br>\sum_{i&#x3D;0}^{n-1} k_i \cdot w_i \le C<br>$$</p><p>并且：</p><p>$$<br>\begin{cases}<br>k_i \in {0,1} &amp; \text{0-1 背包问题} \\<br>k_i \in {0,1,2,\dots,+\infty} &amp; \text{完全背包问题}<br>\end{cases}<br>$$</p>]]>
    </content>
    <id>https://liu-alessia.github.io/2026/05/14/2026-05-15-%E6%97%A5%E8%AE%B08-%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/</id>
    <link href="https://liu-alessia.github.io/2026/05/14/2026-05-15-%E6%97%A5%E8%AE%B08-%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/"/>
    <published>2026-05-14T16:00:00.000Z</published>
    <summary>
      <![CDATA[<p>写此系列博客的榜样来自：<a href="https://books.halfrost.com/leetcode/">leetcode cookbook</a></p>
<h1 id="思考方式"><a href="#思考方式" class="headerlink" tit]]>
    </summary>
    <title>动态规划</title>
    <updated>2026-08-31T14:48:42.067Z</updated>
  </entry>
  <entry>
    <author>
      <name>Alessia</name>
    </author>
    <category term="力扣刷题日记" scheme="https://liu-alessia.github.io/categories/%E5%8A%9B%E6%89%A3%E5%88%B7%E9%A2%98%E6%97%A5%E8%AE%B0/"/>
    <category term="leetcode" scheme="https://liu-alessia.github.io/tags/leetcode/"/>
    <content>
      <![CDATA[<p>写此系列博客的榜样来自：<a href="https://books.halfrost.com/leetcode/">leetcode cookbook</a></p><h2 id="空间复杂度"><a href="#空间复杂度" class="headerlink" title="空间复杂度"></a>空间复杂度</h2><p>m*n的矩阵不要新开一个一样大小的矩阵来储存结果，可以用用第一行或第一列储存(m+n)，或者新建表</p>]]>
    </content>
    <id>https://liu-alessia.github.io/2026/05/10/2026-05-11-%E6%97%A5%E8%AE%B06-%E7%9F%A9%E9%98%B5/</id>
    <link href="https://liu-alessia.github.io/2026/05/10/2026-05-11-%E6%97%A5%E8%AE%B06-%E7%9F%A9%E9%98%B5/"/>
    <published>2026-05-10T16:00:00.000Z</published>
    <summary>
      <![CDATA[<p>写此系列博客的榜样来自：<a href="https://books.halfrost.com/leetcode/">leetcode cookbook</a></p>
<h2 id="空间复杂度"><a href="#空间复杂度" class="headerlink" t]]>
    </summary>
    <title>矩阵</title>
    <updated>2026-08-31T14:48:42.067Z</updated>
  </entry>
  <entry>
    <author>
      <name>Alessia</name>
    </author>
    <category term="力扣刷题日记" scheme="https://liu-alessia.github.io/categories/%E5%8A%9B%E6%89%A3%E5%88%B7%E9%A2%98%E6%97%A5%E8%AE%B0/"/>
    <category term="leetcode" scheme="https://liu-alessia.github.io/tags/leetcode/"/>
    <content>
      <![CDATA[<p>写此系列博客的榜样来自：<a href="https://books.halfrost.com/leetcode/">leetcode cookbook</a></p><h2 id="双指针"><a href="#双指针" class="headerlink" title="双指针"></a>双指针</h2><p>slow + fast</p><h3 id="环形链表"><a href="#环形链表" class="headerlink" title="环形链表"></a>环形链表</h3><p><strong>题142</strong> 给定一个链表的头节点  head ，返回链表开始入环的第一个节点。 如果链表无环，则返回 null。</p><p>这道题纯粹考数学了哈哈。<strong>参考解答</strong> 作者：Krahets<br>链接：<a href="https://leetcode.cn/problems/linked-list-cycle-ii/solutions/12616/linked-list-cycle-ii-kuai-man-zhi-zhen-shuang-zhi-/">https://leetcode.cn/problems/linked-list-cycle-ii/solutions/12616/linked-list-cycle-ii-kuai-man-zhi-zhen-shuang-zhi-/</a></p><p>这类链表题目一般都是使用双指针法解决的，例如寻找距离尾部第 K 个节点、寻找环入口、寻找公共尾部入口等。</p><p>在本题的求解过程中，双指针会产生两次“相遇”。</p><p>双指针的第一次相遇：<br>设两指针 fast，slow 指向链表头部 head 。<br>令 fast 每轮走 2 步，slow 每轮走 1 步。<br>执行以上两步后，可能出现两种结果：</p><p>第一种结果： fast 指针走过链表末端，说明链表无环，此时直接返回 null。</p><p>如果链表存在环，则双指针一定会相遇。因为每走 1 轮，fast 与 slow 的间距 +1，fast 一定会追上 slow 。</p><p>第二种结果： 当fast &#x3D;&#x3D; slow时， 两指针在环中第一次相遇。下面分析此时 fast 与 slow 走过的步数关系：</p><p>设链表共有 a+b 个节点，其中 链表头部到链表入口 有 a 个节点（不计链表入口节点）， 链表环 有 b 个节点（这里需要注意，a 和 b 是未知数，例如图解上链表 a&#x3D;4 , b&#x3D;5）；设两指针分别走了 f，s 步，则有：</p><p>fast 走的步数是 slow 步数的 2 倍，即 f&#x3D;2s；（解析： fast 每轮走 2 步）<br>fast 比 slow 多走了 n 个环的长度，即 f&#x3D;s+nb；（ 解析： 双指针都走过 a 步，然后在环内绕圈直到重合，重合时 fast 比 slow 多走 环的长度整数倍 ）。<br>将以上两式相减得到 f&#x3D;2nb，s&#x3D;nb，即 fast 和 slow 指针分别走了 2n，n 个环的周长。</p><p>接下来该怎么做呢？</p><p>如果让指针从链表头部一直向前走并统计步数k，那么所有 走到链表入口节点时的步数 是：k&#x3D;a+nb ，即先走 a 步到入口节点，之后每绕 1 圈环（ b 步）都会再次到入口节点。而目前 slow 指针走了 nb 步。因此，我们只要想办法让 slow 再走 a 步停下来，就可以到环的入口。</p><p>但是我们不知道 a 的值，该怎么办？依然是使用双指针法。考虑构建一个指针，此指针需要有以下性质：此指针和 slow 一起向前走 a 步后，两者在入口节点重合。那么从哪里走到入口节点需要 a 步？答案是链表头节点head。</p>]]>
    </content>
    <id>https://liu-alessia.github.io/2026/05/09/2026-05-10-%E6%97%A5%E8%AE%B05-%E9%93%BE%E8%A1%A8/</id>
    <link href="https://liu-alessia.github.io/2026/05/09/2026-05-10-%E6%97%A5%E8%AE%B05-%E9%93%BE%E8%A1%A8/"/>
    <published>2026-05-09T16:00:00.000Z</published>
    <summary>
      <![CDATA[<p>写此系列博客的榜样来自：<a href="https://books.halfrost.com/leetcode/">leetcode cookbook</a></p>
<h2 id="双指针"><a href="#双指针" class="headerlink" title]]>
    </summary>
    <title>链表</title>
    <updated>2026-08-31T14:48:42.067Z</updated>
  </entry>
  <entry>
    <author>
      <name>Alessia</name>
    </author>
    <category term="力扣刷题日记" scheme="https://liu-alessia.github.io/categories/%E5%8A%9B%E6%89%A3%E5%88%B7%E9%A2%98%E6%97%A5%E8%AE%B0/"/>
    <category term="leetcode" scheme="https://liu-alessia.github.io/tags/leetcode/"/>
    <content>
      <![CDATA[<p>写此系列博客的榜样来自：<a href="https://books.halfrost.com/leetcode/">leetcode cookbook</a></p><h1 id="递归"><a href="#递归" class="headerlink" title="递归"></a>递归</h1><ol><li>如何思考二叉树相关问题？</li></ol><ul><li>不要一开始就陷入细节，而是思考整棵树与其左右子树的关系。</li></ul><ol start="2"><li>为什么需要使用递归？</li></ol><ul><li>子问题和原问题是相似的，他们执行的代码也是相同的（类比循环），但是子问题需要把计算结果返回给上一级，这更适合用递归实现。</li></ul><ol start="3"><li>为什么这样写就一定能算出正确答案？</li></ol><ul><li>由于子问题的规模比原问题小，不断“递”下去，总会有个尽头，即递归的边界条件 ( base case )，直接返回它的答案“归”；</li><li>类似于数学归纳法（多米诺骨牌），n&#x3D;1时类似边界条件；n&#x3D;m时类似往后任意一个节点</li></ul><ol start="4"><li>计算机是怎么执行递归的？</li></ol><ul><li>当程序执行“递”动作时，计算机使用栈保存这个发出“递”动作的对象，程序不断“递”，计算机不断压栈，直到边界时，程序发生“归”动作，正好将执行的答案“归”给栈顶元素，随后程序不断“归”，计算机不断出栈，直到返回原问题的答案，栈空。</li></ul><p><img src="/images/posts/leetcode/4-tree/python%E6%89%A7%E8%A1%8C%E9%80%92%E5%BD%92%E8%BF%87%E7%A8%8B%E5%8F%AF%E8%A7%86%E5%8C%96.png" alt="alt text"></p><ol start="5"><li>另一种递归思路</li></ol><ul><li>维护全局变量，使用二叉树遍历函数，不断更新全局变量最大值。</li></ul>]]>
    </content>
    <id>https://liu-alessia.github.io/2026/05/08/2026-05-09-%E6%97%A5%E8%AE%B04-%E4%BA%8C%E5%8F%89%E6%A0%91/</id>
    <link href="https://liu-alessia.github.io/2026/05/08/2026-05-09-%E6%97%A5%E8%AE%B04-%E4%BA%8C%E5%8F%89%E6%A0%91/"/>
    <published>2026-05-08T16:00:00.000Z</published>
    <summary>
      <![CDATA[<p>写此系列博客的榜样来自：<a href="https://books.halfrost.com/leetcode/">leetcode cookbook</a></p>
<h1 id="递归"><a href="#递归" class="headerlink" title="]]>
    </summary>
    <title>binary tree</title>
    <updated>2026-08-31T14:48:42.067Z</updated>
  </entry>
  <entry>
    <author>
      <name>Alessia</name>
    </author>
    <category term="力扣刷题日记" scheme="https://liu-alessia.github.io/categories/%E5%8A%9B%E6%89%A3%E5%88%B7%E9%A2%98%E6%97%A5%E8%AE%B0/"/>
    <category term="leetcode" scheme="https://liu-alessia.github.io/tags/leetcode/"/>
    <content>
      <![CDATA[<p>写此系列博客的榜样来自：<a href="https://books.halfrost.com/leetcode/">leetcode cookbook</a></p><h1 id="单调栈"><a href="#单调栈" class="headerlink" title="单调栈"></a>单调栈</h1><h2 id="单调栈基础"><a href="#单调栈基础" class="headerlink" title="单调栈基础"></a>单调栈基础</h2><p>作者：Shawxing精讲算法<br>链接：<a href="https://leetcode.cn/discuss/post/L5ZpxA/">https://leetcode.cn/discuss/post/L5ZpxA/</a></p><p>在 O(n) 的时间复杂度内求出数组中各个元素右侧第一个更大的元素及其下标，然后一并得到其他信息。</p><h3 id="原理"><a href="#原理" class="headerlink" title="原理"></a>原理</h3><p><img src="/source/images/posts/leetcode/3-stack/%E5%8D%95%E8%B0%83%E6%A0%88%E5%8E%9F%E7%90%861.jpeg" alt="alt text"></p><p><img src="/source/images/posts/leetcode/3-stack/%E5%8D%95%E8%B0%83%E6%A0%88%E5%8E%9F%E7%90%862.jpeg" alt="alt text"></p><p><img src="/source/images/posts/leetcode/3-stack/%E5%8D%95%E8%B0%83%E6%A0%88%E5%8E%9F%E7%90%863.jpeg" alt="alt text"></p><p><img src="/source/images/posts/leetcode/3-stack/%E5%8D%95%E8%B0%83%E6%A0%88%E5%8E%9F%E7%90%864.jpeg" alt="alt text"></p><p>最终结果<br><img src="/source/images/posts/leetcode/3-stack/result.png" alt="alt text"></p><h3 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h3><figure class="highlight python"><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></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Solution</span>:<br>    <span class="hljs-keyword">def</span> <span class="hljs-title function_">monotonicStack</span>(<span class="hljs-params">self, nums: <span class="hljs-type">List</span>[<span class="hljs-built_in">int</span>]</span>) -&gt; <span class="hljs-type">List</span>[<span class="hljs-built_in">int</span>]:<br>        n = <span class="hljs-built_in">len</span>(nums)<br>        ans = [<span class="hljs-number">0</span>] * n<br>        st = []<br><br>        <span class="hljs-keyword">for</span> i, v <span class="hljs-keyword">in</span> <span class="hljs-built_in">enumerate</span>(nums):<br>            <span class="hljs-keyword">while</span> st <span class="hljs-keyword">and</span> v &gt; nums[st[-<span class="hljs-number">1</span>]]:<br>                prevI = st.pop()<br>                ans[prevI] = i<br>                <span class="hljs-comment"># 还可以针对 prevI, i, nums[prevI], nums[i] 做些其他的处理 </span><br>            st.append(i)<br>        <br>        <span class="hljs-keyword">return</span> ans<br><br></code></pre></td></tr></table></figure><h2 id="相关题目"><a href="#相关题目" class="headerlink" title="相关题目"></a>相关题目</h2><h3 id="T239-滑动窗口最大值"><a href="#T239-滑动窗口最大值" class="headerlink" title="T239 滑动窗口最大值"></a>T239 滑动窗口最大值</h3><p>这是一个降本增笑的故事（参考<a href="https://leetcode.cn/problems/sliding-window-maximum/solutions/2499715/shi-pin-yi-ge-shi-pin-miao-dong-dan-diao-ezj6/">灵茶山艾府</a>的解析）：</p><p>如果新员工比老员工强（或者一样强），把老员工裁掉。（元素进入窗口）<br>如果老员工 35 岁了，也裁掉。（元素离开窗口）<br>裁员后，资历最老（最左边）的人就是最强的员工了。</p><figure class="highlight python"><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></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">maxSlidingWindow</span>(<span class="hljs-params">self, nums: <span class="hljs-type">List</span>[<span class="hljs-built_in">int</span>], k: <span class="hljs-built_in">int</span></span>) -&gt; <span class="hljs-type">List</span>[<span class="hljs-built_in">int</span>]:<br>        ans=[<span class="hljs-number">0</span>]*(<span class="hljs-built_in">len</span>(nums)-k+<span class="hljs-number">1</span>)<br>        q=deque() <span class="hljs-comment">#双端队列</span><br><br>        <span class="hljs-keyword">for</span> i,x <span class="hljs-keyword">in</span> <span class="hljs-built_in">enumerate</span>(nums):<br>            <span class="hljs-comment"># 1.右边入</span><br>            <span class="hljs-keyword">while</span> q <span class="hljs-keyword">and</span> nums[q[-<span class="hljs-number">1</span>]]&lt;=x:<br>                q.pop()<br>            q.append(i)<br><br>            <span class="hljs-comment"># 2.左边出</span><br>            left=i-k+<span class="hljs-number">1</span><br>            <span class="hljs-keyword">if</span> q[<span class="hljs-number">0</span>]&lt;left:<br>                q.popleft()<br><br>            <span class="hljs-comment"># 3.在窗口左端点处记录答案</span><br>            <span class="hljs-keyword">if</span> left&gt;=<span class="hljs-number">0</span>:<br>                ans[left]=nums[q[<span class="hljs-number">0</span>]]<br>        <span class="hljs-keyword">return</span> ans<br><br></code></pre></td></tr></table></figure>]]>
    </content>
    <id>https://liu-alessia.github.io/2026/05/05/2026-05-06-%E6%97%A5%E8%AE%B03-stack/</id>
    <link href="https://liu-alessia.github.io/2026/05/05/2026-05-06-%E6%97%A5%E8%AE%B03-stack/"/>
    <published>2026-05-05T16:00:00.000Z</published>
    <summary>
      <![CDATA[<p>写此系列博客的榜样来自：<a href="https://books.halfrost.com/leetcode/">leetcode cookbook</a></p>
<h1 id="单调栈"><a href="#单调栈" class="headerlink" title]]>
    </summary>
    <title>stack</title>
    <updated>2026-08-31T14:48:42.067Z</updated>
  </entry>
  <entry>
    <author>
      <name>Alessia</name>
    </author>
    <category term="力扣刷题日记" scheme="https://liu-alessia.github.io/categories/%E5%8A%9B%E6%89%A3%E5%88%B7%E9%A2%98%E6%97%A5%E8%AE%B0/"/>
    <category term="leetcode" scheme="https://liu-alessia.github.io/tags/leetcode/"/>
    <content>
      <![CDATA[<p>写此系列博客的榜样来自：<a href="https://books.halfrost.com/leetcode/">leetcode cookbook</a></p><h1 id="内置函数"><a href="#内置函数" class="headerlink" title="内置函数"></a>内置函数</h1><h2 id="常用"><a href="#常用" class="headerlink" title="常用"></a>常用</h2><figure class="highlight python"><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><code class="hljs python"><span class="hljs-built_in">len</span>()<br><span class="hljs-built_in">sorted</span>() <span class="hljs-comment">#返回的是字典</span><br><span class="hljs-built_in">tuple</span>()<br></code></pre></td></tr></table></figure><h2 id="有用"><a href="#有用" class="headerlink" title="有用"></a>有用</h2><figure class="highlight python"><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></pre></td><td class="code"><pre><code class="hljs python">Counter()<br><span class="hljs-string">&#x27;&#x27;&#x27;</span><br><span class="hljs-string">属于 Python 标准库中的 collections 模块。在 LeetCode 环境中，List 和 Counter 通常已经被默认导入，所以你不需要手动写 from collections import Counter。</span><br><span class="hljs-string">主要的功能是：</span><br><span class="hljs-string">统计次数：接收一个可迭代对象（如字符串、列表），自动统计其中每个元素出现的次数。</span><br><span class="hljs-string">字典行为：它本质上是一个字典（dict）的子类，键（key）是元素，值（value）是次数。</span><br><span class="hljs-string">&#x27;&#x27;&#x27;</span><br></code></pre></td></tr></table></figure><h1 id="数据结构"><a href="#数据结构" class="headerlink" title="数据结构"></a>数据结构</h1><h2 id="list"><a href="#list" class="headerlink" title="list"></a>list</h2><p>列表&#x2F;动态数组 <code>list()</code>, <code>[]</code></p><p>从末尾添加或删除元素<br><code>self.nums.append()</code><br><code>self.nums.pop()</code></p><h2 id="dict"><a href="#dict" class="headerlink" title="dict"></a>dict</h2><p><code>&#123;&#125;</code></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs python">d = defaultdict(<span class="hljs-built_in">list</span>) <span class="hljs-comment"># 当遇到不存在的键时，请自动创建一个空列表 [] 作为它的值。</span><br></code></pre></td></tr></table></figure><h2 id="set"><a href="#set" class="headerlink" title="set"></a>set</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs python">st = <span class="hljs-built_in">set</span>(nums)  <span class="hljs-comment"># 把 nums 转成哈希集合</span><br></code></pre></td></tr></table></figure><h2 id="Tree"><a href="#Tree" class="headerlink" title="Tree"></a>Tree</h2><figure class="highlight python"><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><code class="hljs python">root: <span class="hljs-type">Optional</span>[TreeNode] <br><span class="hljs-comment">#Python 的类型提示语法，意思是：这个参数 root 既可以是 TreeNode 类型的对象，也可以是 None</span><br><span class="hljs-comment">#如果输入的树是空的，那么 root 就是 None。如果不加 Optional，类型检查器会报错，因为它以为 root 必须是个节点对象</span><br></code></pre></td></tr></table></figure><h1 id="python-语法"><a href="#python-语法" class="headerlink" title="python 语法"></a>python 语法</h1><p>闭包与 LEGB 规则<br>在 Python 中，当一个函数内部定义了另一个函数时，内部函数可以访问外部函数的变量。这叫做闭包。<br>Python 查找变量时遵循 LEGB 规则：<br>Local：先在函数内部找（比如 node 变量）。<br>Enclosing：如果没找到，去外层嵌套函数找（这里就是 inorderTraversal 里的 ans）。<br>Global：再没找到，去全局找。<br>Built-in：最后去内置模块找。</p><h1 id="空间复杂度"><a href="#空间复杂度" class="headerlink" title="空间复杂度"></a>空间复杂度</h1><h2 id="O-1"><a href="#O-1" class="headerlink" title="O(1)"></a>O(1)</h2><p><code>.reverse()</code>：原地操作，内存效率最高。</p>]]>
    </content>
    <id>https://liu-alessia.github.io/2026/04/21/2026-04-22-%E6%97%A5%E8%AE%B02-python/</id>
    <link href="https://liu-alessia.github.io/2026/04/21/2026-04-22-%E6%97%A5%E8%AE%B02-python/"/>
    <published>2026-04-21T16:00:00.000Z</published>
    <summary>
      <![CDATA[<p>写此系列博客的榜样来自：<a href="https://books.halfrost.com/leetcode/">leetcode cookbook</a></p>
<h1 id="内置函数"><a href="#内置函数" class="headerlink" tit]]>
    </summary>
    <title>python</title>
    <updated>2026-08-31T14:48:42.067Z</updated>
  </entry>
  <entry>
    <author>
      <name>Alessia</name>
    </author>
    <category term="计算机基础" scheme="https://liu-alessia.github.io/categories/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/"/>
    <category term="随笔杂谈" scheme="https://liu-alessia.github.io/tags/%E9%9A%8F%E7%AC%94%E6%9D%82%E8%B0%88/"/>
    <content>
      <![CDATA[<h2 id="显示"><a href="#显示" class="headerlink" title="显示"></a>显示</h2><p>CRT，光栅扫描；LCD(liquid crystal display)技术也用到了光栅扫描</p><p>矢量显示系统，节省空间；character generator, screen buffer, </p><p>光笔，人机交互新方式</p><p>位图，bmp(bit map pictures), frame buffer, </p><h2 id=""><a href="#" class="headerlink" title=""></a></h2>]]>
    </content>
    <id>https://liu-alessia.github.io/2026/04/07/2026-04-08-%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/</id>
    <link href="https://liu-alessia.github.io/2026/04/07/2026-04-08-%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/"/>
    <published>2026-04-07T16:00:00.000Z</published>
    <summary>
      <![CDATA[<h2 id="显示"><a href="#显示" class="headerlink" title="显示"></a>显示</h2><p>CRT，光栅扫描；LCD(liquid crystal display)技术也用到了光栅扫描</p>
<p>矢量显示系统，节省空间；char]]>
    </summary>
    <title>显示</title>
    <updated>2026-08-31T14:48:42.068Z</updated>
  </entry>
</feed>
