記事一覧へ
# エージェントは無限ループに陥っている — メモリの肥大化と伝播がその理由
エージェントは反省なく同じループを繰り返している。なぜか正しい記憶と帯域幅を持てない。長いタスクを与えると、途中で何かをハルシネートし、それを保存し、後で取り出し、そのハルシネーションが「土台」になってしまう。これはモデルの問題ではなく、メモリの問題だ。
エージェントメモリをスケールさせる際の主要なボトルネックは以下の 2 つ:
1. **無制御なメモリ肥大化 (UMG)**: インテリジェントな退避なしに記憶が積み上がり、履歴が多すぎてシステム全体が窒息する。
2. **誤記憶の伝播 (FMP)**: 1 つの誤った事実が保存されると、それが繰り返し取り出され、強化される。気づけばエージェントは何にでも絶対的な確信を持つようになっている。
これら 2 つを直感を交えて詳細に議論し、これが起き続ける他の理由もリストアップする。
## エージェントのメモリ概観
「エージェントメモリ」と言うとき、通常は次の 3 つのいずれかを指す:
1. **インコンテキストメモリ** — プロンプトウィンドウ
2. **外部メモリ** — ベクトル DB やエージェント自身が生成したオフロードファイル
3. **パラメトリックメモリ** — 学習プロセスで獲得した記憶 (実行中は更新不可)
今日の本番エージェントは主に 1 と 2 に依存し、ローリングコンテキストウィンドウ + 古い情報の検索ストアという構成。これは合理的に聞こえるが、どちらのシステムも「何を忘れるか / 何を信頼するか / 間違ったものが保存された場合何をするか」に良い答えを持っていない。
MemGPT の論文はこれを実システムの問題として真剣に考えた数少ない試みの一つ。LLM を CPU として、メモリ階層を明示的なアーキテクチャ要素として扱っている。読む価値がある。コアインサイトは「ナイーブなものではなく、意図的なメモリ管理が必要」ということ。
## 無制御なメモリ肥大化 (UMG)
実際のエージェントパイプラインの大半はこう動く: あらゆるアクション・ツール出力・中間アイデアが全部メモリバンクに保存される。何も忘れない。「コンテキストが多いほど良い」という論理。
そんなわけがない。
これは過剰なノイズを生み、検索を遅くし、最終的には関連性の高い新データの代わりに古い情報を取り出すことになる。
```python
# ナイーブなメモリ蓄積
# スコアリングなし、退避なし、有効期限なし。ただ成長するだけ。
memory_store = []
def store_memory(event):
memory_store.append({
"content": event,
"timestamp": time.time()
# スコアなし、TTL なし、関連性タグなし
})
# 1万インタラクション後、検索は遅く、半分のメモリは古いか間違っている
```
ベクトルには有効期限がない。エンベディングは無限に蓄積し、古いエンベディングは関連性から離れていく。検索時間はベクトルストアのサイズに比例して増加する (特にロングランニングなマルチステップエージェントで顕著)。
古い情報は単に休眠しているのではなく、クエリのエンベディングがそれをうっかり取り出すことで姿を現し、現在の推論を汚染する。多くの情報検索システムには「この情報は今や時代遅れ」という内在的な概念がない。
**直感**: 大学で 1 回目の授業からノートを取り始め、その多くがラフで、時には別科目のノートが同じノートブックに混ざる。試験で正しいノートを探そうとすると見つけるのに苦労する。これがエージェントの無制御メモリの典型例 — コンテキストが腐り始め、コンテキストプールから適切な答えを見つけるのが難しくなる。
## 誤記憶の伝播 (FMP)
FMP はより洗練されており、より恐ろしい。最初に 1 つだけ偽の情報がある。マシンがツールコール結果をハルシネートしたかもしれない、ユーザーが誤った入力をしたかもしれない、API が悪いデータを返したかもしれない。理由は何でも、この偽事実がメモリに記録される。次回の取り出しで出てくる。それが他のことを推論するために使われる。プロセス全体がメモリに保存される。
```python
# エージェントがメモリを取り出して盲目的に信頼する
def answer_with_memory(query, memory_store):
relevant = retrieve_top_k(query, memory_store, k=3)
# 検証なし、信頼度チェックなし
context = "
".join([m["content"] for m in relevant])
response = llm.complete(f"Context: {context}
Question: {query}")
memory_store.append({"content": response}) # 出力も保存
return response
```
Chain of Thought の論文は推論チェインが精度を劇的に改善することを示した。しかし誰も話さない裏面がある: プロセスチェインの初期段階が誤って形成され、それがメモリの一部になると、後続の全プロセスに必然的にその間違いが含まれる。CoT は正しい論理にも誤った論理にも増幅器として作用する。
FMP は表面的には失敗に見えない。エージェントは確信を持ち、一貫性があり、完全に間違っている。エージェントが実行する時間が長いほど、誤記憶が想起ランキングに深く根を下ろす。標準的な測定ツールはこれを検出できない (最終結果しかテストせず内部状態を見ない)。
**直感**: 試験で誰かから公式をコピーする、プロジェクトで誰かが何か計算をする。確認せずに進む。気づけば全員が間違った公式や計算値を使っている。これがエージェントにおける誤記憶の伝播 — 1 つの間違ったコンテキストや記憶ですべてが崩れる。
## RAG はこれを悪化させる、改善しない
誰もがメモリに RAG をフォールバックする。コンセプトはシンプルかつエレガント: 関連ドキュメントを見つけ、生成をグラウンドし、ハルシネーションを避ける。ナレッジベースが慎重にキュレーションされ静的な場合 (社内 wiki や法務文書) には完璧。
問題は **エージェントが自分の検索 DB に書き込む** こと。これがアプローチの根本的欠陥。情報を独立した純粋なデータセットから取得する代わりに、検索器はエージェントが書き込んできた DB から読んでいる (過去のクエリのミスを含む可能性がある)。
- グラウンドトゥルースは「検索コーパスが真実を保持する」という前提。エージェントメモリはグラウンドトゥルースではなく、エージェントの思考の進行中のトランスクリプト。
- 事実の正確さは類似度に組み込まれていない。同じトピックなら、誤ったメモリと正しいメモリは極めて類似することがある。
- 誤ったメモリが浮上するエージェントループの各取り出しは、そのメモリへの「検証シグナル」になる。
## RL を FMP の修正策として使う
これは多くの人が見落とす次元。FMP が強化問題なら、解決策も強化問題として捉えられる。メモリの検証を報酬シグナルとして扱う。
エージェントが推論ステップでメモリを使い、ステップの結果がそのメモリの妥当性のフィードバックになる。検証可能な結果を生んだら、エージェントはそのメモリの信頼度スコアを上げる。失敗したら、メモリはペナルティを受け削除される可能性がある。
```python
# RL 風メモリ信頼度スコアリング (報酬・ペナルティのパイプライン)
def update_memory_confidence(memory_id, outcome):
memory = memory_store.get(memory_id)
if outcome == "correct":
memory["confidence"] = min(1.0, memory["confidence"] + 0.1)
elif outcome == "contradicted":
memory["confidence"] -= 0.3
if memory["confidence"] < 0.2:
memory_store.delete(memory_id) # 低信頼メモリを退避
memory_store.update(memory_id, memory)
```
InstructGPT の論文は人間の選好にモデル出力を整合させる RLHF フレームワークを示した。同じロジックがここに自然に拡張する。モデル出力をスコアリングするのではなく、メモリエントリを「時間と共にどれだけ信頼できることが証明されたか」でスコアリングする。
- 報酬シグナルはタスク完了の成功・ユーザーの修正・既知ソースとの結果検証から得る。
- 信頼度の低いメモリは想起に使わないか削除する (フィードバック循環を断ち切る)。
- このシステムは各メモリが一意に識別・評価可能であることを要求する (現行パイプラインは提供できない)。
## 出発点としてのファイルベースメモリ
完全なグラフメモリシステムを構築する前に、ファイルベースメモリを実装するのが有益。生のメモリにベクトル追加だけで十分な場合もあるが、メタ情報を含む構造化メモリをファイルに追加する方が有益。メタデータには タイムスタンプ・重要度・ソース・確実性レベル を含む。
Generative Agents 論文の例: メモリストリームに「エージェントの視点での相対的重要度」スコアが含まれていた。想起は recency / importance / relevance のパラメータで実行された。
```python
# Recency と confidence スコアリング付きファイルベースメモリ
import json, time
def store_memory(content, source, confidence=0.8):
entry = {
"content": content, "source": source,
"timestamp": time.time(), "confidence": confidence,
"access_count": 0
}
with open("memory.jsonl", "a") as f:
f.write(json.dumps(entry) + "
")
def retrieve_memory(query_embedding, top_k=5):
memories = load_all()
for m in memories:
m["score"] = (
0.4 * cosine_sim(query_embedding, m["embedding"]) +
0.3 * recency_score(m["timestamp"]) +
0.3 * m["confidence"]
)
return sorted(memories, key=lambda x: x["score"], reverse=True)[:top_k]
```
- メタデータ対応の検索により、古い・低信頼度メモリをランキング段階に入る前にフィルタできる
- JSONL 形式は監査可能。エントリを検査・デバッグ・手動修正できる (ブラックボックスベクトルストアではできない)
- access_count フィールドで「どのメモリが最も取り出されているか」を追跡可能 (エージェント挙動への影響の代理指標)
## グラフメモリこそ本物のアップグレード
ファイルベースメモリは悪くない。グラフベースメモリは更に良い。リストベースメモリは各メモリを独立データとして扱うため、関係的記憶を持たない。「ユーザーは Python を好む」と「ユーザーのプロジェクトは asyncio を使う」は別々のメモリだが、関連している。これらを別々に保存・取り出すと、検索時にその関係を判定できない。
グラフベースメモリはノードの概念に基づく。ノードがメモリを表し、エッジが メモリ間の関係 (矛盾・依存・派生・更新) を表す。任意のノードを取り出すことはエッジの巡回も意味するため、検索時に常に関係的コンテキストと矛盾が得られる。
- 矛盾の検出が構造的に行われる: 矛盾エッジがマークされたメモリが導入されると、システムは黙って上書きせず調査するようアラートを出す
- グラフ巡回により類似クエリ数を増やさずに豊かな結果を達成
- MemoryBank はグラフ構造メモリがエージェントに「フラット検索より遥かに一貫したペルソナと事実情報」を保持させることを証明
- 「derived from」エッジは FMP 検出に特に有用 (1 つの誤った根メモリが他の複数メモリを生成 → 剪定対象を特定可能)
## コンテキストウィンドウは味方ではない
人々はコンテキストウィンドウを大きくすればメモリ問題が解決すると思っている。しない。1M トークンのコンテキストウィンドウは、間違った情報を一気に多く詰め込めるだけ。検索問題は消えない。場所が移るだけ。「何を取り出すか」を決める代わりに、「非常に長いプロンプトに何を含めるか」を決めることになり、モデルはその文章の壁の中で何が関連かを判断しなければならない。
「Lost in the Middle」論文は不快な事実を示した: LLM はロングコンテキストの中央に出現する情報を、開始や終了に出現する情報に比べて著しく上手く使えない。だからすべてをコンテキストにダンプしても、モデルはそれを均等に扱わない。位置が重要、最近性が重要。検索問題はコンテキストウィンドウの中に移っただけ。
- 長いコンテキストは問題を遅延させるチートに過ぎず、解決はしない
- コンテキストの中央部は自動的に過小評価される (そこに保存された重要メモリは見過ごされる)
- 複雑なマルチステージプロセスでは、選択的想起を持つインテリジェントな外部メモリが、コンテキストダンピングに常に勝つ
## 結論
エージェントのボトルネックは計算ではなく、認識論。「自分が知っていること」と「知っていると信じ込んでいること」を区別できないエージェントは信頼できない。UMG は探索空間を肥大化させる。FMP はデータソースを汚染する。RAG は汚染源から取り出す。広いコンテキストは扱う毒が増えるだけ。
解決策は 1 本の論文や 1 つのフレームワークから来ない。データベース管理を真剣に扱うのと同じように、エージェントメモリを真剣に扱うことから来る。スキーマ、検証プロセス、退避戦略、スコアリングアルゴリズム、監査。それをするまで、エージェントは確信を持って、しかし誤って、ループを回り続ける。

エージェント記憶RAGハルシネーション対策agent-ops
エージェントのメモリ問題:「無制御な記憶肥大化」と「誤記憶の伝播」を深掘り
♥ 63↻ 8
原文を表示 / Show original
Agents Are Stuck in a Loop. Memory Growth and Propagation is why !
15
8
63
26K
Agents are in an unapologetic loop. They somehow never have the right memory and the bandwidth. You give them a long task, they hallucinate something mid way, store it, retrieve it later, and now that hallucination is load bearing. That's not a model problem. That's a memory problem.
These 2 problems are the main bottlenecks when it comes to agent memory at scale:
Uncontrolled Memory Growth: memory continues piling up without intelligent eviction, causing the entire system to choke because of too much history.
False Memory Propagation: after storing one single false fact, this piece of information will repeatedly be retrieved and reinforced, and before you know it, the agent ends up being absolutely certain about anything and everything.
Lets discuss both of these problems in detail with simple intuitions, as well as a list of other reasons why this keeps happening.
Memory in Agents: A Quick Preview
When people say agent memory they usually mean one of three things.
Firstly, there’s in context memory – the prompt window.
Secondly, there’s external memory, e.g., a vector database, an offloaded file generated by the agent itself.
Thirdly, there’s parametric memory – memories acquired via the learning process and thus cannot be updated while the agent runs.
Production agents today rely primarily on the first two types, having a window of rolling context along with a retrieval store for the older information.
This sounds reasonable until you realize neither system has good answers for what to forget, what to trust, or what to do when something wrong gets stored.
The MemGPT paper is one of the few serious attempts at thinking about this as a real systems problem. They treat the LLM as a CPU and memory tiers as explicit architectural components. Worth reading if you haven't. The core insight is that you need deliberate memory management, not just a naive one.
Uncontrolled Memory Growth (UMG)
This is how most agent pipelines work in reality.
Every action, every tool output, every intermediate idea ends up stored in the memory bank.
Nothing is ever forgotten. The logic is that the more context there is, the better.
No way !!!!
It leads to excessive noise, slows down retrieval, and ultimately leads to retrieving obsolete information in place of relevant new data.
python
#This is what naive memory accumulation looks like
#No scoring, no eviction, no expiry. Just growth.
memory_store = []
def store_memory(event):
memory_store.append({
"content": event,
"timestamp": time.time()
# no score, no TTL, no relevance tag
})
#10,000 interactions later, retrieval is slow and half the memories are stale or wrong
Vectors do not have expiry. Embeddings keep on accumulating infinitely, while older embeddings get further away from being relevant.
Retrieval time will increase linearly with the size of the vector store, particularly when performing long-running multiple-step agent workloads.
Outdated information does not simply lie dormant. Instead, it comes to light through query embeddings that inadvertently retrieve stale information, corrupting present-day inference processes.
There is no intrinsic notion of this information is now outdated in many information retrieval systems.
Intuition:
It often happens with us that we start making notes from the very first lecture in clg, a lot of those notes are rough, irrelevant, sometimes from different course too in the same notebook.
Later on during exams, when we search for the right note, we struggle finding it, this is a classical example of uncontrolled memory in agents, the context starts to rot and finding appropriate answers from the context pool becomes difficult.
False Memory Propagation (FMP)
The FMP approach is more sophisticated and actually more frightening. First, there is one piece of information that is simply false. Perhaps the machine imagined some result from a tool call operation. Perhaps a user entered erroneous input. Perhaps the API provided bad data. For whatever reason, this false fact is recorded in memory. On the next recall, it comes out. It is used to reason about other things. The entire process is saved in memory.
python
#Agent retrieves memory and trusts it blindly
def answer_with_memory(query, memory_store):
relevant = retrieve_top_k(query, memory_store, k=3)
#No validation. No confidence check.
context = "\n".join([m["content"] for m in relevant])
response = llm.complete(f"Context: {context}\nQuestion: {query}")
memory_store.append({"content": response})
#stores the output too
return response
The Chain of Thought paper shows that reasoning chains dramatically improve accuracy. But there's a flip side nobody talks about.
If the initial stage of the process chain was incorrectly formed and this stage turns out to be a part of memory, all subsequent processes will inevitably include the mistake. CoT acts as a power magnifier both for right and for wrong logic.
It is not failure in appearance for FMP. The agent is certain, consistent, and totally wrong.
The more time the agent spends executing, the more ingrained the false memory becomes in the ranking of recall.
Standard measurement tools cannot detect this as they test only final results and not internal states.
Intuition:
Now, for me there is a very interesting intuition for this and we all have experienced this. Sometimes we write an exam and we copy some formula from someone else, or we do a project and someone does a certain calculation somewhere. Without confirming we move on and and eventually now everyone is using the wrong formula or calculated value. This is what false memory propagation in agents is, one wrong context or memory and it all scrambles.
Why RAG Makes This Worse, Not Better
Everyone falls back on RAG for memory. Of course, it's simple and elegant in concept. Find relevant documents, ground the generation, avoid hallucinations. It's perfect for cases where your knowledge base is carefully curated and static, like an internal corporate wiki or a set of legal documents.
The issue lies in the fact that agents write into their retrieval databases. This is the fundamental flaw with the approach. Instead of sourcing information from a separate and pure data set, your retriever is now reading from a database that your agent has been writing to, possibly containing mistakes from past queries.
Ground truth is an assumption in RAG that the retrieval corpus holds. The agent memory is not ground truth; rather, it is the ongoing transcript of the agent’s thoughts.
Factual accuracy is not embedded in similarity. Two memories, one erroneous and one accurate, can be extremely similar if they fall under the same topic.
Each retrieval of the agent loop where a mistaken memory pops up is a signal of validation for that memory as well.
RL as a Fix for FMP
This is a dimension that is often overlooked by most individuals. In the case where FMP is a reinforcement problem, perhaps the solution to the problem can also be approached from the perspective of a reinforcement problem. In this regard, it will be possible to approach the validation of memories as a reward signal.
When the agent uses a memory and applies it in a step in the reasoning process, the result of the step becomes the feedback to indicate the validity of the memory used. When the step results in the production of verifiable results, the agent increases the confidence score of the memory.
However, when the step fails, the memory receives penalties and may be deleted.
python
# Pseudocode: RL-style memory confidence scoring ( somewhat like reward and penalty system - as an extensive pipeline if done )
def update_memory_confidence(memory_id, outcome):
memory = memory_store.get(memory_id)
if outcome == "correct":
memory["confidence"] = min(1.0, memory["confidence"] + 0.1)
elif outcome == "contradicted":
memory["confidence"] -= 0.3
if memory["confidence"] < 0.2:
memory_store.delete(memory_id) # evict low-trust memories
memory_store.update(memory_id, memory)
The InstructGPT paper laid out the RLHF framework for aligning model outputs with human preferences through reward modeling. The same logic extends naturally here. You're not scoring model outputs, you're scoring memory entries based on how reliable they prove to be over time.
Reward signal is obtained from successful completion of the task, corrections made by the user, or verification of results with a known source.
Memories with low confidence ratings are not used for recall or are even deleted, interrupting the feedback cycle.
This system demands that each memory be uniquely identifiable and assessable, something current pipelines cannot provide.
File-Based Memory as a Starting Point
Before getting into building the full graph memory system, it is useful to implement a file based memory system first. The logic here is rather straightforward. While vector appending will do fine in the case of raw memories, adding structured memories to files that contain meta-information can be more beneficial. In particular, the metadata includes a timestamp, the importance of the memories, its source, and the level of certainty.
As an example of how well it works in practice, the Generative Agents paper can be referenced. Namely, the memory stream they used included an importance score for the memories based on their relative importance according to the agent's perspective. Recall was then performed using the parameters of recency, importance, and relevance.
python
# File-based memory with recency and confidence scoring
import json, time
def store_memory(content, source, confidence=0.8):
entry = {
"content": content,
"source": source,
"timestamp": time.time(),
"confidence": confidence,
"access_count": 0
}
with open("memory.jsonl", "a") as f:
f.write(json.dumps(entry) + "\n")
def retrieve_memory(query_embedding, top_k=5):
memories = load_all()
for m in memories:
m["score"] = (
0.4 * cosine_sim(query_embedding, m["embedding"]) +
0.3 * recency_score(m["timestamp"]) +
0.3 * m["confidence"]
)
return sorted(memories, key=lambda x: x["score"], reverse=True)[:top_k]
Metadata aware retrieval lets you filter out old or low-confidence memories before they even enter the ranking stage.
JSONL format keeps it auditable. You can inspect, debug, and manually correct memory entries, something you can't easily do with a black box vector store.
The access count field lets you track which memories are being retrieved most, which is a proxy for influence on agent behavior.
Graph Memory as the Real Upgrade
File based memory systems are decent. Graph-based memory systems are better. List-based memory systems treat each memory as separate data, which means they lack relational memory. User prefers Python and user's project uses asyncio are two separate memories that are related to each other. Storing and retrieving these two memories separately will mean that their relationship cannot be determined at retrieval time.
Graph-based memory systems are based on the concept of nodes. Nodes represent the memories, while edges represent relations between memories. Relations include contradiction, dependency, derivation and updates. Retrieving any node also means traversing the edges, meaning you always get relational context and contradictions at retrieval time.
Detection of contradiction happens structurally, whereby the introduction of memory whose edge is marked contradicting will alert the system to do an investigation rather than overwriting it silently.
Using graph traversal helps achieve richer results through retrieval without having to increase the number of similarity queries.
MemoryBank proves that graph structured memory enables agents to retain far more consistent personae and factual information than would be the case with flat retrieval systems.
The derived from edge becomes particularly helpful in detecting FMPs because one wrong root memory generates several other memories that may need pruning.
The Context Window is Not Your Friend Here
People think bigger context windows solve memory problems. They don't. A 1M token context window just means you can fit more potentially wrong information in one shot. The retrieval problem doesn't disappear. It shifts. Instead of deciding what to retrieve, you're now deciding what to include in a very long prompt, and the model has to figure out what's relevant inside that wall of text.
The Lost in the Middle paper showed something uncomfortable. LLMs perform significantly worse at using information that appears in the middle of long contexts compared to information at the start or end. So even if you dump everything into context, the model is not treating all of it equally. Position matters. Recency matters. The retrieval problem just moved inside the context window.
Long context is merely a cheat to delay the problem, without addressing it.
The middle part of the context is automatically undervalued, meaning that any important memory stored there will simply be overlooked.
Intelligent external memory with selective recall always beats context dumping for complex multi stage processes.
CONCLUSION
The bottleneck for agents is not computation; it’s epistemology. An agent that can’t tell the difference between what it knows and what it believes itself to know cannot be trusted. UMG inflates the search space. FMP contaminates the data source. RAG pulls from a poisoned source. And a wider context simply means more poison to work with.
The solution is not going to come from one research paper or even one framework. It comes from taking agent memories seriously, just like we take database management seriously. Schemas, validation processes, eviction strategies, scoring algorithms, audits. Until we do that, agents will continue to loop around, confidently but mistakenly.