1.1 CAMEL框架与两位主角的舞台


1.1 CAMEL框架与两位主角的舞台

本节摘要:CAMEL 是第一个把"双角色自主协作"做成完整框架的大语言模型多智能体系统,由 KAUST 研究团队提出、发表于 NeurIPS 2023。本节讲清它的定位、舞台上的两位主角各管什么、最小构成的四个部件,以及"两个模型聊天"与"两个智能体演戏"的分界线。承接导读的模糊需求难题,本节先立起全册要用的舞台。

从一次失控的闲聊说起

先看一段真实复现的对话。你把任务"帮我做一个股票交易机器人"同时发给一个模型,并让它自己继续深化,观察它三步之后的表现:

第1轮 你:帮我做一个股票交易机器人。 第2轮 模型:好的,一个交易机器人通常包括数据获取、策略、执行三个模块, 你想从哪个模块开始? 第3轮 你:都重要,你觉得呢? 第4轮 模型:确实都很重要!我们可以先从数据获取开始,它是一切的基础。 您觉得这个方向怎么样? 第5轮 你:行吧,那你写。 第6轮 模型:好的!下面是一个示例框架(略)。如果您有其他想法,我也可以 调整。您希望加入一些可视化功能吗?

六轮过去,需求方没说清任何约束,模型交付了一段建立在未验证假设上的骨架,双方还在"您觉得呢"的循环里打转。这就是单角色对话的结构性困境:对话里缺少一个立场坚定、持续追问具体细节的力量。模型的礼貌性倾向会让它不断附和,而真实工程需要的恰恰是不客气地把需求钉死。

CAMEL 的解法朴素得近乎狡猾:既然缺一个追问的甲方,就再造一个模型来演甲方。整个框架的第一性原理只有一句——用角色扮演引导两个智能体自主协作,同时保持人类意图可控。注意"保持可控"四个字,它是 CAMEL 与"放两个模型自由聊天"的玩具实验的分水岭。

图 2 双智能体舞台的最小构成

图 2 双智能体舞台的最小构成

两位主角的分工与红线

把上图的两块戏份展开成对照表,这张表值得打印出来贴在屏幕边——后面所有调参都是在收紧或放宽这两列的边界。

维度 AI 用户智能体 AI 助理智能体
立场 代表真实人类,守卫任务意图 代表执行侧,守卫交付质量
每轮输出 一条具体、可执行的指令 一份针对该指令的完整方案
禁止动作 一次下达多个任务、自己动手写方案 反过来向甲方提要求、夸甲方的问题好
常见失格 指令越问越模糊,立场漂移成聊伴 礼貌性附和,交付物越来越水
谢幕时机 认为任务完成,输出任务完成标记 收到完成标记或轮次耗尽时停演

两列合起来看,会发现一个精妙的不对称:指令流与方案流是单向循环的,谁也不许反过来质疑对方的立场。这不是刻板,而是防"合谋漂移"的安全索——大量复现实验表明,两个模型自由对话若干轮后会形成一种互相恭维的温和合谋,各自遗忘初始任务。角色红线的本质,是把这种合谋在提示层面提前焊死。

用三十行代码立起舞台

概念讲完,看 CAMEL 里这对主角怎么声明。以下示例使用框架的经典角色扮演会话接口,完整跑一场"股票交易机器人"对手戏的骨架(模型凭据从环境变量读取,示例中省略):

from camel.agents import RolePlaying # 角色扮演会话:舞台总调度 from camel.typing import ModelType # 模型枚举:为两侧演员选角 from camel.configs import ChatGPTConfig # 采样配置:温度等舞台参数 task_prompt = "开发一个股票市场交易机器人的 Python 脚本" # 任务卡 # 建立一场双智能体会话:两侧角色在此声明 session = RolePlaying( assistant_role_name="Python 程序员", # 乙方角色:交付技术方案 user_role_name="股票交易员", # 甲方角色:下达业务指令 task_prompt=task_prompt, with_task_specify=True, # 先让任务分解器把任务卡细化 model_type=ModelType.GPT_4, # 两侧演员使用同一型号模型 assistant_agent_kwargs=dict(model_config=ChatGPTConfig(temperature=0.4)), user_agent_kwargs=dict(model_config=ChatGPTConfig(temperature=0.7)), ) print(f"细化后的任务卡:{session.specified_task_prompt}") print(f"助理侧开场剧本:\n{session.assistant_agent.system_message}") print(f"用户侧开场剧本:\n{session.user_agent.system_message}")

运行后你会看到三段输出:第一段是被任务分解器细化过的任务卡——"九个字的需求"已经变成了几百字的可执行描述;后两段就是两侧演员各自的"开场剧本",里面写死了角色、目标、行为约束。这正是下一章要精读的对象。再看演出循环的最小形态:

input_msg = session.init_chat() # 用户侧先开锣,发出第一条指令 for round_i in range(1, 11): # 轮次上限:本例十轮 assistant_response, user_response = session.step(input_msg) print(f"—— 第 {round_i} 轮 ——") print(f"[助理交付] {assistant_response.msg.content[:120]}") print(f"[用户指令] {user_response.msg.content[:120]}") if assistant_response.terminated: # 谢幕检查:任一侧宣布完成即收 print("任务完成,提前谢幕") break input_msg = assistant_response.msg # 方案作为下一轮的输入回传
—— 第 1 轮 —— [助理交付] 建议模块划分为:行情获取、信号计算、订单模拟三部分,先给出行情…… [用户指令] 方案可行。下一步:为行情模块接入数据源,给出函数签名与伪代码。 —— 第 2 轮 —— [助理交付] 行情模块函数签名 fetch_quotes(symbol, interval) 设计如下…… [用户指令] 确认。下一步:为信号计算模块定义双均线策略的判断逻辑。

三个细节值得停下来看。其一,step 一次推进半轮:先助理交付,再用户针对交付给出新指令,一个循环体正好走完一轮完整对手戏。其二,回传给下一轮的输入是助理的方案而非用户的指令——对话历史的维护方式决定了角色的记忆质量,第 2.4 节拆架构时会展开。其三,terminated 标志来自用户侧喊出的终止口令,这个口令在提示里就写好了,谢幕权在甲方手里。

检验你有没有立住舞台

拿这三个问题自查。第一,你的会话里谁有资格宣布任务完成?答案必须是用户侧——如果助理侧也能随时喊停,交付质量就没了守门人。第二,你的两侧角色名是否具体到职责?"股票交易员"合格,"甲方"不合格;角色名越具体,模型的言行越收敛。第三,轮次上限设了多少、为什么是这个数?上限不是防御性数字,它是成本阀门:每轮都是两次模型调用,十轮对手戏就是二十次调用,上限直接决定一次实验的预算。

本节立起了舞台与主角。下一节把手伸进道具箱,逐个过一遍任务提示、角色设定与启示式提示这三样最容易混淆的核心概念。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U