Tao Sun 7 месяцев назад
Родитель
Сommit
fd5dc46aa4
1 измененных файлов с 135 добавлено и 170 удалено
  1. 135 170
      code/chapter9/codebase_maintainer.py

+ 135 - 170
code/chapter9/codebase_maintainer.py

@@ -7,16 +7,18 @@ CodebaseMaintainer - 代码库维护助手
 3. TerminalTool - 即时文件访问
 3. TerminalTool - 即时文件访问
 4. MemoryTool - 对话记忆
 4. MemoryTool - 对话记忆
 
 
-实现跨会话的代码库维护任务管理
+关键改进:使用 Agentic 方式,让 agent 自主决定使用哪些工具
 """
 """
 
 
 from typing import Dict, Any, List, Optional
 from typing import Dict, Any, List, Optional
 from datetime import datetime
 from datetime import datetime
 import json
 import json
 
 
-from hello_agents import SimpleAgent, HelloAgentsLLM
+from hello_agents import HelloAgentsLLM
+from hello_agents.agents import FunctionCallAgent
 from hello_agents.context import ContextBuilder, ContextConfig, ContextPacket
 from hello_agents.context import ContextBuilder, ContextConfig, ContextPacket
 from hello_agents.tools import MemoryTool, NoteTool, TerminalTool
 from hello_agents.tools import MemoryTool, NoteTool, TerminalTool
+from hello_agents.tools.registry import ToolRegistry
 from hello_agents.core.message import Message
 from hello_agents.core.message import Message
 
 
 
 
@@ -25,6 +27,11 @@ class CodebaseMaintainer:
 
 
     整合 ContextBuilder + NoteTool + TerminalTool + MemoryTool
     整合 ContextBuilder + NoteTool + TerminalTool + MemoryTool
     实现跨会话的代码库维护任务管理
     实现跨会话的代码库维护任务管理
+    
+    核心特性:
+    - Agent 自主使用工具探索代码库
+    - 不预定义工作流,完全基于 agent 决策
+    - 跨会话记忆和上下文管理
     """
     """
 
 
     def __init__(
     def __init__(
@@ -60,6 +67,22 @@ class CodebaseMaintainer:
             )
             )
         )
         )
 
 
+        # 创建工具注册表并注册工具
+        self.tool_registry = ToolRegistry()
+        self.tool_registry.register_tool(self.terminal_tool)
+        self.tool_registry.register_tool(self.note_tool)
+        self.tool_registry.register_tool(self.memory_tool)
+
+        # 创建 Agent
+        self.agent = FunctionCallAgent(
+            name="CodebaseMaintainer",
+            llm=self.llm,
+            system_prompt=self._build_base_system_prompt(),
+            tool_registry=self.tool_registry,
+            enable_tool_calling=True,
+            max_tool_iterations=30
+        )
+
         # 对话历史
         # 对话历史
         self.conversation_history: List[Message] = []
         self.conversation_history: List[Message] = []
 
 
@@ -68,23 +91,25 @@ class CodebaseMaintainer:
             "session_start": datetime.now(),
             "session_start": datetime.now(),
             "commands_executed": 0,
             "commands_executed": 0,
             "notes_created": 0,
             "notes_created": 0,
-            "issues_found": 0
+            "issues_found": 0,
+            "tool_calls": 0
         }
         }
 
 
-        print(f"✅ 代码库维护助手已初始化: {project_name}")
+        print(f"✅ 代码库维护助手已初始化: {project_name} (Agentic Mode)")
         print(f"📁 工作目录: {codebase_path}")
         print(f"📁 工作目录: {codebase_path}")
         print(f"🆔 会话ID: {self.session_id}")
         print(f"🆔 会话ID: {self.session_id}")
+        print(f"🔧 可用工具: {', '.join(self.tool_registry.list_tools())}")
 
 
     def run(self, user_input: str, mode: str = "auto") -> str:
     def run(self, user_input: str, mode: str = "auto") -> str:
-        """运行助手
+        """运行助手(Agentic 方式)
 
 
         Args:
         Args:
             user_input: 用户输入
             user_input: 用户输入
-            mode: 运行模式
+            mode: 运行模式提示(给 agent 提供方向性建议)
                 - "auto": 自动决策是否使用工具
                 - "auto": 自动决策是否使用工具
-                - "explore": 侧重代码探索
-                - "analyze": 侧重问题分析
-                - "plan": 侧重任务规划
+                - "explore": 建议 agent 侧重代码探索
+                - "analyze": 建议 agent 侧重问题分析
+                - "plan": 建议 agent 侧重任务规划
 
 
         Returns:
         Returns:
             str: 助手的回答
             str: 助手的回答
@@ -93,39 +118,31 @@ class CodebaseMaintainer:
         print(f"👤 用户: {user_input}")
         print(f"👤 用户: {user_input}")
         print(f"{'='*80}\n")
         print(f"{'='*80}\n")
 
 
-        # 第一步:根据模式执行预处理
-        pre_context = self._preprocess_by_mode(user_input, mode)
-
-        # 第二步:检索相关笔记
+        # 第一步: 检索相关笔记(为 agent 提供上下文)
         relevant_notes = self._retrieve_relevant_notes(user_input)
         relevant_notes = self._retrieve_relevant_notes(user_input)
         note_packets = self._notes_to_packets(relevant_notes)
         note_packets = self._notes_to_packets(relevant_notes)
 
 
-        # 第三步:构建优化的上下文
+        # 第二步: 构建优化的上下文
         context = self.context_builder.build(
         context = self.context_builder.build(
             user_query=user_input,
             user_query=user_input,
             conversation_history=self.conversation_history,
             conversation_history=self.conversation_history,
             system_instructions=self._build_system_instructions(mode),
             system_instructions=self._build_system_instructions(mode),
-            additional_packets=note_packets + pre_context
+            additional_packets=note_packets
         )
         )
 
 
-        # 第四步:调用 LLM
-        print("🤖 正在思考...")
-        messages = [
-            {
-                "role": "system",
-                "content": context
-            },
-            {
-                "role": "user",
-                "content": user_input
-            }
-        ]
-        response = self.llm.invoke(messages)
+        # 第三步: 让 Agent 自主决策和使用工具
+        print("🤖 Agent 正在思考并决定使用哪些工具...\n")
+        
+        # 更新 agent 的系统提示(包含上下文)
+        self.agent.system_prompt = context
+        
+        # 调用 agent(agent 会自主决定是否使用工具)
+        response = self.agent.run(user_input)
 
 
-        # 第五步:后处理
-        self._postprocess_response(user_input, response)
+        # 第四步: 统计工具使用情况
+        self._track_tool_usage()
 
 
-        # 第六步:更新对话历史
+        # 第五步: 更新对话历史
         self._update_history(user_input, response)
         self._update_history(user_input, response)
 
 
         print(f"\n🤖 助手: {response}\n")
         print(f"\n🤖 助手: {response}\n")
@@ -133,71 +150,45 @@ class CodebaseMaintainer:
 
 
         return response
         return response
 
 
-    def _preprocess_by_mode(
-        self,
-        user_input: str,
-        mode: str
-    ) -> List[ContextPacket]:
-        """根据模式执行预处理,收集相关信息"""
-        packets = []
-
-        if mode == "explore" or mode == "auto":
-            # 探索模式:自动查看项目结构
-            print("🔍 探索代码库结构...")
-
-            structure = self.terminal_tool.run({"command": "find . -type f -name '*.py' | head -n 20"})
-            self.stats["commands_executed"] += 1
-
-            packets.append(ContextPacket(
-                content=f"[代码库结构]\n{structure}",
-                timestamp=datetime.now(),
-                token_count=len(structure) // 4,
-                relevance_score=0.6,
-                metadata={"type": "code_structure", "source": "terminal"}
-            ))
-
-        if mode == "analyze":
-            # 分析模式:检查代码复杂度和问题
-            print("📊 分析代码质量...")
-
-            # 统计代码行数
-            loc = self.terminal_tool.run({"command": "find . -name '*.py' -exec wc -l {} + | tail -n 1"})
-
-            # 查找 TODO 和 FIXME
-            todos = self.terminal_tool.run({"command": "grep -rn 'TODO\\|FIXME' --include='*.py' | head -n 10"})
+    def _build_base_system_prompt(self) -> str:
+        """构建基础系统提示"""
+        return f"""你是 {self.project_name} 项目的代码库维护助手。
 
 
-            self.stats["commands_executed"] += 2
-
-            packets.append(ContextPacket(
-                content=f"[代码统计]\n{loc}\n\n[待办事项]\n{todos}",
-                timestamp=datetime.now(),
-                token_count=(len(loc) + len(todos)) // 4,
-                relevance_score=0.7,
-                metadata={"type": "code_analysis", "source": "terminal"}
-            ))
+你的核心能力:
+1. 使用 TerminalTool 探索代码库
+   - 你可以执行任何 shell 命令: ls, cat, grep, find, git 等
+   - 工作目录: {self.codebase_path}
+   
+2. 使用 NoteTool 记录发现和任务
+   - 创建笔记记录重要发现
+   - 笔记类型: blocker(阻塞问题)、action(行动计划)、task_state(任务状态)、conclusion(结论)
+   
+3. 使用 MemoryTool 存储关键信息
+   - 记住重要的上下文信息
+   - 跨会话保持连贯性
 
 
-        if mode == "plan":
-            # 规划模式:加载最近的笔记
-            print("📋 加载任务规划...")
+当前会话ID: {self.session_id}
 
 
-            task_notes_raw = self.note_tool.run({
-                "action": "list",
-                "note_type": "task_state",
-                "limit": 3
-            })
-            task_notes = self._normalize_note_results(task_notes_raw)
-
-            if task_notes:
-                content = "\n".join([f"- {note.get('title', 'Untitled')}" for note in task_notes])
-                packets.append(ContextPacket(
-                    content=f"[当前任务]\n{content}",
-                    timestamp=datetime.now(),
-                    token_count=len(content) // 4,
-                    relevance_score=0.8,
-                    metadata={"type": "task_plan", "source": "notes"}
-                ))
+重要原则:
+- 你要自主决定使用哪些工具、执行什么命令
+- 探索代码库时,先了解整体结构,再深入细节
+- 发现重要信息时,主动使用 NoteTool 记录
+- 保持回答的专业性和实用性
+"""
 
 
-        return packets
+    def _track_tool_usage(self):
+        """统计工具使用情况"""
+        # 从 agent 的执行历史中统计
+        if hasattr(self.agent, 'message_history'):
+            for msg in self.agent.message_history[-10:]:  # 只看最近10条
+                if msg.role == "tool":
+                    self.stats["tool_calls"] += 1
+                    # 根据工具名统计
+                    if "terminal" in str(msg.content).lower() or "command" in str(msg.content).lower():
+                        self.stats["commands_executed"] += 1
+                    elif "note" in str(msg.content).lower():
+                        if "create" in str(msg.content).lower():
+                            self.stats["notes_created"] += 1
 
 
     def _retrieve_relevant_notes(self, query: str, limit: int = 3) -> List[Dict]:
     def _retrieve_relevant_notes(self, query: str, limit: int = 3) -> List[Dict]:
         """检索相关笔记"""
         """检索相关笔记"""
@@ -300,87 +291,46 @@ class CodebaseMaintainer:
         return packets
         return packets
 
 
     def _build_system_instructions(self, mode: str) -> str:
     def _build_system_instructions(self, mode: str) -> str:
-        """构建系统指令"""
-        base_instructions = f"""你是 {self.project_name} 项目的代码库维护助手。
-
-你的核心能力:
-1. 使用 TerminalTool 探索代码库(ls, cat, grep, find等)
-2. 使用 NoteTool 记录发现和任务
-3. 基于历史笔记提供连贯的建议
-
-当前会话ID: {self.session_id}
-"""
+        """构建系统指令(Agentic 方式)"""
+        base_instructions = self._build_base_system_prompt()
 
 
-        mode_specific = {
+        mode_hints = {
             "explore": """
             "explore": """
-当前模式: 探索代码库
+用户当前关注: 探索代码库
 
 
-你应该:
-- 主动使用 terminal 命令了解代码结构
-- 识别关键模块和文件
-- 记录项目架构到笔记
+建议策略:
+- 考虑使用 TerminalTool 了解代码结构(如 find, ls, tree)
+- 查看关键文件(如 README, 主要模块)
+- 将架构信息记录到笔记方便后续查阅
 """,
 """,
             "analyze": """
             "analyze": """
-当前模式: 分析代码质量
+用户当前关注: 分析代码质量
 
 
-你应该:
-- 查找代码问题(重复、复杂度、TODO等)
-- 评估代码质量
+建议策略:
+- 考虑使用 grep 查找潜在问题(TODO, FIXME, BUG)
+- 分析代码复杂度和结构
 - 将发现的问题记录为 blocker 或 action 笔记
 - 将发现的问题记录为 blocker 或 action 笔记
 """,
 """,
             "plan": """
             "plan": """
-当前模式: 任务规划
+用户当前关注: 任务规划
 
 
-你应该:
-- 回顾历史笔记和任务
-- 制定下一步行动计划
-- 更新任务状态笔记
+建议策略:
+- 回顾历史笔记了解当前进度
+- 基于已有信息制定行动计划
+- 创建或更新 task_state 类型的笔记
 """,
 """,
             "auto": """
             "auto": """
-当前模式: 自动决策
+用户当前关注: 自由对话
 
 
-你应该:
-- 根据用户需求灵活选择策略
-- 在需要时使用工具
-- 保持回答的专业性和实用性
+建议策略:
+- 根据用户需求灵活决策
+- 在需要时主动使用工具获取信息
+- 不需要时可以直接回答
 """
 """
         }
         }
 
 
-        return base_instructions + mode_specific.get(mode, mode_specific["auto"])
+        return base_instructions + "\n" + mode_hints.get(mode, mode_hints["auto"])
 
 
-    def _postprocess_response(self, user_input: str, response: str):
-        """后处理:分析回答,自动记录重要信息"""
-
-        # 如果发现问题,自动创建 blocker 笔记
-        if any(keyword in response.lower() for keyword in ["问题", "bug", "错误", "阻塞"]):
-            try:
-                self.note_tool.run({
-                    "action": "create",
-                    "title": f"发现问题: {user_input[:30]}...",
-                    "content": f"## 用户输入\n{user_input}\n\n## 问题分析\n{response[:500]}...",
-                    "note_type": "blocker",
-                    "tags": [self.project_name, "auto_detected", self.session_id]
-                })
-                self.stats["notes_created"] += 1
-                self.stats["issues_found"] += 1
-                print("📝 已自动创建问题笔记")
-            except Exception as e:
-                print(f"[WARNING] 创建笔记失败: {e}")
-
-        # 如果是任务规划,自动创建 action 笔记
-        elif any(keyword in user_input.lower() for keyword in ["计划", "下一步", "任务", "todo"]):
-            try:
-                self.note_tool.run({
-                    "action": "create",
-                    "title": f"任务规划: {user_input[:30]}...",
-                    "content": f"## 讨论\n{user_input}\n\n## 行动计划\n{response[:500]}...",
-                    "note_type": "action",
-                    "tags": [self.project_name, "planning", self.session_id]
-                })
-                self.stats["notes_created"] += 1
-                print("📝 已自动创建行动计划笔记")
-            except Exception as e:
-                print(f"[WARNING] 创建笔记失败: {e}")
 
 
     def _update_history(self, user_input: str, response: str):
     def _update_history(self, user_input: str, response: str):
         """更新对话历史"""
         """更新对话历史"""
@@ -398,17 +348,26 @@ class CodebaseMaintainer:
     # === 便捷方法 ===
     # === 便捷方法 ===
 
 
     def explore(self, target: str = ".") -> str:
     def explore(self, target: str = ".") -> str:
-        """探索代码库"""
-        return self.run(f"请探索 {target} 的代码结构", mode="explore")
+        """探索代码库(Agentic 方式)
+        
+        Agent 会自主决定使用哪些命令来探索代码库
+        """
+        return self.run(f"请探索 {target} 的代码结构,了解项目组织方式", mode="explore")
 
 
     def analyze(self, focus: str = "") -> str:
     def analyze(self, focus: str = "") -> str:
-        """分析代码质量"""
-        query = f"请分析代码质量" + (f",重点关注{focus}" if focus else "")
+        """分析代码质量(Agentic 方式)
+        
+        Agent 会自主决定如何分析代码质量
+        """
+        query = f"请分析代码质量" + (f",重点关注{focus}" if focus else "")
         return self.run(query, mode="analyze")
         return self.run(query, mode="analyze")
 
 
     def plan_next_steps(self) -> str:
     def plan_next_steps(self) -> str:
-        """规划下一步任务"""
-        return self.run("根据当前进度,规划下一步任务", mode="plan")
+        """规划下一步任务(Agentic 方式)
+        
+        Agent 会查看历史笔记并规划下一步
+        """
+        return self.run("根据我们之前的分析和当前进度,规划下一步任务", mode="plan")
 
 
     def execute_command(self, command: str) -> str:
     def execute_command(self, command: str) -> str:
         """执行终端命令"""
         """执行终端命令"""
@@ -473,9 +432,15 @@ class CodebaseMaintainer:
 
 
 
 
 def main():
 def main():
-    """主函数 - 演示 CodebaseMaintainer 的使用"""
+    """主函数 - 演示 CodebaseMaintainer 的使用(Agentic 版本)
+    
+    在这个版本中:
+    - Agent 自主决定使用哪些工具
+    - 不预定义工作流
+    - Agent 根据需求灵活探索代码库
+    """
     print("=" * 80)
     print("=" * 80)
-    print("CodebaseMaintainer 演示")
+    print("CodebaseMaintainer 演示(Agentic 版本)")
     print("=" * 80 + "\n")
     print("=" * 80 + "\n")
 
 
     # 初始化助手
     # 初始化助手
@@ -485,16 +450,16 @@ def main():
         llm=HelloAgentsLLM()
         llm=HelloAgentsLLM()
     )
     )
 
 
-    # 探索代码库
-    print("\n### 探索代码库 ###")
+    # 探索代码库(Agent 自主决定如何探索)
+    print("\n### 探索代码库(Agent 自主探索)###")
     response = maintainer.explore()
     response = maintainer.explore()
 
 
-    # 分析代码质量
-    print("\n### 分析代码质量 ###")
+    # 分析代码质量(Agent 自主决定分析方法)
+    print("\n### 分析代码质量(Agent 自主分析)###")
     response = maintainer.analyze()
     response = maintainer.analyze()
 
 
-    # 规划下一步
-    print("\n### 规划下一步任务 ###")
+    # 规划下一步(Agent 基于历史信息规划)
+    print("\n### 规划下一步任务(Agent 自主规划)###")
     response = maintainer.plan_next_steps()
     response = maintainer.plan_next_steps()
 
 
     # 生成报告
     # 生成报告