AI 多轮对话引子
之前分享过几个AI应用案例:个人兴趣助手、塔罗牌占卜、AI新闻推送助手。
粗看起来它们的形式和使用工具(插件)各有不同,但是其核心都是工作流——在指定的步骤中完成复杂度不高的任务。
这里的复杂度不高的原因来自三个方面:
- 数据有固定的格式
- AI处理问题的逻辑是一条直线,没有“岔路”
- 处理过程中没有外部的干扰
那缺点就是,只能完成特定场景下的特定问题,AI 含量不高!可能有小伙伴会问了,AI 含量高有什么好处呢?
哈哈,这也是我之前朦胧的地方。
所以,今天就通过一个AI 面试官的应用,探讨在复杂度高一些的场景下,AI 多轮对话应用的实现。
案例:AI 面试官
它的复杂度高在哪里?
-
对话内容没有标准格式,并且面试评判标准也不统一。
-
面试天然就是一个多轮对话的过程,随着对话深入,对话主题会改变。例如:面试官提问过程就是在从不同维度对候选人综合能力评分的过程。
-
真实面试中 可以划分成前后两个阶段。
前期:面试JD 输入–> 候选人匹配 –> 候选人初筛 –> 约定面试时间。
面试环节: 候选人介绍自己 –> 面试官根据岗位和候选人背景提出相关面试问题 –> 候选人回答 –> 面试官继续从不同维度对候选人提问 –> 最终形成候选人综合评分(包括:岗位硬技能、软技能、项目经验、发展和稳定度等)
这里,跳过前期沟通阶段,直接进入面试环节开始后的对话和流程。
梳理后,发现完整的一次面试问答至少需要 4轮对话——
如何实现?
参考梳理出的完整对话过程 。如何在一个工作流(workflow)中逐步识别会话重心发生了改变就成为了关键点。
相比于Agent 的方式,workflow中的识别不是依赖LLM 进行语义分析和逻辑判断,而是依赖工作流中多个变量实现——如问题变量、用户回答变量状态的变化。
这里,直接上结论——
| 对话 | 需要判断的节点 | 具体实现 |
|---|---|---|
| 第一轮 | 对话内容是否和面试相关 | 对话内容和面试相关:就继续后续步骤。 如果内容和面试不相关就直接答复用户“内容和面试无关,无法答复。” |
| 第二轮 | 候选人信息和面试岗位信息是否充分 | 信息充分:就产生面试问题清单。如果信息不充分:就不生成这个清单。 |
| 第三轮 | 面试过程中,候选人 可能只答复其中一条问题,也可能跳着回答 | 用户回答所有问题:就产生用户回答清单。如果用户没有回答全部问题:就引导用户回答,并不生成回答清单。 |
| 第四轮 | 后续对话,是否基于问答内容生成新的面试问题。 | 问答内容会放入“记忆”中。当用户回答完所有问题后,会重新进入问题生成环节,该环节会参考之前的记忆。 |
| 干扰测试 | 如果我在 面试过程中 胡言乱语 会发生什么? | 明显的胡言乱语,会被第一轮识别过滤掉。如果是在面试过程中文不对题,则会在第三轮用户回答过程中识别。 |
效果图
-
完整的工作流
-
对话日志
用户针对提出的问题,乱序完成回答后,面试助手会基于问题和用户回答 打分并提出改进建议——
新一轮对话提出的问题,就参考了之前用户回答中提到项目内容——
例如:这里就提问了在“AI 知识库”这个项目中,如何平衡数据质量和数据覆盖率的问题。
动手实现
这里,会着重展示如何使用工作流中的多个变量控制会话进入到什么阶段。
第一轮 对话
需要筛选与面试相关的内容。如果不相关就回答:“与面试话题无相关。抱歉,我不能答复。”
实现比较简单,直接使用dify的“问题分类器”——
|
|
第二轮 对话
需要引导用户输入面试所需的人员信息和岗位信息。如果用户一次说不完 就提醒用户补充这些背景信息。
这里的判断逻辑为——
|
|
第三轮 对话
需要检查用户输入的回答对应哪个问题,然后提示用户继续回答全部问题。
提示词——
|
|
当用户回答完所有提问问题后,会存入全局变量“userans” 数组中。
这样就完成了一问一答两个数组(变量)的映射:
|
|
有了两个数组(变量),后续就可以在循环中,提取每个问题和回答。
简化下判断逻辑,大概长这样——
|
|
所以,可以直接使用 question 数组中的问题作为控制循环次数和查询知识库的关键字。
第四轮 对话
这里有个小问题,如何判断用户是在继续回答问题,还是在发起新一轮问题?
首先,在第三轮对一问一答两个数组(变量)处理过程中,处理一个问题, question 中就减少一个。全部处理完,question 数组就为空。换个说法就是:如果question 为空,就表示当前是问题产生,而不是问题回答阶段 。
其次,这里用户每次回答的内容userans并没有被清空,而是随着对话变多 而逐步丰富。
所以,只要在第二轮的大模型应用LLM2 中,要求生成问题时,同时参考用户当前输入信息(sys.query)和历史回答信息(userans)就可以产出一轮更深入的问答。
干扰 对话模拟
- 对话过程中,突然暴躁——说出一句“滚”。
问题分类器会做出回应,答复用户 “与面试话题不相关。抱歉, 不能答复。”
-
用户回答 开始答非所问。
LLM4——就是第三轮中的问题识别与关联助手,会识别并关联 用户回答。以及还有哪个问题是没答复的?
下面稍微展开下 使用“RAG” 技术实现面试问答知识库的话题:
为什么需要知识库
使用知识库的原因很简单:LLM 模型在泛化 通用能力上已经可以很好的处理分析问题。例如,写个年终总结报告、生成一段贪吃蛇代码。
但是,如果具体到垂直领域的问题,表现就比较差了。因为它没有这部分领域的准确数据!没有怎么办?大模型就容易出现 “一本正经胡说八道”的情况。此时,问题不在模型不理解、判断不了,而是由于该领域数据不足,无法准确回答。
“知识库”实现了内部私有数据的检索和展示。包含了,数据入库、数据检索和增强LLM上下文 三部分。
先看数据入库阶段——
然后是检索和返回LLM处理过程——
检索模式不止这一种。更多的方式,可以参考:
Advanced RAG Techniques: an Illustrated Overview | by IVAN ILIN | Towards AI
在 dify 中实现面试知识库
大致分为 数据清洗 –> 数据切片 –> 数据向量化&入库 –> 召回验证几个阶段。
1. 拿出准备好的数据集
<面试100 问>
2. 数据集 内容预处理(清洗)
经过测试发现,dify 对pdf 文档的处理时无法识别分段标识符(我这里用的 “BBBBBB” 作为分段标识符)。
所以需要先把pdf 转为 word 。然后,使用正则添加分隔符——
同样可以在关键位置添加换行符——
3. 上传文档。数据分段,并使用embedding 工具完成向量化
这里100个问题被划分成了106个数据块(因为有两个问答对中 重复使用了1. 2. 3. 数字开头,被分段标识符 “BBBBBB” 多划分出了几个段落)
4. 指定 索引和混合检索方式
5. 召回验证
AI 面试官案例中,主要是希望让大模型参考专业HR的标准回答思路,而不是具体内容。
所以 重点参考回答思路中内容。
最后,RAG在哪些场景中效果不好
RAG 技术中很关键的步骤就是 根据输入的内容 快速检索出 与之接近的(向量)数据块。
为了更好的检索效果,引入了混合检索和重排技术。在检索时,同时根据问题向量(vector index)和语义(summary index)召回数据片段。这里权重比为 7:3。
例如使用之前的面试问题提问,查看召回内容:
但是,如果有以下三种情况还是容易出现数据检索不出来的情况:
-
相同的关键字 散落在文档里很多地方。
例如,小说中的 主人公“许仙”。提问:“许仙和白素贞在断桥有几次相遇?” RAG即使检索出来,也无法保证召回的片段覆盖了所有相遇的剧情。
-
检索语义不是通用的,而是带有垂直领域的内容。
例如,”那个在<还珠格格>中饰演尔康的演员还演过其他的什么影视剧?”
这种知识就很难检索出来——“饰演尔康的演员”本身又是另一个检索的结果。知识库得先检索出这个演员的真实名字 ,还要存有每部电视剧的 演员-角色 关系表,然后才可以通过演员信息 检索出所有出演的影视剧。
-
还有一种场景,也比较常见:知识库本身质量不高。
例如:文档格式不统一,文档覆盖面不足,导致检索的时候 得到的内容离问题相关度很远。
此时,属于RAG 技术也帮不了的情况。
前两种是 RAG 机制的导致的,无法避免。最后,这个属于领域知识数据 没达到可用的程度。
除了RAG 还经常听说模型微调?
下面是它们两者间的相同和不同的地方——

| 相同点 | 不同点 | |
|---|---|---|
| 补充模型在某个领域特定知识,解决幻觉问题 | 实现路径不一样 | |
| RAG | 类比:开卷考试——考试时现查 | 根据问题去知识库检索相似内容或案例 |
| 微调 | 类比:考前复习——把之前考试真题全部做一遍 | 通过多轮训练,强化模型在该领域的能力(不仅仅是数据上的,还有推理和逻辑上的针对性强化) |
彩蛋
-
同样的案例,后续会使用n8n 的Agent模式再实现一遍。
到时会豁然开朗:在多轮对话场景中,workflow 和 Agent 有什么差异;以及深入到RAG 调用环节的细节。
-
从产品角度看,AI 应用效果的量化很重要。即 AI 应用内部每个节点状态的可观测性是非常必要的。
以下是通过可观测工具 Langfuse 快速筛选出 “过去三天中 所有执行失败”的那些对话——
是不是非常方便?有了这些对话,为下一步AI 产品迭代升级 提供了基础的数据支撑。
举个例子:用户反应某次对话执行时报错了。那到底是提示词问题,还是大模型响应超时,还是发生了预期外的问题,是不是得有个统计数据在这里呢?
