1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【ローカルLLMチャットボット開発】第4回 RAG登録画面を作成する

1
Last updated at Posted at 2026-06-15

はじめに

前回は、会話履歴を利用して過去の会話を考慮したチャットボットを作成しました。

これで、

  • ローカルLLM
  • RAG
  • 会話履歴

の3つが揃い、実用的なチャットボットの土台が完成しました。

現状では、RAGで利用する文書をSQLで直接登録しています。
そこで今回は、RAG文書を管理するための画面を作成します。

今回作るもの

今回の構成です。

以下の機能を実装します。

  • 文書一覧
  • 文書登録
  • 文書削除

登録時に自動でEmbeddingを生成し、SQL Serverへ保存します。

環境構築

SQL Server準備

前回のテーブルを少し拡張します。

-- 既存データがある場合は削除されます。
DROP TABLE IF EXISTS RagDocuments;
GO

CREATE TABLE RagDocuments
(
    Id INT IDENTITY PRIMARY KEY,
    Title NVARCHAR(200) NOT NULL,
    Content NVARCHAR(MAX) NOT NULL,
    Embedding VARBINARY(MAX) NOT NULL,
    CreatedAt DATETIME2 NOT NULL DEFAULT(GETDATE())
);
カラム 説明
Title タイトル
Content 本文
Embedding ベクトル
CreatedAt 登録日時

実装

ディレクトリ構成

📂LocalChatBot
 ├─📂Controllers
 │  ├─ChatController.cs
 │  └─RagController.cs
 ├─📂Helpers
 │  ├─VectorConverter.cs
 │  └─VectorHelper.cs
 ├─📂Models
 │  ├─ChatHistory.cs
 │  ├─ChatRequest.cs
 │  └─RagDocument.cs
 ├─📂Services
 │  ├─EmbeddingService.cs
 │  ├─OllamaService.cs
 │  └─RagService.cs
 └─📂Views
    ├─📂Chat
    │  └─Index.cshtml
    └─📂Rag
       ├─Create.cshtml
       └─Index.cshtml

モデル作成

Models/RagDocument.cs
namespace LocalChatBot.Models;

public class RagDocument
{
    public int Id { get; set; }

    public string Title { get; set; } = "";

    public string Content { get; set; } = "";

    public DateTime CreatedAt { get; set; }
}

RagService修正

一覧取得処理

Services/RagService.cs
public async Task<List<RagDocument>> GetAllAsync()
{
    using var connection = new SqlConnection(_connectionString);
    await connection.OpenAsync();

    const string sql = @"
SELECT Id
     , Title
     , Content
     , CreatedAt
  FROM RagDocuments
 ORDER BY Id DESC";

    using var command = new SqlCommand(sql, connection);
    using var reader = await command.ExecuteReaderAsync();
    
    var list = new List<RagDocument>();

    while(await reader.ReadAsync())
    {
        list.Add(
            new RagDocument
            {
                Id = reader.GetInt32(0),
                Title = reader.GetString(1),
                Content = reader.GetString(2),
                CreatedAt = reader.GetDateTime(3)
            });
    }

    return list;
}

登録処理

Services/RagService.cs
public async Task InsertAsync(string title, string content)
{
    var embedding = await _embeddingService.CreateAsync(content);
    using var connection = new SqlConnection(_connectionString);
    await connection.OpenAsync();

    const string sql = @"
INSERT INTO RagDocuments
(
    Title,
    Content,
    Embedding
)
VALUES
(
    @Title,
    @Content,
    @Embedding
)";

    using var command = new SqlCommand(sql, connection);

    command.Parameters.AddWithValue("@Title", title);
    command.Parameters.AddWithValue("@Content", content);
    command.Parameters.AddWithValue("@Embedding", VectorConverter.ToBytes(embedding));

    await command.ExecuteNonQueryAsync();
}

削除処理

Services/RagService.cs
public async Task DeleteAsync(int id)
{
    using var connection = new SqlConnection(_connectionString);
    await connection.OpenAsync();

    const string sql = @"DELETE FROM RagDocuments WHERE Id = @Id";

    using var command = new SqlCommand(sql, connection);
    command.Parameters.AddWithValue("@Id", id);
    
    await command.ExecuteNonQueryAsync();
}

Controller作成

Controllers/RagController.cs
using LocalChatBot.Services;
using Microsoft.AspNetCore.Mvc;

namespace LocalChatBot.Controllers;

public class RagController : Controller
{
    private readonly RagService _ragService;

    public RagController(RagService ragService)
    {
        _ragService = ragService;
    }

    public async Task<IActionResult> Index()
    {
        var list = await _ragService.GetAllAsync();

        return View(list);
    }

    public IActionResult Create()
    {
        return View();
    }

    [HttpPost]
    public async Task<IActionResult> Create(string title, string content)
    {
        await _ragService.InsertAsync(title, content);

        return RedirectToAction(nameof(Index));
    }

    [HttpPost]
    public async Task<IActionResult> Delete(int id)
    {
        await _ragService.DeleteAsync(id);

        return RedirectToAction(nameof(Index));
    }
}

一覧画面

Views/Rag/Index.cshtml
@using LocalChatBot.Models
@model List<RagDocument>

<h2>RAG文書一覧</h2>

<p>
    <a asp-controller="Chat" asp-action="Index">チャットへ戻る</a>
</p>
<p>
    <a asp-action="Create">新規登録</a>
</p>

<table border="1">
    <tr>
        <th>ID</th>
        <th>タイトル</th>
        <th>登録日</th>
        <th></th>
    </tr>

    @foreach (var item in Model)
    {
        <tr>
            <td>@item.Id</td>
            <td>@item.Title</td>
            <td>@item.CreatedAt</td>

            <td>
                <form asp-action="Delete">
                    <input type="hidden" name="id" value="@item.Id" />
                    <button type="submit">削除</button>
                </form>
            </td>
        </tr>
    }
</table>

登録画面

Views/Rag/Create.cshtml
<h2>RAG文書登録</h2>

<p>
    <a asp-action="Index">一覧へ戻る</a>
</p>

<form method="post">
    <div>タイトル</div>
    <input type="text" name="title" style="width:500px;" />
    <br /><br />

    <div>本文</div>
    <textarea name="content" rows="15" cols="80"></textarea>
    <br /><br />

    <button type="submit">登録</button>
</form>

チャットボットからの導線

Views/Chat/Index.cshtml
<h2>ローカルLLMチャットボット</h2>

<p>
    <a asp-controller="Rag" asp-action="Index">RAG文書一覧</a>
</p>

<!-- 以下は前回と同じ -->

動作確認

登録画面から文書を登録します。

【タイトル】
有給休暇

【本文】
有給休暇を取得する場合は
3営業日前までに申請し、
前日までに上長の承認を得る必要があります。

チャット画面で質問します。

有休申請は何日前までに出せば良いですか?

RAG検索によって文書が取得され、AIが応答します。

おわりに

今回はRAG文書の管理画面を作成しました。

これで、

  • チャット
  • RAG
  • 会話履歴
  • 文書管理

が揃い、実際の業務で利用できるチャットボットに近づきました。

次回はOllamaを使わず、ローカルLLMを直接実行してみます。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?