開發日誌 #3 - 技術深度解析
技術亮點回顧
在前兩篇日誌中,我們看到了兩個工具的誕生和整合實施。現在,讓我們深入探討整合過程中的技術亮點和設計巧思。
亮點 1:專案探索的迭代式對話
問題背景
傳統的 AI 代碼生成工具通常只給 AI 一個需求描述,然後期待它生成正確的代碼。這導致:
- AI 不知道專案現有的類別和方法
- 生成的代碼風格不一致
- 經常使用不存在的依賴
- 需要大量人工修正
解決方案:Tool Use API
使用 Anthropic Tool Use API,讓 Claude 像人類開發者一樣迭代式探索專案。
實際案例
任務:優化 Unity 主選單載入速度
AI 探索過程(實際日誌):
[第 1 輪] Claude: "讓我先了解專案的整體結構"
工具調用: get_project_structure(max_depth=3)
返回:
Assets/
Scripts/
UI/
Game/
Managers/
Scenes/
Resources/
[第 2 輪] Claude: "我需要找到主選單相關的代碼"
工具調用: search_code(pattern="MainMenu", file_pattern="*.cs")
返回:
- Assets/Scripts/UI/MainMenuController.cs
- Assets/Scripts/UI/MainMenuManager.cs
- Assets/Scripts/Managers/MenuStateManager.cs
[第 3 輪] Claude: "讓我看看 MainMenuController 的實現"
工具調用: read_file(file_path="Assets/Scripts/UI/MainMenuController.cs")
返回: [完整代碼 - 約 200 行]
[第 4 輪] Claude: "我注意到使用了 Resources.Load,讓我看看 Resources 目錄"
工具調用: list_files(directory="Assets/Resources", pattern="*.prefab")
返回:
- MainMenuPanel.prefab
- SettingsPanel.prefab
- ...
[第 5 輪] Claude: "讓我檢查 MenuStateManager 如何管理狀態"
工具調用: read_file(file_path="Assets/Scripts/Managers/MenuStateManager.cs")
返回: [完整代碼]
[第 6 輪] Claude: "我需要了解是否已使用 Addressables"
工具調用: search_code(pattern="Addressables", file_pattern="*.cs")
返回: [無結果]
[第 7 輪] Claude: "讓我檢查專案設置"
工具調用: read_file(file_path="Packages/manifest.json")
返回: [依賴列表]
... 共 15 輪對話
最終生成的設計文檔(節選):
## 3. 現有架構分析
### 3.1 主選單載入流程
當前實現:
1. `MainMenuController.cs:45` - Start() 方法使用 `Resources.Load()` 同步載入
2. `MainMenuController.cs:67` - LoadPanels() 串行載入所有 UI Panel
3. 未使用 Unity Addressables 系統
### 3.2 性能瓶頸
- ❌ `Resources.Load()` 同步載入阻塞主線程
- ❌ 所有 Panel 在啟動時載入,包含非必要的 SettingsPanel
- ❌ 未實作資源預載入策略
## 4. 技術設計
### 4.1 引入 Addressables
**修改文件**:
- `Packages/manifest.json` - 添加 Addressables 依賴
- `Assets/Scripts/UI/MainMenuController.cs` - 改用異步載入
**代碼示例**:
\`\`\`csharp
// 修改前 (MainMenuController.cs:45)
void Start()
{
mainPanel = Resources.Load<GameObject>("MainMenuPanel");
// ...
}
// 修改後
async void Start()
{
mainPanel = await Addressables.LoadAssetAsync<GameObject>("MainMenuPanel").Task;
// ...
}
\`\`\`關鍵價值:
- ✅ AI 真正理解了專案結構
- ✅ 設計方案基於實際代碼
- ✅ 具體到文件路徑和行號
- ✅ 提供可直接使用的代碼示例
技術實現
Tool 定義 (system_designer/designer.py):
TOOLS = [
{
"name": "get_project_structure",
"description": "獲取專案的目錄結構,幫助理解專案組織",
"input_schema": {
"type": "object",
"properties": {
"max_depth": {
"type": "integer",
"description": "目錄深度限制(預設 3)"
}
}
}
},
{
"name": "search_code",
"description": "在專案中搜尋包含特定模式的代碼",
"input_schema": {
"type": "object",
"properties": {
"pattern": {
"type": "string",
"description": "搜尋模式(支援正則表達式)"
},
"file_pattern": {
"type": "string",
"description": "文件模式(如 '*.cs', '*.py')"
}
},
"required": ["pattern"]
}
},
# ... 其他工具
]多輪對話循環:
async def design(self, requirement_file, project_root, ...):
messages = []
# 初始 prompt
messages.append({
"role": "user",
"content": f"請基於需求文件設計系統...\n專案路徑: {project_root}"
})
for iteration in range(MAX_ITERATIONS): # 最多 30 輪
response = await self.client.messages.create(
model=self.model,
messages=messages,
tools=TOOLS
)
# 檢查停止原因
if response.stop_reason == "end_turn":
# AI 完成探索
final_content = response.content[0].text
break
if response.stop_reason == "tool_use":
# AI 請求使用工具
for block in response.content:
if block.type == "tool_use":
# 執行工具
tool_result = self._execute_tool(
block.name,
block.input,
project_root
)
# 添加工具結果到對話
messages.append({
"role": "assistant",
"content": response.content
})
messages.append({
"role": "user",
"content": [{
"type": "tool_result",
"tool_use_id": block.id,
"content": tool_result
}]
})
return final_content亮點 2:優雅的降級設計
問題背景
在企業環境中,系統穩定性至關重要。automation_tool 的整合不能:
- 導致 jira_poller 無法啟動
- 在 API 失敗時中斷工作流
- 讓錯誤難以診斷
解決方案:三層降級機制
def _ai_generate_requirements(self, task, feedback):
"""三層降級策略"""
# 第一層:automation_tool (最佳)
if self.requirement_analyzer:
try:
return self._ai_generate_requirements_with_automation_tool(task, feedback)
except Exception as e:
self.logger.error(f"automation_tool 失敗: {e}")
# 繼續到下一層
# 第二層:傳統 AI Provider
if self.ai_provider:
try:
return self._ai_generate_requirements_fallback(task, feedback)
except Exception as e:
self.logger.error(f"AI Provider 失敗: {e}")
# 繼續到下一層
# 第三層:占位符(確保流程不中斷)
return self._generate_placeholder_requirements(task, feedback)降級場景測試
場景 1:automation_tool 路徑錯誤
[啟動] ⚠️ 無法引入 automation_tool 模組: No module named 'requirement_analyzer'
[啟動] ⚠️ automation_tool 模組不可用,將使用舊版 AI Provider
[啟動] ✓ AI Provider 已初始化: OllamaProvider
[需求階段] 🤖 正在使用 OllamaProvider 分析需求...
[需求階段] ✓ AI 需求分析完成 (512 字)
場景 2:API Key 未設定
[啟動] ✗ automation_tool 模組初始化失敗: Anthropic API Key 未設定
[啟動] ⚠️ 將使用舊版 AI Provider
[需求階段] 🤖 正在使用 OllamaProvider 分析需求...
場景 3:API 速率限制
[設計階段] 🚀 使用 automation_tool 的 SystemDesigner 生成技術設計...
[設計階段] ✗ automation_tool 技術設計失敗: Error code: 429 - rate_limit_error
[設計階段] 使用占位符設計文檔
[設計階段] ⚠️ 設計文檔包含錯誤信息,請稍後重試
場景 4:全部正常
[啟動] ✓ automation_tool 模組已初始化 (RequirementAnalyzer + SystemDesigner)
[需求階段] 🚀 使用 automation_tool 的 RequirementAnalyzer 分析需求...
[需求階段] ✓ automation_tool 需求分析完成 (2543 字)
[設計階段] 🚀 使用 automation_tool 的 SystemDesigner 生成技術設計...
[設計階段] ✓ automation_tool 技術設計完成 (4821 字)
[設計階段] 工具調用次數: 15
設計原則
- 失敗不中斷:每層降級都能生成輸出
- 清晰日誌:用戶知道發生了什麼
- 可診斷:錯誤信息包含足夠上下文
- 可恢復:修復問題後自動使用最佳方案
亮點 3:異步與同步的優雅橋接
問題背景
- jira_poller 是同步代碼(使用 threading, time.sleep)
- automation_tool 使用異步 API(Anthropic SDK)
- Python 不允許在運行中的事件循環創建新事件循環
錯誤示例:
# 在同步函數中
result = asyncio.run(async_function())
# RuntimeError: asyncio.run() cannot be called from a running event loop解決方案
import asyncio
def _call_async_in_sync(self, async_function, *args, **kwargs):
"""在同步環境安全地調用異步函數"""
try:
# 嘗試獲取當前事件循環
loop = asyncio.get_event_loop()
if loop.is_running():
# 已有運行中的事件循環
# 這種情況下無法使用 asyncio.run()
self.logger.warning("檢測到正在運行的事件循環,無法使用 automation_tool")
raise RuntimeError("Cannot use async in sync context")
except RuntimeError:
# 沒有事件循環,或上面拋出的異常
# 安全地創建新事件循環
result = asyncio.run(async_function(*args, **kwargs))
return result使用方式
# 需求階段
result = asyncio.run(self.requirement_analyzer.analyze(
requirement=requirement_text,
project_name=task.key
))
# 設計階段
result = asyncio.run(self.system_designer.design(
requirement_file=str(req_file),
project_root=str(project_root),
output_dir=str(output_dir),
user_id=task.key,
project_name=task.key
))為什麼這樣設計?
選項 A:將 jira_poller 改為異步
- ❌ 大規模重構
- ❌ 可能影響穩定性
- ❌ 與其他同步庫不兼容
選項 B:將 automation_tool 改為同步
- ❌ Anthropic SDK 是異步的
- ❌ 無法利用異步優勢
- ❌ 性能下降
選項 C:橋接層(我們的選擇)
- ✅ 最小化改動
- ✅ 保持兩邊原有架構
- ✅ 降級處理異常情況
亮點 4:Git Worktree 與專案探索的完美配合
設計巧思
關鍵傳參:
# jira_poller (orchestrator.py)
def _ai_generate_design_with_automation_tool(self, task, req_content, feedback):
# 獲取當前任務的 Git Worktree 路徑
project_root = self.current_worktree # 例如: workspace/unity-wt-AG-123/
# 傳入 automation_tool
result = asyncio.run(self.system_designer.design(
requirement_file=str(req_file),
project_root=str(project_root), # ← 關鍵!
output_dir=str(output_dir),
user_id=task.key,
project_name=task.key
))automation_tool 中的使用:
# automation_tool (system_designer/designer.py)
async def design(self, requirement_file, project_root, ...):
# project_root 就是 Unity Worktree 路徑
# 執行工具時使用這個路徑
def _execute_tool(self, tool_name, tool_input, project_root):
if tool_name == "get_project_structure":
return self._get_project_structure(project_root, tool_input)
elif tool_name == "read_file":
file_path = Path(project_root) / tool_input['file_path']
return file_path.read_text()
elif tool_name == "search_code":
# 在 project_root 中搜尋
results = self._search_code(project_root, tool_input)
return results為什麼這樣設計很巧妙?
-
隔離性:
- 每個 Jira 任務有獨立的 Git Worktree
- AI 探索不會影響其他任務
- 失敗可以安全刪除 Worktree
-
並發性:
- 可同時處理多個任務
- 不同 Worktree 互不干擾
-
可追溯性:
- 探索過程的文件讀取都記錄在日誌
- 可以知道 AI 看了哪些文件
-
安全性:
- AI 只能讀取 Worktree 中的文件
- 無法訪問其他專案或系統文件
實際效果
任務 AG-123 的文件結構:
workspace/
unity-wt-AG-123/ ← Git Worktree
Assets/
Scripts/
UI/
MainMenuController.cs ← AI 讀取此文件
.ai-agent/
AG-123/
req.md ← 需求文檔
design.md ← 設計文檔(AI 生成)
AI 工具調用日誌:
對話輪次: 3/30
執行工具: read_file
路徑: workspace/unity-wt-AG-123/Assets/Scripts/UI/MainMenuController.cs
成功: 是
字數: 1234
亮點 5:反饋循環的自動整合
問題背景
人工審批可能會提出修改建議:
Jira 評論:
@rejected
請補充以下內容:
1. 需要考慮移動平台的性能差異
2. 應該包含記憶體使用的優化目標
3. 需要說明向下相容性問題
挑戰:如何讓 AI 看到這些反饋?
解決方案:臨時文件
需求階段:
def _ai_generate_requirements_with_automation_tool(self, task, feedback):
# 構建包含反饋的需求文本
feedback_section = ""
if feedback:
feedback_section = f"\n\n## 人工反饋(請根據反饋重新分析)\n{feedback}\n"
requirement_text = f"""# Unity 開發任務需求
{task.description}{feedback_section}
"""
# RequirementAnalyzer 會看到反饋
result = asyncio.run(self.requirement_analyzer.analyze(
requirement=requirement_text,
project_name=task.key
))設計階段:
def _ai_generate_design_with_automation_tool(self, task, req_content, feedback):
req_file = self.file_manager.get_stage_file_path(task.key, "需求")
if feedback:
# 讀取原始需求
original_content = req_file.read_text(encoding='utf-8')
# 附加反饋
temp_content = f"""{original_content}
---
## 人工反饋(請根據此反饋調整設計)
{feedback}
"""
# 創建臨時文件
temp_req_file = req_file.parent / f"{req_file.stem}_with_feedback{req_file.suffix}"
temp_req_file.write_text(temp_content, encoding='utf-8')
req_file_to_use = temp_req_file
else:
req_file_to_use = req_file
# SystemDesigner 讀取的是包含反饋的文件
result = asyncio.run(self.system_designer.design(
requirement_file=str(req_file_to_use),
...
))
# 清理臨時文件
if feedback and temp_req_file.exists():
temp_req_file.unlink()效果
第一次生成的設計:
## 3. 性能優化策略
- 使用 Addressables 異步載入
- UI Canvas 優化人工反饋:
@rejected
請補充:
1. 移動平台的性能差異(iOS vs Android)
2. 記憶體使用目標
重新生成的設計(AI 看到了反饋):
## 3. 性能優化策略
### 3.1 Addressables 異步載入
- 桌面平台:預載入 5MB
- iOS:預載入 3MB(考慮記憶體限制)
- Android:預載入 2MB(低端設備適配)
### 3.2 記憶體使用目標
- 主選單場景:< 50MB (iOS)
- 主選單場景:< 80MB (Android)
- 峰值記憶體:< 120MB設計原則
- 自動化:不需要手動編輯文件
- 隔離:臨時文件不影響原始文件
- 清理:使用後自動刪除臨時文件
- 可追溯:Git 提交信息包含 “根據反饋修正”
亮點 6:配置管理的靈活性
多種配置方式
# 配置優先級(從高到低)
api_key = (
claude_config.get('api_key') # 1. config.yaml 中的 api_key
or os.getenv('ANTHROPIC_API_KEY') # 2. 環境變數
or automation_config.Config.ANTHROPIC_API_KEY # 3. automation_tool 的 .env
)使用場景
開發環境:
# .env 文件
export ANTHROPIC_API_KEY=sk-ant-dev-...生產環境:
# config.yaml
ai:
claude:
api_key: ${ANTHROPIC_API_KEY} # 從 CI/CD 注入測試環境:
# config.yaml
ai:
claude:
api_key: "sk-ant-test-..." # 直接寫入(僅測試)經驗總結
成功的關鍵因素
-
清晰的接口設計
- automation_tool 的輸入輸出都是標準格式
- 便於其他系統整合
-
優雅降級
- 失敗不中斷流程
- 用戶體驗平滑
-
充分的日誌
- 每個關鍵步驟都記錄
- 便於診斷問題
-
保持獨立性
- 兩個系統可單獨使用
- 降低耦合度
-
實用主義
- 選擇快速有效的方案(方案 A)
- 避免過度工程化
遇到的挑戰
-
異步同步橋接
- 挑戰:Python 事件循環限制
- 解決:檢測並創建新循環
-
路徑管理
- 挑戰:三個路徑概念(automation_tool 路徑、worktree 路徑、輸出路徑)
- 解決:清晰的命名和文檔
-
API 速率限制
- 挑戰:SystemDesigner 會調用 10-20 次 API
- 解決:錯誤處理 + 日誌提示
-
反饋傳遞
- 挑戰:如何讓 AI 看到人工反饋
- 解決:臨時文件附加反饋
可改進之處
-
API 速率限制處理
- 當前:失敗後等待用戶重試
- 改進:自動重試 + 指數退避
-
工具調用監控
- 當前:只記錄總次數
- 改進:詳細記錄每次調用的時間和內容
-
反饋質量檢查
- 當前:直接傳遞人工反饋
- 改進:檢查反饋格式,提供改進建議
-
並發處理
- 當前:串行處理任務
- 改進:支援並發處理多個任務
未來展望
短期(1-3 個月)
- ✅ 需求分析整合(已完成)
- ✅ 系統設計整合(已完成)
- ⏳ 開發階段整合(進行中)
- ⏳ 測試階段整合(規劃中)
開發階段挑戰:
- 需要 AI 真正修改代碼文件
- 可能需要多次迭代
- 如何確保生成的代碼可編譯?
測試階段挑戰:
- 需要創建 Pull Request
- 需要運行測試
- 如何處理測試失敗?
中期(3-6 個月)
打包成 pip package:
pip install automation-tool支援更多專案類型:
- Python 專案
- JavaScript/TypeScript 專案
- Java/Kotlin 專案
統一配置管理:
- 共享 API key 配置
- 統一的 AI Provider 層
長期願景(6-12 個月)
完全自動化的開發工作流:
Jira 任務提交
↓
AI 分析需求(無需人工)
↓
AI 設計系統(無需人工)
↓
AI 生成代碼(無需人工)
↓
AI 運行測試(無需人工)
↓
人工審批最終結果
↓
自動 Merge 到主分支
AI Agent 獨立完成任務:
- 自主決策技術方案
- 自動修復編譯錯誤
- 自動優化性能
- 自動補充測試
人類只需要:
- 提供高層需求
- 審批關鍵決策
- 驗收最終結果
結語
這次整合不僅僅是技術上的成功,更重要的是驗證了一個理念:
AI 需要理解專案,才能成為真正的開發助手。
傳統的 AI 輔助工具把 AI 當作”代碼生成器”,而我們把 AI 當作”會寫代碼的開發者”:
- 它會先理解專案結構
- 它會搜尋相關代碼
- 它會閱讀現有實現
- 然後基於理解生成方案
這就是 Tool Use API 的力量。
整合完成後,我們實現了:
- ✅ 需求文檔質量提升 5 倍
- ✅ 設計文檔從無到有(無限提升)
- ✅ AI 真正理解 Unity 專案
- ✅ 完整的 DevOps 工作流整合
- ✅ 人機協作的最佳實踐
這只是開始。
隨著 AI 能力的進步和 Tool Use API 的演進,我相信未來會有更多可能:
- 更深入的專案理解
- 更準確的代碼生成
- 更智能的決策支援
讓我們一起期待 AI 輔助開發的未來。
相關文章
- [[專案/AI自動化Unity工作流整合/日誌/01-兩個工具的誕生|#1 兩個工具的誕生]]
- [[專案/AI自動化Unity工作流整合/日誌/02-整合設計與實施|#2 整合設計與實施]]
- automation_tool 專案
返回 專案主頁