Un cadre multi-agent dynamique simple basé sur des agents atomiques et un instructeur. Utilise la puissance de Pydantic pour la validation et la sérialisation des données et des schémas.
composer des agents constitués d'une invite système, avec un langage partagé soit d'appels de fonction , soit de mutations GraphQL
un routeur utilise un LLM pour traiter les invites utilisateur « composites » complexes et les acheminer automatiquement vers la meilleure séquence de vos agents
générer via OpenAI ou AWS Bedrock ou groq
attention : le !! framework is at an early stage !!
- les changements majeurs seront indiqués en augmentant la version mineure (la majeure est toujours à zéro).
Un framework d'agents basé sur LLM utilisant une approche de programmation orientée agent pour orchestrer les agents à l'aide d'un langage partagé.
Le langage de l'agent peut être soit basé sur Function Calling , soit basé sur GraphQL .
Le cadre est générique et permet de définir les agents en termes de nom, de description, d'appels d'entrée acceptés et d'appels de sortie autorisés.
Les agents communiquent indirectement à l'aide d'un tableau noir. Le langage est composé d'appels (fonction ou mutation GraphQL) : chaque agent précise ce qu'il comprend comme entrée, et quels appels il est capable de générer. De cette façon, les agents peuvent comprendre les résultats de chacun.
Un routeur prend l'invite de l'utilisateur et génère un plan d'exécution d'agent.
Le plan d'exécution utilise la meilleure séquence d'agents les plus appropriés pour gérer l'invite utilisateur.
Le routeur réécrit l'invite utilisateur en fonction de chaque agent, ce qui améliore la qualité et évite les sorties indésirables.
Remarque : En option, le routeur peut être exécuté séparément, ce qui permet un retour humain sur le plan d'exécution généré par le routeur. De cette manière, l’utilisateur peut collaborer davantage avec le routeur, avant que les agents générateurs ne soient réellement exécutés.
Enfin, la sortie est renvoyée sous la forme d'une liste ordonnée d'appels (Fonction ou GraphQL).
Pour en savoir plus sur cette approche, vous pouvez consulter cet article Medium.
framework is at an early stage
. L’évaluateur n’est pas actuellement implémenté. Lors de l'intégration, selon le type de définitions d'agent utilisé, le client doit :
Il s'agit d'une démo de création de monde "Sim Life". Il utilise 3 agents (Creature Creature, Vegetation Creator, Relationship Creator) pour traiter les invites des utilisateurs. Les agents sont définis en termes de fonctions. Le résultat est une série d’appels de fonction qui peuvent être implémentés par le client pour construire le monde Sim Life.
La fonction AddCreature :
function_add_creature = FunctionSpecSchema (
agent_name = creature_agent_name ,
function_name = "AddCreature" ,
description = "Adds a new creature to the world (not vegetation)" ,
parameters = [
ParameterSpec ( name = "creature_name" , type = ParameterType . string ),
ParameterSpec ( name = "allowed_terrain" , type = ParameterType . string , allowed_values = terrain_types ),
ParameterSpec ( name = "age" , type = ParameterType . int ),
ParameterSpec ( name = "icon_name" , type = ParameterType . string , allowed_values = creature_icons ),
]
)
La fonction AddCreatureRelationship :
function_add_relationship = FunctionSpecSchema (
agent_name = relationship_agent_name ,
function_name = "AddCreatureRelationship" ,
description = "Adds a new relationship between two creatures" ,
parameters = [
ParameterSpec (
name = "from_name" , type = ParameterType . string
),
ParameterSpec (
name = "to_name" , type = ParameterType . string
),
ParameterSpec (
name = "relationship_name" ,
type = ParameterType . string ,
allowed_values = [ "eats" , "buys" , "feeds" , "sells" ],
),
],
)
L'agent Creature Creator est défini de manière déclarative en termes de :
Les agents peuvent collaborer et échanger des informations indirectement, en réutilisant les mêmes définitions de fonctions via un tableau noir.
def build_creature_agent ():
agent_definition = FunctionAgentDefinition (
agent_name = "Creature Creator" ,
description = "Creates new creatures given the user prompt. Ensures that ALL creatures mentioned by the user are created." ,
accepted_functions = [ function_add_creature , function_add_relationship ],
input_schema = FunctionAgentInputSchema ,
initial_input = FunctionAgentInputSchema (
functions_allowed_to_generate = [ function_add_creature ],
previously_generated_functions = []
),
output_schema = FunctionAgentOutputSchema ,
topics = [ "creature" ]
)
return agent_definition
Remarques sur l'agent Creature Creator :
function_add_relationship
. Voir l'exemple de code source pour plus de détails. Il s'agit d'une démo de création de monde "Sim Life". Il utilise 3 agents (Creature Creature, Vegetation Creator, Relationship Creator) pour traiter les invites des utilisateurs. Les agents sont définis de manière déclarative en termes de schéma d'entrée GraphQL et autorisent les mutations générées. Le résultat est une série de mutations GraphQL qui peuvent être exécutées par le client pour construire le monde Sim Life.
Le schéma GraphQL :
type Creature {
id : ID !
creature_name : String !
allowed_terrain : TerrainType !
age : Int !
icon_name : IconType !
}
type Vegetation {
id : ID !
vegetation_name : String !
icon_name : IconType !
allowed_terrain : TerrainType !
}
type Relationship {
id : ID !
from_name : String !
to_name : String !
relationship_kind : RelationshipType !
}
...
Les mutations GraphQL que nous souhaitons que les agents génèrent sont distinctes pour chaque agent :
Agent créateur de créature :
type Mutation {
addCreature ( input : CreatureInput ! ): Creature !
}
input CreatureInput {
creature_name : String !
allowed_terrain : TerrainType !
age : Int !
icon_name : IconType !
}
Agent créateur de végétation :
type Mutation {
addVegetation ( input : VegetationInput ! ): Vegetation !
}
input VegetationInput {
vegetation_name : String !
icon_name : IconType !
allowed_terrain : TerrainType !
}
L'agent Creature Creator est défini de manière déclarative en termes de :
Un agent est essentiellement une composition de schémas d’entrée et de sortie, accompagnée d’une invite.
Les agents collaborent et échangent des informations indirectement via un tableau noir, en réutilisant les mêmes schémas GraphQL et appels de mutation.
creatures_graphql = _read_schema ( "creature.graphql" )
creature_mutations_graphql = _read_schema ( "creature.mutations.graphql" )
def build_creature_agent ():
agent_definition = GraphQLAgentDefinition (
agent_name = "Creature Creator" ,
description = "Creates new creatures given the user prompt. Ensures that ALL creatures mentioned by the user are created." ,
accepted_graphql_schemas = [ creatures_graphql , creature_mutations_graphql ],
input_schema = GraphQLAgentInputSchema ,
initial_input = GraphQLAgentInputSchema (
mutations_allowed_to_generate = [ creature_mutations_graphql ],
previously_generated_mutations = []
),
output_schema = GraphQLAgentOutputSchema ,
topics = [ "creature" ]
)
return agent_definition
Notes sur cet agent :
creature_mutations_graphql
à partir du fichier "creature.mutations.graphql".creature_mutations_graphql
).creatures_graphql
à partir du fichier « creature.graphql ».Les agents peuvent être utilisés ensemble pour former un chatbot :
from gpt_multi_atomic_agents import functions_expert_service , config
from . import agents
def run_chat_loop ( given_user_prompt : str | None = None ) -> list :
CHAT_AGENT_DESCRIPTION = "Handles users questions about an ecosystem game like Sim Life"
agent_definitions = [
build_creature_agent (), build_relationship_agent (), build_vegatation_agent () # for more capabilities, add more agents here
]
_config = config . Config (
ai_platform = config . AI_PLATFORM_Enum . bedrock_anthropic ,
model = config . ANTHROPIC_MODEL ,
max_tokens = config . ANTHROPIC_MAX_TOKENS ,
is_debug = False
)
return functions_expert_service . run_chat_loop ( agent_definitions = agent_definitions , chat_agent_description = CHAT_AGENT_DESCRIPTION , _config = _config , given_user_prompt = given_user_prompt )
remarque : si
given_user_prompt
n'est pas défini, alorsrun_chat_loop()
attendra la saisie de l'utilisateur depuis le clavier
Voir l'exemple de code source pour plus de détails.
ENTRÉE UTILISATEUR :
Add a sheep that eats grass
SORTIR:
Generated 3 function calls
[Agent: Creature Creator] AddCreature( creature_name=sheep, icon_name=sheep-icon, land_type=prairie, age=1 )
[Agent: Plant Creator] AddPlant( plant_name=grass, icon_name=grass-icon, land_type=prairie )
[Agent: Relationship Creator] AddCreatureRelationship( from_name=sheep, to_name=grass, relationship_name=eats )
Étant donné que le framework dispose d'un routeur dynamique, il peut gérer des invites « composites » plus complexes, telles que :
Ajoutez une vache qui mange de l'herbe. Ajoutez un humain – la vache nourrit l’humain. Ajoutez un extraterrestre qui mange l'humain. L'humain mange aussi des vaches.
Le routeur détermine quels agents utiliser, dans quel ordre les exécuter et quelle invite envoyer à chaque agent.
En option, le routeur peut être réexécuté avec les commentaires de l'utilisateur sur son plan généré, avant d'exécuter réellement les agents.
Les agents recommandés sont ensuite exécutés dans l'ordre, en accumulant leurs résultats dans le tableau partagé.
Enfin, le framework combine les appels résultants et les renvoie au client.
ENTRÉE UTILISATEUR :
Add a sheep that eats grass
SORTIR:
['mutation {n addCreature(input: {n creature_name: "sheep",n allowed_terrain: GRASSLAND,n age: 2,n icon_name: SHEEPn }) {n creature_namen allowed_terrainn agen icon_namen }n }']
['mutation {', ' addVegetation(input: {', ' vegetation_name: "Grass",', ' icon_name: GRASS,', ' allowed_terrain: LAND', ' }) {', ' vegetation_name', ' icon_name', ' allowed_terrain', ' }', '}']
['mutation {', ' addCreatureRelationship(input: {', ' from_name: "Sheep",', ' to_name: "Grass",', ' relationship_kind: EATS', ' }) {', ' id', ' }', '}']
Installez Python 3.11 et la poésie
Installez les dépendances.
poetry install
Pour OpenAI :
export OPENAI_API_KEY="xxx"
Ajoutez cela à votre script d'initialisation de shell ( ~/.zprofile
ou similaire)
Charge dans le terminal actuel :
source ~/.zprofile
Script de test :
./test.sh
Voir l'exemple de code source pour plus de détails.