基于 hello_agents 构建“猜猜我是谁“交互式猜人物游戏:LLM 角色扮演、搜索增强与语义匹配的完整实战
2026/9/12 2:32:54 网站建设 项目流程

基于 hello_agents 构建"猜猜我是谁"交互式猜人物游戏:LLM 角色扮演、搜索增强与语义匹配的完整实战

【免费下载链接】hello-agents📚 《从零开始构建智能体》——从零开始的智能体原理与实践教程项目地址: https://gitcode.com/GitHub_Trending/he/hello-agents

本篇文章以开源仓库 hello-agents 中Co-creation-projects/afei-GuessWhoAmI子项目为蓝本,系统拆解如何基于hello_agents框架从零搭建一个由 LLM 驱动、前后端完整的交互式猜人物游戏:Agent 随机扮演历史人物、神话人物或网络红人,玩家通过多轮对话提问、有限次提示与语义猜测来揭开谜底。读完本文,你将掌握 LLM 动态人物生成、Tavily 搜索增强提示、SimpleAgent 角色扮演、LLM 语义匹配与 Wikipedia 图片检索这一整套可复用的 Agent 应用开发方案。

项目定位与核心设计亮点

GuessWhoAmI(猜猜我是谁)是一个基于hello_agents框架开发的交互式猜人物游戏。AI Agent 随机扮演一位历史人物、神话人物或网络红人,用户通过多轮对话提问来猜测其身份。项目在 README 中总结了六大特色:

  • 🤖LLM 动态生成人物—— 每局由大模型随机生成人物,涵盖中西历史、神话、虚构角色、网络红人等多个领域,不重复;
  • 🎭沉浸式角色扮演—— Agent 以第一人称扮演人物,语气符合其性格与时代背景,回答具有迷惑性和引导性;
  • 🔍Tavily 搜索增强—— 自动搜索人物资料,生成由模糊到具体的 3 条提示;
  • 🖼️猜对后展示人物图片—— 猜对后通过 Wikipedia 搜索并展示人物图片;
  • 🧠语义猜测匹配—— 使用 LLM 语义判断猜测是否正确,支持别名、外号等多种表达;
  • FastAPI 高性能后端+ 现代化 Web 前端。

从架构角度看,这个项目最值得学习的地方在于:它把"随机性注入"(防人物重复)、"外部搜索工具"(Tavily)、"无工具纯对话 Agent"(角色扮演)与"LLM 作为判断器"(语义匹配)四种 Agent 能力组合在一条完整的游戏流水线中,是hello_agents框架多工具协同的典型范例。

项目结构与模块划分

afei-GuessWhoAmI/ ├── restart.sh # 一键启动脚本(前后端) ├── backend/ │ ├── main.py # FastAPI 入口,API 路由 │ ├── agents.py # Agent 核心逻辑(人物生成、角色扮演、猜测判断) │ ├── game_logic.py # 游戏状态管理(GameSession) │ ├── config.py # 配置管理(Settings 单例) │ ├── models.py # Pydantic 请求/响应模型 │ ├── requirements.txt # Python 依赖 │ ├── .env.example # 环境变量模板 │ └── tools/ │ ├── tavily_search_tool.py # Tavily 搜索工具(生成提示) │ └── search_image_tool.py # Wikipedia 图片搜索工具 ├── frontend/ │ ├── index.html # 主页面 │ ├── style.css # 样式文件 │ └── app.js # 交互逻辑 └── logs/ ├── backend.log # 后端运行日志 └── frontend.log # 前端服务日志

模块职责非常清晰:main.py只负责 HTTP 层与路由分发,game_logic.py管理游戏状态机,agents.py封装所有 LLM 相关能力,两个工具类继承hello_agentsTool基类独立完成外部能力接入,前端则是零框架依赖的原生 HTML/CSS/JS。

核心架构:一局游戏的完整流水线

一局游戏的启动并非简单地把名字交给 Agent,而是经历一条**"生成 → 搜索 → 扮演"**的三阶段流水线,全部由HistoricalFigureAgent的构造函数串联(见 agents.py):

  1. 人物生成:调用_generate_figure(),由 LLM 随机生成"名称 + 一句话简介";
  2. 提示预生成:调用_generate_hints(),先用 Tavily 搜索人物资料,再让 LLM 基于资料产出 3 条由模糊到具体的提示;
  3. 角色扮演 Agent 创建:调用_create_roleplay_agent(),把人物简介注入 system prompt,创建一个enable_tool_calling=False的纯对话SimpleAgent

下面逐一深入每一阶段的源码实现。

LLM 动态人物生成:如何避免"每次都是同一个人"

人物生成是整个游戏的随机性来源。项目通过三层机制确保每次开局的人物不重复:

第一层:领域候选池随机采样。agents.py 定义了_FIGURE_DOMAINS,包含 13 个领域:中国古代帝王、文人墨客、军事家、中国神话人物、西游记人物、三国人物、西方历史人物、西方神话人物、世界科学家、知名虚构角色、现代体育明星、中国近现代人物、网络红人与 UP 主。每次开局随机选一个领域作为 system prompt 的方向约束。

第二层:随机种子 + 时间戳注入。_build_random_figure_prompt()(agents.py)会生成一个 10000~99999 的随机种子写入 system prompt;同时 user 消息里还会注入毫秒级时间戳ts = int(time.time() * 1000)与一个 1~9999 的随机数。这种做法一方面是打乱 LLM 缓存的相似请求,另一方面从 prompt 层面强制模型发散。

第三层:严格输出格式解析 + 兜底。prompt 要求模型严格输出两行:

名称:<人物名称> 简介:<一句话概括其性格特点与主要成就,50字以内>

_parse_figure()(agents.py)逐行解析,兼容全角/半角冒号与"姓名/名称"两种前缀;一旦解析失败或 LLM 调用异常,则回退到_fallback_figure()内置的人物池(孔子、孙悟空、武则天、诸葛亮、哈利·波特)随机兜底,保证游戏在任何情况下都能开局。

Tavily 搜索增强:由模糊到具体的三条提示

提示(hint)是本游戏的辅助机制,设计上要求"由模糊到具体",第 1 条最模糊、第 3 条最具体,且不能直接说出答案。其实现分两步:

  1. Tavily 搜索人物资料TavilySearchTool(tavily_search_tool.py)继承hello_agents.tools.base.Tool,调用TavilyClient.search(),使用search_depth="basic"max_results=5include_answer=False(只取原始检索结果,不生成 AI 摘要)。出于 token 成本与提示质量平衡,工具只取前 1 条结果,并经过正则清洗(去除 URL、折叠空白、去重标点、规整省略号)后截断到 300 字符。
  2. LLM 生成提示:将搜索资料与答案名一起交给 LLM,由_HINT_SYSTEM_PROMPT(agents.py)约束"每条提示单独一行、格式为提示N:<内容>、由模糊到具体、不能直接说出答案"。_parse_hints()用正则^(提示\d[::]\s*|\d+[\.、]\s*)清洗行前缀,不足 3 条时用通用 fallback 提示补齐。

值得注意的是,Tavily 未配置时系统不会崩溃:_generate_hints()self._search_tool为空时直接走_fallback_hints(),返回"这是一个广为人知的事物"等通用提示,实现优雅降级(详见 agents.py)。

沉浸式角色扮演:SimpleAgent 的"人格注入"

角色扮演 Agent 是游戏体验的核心。_create_roleplay_agent()创建了一个name="guess_who_agent"enable_tool_calling=False的纯对话SimpleAgent——扮演阶段不需要任何工具,避免 Agent 在回答时偏离角色。

其灵魂在于_ROLEPLAY_SYSTEM_PROMPT(agents.py),它要求 Agent:

  1. 以人物第一人称回答,语气措辞符合性格与时代背景;
  2. 必须直接针对用户问题给出明确回应("是的"/"不是"/"确实如此"),不能回避或答非所问;
  3. 在明确回应基础上用符合人物身份的语气补充一句;
  4. 每次回答 1~2 句话,保持简短;
  5. 回答基于人物真实生平,不编造;
  6. 严禁在任何情况下说出人物名称(包括姓名、字号、封号、外号等一切称谓);
  7. 与人物完全无关的问题用符合身份的方式婉转说明。

"先明确作答 + 再角色化补充"的指令设计,兼顾了游戏可玩性(玩家能获得有效信息)与沉浸感(回答有性格),是角色扮演类 Agent prompt 的实用模板。

语义猜测匹配与画像展示

玩家提交猜测后,HistoricalFigureAgent.make_guess()(agents.py)的处理策略是:

  1. 精确匹配优先guess.strip().lower() == actual_name.lower()
  2. LLM 语义匹配兜底:精确匹配失败时调用_semantic_match(),使用_SEMANTIC_MATCH_PROMPT("判断以下两个名称是否指代同一个人物或事物,只需回答'是'或'否'")让 LLM 判断,结果以result.startswith("是")判定。这样"孙悟空 vs 齐天大圣""李太白 vs 李白"这类别名、外号表达也能正确命中。

猜对后,后端调用SearchImageTool.search_photos()(search_image_tool.py)从 Wikipedia 拉取画像。该工具不走容易被 403 的w/api.php搜索接口,而是直接调用 REST Summary API(中文优先、英文兜底,见源码中的_ZH_SUMMARY_URL/_EN_SUMMARY_URL),并伪造浏览器 User-Agent 规避反爬,最终把缩略图与原图 URL 随接口返回,前端据此渲染画像画廊。

游戏状态管理:GameSession 与 GameManager

游戏状态由 game_logic.py 管理:

  • GameSession:每局一个实例,持有session_id(UUID)、current_figure(当前人物)、hints(预生成提示列表)、questions_asked/hints_used(已用提问/提示计数)、is_game_over/is_correctguess_history(猜测历史),并从配置读取max_questions(10)与max_hints(3)。
    • ask_question():提问计数自增,达到上限即置is_game_over=True
    • make_guess():先精确匹配、再由注入的semantic_match_fn兜底;猜对或次数用尽即结束游戏并返回figure_info
    • get_hint():按序返回预生成提示,同时返回hint_level与剩余次数;
    • get_game_status():汇总会话状态供前端刷新。
  • GameManager:维护active_sessions字典,提供create_session/get_session/end_session/cleanup_old_sessions(默认清理超过 60 分钟未更新的会话),并暴露全局单例game_manager

在 main.py 中,会话存储采用session_id -> (GameSession, HistoricalFigureAgent)的元组配对(active_sessions字典),每次请求通过get_session_pair()校验会话存在性,会话不存在返回 404。

环境要求与配置

环境要求

  • Python 3.8+
  • ModelScope API Key(必须,提供 OpenAI 兼容的 LLM 接口)
  • Tavily API Key(必须,用于搜索增强提示,可在 Tavily 平台注册获取)

依赖清单见 requirements.txt:fastapi==0.104.1uvicorn[standard]==0.24.0hello_agents>=0.1.0python-dotenv==1.0.0pydantic==2.5.0httpx==0.25.2tavily-python>=0.3.0requests>=2.31.0

环境变量与配置参数

配置管理在 config.py 中实现:Settings类在模块导入时通过load_dotenv加载backend/.env,并以单例(get_config())方式供全项目读取。环境变量模板见 backend/.env.example。

配置项代码默认值说明
LLM_MODEL_IDqwen-flash使用的 LLM 模型(推荐 flash 系列以降低延迟)
LLM_API_KEYModelScope API Key(必填)
LLM_BASE_URLhttps://api-inference.modelscope.cn/v1/LLM 接口地址(OpenAI 兼容)
LLM_TIMEOUT30(秒)LLM 请求超时;.env.example示例值给出180以应对长响应
TAVILY_API_KEYTavily 搜索 Key(必填),未配置时自动降级为 fallback 提示
MAX_QUESTIONS10每局最大提问次数(代码级常量,不读 .env)
MAX_HINTS3每局最大提示次数(代码级常量,不读 .env)
HOST/PORT0.0.0.0/8000后端监听地址与端口(代码级常量)

需要注意:MAX_QUESTIONSMAX_HINTSHOSTPORT属于"代码级默认值,不存放在 .env"(见 config.py 注释),如需调整需直接修改源码。Settings.validate()会在启动时检查LLM_API_KEY是否为空并打印警告。

快速开始

1. 安装依赖

cd /path/to/repo/Co-creation-projects/afei-GuessWhoAmI/backend pip install -r requirements.txt

2. 配置环境变量

复制模板并填写配置:

cp backend/.env.example backend/.env

编辑backend/.env

# LLM 配置(ModelScope API,必填) LLM_MODEL_ID=qwen-flash LLM_API_KEY=your_modelscope_api_key LLM_BASE_URL=https://api-inference.modelscope.cn/v1/ LLM_TIMEOUT=180 # Tavily 搜索 API(必填,用于搜索增强提示) TAVILY_API_KEY=your_tavily_api_key

3. 一键启动(推荐)

使用 restart.sh 同时启动前后端:

cd /path/to/repo/Co-creation-projects/afei-GuessWhoAmI bash restart.sh

脚本会自动:

  • 停止已有的前后端进程(按端口lsof清理 + 按进程名pgrep清理);
  • 启动后端(FastAPI,端口8000);
  • 启动前端(Pythonhttp.server,端口3000);
  • 通过wait_for_port轮询等待服务就绪(最长 15 秒),超时报错并提示查看日志。

启动成功后输出示例:

✅ All services started successfully! 🔧 Backend → http://localhost:8000 🔧 API Docs → http://localhost:8000/docs 🌐 Frontend → http://localhost:3000

⚠️ 注意:restart.sh中硬编码了 Python 解释器路径VENV_PYTHON="/home/afei/hello_agent_venv/bin/python"(脚本第 14 行),这是作者机器上的虚拟环境路径,其他环境运行前需将其改为本机 Python 路径。

4. 访问地址

服务地址
🌐 游戏前端http://localhost:3000
🔧 后端 APIhttp://localhost:8000
📖 API 文档http://localhost:8000/docs

5. 手动启动(可选)

# 启动后端 cd backend python main.py # 启动前端(另开终端) cd frontend python -m http.server 3000

API 接口一览

后端基于 FastAPI 提供 RESTful 接口(路由定义见 main.py):

方法路径说明
POST/api/game/start开始新游戏(LLM 生成人物 + 预生成提示)
POST/api/game/chat向 Agent 提问(角色扮演对话)
POST/api/game/guess提交猜测(语义匹配判断,猜对返回人物图片)
GET/api/game/hint获取下一条提示
POST/api/game/end结束当前游戏
GET/api/game/status/{session_id}获取当前游戏状态

所有接口统一返回 models.py 中定义的GameResponse结构:

class GameResponse(BaseModel): success: bool message: str data: Optional[dict] = None error: Optional[str] = None

几个实现细节值得注意:

  • start接口在每次开局前调用_clear_log_file()截断后端日志文件——由于日志由 Python 的FileHandler持有文件描述符,代码采用"关闭流 → 截断文件 → 重新打开追加流"的方式安全清空,避免写入 NUL 字节(见 main.py);
  • chat接口在游戏结束后(is_game_over=True)会拒绝消息并提示"请开始新游戏";
  • end接口返回完整状态(含答案figure_name)并从active_sessions中移除会话;
  • CORS中间件配置为allow_origins=["*"],允许所有来源跨域访问,方便前端本地联调。

前端交互与游戏规则

前端是零框架的原生实现:index.html定义页面结构(开始页/游戏页/结果弹窗),style.css负责样式,app.js 用Fetch API与后端通信。核心交互逻辑:

  • startNewGame():POST/api/game/start,把返回的session_idmax_questionsmax_hints存入前端状态,切换到游戏界面并展示欢迎语;
  • sendMessage():POST/api/game/chat,将用户输入渲染为气泡并展示 Agent 回复,随后用服务端返回的remaining_questions刷新统计;
  • requestHint():POST/api/game/hint,展示💡 提示:...并更新剩余提示数;
  • submitGuess():POST/api/game/guess,猜对时调用endGame(true, figure_info, portrait_images)渲染画像画廊,猜错则继续并同步剩余提问数。

完整游戏规则如下:

  1. 点击「开始游戏」,系统由 LLM 随机生成一位人物(历史、神话、虚构、网络红人均有可能);
  2. 通过对话向 Agent 提问,Agent 以该人物第一人称回答,不会直接说出名字
  3. 最多可提问10 次,可使用提示3 次(提示由模糊到具体);
  4. 随时可以提交猜测,支持别名、外号等多种表达方式;
  5. 猜对后展示人物图片;提问次数用完或主动结束则游戏结束并揭晓答案。

技术栈

后端

  • FastAPI—— Web 框架(含自动生成/docs交互式 API 文档)
  • hello_agents—— AI Agent 框架(SimpleAgentHelloAgentsLLMMessageTool基类)
  • Pydantic v2—— 数据验证
  • Uvicorn—— ASGI 服务器
  • Tavily Python SDK—— 搜索增强
  • Wikipedia REST API—— 人物图片搜索

前端

  • HTML5 / CSS3 / JavaScript—— 原生实现,无框架依赖
  • Fetch API—— 与后端通信

AI / LLM

  • ModelScope API—— OpenAI 兼容接口(默认模型:qwen-flash
  • LLM 人物生成—— 动态随机生成,避免重复
  • LLM 语义匹配—— 判断猜测是否与答案指代同一人物

日志与故障排除

日志

运行日志保存在logs/目录:

# 实时查看后端日志 tail -f logs/backend.log # 实时查看前端日志 tail -f logs/frontend.log

后端日志采用"自定义FileHandler挂到 root logger"的方式写入(刻意不用basicConfig,因为它对已被 uvicorn 预配置过 handler 的 root logger 是空操作),格式为时间 [级别] 日志名 - 消息,并在 start 接口中做文件截断清理,相关实现见 main.py。

故障排除

LLM 调用失败

  • 检查backend/.env中的LLM_API_KEYLLM_BASE_URL
  • 确认 ModelScope 账号有对应模型的访问权限;
  • 代码中 LLM 调用异常均有兜底(人物生成走内置人物池、对话返回"抱歉,我现在有些恍惚,请再问一次吧。"),游戏不会因单次调用失败而崩溃。

每次生成同一个人物

  • 已通过随机种子 + 时间戳注入解决;若仍出现,请检查 LLM 模型是否支持随机性参数。

Tavily 搜索不可用

  • 检查backend/.env中的TAVILY_API_KEY是否正确填写;
  • 未配置时系统会自动降级使用 fallback 提示,但提示质量会下降(从源码可见_generate_hints()中 Tavily 与 LLM 任一环节失败都会走 fallback)。

端口被占用

  • restart.sh会自动清理占用端口的进程(kill_portkill_pattern),重新运行脚本即可。

CORS 错误

  • 后端已配置 CORS 允许所有来源,确保前端访问正确的后端端口(默认 8000)。

总结与可扩展方向

GuessWhoAmI 用不到千行代码,完整示范了"LLM 随机内容生成 + 外部搜索工具增强 + 无工具角色扮演 + LLM 语义判断 + 图像检索"五类 Agent 能力的组合方式,且每一环都有降级兜底设计,工程上相当完整。在此基础上还可以继续扩展:

  • 增加难度分级:把人物领域、提问次数、提示数量做成可配置的难度档位;
  • 多人对战:利用GameManager.cleanup_old_sessions的会话清理机制,扩展为多房间同时开局的在线对战模式;
  • 接入更多搜索/图像源TavilySearchToolSearchImageTool均继承自hello_agentsTool基类,只需实现run()get_parameters()即可低成本替换或新增工具;
  • 引入语音/多模态:结合 LLM 多模态能力,让 Agent 用语音作答或支持图片式谜题。

对想要上手hello_agents框架的开发者而言,这个项目是"从框架 API 到完整可玩游戏"的最短路径之一,值得通读其 agents.py 与 game_logic.py 后自行复刻一版。

【免费下载链接】hello-agents📚 《从零开始构建智能体》——从零开始的智能体原理与实践教程项目地址: https://gitcode.com/GitHub_Trending/he/hello-agents

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询