mcpField
A
agent-tracing

agent-tracing

github.com/lobehubAgent 工作流83.6k195 次安装今天更新
代码仓库

关于 agent-tracing

agent-tracing 是用于本地开发的记录与检查工具,可保存并查看 LobeHub Agent 执行过程和目标轨迹。它还支持重放已记录的模型调用,并分析上下文窗口与缓存情况。

主要功能

  1. 01本地记录执行快照
  2. 02检查操作与目标轨迹
  3. 03跨模型重放冻结的 LLM 调用
  4. 04查看上下文与前缀缓存

适用场景

  1. 01调试 Agent 执行步骤
  2. 02比较固定调用的模型输出
  3. 03检查目标决策与候选工作项
  4. 04定位影响缓存复用的上下文变化

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/lobehub/lobehub --skill agent-tracing

安装后在 Claude Code 中输入/agent-tracing确认已加载。

详细介绍

Agent 跟踪 CLI 指南

@lobechat/agent-tracing 是一款零配置的本地开发工具,可将 Agent 执行快照记录到磁盘,并提供用于检查这些快照的 CLI。

工作原理

在 NODE_ENV=development 下,AgentRuntimeService.executeStep() 会自动将每个步骤以部分快照的形式记录到 .agent-tracing/。操作完成后,部分快照会被整理为完整的 ExecutionSnapshot JSON 文件。

数据流:executeStep 循环 -> 构建 StepPresentationData -> 将部分快照写入磁盘 -> 完成时,整理为 .agent-tracing/{timestamp}_{traceId}.json

上下文引擎捕获:在 RuntimeExecutors.ts 中,call_llm 执行器会在 serverMessagesEngine() 处理完消息后调用 ctx.tracingContextEngine(input, output, metadata)。AgentRuntimeService.executeStep 会按步骤缓冲此调用,并将其作为类型化的 contextEngine 字段转发给 OperationTraceRecorder.appendStep。CE 通过此旁路传递,而不经过 events 数组,因此其大型负载(agentDocuments、systemRole、…)不会进入 Redis 状态流水线(LOBE-9110)。metadata 携带流水线针对每个请求的决策记录(裁剪统计信息、缓存预热判断、截断计数)。

软件包位置

packages/agent-tracing/
  src/
    types.ts          # ExecutionSnapshot, StepSnapshot, SnapshotSummary
    store/
      types.ts        # ISnapshotStore interface
      file-store.ts   # FileSnapshotStore (.agent-tracing/*.json)
    recorder/
      index.ts        # appendStepToPartial(), finalizeSnapshot()
    viewer/
      index.ts        # Terminal rendering: renderSnapshot, renderStepDetail, renderMessageDetail, renderSummaryTable, renderPayload, renderPayloadTools, renderMemory
    cli/
      index.ts        # CLI entry point (#!/usr/bin/env bun)
      inspect.ts      # Inspect command (default)
      partial.ts      # Partial snapshot commands (list, inspect, clean)
    index.ts          # Barrel exports

数据存储

  • 已完成的快照:.agent-tracing/{ISO-timestamp}_{traceId-short}.json
  • 最新快照的符号链接:.agent-tracing/latest.json
  • 正在处理的部分快照:.agent-tracing/_partial/{operationId}.json
  • 已下载的远程快照:.agent-tracing/_remote/{operationId}.json
  • FileSnapshotStore 从 process.cwd() 解析路径——请从仓库根目录运行 CLI

远程跟踪(生产环境/预发布环境)

服务器部署也会将已完成的快照上传到对象存储(使用 zstd 压缩;键存储在 agent_operations.trace_s3_key 中)。

首选:lh trace op。 服务器会解析键并为调用方自身的作用域签署对象,因此只需登录 LobeHub——无需 TRACING_BASE_URL、存储桶域名,也无需 SQL 将主题 ID 转换为操作 ID:

lh trace op list --topic tpc_xxx # operations of a topic, newest first, with a TRACE column
lh trace op inspect op_xxx_agt_xxx_tpc_xxx_xxxx
lh trace op inspect op_xxx_agt_xxx_tpc_xxx_xxxx -T # tool injection (enabledToolIds, manifests)

list 中的 TRACE = — 表示该次运行没有记录快照(运行发生在跟踪上传功能推出之前,或当时关闭了上传)。即使记录了快照,超过保留期限后,它仍可能在存储中返回 404。

后端:agentTrace lambda 路由器(getSnapshotUrl / listOperations)。请注意,受限 API 密钥无法使用该路由,因此这些命令需要真实会话,而非作用域密钥。

备用方案:独立的 agent-tracing CLI。 它没有 LobeHub 会话,因此会自行构建对象 URL,并需要配置存储桶的公开域名:

  • 环境变量:TRACING_BASE_URL=https://<bucket-public-domain>/agent-traces
  • 或者在仓库根目录的 .agent-tracing/.env 中添加相同的 TRACING_BASE_URL=... 行

每个部署专属的值都是私有信息,因此有意不记录在此仓库中。请先手动查找操作 ID:

SELECT id, trace_s3_key FROM agent_operations WHERE topic_id = 'tpc_xxx';

无论使用哪种方式,快照都会缓存到 .agent-tracing/_remote/<opId>.json,并且所有 inspect 标志的用法都与本地跟踪相同。

实现:packages/agent-tracing/src/store/loadSnapshot.ts(解析顺序:本地存储 → _remote/ 缓存 → 注入的 resolveDownloadUrl → TRACING_BASE_URL)以及 store/remote-store.ts(URL 构建格式为 {base}/{agentId}/{topicId}/{opId}.json.zst)。读取压缩快照需要 Node >= 22.15。

目标轨迹

一次 goal 是一次完整的 goal 执行,就像一次 operation 是一次完整的 Agent 执行,因此它会在更高一层使用相同的跟踪格式:GoalTrajectory : AdvanceSnapshot 对应 ExecutionSnapshot : StepSnapshot。这里没有 advances 表,正如没有 agent_steps 表一样——goal_traces 为每个 goal 保存一条汇总行和对象键,详情则保存在对象中。

叶节点会向下关联:一次 advance 会记录它启动的 operationId(位于 tick.effects[].operationId),因此 lh trace op inspect <opId> 可以从 goal 跟踪停止的位置继续查看。

agent-tracing goal               # list local goal trajectories
agent-tracing goal goal_xxx      # the run: triggers, outcomes, graph, gates, ops
agent-tracing goal goal_xxx -a 3 # one advance in full, with the frontier it ranked
agent-tracing goal goal_xxx -j   # raw JSON

每个 tick 记录的是决策输入,而不只是结果:它读取的图(作为相对于前一个 tick 的增量)、评估的预算、负责任务的状态,以及每个符合条件的工作节点,包括被跳过的节点。没有这些落选节点,跟踪就无法回答“为什么不是那个节点”。

存储遵循 operation 的切换方式,因此部署中保留其中一种时,也会保留另一种:

  • 已完成:goal-traces/{goalId}.json.zst
  • 进行中:goal-traces/_partial/{goalId}.json.zst(长周期 goal 尚未完成是常见的检查对象)
  • 开发环境:.goal-tracing/{goalId}.json

重放。replayGoalAgainstCurrentCoordinator(trajectory) 会针对记录的输入重新运行真实的 decideNextMove,并在当前协调器会做出不同选择的地方报告 {advanceSeq, tickIndex, field, recorded, replayed}。这会精确复现协调器的_决策_;但无法说明已派发的工作是否会以相同方式进行。

实现位于 packages/agent-tracing/src/goal/,通过 apps/server/src/services/goal/advanceGoal.ts(每次 advance 都会经过的唯一入口)中的 GoalService.tick 的 onDecision 侧信道进行记录。

CLI 命令

所有命令都从仓库根目录运行:

# View latest trace (tree overview, `inspect` is the default command)
agent-tracing
agent-tracing inspect
agent-tracing inspect <traceId>
agent-tracing inspect latest

# List recent snapshots
agent-tracing list
agent-tracing list -l 20

# Inspect specific step (-s is short for --step)
agent-tracing inspect <traceId> -s 0

# View messages (-m is short for --messages)
agent-tracing inspect <traceId> -s 0 -m

# View full content of a specific message (by index shown in -m output)
agent-tracing inspect <traceId> -s 0 --msg 2
agent-tracing inspect <traceId> -s 0 --msg-input 1

# View tool call/result details (-t is short for --tools)
agent-tracing inspect <traceId> -s 1 -t

# View raw events (-e is short for --events)
agent-tracing inspect <traceId> -s 0 -e

# View runtime context (-c is short for --context)
agent-tracing inspect <traceId> -s 0 -c

# View context engine input overview (-p is short for --payload)
agent-tracing inspect <traceId> -p
agent-tracing inspect <traceId> -s 0 -p

# View available tools in payload (-T is short for --payload-tools)
agent-tracing inspect <traceId> -T
agent-tracing inspect <traceId> -s 0 -T

# View user memory (-M is short for --memory)
agent-tracing inspect <traceId> -M
agent-tracing inspect <traceId> -s 0 -M

# Raw JSON output (-j is short for --json)
agent-tracing inspect <traceId> -j
agent-tracing inspect <traceId> -s 0 -j

# List in-progress partial snapshots
agent-tracing partial list

# Inspect a partial (use `inspect` directly — all flags work with partial IDs)
agent-tracing inspect <partialOperationId>
agent-tracing inspect <partialOperationId> -T
agent-tracing inspect <partialOperationId> -p

# Clean up stale partial snapshots
agent-tracing partial clean

# Map the context window composition of every LLM call (cm / map are aliases)
agent-tracing ctx-map
agent-tracing ctx-map <operationId|traceId|path.json>
agent-tracing ctx-map --html            # standalone report under .agent-tracing/_reports/
agent-tracing ctx-map --html out.html

# Re-issue a recorded LLM call against other models (see "replay" below)
agent-tracing replay <operationId|traceId|path.json>
agent-tracing replay <target> -s 4 -m openai/gpt-5,anthropic/claude-sonnet-5
agent-tracing replay <target> --all-steps

replay — 重新发起冻结的调用

快照已冻结某次 LLM 调用所见的一切:steps[].contextEngine.output 是发送给模型的确切消息数组,context.payload.tools 是模型可调用的工具集。replay 会将冻结的载荷重新发送出去,只替换模型,因此输出差异可归因于模型,而非上下文组装。如果所有模型对同一载荷都失败,问题就在上下文;如果有些模型通过了,问题就在模型选择。

两个 CLI 均可使用——agent-tracing replay(读取 LOBEHUB_JWT)和 lh trace op replay(使用 lh login 会话)。两者都需要凭据,因为调用会经由 LobeHub 聊天路由发送。

# One call: defaults to the last call_llm step and the model the op ran on
lh trace op replay <operationId>
lh trace op replay <operationId> -s 4 -m openai/gpt-5,anthropic/claude-sonnet-5
lh trace op replay <operationId> --judge "answers with a concrete file path"

# Every call of the operation
lh trace op replay <operationId> --all-steps
lh trace op replay <operationId> --all-steps --concurrency 8

--all-steps 回答了整个功能要解决的问题:拿一次成功的运行换用另一个模型,看看该模型是否也能完成任务。 它会给出由 llm-rubric 评审器生成的 PASS / FAIL 判定,将重放结果与记录的结果进行比较;传入 --judge "<criteria>",即可自行定义成功标准,而不是使用默认评审标准。

评审器评估的是结果,而非调用路径。通过调用不同工具解决同一问题的模型也算通过。每次调用的工具比较(toolSignature)会作为补充证据列在下方,说明运行采用了不同路径;它绝不会决定 PASS / FAIL。若最终调用未能到达模型,则判定为 FAIL,而不是缺少判定结果。

每次调用都会独立重放,使用运行框架实际为其构建的载荷,因此第 2 次调用的不同回答不会影响第 4 次调用;未能到达服务提供方的调用只会影响自身;各次调用会并发发出(默认每次 4 个)。

曾实现过节点链式调用——将每次重放的输出输入下一次调用——但后来移除了。跟踪无法重新生成工具输出,只能返回已记录的内容,因此模型一旦偏离,就不再有真实结果可供对照;此时运行结果将毫无意义,却仍看似成功。独立重放是有意采用的设计,并非备用方案。

已知限制:不会记录采样参数。 记录器会将运行时步骤上下文保存在 context.payload 下,而不是服务提供方请求正文中,因此目前写入的所有跟踪都不包含 temperature、top_p、max_tokens、惩罚参数和推理配置。重放会使用服务当前的默认值。模型之间的比较仍然有效(每个目标模型收到的请求相同);但如果某次操作使用了非默认设置,则无法将重放结果与记录的输出有效比较。可显式使用 --temperature / --max-tokens 覆盖参数。未记录参数时,CLI 会打印一行 note 提示。

ctx-map — 上下文窗口组成

ctx-map 会为每个 call_llm 步骤渲染一行:该调用发送给模型的消息会拆分为带类型的片段(系统/注入块/用户/推理/工具调用/工具结果),并根据令牌数量按比例显示宽度,排列在模型的上下文窗口中。

第二个维度展示了 ctx-lint 无法显示的内容:每一行都会与上一次调用进行差异比较,因此会标出最长的相同消息前缀——即提供商的前缀缓存可以复用的部分,同时标出发生变化的第一条消息,以及其后重新处理的令牌。一个包含相对时间戳(1m ago → now)的小型注入块会使其后的所有令牌失效,这会在行的前部显示为中断标记。

行的读法:

  • 色块颜色直接表示角色:橙色表示系统,绿色表示用户,蓝色表示助手,灰色表示工具。助手的推理、内容和工具调用使用同一蓝色系中的不同色阶;框架注入块使用比系统提示词更浅的橙色。每个值都是 viewer/contextMapScales.ts 中引入的 LobeHub 色阶索引,具体映射位于 viewer/contextMapPalette.ts。HTML 报告同时提供两种主题,并遵循系统主题。
  • 中性色消息边框用于归组属于同一载荷消息的片段。所有角色使用相同的边框颜色:轮廓仅表示结构,色块填充则表示角色和子类型。原始边框布局会在每条消息内部留出内边距,并在消息之间留出较小的轨道间距,使每条载荷消息在视觉上清晰区分。
  • 填充样式表示提供商是否复用了该内容:带阴影的 ▓(HTML:60% 不透明度的网纹)表示来自前缀缓存;实心的 █(HTML:纯色)表示由模型重新处理。
  • 轨道下方的线是缓存账本——括号/绿色带会精确覆盖缓存前缀,随后是中断标记(终端中为 ▲,HTML 中为贯穿轨道的红线),标记复用停止的列,并显示原因和重新处理的令牌。
标志简写说明
--html [path]独立 HTML 报告(将鼠标悬停在片段上可查看其内容)
--width <n>-w终端中的轨道宽度(列数)
--window <n>覆盖用作轨道的模型上下文窗口
--full-window始终按完整窗口缩放,不按最大调用缩放
--json-j每次调用的片段和缓存统计信息

轨道按上下文窗口缩放;当窗口远大于载荷(例如,50k 载荷位于 1M 窗口中)时,会改为按最大调用缩放,以保持组成图的可读性,标题会说明所用的缩放基准。分析逻辑位于 analysis/contextMap.ts,并导出 buildContextMap(),供下游语料库工作使用。

检查标志参考

标志短选项描述默认步骤
--step <n>-s指定目标步骤—
--messages-m消息上下文(CE 输入 → 参数 → LLM 负载)—
--tools-t工具调用与结果(Agent 调用了什么)—
--events-e原始事件(llm_start、llm_result 等)—
--context-c运行时上下文与负载(原始内容)—
--system-role-r完整的系统角色内容0
--env环境上下文0
--payload-p上下文引擎输入概览(模型、知识、工具摘要、记忆摘要、平台上下文)0
--payload-tools-T可用工具详情(插件清单 + LLM 函数定义)0
--memory-M完整的用户记忆(角色设定、身份、上下文、偏好、经历)0
--diff <n>-d与步骤 N 进行比较(与 -r 或 --env 配合使用)—
--msg <n>Final LLM Payload 中第 N 条消息的完整内容—
--msg-input <n>Context Engine Input 中第 N 条消息的完整内容—
--json-j以 JSON 格式输出(可与上述任意标志组合使用)—

标记为“默认步骤:0”的标志会在未提供 --step 时自动选择步骤 0。所有标志都支持 latest,也可以省略 traceId。

典型调试工作流

# 1. Trigger an agent operation in the dev UI

# 2. See the overview
agent-tracing inspect

# 3. List all traces, get traceId
agent-tracing list

# 4. Quick overview of what was fed into context engine
agent-tracing inspect -p

# 5. Inspect a specific step's messages to see what was sent to the LLM
agent-tracing inspect TRACE_ID -s 0 -m

# 6. Drill into a truncated message for full content
agent-tracing inspect TRACE_ID -s 0 --msg 2

# 7. Check available tools vs actual tool calls
agent-tracing inspect -T      # available tools
agent-tracing inspect -s 1 -t # actual tool calls & results

# 8. Inspect user memory injected into the conversation
agent-tracing inspect -M

# 9. Diff system role between steps (multi-step agents)
agent-tracing inspect TRACE_ID -r -d 2

关键类型

interface ExecutionSnapshot {
  traceId: string;
  operationId: string;
  model?: string;
  provider?: string;
  startedAt: number;
  completedAt?: number;
  completionReason?:
    'done' | 'error' | 'interrupted' | 'max_steps' | 'cost_limit' | 'waiting_for_human';
  totalSteps: number;
  totalTokens: number;
  totalCost: number;
  error?: { type: string; message: string };
  steps: StepSnapshot[];
}

interface StepSnapshot {
  stepIndex: number;
  stepType: 'call_llm' | 'call_tool';
  executionTimeMs: number;
  content?: string; // LLM output
  reasoning?: string; // Reasoning/thinking
  inputTokens?: number;
  outputTokens?: number;
  toolsCalling?: Array<{ apiName: string; identifier: string; arguments?: string }>;
  toolsResult?: Array<{
    apiName: string;
    identifier: string;
    isSuccess?: boolean;
    output?: string;
  }>;
  messages?: any[]; // DB messages before step
  context?: { phase: string; payload?: unknown; stepContext?: unknown };
  events?: Array<{ type: string; [key: string]: unknown }>;
  contextEngine?: {
    input?: unknown; // contextEngineInput minus messages + toolsConfig (reconstructible from baseline)
    output?: unknown; // processed messages array (final LLM payload)
    metadata?: unknown; // pipeline decision records (trim stats, cache gates, truncation counts)
  };
}

--messages 输出结构

使用 --messages 时,输出会显示以下三个部分(如果有上下文引擎数据):

  1. 上下文引擎输入 — 传递给引擎的 DB 消息,带有 [0]、[1]……索引。使用 --msg-input N 查看完整内容。
  2. 上下文引擎参数 — systemRole、model、provider、knowledge、tools、userMemory 等。
  3. 最终 LLM 负载 — 经上下文引擎处理后的消息(系统日期注入、用户记忆、历史记录截断等),带有 [0]、[1]……索引。使用 --msg N 查看完整内容。

集成点

  • 记录:apps/server/src/services/agentRuntime/AgentRuntimeService/executeStep/index.ts — 在 executeStep() 中,saveAndPublishStep 构建 stepPresentationData 后,在开发模式下写入部分快照
  • 上下文引擎捕获:apps/server/src/modules/AgentRuntime/RuntimeExecutors.ts — 在 call_llm 执行器中,serverMessagesEngine() 返回后调用 ctx.tracingContextEngine(input, output, metadata)。AgentRuntimeService.executeStep 会按步骤缓冲该数据,并将其作为有类型的 contextEngine 字段传递给 traceRecorder.appendStep(不放入 events 数组,以避免进入 Redis 状态)。
  • 存储:FileSnapshotStore 会读写相对于 process.cwd() 的 .agent-tracing/

评论

支持 Markdown