Claude Code 深度实战指南
如果说大模型本身是一台电脑主机,那么MCP就是它的USB接口,让模型可以从外界获取资源以及调取需要的工具;Skill 决定了它"知道"怎么做,以及按照我们说的做;Subagent 让它能"并行"工作,相当于将一个主任务拆解为多个子任务分配给多个下属来完成;Hook 让流程"自动化",简单说,就是让这个过程变成流水线;CLAUDE.md 则是贯穿一切的"项目灵魂",一个比较粗糙的类比就是项目开发所
Agent、Subagent、Skill、MCP、Hook 的原理、协作与生产级工作流
本文面向已具备一定 AI 开发基础的工程师,目标是帮助你真正理解 Claude Code 的"五层架构",并将它们组合成可落地的生产级工作流。
一、全局视图:五层架构
在深入每个概念之前,先建立一个整体心智模型。Claude Code 的扩展体系可以被理解为五个相互叠加的层次:
┌─────────────────────────────────────────────────────────┐
│ 第5层 Plugin(插件) │
│ 将 Skill / Slash Command / Hook / MCP 打包分发 │
├─────────────────────────────────────────────────────────┤
│ 第4层 Agent Teams(Agent 团队) │
│ 多个独立 Claude 实例并行协作,拥有各自的上下文窗口 │
├─────────────────────────────────────────────────────────┤
│ 第3层 Subagent(子 Agent) │
│ 在主对话的隔离上下文中执行特定任务并回报结果 │
├─────────────────────────────────────────────────────────┤
│ 第2层 Skills / Slash Commands / Hooks │
│ 技能(按需加载的专家指令)/ 触发器 / 生命周期钩子 │
├─────────────────────────────────────────────────────────┤
│ 第1层 MCP(模型上下文协议) │
│ 连接外部系统:数据库、API、文件系统、SaaS 工具 │
└─────────────────────────────────────────────────────────┘
↑ 所有层次都建立在 CLAUDE.md 的"项目记忆"之上
每一层都不是孤立的。MCP 让 Claude 能触达外部世界;Skill 让它知道"怎么做";Subagent 让它"并行干活";Plugin 则让整套配置可以在团队里复用。理解这个层次关系,是掌握所有后续概念的前提。
二、CLAUDE.md:一切的地基
在讲任何高级功能之前,CLAUDE.md 必须优先讲清楚,因为它是所有其他组件运行时的上下文基础。
CLAUDE.md 是 Claude Code 在进入项目时自动加载的"项目记忆"文件。放在项目根目录的 CLAUDE.md 文件会被注入每一次对话的 system prompt,相当于给 Claude 做了岗前培训。
一个生产级 CLAUDE.md 示例
假设你在维护一个 ROS2 + HarmonyOS 混合项目:
# 项目上下文:Sc_vision
## 项目结构
- `ros2_ws/` — ROS2 工作空间,使用 colcon 构建
- `harmony_app/` — HarmonyOS ArkTS 前端,使用 DevEco Studio 开发
- `shared_proto/` — 两侧共用的 Protobuf 消息定义
## 核心约束(必须遵守)
- 永远不要在未经确认的情况下 `git push`
- 所有 ROS2 节点必须包含 `rclcpp::shutdown()` 的正确生命周期处理
- ArkTS 代码中禁止使用任何 HarmonyOS API 3.x 以下的接口
- 修改 `package.xml` 前必须检查依赖是否在 ros-humble 中存在
## 构建命令
- ROS2: `cd ros2_ws && colcon build --symlink-install --packages-select <pkg>`
- 清理: `rm -rf ros2_ws/build ros2_ws/install ros2_ws/log`
## 代码风格
- C++: 遵循 Google C++ Style Guide,使用 `clang-format`
- ArkTS: 遵循华为官方 ArkTS 编码规范 v4.x
## 当前已知问题
- camera_driver 包的 CMakeLists.txt 中 OpenCV 路径需要手动指定
这个文件让 Claude 在每次对话开始时就具备项目的全局认知,而不需要你反复解释背景。
三、MCP:AI 的"USB-C 接口"
3.1 核心概念
MCP(Model Context Protocol)是 Anthropic 发布的一个开放标准,解决的是"AI 如何连接外部系统"这个问题。在 MCP 出现之前,每个工具都需要写一套专属集成;MCP 就像 USB-C,提供了一个统一的协议,任何系统只要实现这个协议就能被 Claude 调用。
MCP 的核心工作模型非常简单:
- MCP Server 暴露工具(tools)和资源(resources),可以是本地进程(stdio 模式)或远程服务(HTTP/SSE 模式)。
- MCP Client(即 Claude Code 本身)连接到这些 server,将它们暴露的工具当作"原生能力"使用。
关键认知:MCP 解决的是"能触达什么"的问题,而不是"怎么做"的问题。 能查数据库、能提 PR、能查 Slack 消息——这些都是 MCP 的职责范围。
3.2 配置 MCP Server
MCP 的配置通过项目根目录的 .claude/config.json 或全局配置文件来管理。下面是一个完整的生产配置示例:
// .claude/config.json
{
"mcpServers": {
"github": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}"
}
},
"postgres": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-postgres"],
"env": {
"DATABASE_URL": "${DATABASE_URL}"
}
},
"filesystem": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"/home/user/projects/sc_vision"
]
},
"slack": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-slack"],
"env": {
"SLACK_BOT_TOKEN": "${SLACK_BOT_TOKEN}",
"SLACK_TEAM_ID": "${SLACK_TEAM_ID}"
}
}
}
}
3.3 自定义 MCP Server(Python 示例)
当现成的 MCP server 不满足需求时,可以自己写。以下是一个给 ROS2 项目暴露"构建状态"和"话题列表"的自定义 MCP server:
# ros2_mcp_server.py
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp import types
import subprocess
import json
server = Server("ros2-tools")
@server.list_tools()
async def list_tools():
return [
types.Tool(
name="ros2_build",
description="构建指定的 ROS2 包,返回构建日志",
inputSchema={
"type": "object",
"properties": {
"package_name": {
"type": "string",
"description": "要构建的 ROS2 包名"
}
},
"required": ["package_name"]
}
),
types.Tool(
name="ros2_list_topics",
description="列出当前 ROS2 环境中的所有话题",
inputSchema={"type": "object", "properties": {}}
),
types.Tool(
name="ros2_check_package",
description="检查 package.xml 中的依赖是否都在 humble 中存在",
inputSchema={
"type": "object",
"properties": {
"package_path": {"type": "string"}
},
"required": ["package_path"]
}
)
]
@server.call_tool()
async def call_tool(name: str, arguments: dict):
if name == "ros2_build":
pkg = arguments["package_name"]
result = subprocess.run(
["colcon", "build", "--symlink-install", "--packages-select", pkg],
cwd="/home/user/ros2_ws",
capture_output=True,
text=True,
timeout=120
)
return [types.TextContent(
type="text",
text=f"Exit code: {result.returncode}\\n"
f"STDOUT:\\n{result.stdout}\\n"
f"STDERR:\\n{result.stderr}"
)]
elif name == "ros2_list_topics":
result = subprocess.run(
["ros2", "topic", "list"],
capture_output=True, text=True, timeout=10
)
return [types.TextContent(type="text", text=result.stdout)]
elif name == "ros2_check_package":
# 解析 package.xml 并验证依赖
import xml.etree.ElementTree as ET
tree = ET.parse(f"{arguments['package_path']}/package.xml")
root = tree.getroot()
deps = [d.text for d in root.findall("depend")]
return [types.TextContent(
type="text",
text=f"找到 {len(deps)} 个依赖: {', '.join(deps)}"
)]
async def main():
async with stdio_server() as (read_stream, write_stream):
await server.run(read_stream, write_stream,
server.create_initialization_options())
if __name__ == "__main__":
import asyncio
asyncio.run(main())
然后在配置中注册:
"ros2": {
"type": "stdio",
"command": "python3",
"args": ["/home/user/ros2_mcp_server.py"]
}
四、Skills:可移植的专家指令集
4.1 Skills 解决了什么问题
你有没有遇到过这种情况:你花了大量时间写了一个很好的 prompt,让 Claude 按照你团队的规范进行代码审查,结果下次开启新对话时,一切又要从头来过?Skills 正是为了解决这个"Prompt 复用"困境而生的。
Skills 的本质是按需加载的专家指令集。它采用了一个精妙的"渐进式披露"设计:
- Skill 的名字和描述总是在 system prompt 中可见,相当于让 Claude 知道"我有哪些专家可以咨询"。
- 只有当任务与某个 Skill 相关时,Claude 才会主动加载
SKILL.md的详细内容。
这种设计极大地节省了 context window 的 token。你可以注册几十个 Skill,但 Claude 在每次对话中只加载真正用到的那几个。
4.2 目录结构
Skills 存放在 .claude/skills/ 目录下,每个 Skill 是一个独立文件夹:
.claude/
└── skills/
├── code-review/
│ ├── SKILL.md # 必须,主指令文件
│ ├── checklist.md # 可选,审查清单模板
│ └── examples/ # 可选,好坏示例
│ ├── good.cpp
│ └── bad.cpp
├── ros2-node/
│ ├── SKILL.md
│ └── node_template.cpp # 可供参考的代码模板
└── arkts-component/
├── SKILL.md
└── component_template.ets
4.3 一个完整的 Skill 示例:ROS2 节点规范审查
---
name: ros2-node-review
description: >
当用户要求审查、创建或调试 ROS2 节点代码时使用此 Skill。
涵盖 C++ rclcpp 和 Python rclpy 节点,包括生命周期、话题、服务、参数等规范检查。
---
# ROS2 节点规范审查 Skill
## 角色定位
你是一位精通 ROS2 Humble 的嵌入式系统工程师,熟悉生产环境中的最佳实践。
## 审查清单
### 1. 生命周期管理(最高优先级)
- [ ] 是否正确初始化 `rclcpp::init(argc, argv)`
- [ ] 是否使用 `rclcpp::spin()` 或 `rclcpp::spin_some()` 而不是手写循环
- [ ] 是否在退出时调用 `rclcpp::shutdown()`
- [ ] 如果是 LifecycleNode,是否实现了所有必要的状态回调
### 2. 资源管理
- [ ] 订阅者和发布者是否作为类成员变量保存(避免被 GC)
- [ ] Timer 回调是否避免了长时间阻塞
- [ ] 是否正确使用了 `std::shared_ptr` 而非裸指针
### 3. 参数声明
- [ ] 所有参数必须在节点构造函数中用 `declare_parameter()` 声明
- [ ] 动态参数是否注册了 `set_parameters_callback`
### 4. QoS 配置
- [ ] 传感器数据使用 `rclcpp::SensorDataQoS()`
- [ ] 重要状态数据使用 `RELIABLE` 可靠性策略
## 代码生成模板
当被要求创建新节点时,使用以下模板:
```cpp
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
class MyNode : public rclcpp::Node {
public:
MyNode() : Node("my_node") {
// 1. 声明参数
this->declare_parameter("rate_hz", 10.0);
// 2. 创建发布者/订阅者
publisher_ = this->create_publisher<std_msgs::msg::String>("output", 10);
subscriber_ = this->create_subscription<std_msgs::msg::String>(
"input", 10,
std::bind(&MyNode::callback, this, std::placeholders::_1));
// 3. 创建定时器
double rate = this->get_parameter("rate_hz").as_double();
timer_ = this->create_wall_timer(
std::chrono::duration<double>(1.0 / rate),
std::bind(&MyNode::timer_callback, this));
RCLCPP_INFO(this->get_logger(), "Node initialized");
}
private:
void callback(const std_msgs::msg::String::SharedPtr msg) {
RCLCPP_DEBUG(this->get_logger(), "Received: %s", msg->data.c_str());
}
void timer_callback() {
auto message = std_msgs::msg::String();
message.data = "Hello";
publisher_->publish(message);
}
rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;
rclcpp::Subscription<std_msgs::msg::String>::SharedPtr subscriber_;
rclcpp::TimerBase::SharedPtr timer_;
};
int main(int argc, char ** argv) {
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<MyNode>());
rclcpp::shutdown();
return 0;
}
### 4.4 ArkTS 组件规范 Skill
```markdown
---
name: arkts-component
description: >
创建或审查 HarmonyOS ArkUI 组件时使用。
确保组件符合 ArkTS 语法规范(API 12+),
避免使用已废弃的 API 和常见的幻觉性错误。
---
# HarmonyOS ArkTS 组件开发规范
## 重要约束(防止幻觉)
- 只使用 HarmonyOS API 12(SDK 5.x)及以上的 API
- 禁止使用 `@State` 以外的装饰器作为入口组件的参数
- `@Link` 只能用于父子组件传递,不能跨层级
- `ForEach` 的 keyGenerator 参数不能返回非字符串类型
## 组件结构规范
### 必须遵守的顺序
1. 导入语句(`import { ... } from '@ohos/...'`)
2. 常量/枚举定义
3. 自定义组件(`@Component struct MyComponent`)
4. 入口组件(`@Entry @Component struct Index`)
### 状态管理规则
- 局部状态:`@State`
- 父传子(单向):`@Prop`
- 父子双向绑定:`@Link`
- 跨组件共享:`@Provide` / `@Consume`
- 复杂对象观察:`@Observed` + `@ObjectLink`
## 标准组件模板
```typescript
import { router } from '@kit.ArkUI';
interface ItemData {
id: number;
title: string;
value: string;
}
@Component
struct ItemCard {
@Prop item: ItemData;
@State isExpanded: boolean = false;
build() {
Column() {
Row() {
Text(this.item.title)
.fontSize(16)
.fontWeight(FontWeight.Medium)
.fontColor($r('app.color.text_primary'))
Blank()
Image($r('app.media.ic_arrow'))
.width(20)
.height(20)
.rotate({ angle: this.isExpanded ? 180 : 0 })
.animation({ duration: 200, curve: Curve.EaseInOut })
}
.width('100%')
.padding(12)
.onClick(() => { this.isExpanded = !this.isExpanded; })
if (this.isExpanded) {
Text(this.item.value)
.fontSize(14)
.fontColor($r('app.color.text_secondary'))
.padding({ left: 12, right: 12, bottom: 12 })
}
}
.backgroundColor($r('app.color.card_background'))
.borderRadius(8)
.margin({ bottom: 8 })
}
}
@Entry
@Component
struct Index {
@State items: ItemData[] = [
{ id: 1, title: '项目一', value: '详细内容一' },
{ id: 2, title: '项目二', value: '详细内容二' }
];
build() {
Scroll() {
Column() {
ForEach(this.items, (item: ItemData) => {
ItemCard({ item: item })
}, (item: ItemData) => item.id.toString()) // keyGenerator 必须返回 string
}
.padding(16)
}
.scrollable(ScrollDirection.Vertical)
}
}
---
## 五、Subagent:隔离上下文的并行工作者
### 5.1 为什么需要 Subagent
想象你在做一个复杂的功能开发:需要同时调研最佳实践、审查现有代码、编写测试。如果所有这些工作都在同一个对话上下文中进行,会发生两个问题:第一,上下文窗口会被大量的中间输出填满,导致 Claude 对核心任务的关注度下降;第二,某些子任务的产出(比如调研报告)会"污染"主任务的上下文。
Subagent 解决了这个问题。**每个 Subagent 在自己独立的上下文窗口中运行**,完成任务后只将结果摘要返回给主 Agent,就像一个员工完成任务后只向上级汇报结论,而不是把全部工作过程都搬到会议室。
### 5.2 Subagent 文件结构
Subagent 定义文件存放在 `.claude/agents/` 目录:
.claude/ └── agents/ ├── code-reviewer.md ├── test-writer.md ├── documentation-writer.md ├── security-auditor.md └── ros2-debugger.md
### 5.3 完整的 Subagent 示例
**代码审查 Subagent:**
```markdown
---
name: code-reviewer
description: >
当需要对代码进行深度审查时调用此 subagent。
适用于 PR 审查、安全审计、性能分析。
该 subagent 只读取文件,不做任何修改。
tools: Read, Grep, Glob, Bash
model: claude-sonnet-4-6
---
你是一位资深的代码审查工程师,专注于发现安全漏洞、性能问题和代码质量问题。
## 审查维度
1. **安全性**:SQL 注入、XSS、未验证的用户输入、硬编码密钥
2. **性能**:O(n²) 复杂度、不必要的数据库查询、内存泄漏
3. **可维护性**:函数长度(>50行需警告)、魔法数字、缺少注释的复杂逻辑
4. **一致性**:是否遵循了项目的编码规范(参考 CLAUDE.md)
## 输出格式
返回一个结构化报告,包含:
- 🔴 严重问题(必须修复)
- 🟡 警告(建议修复)
- 🟢 建议(可选优化)
- 总体评分(1-10)和一句话总结
## 工作方式
- 使用 Grep 搜索特定模式
- 使用 Glob 遍历相关文件
- 使用 Bash 运行 linter(如 `clang-format --dry-run`)
- 只读不写,所有发现以报告形式返回给主 Agent
测试编写 Subagent:
---
name: test-writer
description: >
为指定模块编写单元测试和集成测试。
在代码审查 subagent 完成后使用,基于审查发现的问题编写针对性测试。
tools: Read, Write, Edit, Bash, Glob, Grep
model: claude-sonnet-4-6
---
你是一位测试工程师,专注于编写高覆盖率、有意义的测试用例。
## 测试策略
- 对每个公共函数编写正常路径和边界条件测试
- 对审查报告中标注的 🔴 和 🟡 问题编写回归测试
- 使用 Google Test(C++)或 pytest(Python)
## ROS2 测试规范
- 使用 `rclcpp::executors::SingleThreadedExecutor` 在测试中运行节点
- 话题测试使用 `rclcpp::WaitSet` 等待消息
- 测试文件放在 `test/` 目录,命名为 `test_<module_name>.cpp`
## 输出
- 生成测试文件
- 返回测试覆盖的场景列表和运行命令给主 Agent
ROS2 调试 Subagent:
---
name: ros2-debugger
description: >
当 ROS2 构建失败或运行时出错时调用。
分析构建日志、检查依赖关系、诊断话题通信问题。
tools: Read, Bash, Grep, Glob
disallowedTools: Write, Edit
model: claude-sonnet-4-6
---
你是 ROS2 调试专家,熟悉 colcon、ament、rcl 的内部机制。
## 调试步骤
1. 读取构建日志,定位第一个错误(ERROR 关键字)
2. 检查 `package.xml` 的依赖声明
3. 检查 `CMakeLists.txt` 中的 `find_package` 和 `target_link_libraries`
4. 如果是运行时错误,检查话题名称和 QoS 配置是否匹配
5. 使用 `ros2 pkg list | grep <pkg>` 验证包是否已安装
## 常见问题模式
- `No rule to make target` → CMakeLists.txt 中文件路径错误
- `undefined reference to` → `target_link_libraries` 缺少库
- `Could not load library` → 需要 `source install/setup.bash`
- `QoS mismatch` → 发布者和订阅者的可靠性策略不一致
返回:根本原因分析 + 具体修复方案(不直接执行修改,方案由主 Agent 确认后执行)
六、Hooks:生命周期钩子
6.1 概念说明
Hooks 是在 Claude Code 工作流的特定生命周期事件发生时自动触发的脚本或命令。它们类似于 Git 的 pre-commit hooks,但作用于 AI 辅助开发的整个生命周期。
主要的 Hook 触发点包括:
PreToolCall:在 Claude 调用任何工具之前PostToolCall:在工具调用完成之后Stop:在 Claude 完成一轮响应之后
6.2 Hooks 配置示例
// .claude/config.json 中的 hooks 配置
{
"hooks": {
"PostToolCall": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/format_code.sh $CLAUDE_TOOL_RESULT_FILE"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/notify.sh"
}
]
}
]
}
}
自动格式化 Hook 脚本:
#!/bin/bash
# .claude/hooks/format_code.sh
# 在每次文件写入后自动运行 linter
FILE="$1"
if [[ "$FILE" == *.cpp ]] || [[ "$FILE" == *.hpp ]]; then
echo "[Hook] 运行 clang-format: $FILE"
clang-format -i "$FILE"
fi
if [[ "$FILE" == *.py ]]; then
echo "[Hook] 运行 black: $FILE"
black "$FILE" --quiet
fi
if [[ "$FILE" == *.ets ]] || [[ "$FILE" == *.ts ]]; then
echo "[Hook] 运行 prettier: $FILE"
npx prettier --write "$FILE" --log-level warn
fi
任务完成通知 Hook:
#!/bin/bash
# .claude/hooks/notify.sh
# Claude 完成任务时发送桌面通知或 Slack 消息
MESSAGE="Claude Code 完成了任务!"
# 桌面通知(Linux)
if command -v notify-send &> /dev/null; then
notify-send "Claude Code" "$MESSAGE" --icon=dialog-information
fi
# 或发送 Slack 消息
if [ -n "$SLACK_WEBHOOK_URL" ]; then
curl -s -X POST "$SLACK_WEBHOOK_URL" \\
-H 'Content-type: application/json' \\
--data "{\\"text\\": \\"$MESSAGE\\"}"
fi
七、生产级工作流实战
理论讲完了,现在把所有概念串联起来,构建三个真实的生产级工作流。
工作流一:Feature Branch 全自动交付流水线
场景描述: 开发完成一个 feature 后,通过一条命令完成:代码审查 → 修复问题 → 编写测试 → 格式化 → 提交 PR。
涉及组件: Subagent(code-reviewer、test-writer)+ MCP(GitHub)+ Skill(change-report)+ Hook(格式化)
Slash Command 定义:
<!-- .claude/commands/ship-feature.md -->
你正在执行 "ship-feature" 工作流。请按照以下步骤严格执行:
## 第一步:代码审查
使用 code-reviewer subagent 审查当前 feature branch 相对于 main 的所有改动。
等待审查报告完成后再继续。
## 第二步:修复严重问题
根据审查报告中的 🔴 严重问题,逐一修复。
修复后告知我,等待我确认再继续。
## 第三步:编写测试
使用 test-writer subagent,针对本次改动和审查发现的问题编写测试。
运行测试确保全部通过。
## 第四步:格式化(Hook 自动触发)
此步骤由 PostToolCall Hook 自动完成,无需手动执行。
## 第五步:提交 PR
使用 GitHub MCP 创建 PR。PR 标题和描述按照以下格式:
- 标题:`[Feature] <功能简述>`
- 描述:使用 change-report skill 生成结构化报告
## 进度汇报
每完成一步,用一行简短的 ✅ 标记告知我进度。
执行时,在 Claude Code 中输入:
/ship-feature
Claude 会自动按步骤编排,调用对应的 Subagent 和 MCP 工具。
工作流二:ROS2 包从零到可运行
场景描述: 用自然语言描述一个 ROS2 节点的功能需求,Claude 自动生成完整的包结构、代码、CMakeLists、package.xml,并完成构建验证。
用到的 CLAUDE.md 上下文 + ros2-node Skill + ros2-debugger Subagent + ROS2 MCP Server。
实际对话示例:
用户: 帮我创建一个叫 sc_camera_driver 的 ROS2 包。
功能:订阅 /camera/raw(sensor_msgs/Image),
用 OpenCV 做灰度转换,发布到 /camera/gray(sensor_msgs/Image)。
节点名叫 GrayscaleConverter,参数有 encoding(默认 "mono8")。
Claude 的执行流程(内部):
- 检测到 ROS2 相关任务 → 自动加载
ros2-nodeSkill - 创建完整的包目录结构
- 生成符合规范的节点代码(基于 Skill 模板)
- 编写
CMakeLists.txt和package.xml - 调用 ROS2 MCP Server 执行构建:
ros2_build("sc_camera_driver") - 如果构建失败 → 启动
ros2-debuggerSubagent 分析日志 - 返回构建结果和运行命令
生成的代码示例(节选):
// src/grayscale_converter.cpp
#include "rclcpp/rclcpp.hpp"
#include "sensor_msgs/msg/image.hpp"
#include "cv_bridge/cv_bridge.h"
#include "opencv2/imgproc.hpp"
class GrayscaleConverter : public rclcpp::Node {
public:
GrayscaleConverter() : Node("grayscale_converter") {
// 遵循 ros2-node Skill:必须先声明参数
this->declare_parameter("encoding", "mono8");
encoding_ = this->get_parameter("encoding").as_string();
subscriber_ = this->create_subscription<sensor_msgs::msg::Image>(
"/camera/raw",
rclcpp::SensorDataQoS(), // 遵循 Skill:传感器数据用 SensorDataQoS
std::bind(&GrayscaleConverter::image_callback, this,
std::placeholders::_1));
publisher_ = this->create_publisher<sensor_msgs::msg::Image>(
"/camera/gray", rclcpp::SensorDataQoS());
RCLCPP_INFO(this->get_logger(),
"GrayscaleConverter initialized, encoding: %s",
encoding_.c_str());
}
private:
void image_callback(const sensor_msgs::msg::Image::SharedPtr msg) {
try {
auto cv_ptr = cv_bridge::toCvCopy(msg, "bgr8");
cv::Mat gray;
cv::cvtColor(cv_ptr->image, gray, cv::COLOR_BGR2GRAY);
auto out_msg = cv_bridge::CvImage(msg->header, encoding_, gray).toImageMsg();
publisher_->publish(*out_msg);
} catch (const cv_bridge::Exception &e) {
RCLCPP_ERROR(this->get_logger(), "cv_bridge exception: %s", e.what());
}
}
std::string encoding_;
rclcpp::Subscription<sensor_msgs::msg::Image>::SharedPtr subscriber_;
rclcpp::Publisher<sensor_msgs::msg::Image>::SharedPtr publisher_;
};
int main(int argc, char **argv) {
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<GrayscaleConverter>());
rclcpp::shutdown();
return 0;
}
工作流三:HarmonyOS 页面开发 + 幻觉防护
场景描述: 开发 HarmonyOS ArkTS 页面时,最大的挑战是 Claude 经常生成不存在的 API(幻觉)。通过 Skill + RAG(ChromaDB)+ Hook 的组合来解决这个问题。
架构设计:
用户需求
│
▼
arkts-component Skill(约束 API 版本和语法规范)
│
▼
Claude 生成初版代码
│
▼
PostToolCall Hook 触发 API 验证脚本
│
├── 调用 ChromaDB(存储了官方 SDK API 列表)验证每个 API 调用
│
├── 发现幻觉 API → 注入修正信息到下一轮对话
│
└── 全部通过 → 格式化并提交
API 验证 Hook 脚本:
#!/usr/bin/env python3
# .claude/hooks/validate_arkts_api.py
"""
在每次 ArkTS 文件写入后,验证使用的 API 是否存在于官方 SDK 中
"""
import sys
import re
import chromadb
def validate_arkts_file(file_path: str) -> list[str]:
"""返回文件中使用的无效 API 列表"""
if not file_path.endswith('.ets'):
return []
with open(file_path) as f:
content = f.read()
# 提取 API 调用模式(简化版)
api_calls = re.findall(r'(\\w+)\\s*\\(', content)
component_names = re.findall(r'(?:^|\\s)([A-Z]\\w+)\\s*\\(', content, re.MULTILINE)
# 查询 ChromaDB
client = chromadb.PersistentClient(path="/home/user/.arkts_api_db")
collection = client.get_collection("harmony_api_12")
invalid_apis = []
for api in set(component_names):
results = collection.query(
query_texts=[api],
n_results=1
)
if results['distances'][0][0] > 0.3: # 相似度阈值
invalid_apis.append(api)
return invalid_apis
if __name__ == "__main__":
file_path = sys.argv[1]
invalid = validate_arkts_file(file_path)
if invalid:
# 向 Claude Code 注入反馈(写入特殊文件,Claude 会读取)
with open(".claude/api_validation_errors.md", "w") as f:
f.write(f"## ⚠️ API 验证警告\\n\\n")
f.write(f"以下 API 在 HarmonyOS API 12 中未找到,可能是幻觉:\\n\\n")
for api in invalid:
f.write(f"- `{api}` — 请查阅官方文档确认正确 API 名称\\n")
print(f"[Hook] 发现 {len(invalid)} 个可疑 API,已写入验证报告")
sys.exit(1) # 非零退出码会通知 Claude Code 有问题
else:
print("[Hook] API 验证通过 ✅")
sys.exit(0)
八、Agent Teams:真正的多 Agent 并行
Agent Teams 是 Claude Code 在 2026 年初引入的实验性功能,允许多个完全独立的 Claude 实例(每个都有自己的完整上下文窗口)并行工作,并相互通信。这与 Subagent 的关键区别在于:Subagent 共享主 Agent 的生命周期,而 Agent Teams 中每个成员都是完全平等的独立进程。
启用方式:
CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 claude
# 或
claude --agent-teams
Agent Teams 适用的场景: 大型重构任务(前后端并行修改)、多模块同步测试、跨代码库的影响分析。
一个复杂的 Agent Teams 工作流示意:
用户: "重构整个认证系统,前端、后端、测试同步完成"
Lead Agent
├── 分解任务
├── 启动 Backend Agent
│ ├── 加载 backend-patterns Skill
│ ├── 修改 auth service、JWT 处理
│ └── 返回:已修改的 API 端点列表
├── 启动 Frontend Agent(并行)
│ ├── 加载 react-patterns Skill
│ ├── 等待 Backend Agent 的 API 列表(通过 SendMessage)
│ └── 更新前端的认证调用
├── 启动 Test Agent(等待前两个完成后)
│ ├── 加载 test-writing Skill
│ ├── 读取前两个 Agent 的修改报告
│ └── 编写端到端测试
└── 汇总所有结果,生成变更报告
九、概念对比速查表
| 概念 | 核心职责 | 持久性 | 适用场景 |
|---|---|---|---|
| CLAUDE.md | 项目记忆和全局约束 | 持久(每次对话加载) | 团队规范、项目背景 |
| MCP | 连接外部系统和数据 | 持久(配置后长期有效) | 数据库、API、SaaS 集成 |
| Skill | 可复用的专家指令集 | 持久(按需自动加载) | 重复性专业任务 |
| Slash Command | 手动触发的工作流快捷键 | 持久(显式触发) | 固定流程的启动入口 |
| Subagent | 隔离上下文的专项工作者 | 临时(任务完成即销毁) | 防止上下文污染的复杂子任务 |
| Hook | 生命周期自动化 | 持久(事件驱动) | 格式化、验证、通知 |
| Agent Teams | 真正的并行多 Agent | 临时(任务完成即结束) | 超大规模并行任务 |
| Plugin | 上述所有概念的打包单元 | 持久(安装后长期有效) | 团队配置分发 |
十、决策流程图:我应该用什么?
我有一个新需求
│
▼
需要访问外部系统(数据库/API/文件)?
├── YES → 配置 MCP Server
└── NO → 继续
│
▼
这是需要重复使用的专业知识或流程?
├── YES → 创建 Skill
└── NO → 继续
│
▼
这个任务会产生大量中间输出/需要独立权限?
├── YES → 创建 Subagent
└── NO → 继续
│
▼
需要在特定事件后自动执行某操作?
├── YES → 创建 Hook
└── NO → 直接 prompt 即可
十一、快速上手行动清单
如果你是第一次系统化配置 Claude Code,建议按照以下顺序进行:
第一天:打好地基 在项目根目录创建 CLAUDE.md,写入项目结构、核心约束、构建命令和技术栈信息。花 30 分钟写好这个文件,可以在后续节省无数次重复解释的时间。
第二天:接入外部工具 根据你的技术栈,配置 1-2 个最常用的 MCP Server(GitHub 和数据库通常是优先级最高的)。验证 Claude 能通过 MCP 成功调用这些工具。
第三天:沉淀专业知识 把你团队里最重要的编码规范、代码模板、审查清单,整理成 1-3 个 Skill。优先选择那些你平时在 prompt 里反复解释的内容。
第四天:创建核心 Subagent 至少创建一个代码审查 Subagent 和一个测试编写 Subagent。这是 ROI 最高的两个 Subagent,几乎适用于所有工程项目。
第五天:串联工作流 用 Slash Command 把以上所有组件串联成 1-2 个高频使用的完整工作流(如 ship-feature)。添加必要的 Hook 实现自动化质量门禁。
总结
Claude Code 的真正威力不在于任何单一功能,而在于这五层架构的协同效应。MCP 决定了 Claude 能"看到"什么,给予其更好的于外界交互的能力,如果说大模型本身是一台电脑主机,那么MCP就是它的USB接口,让模型可以从外界获取资源以及调取需要的工具;Skill 决定了它"知道"怎么做,以及按照我们说的做;Subagent 让它能"并行"工作,相当于将一个主任务拆解为多个子任务分配给多个下属来完成;Hook 让流程"自动化",简单说,就是让这个过程变成流水线;CLAUDE.md 则是贯穿一切的"项目灵魂",一个比较粗糙的类比就是项目开发所必须遵循的原则。
当这些组件配合良好时,Claude Code 不再是一个聊天工具,而是一个真正融入你开发流水线的自动化工程师。它能自动发现适用的技能、调度专项 Agent、在你批准后执行修改、通过 Hook 保障质量,最终通过 MCP 将结果推送到你的版本控制系统。
这,才是生产级 AI 辅助开发应有的样子。
更多推荐



所有评论(0)