
掌握 ADK 遥测配置用 TelemetryConfig 精确控制 Agent 追踪中的提示词与响应内容【免费下载链接】adk-pythonAn open-source, code-first Python toolkit for building, evaluating, and deploying sophisticated AI agents with flexibility and control.项目地址: https://gitcode.com/GitHub_Trending/ad/adk-pythonTelemetryConfig是 ADKAgent Development Kit中决定追踪数据去向的单一入口它控制每一次模型调用、工具调用产生的 OpenTelemetry span 上是否携带提示词与模型回复原文以及内容以何种形式ADK 自有属性、稳定版 GenAI 语义约定的日志记录、实验版语义约定的 span 属性离开进程。本文基于 遥测配置官方指南 与 context.py 源码完整梳理默认行为、三级优先级解析、四个should_*属性背后的路由规则并给出部署级锁定与单次运行调试两套实战配置方案。读完本文你将能准确预测任意环境下 trace 中是否出现对话原文并在隐私合规与可调试性之间做出正确取舍。为什么需要 TelemetryConfigspan 是一条数据出口ADK 会对每次模型调用、每次工具调用以及发给 Agent 的数据产生 span。这些 span 的价值在于细节哪个工具被执行、传入了什么参数、返回了什么结果。但同样的特性也使其成为应用的数据出口——一个承载序列化LlmRequest的 span 属性就等于携带了整段对话。TelemetryConfig是这一决策的唯一裁决点。ADK 追踪代码中的每一个内容开关都读取它的属性因此存在一条统一的优先级阶梯而不是散落在各处的环境变量检查。你可以通过RunConfig.telemetry将配置实例挂载到某次运行上也可以什么都不设置完全交由环境变量裁决。可配置的内容有三项是否捕获提示词prompt与响应response内容是否使用实验版 GenAI 语义约定experimental GenAI semantic conventions替代 ADK 旧有的属性命名是否发出实验性遥测experimental telemetry。从源码看这三项对应 TelemetryConfig 的capture_message_content、genai_semconv_stability_opt_in、adk_experimental_telemetry_opt_in三个字段其定位正如模块 docstring 所述这是每次请求的 OpenTelemetry 配置类型是各遥测旋钮如何解析的单一事实来源。首先面对隐私决策默认行为是全量写入不做任何配置时提示词和响应内容会写入 ADK 的 span。相关属性开箱即用的解析结果如下属性默认值含义should_add_content_to_legacy_spansTrue提示词、模型回复、工具参数与工具结果写入 ADK 自有 span。should_add_content_to_logsFalse不写入发出的日志记录LogRecord。should_add_content_to_experimental_spansFalse不写入实验版 inference span。这三行代表三个不同的目的地而不是同一个 span 的三种等级需要先厘清差异。Legacy span旧有 span是 ADK 自己创建并写入自有属性的 span最典型的是call_llm属性名以gcp.vertex.agent.开头。这是你当前能拿到的 span也是 ADK Web UI 与既有仪表盘读取的对象。Experimental span实验版 span是在你通过genai_semconv_stability_opt_in选择加入实验版 GenAI 语义约定后模型调用产生的 span。选择加入后对话会以该约定定义的gen_ai.*属性名写入该 span而非 ADK 自有命名。两者之间不存在普通 span因为稳定版 GenAI 语义约定根本不会把对话内容放到 span 上。不选择实验版时ADK 仍会为模型调用开启一个generate_content modelspan但它只携带模型名、操作名等元数据消息以gen_ai.system.message、gen_ai.user.message和gen_ai.choice命名的日志记录离开进程——这正是中间一行should_add_content_to_logs所管控的。因此真正的选择是三者之一ADK 自有 span 属性、稳定版约定的日志记录、实验版约定的 span 属性。第一行是最容易让人意外的地方。具体来说运行一个未做任何遥测配置的 Agent用户的完整消息会出现在call_llmspan 上属性名为gcp.vertex.agent.llm_request。无论你的 exporter 指向哪里——Cloud Trace、OTLP collector 还是第三方可观测性厂商——该文本都会随之离开进程除非你另行声明。这一默认值有两个成因且都不使其更安全其一没有提示词的 trace 对Agent 答错了这类最常见问题几乎毫无调试价值因此该设置被选为让默认安装开箱即可调试其二历史原因——ADK_CAPTURE_MESSAGE_CONTENT_IN_SPANS早于 OpenTelemetry 的内容捕获变量默认开启而 OpenTelemetry 的对应变量默认关闭。无论原因为何对未配置的部署而言效果就是对话内容随 trace 离开进程所以请在发布前、而非发布后做出决定。针对整个进程关闭一旦 trace 离开你控制的系统就应采用的设置export ADK_CAPTURE_MESSAGE_CONTENT_IN_SPANSfalse针对单次运行关闭传入显式模式run_config RunConfig( telemetryTelemetryConfig( capture_message_contentContentCapturingMode.NO_CONTENT ) )二者并不等价环境变量只静默 ADK 自有 spanOpenTelemetry 路径保持其各自默认NO_CONTENT则静默一切。若想获得部署级、应用代码无法撤销的保证参见下文 锁定策略防止应用代码覆盖。此外无论开关如何都会发生一定的脱敏redaction请求的http_options会被排除在序列化请求之外因为headers通常携带授权 bearer tokenextra_body又是自由格式透传内联二进制部分会被替换为inline_data: image/png, 20481 bytes这类占位符而不是把 base64 编码到属性上。这两项都不会触及真正的消息文本——那才是隐私审查真正关注的部分。源码中_build_llm_request_for_trace明确注释了http_options携带调用方凭据因而在序列化时被剔除_summarize_inline_data则负责把inline_data替换为inline_data: mime_type, size摘要。快速上手把配置挂到一次运行上from google.adk.agents.run_config import RunConfig from google.adk.telemetry import ContentCapturingMode from google.adk.telemetry import TelemetryConfig telemetry TelemetryConfig( capture_message_contentContentCapturingMode.NO_CONTENT, ) async for event in runner.run_async( user_iduser-123, session_idsession.id, new_messagemessage, run_configRunConfig(telemetrytelemetry), ): ...TelemetryConfig是冻结frozen对象同一实例可在并发运行间共享而无需拷贝。它懒读取环境变量——在属性被查询的那一刻读取——因此进程后续改动的变量仍然生效。两点需要说明从源码看TelemetryConfig的model_post_init在构造时一次性解析并缓存所有环境变量回退值而RunConfig.telemetry字段见 run_config.py的注释明确其作用是在本次运行期间覆盖进程级遥测环境变量。因此官方指南中环境变量懒读取、改后即时生效指的是在不同TelemetryConfig实例之间比较时各实例会读到不同环境快照要在一个进程里让新环境变量生效应构造一个新的TelemetryConfig实例而非复用旧实例。另外由于TelemetryConfig基于 Pydantic 且配置了extraforbid未知字段会在构造时直接抛错拼写错误的参数不会被静默忽略。工作原理统一的四级解析阶梯每个设置都以相同方式解析来自三个字段由一个固定的优先级阶梯按序读取。理解这个顺序就能预测给定部署实际会发生什么。解析顺序每个属性都回答同一个四步问题顺序如下管理员锁admin lock若ADK_TELEMETRY_IGNORE_RUN_CONFIG为1或true则完全跳过 per-request 字段解析从第 3 步开始。锁存在的意义是让部署运维方阻止应用代码覆盖遥测策略。per-request 字段若非None。该设置对应的环境变量。内置默认值。字段保持None不代表关闭而是表示我没有意见解析将落入环境变量。这一阶梯在 context.py 的各个should_*/resolved_*属性中逐一实现模块 docstring 将其概括为admin lock per-request field OTEL_*env var default。三个字段TelemetryConfig携带三个字段每个都有在字段为None时回退的环境变量。字段类型默认值环境变量capture_message_contentContentCapturingMode \| NoneNoneOTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENTgenai_semconv_stability_opt_instable \| experimental \| NoneNoneOTEL_SEMCONV_STABILITY_OPT_INadk_experimental_telemetry_opt_inbool \| NoneNoneADK_EXPERIMENTAL_TELEMETRY模型禁止未知字段因此拼写错误的参数会在构造时抛错而非被忽略ConfigDict(frozenTrue, extraforbid)。capture_message_content接受一个ContentCapturingMode该枚举有四个成员分别指定内容允许去向NO_CONTENT哪里都不允许。EVENT_ONLY只允许写入发出的日志记录。SPAN_ONLY只允许写入当前活跃 span。SPAN_AND_EVENT两者都允许。其环境变量接受对应的大写字符串也接受历史遗留的true或1会被解读为EVENT_ONLY。任何其他值包括拼写错误都会在无警告的情况下解析为NO_CONTENT。该解析逻辑见 context.py先做布尔兼容转换再尝试ContentCapturingMode(stripped.upper())ValueError一律落入NO_CONTENT。genai_semconv_stability_opt_in在 ADK 既有gcp.vertex.agent.*span 属性与实验版 GenAI 语义约定之间切换。环境变量路径只理解选择加入它会在逗号分隔的变量中查找gen_ai_latest_experimental这个 token其缺席则推断为 stable。所以stable是一个没有环境变量等价物的 per-request 值也是在整个部署已选择加入的情况下把某一次运行保持在使用旧属性上的方式。实现见_read_experimental_genai_semconvcontext.py对变量按逗号切分并strip后做成员判断。adk_experimental_telemetry_opt_in管控形态仍在变化的遥测——到目前为止指 skills技能相关的 span 与属性。它默认关闭因为一个在版本间改名的属性会摧毁基于它构建的仪表盘。实验性属性集中定义在 _adk_attributes.py 中全部以adk.experimental.前缀命名如adk.experimental.skill.name、adk.experimental.skill.script.exit_code且按注释明确不提供兼容性保证。为什么一个字段驱动四个属性capture_message_content被四个独立的should_*属性读取因为 ADK 有两代 span且路由规则不同。should_add_content_to_logs与should_add_content_to_experimental_spans严格遵循 OpenTelemetry 规则日志记录在EVENT_ONLY和SPAN_AND_EVENT下获得内容span 在SPAN_ONLY和SPAN_AND_EVENT下获得内容。should_add_content_to_legacy_spans管控 ADK 自行写入的属性分为三组模型交换gcp.vertex.agent.llm_request与llm_response、工具交换tool_call_args与tool_response、Agent 输入data。它是唯一拥有独立环境变量回退的属性——ADK_CAPTURE_MESSAGE_CONTENT_IN_SPANS默认开启。一旦capture_message_content被设置为任意值该回退即被绕过转而采用 OpenTelemetry 的 span 路由——因此EVENT_ONLY会把 legacy span 的内容关掉。这正是两种关闭方式的分野ADK_CAPTURE_MESSAGE_CONTENT_IN_SPANSfalse静默 legacy spanOpenTelemetry 规范路径保持各自默认capture_message_contentNO_CONTENT静默一切包括 OpenTelemetry 变量已开启的内容。EVENT_ONLY同样会静默 legacy span——这一点常被忽略因为它的名字看不出与 span 有关。一个值得注意的实现细节当内容被抑制时属性并不会被丢弃而是被设为字符串{}。span 形状保持不变依赖这些键的消费方消费者、仪表盘可以继续正常工作。这一点在 tracing.py 中体现得淋漓尽致无论捕获与否gcp.vertex.agent.llm_request、gcp.vertex.agent.tool_call_args、gcp.vertex.agent.tool_response等键始终被写入内容开关只决定写入的是序列化内容还是{}。插桩库的注意事项如果安装了opentelemetry-instrumentation-google-genai它会包装google.genai.Models.generate_content并自行创建 inference span读取它自己的 OpenTelemetry 环境变量。per-request 覆盖无法到达该 span。它们仍作用于 ADK 拥有的每个 span因此效果是策略分裂模型调用遵循该库的规则其余部分遵循你的规则。高级应用部署级锁定与单次调试两种需求方向相反运维方希望策略对全部署固定开发者希望为某次会话捕获内容。该配置同时服务两者而管理员锁正是防止后者击败前者的机制。锁定策略防止应用代码覆盖平台团队若已决定提示词内容绝不能离开进程就不能指望每个 Agent 作者都传入正确的RunConfig。请在部署环境中同时设置两个变量export ADK_CAPTURE_MESSAGE_CONTENT_IN_SPANSfalse export ADK_TELEMETRY_IGNORE_RUN_CONFIG1前者设定策略后者让TelemetryConfig忽略 per-request 字段——于是应用即使传入capture_message_contentSPAN_AND_EVENT也只会得到NO_CONTENT。从源码看_ignore_per_request属性context.py在解析时被最先检查只要其为真各should_*属性便跳过字段、直接落到缓存的环境值上。为单次运行打开内容捕获反向场景正是 per-request 字段存在的理由平时不让内容进入 trace调试时再为那一个会话打开。debug_telemetry TelemetryConfig( capture_message_contentContentCapturingMode.SPAN_AND_EVENT ) run_config RunConfig(telemetrydebug_telemetry if is_debug else None)传入None是表达没有意见的正确方式因为它让部署默认值说了算而不是把本次运行恰好想要的值钉死。局限与边界ADK span 的内容捕获默认开启。提示词文本、模型回复、工具参数与工具结果会随 trace 离开进程直到你设置ADK_CAPTURE_MESSAGE_CONTENT_IN_SPANSfalse或传入capture_message_contentNO_CONTENT。无法识别的环境变量值会静默失败。四个模式名及历史遗留的true、1之外的任何值都解析为NO_CONTENT且无警告因此一个拼写错误会悄悄禁用捕获。ADK_TELEMETRY_IGNORE_RUN_CONFIG与ADK_EXPERIMENTAL_TELEMETRY反向同理只有1和true算作已设置见 context.py 的_TRUTHY_ENV_VALUES。stable无法用环境变量表达。语义约定变量只支持选择加入。粒度是整个请求。没有按字段或按 Agent 的脱敏也没有在导出前重写属性的钩子要么全部内容要么全无。选择性脱敏需要自备 OpenTelemetry span processor。RunConfig.telemetry无法触及外部插桩库。已安装的opentelemetry-instrumentation-google-genai会自行创建 inference span且只读取自己的 OpenTelemetry 环境变量。相关指南与验证路径RunConfig是TelemetryConfig挂载的对象并覆盖单次运行其余的可控项参见 RunConfig 源码。想亲眼验证上述行为仓库测试是最好的参考优先级阶梯与管理员锁的行为在 test_telemetry_context.py 中有完整覆盖ADK_CAPTURE_MESSAGE_CONTENT_IN_SPANS在 test_spans.py 中被反复用于控制内容开关稳定版语义约定的日志体构建见 test_stable_semconv.py。需要调整 Web UI 或导出端消费 span 的方式可继续阅读 遥测配置指南 对应的 追踪实现 与 稳定版语义约定模块。上图展示的 ADK Web UI 正是 legacy span 的消费方之一左侧流程图呈现函数调用链process_input、generate_headline、route_headline等节点右侧Events/Traces面板列出运行过程中的事件序列。这也意味着当你关闭内容捕获后这类界面中的消息文本将不再可见属性值变为{}而 span 结构与调用链视图保持不变——理解这一点有助于在调试体验与数据合规之间做出权衡。【免费下载链接】adk-pythonAn open-source, code-first Python toolkit for building, evaluating, and deploying sophisticated AI agents with flexibility and control.项目地址: https://gitcode.com/GitHub_Trending/ad/adk-python创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考