Maison  >  Article  >  développement back-end  >  Création d'une bibliothèque de machines d'état avec l'aide d'outils d'IA

Création d'une bibliothèque de machines d'état avec l'aide d'outils d'IA

Barbara Streisand
Barbara Streisandoriginal
2024-11-27 13:02:11157parcourir

Par ennui, en attendant mes séances d'entretiens de suivi, j'ai construit une bibliothèque de machines à états, alimentée par genruler. J'en ai construit un dans le passé, pour être exact, lors de mon premier emploi après l'obtention de mon diplôme. Cette implémentation est vaguement basée sur la conception rédigée par mon superviseur à l'époque. Le projet visait également à montrer comment la règle DSL peut être utilisée.

D'après le résumé utile renvoyé par une recherche Google sur la machine à états finis (c'est moi qui souligne)

Une « machine à états finis » désigne un modèle informatique dans lequel un système ne peut être que dans un nombre limité d'états distincts à un moment donné, et les transitions entre ces états sont déclenchées par des entrées spécifiques, permettant essentiellement il traite des informations sur la base d'un ensemble de conditions définies sans possibilité d'avoir un nombre infini d'états ; « fini » fait ici référence à l'ensemble limité d'états possibles dans lesquels le système peut exister.

La bibliothèque reçoit un dictionnaire qui représente le schéma de la machine à états finis. Par exemple, nous souhaitons construire un système de suivi des commandes

Building state machine library with help from AI tools
Diagramme de machine à états finis généré par Graphviz

Et le schéma ressemblerait à ceci (sous forme YAML tronquée pour plus de clarté)

machine:
  initial_state: pending_payment

states:
  pending_payment:
    name: pending payment
    transitions:
      order_authorization:
        name: order is authorized
        destination: authorized
        rule: (condition.equal (basic.field "is_authorized") (boolean.tautology))

  authorized:
    name: authorized
    action: authorize_order
    transitions:
      order_partially_paid:
        name: order is partially paid
        destination: partially_paid
        rule: (boolean.tautology)
      order_fully_paid:
        name: order is fully paid
        destination: paid
        rule: (boolean.tautology)

    ...

Par conséquent, pour tout mettre en place, nous appelons

import genstates
import yaml
import order_processor

with open("states.yaml") as schema:
  machine = genstates.Machine(yaml.safe_load(schema), order_processor)

Donc, dans cet exemple fictif, nous recevrons une charge utile chaque fois qu'il y aura un changement dans la commande. Par exemple, lorsque le vendeur accuse réception de la commande, nous obtenons

{
  "is_authorized": true,
  ...
}

On pourra alors vérifier dans la bibliothèque

state = machine.initial # assume the order is created

transition = machine.get_transition(state, "order_authorization")

assert transition.check_condition(payload)

Le contrôle exécute également un contrôle de validation supplémentaire s'il est défini dans le schéma. Ceci est utile si vous avez l'intention de renvoyer un message d'erreur à l'appelant.

try:
  assert transition.check_condition(payload)
except ValidationFailedError as e:
  logger.exception(e)

Parfois, on sait qu’à chaque fois que la charge utile arrive, elle doit déclencher une transition, mais on ne sait pas toujours laquelle. Par conséquent, nous le transmettons simplement dans Machine.progress

try:
  state = machine.progress(state, payload)
except ValidationFailedError as e:
  logger.exception(e)

Une fois que nous savons dans quel état la commande doit progresser, nous pouvons commencer à écrire du code pour travailler sur la logique

# fetch the order from database
order = Order.get(id=payload["order_id"])
current_state = machine.states[order.state]

# fetch next state
try:
    new_state = machine.progress(current_state, payload)
except ValidationFailedError as e:
    # validation failed, do something
    logger.exception(e)
    return
except MissingTransitionError as e:
    # can't find a valid transition from given payload
    logger.exception(e)
    return
except DuplicateTransitionError as e:
    # found more than one transition from given payload
    logger.exception(e)
    return

# do processing (example)
log = Log.create(order=order, **payload)
log.save()

order.state = new_state.key
order.save()

Idéalement, je peux également extraire la logique de traitement, c'est la raison pour laquelle j'ai importé order_processor au début. Dans la définition de l'état d'autorisation, nous avons également défini une action

authorized:
    name: authorized
    action: authorize_order
    ...

Donc dans le module order_processor, on définit une nouvelle fonction appelée approved_order

def authorize_order(payload):
    # do the processing here instead
    pass

De telle sorte que ce qui suit est possible, où le code de gestion de l'état est séparé du reste de la logique de traitement

machine:
  initial_state: pending_payment

states:
  pending_payment:
    name: pending payment
    transitions:
      order_authorization:
        name: order is authorized
        destination: authorized
        rule: (condition.equal (basic.field "is_authorized") (boolean.tautology))

  authorized:
    name: authorized
    action: authorize_order
    transitions:
      order_partially_paid:
        name: order is partially paid
        destination: partially_paid
        rule: (boolean.tautology)
      order_fully_paid:
        name: order is fully paid
        destination: paid
        rule: (boolean.tautology)

    ...

Cependant, je travaille toujours dessus et je devrais le faire dans la prochaine version. Parallèlement, il est également capable de faire quelque chose de similaire, comme cartographier et réduire si chaque État a défini une action. N'hésitez pas à vérifier le projet pour connaître l'avancement du développement. Et Genruler et Genstates sont désormais disponibles sur PyPI, ouais !

Et maintenant, qu’en est-il de l’IA ?

J'ai téléchargé Codeium Windsurf après que la bibliothèque soit quelque peu utilisable. Je l'ai finalement utilisé pour supprimer ma dépendance de Genruler et j'ai ajouté de la documentation et un fichier README au projet. Pour les états générateurs, j'ai utilisé cascade pour générer de la documentation, du README, ainsi que des tests. Dans l'ensemble, j'ai l'impression d'avoir un programmeur intermédiaire à senior pour m'aider dans les tâches que j'attribuerais à mes stagiaires ou même à mes juniors.

La majeure partie de la logique de base vient toujours de mon côté, aussi intelligent que soit le modèle de langage pour le moment, ils font toujours des erreurs ici et là et nécessitent donc une supervision. J'ai également expérimenté le modèle qwen2.5-coder:7b, et cela fonctionne plutôt bien, bien qu'assez lent à cause de mon poste de travail de mauvaise qualité. Je trouve que le prix demandé par Codeium est juste, si je veux créer mon propre produit et que je parviens à en tirer profit.

Bien que les parties de génération fonctionnent bien, l'écriture du code réel n'est pas aussi géniale. Je ne sais pas si Pylance fonctionne correctement là-bas, considéré comme propriétaire, ou si cela est dû à l'achèvement de Magic Windsurf, mon éditeur n'est plus en mesure d'importer automatiquement les bibliothèques lorsque j'écris du code. Par exemple, lorsque je complète automatiquement la fonction réduire() dans mon code, dans vscode, elle s'insérerait automatiquement depuis functools import réduire dans mon code. Cependant, ce n’est pas le cas en planche à voile, ce qui la rend un peu irritante. Cependant, étant donné qu'il s'agit d'une nouveauté, l'expérience de codage devrait être corrigée au fil du temps.

Par contre, je suis toujours à la recherche d'un éditeur plus léger, et zed attire mon attention. Cependant, depuis que mon Surface Book 2 est mort récemment, il ne me reste qu'un Samsung Galaxy Tab S7FE lorsque je suis loin de mon bureau à domicile. Par conséquent, vscode avec une interface Web (et il est étonnamment utilisable) connecté à mon poste de travail est toujours mon éditeur principal (il fonctionne même avec l'extension neovim).

L’IA générative propulsée par LLM change rapidement nos vies, il ne sert à rien d’y résister. Cependant, à mon humble avis, nous devrions également faire preuve d’une certaine retenue pour ne pas l’utiliser pour tout. Il devrait vraiment être utilisé comme complément au travail innovant ou créatif, et non comme substitut à l’innovation et à la créativité.

Nous devrions également savoir ce qu'il produit, au lieu d'accepter aveuglément ce qu'il fait. Par exemple, dans Genruler, je l'ai fait améliorer mon README original avec des exemples plus complets. Au lieu de l'accepter tel quel, je l'ai fait générer des tests pour tous les exemples qu'il génère dans le README, afin que l'exemple de code passe et fonctionne comme je le souhaitais.

Dans l'ensemble, oui, je pense que ces éditeurs améliorés par l'IA générative valent l'argent qu'ils demandent. En fin de compte, ce sont des outils, ils sont destinés à offrir une aide au travail, et non à remplacer la personne qui frappe le clavier.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn