从零构建赛博小镇:用 HelloAgents 框架与 Godot 引擎打造具备记忆与好感度的 AI NPC 世界

从零构建赛博小镇:用 HelloAgents 框架与 Godot 引擎打造具备记忆与好感度的 AI NPC 世界 从零构建赛博小镇用 HelloAgents 框架与 Godot 引擎打造具备记忆与好感度的 AI NPC 世界【免费下载链接】hello-agents 《从零开始构建智能体》——从零开始的智能体原理与实践教程项目地址: https://gitcode.com/datawhalechina/hello-agents赛博小镇是一个将智能体技术与游戏引擎结合的实战项目以 HelloAgents 框架驱动 NPC 的对话、记忆与好感度以 FastAPI 提供后端服务以 Godot 4 游戏引擎渲染 2D 像素风办公室场景让玩家可以用自然语言与真正活着的 NPC 自由交流。读完本文你将掌握 AI NPC 的三层核心技术——基于 SimpleAgent 的角色化智能体构建、短期长期双记忆系统与五级好感度机制、批量生成即时响应的混合对话模式以及 Godot 前端与 FastAPI 后端的完整通信链路。为什么要把智能体放进游戏引擎传统游戏中的 NPC 通常只能说固定台词或通过预设的对话树进行有限互动。即使是最复杂的 RPGNPC 对话也由编剧事先写好可控但缺乏真正的智能与生命力。赛博小镇给出了另一种可能NPC 能够理解玩家说出的任何自然语言记住上次聊了什么、你们的关系如何甚至记住你的喜好。每个 NPC 都有独立的职业、性格和说话风格对你的态度会随互动从陌生变为朋友甚至挚友。这种游戏引擎 大语言模型的组合应用场景广泛——教育游戏中 NPC 可以扮演历史人物进行互动式教学虚拟办公室中 NPC 可以扮演同事与导师NPC 还可以作为情感陪伴者服务于心理健康领域最直接的应用则是为传统游戏注入 AI NPC 以提升玩家体验。赛博小镇包含五项核心功能智能 NPC 对话系统、短期长期记忆系统、五级好感度系统、2D 像素风格办公室中的游戏化交互以及实时日志系统所有对话与互动均被记录便于调试分析。项目架构与数据流转四层分离式技术架构赛博小镇采用游戏引擎 后端服务的分离架构分为四个层次各层职责单一、可独立开发与测试前端层Godot 4.5 游戏引擎负责游戏渲染、玩家控制、NPC 显示和对话 UI。Godot 是开源免费的 2D/3D 游戏引擎非常适合快速开发像素风格游戏。后端层FastAPI负责 API 路由、NPC 状态管理、对话处理和日志记录。FastAPI 是现代化的 Python Web 框架性能优秀且开发效率高。智能体层HelloAgents 框架负责 NPC 智能、记忆管理和好感度计算。每个 NPC 都是一个SimpleAgent实例拥有独立的记忆和状态。外部服务层提供 LLM 能力如 OpenAI、DeepSeek、智谱等 API、向量存储与数据持久化。架构如图 15.1 所示一次完整的交互循环玩家在 Godot 中按 E 键与 NPC 互动Godot 通过 HTTP API 发送对话请求到 FastAPI 后端后端调用 HelloAgents 的SimpleAgent处理对话Agent 从记忆系统中检索相关历史再调用 LLM 生成回复后端随后更新 NPC 状态和好感度记录日志到控制台与文件最后返回回复给 Godot 前端Godot 显示回复并更新 UI完成一次完整的交互循环。项目目录结构仓库中的完整项目位于code/chapter15/Helloagents-AI-Town源码组织如下Helloagents-AI-Town/ ├── helloagents-ai-town/ # Godot游戏项目 │ ├── project.godot # Godot项目配置 │ ├── scenes/ # main.tscn / player.tscn / npc.tscn / dialogue_ui.tscn │ ├── scripts/ # main.gd / player.gd / npc.gd / dialogue_ui.gd / api_client.gd / config.gd │ └── assets/ # characters / interiors / ui / audio └── backend/ # Python后端 ├── main.py # FastAPI主程序与API路由 ├── agents.py # NPC Agent系统角色配置、记忆管理 ├── batch_generator.py # 批量对话生成器 ├── relationship_manager.py # 好感度管理 ├── state_manager.py # NPC状态管理与定时更新 ├── logger.py # 日志系统 ├── view_logs.py # 实时查看日志工具 ├── config.py # 配置管理从 .env 读取 ├── models.py # Pydantic 数据模型 ├── requirements.txt # Python依赖 └── memory_data/ # 每个NPC的独立记忆存储目录5 分钟快速体验环境要求Godot 4.2 或更高版本、Python 3.10 或更高版本、一个 LLM API 密钥OpenAI、DeepSeek、智谱、ModelScope 等。启动后端在code/chapter15/Helloagents-AI-Town/backend目录下# 1. 安装依赖 pip install -r requirements.txt # 2. 配置环境变量编辑 .env 文件填写 API 密钥 cp .env.example .env # 3. 启动后端服务 python main.py成功后输出 赛博小镇后端服务启动中... ✅ 所有服务已启动! API地址: http://0.0.0.0:8000 API文档: http://0.0.0.0:8000/docs 后端配置集中在 config.py 中服务监听0.0.0.0:8000NPC 状态更新间隔默认 30 秒LLM 配置从.env读取默认模型为Qwen/Qwen2.5-72B-Instruct默认服务地址为https://api-inference.modelscope.cn/v1/。未配置LLM_API_KEY时系统会打印警告并以模拟模式运行NPC 会返回占位回复方便无密钥时先验证整体流程。启动 Godot打开 Godot 引擎点击导入选择code/chapter15/Helloagents-AI-Town/helloagents-ai-town/scenes/main.tscn导入并编辑后按 F5 或点击运行。体验核心功能游戏启动后进入像素风格的 Datawhale 办公室场景使用 WASD 移动角色走近 NPC 会出现按 E 键交互提示。按下 E 键弹出对话框即可输入任何想说的话NPC 会依据角色设定Python 工程师、产品经理、UI 设计师与互动历史回应好感度会随对话从陌生逐渐升级到挚友。所有好感度变化都会记录在后端日志中可用以下命令实时查看# 在 backend 目录下 python view_logs.pyNPC 智能体系统基于 SimpleAgent 的 NPC 角色化每个 NPC 都是一个独立的SimpleAgent实例。回顾第七章学到的知识SimpleAgent的核心是一个简单的对话循环接收用户消息 → 调用 LLM 生成回复 → 返回结果。在赛博小镇中关键是为每个 NPC 配置独特的系统提示词使其拥有不同的性格与角色设定。创建 NPC Agent 的基本流程是定义 NPC 基本信息ID、名称、职业、性格→ 据此构建系统提示词 → 创建SimpleAgent并配置记忆管理器。从仓库实际实现看agents.py 中的NPC_ROLES字典比文档示例更丰富每位 NPC 拥有 7 个维度的人格配置NPC_ROLES { 张三: { title: Python工程师, location: 工位区, activity: 写代码, personality: 技术宅,喜欢讨论算法和框架, expertise: 多智能体系统、HelloAgents框架、Python开发、代码优化, style: 简洁专业,喜欢用技术术语,偶尔吐槽bug, hobbies: 看技术博客、刷LeetCode、研究新框架 }, 李四: { title: 产品经理, location: 会议室, activity: 整理需求, ... }, 王五: { title: UI设计师, location: 休息区, activity: 喝咖啡, ... } }create_system_prompt()会将上述维度组织成完整的角色提示词包含角色设定职位/性格/专长/说话风格/爱好/位置/活动、行为准则保持角色一致性、用第一人称、回复控制在 30-50 字、可适当提及工作与爱好、超出专长时推荐同事以及对话示例few-shot 示范并在重要中明确要求 NPC 不要自称AI或语言模型要像真实同事一样自然对话、可表达情绪。这些细节是让 NPC活起来的关键。记忆系统集成短期与长期双层记忆记忆系统是 NPC 智能的关键。赛博小镇采用 HelloAgents 的WorkingMemory与EpisodicMemory分别构造短期与长期记忆短期记忆存储最近的对话容量有限、随时间自动清理作用是保持对话连贯性——例如玩家说它是什么颜色的时NPC 需要从短期记忆中定位它指什么。长期记忆存储全部对话历史使用向量数据库进行语义检索——例如玩家说还记得上次讨论的项目吗时NPC 可以从长期记忆中找回相关记录。仓库实现中NPCAgentManager._create_memory_manager()为每个 NPC 创建独立的MemoryManager参数比文档示例更加完整直接映射了记忆系统的底层行为memory_config MemoryConfig( storage_pathmemory_dir, # 每个NPC独立目录: memory_data/{npc_name}/ working_memory_capacity10, # 短期记忆最近10条对话 working_memory_tokens2000, # 短期记忆最多2000个token max_capacity100, # 长期记忆最多100条 importance_threshold0.3, # 只检索/整合重要性0.3的记忆 decay_factor0.95 # 时间衰减系数 ) memory_manager MemoryManager( configmemory_config, user_idnpc_name, # 以NPC名字作为user_id enable_workingTrue, # 启用工作记忆短期 enable_episodicTrue, # 启用情景记忆长期 enable_semanticFalse, # 不需要语义记忆 enable_perceptualFalse # 不需要感知记忆 )记忆数据会持久化到backend/memory_data/{npc_name}/memory.db仓库中已能看到张三、李四、王五各自的记忆库这意味着重启后端后 NPC 仍能记住与玩家的历史互动。一次对话的完整处理流程见agents.py中的chat()方法清晰体现了记忆与好感度的协同获取当前好感度与等级构建当前关系上下文用retrieve_memories(querymessage, memory_types[working, episodic], limit5, min_importance0.3)检索相关记忆构建增强提示词好感度上下文 记忆上下文 玩家当前消息调用agent.run(enhanced_message)生成回复调用好感度管理器分析情感并更新分数将玩家消息与 NPC 回复附带好感度、情感倾向等元数据写入记忆系统。值得一提的是每次保存对话时都会在metadata中记录当时的好感度、好感度变化量与情感倾向positive/neutral/negative为后续分析关系发展轨迹提供了数据基础。批量对话生成一次 LLM 调用喂饱整个办公室当多个玩家同时与不同 NPC 对话时后端需要并发处理多个 LLM 请求不仅增加成本还可能因并发限制导致失败或延迟。赛博小镇的解法是批量对话生成将多个 NPC 的对话请求合并成一次 LLM 调用让 LLM 一次性生成所有 NPC 的回复——就像餐厅提前批量备好的预制菜大幅降低成本和延迟。agents.py 中的批量生成器实现NPCBatchGenerator的关键在于提示词构建明确要求 LLM 为 3 个 NPC 各生成 1 句 20-40 字的对话内容符合角色设定与场景氛围并必须严格按照 JSON 格式返回同时提供示例输出作为 few-shot 参考prompt f请为Datawhale办公室的3个NPC生成当前的对话或行为描述。 【场景】{context} 【NPC信息】 {npc_desc_text} 【生成要求】 1. 每个NPC生成1句话(20-40字) ... 【输出格式】(严格遵守) {{张三: ..., 李四: ..., 王五: ...}} 【示例输出】 {{张三: 这个bug真是见鬼了,已经调试两小时了..., 李四: 嗯,这个功能的优先级需要重新评估一下。, 王五: 这杯咖啡的拉花真不错,灵感来了!}} 请生成(只返回JSON,不要其他内容): _parse_response()对 LLM 输出做了三重容错先直接json.loads解析失败则提取第一个{到最后一个}之间的子串再解析再失败则回退到预设对话库。这个严苛的格式约束 健壮的解析降级组合值得在任何 LLM 结构化输出场景复用。批量生成还有两个工程细节场景自动推断_get_current_context()根据当前小时自动推断办公室氛围清晨/上午工作/午餐/下午工作/傍晚/夜晚让背景对话随时间流动预设对话兜底preset_dialogues内置了 morning/noon/afternoon/evening 四个时段的对话模板当 LLM 不可用或解析失败时自动降级保证游戏在任何情况下都能运行。批量生成适合背景对话定时更新场景氛围降低成本四类场景但不适合玩家直接互动——玩家发起的对话必须使用独立 Agent 即时处理以保证个性化与准确性。混合模式批量生成 即时响应实际实现采用混合模式后台任务定期批量生成所有 NPC 的背景对话并缓存玩家靠近 NPC 但未交互时NPC 会显示这些正在调试代码…在看产品文档…的自主对话看起来是活着的一旦玩家按下 E 键系统立即切换到即时响应模式调用该 NPC 的专属 Agent 结合具体消息、历史记忆与好感度生成个性化回复。实际代码中这一逻辑由 state_manager.py 承担NPCStateManager.start()启动asyncio后台任务按NPC_UPDATE_INTERVAL默认 30 秒周期性调用generate_batch_dialogues()更新current_dialogues缓存/npcs/status接口向 Godot 前端提供这些背景对话/npcs/status/refresh可强制立即刷新。混合模式的四大优势是背景对话批量生成成本低、玩家交互即时响应质量高、NPC 始终保持生动的自主行为、批量生成频率可随服务器负载动态调整。好感度系统设计五级好感度划分好感度系统的核心思想是量化 NPC 与玩家的关系让回复更有层次感。系统划分为五个等级等级分数范围行为表现陌生0-20 分态度礼貌但保持距离回复简短不主动分享个人信息熟悉21-40 分开始记住玩家回复更自然偶尔分享工作相关信息友好41-60 分视玩家为朋友回复更详细主动询问玩家情况亲密61-80 分非常信任玩家愿意分享私人话题回复充满热情并提供建议挚友81-100 分视玩家为最好朋友无话不谈分享内心想法与感受基于 LLM 情感分析的计算逻辑好感度计算不采用固定加分而是使用 LLM 分析对话内容自动判断玩家态度友好/中立/不友好后动态调整分数。仓库实现 relationship_manager.py 将情感分析封装为一个独立的SimpleAgent名为AffinityAnalyzer其系统提示词定义了量化的变化规则赞美、感谢、请教3 到 8友好问候、正常交流1 到 3普通闲聊、中性话题0批评、质疑、不耐烦-3 到 -8侮辱、攻击、恶意-8 到 -15分析结果要求以严格 JSON 返回should_change/change_amount/reason/sentiment并内置 5 个 few-shot 示例。_parse_analysis()同样采用直接解析 → 提取 JSON 子串 → 正则抽取 → 默认值四级降级策略保证分析失败时系统仍可运行。好感度更新时会被限制在 0-100 区间内max(0.0, min(100.0, affinity))初始好感度为 50.0即友好档文档示例中 0 起步的设定在实际实现中已被调整。好感度如何影响对话好感度不仅是数字更会真正改变 NPC 的行为。实现方式是在对话前把当前好感度等级与风格修饰词注入系统提示词。get_affinity_modifier()将分数映射为对话风格if affinity 80: return 非常热情友好,像老朋友一样亲切,愿意分享私人话题 elif affinity 60: return 友好热情,愿意多聊,会主动关心对方 elif affinity 40: return 礼貌友善,正常交流,保持专业 elif affinity 20: return 礼貌但略显生疏,回答简洁 else: return 冷淡疏离,不太愿意多说,回答简短在agents.py的chat()中好感度上下文会被拼接到增强提示词中你与玩家的关系: {level} (好感度: {affinity:.0f}/100)【对话风格】{modifier}从而让 NPC 的回复随关系动态变化。玩家能明显感受到态度转变极大增强沉浸感。后端服务实现FastAPI 应用结构与核心 API后端采用模块化设计将不同功能拆分到独立文件。与文档示例相比实际 main.py 实现了更完整的 REST API 集合方法与路径功能GET /服务信息与端点列表GET /health健康检查POST /chat与 NPC 实时对话即时响应模式GET /npcs获取所有 NPC 列表GET /npcs/status获取所有 NPC 当前状态批量生成的背景对话POST /npcs/status/refresh强制刷新 NPC 状态GET /npcs/{npc_name}获取指定 NPC 详细信息含当前对话GET/DELETE /npcs/{npc_name}/memories获取/清空 NPC 记忆清空用于测试GET /npcs/{npc_name}/affinity查询玩家与 NPC 的好感度PUT /npcs/{npc_name}/affinity设置好感度用于测试校验 0-100 范围GET /affinities获取所有 NPC 对玩家的好感度文档示例中的/dialogue接口在实际仓库中演化为/chat通过NPCAgentManager.chat()完成取好感度 → 检索记忆 → 增强提示词 → 生成回复 → 更新好感度 → 保存记忆 → 记录日志的完整链路。应用使用lifespan上下文管理器在启动时校验配置、初始化 NPC 管理器并启动状态管理器关闭时优雅停止后台任务。CORS 中间件默认允许所有来源allow_origins[*]文档与实际源码均注明生产环境应限制具体域名。状态管理与日志系统状态管理器state_manager.py跟踪每个 NPC 的当前状态负责定时批量更新背景对话与缓存管理从源码结构看也承担了文档所描述的忙碌状态防并发职责的设计基础。日志系统logger.pyview_logs.py实现控制台与文件双输出控制台处理器使用%H:%M:%S时间格式便于实时观察文件处理器使用%Y-%m-%d %H:%M:%S格式并按日期分文件保存logs/dialogue_YYYY-MM-DD.log。agents.py中的对话流程在各关键节点调用日志函数对话开始、好感度查询、记忆检索、生成回复、情感分析、好感度变化、记忆保存、对话结束让每条日志都能完整还原一次对话的前因后果。view_logs.py则提供了实时查看入口。Godot 游戏场景构建为什么选择 Godot文档给出了四个选择理由同样适用于你的项目决策Godot 的 2D 引擎成熟TileMap、AnimatedSprite2D、CharacterBody2D 等专为 2D 设计的节点非常适合像素风俯视角游戏完全开源免费MIT 许可证无版权费用与收入分成GDScript 语法接近 Python对 Python 开发者几乎零门槛内置 HTTPRequest 节点与 Python 后端集成简单。局限性在于其 3D 能力相比 Unreal/Unity 仍有差距大型 3D 项目需谨慎选型。场景系统节点、场景与实例化理解 Godot 必须理解两个核心概念节点Node是最基本的构建块如 Sprite2D 显示图片、AudioStreamPlayer 播放音频、CharacterBody2D 处理物理移动节点可形成父子树状结构移动父节点会同时移动所有子节点场景Scene是节点的集合保存在.tscn文件中可理解为预制件支持在一个场景中实例化另一个场景形成嵌套结构且修改场景会自动影响所有实例。例如一个玩家场景的节点树Player (CharacterBody2D) ← 根节点,负责物理移动 ├─ AnimatedSprite2D ← 子节点,显示角色动画 ├─ CollisionShape2D ← 子节点,定义碰撞形状 └─ Camera2D ← 子节点,摄像机跟随玩家赛博小镇正是利用场景复用构建了三个 NPC张三、李四、王五都是同一个NPC.tscn的实例仅通过脚本参数export var npc_name、export var npc_title设置不同角色信息。若想给所有 NPC 增加头顶对话气泡只需修改NPC.tscn一处。玩家控制与 NPC 行为玩家控制scripts/player.gd实现了 WASD 移动、4 方向动画切换、碰撞检测、与 NPC 交互及音效系统。核心设计包括add_to_group(player)将玩家注册到组中NPC 通过组来识别玩家_physics_process中根据输入向量计算速度并move_and_slide()update_animation()按横向优先 flip_h 翻转策略选择 walk_right/left/up/down 动画交互期间is_interactingtrue禁用移动按 E 或 Enter 触发interact_with_npc()通过get_tree().call_group(dialogue_system, start_dialogue, ...)通知对话系统。NPC 行为scripts/npc.gd实现三项核心功能随机巡逻、响应交互、显示对话气泡。巡逻逻辑围绕export配置参数展开——move_speed默认 50.0、wander_enabled是否巡逻、wander_range巡逻范围 200.0、wander_interval_min/max间隔 3-8 秒——NPC 在出生位置附近随机选点并移动到达后播放 idle。交互通过InteractionAreaArea2D检测玩家body_entered时调用player.set_nearby_npc(self)body_exited时置空。update_dialogue()负责显示对话气泡并在 10 秒后自动隐藏。前后端通信实现API 客户端封装Godot 前端通过 api_client.gd 与后端通信该脚本被设为 AutoLoad 单例。它封装了三个核心功能发送对话请求、获取 NPC 状态、获取 NPC 列表每个功能使用独立的 HTTPRequest 节点可同时发多个请求互不干扰。工程上值得借鉴的两个设计信号驱动而非 awaitHTTPRequest是异步节点发送请求后不阻塞游戏通过request_completed信号回调自定义信号chat_response_received、npc_status_received等让多个脚本可同时监听同一响应保证高网络延迟下游戏依然流畅防重入检查get_npc_status()会检查http_status.get_http_client_status() ! HTTPClient.STATUS_DISCONNECTED请求处理中直接跳过本次避免重复请求堆积。对话 UI 与主场景整合对话 UIdialogue_ui.gd基于 CanvasLayer始终显示在最上层由 Panel 承载 NPC 名称、职位、富文本对话区、输入框与按钮。发送消息后禁用输入框防止重复提交收到chat_response_received信号后恢复输入并追加 NPC 回复。对话框显示/隐藏时分别调用玩家set_interacting(true/false)以禁用/恢复移动。主场景main.gd负责协调全局_ready()中获取 APIClient 单例并连接npc_status_received信号、立即拉取一次状态_process()按Config.NPC_STATUS_UPDATE_INTERVAL默认 30 秒定时拉取 NPC 状态回调中按 NPC 名字分发到对应节点调用update_dialogue()刷新对话气泡。这样即使玩家不与 NPC 交互也能看到 NPC 之间由后端批量生成的自主对话整个办公室因此始终生机勃勃。总结与展望赛博小镇完整展示了游戏引擎 智能体框架的落地路径分层架构Godot/FastAPI/HelloAgents/外部服务保证各部分独立可测SimpleAgent 角色化提示词让每个 NPC 拥有独立人格短期长期双层记忆让 NPC 记住玩家LLM 情感分析驱动的五级好感度让关系动态演化批量生成与即时响应混合模式在成本与体验间取得平衡信号驱动的异步通信保证游戏流畅。从仓库实际实现可以看出生产级细节往往在文档示例之外记忆持久化到 SQLite、记忆检索附带重要性阈值与时间衰减、LLM 结构化输出配多级解析降级、无密钥时自动进入模拟模式、日志按日期分文件保存——这些设计让项目在真实环境中依然稳健。文档同时给出了值得探索的扩展方向多人在线支持WebSocket 数据库持久化、任务系统高好感度解锁特殊任务、NPC 之间的互动、更复杂的情感系统、动态事件系统、更大的世界地图、以及基于玩家偏好的个性化学习。AI NPC 也面临现实挑战——每次对话调用 LLM 的成本、推理延迟、生成内容可控性需要良好的提示词与内容过滤机制。随着推理速度提升、成本下降与本地化小模型发展未来 NPC 甚至可能直接运行在玩家设备上完全脱离网络请求。在第五部分的毕业设计章节你将会学习如何用单智能体和多智能体构造通用智能体届时可以将本章的场景复刻为真正的创作舞台。【免费下载链接】hello-agents 《从零开始构建智能体》——从零开始的智能体原理与实践教程项目地址: https://gitcode.com/datawhalechina/hello-agents创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考