不用神经网络!自己设计一款带记忆、同义词识别的轻量对话机器人(符号派小Demo)
前言
很多同学一听到人工智能、聊天AI,第一反应就是大模型、Transformer、神经网络、海量数据集、GPU训练。
包括我最开始也是这么认为的:AI = 写一堆复杂Python代码训练模型。
不一定所有AI都要神经网络,来试试手写一个带记忆的对话机器人

但还有一条古老、有趣、完全可控的路线:符号主义AI。
不需要深度学习、不需要训练、不需要数据集,依靠「关键词分组(同义词)+ 状态记忆 + 候选回复池」,也能做出一个不死板、有简单记忆能力的对话程序。
它不是通用大模型,理解能力有限,但胜在:
✅ 代码全透明,每一条回复逻辑都能看懂
✅ 上手门槛低,只需要基础C++
✅ 脱离死板的 if(输入=="xxx") 一对一查表
✅ 同一个语义,换不同说法也能识别,并且共享对话记忆
本文就带着大家从零实现这个小Demo,一起感受这种不一样的“人工心智”设计思路。
设计思路说明
先讲清楚核心架构,这是这个小机器人最精髓的地方:
- 同义词分组:把表达同一个意思的词语归为一组,映射到同一个话题标识。比如
hello、hi、你好、嗨都属于打招呼话题。只要命中组内任意一词,都进入同一个状态。 - 话题状态记忆:给每个话题维护一个计数器,记录这个话题被用户询问过多少次。
- 差异化回复池:同一个话题,第一次触发、多次触发,分别准备多句候选回复,随机抽取,避免每次回答一模一样。
- 隔离状态污染:只有本轮输入命中关键词,才更新计数;本轮没有命中任何话题,直接返回听不懂,不会拿历史状态乱拼接回复(修复容易踩坑的bug)。
- 多话题同时命中支持:一句话同时命中多个话题时,可以输出混合风格的回复。
重点区分:
- 传统查表机器人:输入A→固定输出1,一一映射,非常死板
- 神经网络大模型:依靠数据拟合概率分布,黑盒,需要训练
- 我们这款符号对话机器人:人工定义语义分组与规则,靠状态叠加产生变化,可解释、可控
完整代码
#include <iostream>
#include <unordered_map>
#include <string>
#include <vector>
#include <random>
using namespace std;
// 判断字符串s是否包含子串sub
bool str_contains(const string& s, const string& sub) {
return s.find(sub) != string::npos;
}
// 从候选回复数组中随机挑选一条
string random_pick(const vector<string>& arr) {
static mt19937 rng(random_device{}());
uniform_int_distribution<int> dist(0, arr.size() - 1);
return arr[dist(rng)];
}
// 存储各个话题的交互次数(记忆结构体)
struct Data {
unordered_map<string, int> ask_times = {};
Data() {
ask_times["hello"] = 0;
ask_times["weather"] = 0;
}
};
Data s;
// ========== 配置区:同义词分组,新增话题只在这里扩展 ==========
unordered_map<string, vector<string>> keyword_group = {
{"hello", {"hello", "hi", "嗨", "你好"}},
{"weather", {"weather", "天气", "下雨", "热不热"}}
};
// 检测输入,返回所有命中的话题列表
vector<string> detect_topic(const string& ipt) {
vector<string> hit_topics;
for (auto& item : keyword_group) {
string topic = item.first;
auto& words = item.second;
for (auto& w : words) {
if (str_contains(ipt, w)) {
hit_topics.push_back(topic);
break; // 当前话题只要命中一个同义词即可,不再重复检测本组其他词
}
}
}
return hit_topics;
}
// 根据本轮命中话题 + 历史计数,生成回复
string generate_reply(bool hit_hello, bool hit_weather) {
// 同时命中多个话题,混合回复
if (hit_hello && hit_weather) {
vector<string> mix = {
"一边打招呼一边问天气呀~",
"哈喽,你是想问问天气吗?"
};
return random_pick(mix);
}
// 打招呼话题分支
if (hit_hello) {
int cnt = s.ask_times["hello"];
if (cnt <= 1) {
vector<string> hello_first = {
"你好呀,很高兴认识你!",
"哈喽!很高兴和你聊天~",
"嗨,你好呀!"
};
return random_pick(hello_first);
} else {
vector<string> hello_more = {
"你好呀,怎么又打了一次招呼呀!",
"又见到你啦,哈喽~",
"又跟我打招呼啦!"
};
return random_pick(hello_first);
}
}
// 天气话题分支
if (hit_weather) {
int cnt = s.ask_times["weather"];
if (cnt <= 1) {
vector<string> weather_first = {
"今天的天气看起来还不错哦",
"你想了解天气吗?",
"来聊聊天气啦"
};
return random_pick(weather_first);
} else {
vector<string> weather_more = {
"又问天气啦,你很关心天气呀",
"怎么又想知道天气啦?",
"还在关心天气情况嘛"
};
return random_pick(weather_more);
}
}
// 本轮没有命中任何关键词
return "我还暂时没听明白你的问题";
}
int main() {
cout << "===== 符号派简易对话机器人 =====" << endl;
while (true) {
cout << "\n请输入你想问的内容:" << endl;
string ipt;
cin >> ipt;
auto hit_list = detect_topic(ipt);
bool hit_hello = false;
bool hit_weather = false;
for (auto& t : hit_list) {
if (t == "hello") hit_hello = true;
if (t == "weather") hit_weather = true;
}
// 仅本轮命中话题才增加计数,避免记忆污染
if (hit_hello) s.ask_times["hello"]++;
if (hit_weather) s.ask_times["weather"]++;
cout << generate_reply(hit_hello, hit_weather) << endl;
}
return 0;
}
运行测试示例
===== 符号派简易对话机器人 =====
请输入你想问的内容:
hello
你好呀,很高兴认识你!
请输入你想问的内容:
你好
你好呀,怎么又打了一次招呼呀!
请输入你想问的内容:
weather
你想了解天气吗?
请输入你想问的内容:
天气
又问天气啦,你很关心天气呀
请输入你想问的内容:
aaaa
我还暂时没听明白你的问题
可以看到:
hello 和 你好 属于同一个话题,记忆互通;weather 和 天气 互通。
多次输入同义内容,会切换二次话术;无关输入不会乱触发历史记忆。
优缺点分析(客观看待,不神化)
✅ 优点
- 完全不需要机器学习、不需要训练数据集,纯C++规则代码;
- 逻辑透明,出问题可以直接定位;
- 拓展简单:新增话题只需要在
keyword_group添加分组,再补充对应的回复数组; - 规避了最简单一对一if查表的死板问题。
❌ 局限(非常重要,要和大模型区分开)
- 所有能识别的词、所有回复全部需要人工预先写好,无法自主学习新词、新知识;
- 只是简单子串匹配,容易误触发;
- 没有复杂语义理解,没法处理开放式、全新的问题;
- 记忆只有简单计数器,没有复杂上下文理解(比如“那明天呢”这种承接语句)。
一句话总结:它是一套人工精心设计的状态对话引擎,不是通用人工智能。
它代表的是早期符号AI的思路,现在大量用在游戏NPC、简单客服机器人、交互式脚本里。
后续拓展方向(留给读者动手)
感兴趣的朋友可以在这个基础上继续改造,保持纯规则路线,不用神经网络:
- 遗忘机制:设置衰减,多次不聊某个话题,计数慢慢清零,模拟“慢慢忘记”;
- 话题权重:一句话命中多个话题时,优先选择权重更高的话题回复;
- 上下文承接:单独记录上一轮话题,本轮无匹配关键词时,可以承接上一个话题;
- 配置解耦:把关键词、话术、权重放到json/文本配置文件,代码不用改动;
- 优化匹配算法:不用简单
find子串匹配,做简单分词,减少误命中。
写在最后
很多人接触AI,直接跳进大模型、深度学习的赛道,容易忽略这条古老但有趣的符号主义路线。
智能不一定只有“训练拟合”这一条路。
亲手去设计状态、语义分组、记忆规则,看着程序按照我们设计的逻辑产生不一样的回复,是一种完全不一样的乐趣。
这个小Demo适合编程新手用来拓宽思路:原来聊天机器人,还可以这么做。
如果你有更好的拓展想法,欢迎在评论区一起交流!
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)