agent-memory 排障指南:日志定位、按症状分流与错误码体系详解
人工智能AI AgentAgent 记忆RAGMCP 服务【免费下载链接】agent-memoryMemory 是一款面向 AI 智能体的长期记忆模块为运行在 openJiuwen 框架上的智能体提供记忆提取、存储、检索与迁移能力。项目地址https://gitcode.com/openJiuwen/agent-memory点击查看免费下载本文基于 agent-memory 仓库官方 FAQ 文档docs/en/FAQ/README.md与对应源码实现系统讲解该记忆服务的故障定位方法论先确认日志落点再按 HTTP 响应体做症状分诊进入五大典型场景服务不可用、请求报错、写入成功但召回为空、召回结果异常、请求缓慢逐步排查并附完整的异常类到 HTTP 状态码映射表与错误消息脱敏规则。读完你可以掌握一套可落地的运维排障路径并理解 agent-memory 双层错误体系与索引构建静默降级这类关键设计背后的取舍。1. 排障总路线定位 → 分诊 → 场景agent-memory 的官方排障文档将故障定位定义为一个问题定位指南problem-locating guide核心路径是三步走确认日志在哪里Confirm Where the Logs Are按症状分诊Triage by Symptom——第一次分诊的依据是HTTP 响应体大多数问题读完响应就答了一半进入匹配的场景按步骤逐层推进。安装、Docker 部署与通用配置问题不在本指南范围内请参见 容器化部署文档 与 SDK 部署文档。文档给出的场景分流结构如下Problem occurs │ ├─ Service wont start / requests cant get through ───→ 场景 1 ├─ Request gets a response, but returns an error ──────→ 场景 2 ├─ Write returns oktrue, but search recall is empty ──→ 场景 3最高频 ├─ Recall works, but results are wrong (missing/biased/extra/stale) → 场景 4 └─ Requests go through, but slowly ────────────────────→ 场景 52. 第一步确认日志在哪里2.1 引擎日志的落盘配置引擎日志默认只写终端要持久化到磁盘需在config.yml中配置memory_api.globals段memory_api: globals: log_file: /var/log/agent-memory/engine.log # 文件路径不配置则仅输出到终端 log_level: INFO # 默认INFO从源码结构看jiuwen_memory/common/log/base.py日志参数log_level/log_format/log_datefmt/log_file写在跨切面配置中沿配置树父链回退读取None时用默认值INFO 级别 标准格式。Handler 策略与文档描述一致log_file为空仅挂载StreamHandler终端 stderr 输出log_file非空StreamHandlerFileHandler终端与文件双写并自动创建日志文件所在目录。2.2 按运行形态定位日志运行形态引擎日志位置Dockerdocker compose logs -f agent-memory终端流容器内的log_file路径若已配置本地 HTTP 服务启动终端log_file路径若已配置CLI控制台log_file路径若已配置SDK进程内引擎日志不会传播到宿主根 logger宿主需直接读取agent_memory.*日志子树或自行调用setup_logging2.3 两个需要建立的预期HTTP / CLI 入口正常时不做逐请求日志内部失败只记录脱敏后的request_id与异常类型请求成功/失败信息全部在 HTTP 响应体中响应同时提供request_id和X-Request-ID头用于与审计记录、下游日志做关联。日志名自带模块前缀如agent_memory.construction.index_builder_impl.vector_index_builder可按前缀过滤区分层次。2.4 如何在海量日志中定位我的那次请求HTTP 请求带有服务端生成的 request id横跨响应与审计记录引擎日志则主要依赖两个业务标识scopeorg/space/user/session——Engine.write .../Recaller ...等行都携带 scope按它过滤即可圈定该租户/会话的日志段unit id 的前 8 位——VectorIndexBuilder的 WARN 行携带该前缀可以把 add 响应里的item_id直接映射到具体记忆单元。3. 第二步按症状分诊——先读 HTTP 响应体3.1 响应体关键字段字段含义oktrue表示请求管线本身跑完了error/message失败时的异常类名与原因类名对照第 9 节附录 A映射item_idadd 成功时返回的记忆 id为null且带skipped时见下行skipped仅 add 出现infertrue时所有派生记忆都被去重判为 update/noop——这是正常语义不是失败trajectorysearch 携带trace: true时返回的检索轨迹见场景 3 步骤②决策优先级error非空即失败进场景 2oktrue只表示请求管线成功不保证记忆可被召回索引构建失败会静默降级进场景 3。3.2 错误响应的统一契约错误响应统一包含error、message、request_id、retryable四个字段并在X-Request-ID头返回同一 request id。400/策略类错误的 message 经过脱敏401/403/404/409/429/500/503 使用固定的泛化文案HTTP 响应永不包含 traceback 或回显凭据。这一契约在源码中由一张稳定映射表实现见 jiuwen_memory_entry/core/error_response.py_HTTP_ERROR_POLICIES { ValidationError: (400, False, None), AuthenticationError: (401, False, authentication failed), PermissionDeniedError: (403, False, permission denied), NotFoundError: (404, False, resource not found), UnknownVerb: (404, False, resource not found), ConflictError: (409, False, resource conflict), PartialFailureError: (409, False, None), RateLimitedError: (429, True, too many requests), PayloadTooLarge: (413, False, request body is too large), BackendError: (503, True, service temporarily unavailable), HealthCheckError: (503, True, service temporarily unavailable), InternalError: (500, False, internal server error), # ... }其中第三项为fixed_message非None时对外只给固定泛化文案即固定通用文本的来源为None时 400 类错误才使用经safe_error_message脱敏后的真实消息。PartialFailureError额外保留completed/failed/retry_action三个字段429 响应附带Retry-After: 1。4. 场景 1服务不可达 / 起不来① 存活探针curl http://localhost:8137/healthz只确认服务进程本身活着健康响应为 200{status: ok, profile: ...}它不探测后端——Redis/ES/Milvus 挂掉时 healthz 仍返回 200。后端不可用的表现是真实请求以BackendError失败进场景 2或容器不健康见 ②。② 检查容器状态docker compose ps找 unhealthy / 重启循环的容器。③ 按服务查日志docker compose logs service。应用容器看启动阶段的启动异常后端容器Redis/ES/Milvus看它们自身的错误端口冲突、挂载路径、内存溢出是常见原因。④ 服务起来了但请求返回 404{error: UnknownVerb}→ verb 拼写错误对照路由表检查add / batch_add / search / list / get / update / delete / evolve / ...。5. 场景 2请求直接失败① 读状态码与异常类名按下表分诊异常类出错层下一步ValidationError请求参数校验对照message自查参数metadata 拆分为系统/用户段、k非正整数、缺参数无需查日志NotFoundError/ConflictError/PermissionDeniedErrorAPI 层语义校验id 不存在 / 重复创建 / scope 未授权按message处理InvalidExtractionJSONErrorLLM 抽取在日志中搜Extractor含LLM response is not valid JSON的 WARN确认 LLM 端点可达、响应未被截断LockError/LockTimeoutError/LockLostError分布式锁多实例并发写同一 scope 的锁竞争检查 Redis 锁配置与实例数量BackendError存储层后端网络/IO 失败转场景 1 的 ②③ 逐服务查容器日志PayloadTooLargeHTTP 入口请求体超过服务端限制压缩或拆分请求StorageRetrievalError召回层关键词 向量通道同时失败分别排查 Milvus / ESUnsupportedStorageCapabilityError装配配置配置中移除了某后端但算子仍引用其能力检查配置-算子一致性InternalError内部 bug响应只含internal server error用request_id关联服务端失败记录与审计事件完整状态码映射见第 9 节。其中PayloadTooLarge的产生路径在源码中可直接确认jiuwen_memory_entry/http_server/main.py 在读取请求前先用Content-Length与max_body_bytes比较超限直接返回 413不消费请求体。② 按 scope 过滤引擎日志见第 2 节定位该请求的日志段。③ 沿调用链下钻各层日志前缀与含义POST /v1/verb → HTTP 入口verb 分发 参数校验不打日志ValidationError 在此抛出 → API 层鉴权与参数组装不打日志 → Engine日志前缀 Engine.write 按 infer/procedural/middle 分发 ├─ 写入 → 抽取与索引 │ ├─ Extractor前缀 Extractor:LLM 抽取与重试 │ └─ IndexBuilder前缀 Forward/Fulltext/Vector/HybridIndexBuilder: │ embedding 与向量写入失败在此静默降级为 WARN └─ 召回 ├─ Recaller前缀 KeywordRecaller: / VectorRecaller:带 hits/units 计数 └─ Retriever / Fuser多通道融合部分通道失败返回 ChannelError → 存储层后端 IO 失败抛 BackendErrorscope 隔离在此强制执行6. 场景 3写入成功但召回为空最高频oktrue≠ 记忆可召回。写入链路上embedding 与向量写入失败只记 WARN 然后跳过——HTTP 仍返回oktrue。这个静默降级在源码中可以直接看到jiuwen_memory/construction/index_builder_impl/_index_ops.pyvectors embedder.embed([c.text for c in chunks]) # 失败时 logger.warning( index_ops: Embedder.embed failed for unit %s: error_type%s, unit.id[:8], type(exc).__name__, )以及向量写入失败时同样只记 WARNVectorStore.insert failed for scope ...随后尝试 update 兜底。按以下顺序排查6.1 ① 查写入时刻的引擎日志确认索引是否真的构建了日志行含义Engine.write inferTrue: N originals, M derived added, scope...infer 抽取路径完成M 为派生条数ForwardIndexBuilder: building forward index for N units记忆本体正排 KV已写入缺它则 get/list 都查不到VectorIndexBuilder: building index for N units向量索引开始构建FulltextIndexBuilder: building index for N units全文索引构建WARNVectorIndexBuilder: Embedder.embed failed for unit ...嵌入失败该单元向量索引缺失——关键词能召回、向量召不回的直接根因WARNVectorIndexBuilder: VectorStore.insert failed for scope ...Milvus 写入失败向量索引整体缺失Extractor: received N units, M accepted after preprocessingLLM 抽取入口M0 说明预处理全部拒收命中 WARN 的处理Embedder.embed failed/VectorStore.insert failed→ 已发生静默降级修复嵌入端点 / Milvus 后重写该批记忆。本体正排索引不受影响——get/list仍可查到Extractor的重试类 WARN → 内部先重试达到阈值才上抛错误只有最终失败才算写入失败。6.2 ② search 带trace: true分通道二分响应的trajectory数组按步骤携带stage/channel/candidate_count/cost_ms哪一步哪个通道归零一目了然关键词通道candidate_count0而向量通道为 0 → embedding 问题回 ① 查降级 WARN两通道都为 0 → scope 不匹配或后端故障转 ③ / 场景 1也可以在日志中搜KeywordRecaller:/VectorRecaller:的hitsN unitsN行交叉验证各通道命中数。检索轨迹能力在 API 层对应with_trajectory参数定义见 jiuwen_memory/api/memory_api.pyHTTP 侧即 search 请求中的trace: true。6.3 ③ 核对 scope 一致性写入与查询使用的 scopeorg/space/user/session必须完全一致——scope 是隔离轴跨 scope 查询查不到是设计行为不是数据丢失。6.4 ④ as-of 时间旅行查询确认单元的t_valid已正确设置缺少t_valid的单元会被 as-of 查询跳过或排序错乱。7. 场景 4召回结果不符合预期① 召回 metadata 为空SDKrecall()需要输出 metadata 时必须显式传output_fields[metadata]否则返回为空。② metadata 过滤不生效过滤键必须带user_metadata.前缀裸键名匹配不到任何东西。③ 不该出现的旧记忆出现了双时相bitemporal模型下as-of 查询按t_valid回卷历史版本——这是正常语义若单元缺少t_valid则会出现错误回卷转场景 3 的 ④。④ 结果偏科/缺失search 加trace: true查看各通道candidate_count见场景 3 ②区分是单通道质量问题还是融合问题。8. 场景 5请求缓慢症状诊断首个请求慢秒级正常现象本地模式下 bge 嵌入模型在加载之后常驻内存写入慢infertrueLLM 抽取路径是成本大头搜日志中的Extractor:查看 LLM 端点延迟与重试次数召回慢tracetrue的trajectory中每步cost_ms可定位昂贵阶段向量通道慢先查 Milvus 加载状态间歇性慢后端资源竞争用docker stats查看容器资源水位9. 附录错误码体系双层结构agent-memory 的错误体系是双层结构区别于数值错误码异常层12 个异常类基类AgentMemoryError 11 个子类另有锁异常族与抽取异常族——SDK 调用方可以跨后端、跨层使用同一套异常层次HTTP 层HTTP 入口统一转换为状态码响应体含error、message、request_id、retryable同一 request id 经X-Request-ID头返回。异常层定义见 jiuwen_memory/common/errors.py所有异常继承AgentMemoryError命名避开 Python 内置MemoryError调用方可用它一把兜底。9.1 异常类 ↔ HTTP 状态码对照表映射规则HTTP 边缘按下表做稳定翻译非 HTTP 的旧版分发保持既有兼容语义。异常类HTTP语义典型原因NotFoundError404目标实体/记录/键不存在get/update/inspect/trace 的 id 不存在scope 为空MethodNotAllowed405不支持的 HTTP 方法只使用已注册的 POST/GET 端点PermissionDeniedError403actor 无权对目标 scope 执行该动作策略未授权该 actor/action/scope 组合ConflictError409与现有记录冲突insert 时 id 已存在空间名重复PartialFailureError409批量操作部分成功按retry_action重试failed项响应保留completed/failed/retry_actionValidationError400输入非法或越界metadata 含非标量值dict/listk非正整数缺参数UnsupportedCapabilityError400组件不支持请求的能力请求的模态或路由能力未配置PolicyError400运行时策略操作被拒未知策略键尝试修改不可变配置AuthenticationError401凭据缺失/格式非法/校验失败API key 错误或缺失对外消息固定为authentication failedRateLimitedError429超出速率上限发生在认证之前限流桶耗尽retryabletrueRetry-After: 1HealthCheckError503组件健康检查失败Redis/ES/Milvus/embedder 组件 health() 探测失败retryabletrueBackendError503底层存储意外失败后端网络/IO 失败retryabletruePayloadTooLarge413请求体超过配置上限压缩或拆分请求retryablefalseUnsupportedStorageCapabilityError400Storage 未声明请求的端口能力配置中移除后端但算子仍引用其能力StorageRetrievalError400所有选中的召回入口均失败关键词 向量通道同时失败未预期异常500{error: InternalError, message: internal server error}内部 bug用request_id关联服务端失败记录与审计事件未知 verb404{error: UnknownVerb}。值得注意的设计取舍源码注释可佐证AuthenticationError401不知道你是谁与PermissionDeniedError403知道你是谁但不许做必须可分否则 HTTP 层无法映射正确状态码、调用方也无法区分该带凭据与该申请授权同理RateLimitedError429必须与 401 可分因为限流发生在认证之前。两者的对外消息都刻意笼统具体原因只写入审计事件避免成为主体枚举或限流参数反推的侧信道。9.2 写入路径特有错误异常触发点含义InvalidExtractionJSONError/InvalidExtractionCandidateErrorLLM 抽取LLM 抽取输出不是合法 JSON / 候选结构非法内部重试仅在最终失败时上抛HTTP 映射为 500LockError/LockTimeoutError/LockLostError分布式锁多实例并发写同一 scope 时的锁竞争 / 租约过期9.3 错误消息脱敏Error Message Redactionsafe_error_message对异常文本做脱敏后截断至 200 字符。其实现见 jiuwen_memory/common/errors.pydef safe_error_message(exc: Exception, *, limit: int 200) - str: 规范化并脱敏可进入日志或结构化错误的异常文本。 text .join(str(exc).split()) text _ERROR_CREDENTIAL_RE.sub(//redacted:redacted, text) text _ERROR_AUTH_HEADER_RE.sub(lambda match: f{match.group(1)}redacted, text) text _ERROR_AUTH_VALUE_RE.sub(lambda match: f{match.group(1)}redacted, text) text _ERROR_SECRET_RE.sub(lambda match: f{match.group(1)}redacted, text) return text[:limit]具体替换规则password / passwd / pwd / token / api_key / secret的键值 →redactedAuthorization: Bearer/Basic ...头 → 凭证部分替换为redactedURL 内嵌凭据//user:pass→//redacted:redacted。HTTP 400/策略类错误使用该 helper401/403/404/409/429/500/503 使用固定泛化文案。HTTP 响应永远不包含 traceback用响应中的request_id去定位服务端日志与审计记录。10. 小结排障时的三个关键判断healthz 200 不代表后端健康——它只是进程存活探针Redis/ES/Milvus 故障要靠真实请求的BackendError或容器状态暴露oktrue不代表记忆可召回——embedding/向量写入失败会静默降级为 WARN排查写入成功却召不回必须先看写入时刻的VectorIndexBuilderWARN 行再用trace: true分通道二分skipped不是错误——infertrue时派生记忆全部被去重判为 update/noop 属正常语义而 429/503 的retryabletrue才是可安全重试的信号。按响应体先于日志、scope 先于全量过滤、WARN 日志先于猜测的顺序推进绝大多数 agent-memory 运行时问题都能在场景 15 的路径内收敛定位。赞分享人工智能AI AgentAgent 记忆RAGMCP 服务【免费下载链接】agent-memoryMemory 是一款面向 AI 智能体的长期记忆模块为运行在 openJiuwen 框架上的智能体提供记忆提取、存储、检索与迁移能力。项目地址https://gitcode.com/openJiuwen/agent-memory点击查看免费下载相关推荐openJiuwen DeepSearch 运维排障实战日志体系、错误码定位与常见故障修复指南openJiuwen DeepSearch 运维排障实战日志体系、错误码定位与常见故障修复指南 openJiuwen DeepSearch 是一个知识增强的深人工智能大模型AI AgentRAG深度研究搜索引擎后端代码智能体终极终端故障排查指南xterm.js错误日志分析与问题定位全攻略终极终端故障排查指南xterm.js错误日志分析与问题定位全攻略 xterm.js 是一款功能强大的 Web 终端库让开发者能够在浏览器中构建高效的终端界面前端UI组件3分钟定位doccano故障日志分析与排错指南3分钟定位doccano故障日志分析与排错指南 你是否曾在使用doccano进行数据标注时遇到过文件导入失败、任务卡死或界面无响应的情况作为一款开源的机器学数据标注后端前端创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考