爱莉这个角色,你大概率不是第一次听说。不管从哪个社区刷到过她的名字,你最终关心的其实是同一件事:一个虚拟角色,从一张立绘到能聊天、能说话、能陪你写点小故事,到底是怎么做出来的?
这篇文章不准备只放几张效果图,然后说“AI真强大”。我更想拆开来看:如果你想给自己做一个专属 AI 角色,比如一个叫爱莉、主题是“橙色少女心”的原创角色,从角色设定、立绘生成、声音定制,到对话系统封装和本地验证,完整链路应该怎么搭。每一步需要什么工具、什么代码、什么配置,会遇到什么坑,我都会尽量讲透。
先说一个我的判断:AI 角色创作这件事,真正值钱的不是大模型本身,而是你围绕一个角色做的整套封装——人设、声音、记忆、情绪反馈、调用链路。模型是通用的,角色是唯一的。你学会的是模型调用,但你沉淀下来的是一个可以被反复使用、持续进化的角色工程模板。
这篇文章会从一个最小可用的角色工程出发,用“橙色少女心”这个偏治愈、温暖、活泼的风格作为例子,带你跑通一条从零到一的角色开发流程。就算你对 Stable Diffusion、Python、LLM 调用都只是听说过,也能跟着做出来。
1. 为什么要关注 AI 角色工程
如果你过去两年关注过 AI 内容创作,会发现一个很明显的趋势:单次生成一张图、写一段诗的玩法正在退潮,取而代之的是“角色化的持续性产品”。什么叫角色化?就是给 AI 一个固定的名字、固定的人设、固定的声音和固定的反馈习惯,用户每一次打开它,面对的都是同一个“人”。
这件事对开发者的意义,不在于角色本身有多好看,而在于产品形态彻底变了。以前做一个陪伴类应用,你需要写状态机、写分支对话、写情绪标签,所有交互都是脚本化的,用户玩两天就到底了。现在不一样,大模型把“对话理解”这件事的成本打到了非常低,你只需要把角色的人设、语气、知识边界封装进提示词和上下文管理,剩下的自由对话交给模型。这意味着一个很小的团队,甚至一个独立开发者,就能做出以前需要一整个内容团队才能维护的角色产品。
“爱莉”这个名字在社区里有很多同人解读,但作为技术主题,我更建议你把它当作一个原创角色模板来看待。“橙色少女心”是一种很典型的角色风格标签:温暖、明快、带一点少女感的治愈气质。这个标签不是随便写进提示词的,它会直接影响立绘配色、语音音色选择、对话语气设计,甚至表情包的生成方向。也就是说,你首先要做的不是写代码,而是确定角色定义。
这篇文章会覆盖四件事:角色怎么设计、视觉形象怎么生成、声音怎么合成、对话怎么封装。每件事都有代码和配置,每件事也都有对应的验证方法。
2. 基础概念与整体架构
2.1 为什么“角色工程”不是单纯的提示词写作
很多人以为做一个 AI 角色就是写一段 System Prompt,比如“你是爱莉,你喜欢橙色”。这句话能成立,但离可用还差很远。真实场景里,用户会问你今天心情怎么样、会不会推荐一首歌、还记得我上次说的那只猫吗——这些问题背后需要三层能力:
第一层是语言风格层。角色说话要稳定,不能突然从少女变成客服。这个靠人设提示词约束。
第二层是上下文记忆层。用户说过的名字、偏好、故事,要在多次对话中延续。这个靠记忆管理和向量检索,或者至少是结构化的会话摘要。
第三层是表达通道层。角色不只是文字,还有形象、声音、表情。这个靠 AI 绘画和语音合成模型提供接口。
对应到技术上,一个完整的 AI 角色应用至少包含五个模块:
| 模块 | 作用 | 常用技术方案 |
|---|---|---|
| 角色配置 | 定义人设、语气、风格、背景故事 | YAML / JSON 配置或提示词模板 |
| 视觉模块 | 生成角色立绘、头像、表情包 | Stable Diffusion、Midjourney、即梦等绘画模型 |
| 语音模块 | 生成角色专属音色语音 | 边缘 TTS、商业化语音合成 API |
| 对话模块 | 理解用户输入并按照人设回复 | 大模型 API、流式输出 |
| 记忆模块 | 保存用户资料和对话历史 | 会话摘要、向量数据库 |
2.2 整个链路的数据流向
一次完整的角色交互,用户看到的效果是:发消息给角色,角色带表情回复,还附一段语音。背后数据流向是:
- 用户输入文本,先进入对话模块。
- 对话模块把用户输入和角色人设、历史记录拼成上下文,发送给大模型。
- 大模型返回文本回复。
- 文本回复传入语音模块,合成音频。
- 前端把角色立绘、文本、音频一起展示给用户。
在实际工程里,绘画生成和语音合成不一定发生在每次会话中。立绘是离线预生成的,语音可以按句生成或者只在启用语音时触发。理解这个流程后,你就知道每一步卡在哪里,下一步排错也有方向。
3. 环境准备与前置条件
这一节做两件事:准备本地开发环境,以及规划项目目录。下面的内容只涉及本地开发工具和公开模型接口,不涉及任何违规操作,请放心继续。
3.1 硬件与软件环境
以最稳妥的 Python 技术栈为例:
- 操作系统:推荐 Ubuntu 22.04 或 macOS,Windows 也可以,但部分音频处理库需要额外安装依赖。
- Python:3.10 或 3.11,建议使用虚拟环境。如果你的电脑同时装了多个 Python 版本,用
python3 -m venv venv新建环境最省心。 - 包管理:pip。
- 代码编辑:VS Code 或 PyCharm,二者均可。
- 大模型 API 的 Python SDK:以你实际使用的服务商文档为准。文中的示例采用 OpenAI 兼容格式,大多数国内模型服务和开源模型网关都支持这种格式,方便替换。
3.2 创建项目目录
建议把项目按功能拆分,不要所有代码堆在一个文件里。以“AI爱莉”角色为例,目录设计可以是这样:
ai-aili/ ├── config/ │ └── character.yaml # 角色配置文件 ├── scripts/ │ ├── generate_avatar.py # 立绘生成脚本 │ ├── generate_voice.py # 语音合成脚本 │ └── chat_demo.py # 对话演示脚本 ├── assets/ │ ├── images/ # 生成的立绘和表情 │ └── audio/ # 生成的语音 ├── prompts/ │ └── system_prompt.txt # 角色人设提示词模板 └── requirements.txt这个结构很小,但足够演示一条完整链路。你后续加记忆模块、加 Web 界面,都可以在这个基础上扩展。
3.3 安装依赖
下面这个 requirements.txt 是一个保守选型,没有绑定任何私有包版本,重点是把功能跑通:
# requirements.txt # 项目:AI爱莉 - 橙色少女心角色工程 # Python 3.10+ # 对话模块:可用任意 OpenAI 兼容接口 openai>=1.0.0 # HTTP 请求,用于调用绘画和语音 API requests>=2.31.0 # 图片和音频处理 Pillow>=10.0.0 # 配置解析 PyYAML>=6.0 # 环境变量管理 python-dotenv>=1.0.0安装命令:
cd ai-aili python3 -m venv venv source venv/bin/activate # Windows 系统使用 venv\Scripts\activate pip install -r requirements.txt这里真正容易踩坑的地方是:Windows 环境下 Pillow 偶尔需要预编译库,如果安装失败,直接安装官方预编译 wheel 即可:
pip install --only-binary :all: Pillow3.4 准备 API 密钥
无论你选择哪家大模型服务,都需要一个 API Key。建议单独建一个.env文件,把密钥放在里面,不要提交到 Git:
# .env 示例 LLM_API_KEY=你的大模型密钥 LLM_BASE_URL=https://api.example.com/v1 LLM_MODEL=你的模型名称 VOICE_API_KEY=你的语音服务密钥 IMAGE_API_KEY=你的绘画服务密钥加载方式使用 python-dotenv:
# config/load_env.py import os from dotenv import load_dotenv load_dotenv() LLM_API_KEY = os.getenv("LLM_API_KEY") LLM_BASE_URL = os.getenv("LLM_BASE_URL") LLM_MODEL = os.getenv("LLM_MODEL")写代码时养成一个习惯:密钥永远走环境变量,永远不要硬编码在源码里。角色工程一旦发布成产品,密钥泄露是最常见的安全事故源头。
4. 核心流程拆解
4.1 第一步:定义角色人设
人设是整个角色工程的“地基”。立绘、声音、语气都要服务人设。以“橙色少女心”为主题,我建议爱莉的基础设定可以写成这样:
- 名字:爱莉
- 性格:温暖、活泼、细腻,带一点小固执。
- 说话习惯:短句为主,习惯用感叹号,偶尔会重复重要的关心词。
- 主题色彩:橙色、暖白,视觉元素包括落日、橘子汽水、毛绒玩具。
- 角色目标:给用户提供情绪陪伴和轻量的生活鼓励,不输出医疗、法律等专业意见。
这部分要写成结构化配置,方便对话模块读取。下面是一个 character.yaml 示例:
# config/character.yaml character: name: "爱莉" theme: "橙色少女心" style: ["温暖", "活泼", "治愈", "少年感"] tone: "短句,自然,带感叹号,不使用机械的客服语气" background: | 爱莉是一个喜欢橙色的小镇少女。 她喜欢在傍晚看日落,喜欢橘子汽水, 也喜欢收集路边的落叶做成书签。 她说话直接但不尖锐,总是先关心对方的感受。 greeting: "哈喽,今天的天气感觉怎么样?我这里有橘子汽水,要不要一起喝?" constraints: - "不扮演真实人物" - "不提供医疗、法律、投资等专业建议" - "不回答与角色设定无关的敏感问题,礼貌转回日常话题" - "每次回复尽量在100字以内"注意 constraints 这一段非常重要。扮演层既要控制角色一致性,也要做安全边界。虚拟角色不是真正的“无限制聊天”,越是一个好角色,越清楚自己在什么时候不应该越界。
4.2 第二步:生成视觉形象
视觉形象最直接的产出就是立绘。公开可用的方案很多,例如 Stable Diffusion WebUI、即梦、通义万相等。这里不推荐具体平台,但会提供一个标准调用范式。
要生成一张符合“橙色少女心”主题的立绘,提示词可以这样组织:
1girl, original character, name Aili, warm orange theme, bright afternoon light, orange sunset background, casual hoodie, gentle smile, sweet teenage atmosphere, clean composition, high quality illustration, soft colors 负面提示词(可选): lowres, bad anatomy, bad hands, extra fingers, blurry如果你使用支持 API 的绘画服务,下面是一个通用的 Python 调用模板:
# scripts/generate_avatar.py import requests import os import base64 from dotenv import load_dotenv load_dotenv() IMAGE_API_KEY = os.getenv("IMAGE_API_KEY") IMAGE_API_URL = os.getenv("IMAGE_API_URL", "https://api.example.com/v1/images/generations") def generate_avatar(prompt: str, save_path: str = "assets/images/aili.png") -> str: headers = { "Authorization": f"Bearer {IMAGE_API_KEY}", "Content-Type": "application/json" } payload = { "prompt": prompt, "n": 1, "size": "1024x1024", "response_format": "b64_json" } resp = requests.post(IMAGE_API_URL, headers=headers, json=payload, timeout=120) resp.raise_for_status() data = resp.json() image_b64 = data["data"][0]["b64_json"] os.makedirs(os.path.dirname(save_path), exist_ok=True) with open(save_path, "wb") as f: f.write(base64.b64decode(image_b64)) return save_path if __name__ == "__main__": prompt = ( "1girl, original character, name Aili, warm orange theme, " "orange sunset background, casual hoodie, gentle smile, " "sweet teenage atmosphere, high quality illustration" ) result = generate_avatar(prompt) print(f"立绘已保存到: {result}")这段代码不绑定任何特定平台。你的绘画服务如果支持 OpenAI 兼容格式,直接把 URL 和 Key 替换掉就能跑。如果服务只提供 Web 界面,那更简单:你在网页上输入同一段提示词生成图片,然后下载到assets/images/目录就行。
4.3 第三步:定制角色声音
语音模块的输入是文本,输出是音频文件。常见方案有两类:一类是本地开源模型,需要较强的 GPU;另一类是云端 API,简单稳定。对大多数角色工程,建议先从云端 API 开始。
通用调用逻辑是统一的:把文本 POST 给语音服务,服务返回音频字节流,本地保存为 mp3 或 wav。示例:
# scripts/generate_voice.py import requests import os from dotenv import load_dotenv load_dotenv() VOICE_API_KEY = os.getenv("VOICE_API_KEY") VOICE_API_URL = os.getenv("VOICE_API_URL", "https://api.example.com/v1/audio/speech") def text_to_speech(text: str, save_path: str = "assets/audio/aili_greeting.mp3", voice: str = "alloy") -> str: headers = { "Authorization": f"Bearer {VOICE_API_KEY}", "Content-Type": "application/json" } payload = { "model": os.getenv("VOICE_MODEL", "tts-1"), "input": text, "voice": voice } resp = requests.post(VOICE_API_URL, headers=headers, json=payload, timeout=60) resp.raise_for_status() os.makedirs(os.path.dirname(save_path), exist_ok=True) with open(save_path, "wb") as f: f.write(resp.content) return save_path if __name__ == "__main__": greeting = "哈喽,今天的天气感觉怎么样?我这里有橘子汽水,要不要一起喝?" result = text_to_speech(greeting) print(f"语音已保存到: {result}")在真实项目中,“选择哪个音色”比“怎么调接口”更影响角色质感。杏色、清澈、偏少女的音色,和御姐音、童声是完全不同的体验。建议测试三个以上音色,让真人听众盲选,再决定角色默认音色。
4.4 第四步:封装对话模块
对话模块是整个角色的心脏。它本质上做三件事:
- 读取角色配置文件。
- 把角色人设渲染成 System Prompt。
- 把用户消息和历史消息拼接成上下文,调用大模型,返回回复文本。
下面是完整的 chat 示例:
# scripts/chat_demo.py import os import yaml from openai import OpenAI from dotenv import load_dotenv load_dotenv() def load_character(path: str = "config/character.yaml") -> dict: with open(path, "r", encoding="utf-8") as f: return yaml.safe_load(f)["character"] def build_system_prompt(character: dict) -> str: prompt = f"""你正在扮演一个虚拟角色,角色信息如下: 名字:{character['name']} 主题:{character['theme']} 性格特质:{'、'.join(character['style'])} 说话语气:{character['tone']} 背景故事: {character['background']} 约束条件: """ for rule in character["constraints"]: prompt += f"- {rule}\n" return prompt def chat_once(user_input: str, history: list): character = load_character() system_prompt = build_system_prompt(character) client = OpenAI( api_key=os.getenv("LLM_API_KEY"), base_url=os.getenv("LLM_BASE_URL"), ) messages = [{"role": "system", "content": system_prompt}] messages.extend(history) messages.append({"role": "user", "content": user_input}) response = client.chat.completions.create( model=os.getenv("LLM_MODEL"), messages=messages, temperature=0.8, max_tokens=200, ) reply = response.choices[0].message.content return reply if __name__ == "__main__": # 模拟两轮对话 history = [ {"role": "user", "content": "我今天心情不太好。"}, {"role": "assistant", "content": "那要不要先喝一口橘子汽水?我陪你坐一会儿。"}, ] user_message = "你还记得我喜欢喝什么吗?" reply = chat_once(user_message, history) print(f"爱莉:{reply}")这里的核心是build_system_prompt。它把人物设定、语气、约束条件统一渲染成提示词,模型每次回复都先读取这份提示词,从而保证角色一致性。
但也必须提醒你:History 列表只是一个临时内存。真实产品里,会话记录要落库,会话过长时要压缩摘要,用户画像要单独存储。具体怎么做,我在最佳实践部分会展开。
5. 完整示例与代码实现
下面把四个模块串成一个可运行的完整 Demo。运行顺序是:先加载配置 -> 生成角色介绍文本 -> 生成语音 -> 执行一段简单对话。这能验证整条链路的联通性。
5.1 组装链路脚本
# scripts/run_aili_demo.py import os import yaml import time from openai import OpenAI from dotenv import load_dotenv from generate_avatar import generate_avatar from generate_voice import text_to_speech load_dotenv() def load_character(path: str = "config/character.yaml") -> dict: with open(path, "r", encoding="utf-8") as f: return yaml.safe_load(f)["character"] def build_intro(character: dict) -> str: return ( f"我是{character['name']},一个喜欢橙色的小镇少女。" f"我平时喜欢看日落,喝橘子汽水,收集落叶书签。" f"今天想和你聊聊天!" ) def main(): character = load_character() print(f"角色:{character['name']} / 主题:{character['theme']}") # 1. 生成角色介绍文本 intro_text = build_intro(character) print(f"介绍文本:{intro_text}") # 2. 生成语音 voice_path = text_to_speech(intro_text, save_path="assets/audio/aili_intro.mp3") print(f"语音文件:{voice_path}") # 3. 简单对话验证 client = OpenAI( api_key=os.getenv("LLM_API_KEY"), base_url=os.getenv("LLM_BASE_URL"), ) system_prompt = ( f"你是{character['name']},主题是{character['theme']}。" f"说话短句、温暖、活泼。约束:不提供专业建议,不说教。" ) resp = client.chat.completions.create( model=os.getenv("LLM_MODEL"), messages=[ {"role": "system", "content": system_prompt}, {"role": "user", "content": "爱莉,你好呀!介绍一下你自己吧。"}, ], temperature=0.8, max_tokens=200, ) reply = resp.choices[0].message.content print(f"爱莉:{reply}") # 4. 顺手生成一张立绘(可选) # avatar_path = generate_avatar("1girl, original character, warm orange theme, sunset background") # print(f"立绘文件:{avatar_path}") if __name__ == "__main__": main()5.2 为什么要把语音、绘画、对话分开
很多新手喜欢把所有功能写进一个类里,方便是方便,但后来加缓存、加日志、换模型供应商时,就会变得很痛苦。上面的脚本刻意把三个功能分散到不同脚本中,原因是它们的调用频率完全不同:绘画是低频离线任务,语音是低频按需任务,对话是高频在线任务。三者混在一起,后续做性能优化无从下手。
如果你以后做成 Web 服务,推荐用 FastAPI 包一层。对话接口走流式返回,语音和绘画接口走异步队列,这样体感最好。
5.3 把角色配置做成热加载
如果你已经跑通了上面的脚本,下一步可以做一个非常实用的小优化:让角色配置支持热加载。改人设不用改代码,重启即可生效。
实现方式很简单:把配置文件的读取放到每次请求时动态执行。项目初期不需要做复杂的配置中心,一个 YAML 文件加上文件修改时间判断就够了:
import os import yaml from functools import lru_cache CONFIG_PATH = "config/character.yaml" _last_mtime = 0 _cache = None def load_character(): global _last_mtime, _cache mtime = os.path.getmtime(CONFIG_PATH) if mtime != _last_mtime: with open(CONFIG_PATH, "r", encoding="utf-8") as f: _cache = yaml.safe_load(f)["character"] _last_mtime = mtime return _cache这里真正的价值不是省一次文件读取,而是把“角色的定义”和“角色的执行”分离。你编辑一下 YAML,给爱莉换一段背景故事,对话风格立刻变,代码一行不用动。
6. 运行结果与效果验证
6.1 运行命令
确保虚拟环境已激活,然后在项目根目录执行:
python scripts/run_aili_demo.py如果一切正常,你会在终端看到类似这样的输出:
角色:爱莉 / 主题:橙色少女心 介绍文本:我是爱莉,一个喜欢橙色的小镇少女。我平时喜欢看日落,喝橘子汽水,收集落叶书签。今天想和你聊聊天! 语音文件:assets/audio/aili_intro.mp3 爱莉:你好呀!我是爱莉,今天的天空也是橙色的,像橘子汽水一样。你呢,今天过得怎么样?6.2 判断是否成功运行
有三个检查点:
- 终端能看到完整的角色介绍文本,说明 YAML 配置解析成功。
assets/audio/aili_intro.mp3文件存在,且能正常播放,说明语音 API 链路通。- 爱莉的回复语气接近角色设定,并且没有出现客服腔、说教腔,说明 System Prompt 起效了。
如果失败,第一步不要猜,直接看终端抛出的异常信息。大多数问题集中在 API Key 无效、网络不通、模型名称错误这三类。
6.3 验证角色一致性
一个常见的误区是:只要大模型回复得像角色,就算成功。真正的角色一致性测试需要连续对话十轮以上,并且中间故意插入干扰问题,比如“你不是 AI 吗”“你真的是小镇少女吗”。好的角色工程能在打断后继续回到角色。
建议你做这样一个测试脚本:
# scripts/test_stability.py import os from openai import OpenAI from dotenv import load_dotenv load_dotenv() client = OpenAI( api_key=os.getenv("LLM_API_KEY"), base_url=os.getenv("LLM_BASE_URL"), ) system_prompt = ( "你是爱莉,一个喜欢橙色的小镇少女。" "温暖、活泼、短句表达。用户叫你 AI 时,自然承认自己是虚拟角色," "但依然保持爱莉的语气。" ) messages = [{"role": "system", "content": system_prompt}] test_inputs = [ "你叫什么名字?", "你是不是AI?", "今天天气不好,我有点闷。", "那你到底是真人还是程序?", "陪我聊五分钟好不好?", ] for text in test_inputs: messages.append({"role": "user", "content": text}) resp = client.chat.completions.create( model=os.getenv("LLM_MODEL"), messages=messages, temperature=0.7, ) reply = resp.choices[0].message.content print(f"用户:{text}") print(f"爱莉:{reply}") print("-" * 40)这个测试脚本要关注两件事:第一,爱莉是否始终使用统一的人称和语气;第二,当用户试探“你是 AI 吗”时,她没有惊慌失措,也没有跳出角色变成客服。能做到这两点,角色的稳定性才算过关。
7. 常见问题与排查思路
下面的表格整理了 AI 角色工程中最高频的五类问题,每一类都是我实际在项目中见过且常见的:
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 调用大模型返回 401 | API Key 错误或权限不足 | 检查 .env 中密钥是否拼写正确,在服务商控制台确认额度 | 重新生成密钥,确认环境变量已加载 |
| 角色回复时像客服,不像角色 | System Prompt 过于简略,约束不够 | 打印实际发送到模型的 messages,检查 system 内容 | 加强语气约束,添加角色背景故事和“禁止”列表 |
| 角色记忆不连续,忘记用户名字 | 每次请求没有带上历史消息 | 检查 chat 脚本的 messages 是否包含 history | 维护会话历史列表或引入向量记忆 |
| 绘画生成的立绘不符合主题 | 提示词缺少场景和色彩约束 | 检查 prompt 是否包含 “warm orange”、“sunset” 等关键词 | 补充更多风格词,并简化负面提示词 |
| 语音生成失败或音频失真 | 音频格式与服务端不匹配 | 查看响应 Content-Type,使用 ffprobe 检查音频编码 | 统一保存为 mp3 或 wav,先人工播放一次 |
这里再说一个容易被忽略的点:角色工程里,“日志”比“报错”更重要。这类应用有大量的交互状态,用户上一句话、角色上一句话、记忆摘要、当前情绪标记,都应该打到结构化日志里。报错只是结果,日志能帮你还原整个过程。
8. 最佳实践与工程建议
8.1 人设即代码,角色配置必须版本管理
角色设定不是一个文档,而是一份配置,必须进入 Git 版本管理。每次角色改动都应该有记录:改了语气,还是改了背景故事,还是新增了处理规则?这样做有两个直接好处:一是改坏了能一键回滚;二是多个角色可以复用同一个执行框架,只换 YAML 文件就得到完全不同的角色。
8.2 安全边界要提前设计
这一点必须单独强调。AI 角色可以温暖、可以活泼,但绝对不能无边界的“无限制”回复任何内容。角色工程里,安全边界不是 SDK 功能,而是产品设计的一部分。
具体操作:
- 在 System Prompt 中明确约束:不提供医疗、法律、投资等专业建议。
- 对高危话题设置退避机制:礼貌表达“我不太懂这个,不如聊聊今天的心情”。
- 在客户端增加敏感词过滤和人工投诉入口。
- 如果角色面向未成年人,内容尺度必须额外收紧。
不要把安全过滤完全交给大模型。大模型是概率输出,边界要靠工程钳制:提示词用于引导,策略用于拦截,日志用于审计。
8.3 成本控制与缓存策略
角色应用有一个隐蔽的成本坑:每次对话都是完整上下文传输,如果历史消息越来越多,Token 消耗会指数增长,回复延迟也会变大。
常规策略是窗口管理:只保留最近 10 到 20 轮对话;更早的内容压缩成 100 字以内的摘要,作为背景记忆。对画像类信息,例如用户提到“我喜欢喝橘子汽水”,应该抽出来存储,而不是每次都让模型从对话历史里理解。
伪代码示意:
def build_context(history, user_profile): recent = history[-10:] context = [] if user_profile: context.append({"role": "system", "content": f"用户画像:{user_profile}"}) context.extend(recent) return context8.4 立绘和语音的资产管理
角色工程必然会积累大量图片和音频文件。强烈建议建立命名规范,例如aili_avatar_v1.png、aili_greeting_v1.mp3。生成时间和参数建议写进元数据 JSON,不然三个月后你看到一批图片,根本分不清哪版是最新的。
// assets/meta.json { "avatar": { "file": "images/aili_avatar_v1.png", "prompt": "1girl, original character, warm orange theme, sunset background", "created_at": "2025-01-01" }, "greeting_voice": { "file": "audio/aili_greeting_v1.mp3", "text": "哈喽,今天的天气感觉怎么样?", "voice": "alloy", "created_at": "2025-01-02" } }8.5 从 Demo 到产品,还差哪些模块
本文给出的链路是角色工程的最小闭环。从 Demo 到真实可用的产品,至少还需要补齐:
- Web 或小程序前端:展示立绘、聊天记录、播放语音。
- 后端服务:使用 FastAPI 包装对话接口,加入流式输出。
- 持久化:使用 SQLite 或 MySQL 存储会话和用户画像。
- 语音缓存:相同文本不重复合成,直接返回已有音频。
- 监控告警:记录每次调用的延迟、Token 消耗、失败率。
9. 总结与后续学习方向
这篇文章从“AI爱莉”和“橙色少女心”这个主题切入,拆解了一套完整的 AI 角色工程链路:角色配置管理、视觉形象生成、语音合成、对话封装、稳定性验证和最佳实践。核心观点只有一个:AI 角色的竞争力不在于单一模型,而在于围绕角色身份构建的整套工程体系。
如果你只是对角色扮演感兴趣,建议你先把第三节到第五节的代码跑通,生成一张属于你角色的立绘和一句语音,体验全流程。这是最快建立整体认知的方式。
如果你已经是开发者,建议下一步选择两个方向之一深入:一是记忆系统,把临时 history 升级为长期记忆,让角色记住用户;二是多模态交互,把文字回复自动转化成带表情的语音反馈。这两个方向直接决定了角色产品的体验上限。
最后再叮嘱一句:角色工程的技术门槛不高,真正的护城河是你对角色的理解、不断的测试迭代,和一套可靠的安全边界。把配置当代码管理,把每一次角色调整当产品迭代去推进,这个项目才算真正落地。
现在,你可以打开编辑器,新建那个config/character.yaml,开始定义属于你的“爱莉”了。