Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

第 15 章:Agent 智能体开发

本章介绍 Agent(智能体)的核心概念、架构设计和开发实践。通过 DashScope 的 Function Calling 能力,构建能够自主规划、调用工具、与人协作的 AI Agent。

本章内容提要

主题核心技能
Agent 基础架构原理、ReAct 框架、自主决策
工具调用Function Calling、插件系统、工具注册
记忆管理短期记忆、长期记忆、记忆检索
多 Agent 协作Agent 编排、任务分解、结果聚合

15.1 Agent 架构原理

15.1.1 什么是 Agent?

Agent(智能体)是一种能够感知环境、做出决策并执行行动的智能系统。与简单的 LLM 调用不同,Agent 具有:

  • 自主性:能够独立规划和执行任务
  • 工具使用:可以调用外部工具和 API
  • 记忆能力:能够记忆和利用历史信息
  • 目标导向:能够分解复杂任务并逐步完成
graph TB
    A[用户输入] --> B[规划器 Planner]
    B --> C[决策 Decide]
    C --> D{执行什么?}
    D -->|思考| E[使用工具]
    D -->|回答| F[直接回复]
    E --> G[工具执行]
    G --> H[观察结果]
    H --> B
    F --> I[最终回答]
    H --> I
    
    J[记忆 Memory] <--> B
    J <--> E

15.1.2 ReAct 框架详解

ReAct(Reasoning + Acting)是最经典的 Agent 框架之一:

# src/agent/react.py
from typing import List, Dict, Any, Callable
from enum import Enum

class AgentAction(Enum):
    """Agent 可以执行的动作类型"""
    THINK = "think"      # 思考下一步
    ACT = "act"         # 执行工具
    OBSERVE = "observe" # 观察结果
    ANSWER = "answer"    # 生成最终答案

class ReActAgent:
    """基于 ReAct 框架的 Agent"""
    
    def __init__(
        self,
        llm_client,
        tools: List[Dict],
        max_iterations: int = 10
    ):
        self.llm = llm_client
        self.tools = tools
        self.max_iterations = max_iterations
        
        # 构建工具描述
        self.tool_descriptions = self._build_tool_description()
    
    def _build_tool_description(self) -> str:
        """构建工具描述字符串"""
        descriptions = []
        for i, tool in enumerate(self.tools):
            param_info = ", ".join([
                f"{p['name']}: {p['type']}"
                for p in tool.get('parameters', {}).get('properties', {}).values()
            ])
            descriptions.append(
                f"{i}. {tool['name']}: {tool['description']} (参数: {param_info})"
            )
        return "\n".join(descriptions)
    
    def run(self, user_input: str) -> Dict:
        """运行 Agent"""
        history = []
        context = ""
        
        for iteration in range(self.max_iterations):
            # 1. 生成思考
            thought = self._generate_thought(user_input, context, history)
            history.append({"role": "assistant", "content": thought})
            
            # 2. 决定下一步动作
            action = self._parse_action(thought)
            
            if action['type'] == 'answer':
                # 生成最终答案
                answer = self._generate_answer(user_input, context)
                return {
                    "answer": answer,
                    "thoughts": history,
                    "iterations": iteration + 1
                }
            
            elif action['type'] == 'tool':
                # 3. 执行工具
                tool_name = action['tool']
                tool_args = action['args']
                
                result = self._execute_tool(tool_name, tool_args)
                observation = f"观察结果: {result}"
                history.append({"role": "user", "content": observation})
                context += f"\n{observation}"
            
            else:  # think
                context += f"\n思考: {action['content']}"
        
        # 达到最大迭代次数
        return {
            "answer": "抱歉,我无法在规定步骤内完成任务。",
            "thoughts": history,
            "iterations": self.max_iterations
        }
    
    def _generate_thought(
        self,
        user_input: str,
        context: str,
        history: List[Dict]
    ) -> str:
        """生成思考和行动"""
        
        system_prompt = f"""你是一个能够自主思考和行动的 AI Agent。

当前时间: 2026-04-18

你拥有以下工具可以使用:
{self.tool_descriptions}

你必须按照以下格式思考和行动:

## 思考
分析当前情况,考虑是否需要使用工具来完成任务。

## 动作
根据思考结果,选择以下之一:
- tool: 使用工具。格式: tool: {{"tool": "工具名", "args": {{"参数": "值"}}}}
- answer: 直接回答用户问题。格式: answer: [你的回答]
- think: 继续思考。格式: think: [你的思考内容]

## 历史对话
{context if context else "无"}

## 用户问题
{user_input}

请开始推理:"""

        response = self.llm.chat([
            {"role": "system", "content": system_prompt}
        ])
        
        return response
    
    def _parse_action(self, thought: str) -> Dict:
        """解析思考内容中的动作"""
        import json
        import re
        
        # 查找动作指令
        patterns = [
            (r'tool:\s*(\{{[^}}]+\}})', 'tool'),
            (r'think:\s*(.+)', 'think'),
            (r'answer:\s*(.+)', 'answer'),
        ]
        
        for pattern, action_type in patterns:
            match = re.search(pattern, thought, re.DOTALL)
            if match:
                if action_type == 'tool':
                    try:
                        args = json.loads(match.group(1))
                        return {"type": "tool", "tool": args.get("tool"), "args": args.get("args", {})}
                    except:
                        return {"type": "think", "content": thought}
                elif action_type == 'think':
                    return {"type": "think", "content": match.group(1)}
                else:  # answer
                    return {"type": "answer", "content": match.group(1)}
        
        return {"type": "think", "content": thought}
    
    def _execute_tool(self, tool_name: str, args: Dict) -> Any:
        """执行工具"""
        for tool in self.tools:
            if tool['name'] == tool_name:
                return tool['function'](**args)
        
        return f"错误: 找不到工具 '{tool_name}'"
    
    def _generate_answer(
        self,
        user_input: str,
        context: str
    ) -> str:
        """生成最终答案"""
        prompt = f"""基于之前的推理过程,给出最终答案。

用户问题: {user_input}

推理过程:
{context}

请给出完整、准确的回答:"""

        return self.llm.chat([{"role": "user", "content": prompt}])

15.1.3 Agent 与 LLM 的区别

特性纯 LLMAgent
输入当前对话当前 + 历史 + 环境
输出文本思考 + 动作 + 文本
工具使用
多步推理有限完整
记忆能力对话窗口可扩展存储

15.2 Function Calling 实践

15.2.1 DashScope Function Calling

DashScope 支持 Function Calling,可以定义工具让模型调用:

# src/agent/tools/dashscope_tools.py
from typing import List, Dict, Any, Callable
import json

class DashScopeFunctionCaller:
    """DashScope Function Calling 封装"""
    
    def __init__(self, llm_client):
        self.llm = llm_client
        self.registered_tools: Dict[str, Callable] = {}
    
    def register_tool(
        self,
        name: str,
        description: str,
        parameters: Dict,
        function: Callable
    ):
        """注册工具"""
        self.registered_tools[name] = function
        
        # 构建函数定义
        if 'functions' not in self.__dict__:
            self.functions = []
        
        self.functions.append({
            "name": name,
            "description": description,
            "parameters": parameters
        })
    
    def chat_with_functions(
        self,
        messages: List[Dict],
        functions: List[Dict] = None
    ) -> Dict:
        """调用 LLM,支持函数调用"""
        if functions is None:
            functions = self.functions
        
        response = self.llm.chat(
            messages,
            functions=functions if functions else None
        )
        
        return response
    
    def run_with_tools(
        self,
        user_input: str,
        max_turns: int = 5
    ) -> Dict:
        """带工具调用的对话"""
        messages = [{"role": "user", "content": user_input}]
        iterations = 0
        
        while iterations < max_turns:
            # 调用 LLM
            response = self.chat_with_functions(messages)
            
            if response.get('function_call'):
                # 解析函数调用
                func_name = response['function_call']['name']
                func_args = json.loads(response['function_call']['arguments'])
                
                # 添加助手消息
                messages.append({
                    "role": "assistant",
                    "content": response.get('output') or "",
                    "function_call": {
                        "name": func_name,
                        "arguments": response['function_call']['arguments']
                    }
                })
                
                # 执行函数
                if func_name in self.registered_tools:
                    func_result = self.registered_tools[func_name](**func_args)
                else:
                    func_result = f"错误: 未知函数 {func_name}"
                
                # 添加函数结果
                messages.append({
                    "role": "function",
                    "name": func_name,
                    "content": str(func_result)
                })
                
                iterations += 1
            else:
                # 无函数调用,直接返回
                return {
                    "answer": response.get('output', response.get('text', '')),
                    "iterations": iterations,
                    "function_calls": []
                }
        
        return {
            "answer": "已达到最大迭代次数",
            "iterations": iterations
        }

15.2.2 常用工具定义

以下是几个常用的工具定义示例:

# 定义搜索工具
search_tool = {
    "name": "search_knowledge_base",
    "description": "搜索知识库获取相关信息。当用户询问具体知识点、产品功能、政策法规等内容时使用。",
    "parameters": {
        "type": "object",
        "properties": {
            "query": {
                "type": "string",
                "description": "搜索查询词"
            },
            "top_k": {
                "type": "integer",
                "description": "返回结果数量,默认 5",
                "default": 5
            }
        },
        "required": ["query"]
    }
}

# 定义数据库查询工具
db_query_tool = {
    "name": "query_database",
    "description": "查询数据库获取结构化数据。用于用户询问具体数据、数值、统计信息时使用。",
    "parameters": {
        "type": "object",
        "properties": {
            "sql": {
                "type": "string",
                "description": "SQL 查询语句"
            },
            "params": {
                "type": "object",
                "description": "查询参数"
            }
        },
        "required": ["sql"]
    }
}

# 定义计算工具
calculator_tool = {
    "name": "calculate",
    "description": "执行数学计算。用于需要精确计算的场景,如费用计算、统计分析等。",
    "parameters": {
        "type": "object",
        "properties": {
            "expression": {
                "type": "string",
                "description": "数学表达式,如 '100 * 0.05 * 30'"
            }
        },
        "required": ["expression"]
    }
}

# 定义发送通知工具
notification_tool = {
    "name": "send_notification",
    "description": "发送通知给用户。支持邮件、短信、应用内通知。",
    "parameters": {
        "type": "object",
        "properties": {
            "channel": {
                "type": "string",
                "enum": ["email", "sms", "app"],
                "description": "通知渠道"
            },
            "recipient": {
                "type": "string",
                "description": "接收人标识"
            },
            "title": {
                "type": "string",
                "description": "通知标题"
            },
            "content": {
                "type": "string",
                "description": "通知内容"
            }
        },
        "required": ["channel", "recipient", "content"]
    }
}

15.2.3 工具执行函数实现

# 工具函数实现
def search_knowledge_base(query: str, top_k: int = 5) -> str:
    """知识库搜索实现"""
    from your_rag_module import KnowledgeBase
    
    kb = KnowledgeBase("/path/to/knowledge_base")
    results = kb.search(query, top_k=top_k)
    
    if not results:
        return "未找到相关信息"
    
    formatted = []
    for i, r in enumerate(results, 1):
        formatted.append(f"{i}. {r['content'][:200]}...")
    
    return "\n".join(formatted)


def query_database(sql: str, params: dict = None) -> str:
    """数据库查询实现"""
    import sqlite3
    
    conn = sqlite3.connect("/path/to/database.db")
    cursor = conn.cursor()
    
    try:
        cursor.execute(sql, params or {})
        rows = cursor.fetchall()
        columns = [desc[0] for desc in cursor.description]
        
        if not rows:
            return "查询结果为空"
        
        # 格式化结果
        result = [f"列: {', '.join(columns)}"]
        for row in rows[:10]:  # 限制返回行数
            result.append(", ".join(str(v) for v in row))
        
        return "\n".join(result)
    finally:
        conn.close()


def calculate(expression: str) -> str:
    """数学计算实现"""
    import math
    import operator
    
    # 安全计算(限制可用函数)
    safe_dict = {
        "abs": abs,
        "round": round,
        "min": min,
        "max": max,
        "sum": sum,
        "pow": pow,
        "pi": math.pi,
        "e": math.e,
        "sqrt": math.sqrt,
        "sin": math.sin,
        "cos": math.cos,
        "log": math.log,
    }
    
    try:
        result = eval(expression, {"__builtins__": {}}, safe_dict)
        return f"计算结果: {result}"
    except Exception as e:
        return f"计算错误: {str(e)}"


def send_notification(
    channel: str,
    recipient: str,
    title: str,
    content: str
) -> str:
    """发送通知实现"""
    if channel == "email":
        # 使用邮件服务发送
        return f"邮件已发送给 {recipient}: {title}"
    elif channel == "sms":
        return f"短信已发送给 {recipient}"
    elif channel == "app":
        return f"应用通知已发送给 {recipient}"
    else:
        return f"不支持的通知渠道: {channel}"

15.3 Agent 记忆管理

15.3.1 记忆系统架构

Agent 需要管理多种类型的记忆:

graph TB
    A[用户输入] --> S[感知记忆]
    S --> W[工作记忆]
    W --> L[长期记忆]
    L --> W
    
    subgraph 工作记忆
    W1[当前对话]
    W2[当前任务]
    W3[上下文]
    end
    
    subgraph 长期记忆
    L1[会话历史]
    L2[知识存储]
    L3[偏好设置]
    L4[技能索引]
    end

15.3.2 记忆实现

# src/agent/memory.py
from typing import List, Dict, Any, Optional
from datetime import datetime
import json
from pathlib import Path

class AgentMemory:
    """Agent 记忆系统"""
    
    def __init__(self, storage_path: Optional[str] = None):
        self.storage_path = Path(storage_path) if storage_path else None
        if self.storage_path:
            self.storage_path.mkdir(parents=True, exist_ok=True)
        
        # 工作记忆(当前上下文)
        self.working_memory = {
            'conversation': [],
            'current_task': None,
            'context': {}
        }
        
        # 长期记忆索引
        self.memory_index = {
            'episodes': [],      # 情节记忆
            'knowledge': [],      # 知识
            'preferences': {},    # 偏好
            'skills': []          # 技能
        }
        
        self._load_memory()
    
    def _load_memory(self):
        """加载持久化的记忆"""
        if self.storage_path and (self.storage_path / "memory.json").exists():
            with open(self.storage_path / "memory.json") as f:
                self.memory_index = json.load(f)
    
    def _save_memory(self):
        """保存记忆到磁盘"""
        if self.storage_path:
            with open(self.storage_path / "memory.json", "w") as f:
                json.dump(self.memory_index, f, ensure_ascii=False, indent=2)
    
    # ========== 工作记忆 ==========
    
    def add_working_memory(self, role: str, content: str):
        """添加到工作记忆"""
        self.working_memory['conversation'].append({
            'role': role,
            'content': content,
            'timestamp': datetime.now().isoformat()
        })
    
    def get_conversation_context(
        self,
        max_turns: int = 10
    ) -> List[Dict]:
        """获取最近对话上下文"""
        return self.working_memory['conversation'][-max_turns:]
    
    def set_current_task(self, task: str):
        """设置当前任务"""
        self.working_memory['current_task'] = {
            'task': task,
            'started_at': datetime.now().isoformat(),
            'steps': []
        }
    
    def add_task_step(self, step: str):
        """添加任务步骤"""
        if self.working_memory['current_task']:
            self.working_memory['current_task']['steps'].append({
                'step': step,
                'timestamp': datetime.now().isoformat()
            })
    
    def get_task_progress(self) -> str:
        """获取任务进度"""
        task = self.working_memory.get('current_task')
        if not task:
            return "无进行中的任务"
        
        steps = task.get('steps', [])
        return f"任务: {task['task']}\n进度: {len(steps)} 步骤已完成"
    
    # ========== 长期记忆 ==========
    
    def store_episode(
        self,
        situation: str,
        action: str,
        result: str,
        reflection: Optional[str] = None
    ):
        """存储情节记忆"""
        episode = {
            'type': 'episode',
            'situation': situation,
            'action': action,
            'result': result,
            'reflection': reflection,
            'created_at': datetime.now().isoformat(),
            'access_count': 0
        }
        self.memory_index['episodes'].append(episode)
        self._save_memory()
    
    def store_knowledge(
        self,
        topic: str,
        content: str,
        source: Optional[str] = None
    ):
        """存储知识"""
        # 检查是否已存在
        for item in self.memory_index['knowledge']:
            if item['topic'] == topic:
                item['content'] = content
                item['updated_at'] = datetime.now().isoformat()
                self._save_memory()
                return
        
        # 新增知识
        self.memory_index['knowledge'].append({
            'type': 'knowledge',
            'topic': topic,
            'content': content,
            'source': source,
            'created_at': datetime.now().isoformat()
        })
        self._save_memory()
    
    def retrieve_memories(
        self,
        query: str,
        memory_types: List[str] = None,
        top_k: int = 5
    ) -> List[Dict]:
        """检索相关记忆(简化版,实际应该用 embedding)"""
        if memory_types is None:
            memory_types = ['episodes', 'knowledge']
        
        results = []
        
        for mem_type in memory_types:
            if mem_type == 'episodes':
                for ep in self.memory_index.get('episodes', []):
                    if query.lower() in ep['situation'].lower() or \
                       query.lower() in ep['action'].lower():
                        ep['access_count'] += 1
                        results.append(ep)
            
            elif mem_type == 'knowledge':
                for kw in self.memory_index.get('knowledge', []):
                    if query.lower() in kw['topic'].lower() or \
                       query.lower() in kw['content'].lower():
                        results.append(kw)
        
        # 按访问频率和相关性排序
        results.sort(key=lambda x: x.get('access_count', 0), reverse=True)
        return results[:top_k]
    
    def update_preference(self, key: str, value: Any):
        """更新偏好设置"""
        self.memory_index['preferences'][key] = value
        self._save_memory()
    
    def get_preference(self, key: str, default: Any = None) -> Any:
        """获取偏好设置"""
        return self.memory_index['preferences'].get(key, default)
    
    def summarize_and_consolidate(self, llm_client) -> str:
        """总结和整合记忆(定期调用)"""
        if not self.working_memory['conversation']:
            return "无需整合"
        
        # 提取关键信息
        summary_prompt = f"""总结以下对话中的关键信息,包括:
1. 用户的主要需求
2. 完成任务的关键步骤
3. 重要的中间结果
4. 最终答案

对话:
{json.dumps(self.working_memory['conversation'], ensure_ascii=False)}

总结(JSON格式):"""

        summary = llm_client.chat([{"role": "user", "content": summary_prompt}])
        
        # 存储为情节记忆
        self.store_episode(
            situation=f"用户询问了关于{self.working_memory['conversation'][0]['content'][:50]}...",
            action="执行了多步推理",
            result=summary[:200],
            reflection="这是一个有效的解决方案"
        )
        
        # 清空当前对话
        self.working_memory['conversation'] = []
        
        return summary

15.4 工具注册与管理

15.4.1 工具注册中心

# src/agent/tool_registry.py
from typing import Dict, Callable, List, Any
from dataclasses import dataclass
import json

@dataclass
class ToolDefinition:
    """工具定义"""
    name: str
    description: str
    parameters: Dict
    function: Callable
    tags: List[str] = None
    
    def __post_init__(self):
        if self.tags is None:
            self.tags = []

class ToolRegistry:
    """工具注册中心"""
    
    def __init__(self):
        self._tools: Dict[str, ToolDefinition] = {}
        self._tags: Dict[str, List[str]] = {}  # tag -> tool names
    
    def register(
        self,
        name: str,
        description: str,
        parameters: Dict,
        function: Callable,
        tags: List[str] = None
    ):
        """注册工具"""
        tool = ToolDefinition(
            name=name,
            description=description,
            parameters=parameters,
            function=function,
            tags=tags or []
        )
        
        self._tools[name] = tool
        
        # 更新标签索引
        for tag in tool.tags:
            if tag not in self._tags:
                self._tags[tag] = []
            self._tags[tag].append(name)
    
    def get_tool(self, name: str) -> ToolDefinition:
        """获取工具定义"""
        return self._tools.get(name)
    
    def get_all_tools(self) -> List[Dict]:
        """获取所有工具定义(用于 LLM)"""
        return [
            {
                "name": t.name,
                "description": t.description,
                "parameters": t.parameters
            }
            for t in self._tools.values()
        ]
    
    def get_tools_by_tag(self, tag: str) -> List[ToolDefinition]:
        """根据标签获取工具"""
        tool_names = self._tags.get(tag, [])
        return [self._tools[name] for name in tool_names]
    
    def execute(self, name: str, **kwargs) -> Any:
        """执行工具"""
        tool = self._tools.get(name)
        if not tool:
            raise ValueError(f"未知工具: {name}")
        
        return tool.function(**kwargs)
    
    def get_tool_schema(self) -> str:
        """获取工具 schema(用于文档生成)"""
        schemas = []
        for tool in self._tools.values():
            schema = {
                "name": tool.name,
                "description": tool.description,
                "parameters": tool.parameters
            }
            schemas.append(schema)
        
        return json.dumps(schemas, ensure_ascii=False, indent=2)


# 全局注册中心
_global_registry = ToolRegistry()

def get_registry() -> ToolRegistry:
    return _global_registry

def register_tool(
    description: str,
    parameters: Dict,
    tags: List[str] = None
):
    """装饰器注册工具"""
    def decorator(func: Callable):
        _global_registry.register(
            name=func.__name__,
            description=description,
            parameters=parameters,
            function=func,
            tags=tags
        )
        return func
    return decorator

15.4.2 工具使用示例

# examples/agent_tools_demo.py
from src.agent.tool_registry import get_registry, register_tool

registry = get_registry()

# 注册工具
@register_tool(
    description="获取当前日期和时间",
    parameters={
        "type": "object",
        "properties": {},
        "required": []
    },
    tags=["utility", "time"]
)
def get_current_time():
    from datetime import datetime
    return datetime.now().strftime("%Y-%m-%d %H:%M:%S")

@register_tool(
    description="搜索互联网获取实时信息",
    parameters={
        "type": "object",
        "properties": {
            "query": {
                "type": "string",
                "description": "搜索关键词"
            }
        },
        "required": ["query"]
    },
    tags=["search"]
)
def web_search(query: str):
    # 实际实现调用搜索 API
    return f"搜索结果: 关于'{query}'的信息..."

@register_tool(
    description="发送邮件",
    parameters={
        "type": "object",
        "properties": {
            "to": {"type": "string", "description": "收件人邮箱"},
            "subject": {"type": "string", "description": "邮件主题"},
            "body": {"type": "string", "description": "邮件正文"}
        },
        "required": ["to", "subject", "body"]
    },
    tags=["communication"]
)
def send_email(to: str, subject: str, body: str):
    return f"邮件已发送给 {to}: {subject}"

15.5 多 Agent 协作

15.5.1 Agent 编排模式

复杂任务可以由多个 Agent 协作完成:

graph TB
    A[用户请求] --> O[编排器 Orchestrator]
    O --> T1[任务分解]
    T1 --> T2[任务 A]
    T1 --> T3[任务 B]
    T1 --> T4[任务 C]
    T2 --> R[结果聚合]
    T3 --> R
    T4 --> R
    R --> A2[答案生成]
    A2 --> F[最终输出]

15.5.2 简单编排器实现

# src/agent/orchestrator.py
from typing import List, Dict, Any, Callable
from dataclasses import dataclass
from concurrent.futures import ThreadPoolExecutor
import asyncio

@dataclass
class SubAgent:
    """子 Agent 定义"""
    name: str
    description: str
    system_prompt: str
    tools: List[Dict]
    executor: Callable  # 执行函数

class AgentOrchestrator:
    """Agent 编排器"""
    
    def __init__(self, llm_client):
        self.llm = llm_client
        self.agents: Dict[str, SubAgent] = {}
    
    def register_agent(self, agent: SubAgent):
        """注册子 Agent"""
        self.agents[agent.name] = agent
    
    async def orchestrate(
        self,
        task: str,
        agent_names: List[str] = None
    ) -> Dict:
        """编排任务执行"""
        
        # 1. 任务分析
        if agent_names is None:
            agent_names = self._route_task(task)
        
        # 2. 并行执行子任务
        results = await self._execute_parallel(task, agent_names)
        
        # 3. 聚合结果
        aggregated = self._aggregate_results(task, results)
        
        return {
            "task": task,
            "sub_results": results,
            "final_answer": aggregated
        }
    
    def _route_task(self, task: str) -> List[str]:
        """任务路由 - 确定需要哪些 Agent"""
        # 使用 LLM 判断
        prompt = f"""分析以下任务,确定需要哪些专业 Agent 协作完成。

任务: {task}

可用 Agent:
{self._list_agents()}

请列出需要的 Agent 名称(逗号分隔),每个任务建议 1-3 个 Agent:"""

        response = self.llm.chat([{"role": "user", "content": prompt}])
        
        # 解析响应,提取 Agent 名称
        agent_names = []
        for name in self.agents.keys():
            if name in response:
                agent_names.append(name)
        
        return agent_names if agent_names else ["general"]
    
    def _list_agents(self) -> str:
        """列出所有 Agent"""
        return "\n".join([
            f"- {name}: {agent.description}"
            for name, agent in self.agents.items()
        ])
    
    async def _execute_parallel(
        self,
        task: str,
        agent_names: List[str]
    ) -> Dict[str, Any]:
        """并行执行多个子 Agent"""
        results = {}
        
        async def run_agent(name: str):
            agent = self.agents.get(name)
            if not agent:
                return name, {"error": f"Agent {name} 不存在"}
            
            # 构建 Agent prompt
            full_prompt = f"{agent.system_prompt}\n\n任务: {task}"
            
            # 使用 ReAct 或直接调用
            result = await self._run_agent_task(agent, task)
            return name, result
        
        # 并发执行
        tasks = [run_agent(name) for name in agent_names]
        completed = await asyncio.gather(*tasks, return_exceptions=True)
        
        for item in completed:
            if isinstance(item, tuple):
                name, result = item
                results[name] = result
            elif isinstance(item, Exception):
                results["error"] = str(item)
        
        return results
    
    async def _run_agent_task(
        self,
        agent: SubAgent,
        task: str
    ) -> str:
        """运行单个 Agent 任务"""
        # 简化实现:直接调用 LLM
        messages = [
            {"role": "system", "content": agent.system_prompt},
            {"role": "user", "content": task}
        ]
        
        response = self.llm.chat(messages, functions=agent.tools)
        return response.get('output', str(response))
    
    def _aggregate_results(
        self,
        task: str,
        results: Dict[str, Any]
    ) -> str:
        """聚合子 Agent 结果"""
        # 构建聚合 prompt
        result_text = "\n\n".join([
            f"=== {name} 的结果 ===\n{result}"
            for name, result in results.items()
        ])
        
        aggregation_prompt = f"""基于以下多个 Agent 的分析结果,给出综合性的最终答案。

原始任务: {task}

各 Agent 分析:
{result_text}

要求:
1. 综合各方观点
2. 突出关键发现
3. 给出明确结论
4. 如有分歧,说明权衡

最终答案:"""

        return self.llm.chat([{"role": "user", "content": aggregation_prompt}])

15.5.3 协作示例:校园助手

# examples/campus_assistant_orchestrator.py
from src.agent.orchestrator import AgentOrchestrator, SubAgent
from src.agent.tools.dashscope_tools import DashScopeFunctionCaller

# 创建编排器
orchestrator = AgentOrchestrator(dashscope_llm)

# 注册课程 Agent
orchestrator.register_agent(SubAgent(
    name="course_agent",
    description="课程咨询 Agent",
    system_prompt="你是一个课程顾问,专注于回答课程相关问题,包括选课、教学计划、课程内容等。",
    tools=[search_tool, get_course_info_tool],
    executor=None
))

# 注册图书馆 Agent
orchestrator.register_agent(SubAgent(
    name="library_agent",
    description="图书馆服务 Agent",
    system_prompt="你是一个图书馆助手,帮助查找图书、期刊、数据库资源。",
    tools=[search_book_tool, check_availability_tool],
    executor=None
))

# 注册行政 Agent
orchestrator.register_agent(SubAgent(
    name="admin_agent",
    description="行政服务 Agent",
    system_prompt="你处理请假、证明办理、缴费等行政事务。",
    tools=[query_policy_tool, submit_form_tool],
    executor=None
))

# 用户请求需要多个 Agent 协作
result = await orchestrator.orchestrate(
    "我下周要参加一个学术会议,想申请请假,同时想借一些相关的参考资料"
)

print(result["final_answer"])

15.6 完整 Agent 系统

15.6.1 系统架构

# src/agent/campus_agent.py
from typing import List, Dict, Optional
import json

class CampusAssistantAgent:
    """校园助手 Agent 完整实现"""
    
    def __init__(self, config: Dict):
        # 初始化各组件
        self.llm = self._init_llm(config['dashscope_api_key'])
        self.memory = AgentMemory(config.get('memory_path'))
        self.tools = self._register_tools()
        self.function_caller = DashScopeFunctionCaller(self.llm)
        
        # 注册工具
        for tool in self.tools:
            self.function_caller.register_tool(
                name=tool['name'],
                description=tool['description'],
                parameters=tool['parameters'],
                function=tool['function']
            )
    
    def _init_llm(self, api_key: str):
        """初始化 LLM 客户端"""
        import dashscope
        dashscope.api_key = api_key
        return dashscope
    
    def _register_tools(self) -> List[Dict]:
        """注册可用工具"""
        return [
            {
                "name": "search_knowledge_base",
                "description": "搜索校园知识库获取相关信息",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "query": {"type": "string", "description": "搜索查询"}
                    },
                    "required": ["query"]
                },
                "function": self._search_kb
            },
            {
                "name": "get_schedule",
                "description": "获取课程表或日程安排",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "date": {"type": "string", "description": "日期 (YYYY-MM-DD)"},
                        "user_id": {"type": "string", "description": "用户 ID"}
                    },
                    "required": ["date"]
                },
                "function": self._get_schedule
            },
            {
                "name": "book_room",
                "description": "预约会议室或自习室",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "room_id": {"type": "string", "description": "房间 ID"},
                        "date": {"type": "string", "description": "日期"},
                        "time_slot": {"type": "string", "description": "时间段"}
                    },
                    "required": ["room_id", "date", "time_slot"]
                },
                "function": self._book_room
            },
            {
                "name": "send_notification",
                "description": "发送通知提醒",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "user_id": {"type": "string"},
                        "message": {"type": "string", "description": "通知内容"}
                    },
                    "required": ["user_id", "message"]
                },
                "function": self._send_notification
            }
        ]
    
    # 工具函数实现
    def _search_kb(self, query: str) -> str:
        """搜索知识库"""
        # 实现知识库搜索
        return f"知识库搜索结果: {query}"
    
    def _get_schedule(self, date: str, user_id: str = None) -> str:
        """获取日程"""
        return f"{date} 的日程安排"
    
    def _book_room(self, room_id: str, date: str, time_slot: str) -> str:
        """预约房间"""
        return f"已预约 {room_id},日期: {date},时间段: {time_slot}"
    
    def _send_notification(self, user_id: str, message: str) -> str:
        """发送通知"""
        return f"通知已发送给 {user_id}: {message}"
    
    def chat(self, user_input: str) -> Dict:
        """对话接口"""
        # 添加到工作记忆
        self.memory.add_working_memory("user", user_input)
        
        # 检查长期记忆
        relevant_memories = self.memory.retrieve_memories(user_input)
        if relevant_memories:
            context_hint = "\n\n相关记忆:\n" + "\n".join([
                f"- {m.get('content', m.get('result', ''))[:100]}"
                for m in relevant_memories[:3]
            ])
        else:
            context_hint = ""
        
        # 扩展用户输入
        enhanced_input = user_input + context_hint
        
        # 带工具调用
        result = self.function_caller.run_with_tools(enhanced_input)
        
        # 添加到记忆
        self.memory.add_working_memory("assistant", result['answer'])
        
        # 如果是多轮交互结束,整理记忆
        if len(self.memory.working_memory['conversation']) >= 10:
            self.memory.summarize_and_consolidate(self.llm)
        
        return result

15.6.2 使用示例

# 使用示例
if __name__ == "__main__":
    agent = CampusAssistantAgent({
        'dashscope_api_key': 'your-api-key',
        'memory_path': './memory'
    })
    
    # 对话
    response = agent.chat("我想查一下明天的课程安排")
    print("助手:", response['answer'])
    
    response = agent.chat("顺便帮我预约一个自习室,下午 3 点到 5 点")
    print("助手:", response['answer'])

15.7 本章小结

本章介绍了 Agent 智能体开发的核心内容:

主题核心要点
Agent 基础自主性、工具使用、记忆能力、目标导向
ReAct 框架思考→动作→观察循环
Function CallingDashScope 工具调用、函数定义与执行
记忆管理工作记忆、长期记忆、记忆检索
多 Agent 协作任务分解、并行执行、结果聚合

进阶学习路径

  1. 自主规划:引入 Planning 模块,实现复杂任务的自动分解
  2. 持续学习:让 Agent 从交互中持续学习和改进
  3. 安全控制:添加权限控制、审计日志等安全机制

延伸阅读