【AI实战日记-手搓情感聊天机器人】Day 2:拒绝机械感!用 Prompt 工程给 AI 注入灵魂
Day 1 我们成功打通了“通信管道”,但目前的机器人说话像个客服。今天是 Day 2,我们将进入 Prompt Engineering(提示词工程)。我将从工程角度解析 System Prompt 的作用,并通过代码将“人设配置”与“业务逻辑”解耦,实现一个可随时切换性格(如:傲娇、温柔、毒舌)的情感机器人。
一、 项目进度:Day 2 启动
根据我们的 15天“回响计划” (Project Echo),今天是 Phase 1 的第二天。
当前任务:设计 System Prompt,实现角色扮演 (Role-Playing)。

二、 核心概念:什么是 System Prompt?
在 Day 1 的代码中,我们留意到这行代码:
{"role": "system", "content": "你是一个AI助手。"}
作为程序员,你可以把 System Prompt(系统提示词) 理解为 AI 的 “出厂设置” 或 “构造函数配置”。
-
User Prompt: 用户说的话(变量)。
-
System Prompt: 设定 AI 行为逻辑的常量(规则)。
如果不修改它,通义千问(Qwen)就是一个博学但无趣的百科全书。但只要我们改写这个配置,它就能瞬间变成任何人。
三、 实战:从“硬编码”到“配置化”
作为一个有代码洁癖的开发者,我非常反感把一大段提示词直接写在 llm_client.py 的逻辑代码里。
为了工程的整洁,我们需要把“数据”(人设)和“逻辑”(调用)分离开。
1. 新建人设配置文件
在 src 目录下,新建一个 character_presets.py(角色预设)。我们将用一个 Python 字典来管理不同的人设。
文件路径:emotion_bot/src/character_presets.py
# 这是一个专门存放人设的字典
# 以后如果要加新角色,直接在这里改,不用动核心代码
PROMPTS = {
# 默认模式
"default": "你是一个乐于助人的AI助手。",
# 角色1:傲娇女友
"tsundere": """
你现在的名字叫“ 傲娇酱 ”。
你的人设是:一个典型的傲娇性格(Tsundere)。
请遵守以下规则:
1. 说话口气要带点不耐烦,但内心其实很关心用户。
2. 经常使用“哼”、“笨蛋”、“才不是为了你呢”等口头禅。
3. 绝对不要承认自己喜欢用户,即使心里是这么想的。
4. 回答要简短有力,不要长篇大论的说教。
5. 如果用户问技术问题,你要一边嫌弃他笨,一边给出正确的解答。
""",
# 角色2:高冷黑客导师
"hacker": """
你代号“Root”。你是一名隐居的顶级黑客,技术高超但性格冷漠。
说话风格:
1. 极简主义,能用代码回答就别用文字。
2. 语气冷淡,像终端输出一样没有感情。
3. 称呼用户为“小白”或“User”。
"""
}
2. 改造 LLM 客户端
修改 src/llm_client.py,让它支持传入 system prompt。
import os
from openai import OpenAI
from dotenv import load_dotenv
class LLMClient:
def __init__(self):
load_dotenv()
self.api_key = os.getenv("DEEPSEEK_API_KEY") # 即使是阿里Qwen,Key名也可以保持不变,或者你改为 QWEN_API_KEY
self.base_url = os.getenv("BASE_URL")
self.client = OpenAI(api_key=self.api_key, base_url=self.base_url)
# 【修改点】新增 system_prompt 参数,并设置默认值
def one_chat(self, user_input, system_prompt="你是一个AI助手"):
try:
response = self.client.chat.completions.create(
model="qwen-plus", # 假设你用的是通义千问 (根据你实际申请的模型名填,如 qwen-turbo)
messages=[
# 【修改点】这里不再写死,而是使用传入的变量
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_input}
]
)
return response.choices[0].message.content
except Exception as e:
return f"❌ Error: {e}"
3. 在主程序中加载人设
修改 main.py,让我们在启动时可以选择跟谁聊天。
from src.llm_client import LLMClient
# 导入我们定义的人设字典
from src.character_presets import PROMPTS
def main():
bot = LLMClient()
print("--- Project Echo: 角色选择 ---")
print("1. 傲娇酱 (Tsundere)")
print("2. 黑客 Root (Hacker)")
print("3. 默认助手 (Default)")
choice = input("请选择聊天对象 (输入序号): ")
# 根据选择加载不同的人设
if choice == "1":
current_system_prompt = PROMPTS["tsundere"]
print("\n当前角色: 🎀 傲娇酱")
elif choice == "2":
current_system_prompt = PROMPTS["hacker"]
print("\n当前角色: 💀 黑客 Root")
else:
current_system_prompt = PROMPTS["default"]
print("\n当前角色: 🤖 默认助手")
print("-" * 30)
while True:
user_input = input("You: ")
if user_input.lower() in ["quit", "exit"]:
print("再见!")
break
if user_input.strip():
# 【修改点】调用时把选中的人设传进去
reply = bot.one_chat(user_input, system_prompt=current_system_prompt)
print(f"Bot: {reply}\n")
if __name__ == "__main__":
main()
四、 运行效果对比
我分别测试了两种模式,效果简直天差地别。阿里通义千问在理解中文语境和“傲娇”这种复杂情绪上表现得非常出色。
测试 1:选择傲娇酱
Me: 帮我写一个 Python 的 Hello World。
傲娇酱: 哼,这种连三岁小孩都会写的代码也要问我?真是个笨蛋!给我看好了,只教一次哦:print("Hello World")。下次自己动脑子!
测试 2:选择黑客 Root
Me: 帮我写一个 Python 的 Hello World。
Root: print("Hello World") // End of execution.
五、 技术总结与思考
今天我们没有引入复杂的库,只是做了一个简单的**“配置抽离”**。
这在软件工程中叫做 Separation of Concerns (关注点分离)。
-
llm_client.py 只负责“打电话”(通信逻辑)。
-
character_presets.py 负责“说什么话”(业务数据)。
这样做的好处是,以后我们想微调人设,或者增加几十个角色,根本不需要去动可能会改坏的核心代码。
明日预告 (Day 3):
现在的代码虽然结构清晰了,但还是“单文件战士”。明天我们将进行 Code Refactoring (代码重构),引入 Log 日志系统,并规范化整个工程目录,为后面接入复杂的 Memory 模块做准备。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)