全网爆火的AI狼人杀:开源了

大模型增长营销云安全

picture.image

❝ 近期网上疯狂流传了一个人类与AI参与的VR狼人杀游戏,十分有趣。通过对游戏内容的分析,我发现游戏VR的表现形式十分吸引人,但其中的AI对话部分并不复杂。于是小智使用LangGraph实现了一个文字版本,今天将代码开源(文末获取) ,希望大家能喜欢。

AI狼人杀,人类一败涂地

首先给没看过视频的小伙伴们介绍下:

一个名为 Tore Knabe 的网友在 X 平台发布了一个视频,展示了一个有趣的实验:

这是一次反向图灵测试 ,几个全球最先进的大模型坐在一起,坐着火车唱着歌,但其中混进了人类:

picture.image

参与者扮演历史知名人物,古希腊巨哲 —— 亚里士多德(GPT4 Turbo),维也纳古典乐派代表人物 —— 莫扎特(Claude3 Opus),意大利文艺复兴时期画家 —— 列奥纳多・达・芬奇(Llama3),埃及艳后 —— 克利奥帕特拉七世(Gemini Pro)。其中蒙古军事家 —— 成吉思汗由人类扮演。picture.image

游戏规则要求,参与者通过提问和回答来分辨人类与 AI,最后通过投票确定谁是人类。

人类扮演者因缺乏深度和逻辑性的回答,在第一轮的投票中就被3票淘汰,人类一败涂地picture.image

代码实现

接下来,我们来看看如何用LangGraph 把这个游戏做出来吧!

游戏过程

游戏的过程很简单,主要包括以下三个环节。小智使用主持人Agent 来将整个流程串起来。

  • 第一环节:提问与回答 ,各个游戏角色之间进行互相提问,并回复问题。

        
          
def ask\_for\_speak(state: GameState):  
    # 如果待发言池为空,则进入投票阶段  
    if len(state['waiting']) == 0:  
        state['waiting'] = state['roles'].copy()  
        state['stage'] = 'vote'  
        print(f"主持人:游戏结束,请进行投票。请大家耐心等待投票结果!")  
        return ask_for_vote(state)  
    chat_history = state['chat\_history']  
    last_chat = chat_history[-1]  
    last_chat_str = last_chat[0]+': '+last_chat[1]  
    waiting_roles_str = ','.join(state['waiting'])  
    llm = ChatOpenAI(model="glm-4",  temperature=0.01)  
    choose_prompt = ChatPromptTemplate.from_template(load_prompt("prompt/choose\_speaker.prompt"))  
    chain = choose_prompt|llm|StrOutputParser()  
    role_chosen = chain.invoke({"history": last_chat_str, "waitings": waiting_roles_str})  
    if role_chosen in state['waiting']:  
        state['waiting'].remove(role_chosen)  
        state['next\_speaker'] = role_chosen  
    else:  
        next = random.choice(state['waiting'])  
        state['next\_speaker'] = next  
        state['waiting'].remove(next)  
    return state  

      
  • 第二环节:投票 :在所有角色依次发言后,玩家将根据之前的互动和提问环节的表现,进行相互投票以确定谁是人类。

        
          
def ask\_for\_vote(state: GameState):  
    if len(state['waiting']) == 0:  
        human_role = state['human\_role']  
        round = state['round']  
        # 统计票数决定是否结束游戏  
        vote_store = state['vote\_store']  
        human_vote_count = 0  
        for vote in vote_store:  
            vote_role = vote[1]['vote']  
            if vote_role == human_role:  
                human_vote_count += 1  
        totle_votes = len(state['roles'])  
        # 如果人类角色票数超过一半,结束游戏  
        if human_vote_count > totle_votes / 2:  
            state['stage'] = 'end'  
            print("AI win!")  
            print("投票详情如下:"+json.dumps(vote_store, ensure_ascii=False))  
        elif round == 3:  
            state['stage'] = 'end'  
            print("Human存活超过3轮,Human win!")  
        else:  
            print("Human存活,游戏继续!")  
            print("上轮投票详情如下:"+json.dumps(vote_store, ensure_ascii=False))  
            state = gen_and_dispatch_role(state)  
        return state  
    next = random.choice(state['waiting'])  
    state['next\_speaker'] = next  
    state['waiting'].remove(next)  
    return state  

      
  • 最后:结果揭晓 ,基于投票判断人类扮演者是否被发现。

游戏角色

有了主持人Agent控场,那么其他角色就很好设计了,由于AI除了扮演角色不一样外,所执行的逻辑是一致的,我们可以统一抽象为AI角色扮演Agent ,再就是用于人类输出的人类Agent

  • AI角色扮演Agent :由四个AI NPC扮演历史知名人物,发表演讲,并在投票阶段进行投票。

        
          
def speak(state: GameState):  
    role = state['next\_speaker']  
    roles_str = ','.join(state['roles'])  
    chat_history = state['chat\_history']  
    history = ""  
    for chat in chat_history:  
        history += f"{chat[0]}: {chat[1]}\n"  
    llm = ChatOpenAI(model="glm-4",  temperature=0.8)  
    role_prompt = ChatPromptTemplate.from_template(load_prompt("prompt/role.prompt"))  
    chain = role_prompt|llm|StrOutputParser()  
    rsp = chain.stream({"role": role, "roles": roles_str, "history": history})  
    output = ''  
    print(role+':', end='', flush=True)  
    for token in rsp:  
        output += token  
        print(token, end='', flush=True)  
    print()  
    print("---------------------------")  
    state['chat\_history'].append((role, output))  
    return state  
  
def vote(state: GameState):  
    role = state['next\_speaker']  
    roles_str = ','.join(state['roles'])  
    chat_history = state['chat\_history']  
    history = ""  
    for chat in chat_history:  
        history += f"{chat[0]}: {chat[1]}\n"  
    llm = ChatOpenAI(model="glm-4",  temperature=0.01)  
    vote_prompt = ChatPromptTemplate.from_template(load_prompt("prompt/vote.prompt"))  
    chain = vote_prompt|llm|JsonOutputParser()  
    output = chain.invoke({"role": role, "roles": roles_str, "history": history})  
    state['vote\_store'].append((role, output))  
    return state  

      
  • 人类Agent : 人类Agent的逻辑相比AI更加简单只需要在恰当的阶段,提示人类玩家进行输出。

        
          
def speak(state: GameState):  
    role = state['next\_speaker']  
    print("你当前的角色是:"+role)  
    user_input = input("请输入你的对话内容: ")  
    state['chat\_history'].append((role, user_input))  
    return state  
  
def vote(state: GameState):  
    role = state['next\_speaker']  
    roles_str = ','.join(state['roles'])  
    print("你当前的角色是:"+role)  
    print("可供投票的选项有:"+roles_str)  
    user_vote = input("请输入你的投票选择: ")  
    user_reason = input("请输入你的投票原因: ")  
    state['vote\_store'].append((role, {"vote":user_vote,"reason":user_reason}))  
    return state  
  

      

实现效果及完整代码

最终实现效果如下所示

游戏的完整代码已上传github开源,感兴趣的小伙伴可以拉取到自己本地玩一玩: https://github.com/q2wxec/langgraph-demo/tree/master/werewolf

今天的内容就到这里,如果老铁觉得还行,可以来一波三连,感谢!

PS

AI小智技术交流群(技术交流、摸鱼、白嫖课程为主)又不定时开放了,感兴趣的朋友,可以在下方公号内回复:666,即可进入。

老规矩

,道友们还记得么,

右下角的 “在看” 点一下

, 如果感觉文章内容不错的话,记得分享朋友圈让更多的人知道!

0
0
0
0
关于作者
关于作者

文章

0

获赞

0

收藏

0

相关资源
ByteHouse极致降本实践指南
抖音集团以及金融、游戏等行业基于数据仓库的降本增效经验
相关产品
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论