Observação: este artigo usa o Dify v0.7.2.
Esse fluxo de bate-papo mostra como criar um chatbot para orientação ambulatorial que pode coletar dados do paciente por meio de diálogo na Web ou por voz. Em termos simples, isso significa que o paciente recebe uma recomendação para um departamento com base nas informações do paciente (idade, sexo e sintomas).
I. Pensamento de fluxo de trabalho
1. captura de tela do fluxo de trabalho
Captura de tela do fluxo de trabalho completo da orientação ambulatorial, mostrada abaixo:
2. pseudofluxograma do fluxo de trabalho
O objetivo do fluxo de trabalho de orientação ambulatorial é recomendar um departamento a um paciente com base na entrada de idade, gênero e sintomas do paciente. Na primeira rodada de diálogo, como o paciente pode inserir todas as informações ou parte delas de uma só vez, o nó "Parameter Extractor" é usado para extrair o gênero, o sintoma e a idade da primeira entrada do paciente. A variável de diálogo is_first_message é definida como 0 pelo nó "Variable Assignment" (Atribuição de variável).
3. problemas 1
Durante as rodadas subsequentes de diálogo, apenas um tipo de informação de campo é reconhecido por vez, embora o paciente possa fornecer vários campos, com os campos reconhecidos na ordem de idade, sexo e sintomas.
4. problemas 2
Se um departamento já tiver sido recomendado com base nas informações do paciente, a inserção de qualquer informação novamente recomendará o último departamento. Como o campo de departamento não está vazio, o processo de resposta direta é seguido.
II. Variáveis da sessão
A variável de sessão é usada para armazenar informações contextuais necessárias ao LLM, como preferências do usuário, histórico de diálogos etc. Ela é de leitura e gravação. As variáveis de sessão são orientadas para cenários de diálogo de várias rodadas, portanto, as variáveis de sessão só estão disponíveis para aplicativos do tipo Chatflow (Chat Assistant -> Workflow Orchestration).
1.variável de sessãotipo de dados
(1) Cordas
(2) Número
(3) Objeto
(4) Array[string] array de strings
(5) Array[number] Array de números
(6) Array[object] Array de objetos
2.variável de sessãocaracterização
(1) As variáveis de sessão podem ser referenciadas globalmente na maioria dos nós;
(2) A gravação de variáveis de sessão requer o uso da funçãoatribuição de variáveisNós;
(3) As variáveis de sessão são de leitura e gravação.
3. variáveis de sessão definidas nesse fluxo de trabalho
As cinco variáveis de sessão definidas para esse fluxo de trabalho são: se é a primeira rodada de diálogo, idade, gênero, sintomas e departamento.
III. Interfaces relacionadas ao fluxo de trabalho
1. obter a interface para o fluxo de trabalho
(1) Localização do código-fonte
- Localização do código-fonte: dedify-0.7.2\api\controllers\console\app\workflow.py
- Localização do código-fonte: dedify-0.7.2\api\services\workflow_service.py
(2) Obtenção de operações de fluxo de trabalho
http://localhost:5001/console/api/apps/3c309371-54f6-4bfb-894a-4193b189ffa5/workflows/draft. onde rascunho, como rascunho, indica depuração na página de fluxo de trabalho.
(3) Aquisição de implementações de fluxo de trabalho
O fluxo de trabalho armazena um registro na tabela de dados de fluxos de trabalho. A versão agora é rascunho e toda vez que um fluxo de trabalho é publicado, um registro é inserido nessa tabela. Como mostrado abaixo:
(4) Estrutura de dados do fluxo de trabalho
A estrutura de dados do fluxo de trabalho retornada pela interface é mostrada abaixo:
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)
recursos: 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. atualizar as interfaces de fluxo de trabalho
(1) Localização do código-fonte
- Localização da fonte: dedify-0.7.2\web\app\componentes\workflow\hooks\use-nodes-sync-draft.ts
- Localização do código-fonte: dedify-0.7.2\web\service\workflow.ts
(2) Atualizar as operações de fluxo de trabalho
http://localhost:5001/console/api/apps/3c309371-54f6-4bfb-894a-4193b189ffa5/workflows/draft.
(3) Atualizar o código de front-end do fluxo de trabalho
Devido à estrutura React Flow usada no front-end do fluxo de trabalho do Dify, especula-se que as operações POST, como adicionar, excluir e alterar, podem ser executadas quando o fluxo de trabalho é alterado. Por meio dos registros no Console do back-end, verificou-se que a chamada para a funçãoworkflows/draft?_token=
::
aprovar (um projeto de lei ou inspeção etc.)workflows/draft?_token=
Ao pesquisar o código de front-end, encontrei apenas um local para usá-lo, que deve ser aqui.
Como a operação POST é executada, deve haver um parâmetro Payload, certo, e o parâmetro de fluxo de trabalho é encontrado nesse arquivo.
Quando a dependênciagetPostParams
Quando ocorre uma alteração, ela é executada de forma assíncronasyncWorkflowDraft(postParams)
.
(indica relação causal)syncWorkflowDraft(postParams)
A chamada real é POST, conforme mostrado abaixo:
(4) Resumo das funções de fluxo de trabalho
direitodify-0.7.2\web\service\workflow.ts
As funções estão resumidas a seguir:
número de série | nome da função | função função função | Parâmetros e explicações |
---|---|---|---|
1 | buscarWorkflowDraft |
Obtenha o rascunho do fluxo de trabalho. | url URL da solicitação: String, o URL da solicitação. |
2 | syncWorkflowDraft |
Sincronizar rascunhos de fluxo de trabalho. | url URL da solicitação: String, o URL da solicitação.parâmetros Objeto: os parâmetros da solicitação, contendo o gráfico erecursos evariáveis_ambientais responder cantando variáveis_de_conversação . |
3 | fetchNodesDefaultConfigs |
Obter a configuração padrão do nó. | url URL da solicitação: String, o URL da solicitação. |
4 | buscarWorkflowRunHistory |
Obter histórico de execução do fluxo de trabalho. | url URL da solicitação: String, o URL da solicitação. |
5 | fetcChatRunHistory |
Obter histórico de execução do bate-papo. | url URL da solicitação: String, o URL da solicitação. |
6 | singleNodeRun |
Executar um único nó. | appId ID do aplicativo: String, ID do aplicativo.nodeId ID do nó: String, a ID do nó.parâmetros Objeto: Objeto, parâmetros da solicitação. |
7 | getIterationSingleNodeRunUrl |
Obtém o URL da execução da iteração para um único nó. | isChatFlow Valor booleano que indica se é ou não um fluxo de bate-papo.appId ID do aplicativo: String, ID do aplicativo.nodeId ID do nó: String, a ID do nó. |
8 | publicarWorkflow |
Publique um fluxo de trabalho. | url URL da solicitação: String, o URL da solicitação. |
9 | fetchPublishedWorkflow |
Obter fluxos de trabalho publicados. | url URL da solicitação: String, o URL da solicitação. |
10 | stopWorkflowRun |
Interromper a execução do fluxo de trabalho. | url URL da solicitação: String, o URL da solicitação. |
11 | fetchNodeDefault |
Obter a configuração padrão do nó. | appId ID do aplicativo: String, ID do aplicativo.blockType Tipo de nó: Valor de enumeração, tipo de nó.consulta Objeto, opcional, parâmetro de consulta. |
12 | updateWorkflowDraftFromDSL |
Atualizar rascunhos de fluxo de trabalho do DSL. | appId ID do aplicativo: String, ID do aplicativo.dados Dados DSL: String, dados DSL. |
13 | fetchCurrentValueOfConversationVariable (buscar valor atual da variável de conversa) |
Obtém o valor atual da variável de sessão. | url URL da solicitação: String, o URL da solicitação.parâmetros Objeto: os parâmetros da solicitação, contendo o conversation_id . |
3. implementação do fluxo de trabalho
Referência aoImplementação do processo de operações de criação, atualização, execução e exclusão do ChatflowA seção "Implementação do Chatflow" em [6].
4. publicação do fluxo de trabalho
(1) Localização do código-fonte
- Localização do código-fonte: dedify-0.7.2\api\controllers\console\app\workflow.py
- Localização do código-fonte: dedify-0.7.2\api\services\workflow_service.py
- Local de origem: dedify-0.7.2\api\events\event_handlers\update_app_dataset_join_when_app_published_workflow_updated.py
(2) Interface de publicação do fluxo de trabalho
Isso é executado quando você clica em Publicar fluxo de trabalhohttp://localhost:5001/console/api/apps/3c309371-54f6-4bfb-894a-4193b189ffa5/workflows/publish
Interface.
Ele consiste principalmente na criação de um novo fluxo de trabalho e no acionamento do evento de fluxo de trabalho do aplicativo. Como mostrado abaixo:
(3) Criação de um novo registro de fluxo de trabalho
Isso consiste principalmente na criação de um novo registro de fluxo de trabalho em que o conteúdo do campo de versão é 2024-09-07 09:11:25.894535. indicando que o fluxo de trabalho foi publicado, e não rascunho (o fluxo de trabalho não foi publicado e ainda está sendo depurado na tela de fluxo de trabalho). Como mostrado abaixo:
(4) Implementação do evento app_published_workflow_was_updated
@app_published_workflow_was_updated.connect
def handle(sender, **kwargs):
app = remetente
fluxo de trabalho_publicado = kwargs.get("fluxo de trabalho_publicado")
fluxo_de_trabalho_publicado = cast(fluxo_de_trabalho, fluxo_de_trabalho_publicado)
dataset_ids = get_dataset_ids_from_workflow(published_workflow) # Obter ID do conjunto de dados do fluxo de trabalho
app_dataset_joins = db.session.query(AppDatasetJoin).filter(AppDatasetJoin.app_id == app.id).all() # Obter associações de conjuntos de dados de aplicativos
removed_dataset_ids = [] # Use para armazenar IDs de conjuntos de dados removidos
if not app_dataset_joins: # Se não houver associações de conjuntos de dados de aplicativos
added_dataset_ids = dataset_ids # Adicionar IDs de conjuntos de dados
else: # Se houver uma associação de conjunto de dados do aplicativo
old_dataset_ids = set() # para armazenar IDs de conjuntos de dados antigos
for app_dataset_join in app_dataset_joins: # Iterar sobre as associações de conjuntos de dados do aplicativo
old_dataset_ids.add(app_dataset_join.dataset_id) # Adicionar IDs de conjuntos de dados
added_dataset_ids = dataset_ids - old_dataset_ids # Adicionar IDs de conjuntos de dados
removed_dataset_ids = old_dataset_ids - dataset_ids # Remover IDs do conjunto de dados
if removed_dataset_ids: # Se houver um ID de conjunto de dados removido
for dataset_id in removed_dataset_ids: # Iterar sobre os IDs de conjuntos de dados removidos
db.session.query(AppDatasetJoin).filter(
AppDatasetJoin.app_id == app.id, AppDatasetJoin.dataset_id == dataset_id
).delete() # Excluir a associação do conjunto de dados do aplicativo
if added_dataset_ids: # Se houver IDs de conjuntos de dados adicionados
for dataset_id in added_dataset_ids: # Iterar sobre os IDs dos conjuntos de dados adicionados
app_dataset_join = AppDatasetJoin(app_id=app.id, dataset_id=dataset_id) # Criando a associação do conjunto de dados do aplicativo
db.session.add(app_dataset_join) # Adicionar uma associação de conjunto de dados do aplicativo
db.session.commit() # Confirmar a transação
A função desse código é lidar com o app_published_workflow_was_updated
Sinal para atualizar o relacionamento de associação entre um aplicativo e um conjunto de dados quando o fluxo de trabalho publicado para esse aplicativo for atualizado. As etapas específicas são as seguintes:
- Obter o objeto do aplicativo que envia o sinal
aplicativo
e objetos de fluxo de trabalho atualizadosfluxo de trabalho publicado
. - invocações
get_dataset_ids_from_workflow
função que extrai a coleção de IDs de conjunto de dados do fluxo de trabalho atualizadodataset_ids
. - Consultar o banco de dados para obter todas as informações do aplicativo atual
AppDatasetJoin
Registros. - Calcula os IDs do conjunto de dados a serem adicionados e excluídos:
- Se não houver nenhum
AppDatasetJoin
todos os IDs de conjuntos de dados extraídos precisam ser adicionados. - Caso contrário, calcule os IDs do conjunto de dados a serem adicionados e excluídos.
- Se não houver nenhum
- Eliminação da necessidade de remover
AppDatasetJoin
Registros. - Adicionar novo
AppDatasetJoin
Registros. - Enviar uma transação de banco de dados.
(5) Função da tabela AppDatasetJoin
A tabela AppDatasetJoin serve para manter um relacionamento de muitos para muitos entre um aplicativo (App) e um conjunto de dados (Dataset). Cada registro representa a associação de um aplicativo com um conjunto de dados. Os campos específicos são os seguintes:
- id: chave primária, identifica de forma exclusiva um registro.
- app_id: o identificador exclusivo do aplicativo.
- dataset_id: Identificador exclusivo do conjunto de dados.
- created_at: o registro de data e hora da criação do registro.
- Com essa tabela, é possível consultar quais conjuntos de dados estão associados a um determinado aplicativo ou a quais aplicativos um determinado conjunto de dados está associado.
(6) Implementação de get_dataset_ids_from_workflow()
def get_dataset_ids_from_workflow(published_workflow: Workflow) -> set: # Obter IDs de conjunto de dados do fluxo de trabalho
dataset_ids = set() # Usado para armazenar IDs de conjuntos de dados
graph = published_workflow.graph_dict # Obter o gráfico do fluxo de trabalho
if not graph: # Se não houver gráfico
return dataset_ids # return empty set
nodes = graph.get("nodes", []) # buscar os nós no gráfico
# buscar todos os nós de recuperação de conhecimento # buscar todos os nós de recuperação de conhecimento
knowledge_retrieval_nodes = [
node for node in nodes if node.get("data", {}).get("type") == NodeType.KNOWLEDGE_RETRIEVAL.value
] # Obter todos os nós de recuperação de conhecimento
if not knowledge_retrieval_nodes: # Se não houver nós de recuperação de conhecimento
return dataset_ids # Retorna o conjunto vazio.
for node in knowledge_retrieval_nodes: # Iterar sobre os nós de recuperação de conhecimento
try: node_data = Knowledge_retrieval_nodes.
node_data = KnowledgeRetrievalNodeData(**node.get("data", {})) # obter dados do nó
dataset_ids.update(node_data.dataset_ids) # Atualizar IDs do conjunto de dados
except Exception as e: # se ocorrer uma exceção
continuar
return dataset_ids
A principal função da função get_dataset_ids_from_workflow é extrair os IDs de conjuntos de dados relevantes de todos os nós de recuperação de conhecimento de um determinado objeto de fluxo de trabalho:
- Inicialize uma coleção dataset_ids vazia para armazenar IDs de conjuntos de dados.
- Obtém a estrutura do gráfico do fluxo de trabalho.
- Retorna a coleção dataset_ids vazia se a estrutura do gráfico estiver vazia.
- Obtém todos os nós do gráfico.
- Filtrar todos os nós do tipo KNOWLEDGE_RETRIEVAL knowledge_retrieval knowledge_retrieval_nodes.
- Iterar sobre esses nós de recuperação de conhecimento, extrair seus IDs de conjunto de dados e atualizá-los na coleção dataset_ids.
- Retorna uma coleção de todos os IDs de conjuntos de dados extraídos.
5. outras interfaces de fluxo de trabalho
Essa parte da interface não será elaborada, pois a API de aplicativo de conversação de orquestração de fluxo de trabalho foi descrita com muita clareza.
número de série | nome da interface | link de interface | Explicação das funções de interface |
---|---|---|---|
1 | Enviar uma mensagem de diálogo | POST /chat-messages | Crie mensagens de sessão que enviem entradas do usuário ou façam perguntas. |
2 | Carregamento de arquivos | POST /files/upload | Faça upload de arquivos (no momento, apenas imagens são suportadas) para uso ao enviar mensagens. |
3 | parar de responder | POST /chat-messages/:task_id/stop | Interromper respostas de streaming (somente o modo de streaming é compatível). |
4 | Feedback da mensagem (curtidas) | POST /messages/:message_id/feedbacks | Feedback do usuário e curtidas nas mensagens para facilitar a otimização do resultado. |
5 | Obtenha uma lista de sugestões de perguntas para a próxima rodada | GET /messages/{message_id}/suggested | Obtenha uma lista de sugestões de perguntas para a próxima rodada. |
6 | Obter mensagens do histórico da sessão | GET /messages | Obtenha o histórico dos registros de mensagens da sessão. |
7 | Obter lista de sessões | GET /conversations | Obtém uma lista das sessões do usuário atual. |
8 | Exclusão de uma sessão | DELETE /conversations/:conversation_id | Exclui a sessão especificada. |
9 | renomeação de sessões | POST /conversations/:conversation_id/name | Renomear a sessão. |
10 | conversão de voz em texto | POST /audio-to-text | Converta arquivos de voz em texto. |
11 | conversão de texto em fala | POST /text-to-audio | Converta texto em fala. |
12 | Obtenção de informações de configuração do aplicativo | GET /parameters | Obter informações de configuração do aplicativo, como chaves de função, parâmetros de entrada, etc. |
13 | Obtenção de metainformações do aplicativo | GET /meta | Obtenha as informações Meta do aplicativo para obter o ícone da ferramenta. |
bibliografia
[1] Variáveis de sessão: https://docs.dify.ai/v/zh-hans/guides/workflow/variables
[2] Atribuição de variável: https://docs.dify.ai/v/zh-hans/guides/workflow/node/variable-assignment
[3] Agregação de variáveis: https://docs.dify.ai/v/zh-hans/guides/workflow/node/variable-assigner
[4] Reagir Site em chinês do Flow: https://reactflow-cn.js.org/
[5] Site em inglês do React Flow: https://reactflow.dev/
[6] Implementação do processo das operações de criação, atualização, execução e exclusão do Chatflow: https://z0yrmerhgi8.feishu.cn/wiki/FFzxwdF4PijlhjkLUoecOv6Vn8a