Hello-Agents 第二部分-第六章:框架开发实践

作者:逆境不可逃

技术永无止境

希望我的内容可以帮助到你!!!!!


大家吼 ! 我是 逆境不可逃 今天给大家带来文章**《Hello-Agents 第二部分-第四章总结:智能体经典范式构建》.**

Hello-Agents 官方地址: datawhalechina/hello-agents: 📚 《从零开始构建智能体》------从零开始的智能体原理与实践教程

1. 本章主线

第四章从零实现了 ReAct、Plan-and-Solve、Reflection,重点是理解 Agent Loop 的底层机制;第五章体验低代码平台,重点是快速搭建。本章进入框架开发实践:使用成熟智能体框架,把通用能力交给框架,把开发者注意力集中到角色、流程、工具、状态和业务逻辑上。

一个智能体框架的价值,不只是少写代码,而是提供一套可复用的工程规范:

  • 模型层:统一接入不同 LLM 后端;
  • 工具层:标准化工具定义、注册、调用和错误处理;
  • 状态层:管理对话历史、中间结果、任务进度和持久化;
  • 协作层:组织单智能体或多智能体之间的消息交互;
  • 可观测层:记录事件、消息、工具调用和执行轨迹;
  • 部署层:支持异步、并发、分布式、恢复和监控。

第六章选择了四个代表性框架:

框架 核心思想 更适合的任务
AutoGen 用对话驱动多智能体协作 软件开发团队、角色分工、群聊式协作
AgentScope 工程化优先的消息驱动多智能体平台 大规模、高并发、分布式、多角色交互
CAMEL 角色扮演和引导性提示激发协作 双智能体深度协作、创作、研究、头脑风暴
LangGraph 把智能体流程建模为状态机和有向图 可控流程、循环、反思、测试修复、审计场景

可以用一句话记住它们的差异:

复制代码
AutoGen:     把任务变成一场多角色会议
AgentScope: 把多智能体系统做成工程化消息网络
CAMEL:       用角色扮演让专家智能体自主协作
LangGraph:   用图和状态机精确控制每一步

2. 为什么需要智能体框架

手写 Agent Loop 适合教学和原型,但当任务变复杂后,重复问题会迅速出现:

  • 每个 Agent 都要写模型调用、历史管理、工具分发;
  • 多智能体之间需要消息路由、状态同步、终止条件;
  • 工具调用失败、模型输出格式错误、循环失控需要统一处理;
  • 线上系统需要日志、追踪、恢复、并发和权限边界;
  • 复杂流程需要可视化、可测试、可审计。

框架的本质是把这些重复部分封装为稳定抽象。第六章的核心不是 "哪个框架最好",而是理解不同框架背后的设计取舍:

取舍维度 涌现式协作 显式控制
代表框架 AutoGen、CAMEL LangGraph
开发重点 定义角色和目标 定义状态、节点和边
优点 自然、灵活、像人类协作 可控、可测、可审计
风险 不确定性高,调试依赖对话历史 前期样板代码更多

AgentScope 则强调另一个维度:工程化。它关注的是多智能体系统从 "能跑" 到 "能稳定服务" 的问题,包括异步、消息驱动、分布式和容错。

3. chapter6 代码目录

官方代码目录包含四个示例:

复制代码
chapter6/
  AutoGenDemo/
    autogen_software_team.py
    output.py
    README.md
    requirements.txt
  AgentScopeDemo/
    main_cn.py
    prompt_cn.py
    game_roles.py
    structured_output_cn.py
    utils_cn.py
    README.md
    requirements.txt
  CAMEL/
    DigitalBookWriting.py
    requirements.txt
  Langgraph/
    Dialogue_System.py
    requirements.txt

依赖摘要:

复制代码
AutoGenDemo:    autogen-agentchat, autogen-ext[openai,azure], streamlit, requests
AgentScopeDemo: agentscope==1.0.2
CAMEL:          camel-ai==0.2.75
Langgraph:      langgraph==1.0.0a3, langchain_openai, tavily-python

4. AutoGen:对话驱动的软件开发团队

4.1 核心机制

AutoGen 的核心抽象是 "可对话智能体"。开发者定义多个角色,让它们通过消息自动协作。第六章以 AutoGen 0.7.4 的新架构为例,强调两点:

  • 分层架构:autogen-core 负责底层模型交互和消息传递,autogen-agentchat 提供对话式智能体高级接口;
  • 异步优先:多智能体协作中 LLM 调用是主要耗时点,async/await 能避免阻塞。

案例目标:构建一个软件开发团队,自动完成 "比特币价格显示应用" 的需求分析、代码实现、审查和测试。

团队角色:

角色 类 职责
产品经理 AssistantAgent 需求分析、功能拆解、验收标准
软件工程师 AssistantAgent 编写完整可运行代码
代码审查员 AssistantAgent 审查代码质量、安全性、最佳实践
用户代理 UserProxyAgent 代表用户测试,负责终止流程

4.2 模型客户端配置

来自 AutoGenDemo/autogen_software_team.py:

复制代码
import os
from dotenv import load_dotenv
from autogen_ext.models.openai import OpenAIChatCompletionClient

load_dotenv()


def create_openai_model_client():
    """创建 OpenAI 兼容模型客户端。"""
    return OpenAIChatCompletionClient(
        model=os.getenv("LLM_MODEL_ID", "gpt-4o"),
        api_key=os.getenv("LLM_API_KEY"),
        base_url=os.getenv("LLM_BASE_URL", "https://api.openai.com/v1"),
    )

这个函数把模型服务隔离成统一客户端,后续每个 Agent 都复用它。这样可以切换 OpenAI、Azure OpenAI、本地兼容服务或第三方模型服务。

4.3 定义团队角色

产品经理的系统消息:

复制代码
from autogen_agentchat.agents import AssistantAgent, UserProxyAgent


def create_product_manager(model_client):
    system_message = """你是一位经验丰富的产品经理,专门负责软件产品的需求分析和项目规划。

你的核心职责包括:
1. 需求分析:深入理解用户需求,识别核心功能和边界条件
2. 技术规划:基于需求制定清晰的技术实现路径
3. 风险评估:识别潜在的技术风险和用户体验问题
4. 协调沟通:与工程师和其他团队成员进行有效沟通

当接到开发任务时,请按以下结构进行分析:
1. 需求理解与分析
2. 功能模块划分
3. 技术选型建议
4. 实现优先级排序
5. 验收标准定义

请简洁明了地回应,并在分析完成后说"请工程师开始实现"。"""

    return AssistantAgent(
        name="ProductManager",
        model_client=model_client,
        system_message=system_message,
    )

工程师和审查员同样通过 system_message 定义职责。AutoGen 的关键不是写复杂状态机,而是把团队中 "谁负责什么" 描述清楚。

用户代理:

复制代码
def create_user_proxy():
    """创建用户代理智能体。"""
    return UserProxyAgent(
        name="UserProxy",
        description="""用户代理,负责以下职责:
1. 代表用户提出开发需求
2. 执行最终的代码实现
3. 验证功能是否符合预期
4. 提供用户反馈和建议

完成测试后请回复 TERMINATE。""",
    )

UserProxyAgent 是 AutoGen 中很重要的设计:它既可以代表人类发起需求,也可以作为执行器或人工在环接口,让对话式协作不完全脱离真实执行。

4.4 组织群聊与终止条件

复制代码
import asyncio
from autogen_agentchat.teams import RoundRobinGroupChat
from autogen_agentchat.conditions import TextMentionTermination
from autogen_agentchat.ui import Console


async def run_software_development_team():
    model_client = create_openai_model_client()

    product_manager = create_product_manager(model_client)
    engineer = create_engineer(model_client)
    code_reviewer = create_code_reviewer(model_client)
    user_proxy = create_user_proxy()

    termination = TextMentionTermination("TERMINATE")

    team_chat = RoundRobinGroupChat(
        participants=[
            product_manager,
            engineer,
            code_reviewer,
            user_proxy,
        ],
        termination_condition=termination,
        max_turns=20,
    )

    task = """我们需要开发一个比特币价格显示应用,具体要求如下:

核心功能:
- 实时显示比特币当前价格(USD)
- 显示24小时价格变化趋势(涨跌幅和涨跌额)
- 提供价格刷新功能

技术要求:
- 使用 Streamlit 框架创建 Web 应用
- 界面简洁美观,用户友好
- 添加适当的错误处理和加载状态

请团队协作完成这个任务,从需求分析到最终实现。"""

    result = await Console(team_chat.run_stream(task=task))
    return result


if __name__ == "__main__":
    asyncio.run(run_software_development_team())

这里的关键组件:

  • RoundRobinGroupChat:按固定顺序让成员轮流发言;
  • TextMentionTermination("TERMINATE"):检测到终止词后结束协作;
  • Console(team_chat.run_stream(...)):流式展示协作过程。

4.5 团队生成的应用代码

AutoGenDemo/output.py 是团队协作生成的 Streamlit 比特币价格应用:

复制代码
import streamlit as st
import requests


def get_bitcoin_price():
    try:
        response = requests.get(
            "https://api.coingecko.com/api/v3/simple/price"
            "?ids=bitcoin&vs_currencies=usd&include_24hr_change=true"
        )
        data = response.json()
        current_price = data["bitcoin"]["usd"]
        price_change_percentage = data["bitcoin"]["usd_24h_change"]
        return current_price, price_change_percentage
    except requests.exceptions.RequestException as e:
        st.error(f"Error fetching data: {e}")
        return None, None


st.title("实时比特币价格")
st.subheader("获取最新的比特币价格信息及其24小时价格变化趋势")

if st.button("刷新价格"):
    st.experimental_rerun()

with st.spinner("加载中..."):
    current_price, price_change_percentage = get_bitcoin_price()

if current_price is not None:
    st.metric(label="当前比特币价格 (USD)", value=f"${current_price}")
    if price_change_percentage is not None:
        st.metric(label="24小时变化 (%)", value=f"{price_change_percentage:.2f}%")
else:
    st.error("无法获取数据,请稍后重试。")

这个应用能体现 AutoGen 案例的闭环:产品经理拆解需求,工程师生成代码,审查员给出质量建议,用户代理验证功能。

4.6 AutoGen 适用性

优势:

  • 角色分工自然,适合模拟人类团队;
  • system_message 复用性强,可以沉淀角色模板;
  • 群聊机制降低复杂协作建模门槛;
  • UserProxyAgent 方便接入人类在环和执行反馈;
  • 异步架构适合多 Agent 远程 LLM 调用。

局限:

  • 对话式协作不完全可控,可能偏题或循环;
  • 调试依赖长对话历史,定位问题比传统堆栈更难;
  • 轮询群聊适合固定流程,不适合复杂动态路由;
  • 角色提示词质量直接影响协作质量。

适合:

  • 软件开发协作;
  • 方案评审;
  • 多角色头脑风暴;
  • 需要人类在环的任务处理。

5. AgentScope:消息驱动的三国狼人杀

5.1 核心机制

AgentScope 的设计更偏工程化。它不是单纯组织几个 Agent 聊天,而是围绕消息、生命周期、分布式和可观测性构建多智能体平台。

核心组件:

组件 作用
Msg 统一消息结构
AgentBase / ReActAgent 智能体基础抽象
MsgHub 消息中心,负责路由、广播、组播
pipeline 编排顺序、并发等执行模式
结构化输出 用 Pydantic 约束 Agent 行为

第六章案例是 "三国狼人杀":每个 Agent 同时有游戏身份和三国人物人格,例如 "狼人曹操""预言家诸葛亮"。

5.2 角色定义

来自 AgentScopeDemo/game_roles.py:

复制代码
class GameRoles:
    """游戏角色管理类。"""

    ROLES = {
        "狼人": {
            "description": "狼人",
            "ability": "夜晚可以击杀一名玩家",
            "win_condition": "消灭所有好人或与好人数量相等",
            "team": "狼人阵营",
        },
        "预言家": {
            "description": "预言家",
            "ability": "每晚可以查验一名玩家的身份",
            "win_condition": "消灭所有狼人",
            "team": "好人阵营",
        },
        "女巫": {
            "description": "女巫",
            "ability": "拥有解药和毒药各一瓶,可以救人或杀人",
            "win_condition": "消灭所有狼人",
            "team": "好人阵营",
        },
        "村民": {
            "description": "村民",
            "ability": "无特殊技能,依靠推理和投票",
            "win_condition": "消灭所有狼人",
            "team": "好人阵营",
        },
    }

    CHARACTER_TRAITS = {
        "刘备": "仁德宽厚,善于团结众人,说话温和有礼",
        "关羽": "忠义刚烈,言辞直接,重情重义",
        "张飞": "性格豪爽,说话大声直接,容易冲动",
        "诸葛亮": "智慧超群,分析透彻,言辞谨慎",
        "曹操": "雄才大略,善于权谋,话语犀利",
        "司马懿": "深谋远虑,城府极深,言辞含蓄",
    }

这个文件把 "游戏规则" 和 "人物人格" 分开维护,便于扩展新身份和新角色。

5.3 角色提示词

来自 AgentScopeDemo/prompt_cn.py:

复制代码
class ChinesePrompts:
    """中文提示词管理类。"""

    @staticmethod
    def get_role_prompt(role: str, character: str) -> str:
        base_prompt = f"""你是{character},在这场三国狼人杀游戏中扮演{role}。

请严格按照以下JSON格式回复,不要添加任何其他文字:
{{
    "reach_agreement": true/false,
    "confidence_level": 1-10的数字,
    "key_evidence": "你的证据或观点"
}}

角色特点:
"""

        if role == "狼人":
            return base_prompt + f"""
- 你是狼人阵营,目标是消灭所有好人
- 夜晚可以与其他狼人协商击杀目标
- 白天要隐藏身份,误导好人
- 以{character}的性格说话和行动
"""
        elif role == "预言家":
            return base_prompt + f"""
- 你是好人阵营的预言家,目标是找出所有狼人
- 每晚可以查验一名玩家的真实身份
- 要合理公布查验结果,引导好人投票
- 以{character}的智慧和洞察力分析局势
"""
        else:
            return base_prompt + f"""
- 你是好人阵营的村民
- 没有特殊技能,只能通过推理和投票
- 要仔细观察,找出狼人的破绽
- 以{character}的性格参与讨论
"""

这里的提示词有双重约束:

  • 游戏身份:狼人、预言家、女巫、村民;
  • 人格风格:刘备、曹操、司马懿等。

这正是多智能体角色扮演案例的关键:同样是狼人,曹操和张飞的策略风格应当不同。

5.4 结构化输出约束

来自 AgentScopeDemo/structured_output_cn.py:

复制代码
from typing import Literal, Optional
from pydantic import BaseModel, Field
from agentscope.agent import AgentBase


class DiscussionModelCN(BaseModel):
    """讨论输出格式。"""

    reach_agreement: bool = Field(description="是否已达成一致意见")
    confidence_level: int = Field(
        description="对当前推理的信心程度(1-10)",
        ge=1,
        le=10,
    )
    key_evidence: Optional[str] = Field(
        description="支持你观点的关键证据",
        default=None,
    )


def get_vote_model_cn(agents: list[AgentBase]) -> type[BaseModel]:
    """根据存活玩家动态生成投票模型。"""

    class VoteModelCN(BaseModel):
        vote: Literal[tuple(_.name for _ in agents)] = Field(
            description="你要投票淘汰的玩家姓名",
        )
        reason: str = Field(description="投票理由,简要说明为什么选择此人")
        suspicion_level: int = Field(
            description="对被投票者的怀疑程度(1-10)",
            ge=1,
            le=10,
        )

    return VoteModelCN

结构化输出解决了游戏类 Agent 的核心问题:模型不能随便说一段自然语言,而必须输出符合规则的决策对象。例如投票目标必须是存活玩家之一,信心等级必须在 1-10。

女巫动作:

复制代码
class WitchActionModelCN(BaseModel):
    """女巫行动模型。"""

    use_antidote: bool = Field(description="是否使用解药救人", default=False)
    use_poison: bool = Field(description="是否使用毒药杀人", default=False)
    target_name: Optional[str] = Field(
        description="目标玩家姓名",
        default=None,
    )
    action_reason: Optional[str] = Field(description="行动理由", default=None)

5.5 游戏主控制器

来自 AgentScopeDemo/main_cn.py,主类维护全局状态:

复制代码
class ThreeKingdomsWerewolfGame:
    """三国狼人杀游戏主类。"""

    def __init__(self):
        self.players = {}
        self.roles = {}
        self.moderator = GameModerator()
        self.alive_players = []
        self.werewolves = []
        self.villagers = []
        self.seer = []
        self.witch = []
        self.hunter = []

        self.witch_has_antidote = True
        self.witch_has_poison = True

创建玩家:

复制代码
from agentscope.agent import ReActAgent
from agentscope.model import DashScopeChatModel
from agentscope.formatter import DashScopeMultiAgentFormatter


async def create_player(self, role: str, character: str) -> ReActAgent:
    name = get_chinese_name(character)
    self.roles[name] = role

    agent = ReActAgent(
        name=name,
        sys_prompt=ChinesePrompts.get_role_prompt(role, character),
        model=DashScopeChatModel(
            model_name="qwen-max",
            api_key=os.environ["DASHSCOPE_API_KEY"],
            enable_thinking=True,
        ),
        formatter=DashScopeMultiAgentFormatter(),
    )

    await agent.observe(
        await self.moderator.announce(
            f"【{name}】你在这场三国狼人杀中扮演{GameRoles.get_role_desc(role)},"
            f"你的角色是{character}。{GameRoles.get_role_ability(role)}"
        )
    )

    self.players[name] = agent
    return agent

这里可以看到 AgentScope 的编程模型:Agent 可以 observe 消息,也可以在后续阶段被调用产生结构化响应。

5.6 MsgHub:狼人私密讨论

狼人阶段是消息驱动架构最典型的体现:

复制代码
from agentscope.pipeline import MsgHub, fanout_pipeline


async def werewolf_phase(self, round_num: int):
    """狼人阶段。"""
    if not self.werewolves:
        return None

    async with MsgHub(
        self.werewolves,
        enable_auto_broadcast=True,
        announcement=await self.moderator.announce(
            f"狼人们,请讨论今晚的击杀目标。存活玩家:{format_player_list(self.alive_players)}"
        ),
    ) as werewolves_hub:
        for _ in range(MAX_DISCUSSION_ROUND):
            for wolf in self.werewolves:
                await wolf(structured_model=DiscussionModelCN)

        werewolves_hub.set_auto_broadcast(False)
        kill_votes = await fanout_pipeline(
            self.werewolves,
            msg=await self.moderator.announce("请选择击杀目标"),
            structured_model=WerewolfKillModelCN,
            enable_gather=False,
        )

        votes = {}
        for i, vote_msg in enumerate(kill_votes):
            if vote_msg is not None and getattr(vote_msg, "metadata", None) is not None:
                votes[self.werewolves[i].name] = vote_msg.metadata.get("target")
            else:
                valid_targets = [
                    p.name
                    for p in self.alive_players
                    if p.name not in [w.name for w in self.werewolves]
                ]
                votes[self.werewolves[i].name] = random.choice(valid_targets) if valid_targets else None

        killed_player, _ = majority_vote_cn(votes)
        return killed_player

关键点:

  • MsgHub 创建一个临时通信空间;
  • enable_auto_broadcast=True 表示狼人发言会自动广播给同频道成员;
  • fanout_pipeline 并发收集多个 Agent 的决策;
  • 对无效返回做兜底,保证游戏流程继续。

5.7 工具函数与胜负判断

来自 AgentScopeDemo/utils_cn.py:

复制代码
from collections import Counter


def majority_vote_cn(votes: dict[str, str]) -> tuple[str, int]:
    """多数投票统计。"""
    if not votes:
        return "无人", 0

    vote_counts = Counter(votes.values())
    most_voted = vote_counts.most_common(1)[0]
    return most_voted[0], most_voted[1]


def check_winning_cn(alive_players, roles: dict[str, str]) -> str | None:
    """检查游戏胜利条件。"""
    alive_roles = [roles.get(p.name, "村民") for p in alive_players]
    werewolf_count = alive_roles.count("狼人")
    villager_count = len(alive_roles) - werewolf_count

    if werewolf_count == 0:
        return "好人阵营胜利!所有狼人已被淘汰!"
    if werewolf_count >= villager_count:
        return "狼人阵营胜利!狼人数量已达到或超过好人!"

    return None

这些函数把游戏规则从 Agent 推理中抽离出来,避免让模型自己裁定胜负。重要规则应该由确定性代码执行,而不是交给 LLM 猜。

5.8 AgentScope 适用性

优势:

  • 消息驱动天然适合多智能体通信;
  • 异步和并发能力强;
  • MsgHub 支持广播、私聊、组播等通信模式;
  • 结构化输出能把规则约束落到代码层;
  • 容错和分布式能力适合生产级系统。

局限:

  • 学习成本高于简单对话框架;
  • 对异步、消息、分布式概念有要求;
  • 对简单原型可能显得重;
  • 生态相对新,需要更多工程沉淀。

适合:

  • 多人游戏模拟;
  • 分布式 Agent 服务;
  • 高并发客服 / 任务调度;
  • 长期运行的多智能体系统。

6. CAMEL:角色扮演的电子书创作

6.1 核心机制

CAMEL 的核心是 RolePlaying:通过为两个智能体设定互补角色和共同任务,让它们在 "引导性提示" 下自主协作。

两个关键概念:

  • 角色扮演:例如 "心理学家" 和 "作家";
  • 引导性提示:在对话开始前,为双方注入任务目标、行为约束、协作协议和终止标志。

与 AutoGen 相比,CAMEL 更轻量;与 LangGraph 相比,CAMEL 更依赖角色和提示词,而不是显式流程控制。

6.2 电子书创作任务

来自 CAMEL/DigitalBookWriting.py:

复制代码
from colorama import Fore
from camel.societies import RolePlaying
from camel.utils import print_text_animated
from camel.models import ModelFactory
from camel.types import ModelPlatformType
from dotenv import load_dotenv
import os

load_dotenv()
LLM_API_KEY = os.getenv("LLM_API_KEY")
LLM_BASE_URL = os.getenv("LLM_BASE_URL")
LLM_MODEL = os.getenv("LLM_MODEL")

model = ModelFactory.create(
    model_platform=ModelPlatformType.QWEN,
    model_type=LLM_MODEL,
    url=LLM_BASE_URL,
    api_key=LLM_API_KEY,
)

任务定义:

复制代码
task_prompt = """
创作一本关于"拖延症心理学"的短篇电子书,目标读者是对心理学感兴趣的普通大众。
要求:
1. 内容科学严谨,基于实证研究
2. 语言通俗易懂,避免过多专业术语
3. 包含实用的改善建议和案例分析
4. 篇幅控制在8000-10000字
5. 结构清晰,包含引言、核心章节和总结
"""

这个任务明确了产物、读者、风格、长度和结构,是 CAMEL 能稳定协作的前提。如果任务过泛,两个角色会很容易发散。

6.3 RolePlaying 会话

复制代码
role_play_session = RolePlaying(
    assistant_role_name="心理学家",
    user_role_name="作家",
    task_prompt=task_prompt,
    model=model,
)

chat_turn_limit, n = 30, 0
input_msg = role_play_session.init_chat()

while n < chat_turn_limit:
    n += 1
    assistant_response, user_response = role_play_session.step(input_msg)

    print_text_animated(Fore.BLUE + f"作家:\n\n{user_response.msg.content}\n")
    print_text_animated(Fore.GREEN + f"心理学家:\n\n{assistant_response.msg.content}\n")

    if "CAMEL_TASK_DONE" in user_response.msg.content:
        print(Fore.MAGENTA + "电子书创作完成!")
        break

    input_msg = assistant_response.msg

这里的对话结构是:

复制代码
作家:提出章节结构、写作要求、修订请求
心理学家:提供专业知识、研究依据、概念解释
作家:把知识转化为大众化文本
心理学家:继续补充和校验

6.4 协作阶段

电子书案例可以拆成四个阶段:

阶段 主要行为
框架搭建 作家提出目录,心理学家补齐核心理论模块
内容生成 心理学家提供专业知识,作家转译成通俗语言
迭代优化 作家打磨可读性,心理学家检查科学准确性
总结收尾 共同完成实用建议、案例和结论

CAMEL 的亮点在于:开发者没有显式写流程图,协作行为从角色和任务中 "涌现" 出来。

6.5 CAMEL 适用性

优势:

  • API 简洁,启动成本低;
  • 角色扮演直观,适合模拟专家协作;
  • 适合创作、研究、头脑风暴、跨领域协同;
  • 对话可以自然推进,不需要开发者编写复杂状态机。

局限:

  • 高度依赖初始提示;
  • 调试不佳时难判断是角色、任务还是协议问题;
  • 双智能体很强,但大规模协作需要更复杂模块;
  • 对严格流程和审计要求不如 LangGraph。

6.6 CAMEL Workforce 补充

习题要求查阅 CAMEL 最新 Workforce。根据 CAMEL 官方文档,Workforce 是 CAMEL-AI 的多智能体协作引擎,用于组装、管理和扩展多个专门 Agent 来处理单 Agent 难以完成的复杂任务。官方文档说明其核心包括:

  • Workforce:中心编排器,管理多智能体任务生命周期;
  • SingleAgentWorker:由一个 ChatAgent 加系统提示和工具组成的 worker;
  • RolePlayingWorker:内部使用两个 Agent 的 RolePlaying 会话,适合辩论、设计、探索;
  • 任务生命周期:分解、分配、执行、完成、失败恢复;
  • 可选能力:共享记忆、结构化输出处理、callbacks、人类在环。

官方示例的典型结构:

复制代码
from camel.societies.workforce import Workforce
from camel.agents import ChatAgent

workforce = Workforce("My Research Team")

general_agent = ChatAgent(
    system_message="You are a helpful research assistant."
)

workforce.add_single_agent_worker(
    description="A worker for general research tasks",
    worker=general_agent,
)

这说明 CAMEL 已经不只是最初的 "双智能体 RolePlaying",而是在向多 worker 编排系统发展。

资料来源:CAMEL 官方 Workforce 文档,https://docs.camel-ai.org/key_modules/workforce。

7. LangGraph:状态机与图工作流

7.1 核心机制

LangGraph 把智能体流程建模为状态机和有向图:

  • State:全局状态,记录消息、搜索词、结果、最终答案等;
  • Node:计算步骤,接收状态,返回状态增量;
  • Edge:节点之间的跳转;
  • Conditional Edge:根据状态动态选择下一步;
  • Checkpointer:保存会话状态,支持多轮和恢复。

与对话式框架不同,LangGraph 要求开发者显式定义流程,因此更适合对可靠性、可审计性要求高的系统。

7.2 状态结构

来自 Langgraph/Dialogue_System.py:

复制代码
from typing import Annotated, TypedDict
from langgraph.graph.message import add_messages


class SearchState(TypedDict):
    messages: Annotated[list, add_messages]
    user_query: str
    search_query: str
    search_results: str
    final_answer: str
    step: str

messages 使用 add_messages,表示新消息会追加到历史,而不是覆盖。这是 LangGraph 状态管理的一个关键点。

7.3 初始化模型和 Tavily

复制代码
import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from tavily import TavilyClient

load_dotenv()

llm = ChatOpenAI(
    model=os.getenv("LLM_MODEL_ID", "gpt-4o-mini"),
    api_key=os.getenv("LLM_API_KEY"),
    base_url=os.getenv("LLM_BASE_URL", "https://api.openai.com/v1"),
    temperature=0.7,
)

tavily_client = TavilyClient(api_key=os.getenv("TAVILY_API_KEY"))

这个示例结合了 LLM 和真实搜索工具 Tavily,流程是 "理解问题 -> 搜索 -> 生成答案"。

7.4 节点 1:理解查询

复制代码
from langchain_core.messages import HumanMessage, AIMessage, SystemMessage


def understand_query_node(state: SearchState) -> SearchState:
    """理解用户查询并生成搜索关键词。"""
    user_message = ""
    for msg in reversed(state["messages"]):
        if isinstance(msg, HumanMessage):
            user_message = msg.content
            break

    understand_prompt = f"""分析用户的查询:"{user_message}"

请完成两个任务:
1. 简洁总结用户想要了解什么
2. 生成最适合搜索的关键词

格式:
理解:[用户需求总结]
搜索词:[最佳搜索关键词]"""

    response = llm.invoke([SystemMessage(content=understand_prompt)])
    response_text = response.content
    search_query = user_message

    if "搜索词:" in response_text:
        search_query = response_text.split("搜索词:")[1].strip()
    elif "搜索关键词:" in response_text:
        search_query = response_text.split("搜索关键词:")[1].strip()

    return {
        "user_query": response.content,
        "search_query": search_query,
        "step": "understood",
        "messages": [AIMessage(content=f"我理解您的需求:{response.content}")],
    }

节点函数只做一件事:读状态,处理,返回状态更新。

7.5 节点 2:搜索

复制代码
def tavily_search_node(state: SearchState) -> SearchState:
    """使用 Tavily API 搜索信息。"""
    search_query = state["search_query"]

    try:
        response = tavily_client.search(
            query=search_query,
            search_depth="basic",
            include_answer=True,
            include_raw_content=False,
            max_results=5,
        )

        search_results = ""
        if response.get("answer"):
            search_results = f"综合答案:\n{response['answer']}\n\n"

        if response.get("results"):
            search_results += "相关信息:\n"
            for i, result in enumerate(response["results"][:3], 1):
                title = result.get("title", "")
                content = result.get("content", "")
                url = result.get("url", "")
                search_results += f"{i}. {title}\n{content}\n来源:{url}\n\n"

        if not search_results:
            search_results = "抱歉,没有找到相关信息。"

        return {
            "search_results": search_results,
            "step": "searched",
            "messages": [AIMessage(content="搜索完成,正在整理答案。")],
        }

    except Exception as e:
        return {
            "search_results": f"搜索失败:{e}",
            "step": "search_failed",
            "messages": [AIMessage(content="搜索遇到问题,将基于已有知识回答。")],
        }

这里通过 step 字段把成功和失败写入状态,为后续分支或回退留出空间。

7.6 节点 3:回答

复制代码
def generate_answer_node(state: SearchState) -> SearchState:
    """基于搜索结果生成最终答案。"""
    if state["step"] == "search_failed":
        fallback_prompt = f"""搜索 API 暂时不可用,请基于已有知识回答用户问题:

用户问题:{state['user_query']}

请提供有用回答,并说明这是基于已有知识的回答。"""
        response = llm.invoke([SystemMessage(content=fallback_prompt)])
        return {
            "final_answer": response.content,
            "step": "completed",
            "messages": [AIMessage(content=response.content)],
        }

    answer_prompt = f"""基于以下搜索结果为用户提供完整、准确的答案:

用户问题:{state['user_query']}

搜索结果:
{state['search_results']}

要求:
1. 综合搜索结果,提供准确、有用的回答
2. 如果是技术问题,提供具体方案或代码
3. 引用重要信息来源
4. 回答结构清晰
5. 如果搜索结果不完整,请说明并给出补充建议"""

    response = llm.invoke([SystemMessage(content=answer_prompt)])
    return {
        "final_answer": response.content,
        "step": "completed",
        "messages": [AIMessage(content=response.content)],
    }

7.7 构建图

复制代码
from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.memory import InMemorySaver


def create_search_assistant():
    workflow = StateGraph(SearchState)

    workflow.add_node("understand", understand_query_node)
    workflow.add_node("search", tavily_search_node)
    workflow.add_node("answer", generate_answer_node)

    workflow.add_edge(START, "understand")
    workflow.add_edge("understand", "search")
    workflow.add_edge("search", "answer")
    workflow.add_edge("answer", END)

    memory = InMemorySaver()
    app = workflow.compile(checkpointer=memory)
    return app

图结构:

复制代码
START
  ↓
understand
  ↓
search
  ↓
answer
  ↓
END

7.8 运行工作流

复制代码
initial_state = {
    "messages": [HumanMessage(content=user_input)],
    "user_query": "",
    "search_query": "",
    "search_results": "",
    "final_answer": "",
    "step": "start",
}

config = {"configurable": {"thread_id": f"search-session-{session_count}"}}

async for output in app.astream(initial_state, config=config):
    for node_name, node_output in output.items():
        if "messages" in node_output and node_output["messages"]:
            latest_message = node_output["messages"][-1]
            if isinstance(latest_message, AIMessage):
                print(node_name, latest_message.content)

thread_id 用来区分会话,astream 可以流式观察每个节点输出。

7.9 LangGraph 适用性

优势:

  • 流程显式,可控、可测、可审计;
  • 原生支持循环和条件分支;
  • 状态结构清晰,便于调试;
  • 适合可靠性要求高的生产流程;
  • 可以自然实现 "生成 - 检查 - 修复" 类闭环。

局限:

  • 前期样板代码多;
  • 对简单聊天或创作任务可能偏重;
  • 开发者必须明确建模状态和跳转;
  • 节点内部错误、状态污染、条件边判断错误都需要系统调试。

适合:

  • 金融审批;
  • 工单处理;
  • 搜索问答;
  • 代码生成 - 测试 - 修复;
  • 论文写作 - 审阅 - 修改;
  • 任何需要明确流程和审计的 Agent 应用。

8. 四个框架横向选型

维度 AutoGen AgentScope CAMEL LangGraph
协作方式 群聊式对话 消息驱动网络 角色扮演 图工作流
控制方式 中等,靠群聊规则 中等偏强,靠消息和编排 较弱,靠提示词 最强,显式节点和边
工程化 中等 强 中等 强
上手成本 中等 较高 低到中等 中等偏高
适合规模 小到中型团队协作 大规模多智能体 双智能体或小团队深度协作 复杂流程
典型风险 对话偏移、循环 过度工程化 提示词敏感 样板代码多

选型建议:

  • 想模拟一个多人团队开会协作:选 AutoGen;
  • 想构建长期运行、高并发、多 Agent 系统:选 AgentScope;
  • 想让两个专家深度创作或研究:选 CAMEL;
  • 想做强流程、强审计、强控制:选 LangGraph;
  • 任务极简单、流程固定、没有多 Agent 需求:从零写脚本即可。

9. 本章习题解析

习题 1:四个框架对比与设计哲学

题目要求选择两个框架,从协作模式、控制方式、适用场景对比,并解释 "涌现式协作" 和 "显式控制"。

以 AutoGen 和 LangGraph 为例:

维度 AutoGen LangGraph
协作模式 多 Agent 群聊,角色轮流发言 节点按图执行,状态在节点间流转
控制方式 通过发言顺序、终止条件、角色提示控制 通过状态、节点、边、条件边控制
适用场景 需求评审、代码开发、多人讨论、方案协作 审批流程、搜索问答、测试修复、反思循环
调试方式 查看对话历史 查看状态变化和节点输出
风险 对话跑偏、不稳定 前期设计复杂、灵活性较低

"涌现式协作" 指开发者只定义角色、目标和基本规则,让复杂协作行为从 Agent 对话中自然产生。AutoGen 和 CAMEL 更接近这种模式。

"显式控制" 指开发者明确规定每一步流程、状态字段和跳转条件。LangGraph 更接近这种模式。

核心取舍:

复制代码
涌现式协作: 更自然、更灵活,但难预测
显式控制: 更可靠、更可审计,但开发成本更高

习题 2:AutoGen 动态回退、测试工程师和对话监控

动态回退机制

当前 RoundRobinGroupChat 是固定顺序:

复制代码
ProductManager -> Engineer -> CodeReviewer -> UserProxy

如果代码审查发现需求理解错误,应该回退到产品经理重新澄清:

复制代码
ProductManager -> Engineer -> CodeReviewer
                         ↓
                   发现需求偏差
                         ↓
                  ProductManager 重新审核

实现思路:

  • 简单方案:保留轮询,但要求审查员输出 "RETURN_TO_PM";
  • 框架检测到该标志后,将下一轮任务描述明确交给产品经理;
  • 更强方案:使用 Selector/Router 类团队,让路由器根据消息选择下一个发言者。

伪代码:

复制代码
def route_next_agent(last_message: str) -> str:
    if "RETURN_TO_PM" in last_message:
        return "ProductManager"
    if "请工程师开始实现" in last_message:
        return "Engineer"
    if "请代码审查员检查" in last_message:
        return "CodeReviewer"
    if "代码审查完成" in last_message:
        return "QAEngineer"
    return "UserProxy"
添加测试工程师

测试工程师系统消息:

复制代码
def create_qa_engineer(model_client):
    system_message = """你是一位严谨的测试工程师,负责验证工程师提交的代码是否满足需求。

你的职责:
1. 阅读产品需求和工程师代码
2. 设计测试用例,包括正常路径、异常路径和边界情况
3. 检查依赖、运行方式和错误处理
4. 如果代码可执行,给出测试步骤和预期结果
5. 如果发现问题,明确指出失败原因和修复建议

输出格式:
1. 测试范围
2. 测试用例列表
3. 发现的问题
4. 是否通过验收

如果测试通过,请回复"测试通过,请用户代理最终确认"。
如果测试失败,请回复"测试失败,请工程师修复"。"""

    return AssistantAgent(
        name="QAEngineer",
        model_client=model_client,
        system_message=system_message,
    )

团队成员调整:

复制代码
team_chat = RoundRobinGroupChat(
    participants=[
        product_manager,
        engineer,
        code_reviewer,
        qa_engineer,
        user_proxy,
    ],
    termination_condition=TextMentionTermination("TERMINATE"),
    max_turns=30,
)
对话质量监控

监控指标:

  • 是否连续多轮没有新信息;
  • 是否偏离原始任务;
  • 是否重复同一观点;
  • 是否超过最大轮次;
  • 是否出现无效工具调用;
  • 是否未按角色职责发言;
  • 是否没有输出可执行产物。

干预策略:

复制代码
轻度异常: 给当前 Agent 注入提醒
中度异常: 路由到产品经理重新澄清
严重异常: 终止流程并请求人工介入

伪代码:

复制代码
class ConversationMonitor:
    def __init__(self):
        self.no_progress_turns = 0

    def evaluate(self, history: list[str]) -> str:
        if len(history) > 30:
            return "terminate"
        if self._is_repeating(history[-3:]):
            return "intervene"
        if self._is_off_topic(history[-1]):
            return "redirect"
        return "continue"

    def _is_repeating(self, recent: list[str]) -> bool:
        return len(set(recent)) <= 1

    def _is_off_topic(self, message: str) -> bool:
        keywords = ["比特币", "价格", "Streamlit", "API", "代码"]
        return not any(keyword in message for keyword in keywords)

习题 3:AgentScope 消息驱动、猎人模型和分布式挑战

消息驱动相比函数调用的优势

传统函数调用:

复制代码
A 调用 B -> 等待 B 返回 -> A 继续

消息驱动:

复制代码
A 发送消息 -> 消息中心路由 -> B 接收处理 -> 返回消息

优势:

  • 发送方和接收方解耦;
  • 支持异步和并发;
  • 支持广播、组播、点对点;
  • 容易记录和追踪消息;
  • 智能体可以分布在不同进程或服务器;
  • 某个智能体失败时,系统可重试或降级。

特别有价值的场景:

  • 多智能体游戏;
  • 群体辩论;
  • 分布式客服;
  • 并行任务处理;
  • 长时间运行的模拟系统。
设计猎人结构化输出

本地代码已经有 get_hunter_model_cn,可以进一步增强验证:

复制代码
from typing import Optional
from pydantic import BaseModel, Field, model_validator
from agentscope.agent import AgentBase


def get_hunter_model_cn(agents: list[AgentBase]) -> type[BaseModel]:
    """猎人开枪行为模型。"""

    valid_names = {agent.name for agent in agents}

    class HunterModelCN(BaseModel):
        shoot: bool = Field(description="是否使用开枪技能")
        target: Optional[str] = Field(
            description="开枪目标玩家姓名;如果不使用技能则为空",
            default=None,
        )
        shoot_reason: Optional[str] = Field(
            description="开枪理由;使用技能时必须说明",
            default=None,
        )
        confidence_level: int = Field(
            description="对目标是狼人的信心程度(1-10)",
            ge=1,
            le=10,
        )

        @model_validator(mode="after")
        def validate_target(self):
            if self.shoot and not self.target:
                raise ValueError("选择开枪时必须指定 target。")
            if self.shoot and self.target not in valid_names:
                raise ValueError(f"target 必须是存活玩家之一:{sorted(valid_names)}")
            if self.shoot and not self.shoot_reason:
                raise ValueError("选择开枪时必须说明 shoot_reason。")
            if not self.shoot and self.target:
                raise ValueError("不使用技能时 target 应为空。")
            return self

    return HunterModelCN
分布式部署挑战

实时狼人杀分布式部署会遇到:

  • 消息顺序问题:不同节点网络延迟不同;
  • 状态一致性问题:玩家生死、投票结果必须一致;
  • 并发冲突:多个动作同时更新状态;
  • 失败恢复:某个 Agent 节点宕机;
  • 时钟同步:夜晚 / 白天阶段切换必须统一;
  • 幂等性:重复消息不能导致重复投票或重复击杀。

解决方案:

挑战 方案
消息顺序 为消息加 round_id、phase_id、递增序号
状态一致性 主持人节点作为权威状态源
并发冲突 投票收集后统一结算,不直接改状态
节点失败 超时默认弃权或使用 fallback 响应
重复消息 使用 message_id 做幂等去重
可追溯 所有消息写入事件日志

习题 4:CAMEL 冲突解决与 Workforce 对比 AutoGen

任务完成冲突处理

如果一个智能体认为应终止,另一个认为不应终止,可以加入 "仲裁机制":

复制代码
Writer/Psychologist
  ↓
Completion Judge
  ↓
判断是否满足任务验收标准
  ↓
继续协作 or 终止

验收标准可结构化:

复制代码
{
  "content_complete": true,
  "scientific_accuracy": 8,
  "readability": 8,
  "has_cases": true,
  "has_practical_advice": true,
  "should_stop": true,
  "missing_parts": []
}

伪代码:

复制代码
def should_stop_by_judge(writer_msg: str, psychologist_msg: str, task_spec: str) -> bool:
    judge_prompt = f"""
请判断当前电子书协作是否可以终止。

任务要求:
{task_spec}

作家最新意见:
{writer_msg}

心理学家最新意见:
{psychologist_msg}

请输出 JSON:
{{
  "should_stop": true/false,
  "reason": "...",
  "missing_parts": ["..."]
}}
"""
    result = judge_llm(judge_prompt)
    return result["should_stop"]

更稳妥的终止条件:

  • 双方都输出完成标志;
  • 或仲裁 Agent 判定满足验收标准;
  • 或达到最大轮数后输出未完成清单;
  • 或人类确认终止。
CAMEL Workforce 与 AutoGen 群聊的区别

根据 CAMEL 官方 Workforce 文档,Workforce 是中心编排器,负责多智能体任务的分解、分配、执行、完成和失败恢复。它可以添加 SingleAgentWorker 和 RolePlayingWorker,并支持结构化输出、callbacks、共享记忆和人类在环。

与 AutoGen 群聊对比:

维度 CAMEL Workforce AutoGen 群聊
组织方式 任务编排器 + workers 多 Agent 消息对话
核心对象 Workforce、Worker、Task AssistantAgent、UserProxyAgent、GroupChat
协作逻辑 分解任务,分配给合适 worker 让角色在群聊中轮流或路由发言
适合任务 多子任务、多 worker、可分配工作 讨论式协作、评审、团队模拟
控制感 更偏任务调度 更偏对话推进
冲突处理 可通过 coordinator /recovery 依赖群聊规则或外部监控

简单理解:

复制代码
AutoGen 像会议室:多个角色围绕同一话题交流。
CAMEL Workforce 像项目经理:拆任务、分派 worker、收集结果、处理失败。

习题 5:LangGraph 图结构、反思节点与复杂循环

理解 - 搜索 - 回答图结构

当前案例:

复制代码
START
  ↓
understand
  ↓
search
  ↓
answer
  ↓
END

状态字段:

复制代码
messages       对话历史
user_query     用户需求总结
search_query   优化后的搜索词
search_results 搜索结果
final_answer   最终答案
step           当前步骤
添加反思节点

扩展图:

复制代码
START
  ↓
understand
  ↓
search
  ↓
answer
  ↓
reflect
  ├── good -> END
  ├── weak_search -> search
  └── weak_answer -> answer

反思节点:

复制代码
def reflect_answer_node(state: SearchState) -> SearchState:
    answer = state["final_answer"]
    search_results = state["search_results"]

    if len(answer) < 300:
        quality = "weak_answer"
    elif "来源:" not in search_results and "搜索失败" not in search_results:
        quality = "weak_search"
    else:
        quality = "good"

    return {
        "step": quality,
        "messages": [AIMessage(content=f"答案质量检查结果:{quality}")],
    }


def route_after_reflection(state: SearchState) -> str:
    if state["step"] == "good":
        return END
    if state["step"] == "weak_search":
        return "search"
    return "answer"

图注册:

复制代码
workflow.add_node("reflect", reflect_answer_node)
workflow.add_edge("answer", "reflect")
workflow.add_conditional_edges(
    "reflect",
    route_after_reflection,
    {
        "search": "search",
        "answer": "answer",
        END: END,
    },
)

生产系统还需要增加最大循环次数:

复制代码
class SearchState(TypedDict):
    messages: Annotated[list, add_messages]
    user_query: str
    search_query: str
    search_results: str
    final_answer: str
    step: str
    retry_count: int
代码生成 - 测试 - 修复循环
复制代码
START
  ↓
generate_code
  ↓
run_tests
  ↓
analyze_result
  ├── tests_pass -> END
  └── tests_fail -> fix_code -> run_tests

节点职责:

节点 功能
generate_code 根据需求生成初版代码
run_tests 执行单元测试或静态检查
analyze_result 判断测试是否通过,提取错误信息
fix_code 根据错误修复代码
END 输出最终代码和测试结果

这个场景非常适合 LangGraph,因为它天然需要循环、条件分支、状态追踪和审计。


习题 6:三个产品的框架选型

应用 A:高并发智能客服系统

需求:

  • 每秒 1000+ 请求;
  • 响应时间低于 2 秒;
  • 7x24 稳定运行;
  • 支持水平扩展。

推荐:AgentScope,部分模块可自研。

理由:

  • 消息驱动和异步架构适合高并发;
  • 分布式部署能力更贴近生产环境;
  • 消息可追踪,利于监控和排障;
  • 客服系统需要任务路由、状态管理、失败重试和容错;
  • 简单群聊式框架不适合 1000+ QPS 的线上客服主链路。

架构建议:

复制代码
API Gateway
  ↓
Session Router
  ↓
AgentScope MsgHub
  ↓
Intent Agent / Policy Agent / Tool Agent / Reply Agent
  ↓
Human Handoff

注意:如果延迟硬性小于 2 秒,不能让每个请求都走复杂多 Agent。应把高频简单问题用检索、规则、小模型处理,复杂问题再进入多 Agent。

应用 B:科研论文辅助写作平台

需求:

  • 研究员智能体和写作智能体深度协作;
  • 文献综述、实验设计、数据分析、论文撰写;
  • 多轮讨论,自主推进。

推荐:CAMEL 或 CAMEL Workforce。

理由:

  • 研究员和写作者是典型互补角色;
  • 任务需要深度讨论和知识转译;
  • CAMEL 的 RolePlaying 很适合双专家协作;
  • 如果后续扩展统计专家、审稿人、引用检查员,可升级到 Workforce。

架构建议:

复制代码
RolePlaying:
  User Role: 研究员
  Assistant Role: 写作智能体

Workforce 扩展:
  Literature Worker
  Method Worker
  Data Analysis Worker
  Writing Worker
  Reviewer Worker

如果平台需要严格流程和版本审计,可以在外层用 LangGraph 管控阶段,内部单个节点调用 CAMEL 协作。

应用 C:金融风控审批系统

需求:

  • 资料审核 -> 风险评估 -> 额度计算 -> 合规检查 -> 人工复核 -> 最终决策;
  • 明确判断标准和分支逻辑;
  • 要求可追溯、可审计。

推荐:LangGraph。

理由:

  • 金融审批是强流程、强合规场景;
  • 每一步都要显式记录输入、输出、判断依据;
  • 条件边适合表达风险等级、额度区间、人工复核;
  • 状态机便于审计和回放;
  • 对话式涌现不适合直接控制金融决策主流程。

图结构:

复制代码
START
  ↓
document_check
  ├── missing_docs -> request_more_info -> END
  ↓
risk_assessment
  ├── high_risk -> manual_review
  ↓
limit_calculation
  ↓
compliance_check
  ├── compliance_fail -> reject
  ↓
manual_review
  ↓
final_decision
  ↓
END

关键工程要求:

  • 每个节点输出结构化 JSON;
  • 所有状态写入审计日志;
  • 高风险节点必须人工复核;
  • 模型只能给建议,最终决策需规则和人工兜底;
  • 版本化保存规则、提示词和模型参数。

10. 总结

第六章的重点不是学会某一个框架的 API,而是建立框架选型判断:

  • `AutoGen` 用对话组织协作,适合多角色团队任务;
  • `AgentScope` 用消息驱动和工程化能力支撑生产级多智能体系统;
  • `CAMEL` 用角色扮演和引导性提示激发深度协作;
  • `LangGraph` 用状态机和图结构提供强控制、可追溯和循环能力。

真实项目里,框架往往可以组合使用:用 `LangGraph` 管主流程,用 `AutoGen` 或 `CAMEL` 完成局部协作,用 `AgentScope` 承载高并发消息和分布式运行。关键是先判断任务需要"涌现式协作"还是"显式控制",再决定框架,而不是先选框架再硬套任务。

相关推荐
天空属于哈夫克34 天前
企业微信二次开发:精准实现关键词自动回复
架构·企业微信
小羊没烦恼!4 天前
微服务化的基石——持续集成
java·大数据·word·powerpoint·.net
回眸&啤酒鸭4 天前
【回眸】Minicart 电商购物车核心功能落地指南
人工智能
一隅论数智4 天前
给AI一张“业务概念地图“:本体如何从哲学走向企业智能
大数据·人工智能·经验分享·笔记·学习·学习方法·政务
AI的探索之旅4 天前
97 个 OpenCV 实例(三十):双目立体,从标定到点云
人工智能·opencv·计算机视觉
AlbertZein4 天前
Step-5-Preview 上手实测:3D 游戏、金融分析、网页设计一次跑完
人工智能·aigc
俊昭喜喜里4 天前
java中的继承和多态的区别
java
小羊没烦恼!4 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
XiHongShi20164 天前
STM32F407 RTC定时器例程,建议保存
stm32·单片机·学习