ObsidianノートでのLLM活用
ObsidianなどのノートツールでOllamaを使用してローカルLLMを組み込む方法について解説しています。
キーポイント
ObsidianノートとLLMの統合により、ユーザーは自身のノートに対して質問し、洞察を得ることが可能になる
大量のノートコンテンツを扱うために、埋め込み(embeddings)とインデックス作成が重要であり、Llama IndexやLangChainなどのツールが活用できる
ローカル環境での実行も可能な代替手段(Ollamaのembed機能など)が存在し、プライバシーやコスト面での選択肢が広がっている
影響分析・編集コメントを表示
影響分析
この記事は、個人の知識管理ツール(Obsidian)と大規模言語モデル(LLM)を組み合わせる実践的な方法を示しており、個人の生産性向上や知識探索の新たな可能性を開く。技術的には既存ツールの応用だが、具体的な実装例を提供することで、開発者や高度ユーザーにとって実用的な価値がある。
編集コメント
個人のデジタルガーデンとAIを結びつける実用的なガイド。技術的に高度だが、コード例を交えた具体的な説明が開発者層に刺さる内容。
ObsidianノートにおけるLLM活用の可能性と実装手法
Hacker Newsで、ObsidianとChatGPTを連携させる新たなプラグインが話題となっている。この種のツールは複数存在し、ノートとの新たな関係性を築き、思考を深化させる可能性に注目が集まっている。一部からは「自分自身で行うべき作業を代替するもの」との批判もあるが、むしろユーザーの能力を革新的に拡張するツールと捉えられる。
LLMをノート活用に組み込む際の第一の目的は、ノートとの対話である。蓄積したノートに対して質問を投げかけ、新たな洞察を得ることが理想だ。しかし、ほとんどのLLMは全てのノートコンテンツを一度に処理できないため、質問に関連する部分だけを選び出してモデルに渡す技術が必要となる。
ここで課題となるのが、Obsidianの標準検索機能が単語や句の完全一致に依存している点だ。我々が必要とするのは、概念に基づく検索である。これを実現する鍵が「埋め込み(Embeddings)」技術であり、意味を理解した上で関連文書を検索するためのインデックス作成が不可欠となる。
具体的な実装方法として、Obsidianプラグインは起動時やコマンド実行時など、様々な契機で動作を設定できる。効率化のため、プラグイン起動時にノートを理解するプロセスを開始し、生成したインデックスを保存して再利用する仕組みが望ましい。
技術的には、Llama IndexやLangChainなどのライブラリが利用できる。実装例では、まずメモリ内データストアを初期化し、インデックスの永続化を設定する。次に、Markdownファイルのパスを取得し、リーダーで読み込む。Llama IndexはMarkdownの構造を理解できるだけでなく、PDFやテキストファイル、Notionドキュメントなど多様な形式に対応し、単語の意味と文脈中の関係性を捉えたインデックスを作成する。
インデックス作成にはOpenAIのサービスを利用する方法が示されているが、これはChatGPTとは異なるモデルである。また、LangChainにはローカル環境で実行できる(速度は遅いが)代替手段があり、Ollamaの埋め込み機能を利用する選択肢もある。これにより、外部サービスへの依存を減らすことも可能だ。
要するに、LLMとObsidianの連携は、単なる情報検索を超えて、ユーザーの知的作業を拡張するための強力な基盤を提供する。概念ベースの検索を実現する埋め込み技術と適切なインデックス構築により、個人のナレッジベースは静的な記録から、対話を通じて新たな価値を生み出す動的なシステムへと進化するのである。
原文を表示
Leveraging LLMs in your Obsidian Notes
Today I saw a post on Hacker News about another plugin for Obsidian that integrates with ChatGPT. There are a bunch of these tools out there, and I love seeing the different ways to use them with the Obsidian. Making connections, letting you go further with your notes. Some commenters suggested it’s doing the work you need to do yourself, but I think it empowers you in new and incredible ways.
The first and perhaps most obvious thing you probably want to do is be able to converse with your notes. Ask it questions to gain further insights. It would be convenient if you could just point the model at your notes and be done with it. But most models can’t accept all that content all at once.
When you ask a question, not all of your notes are relevant. So you need to find the parts that are relevant and hand that to the model. Obsidian has a Search function, but it’s just searching for exact words and phrases, and we need to search for concepts. That’s where embeddings come in. We have to create an index. It turns out to be pretty easy to do.
When you create an Obsidian plugin, you can have it do something when the plugin loads up, and then other things when you trigger a command or open a note, or other activities in Obsidian. So we want something to understand your notes at the start of the plugin, and it should save its progress, so it doesn’t have to regenerate the index again. Let’s look at a code sample to index one of our notes. I am going to use Llama Index in this one, but LangChain is another great option.
import { VectorStoreIndex, serviceContextFromDefaults, storageContextFromDefaults, MarkdownReader } from "llamaindex"; const service_context = serviceContextFromDefaults({ chunkSize: 256 }) const storage_context = await storageContextFromDefaults({ persistDir: "./storage" }); const mdpath = process.argv[2]; const mdreader = new MarkdownReader(); const thedoc = await mdreader.loadData(mdpath) First, we need to initialize an in-memory data store. This is the in-memory store that comes with Llama Index, but Chroma DB is another popular option. And this second line is saying we’ll persist everything we index. Next, I get the path for the file and initialize a reader. Then I read the file. Llama Index knows Markdown, so it reads it in appropriately and indexes it. It also knows about PDFs, and text files, and notion docs, and more. It’s not just storing words, but also understanding the meanings of the words and how they relate to the other words in this text.
await VectorStoreIndex.fromDocuments(thedoc, { storageContext: storage_context, serviceContext: service_context }); Now, this part is using a service from OpenAI, but it’s separate from ChatGPT, different model, different product, and there are alternatives in Langchain that will do this locally, but a bit slower. Ollama also has an embed function. You could also use those services on a superfast self-hosted instance in the cloud and then close that down when indexing is done.
And now let’s search our notes
Now we have an index for this file. Obsidian can give us a list of all the files, so we can run that over and over again. And we are persisting, so this is a one-time action. Now, how can we ask a question? We want some code that will find the relevant bits in our notes, hand it off to the model, and use that info to come up with an answer.
const storage_context = await storageContextFromDefaults({ persistDir: "./storage" }); const index = await VectorStoreIndex.init({ storageContext: storage_context }); const ret = index.asRetriever(); ret.similarityTopK = 5 const prompt = process.argv[2]; const response = await ret.retrieve(prompt); const systemPrompt = Use the following text to help come up with an answer to the prompt: ${response.map(r => r.node.toJSON().text).join(" - ")} So in this code sample, we are initializing the index using the content we already processed. The Retriever.retrieve line is going to take the prompt and find all the chunks of notes that are relevant and return the text to us. We said to use the top 5 matches here. So I will get 5 chunks of text from our notes. With that raw information, we can generate a system prompt to help our model know what to do when we ask a question.
const ollama = new Ollama(); ollama.setModel("llama2"); ollama.setSystemPrompt(systemPrompt); const genout = await ollama.generate(prompt); And so now we get to use the model. I am using a library I created a few days ago that is on npm. I can set the model to use llama2, which is already downloaded to my machine using the command ollama pull llama2. You can try different models to find the one that works best for you.
To get answers back quickly, you will want to stick to a small model. But you also want a model that will have an input context size large enough to accept all of our text chunks. I have up to 5 chunks that are 256 tokens each
関連記事
今日のまとめ
AI日報で今日の重要ニュースをまとめ読み