关于《我有严重的江湖病》游戏内置Ai助手开发心得
修改于04/06138 浏览开发心得
《我有很严重的江湖病》—— "道灵"AI助手开发心得
一、为什么要做游戏内AI助手
修仙塔防本身系统比较多——五行克制、阵眼搭配、阵魂选择、天劫机制、阴阳平衡……新玩家很容易一脸懵。传统做法是写个图文攻略或新手引导,但总感觉不够"修仙"。
后来想到:既然是修仙题材,不如做一个"老道"角色当引路人,玩家有问题直接问他。于是就有了"道灵"——一个住在游戏里的修仙引路人。
二、整体构建思路
道灵的核心设计目标:不联网、不烧钱、响应快、有人味儿。
整个系统分三层:
第一层:知识库(ai_knowledge.lua)
这是道灵的"记忆",手工整理了所有游戏系统的问答内容:
游戏知识:五行克制、各阵眼/阵基/阵魂的详细数据和用法、地图攻略、Boss打法
闲聊内容:天气、心情、讲笑话、讲故事等日常话题
每个条目都包含关键词列表、优先级和回答文本
相当于给道灵"灌"了一本修仙百科全书。
第二层:智能匹配引擎(ai_chat.lua)
玩家输入一句话后,系统做以下处理:
玩家输入 → 同义词展开 → 关键词评分匹配 → 情绪检测 → 组装回复
关键设计点:
同义词映射:“塔”→“阵眼”、“技能”→“神通”、“地图”→“秘境”,让玩家用自己习惯的词也能匹配到
加权评分:关键词越长、匹配越多,得分越高,避免短词误匹配
情绪感知:检测玩家文字中的情绪(开心、沮丧、愤怒等),回复时加入共情内容
对话记忆:记住最近聊过的5个话题,检测重复提问,到了特定问答次数还会触发彩蛋
第三层:交互功能
除了问答,道灵还能:
占卜:随机算一卦,给出幸运元素和建议
猜谜:出修仙主题谜语,玩家回答后判定对错
这些小互动让道灵不只是个"百科机器人",更像一个有趣的NPC
三、让回复更有"人味"的技巧
最怕的是玩家觉得"这就是个搜索框"。为了让道灵像个真正的老道士,做了几件事:
人设一致性:道灵自称"老道",称玩家"道友",说话带修仙口吻(“让老道掐指一算”、“此事说来话长”)
随机变化:每次回复的开头语、结尾语、过场动作都随机抽取,同样的问题问两次,措辞不完全相同
打字动画:"道灵正在参悟…"的延迟效果,模拟思考过程,而不是瞬间弹出答案
主动推荐:回答完一个问题后,根据话题推荐关联问题(“你可能还想了解:阵魂搭配/天劫应对”)
四、关于"后端AI Key"的问题
有朋友问道灵是不是接了大模型API——并没有。
道灵是纯本地运行的知识库系统,不需要联网,不需要API Key,不会产生任何调用费用。所有问答逻辑都在客户端完成。
选择这个方案的原因:
零延迟:本地匹配比网络请求快得多
零成本:不用为每次对话付API费用
离线可用:没网也能正常使用
可控性强:回答内容完全可控,不会出现大模型"幻觉"导致的错误攻略
当然这个方案的代价是:所有知识都需要手动维护,大概写了6万多字的知识库内容。但对于一个系统明确的游戏来说,手写的精准度反而比大模型更高。
五、UI设计心得
道灵的界面参考了微信聊天的交互习惯:
右下角呼吸动画的浮动图标,点击展开聊天面板
气泡式对话,左边道灵头像、右边玩家头像
底部快捷问题分类标签(常用/地图/系统/战斗/互动),降低输入门槛
图标支持拖拽,不会挡住游戏画面
一个细节:图标做了"点击"和"拖拽"的区分——移动超过3像素才算拖拽,否则算点击打开面板。这个小处理让操作体验顺滑很多。
六、给想做类似功能的开发者的建议
知识库是核心:匹配算法再聪明,知识库内容不全也白搭。先把游戏系统梳理清楚,再写代码
同义词很重要:玩家的表达方式五花八门,多想想同一个概念还有哪些说法
做好兜底:匹配不到时,不要只说"我不知道",引导玩家换种方式提问
人设要贯穿始终:一旦确定了角色性格,所有文本都要保持风格统一
安全过滤别忘了:有些游戏内部数据(伤害公式、掉落概率等)不适合直接告诉玩家,要做好屏蔽
以上就是道灵AI助手的开发全过程,希望对大家有参考价值。有什么问题欢迎评论区交流!
如果你想制造一个类似的游戏内工具,让玩家在游戏内就能自行查找攻略,以下是我开发这个工具的思路:
整体架构
整个系统只需要两个文件:
scripts/
├── ai_knowledge.lua -- 知识库(数据层)
└── ai_chat.lua -- 聊天逻辑 + UI(逻辑层 + 表现层)
不需要后端,不需要API Key,纯本地运行。
第一步:知识库模板(ai_knowledge.lua)
这是AI助手的"大脑",所有问答内容都在这里维护。直接复制下面的结构,把内容换成你自己游戏的:
lua
复制
local K = {}
-- ============================================================
-- 1. 安全过滤词(不想让玩家知道的内部数据)
-- ============================================================
K.BLOCKED_KEYWORDS = {
"伤害公式", "掉落概率", "源代码", "配置表",
-- 加你自己不想暴露的关键词...
}
K.BLOCK_REPLY = {
"这个属于天机,不可泄露哦~",
"这个问题超出了我的权限范围。",
-- 多写几条随机回复,显得自然
}
-- ============================================================
-- 2. 游戏知识库(核心!花时间整理这个)
-- ============================================================
-- 每条格式:{ keys = {匹配关键词}, answer = "回答", priority = 优先级 }
-- priority 越高越优先匹配,默认 5
K.GAME_KNOWLEDGE = {
{
keys = { "新手", "怎么玩", "入门", "教程" },
answer = "欢迎来到游戏!\n\n1. 先做XXX\n2. 再做YYY\n3. 最后ZZZ",
priority = 9, -- 新手引导优先级最高
},
{
keys = { "角色", "职业", "选什么" },
answer = "游戏共有3个职业:\n・战士:近战高血量\n・法师:远程高伤害\n・盗贼:灵活高暴击",
priority = 7,
},
-- 继续添加你的游戏知识...
}
-- ============================================================
-- 3. 闲聊知识库(让AI有人情味)
-- ============================================================
K.CHAT_KNOWLEDGE = {
{
keys = { "你好", "在吗", "你是谁" },
answer = "你好呀!我是你的游戏小助手,有什么问题尽管问!",
},
{
keys = { "无聊", "没意思" },
answer = "无聊了?试试这些玩法:\n1. 挑战高难度\n2. 收集隐藏成就\n3. 和我猜谜!",
},
{
keys = { "谢谢", "感谢" },
answer = "不客气!有问题随时来找我~",
},
-- 天气、吃饭、睡觉、笑话等日常话题...
}
-- ============================================================
-- 4. 情绪关键词(检测玩家心情)
-- ============================================================
K.EMOTION_PATTERNS = {
happy = { "开心", "高兴", "哈哈", "太好了", "666", "厉害", "通关了" },
sad = { "难过", "伤心", "不开心", "唉", "烦", "累了" },
angry = { "生气", "垃圾", "什么鬼", "坑", "不公平", "无语" },
}
K.EMOTION_RESPONSES = {
happy = {
{ prefix = "看你这么开心,我也跟着高兴!", suffix = "继续加油!" },
},
sad = {
{ prefix = "别难过~", suffix = "有什么烦恼说出来,说不定我能帮忙。" },
},
angry = {
{ prefix = "消消气!", suffix = "有什么问题咱们一起解决。" },
},
}
-- ============================================================
-- 5. 互动功能(占卜/猜谜,可选)
-- ============================================================
K.FORTUNE_RESULTS = {
{ fortune = "大吉", message = "今天运气爆棚!适合挑战高难度!" },
{ fortune = "小吉", message = "运势不错,稳步推进。" },
{ fortune = "平", message = "平平淡淡才是真,量力而行。" },
}
K.RIDDLES = {
{
question = "猜谜:「XXX」\n这说的是什么?",
answer_key = { "答案A", "答案B" }, -- 多个关键词都算对
reveal = "答案是【XXX】!因为..."
},
}
-- ============================================================
-- 6. AI人设(让回复有个性)
-- ============================================================
K.PERSONALITY = {
name = "小助手", -- 改成你的AI角色名
title = "游戏引路人",
idle_actions = { -- 随机小动作,穿插在回复中增加趣味
"(小助手想了想)",
"(小助手翻了翻笔记)",
"(小助手点点头)",
},
follow_ups = { -- 回答后的追问建议
system = { "想了解更多系统机制吗?", "需要搭配建议吗?" },
chat = { "要不要来占个卜?", "聊点别的?" },
},
}
-- 话题分类(用来触发对应的追问建议)
K.TOPIC_TAGS = {
["角色"] = "system",
["装备"] = "system",
["笑话"] = "chat",
}
-- 随机开场白
K.REPLY_OPENERS = {
game = { "好问题!\n\n", "来,我给你讲讲。\n\n", "" },
chat = { "哈哈~\n\n", "" },
}
-- 随机结尾
K.REPLY_CLOSERS = {
"还有什么想问的?", "随时找我!", "",
}
-- 兜底回答(啥都匹配不上时用)
K.DEFAULT_REPLIES = {
"这个问题我暂时答不上来...\n\n试试问:「怎么玩」「角色推荐」「装备搭配」",
"换个方式问问?我擅长游戏攻略和系统讲解~",
}
return K
第二步:聊天逻辑模板(ai_chat.lua)
核心匹配算法,直接复制即可用:
lua
复制
local UI = require("urhox-libs/UI")
local K = require("ai_knowledge")
local AIChat = {}
-- ============================================================
-- 安全过滤
-- ============================================================
local function IsBlocked(text)
for _, kw in ipairs(K.BLOCKED_KEYWORDS) do
if string.find(text, kw, 1, true) then return true end
end
return false
end
-- ============================================================
-- 对话记忆
-- ============================================================
local memory_ = {
recentTopics = {},
questionCount = 0,
repeatedQuestions = {},
}
local function CheckRepeat(text)
local key = string.gsub(text, "[%s%p]", "")
memory_.repeatedQuestions[key] = (memory_.repeatedQuestions[key] or 0) + 1
return memory_.repeatedQuestions[key]
end
-- ============================================================
-- 情绪检测
-- ============================================================
local function DetectEmotion(text)
local best, bestScore = nil, 0
for emotion, keywords in pairs(K.EMOTION_PATTERNS) do
local score = 0
for _, kw in ipairs(keywords) do
if string.find(text, kw, 1, true) then
score = score + #kw
end
end
if score > bestScore then bestScore = score; best = emotion end
end
return bestScore >= 2 and best or nil
end
-- ============================================================
-- 同义词扩展(关键!让玩家用任何说法都能匹配到)
-- ============================================================
local SYNONYMS = {
-- 格式:["玩家可能说的"] = "知识库里用的标准词"
["塔"] = "阵眼",
["技能"] = "神通",
["地图"] = "关卡",
-- 根据你的游戏添加...
}
local function ExpandText(text)
local expanded = text
for slang, standard in pairs(SYNONYMS) do
if string.find(text, slang, 1, true) then
expanded = expanded .. " " .. standard
end
end
return expanded
end
-- ============================================================
-- 知识库评分匹配(核心算法)
-- ============================================================
local function SearchKB(kb, text, minScore)
local best, bestScore = nil, 0
for _, entry in ipairs(kb) do
local score, matchCount = 0, 0
for _, k in ipairs(entry.keys) do
if string.find(text, k, 1, true) then
score = score + #k -- 关键词越长,权重越高
matchCount = matchCount + 1
end
end
if matchCount >= 2 then -- 多关键词命中加分
score = score + matchCount * 3
end
score = score * ((entry.priority or 5) / 5.0)
if score > bestScore and score >= minScore then
bestScore = score; best = entry
end
end
return best, bestScore
end
-- ============================================================
-- 互动指令(占卜/猜谜)
-- ============================================================
local riddleState_ = { active = false, current = nil }
local function HandleCommand(text)
-- 占卜
if string.find(text, "占卜", 1, true) or string.find(text, "算一卦", 1, true) then
local f = K.FORTUNE_RESULTS[math.random(#K.FORTUNE_RESULTS)]
return "【" .. f.fortune .. "】\n\n" .. f.message
end
-- 猜谜
if string.find(text, "猜谜", 1, true) or string.find(text, "出题", 1, true) then
local r = K.RIDDLES[math.random(#K.RIDDLES)]
riddleState_ = { active = true, current = r }
return r.question
end
-- 检查谜底
if riddleState_.active and riddleState_.current then
for _, key in ipairs(riddleState_.current.answer_key) do
if string.find(text, key, 1, true) then
local reveal = riddleState_.current.reveal
riddleState_ = { active = false, current = nil }
return "答对了!\n\n" .. reveal
end
end
if string.find(text, "不知道", 1, true) or string.find(text, "放弃", 1, true) then
local reveal = riddleState_.current.reveal
riddleState_ = { active = false, current = nil }
return reveal
end
if #text <= 20 then
return "不对哦~再想想?"
end
end
return nil
end
-- ============================================================
-- 主匹配函数(把上面的模块串起来)
-- ============================================================
local function MatchQuestion(text)
-- 1. 安全检查
if IsBlocked(text) then
return K.BLOCK_REPLY[math.random(#K.BLOCK_REPLY)]
end
-- 2. 重复检测
memory_.questionCount = memory_.questionCount + 1
if CheckRepeat(text) >= 3 then
return "这个问题你已经问过好几次了哦~换个问题试试?"
end
-- 3. 情绪检测
local emotion = DetectEmotion(text)
local emotionPrefix = ""
if emotion then
local responses = K.EMOTION_RESPONSES[emotion]
if responses then
local r = responses[math.random(#responses)]
emotionPrefix = r.prefix .. "\n\n"
end
end
-- 4. 互动指令
local cmdReply = HandleCommand(text)
if cmdReply then return emotionPrefix .. cmdReply end
-- 5. 知识库匹配
local expanded = ExpandText(text)
local gameBest, gameScore = SearchKB(K.GAME_KNOWLEDGE, expanded, 2)
local chatBest, chatScore = SearchKB(K.CHAT_KNOWLEDGE, expanded, 2)
-- 取高分结果(游戏知识略微优先)
local answer
if gameBest and (not chatBest or gameScore * 1.1 >= chatScore) then
answer = gameBest.answer
elseif chatBest then
answer = chatBest.answer
end
if answer then
-- 随机加开场白和结尾
local opener = K.REPLY_OPENERS.game[math.random(#K.REPLY_OPENERS.game)]
local closer = K.REPLY_CLOSERS[math.random(#K.REPLY_CLOSERS)]
local action = math.random(100) <= 30
and K.PERSONALITY.idle_actions[math.random(#K.PERSONALITY.idle_actions)] .. "\n"
or ""
return emotionPrefix .. action .. opener .. answer
.. (closer ~= "" and "\n\n" .. closer or "")
end
-- 6. 纯情绪回应
if emotion then
local r = K.EMOTION_RESPONSES[emotion][1]
return r.prefix .. "\n\n" .. r.suffix
end
-- 7. 兜底
return K.DEFAULT_REPLIES[math.random(#K.DEFAULT_REPLIES)]
end
第三步:接入主程序
lua
复制
-- main.lua 里三行代码搞定
local AIChat = require("ai_chat")
-- 初始化(传入UI根节点)
AIChat.Init(uiRoot)
-- 每帧更新打字动画
function HandleUpdate(eventType, eventData)
local dt = eventData["TimeStep"]:GetFloat()
AIChat.UpdateTypingAnimation(dt)
end
-- 进战斗时隐藏,回大厅时显示
AIChat.SetVisible(false) -- 隐藏
AIChat.SetVisible(true) -- 显示
让AI更"聪明"的核心技巧
技巧 做法 效果
同义词映射 “塔”→“阵眼”、“技能”→“神通” 玩家怎么说都能匹配
加权评分 关键词越长得分越高,多词命中加分 避免短词误匹配
priority 优先级 新手引导=9、通关攻略=9、闲聊=5 重要内容优先返回
随机变体 开场白、结尾、小动作随机组合 同问题不同回答,像真人
情绪感知 检测"开心/难过/生气"等关键词 回复前先共情,有温度
重复检测 同一问题问3次提示换个问法 避免机械重复
安全过滤 屏蔽"伤害公式/掉率"等 保护游戏内部数据
常见问题
Q: 不用大模型API,效果够用吗?
A: 对于游戏助手完全够用。游戏系统是有限的,手写50-100条高质量问答就能覆盖绝大部分玩家提问。而且响应速度是0延迟,比调API快得多。
Q: 知识库要写多少条?
A: 建议至少:游戏知识30-50条 + 闲聊15-20条 + 情绪回复每种2-3条。道灵的知识库大约80+条,6万字左右。
Q: 最重要的是哪部分?
A: 同义词映射和知识库内容质量。算法可以直接抄,但知识库必须你自己根据游戏内容来写。
以上就是完整的模板,复制后把知识库内容换成你自己游戏的就能用。祝大家都能给自己的游戏做一个有趣的AI助手!


