Самостоятельная работа с амбулаторными рекомендациями (chatflow) в Dify
Примечание: В этой статье используется Dify v0.7.2.
Этот чат-поток показывает, как создать чат-бот для амбулаторных рекомендаций, который может собирать данные о пациенте с помощью веб- или голосового диалога. В простом понимании это означает, что пациенту дается рекомендация отделения, основанная на информации о пациенте (возраст, пол и симптомы).
I. Мышление рабочего процесса
1. Скриншот рабочего процесса
Скриншот полного рабочего процесса амбулаторной ориентации, показанный ниже:

2. Псевдосхема рабочего процесса
Цель рабочего процесса "Амбулаторная консультация" - порекомендовать пациенту отделение на основе введенных пациентом данных о возрасте, поле и симптомах. В первом раунде диалога, поскольку пациент может ввести всю или часть информации сразу, узел "Извлекатель параметров" используется для извлечения пола, симптомов и возраста из первого введенного пациентом значения. Диалоговая переменная is_first_message устанавливается в 0 узлом "Назначение переменной".
3. Проблемы 1
Во время последующих раундов диалога одновременно распознается только один тип полевой информации, хотя пациент может предоставить несколько полей, причем поля распознаются в порядке возраста, пола и симптомов.

4. Проблемы 2
Если отделение уже было рекомендовано на основе информации о пациенте, то при повторном вводе любой информации будет рекомендовано последнее отделение. Поскольку поле "Отделение" не является пустым, выполняется процесс прямого ответа.

II. Переменные сессии
Переменная сессии используется для хранения контекстной информации, необходимой LLM, такой как предпочтения пользователя, история диалогов и т. д. Она доступна для чтения и записи. Переменные сессии ориентированы на сценарии многораундового диалога, поэтому переменные сессии доступны только для приложений типа Chatflow (Chat Assistant -> Workflow Orchestration).
1.переменная сессиитип данных
(1) Струна
(2) Количество
(3) Объект
(4) Array[string] массив строк
(5) Array[number] Массив чисел
(6) Array[object] Массив объектов
2.переменная сессиихарактеристика
(1) На переменные сеанса можно глобально ссылаться в большинстве узлов;
(2) Запись переменных сеанса требует использованияприсвоение переменныхУзлы;
(3) Переменные сессии доступны для чтения и записи.
3. Переменные сеанса, определенные в этом рабочем процессе
Пять переменных сессии, определенных для этого рабочего процесса: первый ли это раунд диалога, возраст, пол, симптомы и отделение.

III. Интерфейсы, связанные с рабочим процессом
1. Получите интерфейс для рабочего процесса
(1) Расположение исходного кода
- Расположение исходного кода: dedify-0.7.2\api\controllers\console\app\workflow.py
- Расположение исходного кода: dedify-0.7.2\api\services\workflow_service.py
(2) Получение операций рабочего процесса
http://localhost:5001/console/api/apps/3c309371-54f6-4bfb-894a-4193b189ffa5/workflows/draft. где draft, как и draft, указывает на отладку на странице рабочего процесса.

(3) Приобретение реализаций рабочих процессов
Рабочий процесс сохраняет запись в таблице данных рабочих процессов. Сейчас эта версия является черновой, и каждый раз, когда рабочий процесс публикуется, в эту таблицу вставляется запись. Как показано ниже:

(4) Структура данных рабочего процесса
Структура данных Workflow, возвращаемая интерфейсом, показана ниже:
class Workflow(db.Model):
__tablename__ = 'workflows'
__table_args__ = (
db.PrimaryKeyConstraint('id', name='workflow_pkey'),
db.Index('workflow_version_idx', 'tenant_id', 'app_id', 'version'),
)
id: Mapped[str] = db.Column(StringUUID, server_default=db.text('uuid_generate_v4()'))
tenant_id: Mapped[str] = db.Column(StringUUID, nullable=False)
app_id: Mapped[str] = db.Column(StringUUID, nullable=False)
type: Mapped[str] = db.Column(db.String(255), nullable=False)
version: Mapped[str] = db.Column(db.String(255), nullable=False)
graph: Mapped[str] = db.Column(db.Text)
features: Mapped[str] = db.Column(db.Text)
created_by: Mapped[str] = db.Column(StringUUID, nullable=False)
created_at: Mapped[datetime] = db.Column(db.DateTime, nullable=False, server_default=db.text('CURRENT_TIMESTAMP(0)'))
updated_by: Mapped[str] = db.Column(StringUUID)
updated_at: Mapped[datetime] = db.Column(db.DateTime)
_environment_variables: Mapped[str] = db.Column('environment_variables', db.Text, nullable=False, server_default='{}')
_conversation_variables: Mapped[str] = db.Column('conversation_variables', db.Text, nullable=False, server_default='{}')
2. Обновление интерфейсов рабочих процессов
(1) Расположение исходного кода
- Расположение источника: dedify-0.7.2\web\app\components\workflow\hooks\use-nodes-sync-draft.ts
- Расположение исходного кода: dedify-0.7.2\web\service\workflow.ts
(2) Обновление операций рабочего процесса
http://localhost:5001/console/api/apps/3c309371-54f6-4bfb-894a-4193b189ffa5/workflows/draft.

(3) Обновление внешнего кода рабочего процесса
Из-за фреймворка React Flow, используемого во фронтенде рабочего процесса Dify, можно предположить, что при изменении рабочего процесса могут выполняться POST-операции, такие как добавление, удаление и изменение. С помощью журналов в консоли внутренней части было обнаружено, что вызов функцииworkflows/draft?_token=
::

пройти (законопроект, проверку и т.д.)workflows/draft?_token=
Поиск во внешнем коде нашел только одно место для его использования, и это должно быть здесь.

Поскольку выполняется операция POST, должен быть параметр Payload, а параметр рабочего процесса находится в этом файле.

Когда зависимостьgetPostParams
Когда происходит изменение, оно выполняется асинхронноsyncWorkflowDraft(postParams)
.

(указывает на причинно-следственную связь)syncWorkflowDraft(postParams)
Фактический вызов - POST. как показано ниже:

(4) Краткое описание функций рабочего процесса
справаdify-0.7.2\web\service\workflow.ts
Ниже приведены основные функции:
серийный номер | название функции | функция функция | Параметры и пояснения |
---|---|---|---|
1 | fetchWorkflowDraft | Получите проект рабочего процесса. | url : Строка, URL-адрес запроса. |
2 | syncWorkflowDraft | Синхронизируйте черновики рабочего процесса. | url : Строка, URL-адрес запроса.params : объект, параметры запроса, содержащие graph , иfeatures , иenvironment_variables ответить пением conversation_variables . |
3 | fetchNodesDefaultConfigs | Получите конфигурацию узла по умолчанию. | url : Строка, URL-адрес запроса. |
4 | fetchWorkflowRunHistory | Получение истории выполнения рабочего процесса. | url : Строка, URL-адрес запроса. |
5 | fetcChatRunHistory | Получите историю выполнения чата. | url : Строка, URL-адрес запроса. |
6 | singleNodeRun | Запустите один узел. | appId : Строка, идентификатор приложения.nodeId : Строка, идентификатор узла.params : Объект, параметры запроса. |
7 | getIterationSingleNodeRunUrl | Получает URL-адрес запуска итерации для одного узла. | isChatFlow : Булево значение, указывающее, является ли это потоком чата или нет.appId : Строка, идентификатор приложения.nodeId : Строка, идентификатор узла. |
8 | publishWorkflow | Опубликуйте рабочий процесс. | url : Строка, URL-адрес запроса. |
9 | fetchPublishedWorkflow | Получите опубликованные рабочие процессы. | url : Строка, URL-адрес запроса. |
10 | stopWorkflowRun | Остановите выполнение рабочего процесса. | url : Строка, URL-адрес запроса. |
11 | fetchNodeDefault | Получите конфигурацию узла по умолчанию. | appId : Строка, идентификатор приложения.blockType : Значение перечисления, тип узла.query : Объект, необязательный, параметр запроса. |
12 | updateWorkflowDraftFromDSL | Обновление черновиков рабочего процесса из DSL. | appId : Строка, идентификатор приложения.data : Строка, данные DSL. |
13 | fetchCurrentValueOfConversationVariable | Получает текущее значение переменной сессии. | url : Строка, URL-адрес запроса.params : объект, параметры запроса, содержащие conversation_id . |
3. реализация рабочих процессов
Ссылка наРеализация процессов создания, обновления, выполнения и удаления операций ChatflowРаздел "Реализация Chatflow" в [6].
4. публикация рабочих процессов
(1) Расположение исходного кода
- Расположение исходного кода: dedify-0.7.2\api\controllers\console\app\workflow.py
- Расположение исходного кода: dedify-0.7.2\api\services\workflow_service.py
- Расположение источника: dedify-0.7.2\api\events\event_handlers\update_app_dataset_join_when_app_published_workflow_updated.py
(2) Интерфейс публикации рабочих процессов
Это действие выполняется, когда вы нажимаете кнопку Опубликовать рабочий процессhttp://localhost:5001/console/api/apps/3c309371-54f6-4bfb-894a-4193b189ffa5/workflows/publish
Интерфейс.

В основном он заключается в создании нового рабочего процесса и запуске события рабочего процесса приложения. Как показано ниже:

(3) Создание новой записи рабочего процесса
В основном это заключается в создании новой записи рабочего процесса, где содержимое поля version имеет значение 2024-09-07 09:11:25.894535. что указывает на то, что рабочий процесс был опубликован, а не черновик (рабочий процесс не был опубликован и все еще находится в стадии отладки в канве рабочего процесса). Как показано ниже:

(4) реализация события app_published_workflow_was_updated
@app_published_workflow_was_updated.connect
def handle(sender, **kwargs):
app = sender
published_workflow = kwargs.get("published_workflow")
published_workflow = cast(Workflow, published_workflow)
dataset_ids = get_dataset_ids_from_workflow(published_workflow) # 从工作流中获取数据集ID
app_dataset_joins = db.session.query(AppDatasetJoin).filter(AppDatasetJoin.app_id == app.id).all() # 获取应用数据集关联
removed_dataset_ids = [] # 用于存储移除的数据集ID
if not app_dataset_joins: # 如果没有应用数据集关联
added_dataset_ids = dataset_ids # 添加数据集ID
else: # 如果有应用数据集关联
old_dataset_ids = set() # 用于存储旧的数据集ID
for app_dataset_join in app_dataset_joins: # 遍历应用数据集关联
old_dataset_ids.add(app_dataset_join.dataset_id) # 添加数据集ID
added_dataset_ids = dataset_ids - old_dataset_ids # 添加数据集ID
removed_dataset_ids = old_dataset_ids - dataset_ids # 移除数据集ID
if removed_dataset_ids: # 如果有移除的数据集ID
for dataset_id in removed_dataset_ids: # 遍历移除的数据集ID
db.session.query(AppDatasetJoin).filter(
AppDatasetJoin.app_id == app.id, AppDatasetJoin.dataset_id == dataset_id
).delete() # 删除应用数据集关联
if added_dataset_ids: # 如果有添加的数据集ID
for dataset_id in added_dataset_ids: # 遍历添加的数据集ID
app_dataset_join = AppDatasetJoin(app_id=app.id, dataset_id=dataset_id) # 创建应用数据集关联
db.session.add(app_dataset_join) # 添加应用数据集关联
db.session.commit() # 提交事务
Функция этого кода заключается в обработке app_published_workflow_was_updated
Сигнал для обновления отношений ассоциации между приложением и набором данных при обновлении опубликованного рабочего процесса для этого приложения. Конкретные шаги выглядят следующим образом:
- Получите объект приложения, отправившего сигнал
app
и обновленные объекты рабочего процессаpublished_workflow
. - приглашения
get_dataset_ids_from_workflow
функция, которая извлекает коллекцию идентификаторов наборов данных из обновленного рабочего процессаdataset_ids
. - Запросите базу данных, чтобы получить все данные текущего приложения
AppDatasetJoin
Записи. - Вычислите идентификаторы наборов данных, которые нужно добавить и удалить:
- Если нет текущих
AppDatasetJoin
записей, то необходимо добавить все извлеченные идентификаторы наборов данных. - В противном случае вычислите идентификаторы наборов данных, которые нужно добавить и удалить.
- Если нет текущих
- Удаление необходимости удаления
AppDatasetJoin
Записи. - Добавить новый
AppDatasetJoin
Записи. - Отправьте транзакцию базы данных.
(5) Роль таблицы AppDatasetJoin
Таблица AppDatasetJoin служит для поддержания отношений "многие-ко-многим" между приложением (App) и набором данных (Dataset). Каждая запись представляет собой связь приложения с набором данных. Конкретные поля приведены ниже:
- id: первичный ключ, однозначно идентифицирующий запись.
- app_id: уникальный идентификатор приложения.
- dataset_id: уникальный идентификатор набора данных.
- created_at: Временная метка создания записи.
- С помощью этой таблицы можно запросить, какие наборы данных связаны с определенным приложением, или с какими приложениями связан тот или иной набор данных.
(6) реализация функции get_dataset_ids_from_workflow()
def get_dataset_ids_from_workflow(published_workflow: Workflow) -> set: # 从工作流中获取数据集ID
dataset_ids = set() # 用于存储数据集ID
graph = published_workflow.graph_dict # 获取工作流图
if not graph: # 如果没有图
return dataset_ids # 返回空集合
nodes = graph.get("nodes", []) # 获取图中的节点
# fetch all knowledge retrieval nodes # 获取所有知识检索节点
knowledge_retrieval_nodes = [
node for node in nodes if node.get("data", {}).get("type") == NodeType.KNOWLEDGE_RETRIEVAL.value
] # 获取所有知识检索节点
if not knowledge_retrieval_nodes: # 如果没有知识检索节点
return dataset_ids # 返回空集合
for node in knowledge_retrieval_nodes: # 遍历知识检索节点
try:
node_data = KnowledgeRetrievalNodeData(**node.get("data", {})) # 获取节点数据
dataset_ids.update(node_data.dataset_ids) # 更新数据集ID
except Exception as e: # 如果出现异常
continue
return dataset_ids
Основная задача функции get_dataset_ids_from_workflow заключается в извлечении соответствующих идентификаторов наборов данных всех узлов поиска знаний из заданного объекта рабочего процесса:
- Инициализируйте пустую коллекцию dataset_ids для хранения идентификаторов наборов данных.
- Получение графовой структуры графа рабочего процесса.
- Возвращает пустую коллекцию dataset_ids, если структура графа пуста.
- Получите все узловые точки графа.
- Отфильтруйте все узлы типа KNOWLEDGE_RETRIEVAL knowledge_retrieval_nodes.
- Итерация по этим узлам поиска знаний, извлечение их идентификаторов наборов данных и обновление их в коллекции dataset_ids.
- Возвращает коллекцию всех извлеченных идентификаторов наборов данных.
5. другие интерфейсы рабочего процесса
На этой части интерфейса мы останавливаться не будем, API разговорного приложения для оркестровки рабочих процессов был описан очень четко.
серийный номер | имя интерфейса | интерфейсное соединение | Объяснение функций интерфейса |
---|---|---|---|
1 | Отправить диалоговое сообщение | POST /chat-messages | Создайте сообщения сеанса, которые отправляют данные пользователю или задают вопросы. |
2 | Загрузка файлов | POST /files/upload | Загружайте файлы (в настоящее время поддерживаются только изображения) для использования при отправке сообщений. |
3 | перестать отвечать | POST /chat-messages/:task_id/stop | Остановка потоковой передачи ответов (поддерживается только потоковый режим). |
4 | Отзывы о сообщении (Likes) | POST /messages/:message_id/feedbacks | Отзывы и лайки пользователей о сообщениях для оптимизации вывода. |
5 | Получите список предлагаемых вопросов для следующего раунда | GET /messages/{message_id}/suggested | Получите список предлагаемых вопросов для следующего раунда. |
6 | Получение сообщений истории сеансов | GET /messages | Получает историю журналов сообщений сессии. |
7 | Получить список сеансов | GET /conversations | Получает список сеансов текущего пользователя. |
8 | Удаление сеанса | DELETE /conversations/:conversation_id | Удаляет указанную сессию. |
9 | переименование сеансов | POST /conversations/:conversation_id/name | Переименуйте сессию. |
10 | преобразование речи в текст | POST /audio-to-text | Преобразование голосовых файлов в текст. |
11 | преобразование текста в речь | POST /text-to-audio | Преобразование текста в речь. |
12 | Получение информации о конфигурации приложения | GET /parameters | Получение информации о конфигурации приложения, такой как функциональные переключатели, входные параметры и т.д. |
13 | Получение метаинформации приложения | GET /meta | Получите метаинформацию приложения для получения значка инструмента. |
библиография
[1] Переменные сессии: https://docs.dify.ai/v/zh-hans/guides/workflow/variables[2] Назначение переменной: https://docs.dify.ai/v/zh-hans/guides/workflow/node/variable-assignment[3] Агрегация переменных: https://docs.dify.ai/v/zh-hans/guides/workflow/node/variable-assigner[4] React Китайский сайт Flow: https://reactflow-cn.js.org/[5] Англоязычный сайт React Flow: https://reactflow.dev/.[6] Реализация процессов создания, обновления, выполнения и удаления операций Chatflow: https://z0yrmerhgi8.feishu.cn/wiki/FFzxwdF4PijlhjkLUoecOv6Vn8a© заявление об авторских правах
Авторское право на статью Круг обмена ИИ Пожалуйста, не воспроизводите без разрешения.
Похожие статьи
Нет комментариев...