关于 massgen-log-analyzer
为 MassGen 实验提供运行、追踪和日志分析流程的技能,面向调试多 Agent 协作与性能的开发者。可结合 Logfire 查询追踪,也能从本地日志生成 Markdown 报告。
主要功能
- 01运行并监测 MassGen 实验
- 02分析本地日志与 Logfire 追踪
- 03检查 Agent 行为和协作
- 04定位性能瓶颈与异常
- 05生成 Markdown 分析报告
适用场景
- 01排查 Agent 重试及失败原因
- 02比较多轮实验的耗时表现
- 03分析工具调用和投票决策
MCP 相关
可选配置 Logfire MCP 服务,以查询追踪数据、查找异常并创建追踪链接;未配置时可仅分析本地日志。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ massgen/ massgen --skill massgen-log-analyzer安装后在 Claude Code 中输入/massgen-log-analyzer确认已加载。
详细介绍
MassGen 日志分析器
此技能提供了一套结构化工作流,用于运行 MassGen 实验,并使用 Logfire 分析生成的跟踪记录和日志。
用途
日志分析器技能可帮助你:
- 使用适当的检测机制运行 MassGen 实验
- 分层查询和分析跟踪记录
- 调试 Agent 行为和协作模式
- 衡量性能并识别瓶颈
- 改进日志结构本身
- 生成 Markdown 分析报告并保存到日志目录
CLI 快速参考
massgen logs CLI 提供了快速访问日志分析的方式:
列出日志及其分析状态
uv run massgen logs list # Show all recent logs with analysis status
uv run massgen logs list --analyzed # Only logs with ANALYSIS_REPORT.md
uv run massgen logs list --unanalyzed # Only logs needing analysis
uv run massgen logs list --limit 20 # Show more logs
生成分析提示词
# Run from within your coding CLI (e.g., Claude Code) so it sees output
uv run massgen logs analyze # Analyze latest turn of latest log
uv run massgen logs analyze --log-dir PATH # Analyze specific log
uv run massgen logs analyze --turn 1 # Analyze specific turn
提示词输出会告知你的编码 CLI 在指定的日志目录中使用此技能。
多 Agent 自我分析
uv run massgen logs analyze --mode self # Run 3-agent analysis team (prompts if report exists)
uv run massgen logs analyze --mode self --force # Overwrite existing report without prompting
uv run massgen logs analyze --mode self --turn 2 # Analyze specific turn
uv run massgen logs analyze --mode self --config PATH # Use custom config
自我分析模式会运行 MassGen,让多个 Agent 从不同角度(正确性、效率、行为)分析日志,并生成一份综合的 ANALYSIS_REPORT.md。
多轮会话
MassGen 日志目录支持多轮(协作会话)。每一轮都有自己的 turn_N/ 目录,其中包含各次尝试:
log_YYYYMMDD_HHMMSS/
├── turn_1/ # First coordination session
│ ├── ANALYSIS_REPORT.md # Report for turn 1
│ ├── attempt_1/ # First attempt
│ └── attempt_2/ # Retry if orchestration restarted
├── turn_2/ # Second coordination session (if multi-turn)
│ ├── ANALYSIS_REPORT.md # Report for turn 2
│ └── attempt_1/
分析时,--turn 标志用于指定要分析的轮次。不指定时,将分析最新一轮。
何时使用 Logfire,何时使用本地日志
在以下情况下使用本地日志文件:
- 分析命令模式和重复情况(命令位于
streaming_debug.log) - 检查详细的工具参数和输出(位于
coordination_events.json) - 查看投票理由和 Agent 决策(位于
agent_*/*/vote.json) - 查看协调流程表(位于
coordination_table.txt) - 获取费用和令牌汇总(位于
metrics_summary.json)
在以下情况下使用 Logfire:
- 需要精确到毫秒的计时数据
- 分析 Span 层级和父子关系
- 查找异常和错误堆栈跟踪
- 创建可分享的追踪链接以便协作
- 跨多个会话查询(例如,“查找所有出错的会话”)
- 实时监控正在运行的实验
**速率限制:**如果 Logfire 返回速率限制错误,请等待最多 60 秒后重试,而不是改用本地日志。速率限制会很快重置;当需要进行计时/层级分析时,等待 Logfire 数据是值得的。
主要本地日志文件:
| 文件 | 内容 |
|---|---|
status.json | 实时状态,包含 Agent 可靠性指标(强制执行事件、缓冲区丢失) |
metrics_summary.json | 费用、令牌、工具统计数据、轮次历史记录 |
coordination_events.json | 包含工具调用的完整事件时间线 |
coordination_table.txt | 易于阅读的协调流程 |
streaming_debug.log | 原始流式数据,包括命令字符串 |
agent_*/*/vote.json | 投票理由和上下文 |
agent_*/*/execution_trace.md | 完整的工具调用、参数、结果和推理过程——对调试非常有用 |
execution_metadata.yaml | 配置和会话元数据 |
执行追踪(execution_trace.md):
这是最详细的调试资料。每个 Agent 快照都包含一份执行追踪,其中包括:
- 完整的工具调用及完整参数(未截断)
- 完整的工具结果(未截断)
- 来自模型的推理/思考内容块
- 时间戳和轮次标记
当你需要确切了解某个 Agent 做了什么以及原因时,请使用执行追踪——它会记录 Agent 在该次回答/投票迭代中看到和生成的所有内容。
强制执行可靠性(status.json):
status.json 文件包含按 Agent 划分的可靠性指标,用于跟踪工作流强制执行事件:
{
"agents": {
"agent_a": {
"reliability": {
"enforcement_attempts": [
{
"round": 0,
"attempt": 1,
"max_attempts": 3,
"reason": "no_workflow_tool",
"tool_calls": ["search", "read_file"],
"error_message": "Must use workflow tools",
"buffer_preview": "First 500 chars of lost content...",
"buffer_chars": 1500,
"timestamp": 1736683468.123
}
],
"by_round": {"0": {"count": 2, "reasons": ["no_workflow_tool", "invalid_vote_id"]}},
"unknown_tools": ["execute_command"],
"workflow_errors": ["invalid_vote_id"],
"total_enforcement_retries": 2,
"total_buffer_chars_lost": 3000,
"outcome": "ok"
}
}
}
}
强制执行原因代码:
| 原因 | 说明 |
|---|---|
no_workflow_tool | Agent 调用了工具,但没有调用 vote 或 new_answer |
no_tool_calls | Agent 仅提供文本响应,未调用任何工具 |
invalid_vote_id | Agent 投票给了不存在的 Agent ID |
vote_no_answers | Agent 在没有答案时尝试投票 |
vote_and_answer | Agent 在同一响应中同时使用了 vote 和 new_answer |
answer_limit | Agent 达到答案数量上限 |
answer_novelty | 答案与现有答案过于相似 |
answer_duplicate | 答案与现有答案完全重复 |
api_error | API/流式传输错误(例如,“peer closed connection”) |
connection_recovery | API 流提前结束,已通过保留的上下文恢复 |
mcp_disconnected | MCP 服务在会话中途断开连接(例如,“Server 'X' not connected”) |
这些数据对于了解Agent 为何需要重试以及强制执行重启导致丢失了多少内容非常有用。
Logfire 设置
使用此技能前,需要先设置 Logfire 以实现可观测性。
步骤 1:安装支持可观测性的 MassGen
pip install "massgen[observability]"
# Or with uv
uv pip install "massgen[observability]"
步骤 2:创建 Logfire 账户
前往 https://logfire.pydantic.dev/,创建免费账户。
步骤 3:通过 Logfire 进行身份验证
# This creates ~/.logfire/credentials.json
uv run logfire auth
# Or set the token directly as an environment variable
export LOGFIRE_TOKEN=your_token_here
步骤 4:获取 MCP 服务的读取令牌
- 前往 https://logfire.pydantic.dev/ 并登录
- 前往项目设置
- 创建一个读取令牌(这与用于身份验证的写入令牌不同)
- 复制此令牌,以便在步骤 5 中使用
第 5 步:添加 Logfire MCP 服务
claude mcp add logfire -e LOGFIRE_READ_TOKEN="your-read-token-here" -- uvx logfire-mcp@latest
然后重启 Claude Code,并再次调用此技能。
前置条件
Logfire MCP 服务(可选,但推荐):
Logfire MCP 服务可通过精确的时间数据和跨会话查询增强分析能力。如果未设置 LOGFIRE_READ_TOKEN,自分析模式将自动禁用 Logfire MCP,并仅回退到本地日志文件。
配置后,MCP 服务会提供以下工具:
mcp__logfire__arbitrary_query- 对 logfire 数据运行 SQL 查询mcp__logfire__schema_reference- 获取数据库架构mcp__logfire__find_exceptions_in_file- 在文件中查找异常mcp__logfire__logfire_link- 创建指向 UI 中跟踪记录的链接
必需标志:
--automation- 为程序化解析生成简洁输出;有关此标志的更多信息,请参阅massgen-develops-massgen技能--logfire- 启用 Logfire 跟踪(可选,但填充 Logfire 数据时必需)
第 1 部分:运行 MassGen 实验
基本命令格式
uv run massgen --automation --logfire --config [config_file] "[question]"
在后台运行(推荐)
使用 run_in_background: true(或以其他方式在后台运行任务)异步运行实验,以便监控进度并在需要时提前结束。
预期输出(前几行):
LOG_DIR: .massgen/massgen_logs/log_YYYYMMDD_HHMMSS_ffffff
STATUS: .massgen/massgen_logs/log_YYYYMMDD_HHMMSS_ffffff/turn_1/attempt_1/status.json
QUESTION: Your task here
[Coordination in progress - monitor status.json for real-time updates]
解析 LOG_DIR——文件分析时需要用到它!
监控进度
status.json 每 2 秒更新一次;可用它跟踪进度。
cat [log_dir]/turn_1/attempt_1/status.json
需监控的关键字段:
coordination.completion_percentage(0-100)coordination.phase- "initial_answer"、"enforcement"、"presentation"results.winner- 运行期间为 null,完成后为 agent_idagents[].status- "waiting"、"streaming"、"answered"、"voted"、"error"agents[].error- 正常时为 null,失败时为错误详情
读取最终结果
完成后(退出代码为 0):
# Read the final answer
cat [log_dir]/turn_1/attempt_1/final/[winner]/answer.txt
其他有用文件:
execution_metadata.yaml- 完整配置和执行详情coordination_events.json- 完整事件日志coordination_table.txt- 易读的协调摘要
第 2 部分:查询 Logfire
数据库架构
主表为 records,包含以下关键列:
| 列 | 说明 |
|---|---|
span_name | span 的名称(例如,“agent.agent_a.round_0”) |
span_id | 此 span 的唯一标识符 |
parent_span_id | 父 span 的 ID(根 span 为 null) |
trace_id | 对单个跟踪记录中的所有 span 进行分组 |
duration | 时间,单位为秒 |
start_timestamp | span 的开始时间 |
end_timestamp | span 的结束时间 |
attributes | 包含自定义属性的 JSON 数据 |
message | 日志消息 |
is_exception | 表示是否发生错误的布尔值 |
exception_type | 异常类型(如果有) |
exception_message | 异常消息 |
MassGen Span 层级结构
MassGen 会创建分层 span:
coordination.session (root)
├── Coordination event: coordination_started
├── agent.agent_a.round_0
│ ├── llm.openrouter.stream
│ ├── mcp.filesystem.write_file
│ └── Tool execution: mcp__filesystem__write_file
├── agent.agent_b.round_0
├── Agent answer: agent1.1
├── agent.agent_a.round_1 (voting round)
├── Agent vote: agent_a -> agent1.1
├── Coordination event: winner_selected
└── agent.agent_a.presentation
├── Winner selected: agent1.1
├── llm.openrouter.stream
└── Final answer from agent_a
自定义属性
MassGen 跨度包含以下自定义属性(通过 attributes->'key' 访问):
| 属性 | 描述 |
|---|---|
massgen.agent_id | Agent 标识符(agent_a、agent_b) |
massgen.iteration | 当前迭代次数 |
massgen.round | 此 Agent 的轮次编号 |
massgen.round_type | “initial_answer”、“voting” 或 “presentation” |
massgen.backend | 后端提供方名称 |
massgen.num_context_answers | 上下文中的答案数量 |
massgen.is_winner | 在 presentation 跨度中为 True |
massgen.outcome | “vote”、“answer” 或 “error”(轮次完成后设置) |
massgen.voted_for | 投票选中的 Agent ID(仅对投票设置) |
massgen.voted_for_label | 投票选中的答案标签(例如,“agent1.1”,仅对投票设置) |
massgen.answer_label | 分配的答案标签(例如,“agent1.1”,仅对答案设置) |
massgen.error_message | 错误消息(仅当 outcome 为 “error” 时设置) |
massgen.usage.input | 输入 token 数量 |
massgen.usage.output | 输出 token 数量 |
massgen.usage.reasoning | 推理 token 数量 |
massgen.usage.cached_input | 缓存的输入 token 数量 |
massgen.usage.cost | 以 USD 计的估算成本 |
第 3 部分:常见分析查询
1. 查看追踪层级
SELECT span_name, span_id, parent_span_id, duration, start_timestamp
FROM records
WHERE trace_id = '[YOUR_TRACE_ID]'
ORDER BY start_timestamp
LIMIT 50
2. 查找近期会话
SELECT span_name, trace_id, duration, start_timestamp
FROM records
WHERE span_name = 'coordination.session'
ORDER BY start_timestamp DESC
LIMIT 10
3. Agent 轮次性能
SELECT
span_name,
duration,
attributes->>'massgen.agent_id' as agent_id,
attributes->>'massgen.round' as round,
attributes->>'massgen.round_type' as round_type
FROM records
WHERE span_name LIKE 'agent.%'
ORDER BY start_timestamp DESC
LIMIT 20
4. 工具调用分析
SELECT
span_name,
duration,
parent_span_id,
start_timestamp
FROM records
WHERE span_name LIKE 'mcp.%' OR span_name LIKE 'Tool execution:%'
ORDER BY start_timestamp DESC
LIMIT 30
5. 查找错误
SELECT
span_name,
exception_type,
exception_message,
trace_id,
start_timestamp
FROM records
WHERE is_exception = true
ORDER BY start_timestamp DESC
LIMIT 20
6. 大模型调用性能
SELECT
span_name,
duration,
attributes->>'gen_ai.request.model' as model,
start_timestamp
FROM records
WHERE span_name LIKE 'llm.%'
ORDER BY start_timestamp DESC
LIMIT 30
7. 包含层级结构的完整追踪(嵌套视图)
SELECT
CASE
WHEN parent_span_id IS NULL THEN span_name
ELSE ' └─ ' || span_name
END as hierarchy,
duration,
span_id,
parent_span_id
FROM records
WHERE trace_id = '[YOUR_TRACE_ID]'
ORDER BY start_timestamp
8. 协调事件时间线
SELECT span_name, message, duration, start_timestamp
FROM records
WHERE span_name LIKE 'Coordination event:%'
OR span_name LIKE 'Agent answer:%'
OR span_name LIKE 'Agent vote:%'
OR span_name LIKE 'Winner selected:%'
ORDER BY start_timestamp DESC
LIMIT 30
第 4 部分:分析工作流
第 1 步:运行实验
uv run massgen --automation --logfire --config [config] "[prompt]" 2>&1
第 2 步:查找追踪
查询近期会话:
SELECT trace_id, duration, start_timestamp
FROM records
WHERE span_name = 'coordination.session'
ORDER BY start_timestamp DESC
LIMIT 5
第 3 步:分析层级结构
获取完整追踪结构:
SELECT span_name, span_id, parent_span_id, duration
FROM records
WHERE trace_id = '[trace_id_from_step_2]'
ORDER BY start_timestamp
第 4 步:调查具体问题
工具调用缓慢:
SELECT span_name, duration, parent_span_id
FROM records
WHERE trace_id = '[trace_id]' AND span_name LIKE 'mcp.%'
ORDER BY duration DESC
Agent 对比:
SELECT
attributes->>'massgen.agent_id' as agent,
COUNT(*) as rounds,
SUM(duration) as total_time,
AVG(duration) as avg_round_time
FROM records
WHERE trace_id = '[trace_id]' AND span_name LIKE 'agent.%'
GROUP BY attributes->>'massgen.agent_id'
第 5 步:创建追踪链接
使用 MCP 工具创建可查看的链接:
mcp__logfire__logfire_link(trace_id="[your_trace_id]")
第 5 部分:改进日志结构
当前跨度类型
| 跨度模式 | 来源 | 描述 |
|---|---|---|
coordination.session | coordination_tracker.py | 根会话跨度 |
agent.{id}.round_{n} | orchestrator.py | Agent 执行轮次 |
agent.{id}.presentation | orchestrator.py | 获胜者的最终展示 |
mcp.{server}.{tool} | mcp_tools/client.py | MCP 工具执行 |
llm.{provider}.stream | backends | 大模型流式调用 |
Tool execution: {name} | base_with_custom_tool.py | 工具包装器 |
Coordination event: * | coordination_tracker.py | 协调事件 |
Agent answer: {label} | coordination_tracker.py | 答案提交 |
Agent vote: {from} -> {to} | coordination_tracker.py | 投票 |
添加新跨度
使用 structured_logging 中的 tracer:
from massgen.structured_logging import get_tracer
tracer = get_tracer()
with tracer.span("my_operation", attributes={
"massgen.custom_key": "value",
}):
do_work()
上下文传播说明
已知限制: 多个 Agent 通过 asyncio.create_task 并发运行时,子跨度可能无法正确嵌套在 Agent 轮次跨度下。这是 OpenTelemetry 在并发异步代码中的上下文传播问题。由于 presentation 阶段只有一个 Agent 运行,因此该阶段可以正常工作。
解决方法: 若要在并发场景中实现准确嵌套,需要通过 contextvars.copy_context() 显式传递上下文。
Logfire 文档参考
主要文档: https://logfire.pydantic.dev/docs/
需要了解的关键页面
| 主题 | URL | 描述 |
|---|---|---|
| 快速入门 | /docs/ | 概览、设置和核心概念 |
| 手动追踪 | /docs/guides/onboarding-checklist/add-manual-tracing/ | 创建 span、添加属性 |
| SQL 浏览器 | /docs/guides/web-ui/explore/ | 在界面中编写 SQL 查询 |
| 实时视图 | /docs/guides/web-ui/live/ | 实时追踪监控 |
| 查询 API | /docs/how-to-guides/query-api/ | 以编程方式访问数据 |
| OpenAI 集成 | /docs/integrations/llms/openai/ | 对大模型调用进行插桩 |
Logfire 概念
Span 与日志:
- Span 表示具有可测量持续时间的操作(使用
with logfire.span():) - 日志 捕获某一时刻发生的事件(使用
logfire.info()、logfire.error()等) - Span 块内的 span 和日志会成为该 span 的子项
Span 名称与消息:
span_name= 第一个参数(用于筛选,应保持低基数)message= 插入属性值后格式化得到的结果- 示例:
logfire.info('Hello {name}', name='Alice')→ span_name="Hello {name}", message="Hello Alice"
属性:
- 关键字参数会成为结构化 JSON 属性
- 在 SQL 中通过
attributes->>'key'或attributes->'key'访问 - 按需转换类型:
(attributes->'cost')::float
实时视图功能
Logfire 实时视图界面(https://logfire.pydantic.dev/)提供:
- 实时流式传输,在追踪到达时显示
- SQL 搜索窗格(按
/打开),支持自动补全 - 自然语言转 SQL——描述所需内容并获取查询
- 时间线直方图,显示一段时间内的 span 数量
- 追踪详情面板,包含属性、异常和 OpenTelemetry 数据
- 交叉链接,通过 trace_id/span_id 在 SQL 结果和追踪视图之间跳转
SQL 浏览器提示
Explore 页面使用 Apache DataFusion SQL 语法(类似 Postgres):
-- Subqueries and CTEs work
WITH recent AS (
SELECT * FROM records
WHERE start_timestamp > now() - interval '1 hour'
)
SELECT * FROM recent WHERE is_exception;
-- Access nested JSON
SELECT attributes->>'massgen.agent_id' as agent FROM records;
-- Cast JSON values
SELECT (attributes->'token_count')::int as tokens FROM records;
-- Time filtering is efficient
WHERE start_timestamp > now() - interval '30 minutes'
大模型插桩
配置后,Logfire 会自动为 OpenAI 调用插桩:
- 捕获对话显示内容、令牌用量和响应元数据
- 为流式请求和响应分别创建 span
- 同时适用于同步和异步客户端
MassGen 的后端使用此功能创建 llm.{provider}.stream span。
参考文档
Logfire:
- 主文档:https://logfire.pydantic.dev/docs/
- 实时视图:https://logfire.pydantic.dev/docs/guides/web-ui/live/
- SQL 浏览器:https://logfire.pydantic.dev/docs/guides/web-ui/explore/
- 查询 API:https://logfire.pydantic.dev/docs/how-to-guides/query-api/
- 手动追踪:https://logfire.pydantic.dev/docs/guides/onboarding-checklist/add-manual-tracing/
- OpenAI 集成:https://logfire.pydantic.dev/docs/integrations/llms/openai/
- Schema 参考:使用
mcp__logfire__schema_reference工具
MassGen:
- 自动化模式:
AI_USAGE.md - 状态文件参考:
docs/source/reference/status_file.rst - 结构化日志:
massgen/structured_logging.py
高效分析提示
- 始终同时使用两个标志:
--automation --logfire - 长任务应在后台运行,以便监控进度
- 按 trace_id 查询,以隔离特定会话
- 检查 parent_span_id,以了解层级关系
- 使用 duration 识别瓶颈
- 查看 attributes,了解 MassGen 特定上下文
- 创建追踪链接,与团队分享发现
请注意,你可能会遇到如下错误:
Error: Error executing tool arbitrary_query: b'{"detail":"Rate limit exceeded for organization xxx: per minute
limit reached."}'
遇到这种情况时,请等待片刻(最多一分钟)后重试。
第 6 部分:全面日志分析报告
收到分析 MassGen 日志运行的请求时,请生成一份 Markdown 报告,并保存到 [log_dir]/turn_N/ANALYSIS_REPORT.md,其中 N 为正在分析的轮次。每个轮次(协调会话)都应有独立的分析报告,与尝试目录处于同一级。报告必须涵盖下方的标准分析问题。
重要:基准答案与正确性
关键:除非用户明确提供基准答案,否则不要假定任何 Agent 的回答是“正确的”。
- 报告每个 Agent 声称或给出的内容,不要断言其正确性
- 说明 Agent 之间是否一致或有分歧,但不要声称一致就代表正确
- 如果 Agent 给出的答案不同,请中立地呈现双方答案
- 只有在用户提供实际答案时,才将答案标记为正确或错误
- 避免使用的表述:“正确地识别出”“给出了正确答案”“正确地解决了”
- 建议使用的表述:“声称”“给出”“提交”“得出”
标准分析问题
每份分析报告都必须回答以下问题:
1. 正确性
- 协调是否成功完成?
- 所有 Agent 是否都提交了答案?
- 投票是否正确进行?
- 是否选出了获胜者,且该 Agent 是否给出了最终答案?
2. 效率与瓶颈
- 总耗时是多少,各阶段分别耗时多少?
- 最慢的操作有哪些?
- 哪些工具耗时最长?
- 构建一张按 Agent 排序的逐轮计时表,包括:
- 回合开始/结束时间戳
- 回合总耗时
- 工具墙钟时间
- 非工具耗时(模型/流式传输/等待)
- 将每个包含清单的回合拆分为:
- 评估 = 回合开始 -> 首次
submit_checklist开始 - 清单->提议 = 首次
submit_checklist结束 -> 首次draft_approach开始 - 实施 = 首次
draft_approach结束 -> 回合结束 - 清单后(无提议) = 首次
submit_checklist结束 -> 回合结束(若未进行draft_approach)
- 评估 = 回合开始 -> 首次
- 报告评估与实施的时间占比:
- 在所有包含清单的时段中
- 仅在实际包含
draft_approach的时段中
3. 命令模式分析
- 是否频繁重复执行了本可避免的命令?(例如
openskills read、npm install、ls -R) - 哪些命令产生了不必要的长输出?(例如技能文档、目录列表)
- 最慢的
execute_command模式有哪些?(例如网页抓取、软件包安装)
4. 工作重复分析
- 是否不必要地重复了耗时的工作(例如图像生成)?
- 两个 Agent 是否生成了相似/相同的素材?
- 是否在重启后重新生成素材,而没有复用?
- 缓存或共享是否可以节省时间/成本?
5. Agent 行为与决策
- **Agent 如何评估之前的答案?**他们给出了什么推理?
- Agent 如何决定投票还是提供新答案?
- Agent 是否确实在彼此工作的基础上继续推进,还是各自独立工作?
- 是否发生超时或未完成的回合?
6. 成本与 Token 分析
- 总成本及各 Agent 的成本明细
- Token 用量(输入、输出、推理、缓存)
- 缓存命中率
7. 错误与问题
- 是否发生异常或失败?
- 是否发生超时?
- 是否存在 Agent 错误?
8. Agent 推理与行为分析(关键)
这是最重要的部分。 分析 Agent 的思考和行动方式,有助于揭示成功与失败的根本原因。
数据来源:
agent_outputs/agent_*.txt- 完整输出,包括推理内容(如果有)agent_*/*/execution_trace.md- 完整的工具调用、参数和结果streaming_debug.log- 原始流式数据块
注意:某些模型不会输出明确的推理轨迹。对于这些模型,应改为分析工具调用模式和内容——行动顺序依然能体现决策过程。
对每个 Agent 进行分析:
- 策略 - 它们采取了什么方法?(根据推理内容或工具调用顺序)
- 工具响应 - 它们如何处理成功、失败或不一致的结果?
- 错误恢复 - 它们是否发现了问题?是否采取了变通方案?
- 决策质量 - 是否存在逻辑错误?验证过度或不足?分析瘫痪?
- 跨 Agent 比较 - 哪个 Agent 的推理最佳?哪些模式带来了成功?
关键模式:
| 模式 | 良好表现 | 不良表现 |
|---|---|---|
| 故障检测 | 失败 2-3 次后调整方向 | 6 次或更多地重复无效方法 |
| 结果验证 | 交叉验证输出 | 不加核实地接受第一个结果 |
| 不一致处理 | 调查冲突 | 忽略矛盾 |
| 变通方案 | 陷入困境时寻找创造性的替代方案 | 放弃或陷入循环 |
| 时间管理 | 有把握时提交 | 无休止地验证,不给出答案 |
**提取关键证据:**对每个 Agent,引用 2-3 条内容(如果有推理记录),或描述能体现其决策质量的关键工具调用顺序。
9. 工具可靠性分析
分析工具行为模式,而不只是简单列出错误:
- 一致性 - 相同输入是否得到相同输出?记录差异。
- 误报/漏报 - 工具是否错误地报告成功或失败状态?
- 根因假设 - 针对每种故障模式,提出可能的原因(路径问题、速率限制、模型限制等)。
10. 强制执行与工作流可靠性分析
数据来源:status.json → agents[].reliability
检查 Agent 是否因违反工作流而需要重试。关键指标:
total_enforcement_retries- Agent 被强制重试的次数total_buffer_chars_lost- 因重启而丢弃的内容量unknown_tools- 幻觉出的工具名称by_round- 出现问题的轮次
**危险信号:**每轮重试 >=2 次、丢失 >5000 个字符、unknown_tools 列表非空。
完整的数据结构和原因代码,请参阅“关键本地日志文件”部分中的“强制执行可靠性”。
11. 答案质量的演进
数据来源:agent_outputs/agent_*.txt、agent_*/*/execution_trace.md、agent_*/*/vote.json
对每个 Agent,追踪其答案质量在各轮中的变化:
- 答案 N 与答案 N+1 之间具体发生了哪些变化?
- 这些变化是实质性的(新方法、新功能、结构改进)还是表面性的(措辞上的细微调整、小幅风格修改)?
- 是否有 Agent 在看到其他人的答案后退步,给出了更差的答案?
- 哪些评估标准逐轮改善,哪些停滞不前?
对每轮之间的变化评分:
- 🟢 实质性改进 — 至少在一个重要维度上有明显提升
- 🟡 边际改进 — 表述更加完善,但没有新增能力或见解
- 🔴 没有改进 / 出现退步 — 尽管付出了成本,答案仍相同或更差
12. 改进提案质量
数据来源: agent_outputs/agent_*.txt(查找差距分析、诊断部分、改进计划)、agent_*/*/vote.json
在给出每个新答案之前,Agent(或协调系统)都会提出改进建议。逐项分析:
- 具体性:提案是否指出了问题失败的原因,还是只说明问题失败了?(“动画时长与 5 秒观看窗口不匹配”与“改进动画”)
- 可执行性:下游 Agent 能否无需额外推理就实施该提案?
- 准确性:提案是否正确诊断了根本问题,还是只处理了表面症状?
- 完整性:提案是否涵盖所有关键差距,还是遗漏了决定性的差异点?
评估每项提案:
| 提案 | 具体? | 可执行? | 准确? | 是否判断正确? |
|---|---|---|---|---|
| [提案摘要] | 是/否 | 是/否 | 是/否 | 是/否 — [原因] |
另请注明:改进建议是由 Agent 自行提出的(自我反思)、通过同行评估提出的,还是根据评估标准中的差距推断得出的。
13. 轮次投资回报(“值得吗?”)
数据来源: metrics_summary.json、coordination_events.json、Agent 输出
评估每一轮的投资回报:
- 成本:本轮的 token 数量 × 模型费率
- 耗时:本轮的实际用时(秒)
- 质量变化:与之前的最佳答案相比,发生了哪些实质性变化
- 结论:这一轮是否值得付出相应的成本和时间?
| 轮次 | Agent | 成本 | 耗时 | 质量变化 | 结论 |
|---|---|---|---|---|---|
| R0 | agent_a | $X | Xs | 基线 | — |
| R1 | agent_a | $X | Xs | [变化内容] | 🟢/🟡/🔴 |
检测边际收益递减:从哪一轮开始,额外迭代不再带来有意义的改进?系统是否错过了明确的停止时机?
另请标记:是否有 Agent 花费高成本进行轮次迭代,却只是验证结果,而非改进结果?
14. 委派与模型分配分析
数据来源: agent_outputs/agent_*.txt、execution_trace.md、metrics_summary.json
分析每个 Agent 的工作中,机械性任务与需要真正智能的任务各占多少比例,以及是否使用了合适的模型层级。
按轮次分类每个 Agent 的工作:
-
机械性任务(可预测、模板化、较弱的模型也能完成——且消耗的上下文足够多,值得委派):
- 结构验证(元素数量、尺寸检查、格式合规性)——尤其是会生成大量 shell 输出的任务
- 样板代码生成(循环、坐标计算、填充模板)——大量重复的代码块
- 二元清单评分(E1–E4 风格:功能 X 是否存在?)——涉及许多工具调用或较长输出时
- 证据收集(运行 shell 命令、解析输出、像素差异比较)——Token 成本高,但推理内容少
注意:任务状态更新、工作流工具调用等协议步骤不值得委派——它们所需上下文少,主模型在行内处理的成本很低。关键在于委派是否能节省有意义的 Token,而不仅仅是较弱模型理论上能否完成。
-
质量/智能(需要真正的推理、综合或创造力):
- 根因诊断(将症状与底层设计缺陷联系起来)
- 跨 Agent 综合(从 N 个答案中找出最佳要素,并规划混合方案)
- 创新方案设计(提出以往答案中都没有的功能或设计)
- 教学或领域推理(例如,“这个动画的节奏错过了 5s 的注意力窗口”)
- 权衡分析(针对特定目标,解释为何一种设计选择优于另一种)
针对每个 Agent/轮次,估算:
- 机械性任务与质量推理各占的百分比
- 哪些具体活动属于机械性任务,哪些需要智能
- 引用片段:机械式填充模板与真正的诊断洞见
总体评估:
- 整个运行中,机械性任务占总上下文(Token)的多少?
- 更便宜的模型(例如 Haiku)能否处理机械性任务,而不降低输出质量?
- 是否有质量至关重要的环节交给了较弱的子 Agent(或本应升级模型)?
- 如果将机械性任务分配给更便宜的模型层级,预计可节省多少成本?
各问题的数据来源
| 问题 | 主要来源 | 次要来源 |
|---|---|---|
| 正确性 | coordination_events.json、coordination_table.txt | Logfire 协调事件 |
| 效率 | metrics_summary.json | Logfire 耗时查询 |
| 命令模式 | streaming_debug.log(grep 搜索 "command":) | - |
| 工作重复 | streaming_debug.log(grep 搜索工具提示词/参数) | metrics_summary.json 工具计数 |
| Agent 决策 | agent_*/*/vote.json、coordination_events.json | Logfire 投票跨度 |
| 评估与实现耗时 | status.json、metrics_events.json | events.jsonl、Logfire 跨度时长 |
| 成本/Token | metrics_summary.json | Logfire 使用量属性 |
| 错误 | coordination_events.json、metrics_summary.json | Logfire is_exception=true |
| 执行情况 | status.json → agents[].reliability | - |
分析命令
查找重复的命令:
grep -o '"command": "[^"]*"' streaming_debug.log | sed 's/"command": "//;s/"$//' | sort | uniq -c | sort -rn | head -30
查找 generate_media 提示词(检查是否重复):
grep -o '"prompts": \[.*\]' streaming_debug.log
检查投票推理:
cat agent_*/*/vote.json | jq '.reason'
查找超时事件:
cat coordination_events.json | jq '.events[] | select(.event_type == "agent_timeout")'
计算每轮评估与实现的耗时(按 Agent 排序):
python - <<'PY'
import json
from collections import defaultdict
from pathlib import Path
base = Path(".")
status = json.loads((base / "status.json").read_text())
metrics = json.loads((base / "metrics_events.json").read_text())
def m(seconds):
return seconds / 60.0
def union(intervals):
if not intervals:
return 0.0
intervals = sorted(intervals)
cs, ce = intervals[0]
total = 0.0
for s, e in intervals[1:]:
if s <= ce:
ce = max(ce, e)
else:
total += ce - cs
cs, ce = s, e
total += ce - cs
return total
segments = []
for agent_id, agent_data in status["agents"].items():
rounds = sorted(agent_data.get("round_history", []), key=lambda r: r["start_time"])
for idx, r in enumerate(rounds, 1):
segments.append({
"agent": agent_id,
"seg_idx": idx,
"round_number": r["round_number"],
"round_type": r["round_type"],
"outcome": r["outcome"],
"start": float(r["start_time"]),
"end": float(r["end_time"]),
"duration": float(r["duration_ms"]) / 1000.0,
})
by_segment = defaultdict(list)
for t in metrics["tool_executions"]:
ts = float(t["start_time"])
te = float(t["end_time"])
candidates = [
s for s in segments
if s["agent"] == t["agent_id"] and not (te < s["start"] or ts > s["end"])
]
if not candidates:
continue
best = max(
candidates,
key=lambda s: max(0.0, min(te, s["end"]) - max(ts, s["start"])),
)
by_segment[(best["agent"], best["seg_idx"])].append(t)
rows = []
for s in sorted(segments, key=lambda x: (x["agent"], x["start"])):
calls = sorted(by_segment.get((s["agent"], s["seg_idx"]), []), key=lambda t: t["start_time"])
submit = [t for t in calls if t["tool_name"] == "mcp__massgen_checklist__submit_checklist"]
propose = [t for t in calls if t["tool_name"] == "mcp__massgen_checklist__draft_approach"]
# round-level tool wall time
ints = []
for t in calls:
ts, te = float(t["start_time"]), float(t["end_time"])
ov = max(0.0, min(te, s["end"]) - max(ts, s["start"]))
if ov > 0:
ints.append((max(ts, s["start"]), min(te, s["end"])))
tool_wall = union(ints)
non_tool = max(0.0, s["duration"] - tool_wall)
eval_pre = mid = impl_post = post_no_propose = 0.0
first_submit = submit[0] if submit else None
first_propose = propose[0] if propose else None
if first_submit:
eval_pre = max(0.0, min(s["end"], float(first_submit["start_time"])) - s["start"])
elif first_propose:
eval_pre = max(0.0, min(s["end"], float(first_propose["start_time"])) - s["start"])
if first_submit and first_propose:
mid = max(0.0, min(s["end"], float(first_propose["start_time"])) - float(first_submit["end_time"]))
impl_post = max(0.0, s["end"] - float(first_propose["end_time"]))
elif first_submit and not first_propose:
post_no_propose = max(0.0, s["end"] - float(first_submit["end_time"]))
elif first_propose and not first_submit:
impl_post = max(0.0, s["end"] - float(first_propose["end_time"]))
rows.append({
**s,
"tool_wall": tool_wall,
"non_tool": non_tool,
"submit_count": len(submit),
"propose_count": len(propose),
"eval_pre": eval_pre,
"mid": mid,
"impl_post": impl_post,
"post_no_propose": post_no_propose,
})
print("| Agent | Segment | Round | Type | Outcome | Total (min) | Tool wall (min) | Non-tool (min) | Eval pre (min) | Checklist->Propose (min) | Improve post-propose (min) | Post-checklist no-propose (min) |")
print("|---|---:|---:|---|---|---:|---:|---:|---:|---:|---:|---:|")
for r in rows:
print(
f"| {r['agent']} | {r['seg_idx']} | {r['round_number']} | {r['round_type']} | {r['outcome']} | "
f"{m(r['duration']):.2f} | {m(r['tool_wall']):.2f} | {m(r['non_tool']):.2f} | "
f"{m(r['eval_pre']):.2f} | {m(r['mid']):.2f} | {m(r['impl_post']):.2f} | {m(r['post_no_propose']):.2f} |"
)
PY
报告模板
将此报告保存到 [log_dir]/turn_N/ANALYSIS_REPORT.md(其中 N 是正在分析的轮次编号):
# MassGen Log Analysis Report
**Session:** [log_dir name]
**Trace ID:** [trace_id if available]
**Generated:** [timestamp]
**Logfire Link:** [link if available]
## Executive Summary
[2-3 sentence summary of the run: what was the task, did it succeed, key findings]
## Session Overview
| Metric | Value |
|--------|-------|
| Duration | X minutes |
| Agents | [list] |
| Winner | [agent_id] |
| Total Cost | $X.XX |
| Total Answers | X |
| Total Votes | X |
| Total Restarts | X |
## 1. Correctness Analysis
### Coordination Flow
[Timeline of key events]
### Status
- [ ] All phases completed
- [ ] All agents submitted answers
- [ ] Voting completed correctly
- [ ] Winner selected
- [ ] Final answer delivered
### Issues Found
[List any correctness issues]
## 2. Efficiency Analysis
### Phase Duration Breakdown
| Phase | Count | Avg (s) | Max (s) | Total (s) | % of Total |
|-------|-------|---------|---------|-----------|------------|
| initial_answer | | | | | |
| voting | | | | | |
| presentation | | | | | |
### Per-Round Timing (Sorted by Agent)
| Agent | Segment | Round | Type | Outcome | Start-End | Total (min) | Tool wall (min) | Non-tool (min) |
|-------|---------|-------|------|---------|-----------|-------------|-----------------|----------------|
| agent_a | 1 | r0 | initial_answer | answer | HH:MM:SS-HH:MM:SS | | | |
| ... | | | | | | | | |
### Evaluation vs Implementation Timing (Checklist-Gated Phases)
**Phase definitions used in this report:**
- Evaluation = round start -> first `submit_checklist` start
- Checklist->Propose = first `submit_checklist` end -> first `draft_approach` start
- Implementation = first `draft_approach` end -> round end
- Post-checklist (no propose) = first `submit_checklist` end -> round end (if no propose happened)
| Scope | Evaluation (min / %) | Checklist->Propose (min / %) | Implementation (min / %) | Post-checklist no-propose (min / %) |
|-------|-----------------------|-------------------------------|---------------------------|--------------------------------------|
| All checklist-containing segments | | | | |
| Only segments with draft_approach | | | | |
### Per-Round Evaluation vs Improvement Table
| Agent | Segment | Round | Total (min) | Eval pre-checklist (min) | Checklist->Propose (min) | Improve post-propose (min) | Post-checklist no-propose (min) | Eval vs Improve verdict |
|-------|---------|-------|-------------|----------------------------|---------------------------|-----------------------------|----------------------------------|-------------------------|
| agent_c | 2 | r1 | | | | | | [which side dominates and why] |
| ... | | | | | | | | |
### Top Bottlenecks
1. [Operation] - X seconds (X% of total)
2. [Operation] - X seconds
3. [Operation] - X seconds
## 3. Command Pattern Analysis
### Frequently Repeated Commands
| Command | Times Run | Issue | Recommendation |
|---------|-----------|-------|----------------|
| `openskills read pptx` | X | Long output (~5KB) re-read after restarts | Cache skill docs |
| `npm install ...` | X | Reinstalled after each restart | Persist node_modules |
| ... | | | |
### Commands with Excessive Output
| Command | Output Size | Issue |
|---------|-------------|-------|
| | | |
### Slowest Command Patterns
| Pattern | Max Time | Avg Time | Notes |
|---------|----------|----------|-------|
| Web scraping (crawl4ai) | Xs | Xs | |
| npm install | Xs | Xs | |
| PPTX pipeline | Xs | Xs | |
## 4. Work Duplication Analysis
### Duplicated Work Found
| Work Type | Times Repeated | Wasted Time | Wasted Cost |
|-----------|----------------|-------------|-------------|
| Image generation | X | X min | $X.XX |
| Research/scraping | X | X min | - |
| Package installs | X | X min | - |
### Specific Examples
[List specific examples of duplicated work with prompts/commands]
### Recommendations
1. [Specific recommendation to avoid duplication]
2. [Specific recommendation]
## 5. Agent Behavior Analysis
### Answer Progression
| Label | Agent | Time | Summary |
|-------|-------|------|---------|
| agent1.1 | agent_a | HH:MM | [brief description] |
| agent2.1 | agent_b | HH:MM | [brief description] |
| ... | | | |
### Voting Analysis
| Voter | Voted For | Reasoning Summary |
|-------|-----------|-------------------|
| agent_b | agent1.1 | "[key quote from reasoning]" |
### Vote vs New Answer Decisions
[Explain how agents decided whether to vote or provide new answers]
### Agent Collaboration Quality
- Did agents read each other's answers? [Yes/No with evidence]
- Did agents build upon previous work? [Yes/No with evidence]
- Did agents provide genuine evaluation? [Yes/No with evidence]
### Timeouts/Incomplete Rounds
[List any timeouts with context]
## 6. Cost & Token Analysis
### Cost Breakdown
| Agent | Input Tokens | Output Tokens | Reasoning | Cost |
|-------|--------------|---------------|-----------|------|
| agent_a | | | | $X.XX |
| agent_b | | | | $X.XX |
| **Total** | | | | **$X.XX** |
### Cache Efficiency
- Cached input tokens: X (X% cache hit rate)
### Tool Cost Impact
| Tool | Calls | Est. Time Cost | Notes |
|------|-------|----------------|-------|
| generate_media | X | X min | |
| command_line | X | X min | |
## 7. Errors & Issues
### Exceptions
[List any exceptions with type and message]
### Failed Tool Calls
[List any failed tools]
### Agent Errors
[List any agent-level errors]
### Timeouts
[List any timeouts with duration and context]
## 8. Recommendations
### High Priority
1. **[Issue]**: [Specific actionable recommendation]
2. **[Issue]**: [Specific actionable recommendation]
### Medium Priority
1. **[Issue]**: [Recommendation]
### Low Priority / Future Improvements
1. **[Issue]**: [Recommendation]
## 9. Suggested Linear Issues
Based on the analysis, the following issues are suggested for tracking. If you have access to the Linear project and the session is interactive, **present these to the user for approval before creating.** Regardless of access, you should write them in a section as below, as we want to learn from the logs to propose and later solve concrete issues:
| Priority | Title | Description | Labels |
|----------|-------|-------------|--------|
| High | [Short title] | [1-2 sentence description] | log-analysis, [area] |
| Medium | [Short title] | [Description] | log-analysis, [area] |
**After user approval**, create issues in Linear with:
- Project: MassGen
- Label: `log-analysis` (to identify issues from log analysis)
- Additional labels as appropriate (e.g., `performance`, `agent-behavior`, `tooling`)
## Appendix
### Configuration Used
[Key config settings from execution_metadata.yaml]
### Files Generated
[List of output files in the workspace]
生成报告的工作流
- 先读取本地文件(metrics_summary.json、coordination_table.txt、coordination_events.json、status.json、metrics_events.json)
- 构建按 Agent 排序的逐轮计时表,包括总时间、工具时间和非工具时间
- 计算清单阶段的时间窗口(
pre_checklist、checklist_to_propose、post_propose、post_checklist_no_propose),以及评估和实现所占百分比 - 对于大型日志,并行分析工作流:为每个 Agent/工作流通道分配一个子 Agent,并合并其计时表
- 查询 Logfire,获取 trace_id 和计时数据(如果可用;遇到速率限制时请等待并重试)
- 分析 streaming_debug.log 中的命令模式
- 检查 vote.json 文件,了解 Agent 的推理过程
- 使用模板生成报告
- 保存到
[log_dir]/turn_N/ANALYSIS_REPORT.md(N = 正在分析的轮次) - 向用户打印摘要
- 根据发现建议创建 Linear 事项——如果会话处于交互模式,请先征求用户批准
- 在 Linear 中使用
log-analysis标签创建已批准的事项
第 7 部分:快速参考——SQL 查询
正确性查询
-- Check coordination flow
SELECT span_name, start_timestamp, duration
FROM records
WHERE trace_id = '[TRACE_ID]'
AND (span_name LIKE 'Coordination event:%'
OR span_name LIKE 'Agent answer:%'
OR span_name LIKE 'Agent vote:%'
OR span_name LIKE 'Winner selected:%'
OR span_name LIKE 'Final answer%')
ORDER BY start_timestamp
效率查询
-- Phase duration breakdown
SELECT
CASE
WHEN span_name LIKE 'agent.%.round_0' THEN 'initial_answer'
WHEN span_name LIKE 'agent.%.round_%' THEN 'voting'
WHEN span_name LIKE 'agent.%.presentation' THEN 'presentation'
ELSE 'other'
END as phase,
COUNT(*) as count,
ROUND(AVG(duration)::numeric, 2) as avg_duration_sec,
ROUND(MAX(duration)::numeric, 2) as max_duration_sec,
ROUND(SUM(duration)::numeric, 2) as total_duration_sec
FROM records
WHERE trace_id = '[TRACE_ID]'
AND span_name LIKE 'agent.%'
GROUP BY 1
ORDER BY total_duration_sec DESC
错误查询
-- Find all exceptions
SELECT span_name, exception_type, exception_message, start_timestamp
FROM records
WHERE trace_id = '[TRACE_ID]' AND is_exception = true
ORDER BY start_timestamp
成本查询
-- Token usage by agent
SELECT
attributes->>'massgen.agent_id' as agent,
SUM((attributes->'massgen.usage.input')::int) as total_input_tokens,
SUM((attributes->'massgen.usage.output')::int) as total_output_tokens,
SUM((attributes->'massgen.usage.cost')::float) as total_cost_usd
FROM records
WHERE trace_id = '[TRACE_ID]'
AND span_name LIKE 'agent.%'
AND attributes->>'massgen.usage.input' IS NOT NULL
GROUP BY attributes->>'massgen.agent_id'
第 8 部分:墙钟时间阶段分析
分析运行过程中的墙钟时间瓶颈时,请按每轮、每个 Agent 划分阶段,计算思考时间与工具执行时间,并确定关键路径。本节为执行此类分析提供参考。
阶段类别
每轮中 Agent 工作的每个片段都归入以下类别之一:
| 类别 | 描述 | 信号 |
|---|---|---|
| THINKING | 未调用任何工具时的模型推理(扩展思考、在脑中规划) | 一轮中首次出现 tool_start 前间隔较长,或完全没有工具调用 |
| SCAFFOLD | 项目准备工作(changedoc、CONTEXT.md、任务计划、读取技能文档) | 使用 write_file 编写规划文档、openskills read、在轮次开始时更新任务状态 |
| BUILD | 创建或重写交付物 | 使用 write_file/execute_command 创建生成器、脚本、素材 |
| VERIFY | 检查交付物是否正确 | 使用 read_media、捕获屏幕截图、像素差异对比、检查文件结构 |
| FIX | 修正验证中发现的问题 | VERIFY 阶段后立即进行的编辑/重写循环 |
| SCORE | 评估清单并规划改进 | submit_checklist、draft_approach、诊断报告 |
| HANDOFF | 轮次结束时的记录整理 | 验证备忘录、必要文件清单、将任务状态标记为完成 |
| WASTE | 无成效的工作(钻牛角尖、反复失败) | 同一方案连续失败 3 次以上、工具崩溃、环境问题 |
阅读 execution_trace.md 或 events.jsonl,按用途对连续的工具调用分组,并据此分配类别。如果多个阶段紧密交错,一个区块可以包含多个类别(例如 VERIFY+FIX)。
根据 events.jsonl 计算思考时间与工具执行时间
主要数据源是尝试目录中的 events.jsonl。每行都是一个 JSON 对象,包含以下字段:timestamp(ISO 格式)、event_type、agent_id、round_number、data。
相关事件类型:
| 事件类型 | data 中的关键字段 | 说明 |
|---|---|---|
round_start | — | 标记某个 Agent 一轮的开始 |
round_end | — | 标记某一轮的结束 |
tool_start | tool_id、tool_name、args、server_name | 工具开始执行 |
tool_complete | tool_id、tool_name、elapsed_seconds、status | 工具执行结束 |
算法:
- 按
agent_id和round_number筛选事件。 - 根据
tool_id配对tool_start和tool_complete。 - 将所有
[tool_start.timestamp, tool_complete.timestamp]时间区间合并,计算工具执行时间总和(并发或后台工具的重叠区间需合并)。 - 思考时间 = 一轮持续时间减去工具执行时间总和。该时间包括模型推理、API 延迟、SDK 开销,以及任何未跟踪的间隔。
- 对于每个阶段区块(具有相同类别的连续工具调用组),分别报告思考时间(工具之间的间隔)和执行时间(工具执行时长)。
from datetime import datetime
from collections import defaultdict
def parse_events(events, agent_id, round_number):
"""Return tool intervals and round boundaries for one agent-round."""
starts = {} # tool_id -> timestamp
intervals = []
round_start = round_end = None
for e in events:
if e["agent_id"] != agent_id:
continue
ts = datetime.fromisoformat(e["timestamp"])
if e["event_type"] == "round_start" and e["round_number"] == round_number:
round_start = ts
elif e["event_type"] == "round_end" and e["round_number"] == round_number:
round_end = ts
elif e["event_type"] == "tool_start" and e["round_number"] == round_number:
starts[e["data"]["tool_id"]] = ts
elif e["event_type"] == "tool_complete" and e["round_number"] == round_number:
tid = e["data"]["tool_id"]
if tid in starts:
intervals.append((starts[tid], ts, e["data"]["tool_name"]))
return round_start, round_end, intervals
def compute_think_vs_exec(round_start, round_end, intervals):
"""Return total think and exec seconds, plus merged exec intervals."""
if not round_start or not round_end:
return 0, 0
# Merge overlapping intervals
sorted_iv = sorted((s.timestamp(), e.timestamp()) for s, e, _ in intervals)
merged = []
for s, e in sorted_iv:
if merged and s <= merged[-1][1]:
merged[-1] = (merged[-1][0], max(merged[-1][1], e))
else:
merged.append((s, e))
exec_total = sum(e - s for s, e in merged)
round_total = (round_end - round_start).total_seconds()
return round_total - exec_total, exec_total
确定关键路径
每轮的关键路径 Agent 是该轮墙钟时间最长的 Agent,因为各 Agent 在一轮内并发运行。
- 对每轮,找出最长的 Agent 一轮持续时间,并将该 Agent 标记为
[CP]。 - 将所有轮次中 CP Agent 的持续时间与任何阻塞性的轮前阶段(标准生成、任务分解)相加,得到关键路径总时间。
- 关键路径细分展示了墙钟时间的实际去向——优化非 CP Agent 无关紧要,除非它成为新的瓶颈。
输出表格格式:
| 阶段 | 持续时间 | 占总时间的百分比 |
|---|---|---|
| 标准生成 | Xm | X% |
第 0 轮(agent_b)[CP] | Xm | X% |
第 1 轮(agent_a)[CP] | Xm | X% |
要提取的关键指标
TTFT(首次工具调用时间): 从该 Agent 在该轮的 round_start 到首次 tool_start 的时间。较长的 TTFT(>2 min)表示模型在采取行动前进行了较长时间的扩展思考。TTFT 持续偏高的 Agent 值得考虑调整提示词,以鼓励渐进式使用工具。
bg_wait 时间: custom_tool__wait_for_background_tool 调用的总时长(在 events.jsonl 中根据 tool_id 配对,或对 tool_name 包含 wait_for_background_tool 的 tool_complete 事件中的 elapsed_seconds 求和)。这用于衡量 Agent 等待 read_media 或 generate_media 等异步工作的阻塞时间。
按类型统计工具调用次数: 按 Agent 和轮次对 tool_start 事件中的 tool_name 分组。规划工具调用次数过多(例如,24 次任务状态更新)或重复失败的命令,都表明存在值得调查的开销。
每轮成本: 从 metrics_summary.json 获取,或从每轮 Agent span 的 Logfire massgen.usage.cost 属性获取。
已知数据缺口
| 缺口 | 影响 | 无法测量的内容 |
|---|---|---|
| Claude Code 后端没有 API 计时 | 无法将思考时间拆分为 API 延迟、模型推理和 SDK 开销 | claude_code.py 不会调用 start_api_call_timing/end_api_call_timing。13 分钟的 TTFT 是个黑箱。 |
| Codex 每轮跟踪 1 次 API 调用,而非每次工具调用 | 无法分解各个工具之间的思考间隔 | 只能在会话级别获取 TTFT;工具间隔无法查明。 |
| 未区分推理和输出生成 | 无法判断较长的间隔是模型思考还是生成大量输出(例如 90KB 的 SVG) | 适用于所有后端。 |
| read_media / generate_media 没有内部计时 | 无法区分多模态模型延迟与后台工具框架开销 | 等待时间为 30-70 秒,但没有细分。 |
| Criteria gen 子 Agent 没有逐轮细分 | 阻塞式轮次前时间不可见,无法了解内部步骤 | 只能获取总时长。 |
如果这些缺口影响分析,请在报告中明确说明,不要猜测。建议将计时功能改进(例如“为 Claude Code 后端添加 API 计时”)列为可执行事项。
阶段分析报告结构
生成墙钟时间阶段分析时,按每个 Agent 的每一轮使用以下结构:
### ROUND N -- Xm wall time | $X.XX
#### agent_id (Backend / Model) -- Xm | $X.XX | N tools [CP]
| # | Category | Duration | Think | Exec | Tools | What |
|---|----------|----------|-------|------|-------|------|
| 1 | SCAFFOLD | 0.9m | 0.9m | 0.0m | 3 | Create changedoc, task plan |
| 2 | BUILD | 4.4m | 4.4m | 0.0m | 6 | Write SVG generator |
| ... | | | | | | |
| | **Total** | **Xm** | **Xm** | **Xm** | **N** | |
后续内容包括:
- 关键路径摘要表格(每轮中哪个 Agent 位于关键路径上、关键路径总时间)
- 类别汇总(仅关键路径:汇总所有轮次中各类别的时间)
- 总时间细分(模型思考、TTFT、bg_wait、Shell 命令、其他工具执行、未计入项)
- 结构模式(关键观察事项的编号列表:重复脚手架、无限改进循环、浪费时间的探索等)
- 按墙钟时间影响排序的可执行机会