06 — Chat Works. Does the Agent Actually Retrieve Memory?
06 — Chat Works. Does the Agent Actually Retrieve Memory?
06 — 聊天功能正常,但智能体真的检索到了记忆吗?
The images in this article are explanatory diagrams with Chinese labels, not screenshots of test results. Each caption summarizes the diagram in English. 本文中的图片均为带有中文标签的解释性图表,而非测试结果截图。每段说明文字都以英文概括了图表内容。
I wanted to make projects easier to resume across conversations and agents. Before testing whether the next agent could pick up where the previous one stopped, I checked something more basic: could it actively retrieve memory? 我希望让项目在不同的对话和智能体之间更容易恢复。在测试下一个智能体能否从上一个智能体中断的地方继续工作之前,我先检查了一个更基础的问题:它能主动检索记忆吗?
In the Docker deployment I was investigating, retrieval requests timed out while ordinary conversation continued. That combination was easy to misread. The assistant still answered, and memory content appeared in its context. Neither observation proved that its retrieval tools worked. 在我调查的 Docker 部署中,检索请求超时了,但普通对话仍在继续。这种组合很容易被误读。助手依然在回答,记忆内容也出现在了上下文中。但这两种现象都不能证明其检索工具在正常工作。
A successful conversation validates only part of the system. Chat and tool execution involve different requests. A working conversation showed that the client could communicate with the gateway. It did not establish that the client’s tool execution environment could reach an address supplied inside a tool prompt. 成功的对话只能验证系统的一部分。聊天和工具执行涉及不同的请求。对话正常只能说明客户端可以与网关通信,并不能证明客户端的工具执行环境能够访问工具提示(tool prompt)中提供的地址。
The responsibility split matters: the model chooses a tool; the agent client’s execution environment sends the request. A sensible tool choice can therefore produce a network failure. Debugging the model’s decision alone will not reveal where that request actually went. 责任分工很重要:模型选择工具,而智能体客户端的执行环境发送请求。因此,即使是合理的工具选择也可能导致网络故障。仅调试模型的决策过程,无法揭示请求实际发送到了哪里。
Figure 1: A simplified architecture diagram, rearranged from an existing Archify diagram. The chat connection and client-executed tool requests need separate checks. 图 1:简化架构图,根据现有的 Archify 图表重新整理。聊天连接和客户端执行的工具请求需要分别进行检查。
Memory in context is not proof of retrieval. The proxy has two paths that share configuration and injection machinery but can succeed or fail separately. Passive injection reads memory content or indexes on the server side and includes them in the context. This can include L3 core memory, L2 scenario indexes, persona information, and a skill list. In this deployment, passive injection continued to work. 上下文中的记忆并不等同于检索成功。代理有两个路径,它们共享配置和注入机制,但可以分别成功或失败。被动注入在服务器端读取记忆内容或索引,并将其包含在上下文中。这可能包括 L3 核心记忆、L2 场景索引、角色信息和技能列表。在此部署中,被动注入功能一直正常。
Active retrieval supplies endpoints through tool prompts. The client then requests addresses such as ${base}/memory-bridge/v3 and ${base}/skill-bridge/v3/skill. This depends on the client being able to reach the generated address. That explains how context could contain memory while retrieval failed. The server’s read path worked; the URL handed to the client’s tool executor did not.
主动检索通过工具提示提供端点。客户端随后请求诸如 ${base}/memory-bridge/v3 和 ${base}/skill-bridge/v3/skill 之类的地址。这取决于客户端能否访问生成的地址。这就解释了为什么上下文可以包含记忆,而检索却失败了:服务器的读取路径是通的,但交给客户端工具执行器的 URL 却无法访问。
The failure was also easy to miss in the conversation. Tool requests timed out or produced no HTTP response, recorded as 000. The assistant continued with file reads and local searches, without presenting a visible tool error to the user. I did not measure how much this fallback affected answer quality. 这种失败在对话中也很容易被忽略。工具请求超时或没有产生 HTTP 响应(记录为 000)。助手继续进行文件读取和本地搜索,而没有向用户显示可见的工具错误。我没有衡量这种回退机制对回答质量的影响程度。
Figure 2: Passive injection can supply context even when active retrieval fails. A plausible answer is insufficient evidence that the retrieval path succeeded. 图 2:即使主动检索失败,被动注入仍能提供上下文。合理的回答不足以证明检索路径已成功。
The missing setting was the injected gateway address. Following the failing path led to the URL-generation logic. In the feat/server_team source I checked on September 19, 2026, injection.externalGatewayUrl takes precedence when configured. If it is absent and the configured host is 0.0.0.0 or 127.0.0.1, the fallback selects the first non-internal IPv4 address and builds an http://<host>:<port> base URL. It also emits a warning.
缺失的设置是注入的网关地址。追踪失败路径指向了 URL 生成逻辑。在我于 2026 年 9 月 19 日检查的 feat/server_team 源码中,如果配置了 injection.externalGatewayUrl,它将具有最高优先级。如果该项缺失且配置的主机为 0.0.0.0 或 127.0.0.1,回退机制会选择第一个非内部 IPv4 地址并构建 http://<host>:<port> 基础 URL,同时发出警告。
My Docker deployment had taken that fallback. The selected address belonged to the deployment’s container network, while the client’s tool execution environment was outside that network. Retrieval requests consequently timed out or received no HTTP response. 我的 Docker 部署采用了该回退方案。所选地址属于部署的容器网络,而客户端的工具执行环境位于该网络之外。因此,检索请求超时或未收到 HTTP 响应。
The missing piece was an existing configuration field. The source already documented explicit configuration for multi-node deployments; this was a deployment mistake, not a newly discovered upstream vulnerability. 缺失的部分是一个现有的配置字段。源码中已经记录了针对多节点部署的明确配置;这是一个部署错误,而非新发现的上游漏洞。
Two useful starting points are the startup warning and the address actually injected into the tool prompt. Comparing that address with the client’s gateway configuration can expose a discrepancy. A discrepancy still needs investigation: different addresses may be intentional, so test from the environment that executes the tool. 两个有用的切入点是启动警告和实际注入工具提示的地址。将该地址与客户端的网关配置进行比较,可以发现差异。差异仍需调查:不同的地址可能是刻意为之,因此请务必从执行工具的环境中进行测试。
Interpret the probe before changing configuration. Two probe results deserve careful reading: 401 means an HTTP service responded and requires authentication. It does not demonstrate a successful memory operation, or establish by itself that this is the intended service. 000 means the probe received no HTTP response. It is not an HTTP status code identifying one cause. Timeouts, DNS resolution, and routing still need examination. 在更改配置之前,请先解读探测结果。两个探测结果值得仔细研读:401 表示 HTTP 服务已响应但需要身份验证,这并不证明记忆操作成功,也不能单独证明这就是预期的服务。000 表示探测未收到 HTTP 响应,它不是标识单一原因的 HTTP 状态码,超时、DNS 解析和路由问题仍需检查。
For the gateway, the proposed configuration change is straightforward: 对于网关,建议的配置更改很简单:
injection:
externalGatewayUrl: "https://gateway.example.com"
The domain above is a placeholder. The real entry point must be reachable from the tool execution environment, and the reverse proxy must forward the relevant bridge paths. The source handles a trailing slash; reachability and routing are the consequential checks. I also need to change the persistent configuration source. Editing a file regenerated by a startup script would make the correction disappear on the next run. 上面的域名是一个占位符。真正的入口点必须能从工具执行环境访问,且反向代理必须转发相关的桥接路径。源码会处理末尾的斜杠;可达性和路由是后续需要检查的关键。我还必须更改持久化配置源。如果编辑一个由启动脚本重新生成的文件,修正内容会在下次运行时消失。
Knowledge resources have their own URLs. Another failure in the same investigation had a separate cause. Tools for resources such as a wiki or code graph use URLs stored when those resources are registered. The injector copies those resource URLs. Changing externalGatewayUrl does not update independently registered knowledge-resource addresses. Each one needs its own check.
知识资源有其各自的 URL。在同一调查中,另一个失败有其独立的原因。用于维基或代码图谱等资源的工具,使用的是注册这些资源时存储的 URL。注入器会复制这些资源 URL。更改 externalGatewayUrl 不会更新独立注册的知识资源地址。每一个都需要单独检查。
The example in my notes used host.docker.internal. That name is a Docker Desktop convention; in a Linux environment without corresponding configuration, it may not resolve. The useful question is whether the name resolves and connects from this particular tool execution environment. These failures pointed to injected addresses and name resolution. They did not establish that memory storage was damaged.
我笔记中的示例使用了 host.docker.internal。该名称是 Docker Desktop 的约定;在没有相应配置的 Linux 环境中,它可能无法解析。有用的问题是,该名称能否从这个特定的工具执行环境中解析并连接。这些失败指向了注入地址和名称解析问题,它们并不能证明记忆存储已损坏。
Figure 3: Memory and skill bridge addresses use the gateway base URL. Knowledge tools use their individually registered resource URLs. Fixing one source does not fix the other. 图 3:记忆和技能桥接地址使用网关基础 URL。知识工具使用其各自注册的资源 URL。修复其中一个源并不能修复另一个。
The verification I still need to finish: I have the diagnosis and a proposed correction. The post-fix checks are still pending. My next steps… 我仍需完成的验证:我已经有了诊断结果和建议的修正方案。修复后的检查尚待进行。我的下一步计划……