主题
3. 框架埋点(Instrumentation)
1. 埋点总览
框架在 Agent 执行链路的四个层级创建 Span,并在 Span 结束前 调用对应的 trace_*() 函数写入属性:
| 层级 | Span 名称 | 创建位置 | 属性写入函数 | gen_ai.operation.name |
|---|---|---|---|---|
| Runner | invocation | runners.py | trace_runner() / trace_cancellation() | run_runner / run_runner_cancelled |
| Agent | agent_run [{name}] | agents/_base_agent.py | trace_agent() | run_agent |
| LLM | call_llm | agents/core/_llm_processor.py | trace_call_llm() | call_llm |
| Tool | execute_tool {name} | agents/core/_tools_processor.py | trace_tool_call() | execute_tool |
Langfuse 映射层根据 gen_ai.operation.name 决定 Observation 类型(Trace 级 / Generation / Span)。
2. Span 创建方式差异
外层:start_span(不激活 context)
python
# runners.py
span = tracer.start_span("invocation")
try:
# ... 执行 agent ...
trace_runner(...)
finally:
span.end()python
# agents/_base_agent.py
span = tracer.start_span(f"agent_run [{self.name}]")
try:
# ... agent 逻辑 ...
trace_agent(...)
finally:
span.end()原因:async generator 在取消时可能跨上下文关闭,使用 start_as_current_span 会触发 OpenTelemetry context detach 错误。
内层:start_as_current_span(激活 context)
python
# agents/core/_llm_processor.py
with tracer.start_as_current_span('call_llm'):
async for llm_response in self.model.generate_async(...):
...
trace_call_llm(context, event_id, request, final_llm_response, ...)python
# agents/core/_tools_processor.py
with tracer.start_as_current_span(f"execute_tool {tool.name}", attributes={...}):
result = await tool.run_async(...)
trace_tool_call(tool, args, function_response_event, ...)3. trace_runner() — Runner 级 Trace 属性
调用时机:Runner.run_async() 正常结束,在 finally 之前。
写入的关键属性(前缀 trpc.python.agent,可通过 set_trpc_agent_span_name() 修改):
| 属性 | 含义 |
|---|---|
gen_ai.operation.name | run_runner |
{prefix}.runner.app_name | 应用名 |
{prefix}.runner.name | [trpc-agent]: {app}/{agent} |
{prefix}.runner.user_id | 用户 ID |
{prefix}.runner.session_id | 会话 ID |
{prefix}.runner.input | 用户输入文本 |
{prefix}.runner.output | 最后一次非 streaming Event 的文本输出 |
{prefix}.state.begin / state.end | 执行前后 session state JSON |
取消场景:捕获 RunCancelledException 时调用 trace_cancellation(),gen_ai.operation.name 为 run_runner_cancelled,并写入 cancellation.reason 等。
4. trace_agent() — Agent 级 Span 属性
调用时机:BaseAgent.run_async() 的 finally 块。
| 属性 | 含义 |
|---|---|
gen_ai.operation.name | run_agent |
{prefix}.agent.name | Agent 名称 |
{prefix}.agent.input | 用户 content 文本 |
{prefix}.agent.output | 所有非 partial Event 拼接成的 action 字符串 |
{prefix}.state.begin / state.end | Agent 执行前后 state |
agent.output 由 _build_action_string_from_events() 从 Event 流构建,包含文本、function call、function response 等。
5. trace_call_llm() — LLM Generation 属性
调用时机:_llm_processor.py 中 LLM 流式/非流式调用完成后,只 trace 一次最终完整 response(避免 partial chunk 覆盖属性)。
| 属性 | 含义 |
|---|---|
gen_ai.operation.name | call_llm |
gen_ai.request.model | 模型名 |
gen_ai.usage.input_tokens / output_tokens | Token 用量 |
{prefix}.llm_request | 序列化后的请求(contents + config,不含 bytes) |
{prefix}.llm_response | LlmResponse JSON |
{prefix}.instruction.name / .version | Instruction 版本(若使用 RemoteInstructionManager) |
{prefix}.stream_function_calls.* | 流式 function call 聚合(可选) |
6. trace_tool_call() — Tool Span 属性
调用时机:Tool 执行完毕,在 execute_tool Span 的 context 内。
| 属性 | 含义 |
|---|---|
gen_ai.operation.name | execute_tool |
gen_ai.tool.name / .description / .call.id | Tool 元信息 |
{prefix}.tool_call_args | 调用参数 JSON |
{prefix}.tool_response | 返回结果 JSON |
并行 Tool:多个 Tool 并行执行时,合并为一个 execute_tool (merged) Span,调用 trace_merged_tool_calls()。
7. 执行时序(单次对话)
Runner.run_async()
│
├─ start_span("invocation")
│
├─ Agent.run_async()
│ ├─ start_span("agent_run [weather_agent]")
│ │
│ ├─ LlmProcessor.process()
│ │ └─ with start_as_current_span("call_llm")
│ │ └─ trace_call_llm() ← Generation 数据
│ │
│ ├─ ToolsProcessor.process()
│ │ └─ with start_as_current_span("execute_tool get_weather")
│ │ └─ trace_tool_call() ← Tool Span 数据
│ │
│ └─ trace_agent() ← Agent Span 属性
│ └─ span.end()
│
├─ trace_runner() ← Trace 级 input/output
└─ span.end()8. 自定义 Agent 埋点
对于 RemoteA2AAgent、ClaudeAgent 等非标准 LlmAgent,使用 CustomTraceReporter(见 7_custom_trace.md),在 Event 流上手动创建 call_llm / execute_tool Span。
LangGraph Agent 在 agents/utils/_langgraph.py 中有独立的 start_as_current_span + trace_call_llm 逻辑。
9. 用户自定义 Span
官方文档支持在 Tool 或 CustomAgent 中直接使用 OTel + Langfuse 属性:
python
from trpc_agent.telemetry import tracer
from opentelemetry import trace
def my_custom_trace() -> str:
with tracer.start_as_current_span("my_custom_trace"):
span = trace.get_current_span()
span.set_attribute("langfuse.observation.input", "Hello Langfuse")
span.set_attribute("langfuse.observation.output", "Hello User")
return "Hello, Langfuse"映射层对未知 gen_ai.operation.name 走 _map_span_observation_attributes(),保留原始 attributes 并设 langfuse.observation.type=span。