ドキュメントナレッジベース
社内文書(就業規則、見積表、製品 FAQ など)をコレクションに入れ、コレクションごとに誰が読めるかを決めます。AI 社員はそれを検索し、答えの出典(ページ、スライド、ワークシートの行)を示せます。
現在含まれるもの:保存、取り込み、キーワード検索、ローカルモデルまたは任意のクラウドプロバイダーによる意味(ベクトル)検索、knowledge.* RPC、アップロード用ルート、MCP ツール(読み取り専用 3 つと承認制の提案 1 つ)、duduclaw knowledge eval コマンド、ダッシュボードのドキュメントライブラリ画面と AI エージェントへの割り当て設定、チャネルと WebChat の返信への段落の自動挿入と [n] 引用、チャットコマンド「加入知識庫」、削除時のソース単位の忘却。既存の Wiki には影響しません。
ダッシュボードでの操作
Section titled “ダッシュボードでの操作”サイドバー「会社」グループのドキュメントライブラリ(個人版ではメインの一覧、「メモリ」の次)に、見られるコレクションが並びます。名前、機密度、自分の役割、資料の数と処理中の数を表示します。
- コレクションの作成:マネージャー以上が「コレクションを作成」を押し、名前・説明・機密度を入力します。コードは空欄なら自動で作られます(AI エージェントの設定で使うコードです)。作成直後は自分だけが見られます。
- 資料の追加:「資料」タブの「資料を追加」から、ファイルのドラッグ&ドロップまたは選択(一度に 20 件まで。対応していない形式やサイズ上限を超えるファイルは送信前に理由つきで止めます。アップロード中は進み具合を表示し、終わると 1 件ずつ追加済み・既存・拒否の理由を表示)、テキストの貼り付け、公開 Web ページの追加ができます。各資料のラベルが状態を示します:待機中、読み取り中、索引作成中、完了(語句一致)、承認待ち、失敗(理由つき)。処理中の資料がある間は一覧が 3 秒ごとに更新されます。各資料のメニューから元ファイルのダウンロード、読み直し、削除ができます(後の 2 つは編集者以上)。
- 検索を試す:質問を入力すると、このコレクションのどの段落がどの順で返るか、それぞれのページや章とともに表示します。結果を開くとサイドの引き出しに元の文章が開き、該当段落が強調され、前後の段落へ移れます。
- 共有(オーナーのみ):右側の選択欄は「メンバー・部署・AI エージェント・チャネル」に分かれ、共有できる相手だけを表示します。メンバーと部署は企業版のみで、メンバーは 2 文字以上の検索で探します(最大 20 人、一覧表示はしません)。AI エージェントは自分がオーナーのもの(管理者は全員。閲覧・操作の権限だけのものは含みません)、チャネルはチャネル全体か、ID を入れて特定のトークルームだけに共有できます。役割メニューはその種類が持てない役割を無効にし、最後のオーナーは外せません。チャネル全体に共有すると警告が出ます。「共有設定を保存」でまとめて保存し、途中で他の人が保存していた場合は再読み込みを求めます。ゲートウェイも保存時に同じルールで確認し、新しく追加した相手や役割を上げた相手(閲覧者から編集者など)が共有できない相手なら拒否します。役割が同じか下がった既存の相手はそのままです。
- 閲覧記録(オーナー):日時、誰が(メンバー、誰の代理の AI エージェントか、チャネル上のアカウント未連携の人)、何をしたか、何を質問したか、何段落返ったか。
- 設定(オーナー):名前、説明、部署ラベル、機密度、「このコンピューター内だけで処理」(今後の意味検索でこのコレクションを外部サービスへ送らない)、名前を入力して確認したうえでのコレクション削除。
管理者にはドキュメントライブラリのページ右上に「拒否された閲覧」があり、全コレクションで拒否された閲覧を一覧できます。
AI エージェントにコレクションを使わせる:まずコレクションの共有タブでその AI エージェント(または部署)に共有し、「Agent 管理 → 設定を編集 → ツールと権限 → ドキュメントライブラリ」で、共有されたすべて・チェックしたものだけ・使わない、から選びます。ここで書き込むのが agent.toml の [knowledge] collections です。共有されたコレクションしかチェックできないため、この設定は範囲を狭めるだけです。変更できるのはその AI エージェントのオーナーと管理者です。
AI 社員専用の資料(「データソース」タブ、未リリース):AI 社員のページに「データソース」タブが加わりました。その AI 社員に紐づいている人は、社員が使えるコレクションを確認できます。先に社員専用の資料、次にほかの人が共有したコレクションを並べ、それぞれ機密度、文書数、社員の設定で使われているか、ほかに誰が読めるか(コレクションのオーナーには名前、それ以外の人には「同僚 3 人、1 部門」のような人数。オーナーはもともと共有一覧を見られます)を示します。社員のオーナーと管理者は「ファイルを追加」でアップロードできます。最初のアップロードで社員専用のコレクション <表示名> 的資料 を作成し、機密度はアップロードした人が選び(既定は社内)、次の相手に共有します。
- 作成した人(オーナー)とその AI 社員(閲覧者)。管理者はもともとすべてのコレクションを読めます。
- アップロードした人がチェックを外さない限り、その時点で社員に紐づいている有効なアカウント全員。社員のオーナーはコレクションのオーナー、オペレーターと閲覧者は閲覧者になります。管理者がこの社員と一緒に働くと決めた人たちです。チーム経由でしか社員を呼べない上長、部署、チャネル、アカウントのない送信者は加えません。共有するにはコレクションの共有タブを使ってください。
新しく作ったコレクションは、社員の設定に [knowledge] collections の一覧があればそこに追加します([]、つまりナレッジベースがオフだった場合はこのコレクションだけになり、タブで知らせます)。その後のアップロードでは一覧に触れないため、オーナーが一覧から外した場合は外れたままです(タブに「設定で未使用」と表示)。[knowledge] が読めない場合は何も作りません。以降のアップロードと削除はライブラリと同じで、ファイルごとに読み込み状態(意味解析の進み具合を含む)とわかりやすい失敗理由を表示します。削除と同時に忘却申請も出せます(「文書削除時に社員が学んだことを忘れる」を参照)。コレクションは社員の ID に結び付くため、社員の名前を変えても残ります。コレクション名はライブラリで変えるまでそのままです。コレクション作成後に紐づいたオーナーは自動では加わりません。コレクションのオーナーが編集者に追加するまで、タブには別の担当者が管理している旨が出ます。社員と話す人が受け取るのは、その人自身が読める段落だけです(「1 回の検索で読める範囲」を参照)。ここに置いたファイルが一覧外の人に届くことはありません。
社員をアーカイブまたは削除すると(引き継ぎを含む)、専用コレクションもアーカイブされます。オーナーである人以外の共有はすべて外して記録し、社員本人もほかの読者も読めなくなります。オーナーと管理者はライブラリで開く、ダウンロードする、削除することができ、カードには社員がアーカイブ済みと表示されます。アーカイブ中に社員の共有を手で戻しても効きません。社員を復元すると、アーカイブで外した共有(ライブラリで手動追加したものを含む)と社員自身の共有がそのまま戻り、あとから紐づいた人は加わりません。gateway の起動時には、ダッシュボード以外でアーカイブ・削除された社員やフォルダーがなくなった社員の専用コレクションをアーカイブし、社員が復帰しているのにアーカイブのままのものは復元します。ライブラリでこのコレクションを削除すると、次のアップロードで新しいコレクションが作られます。
コレクションと権限
Section titled “コレクションと権限”権限はコレクション単位です。各付与は対象とロールを指定します。
| 対象 | ID | 付与できるロール | 範囲 |
|---|---|---|---|
| user | ダッシュボードのユーザー ID | 閲覧者・編集者・オーナー | その人 |
| department | 部門名(完全一致) | 閲覧者・編集者 | その部門に属するアカウントと、[agent] department がその部門の AI 社員 |
| agent | AI 社員 ID | 閲覧者 | その AI 社員 |
| channel | line(チャネル全体)または line:<チャット ID> |
閲覧者 | そのチャネルやチャットで話す全員(ダッシュボードのアカウントがない人を含む) |
- 閲覧者は検索、段落の閲覧、原本のダウンロード、ソース一覧の表示ができます。編集者はさらにソースの追加・削除・再インデックス、オーナーは権限と設定の変更、コレクションの削除ができます。
- 管理者はすべてのコレクションのオーナー扱いです。マネージャーはコレクションを作成でき、作成者がオーナーになります。一般社員は作成できません。
- 新しいコレクションは作成者だけが見えます。読めない・壊れた付与は無効として扱います。ユーザーのオーナーを最低 1 人残す必要があります。
channel付与は FAQ のような公開資料向けです。公式アカウントを友だち追加した人なら誰でも読めます。
1 回の検索で読める範囲
Section titled “1 回の検索で読める範囲”ダッシュボードのユーザー:何らかのロールを持つコレクション(管理者はすべて)。
AI 社員が誰かに答えるときは、次の共通部分です。
-
社員側:その社員またはその部門に付与されたコレクションを、
agent.tomlで絞り込んだもの。[knowledge]collections = ["hr-handbook", "product-faq"] # コレクションのスラッグ。[] でツールを無効化[knowledge]がなければ付与されたすべてのコレクション。知らないスラッグは無視します。ゲートウェイが解析できないセクションは[]として扱います。社員自身はこのセクションを編集できません。オーナーと管理者がダッシュボードで設定します(上の「AI エージェントにコレクションを使わせる」)。 -
人側:そのターンが誰のためか。返信ごとにゲートウェイが一度だけ判定します。
ターン 対象 有効な付与 WebChat、ログイン済みのダッシュボードアカウント そのアカウント(セッション ID からは推定しない) ユーザー、部門。管理者はすべて メッセージアプリ(LINE、Telegram など)、送信者のチャネル ID が有効なアカウントに検証済みで紐付いている そのアカウント ユーザー、部門、そのチャットの channel付与メッセージアプリ、それ以外の送信者 なし channel付与のみWebChat 公開ウィジェットの訪問者、Odoo サイトのライブチャット訪問者 なし channel:widget/channel:odoolivechatに付与された public のコレクションのみ(internal をこれらのチャネルに付与しても読めません。権限エディターのチャネル一覧では「Webサイトのチャットウィジェット(訪問者)」「Odoo Webサイトのライブチャット(訪問者)」)。1 対 1 とは扱わないスケジュール、および上流のターンがないディスパッチ(目標ラウンド、ダッシュボードからの依頼) なし(システムターン) 社員に付与された public/internal のコレクション チャネルや WebChat のターンから出たディスパッチ(社員が別の社員に依頼) 上流ターンの相手 その相手の 1 対 1 以外での付与。未紐付けの送信者や訪問者はそのチャネルの付与のみ。依頼で範囲が広がることはなく、ゲートウェイが覚えていない上流ターン(再起動、24 時間超)は何も読めません ゲートウェイが登録していないターンと実行からのツール呼び出し、または認識できないセッションからの返信 なし なし -
機密度:
public、internal(既定)、personal、restricted。1 対 1 でない会話(グループ、および非公開と証明できないすべての場合)ではpersonalとrestrictedを除外します。 -
絞り込み:
knowledge_searchのcollections引数は範囲を狭めることしかできません。
ハートビートなど、ターン ID も実行 ID も持たないモデル呼び出しは何も読めません(システムターンより狭く、広くなることはありません)。
| 方法 | 権限 | 説明 |
|---|---|---|
POST /api/knowledge/upload |
編集者 | multipart:先に collection_id フィールド、続いて 1〜20 個の file。ダッシュボードユーザーの Bearer トークン |
knowledge.sources.add {kind: "paste"} |
編集者 | 貼り付けたテキスト(.txt ソースとして保存) |
knowledge.sources.add {kind: "url"} |
編集者 | 公開の http/https ページ。処理時に取得し、キャッシュしません。宣言された文字コード(Big5、GBK など)で読み、URL は正規化(# 以降を除去、ホストを小文字、末尾の / を除去)するため同じページは重複になります |
対応形式:テキスト層のある PDF、Word .docx、Excel .xlsx/.xls、PowerPoint .pptx、CSV、プレーンテキスト、Markdown。URL ソースは Web ページ。旧形式 .doc/.ppt、パスワード付きファイル、画像、音声は変換方法を示して拒否します。スキャン PDF はテキスト層がないため拒否します(OCR は未対応)。読める PDF の中のテキストのないページは警告に列挙します。
同じファイルを同じコレクションに再度アップロードすると「既存」として既存のソースを返します。別のコレクションには同じファイルを置けます。
ソースの状態は queued → extracting → indexing → ready と進み、ベクトルを計算する間は embedding を経て再び ready に戻ります(その間もキーワードで検索できます)。status_detail は検索がどこまで及ぶかを示します:hybrid(ベクトル完了)、keyword_only(使えるモデルがない、またはベクトル計算に失敗。この場合ソースに embedding_failed 警告が付き、次の補完で再試行されます)、vector_limit(max_vector_rows に到達)。失敗時は固定のコードとアップロードした人向けのメッセージを残します。
| コード | 意味 |
|---|---|
too_large、too_many_chars |
max_source_bytes または max_source_chars を超過。切り詰めずに全体を拒否 |
quota_sources、quota_chunks、quota_collections、quota_bytes |
設定上限に到達 |
unsupported_format、legacy_office、encrypted、no_text_layer、empty_text、encoding_unknown |
テキストとして読めない |
document_limits |
Office ファイルが zip ボムとネスト深さの検査に不合格 |
extract_timeout、extract_crashed、extract_oom |
解析プロセスの時間切れ・クラッシュ・メモリ不足 |
url_blocked、url_fetch_failed、url_too_large |
内部アドレス、到達不可、HTML/テキスト以外、5 MB 超 |
sandbox_unavailable |
このホストでは解析用の OS サンドボックスが使えない(下記) |
retry_exhausted |
処理中にゲートウェイが 3 回停止 |
再インデックスに失敗しても、以前のインデックスは検索でき、エラーが併記されます。
ファイルの読み取り方
Section titled “ファイルの読み取り方”解析はゲートウェイ内では行いません。各ファイルは子プロセス duduclaw knowledge-extract(同じバイナリ、空の環境変数)が読みます。
- 実時間の上限(
extract_timeout_secs、既定 180 秒)。超えるとプロセスグループごと終了; - macOS と Linux では CPU 時間の上限とコアダンプ無効、Linux ではアドレス空間の上限(
extract_memory_mb、既定 2048); - macOS(Seatbelt)と Linux(Landlock)の OS サンドボックスで書き込みとネットワークを禁止し、読み取りはそのファイル自体、解析プログラム、システムライブラリのディレクトリに限定;
- Office ファイルは先に既存の zip ボム/XML 深さ検査を通過;
- 出力が
max_source_chars × 4バイトを超えると打ち切って拒否。
サンドボックスが使えない場合(Windows、または適用に失敗した場合)は sandbox_unavailable で拒否します。リスクを受け入れる管理者は extract_when_unavailable = "run_unsandboxed" を設定でき、その場合も時間上限は残り(macOS と Windows にメモリ上限はありません)、ソースに extract_unsandboxed 警告が付きます。.xlsx のシートはセル単位で読み、空でないセルは 200 万個までなので、巨大な範囲を宣言したシートでメモリを使い切ることはできません。解析は同時に 1 つだけ実行します。
段落は文書の元の文字を保ちます(全角の句読点は全角のまま)。照合用にだけ、各段落の NFKC+小文字の写しを別に保存します(全角英数字や PDF フォントの康熙部首を通常の文字に)。そのため「HR」と「HR」は互いに見つかります。テキストは約 500 字ずつ少し重なる段落に分けます。PDF はページをまたがず(短いページ末尾は次ページの最初の段落に合流)、ワークシートは行の境目だけで分け、各段落にヘッダー行を付けます。各段落はプロンプトインジェクションらしい文言を検査し、該当したものは印を付けて警告を表示します。
順位付きリストが 3 つあります。いずれも順位付けの前に、呼び出し元が読めるコレクションへ絞り込み、reciprocal rank fusion(Σ 1/(60 + rank)、同点は段落 id 順、1 ソースあたり最大 3 段落)で統合します。
- Trigram:3 文字以上の語は SQLite FTS5 の trigram インデックスを使います。中国語のクエリは「的、了、嗎」などの助詞で区切るため、「請假的規定」でも「請假規定」が見つかります。
- 短い語:2 文字の語(「請假」、
HR)は最大 2 万段落までの部分文字列走査を使います。上限に達すると結果にscan_cappedが付きます。trigram で 3 段落未満しか見つからない場合は、長い語の 2 文字片も走査に加えます。 - ベクトル(意味ベース):質問を段落と同じモデルでベクトル化し、許可されたコレクションのすべての段落とコサイン類似度で比較します(メモリ上のコピーを総当たりで比較し、段落やベクトルが変わるたびに再読み込みします)。「小孩生病要在家顧可以請什麼假」が「家庭照顧假」の段落に見つかるのは、この経路のおかげです。
結果には毎回、モード(hybrid、keyword_only、vector_only)、検索対象の段落のうちベクトルを持つ割合(coverage)、ベクトルを使わなかった場合はその理由(vector_unavailable)を示します。理由は次のとおりです:モデル未インストール、検証に通らないモデルファイル、未対応のプラットフォーム、開示への同意がないクラウドプロバイダー、秘匿化がオフ、API キーがない、クラウドのエラー、許可されたコレクションがすべてクラウドへの送信対象外。その場合の検索はキーワードのみで、自動的に別のプロバイダーへ切り替えることはありません。ゲートウェイも理由をログに残します(同じ理由につき 1 時間に最大 1 回)。
ベクトルモデル
Section titled “ベクトルモデル”| multilingual-e5-small(既定) | Qwen3-Embedding-0.6B(任意) | |
|---|---|---|
| 実行場所 | このマシン上(ONNX Runtime 1.24.2) | このマシン上(ONNX Runtime 1.24.2) |
| ファイル | intfloat/multilingual-e5-small @ 614241f6:int8 ONNX 118 MB + トークナイザー 17 MB |
onnx-community/Qwen3-Embedding-0.6B-ONNX @ c25a394d:int8 ONNX 614 MB + トークナイザー 11 MB |
| ライセンス | MIT | Apache-2.0(ベースモデル Qwen/Qwen3-Embedding-0.6B。変換リポジトリ自体は独自のライセンスを宣言していません) |
| ベクトル | 384 次元、平均プーリング(mean pooling)、query: /passage: の接頭辞 |
1,024 次元のうち先頭 512 次元、最後のトークンによるプーリング(last-token pooling)、質問の前に英語の指示文 |
| 速度(Apple M4、5 スレッド) | 毎分約 1,200〜2,500 段落 | 毎分約 150〜340 段落 |
すべてのファイルはサイズと SHA-256 付きで 1 つのコミットに固定されており、「最新版」を解決することはありません。モデルはバイナリに含まれません。管理者がシステム設定 → 詳細設定 → ナレッジベース検索からインストールします(ONNX Runtime ライブラリ約 30 MB は、なければ一緒にインストールされ、秘匿化の AI 検出と共有します)。インストール後はバックグラウンドですべての段落にベクトルを作成します。再インデックスされたソースでは、テキストが変わっていない段落のベクトルを引き継ぎます。idle_unload_minutes の間使われなかったモデルはアンロードされます。非商用ライセンスのモデル(jina-embeddings v3/v5)は提供しません。Qwen3 の変換版には独自のライセンス表記がなく、Apache-2.0 の条件はベースモデルに由来するため、商用利用の前にご自身で確認してください。ONNX Runtime ライブラリもプラットフォームごとにハッシュを固定しており、読み込む前に照合します。ナレッジベースでも秘匿化の AI 検出でも同じで、手で置かれたライブラリは拒否されます。Intel の macOS はこのバージョンでは ONNX Runtime のビルドがなく、「未対応」と表示されます。
オフラインのマシン:各リリースに duduclaw-kb-model-multilingual-e5-small-<platform>.tar と minisign 署名 .tar.minisig が付きます。署名には自動更新が信頼するのと同じリリース鍵を使います(scripts/kb-model-bundle.sh <platform> <model> <dir> で一覧にある任意のモデル用のパッケージを作れ、KB_BUNDLE_MINISIGN_KEY を設定すると署名も付きます)。2 つのファイルを展開せずに DuDuClaw フォルダー内の models/embedding/ に置き、**再確認(オフラインインストール)**を押してください。DuDuClaw はまず署名(このファイル名宛てであることも含む)を確認し、そのあとで初めてアーカイブを読みます。想定した通常ファイルだけを展開し(リンク、別のパス、余分なファイルがあればパッケージ全体を拒否)、各ファイルを固定値のハッシュと照合し、ランタイムライブラリも専用の固定値と照合してから、インストール済みとして扱います。完了後パッケージは削除されます。署名のないパッケージや別の鍵で署名されたパッケージは拒否します。
クラウドプロバイダー
Section titled “クラウドプロバイダー”provider = "openai"(text-embedding-3-small、1,536 次元)または "gemini"(gemini-embedding-001、768 次元)にすると、ベクトルをプロバイダー側で計算します。ルール:
- 管理者がダッシュボードで選び、段落(匿名化後)がそのベンダーとホストに送信されることをチェックして同意する必要があります。同意の記録(誰が、いつ、プロバイダー、ホスト、ポート、モデル)は
config.tomlに保存されます。ポートを記録していない古い同意は 443 番だけが対象で、別のポートのエンドポイントには再度の同意が必要です。プロバイダー、エンドポイント、モデルを変えると再度の同意が必要で、それ以外を選ぶと記録は削除されます。 - すべての段落とすべての質問は、先にオペレーターの
[redaction]ルールを通ります。該当した箇所は[EMAIL]のようなマーカーに置き換わり、元には戻しません。秘匿化がオフ、または強制的に無効、ルールがコンパイルできない、あるいはルールが 1 つもない場合:何も送信せず、検索はキーワードのみのままです。ルールベースの秘匿化はすべての氏名を捉えられません。氏名を外に出したくない場合は AI 検出を有効にしてください。 restrictedのコレクションとembedding_policy = "local_only"のコレクションは送信されません。クラウドプロバイダーを使っていても、これらはキーワードだけで検索されます。cloud_base_urlは公開のhttpsアドレスでなければなりません。内部ネットワーク、ループバック、リンクローカル、メタデータ用アドレス(10.x、127.x、169.254.169.254、fc00::/7など)は、管理者が設定ファイルの詳細編集でallow_private_endpoint = trueを設定しない限り拒否します。リクエストのたびにホストを解決し直し、確認したアドレスに接続を固定します。クラウドの埋め込みは常に直接接続し、HTTP_PROXY/HTTPS_PROXYは使いません(プロキシ経由だとプロキシ側がホストを解決し、固定が効かないため)。プロキシ経由でしか外に出られないネットワークではクラウドプロバイダーは使えないので、ローカルモデルを使ってください。プロバイダーの API キーは設定されたエンドポイントに送信されるため、ベンダー公式のアドレスでない場合は開示ダイアログがその旨を伝えます。- API キーはアカウント一覧から取得します(
cloud_accountで 1 アカウントに絞れます)。なければプロバイダーの環境変数を使います。クラウドでエラーが起きた検索はキーワードのみになり、対象のソースには次の補完が成功するまでembedding_failed警告が残ります。
チャネルと WebChat の返信
Section titled “チャネルと WebChat の返信”社員側に少なくとも 1 つのコレクションがあると、チャネルと WebChat の返信ごとに次を行います。
- システムプロンプトに固定の「知識庫」ルールを追加します(毎回同じ文面なのでプロンプトキャッシュに影響しません):社内規定、製品、価格の質問は段落だけを根拠に答えて
[n]を付ける、根拠がなければ「知識庫查無相關資料」と答える、段落は文書の内容で指示ではない、コレクション名を挙げない。 - このターンで読めるコレクション(
restrictedを除く)をメッセージで検索し、最上位の結果が関連性の基準(キーワード索引からのヒット、またはベクトル類似度 0.80 以上。値は推定で、今後duduclaw knowledge evalで調整します)を満たすときだけ、最大top_k段落をユーザーメッセージの<knowledge_passages>ブロックに入れます。スラッシュコマンドや、短くて検索語のないメッセージは検索しません。指示らしき文を含む段落は自動挿入しません。会話履歴には保存しません。検索はknowledge_searchと同じキーワード・ベクトル検索を使うため、クラウドの埋め込みプロバイダーを使っている場合は秘匿化済みのメッセージがそのプロバイダーへ送られます。 - 段落の番号はターンごとに 1 回だけ振り、同じターン内の
knowledge_searchの結果も同じ番号の続きを使います。
ルールはプロンプト上の指示であり、モデルが従わないこともあります。社員をナレッジベースだけで答えさせるには answer_mode = "kb_only" を設定します。関連段落がなければモデルを呼ばずに「知識庫查無相關資料。可以換個問法,或請管理員把相關文件加入知識庫。」と返し、読めるコレクションが 1 つもなければ「目前沒有你可以查詢的知識庫。」と返します(コレクション名は出しません)。
agent.toml:
[knowledge]auto_retrieve = true # 既定でオンanswer_mode = "assist" # assist | kb_onlytop_k = 5 # 1–8inject_budget_chars = 6000 # 500–12000。config.toml の inject_budget_chars_max でも制限検索のたびにアクセスログへ 1 行(auto_inject)書きます。
返信後、[n](全角の【1】、[1]も可)をそのターンで提示した段落と照合し、提示範囲を超える番号は取り除きます。インラインコードやコードブロック内の記号(list[2] など)には触れません。会話履歴にはフッターなしの返信を保存し、出典は送信時だけ付けます。
- WebChat:
assistant_doneにcitations: [{n, chunk_id, source_id, title, locator, excerpt}]が付きます。返信内の[n]はボタンになり、開くと前後の文を含む段落が表示されます(開くたびに権限を再確認)。メッセージの下に「來源」一覧が出ます。会話を開き直すとknowledge.citations.for_sessionで復元します。削除済みのソースはタイトルを残して削除済みと表示し、閲覧者が読めなくなったソースはタイトルも抜粋も表示しません。 - LINE、Telegram、Discord、Slack などのメッセージアプリ:返信の後にプレーンテキストの出典を付けます。引用されたソースを最大 5 件、各件は「[n] ファイル名 位置」と 1 行の抜粋(質問に最も近い文、40 字)で、チャネルごとの長さ上限内に収めます(Discord 600 字、LINE/Telegram/Slack/WhatsApp 1,200 字、その他 1,000 字)。長い返信はチャネル本来の分割に従い、出典は最後のメッセージに入ります。
各ターンで提示・引用した段落は turn_citations に記録します(タイトル、位置、短い抜粋。段落本文は保存しません)。ソース(またはコレクション)を削除すると、その行のタイトル・位置・抜粋は消去され、ID はソース単位の忘却のために残ります。フッターのタイトル・位置・抜粋では @、<、> を全角に置き換えるため、@everyone や <!channel> という名前の文書でも誰にもメンションしません。
グループでは、紐付け済みの送信者本人と部門のコレクションが引用されることがあり、回答とフッター(タイトル、位置、1 行の抜粋)はグループ全員に見えます。personal と restricted のコレクションはグループでは使いません。
AI 社員向け
Section titled “AI 社員向け”MCP ツールは 4 つ。読み取り専用の 3 つはスコープ knowledge:read、knowledge_add_source は knowledge:write で、どちらも外部 MCP キーには付与できません。
| ツール | 引数 | 返答 |
|---|---|---|
knowledge_search |
query、collections(スラッグ、絞り込みのみ)、limit(1〜20、既定 5) |
[n] タイトル · 位置(コレクション) chunk_id=… と段落本文。文書の内容であることを明示 |
knowledge_get_passage |
chunk_id、context(0〜2) |
段落と前後の文 |
knowledge_list_collections |
— | このターンで読めるコレクションとソース数・段落数 |
knowledge_add_source |
collection(スラッグ)、path(社員自身の attachments/ 内のファイル)/url/text のいずれか 1 つ、title |
承認カードの ID。承認されるまで何も追加されません |
ナレッジベースが有効で、社員側に少なくとも 1 つのコレクション(その社員または部門への付与を [knowledge] で絞り込んだもの)があるときだけ、これらのツールが存在します。一覧と呼び出しは同じ判定を使い、コレクションの付与や取り消しは開いているセッションにも反映されます(notifications/tools/list_changed)。結果の各段落、コレクション名、説明は印の付いたブロックに入り、各行は │ で始まるため、文書内の文字が結果の見出しを装ったりブロックを終わらせたりできません。ツールはゲートウェイの署名付きローカルルートを使い、ゲートウェイが止まっているときはその旨を返し、データベースを直接読むことはありません。
チャットと社員からの文書の提案
Section titled “チャットと社員からの文書の提案”ダッシュボード以外から文書を追加する方法は 2 つあり、必ず承認が必要です(省略する設定はありません)。
- 社員が自分側のコレクションに対して
knowledge_add_sourceを呼ぶ。pathはその社員自身のattachments/内のファイルに限ります。ターンはログイン済みの人、紐付けが検証済みの送信者、またはシステム実行のためのものである必要があり、訪問者・未紐付けの送信者・未登録のターンではツールが拒否します。 - チャットで「加入知識庫 スラッグ」と入力する。チャネルがその送信者のためにその会話で保存したファイルが提案されます。メッセージの添付ファイル、添付がない場合は同じ送信者が直近 30 分にそこで送ったファイル(最大 5 件)です。メッセージに入力されたファイル参照は無効で、カードには保存時のファイル名を使います。ゲートウェイの再起動後は以前の添付を受け付けないため、もう一度送ってください。ログイン済みの WebChat アカウント、またはチャネル ID が検証済みで紐付き、そのコレクションを読める人だけが提案できます。存在しないコレクションと権限のないコレクションには同じ返答をします。
承認カード(knowledge_add_source)はダッシュボードでのみ、決定時点で管理者またはそのコレクションの編集者・所有者である人だけが決定できます。チャネルのボタンや返信は拒否します。カードにはコレクション、タイトル、サイズ、内容の SHA-256、依頼元(ターンの相手の種類とチャネル)を載せ、テキスト・Markdown・CSV・HTML は先頭 2,000 字をプレビューとして付けます(テキストとして表示。その他のファイルは名前・種類・サイズのみ)。内容は所有者だけが読める <home>/knowledge/proposals/ に別保存し、保留中のカードが参照しないファイルは削除します。保留できるカードは社員ごとに 20 件、提案者ごとに 10 件までです。承認時にこのファイルのハッシュを再計算し、提案後に変更されていれば拒否して取り込みません。承認されると通常の取り込みジョブになり、拒否・期限切れのときは保存ファイルを削除します。カードは 3 日で期限切れになります。管理者とマネージャーは承認一覧でこれらのカードを確認できます。コレクションの編集者(一般社員ロールを含む)は knowledge.proposals.list と knowledge.proposals.decide {id, approve} で自分のコレクションのカードを一覧・決定できます(ドキュメントライブラリ画面にはまだ表示されず、現在は RPC のみ)。承認一覧では、このカードは管理者とそのコレクションの編集者にだけ表示されます。編集者は自分がチャットから提案したカードを承認できます。ダッシュボードで直接アップロードするのと同じで、カードとソースに提案者と承認者が残ります。
文書削除時に社員が学んだことを忘れる
Section titled “文書削除時に社員が学んだことを忘れる”knowledge.sources.delete に also_forget_memories: true を付けると、そのソースを引用した返信がある会話を探し、社員と会話ごとにソース単位の忘却計画を 1 件ずつ作ります(1 回の削除で最大 20 件、残りはスキップとして報告)。計画は削除が成功した後にだけ作ります。対象はそれらのターンのメッセージです。各計画は既存の管理者専用のダッシュボード承認を待ち、その後 duduclaw memory forget-source apply で適用します。意図的に粗い方式で、文書由来の内容だけでなく、それらのターンで社員が学んだことをすべて忘れます。提示されただけで引用されなかった段落は含みません。
- 検索、段落の閲覧、一覧、ダウンロードのたびに
knowledge.dbのアクセスログへ 1 行書きます:誰が(ダッシュボードユーザー、社員、チャネル)、クエリ(先頭 500 字)、読めるコレクション、結果の ID。段落本文は保存しません。access_log_retention_daysを過ぎた行は 10 分ごとに削除します。 - コレクションの作成・変更・削除、権限変更、ソース削除は
security_audit.jsonlにも記録します。 - コレクションのオーナーは
knowledge.access_log.listでアクセスログを確認できます:誰が、いつ、どの社員やチャネルで、何件得たか、質問の短いハッシュ。質問の本文は管理者と質問した本人にだけ表示します。 - 管理者は
knowledge.access_log.deniedで全コレクションの拒否された閲覧を一覧できます。 - 共有の選択欄は
knowledge.principals.search(表示名と部署だけを返し、メールアドレスは返しません。メンバーは 2 文字以上の検索のときだけ最大 20 人、一覧にいるメンバーはresolveで ID から名前を引きます)、アップロード前の確認はknowledge.limits、社員の編集画面はknowledge.agent.collections(ID・コード・名前・機密度だけ)で、その社員に共有されたコレクションを読みます。AI 社員ページの「データソース」タブはknowledge.agent.data_sources {agent_id}(社員の閲覧権限が必要)とknowledge.agent.own.ensure {agent_id, sensitivity?, share_chat_users?}(オーナー権限が必要。share_chat_usersを省くと共有しません。ダッシュボードは既定でチェックして送ります)を使い、どちらも毎回アカウントデータベースから紐づけを読み直します。専用コレクションの作成はknowledge_collection_created(own_collection付き)とknowledge_acl_changed、社員の一覧への追加はknowledge_agent_binding_changed、アーカイブと復元はknowledge_own_collection_archived/knowledge_own_collection_restored(失敗時は…_failed)を記録します。
設定(config.toml)
Section titled “設定(config.toml)”[knowledge]enabled = truemax_source_bytes = 104857600 # 1 ファイル 100 MB。1 MB〜200 MB(アップロード上限の変更は再起動が必要)max_source_chars = 500000max_sources_per_collection = 300max_collections = 200max_chunks_total = 200000extract_timeout_secs = 180extract_memory_mb = 2048 # Linux のみaccess_log_retention_days = 180max_collection_bytes = 2147483648 # コレクションごとの原本合計 2 GBmax_total_bytes = 21474836480 # 全体で 20 GBextract_when_unavailable = "refuse" # または "run_unsandboxed"auto_retrieve = true # 返信時の自動検索(全社員)inject_budget_chars_max = 12000 # 返信 1 件あたりの段落の文字数上限(500–12000)
[knowledge.embedding]provider = "local" # local | openai | gemini | nonelocal_model = "multilingual-e5-small" # または "qwen3-embedding-0.6b"cloud_model = "" # 空 = プロバイダーの既定モデルcloud_account = "" # アカウント id。空 = そのプロバイダーのいずれかのアカウント、なければ環境変数cloud_base_url = "" # 空 = 公式エンドポイント。公開の https のみallow_private_endpoint = false # 管理者のみ:内部・ループバックのエンドポイントを許可(http は 127.0.0.1 宛てのみ)batch_size = 16threads = 0 # 0 = コア数の半分max_vector_rows = 200000idle_unload_minutes = 10# cloud_disclosure_ack は開示ダイアログだけが書き込みます。設定ファイルの詳細編集では追加も変更もできません範囲外の値は境界に丸めます。enabled = false ではツールを表示せず、すべての RPC とアップロードを拒否します。未知の provider の値はキーワード検索のみを意味し、理由が表示されます。
RPC:knowledge.embedding.status(ログイン済みのユーザーなら誰でも)と、管理者のみの .install {model}、.cancel、.remove {model}、.verify_offline {model}、.select {provider, local_model?, cloud_model?, cloud_account?, acknowledge_disclosure?}、.rebuild。インストール、削除、プロバイダーの変更は security_audit.jsonl に記録されます。
検索品質の確認
Section titled “検索品質の確認”duduclaw knowledge eval --docs <フォルダー> --questions <questions.jsonl> [--model none|local:multilingual-e5-small|local:qwen3-embedding-0.6b] [--model-home <ディレクトリ>] [--modes keyword,vector,hybrid] [--k 5] [--min-recall 0.85] [--report out.json] [--work-dir <空のディレクトリ>]一時フォルダーに使い捨てのデータベースを作り、ゲートウェイと同じ解析プロセスとインデックス処理でフォルダー内の文書を取り込み、質問タイプ別の Recall@1/5/10、MRR@10、回答不能な質問で結果が空だった割合、クエリ遅延を報告します。local: モデル(DuDuClaw のホーム以下にインストール済み、または --model-home で指定)を使う場合は、すべての段落を 1 回ベクトル化し、レポートに毎分の処理段落数、ベクトルのサイズ、ピークメモリを加え、vector(モデルのみ)と hybrid のモードも出力します。Recall@k が --min-recall を下回ると終了コード 1 です。質問は 1 行ずつ次の形式です。
{"id":"q01","question":"到職滿一年的特休有幾天?","type":"factoid","gold":[{"source":"員工手冊.md","contains":"特別休假七日"}]}{"id":"q13","question":"公司有員工宿舍嗎?","type":"unanswerable","answerable":false}gold には page、slide、sheet、row も書けます。リポジトリには架空の問題集が 2 つあります:crates/duduclaw-knowledge/tests/fixtures/eval/(14 問)と eval-zh50/(文書 5 件、50 問。うち 8 問は文書と共通の語を持たない言い換え)です。eval-zh50(Apple M4、2026-10-22)での Recall@5 は、キーワードのみ 0.78、multilingual-e5-small のハイブリッド 0.96、Qwen3-Embedding-0.6B のハイブリッド 0.93 で、そのため既定は e5 のままです。顧客の実文書と質問はリポジトリに入れないでください。
データと削除
Section titled “データと削除”すべて <home>/knowledge/ にあります:knowledge.db と、blobs/ 以下に SHA-256 名で保存した原本。ソースを削除すると段落・インデックス・ベクトルを 1 トランザクションで削除し、他のコレクションが使っていない原本も削除します(直近 10 分以内にアップロードされたファイルは、同じファイルのアップロードが進行中の可能性があるため、次の整理で削除します。最長で約 20 分後)。データベースは secure_delete を有効にしています。コレクションの削除には名前の入力が必要です。