Skip to content

Commit

Permalink
Site updated: 2024-08-17 23:45:42
Browse files Browse the repository at this point in the history
  • Loading branch information
StdioA committed Aug 17, 2024
1 parent 634114d commit d4551cb
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 15 deletions.
23 changes: 12 additions & 11 deletions 2024/08/beancount-rag/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
<meta property="og:image" content="https://blog.stdioa.com/pics/beancount-rag/rag.png">
<meta property="og:image" content="https://blog.stdioa.com/pics/beancount-rag/result.png">
<meta property="article:published_time" content="2024-08-17T13:20:00.000Z">
<meta property="article:modified_time" content="2024-08-17T13:24:52.412Z">
<meta property="article:modified_time" content="2024-08-17T15:45:31.183Z">
<meta property="article:author" content="David Dai">
<meta property="article:tag" content="Python">
<meta property="article:tag" content="记账">
Expand Down Expand Up @@ -316,7 +316,7 @@ <h1 class="article-title" itemprop="name">
<span class="post-comment"><i class="icon icon-comment"></i> <a href="/2024/08/beancount-rag/#comments" class="article-comment-link">评论</a></span>


<span class="post-wordcount hidden-xs" itemprop="wordCount">字数统计: 1.4k(字)</span>
<span class="post-wordcount hidden-xs" itemprop="wordCount">字数统计: 1.5k(字)</span>



Expand All @@ -331,28 +331,29 @@ <h1 id="背景"><a class="markdownIt-Anchor" href="#背景"></a> 背景</h1>
<p>最近经常骑车去打球,但每次骑完车之后总需要掏出手机去记账,诸如 <code>1.5 支付宝 哈啰单车 自行车</code>。虽然已经手动记账记了七年,但相同的东西记得次数太久了,难免会有写枯燥。<br />
前一阵子刚好在 GitHub 上刷到了基于 sqlite 的向量数据库方案 <a target="_blank" rel="noopener" href="https://github.com/asg017/sqlite-vec">sqlite-vec</a>,因此正好趁这个机会来试试有没有可能通过系统性的手段,进一步降低单笔记账所需的字符数。</p>
<h1 id="基础知识"><a class="markdownIt-Anchor" href="#基础知识"></a> 基础知识</h1>
<p>RAG (Retrieval-Augmented Generation, 增强检索生成)这个概念在 2020 年最初提出,旨在提升大语言模型本身在回答问题时的准确性问题。在 2023 年 LLM 进入爆炸式发展后,人们也在不断地提升 RAG 的准确率和效率<br />
简单来说,RAG 的过程就是预先通过 embedding 技术构建一个离线的向量数据库;在用户提问时,从向量数据库检索到最相关的部分信息,然后将其作为参考信息和用户提问一起喂给 LLM,这样 LLM 的回答就更有可能依据给出的参考信息来进行生成。</p>
<p>RAG (Retrieval-Augmented Generation, 增强检索生成)这个概念在 2020 年最初提出,旨在提升大语言模型本身在回答问题时的准确性问题。在 2023 年 LLM 进入爆炸式发展后,人们也在不断地对 RAG 进行改进<br />
简单来说,RAG 的过程就是预先通过 embedding 技术构建一个离线的向量数据库;在用户提问时,从向量数据库检索到最相关的部分信息,然后将其作为参考信息和用户的问题一起喂给 LLM,这样 LLM 的回答就更有可能依据给出的参考信息来进行生成,出现幻觉的可能性更低</p>
<p>从网上找到了一个比较简洁的 RAG 流程图(<a target="_blank" rel="noopener" href="https://gradientflow.com/techniques-challenges-and-future-of-augmented-language-models/">图片来源</a>):<br />
<img alt="RAG 流程" src="/pics/beancount-rag/newsletter87-RAG-simple.png" style="max-width: 50%"></p>
<p>由于传统的长文本段落切分模式会为 embedding 引入杂音,因此会导致检索准确性不高,进而会干扰到 LLM 的生成。最近一段时间,RAG 的优化方向主要在提高检索准确率和针对复杂问题的分解,研究者们也提出了诸如 GraphRAG MultiHop-RAG 的先进架构</p>
<p>不过对于一个记账应用来说,现有的基于向量数据库的技术,已经能够满足我的需求了。</p>
<p>传统的长文本段落机械切分模式可能影响 embedding 结果,而直接查询检索方式可能导致问题理解不准确。以上问题可能会导致 RAG 的检索精度不足,进而影响到 LLM 的生成效果。近期,RAG 的优化重点在于提升检索准确性和处理复杂问题的能力,研究者们提出了如 GraphRAG MultiHop-RAG 等先进架构</p>
<p>不过对于一个记账应用来说,最简单的 RAG 架构,已经能够满足我的需求了。</p>
<h1 id="应用设计"><a class="markdownIt-Anchor" href="#应用设计"></a> 应用设计</h1>
<h2 id="思路"><a class="markdownIt-Anchor" href="#思路"></a> 思路</h2>
<p>在之前的转换逻辑中,我会通过 <code>&#123;金额&#125; &#123;流出账户&#125; [&#123;流入账户&#125;] &#123;payee&#125; &#123;narration&#125; [&#123;tag1&#125; &#123;tag2&#125;]</code> 的文法来将文本流转换为 Beancount 交易。但如果要构建向量数据库,那匹配元素的优先级排序应是 payee &gt; narration &gt; 账户 &gt; tag,而金额在其中只会对检索构成干扰</p>
<p>因此,我会将历史交易转换为 <code>&#123;payee&#125; &#123;narration&#125; &#123;账户列表&#125; &#123;标签列表&#125;</code>,然后以此来取最近 1000 条非重复交易构建向量数据库。Embedding 模型我选用了 <code>BAAI/bge-large-zh-v1.5</code>.<br />
<p>在之前的文本转换逻辑中,我会通过 <code>&#123;金额&#125; &#123;流出账户&#125; [&#123;流入账户&#125;] &#123;payee&#125; &#123;narration&#125; [&#123;tag1&#125; &#123;tag2&#125;]</code> 的文法来将通过 IM 输入的文本流转换为 Beancount 交易。但如果要构建向量数据库,那匹配元素的优先级排序应是 payee &gt; narration &gt; 账户 &gt; tag,而金额信息只会对检索构成干扰</p>
<p>因此,我会取出最近 1000 条交易,然后将交易记录转换为 <code>&#123;payee&#125; &#123;narration&#125; &#123;账户列表&#125; &#123;标签列表&#125;</code> 的文本,以此来构建向量数据库。由于我的交易中包含中文,因此我选用了 <code>BAAI/bge-large-zh-v1.5</code> 来做 embedding。<br />
但是,在检索时,我是不太容易去判断用户输入的每个词具体属于哪个元素的,因此我会将用户的输入除去开头的金额后,直接进行 embedding,然后通过计算余弦相似性找出相关记录,并找到它们对应的原始交易。<br />
<em>都说汉字的序顺并不定一能影阅响读,但 embedding 不会完全认这个。</em> 为了获得更好的匹配和补全效果,我还需要通过 LLM 来仔细分辨里面的每一个元素,并对可能有问题的元素进行修正。比如,当我使用了新的支付账户进行交易,但系统中没有检索到完全一致的交易记录时,就可以用 LLM 来帮我进行账户的替换。</p>
<h2 id="流程设计"><a class="markdownIt-Anchor" href="#流程设计"></a> 流程设计</h2>
<p>用户输入内容后,首先还是会按照原本的文法来尝试对输入信息进行匹配。若匹配失败,则可以选择两种模式:向量数据库检索,或 RAG 生成。</p>
<p>使用向量数据库匹配时,会从现有数据库中找出多个与 query 最近的条目,然后对其中的词语重排后,送给原有的生成逻辑,从而生成候选条目</p>
<p>使用向量数据库匹配时,会从现有数据库中找出多个相近的条目,然后对其中的词语重排后,再传给原有的生成逻辑,从而生成候选条目</p>
<p><img src="/pics/beancount-rag/vecdb.png" alt="向量数据库流程图" /></p>
<p>若使用 RAG,则会通过向量数据库匹配后,将对应的原始条目塞给 LLM,让 LLM 参考已有条目和用户输入,生成一条全新的条目并输出。</p>
<p><img src="/pics/beancount-rag/rag.png" alt="RAG 流程图" /></p>
<h1 id="尾声"><a class="markdownIt-Anchor" href="#尾声"></a> 尾声</h1>
<p>开发完成后候尝试用了两天,匹配效果还不错,RAG 在 <code>gpt-4o-mini</code><code>deepseek-chat</code> 上的效果都能令我满意。不过我并不太需要使用 RAG,因此日常用的更多的还是向量数据库匹配的模式。</p>
<p>开发完成后尝试用了两天,匹配效果还不错,RAG 在 <code>gpt-4o-mini</code><code>DeepSeek-V2-Chat</code> 上的效果都能令我满意。不过我并不太需要使用 RAG,因此日常用的更多的还是向量数据库匹配的模式。</p>
<img alt="补全效果" src="/pics/beancount-rag/result.png" style="max-width: 50%">
<p>不过话说回来,很多人使用 Beancount 本身就是有隐私保护方面的考虑,因此也不太能够接受把自己的账目数据喂给大公司去用于训练的行为。不过好在现在的端侧小模型也在不断发展,我们也可以用 <a target="_blank" rel="noopener" href="https://ollama.com/">ollama</a> 提供本地的 LLM 和 embedding 服务。不过我使用本地的 <code>gemma2:2b</code> 模型试了一下,RAG 补全效果非常糟糕,希望之后能有更好的效果。</p>
<p>不过话说回来,很多人使用 Beancount 本身就是有隐私保护方面的考虑,因此也不太能够接受把自己的账目数据喂给大公司去用于训练的行为。不过好在现在的端侧小模型对硬件的要求也不算很高,我们也可以用 <a target="_blank" rel="noopener" href="https://ollama.com/">ollama</a> 提供本地的 LLM 和 embedding 服务来保护隐私。<br />
作为参考,我使用本地的 <code>Gemma2-2B</code> 模型试了一下,补全效果非常糟糕,不过 <code>Qwen2-7B-Instruct</code> 在我随便写的 prompt 下就能够正常工作了。</p>
<p>这个 Bot 的代码已经开源,前端支持 Telegram 和 Mattermost,欢迎大家使用和 star: <a target="_blank" rel="noopener" href="https://github.com/StdioA/beancount-bot">https://github.com/StdioA/beancount-bot</a></p>


Expand Down
4 changes: 2 additions & 2 deletions atom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<link href="https://blog.stdioa.com/atom.xml" rel="self"/>

<link href="https://blog.stdioa.com/"/>
<updated>2024-08-17T13:24:52.412Z</updated>
<updated>2024-08-17T15:45:31.183Z</updated>
<id>https://blog.stdioa.com/</id>

<author>
Expand All @@ -21,7 +21,7 @@
<link href="https://blog.stdioa.com/2024/08/beancount-rag/"/>
<id>https://blog.stdioa.com/2024/08/beancount-rag/</id>
<published>2024-08-17T13:20:00.000Z</published>
<updated>2024-08-17T13:24:52.412Z</updated>
<updated>2024-08-17T15:45:31.183Z</updated>


<summary type="html">&lt;p&gt;一个手工记账博主的脑洞大开,通过向量数据库和 RAG 来想办法让自己能再少打几个字。顺便宣传一下最近开源的&lt;a href=&quot;https://github.com/StdioA/beancount-bot&quot;&gt;记账 bot&lt;/a&gt;.&lt;/p&gt;</summary>
Expand Down
2 changes: 1 addition & 1 deletion content.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ <h1 itemprop="name">
<span class="post-comment"><i class="icon icon-comment"></i> <a href="/2024/08/beancount-rag/#comments" class="article-comment-link">评论</a></span>


<span class="post-wordcount hidden-xs" itemprop="wordCount">字数统计: 1.4k(字)</span>
<span class="post-wordcount hidden-xs" itemprop="wordCount">字数统计: 1.5k(字)</span>



Expand Down
Loading

0 comments on commit d4551cb

Please sign in to comment.