Kilo 消息交互完整示例
一、文档概述
本文档通过具体的示例,展示 Kilo 项目中用户与 AI 助手之间的完整消息交互过程,包括:
- 消息的格式和结构
- 消息流转示例分析
- 流式响应的处理
- 工具执行结果的返回
本文档是对 【2】kilo 消息流转过程 的补充,提供实际的消息示例,帮助理解整个交互过程。
二、消息格式基础
2.1 消息层次结构
Kilo 的消息系统分为三个层次:
┌─────────────────────────────────────────────────────────────┐
│ 1. API 层消息 (ApiMessage) │
│ 用于与 LLM API 交互的标准格式消息 │
│ 基于 Anthropic.MessageParam │
│ │
│ 存储位置: api_conversation_history.json │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 2. UI 层消息 (ClineMessage) │
│ 用于 Extension 与 Webview 之间通信 │
│ 包含 UI 展示所需的所有信息 │
│ │
│ 存储位置: ui_messages.json │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 3. 任务层事件 (TaskEvents) │
│ Task 内部事件系统,用于状态管理和通知 │
│ 基于 EventEmitter 的事件机制 │
│ │
└─────────────────────────────────────────────────────────────┘
各层作用:
-
API 层 (ApiMessage)
- 负责与 LLM API 的标准化通信
- 维护完整的对话上下文(包括 tool_use 和 tool_result 的配对)
- 支持上下文压缩和截断管理
- 持久化存储以支持任务恢复
-
UI 层 (ClineMessage)
- 负责 Extension 与 Webview 之间的消息传递
- 包含 UI 展示所需的所有信息(进度、状态、元数据等)
- 支持流式更新(partial 消息机制)
- 区分 ask(需要用户交互)和 say(信息展示)两种类型
-
任务层 (TaskEvents)
- 负责任务状态管理和生命周期控制
- 通过事件机制解耦任务逻辑与 UI 更新
- 支持任务的创建、暂停、恢复、完成等状态转换
- 提供 Token 使用统计和工具调用监控
2.2 API 层消息类型 (ApiMessage)
API 层消息基于 Anthropic 的标准 MessageParam 格式,用于与 LLM API 交互。
2.2.1 基本结构
typescript
// 来源:src/core/task-persistence/apiMessages.ts
export type ApiMessage = Anthropic.MessageParam & {
// 基础字段
role: "user" | "assistant"
content: string | ContentBlock[]
// Kilo 扩展字段
ts?: number // 时间戳
id?: string // 消息唯一标识
// 上下文管理字段
isSummary?: boolean // 是否为总结消息
condenseId?: string // 总结消息的唯一标识
condenseParent?: string // 指向被总结的消息
truncationId?: string // 截断标记的唯一标识
truncationParent?: string // 指向被截断的消息
isTruncationMarker?: boolean // 是否为截断边界标记
// 推理相关字段
type?: "reasoning" // 推理类型消息
reasoning_content?: string // 推理内容(DeepSeek/Z.ai 格式)
reasoning_details?: any[] // 推理详情(OpenRouter 格式)
// 其他字段
summary?: any[] // 总结内容
encrypted_content?: string // 加密内容
text?: string // 文本内容
}
2.2.2 ContentBlock 类型详解
content 字段可以是字符串或 ContentBlock 数组:
1. TextBlock - 文本块
typescript
{
type: "text",
text: "帮我创建一个 Button 组件,要支持不同的尺寸和颜色"
}
- 用途:承载普通文本内容
- 出现位置:user 和 assistant 消息中
- 示例场景:用户输入、AI 回复
2. ImageBlock - 图片块
typescript
// Base64 格式
{
type: "image",
source: {
type: "base64",
media_type: "image/png", // 或 "image/jpeg", "image/gif", "image/webp"
data: "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJ..."
}
}
// URL 格式(Kilo 扩展)
{
type: "image",
source: {
type: "url",
url: "https://example.com/image.png"
}
}
- 用途:承载图片数据
- 出现位置:仅在 user 消息中
- 支持格式:PNG、JPEG、GIF、WebP
- 大小限制:通常不超过 5MB(取决于 API 提供商)
3. ToolUseBlock - 工具调用块
typescript
{
type: "tool_use",
id: "toolu_01A09q90qw90lq917835lq9", // 唯一标识符
name: "read_file", // 工具名称
input: { // 工具参数
path: "src/components/Button.tsx",
should_read_entire_file: true
}
}
- 用途:表示 AI 调用的工具
- 出现位置:仅在 assistant 消息中
- 关键字段 :
id:用于关联 tool_resultname:工具名称(如 read_file、create_file 等)input:工具的输入参数(JSON 对象)
4. ToolResultBlock - 工具结果块
typescript
// 简单文本结果
{
type: "tool_result",
tool_use_id: "toolu_01A09q90qw90lq917835lq9", // 对应的 tool_use ID
content: "文件内容..."
}
- 用途:承载工具执行的结果
- 出现位置:仅在 user 消息中
- 关键字段 :
tool_use_id:必须对应某个 tool_use 的 idcontent:可以是字符串或 ContentBlock 数组is_error:标记是否为错误结果
2.3 UI 层消息类型 (ClineMessage)
UI 层消息用于 Extension 与 Webview 之间的通信,包含 UI 展示所需的所有信息。
2.3.1 基本结构
typescript
// 来源:packages/types/src/message.ts
export type ClineMessage = {
// 基础字段
ts: number // 时间戳(毫秒)
type: "ask" | "say" // 消息类型
// ask 类型的字段
ask?: ClineAsk // 询问类型(需要用户交互)
// say 类型的字段
say?: ClineSay // 说话类型(信息展示)
// 内容字段
text?: string // 文本内容
images?: string[] // 图片列表(base64 或 URL)
reasoning?: string // 推理过程
// 流式相关
partial?: boolean // 是否为部分消息(流式更新)
progressStatus?: ToolProgressStatus // 工具进度状态
// 关联字段
conversationHistoryIndex?: number // 对应的 API 历史索引
// 上下文管理
contextCondense?: ContextCondense // 上下文压缩信息
contextTruncation?: ContextTruncation // 上下文截断信息
// 检查点
checkpoint?: Record<string, unknown> // 检查点数据
// 状态字段
isProtected?: boolean // 是否受保护
isAnswered?: boolean // 是否已回答
apiProtocol?: "openai" | "anthropic" // API 协议
// Kilo 扩展
metadata?: {
kiloCode?: KiloCodeMetaData
}
}
2.3.2 ClineAsk 类型(需要用户交互)
typescript
export type ClineAsk =
// 交互式询问(Interactive)- 需要用户立即响应
| "followup" // 后续问题
| "command" // 命令执行权限
| "tool" // 工具使用权限
| "browser_action_launch" // 浏览器操作权限
| "use_mcp_server" // MCP 服务器使用权限
| "report_bug" // 报告 Bug
| "condense" // 压缩上下文
| "checkpoint_restore" // 恢复检查点
// 空闲状态询问(Idle)- 任务暂停,等待用户决策
| "completion_result" // 任务完成
| "api_req_failed" // API 请求失败
| "resume_completed_task" // 恢复已完成任务
| "mistake_limit_reached" // 错误次数达到上限
| "auto_approval_max_req_reached" // 自动批准次数达到上限
| "payment_required_prompt" // 需要付费
| "invalid_model" // 无效模型
// 可恢复状态询问(Resumable)- 任务可以恢复
| "resume_task" // 恢复任务
// 非阻塞询问(Non-blocking)- 不阻塞任务执行
| "command_output" // 命令输出
2.3.3 ClineSay 类型(信息展示)
typescript
export type ClineSay =
// 错误和状态
| "error" // 错误消息
| "api_req_started" // API 请求开始
| "api_req_finished" // API 请求完成
| "api_req_retried" // API 请求重试
| "api_req_retry_delayed" // API 请求重试延迟
| "api_req_rate_limit_wait" // API 速率限制等待
| "api_req_deleted" // API 请求删除
// 内容展示
| "text" // 普通文本
| "image" // 图片
| "reasoning" // 推理过程
| "completion_result" // 完成结果
| "user_feedback" // 用户反馈
| "user_feedback_diff" // 用户反馈差异
// 命令和浏览器
| "command_output" // 命令输出
| "shell_integration_warning" // Shell 集成警告
| "browser_action" // 浏览器操作
| "browser_action_result" // 浏览器操作结果
| "browser_session_status" // 浏览器会话状态
// MCP 和子任务
| "mcp_server_request_started" // MCP 服务器请求开始
| "mcp_server_response" // MCP 服务器响应
| "subtask_result" // 子任务结果
// 系统功能
| "checkpoint_saved" // 检查点保存
| "rooignore_error" // .rooignore 错误
| "diff_error" // Diff 错误
| "condense_context" // 压缩上下文
| "condense_context_error" // 压缩上下文错误
| "sliding_window_truncation" // 滑动窗口截断
| "codebase_search_result" // 代码库搜索结果
| "user_edit_todos" // 用户编辑待办事项
三、完整对话示例
示例场景:用户请求设计一部心理悬疑电影
让我们通过一个完整的场景来展示消息交互的全过程。
第 1 轮:用户发起请求
用户输入:
帮我设计一部悬疑电影
系统构建的用户消息(存入 api_conversation_history.json):
json
{
"role": "user",
"content": [
{
"type": "text",
"text": "帮我设计一部悬疑电影"
}
],
"ts": 1768187000000
}
同时存入 ui_messages.json 的消息:
json
{
"ts": 1768187000000,
"type": "say",
"say": "text",
"text": "帮我设计一部悬疑电影",
"conversationHistoryIndex": 0
}
发送到 API 的完整请求:
json
{
"model": "claude-sonnet-4",
"max_tokens": 8192,
"system": [
{
"type": "text",
"text": "你是 Kilo,一个 AI 编程助手...",
"cache_control": { "type": "ephemeral" }
}
],
"messages": [
{
"role": "user",
"content": [
{
"type": "text",
"text": "帮我设计一部悬疑电影"
}
],
"ts": 1768187000000
}
]
}
第 2 轮:AI 响应并调用工具
AI 流式响应(原始文本):
好的!我很乐意帮你设计一部悬疑电影。首先让我了解一些关键信息:
<ask_followup_question>
<question>你希望这部悬疑电影属于哪种具体类型?</question>
<follow_up>
<option>心理悬疑 - 专注于角色的内心世界和心理状态</option>
<option>犯罪悬疑 - 围绕犯罪调查和侦破过程</option>
<option>惊悚悬疑 - 强调紧张刺激的氛围</option>
</follow_up>
</ask_followup_question>
流式解析过程:
-
第 1 个 chunk:
"好的!我很乐意"typescript// AssistantMessageParser 解析结果 [ { type: "text", content: "好的!我很乐意", partial: true } ] -
第 2 个 chunk:
"帮你设计一部悬疑电影。首先让我了解一些关键信息:\n\n<ask_followup_question>\n<question>"typescript[ { type: "text", content: "好的!我很乐意帮你设计一部悬疑电影。首先让我了解一些关键信息:", partial: false }, { type: "tool_use", name: "ask_followup_question", params: {}, partial: true } ] -
第 3 个 chunk:
"你希望这部悬疑电影属于哪种具体类型?</question>\n..."typescript[ { type: "text", content: "好的!我很乐意帮你设计一部悬疑电影。首先让我了解一些关键信息:", partial: false }, { type: "tool_use", name: "ask_followup_question", params: { question: "你希望这部悬疑电影属于哪种具体类型?", follow_up: [...] }, partial: false } ]
最终解析的助手消息(存入 api_conversation_history.json):
json
{
"role": "assistant",
"content": [
{
"type": "text",
"text": "好的!我很乐意帮你设计一部悬疑电影。首先让我了解一些关键信息:"
},
{
"type": "tool_use",
"id": "toolu_vrtx_01JVU2miNYbiFZJLeFcVAzi7",
"name": "ask_followup_question",
"input": {
"question": "你希望这部悬疑电影属于哪种具体类型?",
"follow_up": [
{"text": "心理悬疑 - 专注于角色的内心世界和心理状态"},
{"text": "犯罪悬疑 - 围绕犯罪调查和侦破过程"},
{"text": "惊悚悬疑 - 强调紧张刺激的氛围"}
]
}
}
],
"ts": 1768187030000
}
同时存入 ui_messages.json 的消息:
json
[
{
"ts": 1768187030000,
"type": "say",
"say": "api_req_started",
"text": "{\"apiProtocol\":\"openai\",\"tokensIn\":14439,\"tokensOut\":567}"
},
{
"ts": 1768187033000,
"type": "say",
"say": "text",
"text": "好的!我很乐意帮你设计一部悬疑电影。首先让我了解一些关键信息:",
"partial": false
},
{
"ts": 1768187045000,
"type": "ask",
"ask": "followup",
"text": "{\"question\":\"你希望这部悬疑电影属于哪种具体类型?\",\"suggest\":[{\"answer\":\"心理悬疑 - 专注于角色的内心世界和心理状态\"},{\"answer\":\"犯罪悬疑 - 围绕犯罪调查和侦破过程\"},{\"answer\":\"惊悚悬疑 - 强调紧张刺激的氛围\"}]}",
"isAnswered": true
}
]
工具执行流程:
-
presentAssistantMessage 检测到 ask_followup_question 调用
-
显示选项弹窗:
- 心理悬疑 - 专注于角色的内心世界和心理状态
- 犯罪悬疑 - 围绕犯罪调查和侦破过程
- 惊悚悬疑 - 强调紧张刺激的氛围
-
用户选择"心理悬疑 - 专注于角色的内心世界和心理状态"
-
工具执行结果:
用户选择:心理悬疑 - 专注于角色的内心世界和心理状态
构建的工具结果消息(存入 api_conversation_history.json):
json
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_vrtx_01JVU2miNYbiFZJLeFcVAzi7",
"content": "心理悬疑 - 专注于角色的内心世界和心理状态"
}
],
"ts": 1768187060000
}
同时存入 ui_messages.json 的消息:
json
[
{
"ts": 1768187060000,
"type": "say",
"say": "user_feedback",
"text": "心理悬疑 - 专注于角色的内心世界和心理状态",
"conversationHistoryIndex": 2
}
]
第 3 轮:AI 继续询问
AI 流式响应:
很好的选择!心理悬疑能够深入探索人物的内心世界。接下来让我了解更多细节:
<ask_followup_question>
<question>你希望电影探讨什么样的核心主题?</question>
<follow_up>
<option>记忆与现实 - 主人公对自己记忆的真实性产生怀疑</option>
<option>身份认同 - 主人公不确定自己是谁</option>
<option>信任危机 - 主人公无法相信周围的人</option>
</follow_up>
</ask_followup_question>
解析的助手消息(存入 api_conversation_history.json):
json
{
"role": "assistant",
"content": [
{
"type": "text",
"text": "很好的选择!心理悬疑能够深入探索人物的内心世界。接下来让我了解更多细节:"
},
{
"type": "tool_use",
"id": "toolu_vrtx_01JVU2pQbWxNLdXYdqxZfCPV",
"name": "ask_followup_question",
"input": {
"question": "你希望电影探讨什么样的核心主题?",
"follow_up": [
{"text": "记忆与现实 - 主人公对自己记忆的真实性产生怀疑"},
{"text": "身份认同 - 主人公不确定自己是谁"},
{"text": "信任危机 - 主人公无法相信周围的人"}
]
}
}
],
"ts": 1768187090000
}
同时存入 ui_messages.json 的消息:
json
[
{
"ts": 1768187090000,
"type": "say",
"say": "api_req_started",
"text": "{\"apiProtocol\":\"openai\",\"tokensIn\":14439,\"tokensOut\":567}"
},
{
"ts": 1768187093000,
"type": "say",
"say": "text",
"text": "很好的选择!心理悬疑能够深入探索人物的内心世界。接下来让我了解更多细节:",
"partial": false
},
{
"ts": 1768187095000,
"type": "ask",
"ask": "followup",
"text": "{\"question\":\"你希望电影探讨什么样的核心主题?\",\"suggest\":[{\"answer\":\"记忆与现实 - 主人公对自己记忆的真实性产生怀疑\"},{\"answer\":\"身份认同 - 主人公不确定自己是谁\"},{\"answer\":\"信任危机 - 主人公无法相信周围的人\"}]}",
"isAnswered": true
}
]
工具执行结果(存入 api_conversation_history.json):
json
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_vrtx_01JVU2pQbWxNLdXYdqxZfCPV",
"content": "记忆与现实 - 主人公对自己记忆的真实性产生怀疑"
}
],
"ts": 1768187120000
}
同时存入 ui_messages.json 的消息:
json
[
{
"ts": 1768187120000,
"type": "say",
"say": "user_feedback",
"text": "记忆与现实 - 主人公对自己记忆的真实性产生怀疑",
"conversationHistoryIndex": 4
}
]
第 4 轮:AI 继续询问并开始设计
用户回答"城市环境"后,AI 继续询问背景细节,然后开始创建 todo list 和设计电影方案。
AI 流式响应(询问背景):
非常好!现代都市的背景能营造出孤立和疏离感。让我再确认一个细节:
<ask_followup_question>
<question>你希望故事发生在什么样的城市环境?</question>
<follow_up>
<option>城市环境 - 现代大都市,但主人公感到孤立和疏离</option>
<option>小镇环境 - 封闭的小镇社区</option>
<option>郊区环境 - 城市边缘的住宅区</option>
</follow_up>
</ask_followup_question>
用户选择"城市环境"后,AI 开始创建待办事项并设计电影:
AI 流式响应(创建 todo 和设计):
完美!我现在开始为你设计这部心理悬疑电影。让我创建一个详细的设计方案。
<update_todo_list>
<todos>
[
{"id": "1", "content": "设计主人公角色背景", "status": "in_progress"},
{"id": "2", "content": "构建核心悬疑设定", "status": "pending"},
{"id": "3", "content": "设计关键转折点", "status": "pending"},
{"id": "4", "content": "设计结局真相", "status": "pending"},
{"id": "5", "content": "设计配角关系网", "status": "pending"},
{"id": "6", "content": "设计视觉风格", "status": "pending"},
{"id": "7", "content": "设计叙事结构", "status": "pending"},
{"id": "8", "content": "设计关键场景", "status": "pending"},
{"id": "9", "content": "设计悬念布局", "status": "pending"},
{"id": "10", "content": "设计情感曲线", "status": "pending"},
{"id": "11", "content": "设计主题表达", "status": "pending"},
{"id": "12", "content": "设计开场设定", "status": "pending"},
{"id": "13", "content": "设计高潮冲突", "status": "pending"},
{"id": "14", "content": "整合完整方案", "status": "pending"}
]
</todos>
</update_todo_list>
<create_file>
<path>心理悬疑电影设计方案.md</path>
<content>
# 心理悬疑电影设计方案
## 一、基本信息
- **类型**:心理悬疑
- **核心主题**:记忆与现实的界限
- **背景设定**:现代都市
## 二、主人公设定
**姓名**:林墨
**年龄**:35岁
**职业**:建筑师
**性格特点**:理性、追求完美、对细节敏感
## 三、核心悬疑设定
林墨在一场车祸后失去部分记忆,醒来后发现自己的生活似乎"太完美"了...
</content>
</create_file>
流式显示编辑过程:
在工具调用 partial: true 状态时,Kilo 会实时显示编辑内容:
-
显示 todo list 创建
-
打开文件编辑 diff 视图
-
逐步显示新内容:
typescript// 第 1 次更新 "# 心理悬疑电影设计方案\n\n## 一、基本信息" // 第 2 次更新 "# 心理悬疑电影设计方案\n\n## 一、基本信息\n- **类型**:心理悬疑\n- **核心主题**:记忆与现实的界限" // ... 持续更新直到完成
工具调用完成后的审批:
显示完整的 diff 预览:
diff
+ 心理悬疑电影设计方案.md (新文件)
+ # 心理悬疑电影设计方案
+
+ ## 一、基本信息
+ - **类型**:心理悬疑
+ - **核心主题**:记忆与现实的界限
+ - **背景设定**:现代都市
+
+ ## 二、主人公设定
+ **姓名**:林墨
+ **年龄**:35岁
+ **职业**:建筑师
+ ...
用户点击"允许"后,工具执行结果:
typescript
{
role: "user",
content: [
{
type: "tool_result",
tool_use_id: "toolu_xxx_create_file",
content: "Successfully created 心理悬疑电影设计方案.md"
}
]
}
第 5 轮:AI 调用完成工具
AI 响应(调用 attempt_completion 工具):
我已经为你完成了这部心理悬疑电影的完整设计方案!
<attempt_completion>
<result>
我已经为你完成了这部心理悬疑电影的完整设计方案!
## 核心设定
**主人公**:林墨,35岁建筑师
**核心悬疑**:车祸后失忆,逐渐发现自己生活在一个"完美"但虚假的世界中
**终极真相**:他是车祸的肇事者,医院为了治疗他的心理创伤,构建了一个治疗性的虚拟环境
## 主要特色
1. **记忆与现实的模糊界限**:通过建筑细节的不一致性暗示真相
2. **层层递进的悬念**:从日常异常到重大发现
3. **深刻的主题探讨**:罪责、救赎、自我认知
设计方案已保存到 `心理悬疑电影设计方案.md`,包含完整的角色设定、情节结构、关键场景等内容。
</result>
</attempt_completion>
解析的助手消息(存入 api_conversation_history.json):
json
{
"role": "assistant",
"content": [
{
"type": "text",
"text": "我已经为你完成了这部心理悬疑电影的完整设计方案!"
},
{
"type": "tool_use",
"id": "toolu_vrtx_01JVU2xVfZBRNhbhtBbZjGTY",
"name": "attempt_completion",
"input": {
"result": "我已经为你完成了这部心理悬疑电影的完整设计方案!\n\n## 核心设定\n\n**主人公**:林墨,35岁建筑师\n**核心悬疑**:车祸后失忆,逐渐发现自己生活在一个\"完美\"但虚假的世界中\n**终极真相**:他是车祸的肇事者,医院为了治疗他的心理创伤,构建了一个治疗性的虚拟环境\n\n## 主要特色\n\n1. **记忆与现实的模糊界限**:通过建筑细节的不一致性暗示真相\n2. **层层递进的悬念**:从日常异常到重大发现\n3. **深刻的主题探讨**:罪责、救赎、自我认知\n\n设计方案已保存到 `心理悬疑电影设计方案.md`,包含完整的角色设定、情节结构、关键场景等内容。"
}
}
],
"ts": 1768187250000
}
同时存入 ui_messages.json 的消息:
json
[
{
"ts": 1768187250000,
"type": "say",
"say": "text",
"text": "我已经为你完成了这部心理悬疑电影的完整设计方案!",
"partial": false
},
{
"ts": 1768187250100,
"type": "ask",
"ask": "completion_result",
"text": "{\"result\":\"我已经为你完成了这部心理悬疑电影的完整设计方案!\\n\\n## 核心设定\\n\\n**主人公**:林墨,35岁建筑师\\n**核心悬疑**:车祸后失忆,逐渐发现自己生活在一个\\\"完美\\\"但虚假的世界中\\n**终极真相**:他是车祸的肇事者,医院为了治疗他的心理创伤,构建了一个治疗性的虚拟环境\\n\\n## 主要特色\\n\\n1. **记忆与现实的模糊界限**:通过建筑细节的不一致性暗示真相\\n2. **层层递进的悬念**:从日常异常到重大发现\\n3. **深刻的主题探讨**:罪责、救赎、自我认知\\n\\n设计方案已保存到 `心理悬疑电影设计方案.md`,包含完整的角色设定、情节结构、关键场景等内容。\"}",
"isAnswered": false
}
]
工具执行流程:
- 显示完成结果弹窗:展示任务完成的总结
- 用户可以选择 :
- 点击"新任务":开始新的对话
- 继续输入:提供反馈或要求调整
- 任务状态变更 :从
Running→Idle
四、更多工具调用示例
4.1 ask_followup_question 工具的多次使用
在悬疑电影设计的场景中,AI 连续使用了 3 次 ask_followup_question 工具来收集用户需求:
- 第一次:询问电影类型(心理悬疑/犯罪悬疑/惊悚悬疑)
- 第二次:询问核心主题(记忆与现实/身份认同/信任危机)
- 第三次:询问背景环境(城市/小镇/郊区)
这种渐进式的信息收集方式,让 AI 能够:
- 逐步明确用户需求
- 避免一次性询问过多问题
- 根据前一个答案调整后续问题
4.2 execute_command 工具示例
场景: 用户请求安装依赖
AI 响应:
让我安装 lodash 依赖包。
<execute_command>
<command>npm install lodash</command>
</execute_command>
解析结果(存入 api_conversation_history.json):
json
{
"role": "assistant",
"content": [
{
"type": "text",
"text": "让我安装 lodash 依赖包。"
},
{
"type": "tool_use",
"id": "toolu_01D30t03tw03ot040168ot2",
"name": "execute_command",
"input": {
"command": "npm install lodash"
}
}
],
"ts": 1736654500000
}
同时存入 ui_messages.json 的消息:
json
[
{
"ts": 1736654500000,
"type": "say",
"say": "text",
"text": "让我安装 lodash 依赖包。",
"partial": false
},
{
"ts": 1736654500100,
"type": "ask",
"ask": "tool",
"text": "{\"tool\":\"executeCommand\",\"command\":\"npm install lodash\",\"cwd\":\"/Users/user/project\"}"
}
]
工具执行过程:
-
显示审批弹窗:
json{ "tool": "executeCommand", "command": "npm install lodash", "cwd": "/Users/user/project" } -
用户点击"允许"
-
在终端执行命令,实时输出:
npm WARN deprecated ... added 1 package in 2s -
命令完成后返回结果(存入 api_conversation_history.json):
json{ "role": "user", "content": [ { "type": "text", "text": "[execute_command for 'npm install lodash'] Result:" }, { "type": "text", "text": "Command executed in terminal /Users/user/project. Exit code: 0\nOutput:\nnpm WARN deprecated ...\n\nadded 1 package in 2s" } ], "ts": 1736654502000 }同时存入 ui_messages.json 的消息:
json[ { "ts": 1736654502000, "type": "say", "say": "text", "text": "[execute_command for 'npm install lodash'] Result:", "conversationHistoryIndex": 10 }, { "ts": 1736654502100, "type": "say", "say": "command_output", "text": "Command executed in terminal /Users/user/project. Exit code: 0\nOutput:\nnpm WARN deprecated ...\n\nadded 1 package in 2s" } ]
4.3 attempt_completion 工具示例
场景: AI 完成任务后向用户汇报结果
attempt_completion 是 Kilo 中使用频率最高的工具之一,用于 AI 完成任务时:
- 总结完成的工作
- 展示关键成果
- 询问用户是否需要进一步调整
AI 响应(完成 Button 组件创建后):
我已经成功创建了 Button 组件!
<attempt_completion>
<result>
我已经成功创建了 Button 组件!这个组件支持:
1. **三种样式变体:**
- `primary`:蓝色主按钮
- `secondary`:灰色次要按钮
- `outline`:边框按钮
2. **三种尺寸:**
- `sm`:小尺寸
- `md`:中等尺寸(默认)
- `lg`:大尺寸
3. **完全的类型安全:** 继承了所有原生 button 的属性
使用示例:
```tsx
<Button variant="primary" size="lg">
点击我
</Button>
组件文件已创建在 `src/components/Button.tsx`。
</result>
<command>npm run dev</command>
</attempt_completion>
解析结果(存入 api_conversation_history.json):
json
{
"role": "assistant",
"content": [
{
"type": "text",
"text": "我已经成功创建了 Button 组件!"
},
{
"type": "tool_use",
"id": "toolu_01F52v05vx05qv062390qv4",
"name": "attempt_completion",
"input": {
"result": "我已经成功创建了 Button 组件!这个组件支持:\n\n1. **三种样式变体:**\n - `primary`:蓝色主按钮\n - `secondary`:灰色次要按钮\n - `outline`:边框按钮\n\n2. **三种尺寸:**\n - `sm`:小尺寸\n - `md`:中等尺寸(默认)\n - `lg`:大尺寸\n\n3. **完全的类型安全:** 继承了所有原生 button 的属性\n\n使用示例:\n```tsx\n<Button variant=\"primary\" size=\"lg\">\n 点击我\n</Button>\n```\n\n组件文件已创建在 `src/components/Button.tsx`。",
"command": "npm run dev"
}
}
],
"ts": 1736654800000
}
同时存入 ui_messages.json 的消息:
json
[
{
"ts": 1736654800000,
"type": "say",
"say": "text",
"text": "我已经成功创建了 Button 组件!",
"partial": false
},
{
"ts": 1736654800100,
"type": "ask",
"ask": "completion_result",
"text": "{\"result\":\"我已经成功创建了 Button 组件!这个组件支持:\\n\\n1. **三种样式变体:**\\n - `primary`:蓝色主按钮\\n - `secondary`:灰色次要按钮\\n - `outline`:边框按钮\\n\\n2. **三种尺寸:**\\n - `sm`:小尺寸\\n - `md`:中等尺寸(默认)\\n - `lg`:大尺寸\\n\\n3. **完全的类型安全:** 继承了所有原生 button 的属性\\n\\n使用示例:\\n```tsx\\n<Button variant=\\\"primary\\\" size=\\\"lg\\\">\\n 点击我\\n</Button>\\n```\\n\\n组件文件已创建在 `src/components/Button.tsx`。\",\"command\":\"npm run dev\"}"
}
]
attempt_completion 的关键特点:
-
必填参数:
result:任务完成的详细总结(支持 Markdown 格式)
-
可选参数:
command:建议用户执行的命令(如启动开发服务器、运行测试等)
-
使用时机:
- 完成用户请求的所有任务
- 所有文件编辑已完成
- 所有测试已通过(如果需要)
- 没有待处理的 linter 错误
-
最佳实践:
- 总结要清晰、结构化,使用 Markdown 格式
- 突出关键成果和重要变更
- 提供使用示例或下一步建议
- 如果有建议的命令,确保命令是可执行的
五、关键技术点总结
5.1 消息格式转换
Kilo 支持多个 LLM Provider,需要在不同格式之间转换:
Anthropic 原生格式:
typescript
{
role: "assistant",
content: [
{ type: "text", text: "..." },
{ type: "tool_use", id: "...", name: "...", input: {...} }
]
}
OpenAI 格式:
typescript
{
role: "assistant",
content: "...",
tool_calls: [
{
id: "...",
type: "function",
function: {
name: "...",
arguments: "{...}"
}
}
]
}
转换逻辑: 参见 src/api/transform/openai-format.ts
5.2 工具重复检测
目的: 防止 AI 陷入死循环,重复调用相同的工具
检测逻辑:
typescript
class ToolRepetitionDetector {
check(toolUse: ToolUse): { allowExecution: boolean; reason?: string } {
// 检查最近 5 次工具调用
const recentCalls = this.history.slice(-5)
// 如果连续 3 次调用相同工具且参数相同
const repetitionCount = recentCalls.filter(call =>
call.name === toolUse.name &&
JSON.stringify(call.input) === JSON.stringify(toolUse.input)
).length
if (repetitionCount >= 3) {
return {
allowExecution: false,
reason: "检测到重复的工具调用,已自动跳过"
}
}
return { allowExecution: true }
}
}
5.3 自动批准机制
目的: 减少用户干预,提升效率
规则:
- 基于请求次数: 前 N 次工具调用自动批准
- 基于成本: 累计成本低于阈值时自动批准
- 基于工具类型: 某些安全工具(如 read_file)自动批准
实现: 参见 src/core/task/AutoApprovalHandler.ts
六、完整的 API 对话历史
经过上述多轮交互后,apiConversationHistory 的完整内容如下:
typescript
[
// 第 1 轮:用户请求
{
role: "user",
content: [
{
type: "text",
text: "帮我设计一部悬疑电影"
}
],
ts: 1768187000000
},
// 第 2 轮:AI 询问电影类型
{
role: "assistant",
content: [
{
type: "text",
text: "好的!我很乐意帮你设计一部悬疑电影。首先让我了解一些关键信息:"
},
{
type: "tool_use",
id: "toolu_vrtx_01JVU2miNYbiFZJLeFcVAzi7",
name: "ask_followup_question",
input: {
question: "你希望这部悬疑电影属于哪种具体类型?",
follow_up: [
{text: "心理悬疑 - 专注于角色的内心世界和心理状态"},
{text: "犯罪悬疑 - 围绕犯罪调查和侦破过程"},
{text: "惊悚悬疑 - 强调紧张刺激的氛围"}
]
}
}
],
ts: 1768187030000
},
// 用户选择"心理悬疑"
{
role: "user",
content: [
{
type: "tool_result",
tool_use_id: "toolu_vrtx_01JVU2miNYbiFZJLeFcVAzi7",
content: "心理悬疑 - 专注于角色的内心世界和心理状态"
}
],
ts: 1768187060000
},
// 第 3 轮:AI 询问核心主题
{
role: "assistant",
content: [
{
type: "text",
text: "很好的选择!心理悬疑能够深入探索人物的内心世界。接下来让我了解更多细节:"
},
{
type: "tool_use",
id: "toolu_vrtx_01JVU2pQbWxNLdXYdqxZfCPV",
name: "ask_followup_question",
input: {
question: "你希望电影探讨什么样的核心主题?",
follow_up: [
{text: "记忆与现实 - 主人公对自己记忆的真实性产生怀疑"},
{text: "身份认同 - 主人公不确定自己是谁"},
{text: "信任危机 - 主人公无法相信周围的人"}
]
}
}
],
ts: 1768187090000
},
// 用户选择"记忆与现实"
{
role: "user",
content: [
{
type: "tool_result",
tool_use_id: "toolu_vrtx_01JVU2pQbWxNLdXYdqxZfCPV",
content: "记忆与现实 - 主人公对自己记忆的真实性产生怀疑"
}
],
ts: 1768187120000
},
// 第 4 轮:AI 询问背景并开始设计
{
role: "assistant",
content: [
{
type: "text",
text: "非常好!现代都市的背景能营造出孤立和疏离感。让我再确认一个细节:"
},
{
type: "tool_use",
id: "toolu_vrtx_01JVU2sRcXyOLeYZeqyZgDQW",
name: "ask_followup_question",
input: {
question: "你希望故事发生在什么样的城市环境?",
follow_up: [
{text: "城市环境 - 现代大都市,但主人公感到孤立和疏离"},
{text: "小镇环境 - 封闭的小镇社区"},
{text: "郊区环境 - 城市边缘的住宅区"}
]
}
}
],
ts: 1768187150000
},
// 用户选择"城市环境"后,AI 创建 todo 和文件
{
role: "user",
content: [
{
type: "tool_result",
tool_use_id: "toolu_vrtx_01JVU2sRcXyOLeYZeqyZgDQW",
content: "城市环境 - 现代大都市,但主人公感到孤立和疏离"
}
],
ts: 1768187180000
},
// 第 5 轮:AI 创建设计方案
{
role: "assistant",
content: [
{
type: "text",
text: "完美!我现在开始为你设计这部心理悬疑电影。让我创建一个详细的设计方案。"
},
{
type: "tool_use",
id: "toolu_vrtx_01JVU2vTdYzPMfZfrzyZhERX",
name: "update_todo_list",
input: {
todos: [
{id: "1", content: "设计主人公角色背景", status: "in_progress"},
{id: "2", content: "构建核心悬疑设定", status: "pending"},
// ... 其他 12 个待办事项
]
}
},
{
type: "tool_use",
id: "toolu_vrtx_01JVU2wUeZAQNgagsAaZiFS",
name: "create_file",
input: {
path: "心理悬疑电影设计方案.md",
content: "# 心理悬疑电影设计方案\n\n## 一、基本信息\n- **类型**:心理悬疑\n..."
}
}
],
ts: 1768187210000
},
// 工具执行结果
{
role: "user",
content: [
{
type: "tool_result",
tool_use_id: "toolu_vrtx_01JVU2wUeZAQNgagsAaZiFS",
content: "Successfully created 心理悬疑电影设计方案.md"
}
],
ts: 1768187240000
},
// 第 6 轮:AI 完成任务
{
role: "assistant",
content: [
{
type: "text",
text: "我已经为你完成了这部心理悬疑电影的完整设计方案!\n\n## 核心设定\n\n**主人公**:林墨,35岁建筑师\n**核心悬疑**:车祸后失忆,逐渐发现自己生活在一个\"完美\"但虚假的世界中\n**终极真相**:他是车祸的肇事者,医院为了治疗他的心理创伤,构建了一个治疗性的虚拟环境\n\n## 主要特色\n\n1. **记忆与现实的模糊界限**:通过建筑细节的不一致性暗示真相\n2. **层层递进的悬念**:从日常异常到重大发现\n3. **深刻的主题探讨**:罪责、救赎、自我认知\n\n设计方案已保存到 `心理悬疑电影设计方案.md`,包含完整的角色设定、情节结构、关键场景等内容。\n\n还需要我补充或调整什么吗?"
}
],
ts: 1768187250000
}
]
七、总结
本文档通过具体的示例展示了 Kilo 项目中消息交互的完整过程,包括:
- 消息格式: 基于 Anthropic 的标准格式,支持文本、图片、工具调用和工具结果
- 流式处理: 通过 AssistantMessageParser 实现增量解析,实时显示和执行
- 工具执行: 从解析到执行到结果返回的完整闭环
- 错误处理: 工具失败、用户拒绝等场景的处理
- 保护机制: 重复检测、自动批准等智能机制