资讯动态

基于RAG与智能体架构的AI角色系统开发实战

发布时间:2026/9/3 3:36:58 来源:尧图企业网站定制
最近在 GitHub 上闲逛发现了一个特别有意思的项目名字叫“鬼灭的现代生活”。点进去一看好家伙这可不是简单的同人图或者段子合集而是一个用 AI 技术驱动的、让《鬼灭之刃》角色在现代社会“活”起来的互动项目。更绝的是无论场景怎么变富冈义勇那“我没有被讨厌”的稳定发挥总能被精准地复现出来。这让我意识到很多开发者包括之前的我对这类项目的认知可能还停留在“趣味小 demo”的层面。但实际上它背后串联起的是当前 AI 应用开发的一个核心范式如何将成熟的 AI 模型如大语言模型、图像生成模型与具体的领域知识IP人设和交互逻辑深度结合创造出有“灵魂”的智能体Agent。这远比单纯调用 API 生成一段文本或一张图要复杂也更有价值。如果你也对以下问题感兴趣那么这篇文章就是为你写的想用 AI 技术打造一个有持久人设和记忆的虚拟角色但不知从何架构好奇如何让 LLM 不仅回答问题还能基于特定角色性格进行稳定、有趣的“表演”希望了解一个完整的、包含前端交互的 AI 角色项目该如何搭建有哪些技术栈选择本文将以“鬼灭的现代生活”这类项目为引子不仅带你复现一个趣味 demo更会深入拆解其背后的技术架构、设计思想并提供一个可扩展的、工程化的实现方案。你会发现让“义勇师兄”稳定发挥靠的绝不仅仅是 prompt 技巧。1. 核心问题从“AI对话”到“AI角色扮演”的鸿沟首先我们必须厘清一个关键区别。用 ChatGPT 或 Claude 让 AI 模仿某个角色说话与构建一个“鬼灭的现代生活”这样的项目本质上是两件事。前者是单次任务你给出一个指令如“请以富冈义勇的语气回答”模型会根据其训练数据中的相关片段生成一段临时的、无状态的文本。这次对话结束关于这个“义勇”的所有上下文就消失了。下次你再问它又是一个“新”的义勇性格可能发生漂移。后者是系统工程目标是创建一个有持久人设、记忆、行为逻辑的数字化实体。它需要角色一致性无论对话进行到第100轮还是第1000轮义勇的核心性格沉稳、寡言、略带笨拙的真诚必须稳定。知识融合模型需要深度理解《鬼灭之刃》的原作设定世界观、人物关系、经典事件并能将这些知识灵活运用于现代生活场景的推演中。状态管理角色需要记住与“你”用户之间发生过的重要事件、对话历史形成独特的共同记忆。交互多样性不仅限于文本对话可能还包括生成符合场景和角色心情的图片、语音甚至触发特定的行为逻辑。“鬼灭的现代生活”项目的趣味点恰恰在于它成功跨越了这个鸿沟。它让用户感觉不是在和一个“模仿义勇的AI”聊天而是在和一个“生活在现代社会的义勇”互动。而“稳定发挥”正是衡量这个系统是否成功的核心指标。2. 技术架构总览一个可扩展的AI角色系统要实现上述目标我们不能只依赖一个模型。一个健壮的架构通常包含以下层次用户界面 (Web/App) ↓ API网关/交互逻辑层 (处理请求路由、会话管理) ↓ ↓ 智能体引擎 (Agent Engine) —————— 长期记忆存储 (Vector DB) | (协调各模块决策反应) | (存储角色记忆、对话历史) ↓ ↓ 大语言模型 (LLM) —————————— 知识库 (RAG) (核心推理与生成) (检索增强提供原作知识) | ↓ 图像/语音生成模型 (可选) (生成角色立绘、场景图或语音)各组件核心职责智能体引擎 (Agent Engine)系统大脑。它接收用户输入结合当前会话状态、长期记忆和从知识库检索到的信息构造出送给 LLM 的最终提示词 (Prompt)。它也负责解析 LLM 的输出决定下一步是生成文本、调用图像模型还是更新记忆。大语言模型 (LLM)核心的“演员”。根据智能体引擎提供的“剧本”包含人设、记忆、当前场景的详细Prompt生成符合角色的对话和内心独白。知识库与检索 (RAG)角色的“基本功”。将《鬼灭之刃》的维基、剧情摘要、角色设定文档等文本进行向量化存储。当对话涉及原作内容时智能体引擎从此处检索最相关的片段注入Prompt确保回答不偏离原作。长期记忆存储角色的“经历”。使用向量数据库存储每一轮有意义的对话摘要、用户与角色之间发生的独特事件。这些记忆会在后续对话中被检索出来让角色“记得”之前的事情形成连续感。用户界面提供聊天界面并可以展示角色图像、状态如心情值等。接下来我们将从零开始搭建一个简化但核心功能完整的版本。3. 环境准备与核心技术选型我们选择 Python 作为后端语言因为它拥有最丰富的 AI 库生态。基础环境Python 3.10pip 包管理工具核心技术栈选择与理由LLM 接口openai/litellm库。理由OpenAI API 稳定litellm则提供了统一接口调用多种模型如 OpenAI, Anthropic, 本地部署的 Llama 等方便后续切换。向量数据库chromadb。理由轻量级易于嵌入 Python 项目适合原型和中小型项目。后端框架FastAPI。理由异步高性能自动生成 API 文档非常适合构建 AI 应用的 API 层。前端Gradio。理由快速构建机器学习 Web 界面的神器几行代码就能做出交互式聊天界面适合演示和原型。嵌入模型sentence-transformers。理由本地运行免费用于将文本和知识库内容转换为向量。安装依赖 创建一个requirements.txt文件fastapi0.104.1 uvicorn[standard]0.24.0 openai1.3.0 # 或使用 litellmlitellm1.13.2 chromadb0.4.18 sentence-transformers2.2.2 gradio4.8.0 python-dotenv1.0.0 pydantic2.5.0通过 pip 安装pip install -r requirements.txt4. 项目结构与核心模块拆解我们创建一个名为modern_demon_slayer的项目目录结构如下modern_demon_slayer/ ├── app.py # FastAPI 主应用 Gradio 界面 ├── core/ │ ├── __init__.py │ ├── agent.py # 智能体引擎核心类 │ ├── memory.py # 长期记忆管理 │ └── knowledge_base.py # 知识库RAG管理 ├── config.py # 配置文件API密钥等 ├── data/ │ ├── character_profile.md # 角色设定文件 │ └── demon_slayer_knowledge.txt # 鬼灭之刃知识文本 ├── requirements.txt └── .env # 环境变量存储API KEY5. 核心代码实现一步步构建“义勇”5.1 角色定义与知识库构建首先我们需要清晰地定义富冈义勇这个角色。在data/character_profile.md中# 角色设定富冈义勇 (现代版) ## 核心身份 - 原《鬼灭之刃》水柱现为一名普通的都市上班族职业是游泳教练或水务公司职员。 - 年龄25岁左右。 ## 核心性格 1. **外表冷漠内心温柔**话非常少常用简短词语或点头摇头回应。不擅长表达情感和社交。 2. **认真负责**对工作和承诺极其认真一丝不苟。 3. **经典梗** - **“我没有被讨厌”**经常无意识地、一本正经地说出这句话尤其在社交尴尬或试图安慰人时。 - **对锖兔和真菰的怀念**偶尔会流露出对逝去同伴的思念但很快会收敛情绪。 - **对鳞泷左近次的尊敬**提及师父时语气会变得格外恭敬。 4. **现代生活适应性** - 对现代科技如智能手机、社交媒体感到些许困惑但学习能力很强。 - 保留着剑士的作息和纪律性早起注重锻炼。 - 饮食简单偏爱鲑大根萝卜鲑鱼。 ## 说话风格 - 句子极其简短。“嗯。” “好。” “不行。” - 几乎不用感叹号语气平淡。 - 被追问或需要解释时会多说几句但逻辑直接不加修饰。接着准备一些原作知识。在data/demon_slayer_knowledge.txt中放入从官方设定集、维基百科整理的纯文本信息例如富冈义勇鬼杀队前任水柱。...背景介绍 擅长水之呼吸共有十种型。...技能介绍 与锖兔、真菰同为鳞泷左近次的弟子。...人物关系 经典台词“我没有被讨厌。”...经典台词5.2 知识库模块实现core/knowledge_base.py负责加载这些知识并将其存入向量数据库以备检索。# core/knowledge_base.py import chromadb from chromadb.config import Settings from sentence_transformers import SentenceTransformer import os from typing import List class KnowledgeBase: def __init__(self, persist_directory: str ./data/chroma_kb): # 初始化嵌入模型 self.embed_model SentenceTransformer(paraphrase-multilingual-MiniLM-L12-v2) # 一个多语言小模型 # 初始化 ChromaDB 客户端 self.client chromadb.PersistentClient(pathpersist_directory) # 获取或创建集合 self.collection self.client.get_or_create_collection(namedemon_slayer_knowledge) def add_documents(self, texts: List[str], metadatas: List[dict] None): 向知识库添加文档 ids [fdoc_{i} for i in range(len(texts))] # 生成嵌入向量 embeddings self.embed_model.encode(texts).tolist() # 添加到集合 self.collection.add( documentstexts, embeddingsembeddings, metadatasmetadatas, idsids ) print(f已添加 {len(texts)} 条知识到数据库。) def query(self, query_text: str, n_results: int 3) - List[str]: 查询相关知识 # 将查询文本也转换为向量 query_embedding self.embed_model.encode([query_text]).tolist()[0] # 执行相似性搜索 results self.collection.query( query_embeddings[query_embedding], n_resultsn_results ) # 返回相关的文档内容 if results[documents]: return results[documents][0] return [] # 初始化知识库并加载数据的函数 def init_knowledge_base(): kb KnowledgeBase() # 检查是否已存在数据避免重复添加 if kb.collection.count() 0: # 从文件加载知识文本 knowledge_path ./data/demon_slayer_knowledge.txt if os.path.exists(knowledge_path): with open(knowledge_path, r, encodingutf-8) as f: # 简单按段落分割 paragraphs [p.strip() for p in f.read().split(\n\n) if p.strip()] kb.add_documents(paragraphs) print(知识库数据加载完成。) else: print(f知识文件 {knowledge_path} 不存在。) return kb5.3 记忆管理模块实现core/memory.py负责管理对话历史与长期记忆。我们采用一种摘要式记忆法将长对话压缩成关键点存储。# core/memory.py import chromadb from chromadb.config import Settings from datetime import datetime from typing import List, Dict, Any from .knowledge_base import KnowledgeBase # 复用嵌入模型 class MemoryStore: def __init__(self, persist_directory: str ./data/chroma_memory): # 使用另一个集合存储记忆 self.client chromadb.PersistentClient(pathpersist_directory) self.collection self.client.get_or_create_collection(namecharacter_memory) # 同样需要嵌入模型来搜索记忆 from sentence_transformers import SentenceTransformer self.embed_model SentenceTransformer(paraphrase-multilingual-MiniLM-L12-v2) self.conversation_history: List[Dict] [] # 临时会话历史 def add_conversation_turn(self, user_input: str, agent_response: str): 添加一轮对话到历史 self.conversation_history.append({ user: user_input, character: agent_response, timestamp: datetime.now().isoformat() }) # 如果历史太长可以进行摘要并存入长期记忆 if len(self.conversation_history) 5: # 每5轮对话摘要一次 self._summarize_and_store() def _summarize_and_store(self): 摘要最近几轮对话并存入长期记忆 recent_chats self.conversation_history[-5:] # 这里可以调用 LLM 生成摘要简化起见我们手动构造 summary_text f近期对话涉及{recent_chats[0][user][:50]}... 等话题。 memory_embedding self.embed_model.encode([summary_text]).tolist()[0] memory_id fmemory_{datetime.now().strftime(%Y%m%d_%H%M%S)} self.collection.add( documents[summary_text], embeddings[memory_embedding], metadatas[{type: conversation_summary}], ids[memory_id] ) print(f已存储长期记忆{summary_text}) def get_relevant_memories(self, query: str, n_results: int 2) - List[str]: 检索与当前查询相关的长期记忆 query_embedding self.embed_model.encode([query]).tolist()[0] results self.collection.query( query_embeddings[query_embedding], n_resultsn_results ) if results[documents]: return results[documents][0] return [] def get_recent_history(self, turns: int 3) - List[Dict]: 获取最近N轮对话历史 return self.conversation_history[-turns:] if self.conversation_history else []5.4 智能体引擎系统的核心大脑这是最关键的core/agent.py。它将角色设定、知识、记忆和用户输入整合构造出最终的 Prompt。# core/agent.py import openai from typing import List, Dict, Any import os from dotenv import load_dotenv from .memory import MemoryStore from .knowledge_base import KnowledgeBase load_dotenv() # 加载 .env 中的 OPENAI_API_KEY class DemonSlayerAgent: def __init__(self, character_name: str 富冈义勇): self.character_name character_name self.memory MemoryStore() self.knowledge_base KnowledgeBase() self.client openai.OpenAI(api_keyos.getenv(OPENAI_API_KEY)) # 加载角色设定 self.character_profile self._load_character_profile() def _load_character_profile(self) - str: profile_path ./data/character_profile.md if os.path.exists(profile_path): with open(profile_path, r, encodingutf-8) as f: return f.read() return def _construct_system_prompt(self, user_input: str) - str: 构造给 LLM 的系统指令这是角色扮演的灵魂 # 1. 检索相关知识 relevant_knowledge self.knowledge_base.query(user_input) knowledge_context \n.join(relevant_knowledge) if relevant_knowledge else 无特定知识提及。 # 2. 检索相关记忆 relevant_memories self.memory.get_relevant_memories(user_input) memory_context \n.join(relevant_memories) if relevant_memories else 无相关记忆。 # 3. 获取最近对话历史 recent_history self.memory.get_recent_history() history_context for turn in recent_history: history_context f用户{turn[user]}\n角色{turn[character]}\n # 4. 组合成最终的系统提示词 system_prompt f 你正在扮演《鬼灭之刃》中的角色 **{self.character_name}** 在现代社会生活的版本。 ## 你必须严格遵守的角色设定 {self.character_profile} ## 关于《鬼灭之刃》原作的相关知识供你参考 {knowledge_context} ## 你与当前用户之前的互动记忆 {memory_context} ## 最近的对话历史 {history_context} ## 当前对话 用户说{user_input} ## 你的回复必须 1. **严格符合上述角色设定**尤其是说话风格和经典梗。 2. 可以合理地将原作背景与现代生活结合进行回应。 3. 如果对话涉及记忆中的内容请自然衔接。 4. 回复要简短、直接保持角色本色。 5. 最后**只输出角色的回复内容本身**不要添加任何解释、括号内的动作描述或思考过程。 return system_prompt def generate_response(self, user_input: str) - str: 生成角色回复 system_prompt self._construct_system_prompt(user_input) try: response self.client.chat.completions.create( modelgpt-3.5-turbo, # 或 gpt-4 messages[ {role: system, content: system_prompt}, {role: user, content: user_input} ], temperature0.7, # 控制创造性0.7 能平衡一致性和灵活性 max_tokens150 ) agent_response response.choices[0].message.content.strip() # 存储本轮对话到记忆 self.memory.add_conversation_turn(user_input, agent_response) return agent_response except Exception as e: print(f调用 LLM API 出错{e}) return “义勇陷入了沉默似乎网络不太好”5.5 构建 API 与 Web 界面最后我们用 FastAPI 提供 API并用 Gradio 快速包装一个聊天界面。app.py# app.py from fastapi import FastAPI, HTTPException from pydantic import BaseModel import gradio as gr from core.agent import DemonSlayerAgent from core.knowledge_base import init_knowledge_base # 初始化 app FastAPI(title鬼灭的现代生活 API) agent DemonSlayerAgent() # 启动时初始化知识库 init_knowledge_base() # Pydantic 模型用于请求体 class ChatRequest(BaseModel): message: str class ChatResponse(BaseModel): response: str # FastAPI 端点 app.post(/chat, response_modelChatResponse) async def chat_with_character(request: ChatRequest): 与角色聊天的API端点 response_text agent.generate_response(request.message) return ChatResponse(responseresponse_text) # Gradio 界面函数 def gradio_chat_interface(message, history): history history or [] response agent.generate_response(message) history.append((message, response)) return history, history # 创建 Gradio 界面 demo gr.ChatInterface( fngradio_chat_interface, title鬼灭的现代生活与富冈义勇的日常, description和生活在现代的富冈义勇聊聊天吧。他会如何应对现代社会的种种呢, examples[你好义勇先生。, 今天工作怎么样, 你觉得锖兔会喜欢现代生活吗] ) # 将 Gradio 应用挂载到 FastAPI app gr.mount_gradio_app(app, demo, path/) if __name__ __main__: import uvicorn uvicorn.run(app, host0.0.0.0, port7860)6. 运行与效果验证准备环境变量在项目根目录创建.env文件填入你的 OpenAI API Key。OPENAI_API_KEYsk-your-actual-api-key-here启动应用python app.py终端会输出类似信息INFO: Started server process [12345] INFO: Waiting for application startup. INFO: Application startup complete. INFO: Uvicorn running on http://0.0.0.0:7860 (Press CTRLC to quit)访问界面打开浏览器访问http://localhost:7860。进行对话测试测试1基础人设你你好义勇先生。义勇嗯。符合寡言设定测试2经典梗触发你感觉你好像没什么朋友义勇我没有被讨厌。稳定发挥测试3知识库与记忆你还记得我们上次聊到你师父吗义勇鳞泷师父。他很严格。结合了记忆和知识测试4现代生活推演你周末打算做什么义勇晨练。然后去买鲑鱼和萝卜。将角色习惯融入现代场景如何验证成功角色一致性多次对话中义勇的性格和说话方式是否稳定记忆能力询问之前提过的事情如“上次说的鲑鱼好吃吗”看他是否能关联。知识运用问及原作内容如“水之呼吸有哪些型”回答是否准确“稳定发挥”在涉及自我认知或社交的语境下是否高概率出现“我没有被讨厌”或类似表达如果回答生硬、偏离人设或无法关联记忆请检查character_profile.md中的设定是否足够详细和具体。系统 Prompt 的构造逻辑_construct_system_prompt方法是否将角色设定、记忆、知识放在了最关键的指令位置。LLM 的temperature参数是否合适值越低越稳定但可能缺乏趣味值越高越灵活但可能偏离人设。7. 常见问题与排查思路问题现象可能原因排查方式解决方案启动报错ModuleNotFoundError依赖未安装或环境不对检查requirements.txt和当前 Python 环境在项目目录下执行pip install -r requirements.txt访问localhost:7860无响应端口被占用或服务未启动查看终端 uvicorn 是否成功启动有无报错尝试更换端口uvicorn.run(app, port8000)或杀死占用 7860 端口的进程角色回复完全不符合设定1. API Key 无效或未设置2. 系统 Prompt 构造失败3. LLM 模型能力不足1. 检查.env文件格式和 API Key 有效性2. 在_construct_system_prompt方法末尾打印出生成的 prompt 进行检查3. 尝试更换为gpt-4模型1. 确保.env文件内容为OPENAI_API_KEYsk-xxx2. 调试并优化 Prompt 结构确保角色设定指令清晰、前置3. 升级模型或细化角色设定角色不记得之前的对话记忆存储或检索失败1. 检查memory.py中add_conversation_turn和get_relevant_memories是否被正确调用2. 查看 ChromaDB 持久化目录是否生成文件1. 在 Agent 的generate_response方法前后打印日志确认记忆函数被调用2. 确保向量数据库路径有写入权限回复速度很慢1. 网络问题2. 知识库/记忆检索文档过多3. 嵌入模型首次加载慢1. 检查网络连接2. 限制query函数的n_results参数3. 首次加载后速度会提升1. 优化网络或使用国内可访问的模型代理2. 将n_results从 3 调整为 2 或 13. 考虑使用更轻量的嵌入模型知识库检索结果不相关1. 知识文本分割不合理2. 嵌入模型不匹配3. 查询语句太模糊1. 检查demon_slayer_knowledge.txt的段落分割2. 尝试不同的sentence-transformers模型1. 将知识文本按更细粒度如句子分割后存入2. 更换为all-MiniLM-L6-v2等英文模型如果知识主要是英文8. 最佳实践与项目扩展建议一个基础的 demo 跑通后你可以从以下方向深化打造更成熟的项目1. 角色设定的工程化多模态设定不仅用文本可以定义角色的“心情值”、“体力值”等状态属性对话会影响状态状态又反过来影响回复风格。技能系统为角色定义“技能”如“讲述水之呼吸原理”、“做鲑大根料理教学”。当用户触发关键词时可以调用特定的、更复杂的 Prompt 或外部工具。2. 记忆系统的优化分级记忆将记忆分为“短期会话历史”、“中期对话摘要”、“长期核心事实如用户姓名”采用不同的存储和检索策略。记忆衰减与融合为记忆添加“强度”或“新鲜度”概念随时间衰减重要事件可以加强。避免记忆库无限膨胀。3. 引入图像与语音角色立绘使用 Stable Diffusion 等模型根据对话上下文和角色心情实时生成不同的角色头像或场景图。可以预先定义一组关键词如“平静_义勇”、“困惑_义勇”对应不同的图像种子。语音合成使用 TTS 技术为角色的回复配上符合其性格的语音。开源方案如Coqui TTS或商用 API 均可。4. 前端体验增强更换 Gradio使用Streamlit或Vue.js/React构建更美观、交互更丰富的专属前端界面。展示状态在聊天界面侧边栏展示角色的心情、体力等状态条。对话树设计一些非线性的对话分支选项增加互动游戏感。5. 部署与性能API 密钥管理永远不要将 API Key 硬编码在代码中或提交到 Git。使用.env文件并加入.gitignore。异步处理对于耗时的图像生成、语音合成请求使用 Celery 等任务队列异步处理避免阻塞聊天响应。容器化使用 Docker 封装整个应用确保环境一致性便于部署到云服务器。安全与伦理提醒内容过滤在 Agent 生成回复后可以加入一层安全过滤防止生成不当内容。用户知情明确告知用户正在与 AI 交互避免误导。数据隐私妥善处理用户对话数据如需存储应加密并获取用户同意。9. 总结从趣味项目到 AI 智能体开发入门通过“鬼灭的现代生活”这个有趣的项目我们实际上完成了一次标准的 AI 智能体Agent应用开发实战。其核心不在于复现某个动漫角色而在于掌握了一套将LLM 能力、领域知识、状态记忆和交互逻辑有机结合的方法论。这个项目的价值在于提供了一个清晰的模板。你可以轻松地将角色设定文件character_profile.md和知识库demon_slayer_knowledge.txt替换成任何其他 IP 或原创角色快速构建出另一个独特的数字角色。背后的架构——知识检索RAG、记忆管理、Prompt 工程——是通用的。下次当你看到类似“让某个角色活过来”的趣味应用时不妨思考一下它背后可能的技术栈。而作为开发者你完全可以利用本文介绍的模式从零开始创造属于自己的、有“灵魂”的 AI 角色。毕竟技术的魅力不仅在于解决严肃问题也在于创造那些让人会心一笑的、有趣的连接。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价