用户在空目录中运行 Closer Code 时,如果要求创建多文件项目(例如:"写一个50000字的玄幻故事,分为10个章节"),AI 会因为父目录不存在而失败,导致整个工作流中断。
核心问题:
- ❌ AI 缺乏错误处理和自我修复能力
- ❌ 遇到错误就放弃,不会尝试修复
- ❌ 没有重试机制
- ❌ 工具错误信息不够详细
不是:在工具层自动处理一切(绕过 AI 的思考)
而是:
- ✅ 工具返回详细的错误信息和修复建议
- ✅ AI 分析错误并自主决定解决方案
- ✅ AI 执行修复操作
- ✅ AI 重试原操作
- ✅ 系统支持多次重试(最多 3 次)
改进前(自动创建目录 - 错误方案):
// ❌ 这会绕过 AI 的思考
await fs.mkdir(parentDir, { recursive: true });
await fs.writeFile(fullPath, dataToWrite);改进后(返回详细错误 - 正确方案):
export const writeFileTool = betaZodTool({
name: 'writeFile',
description: 'Write content to a file. Returns detailed error messages if the operation fails, allowing you to analyze and fix the issue.',
run: async (input) => {
try {
await fs.writeFile(fullPath, dataToWrite, encoding);
return { success: true, path: fullPath, size: dataToWrite.length };
} catch (error) {
// 🔥 关键:返回详细的错误信息和修复建议
let errorDetail = {
success: false,
error: error.code,
message: error.message,
path: fullPath
};
// 针对常见错误提供修复建议
if (error.code === 'ENOENT') {
const parentDir = path.dirname(fullPath);
errorDetail.suggestion = `Parent directory does not exist. Create it first using: bash tool with "mkdir -p ${parentDir}"`;
errorDetail.hint = 'The parent directory needs to be created before writing the file.';
} else if (error.code === 'EACCES') {
errorDetail.suggestion = 'Permission denied. Check if you have write permissions.';
errorDetail.hint = 'Try writing to a different location or check file permissions.';
}
return errorDetail;
}
}
});关键点:
- ✅ 不自动创建目录,让 AI 自己处理
- ✅ 返回详细的错误信息(error code, message)
- ✅ 提供具体的修复建议(suggestion)
- ✅ 提供额外的提示信息(hint)
添加完整的错误处理和自我修复指导:
this.systemPrompt = `You are Closer, an AI programming assistant...
## Error Handling and Self-Correction (CRITICAL) 🆕
**When a tool returns an error, you MUST analyze and attempt to fix it.**
### Error Analysis Process
1. **Read the error message carefully** - Look for error codes like ENOENT, EACCES, etc.
2. **Identify the root cause** - Understand why the operation failed
3. **Devise a solution** - Determine what needs to be fixed
4. **Execute the fix** - Use appropriate tools to resolve the issue
5. **Retry the original operation** - Attempt the failed operation again
### Common Error Patterns
#### Directory Not Found (ENOENT)
**Error**: "Parent directory does not exist"
**Solution**: Create the directory first
\`\`\`
// Attempt 1 (fails):
You: Call writeFile with "src/components/Button.tsx"
Tool: {"success": false, "error": "ENOENT",
"suggestion": "mkdir -p src/components/"}
// Your analysis:
- Error: ENOENT means directory doesn't exist
- Root cause: src/components/ directory is missing
- Solution: Create the directory first
// Attempt 2 (fix):
You: Call bash with "mkdir -p src/components/"
Tool: {"success": true}
// Attempt 3 (retry):
You: Call writeFile with "src/components/Button.tsx"
Tool: {"success": true}
✅ Success through self-correction!
\`\`\`
### Retry Strategy
- **Maximum retries**: 3 attempts per operation
- **Wait time**: No delay needed for tool operations
- **Different approach**: If the same fix fails twice, try an alternative solution
`;关键点:
- ✅ 明确的错误处理流程
- ✅ 常见错误模式的示例
- ✅ 完整的自我修复演示
- ✅ 重试策略指导
测试错误处理和自我修复流程:
$ node test/test-auto-mkdir.js
🧪 单元测试:writeFile 错误处理和自我修复
测试1: 尝试写入不存在的目录
工具响应:
{
"success": false,
"error": "ENOENT",
"suggestion": "Parent directory does not exist. Create it first using: bash tool with \"mkdir -p ...\"",
"hint": "The parent directory needs to be created before writing the file."
}
✅ 正确返回 ENOENT 错误
✅ 包含修复建议: Yes
✅ 包含提示信息: Yes
测试2: 创建目录(模拟 AI 自我修复)
✅ 目录创建成功
测试3: 重试写入文件
{
"success": true,
"path": ".../chapters/chapter-01.txt",
"size": 16
}
✅ 重试成功!
✅ 所有测试通过!测试覆盖:
- ✅ 工具正确返回 ENOENT 错误
- ✅ 错误响应包含详细的修复建议
- ✅ AI 可以根据错误信息进行自我修复
- ✅ 修复后重试操作成功
用户请求:
写一个50000字的玄幻故事,分为10个章节,保存在
chapters/chapter-01.txt 到 chapters/chapter-10.txt
AI 的执行过程:
📝 第1章 - 尝试1(失败):
┌─────────────────────────────────────┐
│ AI: 调用 writeFile("chapters/chapter-01.txt", content) │
│ Tool: {"success": false, │
│ "error": "ENOENT", │
│ "suggestion": "mkdir -p chapters/"} │
└─────────────────────────────────────┘
🤔 AI 分析:
- 错误代码: ENOENT
- 根本原因: chapters/ 目录不存在
- 解决方案: 先创建目录
🔧 AI 执行修复:
┌─────────────────────────────────────┐
│ AI: 调用 bash("mkdir -p chapters/") │
│ Tool: {"success": true} │
└─────────────────────────────────────┘
📝 第1章 - 尝试2(成功):
┌─────────────────────────────────────┐
│ AI: 调用 writeFile("chapters/chapter-01.txt", content) │
│ Tool: {"success": true, │
│ "path": ".../chapters/chapter-01.txt"} │
└─────────────────────────────────────┘
✅ 成功!AI 学到了经验,后续章节直接创建目录
{
"success": false,
"error": "ENOENT", // 错误代码
"message": "...", // 详细错误信息
"path": "/full/path", // 操作路径
"suggestion": "mkdir -p ...", // 修复建议
"hint": "The parent directory..." // 额外提示
}| 错误代码 | 描述 | 修复建议 |
|---|---|---|
| ENOENT | 文件或目录不存在 | 创建目录或检查路径 |
| EACCES | 权限不足 | 检查权限或换位置 |
| ENOSPC | 磁盘空间不足 | 清理磁盘空间 |
| EISDIR | 路径是目录 | 使用正确的文件路径 |
// ❌ 工具层自动处理
await fs.mkdir(parentDir, { recursive: true });
await fs.writeFile(fullPath, content);问题:
- ❌ 绕过了 AI 的思考过程
- ❌ AI 没有学习到错误处理
- ❌ 不是真正的"智能助理"
- ❌ 用户看不到 AI 的解决问题的能力
// ✅ 返回详细错误,让 AI 自己处理
try {
await fs.writeFile(fullPath, content);
} catch (error) {
return {
success: false,
error: error.code,
suggestion: "mkdir -p ..."
};
}优势:
- ✅ AI 展示错误分析和解决能力
- ✅ AI 从错误中学习和成长
- ✅ 真正的"智能助理"体验
- ✅ 用户可以看到 AI 的思考过程
-
src/tools.js
- 移除自动创建目录的逻辑
- 添加详细的错误响应
- 针对常见错误提供修复建议
-
src/conversation.js
- 添加"Error Handling and Self-Correction"部分
- 提供完整的错误处理流程
- 包含常见错误模式和示例
-
test/test-auto-mkdir.js
- 更新为测试错误处理和自我修复
- 验证错误响应格式
- 模拟 AI 的修复和重试过程
- AUTO_MKDIR_IMPROVEMENT.md(本文档)
- 完整的实现总结
- 设计理念和对比分析
- 测试验证和使用示例
之前:
- ❌ 遇到错误就放弃
- ❌ 不会尝试修复
- ❌ 没有重试机制
现在:
- ✅ 分析错误原因
- ✅ 自主决定解决方案
- ✅ 执行修复操作
- ✅ 重试直到成功(最多3次)
之前:
- ❌ 工作流容易中断
- ❌ 需要用户手动修复
- ❌ AI 显得"不够智能"
现在:
- ✅ AI 自动处理常见错误
- ✅ 工作流更流畅
- ✅ 展示真正的智能
可能的进一步优化:
- 记录错误模式,提前预防
- 学习用户的修复偏好
- 支持更复杂的重试策略
- 添加错误统计和分析
这个改进让 AI 具备了真正的错误处理和自我修复能力,而不是简单地绕过问题。通过返回详细的错误信息和修复建议,并在系统提示词中提供完整的指导,AI 可以像人类开发者一样:分析问题、解决问题、从错误中学习。
关键成果:
- ✅ AI 具备错误分析和自我修复能力
- ✅ 提供详细的错误信息和修复建议
- ✅ 支持最多 3 次重试
- ✅ 测试覆盖完整
- ✅ 真正的"智能助理"体验
测试状态:
- ✅ 单元测试通过
- ✅ 错误响应格式正确
- ✅ 修复建议准确
- ✅ 自我修复流程完整