Browse Source

add chapter7 & code

jjyaoao 9 tháng trước cách đây
mục cha
commit
e43134a59f

+ 6 - 6
README.md

@@ -16,7 +16,7 @@
 
   如果说2024年是"百模大战"的元年,那么2025年无疑开启了"Agent元年"。技术的焦点正从训练更大的基础模型,转向构建更聪明的智能体应用。然而,当前系统性、重实践的教程却极度匮乏。为此,我们发起了 Hello-Agents 项目,希望能为社区提供一本从零开始、理论与实战并重的多智能体系统构建指南。
 
-&emsp;&emsp;Hello-Agents 是一个<strong>系统性的智能体学习教程</strong>,旨在"授人以渔"。教程将带领你穿透框架表象,从智能体的核心原理出发,深入其核心架构,理解其经典范式,并最终亲手构建起属于自己的、强大的多智能体应用。我们相信,最好的学习方式就是动手实践。希望这本书能成为你探索智能体世界的起点,能够从一名 LLM 的"使用者",蜕变为一名智能系统的"构建者"。
+&emsp;&emsp;Hello-Agents 是一个<strong>系统性的智能体学习教程</strong>,旨在"授人以渔"。教程将带领你穿透框架表象,从智能体的核心原理出发,深入其核心架构,理解其经典范式,并最终亲手构建起属于自己的多智能体应用。我们相信,最好的学习方式就是动手实践。希望这本书能成为你探索智能体世界的起点,能够从一名 LLM 的"使用者",蜕变为一名智能系统的"构建者"。
 
 ## 📚 快速开始
 
@@ -31,7 +31,7 @@
 - 📖 <strong>Datawhale 开源免费</strong> 完全免费学习本项目所有内容,与社区共同成长
 - 🔍 <strong>理解核心原理</strong> 深入理解智能体(Agent)的构件、原则与经典范式
 - 🏗️ <strong>亲手实现</strong> 编码复现 ReAct、Plan-and-Solve 等经典智能体架构
-- 🛠️ <strong>掌握高级技能</strong> 学习并应用 CoT、RAG、工具使用等前沿技术
+- 🛠️ <strong>掌握高级技能</strong> 学习并应用 上下文工程、RAG、工具使用等前沿技术
 - 🤝 <strong>构建多智能体</strong> 掌握多智能体协作、通信与评估的核心方法
 - 🚀 <strong>驱动真实案例</strong> 实战开发智能旅行助手、自动化研究员等综合项目"
 
@@ -50,8 +50,8 @@
 | [第六章 框架开发实践](./docs/chapter6/第六章%20框架开发实践.md) | AutoGen、AgentScope、LangGraph 等主流框架应用 | ✅ |
 | [第七章 构建你的Agent框架](./docs/chapter7/第七章%20构建你的Agent框架.md) | 从0开始构建智能体框架 | 🚧 |
 | <strong>第三部分:高级知识扩展</strong> |  |  |
-| [第八章 推理与规划](./docs/chapter8/第八章%20推理与规划.md) | CoT, 逻辑推理, 搜索与规划 | 🚧 |
-| [第九章 记忆与工具](./docs/chapter9/第九章%20记忆与工具.md) | RAG, 向量数据库, API 调用 | 🚧 |
+| [第八章 记忆与检索](./docs/chapter9/第八章%20记忆与检索.md) | RAG, 向量数据库, 记忆系统 | 🚧 |
+| [第九章 上下文工程](./docs/chapter8/第九章%20上下文工程.md) | 持续交互的"情境理解" | 🚧 |
 | [第十章 智能体通信协议](./docs/chapter10/第十章%20智能体通信协议.md) | MCP, A2A, ANP 等协议解析 | 🚧 |
 | [第十一章 多智能体系统](./docs/chapter11/第十一章%20多智能体系统.md) | 协作、通信、博弈论与 AI Society | 🚧 |
 | [第十二章 智能体性能评估](./docs/chapter12/第十二章%20智能体性能评估.md) | 核心指标、基准测试与评估框架 | 🚧 |
@@ -85,14 +85,14 @@
 
 - <strong>第二部分:构建你的大语言模型智能体</strong>(第4章~第7章),这是你动手实践的起点。你将亲手实现 ReAct 等经典范式,体验 Coze 等低代码平台的便捷,并掌握 AutoGen 等主流框架的应用。最终,我们还会带你从零开始构建一个属于自己的智能体框架,让你兼具“用轮子”与“造轮子”的能力。
 
-- <strong>第三部分:高级知识扩展</strong>(第8章~第12章),在这一部分,你的智能体将“学会”思考与协作。我们将深入探索推理、规划、记忆与工具使用等核心技术,并学习多智能体间的通信协议。最终,你将掌握评估一个复杂多智能体系统性能的专业方法。
+- <strong>第三部分:高级知识扩展</strong>(第8章~第12章),在这一部分,你的智能体将“学会”思考与协作。我们将深入探索推理、规划、记忆与检索使用等核心技术,并学习多智能体间的通信协议。最终,你将掌握评估一个复杂多智能体系统性能的专业方法。
 
 - <strong>第四部分:综合案例进阶</strong>(第13章~第15章),这里是理论与实践的交汇点。你将把所学融会贯通,亲手打造 <strong>智能旅行助手</strong>、<strong>自动化深度研究智能体</strong>,乃至一个模拟社会动态的 <strong>赛博小镇</strong>,在真实有趣的项目中淬炼你的高级能。
 
 - <strong>第五部分:毕业设计及未来展望</strong>(第16章),在旅程的终点,你将迎来一个毕业设计,构建一个完整的、属于你自己的多智能体应用,全面检验你的学习成果。我们还将与你一同展望智能体的未来,探索激动人心的前沿方向。
 
 
-&emsp;&emsp;为了获得最佳的学习效果,我们强烈建议你 <strong>将理论与实践相结合</strong>。智能体是一个飞速发展且极度依赖实践的领域。请务必亲手运行、调试甚至修改本书提供的每一份代码。当遇到问题时,欢迎你随时在我们的开源社区中提问和交流。
+&emsp;&emsp;智能体是一个飞速发展且极度依赖实践的领域。为了获得最佳的学习效果,我们在项目的code文件夹内提供了配套的全部代码,强烈建议你 <strong>将理论与实践相结合</strong>。请务必亲手运行、调试甚至修改本书提供的每一份代码。当遇到问题时,欢迎你随时在我们的开源社区中提问和交流。
 
 &emsp;&emsp;现在,准备好进入智能体的奇妙世界了吗?让我们即刻启程!
 

+ 32 - 0
code/chapter7/.env.example

@@ -0,0 +1,32 @@
+# ============================================================================
+# HelloAgents 统一环境变量配置文件
+# ============================================================================
+# 复制此文件为 .env 并填入你的API密钥
+# 系统要求:Python 3.10+ (必需)
+
+# ============================================================================
+# 🚀 统一配置格式(推荐)- 框架自动检测provider
+# ============================================================================
+# 只需配置以下4个通用环境变量,框架会自动识别LLM提供商:
+
+# 模型名称
+LLM_MODEL_ID=your-model-name
+
+# API密钥
+LLM_API_KEY=your-api-key-here
+
+# 服务地址
+LLM_BASE_URL=your-api-base-url
+
+# 超时时间(可选,默认60秒)
+LLM_TIMEOUT=60
+
+# ============================================================================
+# 🛠️ 工具配置(可选)
+# ============================================================================
+
+# Tavily搜索(推荐)- 获取API密钥:https://tavily.com/
+# TAVILY_API_KEY=tvly-your_tavily_key_here
+
+# SerpApi搜索(备选)- 获取API密钥:https://serpapi.com/
+# SERPAPI_API_KEY=your_serpapi_key_here

+ 132 - 0
code/chapter7/my_advanced_search.py

@@ -0,0 +1,132 @@
+# my_advanced_search.py
+import os
+from typing import Optional, List, Dict, Any
+from hello_agents import ToolRegistry
+
+class MyAdvancedSearchTool:
+    """
+    自定义高级搜索工具类
+    展示多源整合和智能选择的设计模式
+    """
+
+    def __init__(self):
+        self.name = "my_advanced_search"
+        self.description = "智能搜索工具,支持多个搜索源,自动选择最佳结果"
+        self.search_sources = []
+        self._setup_search_sources()
+
+    def _setup_search_sources(self):
+        """设置可用的搜索源"""
+        # 检查Tavily可用性
+        if os.getenv("TAVILY_API_KEY"):
+            try:
+                from tavily import TavilyClient
+                self.tavily_client = TavilyClient(api_key=os.getenv("TAVILY_API_KEY"))
+                self.search_sources.append("tavily")
+                print("✅ Tavily搜索源已启用")
+            except ImportError:
+                print("⚠️ Tavily库未安装")
+
+        # 检查SerpApi可用性
+        if os.getenv("SERPAPI_API_KEY"):
+            try:
+                import serpapi
+                self.search_sources.append("serpapi")
+                print("✅ SerpApi搜索源已启用")
+            except ImportError:
+                print("⚠️ SerpApi库未安装")
+
+        if self.search_sources:
+            print(f"🔧 可用搜索源: {', '.join(self.search_sources)}")
+        else:
+            print("⚠️ 没有可用的搜索源,请配置API密钥")
+
+    def search(self, query: str) -> str:
+        """执行智能搜索"""
+        if not query.strip():
+            return "❌ 错误:搜索查询不能为空"
+
+        # 检查是否有可用的搜索源
+        if not self.search_sources:
+            return """❌ 没有可用的搜索源,请配置以下API密钥之一:
+
+1. Tavily API: 设置环境变量 TAVILY_API_KEY
+   获取地址: https://tavily.com/
+
+2. SerpAPI: 设置环境变量 SERPAPI_API_KEY
+   获取地址: https://serpapi.com/
+
+配置后重新运行程序。"""
+
+        print(f"🔍 开始智能搜索: {query}")
+
+        # 尝试多个搜索源,返回最佳结果
+        for source in self.search_sources:
+            try:
+                if source == "tavily":
+                    result = self._search_with_tavily(query)
+                    if result and "未找到" not in result:
+                        return f"📊 Tavily AI搜索结果:\n\n{result}"
+
+                elif source == "serpapi":
+                    result = self._search_with_serpapi(query)
+                    if result and "未找到" not in result:
+                        return f"🌐 SerpApi Google搜索结果:\n\n{result}"
+
+            except Exception as e:
+                print(f"⚠️ {source} 搜索失败: {e}")
+                continue
+
+        return "❌ 所有搜索源都失败了,请检查网络连接和API密钥配置"
+
+    def _search_with_tavily(self, query: str) -> str:
+        """使用Tavily搜索"""
+        response = self.tavily_client.search(query=query, max_results=3)
+
+        if response.get('answer'):
+            result = f"💡 AI直接答案:{response['answer']}\n\n"
+        else:
+            result = ""
+
+        result += "🔗 相关结果:\n"
+        for i, item in enumerate(response.get('results', [])[:3], 1):
+            result += f"[{i}] {item.get('title', '')}\n"
+            result += f"    {item.get('content', '')[:150]}...\n\n"
+
+        return result
+
+    def _search_with_serpapi(self, query: str) -> str:
+        """使用SerpApi搜索"""
+        import serpapi
+
+        search = serpapi.GoogleSearch({
+            "q": query,
+            "api_key": os.getenv("SERPAPI_API_KEY"),
+            "num": 3
+        })
+
+        results = search.get_dict()
+
+        result = "🔗 Google搜索结果:\n"
+        if "organic_results" in results:
+            for i, res in enumerate(results["organic_results"][:3], 1):
+                result += f"[{i}] {res.get('title', '')}\n"
+                result += f"    {res.get('snippet', '')}\n\n"
+
+        return result
+
+def create_advanced_search_registry():
+    """创建包含高级搜索工具的注册表"""
+    registry = ToolRegistry()
+
+    # 创建搜索工具实例
+    search_tool = MyAdvancedSearchTool()
+
+    # 注册搜索工具的方法作为函数
+    registry.register_function(
+        name="advanced_search",
+        description="高级搜索工具,整合Tavily和SerpAPI多个搜索源,提供更全面的搜索结果",
+        func=search_tool.search
+    )
+
+    return registry

+ 62 - 0
code/chapter7/my_calculator_tool.py

@@ -0,0 +1,62 @@
+# my_calculator_tool.py
+import ast
+import operator
+import math
+from hello_agents import ToolRegistry
+
+def my_calculate(expression: str) -> str:
+    """简单的数学计算函数"""
+    if not expression.strip():
+        return "计算表达式不能为空"
+
+    # 支持的基本运算
+    operators = {
+        ast.Add: operator.add,      # +
+        ast.Sub: operator.sub,      # -
+        ast.Mult: operator.mul,     # *
+        ast.Div: operator.truediv,  # /
+    }
+
+    # 支持的基本函数
+    functions = {
+        'sqrt': math.sqrt,
+        'pi': math.pi,
+    }
+
+    try:
+        node = ast.parse(expression, mode='eval')
+        result = _eval_node(node.body, operators, functions)
+        return str(result)
+    except:
+        return "计算失败,请检查表达式格式"
+
+def _eval_node(node, operators, functions):
+    """简化的表达式求值"""
+    if isinstance(node, ast.Constant):
+        return node.value
+    elif isinstance(node, ast.BinOp):
+        left = _eval_node(node.left, operators, functions)
+        right = _eval_node(node.right, operators, functions)
+        op = operators.get(type(node.op))
+        return op(left, right)
+    elif isinstance(node, ast.Call):
+        func_name = node.func.id
+        if func_name in functions:
+            args = [_eval_node(arg, operators, functions) for arg in node.args]
+            return functions[func_name](*args)
+    elif isinstance(node, ast.Name):
+        if node.id in functions:
+            return functions[node.id]
+
+def create_calculator_registry():
+    """创建包含计算器的工具注册表"""
+    registry = ToolRegistry()
+
+    # 注册计算器函数
+    registry.register_function(
+        name="my_calculator",
+        description="简单的数学计算工具,支持基本运算(+,-,*,/)和sqrt函数",
+        func=my_calculate
+    )
+
+    return registry

+ 40 - 0
code/chapter7/my_llm.py

@@ -0,0 +1,40 @@
+# my_llm.py
+import os
+from typing import Optional
+from openai import OpenAI
+from hello_agents import HelloAgentsLLM
+
+class MyLLM(HelloAgentsLLM):
+    def __init__(
+        self,
+        model: Optional[str] = None,
+        api_key: Optional[str] = None,
+        base_url: Optional[str] = None,
+        provider: Optional[str] = "auto",
+        **kwargs
+    ):
+        # 检查provider是否为我们想处理的'modelscope'
+        if provider == "modelscope":
+            print("正在使用自定义的 ModelScope Provider")
+            self.provider = "modelscope"
+            
+            # 解析 ModelScope 的凭证
+            self.api_key = api_key or os.getenv("MODELSCOPE_API_KEY")
+            self.base_url = base_url or "https://api-inference.modelscope.cn/v1/"
+            
+            # 验证凭证是否存在
+            if not self.api_key:
+                raise ValueError("ModelScope API key not found. Please set MODELSCOPE_API_KEY environment variable.")
+
+            # 设置默认模型和其他参数
+            self.model = model or os.getenv("LLM_MODEL_ID") or "Qwen/Qwen2.5-VL-72B-Instruct"
+            self.temperature = kwargs.get('temperature', 0.7)
+            self.max_tokens = kwargs.get('max_tokens')
+            self.timeout = kwargs.get('timeout', 60)
+            
+            # 使用获取的参数创建OpenAI客户端实例
+            self._client = OpenAI(api_key=self.api_key, base_url=self.base_url, timeout=self.timeout)
+
+        else:
+            # 如果不是 modelscope, 则完全使用父类的原始逻辑来处理
+            super().__init__(model=model, api_key=api_key, base_url=base_url, provider=provider, **kwargs)

+ 21 - 0
code/chapter7/my_main.py

@@ -0,0 +1,21 @@
+# my_main.py
+from dotenv import load_dotenv
+from my_llm import MyLLM # 注意:这里导入我们自己的类
+
+# 加载环境变量
+load_dotenv()
+
+# 实例化我们重写的客户端,并指定provider
+llm = MyLLM(provider="modelscope") 
+
+# 准备消息
+messages = [{"role": "user", "content": "你好,请介绍一下你自己。"}]
+
+# 发起调用,think等方法都已从父类继承,无需重写
+response_stream = llm.think(messages)
+
+# 打印响应
+print("ModelScope Response:")
+for chunk in response_stream:
+    # chunk 已经是文本片段,可以直接使用
+    print(chunk, end="", flush=True)

+ 98 - 0
code/chapter7/my_react_agent.py

@@ -0,0 +1,98 @@
+MY_REACT_PROMPT = """你是一个具备推理和行动能力的AI助手。你可以通过思考分析问题,然后调用合适的工具来获取信息,最终给出准确的答案。
+
+## 可用工具
+{tools}
+
+## 工作流程
+请严格按照以下格式进行回应,每次只能执行一个步骤:
+
+**Thought:** 分析当前问题,思考需要什么信息或采取什么行动。
+**Action:** 选择一个行动,格式必须是以下之一:
+- `{{tool_name}}[{{tool_input}}]` - 调用指定工具
+- `Finish[最终答案]` - 当你有足够信息给出最终答案时
+
+## 重要提醒
+1. 每次回应必须包含Thought和Action两部分
+2. 工具调用的格式必须严格遵循:工具名[参数]
+3. 只有当你确信有足够信息回答问题时,才使用Finish
+4. 如果工具返回的信息不够,继续使用其他工具或相同工具的不同参数
+
+## 当前任务
+**Question:** {question}
+
+## 执行历史
+{history}
+
+现在开始你的推理和行动:
+"""
+
+import re
+from typing import Optional, List, Tuple
+from hello_agents import ReActAgent, HelloAgentsLLM, Config, Message, ToolRegistry
+
+class MyReActAgent(ReActAgent):
+    """
+    重写的ReAct Agent - 推理与行动结合的智能体
+    """
+
+    def __init__(
+        self,
+        name: str,
+        llm: HelloAgentsLLM,
+        tool_registry: ToolRegistry,
+        system_prompt: Optional[str] = None,
+        config: Optional[Config] = None,
+        max_steps: int = 5,
+        custom_prompt: Optional[str] = None
+    ):
+        super().__init__(name, llm, system_prompt, config)
+        self.tool_registry = tool_registry
+        self.max_steps = max_steps
+        self.current_history: List[str] = []
+        self.prompt_template = custom_prompt if custom_prompt else MY_REACT_PROMPT
+        print(f"✅ {name} 初始化完成,最大步数: {max_steps}")
+
+    def run(self, input_text: str, **kwargs) -> str:
+        """运行ReAct Agent"""
+        self.current_history = []
+        current_step = 0
+
+        print(f"\n🤖 {self.name} 开始处理问题: {input_text}")
+
+        while current_step < self.max_steps:
+            current_step += 1
+            print(f"\n--- 第 {current_step} 步 ---")
+
+            # 1. 构建提示词
+            tools_desc = self.tool_registry.get_tools_description()
+            history_str = "\n".join(self.current_history)
+            prompt = self.prompt_template.format(
+                tools=tools_desc,
+                question=input_text,
+                history=history_str
+            )
+
+            # 2. 调用LLM
+            messages = [{"role": "user", "content": prompt}]
+            response_text = self.llm.invoke(messages, **kwargs)
+
+            # 3. 解析输出
+            thought, action = self._parse_output(response_text)
+
+            # 4. 检查完成条件
+            if action and action.startswith("Finish"):
+                final_answer = self._parse_action_input(action)
+                self._save_to_history(input_text, final_answer)
+                return final_answer
+
+            # 5. 执行工具调用
+            if action:
+                tool_name, tool_input = self._parse_action(action)
+                observation = self.tool_registry.execute_tool(tool_name, tool_input)
+                self.current_history.append(f"Action: {action}")
+                self.current_history.append(f"Observation: {observation}")
+
+        # 达到最大步数
+        final_answer = "抱歉,我无法在限定步数内完成这个任务。"
+        self._save_to_history(input_text, final_answer)
+        return final_answer

+ 80 - 0
code/chapter7/my_simple_agent.py

@@ -0,0 +1,80 @@
+# my_simple_agent.py
+from typing import Optional
+from hello_agents import SimpleAgent, HelloAgentsLLM, Config, Message
+
+class MySimpleAgent(SimpleAgent):
+    """
+    重写的简单对话Agent
+    展示如何基于框架基类构建自定义Agent
+    """
+
+    def __init__(
+        self,
+        name: str,
+        llm: HelloAgentsLLM,
+        system_prompt: Optional[str] = None,
+        config: Optional[Config] = None
+    ):
+        super().__init__(name, llm, system_prompt, config)
+        print(f"✅ {name} 初始化完成,基于框架基类构建")
+
+    def run(self, input_text: str, **kwargs) -> str:
+        """
+        重写的运行方法 - 实现简单对话逻辑
+        """
+        print(f"🤖 {self.name} 正在处理: {input_text}")
+
+        # 构建消息列表
+        messages = []
+
+        # 添加系统消息
+        if self.system_prompt:
+            messages.append({"role": "system", "content": self.system_prompt})
+
+        # 添加历史消息
+        for msg in self._history:
+            messages.append({"role": msg.role, "content": msg.content})
+
+        # 添加当前用户消息
+        messages.append({"role": "user", "content": input_text})
+
+        # 调用LLM
+        response = self.llm.invoke(messages, **kwargs)
+
+        # 保存到历史记录
+        self.add_message(Message(input_text, "user"))
+        self.add_message(Message(response, "assistant"))
+
+        print(f"✅ {self.name} 响应完成")
+        return response
+    
+    def stream_run(self, input_text: str, **kwargs):
+        """
+        自定义的流式运行方法
+        """
+        print(f"🌊 {self.name} 开始流式处理: {input_text}")
+
+        messages = []
+
+        if self.system_prompt:
+            messages.append({"role": "system", "content": self.system_prompt})
+
+        for msg in self._history:
+            messages.append({"role": msg.role, "content": msg.content})
+
+        messages.append({"role": "user", "content": input_text})
+
+        # 流式调用LLM
+        full_response = ""
+        print("📝 实时响应: ", end="")
+        for chunk in self.llm.stream_invoke(messages, **kwargs):
+            full_response += chunk
+            print(chunk, end="", flush=True)
+            yield chunk
+
+        print()  # 换行
+
+        # 保存完整对话到历史记录
+        self.add_message(Message(input_text, "user"))
+        self.add_message(Message(full_response, "assistant"))
+        print(f"✅ {self.name} 流式响应完成")

+ 53 - 0
code/chapter7/test_advanced_search.py

@@ -0,0 +1,53 @@
+# test_advanced_search.py
+from dotenv import load_dotenv
+from my_advanced_search import create_advanced_search_registry, MyAdvancedSearchTool
+
+# 加载环境变量
+load_dotenv()
+
+def test_advanced_search():
+    """测试高级搜索工具"""
+
+    # 创建包含高级搜索工具的注册表
+    registry = create_advanced_search_registry()
+
+    print("🔍 测试高级搜索工具\n")
+
+    # 测试查询
+    test_queries = [
+        "Python编程语言的历史",
+        "人工智能的最新发展",
+        "2024年科技趋势"
+    ]
+
+    for i, query in enumerate(test_queries, 1):
+        print(f"测试 {i}: {query}")
+        result = registry.execute_tool("advanced_search", query)
+        print(f"结果: {result}\n")
+        print("-" * 60 + "\n")
+
+def test_api_configuration():
+    """测试API配置检查"""
+    print("🔧 测试API配置检查:")
+
+    # 直接创建搜索工具实例
+    search_tool = MyAdvancedSearchTool()
+
+    # 如果没有配置API,会显示配置提示
+    result = search_tool.search("机器学习算法")
+    print(f"搜索结果: {result}")
+
+def test_with_agent():
+    """测试与Agent的集成"""
+    print("\n🤖 与Agent集成测试:")
+    print("高级搜索工具已准备就绪,可以与Agent集成使用")
+
+    # 显示工具描述
+    registry = create_advanced_search_registry()
+    tools_desc = registry.get_tools_description()
+    print(f"工具描述:\n{tools_desc}")
+
+if __name__ == "__main__":
+    test_advanced_search()
+    test_api_configuration()
+    test_with_agent()

+ 64 - 0
code/chapter7/test_my_calculator.py

@@ -0,0 +1,64 @@
+# test_my_calculator.py
+from dotenv import load_dotenv
+from my_calculator_tool import create_calculator_registry
+
+# 加载环境变量
+load_dotenv()
+
+def test_calculator_tool():
+    """测试自定义计算器工具"""
+
+    # 创建包含计算器的注册表
+    registry = create_calculator_registry()
+
+    print("🧪 测试自定义计算器工具\n")
+
+    # 简单测试用例
+    test_cases = [
+        "2 + 3",           # 基本加法
+        "10 - 4",          # 基本减法
+        "5 * 6",           # 基本乘法
+        "15 / 3",          # 基本除法
+        "sqrt(16)",        # 平方根
+    ]
+
+    for i, expression in enumerate(test_cases, 1):
+        print(f"测试 {i}: {expression}")
+        result = registry.execute_tool("my_calculator", expression)
+        print(f"结果: {result}\n")
+
+def test_with_simple_agent():
+    """测试与SimpleAgent的集成"""
+    from hello_agents import HelloAgentsLLM
+
+    # 创建LLM客户端
+    llm = HelloAgentsLLM()
+
+    # 创建包含计算器的注册表
+    registry = create_calculator_registry()
+
+    print("🤖 与SimpleAgent集成测试:")
+
+    # 模拟SimpleAgent使用工具的场景
+    user_question = "请帮我计算 sqrt(16) + 2 * 3"
+
+    print(f"用户问题: {user_question}")
+
+    # 使用工具计算
+    calc_result = registry.execute_tool("my_calculator", "sqrt(16) + 2 * 3")
+    print(f"计算结果: {calc_result}")
+
+    # 构建最终回答
+    final_messages = [
+        {"role": "user", "content": f"计算结果是 {calc_result},请用自然语言回答用户的问题:{user_question}"}
+    ]
+
+    print("\n🎯 SimpleAgent的回答:")
+    response = llm.think(final_messages)
+    for chunk in response:
+        print(chunk, end="", flush=True)
+    print("\n")
+
+if __name__ == "__main__":
+    test_calculator_tool()
+    test_with_simple_agent()

+ 25 - 0
code/chapter7/test_plan_solve_agent.py

@@ -0,0 +1,25 @@
+# test_plan_solve_agent.py
+from dotenv import load_dotenv
+from hello_agents.core.llm import HelloAgentsLLM
+from my_plan_solve_agent import MyPlanAndSolveAgent
+
+# 加载环境变量
+load_dotenv()
+
+# 创建LLM实例
+llm = HelloAgentsLLM()
+
+# 创建自定义PlanAndSolveAgent
+agent = MyPlanAndSolveAgent(
+    name="我的规划执行助手",
+    llm=llm
+)
+
+# 测试复杂问题
+question = "一个水果店周一卖出了15个苹果。周二卖出的苹果数量是周一的两倍。周三卖出的数量比周二少了5个。请问这三天总共卖出了多少个苹果?"
+
+result = agent.run(question)
+print(f"\n最终结果: {result}")
+
+# 查看对话历史
+print(f"对话历史: {len(agent.get_history())} 条消息")

+ 147 - 0
code/chapter7/test_react_agent.py

@@ -0,0 +1,147 @@
+# test_react_agent.py
+from dotenv import load_dotenv
+from hello_agents import HelloAgentsLLM, ToolRegistry
+from my_react_agent import MyReActAgent
+
+# 加载环境变量
+load_dotenv()
+
+def test_react_agent():
+    """测试MyReActAgent的功能"""
+    
+    # 创建LLM实例
+    llm = HelloAgentsLLM()
+    
+    # 创建工具注册表
+    tool_registry = ToolRegistry()
+    
+    # 注册一些基础工具用于测试
+    print("🔧 注册测试工具...")
+    
+    # 注册计算器工具
+    try:
+        from hello_agents import calculate
+        tool_registry.register_tool("calculate", calculate, "执行数学计算,支持基本的四则运算")
+        print("✅ 计算器工具注册成功")
+    except ImportError:
+        print("⚠️ 计算器工具未找到,跳过注册")
+    
+    # 注册搜索工具(如果可用)
+    try:
+        from hello_agents import search
+        tool_registry.register_tool("search", search, "搜索互联网信息")
+        print("✅ 搜索工具注册成功")
+    except ImportError:
+        print("⚠️ 搜索工具未找到,跳过注册")
+    
+    # 创建自定义ReActAgent
+    agent = MyReActAgent(
+        name="我的推理行动助手",
+        llm=llm,
+        tool_registry=tool_registry,
+        max_steps=5
+    )
+    
+    print("\n" + "="*60)
+    print("开始测试 MyReActAgent")
+    print("="*60)
+    
+    # 测试1:数学计算问题
+    print("\n📊 测试1:数学计算问题")
+    math_question = "请帮我计算:(25 + 15) × 3 - 8 的结果是多少?"
+    
+    try:
+        result1 = agent.run(math_question)
+        print(f"\n🎯 测试1结果: {result1}")
+    except Exception as e:
+        print(f"❌ 测试1失败: {e}")
+    
+    # 测试2:需要搜索的问题
+    print("\n🔍 测试2:信息搜索问题")
+    search_question = "Python编程语言是什么时候发布的?请告诉我具体的年份。"
+    
+    try:
+        result2 = agent.run(search_question)
+        print(f"\n🎯 测试2结果: {result2}")
+    except Exception as e:
+        print(f"❌ 测试2失败: {e}")
+    
+    # 测试3:复合问题(需要多步推理)
+    print("\n🧠 测试3:复合推理问题")
+    complex_question = "如果一个班级有30个学生,其中60%是女生,那么男生有多少人?请先计算女生人数,再计算男生人数。"
+    
+    try:
+        result3 = agent.run(complex_question)
+        print(f"\n🎯 测试3结果: {result3}")
+    except Exception as e:
+        print(f"❌ 测试3失败: {e}")
+    
+    # 查看对话历史
+    print(f"\n📝 对话历史记录: {len(agent.get_history())} 条消息")
+    
+    # 显示工具使用统计
+    print(f"\n🛠️ 可用工具数量: {len(tool_registry.tools)}")
+    print("已注册的工具:")
+    for tool_name in tool_registry.tools.keys():
+        print(f"  - {tool_name}")
+    
+    print("\n🎉 测试完成!")
+
+def test_custom_prompt():
+    """测试自定义提示词的ReActAgent"""
+    
+    print("\n" + "="*60)
+    print("测试自定义提示词的 MyReActAgent")
+    print("="*60)
+    
+    # 创建LLM和工具注册表
+    llm = HelloAgentsLLM()
+    tool_registry = ToolRegistry()
+    
+    # 注册计算器工具
+    try:
+        from hello_agents import calculate
+        tool_registry.register_tool("calculate", calculate, "数学计算工具")
+    except ImportError:
+        pass
+    
+    # 自定义提示词(更简洁的版本)
+    custom_prompt = """你是一个数学专家AI助手。
+
+可用工具:{tools}
+
+请按以下格式回应:
+Thought: [你的思考]
+Action: [tool_name[input] 或 Finish[答案]]
+
+问题:{question}
+历史:{history}
+
+开始:"""
+    
+    # 创建使用自定义提示词的Agent
+    custom_agent = MyReActAgent(
+        name="数学专家助手",
+        llm=llm,
+        tool_registry=tool_registry,
+        max_steps=3,
+        custom_prompt=custom_prompt
+    )
+    
+    # 测试数学问题
+    math_question = "计算 15 × 8 + 32 ÷ 4 的结果"
+    
+    try:
+        result = custom_agent.run(math_question)
+        print(f"\n🎯 自定义提示词测试结果: {result}")
+    except Exception as e:
+        print(f"❌ 自定义提示词测试失败: {e}")
+
+if __name__ == "__main__":
+    # 运行基础测试
+    test_react_agent()
+    
+    # 运行自定义提示词测试
+    test_custom_prompt()
+    
+    print("\n✨ 所有测试完成!")

+ 26 - 0
code/chapter7/test_reflection_agent.py

@@ -0,0 +1,26 @@
+# test_reflection_agent.py
+from dotenv import load_dotenv
+from hello_agents import HelloAgentsLLM
+from my_reflection_agent import MyReflectionAgent
+
+load_dotenv()
+llm = HelloAgentsLLM()
+
+# 使用默认通用提示词
+general_agent = MyReflectionAgent(name="我的反思助手", llm=llm)
+
+# 使用自定义代码生成提示词(类似第四章)
+code_prompts = {
+    "initial": "你是Python专家,请编写函数:{task}",
+    "reflect": "请审查代码的算法效率:\n任务:{task}\n代码:{content}",
+    "refine": "请根据反馈优化代码:\n任务:{task}\n反馈:{feedback}"
+}
+code_agent = MyReflectionAgent(
+    name="我的代码生成助手",
+    llm=llm,
+    custom_prompts=code_prompts
+)
+
+# 测试使用
+result = general_agent.run("写一篇关于人工智能发展历程的简短文章")
+print(f"最终结果: {result}")

+ 29 - 0
code/chapter7/test_simple_agent.py

@@ -0,0 +1,29 @@
+# test_simple_agent.py
+from dotenv import load_dotenv
+from hello_agents import HelloAgentsLLM
+from my_simple_agent import MySimpleAgent
+
+# 加载环境变量
+load_dotenv()
+
+# 创建LLM实例
+llm = HelloAgentsLLM()
+
+# 创建自定义SimpleAgent
+agent = MySimpleAgent(
+    name="我的简单助手",
+    llm=llm,
+    system_prompt="你是一个友好的AI助手,请用简洁明了的方式回答问题。"
+)
+
+# 测试标准调用
+response1 = agent.run("你好,请介绍一下自己")
+print(f"标准响应: {response1}")
+
+# 测试流式调用
+print("\n流式响应:")
+for chunk in agent.stream_run("请解释什么是人工智能"):
+    pass  # 内容已在stream_run中实时打印
+
+# 查看对话历史
+print(f"\n对话历史: {len(agent.get_history())} 条消息")

+ 6 - 6
docs/README.md

@@ -16,7 +16,7 @@
 
 &emsp;&emsp;如果说2024年是"百模大战"的元年,那么2025年无疑开启了"Agent元年"。技术的焦点正从训练更大的基础模型,转向构建更聪明的智能体应用。然而,当前系统性、重实践的教程却极度匮乏。为此,我们发起了 Hello-Agents 项目,希望能为社区提供一本从零开始、理论与实战并重的多智能体系统构建指南。
 
-&emsp;&emsp;Hello-Agents 是一个<strong>系统性的智能体学习教程</strong>,旨在"授人以渔"。教程将带领你穿透框架表象,从智能体的核心原理出发,深入其核心架构,理解其经典范式,并最终亲手构建起属于自己的、强大的多智能体应用。我们相信,最好的学习方式就是动手实践。希望这本书能成为你探索智能体世界的起点,能够从一名 LLM 的"使用者",蜕变为一名智能系统的"构建者"。
+&emsp;&emsp;Hello-Agents 是一个<strong>系统性的智能体学习教程</strong>,旨在"授人以渔"。教程将带领你穿透框架表象,从智能体的核心原理出发,深入其核心架构,理解其经典范式,并最终亲手构建起属于自己的多智能体应用。我们相信,最好的学习方式就是动手实践。希望这本书能成为你探索智能体世界的起点,能够从一名 LLM 的"使用者",蜕变为一名智能系统的"构建者"。
 
 ## 🌐 在线阅读
 
@@ -33,7 +33,7 @@
 - 📖 <strong>Datawhale 开源免费</strong> 完全免费学习本项目所有内容,与社区共同成长
 - 🔍 <strong>理解核心原理</strong> 深入理解智能体(Agent)的构件、原则与经典范式
 - 🏗️ <strong>亲手实现</strong> 编码复现 ReAct、Plan-and-Solve 等经典智能体架构
-- 🛠️ <strong>掌握高级技能</strong> 学习并应用 CoT、RAG、工具使用等前沿技术
+- 🛠️ <strong>掌握高级技能</strong> 学习并应用 上下文工程、RAG、工具使用等前沿技术
 - 🤝 <strong>构建多智能体</strong> 掌握多智能体协作、通信与评估的核心方法
 - 🚀 <strong>驱动真实案例</strong> 实战开发智能旅行助手、自动化研究员等综合项目"
 
@@ -52,8 +52,8 @@
 | [第六章 框架开发实践](./chapter6/第六章%20框架开发实践.md) | AutoGen、AgentScope、LangGraph 等主流框架应用 | ✅ |
 | [第七章 构建你的Agent框架](./chapter7/第七章%20构建你的Agent框架.md) | 从0开始构建智能体框架 | 🚧 |
 | <strong>第三部分:高级知识扩展</strong> |  |  |
-| [第八章 推理与规划](./chapter8/第八章%20推理与规划.md) | CoT, 逻辑推理, 搜索与规划 | 🚧 |
-| [第九章 记忆与工具](./chapter9/第九章%20记忆与工具.md) | RAG, 向量数据库, API 调用 | 🚧 |
+| [第八章 记忆与检索](./chapter9/第八章%20记忆与检索.md) | RAG, 向量数据库, 记忆系统 | 🚧 |
+| [第九章 上下文工程](./chapter8/第九章%20上下文工程.md) | 持续交互的"情境理解" | 🚧 |
 | [第十章 智能体通信协议](./chapter10/第十章%20智能体通信协议.md) | MCP, A2A, ANP 等协议解析 | 🚧 |
 | [第十一章 多智能体系统](./chapter11/第十一章%20多智能体系统.md) | 协作、通信、博弈论与 AI Society | 🚧 |
 | [第十二章 智能体性能评估](./chapter12/第十二章%20智能体性能评估.md) | 核心指标、基准测试与评估框架 | 🚧 |
@@ -87,14 +87,14 @@
 
 - <strong>第二部分:构建你的大语言模型智能体</strong>(第4章~第7章),这是你动手实践的起点。你将亲手实现 ReAct 等经典范式,体验 Coze 等低代码平台的便捷,并掌握 AutoGen 等主流框架的应用。最终,我们还会带你从零开始构建一个属于自己的智能体框架,让你兼具“用轮子”与“造轮子”的能力。
 
-- <strong>第三部分:高级知识扩展</strong>(第8章~第12章),在这一部分,你的智能体将“学会”思考与协作。我们将深入探索推理、规划、记忆与工具使用等核心技术,并学习多智能体间的通信协议。最终,你将掌握评估一个复杂多智能体系统性能的专业方法。
+- <strong>第三部分:高级知识扩展</strong>(第8章~第12章),在这一部分,你的智能体将“学会”思考与协作。我们将深入探索推理、规划、记忆与检索使用等核心技术,并学习多智能体间的通信协议。最终,你将掌握评估一个复杂多智能体系统性能的专业方法。
 
 - <strong>第四部分:综合案例进阶</strong>(第13章~第15章),这里是理论与实践的交汇点。你将把所学融会贯通,亲手打造 <strong>智能旅行助手</strong>、<strong>自动化深度研究智能体</strong>,乃至一个模拟社会动态的 <strong>赛博小镇</strong>,在真实有趣的项目中淬炼你的高级能。
 
 - <strong>第五部分:毕业设计及未来展望</strong>(第16章),在旅程的终点,你将迎来一个毕业设计,构建一个完整的、属于你自己的多智能体应用,全面检验你的学习成果。我们还将与你一同展望智能体的未来,探索激动人心的前沿方向。
 
 
-&emsp;&emsp;为了获得最佳的学习效果,我们强烈建议你 <strong>将理论与实践相结合</strong>。智能体是一个飞速发展且极度依赖实践的领域。请务必亲手运行、调试甚至修改本书提供的每一份代码。当遇到问题时,欢迎你随时在我们的开源社区中提问和交流。
+&emsp;&emsp;智能体是一个飞速发展且极度依赖实践的领域。为了获得最佳的学习效果,我们在项目的code文件夹内提供了配套的全部代码,强烈建议你 <strong>将理论与实践相结合</strong>。请务必亲手运行、调试甚至修改本书提供的每一份代码。当遇到问题时,欢迎你随时在我们的开源社区中提问和交流。
 
 &emsp;&emsp;现在,准备好进入智能体的奇妙世界了吗?让我们即刻启程!
 

+ 2 - 2
docs/_sidebar.md

@@ -13,8 +13,8 @@
   - [第七章 构建你的Agent框架](./chapter7/第七章%20构建你的Agent框架.md)
 
 - <strong>第三部分:高级知识扩展</strong>
-  - [第八章 推理与规划](./chapter8/第八章%20推理与规划.md)
-  - [第九章 记忆与工具](./chapter9/第九章%20记忆与工具.md)
+  - [第八章 记忆与检索](./chapter8/第八章%20记忆与检索.md)
+  - [第九章 上下文工程](./chapter9/第九章%20上下文工程.md)
   - [第十章 智能体通信协议](./chapter10/第十章%20智能体通信协议.md)
   - [第十一章 多智能体系统](./chapter11/第十一章%20多智能体系统.md)
   - [第十二章 智能体性能评估](./chapter12/第十二章%20智能体性能评估.md)

+ 1 - 1
docs/chapter1/第一章 初识智能体.md

@@ -222,7 +222,7 @@ Observation: 北京当前天气为晴,气温25摄氏度,微风。
 
 ### 1.3.1 准备工作
 
-为了能从Python程序中访问网络API,我们需要一个HTTP库。`requests`是Python社区中最流行、最易用的选择。请先通过以下命令安装它:
+为了能从Python程序中访问网络API,我们需要一个HTTP库。`requests`是Python社区中最流行、最易用的选择。`tavily-python`是一个强大的AI搜索API客户端,用于获取实时的网络搜索结果,可以在[官网](https://www.tavily.com/)注册后获取API。`openai`是OpenAI官方提供的Python SDK,用于调用GPT等大语言模型服务。请先通过以下命令安装它们:
 
 ```bash
 pip install requests tavily-python openai

+ 1781 - 2
docs/chapter7/第七章 构建你的Agent框架.md

@@ -1,3 +1,1782 @@
-# 第七章 构建你的Agent框架
+# 第七章 构建你的智能体框架
 
-本章内容待补充...
+在前面的章节中,我们讲解了智能体的基础知识,并体验了主流框架带来的开发便利。从本章开始,我们将进入一个更具挑战也更有价值的阶段:**从零开始,逐步构建一个智能体框架——HelloAgents**。
+
+为确保学习过程的连贯性与可复现性,HelloAgents 将以版本迭代的方式推进开发。每一章都会在前一章的基础上增加新的功能模块,并将智能体相关的知识点进行串讲与实现。最终,我们将利用这个自建框架,来高效地实现本书后续章节中的高级应用案例。
+
+## 7.1 框架整体架构设计
+
+### 7.1.1 为何需要自建Agent框架
+
+在智能体技术快速发展的今天,市面上已经存在众多成熟的Agent框架。那么,为什么我们还要从零开始构建一个新的框架呢?
+
+(1)市面框架的快速迭代与局限性
+
+智能体领域是一个快速发展的领域,随时会有新的概念产生,对于智能体的设计每个框架都有自己的定位和理解,不过智能体的核心知识点是一致的。
+
+- **过度抽象的复杂性**:许多框架为了追求通用性,引入了大量抽象层和配置选项。以LangChain为例,其链式调用机制虽然灵活,但对初学者而言学习曲线陡峭,往往需要理解大量概念才能完成简单任务。
+- **快速迭代带来的不稳定性**:商业化框架为了抢占市场,API接口变更频繁。开发者经常面临版本升级后代码无法运行的困扰,维护成本居高不下。
+- **黑盒化的实现逻辑**:许多框架将核心逻辑封装得过于严密,开发者难以理解Agent的内部工作机制,缺乏深度定制能力。遇到问题时只能依赖文档和社区支持,尤其是如果社区不够活跃,可能一个反馈意见会非常久也没有人推进,影响后续的开发效率。
+- **依赖关系的复杂性**:成熟框架往往携带大量依赖包,安装包体积庞大,在需要与别的项目代码配合的下可能出现依赖冲突问题。
+
+(2)从使用者到构建者的能力跃迁
+
+构建自己的Agent框架,实际上是一个从"使用者"向"构建者"转变的过程。这种转变带来的价值是长远的。
+
+- **深度理解Agent工作原理**:通过亲手实现每个组件,开发者能够真正理解Agent的思考过程、工具调用机制、以及各种设计模式的好坏与区别。
+- **获得完全的控制权**:自建框架意味着对每一行代码都有完全的掌控,可以根据具体需求进行精确调优,而不受第三方框架设计理念的束缚。
+- **培养系统设计能力**:框架构建过程涉及模块化设计、接口抽象、错误处理等软件工程核心技能,这些能力对开发者的长期成长具有重要价值。
+
+(3)定制化需求与深度掌握的必要性
+
+在实际应用中,不同场景对智能体的需求差异巨大,往往都需要在通用框架基础上做二次开发。
+
+- **特定领域的优化需求**:金融、医疗、教育等垂直领域往往需要针对性的提示词模板、特殊的工具集成、以及定制化的安全策略。
+- **性能与资源的精确控制**:生产环境中,对响应时间、内存占用、并发处理能力都有严格要求,通用框架的"一刀切"方案往往无法满足精细化需求。
+- **学习与教学的透明性要求**:在我们的教学场景中,学习者更期待的是清晰地看到智能体的每一步构建过程,理解不同范式的工作机制,这要求框架具有高度的可观测性和可解释性。
+
+### 7.1.2 HelloAgents框架的设计理念
+
+构建一个新的Agent框架,关键不在于功能的多少,而在于设计理念是否能真正解决现有框架的痛点。HelloAgents框架的设计围绕着一个核心问题展开:如何让学习者既能快速上手,又能深入理解Agent的工作原理?
+
+当你初次接触任何成熟的框架时,可能会被其丰富的功能所吸引,但很快就会发现一个问题:要完成一个简单的任务,往往需要理解Chain、Agent、Tool、Memory、Retriever等十几个不同的概念。每个概念都有自己的抽象层,学习曲线变得异常陡峭。这种复杂性虽然带来了强大的功能,但也成为了初学者的障碍。HelloAgents框架试图在功能完整性和学习友好性之间找到平衡点,形成了三个核心的设计理念。
+
+(1)轻量级与教学友好的平衡
+
+一个优秀的学习框架应该具备完整的可读性。HelloAgents将核心代码按照章节区分开,这是基于一个简单的原则:任何有一定编程基础的开发者都应该能够在合理的时间内完全理解框架的工作原理。在依赖管理方面,框架采用了极简主义的策略。除了OpenAI的官方SDK和几个必要的基础库外,不引入任何重型依赖。如果遇到问题时,我们可以直接定位到框架本身的代码,而不需要在复杂的依赖关系中寻找答案。
+
+(2)基于标准API的务实选择
+
+OpenAI的API已经成为了行业标准,几乎所有主流的LLM提供商都在努力兼容这套接口。HelloAgents选择在这个标准之上构建,而不是重新发明一套抽象接口。这个决定主要是出于几点动机。首先是兼容性的保证,当你掌握了HelloAgents的使用方法后,迁移到其他框架或将其集成到现有项目中时,底层的API调用逻辑是完全一致的。其次是学习成本的降低。你不需要学习新的概念模型,因为所有的操作都基于你已经熟悉的标准接口。
+
+(3)渐进式学习路径的精心设计
+
+HelloAgents提供了一条清晰的学习路径。我们将会把每一章的学习代码,保存为一个可以pip下载的历史版本,因此无需担心代码的使用成本,因为每一个核心的功能都将会是你自己编写的。这种设计让你能够按照自己的需求和节奏前进。每一步的升级都是自然而然的,不会产生概念上的跳跃或理解上的断层。值得一提的是,我们这一章的内容,也是基于前六章的内容来完善的。同样,这一章也是为后续高级知识学习部分打下框架基础。
+
+### 7.1.3 本章学习目标
+
+让我们先看看第七章的核心学习内容:
+
+```
+hello-agents/
+├── hello_agents/
+│   │
+│   ├── core/                     # 核心框架层
+│   │   ├── agent.py              # Agent基类
+│   │   ├── llm.py                # HelloAgentsLLM统一接口
+│   │   ├── message.py            # 消息系统
+│   │   ├── config.py             # 配置管理
+│   │   └── exceptions.py         # 异常体系
+│   │
+│   ├── agents/                   # Agent实现层
+│   │   ├── simple_agent.py       # SimpleAgent实现
+│   │   ├── react_agent.py        # ReActAgent实现
+│   │   ├── reflection_agent.py   # ReflectionAgent实现
+│   │   └── plan_solve_agent.py   # PlanAndSolveAgent实现
+│   │
+│   ├── tools/                    # 工具系统层
+│   │   ├── base.py               # 工具基类
+│   │   ├── registry.py           # 工具注册机制
+│   │   ├── chain.py              # 工具链管理系统
+│   │   ├── async_executor.py     # 异步工具执行器
+│   │   └── builtin/              # 内置工具集
+│   │       ├── calculator.py     # 计算工具
+│   │       └── search.py         # 搜索工具
+└──
+```
+
+在开始编写具体代码之前,我们需要先建立一个清晰的架构蓝图。HelloAgents的架构设计遵循了"分层解耦、职责单一、接口统一"的核心原则,这样既保持了代码的组织性,也便于按照章节扩展内容。
+
+**快速开始:安装HelloAgents框架**
+
+为了让读者能够快速体验本章的完整功能,我们提供了可直接安装的Python包。你可以通过以下命令安装本章对应的版本:
+
+```bash
+pip install hello-agents==0.1.1
+```
+
+本章的学习可以采用两种方式:
+
+1. **体验式学习**:直接使用`pip`安装框架,运行示例代码,快速体验各种功能
+2. **深度学习**:跟随本章内容,从零开始实现每个组件,深入理解框架的设计思想和实现细节
+
+我们建议采用"先体验,后实现"的学习路径。在本章中,我们提供了完整的测试文件,你可以重写核心函数并运行测试,以检验你的实现是否正确。这种学习方式既保证了实践性,又确保了学习效果。如果你想深入了解框架的实现细节,或者希望参与到框架的开发中来,可以访问这个[GitHub仓库](https://github.com/jjyaoao/helloagents)。
+
+
+
+## 7.2 HelloAgentsLLM扩展
+
+本节内容将在第 4.1.3 节创建的 `HelloAgentsLLM` 基础上进行迭代升级。我们将把这个基础客户端,改造为一个更具适应性的模型调用中枢。本次升级主要围绕以下三个目标展开:
+
+1. **多提供商支持**:实现对 OpenAI、ModelScope、智谱 AI 等多种主流 LLM 服务商的无缝切换,避免框架与特定供应商绑定。
+2. **本地模型集成**:引入 VLLM 和 Ollama 这两种高性能本地部署方案,作为对第 3.2.3 节中 Hugging Face Transformers 方案的生产级补充,满足数据隐私和成本控制的需求。
+3. **自动检测机制**:建立一套自动识别机制,使框架能根据环境信息智能推断所使用的 LLM 服务类型,简化用户的配置过程。
+
+### 7.2.1 支持多提供商
+
+我们之前定义的 `HelloAgentsLLM` 类,已经能够通过 `api_key` 和 `base_url` 这两个核心参数,连接任何兼容 OpenAI 接口的服务。这在理论上保证了通用性,但在实际应用中,不同的服务商在环境变量命名、默认 API 地址和推荐模型等方面都存在差异。如果每次切换服务商都需要用户手动查询并修改代码,会极大影响开发效率。为了解决这一问题,我们引入 `provider`。其改进思路是:让 `HelloAgentsLLM` 在内部处理不同服务商的配置细节,从而为用户提供一个统一、简洁的调用体验。具体的实现细节我们将在7.2.3节“自动检测机制”中详细阐述,在这里,我们首先关注如何利用这一机制来扩展框架。
+
+下面,我们将演示如何通过继承 `HelloAgentsLLM`,来增加对 ModelScope 平台的支持。我们希望读者不仅学会如何“使用”框架,更能掌握如何“扩展”框架。直接修改已安装的库源码是一种不被推荐的做法,因为它会使后续的库升级变得困难。
+
+(1)创建自定义LLM类并继承
+
+假设我们的项目目录中有一个 `my_llm.py` 文件。我们首先从 `hello_agents` 库中导入 `HelloAgentsLLM` 基类,然后创建一个名为 `MyLLM` 的新类继承它。
+
+```python
+# my_llm.py
+import os
+from typing import Optional
+from openai import OpenAI
+from hello_agents import HelloAgentsLLM
+
+class MyLLM(HelloAgentsLLM):
+    """
+    一个自定义的LLM客户端,通过继承增加了对ModelScope的支持。
+    """
+    pass # 暂时留空
+```
+
+(2)重写 `__init__` 方法以支持新供应商
+
+接下来,我们在 `MyLLM` 类中重写 `__init__` 方法。我们的目标是:当用户传入 `provider="modelscope"` 时,执行我们自定义的逻辑;否则,就调用父类 `HelloAgentsLLM` 的原始逻辑,使其能够继续支持 OpenAI 等其他内置的供应商。
+
+```python
+class MyLLM(HelloAgentsLLM):
+    def __init__(
+        self,
+        model: Optional[str] = None,
+        api_key: Optional[str] = None,
+        base_url: Optional[str] = None,
+        provider: Optional[str] = "auto",
+        **kwargs
+    ):
+        # 检查provider是否为我们想处理的'modelscope'
+        if provider == "modelscope":
+            print("正在使用自定义的 ModelScope Provider")
+            self.provider = "modelscope"
+            
+            # 解析 ModelScope 的凭证
+            self.api_key = api_key or os.getenv("MODELSCOPE_API_KEY")
+            self.base_url = base_url or "https://api-inference.modelscope.cn/v1/"
+            
+            # 验证凭证是否存在
+            if not self.api_key:
+                raise ValueError("ModelScope API key not found. Please set MODELSCOPE_API_KEY environment variable.")
+
+            # 设置默认模型和其他参数
+            self.model = model or os.getenv("LLM_MODEL_ID") or "Qwen/Qwen2.5-VL-72B-Instruct"
+            self.temperature = kwargs.get('temperature', 0.7)
+            self.max_tokens = kwargs.get('max_tokens')
+            self.timeout = kwargs.get('timeout', 60)
+            
+            # 使用获取的参数创建OpenAI客户端实例
+            self._client = OpenAI(api_key=self.api_key, base_url=self.base_url, timeout=self.timeout)
+
+        else:
+            # 如果不是 modelscope, 则完全使用父类的原始逻辑来处理
+            super().__init__(model=model, api_key=api_key, base_url=base_url, provider=provider, **kwargs)
+
+```
+
+这段代码展示了“重写”的思想:我们拦截了 `provider="modelscope"` 的情况并进行了特殊处理,对于其他所有情况,则通过 `super().__init__(...)` 交还给父类,保留了原有框架的全部功能。
+
+(3)使用自定义的 `MyLLM` 类
+
+现在,我们可以在项目的业务逻辑中,像使用原生 `HelloAgentsLLM` 一样使用我们自己的 `MyLLM` 类。
+
+首先,在 `.env` 文件中配置 ModelScope 的 API 密钥:
+
+```bash
+# .env file
+MODELSCOPE_API_KEY="your-modelscope-api-key"
+```
+
+然后,在主程序中导入并使用 `MyLLM`:
+
+```python
+# my_main.py
+from dotenv import load_dotenv
+from my_llm import MyLLM # 注意:这里导入我们自己的类
+
+# 加载环境变量
+load_dotenv()
+
+# 实例化我们重写的客户端,并指定provider
+llm = MyLLM(provider="modelscope") 
+
+# 准备消息
+messages = [{"role": "user", "content": "你好,请介绍一下你自己。"}]
+
+# 发起调用,think等方法都已从父类继承,无需重写
+response_stream = llm.think(messages)
+
+# 打印响应
+print("ModelScope Response:")
+for chunk in response_stream:
+    # chunk 已经是文本片段,可以直接使用
+    print(chunk, end="", flush=True)
+```
+
+通过以上步骤,我们就在不修改 `hello-agents` 库源码的前提下,成功为其扩展了新的功能。这种方法不仅保证了代码的整洁和可维护性,也使得未来升级 `hello-agents` 库时,我们的定制化功能不会丢失。
+
+### 7.2.2 本地模型调用
+
+在第 3.2.3 节,我们学习了如何使用 Hugging Face Transformers 库在本地直接运行开源模型。该方法非常适合入门学习和功能验证,但其底层实现在处理高并发请求时性能有限,通常不作为生产环境的首选方案。
+
+为了在本地实现高性能、生产级的模型推理服务,社区涌现出了 VLLM 和 Ollama 等优秀工具。它们通过连续批处理、PagedAttention 等技术,显著提升了模型的吞吐量和运行效率,并将模型封装为兼容 OpenAI 标准的 API 服务。这意味着,我们可以将它们无缝地集成到 `HelloAgentsLLM` 中。
+
+**VLLM**
+
+VLLM 是一个为 LLM 推理设计的高性能 Python 库。它通过 PagedAttention 等先进技术,可以实现比标准 Transformers 实现高出数倍的吞吐量。下面是在本地部署一个 VLLM 服务的完整步骤:
+
+首先,需要根据你的硬件环境(特别是 CUDA 版本)安装 VLLM。推荐遵循其(官方文档)[https://docs.vllm.ai/en/latest/getting_started/installation.html]进行安装,以避免版本不匹配问题。
+
+```python
+pip install vllm
+```
+
+安装完成后,使用以下命令即可启动一个兼容 OpenAI 的 API 服务。VLLM 会自动从 Hugging Face Hub 下载指定的模型权重(如果本地不存在)。我们依然以 Qwen1.5-0.5B-Chat 模型为例:
+
+```
+# 启动 VLLM 服务,并加载 Qwen1.5-0.5B-Chat 模型
+python -m vllm.entrypoints.openai.api_server \
+    --model Qwen/Qwen1.5-0.5B-Chat \
+    --host 0.0.0.0 \
+    --port 8000
+```
+
+服务启动后,便会在 `http://localhost:8000/v1` 地址上提供与 OpenAI 兼容的 API。
+
+**Ollama**
+
+Ollama 进一步简化了本地模型的管理和部署,它将模型下载、配置和服务启动等步骤封装到了一条命令中,非常适合快速上手。访问 Ollama [官方网站](https://ollama.com)下载并安装适用于你操作系统的客户端。
+
+安装后,打开终端,执行以下命令即可下载并运行一个模型(以 Llama 3 为例)。Ollama 会自动处理模型的下载、服务封装和硬件加速配置。
+
+```
+# 首次运行会自动下载模型,之后会直接启动服务
+ollama run llama3
+```
+
+当你在终端看到模型的交互提示时,即表示服务已经成功在后台启动。Ollama 默认会在 `http://localhost:11434/v1` 地址上暴露 OpenAI 兼容的 API 接口。
+
+**接入 `HelloAgentsLLM`**
+
+由于 VLLM 和 Ollama 都遵循了行业标准 API,将它们接入 `HelloAgentsLLM` 的过程非常简单。我们只需在实例化客户端时,将它们视为一个新的 `provider` 即可。
+
+例如,连接本地运行的 **VLLM** 服务:
+
+```python
+llm_client = HelloAgentsLLM(
+    provider="vllm",
+    model="Qwen/Qwen1.5-0.5B-Chat", # 需与服务启动时指定的模型一致
+    base_url="http://localhost:8000/v1",
+    api_key="vllm" # 本地服务通常不需要真实API Key,可填任意非空字符串
+)
+```
+
+或者,通过设置环境变量并让客户端自动检测,实现代码的零修改:
+
+```bash
+# 在 .env 文件中设置
+LLM_BASE_URL="http://localhost:8000/v1"
+LLM_API_KEY="vllm"
+
+# Python 代码中直接实例化即可
+llm_client = HelloAgentsLLM() # 将自动检测为 vllm
+```
+
+同理,连接本地的 **Ollama** 服务也一样简单:
+
+```python
+llm_client = HelloAgentsLLM(
+    provider="ollama",
+    model="llama3", # 需与 `ollama run` 指定的模型一致
+    base_url="http://localhost:11434/v1",
+    api_key="ollama" # 本地服务同样不需要真实 Key
+)
+```
+
+通过这种统一的设计,我们的智能体核心代码无需任何修改,就可以在云端 API 和本地模型之间自由切换。这为后续应用的开发、部署、成本控制以及保护数据隐私提供了极大的灵活性。
+
+### 7.2.3 自动检测机制
+
+为了尽可能减少用户的配置负担并遵循“约定优于配置”的原则,`HelloAgentsLLM` 内部设计了两个核心辅助方法:`_auto_detect_provider` 和 `_resolve_credentials`。它们协同工作,`_auto_detect_provider` 负责根据环境信息推断服务商,而 `_resolve_credentials` 则根据推断结果完成具体的参数配置。
+
+`_auto_detect_provider` 方法负责根据环境信息,按照下述优先级顺序,尝试自动推断服务商:
+
+1. **最高优先级:检查特定服务商的环境变量** 这是最直接、最可靠的判断依据。框架会依次检查 `MODELSCOPE_API_KEY`, `OPENAI_API_KEY`, `ZHIPU_API_KEY` 等环境变量是否存在。一旦发现任何一个,就会立即确定对应的服务商。
+
+2. **次高优先级:根据 `base_url` 进行判断** 如果用户没有设置特定服务商的密钥,但设置了通用的 `LLM_BASE_URL`,框架会转而解析这个 URL。
+
+   - **域名匹配**:通过检查 URL 中是否包含 `"api-inference.modelscope.cn"`, `"api.openai.com"` 等特征字符串来识别云服务商。
+
+   - **端口匹配**:通过检查 URL 中是否包含 `:11434` (Ollama), `:8000` (VLLM) 等本地服务的标准端口来识别本地部署方案。
+
+3. **辅助判断:分析 API 密钥的格式** 在某些情况下,如果上述两种方式都无法确定,框架会尝试分析通用环境变量 `LLM_API_KEY` 的格式。例如,某些服务商的 API 密钥有固定的前缀或独特的编码格式。不过,由于这种方式可能存在模糊性(例如多个服务商的密钥格式相似),因此它的优先级较低,仅作为辅助手段。
+
+其部分关键代码如下:
+
+```python
+def _auto_detect_provider(self, api_key: Optional[str], base_url: Optional[str]) -> str:
+    """
+    自动检测LLM提供商
+    """
+    # 1. 检查特定提供商的环境变量 (最高优先级)
+    if os.getenv("MODELSCOPE_API_KEY"): return "modelscope"
+    if os.getenv("OPENAI_API_KEY"): return "openai"
+    if os.getenv("ZHIPU_API_KEY"): return "zhipu"
+    # ... 其他服务商的环境变量检查
+
+    # 获取通用的环境变量
+    actual_api_key = api_key or os.getenv("LLM_API_KEY")
+    actual_base_url = base_url or os.getenv("LLM_BASE_URL")
+
+    # 2. 根据 base_url 判断
+    if actual_base_url:
+        base_url_lower = actual_base_url.lower()
+        if "api-inference.modelscope.cn" in base_url_lower: return "modelscope"
+        if "open.bigmodel.cn" in base_url_lower: return "zhipu"
+        if "localhost" in base_url_lower or "127.0.0.1" in base_url_lower:
+            if ":11434" in base_url_lower: return "ollama"
+            if ":8000" in base_url_lower: return "vllm"
+            return "local" # 其他本地端口
+
+    # 3. 根据 API 密钥格式辅助判断
+    if actual_api_key:
+        if actual_api_key.startswith("ms-"): return "modelscope"
+        # ... 其他密钥格式判断
+
+    # 4. 默认返回 'auto',使用通用配置
+    return "auto"
+```
+
+一旦 `provider` 被确定(无论是用户指定还是自动检测),`_resolve_credentials` 方法便会接手处理服务商的差异化配置。它会根据 `provider` 的值,去主动查找对应的环境变量,并为其设置默认的 `base_url`。其部分关键实现如下:
+
+```python
+def _resolve_credentials(self, api_key: Optional[str], base_url: Optional[str]) -> tuple[str, str]:
+    """根据provider解析API密钥和base_url"""
+    if self.provider == "openai":
+        resolved_api_key = api_key or os.getenv("OPENAI_API_KEY") or os.getenv("LLM_API_KEY")
+        resolved_base_url = base_url or os.getenv("LLM_BASE_URL") or "https://api.openai.com/v1"
+        return resolved_api_key, resolved_base_url
+
+    elif self.provider == "modelscope":
+        resolved_api_key = api_key or os.getenv("MODELSCOPE_API_KEY") or os.getenv("LLM_API_KEY")
+        resolved_base_url = base_url or os.getenv("LLM_BASE_URL") or "https://api-inference.modelscope.cn/v1/"
+        return resolved_api_key, resolved_base_url
+    
+    # ... 其他服务商的逻辑
+```
+
+让我们通过一个简单的例子来感受自动检测带来的便利。假设一个用户想要使用本地的 Ollama 服务,他只需在 `.env` 文件中进行如下配置:
+
+```bash
+LLM_BASE_URL="http://localhost:11434/v1"
+LLM_MODEL_ID="llama3"
+```
+
+他完全不需要配置 `LLM_API_KEY` 或在代码中指定 `provider`。然后,在 Python 代码中,他只需简单地实例化 `HelloAgentsLLM` 即可:
+
+```python
+from dotenv import load_dotenv
+from hello_agents import HelloAgentsLLM
+
+load_dotenv()
+
+# 无需传入 provider,框架会自动检测
+llm = HelloAgentsLLM() 
+# 框架内部日志会显示检测到 provider 为 'ollama'
+
+# 后续调用方式完全不变
+messages = [{"role": "user", "content": "你好!"}]
+for chunk in llm.think(messages):
+    print(chunk, end="")
+
+```
+
+在这个过程中,`_auto_detect_provider` 方法通过解析 `LLM_BASE_URL` 中的 `"localhost"` 和 `:11434`,成功地将 `provider` 推断为 `"ollama"`。随后,`_resolve_credentials` 方法会为 Ollama 设置正确的默认参数。
+
+相比于4.1.3节的基础实现,现在的HelloAgentsLLM具有以下显著优势:
+
+<div align="center">
+  <p>表 7.1 HelloAgentLLM不同版本特性对比</p>
+  <img src="https://raw.githubusercontent.com/datawhalechina/Hello-Agents/main/docs/images/7-figures/table-01.png" alt="" width="90%"/>
+</div>
+
+如上表7.1所示,这种演进体现了框架设计的重要原则:**从简单开始,逐步完善**。我们在保持接口简洁的同时,增强了功能的完整性。
+
+
+
+## 7.3 框架接口实现
+
+在上节中,我们构建了 `HelloAgentsLLM` 这一核心组件,解决了与大语言模型通信的关键问题。不过它还需要一系列配套的接口和组件来处理数据流、管理配置、应对异常,并为上层应用的构建提供一个清晰、统一的结构。本节将讲述以下三个核心文件:
+
+- **`message.py`**: 定义了框架内统一的消息格式,确保了智能体与模型之间信息传递的标准化。
+- **`config.py`**: 提供了一个中心化的配置管理方案,使框架的行为易于调整和扩展。
+- **`agent.py`**: 定义了所有智能体的抽象基类(`Agent`),为后续实现不同类型的智能体提供了统一的接口和规范。
+
+### 7.3.1 Message 类
+
+在智能体与大语言模型的交互中,对话历史是至关重要的上下文。为了规范地管理这些信息,我们设计了一个简易 `Message` 类。在后续上下文工程章节中,会对其进行扩展。
+
+```python
+"""消息系统"""
+from typing import Optional, Dict, Any, Literal
+from datetime import datetime
+from pydantic import BaseModel
+
+# 定义消息角色的类型,限制其取值
+MessageRole = Literal["user", "assistant", "system", "tool"]
+
+class Message(BaseModel):
+    """消息类"""
+    
+    content: str
+    role: MessageRole
+    timestamp: datetime = None
+    metadata: Optional[Dict[str, Any]] = None
+    
+    def __init__(self, content: str, role: MessageRole, **kwargs):
+        super().__init__(
+            content=content,
+            role=role,
+            timestamp=kwargs.get('timestamp', datetime.now()),
+            metadata=kwargs.get('metadata', {})
+        )
+    
+    def to_dict(self) -> Dict[str, Any]:
+        """转换为字典格式(OpenAI API格式)"""
+        return {
+            "role": self.role,
+            "content": self.content
+        }
+    
+    def __str__(self) -> str:
+        return f"[{self.role}] {self.content}"
+```
+
+该类的设计有几个关键点。首先,我们通过 `typing.Literal` 将 `role` 字段的取值严格限制为 `"user"`, `"assistant"`, `"system"`, `"tool"` 四种,这直接对应 OpenAI API 的规范,保证了类型安全。除了 `content` 和 `role` 这两个核心字段外,我们还增加了 `timestamp` 和 `metadata`,为日志记录和未来功能扩展预留了空间。最后,`to_dict()` 方法是其核心功能之一,负责将内部使用的 `Message` 对象转换为与 OpenAI API 兼容的字典格式,体现了“对内丰富,对外兼容”的设计原则。
+
+### 7.3.2 Config 类
+
+`Config` 类的职责是将代码中硬编码配置参数集中起来,并支持从环境变量中读取。
+
+```python
+"""配置管理"""
+import os
+from typing import Optional, Dict, Any
+from pydantic import BaseModel
+
+class Config(BaseModel):
+    """HelloAgents配置类"""
+    
+    # LLM配置
+    default_model: str = "gpt-3.5-turbo"
+    default_provider: str = "openai"
+    temperature: float = 0.7
+    max_tokens: Optional[int] = None
+    
+    # 系统配置
+    debug: bool = False
+    log_level: str = "INFO"
+    
+    # 其他配置
+    max_history_length: int = 100
+    
+    @classmethod
+    def from_env(cls) -> "Config":
+        """从环境变量创建配置"""
+        return cls(
+            debug=os.getenv("DEBUG", "false").lower() == "true",
+            log_level=os.getenv("LOG_LEVEL", "INFO"),
+            temperature=float(os.getenv("TEMPERATURE", "0.7")),
+            max_tokens=int(os.getenv("MAX_TOKENS")) if os.getenv("MAX_TOKENS") else None,
+        )
+    
+    def to_dict(self) -> Dict[str, Any]:
+        """转换为字典"""
+        return self.dict()
+```
+
+首先,我们将配置项按逻辑划分为 `LLM配置`、`系统配置` 等,使结构一目了然。其次,每个配置项都设有合理的默认值,保证了框架在零配置下也能工作。最核心的是 `from_env()` 类方法,它允许用户通过设置环境变量来覆盖默认配置,无需修改代码,这在部署到不同环境时尤其有用。
+
+### 7.3.3 Agent 抽象基类
+
+`Agent` 类是整个框架的顶层抽象。它定义了一个智能体应该具备的通用行为和属性,但并不关心具体的实现方式。我们通过 Python 的 `abc` (Abstract Base Classes) 模块来实现它,这强制所有具体的智能体实现(如后续章节的 `SimpleAgent`, `ReActAgent` 等)都必须遵循同一个“接口”。
+
+```python
+"""Agent基类"""
+from abc import ABC, abstractmethod
+from typing import Optional, Any
+from .message import Message
+from .llm import HelloAgentsLLM
+from .config import Config
+
+class Agent(ABC):
+    """Agent基类"""
+    
+    def __init__(
+        self,
+        name: str,
+        llm: HelloAgentsLLM,
+        system_prompt: Optional[str] = None,
+        config: Optional[Config] = None
+    ):
+        self.name = name
+        self.llm = llm
+        self.system_prompt = system_prompt
+        self.config = config or Config()
+        self._history: list[Message] = []
+    
+    @abstractmethod
+    def run(self, input_text: str, **kwargs) -> str:
+        """运行Agent"""
+        pass
+    
+    def add_message(self, message: Message):
+        """添加消息到历史记录"""
+        self._history.append(message)
+    
+    def clear_history(self):
+        """清空历史记录"""
+        self._history.clear()
+    
+    def get_history(self) -> list[Message]:
+        """获取历史记录"""
+        return self._history.copy()
+    
+    def __str__(self) -> str:
+        return f"Agent(name={self.name}, provider={self.llm.provider})"
+```
+
+该类的设计体现了面向对象中的抽象原则。首先,它通过继承 `ABC` 被定义为一个不能直接实例化的抽象类。其构造函数 `__init__` 清晰地定义了 Agent 的核心依赖:名称、LLM 实例、系统提示词和配置。最重要的部分是使用 `@abstractmethod` 装饰的 `run` 方法,它强制所有子类必须实现此方法,从而保证了所有智能体都有统一的执行入口。此外,基类还提供了通用的历史记录管理方法,这些方法与 `Message` 类协同工作,体现了组件间的联系。
+
+至此,我们已经完成了 `HelloAgents` 框架核心基础组件的设计与实现。
+
+## 7.4 Agent范式的框架化实现
+
+本节内容将在第四章构建的三种经典Agent范式(ReAct、Plan-and-Solve、Reflection)基础上进行框架化重构,并新增SimpleAgent作为基础对话范式。我们将把这些独立的Agent实现,改造为基于统一架构的框架组件。本次重构主要围绕以下三个核心目标展开:
+
+1. **提示词工程的系统性提升**:对第四章中的提示词进行深度优化,从特定任务导向转向通用化设计,同时增强格式约束和角色定义。
+2. **接口与格式的标准化统一**:建立统一的Agent基类和标准化的运行接口,所有Agent都遵循相同的初始化参数、方法签名和历史管理机制。
+3. **高度可配置的自定义能力**:支持用户自定义提示词模板、配置参数和执行策略。
+
+### 7.4.1 SimpleAgent
+
+SimpleAgent是最基础的Agent实现,它展示了如何在框架基础上构建一个完整的对话智能体。我们将通过继承框架基类来重写SimpleAgent。首先,在你的项目目录中创建一个`my_simple_agent.py`文件:
+
+```python
+# my_simple_agent.py
+from typing import Optional
+from hello_agents import SimpleAgent, HelloAgentsLLM, Config, Message
+
+class MySimpleAgent(SimpleAgent):
+    """
+    重写的简单对话Agent
+    展示如何基于框架基类构建自定义Agent
+    """
+
+    def __init__(
+        self,
+        name: str,
+        llm: HelloAgentsLLM,
+        system_prompt: Optional[str] = None,
+        config: Optional[Config] = None
+    ):
+        super().__init__(name, llm, system_prompt, config)
+        print(f"✅ {name} 初始化完成,基于框架基类构建")
+```
+
+接下来,我们需要重写Agent基类的抽象方法`run`:
+
+```python
+# 继续在 my_simple_agent.py 中添加
+class MySimpleAgent(Agent):
+    # ... 前面的 __init__ 方法
+
+    def run(self, input_text: str, **kwargs) -> str:
+        """
+        重写的运行方法 - 实现简单对话逻辑
+        """
+        print(f"🤖 {self.name} 正在处理: {input_text}")
+
+        # 构建消息列表
+        messages = []
+
+        # 添加系统消息
+        if self.system_prompt:
+            messages.append({"role": "system", "content": self.system_prompt})
+
+        # 添加历史消息
+        for msg in self._history:
+            messages.append({"role": msg.role, "content": msg.content})
+
+        # 添加当前用户消息
+        messages.append({"role": "user", "content": input_text})
+
+        # 调用LLM
+        response = self.llm.invoke(messages, **kwargs)
+
+        # 保存到历史记录
+        self.add_message(Message(input_text, "user"))
+        self.add_message(Message(response, "assistant"))
+
+        print(f"✅ {self.name} 响应完成")
+        return response
+```
+
+我们还可以为自定义Agent添加流式响应功能:
+
+```python
+# 继续在 my_simple_agent.py 中添加
+class MySimpleAgent(Agent):
+    # ... 前面的方法
+
+    def stream_run(self, input_text: str, **kwargs):
+        """
+        自定义的流式运行方法
+        """
+        print(f"🌊 {self.name} 开始流式处理: {input_text}")
+
+        messages = []
+
+        if self.system_prompt:
+            messages.append({"role": "system", "content": self.system_prompt})
+
+        for msg in self._history:
+            messages.append({"role": msg.role, "content": msg.content})
+
+        messages.append({"role": "user", "content": input_text})
+
+        # 流式调用LLM
+        full_response = ""
+        print("📝 实时响应: ", end="")
+        for chunk in self.llm.stream_invoke(messages, **kwargs):
+            full_response += chunk
+            print(chunk, end="", flush=True)
+            yield chunk
+
+        print()  # 换行
+
+        # 保存完整对话到历史记录
+        self.add_message(Message(input_text, "user"))
+        self.add_message(Message(full_response, "assistant"))
+        print(f"✅ {self.name} 流式响应完成")
+```
+
+创建一个测试文件`test_simple_agent.py`:
+
+```python
+# test_simple_agent.py
+from dotenv import load_dotenv
+from hello_agents import HelloAgentsLLM
+from my_simple_agent import MySimpleAgent
+
+# 加载环境变量
+load_dotenv()
+
+# 创建LLM实例
+llm = HelloAgentsLLM()
+
+# 创建自定义SimpleAgent
+agent = MySimpleAgent(
+    name="我的简单助手",
+    llm=llm,
+    system_prompt="你是一个友好的AI助手,请用简洁明了的方式回答问题。"
+)
+
+# 测试标准调用
+response1 = agent.run("你好,请介绍一下自己")
+print(f"标准响应: {response1}")
+
+# 测试流式调用
+print("\n流式响应:")
+for chunk in agent.stream_run("请解释什么是人工智能"):
+    pass  # 内容已在stream_run中实时打印
+
+# 查看对话历史
+print(f"\n对话历史: {len(agent.get_history())} 条消息")
+```
+
+在本节中,我们通过继承 `Agent` 基类,成功构建了一个功能完备且遵循框架规范的基础对话智能体 `MySimpleAgent`,并为其添加了流式响应能力。
+
+### 7.4.2 ReActAgent
+
+框架化的 ReActAgent 在保持核心逻辑不变的同时,提升了代码的组织性和可维护性,主要是通过提示词优化和与框架工具系统的集成。
+
+(1)提示词模板的改进
+
+保持了原有的格式要求,强调"每次只能执行一个步骤",避免混乱,并明确了两种Action的使用场景。
+
+```python
+MY_REACT_PROMPT = """你是一个具备推理和行动能力的AI助手。你可以通过思考分析问题,然后调用合适的工具来获取信息,最终给出准确的答案。
+
+## 可用工具
+{tools}
+
+## 工作流程
+请严格按照以下格式进行回应,每次只能执行一个步骤:
+
+**Thought:** 分析当前问题,思考需要什么信息或采取什么行动。
+**Action:** 选择一个行动,格式必须是以下之一:
+- `{{tool_name}}[{{tool_input}}]` - 调用指定工具
+- `Finish[最终答案]` - 当你有足够信息给出最终答案时
+
+## 重要提醒
+1. 每次回应必须包含Thought和Action两部分
+2. 工具调用的格式必须严格遵循:工具名[参数]
+3. 只有当你确信有足够信息回答问题时,才使用Finish
+4. 如果工具返回的信息不够,继续使用其他工具或相同工具的不同参数
+
+## 当前任务
+**Question:** {question}
+
+## 执行历史
+{history}
+
+现在开始你的推理和行动:
+"""
+```
+
+(2)重写ReActAgent的完整实现
+
+创建`my_react_agent.py`文件来重写ReActAgent:
+
+```python
+# my_react_agent.py
+import re
+from typing import Optional, List, Tuple
+from hello_agents import ReActAgent, HelloAgentsLLM, Config, Message, ToolRegistry
+
+class MyReActAgent(ReActAgent):
+    """
+    重写的ReAct Agent - 推理与行动结合的智能体
+    """
+
+    def __init__(
+        self,
+        name: str,
+        llm: HelloAgentsLLM,
+        tool_registry: ToolRegistry,
+        system_prompt: Optional[str] = None,
+        config: Optional[Config] = None,
+        max_steps: int = 5,
+        custom_prompt: Optional[str] = None
+    ):
+        super().__init__(name, llm, system_prompt, config)
+        self.tool_registry = tool_registry
+        self.max_steps = max_steps
+        self.current_history: List[str] = []
+        self.prompt_template = custom_prompt if custom_prompt else MY_REACT_PROMPT
+        print(f"✅ {name} 初始化完成,最大步数: {max_steps}")
+```
+
+其初始化参数的含义如下:
+
+- `name`: Agent的名称。
+- `llm`: `HelloAgentsLLM`的实例,负责与大语言模型通信。
+- `tool_registry`: `ToolRegistry`的实例,用于管理和执行Agent可用的工具。
+- `system_prompt`: 系统提示词,用于设定Agent的角色和行为准则。
+- `config`: 配置对象,用于传递框架级的设置。
+- `max_steps`: ReAct循环的最大执行步数,防止无限循环。
+- `custom_prompt`: 自定义的提示词模板,用于替换默认的ReAct提示词。
+
+框架化的ReActAgent将执行流程分解为清晰的步骤:
+
+```python
+def run(self, input_text: str, **kwargs) -> str:
+    """运行ReAct Agent"""
+    self.current_history = []
+    current_step = 0
+
+    print(f"\n🤖 {self.name} 开始处理问题: {input_text}")
+
+    while current_step < self.max_steps:
+        current_step += 1
+        print(f"\n--- 第 {current_step} 步 ---")
+
+        # 1. 构建提示词
+        tools_desc = self.tool_registry.get_tools_description()
+        history_str = "\n".join(self.current_history)
+        prompt = self.prompt_template.format(
+            tools=tools_desc,
+            question=input_text,
+            history=history_str
+        )
+
+        # 2. 调用LLM
+        messages = [{"role": "user", "content": prompt}]
+        response_text = self.llm.invoke(messages, **kwargs)
+
+        # 3. 解析输出
+        thought, action = self._parse_output(response_text)
+
+        # 4. 检查完成条件
+        if action and action.startswith("Finish"):
+            final_answer = self._parse_action_input(action)
+            self._save_to_history(input_text, final_answer)
+            return final_answer
+
+        # 5. 执行工具调用
+        if action:
+            tool_name, tool_input = self._parse_action(action)
+            observation = self.tool_registry.execute_tool(tool_name, tool_input)
+            self.current_history.append(f"Action: {action}")
+            self.current_history.append(f"Observation: {observation}")
+
+    # 达到最大步数
+    final_answer = "抱歉,我无法在限定步数内完成这个任务。"
+    self._save_to_history(input_text, final_answer)
+    return final_answer
+```
+
+通过以上重构,我们将 ReAct 范式成功地集成到了框架中。核心改进在于利用了统一的 `ToolRegistry` 接口,并通过一个可配置、格式更严谨的提示词模板,提升了智能体执行思考-行动循环的稳定性。对于ReAct的测试案例,由于需要调用工具,所以统一放在文末提供测试代码。
+
+### 7.4.3 ReflectionAgent
+
+由于这几类Agent已经在第四章实现过核心逻辑,所以这里只给出对应的Prompt。与第四章专门针对代码生成的提示词不同,框架化的版本采用了通用化设计,使其适用于文本生成、分析、创作等多种场景,并通过`custom_prompts`参数支持用户深度定制。
+
+```python
+DEFAULT_PROMPTS = {
+    "initial": """
+请根据以下要求完成任务:
+
+任务: {task}
+
+请提供一个完整、准确的回答。
+""",
+    "reflect": """
+请仔细审查以下回答,并找出可能的问题或改进空间:
+
+# 原始任务:
+{task}
+
+# 当前回答:
+{content}
+
+请分析这个回答的质量,指出不足之处,并提出具体的改进建议。
+如果回答已经很好,请回答"无需改进"。
+""",
+    "refine": """
+请根据反馈意见改进你的回答:
+
+# 原始任务:
+{task}
+
+# 上一轮回答:
+{last_attempt}
+
+# 反馈意见:
+{feedback}
+
+请提供一个改进后的回答。
+"""
+}
+```
+
+你可以尝试根据第四章的代码,以及上文ReAct的实现,构建出自己的MyReflectionAgent。下面提供一个测试代码供验证想法。
+
+```python
+# test_reflection_agent.py
+from dotenv import load_dotenv
+from hello_agents import HelloAgentsLLM
+from my_reflection_agent import MyReflectionAgent
+
+load_dotenv()
+llm = HelloAgentsLLM()
+
+# 使用默认通用提示词
+general_agent = MyReflectionAgent(name="我的反思助手", llm=llm)
+
+# 使用自定义代码生成提示词(类似第四章)
+code_prompts = {
+    "initial": "你是Python专家,请编写函数:{task}",
+    "reflect": "请审查代码的算法效率:\n任务:{task}\n代码:{content}",
+    "refine": "请根据反馈优化代码:\n任务:{task}\n反馈:{feedback}"
+}
+code_agent = MyReflectionAgent(
+    name="我的代码生成助手",
+    llm=llm,
+    custom_prompts=code_prompts
+)
+
+# 测试使用
+result = general_agent.run("写一篇关于人工智能发展历程的简短文章")
+print(f"最终结果: {result}")
+```
+
+### 7.4.4 PlanAndSolveAgent
+
+与第四章自由文本的计划输出不同,框架化版本强制要求Planner以Python列表的格式输出计划,并提供了完整的异常处理机制,确保了后续步骤能够稳定执行。框架化的Plan-and-Solve提示词:
+
+````bash
+# 默认规划器提示词模板
+DEFAULT_PLANNER_PROMPT = """
+你是一个顶级的AI规划专家。你的任务是将用户提出的复杂问题分解成一个由多个简单步骤组成的行动计划。
+请确保计划中的每个步骤都是一个独立的、可执行的子任务,并且严格按照逻辑顺序排列。
+你的输出必须是一个Python列表,其中每个元素都是一个描述子任务的字符串。
+
+问题: {question}
+
+请严格按照以下格式输出你的计划:
+```python
+["步骤1", "步骤2", "步骤3", ...]
+```
+"""
+
+# 默认执行器提示词模板
+DEFAULT_EXECUTOR_PROMPT = """
+你是一位顶级的AI执行专家。你的任务是严格按照给定的计划,一步步地解决问题。
+你将收到原始问题、完整的计划、以及到目前为止已经完成的步骤和结果。
+请你专注于解决"当前步骤",并仅输出该步骤的最终答案,不要输出任何额外的解释或对话。
+
+# 原始问题:
+{question}
+
+# 完整计划:
+{plan}
+
+# 历史步骤与结果:
+{history}
+
+# 当前步骤:
+{current_step}
+
+请仅输出针对"当前步骤"的回答:
+"""
+````
+
+这一节仍然给出一个综合测试文件`test_plan_solve_agent.py`,可以自行设计实现。
+
+```python
+# test_plan_solve_agent.py
+from dotenv import load_dotenv
+from hello_agents.core.llm import HelloAgentsLLM
+from my_plan_solve_agent import MyPlanAndSolveAgent
+
+# 加载环境变量
+load_dotenv()
+
+# 创建LLM实例
+llm = HelloAgentsLLM()
+
+# 创建自定义PlanAndSolveAgent
+agent = MyPlanAndSolveAgent(
+    name="我的规划执行助手",
+    llm=llm
+)
+
+# 测试复杂问题
+question = "一个水果店周一卖出了15个苹果。周二卖出的苹果数量是周一的两倍。周三卖出的数量比周二少了5个。请问这三天总共卖出了多少个苹果?"
+
+result = agent.run(question)
+print(f"\n最终结果: {result}")
+
+# 查看对话历史
+print(f"对话历史: {len(agent.get_history())} 条消息")
+```
+
+在最后可以补充一款新的提示词,可以尝试实现`custom_prompt`载入自定义提示词。
+
+```python
+# 创建专门用于数学问题的自定义提示词
+math_prompts = {
+    "planner": """
+你是数学问题规划专家。请将数学问题分解为计算步骤:
+
+问题: {question}
+
+输出格式:
+python
+["计算步骤1", "计算步骤2", "求总和"]
+
+""",
+    "executor": """
+你是数学计算专家。请计算当前步骤:
+
+问题: {question}
+计划: {plan}
+历史: {history}
+当前步骤: {current_step}
+
+请只输出数值结果:
+"""
+}
+
+# 使用自定义提示词创建数学专用Agent
+math_agent = MyPlanAndSolveAgent(
+    name="数学计算助手",
+    llm=llm,
+    custom_prompts=math_prompts
+)
+
+# 测试数学问题
+math_result = math_agent.run(question)
+print(f"数学专用Agent结果: {math_result}")
+```
+
+如表7.2所示,通过这种框架化的重构,我们不仅保持了第四章中各种Agent范式的核心功能,还大幅提升了代码的组织性、可维护性和扩展性。所有Agent现在都共享统一的基础架构,同时保持了各自的特色和优势。
+
+<div align="center">
+  <p>表 7.2 Agent不同章节实现对比</p>
+  <img src="https://raw.githubusercontent.com/datawhalechina/Hello-Agents/main/docs/images/7-figures/table-02.png" alt="" width="90%"/>
+</div>
+
+## 7.5 工具系统
+
+本节内容将在前面构建的Agent基础架构上,深入探讨工具系统的设计与实现。我们将从基础设施建设开始,逐步深入到自定义开发设计。本节的学习目标围绕以下三个核心方面展开:
+
+1. **统一的工具抽象与管理**:建立标准化的Tool基类和ToolRegistry注册机制,为工具的开发、注册、发现和执行提供统一的基础设施。
+
+2. **实战驱动的工具开发**:以数学计算工具为案例,展示如何设计和实现自定义工具,让读者掌握工具开发的完整流程。
+
+3. **高级整合与优化策略**:通过多源搜索工具的设计,展示如何整合多个外部服务,实现智能后端选择、结果合并和容错处理,体现工具系统在复杂场景下的设计思维。
+
+### 7.5.1 工具基类与注册机制设计
+
+在构建可扩展的工具系统时,我们需要首先建立一套标准化的基础设施。这套基础设施包括Tool基类、ToolRegistry注册表,以及工具管理机制。
+
+(1)Tool基类的抽象设计
+
+Tool基类是整个工具系统的核心抽象,它定义了所有工具必须遵循的接口规范:
+
+````python
+class Tool(ABC):
+    """工具基类"""
+
+    def __init__(self, name: str, description: str):
+        self.name = name
+        self.description = description
+
+    @abstractmethod
+    def run(self, parameters: Dict[str, Any]) -> str:
+        """执行工具"""
+        pass
+
+    @abstractmethod
+    def get_parameters(self) -> List[ToolParameter]:
+        """获取工具参数定义"""
+        pass
+````
+这个设计体现了面向对象设计的核心思想:通过统一的`run`方法接口,所有工具都能以一致的方式执行,接受字典参数并返回字符串结果,确保了框架的一致性。同时,工具具备了自描述能力,通过`get_parameters`方法能够清晰地告诉调用者自己需要什么参数,这种内省机制为自动化文档生成和参数验证提供了基础。而name和description等元数据的设计,则让工具系统具备了良好的可发现性和可理解性。
+
+(2)ToolParameter参数定义系统
+
+为了支持复杂的参数验证和文档生成,我们设计了ToolParameter类:
+
+````python
+class ToolParameter(BaseModel):
+    """工具参数定义"""
+    name: str
+    type: str
+    description: str
+    required: bool = True
+    default: Any = None
+````
+这种设计让工具能够精确描述自己的参数需求,支持类型检查、默认值设置和文档自动生成。
+
+(3)ToolRegistry注册表的实现
+
+ToolRegistry是工具系统的管理中枢,它提供了工具的注册、发现、执行等核心功能,在这一节我们主要用到以下功能:
+
+````python
+class ToolRegistry:
+    """HelloAgents工具注册表"""
+
+    def __init__(self):
+        self._tools: dict[str, Tool] = {}
+        self._functions: dict[str, dict[str, Any]] = {}
+
+    def register_tool(self, tool: Tool):
+        """注册Tool对象"""
+        if tool.name in self._tools:
+            print(f"⚠️ 警告:工具 '{tool.name}' 已存在,将被覆盖。")
+        self._tools[tool.name] = tool
+        print(f"✅ 工具 '{tool.name}' 已注册。")
+        
+    def register_function(self, name: str, description: str, func: Callable[[str], str]):
+        """
+        直接注册函数作为工具(简便方式)
+
+        Args:
+            name: 工具名称
+            description: 工具描述
+            func: 工具函数,接受字符串参数,返回字符串结果
+        """
+        if name in self._functions:
+            print(f"⚠️ 警告:工具 '{name}' 已存在,将被覆盖。")
+
+        self._functions[name] = {
+            "description": description,
+            "func": func
+        }
+        print(f"✅ 工具 '{name}' 已注册。")
+````
+ToolRegistry支持两种注册方式:
+
+1. **Tool对象注册**:适合复杂工具,支持完整的参数定义和验证
+2. **函数直接注册**:适合简单工具,快速集成现有函数
+
+(4)工具发现与管理机制
+
+注册表提供了丰富的工具管理功能:
+
+````python
+def get_tools_description(self) -> str:
+    """获取所有可用工具的格式化描述字符串"""
+    descriptions = []
+
+    # Tool对象描述
+    for tool in self._tools.values():
+        descriptions.append(f"- {tool.name}: {tool.description}")
+
+    # 函数工具描述
+    for name, info in self._functions.items():
+        descriptions.append(f"- {name}: {info['description']}")
+
+    return "\n".join(descriptions) if descriptions else "暂无可用工具"
+````
+这个方法生成的描述字符串可以直接用于构建Agent的提示词,让Agent了解可用的工具。
+
+### 7.5.2 自定义工具开发
+
+有了基础设施后,我们来看看如何开发一个完整的自定义工具。数学计算工具是一个很好的例子,因为它简单直观,最直接的方式是使用ToolRegistry的函数注册功能。
+
+让我们创建一个自定义的数学计算工具。首先,在你的项目目录中创建`my_calculator_tool.py`:
+
+```python
+# my_calculator_tool.py
+import ast
+import operator
+import math
+from hello_agents import ToolRegistry
+
+def my_calculate(expression: str) -> str:
+    """简单的数学计算函数"""
+    if not expression.strip():
+        return "计算表达式不能为空"
+
+    # 支持的基本运算
+    operators = {
+        ast.Add: operator.add,      # +
+        ast.Sub: operator.sub,      # -
+        ast.Mult: operator.mul,     # *
+        ast.Div: operator.truediv,  # /
+    }
+
+    # 支持的基本函数
+    functions = {
+        'sqrt': math.sqrt,
+        'pi': math.pi,
+    }
+
+    try:
+        node = ast.parse(expression, mode='eval')
+        result = _eval_node(node.body, operators, functions)
+        return str(result)
+    except:
+        return "计算失败,请检查表达式格式"
+
+def _eval_node(node, operators, functions):
+    """简化的表达式求值"""
+    if isinstance(node, ast.Constant):
+        return node.value
+    elif isinstance(node, ast.BinOp):
+        left = _eval_node(node.left, operators, functions)
+        right = _eval_node(node.right, operators, functions)
+        op = operators.get(type(node.op))
+        return op(left, right)
+    elif isinstance(node, ast.Call):
+        func_name = node.func.id
+        if func_name in functions:
+            args = [_eval_node(arg, operators, functions) for arg in node.args]
+            return functions[func_name](*args)
+    elif isinstance(node, ast.Name):
+        if node.id in functions:
+            return functions[node.id]
+
+def create_calculator_registry():
+    """创建包含计算器的工具注册表"""
+    registry = ToolRegistry()
+
+    # 注册计算器函数
+    registry.register_function(
+        name="my_calculator",
+        description="简单的数学计算工具,支持基本运算(+,-,*,/)和sqrt函数",
+        func=my_calculate
+    )
+
+    return registry
+```
+
+工具不仅支持基本的四则运算,还涵盖了常用的数学函数和常数,满足了大多数计算场景的需求。你也可以自己扩展这个文件,制作一个更加完备的计算函数。我们提供一个测试文件`test_my_calculator.py`帮助你验证功能实现:
+
+```python
+# test_my_calculator.py
+from dotenv import load_dotenv
+from my_calculator_tool import create_calculator_registry
+
+# 加载环境变量
+load_dotenv()
+
+def test_calculator_tool():
+    """测试自定义计算器工具"""
+
+    # 创建包含计算器的注册表
+    registry = create_calculator_registry()
+
+    print("🧪 测试自定义计算器工具\n")
+
+    # 简单测试用例
+    test_cases = [
+        "2 + 3",           # 基本加法
+        "10 - 4",          # 基本减法
+        "5 * 6",           # 基本乘法
+        "15 / 3",          # 基本除法
+        "sqrt(16)",        # 平方根
+    ]
+
+    for i, expression in enumerate(test_cases, 1):
+        print(f"测试 {i}: {expression}")
+        result = registry.execute_tool("my_calculator", expression)
+        print(f"结果: {result}\n")
+
+def test_with_simple_agent():
+    """测试与SimpleAgent的集成"""
+    from hello_agents import HelloAgentsLLM
+
+    # 创建LLM客户端
+    llm = HelloAgentsLLM()
+
+    # 创建包含计算器的注册表
+    registry = create_calculator_registry()
+
+    print("🤖 与SimpleAgent集成测试:")
+
+    # 模拟SimpleAgent使用工具的场景
+    user_question = "请帮我计算 sqrt(16) + 2 * 3"
+
+    print(f"用户问题: {user_question}")
+
+    # 使用工具计算
+    calc_result = registry.execute_tool("my_calculator", "sqrt(16) + 2 * 3")
+    print(f"计算结果: {calc_result}")
+
+    # 构建最终回答
+    final_messages = [
+        {"role": "user", "content": f"计算结果是 {calc_result},请用自然语言回答用户的问题:{user_question}"}
+    ]
+
+    print("\n🎯 SimpleAgent的回答:")
+    response = llm.think(final_messages)
+    for chunk in response:
+        print(chunk, end="", flush=True)
+    print("\n")
+
+if __name__ == "__main__":
+    test_calculator_tool()
+    test_with_simple_agent()
+```
+
+通过这个简化的数学计算工具案例,我们学会了如何快速开发自定义工具:编写一个简单的计算函数,通过ToolRegistry注册,然后与SimpleAgent集成使用。为了更直观的观察,这里提供了图7.1,可以清晰理解代码的运行逻辑。
+
+<div align="center">
+  <img src="https://raw.githubusercontent.com/datawhalechina/Hello-Agents/main/docs/images/7-figures/01.png" alt="" width="90%"/>
+  <p>表 7.1 基于Helloagents的SimpleAgent运行工作流</p>
+</div>
+
+### 7.5.3 多源搜索工具
+
+在实际应用中,我们经常需要整合多个外部服务来提供更强大的功能。搜索工具就是一个典型的例子,它整合多个搜索引擎,能提供更加完备的真实信息。在第一章我们使用过Tavily的搜索API,在第四章我们使用过SerpApi的搜索API。因此这次我们使用这两个API来实现多源搜索功能。如果没安装对应的python依赖可以运行下面这条脚本:
+
+```bash
+pip install hello-agents[search]==0.1.1
+```
+
+(1)搜索工具的统一接口设计
+
+HelloAgents框架内置的SearchTool展示了如何设计一个高级的多源搜索工具:
+
+````python
+class SearchTool(Tool):
+    """
+    智能混合搜索工具
+
+    支持多种搜索引擎后端,智能选择最佳搜索源:
+    1. 混合模式 (hybrid) - 智能选择TAVILY或SERPAPI
+    2. Tavily API (tavily) - 专业AI搜索
+    3. SerpApi (serpapi) - 传统Google搜索
+    """
+
+    def __init__(self, backend: str = "hybrid", tavily_key: Optional[str] = None, serpapi_key: Optional[str] = None):
+        super().__init__(
+            name="search",
+            description="一个智能网页搜索引擎。支持混合搜索模式,自动选择最佳搜索源。"
+        )
+        self.backend = backend
+        self.tavily_key = tavily_key or os.getenv("TAVILY_API_KEY")
+        self.serpapi_key = serpapi_key or os.getenv("SERPAPI_API_KEY")
+        self.available_backends = []
+        self._setup_backends()
+````
+这个设计的核心思想是根据可用的API密钥和依赖库,自动选择最佳的搜索后端。
+
+(2)TAVILY与SERPAPI搜索源的整合策略
+
+框架实现了智能的后端选择逻辑:
+
+````python
+def _search_hybrid(self, query: str) -> str:
+    """混合搜索 - 智能选择最佳搜索源"""
+    # 优先使用Tavily(AI优化的搜索)
+    if "tavily" in self.available_backends:
+        try:
+            return self._search_tavily(query)
+        except Exception as e:
+            print(f"⚠️ Tavily搜索失败: {e}")
+            # 如果Tavily失败,尝试SerpApi
+            if "serpapi" in self.available_backends:
+                print("🔄 切换到SerpApi搜索")
+                return self._search_serpapi(query)
+
+    # 如果Tavily不可用,使用SerpApi
+    elif "serpapi" in self.available_backends:
+        try:
+            return self._search_serpapi(query)
+        except Exception as e:
+            print(f"⚠️ SerpApi搜索失败: {e}")
+
+    # 如果都不可用,提示用户配置API
+    return "❌ 没有可用的搜索源,请配置TAVILY_API_KEY或SERPAPI_API_KEY环境变量"
+````
+这种设计体现了高可用系统的核心理念:通过降级机制,系统能够从最优的搜索源逐步降级到可用的备选方案。当所有搜索源都不可用时,明确提示用户配置正确的API密钥。
+
+(3)搜索结果的统一格式化
+
+不同搜索引擎返回的结果格式不同,框架通过统一的格式化方法来处理:
+
+````python
+def _search_tavily(self, query: str) -> str:
+    """使用Tavily搜索"""
+    response = self.tavily_client.search(
+        query=query,
+        search_depth="basic",
+        include_answer=True,
+        max_results=3
+    )
+
+    result = f"🎯 Tavily AI搜索结果:{response.get('answer', '未找到直接答案')}\n\n"
+
+    for i, item in enumerate(response.get('results', [])[:3], 1):
+        result += f"[{i}] {item.get('title', '')}\n"
+        result += f"    {item.get('content', '')[:200]}...\n"
+        result += f"    来源: {item.get('url', '')}\n\n"
+
+    return result
+````
+
+基于框架的设计思想,我们可以创建自己的高级搜索工具。这次我们使用类的方式来展示不同的实现方法,创建`my_advanced_search.py`:
+
+```python
+# my_advanced_search.py
+import os
+from typing import Optional, List, Dict, Any
+from hello_agents import ToolRegistry
+
+class MyAdvancedSearchTool:
+    """
+    自定义高级搜索工具类
+    展示多源整合和智能选择的设计模式
+    """
+
+    def __init__(self):
+        self.name = "my_advanced_search"
+        self.description = "智能搜索工具,支持多个搜索源,自动选择最佳结果"
+        self.search_sources = []
+        self._setup_search_sources()
+
+    def _setup_search_sources(self):
+        """设置可用的搜索源"""
+        # 检查Tavily可用性
+        if os.getenv("TAVILY_API_KEY"):
+            try:
+                from tavily import TavilyClient
+                self.tavily_client = TavilyClient(api_key=os.getenv("TAVILY_API_KEY"))
+                self.search_sources.append("tavily")
+                print("✅ Tavily搜索源已启用")
+            except ImportError:
+                print("⚠️ Tavily库未安装")
+
+        # 检查SerpApi可用性
+        if os.getenv("SERPAPI_API_KEY"):
+            try:
+                import serpapi
+                self.search_sources.append("serpapi")
+                print("✅ SerpApi搜索源已启用")
+            except ImportError:
+                print("⚠️ SerpApi库未安装")
+
+        if self.search_sources:
+            print(f"🔧 可用搜索源: {', '.join(self.search_sources)}")
+        else:
+            print("⚠️ 没有可用的搜索源,请配置API密钥")
+
+    def search(self, query: str) -> str:
+        """执行智能搜索"""
+        if not query.strip():
+            return "❌ 错误:搜索查询不能为空"
+
+        # 检查是否有可用的搜索源
+        if not self.search_sources:
+            return """❌ 没有可用的搜索源,请配置以下API密钥之一:
+
+1. Tavily API: 设置环境变量 TAVILY_API_KEY
+   获取地址: https://tavily.com/
+
+2. SerpAPI: 设置环境变量 SERPAPI_API_KEY
+   获取地址: https://serpapi.com/
+
+配置后重新运行程序。"""
+
+        print(f"🔍 开始智能搜索: {query}")
+
+        # 尝试多个搜索源,返回最佳结果
+        for source in self.search_sources:
+            try:
+                if source == "tavily":
+                    result = self._search_with_tavily(query)
+                    if result and "未找到" not in result:
+                        return f"📊 Tavily AI搜索结果:\n\n{result}"
+
+                elif source == "serpapi":
+                    result = self._search_with_serpapi(query)
+                    if result and "未找到" not in result:
+                        return f"🌐 SerpApi Google搜索结果:\n\n{result}"
+
+            except Exception as e:
+                print(f"⚠️ {source} 搜索失败: {e}")
+                continue
+
+        return "❌ 所有搜索源都失败了,请检查网络连接和API密钥配置"
+
+    def _search_with_tavily(self, query: str) -> str:
+        """使用Tavily搜索"""
+        response = self.tavily_client.search(query=query, max_results=3)
+
+        if response.get('answer'):
+            result = f"💡 AI直接答案:{response['answer']}\n\n"
+        else:
+            result = ""
+
+        result += "🔗 相关结果:\n"
+        for i, item in enumerate(response.get('results', [])[:3], 1):
+            result += f"[{i}] {item.get('title', '')}\n"
+            result += f"    {item.get('content', '')[:150]}...\n\n"
+
+        return result
+
+    def _search_with_serpapi(self, query: str) -> str:
+        """使用SerpApi搜索"""
+        import serpapi
+
+        search = serpapi.GoogleSearch({
+            "q": query,
+            "api_key": os.getenv("SERPAPI_API_KEY"),
+            "num": 3
+        })
+
+        results = search.get_dict()
+
+        result = "🔗 Google搜索结果:\n"
+        if "organic_results" in results:
+            for i, res in enumerate(results["organic_results"][:3], 1):
+                result += f"[{i}] {res.get('title', '')}\n"
+                result += f"    {res.get('snippet', '')}\n\n"
+
+        return result
+
+def create_advanced_search_registry():
+    """创建包含高级搜索工具的注册表"""
+    registry = ToolRegistry()
+
+    # 创建搜索工具实例
+    search_tool = MyAdvancedSearchTool()
+
+    # 注册搜索工具的方法作为函数
+    registry.register_function(
+        name="advanced_search",
+        description="高级搜索工具,整合Tavily和SerpAPI多个搜索源,提供更全面的搜索结果",
+        func=search_tool.search
+    )
+
+    return registry
+```
+
+接下来可以测试我们自己编写的工具,创建`test_advanced_search.py`:
+
+```python
+# test_advanced_search.py
+from dotenv import load_dotenv
+from my_advanced_search import create_advanced_search_registry, MyAdvancedSearchTool
+
+# 加载环境变量
+load_dotenv()
+
+def test_advanced_search():
+    """测试高级搜索工具"""
+
+    # 创建包含高级搜索工具的注册表
+    registry = create_advanced_search_registry()
+
+    print("🔍 测试高级搜索工具\n")
+
+    # 测试查询
+    test_queries = [
+        "Python编程语言的历史",
+        "人工智能的最新发展",
+        "2024年科技趋势"
+    ]
+
+    for i, query in enumerate(test_queries, 1):
+        print(f"测试 {i}: {query}")
+        result = registry.execute_tool("advanced_search", query)
+        print(f"结果: {result}\n")
+        print("-" * 60 + "\n")
+
+def test_api_configuration():
+    """测试API配置检查"""
+    print("🔧 测试API配置检查:")
+
+    # 直接创建搜索工具实例
+    search_tool = MyAdvancedSearchTool()
+
+    # 如果没有配置API,会显示配置提示
+    result = search_tool.search("机器学习算法")
+    print(f"搜索结果: {result}")
+
+def test_with_agent():
+    """测试与Agent的集成"""
+    print("\n🤖 与Agent集成测试:")
+    print("高级搜索工具已准备就绪,可以与Agent集成使用")
+
+    # 显示工具描述
+    registry = create_advanced_search_registry()
+    tools_desc = registry.get_tools_description()
+    print(f"工具描述:\n{tools_desc}")
+
+if __name__ == "__main__":
+    test_advanced_search()
+    test_api_configuration()
+    test_with_agent()
+```
+
+通过这个高级搜索工具的设计实践,我们学会了如何使用类的方式来构建复杂的工具系统。相比函数方式,类方式更适合需要维护状态(如API客户端、配置信息)的工具。
+
+### 7.5.4 工具系统的高级特性
+
+在掌握了基础的工具开发和多源整合后,我们来探讨工具系统的高级特性。这些特性能够让工具系统在复杂的生产环境中稳定运行,并为Agent提供更强大的能力。
+
+(1)工具链式调用机制
+
+在实际应用中,Agent经常需要组合使用多个工具来完成复杂任务。我们可以设计一个工具链管理器来支持这种场景,这里借鉴了第六章中提到的图的概念:
+
+```python
+# tool_chain_manager.py
+from typing import List, Dict, Any, Optional
+from hello_agents import ToolRegistry
+
+class ToolChain:
+    """工具链 - 支持多个工具的顺序执行"""
+
+    def __init__(self, name: str, description: str):
+        self.name = name
+        self.description = description
+        self.steps: List[Dict[str, Any]] = []
+
+    def add_step(self, tool_name: str, input_template: str, output_key: str = None):
+        """
+        添加工具执行步骤
+
+        Args:
+            tool_name: 工具名称
+            input_template: 输入模板,支持变量替换
+            output_key: 输出结果的键名,用于后续步骤引用
+        """
+        self.steps.append({
+            "tool_name": tool_name,
+            "input_template": input_template,
+            "output_key": output_key or f"step_{len(self.steps)}_result"
+        })
+
+    def execute(self, registry: ToolRegistry, initial_input: str, context: Dict[str, Any] = None) -> str:
+        """执行工具链"""
+        context = context or {}
+        context["input"] = initial_input
+
+        print(f"🔗 开始执行工具链: {self.name}")
+
+        for i, step in enumerate(self.steps, 1):
+            tool_name = step["tool_name"]
+            input_template = step["input_template"]
+            output_key = step["output_key"]
+
+            # 替换模板中的变量
+            try:
+                tool_input = input_template.format(**context)
+            except KeyError as e:
+                return f"❌ 工具链执行失败:模板变量 {e} 未找到"
+
+            print(f"  步骤 {i}: 使用 {tool_name} 处理 '{tool_input[:50]}...'")
+
+            # 执行工具
+            result = registry.execute_tool(tool_name, tool_input)
+            context[output_key] = result
+
+            print(f"  ✅ 步骤 {i} 完成,结果长度: {len(result)} 字符")
+
+        # 返回最后一步的结果
+        final_result = context[self.steps[-1]["output_key"]]
+        print(f"🎉 工具链 '{self.name}' 执行完成")
+        return final_result
+
+class ToolChainManager:
+    """工具链管理器"""
+
+    def __init__(self, registry: ToolRegistry):
+        self.registry = registry
+        self.chains: Dict[str, ToolChain] = {}
+
+    def register_chain(self, chain: ToolChain):
+        """注册工具链"""
+        self.chains[chain.name] = chain
+        print(f"✅ 工具链 '{chain.name}' 已注册")
+
+    def execute_chain(self, chain_name: str, input_data: str, context: Dict[str, Any] = None) -> str:
+        """执行指定的工具链"""
+        if chain_name not in self.chains:
+            return f"❌ 工具链 '{chain_name}' 不存在"
+
+        chain = self.chains[chain_name]
+        return chain.execute(self.registry, input_data, context)
+
+    def list_chains(self) -> List[str]:
+        """列出所有工具链"""
+        return list(self.chains.keys())
+
+# 使用示例
+def create_research_chain() -> ToolChain:
+    """创建一个研究工具链:搜索 -> 计算 -> 总结"""
+    chain = ToolChain(
+        name="research_and_calculate",
+        description="搜索信息并进行相关计算"
+    )
+
+    # 步骤1:搜索信息
+    chain.add_step(
+        tool_name="search",
+        input_template="{input}",
+        output_key="search_result"
+    )
+
+    # 步骤2:基于搜索结果进行计算(如果需要)
+    chain.add_step(
+        tool_name="my_calculator",
+        input_template="根据以下信息计算相关数值:{search_result}",
+        output_key="calculation_result"
+    )
+
+    return chain
+```
+
+(2)异步工具执行支持
+
+对于耗时的工具操作,我们可以提供异步执行支持:
+
+```python
+# async_tool_executor.py
+import asyncio
+import concurrent.futures
+from typing import Dict, Any, List, Callable
+from hello_agents import ToolRegistry
+
+class AsyncToolExecutor:
+    """异步工具执行器"""
+
+    def __init__(self, registry: ToolRegistry, max_workers: int = 4):
+        self.registry = registry
+        self.executor = concurrent.futures.ThreadPoolExecutor(max_workers=max_workers)
+
+    async def execute_tool_async(self, tool_name: str, input_data: str) -> str:
+        """异步执行单个工具"""
+        loop = asyncio.get_event_loop()
+
+        def _execute():
+            return self.registry.execute_tool(tool_name, input_data)
+
+        result = await loop.run_in_executor(self.executor, _execute)
+        return result
+
+    async def execute_tools_parallel(self, tasks: List[Dict[str, str]]) -> List[str]:
+        """并行执行多个工具"""
+        print(f"🚀 开始并行执行 {len(tasks)} 个工具任务")
+
+        # 创建异步任务
+        async_tasks = []
+        for task in tasks:
+            tool_name = task["tool_name"]
+            input_data = task["input_data"]
+            async_task = self.execute_tool_async(tool_name, input_data)
+            async_tasks.append(async_task)
+
+        # 等待所有任务完成
+        results = await asyncio.gather(*async_tasks)
+
+        print(f"✅ 所有工具任务执行完成")
+        return results
+
+    def __del__(self):
+        """清理资源"""
+        if hasattr(self, 'executor'):
+            self.executor.shutdown(wait=True)
+
+# 使用示例
+async def test_parallel_execution():
+    """测试并行工具执行"""
+    from hello_agents import ToolRegistry
+
+    registry = ToolRegistry()
+    # 假设已经注册了搜索和计算工具
+
+    executor = AsyncToolExecutor(registry)
+
+    # 定义并行任务
+    tasks = [
+        {"tool_name": "search", "input_data": "Python编程"},
+        {"tool_name": "search", "input_data": "机器学习"},
+        {"tool_name": "my_calculator", "input_data": "2 + 2"},
+        {"tool_name": "my_calculator", "input_data": "sqrt(16)"},
+    ]
+
+    # 并行执行
+    results = await executor.execute_tools_parallel(tasks)
+
+    for i, result in enumerate(results):
+        print(f"任务 {i+1} 结果: {result[:100]}...")
+```
+
+基于以上的设计和实现经验,我们可以总结出工具系统开发的核心理念:在设计层面,每个工具都应该遵循单一职责原则,专注于特定功能的同时保持接口的统一性,并将完善的异常处理和安全优先的输入验证作为基本要求。在性能优化方面,利用异步执行提高并发处理能力,同时合理管理外部连接和系统资源。
+
+
+
+## 7.6 本章小结
+
+在正式总结之前,我们想告诉大家一个好消息:对于本章实现的所有方法和功能,都在GitHub仓库中提供了完整的测试案例。你可以访问[这个链接](https://github.com/jjyaoao/HelloAgents/blob/main/examples/chapter07_basic_setup.py)查看和运行这些测试代码。这个文件包含了四种Agent范式的演示、工具系统的集成测试、高级功能的使用示例,以及交互式的Agent体验。如果你想验证自己的实现是否正确,或者想深入了解框架的实际使用方式,这些测试案例将是有价值的参考。
+
+回顾本章,我们完成了一项富有挑战的任务:一步步构建了一个基础的智能体框架——HelloAgents。这个过程始终遵循着“分层解耦、职责单一、接口统一”的核心原则。
+
+在框架的具体实现中,我们再次实现了四种经典的Agent范式。从SimpleAgent的基础对话模式,到ReActAgent的推理与行动结合;从ReflectionAgent的自我反思与迭代优化,到PlanAndSolveAgent的分解规划与逐步执行。而工具系统作为Agent能力延伸的核心,其构建过程则是一次完整的工程实践。
+
+更重要的是,第七章的构建并非终点,而是为后续更深入学习提供了必要的技术基础。我们在设计之初便充分考虑了后续内容的延展性,为高级功能的实现预留了必要的接口和扩展点。我们所建立的统一LLM接口、标准化消息系统、工具注册机制,共同构成了一个完备的技术底座。这使得我们在后续章节中,可以更加从容地去学习更高级的主题:第八章的记忆与RAG系统将基于此扩展Agent的能力边界;第九章的上下文工程将深入我们已经建立的消息处理机制;第十章的智能体协议则需要扩展新的工具。
+
+接下来,我们将一起探索如何往框架中加入RAG系统与Memory机制,敬请期待第八章!

+ 0 - 3
docs/chapter8/第八章 推理与规划.md

@@ -1,3 +0,0 @@
-# 第八章 推理与规划
-
-本章内容待补充...

+ 3 - 0
docs/chapter8/第八章 记忆与检索.md

@@ -0,0 +1,3 @@
+# 第八章 记忆与检索
+
+本章内容待补充...

+ 3 - 0
docs/chapter9/第九章 上下文工程.md

@@ -0,0 +1,3 @@
+# 第九章 上下文工程
+
+本章内容待补充...

+ 0 - 3
docs/chapter9/第九章 记忆与工具.md

@@ -1,3 +0,0 @@
-# 第九章 记忆与工具
-
-本章内容待补充...

BIN
docs/images/7-figures/01.png


BIN
docs/images/7-figures/table-01.png


BIN
docs/images/7-figures/table-02.png


+ 1 - 1
docs/前言.md

@@ -7,7 +7,7 @@
 
 然而,当前的生态中存在一个明显的断层:一方面是层出不穷的 Agent 框架和应用,令人眼花缭乱;另一方面,却是系统性知识的极度匮乏。大多数教程聚焦于某个特定框架的 API 调用,学习者往往“知其然,而不知其所以然”,在面对复杂需求时,依然感到力不从心。我们缺少一本能够穿透框架表象,从第一性原理出发,系统讲解智能体设计、构建与协作的实战指南。
 
-鉴于此,我们发起了这个名为Hello-Agents的开源项目。本书的目标,是授人以渔。我们不仅会带你领略智能体领域最前沿的技术,更会引导你深入其核心架构,理解其经典范式,并最终亲手构建起属于自己的、强大的多智能体应用。我们相信,最好的学习方式就是动手实践。
+鉴于此,我们发起了这个名为Hello-Agents的开源项目。本书的目标,是授人以渔。我们不仅会带你领略智能体领域最前沿的技术,更会引导你深入其核心架构,理解其经典范式,并最终亲手构建起属于自己的多智能体应用。我们相信,最好的学习方式就是动手实践。
 
 希望这本书能成为你探索智能体浩瀚世界的起点,帮助你从一名 LLM 的“使用者”,蜕变为一名智能系统的“构建者”。让我们一起,迎接正在到来的智能革命。