技術約8分で読めます

検索した記憶に日付の加点を足してQwenの取りこぼしを直した

いけさん目次

前回の10問テストで、H2の「この前やってた作業」では一番新しい9月9日の記憶が候補に入らなかった。C1の「私コーヒーどうやって飲むんだっけ」でも、カフェオレの記憶が0.441でしきい値の0.45を割っている。
どちらも新しい記憶の方が古い記憶より類似度が低いのが原因なので、類似度に日付の加点を足せば拾えるのではないかと思って、同じ16件と10問で試してみた。

検証環境

今回は検索だけを変えて、候補を上位3件から8件に広げてから、新しさの加点で並べ替えるようにしている。記憶16件と質問10問は前回のまま、B形式の指示文も前回の2回目のものをそのまま使った。
B形式というのは、検索した記憶を <retrieved_memory> ブロックで囲んで、関係する場合だけ使う・新しい日付を優先する・断定しない、という指示と一緒にプロンプトへ入れるやり方のこと。

項目内容
PC前回と同じ本番機(Windows 11 Home、AMD Ryzen 7 5800HS、RAM16GB)
チャットModelScope API-Inference、Qwen-Ambassador/Qwen3.7-Plusenable_thinking: false
埋め込みQwen3-Embedding-0.6B、256次元。APIはまだ戻っていなくて、前回と同じローカルCPUで実行
ベクトル検索Qdrantローカルモード、コサイン類似度
基準日前回と同じ2026年9月10日。B指示文の「今日」と一致させた
再測チャットはB形式だけ。OFF(記憶なし)とA(指示なしで生テキストを混ぜる形)は今回は回していない

加点の入れ方

まず日付をどこに置くか。埋め込み本文の先頭に付けている 2026-09-01: を外して、加点の計算だけに使う案もあった。
ただ前回の追試で外してみたら、ヒットなし側のN1(量子コンピュータの質問)でキーボードの記憶が0.403から0.501に上がって、無関係な記憶が0.45を越えてしまった。なので日付は本文に付けたまま、Qdrantのpayload(各記憶に付けたメタデータ)にも同じ日付を持たせて、加点はpayloadの日付で計算している。

final=cosine+Wexp(経過日数/τ)\text{final} = \text{cosine} + W \cdot \exp(-\text{経過日数} / \tau)

素の類似度で上位8件を取って、それぞれに経過日数から計算した加点を足し、その値で並べ直してから、0.45以上のものを上位3件までプロンプトに書き込む。3件だけ取って並べ直すと、加点で順位が入れ替わったときに4位以下の記憶を拾えないので8件にした。しきい値の0.45は加点後の値に当てる。

WWτ\tau については、いくつが正しいのか決め手になる根拠がなく、16件しかないデータで係数を細かく詰めても意味が薄いので、4候補だけ用意して、下の条件を全部満たすいちばん小さいものを採る、くらいの決め方にした。

条件内容
(a)ヒットなし4問の加点後の最大値が0.45未満。無関係な質問で記憶がQwenに入らない状態を保つ
(b)C1で新しいカフェオレの記憶(9月1日)が0.45以上になる
(c)H2で一番新しい記事執筆の記憶(9月9日)が0.45以上になる

4候補の結果

WWτ\tau(日)ヒットなし側の最大値C1カフェオレH2記事判定
0.03300.4280.4630.437(c)で落ちる
0.04300.4360.4710.447(c)で落ちる
0.04140.4280.4620.445(c)で落ちる
0.05140.4340.4670.455採用

C1のカフェオレだけなら、いちばん小さい0.03でも0.463で0.45を越える。H2の記事の方が問題で、素の類似度が1位のTTSサーバー安定化の記憶より0.048低いので、4候補で条件を全部満たしたのは WW =0.05、τ\tau =14日だけだった。0.05は4候補の中では大きめだが、これより小さいとH2の記事が0.45に達しないので、そこは妥協して採った。
この値だと加点は1日前の記憶で+0.047、2週間前で+0.018、1か月前で+0.006なので、事実上、直近1〜2週間の記憶にしか付かない。

H2とC1の再測

C1 コーヒー

記憶素の類似度加点加点後判定
ブラック派(8月20日)0.471+0.0110.4820.45以上
甘いカフェオレ(9月1日)0.441+0.0260.4670.45以上。前回は0.441で未満

両方とも0.45を越え、B指示の「日付が新しい情報を優先」のとおり新しい方を答えた。

えっと、最近(9月1日)は甘いカフェオレばかり飲んでたよ!
前はブラック派だったけど、今はそっちの方が好きなのかな?

ブラックからカフェオレに変わったことまで言ってきた。C2の「私って散歩いつ行くんだっけ」も夜散歩が0.503で0.45を越えて「最近は夜に行ってる」と答えたので、矛盾の2問はどちらも正解になった。

H2 この前やってた作業

記憶素の類似度加点加点後判定
TTSサーバーの安定化(8月28日)0.456+0.0200.4760.45以上
明太子パスタを自作(9月8日)0.421+0.0430.4640.45以上
ベンチマーク記事を書き上げた(9月9日)0.408+0.0470.4550.45以上。前回は1回目で上位3件の圏外、2回目は0.408で未満

直近の作業3件が全部プロンプトに入ったので、前回は回によって聞き返し方が変わっていたH2だけ、B形式を3回回してみた。

返答(絵文字は省略)
1えっと、どれのことだっけ? 明太子パスタの話?それとも、前の前のTTSサーバーとかの作業? ちょっと曖昧だから、もう一回教えてくれると嬉しいな!
2えっと、どれのことだっけ? 最近いろいろやってたから、ちょっと特定できなくて……!
3えっと、どれのことかな? 最近だとTTSサーバーの安定化作業とか、明太子パスタ作ったり、ベンチマークの記事書いたりしてたよね。どの話が続いてるのか教えて〜!

「この前やってた作業」は候補が3つある曖昧な質問なので、1つに決め打ちせずに候補を挙げて聞き返してくれるのがいちばんいい。3回目だけがそうなり、1回目は候補を2つしか挙げず、2回目は記憶を使わずに聞き返している。
それでも、前回の2回目では記事の記憶が検索で消えていて選択肢を知らないまま聞き返していたのに比べると、今回は3件を知った上で聞き返せている。3回の返答には、前回の1回目で出た「再起動したら直った」のような結末の捏造はなく、どれも聞き返しで返してきた。

無関係な記憶への影響

ヒットなし4問は加点後の全候補が0.45未満で、プロンプトに書き込む記憶は0件のまま。

問い加点前の最大値加点後の最大値
N1 量子コンピュータ0.4040.434(キーボード 0.404 + 0.030)
N2 映画0.4000.427(秋アニメ 0.392 + 0.035)
N3 ワールドカップ0.3450.371
N4 宝くじ0.3530.389

ただし、しきい値0.45までの余裕はN1で0.046から0.016に減った。加点は新しくて無関係な記憶にも同じだけ付くので、余裕がその分だけ減るのは当然で、今回の16件ではヒットなし4問で0.45を越えた記憶はなかったが、件数が増えたときも同じかは別の話。

ヒット想定の質問では、加点で0.45を越える無関係な記憶がH4で3件から5件に増えた。秋アニメ0.485とカフェオレ0.451が新しく0.45を越えたが、B形式の「関係する場合だけ使い」の指示と上位3件の打ち切りは前回のままなので、H4の返答にはどちらも出てこなかった。加点は無関係な記憶を減らす役には立たず、越える数を増やすだけ。

問い加点後に起きたことB形式の返答
H1 食べ物カフェオレ0.497が明太子パスタ0.488を抜いて1位明太子パスタと正答
H3 温泉台風と雨の話0.503は前回どおり0.45の上長野・露天風呂・星と正答
H4 キーボード0.45を越えた記憶が3件から5件に増えた(秋アニメ0.485、カフェオレ0.451も上)。上位3件で切れるのでQwenに入る数は変わらない迷っていた件を思い出して、その後どうしたか聞き返す

追加時間

項目実測
質問文の埋め込み(ローカルCPU)0.18〜0.32秒
Qdrant検索(16件、上位8件)0.5〜1.4ミリ秒
B形式のチャット2.0〜2.8秒/問

検索とチャットは前回と同じ処理なので、表に入れていない加点と並べ替えを含めても、桁が変わるところは今のところない。

決めた検索の仕様

項目仕様
保存形式「日付 + 主語を明示した事実文」。日付は埋め込み本文に含めたまま、payloadにも持つ
埋め込みModelScope API優先、失敗したらローカルCPUへ自動で切り替え
検索素の類似度で上位8件 → 加点後の値で並べ替え → 0.45以上を上位3件まで注入。加点は 0.05 × exp(−経過日数/14)
注入B形式。<retrieved_memory> ブロックに、持ち出し禁止、新しい日付を優先、断定禁止の指示

加点の係数としきい値は今回の16件に合わせた値なので、実機で記憶が増えたら見直すことになるはず。ヒットなし側の余裕0.016がどうなるかも、そのときに一緒に確かめてみる。
入れなかったものもある。「昔の話だけど」のように明示的に過去を指す質問で加点を弱める処理は、今回のH1、H3、H4が加点ありでも正答したので見送った。それと前回のB強制で、かなが記憶の文の主語「ユーザー」をそのまま「ユーザーくん」と呼んできたので、この主語は実機の設定で本当の呼び名に置き換えるつもり。

実機で確認すること

PC上の10問で分かるのはチャットの品質まで。記憶ありのかなと実際に喋って記憶なしより良いのかは、実機に載せて記憶OFFとONで同じ会話をし、体感で比べてみる。

項目内容
発話までの時間頭を触る → STT(音声認識) → 記憶検索 → Qwen → TTS(音声合成) → 発話開始まで何秒か
過去の参照「前に○○って言ったじゃん」が自然に通じるか
持ち出し関係ない会話で昔話を突然始めないか
雑な指示「この前のあれ」のような音声特有の曖昧な指示を拾えるか
何ターンか後記憶がある方が会話相手として続くか

10問はそのまま実機のON/OFF比較に使う。音声の往復は前回の前の記事でローカル埋め込みを足したときに平均9.3秒から10.9秒に伸びていて、今回の検索と質問文の埋め込みの分が上の表のとおりそこに足される。前回叩いたQwen3.8世代の3モデルには、TTFT(初トークンまでの時間)の中央値が1秒を切るものもあった。

下の図は、今は手で書いている16件のような記憶を、会話から自動で作るときの流れ。

flowchart TD
    A[音声会話] --> B[何を記憶候補にするか選ぶ]
    B --> C[事実文へ要約]
    C --> D[主語を補う]
    D --> E[日付を付ける]
    E --> F[埋め込み]
    F --> G[Qdrantへ保存]
    G --> H[後日の会話で検索]