人工智能AI AgentAgent 记忆RAG【免费下载链接】EverOSOne portable memory layer for every AI agent: local-first, Markdown-native, user-owned, and self-evolving across apps, tools, and workflows.项目地址https://gitcode.com/gh_mirrors/ev/EverOS点击查看免费下载本文是 EverOS 项目的《Logging observability rule》工程规范的完整实战解读。EverOS 是一个 local-first、Markdown-native 的 AI Agent 记忆层其可观测性体系围绕structlog 结构化日志 Prometheus 指标 可选 OpenTelemetry 追踪三层展开。读完本文你将掌握在 EverOS 代码库中正确使用日志、指标与追踪 API 的全部约定——包括事件命名、级别语义、隐私边界capture_content、脱敏与截断、token 用量上报set_generation_usage以及 request_id 与 trace_id 的协作关系并理解这些规则在源码层面的落地实现可直接指导你在该仓库中的二次开发与排障。一、规则总览三层可观测性分工EverOS 的可观测性由三个彼此独立、又可协作的模块构成全部集中在 src/everos/core/observability 目录下层模块用途默认状态日志logging事件与生命周期记录structlog默认开启指标metrics计数、直方图、仪表Prometheus 风格默认开启追踪tracing分布式 Span 与 token 用量OpenTelemetry / Langfuse默认关闭可选[otel]extra规则的核心精神只有一句话可观测性 API 对调用方零负担。追踪在配置开启前是 no-op调用点无需根据配置分支日志统一走项目 logger指标统一走 registry 助手。规范原文位于 .claude/rules/logging-observability.md本文逐条展开并结合源码佐证。二、统一日志入口永远使用项目 logger规则第一条使用项目 logger绝不使用print或直接使用 stdlibloggingfrom everos.core.observability.logging import get_logger logger get_logger(__name__)该入口由 logging/init.py 从 factory.py 导出。configure_logging(level)在进程启动时调用一次例如 run.py 或 API lifespan 中完成两件事统一渲染格式按 structlog 官方的 Foreign Log Integration 配方用一个ProcessorFormatter同时渲染 EverOS 自身get_logger(...)的输出和第三方库uvicorn、fastapi、httpx、openai 等通过 stdliblogging.getLogger(...)产生的记录把所有历史上前缀不一致的输出INFO:、[warning ]、无前缀折叠为统一的[level] event keyvalue形态见 factory.py 的模块文档。清理根 handler用指向sys.stdout的单一StreamHandler替换根 logger 上已有的 handler。服务端入口还需配合uvicorn.run(..., log_configNone)否则 uvicorn 每次启动都会重新安装自己的 handler 覆盖配置见 factory.py。工厂里还做了一项重要的运行期调优将httpx、httpcore、urllib3三个 HTTP 客户端库的日志级别降为WARNING。原因是它们会对每次成功的请求打一条 INFO一次 LoCoMo 会话可产生上千条淹没 EverOS 自身事件而失败路径已由异常与状态码暴露无需靠这些噪音排查见 factory.py。注意LanceDB / Lance / Arrow 的 Rust 侧 logger 走 Rustlogcrate直接输出到 stderr不经过 Python需用RUST_LOG环境变量控制其级别见 factory.py。三、结构化日志事件名在前字段用 kwargs规则第二条结构化日志structlog上下文用关键字字段传递不要拼 f-stringlogger.info(memory.search.completed, owner_typeowner, n_resultslen(items))约束拆解如下事件名放在第一位置使用点分隔、稳定不变的事件名如memory.search.completed相当于日志的表名便于检索与聚合上下文一律用结构化 kwargsowner_typeowner、n_resultslen(items)会被 structlog 渲染为键值对保持日志可查询queryable禁止 f-string 插值把动态值拼进消息字符串会破坏结构化、且容易把 PII 泄漏进消息文本。从 factory.py 的 processor 链可以看到输出形态merge_contextvars合并 contextvars 中的上下文如 request_id→add_log_level注入级别→TimeStamper(fmtiso)ISO 时间戳→StackInfoRenderer栈信息。最终由ConsoleRenderer渲染成[level] event keyvalue的可读格式。异常渲染也经过了针对 async 栈的调优structlog 默认的RichTracebackFormatter(show_localsTrue, max_frames100, extra_lines3)在一次 soak 测试中曾把单个未处理异常渲染成6423 行日志约 85MB且每次渲染约消耗 290ms 同步 CPU会阻塞事件循环locals 还有泄漏请求 payload 的风险。EverOS 将其收紧为show_localsFalse, max_frames15, extra_lines1——保留栈帧丢弃 locals见 factory.py。四、日志级别语义四种级别的清晰分工规则第四条给出了明确的级别约定这是团队评审代码时的重要标尺级别适用场景示例debug开发者排障细节各 pipeline 中间产物、耗时明细info生命周期里程碑tracing_initialized、启动完成、任务开始/结束warning可恢复的异常遥测导出失败绝不抛给调用方error带栈/上下文的失败异常捕获后带exc_infoTrue记录代码中随处可见对这套语义的落实。例如 provider.py 在追踪初始化时打info级tracing_initialized生命周期里程碑而在[otel]extra 未安装时打warning级observability_enabled_but_otel_not_installed可恢复异常。force_flush/shutdown_tracing的异常路径则统一用logger.warning(..., exc_infoTrue)确保遥测故障永远不会反向破坏业务调用见 provider.py——这是遥测不得影响主流程原则在代码层面的落地。五、指标统一走 Prometheus registry不发明临时计数器规则第三条指标一律通过core.observability.metricsPrometheus 风格走不要自造 ad-hoc 计数器histogram/counter/gauge 都有 registry 助手。该模块从 metrics/init.py 导出from everos.core.observability.metrics import ( Counter, Gauge, Histogram, HistogramBuckets, get_metrics_registry, generate_metrics_response, )除基础类型外还提供带 label 的变体LabeledCounter、LabeledGauge、LabeledHistogram。registry 助手包括get_metrics_registry/set_metrics_registry/reset_metrics_registry测试中用于替换或重置以及generate_metrics_response把当前 registry 渲染为 Prometheus 文本格式。API 层已有对应的 metrics.py 路由对外暴露指标配合 prometheus.py 中间件使用因此业务代码只需创建/累加指标无需关心抓取与导出。六、安全红线日志里绝不出现密钥与敏感内容规则第五条非常明确不要在任何info及以上级别记录 secrets、API keys 或完整记忆内容。这条红线在配置层有双重保障api_key类字段全部声明为SecretStr类型见 settings.py避免在 repr / 序列化时明文泄漏追踪内容捕获默认关闭见下节Span 默认只携带元数据。同时factory.py 的RichTracebackFormatter(show_localsFalse)刻意不打印异常帧的局部变量正是为了防止请求 payload 中的敏感数据随堆栈一起落盘——这条看似性能优化的配置本质上是隐私设计。七、分布式追踪可选、默认关闭、调用点零分支追踪是 EverOS 可观测性的第三层规则说明如下可选依赖OpenTelemetry 属于[otel]extra默认不安装、默认关闭no-op 安全memory_span(...)来自core.observability.tracing会为 Span 打上 Langfuse 的langfuse.*属性但在[observability] enabled之前是no-op——调用点永远不需要根据配置分支token 用量LLM / embedding 的 token 用量通过set_generation_usage挂到当前活跃 Span 上Langfuse 据此计算成本。7.1 配置开关与导出追踪的开关在[observability]配置段见 default.toml[observability] # OpenTelemetry tracing export. Off by default; pure OTLP/HTTP, vendor-neutral # (Langfuse, an OTel Collector, or any OTLP backend). EverOS ships no vendor SDK. # Override via EVEROS_OBSERVABILITY__ENABLED, EVEROS_OBSERVABILITY__ENDPOINT, etc. enabled false exporter otlp_http # otlp_http | none endpoint # e.g. https://us.cloud.langfuse.com/api/public/otel/v1/traces service_name everos sample_rate 1.0 # 0.0 to 1.0 # Privacy: false (default) metadata only; true also emits query / extracted # memory / .md paths as span input/output (redacted truncated). capture_content false对应的 Pydantic 模型为 ObservabilitySettings完整字段如下字段默认值说明enabledfalse总开关exporterotlp_httpotlp_http|noneendpointOTLP/HTTP 导出地址如 Langfuse 的/api/public/otel/v1/tracesheaders{}自定义导出头service_nameeverosOTel Resource 的service.namesample_rate1.0采样率0.0–1.0经ParentBased(TraceIdRatioBased(...))采样capture_contentfalse是否捕获请求/响应内容脱敏截断langfuse_public_key/langfuse_secret_key/langfuse_host空Langfuse 便捷凭据secret 不随仓库下发需在 everos.toml 或环境变量中配置emit_recall_scorestrue是否向 Langfuse 推送召回质量分数recall_hit_threshold0.6hit 阈值仅对校准类方法有意义所有字段均可用EVEROS_OBSERVABILITY__KEY环境变量覆盖如EVEROS_OBSERVABILITY__ENABLEDtrue。导出链路是纯 OpenTelemetry、厂商中立的init_tracing构建TracerProviderResource 带service.nameservice.version默认挂BatchSpanProcessorOTLPSpanExporter见 provider.py。一个贴心设计是当langfuse_public_key/langfuse_secret_key/langfuse_host都设置了而endpoint为空时会自动推导出 Langfuse 的 OTLP 端点并生成 Basic Auth 头显式指定endpoint/headers永远优先见 provider.py因此同一套配置既可以直连 Langfuse也可以对接任意 OTel Collector。TracerProvider被刻意保存在模块局部而非 OTel 全局目的是允许反复构建/销毁测试与重启场景规避 OTel set global provider once 的守卫父子 Span 嵌套依赖的 contextvars 与 provider 无关不受影响见 provider.py。7.2 开 Spanmemory_span 与 langfuse.* 属性from everos.core.observability.tracing import memory_span with memory_span( everos.memory.search, observation_typespan, # span / generation / embedding / retriever / agent session_idsession_id, user_iduser_id, metadata{scope: global}, tags(everos, memory), ) as span: ...memory_span见 attributes.py会在共享的everostracer 下开一个 Span并打上langfuse.observation.type、langfuse.session.id、langfuse.user.id、langfuse.trace.tags、langfuse.trace.metadata.key等属性。值得注意的两个参数metadata中值为None的键会被丢弃而不是写成字符串Nonenested_onlyTrue时仅在已有活跃 Span 时才开新 Span——否则像 cascade 索引期 embedding 这类在请求 trace 之外的调用会为每个 chunk 开启一个新的根 trace造成每 chunk 一个 trace的爆炸nested_only让这类调用直接 no-op。7.3 token 用量上报set_generation_usageLLM / embedding 的 token 用量通过set_generation_usage挂到当前活跃 Span上见 attributes.pyfrom everos.core.observability.tracing import set_generation_usage set_generation_usage(modelmodel, input_tokensn_in, output_tokensn_out)它写入gen_ai.request.model、gen_ai.usage.input_tokens、gen_ai.usage.output_tokens三个属性Langfuse 会基于这些gen_ai.*属性计算成本。两个关键实现细节token 计数是累计的一个 Span 包裹多次chat调用如 agentic/rank 搜索路径在一次everos.search.rankSpan 下发起多次 LLM 调用时每次的 usage 累加而非后写覆盖model则是 last-wins。无条件调用安全没有 OTel、没有活跃记录 Span 时直接 no-op。实际接入点是 component/llm/_usage_client.py 中的UsageRecordingClient——一个包装任意LLMClient的代理chat()完成后把response.usageprompt/completion tokens与response.model写入当前 Span业务响应原样返回。这正是 token 用量到达everos.extractgeneration Span 的通道everalgo 的 extractor 持有chat调用并丢弃了ChatResponse用量在客户端边界被截获无需改动 everalgo见 _usage_client.py。7.4 内容捕获capture_content、脱敏钩子与截断规则明确请求/响应内容仅在capture_content开启时才发出脱敏钩子 截断。默认capture_contentfalseSpan 只带元数据不携带任何查询文本、抽取出的记忆或 .md 路径见 settings.py。开启后capture_input(span, value)/capture_output(span, value)见 attributes.py写入langfuse.observation.input/langfuse.observation.output内容先经_prepare_content处理非字符串先 JSON 序列化 → 过redaction hookset_redactor(callable)可安装自定义脱敏函数把密钥/身份证号等替换掉→ 截断到_MAX_CONTENT_CHARS 4096字符见 attributes.py模块级开关_capture_content由init_tracing从配置设置、shutdown_tracing复位见 provider.py。八、request_id 与 trace_id独立身份 上游 trace 延续规则最后一条request_id与 OTeltrace_id保持独立上游存在traceparentheader 时继续该 trace。gen_request_id()见 ids.py返回 32 位小写 hex128-bit、无前缀与 W3Ctrace_id/ OTel trace identifier 同格式——不发明 uuid 或带前缀的自有格式保证与 OpenTelemetry 导出器及标准 APM 工具兼容。两者在 HTTP 入口解耦RequestIdMiddleware见 middleware/request_id.py为每个请求铸造request_id通过request.state、core.context的 contextvar 以及structlog.contextvars.bind_contextvars(request_id...)三处绑定使每一条日志行都携带 request_id并回显在X-Request-Id响应头与此同时若请求带 W3Ctraceparentheader则用use_traceparent见 attributes.py把当前 context 附加为上游 trace 的子节点让本服务的首个 Span 嵌套进调用方的分布式 trace没有则自建根 trace。current_traceparent()/current_trace_ids()则服务于跨 async/进程边界OME 入队时捕获traceparent后台策略 Span 通过use_traceparent重新挂回源 tracecurrent_trace_ids返回与 Langfuse OTLP 摄取一致的 hex 格式 traceId/observationId供召回分数挂到正确的 observation 上见 attributes.py。这套独立 request_id 延续 traceparent的设计让日志检索按 request_id与分布式链路分析按 trace_id各司其职、互不污染。九、落地自查清单结合规范原文与源码实现提交或评审代码时可对照以下清单日志是否统一走everos.core.observability.logging.get_logger是否出现print/ 裸 stdliblogging事件名是否点分隔、稳定、放第一位上下文是否用 kwargs 而非 f-string 插值级别是否符合debug 细节 / info 里程碑 / warning 可恢复 / error 带栈上下文的语义指标是否复用了core.observability.metrics的 Counter/Gauge/Histogram 与 registry 助手日志与 Span 属性中是否含有 secrets、API keys、完整记忆内容SecretStr保护 API keycapture_contentfalse时 Span 只带元数据追踪调用是否做到了无条件安全no-op 前提内容捕获若开启是否已安装 redaction hook 并接受 4096 字符截断token 用量是否经由set_generation_usage上报到当前活跃 Span而非自造计数器涉及后台任务的代码是否用current_traceparent/use_traceparent延续了源 tracenested_only是否避免了对根 trace 的误创建十、延伸阅读规范原文.claude/rules/logging-observability.md日志工厂实现logging/factory.py指标原语与 registrymetrics/init.py、metrics/registry.py追踪 provider 生命周期tracing/provider.pySpan 属性与隐私控制tracing/attributes.pytoken 用量接入点component/llm/_usage_client.py配置定义config/settings.py、config/default.tomlHTTP 入口的 request_id 与 trace 延续core/middleware/request_id.py赞分享人工智能AI AgentAgent 记忆RAG【免费下载链接】EverOSOne portable memory layer for every AI agent: local-first, Markdown-native, user-owned, and self-evolving across apps, tools, and workflows.项目地址https://gitcode.com/gh_mirrors/ev/EverOS点击查看免费下载相关推荐dotnet-starter-kit 日志与可观测性实战指南结构化日志、Serilog、关联追踪与 OpenTelemetry 全链路接入dotnet starter kit 日志与可观测性实战指南结构化日志、Serilog、关联追踪与 OpenTelemetry 全链路接入 导读本文以 Fu后端前端示例工程认证鉴权Baserow 可观测性实战用 OpenTelemetry 配置日志、指标与尾采样追踪Baserow 可观测性实战用 OpenTelemetry 配置日志、指标与尾采样追踪 本篇指南基于 Baserow 仓库的 监控文档 https://lin后端前端数据库低代码工作流自动化FastStream 应用与应用访问日志指南从 Context 日志到 Structlog 结构化日志FastStream 应用与应用访问日志指南从 Context 日志到 Structlog 结构化日志 导读 FastStream 作为面向 Kafka、Ra后端消息队列微服务创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考