Agent 全链路追踪:一次对话在模型、工具、存储间的完整路径

发布时间:2026/7/12 16:45:07

Agent 全链路追踪:一次对话在模型、工具、存储间的完整路径
Agent 全链路追踪一次对话在模型、工具、存储间的完整路径一、为什么一次简单的对话却要翻几十个服务日志排查 Agent 对话问题时最让人抓狂的不是业务逻辑而是追踪。一次对话经过 Prompt 拼接、模型调用、工具选择、工具执行、结果注入、二次推理……涉及五六个组件、十几个调用。出问题后你得在模型服务的 Pod 日志、工具服务的 Sentinel 面板、向量数据库的 Query Log、消息队列的消费位点之间来回切时间都花在找日志而非读日志。核心矛盾在于Agent 系统的调用链路远比传统微服务复杂。传统 API Gateway 进来的请求是一条线Agent 的思维链本质上是一棵树——模型可能在推理中途分叉出多个工具调用每个工具调用又可能产生子链。传统的 traceId 只能追踪线性调用撑不起这种拓扑。我们后来落地了一套方案把 Agent 会话的全链路追踪拆成 Session、Turn、Step、Span 四层模型配合 OpenTelemetry 的 Baggage 机制注入对话上下文。排查问题时输入session_id就能捞出整个对话的完整轨迹。二、四层追踪模型与上下文传播机制Agent 的调用特点决定了不能简单套用 RPC 的 Span 嵌套模型。Agent 的执行是推理-行动-观测的循环ReAct 模式每个循环是一个 Decision Point模型在这个点上决定调用哪些工具。下面是我们的四层追踪模型graph TD Session[Session: 一次完整对话] Turn1[Turn 1: 第一轮对话] Turn2[Turn 2: 第二轮对话] Step1[Step: Prompt构建 LLM调用] Step2[Step: 工具调用 - 搜索] Step3[Step: 工具调用 - 计算] Step4[Step: 结果注入 二次推理] Session -- Turn1 Session -- Turn2 Turn1 -- Step1 Turn1 -- Step2 Turn1 -- Step3 Turn1 -- Step4 SubStep2a[Span: API Request] SubStep2b[Span: Response Parse] SubStep3a[Span: Code Execute] SubStep3b[Span: Sandbox Cleanup] Step2 -- SubStep2a Step2 -- SubStep2b Step3 -- SubStep3a Step3 -- SubStep3b style Session fill:#4A90D9,color:#fff style Turn1 fill:#50B86C,color:#fff style Turn2 fill:#50B86C,color:#fff style Step1 fill:#F5A623,color:#fff style Step2 fill:#F5A623,color:#fff style Step3 fill:#F5A623,color:#fff style Step4 fill:#F5A623,color:#fffSession一次完整对话对应session_id。Turn每轮用户输入Agent回复构成一个 Turn对应turn_id。StepAgent 思维链中的一个决策点可能是 LLM 推理、工具调用或结果整合。Span对应 OpenTelemetry 的 Span是单一的 RPC 调用或函数执行。关键设计是在 Span 的 Attributes 里注入完整的对话上下文session_id、turn_id、step_id、tool_name、model_name。这样 Collector 端可以通过session_id聚合出完整树不需要应用层额外维护关联表。上下文传播通过 OpenTelemetry 的 Context Propagation 实现。在 Python 侧from opentelemetry import trace, context from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator propagator TraceContextTextMapPropagator()将当前 trace context 注入到工具调用的 HTTP 请求头中工具服务侧再提取还原。这样即使工具是外部服务也能接上链路。三、生产级实现Trace Collector 查询聚合核心代码分两层Agent 侧的埋点封装和 Collector 侧的聚合查询。Agent 侧埋点import time from typing import Optional, Dict, Any from opentelemetry import trace from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter from opentelemetry.sdk.resources import SERVICE_NAME, Resource # 初始化 TracerProvider使用 OTLP 协议上报 # 为什么用 BatchSpanProcessor 而非 SimpleSpanProcessor # Agent 的 Span 密度很高一次对话可能有数十个 Span # 同步上报会造成 LLM 调用的额外等待批量异步上报将延迟控制在 100ms 以内 resource Resource(attributes{SERVICE_NAME: agent-runtime}) provider TracerProvider(resourceresource) processor BatchSpanProcessor( OTLPSpanExporter(endpointhttp://otel-collector:4317, insecureTrue), # 每 512 个 Span 或每 5 秒刷新一次避免内存堆积 max_export_batch_size512, schedule_delay_millis5000, ) provider.add_span_processor(processor) trace.set_tracer_provider(provider) tracer trace.get_tracer(__name__) class AgentTraceContext: 封装 Agent 对话层级的 trace 上下文 def __init__(self, session_id: str, user_id: str ): self.session_id session_id self.user_id user_id self.turn_counter 0 def create_turn_span(self, user_input: str) - trace.Span: 为每轮对话创建一个 Turn Span self.turn_counter 1 turn_span tracer.start_span( fagent_turn_{self.turn_counter}, attributes{ session.id: self.session_id, turn.id: f{self.session_id}:{self.turn_counter}, user.id: self.user_id, turn.input: user_input[:500], # 截断避免 Span 过大 turn.timestamp: int(time.time()), } ) return turn_span def create_step_span( self, parent_span: trace.Span, step_type: str, step_name: str, extra_attrs: Optional[Dict[str, Any]] None ) - trace.Span: 在 Turn 下创建 Step Span # 使用父 Span 的 Context 建立层级关系 ctx trace.set_span_in_context(parent_span) step_span tracer.start_span( f{step_type}:{step_name}, contextctx, attributes{ session.id: self.session_id, step.type: step_type, # llm_call | tool_call | reasoning step.name: step_name, step.timestamp: int(time.time()), **(extra_attrs or {}), } ) return step_span def propagate_context(self, headers: Dict[str, str], current_span: trace.Span): 将当前 trace context 注入到 HTTP headers 中。 调用外部工具时必须调用此方法传递上下文。 ctx trace.set_span_in_context(current_span) propagator TraceContextTextMapPropagator() propagator.inject(headers, contextctx) # 使用示例Agent 执行循环 def agent_run(session_id: str, user_input: str): ctx AgentTraceContext(session_id, user_iduser_123) with ctx.create_turn_span(user_input) as turn_span: try: # Step 1: Prompt 构建 with ctx.create_step_span(turn_span, llm_call, prompt_build) as step: prompt build_prompt(user_input) step.set_attribute(prompt.length, len(prompt)) # Step 2: LLM 调用 with ctx.create_step_span(turn_span, llm_call, model_inference) as step: response call_llm(prompt, trace_ctxctx, parent_spanstep) step.set_attribute(model.name, gpt-4) step.set_attribute(response.tokens, response.token_count) # Step 3: 工具调用如果 LLM 返回工具调用 if response.tool_calls: for tool_call in response.tool_calls: with ctx.create_step_span( turn_span, tool_call, tool_call.name, extra_attrs{tool.args: str(tool_call.args)[:500]} ) as tool_span: result execute_tool(tool_call, trace_ctxctx, parent_spantool_span) tool_span.set_attribute(tool.success, result.success) tool_span.set_attribute(tool.duration_ms, result.duration_ms) # Step 4: 结果注入 二次推理 with ctx.create_step_span(turn_span, llm_call, final_response) as step: final call_llm_with_tools_result(prompt, tool_results, trace_ctxctx, parent_spanstep) turn_span.set_attribute(turn.success, True) return final except Exception as e: turn_span.set_attribute(turn.success, False) turn_span.record_exception(e) raiseCollector 侧聚合查询import asyncpg from typing import List, Dict, Any from dataclasses import dataclass dataclass class TraceSpan: session_id: str turn_id: str step_type: str step_name: str span_id: str parent_span_id: str start_time: int duration_ms: int attributes: Dict[str, Any] class TraceQueryService: 基于 ClickHouse 的全链路查询服务 def __init__(self, clickhouse_dsn: str): # ClickHouse 在宽表查询和时序聚合上秒杀 MySQL # Agent 的 Span 数据写入量大每天百万级必须用列存 self.pool None self.clickhouse_dsn clickhouse_dsn async def init(self): self.pool await asyncpg.create_pool(self.clickhouse_dsn, min_size5, max_size20) async def query_session_trace(self, session_id: str) - List[TraceSpan]: 根据 session_id 查询完整对话链路 query SELECT session_id, turn_id, step_type, step_name, span_id, parent_span_id, toUnixTimestamp(start_time) as start_time, duration_ms, attributes FROM agent_traces WHERE session_id $1 AND date today() - INTERVAL 7 DAY -- 限制时间范围避免全表扫描 ORDER BY start_time ASC async with self.pool.acquire() as conn: rows await conn.fetch(query, session_id) traces [] for row in rows: traces.append(TraceSpan( session_idrow[session_id], turn_idrow[turn_id], step_typerow[step_type], step_namerow[step_name], span_idrow[span_id], parent_span_idrow[parent_span_id], start_timerow[start_time], duration_msrow[duration_ms], attributesrow[attributes], )) return traces async def analyze_session_performance(self, session_id: str) - Dict[str, Any]: 分析单次会话的性能瓶颈 query SELECT step_type, step_name, count() as call_count, avg(duration_ms) as avg_duration, quantile(0.95)(duration_ms) as p95_duration, max(duration_ms) as max_duration FROM agent_traces WHERE session_id $1 GROUP BY step_type, step_name ORDER BY avg_duration DESC async with self.pool.acquire() as conn: rows await conn.fetch(query, session_id) bottlenecks [] for row in rows: bottlenecks.append({ step_type: row[step_type], step_name: row[step_name], call_count: row[call_count], avg_duration_ms: row[avg_duration], p95_duration_ms: row[p95_duration], max_duration_ms: row[max_duration], }) return {session_id: session_id, bottlenecks: bottlenecks}四、这套方案不适合哪些场景缺点Span 膨胀问题一个复杂对话可能产生 50 个 SpanCollector 的存储成本上升很快。需要配置采样策略对成功且100ms 的 Span 按 10% 采样。Batching 带来的延迟BatchSpanProcessor 在进程异常退出时会丢失最后一批 Span。关键操作应设置OnEnd回调写本地日志兜底。跨语言传播的一致性Baggage 的传播在 Go/Python/Node.js 的 OTel SDK 表现不完全一致混用语言时需要 Mock 测试验证。禁用场景对延迟极度敏感、不允许额外 1-2ms 埋点开销的实时系统。对话内容包含强合规数据如金融交易指令不可将输入采样到 Span Attributes 中的场景。五、总结Agent 全链路追踪的核心是用对话语义层替代传统的RPC 调用层来组织链路。四层模型Session→Turn→Step→Span适配了 Agent 的树状执行特征配合 OpenTelemetry 的 Baggage 机制实现了跨服务的上下文透传。落地时Span 采样策略和异常退出的 Span 丢失是两个必须处理的工程问题。

相关新闻

Vue 3 + ezuikit-js 7.7.7 集成萤石云:3步实现监控、云台控制与全屏

Vue 3 + ezuikit-js 7.7.7 集成萤石云:3步实现监控、云台控制与全屏

2026/7/12 16:45:07

Vue 3 集成萤石云监控:从零实现播放、云台控制与全屏功能在智能安防和远程监控需求日益增长的今天,前端开发者经常需要将视频监控功能集成到Web应用中。本文将详细介绍如何使用Vue 3和官方ezuikit-js SDK(7.7.7版本)快速实现萤石云…

vLLM CPU推理优化:Phi-4-da8w8-torchao-v0.16.0环境变量设置最佳实践

vLLM CPU推理优化:Phi-4-da8w8-torchao-v0.16.0环境变量设置最佳实践

2026/7/12 16:45:07

vLLM CPU推理优化:Phi-4-da8w8-torchao-v0.16.0环境变量设置最佳实践 【免费下载链接】Phi-4-da8w8-torchao-v0.16.0 项目地址: https://ai.gitcode.com/hf_mirrors/amd/Phi-4-da8w8-torchao-v0.16.0 Phi-4-da8w8-torchao-v0.16.0是基于Phi3架构的大语言模型…

OpenAPI规范验证终极指南:使用OAS-Kit oas-validator确保API定义正确性

OpenAPI规范验证终极指南:使用OAS-Kit oas-validator确保API定义正确性

2026/7/12 16:45:07

OpenAPI规范验证终极指南:使用OAS-Kit oas-validator确保API定义正确性 【免费下载链接】oas-kit Convert Swagger 2.0 definitions to OpenAPI 3.0 and resolve/validate/lint 项目地址: https://gitcode.com/gh_mirrors/oa/oas-kit 在API开发过程中&#x…

如何通过CC Switch深度链接协议快速配置AI助手?终极指南

如何通过CC Switch深度链接协议快速配置AI助手?终极指南

2026/7/12 18:35:11

如何通过CC Switch深度链接协议快速配置AI助手?终极指南 【免费下载链接】cc-switch A cross-platform desktop All-in-One assistant for Claude Code, Codex, OpenCode, OpenClaw, Gemini CLI & Hermes Agent. Only official website: ccswitch.io 项目地址…

选择排序算法详解:核心思想、变种、时间复杂度与大数据应用(红色个人注释)

选择排序算法详解:核心思想、变种、时间复杂度与大数据应用(红色个人注释)

2026/7/12 18:35:11

1. 选择排序的核心思想 选择排序(Selection Sort)是一种简单直观的排序算法。它的基本思想是:在未排序序列中,反复查找最小(或最大)元素,并将其放到已排序序列的末尾。(注释&#x…

Android设备变身USB键盘鼠标:终极远程控制解决方案指南

Android设备变身USB键盘鼠标:终极远程控制解决方案指南

2026/7/12 18:35:11

Android设备变身USB键盘鼠标:终极远程控制解决方案指南 【免费下载链接】android-keyboard-gadget Convert your Android device into USB keyboard/mouse, control your PC from your Android device remotely, including BIOS/bootloader. 项目地址: https://gi…

【Git命令认知革命】:基于LLM的命令意图识别技术首次落地——实测ChatGPT对git stash --include-untracked等冷门参数解释准确率达92.7%

【Git命令认知革命】:基于LLM的命令意图识别技术首次落地——实测ChatGPT对git stash --include-untracked等冷门参数解释准确率达92.7%

2026/7/12 18:35:11

更多请点击: https://kaifayun.com 第一章:ChatGPT git命令解释 在日常开发中,开发者常借助 ChatGPT 辅助理解复杂或不熟悉的 Git 命令。但需注意:ChatGPT 本身**不执行** Git 操作,它仅提供语义解析、上下文说明与安…

终极指南:如何用ER-Save-Editor安全修改艾尔登法环存档

终极指南:如何用ER-Save-Editor安全修改艾尔登法环存档

2026/7/12 18:35:11

终极指南:如何用ER-Save-Editor安全修改艾尔登法环存档 【免费下载链接】ER-Save-Editor Elden Ring Save Editor. Compatible with PC and Playstation saves. 项目地址: https://gitcode.com/GitHub_Trending/er/ER-Save-Editor ER-Save-Editor是一款专为《…

Codex 真的比 Claude Code 好用吗?深入对比两大AI编程助手

Codex 真的比 Claude Code 好用吗?深入对比两大AI编程助手

2026/7/12 18:25:10

引言 在AI编程助手日益普及的今天,OpenAI的Codex(驱动GitHub Copilot)和Anthropic的Claude Code(Claude 3.5 Sonnet的代码能力)无疑是两个最受瞩目的选手。开发者们常常会问:“Codex真的比Claude Code好用吗…

Unity游戏文本翻译架构深度解析:XUnity.AutoTranslator的技术实现与工程实践

Unity游戏文本翻译架构深度解析:XUnity.AutoTranslator的技术实现与工程实践

2026/7/12 0:03:42

Unity游戏文本翻译架构深度解析:XUnity.AutoTranslator的技术实现与工程实践 【免费下载链接】XUnity.AutoTranslator 项目地址: https://gitcode.com/gh_mirrors/xu/XUnity.AutoTranslator XUnity.AutoTranslator作为Unity游戏社区中最成熟的文本翻译解决方…

openEuler Raspberry Pi Kernel设备驱动开发指南:为树莓派硬件添加支持

openEuler Raspberry Pi Kernel设备驱动开发指南:为树莓派硬件添加支持

2026/7/12 0:03:42

openEuler Raspberry Pi Kernel设备驱动开发指南:为树莓派硬件添加支持 【免费下载链接】raspberrypi-kernel It provides openEuler kernel source for Raspberry Pi 项目地址: https://gitcode.com/openeuler/raspberrypi-kernel 前往项目官网免费下载&…

openEuler系统集成测试实战:基于smoke-test套件的环境验证技巧

openEuler系统集成测试实战:基于smoke-test套件的环境验证技巧

2026/7/12 0:03:42

openEuler系统集成测试实战:基于smoke-test套件的环境验证技巧 【免费下载链接】integration-test The repo contains test suits for system integration test 项目地址: https://gitcode.com/openeuler/integration-test 前往项目官网免费下载:…

Unity游戏文本翻译架构深度解析:XUnity.AutoTranslator的技术实现与工程实践

Unity游戏文本翻译架构深度解析:XUnity.AutoTranslator的技术实现与工程实践

2026/7/12 0:03:42

Unity游戏文本翻译架构深度解析:XUnity.AutoTranslator的技术实现与工程实践 【免费下载链接】XUnity.AutoTranslator 项目地址: https://gitcode.com/gh_mirrors/xu/XUnity.AutoTranslator XUnity.AutoTranslator作为Unity游戏社区中最成熟的文本翻译解决方…

openEuler Raspberry Pi Kernel设备驱动开发指南:为树莓派硬件添加支持

openEuler Raspberry Pi Kernel设备驱动开发指南:为树莓派硬件添加支持

2026/7/12 0:03:42

openEuler Raspberry Pi Kernel设备驱动开发指南:为树莓派硬件添加支持 【免费下载链接】raspberrypi-kernel It provides openEuler kernel source for Raspberry Pi 项目地址: https://gitcode.com/openeuler/raspberrypi-kernel 前往项目官网免费下载&…

openEuler系统集成测试实战:基于smoke-test套件的环境验证技巧

openEuler系统集成测试实战:基于smoke-test套件的环境验证技巧

2026/7/12 0:03:42

openEuler系统集成测试实战:基于smoke-test套件的环境验证技巧 【免费下载链接】integration-test The repo contains test suits for system integration test 项目地址: https://gitcode.com/openeuler/integration-test 前往项目官网免费下载:…