写在前面
上次写dify上的 AI 面试官案例后,没几天就看到了BOSS 上的一条回复——
哈哈,是不是有种一眼看穿的感觉——是的,这里HR调用了AI,结合岗位和面试人员背景提出了三个不同维度( 分别是:产品mvp的规划和定义,推进中的协调和调整,上线后的反思和改进)的问题。
今天,将在n8n上实现相同AI智能面试官的任务。
不同于dify 工作流中需要特别关注对话内容递进和信息流转,本文会更为关注Agent框架下实现相同需求的差异和优缺点。
完成这个任务,后续可以作为一个MCP tool 再被其他Agent调用。例如,面向整个招聘环节的 “HR AI招聘系统”。
通过本文,可以收获以下内容:
- 知识库文档切分、向量化和入库的细节
- 多轮对话中,使用思维链(CoT)提示词约束LLM行为的同时,也发挥Agent更为优秀的输出能力
- RAG召回后,如何与LLM协同完成问题的回答
- 多轮对话中,Agent与Tools、LLM 之间的调用关系
- 同一个应用,不同实现路径(Workflow vs Agent )间的差异
效果展示
老样子,先上效果图。
-
本地知识库内容向量化入库:
-
通过Agent 完成多轮面试问答:
-
面试问题总结和评估:
实现步骤
1. 上传文档,并使用RAG技术分片存储
还是使用之前预处理过的两个面试问答文档:
不过,需要把它们上传到n8n docker 应用中去,这里我是放在 /home/node/upload_files/ 文件夹下:
向量数据库就使用之前dify中安装好的Weaviate。
因为在Weaviate数据库建立的时候没有设置API Key,这里在n8n中只需关联Weaviate链接地址(http://difiy.host:8080)就可以查看内部数据表了:
如果本地没有向量数据库,也不希望把文档吐给云上的向量数据库,可以使用n8n提供的本地“简单向量存储”工具。该工具是把向量和分片数据储存到内存当中的,就是重启后那些处理过的数据会全部。只建议在测试环境中使用这个“简单向量存储”。
最终,将以上节点组合起来,就是第一个工作流——知识库文档向量化并存储。
手动点击”执行“,看一眼输出结果。
在n8n的logs 中可以清楚地看到向量化的过程:
读取本地目录中的文件 –> 进入循环 –> Weaviate 向量库工具,先是根据文档中的切分标记“BBBBBB” 对文档分片 –> 然后使用embedding 模型计算每个分片的向量值 (这里设定每次处理20个分片) –> 第一个文档切分为了101片,所以经过6次的重复计算 –> 将每个分片的信息(含原始文本内容和元数据)与embedding 计算后的向量值关联在一起储存 –> 这样就完成了第一个文档的切分和向量化存储 –> 同样地过程处理第二个文档 –> 直至所有文档处理完成,循环结束
例如,其中一个分片按照以下格式存储在向量数据库中——
|
|
其中,有原始的文本,有文档切片元数据(指明了对应原始文档的第349行到357行),还有一长串向量。
而这个向量,就是后续向量库检索时的条件。
另外,有两点再补充一下:
-
不同于Transformers 模型,encoder时是按照每个Token 完成向量化计算(得到512x1 的矩阵)。
RAG中embedding 向量化的对象是全部的输入。
例如,下面查询句子"hello Qwen3"的向量结果——
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15# 向OLLAMA API接口发起这段话”hello Qwen3“的向量查询,使用的模型是qwen3-embedding:8b 。 curl http://ollama.host:11434/api/embed -d '{"model":"qwen3-embedding:8b","input": "hello Qwen3"}' # 返回的内容格式如下,其中 embeddings对应的就是一个 4096 长度的列表。 { "model":"qwen3-embedding:8b", "embeddings": [[0.005400424,0.004791923,-0.009427172,-0.01674511,-0.0012024766, ...... 省略中间部分 -0.00039164326,-0.015191954,-0.011491347,0.00041572566] ], "total_duration":7977521700, "load_duration":100531700, "prompt_eval_count":4 }所以,拆分后的100个问答对,就会产生100个向量。而向量长度取决于模型。
-
qwen3-embedding:8b 模型,把内容向量化后,默认是得到一个4096x1 的一维向量。上图最右侧展示了 4081 ~ 4095 这几个位置的向量值。
不同的embedding 模型其向量化后的长度不一定一样。
使用的时候需要注意筛选:越长的向量化输出,带来更精细的的向量数据和更大的资源开销。
这边根据网上资料,整理了常见的向量化模型——
模型 (Model) 开发者/机构 (Developer/Organization) 最大/默认向量长度 (Max/Default Dimension) 备注 (Notes) 支持可变维度的先进模型 Qwen3-Embedding-8B 阿里巴巴 (Alibaba) 4096 支持MRL,可截断为 32 到 4096 之间的任意维度。上下文长度 32k。 text-embedding-3-large OpenAI 3072 支持MRL,API中可指定 dimensions参数,例如 256, 512, 1024, 1536。text-embedding-3-small OpenAI 1536 支持MRL,API中可指定 dimensions参数,例如 256, 512。主流闭源模型 text-embedding-ada-002 OpenAI 1536 不支持可变维度。曾是业界最广泛使用的API模型之一。 text-embedding-gecko Google (Vertex AI) 768 Google PaLM 2 系列的 embedding 模型。 主流开源模型 bge-large-en-v1.5 BAAI (智源研究院) 1024 MTEB 排行榜上的常客,性能强大。 e5-large-v2 Microsoft 1024 另一个经典的、性能优异的开源模型。
2. Agent 实现多轮问答和记忆
Agent 这部分内容,我们之前在AI 新闻采集与推送助手的案例中有经验:
主要由 LLM + memory + tools 几部分组成。
如今在同样的多轮对话场景下,Agent又是如何实现这些过程呢?
-
与workflow 方式不同的是:Agent中分析、判断、推理能力成为出厂默认配置,不再需要人工提取和干预,而是交给AI 自主决策——俗称AI max 。
具体操作层面:
通过带有思维链的提示词,引导AI完成上述对话环节分析和打分评估。
|
|
是不是有点意外:之前挺复杂的工作流,在Agent 这里一个节点就搞定了。
效果就是开头效果展示里面的样子 。
- 这里稍微提一句 “记忆”模块,它的作用就是在Agent工作前输入历史对话信息,Agent输出后追加本次对话内容(Human 和 AI对话内容)。所以,随着对话内容变多“记忆”的内容也是越来越多的。
也正是因为有“记忆”这个模块,每一次对话时 Agent 才知道当前对话主题是什么,进入到什么阶段了。
下图可以看到**“记忆”模块在Agent中的位置**——一开始和最后。
3. Agent 调用知识库内容完成任务的详细步骤
本章节着重看观察 Agent是如何协调大模型和RAG 知识库完成面试问题回答和评价的:
有了这些细节,再回过头看之前的 RAG 检索示意图,是不是清楚多了?
其中2.1 ~ 2.3 对应 RAG的检索,3.1 ~ 3.2 对应RAG的提示增强, 4.1 对应生成回答 。
4. Agent 、LLM与Tools 间的关系
就像提示词中写得:Agent 调用 tools 工具(“quary vector info”)只在会话进行到第三轮时,才会去RAG检索。并不是每次都会调用的。
后续,如果有其他工具,例如 “背调工具"就也可以加进去。这样扩充能力后,Agent可以自主判断、执行的操作就越来越多。 今年除了 claudecode cursor Trace这些常见的编程工具外,Manus 应用也火爆起来,背后就是大家都希望AI 可以做得更多、更好,而人类只需要检查AI 的输出就好的美好愿景。
可以说 Agent 的魅力也在 这种“可以丰富扩展”的想象。
具体落实到产品层面的话,还有不少的难题需要处理,后续会陆陆续续展开一些。
对比这两种路径
同样一个需求 是使用Workflow 还是 Agent 背后关乎成本、需求、实现平台等等因素。
| 角度 | Workflow | Agent |
|---|---|---|
| 不同点 | ||
| 处理方式&难度 | 围绕SoP,设计每一步的输入、输出内容和格式 | 使用提示词控制LLM关注方向,实现复杂场景下的内容输出 |
| LLM 模型能力要求 | 一般 | 高 |
| 输出内容 | 可以稳定执行,但是语言上不够自然 | 更接近于自然沟通、交流 |
| 范围外输出 | 不会发生 | 会发生,可能存在一定泄漏数据或提示词的风险 |
| Token 消耗 | 低 | 高 |
| 相同点 | ||
| 知识内容更新 | 更新知识库就行,无需调整工作流 | 同样,只更新知识库就行,无需修改Agent 提示词 |
| 知识库使用方式 | 作为上下文的一部分 | 同样,也是作为上下文的一部分 |
再补充两个细节:
-
在本案例中,我一开始打算全部使用本地显卡上运行的 deepseek-r1:8b或 qwen3:8b 两个模型实现。
结果发现:在RAG检索和提示增强时,用本地的8b模型还可以,但是Agent 中也使用这两个8b 模型都无法正确理解每轮对话的关注点,导致对话无法正常执行下去。
而与之对比的是 dify 中,全部使用的是本地 qewn3:8b 模型。
-
在token 消耗这块,Agent 也是比workflow 多的。主要多在两个方面:
- Agent 每轮对话的内容都保留在 一个记忆对象中。随着对话内容多了,这里面的内容是越来越长的。而且容易有无关的内容也混在其中,无关内容多了后也会干扰LLM模型的注意力。
而workflow 中有分流节点(类似 if/else)的存在,即需要在某个执行节点查看只与本节点相关的记忆即可。
- 因为Agent对模型能力要求更高了,所需的算力也更多,自然花费也大一些。
在下图中也体现了这一点:
小结
Workflow 的路线像是自己做菜——洗、切、炒之外,菜板、刀、调味料这些基础条件也需要自己操行。
Agent 的路线更像是 中央厨房做好了预制菜——买回来,自己只需要加点喜欢的菜、上锅热一热就齐活了!
RAG 本质上是一种工程解决方案:目的是在有限的上下文窗口内,提供预先处理过得高质量数据。
从而提高LLM的注意力和回复质量,同时规避“幻觉”和频繁调用外部工具的麻烦。
感谢你看到这里,听我分享这些。我们下期见。
