跳到正文
Mohamed Moustafa 技术博客·· 2025-11-27AI 评分65

用逐对象推理轨迹防止 Agent 死循环修改

Preventing agent doom loops with per-object reasoning traces

AI 导读

作者提出防止 Agent 修改外部对象时陷入死循环的方法:每次改动前先理解对象如何进入当前状态,并强制工具注入 reasoningForUpdates 参数,把改动原因持久化到对象上供后续更新参考。以 updateUserProfile 工具为例,注入推理轨迹后 LLM 不会因用户询问 Austin 天气就错误改写居住地;代价可能是额外一次 LLM 调用和轨迹去重成本。

正文 · 原文

When an agent updates an external system through a tool, it tends to eventually get stuck in a loop: fixing one issue produces a second, and fixing the second brings back the first.

This happens to any agent modifying an external object, but it's most obvious in coding agents — the unstable bug wall you hit that blocks progress without manual intervention. Ilya Sutskever cites it as the key example of LLMs failing at simple human tasks.

The solution is simple. The golden rule: don't modify an object until you understand how it ended up in its current state (this is Chesterton's Fence).

What counts as an object is an engineering tradeoff. For coding agents a codebase is too big, a function too small — a class or module is about right. The "how it ended up in its current state" piece is the reasoning trace: every time an agent modifies an object, it must give a concise reason for the change, and we persist that on the object to be reviewed on future modifications. [1]

A real example: a personal AI assistant keeps a user profile (the object) in chat context, updated every few messages via an updateUserProfile tool. We inject a reasoningForUpdates argument that is never shown in chat context, only saved for future reference.

{
  name: "updateUserProfile",
  parameters: {
    firstName: { type: "string" },
    primaryLanguage: { type: "string" },
    residenceCityAndState: { type: "string" },
    // injected:
    reasoningForUpdates: { type: "array", items: { type: "string" } },
    required: ["reasoningForUpdates"],
  },
}

Say I mention I live in San Francisco. My profile gets residenceCityAndState: "San Francisco, CA" and the trace left behind is "User asked about San Francisco residential parking permits".

Later I ask for the weather in Austin, TX. With only the existing profile as context, the LLM won't hesitate to flip my residence to Austin — wrong, I was just traveling. And next time I ask about San Francisco weather, it flips right back. A doom loop.

Instead, we pass the profile's accumulated reasoning traces as context right as we're about to update. Armed with the parking-permit inquiry from before, any capable LLM will not touch residenceCityAndState. It has the confidence for stability.

This might cost you a second LLM call, and at scale you'll deduplicate traces and pay for context — but those are details. The golden rule once more: don't modify an object until you understand how it ended up in its current state. It seems simple because it is.


[1] This can be done with good ol' code comments for coding agents. Although this is very fragile as LLMs do not like to append to comments across changes or use them as a history log, so I keep a separate index for reasoning traces on a project's files.

来源:Mohamed Moustafa 技术博客 · mmoustafa.com