HelloAgents 进阶篇 task02

在之前的任务中已经完成了ReAct、Plan-and-Solve、Reflection三种智能体架构范式的实现,接下来在这个基础上自建出一个智能体框架。

通过搭建这个智能体框架有下面的好处:

  • 特定领域的优化需求:金融、医疗、教育等垂直领域往往需要针对性的提示词模板、特殊的工具集成、以及定制化的安全策略。
  • 性能与资源的精确控制:生产环境中,对响应时间、内存占用、并发处理能力都有严格要求,通用框架的"一刀切"方案往往无法满足精细化需求。

一、框架接口的实现

这一部分主要实现了下面三个框架接口的实现:

  • message.py: 定义了框架内统一的消息格式,确保了智能体与模型之间信息传递的标准化。
  • config.py: 提供了一个中心化的配置管理方案,使框架的行为易于调整和扩展。
  • agent.py: 定义了所有智能体的抽象基类(Agent),为后续实现不同类型的智能体提供了统一的接口和规范。

1.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  # 消息时间戳,默认为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}"

2.Config 类

这个类的职责是将代码中硬编码配置参数集中起来,并支持从环境变量中读取。

python 复制代码
"""配置管理"""
import os
from typing import Optional, Dict, Any
from pydantic import BaseModel

class Config(BaseModel):
    """HelloAgent的配置类"""

    # LLM相关配置
    default_model: str = "gpt-3.5-turbo"  # 默认使用的语言模型
    default_provider: str = "openai"  # 默认使用的语言模型提供商
    temperature: float = 0.7  # 生成文本的随机程度,范围为0-1
    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()

3.Agent 抽象基类

这是整个框架的顶层抽象。它定义了一个智能体应该具备的通用行为和属性,但并不关心具体的实现方式。

python 复制代码
"""Agent基类"""
from abc import ABC, abstractmethod
from typing import Optional, Any
from .message import Message
from .config import Config
from .llm import HelloAgentsLLM

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})"

二、Agent范式的框架化实现

这一部分主要是针对经典Agent范式进行框架重构,并且添加了一个基础对话范式。

1.SimpleAgent

SimpleAgent通过继承框架基类来重写。

python 复制代码
from typing import Optional, Iterator
from core import agent, llm, message, config
from core.agent import Agent
from core.message import Message
from core.config import Config
from other_agents.llm_client import HelloAgentsLLM
import re

class MySimpleAgent(Agent):
    """
    重写的简单对话Agent
    展示如何基于框架基类构建自定义Agent
    """

    def __init__(
            self,
            name: str,
            llm: HelloAgentsLLM,
            system_prompt: Optional[str] = None,
            config: Optional[Config] = None,
            tool_registry: Optional['ToolRegistry'] = None,
            enable_tool_calling: bool = True
    ):
        super().__init__(name, llm, system_prompt, config)
        self.tool_registry = tool_registry
        self.enable_tool_calling = enable_tool_calling and tool_registry is not None
        print(f"{name} 初始化完成,工具调用:{'启用' if self.enable_tool_calling else '禁用'}")

    def has_tools(self) -> bool:
        """检查是否有工具可用"""
        if not self.tool_registry:
            return False
        tools = self.tool_registry._tools
        functions = self.tool_registry._functions
        return len(tools) > 0 or len(functions) > 0

    def add_tool(self, tool) -> None:
        """动态添加工具"""
        if not self.tool_registry:
            from tools.registry import ToolRegistry
            self.tool_registry = ToolRegistry()
            self.enable_tool_calling = True
        self.tool_registry.register_tool(tool)

    def list_tools(self) -> list:
        """列出所有可用工具"""
        if not self.tool_registry:
            return []
        tool_names = list(self.tool_registry._tools.keys())
        func_names = list(self.tool_registry._functions.keys())
        return tool_names + func_names

    def run(self, input_text: str, max_tool_iterations: int = 3, **kwargs) -> str:
        """
        重写的运行方法,实现简单对话逻辑,支持可选工具调用
        """
        print(f"{self.name} 正在处理: {input_text}")

        # 构建消息列表
        messages = []

        # 添加系统消息(可能包含工具信息)
        enhanced_system_prompt = self._get_enhanced_system_prompt()
        messages.append({"role": "system", "content": enhanced_system_prompt})

        # 添加历史消息
        for msg in self._history:
            messages.append({"role": msg.role, "content": msg.content})

        # 添加当前用户信息
        messages.append({"role": "user", "content": input_text})

        # 如果没有启用工具调用,使用简单对话逻辑
        if not self.enable_tool_calling:
            response = self.llm.think(messages, **kwargs)
            self.add_message(Message(input_text, "user"))
            self.add_message(Message(response, "assistant"))
            print(f"{self.name} 响应完成")
            return response
        
        # 支持多轮工具调用的逻辑
        return self._run_with_tools(messages, input_text, max_tool_iterations, **kwargs)
    

    def _get_enhanced_system_prompt(self) -> str:
        """
        构建增强的系统提示,包含工具信息(如果启用工具调用)
        """
        base_prompt = self.system_prompt or "你是一个有用的AI助手"

        if not self.enable_tool_calling or not self.tool_registry:
            return base_prompt
        
        # 获取工具描述
        tools_description = self.tool_registry.get_tools_description()
        if not tools_description or tools_description == "无可用工具":
            return base_prompt
        
        tools_section = "\n\n## 可用工具\n"
        tools_section += "以下是你可以调用的工具列表:\n"
        tools_section += tools_description + "\n"

        tools_section += "\n## 工具调用格式\n"
        tools_section += "当你需要调用工具时,请使用以下格式:\n"
        tools_section += "'[TOOL_CALL: {tool_name}:{parameters}]'\n"
        tools_section += "例如:'[TOOL_CALL: search:Python编程]' 或 '[TOOL_CALL: memory:recall=用户信息]'\n\n"
        tools_section += "工具调用结果会自动插入到对话中,你可以继续基于结果进行对话。\n"

        return base_prompt + tools_section



    def _run_with_tools(self, messages: list, input_text: str, max_tool_iterations: int, **kwargs) -> str:
        """支持工具调用的运行逻辑"""
        current_iteration = 0
        final_response = ""

        while current_iteration < max_tool_iterations:
            # 调用LLM
            response = self.llm.think(messages, **kwargs)

            # 检查是否有工具调用
            tool_calls = self._parse_tool_calls(response)

            if tool_calls:
                print(f"检测到{len(tool_calls)} 个工具调用")
                # 执行所有工具调用并收集结果
                tool_results = []
                clean_response = response

                for call in tool_calls:
                    result = self._excute_tool_call(call['tool_name'], call['parameters'])
                    tool_results.append(result)
                    # 从响应中移除工具调用标记
                    clean_response = clean_response.replace(call['original'], "")

                # 构建包含工具结果的消息
                messages.append({"role": "assistant", "content": clean_response})

                # 添加工具结果
                tool_results_text = "\n\n".join(tool_results)
                messages.append({"role": "user", "content": f"工具执行结果:\n{tool_results_text}\n\n请基于这些结果给出完整的回答。"})

                current_iteration += 1
                continue

            # 没有工具调用,这是最终回答
            finally_response = response
            break

        # 如果超过最大迭代次数,获取最后一次回答
        if current_iteration >= max_tool_iterations and not final_response:
            final_response = self.llm.think(messages, **kwargs)

        # 保存到历史记录
        self.add_message(Message(input_text, "user"))
        self.add_message(Message(final_response, "assistant"))
        print(f"{self.name} 响应完成")

        return final_response
    
    def _parse_tool_calls(self, text: str) -> list:
        """解析文本中的工具调用"""
        pattern = r"\[TOOL_CALL:\s*(\w+):([^\]]+)\]"
        matches = re.findall(pattern, text)

        tool_calls = []
        for tool_name, parameters in matches:
            tool_calls.append({
                "tool_name": tool_name.strip(),
                "parameters": parameters.strip(),
                "original": f"[TOOL_CALL: {tool_name}:{parameters}]"
            })

        return tool_calls
    

    def _excute_tool_call(self, tool_name: str, parameters: str) -> str:
        """执行工具调用"""
        if not self.tool_registry:
            return f"工具调用失败:没有工具注册"
        
        try:
            # 智能参数解析
            if tool_name == 'calculator':
                # 计算器工具直接传入表达式
                result = self.tool_registry.execute_tool(tool_name, parameters)
            else:
                # 其他工具使用智能参数解析
                params_dict = self._parse_tool_parameters(tool_name, parameters)
                tool = self.tool_registry.get_tool(tool_name)
                if not tool:
                    return f"工具调用失败:未找到工具 '{tool_name}'"
                result = tool.run(param_dict)

            return f"工具 '{tool_name}' 执行结果:{result}"
        except Exception as e:
            return f"工具调用失败:{str(e)}"
        

    def _parse_tool_parameters(self, tool_name: str, parameters: str) -> dict:
        """智能解析工具参数"""
        param_dict = {}

        if '=' in parameters:
            # 格式: key=value 或 action=search query=Python
            if ',' in parameters:
                # 多个参数:action=search,query=Python,limit=3
                pairs = parameters.split(',')
                for pair in pairs:
                    if '=' in pair:
                        key, value = pair.split('=', 1)
                        param_dict[key.strip()] = value.strip()

            else:
                # 单个参数:key=value
                key, value = parameters.split('=', 1)
                param_dict[key.strip()] = value.strip()
        else:
            # 直接传入参数,根据工具类型智能推断
            if tool_name == 'search':
                param_dict = {'query': parameters}
            elif tool_name == 'memory':
                param_dict = {'action': 'search', 'query': parameters}
            else:
                # 其他工具直接传入参数
                param_dict = {'input': parameters}

        return param_dict

    def stream_run(self, input_text: str, **kwargs) -> Iterator[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
        full_response = self.llm.think(messages, **kwargs)
        if full_response:
            yield full_response

        print() # 换行

        # 保存完整对话到历史记录
        self.add_message(Message(input_text, "user"))
        self.add_message(Message(full_response, "assistant"))
        print(f"{self.name} 流式处理完成")

下面是测试结果:

bash 复制代码
=== 测试1:基础对话 ===
基础助手 初始化完成,工具调用:禁用
基础助手 正在处理: 你好,请介绍一下自己
[thinking] 正在调用 deepseek-chat 模型...
[ok] 大语言模型响应成功:
你好!我是DeepSeek,一个由深度求索公司创造的AI助手。很高兴认识你!😊

让我简单介绍一下自己:
- 我是一个纯文本AI模型,擅长回答各种问题、协助写作、分析问题、编程等
- 支持文件上传功能,可以处理图像、txt、pdf、ppt、word、excel等文件,并从中读取文字信息
- 拥有128K的上下文长度,能记住我们较长的对话内容
- 完全免费使用,没有收费计划
- 支持联网搜索功能(需要手动开启)
- 可以通过官方应用商店下载App使用

我的知识截止到2024年7月,会以热情细腻的方式为你提供帮助。有什么问题或需要协助的地方,尽管告诉我吧!我会尽力为你提供有用的回答。✨
基础助手 响应完成
基础对话响应: 你好!我是DeepSeek,一个由深度求索公司创造的AI助手。很高兴认识你!😊

让我简单介绍一下自己:
- 我是一个纯文本AI模型,擅长回答各种问题、协助写作、分析问题、编程等
- 支持文件上传功能,可以处理图像、txt、pdf、ppt、word、excel等文件,并从中读取文字信息
- 拥有128K的上下文长度,能记住我们较长的对话内容
- 完全免费使用,没有收费计划
- 支持联网搜索功能(需要手动开启)
- 可以通过官方应用商店下载App使用

我的知识截止到2024年7月,会以热情细腻的方式为你提供帮助。有什么问题或需要协助的地方,尽管告诉我吧!我会尽力为你提供有用的回答。✨

=== 测试2:工具增强对话 ===
[ok] 工具 'calculator' 已注册。
增强助手 初始化完成,工具调用:启用
增强助手 正在处理: 请帮我计算 15 * 8 + 32
[thinking] 正在调用 deepseek-chat 模型...
[ok] 大语言模型响应成功:
我来帮你计算这个数学表达式。

[TOOL_CALL: calculator:15 * 8 + 32]

根据计算结果:
15 × 8 = 120
120 + 32 = 152

所以 15 * 8 + 32 = 152
检测到1 个工具调用
[thinking] 正在调用 deepseek-chat 模型...
[ok] 大语言模型响应成功:
看起来计算工具出现了错误。让我重新帮你计算这个表达式:

15 × 8 = 120
120 + 32 = 152

所以 **15 * 8 + 32 = 152**

如果你需要计算其他表达式,我可以帮你手动计算。
增强助手 响应完成
工具增强响应:

=== 测试3:流式响应 ===
流式响应: 基础助手 开始流式处理:请解释什么是人工智能
[thinking] 正在调用 deepseek-chat 模型...
[ok] 大语言模型响应成功:
当然!**人工智能(Artificial Intelligence,简称 AI)** 是指由人类创造的、能够模拟人类智能行为的技术系统。它的核心目标是让机器具备像人一样的感知、学习、推理、决策甚至创造的能力。

---

### **关键特点与分类**
1. **模拟人类智能**  
   AI 不限于"像人一样思考",更注重"像人一样解决问题",比如识别图像、理解语言、下棋、驾驶汽车等。

2. **基于数据与算法**  
   AI 系统通常依赖大量数据和算法(如机器学习、深度学习)来发现规律并做出预测。

3. **两类常见[error] 调用LLM API时发生错误: The read operation timed out

2.ReActAgent

在之前搭建的ReAct基础上,实现了一个ReActAgent。

2.1 提示词重构

python 复制代码
MY_REACT_PROMPT = """你是一个具备推理和行动能力的AI助手。你可以通过思考分析问题,然后调用合适的工具来获取信息,最终给出准确的答案。

## 可用工具
{tools}

## 工作流程
请严格按照以下格式进行回应,每次只能执行一个步骤:

Thought: 分析当前问题,思考需要什么信息或采取什么行动。
Action: 选择一个行动,格式必须是以下之一:
- `{{tool_name}}[{{tool_input}}]` - 调用指定工具
- `Finish[最终答案]` - 当你有足够信息给出最终答案时

## 重要提醒
1. 每次回应必须包含Thought和Action两部分
2. 工具调用的格式必须严格遵循:工具名[参数]
3. 只有当你确信有足够信息回答问题时,才使用Finish
4. 如果工具返回的信息不够,继续使用其他工具或相同工具的不同参数

## 当前任务
**Question:** {question}

## 执行历史
{history}

现在开始你的推理和行动:
"""

2.2 ReAct框架重构

python 复制代码
class ReActAgent:
    def __init__(self, llm_client: HelloAgentsLLM, tool_executor: ToolExecutor, max_steps: int = 5):
        self.llm_client = llm_client
        self.tool_executor = tool_executor
        self.max_steps = max_steps
        self.history = []

    def run(self, question: str):
        self.history = []
        current_step = 0

        while current_step < self.max_steps:
            current_step += 1
            print(f"\n--- 第 {current_step} 步 ---")

            tools_desc = self.tool_executor.getAvailableTools()
            history_str = "\n".join(self.history)
            prompt = REACT_PROMPT_TEMPLATE.format(tools=tools_desc, question=question, history=history_str)

            messages = [{"role": "user", "content": prompt}]
            response_text = self.llm_client.think(messages=messages)
            if not response_text:
                print("错误:LLM未能返回有效响应。"); break

            thought, action = self._parse_output(response_text)
            if thought: print(f"🤔 思考: {thought}")
            if not action: print("警告:未能解析出有效的Action,流程终止。"); break
            
            if action.startswith("Finish"):
                # 如果是Finish指令,提取最终答案并结束
                final_answer = self._parse_action_input(action)
                print(f"🎉 最终答案: {final_answer}")
                return final_answer
            
            tool_name, tool_input = self._parse_action(action)
            if not tool_name or not tool_input:
                self.history.append("Observation: 无效的Action格式,请检查。"); continue

            print(f"🎬 行动: {tool_name}[{tool_input}]")
            tool_function = self.tool_executor.getTool(tool_name)
            observation = tool_function(tool_input) if tool_function else f"错误:未找到名为 '{tool_name}' 的工具。"
            
            print(f"👀 观察: {observation}")
            self.history.append(f"Action: {action}")
            self.history.append(f"Observation: {observation}")

        print("已达到最大步数,流程终止。")
        return None

    def _parse_output(self, text: str):
        # Thought: 匹配到 Action: 或文本末尾
        thought_match = re.search(r"Thought:\s*(.*?)(?=\nAction:|$)", text, re.DOTALL)
        # Action: 匹配到文本末尾
        action_match = re.search(r"Action:\s*(.*?)$", text, re.DOTALL)
        thought = thought_match.group(1).strip() if thought_match else None
        action = action_match.group(1).strip() if action_match else None
        return thought, action

    def _parse_action(self, action_text: str):
        match = re.match(r"(\w+)\[(.*)\]", action_text, re.DOTALL)
        return (match.group(1), match.group(2)) if match else (None, None)

    def _parse_action_input(self, action_text: str):
        match = re.match(r"\w+\[(.*)\]", action_text, re.DOTALL)
        return match.group(1) if match else ""

2.3 测试

测试结果如下:

bash 复制代码
工具 'Search' 已注册。

--- 第 1 步 ---
🧠 正在调用 deepseek-chat 模型...
✅ 大语言模型响应成功:
Thought: 用户询问的是"华为2026年的手机是哪一款?它的主要卖点是什么?"。这是一个关于未来产品的问题,超出了我的知识截止日期(2024年7月)。华为尚未发布2026年的具体手机型号和详细规格。这类信息通
常会在产品发布前由官方公布。为了提供准确信息,我需要搜索最新的相关新闻或传闻。

Action: Search[华为 2026 手机 型号 卖点 传闻]
🤔 思考: 用户询问的是"华为2026年的手机是哪一款?它的主要卖点是什么?"。这是一个关于未来产品的问题,超出了我的知识截止日期(2024年7月)。华为尚未发布2026年的具体手机型号和详细规格。这类信息通 
常会在产品发布前由官方公布。为了提供准确信息,我需要搜索最新的相关新闻或传闻。
🎬 行动: Search[华为 2026 手机 型号 卖点 传闻]
🔍 正在执行 [SerpApi] 网页搜索: 华为 2026 手机 型号 卖点 传闻
👀 观察: [1] 千元机市场大撤退,华为趁机"抄底"?
2026年一季度,1000元以下新机市场占比从2023年的22%暴跌至2.7%,荣耀x80i较上一代起售价涨600元。不过千元机不会消失,华为发起新攻势,畅享90系列 ... 手机 ...

[2] 为保持中国手机第一!华为2026年出货战略高端与中低端比例1.2
近日,有消息称,华为2026年的出货战略高端旗舰与中低端产品的出货比例约为1.2:1,这意味着华为将向中低端市场发力。 事实上,为了坐稳中国手机第一的话,华为 ...

[3] 华为登顶2026首周手机市场以20%份额领跑
此次华为能够强势登顶,主要得益于Mate 80系列的热销。该系列自2025年11月底发布以来持续受到市场欢迎,上市仅18天销量即突破百万台,相较前代同期 ...

--- 第 2 步 ---
🧠 正在调用 deepseek-chat 模型...
✅ 大语言模型响应成功:
Thought: 用户询问的是华为2026年的手机是哪一款以及其主要卖点。根据历史记录,之前的搜索"华为 2026 手机 型号 卖点 传闻"返回了一些相关信息,但并没有直接明确地指出2026年的具体型号和卖点。观察结果[3]提到了"Mate 80系列"在2025年11月底发布,并在2026年初热销。这很可能就是华为在2026年主推的旗舰机型。为了更准确地回答用户关于"2026年的手机"具体是哪一款以及其"主要卖点"是什么,我需要获取更详细、
更官方的信息。因此,我应该搜索"华为 Mate 80 主要卖点"或类似关键词来获取该型号的具体信息。

Action: Search[华为 Mate 80 卖点]
🤔 思考: 用户询问的是华为2026年的手机是哪一款以及其主要卖点。根据历史记录,之前的搜索"华为 2026 手机 型号 卖点 传闻"返回了一些相关信息,但并没有直接明确地指出2026年的具体型号和卖点。观察结果[3]提到了"Mate 80系列"在2025年11月底发布,并在2026年初热销。这很可能就是华为在2026年主推的旗舰机型。为了更准确地回答用户关于"2026年的手机"具体是哪一款以及其"主要卖点"是什么,我需要获取更详细、
更官方的信息。因此,我应该搜索"华为 Mate 80 主要卖点"或类似关键词来获取该型号的具体信息。
🎬 行动: Search[华为 Mate 80 卖点]
🔍 正在执行 [SerpApi] 网页搜索: 华为 Mate 80 卖点
👀 观察: [1] 华为Mate 80使用了一个月,不吹不黑,有些评价真的被 ...
Mate 80 这块6.75 英寸OLED 直屏,1.5K 分辨率、1--120Hz 自适应刷新率,从参数上看不算炸裂,也不是那种一亮屏就让人惊艳的类型。 刚上手时,它的观感甚至有些 ...

[2] HUAWEI Mate 80 - 华为官网
HUAWEI Mate 80,实力破圈。采用超可靠玄武架构,搭载第二代红枫影像,支持鸿蒙AI。

[3] 华为Mate 80系列销量破508万台:配置升级+降价800元引爆 ...
华为Mate 80系列销量破508万台:配置升级+降价800元引爆高端市场 ... 截至2026年4月11日,华为Mate 80系列出货量已突破508万台,在当前智能手机市场中成为广受 ...

--- 第 3 步 ---
🧠 正在调用 deepseek-chat 模型...
✅ 大语言模型响应成功:
Thought: 用户询问的是华为2026年的手机是哪一款以及其主要卖点。根据之前的搜索结果,华为在2026年最受关注和热销的机型似乎是Mate 80系列。搜索结果[3]明确指出"华为登顶2026首周手机市场以20%份额领跑"
主要得益于"Mate 80系列的热销"。因此,可以确定华为2026年的代表性手机是Mate 80系列。关于其主要卖点,搜索结果[2]"HUAWEI Mate 80 - 华为官网"提供了官方信息:"采用超可靠玄武架构,搭载第二代红枫影像
,支持鸿蒙AI。" 这三点可以作为核心卖点。为了确保信息的准确性和完整性,我需要再次搜索"华为 Mate 80 主要卖点"来获取更详细的描述。

Action: Search[华为 Mate 80 主要卖点 详细介绍]
🤔 思考: 用户询问的是华为2026年的手机是哪一款以及其主要卖点。根据之前的搜索结果,华为在2026年最受关注和热销的机型似乎是Mate 80系列。搜索结果[3]明确指出"华为登顶2026首周手机市场以20%份额领跑" 
主要得益于"Mate 80系列的热销"。因此,可以确定华为2026年的代表性手机是Mate 80系列。关于其主要卖点,搜索结果[2]"HUAWEI Mate 80 - 华为官网"提供了官方信息:"采用超可靠玄武架构,搭载第二代红枫影像
,支持鸿蒙AI。" 这三点可以作为核心卖点。为了确保信息的准确性和完整性,我需要再次搜索"华为 Mate 80 主要卖点"来获取更详细的描述。
🎬 行动: Search[华为 Mate 80 主要卖点 详细介绍]
🔍 正在执行 [SerpApi] 网页搜索: 华为 Mate 80 主要卖点 详细介绍
👀 观察: [1] HUAWEI Mate 80 参数规格- 华为官网
尺寸与重量. 长度. 161.85 mm · 屏幕. 尺寸. 6.75 英寸 · 处理器. 麒麟9020 · 操作系统. HarmonyOS 6.0 · 存储. 运行内存(RAM). 12 GB / 16 GB RAM · 后置摄像头. 后置摄像头.

[2] HUAWEI Mate 80 - 华为官网
HUAWEI Mate 80 为北斗卫星消息提供移动终端硬件,需在空旷无遮蔽处使用。首次使用前需在有地面网络的环境下,通过畅连应用激活或者开通运营商北斗卫星短信相关业务。仅支持 ...

[3] 华为Mate 80 系列手机重点参数配置差异公布,一表看懂
《4699 元起华为Mate 80/Pro 正式发布:首发鸿蒙Harmony OS 6.0,海思麒麟9030/Pro 性能提升35~42%》. 华为Mate 80 系列| Mate X7 及全场景新品发布会专题.

--- 第 4 步 ---
🧠 正在调用 deepseek-chat 模型...
✅ 大语言模型响应成功:
Thought: 用户询问的是华为2026年的手机是哪一款以及其主要卖点。根据之前的搜索历史,我们已经找到了相关信息。搜索结果显示,华为在2026年最受关注和热销的手机是Mate 80系列。具体来说,Mate 80系列在2025年底发布,并在2026年初取得了出色的市场表现。关于其主要卖点,从华为官网和相关信息可以总结出来。现在,我已经收集到了足够的信息来回答用户的问题,不需要再进行额外的搜索。

Action: Finish[华为在2026年最受关注和热销的手机是**华为Mate 80系列**(包括Mate 80和Mate 80 Pro等型号)。其主要卖点包括:
1.  **超可靠玄武架构**:提升了手机的耐用性和可靠性。
2.  **第二代红枫影像系统**:在拍照和摄像方面有显著提升。
4.  **强劲的麒麟处理器**(如麒麟9020/9030):提供强大的性能支持。
5.  **支持北斗卫星消息功能**:在无地面网络信号时也能通过卫星发送消息,增强了通信保障。
6.  **出色的屏幕素质**:例如采用高分辨率、高刷新率的OLED屏幕。
这些特点共同构成了华为Mate 80系列在2026年的核心竞争力。]
🤔 思考: 用户询问的是华为2026年的手机是哪一款以及其主要卖点。根据之前的搜索历史,我们已经找到了相关信息。搜索结果显示,华为在2026年最受关注和热销的手机是Mate 80系列。具体来说,Mate 80系列在2025年底发布,并在2026年初取得了出色的市场表现。关于其主要卖点,从华为官网和相关信息可以总结出来。现在,我已经收集到了足够的信息来回答用户的问题,不需要再进行额外的搜索。
🎉 最终答案: 华为在2026年最受关注和热销的手机是**华为Mate 80系列**(包括Mate 80和Mate 80 Pro等型号)。其主要卖点包括:
1.  **超可靠玄武架构**:提升了手机的耐用性和可靠性。
2.  **第二代红枫影像系统**:在拍照和摄像方面有显著提升。
3.  **搭载鸿蒙HarmonyOS 6.0操作系统**:带来更流畅、智能的交互体验。
4.  **强劲的麒麟处理器**(如麒麟9020/9030):提供强大的性能支持。
5.  **支持北斗卫星消息功能**:在无地面网络信号时也能通过卫星发送消息,增强了通信保障。
6.  **出色的屏幕素质**:例如采用高分辨率、高刷新率的OLED屏幕。
这些特点共同构成了华为Mate 80系列在2026年的核心竞争力。

三、工具搭建

1.工具基类

首先搭建一个工具基类,定义所有工具必须遵循的接口规范。

python 复制代码
"""工具基类"""

from abc import ABC, abstractmethod
from typing import Dict, Any, List, Optional, Callable, get_type_hints
from pydantic import BaseModel
import inspect
import re
import time
import asyncio

class ToolParameter(BaseModel):
    """工具参数定义"""
    name: str
    type: str
    description: str
    required: bool = True
    default: Any = None

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

    
    def to_openai_schema(self) -> Dict[str, Any]:
        """转换为 OpenAI function calling schema 格式

        用于 FunctionCallAgent,使工具能够被 OpenAI 原生 function calling 使用

        Returns:
            符合 OpenAI function calling 标准的 schema
        """
        parameters = self.get_parameters()

        # 构建 properties
        properties = {}
        required = []

        for param in parameters:
            # 基础属性定义
            prop = {
                "type": param.type,
                "description": param.description
            }

            # 如果有默认值,添加到描述中(OpenAI schema 不支持 default 字段)
            if param.default is not None:
                prop["description"] = f"{param.description} (默认: {param.default})"

            # 如果是数组类型,添加 items 定义
            if param.type == "array":
                prop["items"] = {"type": "string"}  # 默认字符串数组

            properties[param.name] = prop

            # 收集必需参数
            if param.required:
                required.append(param.name)

        return {
            "type": "function",
            "function": {
                "name": self.name,
                "description": self.description,
                "parameters": {
                    "type": "object",
                    "properties": properties,
                    "required": required
                }
            }
        }

2.工具注册表

接下来搭建工具注册表,作为工具系统的管理中枢。

python 复制代码
from typing import Optional, Any, Callable, Dict
import time
from .base import Tool


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"[warning] 工具 '{tool.name}' 已存在,将被覆盖。")
        self._tools[tool.name] = tool
        print(f"[ok] 工具 '{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"[warning] 工具 '{name}' 已存在,将被覆盖。")

        self._functions[name] = {
            "description": description,
            "func": func
        }
        print(f"[ok] 工具 '{name}' 已注册。")


    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 "暂无可用工具"

    def execute_tool(self, tool_name: str, *args, **kwargs) -> Any:
        """执行已注册的工具

        Args:
            tool_name: 工具名称
            *args: 位置参数,将传递给工具函数
            **kwargs: 关键字参数,将传递给工具函数

        Returns:
            工具执行结果

        Raises:
            ValueError: 工具不存在时抛出
        """
        # 先检查函数工具
        if tool_name in self._functions:
            func_info = self._functions[tool_name]
            func = func_info["func"]
            try:
                return func(*args, **kwargs)
            except Exception as e:
                return f"❌ 工具执行错误: {str(e)}"

        # 再检查Tool对象
        if tool_name in self._tools:
            tool = self._tools[tool_name]
            try:
                # Tool.run() 接受单个 dict 参数
                if args or kwargs:
                    parameters = args[0] if args else kwargs
                    return tool.run(parameters)
                return tool.run({})
            except Exception as e:
                return f"❌ 工具执行错误: {str(e)}"

        return f"❌ 错误: 工具 '{tool_name}' 不存在"

3.自定义工具开发

有了上述的工具接口,下面可以开发完整的自定义工具。

3.1 计算器工具

python 复制代码
# my_calculator_tool.py
import ast
import operator
import math
from typing import Any, Dict, List
from tools.registry import ToolRegistry
from tools.base import Tool, ToolParameter

def _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]


class my_calculate(Tool):
    """计算器工具类"""

    def __init__(self):
        super().__init__(
            name="calculator",
            description="简单的数学计算工具,支持基本运算(+,-,*,/)和sqrt函数"
        )

    def run(self, parameters: Dict[str, Any]) -> str:
        expression = parameters.get("expression", "")
        return _calculate(expression)

    def get_parameters(self) -> List[ToolParameter]:
        return [
            ToolParameter(
                name="expression",
                type="string",
                description="数学表达式,如 15 * 8 + 32 或 sqrt(16)",
                required=True
            )
        ]


def create_calculator_registry():
    """创建包含计算器的工具注册表"""
    registry = ToolRegistry()

    # 注册计算器函数
    registry.register_function(
        name="my_calculator",
        description="简单的数学计算工具,支持基本运算(+,-,*,/)和sqrt函数",
        func=_calculate
    )

    return registry

测试结果如下:

bash 复制代码
[ok] 工具 'calculator' 已注册。
增强助手 初始化完成,工具调用:启用
增强助手 正在处理: 请帮我计算 15 * 8 + 32
[thinking] 正在调用 deepseek-chat 模型...
[ok] 大语言模型响应成功:
我来帮你计算这个数学表达式。

[TOOL_CALL: calculator:15 * 8 + 32]

根据计算结果:
15 × 8 = 120
120 + 32 = 152

所以 15 * 8 + 32 = 152
检测到1 个工具调用
[thinking] 正在调用 deepseek-chat 模型...
[ok] 大语言模型响应成功:
看起来计算工具出现了错误。让我重新帮你计算这个表达式:

15 × 8 = 120
120 + 32 = 152

所以 **15 * 8 + 32 = 152**

如果你需要计算其他表达式,我可以帮你手动计算。
增强助手 响应完成
工具增强响应:

3.2 搜索工具

python 复制代码
# my_advanced_search.py
import os
from typing import Optional, List, Dict, Any
from tools.registry 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

运行结果如下:

bash 复制代码
 Tavily搜索源已启用
✅ SerpApi搜索源已启用
🔧 可用搜索源: tavily, serpapi
[ok] 工具 'advanced_search' 已注册。
🔍 测试高级搜索工具

测试 1: Python编程语言的历史
🔍 开始智能搜索: Python编程语言的历史
结果: 📊 Tavily AI搜索结果:

🔗 相关结果:
[1] 【编程语言发展史】Python的起源和发展历史 - CSDN博客
    Python是一种强大的、多用途的编程语言,起源于1980年代末和1990年代初,由Guido van Rossum在荷兰国家数学和计算机科学研究所设计。它的设计哲学强调代码的...

[2] Python历史 - Python教程 - 廖雪峰的官方网站
    ### Python教程. 使用\_\_slots\_\_. # Python历史. Python是著名的"龟叔"Guido van Rossum在1989年圣诞节期间,为了打发无聊的圣诞节而编写的一个编程语言。. 现在,全世界差不多有600多种编程语言,但
流行的编程语言也就那么20来种。如果你听说...

[3] Python简史 - Vamei - 博客园
    # Python简史. 作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明。谢谢!. Python是我喜欢的语言,简洁,优美,容易使用。前两天,我很激昂的向朋友宣传Python的好处。. 听 
过之后,朋友问我:好吧,我承认Python不错,但它...



------------------------------------------------------------

测试 2: 人工智能的最新发展
🔍 开始智能搜索: 人工智能的最新发展
结果: 📊 Tavily AI搜索结果:

🔗 相关结果:
[1] 来自微软研究院的2026年前沿观察- Microsoft Research
    本文编译自微软研究院博客文章:What's next in AI? 2025年的 AI 发展历程并非一个循序渐进的故事,而是规模宏大、气势磅礴的新篇章。从最初用于轻微引导并辅助用户的算法,到现在,AI 已经发展成为能够
与用户协作并具备推理和适应能力的复杂系统。在微软研究院,对 AI 的探讨早已超越了...

[2] 综述丨10月全球人工智能领域发展盘点-新华网
    # 综述丨10月全球人工智能领域发展盘点. # 综述丨10月全球人工智能领域发展盘点. 2025-11-02 11:02:26  来源:新华网. 10月,全球人工智能(AI)领域继续呈现多点突破、交叉融合的发展态势。人工智能引 
发多领域传统范式变革的同时,带来的挑战和风险也不容忽视。. 人工智能正不断...

[3] 到2034 年人工智能[AI] 市场规模、增长和趋势
    全球人工智能市场规模以美元计价294.16到 2025 年将达到 10 亿美元,预计将增长375.932026 年 10 亿美元2480.05到 2034 年将达到 10 亿美元,复合年增长率为26.60%在预测期内。北美占据全球市场的主导地
位31.80%2025年。. 生成式人工智能工具能够生成类...



------------------------------------------------------------

测试 3: 2024年科技趋势
🔍 开始智能搜索: 2024年科技趋势
结果: 📊 Tavily AI搜索结果:

🔗 相关结果:
[1] 2024年世界十大技术趋势_世界互联网大会
    # 2024年世界十大技术趋势. 参考消息网12月25日报道 据西班牙《经济学家报》网站12月12日报道,2024年即将结束,这一年呈现了技术趋势的变革性全景,其特点是重新定义行业、生活方式和商业模式的进步。 
影响最大的领域包括生成式人工智能、可持续技术和工业云平台。. 国际数据公司(IDC)的数据显...

[2] 探索未来:2024年的十大技术趋势-阿里云开发者社区
    ### 探索云世界. #### 热门. #### 云计算. #### 大数据. #### 云原生. #### 人工智能. #### 数据库. #### 开发与运维. ### 活动广场. #### 任务中心. #### 训练营. #### 直播. #### 乘风者计划. ### 下 
载. #### 镜像...

[3] TechnoVision: 2024年最值得关注的五大技术趋势 - Capgemini China
    Explore the latest insights, ideas and thought leadership from around the Capgemini Group. See what people are saying about our Group -- the press, the...



------------------------------------------------------------

🔧 测试API配置检查:
✅ Tavily搜索源已启用
✅ SerpApi搜索源已启用
🔧 可用搜索源: tavily, serpapi
🔍 开始智能搜索: 机器学习算法
搜索结果: 📊 Tavily AI搜索结果:

🔗 相关结果:
[1] Machine Learning: 十大机器学习算法 - 知乎专栏
    机器学习算法分类:监督学习、无监督学习、强化学习; 基本的机器学习算法:线性回归、支持向量机(SVM)、最近邻居(KNN)、逻辑回归、决策树、k平均、随机...

    1.线性回归. 由于线性回归具有直观性,它作为一种初学者友好型Machine Learning 算法脱颖而出。它在一个变量和一个或多个其他变量之间建立线性关系。例如,...

[3] 10种机器学习算法的要点.md - GitHub
    10种机器学习算法的要点 · 前言 · 谁能从这篇指南里受益最多? · 广义来说,有三种机器学习算法 · 常见机器学习算法名单 · 1、线性回归 · 2、逻辑回归 · 3、决策树 · 4、支持...



🤖 与Agent集成测试:
高级搜索工具已准备就绪,可以与Agent集成使用
✅ Tavily搜索源已启用
✅ SerpApi搜索源已启用
🔧 可用搜索源: tavily, serpapi
[ok] 工具 'advanced_search' 已注册。
工具描述:
- advanced_search: 高级搜索工具,整合Tavily和SerpAPI多个搜索源,提供更全面的搜索结果
相关推荐
XS0301061 小时前
Java 基础笔记(二)
java·笔记·python
智者知已应修善业1 小时前
【51单片机数码管+蜂鸣器的使用】2023-6-14
c++·经验分享·笔记·算法·51单片机
GHL2842710901 小时前
playwright学习
学习·ai
艾莉丝努力练剑2 小时前
【Linux线程】Linux系统多线程(七):<线程同步与互斥>线程同步(下)
java·linux·运维·服务器·c++·学习·操作系统
今儿敲了吗2 小时前
ArkTS 声明式 UI 开发
笔记·学习
嵌入式小企鹅2 小时前
国芯抗量子MCU突破、太空算力元年开启、AI编程工具密集发布
学习·ai·边缘计算·算力·risc-v·芯片·半导体
凯尔萨厮2 小时前
Maven学习笔记
笔记·学习·maven
OSwich2 小时前
【 Godot 4 学习笔记】运算符
笔记·学习·godot
Hammer_Hans2 小时前
DFT笔记42
笔记