关于 agent-tracing
agent-tracing 是用于本地开发的记录与检查工具,可保存并查看 LobeHub Agent 执行过程和目标轨迹。它还支持重放已记录的模型调用,并分析上下文窗口与缓存情况。
主要功能
- 01本地记录执行快照
- 02检查操作与目标轨迹
- 03跨模型重放冻结的 LLM 调用
- 04查看上下文与前缀缓存
适用场景
- 01调试 Agent 执行步骤
- 02比较固定调用的模型输出
- 03检查目标决策与候选工作项
- 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 时,输出会显示以下三个部分(如果有上下文引擎数据):
- 上下文引擎输入 — 传递给引擎的 DB 消息,带有
[0]、[1]……索引。使用--msg-input N查看完整内容。 - 上下文引擎参数 — systemRole、model、provider、knowledge、tools、userMemory 等。
- 最终 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/