1. 项目概览
https://github.com/bojieli/ai-agent-book
本项目是《深入理解 AI Agent》第 2 章配套实验代码,主题是大语言模型注意力机制可视化。它围绕 Qwen3-0.6B 等真实模型,捕获生成过程中的 self-attention 权重,并通过 Matplotlib 热力图、JSON 轨迹文件和 Next.js 前端进行展示。
从工程角度看,它不是单一脚本,而是一个包含以下能力的小型实验系统:
- 直接加载 Hugging Face Transformers 模型并捕获注意力;
- 生成 token 级注意力轨迹;
- 支持 ReAct 工具调用 Agent 的多步推理过程记录;
- 提供命令行热力图生成工具;
- 提供可复现的章节实验脚本;
- 提供前端页面查看 trajectory JSON;
- 包含针对实验逻辑和轨迹保存的回归测试。
1.1 学习价值
这个仓库适合同时学习以下内容:
-
Transformer 注意力机制工程化捕获
- 如何通过
LogitsProcessor和 hook 获取生成阶段 attention; - 如何区分输入上下文、生成 token、layer、head;
- 如何将 attention 矩阵保存为
.npz或 JSON。
- 如何通过
-
AI Agent 可观测性
- 普通生成与 ReAct 多步工具调用的轨迹结构;
- 如何保存 query、response、attention steps、tool call 等信息;
- 如何让前端消费这些轨迹数据。
-
实验复现与验证
run_attention_experiment.py对应实验 2-2;run_status_bar_experiment.py对应实验 2-7;- 测试文件验证 layer 解析、区域索引、attention sink、状态条行为等关键逻辑。
-
全栈可视化闭环
- Python 后端负责模型推理和数据导出;
frontend/下的 Next.js 应用负责交互式展示;- JSON 文件作为前后端解耦的数据契约。
1.2 解决的行业痛点
在大模型应用开发中,注意力和推理过程通常是黑盒。本项目尝试解决以下问题:
- 模型为什么关注某些 token,难以直观解释;
- ReAct Agent 的工具调用链路缺少结构化记录;
- 教学实验中热力图容易只停留在展示层,缺少可复现实验证据;
- 不同 layer、head、prompt 模板下注意力模式难以横向比较;
- 前端展示与模型生成逻辑耦合,导致调试困难。
本项目通过"模型捕获 → JSON/NPZ 落盘 → 静态图或前端展示"的方式,把注意力分析变成可复现、可检查、可扩展的工程流程。
1.3 前置知识要求
建议读者具备以下基础:
| 知识领域 | 最低要求 | 学习重点 |
|---|---|---|
| Python | 能运行脚本、安装依赖、理解函数和类 | argparse、pathlib、json、类型注解 |
| PyTorch | 了解 tensor、model 加载、device | attention tensor 形状、hook、推理 |
| Transformers | 知道 tokenizer、model.generate、chat template | Qwen3 模型加载、生成参数 |
| Attention | 了解 Query、Key、Value 和因果注意力 | layer/head 维度、attention sink |
| 前端基础 | 能运行 npm 项目即可 | Next.js 页面如何加载 JSON |
| Agent | 了解 ReAct 或工具调用基本概念 | main.py 中的多步循环 |
如果完全没有 PyTorch 经验,也可以先从 attention_cli.py 的默认命令开始,先观察输出图,再回头阅读 agent.py。
2. 目录结构速览
仓库根目录位于:
text
\chapter2\attention_visualization
核心结构如下:
text
attention_visualization/
├── README.md
├── agent.py
├── attention_cli.py
├── config.py
├── env.example
├── main.py
├── requirements.txt
├── run_attention_experiment.py
├── run_status_bar_experiment.py
├── test_attention_experiment.py
├── test_full_content.py
├── test_save_trajectory.py
├── test_status_bar_experiment.py
├── test_streaming.py
├── tools.py
├── visualization.py
├── frontend/
│ ├── next-env.d.ts
│ ├── next.config.js
│ ├── package-lock.json
│ ├── package.json
│ ├── postcss.config.js
│ ├── tailwind.config.js
│ ├── tsconfig.json
│ ├── components/
│ │ ├── AttentionHeatmap.tsx
│ │ ├── AttentionModal.tsx
│ │ ├── AttentionPreview.tsx
│ │ ├── AttentionStats.tsx
│ │ ├── PromptDisplay.tsx
│ │ ├── ResponseDisplay.tsx
│ │ └── TestCaseSelector.tsx
│ ├── pages/
│ │ ├── _app.tsx
│ │ └── index.tsx
│ ├── public/
│ │ └── trajectories/
│ │ ├── manifest.json
│ │ ├── trajectory_20250914_211312.json
│ │ └── trajectory_20250914_211442.json
│ └── styles/
│ └── globals.css
├── runs/
│ ├── exp2-2-qwen3-0.6b-20260730-v1/
│ │ └── attention_matrices.npz
│ ├── exp2-2-qwen3-0.6b-20260730-v2/
│ │ └── attention_matrices.npz
│ ├── exp2-2-qwen3-0.6b-20260730-v3/
│ │ └── attention_matrices.npz
│ ├── exp2-7-qwen3-0.6b-20260730-v1/
│ │ └── attention_matrices.npz
│ └── exp2-7-qwen3-0.6b-20260730-v2/
│ └── attention_matrices.npz
└── validation/
└── latest.json
目录职责可按下面方式理解:
| 路径 | 职责 |
|---|---|
agent.py |
基础注意力追踪 Agent,负责模型加载、生成、attention 捕获、轨迹保存 |
main.py |
ReAct 工具调用 Agent,继承基础 Agent,增加多步推理和工具执行 |
tools.py |
示例工具注册表,包含天气、时间、汇率、代码解释器等工具 |
attention_cli.py |
独立命令行入口,快速生成单张或多层对比热力图 |
visualization.py |
Matplotlib/Seaborn 可视化函数集合 |
run_attention_experiment.py |
章节实验 2-2 的规范化实验脚本 |
run_status_bar_experiment.py |
章节实验 2-7 的状态条对比实验脚本 |
config.py |
从 .env 读取配置 |
frontend/ |
Next.js 前端,用于浏览 trajectory JSON |
runs/ |
实验输出目录,已有 .npz 注意力矩阵文件 |
validation/ |
校验结果目录,目前摘要中发现 latest.json |
test_*.py |
回归测试和实验逻辑测试 |
需要注意:摘要中没有提供 requirements.txt 的具体依赖版本,也没有提供前端 package.json 的完整脚本内容;相关命令只能依据 README 中明确出现的信息说明,不能编造。
3. 核心模块与职责
3.1 agent.py:基础注意力追踪 Agent
agent.py 是整个项目的核心后端模块,模块说明为 Attention Visualization Agent。
主要类:
| 类/函数 | 职责 |
|---|---|
AttentionStep |
表示单个生成步骤的注意力数据,可通过 to_dict() 序列化 |
GenerationResult |
表示一次生成结果,包含生成文本、token、注意力步骤等 |
AttentionTracker |
继承自 Transformers 的 LogitsProcessor,在生成过程中记录注意力 |
AttentionVisualizationAgent |
加载模型和 tokenizer,捕获 attention,保存 trajectory |
demonstrate_attention_tracking() |
演示基础注意力追踪流程 |
关键机制:
-
AttentionTracker.reset()- 清空历史 attention steps;
- 每次新生成前应调用,避免不同请求数据混杂。
-
AttentionTracker.__call__(input_ids, scores)- 在
model.generate的 logits 处理阶段被调用; - 可结合当前位置记录生成过程中的注意力状态。
- 在
-
AttentionTracker.update_attention(position, attention_weights)- 更新某个生成位置的注意力权重;
- 是连接模型输出和轨迹数据的重要方法。
-
AttentionVisualizationAgent._capture_attention_hook(module, input, output)- 通过 PyTorch hook 捕获模块输出中的 attention;
- 用于获取 layer/head 级别的矩阵。
-
AttentionVisualizationAgent.generate_with_attention(...)- 执行带注意力记录的文本生成;
- 支持
temperature、top_p、do_sample、max_new_tokens等参数; - 可选择保存 trajectory。
-
AttentionVisualizationAgent.save_trajectory(...)- 将生成结果保存为 JSON;
- README 中说明 trajectory 存储在
frontend/public/trajectories/下。
-
chat(message, **kwargs)- 维护对话上下文;
- 适合多轮对话场景。
-
reset_conversation()- 重置对话状态。
3.2 main.py:ReAct 工具调用 Agent
main.py 在基础 Agent 之上实现 ReAct 风格工具调用,模块说明为 ReAct Tool-Calling Agent with Attention Visualization。
主要类:
| 类/函数 | 职责 |
|---|---|
ReActStep |
表示 ReAct 循环中的一步,可序列化为字典 |
ReActAttentionAgent |
继承 AttentionVisualizationAgent,增加工具调用和流式生成 |
demonstrate_react_agent() |
演示 ReAct Agent |
关键方法:
create_initial_messages(query):根据用户问题构造初始消息;parse_tool_calls(text):从模型输出中解析工具调用;generate_with_streaming(...):流式生成,可选择展示 token id 和追踪 attention;generate_with_attention_streaming(...):流式生成并记录注意力;execute_react_loop(...):执行"思考 → 工具调用 → 观察 → 继续生成"的循环;save_react_trajectory(...):保存 ReAct 多步轨迹。
这个模块体现了 Agent 可观测性的核心:不仅保存最终答案,还保存中间步骤和注意力变化。
3.3 tools.py:工具注册表
tools.py 提供示例工具,模块说明为 Sample tools for demonstrating tool calling functionality with attention visualization。
核心类是 ToolRegistry:
| 方法 | 职责 |
|---|---|
_register_default_tools() |
注册默认工具 |
register_tool(...) |
动态注册工具 |
get_tool_schemas() |
获取工具 schema,供模型调用 |
get_tools_prompt() |
生成工具说明 prompt |
execute_tool(name, arguments) |
根据名称和参数执行工具 |
默认工具包括:
get_current_temperature(location, unit)get_current_time(timezone)convert_currency(amount, from_currency, to_currency)code_interpreter(code)
模块还提供 format_tool_response(tool_name, tool_result),用于把工具执行结果格式化后送回模型。
注意:摘要显示 requests 被导入,因此天气等工具可能依赖外部 HTTP 请求;但具体 API 地址和认证方式未在摘要中发现。运行真实工具前应查看 tools.py 和 config.py。
3.4 attention_cli.py:快速热力图命令行工具
attention_cli.py 是 README 推荐的最快复现入口,模块说明为 Attention Visualization CLI。
主要函数:
| 函数 | 职责 |
|---|---|
build_parser() |
构建命令行参数解析器 |
build_input_ids(agent, prompt, use_chat_template) |
将 prompt 编码为 input ids,可选择是否使用 chat template |
extract_layer_matrix(attentions, layer, head) |
从 attention 输出中提取指定 layer/head 矩阵 |
run(args) |
执行命令行任务 |
main() |
CLI 主入口 |
README 中明确给出的参数包括:
| Flag | 含义 | 默认值 |
|---|---|---|
-p, --prompt |
要可视化的文本 | 北京 的 天气 怎么样 |
-o, --output |
输出 PNG 路径 | attention_heatmap.png |
-m, --model |
Hugging Face 模型名或本地路径 | Qwen/Qwen3-0.6B |
--device |
cuda / mps / cpu |
自动检测 |
-l, --layer |
layer 索引,-1 表示最后一层 |
-1 |
--head |
head 索引,-1 表示 head 平均 |
-1 |
--compare-layers |
并排渲染多个 layer | 关闭 |
--max-new-tokens |
先生成 N 个 token,再捕获注意力 | 0 |
--no-chat-template |
使用原始 prompt,不加 `< | im_start |
--cmap |
Matplotlib 色图 | viridis |
3.5 visualization.py:可视化工具函数
visualization.py 负责把注意力矩阵画成图。
主要函数:
| 函数 | 职责 |
|---|---|
_configure_cjk_font() |
配置中文字体,避免中文 token 乱码 |
create_attention_heatmap(...) |
创建输入/输出 token 间的注意力热力图 |
create_attention_flow_diagram(...) |
创建注意力流向图 |
create_token_attention_summary(...) |
创建 token 级注意力摘要图 |
visualize_results(results_path, output_dir, formats) |
从结果文件批量生成可视化 |
clean_token_labels(tokens, max_len) |
清理过长 token 标签 |
attention_sink_stats(attention_matrix, sink_index) |
统计 attention sink 占比 |
create_layer_attention_heatmap(...) |
创建单层注意力热力图 |
create_attention_comparison(...) |
创建多矩阵对比图 |
该模块依赖 matplotlib、seaborn、numpy,是 CLI 和实验脚本的图像输出基础。
3.6 run_attention_experiment.py:实验 2-2 规范化入口
该文件对应 Canonical real-model campaign for Chapter 2 Experiment 2-2。
主要函数:
| 函数 | 职责 |
|---|---|
sha256(path) |
计算文件 SHA256,用于记录模型或输出文件指纹 |
resolve_layer(index, count) |
解析 layer 索引,支持负数索引 |
region_indices(tokens, context_length) |
划分 thinking 和 answer 等区域 |
matrix_metrics(matrix) |
计算注意力矩阵指标 |
capture(model, ids, layers) |
捕获指定 layers 的注意力 |
draw(matrices, tokens, path, title) |
绘制实验图 |
main() |
实验主入口 |
README 中说明该实验会:
- 固定真实 Qwen3-0.6B revision;
- 保留第一层、中间层、最后层的无损矩阵;
- 使用
北京 的 天气 怎么样prompt; - 生成包含
<think>和最终答案区域的序列; - 数值验证因果上三角;
- 报告 attention sink 以及开头、中间、结尾位置的测量值。
已有输出目录包括:
text
runs/exp2-2-qwen3-0.6b-20260730-v1/attention_matrices.npz
runs/exp2-2-qwen3-0.6b-20260730-v2/attention_matrices.npz
runs/exp2-2-qwen3-0.6b-20260730-v3/attention_matrices.npz
3.7 run_status_bar_experiment.py:实验 2-7 状态条对比
该文件对应 Real Qwen3 attention comparison for Chapter 2 Experiment 2-7。
主要函数:
| 函数 | 职责 |
|---|---|
sha256_bytes(value) |
计算字节内容哈希 |
utc_now() |
获取 UTC 时间 |
tools() |
构造工具定义 |
assistant_tool(name, arguments, call_id) |
构造助手工具调用消息 |
base_messages(protocol) |
构造基础消息轨迹 |
status_message() |
构造状态条消息 |
render(tokenizer, messages) |
使用 tokenizer 渲染消息 |
find_region_indices(tokenizer, rendered) |
查找区域索引 |
classify(text) |
分类模型行为,如调用工具或拒绝 |
generate_one(model, tokenizer, rendered, protocol, seed) |
执行一次生成 |
capture_attention(model, full_ids, context_length, regions) |
捕获区域注意力 |
draw_heatmaps(records, path) |
绘制状态条实验热力图 |
main() |
实验主入口 |
已有输出目录包括:
text
runs/exp2-7-qwen3-0.6b-20260730-v1/attention_matrices.npz
runs/exp2-7-qwen3-0.6b-20260730-v2/attention_matrices.npz
3.8 前端模块
前端位于 frontend/,基于 Next.js。摘要中发现的组件如下:
| 组件 | 推测职责 |
|---|---|
AttentionHeatmap.tsx |
展示注意力热力图 |
AttentionModal.tsx |
弹窗查看注意力详情 |
AttentionPreview.tsx |
注意力预览 |
AttentionStats.tsx |
展示注意力统计指标 |
PromptDisplay.tsx |
展示输入 prompt |
ResponseDisplay.tsx |
展示模型响应 |
TestCaseSelector.tsx |
测试用例选择器 |
pages/index.tsx |
前端主页面 |
pages/_app.tsx |
Next.js 应用入口 |
public/trajectories/manifest.json |
trajectory 清单 |
public/trajectories/*.json |
已生成的轨迹文件 |
摘要中没有提供 TypeScript 组件的具体 props 和接口定义,因此前端内部数据结构未在解析摘要中发现。
3.9 核心原理通俗解读
可以把这个项目理解成给大模型做"注意力 CT 扫描"。
-
模型生成 token
- 输入一句话,模型逐 token 生成后续内容;
- 每个 token 在生成时都会关注前面的 token。
-
Hook 和 LogitsProcessor 记录注意力
- Hook 像在模型内部放传感器;
LogitsProcessor像在生成流水线上放检查站;- 两者配合,把每一步的 attention 保存下来。
-
矩阵变成图
- 注意力矩阵的行表示 Query 位置;
- 列表示 Key 位置;
- 颜色越亮,表示当前 token 越关注对应位置。
-
轨迹变成前端可查看的故事
- JSON 中保存 prompt、response、attention steps;
- 前端读取这些 JSON,把模型"看哪里"展示出来。
-
ReAct Agent 进一步记录工具调用
- 普通生成只记录 token;
- ReAct 还记录模型何时想调用工具、调用了什么、工具返回了什么;
- 因此可以分析工具调用前后注意力如何变化。
4. 关键数据流与调用链
4.1 基础注意力生成数据流
以 attention_cli.py 为例:
text
用户命令
↓
attention_cli.py: main()
↓
build_parser() 解析参数
↓
run(args)
↓
AttentionVisualizationAgent 加载 tokenizer/model
↓
build_input_ids(agent, prompt, use_chat_template)
↓
模型推理 / model.generate
↓
AttentionTracker + attention hook 捕获权重
↓
extract_layer_matrix(attentions, layer, head)
↓
visualization.py 绘制热力图
↓
输出 PNG 文件
关键数据对象:
| 数据 | 来源 | 去向 |
|---|---|---|
prompt |
CLI 参数 | tokenizer |
input_ids |
tokenizer 编码 | 模型输入 |
attentions |
模型输出/hook | 矩阵提取函数 |
attention_weights |
tracker/hook | AttentionStep |
GenerationResult |
生成流程汇总 | JSON 或可视化 |
| PNG 图 | Matplotlib | 用户查看 |
4.2 Trajectory 保存数据流
以 agent.py 或 main.py 生成轨迹为例:
text
用户 query
↓
AttentionVisualizationAgent.generate_with_attention()
或 ReActAttentionAgent.execute_react_loop()
↓
模型逐 token 生成
↓
AttentionTracker 记录每一步 attention
↓
组装 GenerationResult / ReActStep
↓
save_trajectory() 或 save_react_trajectory()
↓
写入 frontend/public/trajectories/*.json
↓
manifest.json 被前端读取
↓
Next.js 页面展示轨迹
README 中明确说明架构为:
- Agent generates trajectories;
- JSON storage under
frontend/public/trajectories/; - Frontend visualization loads trajectories with tab navigation。
4.3 ReAct 工具调用数据流
main.py 的典型调用链:
text
用户 query
↓
create_initial_messages(query)
↓
generate_with_attention_streaming()
↓
模型输出文本
↓
parse_tool_calls(text)
↓
是否包含工具调用?
├─ 是:
│ ↓
│ ToolRegistry.execute_tool(name, arguments)
│ ↓
│ format_tool_response()
│ ↓
│ 将工具结果追加到消息
│ ↓
│ 继续下一轮生成
│
└─ 否:
↓
得到 final_answer
↓
save_react_trajectory()
这个流程中,ReActStep 应记录每一步的模型输出、工具调用、工具结果和注意力信息。具体字段定义未在摘要中完整展开,需阅读源码确认。
4.4 实验 2-2 数据流
text
run_attention_experiment.py main()
↓
解析 --output 等参数
↓
加载 Qwen3-0.6B 模型和 tokenizer
↓
编码 prompt:北京 的 天气 怎么样
↓
capture(model, ids, layers)
↓
resolve_layer() 解析第一层/中间层/最后层
↓
matrix_metrics() 计算因果三角、sink 等指标
↓
region_indices() 划分 thinking/answer 区域
↓
draw() 输出图像
↓
保存 attention_matrices.npz 和元数据
README 中给出的运行方式:
bash
python run_attention_experiment.py \
--output runs/exp2-2-qwen3-0.6b-$(date +%Y%m%d-%H%M%S)
Windows PowerShell 中 $(date +%Y%m%d-%H%M%S) 不一定可用,建议直接指定明确目录,例如:
powershell
python run_attention_experiment.py --output runs/exp2-2-qwen3-0.6b-manual-test
4.5 实验 2-7 数据流
text
run_status_bar_experiment.py main()
↓
构造 tools()
↓
base_messages(protocol) 生成基础轨迹
↓
status_message() 添加状态条消息
↓
render(tokenizer, messages) 渲染为模型输入
↓
find_region_indices() 定位不同区域
↓
generate_one() 生成模型响应
↓
classify(text) 判断是工具调用还是拒绝
↓
capture_attention() 捕获区域注意力
↓
draw_heatmaps() 输出对比图
↓
保存实验结果
4.6 流程易错节点标注
| 节点 | 易错点 | 后果 | 建议 |
|---|---|---|---|
| 模型加载 | 模型名错误、本地路径不存在、网络无法下载 | 启动失败 | 先用 Qwen/Qwen3-0.6B 或本地模型路径测试 |
| device 选择 | CUDA/MPS 不可用却强制指定 | 运行报错或极慢 | 使用自动检测,必要时显式 --device cpu |
| chat template | --no-chat-template 使用不当 |
token 区域与预期不同 | 对比开启/关闭模板的 token 长度 |
| layer 索引 | 负数索引或超出层数 | 矩阵提取失败 | 使用 resolve_layer() 同类逻辑校验 |
| head 索引 | 指定 head 超出 head 数 | 索引错误 | --head -1 先看平均,再指定具体 head |
| attention 保存 | 未重置 tracker | 多次运行数据混杂 | 每次生成前调用 reset() |
| trajectory 路径 | 未写入 frontend/public/trajectories/ |
前端看不到结果 | 按 README 规定目录保存 |
| 工具执行 | 外部 API 缺少环境变量 | 工具返回错误 | 检查 .env 和 config.py |
| 中文字体 | Matplotlib 未配置 CJK 字体 | 图中中文乱码 | 使用 _configure_cjk_font() |
| 实验输出 | 输出目录已存在或权限不足 | 文件写入失败 | 使用新的时间戳目录或手动空目录 |
5. 关键类/函数速查表
5.1 agent.py
| 名称 | 类型 | 关键方法/参数 | 用途 |
|---|---|---|---|
AttentionStep |
数据类 | to_dict() |
单步注意力记录 |
GenerationResult |
数据类 | __post_init__()、to_dict() |
一次生成结果 |
AttentionTracker |
LogitsProcessor | reset()、__call__()、update_attention()、get_attention_steps() |
生成过程中追踪注意力 |
AttentionVisualizationAgent |
Agent 类 | model_name、device、attention_layer_index、verbose |
加载模型并生成带注意力的结果 |
_capture_attention_hook |
实例方法 | module, input, output |
注册 PyTorch hook 捕获 attention |
generate_with_attention |
实例方法 | prompt, max_new_tokens, temperature, top_p, do_sample, save_trajectory, category, store_full_tokens |
带注意力记录的生成 |
save_trajectory |
实例方法 | result, query, category, temperature, max_new_tokens |
保存轨迹 JSON |
chat |
实例方法 | message, **kwargs |
多轮对话生成 |
reset_conversation |
实例方法 | 无 | 清空对话历史 |
5.2 main.py
| 名称 | 类型 | 用途 |
|---|---|---|
ReActStep |
数据类 | 记录 ReAct 单步信息 |
ReActAttentionAgent |
类 | 支持工具调用和注意力追踪的 Agent |
create_initial_messages |
方法 | 创建初始消息 |
parse_tool_calls |
方法 | 解析模型输出中的工具调用 |
generate_with_streaming |
方法 | 流式生成文本 |
generate_with_attention_streaming |
方法 | 流式生成并记录注意力 |
execute_react_loop |
方法 | 执行 ReAct 循环 |
save_react_trajectory |
方法 | 保存 ReAct 轨迹 |
5.3 tools.py
| 名称 | 类型 | 用途 |
|---|---|---|
ToolRegistry |
类 | 工具注册、schema 生成、执行工具 |
register_tool |
方法 | 注册自定义工具 |
get_tool_schemas |
方法 | 获取工具 schema |
get_tools_prompt |
方法 | 获取工具提示词 |
execute_tool |
方法 | 执行指定工具 |
get_current_temperature |
方法 | 查询温度 |
get_current_time |
方法 | 查询时间 |
convert_currency |
方法 | 汇率转换 |
code_interpreter |
方法 | 执行代码 |
format_tool_response |
函数 | 格式化工具返回 |
5.4 attention_cli.py
| 名称 | 类型 | 用途 |
|---|---|---|
build_parser |
函数 | 构建 CLI 参数 |
build_input_ids |
函数 | 编码 prompt |
extract_layer_matrix |
函数 | 提取指定层/头矩阵 |
run |
函数 | 执行 CLI 逻辑 |
main |
函数 | CLI 入口 |
5.5 visualization.py
| 名称 | 类型 | 用途 |
|---|---|---|
create_attention_heatmap |
函数 | 绘制注意力热力图 |
create_attention_flow_diagram |
函数 | 绘制注意力流向图 |
create_token_attention_summary |
函数 | 绘制 token 注意力摘要 |
visualize_results |
函数 | 批量可视化结果 |
attention_sink_stats |
函数 | 统计 sink 占比 |
create_layer_attention_heatmap |
函数 | 绘制单层热力图 |
create_attention_comparison |
函数 | 绘制多层/多矩阵对比图 |
5.6 实验脚本
| 文件 | 函数 | 用途 |
|---|---|---|
run_attention_experiment.py |
resolve_layer |
解析 layer 索引 |
run_attention_experiment.py |
region_indices |
划分 token 区域 |
run_attention_experiment.py |
matrix_metrics |
计算矩阵指标 |
run_attention_experiment.py |
capture |
捕获注意力 |
run_attention_experiment.py |
draw |
绘制实验图 |
run_status_bar_experiment.py |
base_messages |
构造基础消息 |
run_status_bar_experiment.py |
classify |
分类模型行为 |
run_status_bar_experiment.py |
generate_one |
单次生成 |
run_status_bar_experiment.py |
capture_attention |
捕获区域注意力 |
run_status_bar_experiment.py |
draw_heatmaps |
绘制状态条对比图 |
6. 如何运行与调试(基于摘要推断,无法确定则说明)
本节严格依据 README 和模块摘要编写。未在摘要中发现的内容会明确标注。
6.1 环境准备
6.1.1 Python 环境
建议在项目根目录执行:
bash
python --version
摘要中未明确要求 Python 版本。考虑到项目使用 transformers、torch、seaborn、matplotlib、numpy、python-dotenv、requests,建议使用较新的 Python 3 版本。具体版本约束未在解析摘要中发现。
安装依赖:
bash
pip install -r requirements.txt
requirements.txt 的具体内容未在摘要中展开,因此无法确认版本锁定情况。
6.1.2 模型准备
默认模型为:
text
Qwen/Qwen3-0.6B
README 明确说明:
- 第一次运行会下载模型权重,约 1--2 GB;
- 推荐 GPU/MPS;
- CPU 可以运行短 prompt。
如果网络环境不稳定,可以提前下载模型到本地,并通过 -m 或相关模型参数指定本地路径。
6.1.3 环境变量
根目录存在:
text
env.example
config.py
config.py 使用 dotenv 和 os 读取配置。摘要未展示 .env 需要哪些变量。若要使用天气、汇率等外部工具,应复制:
bash
cp env.example .env
Windows PowerShell:
powershell
Copy-Item env.example .env
然后根据实际工具需要填写配置。具体变量名未在解析摘要中发现。
6.2 最快上手:运行独立 CLI 热力图
步骤 1:执行默认命令
在项目根目录运行:
bash
python attention_cli.py
执行目的:
- 使用默认 prompt:
北京 的 天气 怎么样; - 使用默认模型:
Qwen/Qwen3-0.6B; - 捕获最后一层、所有 head 平均后的注意力;
- 输出默认 PNG:
attention_heatmap.png。
预期生成文件:
text
attention_heatmap.png
正常控制台输出特征:
- 可能显示模型加载进度;
- 首次运行会显示下载进度;
- README 说明工具会打印 attention-sink share,即每一行注意力分配到第一个 token 的比例;
- 在 Qwen3-0.6B 最后一层,sink 常达到约 75--85%。该数值来自 README 描述,不代表所有环境必然完全一致。
步骤 2:自定义 prompt、layer、head 和输出路径
bash
python attention_cli.py --prompt "北京 的 天气 怎么样" \
--layer 0 --head 3 --output layer0_head3.png
执行目的:
- 观察第 0 层第 3 个 head 的注意力模式;
- 与最后一层平均模式对比。
预期生成文件:
text
layer0_head3.png
建议对比:
--layer -1 --head -1:最后一层 head 平均;--layer 0 --head -1:第一层 head 平均;--layer 0 --head 3:特定低层 head。
步骤 3:先生成再可视化
bash
python attention_cli.py --prompt "Explain attention in one sentence." \
--max-new-tokens 40
执行目的:
- 让模型先生成 40 个新 token;
- 再对包含上下文和生成内容的完整序列捕获注意力;
- 观察生成 token 对前文的依赖。
预期生成文件:
text
attention_heatmap.png
如果指定了 -o,则输出到指定路径。
步骤 4:多层对比
bash
python attention_cli.py --compare-layers 0 13 -1 --output layer_compare.png
执行目的:
- 并排比较第 0 层、第 13 层和最后一层;
- 观察 attention sink 如何在不同层中变化。
预期生成文件:
text
layer_compare.png
注意:13 是否有效取决于模型实际层数。如果层索引超出范围,可能报错。可先使用默认最后层,再根据模型层数调整。
步骤 5:查看完整参数
bash
python attention_cli.py --help
执行目的:
- 查看当前代码版本支持的全部参数;
- 避免依赖文档中可能滞后的参数说明。
6.3 方案优劣对比:CLI 直接出图 vs Trajectory + 前端
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
attention_cli.py 直接输出 PNG |
启动快、步骤少、无需前端 | 交互能力弱,不适合浏览多步轨迹 | 快速验证、论文/教学截图 |
agent.py 生成 trajectory JSON |
可保存完整上下文和注意力步骤 | 需要前端或额外工具查看 | 后端实验、轨迹归档 |
main.py ReAct trajectory |
能记录工具调用和多步推理 | 流程更复杂,工具可能依赖外部 API | Agent 可观测性、调试工具调用 |
run_attention_experiment.py |
规范化、可复现、指标完整 | 运行时间更长,输出更多 | 章节实验验收、对比实验 |
| Next.js 前端 | 可视化体验好,支持切换轨迹 | 需要 Node.js 和 npm 环境 | 演示、交互分析 |
6.4 运行实验 2-2
README 给出的命令:
bash
python run_attention_experiment.py \
--output runs/exp2-2-qwen3-0.6b-$(date +%Y%m%d-%H%M%S)
步骤 1:选择输出目录
类 Unix 系统可直接使用上面的命令。
Windows 上建议使用 PowerShell 明确指定:
powershell
python run_attention_experiment.py --output runs/exp2-2-qwen3-0.6b-manual
执行目的:
- 避免 shell 日期格式不兼容;
- 将本次实验结果写入独立目录,方便复现和对比。
步骤 2:观察输出目录
运行成功后,预期目录类似:
text
runs/exp2-2-qwen3-0.6b-manual/
摘要中已有同类文件:
text
attention_matrices.npz
该 .npz 文件用于保存多层注意力矩阵。是否还生成图片、JSON 或元数据文件,摘要未完整列出,需以实际运行为准。
步骤 3:关注控制台指标
根据 README,实验会报告:
- attention sink;
- 开头、中间、结尾位置测量;
- 因果上三角验证;
<think>和最终答案区域。
无实测结果:摘要没有提供本次运行的具体数值,因此不能编造实验输出。建议读者将自己的控制台结果保存到日志文件,例如:
bash
python run_attention_experiment.py --output runs/manual-test > runs/manual-test.log 2>&1
Windows PowerShell 可使用:
powershell
python run_attention_experiment.py --output runs/manual-test *> runs/manual-test.log
6.5 运行实验 2-7
摘要中没有给出 README 对实验 2-7 的完整命令预览,只说明该文件是 Real Qwen3 attention comparison for Chapter 2 Experiment 2-7。
可先查看帮助:
bash
python run_status_bar_experiment.py --help
执行目的:
- 确认该脚本支持的参数;
- 避免使用未在摘要中发现的参数。
从函数设计推断,该实验会:
- 构造工具调用轨迹;
- 添加状态条消息;
- 渲染 tokenizer 输入;
- 生成模型响应;
- 分类模型是调用工具还是拒绝;
- 捕获不同区域注意力;
- 绘制热力图。
已有输出目录:
text
runs/exp2-7-qwen3-0.6b-20260730-v1/
runs/exp2-7-qwen3-0.6b-20260730-v2/
具体命令参数未在解析摘要中发现,需以 --help 或源码为准。
6.6 生成 trajectory 并启动前端
README 中给出的交互流程分为三步。
Step 1:生成 trajectories
README 提供两个选项。
Option A:基础注意力追踪 demo。
README 中没有展示完整命令,只写明:
text
Option A: basic attention tracking demo
结合入口线索,可能入口为:
bash
python agent.py
但该命令的具体参数和行为未在摘要中完整说明,运行前建议先执行:
bash
python agent.py --help
如果 agent.py 不支持 --help,则需阅读源码中的 demonstrate_attention_tracking() 和 if __name__ == "__main__" 部分。
Option B:ReAct agent with tool calling。
README 中写明:
text
Option B: ReAct agent with tool calling (multi-step reasoning)
结合入口线索,可能入口为:
bash
python main.py
同样,具体参数未在摘要中完整发现,建议先查看:
bash
python main.py --help
或阅读 demonstrate_react_agent()。
生成成功后,根据 README 架构说明,JSON 应位于:
text
frontend/public/trajectories/
该目录中已存在:
text
manifest.json
trajectory_20250914_211312.json
trajectory_20250914_211442.json
Step 2:启动前端
进入前端目录:
bash
cd frontend
安装依赖:
bash
npm install
启动开发服务:
bash
npm run dev
说明:摘要中没有展示 package.json 的 scripts 字段,因此 npm run dev 是 Next.js 项目的常见推断命令,未在解析摘要中明确发现。若命令失败,应以 frontend/package.json 中实际 scripts 为准。
Step 3:查看页面
如果前端服务正常启动,通常可通过 Next.js 默认地址访问:
text
http://localhost:3000
该地址未在解析摘要中明确发现,属于 Next.js 默认开发地址推断。
页面预期能力:
- 加载
manifest.json; - 列出 trajectory;
- 通过 tab 或选择器切换不同轨迹;
- 展示 prompt、response、attention heatmap 和 stats。
前端组件 props 和交互细节未在解析摘要中发现。
6.7 运行测试
摘要中发现以下测试文件:
text
test_attention_experiment.py
test_full_content.py
test_save_trajectory.py
test_status_bar_experiment.py
test_streaming.py
其中部分测试函数明确可识别:
| 测试文件 | 测试函数 | 测试目标 |
|---|---|---|
test_attention_experiment.py |
test_resolve_negative_layer |
负数 layer 解析 |
test_attention_experiment.py |
test_region_indices_separates_thinking_and_answer |
thinking/answer 区域切分 |
test_attention_experiment.py |
test_matrix_metrics_detects_causal_triangle_and_sink |
因果三角和 sink 指标 |
test_save_trajectory.py |
test_save_trajectory_writes_json_with_metadata |
trajectory JSON 元数据 |
test_save_trajectory.py |
test_save_trajectory_default_params_no_nameerror |
默认参数不产生 NameError |
test_status_bar_experiment.py |
test_base_trajectory_has_three_calls_and_four_distractors |
基础轨迹结构 |
test_status_bar_experiment.py |
test_status_block_matches_manuscript |
状态块与文稿匹配 |
test_status_bar_experiment.py |
test_behavior_classifier_distinguishes_call_and_refusal |
行为分类器 |
可尝试运行:
bash
pytest
或运行单个测试文件:
bash
pytest test_attention_experiment.py
pytest test_save_trajectory.py
pytest test_status_bar_experiment.py
test_full_content.py 和 test_streaming.py 的具体内容未在摘要中展开。
6.8 调试建议
6.8.1 优先使用短 prompt
CPU 用户建议先用:
bash
python attention_cli.py --max-new-tokens 5
目的:
- 减少生成时间;
- 快速确认模型、tokenizer、attention 捕获和绘图链路是否正常。
6.8.2 先看 head 平均,再看具体 head
推荐顺序:
--layer -1 --head -1--layer 0 --head -1--layer 0 --head 0- 逐步切换到其他 head
原因:
- head 平均图更稳定;
- 特定 head 可能模式稀疏,初学者不容易判断是否异常。
6.8.3 保存日志
实验脚本建议把 stdout/stderr 保存下来,方便对比:
bash
python run_attention_experiment.py --output runs/debug-test > runs/debug-test.log 2>&1
6.8.4 检查输出文件
重点检查:
- PNG 是否生成;
frontend/public/trajectories/是否出现新的 JSON;runs/.../attention_matrices.npz是否存在;- JSON 是否能被正常
json.load()读取; - NPZ 是否能被
numpy.load()读取。
7. 可扩展点与二次开发建议
7.1 新增模型支持
当前默认模型为 Qwen/Qwen3-0.6B,但 CLI 已提供 -m, --model 参数。
扩展方式:
- 确认目标模型可通过
transformers加载; - 确认模型输出中支持 attentions 或可通过 hook 获取;
- 使用
-m指定模型名或本地路径; - 检查 chat template 是否兼容;
- 对 layer 数、head 数进行适配。
风险点:
- 不同模型的 attention 返回结构可能不同;
- 模型可能不输出 attentions;
- token 模板特殊符号可能影响区域划分。
7.2 新增工具
在 tools.py 中通过 ToolRegistry.register_tool(...) 注册新工具。
开发步骤:
- 实现工具函数;
- 定义工具名称、描述和参数 schema;
- 在
_register_default_tools()中注册; - 在
main.py的 ReAct 循环中验证模型能否正确调用; - 保存 trajectory,检查工具调用前后注意力变化。
适合新增的工具:
- 数据库查询;
- 内部知识库检索;
- 数学计算;
- 文件读取;
- 企业 API 调用。
注意:涉及代码执行和外部请求时,应增加沙箱、超时、鉴权和错误处理。
7.3 新增可视化图表
visualization.py 已经提供多种图:
- heatmap;
- flow diagram;
- token summary;
- layer comparison;
- sink stats。
可扩展方向:
- 按 head 网格展示全部 head;
- 绘制不同 temperature 下注意力差异;
- 绘制工具调用前后注意力差分图;
- 将 attention sink 随 layer 变化画成折线图;
- 导出交互式 HTML 图。
7.4 扩展前端
前端已有组件:
AttentionHeatmap.tsxAttentionStats.tsxPromptDisplay.tsxResponseDisplay.tsxTestCaseSelector.tsx
可扩展功能:
- trajectory 搜索和标签筛选;
- layer/head 下拉选择;
- token 悬浮高亮;
- 多 trajectory 对比;
- ReAct 步骤时间线;
- 工具调用详情折叠面板;
- 从本地上传 JSON trajectory。
由于摘要未提供前端接口定义,开发前应先阅读 frontend/public/trajectories/*.json 和组件源码。
7.5 增加实验指标
run_attention_experiment.py 中已有 matrix_metrics(),可继续增加:
- entropy:注意力分布熵;
- max attention ratio;
- diagonal mass;
- local window attention;
- special token attention;
<think>区域与 answer 区域的注意力差异。
建议同时更新:
test_attention_experiment.pyvisualization.py- README 中的实验说明
7.6 增加自动化校验
validation/latest.json 表明项目可能有校验结果输出机制,但摘要未说明其生成逻辑。
可扩展:
- 每次实验后写入 JSON 校验报告;
- 对关键指标设置阈值;
- 将模型 revision、依赖版本、SHA256、机器信息写入报告;
- 在 CI 中运行轻量测试。
注意:README 明确说观测到的数值是结果,不应作为"有利结果门槛"。因此自动化校验应关注结构正确性、因果掩码、文件完整性,而不是强行要求某个固定注意力比例。
7.7 二次开发落地场景
| 场景 | 可复用模块 | 开发建议 |
|---|---|---|
| 教学演示 | attention_cli.py、visualization.py |
准备多个 prompt,一键生成对比图 |
| Agent 调试 | main.py、tools.py |
保存 ReAct trajectory,分析工具调用失败原因 |
| 模型评测 | run_attention_experiment.py |
增加多 prompt、多 seed、多 layer 指标 |
| 可解释性报告 | visualization.py、前端 |
导出 PNG/JSON,形成报告附件 |
| 企业内部知识库 Agent | ToolRegistry |
接入检索工具,记录检索前后注意力 |
| 前端交互分析平台 | frontend/ |
增加上传、筛选、对比功能 |
7.8 面试考点提炼
-
Transformer 中 attention 矩阵的行列分别表示什么?
- 行是 Query 位置,列是 Key 位置。
-
为什么因果注意力矩阵是上三角或下三角?
- 取决于矩阵布局;核心是当前位置只能看见已出现位置,不能看见未来 token。
-
什么是 attention sink?
- 模型大量注意力集中在某些起始或特殊 token 上的现象。
-
如何在
model.generate过程中记录 attention?- 可以使用
LogitsProcessor跟踪生成步骤,也可以通过 PyTorch hook 捕获模块输出。
- 可以使用
-
ReAct Agent 的轨迹为什么要保存?
- 便于复现推理过程、定位工具调用错误、分析模型决策依据。
-
为什么要把 trajectory 保存为 JSON?
- 便于前端读取、跨语言传输、归档和回归测试。
-
layer 和 head 分析有什么意义?
- 不同层可能承担不同功能;head 平均图适合总览,特定 head 适合发现细粒度模式。
-
如何保证实验可复现?
- 固定模型 revision、prompt、seed、参数、依赖版本,并保存输出哈希和元数据。
8. 常见问题与排查清单
8.1 模型下载失败或加载失败
【故障现象】→ 运行 python attention_cli.py 时卡在下载,或提示模型无法找到、权限失败、网络超时。
【根因】→ 默认模型 Qwen/Qwen3-0.6B 需要从 Hugging Face 下载;网络不可达、代理未配置、磁盘空间不足或本地路径错误都可能导致失败。
【修复方案】→
- 检查网络和代理;
- 确认磁盘空间至少能容纳 1--2 GB 模型;
- 手动下载模型到本地;
- 使用
-m指定本地模型路径; - 如果使用公司内网,配置 Hugging Face 镜像或缓存目录。
8.2 CUDA/MPS 不可用
【故障现象】→ 指定 --device cuda 或 mps 后报错,提示设备不可用或 PyTorch 不支持。
【根因】→ 当前 PyTorch 版本未编译 CUDA 支持、机器没有 NVIDIA GPU、Mac 设备不支持 MPS,或驱动环境不匹配。
【修复方案】→
- 先让脚本自动检测 device;
- 临时使用
--device cpu; - 检查
torch.cuda.is_available(); - 如确需 GPU,安装与 CUDA 版本匹配的 PyTorch。
8.3 CPU 运行很慢
【故障现象】→ 生成时间很长,尤其是设置较大 --max-new-tokens 时。
【根因】→ 自回归生成在 CPU 上较慢,attention 捕获和绘图也会增加开销。
【修复方案】→
- 先用
--max-new-tokens 0或很小的值测试; - 使用短 prompt;
- 使用 GPU/MPS;
- 避免一次性比较过多 layer;
- 调试时优先跑单张图。
8.4 layer 索引越界
【故障现象】→ 指定 --layer 13 或实验脚本捕获层时提示索引超出范围。
【根因】→ 模型实际层数小于指定索引,或负数 layer 解析不符合预期。
【修复方案】→
- 先使用
-1表示最后一层; - 查看模型配置中的层数;
- 使用
resolve_layer(index, count)逻辑统一处理负数; - 在实验脚本中加入层索引合法性检查。
8.5 head 索引越界
【故障现象】→ 指定 --head 3 后提示 head 索引超出范围。
【根因】→ 指定 head 大于模型实际 attention head 数。
【修复方案】→
- 先用
--head -1查看 head 平均; - 查看模型配置中的 attention head 数;
- 再逐步指定合法 head。
8.6 热力图中文乱码
【故障现象】→ PNG 中中文 token 显示为方框或乱码。
【根因】→ Matplotlib 没有找到可用的中文字体,或 _configure_cjk_font() 未生效。
【修复方案】→
- 确认系统安装中文字体;
- 检查
visualization.py中_configure_cjk_font()的字体列表; - 将可用中文字体加入 Matplotlib 字体配置;
- 重新生成图片。
8.7 前端看不到新生成的 trajectory
【故障现象】→ Python 脚本运行成功,但前端列表没有新轨迹。
【根因】→ JSON 没有写入 frontend/public/trajectories/,或 manifest.json 没有更新,或前端服务未刷新。
【修复方案】→
- 检查
frontend/public/trajectories/目录; - 确认新 JSON 文件存在且格式合法;
- 检查
manifest.json是否包含新文件; - 重启前端开发服务;
- 浏览器强制刷新。
8.8 trajectory JSON 无法读取
【故障现象】→ 前端加载失败,或 Python 中 json.load() 报错。
【根因】→ 写入过程中断、JSON 结构不完整、字段缺失或文件编码异常。
【修复方案】→
- 打开 JSON 检查是否完整;
- 使用
python -m json.tool <file>校验; - 检查
save_trajectory()是否在异常情况下写了半个文件; - 重新生成 trajectory;
- 保存时使用临时文件写完后再原子替换。
8.9 工具调用失败
【故障现象】→ ReAct Agent 输出工具调用,但工具返回错误,或流程中断。
【根因】→ 外部 API 未配置、网络失败、参数 schema 不匹配、工具函数内部异常。
【修复方案】→
- 检查
.env是否从env.example复制并填写; - 单独调用工具函数测试;
- 查看
parse_tool_calls()解析出的参数; - 在
execute_tool()中增加异常捕获和错误返回; - 确认工具 schema 与函数参数一致。
8.10 多次生成的注意力数据混杂
【故障现象】→ 图中出现不属于当前 prompt 的 token,或 attention step 数量异常多。
【根因】→ AttentionTracker.reset() 没有在新生成前调用,或对话历史没有清空。
【修复方案】→
- 每次生成前调用 tracker 的
reset(); - 对新会话调用
reset_conversation(); - 检查
generate_with_attention()是否复用了旧状态; - 单测覆盖重复生成场景。
8.11 chat template 导致结果不符合预期
【故障现象】→ 同样的 prompt,加不加 chat template 的注意力图差异很大。
【根因】→ chat template 会加入 <|im_start|> 等特殊 token,改变上下文长度和注意力边界。
【修复方案】→
- 明确实验是否需要模板;
- CLI 中对比默认模式与
--no-chat-template; - 在图中标出 context boundary;
- 保存轨迹时记录是否使用 chat template。
8.12 实验输出目录无法写入
【故障现象】→ run_attention_experiment.py 提示权限错误、目录已存在或路径无效。
【根因】→ 输出路径不存在、无权限、磁盘满,或脚本期望空目录但目录中已有文件。
【修复方案】→
- 使用新的输出目录;
- 检查目录权限;
- 确认磁盘剩余空间;
- Windows 避免使用 shell 不支持的日期表达式;
- 必要时手动创建目录。
8.13 测试失败
【故障现象】→ 运行 pytest 后部分测试失败。
【根因】→ 代码修改破坏了 layer 解析、区域划分、trajectory 保存或状态条分类逻辑;也可能缺少测试依赖。
【修复方案】→
-
先运行单个测试文件定位问题;
-
检查失败断言对应的数据结构;
-
对实验逻辑优先运行:
bashpytest test_attention_experiment.py -v pytest test_status_bar_experiment.py -v pytest test_save_trajectory.py -v -
若缺少
pytest,先安装测试依赖; -
修改代码后补充回归测试。
8.14 前端依赖安装或启动失败
【故障现象】→ 在 frontend/ 下执行 npm install 或 npm run dev 失败。
【根因】→ Node.js/npm 版本不兼容、网络问题、依赖锁文件冲突,或实际启动脚本不是 dev。
【修复方案】→
- 检查 Node.js 和 npm 版本;
- 查看
frontend/package.json中的scripts; - 优先使用
package-lock.json对应版本安装; - 网络异常时配置 npm 镜像;
- 删除
node_modules后重新安装时需谨慎,避免破坏已有环境。
8.15 实验结果与 README 数值不完全一致
【故障现象】→ 自己运行得到的 attention sink 比例不是 README 中提到的 75--85%。
【根因】→ 模型 revision、生成参数、采样随机性、设备、依赖版本、prompt 模板不同,都可能导致数值差异。
【修复方案】→
- 确认使用相同模型和 prompt;
- 固定 seed 和生成参数;
- 使用规范化实验脚本而不是手动临时命令;
- 保存模型 revision、SHA256、参数和日志;
- 将 README 数值理解为观测范围,而不是所有环境的硬性阈值。