跳到主要内容

RolePlaying — 对称双人对话

这章讲什么: RolePlaying 是 CAMEL 这个名字的由来。它让两个角色对称地结对:一个扮「用户」不停下指令,一个扮「助手」不停执行,框架在两者间转发消息推进任务。理解它能看清 CAMEL 「communicative agents」的初心。

1. 它要解决的小问题

人想让 AI 完成一个复杂任务("开发一个股票交易机器人"),但人懒得一步步下指令。RolePlaying 的点子:再造一个 AI 来扮演那个「不停下指令的人」。于是变成两个 AI 对话——一个负责想下一步该干嘛,一个负责真的干。

2. 思路 / 直觉

两个角色不对等但对称地轮流:

  • user agent(扮指令方):看当前进展,产出「下一条指令」。
  • assistant agent(扮执行方):收到指令,产出「执行结果」。

一来一回就是一个 step()。注意箭头:assistant 的输出喂给 user,user 产出新指令再喂给 assistant。

开始前还可能有两个辅助 agent 先加工任务:

辅助 agent作用默认开?
TaskSpecifyAgent把模糊任务变具体("做个游戏" → 详细规格)是(with_task_specify=True)
TaskPlannerAgent给任务追加一个执行计划

3. 图示:一个 step 的消息流

上一轮 assistant_msg


┌──────────────┐ 产出「下一条指令」 user_msg
│ user_agent │ ───────────────────────────┐
│ (扮指令方) │ │
└──────────────┘ ▼
┌────────────────┐
新的 assistant_msg ◀────────────── │ assistant_agent │
(下一轮的输入) 产出「执行结果」 │ (扮执行方) │
└────────────────┘

怎么读:一个 step() = 先让 user 出指令,再让 assistant 执行。两个箭头首尾相接,所以连续 step() 就是不断的一问一答。

4. 原理演示

# 示意,非源码:RolePlaying 的主循环用法
from camel.societies import RolePlaying

session = RolePlaying(
assistant_role_name="Python 程序员",
user_role_name="股票交易员",
task_prompt="开发一个股票交易机器人",
)
assistant_msg = session.init_chat() # 拿到开场白
for _ in range(10): # 跑 10 轮
assistant_resp, user_resp = session.step(assistant_msg)
print("用户说:", user_resp.msg.content) # 这一轮的指令
print("助手做:", assistant_resp.msg.content) # 这一轮的执行
assistant_msg = assistant_resp.msg # 助手输出 → 下一轮输入

重点看最后一行:assistant 的输出回灌成下一轮的起点,对话就这样自我推进。

5. 真实实现

RolePlaying.step()(role_playing.py:631)的真实顺序与上图一致:

  • role_playing.py:661 user_response = self.user_agent.step(assistant_msg)——先让 user agent 基于上一轮 assistant 的话,产出新指令。
  • role_playing.py:671 user_msg = self._reduce_message_options(user_response.msgs)——若开了 critic 或多候选,在这里收敛成一条。
  • role_playing.py:681 assistant_response = self.assistant_agent.step(user_msg)——再把这条指令喂给 assistant 执行。
  • 最后(role_playing.py:698-708)把两边结果打包成 (assistant_response, user_response) 返回。

开场消息由 init_chat(role_playing.py:548)产生,默认内容是 "Now start to give me instructions one by one..."(role_playing.py:565-568)——即让 assistant 先发话,邀请 user 开始下指令。

任务预处理在构造函数里就跑完:_init_specified_task_prompt(role_playing.py:214)调 TaskSpecifyAgent 把任务具体化;_init_planned_task_prompt(role_playing.py:264)可选地追加计划。

6. 关键细节 / 坑

① 系统提示决定「入戏」程度。 两个 agent 的系统消息由 SystemMessageGenerator.from_dicts(role_playing.py:345-353)按角色名 + 任务生成,这就是论文里的「inception prompting」:用提示把 LLM 锁进角色,让它持续以该角色说话。

② 可以塞 critic 做「三选一」。 with_critic_in_the_loop=True 时,某一方可产出多个候选消息,CriticAgent 来挑一个(_reduce_message_options,role_playing.py:540-542)。

③ 终止靠任一方 terminated 若 user 或 assistant 的 step 返回 terminated=True(或 msgs 为空),step() 立即返回空消息(role_playing.py:662-670:682-692),对话结束。

④ 与 Workforce 的关系: RolePlaying 也能作为 Workforce 里的一个工人节点(RolePlayingWorker),即「一个工位上坐着结对的两个 agent」。详见 03-workforce.md

7. 横向对比

RolePlayingWorkforce
结构对称(两个固定角色轮流)非对称(协调者 + 多工人)
任务拆分不拆,靠对话逐步推进显式拆成子任务并行派发
失败处理无内建恢复多种恢复策略
适合探索性、数据生成、两角色协作工程化、多专长并行流水线

8. 代码地图

主题文件符号
一轮对话camel/societies/role_playing.pyRolePlaying.step / astep
开场消息camel/societies/role_playing.pyRolePlaying.init_chat
任务具体化camel/societies/role_playing.pyRolePlaying._init_specified_task_prompt
多候选收敛camel/societies/role_playing.pyRolePlaying._reduce_message_options
系统提示生成camel/generators.pySystemMessageGenerator