開發日誌 #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

設計原則

  1. 失敗不中斷:每層降級都能生成輸出
  2. 清晰日誌:用戶知道發生了什麼
  3. 可診斷:錯誤信息包含足夠上下文
  4. 可恢復:修復問題後自動使用最佳方案

亮點 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

為什麼這樣設計很巧妙?

  1. 隔離性

    • 每個 Jira 任務有獨立的 Git Worktree
    • AI 探索不會影響其他任務
    • 失敗可以安全刪除 Worktree
  2. 並發性

    • 可同時處理多個任務
    • 不同 Worktree 互不干擾
  3. 可追溯性

    • 探索過程的文件讀取都記錄在日誌
    • 可以知道 AI 看了哪些文件
  4. 安全性

    • 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

設計原則

  1. 自動化:不需要手動編輯文件
  2. 隔離:臨時文件不影響原始文件
  3. 清理:使用後自動刪除臨時文件
  4. 可追溯: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-..."  # 直接寫入(僅測試)

經驗總結

成功的關鍵因素

  1. 清晰的接口設計

    • automation_tool 的輸入輸出都是標準格式
    • 便於其他系統整合
  2. 優雅降級

    • 失敗不中斷流程
    • 用戶體驗平滑
  3. 充分的日誌

    • 每個關鍵步驟都記錄
    • 便於診斷問題
  4. 保持獨立性

    • 兩個系統可單獨使用
    • 降低耦合度
  5. 實用主義

    • 選擇快速有效的方案(方案 A)
    • 避免過度工程化

遇到的挑戰

  1. 異步同步橋接

    • 挑戰:Python 事件循環限制
    • 解決:檢測並創建新循環
  2. 路徑管理

    • 挑戰:三個路徑概念(automation_tool 路徑、worktree 路徑、輸出路徑)
    • 解決:清晰的命名和文檔
  3. API 速率限制

    • 挑戰:SystemDesigner 會調用 10-20 次 API
    • 解決:錯誤處理 + 日誌提示
  4. 反饋傳遞

    • 挑戰:如何讓 AI 看到人工反饋
    • 解決:臨時文件附加反饋

可改進之處

  1. API 速率限制處理

    • 當前:失敗後等待用戶重試
    • 改進:自動重試 + 指數退避
  2. 工具調用監控

    • 當前:只記錄總次數
    • 改進:詳細記錄每次調用的時間和內容
  3. 反饋質量檢查

    • 當前:直接傳遞人工反饋
    • 改進:檢查反饋格式,提供改進建議
  4. 並發處理

    • 當前:串行處理任務
    • 改進:支援並發處理多個任務

未來展望

短期(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 專案

返回 專案主頁