mcpField
B
braintrust-tracing

braintrust-tracing

github.com/parcadeiAgent 工作流3.9k497 次安装39 周前更新
代码仓库

关于 braintrust-tracing

braintrust-tracing 是一套用于在 Braintrust 中追踪 Claude Code 会话的指南和 Hook 配置。它记录会话、轮次、工具及 LLM Span,并介绍对独立子 Agent 轨迹进行事后关联的方法。

主要功能

  1. 01记录会话和轮次 Span
  2. 02捕获工具与 LLM Span
  3. 03保存单会话追踪状态
  4. 04提供轨迹分析命令
  5. 05说明子 Agent 轨迹的事后关联

适用场景

  1. 01检查 Claude Code 会话活动
  2. 02通过 Hook 日志排查 Span 缺失
  3. 03基于父会话和子 Agent 轨迹构建数据集

MCP 相关

该项目介绍将 Claude Code 会话轨迹发送到 Braintrust 的 Hook;它不是 MCP 服务。README 未说明 MCP 集成。

安装

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

$npx skills add https://github.com/parcadei/continuous-claude-v3 --skill braintrust-tracing

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

详细介绍

Claude Code 的 Braintrust 追踪

在 Braintrust 中追踪 Claude Code 会话的综合指南,包括子 Agent 关联。

架构概览

                         PARENT SESSION
                    +---------------------+
                    |  SessionStart       |
                    |  (creates root)     |
                    +----------+----------+
                               |
                    +----------v----------+
                    |  UserPromptSubmit   |
                    |  (creates Turn)     |
                    +----------+----------+
                               |
          +--------------------+--------------------+
          |                    |                    |
+---------v--------+  +--------v--------+  +--------v--------+
| PostToolUse      |  | PostToolUse     |  | PreToolUse      |
| (Read span)      |  | (Edit span)     |  | (Task - inject) |
+------------------+  +-----------------+  +--------+--------+
                                                    |
                                         +----------v----------+
                                         |   SUB-AGENT         |
                                         |   SessionStart      |
                                         |   (NEW root_span_id)|
                                         +----------+----------+
                                                    |
                                         +----------v----------+
                                         |   SubagentStop      |
                                         |   (has session_id)  |
                                         +---------------------+

Hook 事件流程

Hook触发条件创建内容关键字段
SessionStart会话开始根 Spansession_id、root_span_id
UserPromptSubmit用户发送提示词回合 Spanprompt、turn_number
PreToolUse工具运行前(修改 Task 提示词)tool_input.prompt
PostToolUse工具运行后工具 Spantool_name、input、output
Stop回合完成LLM Spanmodel、tokens、tool_calls
SubagentStop子 Agent 完成(无 Span)子 Agent 的 session_id
SessionEnd会话结束(完成根 Span)turn_count、tool_count

追踪层级

Session (task span) - root_span_id = session_id
|
+-- Turn 1 (task span)
|   |
|   +-- claude-sonnet (llm span) - model call with tool_use
|   +-- Read (tool span)
|   +-- Edit (tool span)
|   +-- claude-sonnet (llm span) - response after tools
|
+-- Turn 2 (task span)
|   |
|   +-- claude-sonnet (llm span)
|   +-- Task (tool span) -----> [Sub-agent session - SEPARATE trace]
|   +-- claude-sonnet (llm span)
|
+-- Turn 3 ...

子 Agent 追踪:可行与不可行之处

不可行之处

SessionStart 不会收到 Task 提示词。

我们尝试通过 PreToolUse 将追踪上下文注入 Task 提示词:

# PreToolUse hook injects:
[BRAINTRUST_TRACE_CONTEXT]
{"root_span_id": "abc", "parent_span_id": "xyz", "project_id": "123"}
[/BRAINTRUST_TRACE_CONTEXT]

但 SessionStart 只会收到会话元数据,不会收到修改后的提示词。注入的上下文会丢失。

可行之处

父会话中的 Task Span 包含所有信息:

  • agentId - 子 Agent 运行的标识符
  • totalTokens、totalToolUseCount - 指标
  • content - Agent 的完整响应/摘要
  • tool_input.prompt - 原始任务提示词
  • tool_input.subagent_type - Agent 类型(例如,“oracle”)

SubagentStop hook 会收到子 Agent 的 session_id:

  • 该值等于子 Agent 孤立追踪的 root_span_id
  • 可用于关联父 Task Span 与子追踪
关联模式

**当前状态:**子 Agent 会创建孤立追踪(新的 root_span_id)。

关联方法:

  1. 查询父会话的 Task Span,获取 Agent 元数据
  2. 将 agentId 或时间与孤立追踪进行匹配
  3. 子 Agent 的 session_id = 其追踪的 root_span_id

未来方案(尚未实现):

SubagentStop fires -> writes session_id to temp file
PostToolUse (Task) -> reads temp file -> adds child_session_id to Task span metadata

这样即可关联:Task.agentId + Task.child_session_id -> 孤立追踪的 root_span_id

状态管理

每个会话的状态文件
~/.claude/state/braintrust_sessions/
  {session_id}.json       # Per-session state

每个会话文件包含:

{
  "root_span_id": "abc-123",
  "project_id": "proj-456",
  "turn_count": 5,
  "tool_count": 23,
  "current_turn_span_id": "turn-789",
  "current_turn_start": 1703456789,
  "started": "2025-12-24T10:00:00.000Z",
  "is_subagent": false
}
全局状态
~/.claude/state/braintrust_global.json   # Cached project_id
~/.claude/state/braintrust_hook.log      # Debug log

调试命令

检查追踪是否处于活动状态
# View hook logs in real-time
tail -f ~/.claude/state/braintrust_hook.log

# Check if session has state
cat ~/.claude/state/braintrust_sessions/*.json | jq -s '.'

# Verify environment
echo "TRACE_TO_BRAINTRUST=$TRACE_TO_BRAINTRUST"
echo "BRAINTRUST_API_KEY=${BRAINTRUST_API_KEY:+set}"
直接查询 Braintrust
# List recent sessions
uv run python -m runtime.harness scripts/braintrust_analyze.py --sessions 5

# Analyze last session
uv run python -m runtime.harness scripts/braintrust_analyze.py --last-session

# Replay specific session
uv run python -m runtime.harness scripts/braintrust_analyze.py --replay <session-id>

# Find sub-agent traces (orphaned roots)
uv run python -m runtime.harness scripts/braintrust_analyze.py --agent-stats
调试 Hook 执行
# Enable verbose logging
export BRAINTRUST_CC_DEBUG=true

# Test hooks manually
echo '{"session_id":"test-123","type":"resume"}' | \
  bash "$CLAUDE_PROJECT_DIR/.claude/plugins/braintrust-tracing/hooks/session_start.sh"

# Test PreToolUse (Task injection)
echo '{"session_id":"test-123","tool_name":"Task","tool_input":{"prompt":"test"}}' | \
  bash "$CLAUDE_PROJECT_DIR/.claude/plugins/braintrust-tracing/hooks/pre_tool_use.sh"
敥障排查清单
  1. 没有出现追踪记录:

    • 检查 .claude/settings.local.json 中的 TRACE_TO_BRAINTRUST=true
    • 验证 API 密钥:echo $BRAINTRUST_API_KEY
    • 检查日志:tail -20 ~/.claude/state/braintrust_hook.log
  2. 子 Agent 未关联:

    • 这是预期行为——子 Agent 会创建孤立追踪
    • 使用 --agent-stats 查找 Agent 活动
    • 通过时间或父 Task Span 中的 agentId 进行关联
  3. Span 缺失:

    • 检查会话状态中的 current_turn_span_id
    • 确保 Stop hook 已运行(回合最终处理)
    • 在日志中查找“Failed to create”错误
  4. 状态损坏:

    • 移除会话状态:rm ~/.claude/state/braintrust_sessions/*.json
    • 清除全局缓存:rm ~/.claude/state/braintrust_global.json

关键文件

文件用途
.claude/plugins/braintrust-tracing/hooks/common.sh共享实用工具、API 和状态管理
.claude/plugins/braintrust-tracing/hooks/session_start.sh创建根 Span,处理子 Agent 上下文
.claude/plugins/braintrust-tracing/hooks/user_prompt_submit.sh为每条用户消息创建 Turn Span
.claude/plugins/braintrust-tracing/hooks/pre_tool_use.sh将追踪上下文注入 Task 提示词
.claude/plugins/braintrust-tracing/hooks/post_tool_use.sh创建工具 Span,捕获 Agent/技能元数据
.claude/plugins/braintrust-tracing/hooks/stop_hook.sh创建 LLM Span,结束 Turn
.claude/plugins/braintrust-tracing/hooks/session_end.sh结束会话,触发学习内容提取
scripts/braintrust_analyze.py查询和分析追踪的会话
~/.claude/state/braintrust_sessions/每个会话的状态文件
~/.claude/state/braintrust_hook.log调试日志

环境变量

变量必需默认值说明
TRACE_TO_BRAINTRUST是-设置为 "true" 以启用
BRAINTRUST_API_KEY是-Braintrust 的 API 密钥
BRAINTRUST_CC_PROJECT否claude-code项目名称
BRAINTRUST_CC_DEBUG否false详细日志记录
BRAINTRUST_API_URL否https://api.braintrust.devAPI 端点

会话学习成果

我们对子 Agent 追踪的发现(2025 年 12 月)

尝试方案: 通过 PreToolUse 将追踪上下文注入 Task 提示词。

结果: 失败——SessionStart 只接收会话元数据,不接收提示词。

发现: Task Span 已包含丰富的子 Agent 数据:

  • metadata.agent_type - 来自 subagent_type 的 Agent 类型
  • metadata.skill_name - 来自 Skill 工具的技能
  • tool_input - 发送给 Agent 的完整提示词
  • tool_output - Agent 的响应

当前关联路径:

  1. 父会话 Task Span 包含 agentId 和时间信息
  2. 子 Agent 创建孤立追踪,其 root_span_id = session_id
  3. SubagentStop 提供子 Agent 的 session_id
  4. 手动关联:匹配时间信息或使用 session_id 链接

后续工作: 在 SubagentStop 之后,通过 PostToolUse 将 child_session_id 写入 Task Span 元数据。

我们对关联子 Agent 的发现

问题
  • 通过 Task 工具生成的子 Agent 会创建孤立的 Braintrust 追踪
  • 父会话有包含 agentId 的 Task Span,子 Agent 则有单独的 session_id
  • 两者之间没有内置链接
不起作用的方式

1. 通过 PreToolUse 注入提示词

SessionStart Hook 只接收会话元数据(session_id、type、cwd),不会接收提示词。注入的追踪上下文永远不会被看到。

Hook 收到的内容:

{
  "session_id": "...",
  "type": "start|resume|compact|clear",
  "cwd": "...",
  "env": {...}
}

不存在提示词字段,因此不可能在 SessionStart 时注入上下文。

2. SubagentStop → PostToolUse 文件交接

存在竞态条件。这些是独立的异步 Hook,没有时序保证:

  • 子 Agent 会话结束时触发 SubagentStop
  • Task 工具完成时触发 PostToolUse(Task)
  • 两者之间没有顺序保证
  • 写入关联文件会造成竞态

3. PreToolUse 关联文件

SessionStart 无法访问 task_span_id,因为它没有关于哪个 Task 生成了该会话的上下文。PreToolUse 会修改提示词,但不会创建 SessionStart 能可靠访问的状态文件。

有效的做法

事后匹配以构建数据集:

父会话的 Task span 包含:

  • agentId - 子 Agent 运行的标识符
  • totalTokens、totalToolUseCount - 汇总指标
  • content - 完整的 Agent 响应/摘要
  • tool_input.prompt - 原始任务提示词
  • tool_input.subagent_type - Agent 类型(例如,“oracle”)
  • 开始/结束时间戳

子 Agent 会话包含:

  • session_id(等于孤立 trace 的 root_span_id)
  • 开始/结束时间戳
  • 所有内部 span 和工具调用

关联策略:

  1. 导出父会话 trace(查询父级 root_span_id)
  2. 导出子 Agent trace(查询在父会话时间范围内创建的所有会话)
  3. 根据以下信息进行匹配:
    • 时间:Task span 结束时间 ≈ 子 Agent 会话结束时间
    • 元数据:Task 提示词中的 subagent_type
    • ID:SubagentStop hook 提供 session_id(可将其捕获并记录)
架构方面的认识

SessionStart 输入刻意保持精简——其中不包含提示词或工具上下文:

interface SessionStartInput {
  session_id: string;
  type: "start" | "resume" | "compact" | "clear";
  cwd: string;
  env: { [key: string]: string };
  // NO: prompt, tool_context, task_span_id, parent_span_id
}

这种设计边界使 hook 执行时无法进行实时关联。

建议

如需构建带有子 Agent 关联信息的 Agent 运行数据集:

  1. 会话内记录: 在日志或状态中捕获 SubagentStop session_id
  2. 会话结束后导出: 通过 Braintrust API 查询父级和子 Agent trace
  3. 离线关联: 在脚本中根据时间和元数据匹配 trace
  4. 不要尝试实时关联: hook 不具备必要的上下文

脚本示例模式:

# 1. Export parent session
braintrust_analyze.py --replay <parent-session-id> > parent_traces.json

# 2. Query for orphaned sub-agent traces (those created during parent's time window)
braintrust_analyze.py --agent-stats > all_agent_traces.json

# 3. Correlate in Python:
#    - Parent Task spans -> agentId, timestamps, subagent_type
#    - Orphaned traces -> root_span_id, timestamps
#    - Match by timing and type

这种方法可靠、可测试,而且不需要 hook 维护隐式状态。

评论

支持 Markdown