第7课:AI 对话核心 —— Agent 和 SDK 怎么配合
本课目标
搞懂 AI 在这个系统里扮演什么角色、有哪些工具、怎么跟用户对话。
AI 在系统里的位置
graph LR
A["用户说话"] --> B["WebSocket"] --> C["Session 管理"] --> D["Claude Agent SDK"] --> E["Claude API"]
D --- F["自定义工具(搜索邮件、读邮件等)"]
D --- G["子Agent(搜索专家)"]
D --- H["系统提示词(你是邮件助手...)"]
AI 不是一个简单的聊天机器人——它有工具,能实际操作你的邮箱。
Session 管理:一次完整的对话
位置:ccsdk/session.ts
每当你在聊天框发一条消息,后端就启动一个"会话"来处理:
// 简化版
class Session {
async handleUserMessage(message: string) {
// 1. 把消息交给 Claude Agent SDK
const client = new ClaudeSDKClient(this.options);
// 2. 发送用户消息
await client.query(message);
// 3. 接收 AI 的回复流
for await (const msg of client.receiveResponse()) {
if (msg.type === 'assistant') {
// AI 的文字回复 → 推送到前端
this.websocket.send({
type: 'assistant_message',
content: msg.text
});
} else if (msg.type === 'tool_use') {
// AI 要用工具 → 推送到前端让用户看到
this.websocket.send({
type: 'tool_use',
name: msg.toolName,
input: msg.input
});
}
}
}
}
会话是有状态的——AI 记得之前的对话内容,所以你可以连续追问。
AI 的系统提示词
位置:ccsdk/email-agent-prompt.ts
这是 AI 的"身份说明书",告诉它:你是谁、能干什么、怎么干。
你是一个智能邮件助手。你可以帮助用户:
- 搜索和浏览邮件
- 分析邮件内容
- 执行邮件操作(归档、标星、贴标签等)
- 创建一键操作(Actions)
- 设置自动化规则(Listeners)
- 管理数据看板(UI State)
你有以下工具可以使用:
- email_search: 搜索邮件
- email_read: 读取邮件全文
- email_archive: 归档邮件
- email_star: 标星邮件
- email_label: 给邮件贴标签
- ...
当用户的请求涉及复杂搜索时,你应该使用 inbox-searcher 子Agent 来帮你。
AI 的工具箱
位置:ccsdk/custom-tools.ts
这些是给 AI 用的"手"——让它能操作邮箱。
| 工具 | 功能 | 使用场景 |
|---|---|---|
email_search |
搜索邮件 | "找上周的发票" |
email_read |
读取邮件全文 | "这封邮件说了什么?" |
email_archive |
归档邮件 | "把这封归档了" |
email_star |
标星/取消星标 | "给这封加个星标" |
email_label |
添加/删除标签 | "标记为紧急" |
email_mark_read |
标记已读/未读 | "标为未读" |
这些工具都是自定义的(不是 SDK 内置的),定义在 custom-tools.ts 里,通过 MCP 协议注册给 Claude。
工具定义示例
// 自定义搜索工具(简化版)
const emailSearchTool = {
name: "email_search",
description: "搜索邮件。支持 Gmail 搜索语法如 from:, to:, subject:, after:, before:",
input_schema: {
type: "object",
properties: {
query: {
type: "string",
description: "搜索关键词或 Gmail 查询语法"
},
limit: {
type: "number",
description: "返回结果数量,默认20"
}
},
required: ["query"]
},
handler: async (args) => {
const results = await database.searchEmails(args.query, args.limit);
return {
content: [{
type: "text",
text: JSON.stringify(results)
}]
};
}
};
搜索子Agent:inbox-searcher
位置:agent/.claude/agents/inbox-searcher.md
当搜索比较复杂时,主 Agent 会派出一个搜索专家子Agent:
用户: "找一下今年所有跟 AWS 相关的账单邮件"
主 Agent: "这个搜索比较复杂,我派搜索专家去"
│
▼ Task 工具
搜索子Agent (inbox-searcher):
"让我用假设驱动搜索法来找..."
→ 第1轮: from:aws OR from:amazon subject:invoice → 找到 12 封
→ 第2轮: from:aws subject:billing → 找到 5 封(有重复)
→ 第3轮: subject:AWS charge → 找到 3 封新的
→ 去重汇总: 共 15 封不同的 AWS 账单邮件
│
▼ 结果返回
主 Agent: "我找到了 15 封 AWS 账单邮件,时间从1月到现在..."
搜索子Agent 的提示词强调假设驱动搜索——不是暴力遍历所有邮件,而是像侦探一样,先假设"可能是什么",然后有针对性地搜。
AI 生成 Actions:聊天里的按钮
这是 demo 的亮点之一。AI 不只是回复文字,还能在聊天里生成可点击的按钮:
用户: "帮我把超过30天的订阅邮件清理了"
AI: "我找到了 47 封过期订阅邮件。要我帮你归档吗?"
┌──────────────────────────────────────┐
│ 🔘 归档 47 封过期订阅邮件 │ ← 这是 AI 生成的 Action 按钮
└──────────────────────────────────────┘
用户点击按钮后,Action 在后端执行,批量归档邮件。这比 AI 直接操作更安全——用户有确认的机会。
callAgent:代码里调用 AI
这是 demo 最独特的模式。不只是用户在聊天里调用 AI,代码也能调用 AI:
// 在 Listener 或 Action 的代码里
const result = await context.callAgent({
prompt: `分析这封邮件:
主题: ${email.subject}
发件人: ${email.from}
内容: ${email.body_text}
判断这是什么类型的邮件?如果是发票,提取金额和供应商名称。`,
schema: {
type: "object",
properties: {
email_type: { type: "string", enum: ["invoice", "newsletter", "personal", "work", "other"] },
amount: { type: "number" },
vendor: { type: "string" }
}
}
});
// result 是 AI 返回的结构化数据:
// { email_type: "invoice", amount: 500, vendor: "Acme Corp" }
if (result.email_type === "invoice") {
await context.uiState.update('financial-dashboard', {
// 把这笔支出记到财务看板
});
}
代码控制流程,AI 做智能判断——这就是"递归 AI"模式的核心。
本课小结
- Session 管理每次对话的生命周期
- 系统提示词 定义了 AI 的角色和能力
- 自定义工具 让 AI 能操作邮箱(搜索、归档、贴标签等)
- 搜索子Agent 处理复杂搜索,用假设驱动而非暴力遍历
- Action 按钮 让 AI 在聊天中生成可点击操作
- callAgent 让代码能调用 AI 做判断(递归 AI 模式)