Dify 应用详解-文本生成应用

概览

文本生成应用是 Dify 中最简单的一种应用。但是流程和其他应用(聊天助手,Agent)差不多。所以做为入门了解整个问答流程,是非常不错的选择。

文本生成应用

功能描述

文本生成应用支持以下功能:

功能名称 功能含义
前缀提示词 提示词用于对AI的回复做出一系列指令和约束。可插入表单变量例如{input}。这段提示词不会被最终用户所看到。
变量 变量将以表单形式让用户在对话前填写,用户填写的表单内容将自动替换提示词中的变量
上下文 支持添加知识库做为上下文信息,且支持两种召回方式。N选1召回和多路召回。
更多类似 一次生成多条文本,可在此基础上编辑并继续生成
文字转语音 启用后,文本可以转换成语音
内容审查 您可以调用审查 API 或者维护敏感词库来使模型更安全地输出。支持 OpenAI Moderation,关键词,API 拓展三种方式

接口信息

调用 /console/api/apps/xxx/completion-messages 接口。调用 AppGenerateService.generate 方法,app_model.mode 是 ‘completion’。

流程详解

  1. 文本生成应用,因为没有会话的概念,所以和其他类型的 APP 不一样,这里就没有 conversation,conversation 为 None
  2. 然后根据 app_model 和 conversation 获取 app model config, 如果是 debug 模式,则允许用户传递的 model config 覆盖 app model config
  3. 解析文件得到 file_objs
  4. 转换为 app config
  5. 初始化 application generate entity
  6. 初始化 generate records。得到一个 conversation 和 message 对象
  7. 初始化 queue manager
  8. 启动线程,调用 _generate_worker 方法
    1. 判断 token 数量是否足够。加载模型实例,获取模型的最大 token 数,将用户自定义的变量和问题组合成为一个 prompt,然后计算 prompt 的需要的 token 数,最后计算 token 是否足够,不足够则返回异常
    2. 重新组织 prompt message
    3. 敏感词检测
    4. 填写来自外部数据工具的变量输入,获取上下文信息
    5. 再次重新组织 prompt message
    6. 再次敏感词检测
    7. 重新判断 token 数量是否足够
    8. 初始化模型实例,调用大模型
  9. 得到 response,将 response 转换后返回出去

在 dify 中,问答的逻辑都是在线程中处理的,线程中的结果通过内存消息队列进行传输。也就是说,在线程中进行与大模型等各种的交互,交互的结果通过队列传输到线程外。所以在第 7 步的内容是初始化了一个队列,消息队列的基本操作如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class AppQueueManager:
def __init__():
q = queue.Queue()
self._q = q

def listen(self) -> Generator:
while True:
try:
message = self._q.get(timeout=1)
if message is None:
break

yield message
except queue.Empty:
continue
finally:
...

def stop_listen(self) -> None:
self._q.put(None)

def publish(self, event: AppQueueEvent, pub_from: PublishFrom) -> None:
self._publish(event, pub_from)

@abstractmethod
def _publish(self, event: AppQueueEvent, pub_from: PublishFrom) -> None:
raise NotImplementedError

敏感词检测是通过用户不同的选择(前端界面)来进行的。主要逻辑为实例化 ModerationFactory,然后调用 moderation_for_inputs 方法。如果匹配到敏感词,就不会继续下面的流程了。

1
2
moderation_factory = ModerationFactory(...)
moderation_result = moderation_factory.moderation_for_inputs(inputs, query)

从知识库中获取上下文,也是整个环节中比较重要的一部分,并且支持不同的召回方式(N选1召回和多路召回),有因为不同的模型所支持的功能不一样,所以这里的实现也有所区别。

N选1召回

  1. 如果大模型支持 FunctionCall,且作为上下文的知识库的数量大于1,那么就会让大模型来进行选择。大模型返回被调用的 function 名称
  2. 如果大模型不支持 FunctionCall,且作为上下文的知识库的数量大于1,那么就使用 ReAct 的方法

多路召回

  1. 多路召回则直接启用多线程去向量数据库中查询,比如目前有三个知识库作为上下文,则启动三个线程进行相关 document 的召回。然后在使用 rerank 模型对召回的结果进行重新排序。

当上下文从知识库中查询出来后,下一步会重新组织 prompt message,将上下文信息添加到 prompt message 中去。重新计算 token 等。

总结

生成文本应用比较简单,和聊天助手相比,少了一些功能,例如:对话开场白,下一步问题建议,引用和归属,标注回复等。和 Agent 相比,也没有那么复杂,Agent 涉及 FunctionCall,CoT 等调用方式。

不过三者在调用流程上都是差不多的,其他两种应用的调用流程和本次介绍的调用流程,差不多 90% 的部分是类似的。只是细节实现和侧重点不一样而已。