echo-agent 前身为 2025 年 11 月启动的个人助理项目 fubot,最初面向长期陪伴型个人智能体,围绕认知记忆、上下文延续、用户偏好沉淀、任务闭环与持续自我优化展开。随着真实场景迭代,项目逐步形成多入口接入、统一事件模型、消息总线、Agent Loop、多模型抽象、工具调用、MCP 接入、任务调度、权限审批、运行轨迹、长期记忆和受控自演进等能力。目前已支持微信、QQ、CLI、Gateway、Webhook、Cron 等入口,服务用户超过 20 万、累计下载超过 50 万,是面向长期运行、记忆增强和可持续成长智能体的开源 Agent Runtime。

项目地址:GitHub - fuyuxiang/echo-agent: Echo Agent 是一个可自托管、长期运行、持续学习的 AI Agent,面向个人与团队的私有自动化场景。它可以部署在自有服务器上,统一连接模型、工具、记忆、权限与消息入口。内置四层认知记忆、遗忘曲线与矛盾检测机制,能够在跨会话任务中持续沉淀上下文,并保持长期记忆的质量。针对命令执行、文件操作等高风险行为,它提供基于 LLM 的审批与解释机制,为关键操作建立可审计、可追溯的安全边界。原生支持 MCP、A2A、多模型路由、任务调度、工具调用和多通道接入,覆盖 CLI、Gateway API、微信、Telegram 等入口。它让 Agent 带着长期记忆和可进化技能,持续、安全地为你工作。 · GitHub

27-cover

线上 Agent 出问题时,最怕听到一句话:“它刚才没回。”

没回是什么意思?请求没进来,还是进来了但被限流?模型慢,还是工具卡住?最终回答生成了,但通道投递失败?如果用户说“它用了不该用的工具”,问题又变成:工具为什么暴露给模型,审批有没有触发,执行上下文是否真的允许?

普通后端排障时,我们通常看日志、错误码、数据库和下游服务。Agent 系统不够。因为一次回答不是一个确定函数的返回值,而是一条由上下文、模型、工具、审批、通道和记忆共同组成的行动链。

本篇只讲一个点:Agent 的可观测性不是多打几行日志,而是把一次行动背后的因果链、组件健康和外部遥测建立起来。

问题入口

如果只看最终文本,很多 Agent 问题会被压扁成同一种现象。

用户觉得“慢”,可能是 ContextStage 在构造长上下文,也可能是模型 provider 降级,也可能是工具调用超时,还可能是 Gateway wait 等到了 504,但后台任务仍在继续。

用户觉得“错”,也不一定是模型生成错。可能是检索片段不对、工具结果没截断、allowed tools 暴露过宽、ApprovalGate 拒绝后没有给出清晰反馈,或者最终回复投递到了错误通道。

这就是 Agent 和普通 Web 服务的差别。

维度普通后端服务Agent 系统
路径代码路径相对确定每轮可能重新规划
依赖数据库、缓存、下游 API模型、工具、记忆、知识库、审批、通道
失败形态错误码、异常、超时系统失败与认知失败并存
排障入口日志和指标通常够用需要 trace、日志、审计、健康和 usage
关键问题哪里慢、哪里错为什么这样行动、是否越界、结果是否送达

会调用工具只说明有行动接口;能否稳定运行,要看每次行动是否能被追踪、解释和复盘。

为了不停留在抽象层面,下面以 echo-agent 的实现为例。它的可观测性由三层组成:本地 trace logging、组件健康检查和 OpenTelemetry 遥测。

Trace

Trace 的核心不是“记录很多事件”,而是给一次处理建立因果结构。

echo-agent 使用 TraceSpan 表示一次处理中的最小观测单元。一个 span 会记录 span_idtrace_idparent_idnamekind、开始时间、结束时间、metadata 和 error。kind 用来区分输入、上下文、模型调用、工具调用、输出等阶段;metadata 保存模型名、provider、路由原因、finish reason、工具成功状态等业务信息。

真正关键的是 trace_id。同一次用户请求里的多个 span 共享同一个 trace_id,工程师才能按一条链路去看,而不是在日志里搜索零散关键词。

27-trace因果链

一次复杂请求可能被拆成这样的序列:

 

llm_0 -> tool_0_0 -> tool_0_1 -> llm_1 -> tool_1_0 -> llm_2

这条链路比“模型调用成功”“工具调用成功”更有价值。因为它告诉你:模型先做了什么判断,调了哪些工具,工具后是否再次进入模型,最终在哪一步结束。

举个工程场景:用户说“帮我修复测试失败”。最终回答只会告诉你“已修复”或“修复失败”,但 trace 应该能看到更细的链路:上下文阶段读到了哪些测试日志,第一次模型调用选择了哪个修复策略,工具阶段是否读取了文件、运行了测试、修改了代码,第二次模型调用是否根据新的报错调整方案,最后输出是否带着验证结果返回。

如果这次任务失败,trace 还能把失败拆开。是模型没有看到关键日志,还是工具执行超时;是测试命令失败,还是文件写入被权限策略阻断;是 Agent 已经生成最终回答,但通道投递失败。没有这条链,工程师只能复现;有了这条链,工程师可以定位。

最小实现并不复杂:

 

span = tracer.start_span(
    trace_id,
    name=f"llm_{iteration}",
    kind="llm_call",
    parent_id=current_parent,
)
try:
    response = await provider.chat(messages, tools=active_tools)
    tracer.end_span(span, metadata={
        "model": route_decision.model,
        "provider": route_decision.provider_name,
        "route_reason": route_decision.reason,
        "finish": response.finish_reason,
    })
except Exception as exc:
    tracer.end_span(span, error=str(exc))
    raise

工具调用也一样。执行前创建 tool_call span,执行后记录 success;如果被审批拒绝,也要结束 span 并标记 denied。否则排障时只能看到“工具没执行”,却不知道是模型没选、权限不允许、审批拒绝,还是执行器失败。

echo-agent 的 TraceLogger 负责创建、结束、查询和落盘 trace。get_trace(trace_id) 可以查看内存 span 列表;flush_trace(trace_id) 会把 span 序列化为 trace_{trace_id}.json。这对本地调试很重要,尤其是在没有外部 OTel 后端时。

三层观测

Trace 解决单次请求的链路问题,但生产环境还需要回答另外两个问题:系统当前是否健康,这些观测数据能否进入团队已有监控体系。

echo-agent 的三层结构可以这样理解:

27-三层观测

第一层是本地 trace。它面向开发和排障,不依赖外部系统。只要有 TraceLogger,一次模型调用、工具调用、输出投递就能被串起来。

第二层是健康检查。HealthChecker 监控 bus、agent、storage 等组件。组件状态包括 HEALTHYDEGRADEDUNHEALTHYUNKNOWN。注册检查时可以提供 check_fn 和可选的 recovery_fn;后台 loop 会按 interval 调用 check_all(),组件 unhealthy 且有恢复函数时尝试恢复。

它的汇总规则很硬:只要有 UNHEALTHY,overall 就是 unhealthy;否则只要有 DEGRADED,overall 就是 degraded;都没有才是 healthy。

Gateway 还有自己的健康视图。它面向 HTTP/WebSocket 入口:服务是否运行、是否有活跃通道、限流 bucket 状态、媒体缓存大小、活跃 session 数量、hook 数量和 delivery rule 数量。如果 Gateway 没运行,状态是 unhealthy;如果运行但没有活跃通道,状态是 degraded。

健康检查也要分层看。进程还在,只能说明系统存活;模型 provider、存储、消息总线和通道可用,才说明系统具备基础能力;工具权限、审批配置、Gateway 鉴权和日志脱敏符合部署要求,才更接近可信。echo-agent 当前已经覆盖组件状态和 Gateway 入口状态,平台级扩展可以继续把安全姿态、关键工具和代表性任务纳入 health。

这能避免一个常见误判:监控面板显示绿色,但用户仍然无法完成任务。比如 Gateway 进程正常、HTTP 也能返回 200,可是没有活跃通道,或者模型 provider 正在 cooldown,或者高风险工具全部被策略阻断。Agent 的健康不是一个灯,而是一组能力边界。

第三层是 OpenTelemetry。TelemetryManager 管理 OTel providers 和 exporters。安装了 OTel 时,它会创建包含 service.name 的 Resource,设置 tracer provider;配置了 otel_endpoint 时尝试使用 OTLP gRPC exporter,否则使用 console exporter。没有安装 OTel 时,系统优雅降级,遥测关闭但 Agent 仍可运行。

这个取舍很重要。可观测性应该增强系统,而不是成为新的硬依赖。

遥测与成本

OTel 的价值在于把本地事实接入外部观测系统。

echo-agent 在 observability/spans.py 里提供 GenAI span helper:start_llm_span() 记录模型调用,设置 gen_ai.systemgen_ai.request.modelgen_ai.operation.name 等属性;record_llm_usage() 记录 gen_ai.usage.input_tokensgen_ai.usage.output_tokens、cache read 和 cache creation token;start_tool_span() 记录工具名;start_agent_span() 记录 agent iteration 和 strategy。

这些 helper 在 tracer 为 None 或 OTel 不可用时都是 no-op。这让测试和轻量部署更简单:不用为了跑一个 Agent 就先搭整套观测后端。

usage 不是账单附属品,而是成本观测入口。Agent 引入记忆、知识库和技能后,上下文很容易膨胀。没有 usage,成本问题通常要到月底账单才暴露。

一个可用的 usage 视角至少要能回答:

问题观测字段
输入是否过大input tokens、上下文阶段耗时
输出是否异常output tokens、finish reason
缓存是否有效cache read / creation tokens
模型是否经济provider/model 维度成本与成功率
任务是否失控单次 trace 的迭代次数和工具调用次数

单点指标只能告诉你“慢了”或“贵了”,trace 才能告诉你为什么慢、为什么贵。

日志与审计

可观测性不是只有 trace。

echo-agent 使用 loguru 记录运行日志:MCP 连接失败和重试、模型 provider 降级和 cooldown、工具 circuit breaker、ApprovalGate 拒绝、Channel start/stop、Gateway auth audit、多 Agent delegation audit、调度器 job 错误等。

但日志、trace 和 audit 的职责不同。

类型适合记录不适合替代
日志离散事件、异常、重试、模块状态一次请求的结构化因果链
Tracespan 链路、耗时、模型与工具阶段安全审计和长期决策事实
Audit认证、审批、委派、越权尝试性能分析和阶段耗时

多 Agent 委派写 JSONL audit,记录任务摘要、worker 状态、迭代次数和耗时。Gateway auth 写 audit.jsonl,记录认证成功或失败。这些事实和 trace 一起,才能让系统既可调试,又可审计。

负例也要被观测。审批拒绝、工具被阻断、模型格式错误、知识库无结果、Gateway wait 超时,都不应该简单归为 error。它们语义不同,修复路径也不同。一次危险命令被拒绝,可能说明安全系统正常工作;频繁被拒绝,可能说明工具描述诱导模型走错路。

隐私边界

Agent 的观测数据往往比普通服务日志更敏感。它可能包含用户输入、文件路径、工具参数、知识库片段、模型输出、错误栈、审批原因和凭证名称。

所以生产系统不能把“记录越多越好”当原则。

27-隐私边界

echo-agent 这一章给出的边界很明确:trace metadata 尽量记录 ID、状态、模型、耗时和错误摘要,而不是完整敏感内容;工具参数里的 token、password、secret 要在记录前脱敏;Gateway auth audit 不应记录 API token 明文;模型输出日志应可配置,默认避免记录大段用户内容;OTel exporter 发到外部系统前,要确认数据合规。

这背后是一个工程判断:可观测性的目标是调试系统,不是复制用户会话数据库。

更成熟的部署可以按环境提供不同 profile:开发模式更详细,生产模式更脱敏,公共 Gateway 模式更保守。低敏指标可以长期聚合,高敏原文应该短期保留、加密或只在授权诊断包中出现。

排障路径

观测系统最终要服务行动。指标如果不能驱动策略调整,就只是仪表盘。

下面这些排障路径,比“先看日志”更接近 Agent 的真实问题结构。

用户反馈优先检查
没有回复inbound event 是否进入 bus、session 是否限流、Agent Loop 是否运行、outbound 是否发布、channel 是否发送失败
回复很慢ContextStage 耗时、模型调用耗时、provider fallback、工具超时、重复工具调用
用了不该用的工具active tool list、InferenceController allowed/blocked、ApprovalGate、ToolExecutionContext allowed_tools、工具执行日志
Gateway wait 超时pending_http 是否创建、inbound 是否被 bus 接收、final outbound 是否带 correlation id、是否被 handler drop、Agent 是否仍在后台执行

生产级 Agent 的可观测性,可以用几条硬标准判断。

检查项合格标准
Trace每次请求有 trace_id,LLM/tool/output 有 span
工具工具调用成功、失败、拒绝、超时可区分
健康组件健康和 Gateway 入口健康分层暴露
遥测OTel 可接入外部系统,不可用时 no-op 降级
Usagetoken、缓存命中、provider/model 维度可分析
审计认证、审批、委派等安全事实可追踪
隐私参数脱敏、导出可控、保留期限和权限清晰
回归高价值 trace 能脱敏转成评估样本

最后一条连接到下一篇。Trace 记录一次运行发生了什么,评估判断系统做得好不好。真实 trace 是评估样本的来源:失败、用户纠正、高风险审批、复杂工具链和长任务恢复,都会暴露系统边界。把它们脱敏后进入评估集,Agent 才能从“出了问题再排查”走向“同类问题不再复发”。

小结

Agent 自己需要记忆,工程师也需要系统记忆。

日志、trace、health check、metrics 和 audit,就是工程师理解 Agent 行为的记忆系统。没有它们,失败会被简化成“模型没答好”;有了它们,团队才能追问上下文怎么来的、模型为什么这样路由、工具为什么被调用、审批为什么通过或拒绝、最终回答是否成功投递。

echo-agent 当前的做法是:用 TraceLogger 记录单次处理链路,用 HealthChecker 和 Gateway health 暴露组件与入口状态,用 TelemetryManager 和 GenAI span helper 接入 OTel,同时通过日志和 audit 保留关键运行事实。

这套系统的价值不在于仪表盘好看,而在于让 Agent 的认知和行动都能被工程化理解。可观测性不是事后装饰,它是生产级 Agent 的基础设施。

(全篇完)


本文为 echo-agent 设计笔记系列第 27 篇。项目源码已开源至 GitHub。如果你对工业级 Agent 的工程落地感兴趣,欢迎加入技术交流群参与日常讨论。下一篇我们将探讨 《Agent 评估体系:从单次回答到质量回归》,敬请期待。

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐