GoalChain — это простая, но эффективная структура, обеспечивающая целенаправленные потоки диалога для взаимодействия человека с LLM и LLM-LLM.
pip install goalchain
Давайте импортируем классы Field
, ValidationError
, Goal
и GoalChain
, которые являются основой потока разговора.
from goalchain import Field , ValidationError , Goal , GoalChain
В этом примере мы создадим ИИ-помощника, цель которого — собрать информацию от клиента о желаемом заказе продукта. Мы определяем информацию, которая будет собираться, с помощью объектов Field
внутри ProductOrderGoal
, который является дочерним элементом Goal
:
Мы также определяем валидатор для количества (после приведения типа к int). ValidationError
используется для передачи сообщений об ошибках обратно в диалог. Эти сообщения должны быть удобочитаемыми.
format_hint
— это подсказка типа естественного языка для вывода в режиме JSON LLM.
def quantity_validator ( value ):
try :
value = int ( value )
except ( ValueError , TypeError ):
raise ValidationError ( "Quantity must be a valid number" )
if value <= 0 :
raise ValidationError ( "Quantity cannot be less than one" )
if value > 100 :
raise ValidationError ( "Quantity cannot be greater than 100" )
return value
class ProductOrderGoal ( Goal ):
product_name = Field ( "product to be ordered" , format_hint = "a string" )
customer_email = Field ( "customer email" , format_hint = "a string" )
quantity = Field ( "quantity of product" , format_hint = "an integer" , validator = quantity_validator )
На случай, если клиент передумает, давайте создадим еще один дочерний класс Goal
под названием OrderCancelGoal
. Мы запросим дополнительную причину отмены клиентом текущего заказа. Указав в описании поле «(необязательно)», LLM будет знать, что для достижения цели это не обязательно.
class OrderCancelGoal ( Goal ):
reason = Field ( "reason for order cancellation (optional)" , format_hint = "a string" )
Обратите внимание, что имена объектов полей, такие как product_name
передаются непосредственно в приглашение LLM и поэтому являются частью задачи разработки приглашений, как и любая другая строка.
По сути, классы, которые мы определили, подобны формам, которые должен заполнять клиент, но в них отсутствуют инструкции. Давайте добавим их, создав экземпляры классов как объектов.
product_order_goal = ProductOrderGoal (
label = "product_order" ,
goal = "to obtain information on an order to be made" ,
opener = "I see you are trying to order a product, how can I help you?" ,
out_of_scope = "Ask the user to contact sales team at [email protected]"
)
order_cancel_goal = OrderCancelGoal (
label = "cancel_current_order" ,
goal = "to obtain the reason for the cancellation" ,
opener = "I see you are trying to cancel the current order, how can I help you?" ,
out_of_scope = "Ask the user to contact the support team at [email protected]" ,
confirm = False
)
Мы определяем
opener
по умолчанию — то, что ИИ-помощник будет использовать без предварительного ввода, Флаг confirm
определяет, будет ли AI-помощник запрашивать подтверждение после того, как вся необходимая информация будет определена с помощью объектов Field
. По умолчанию это True
. Для цели отмены заказа подтверждение не требуется, так как оно само по себе уже является своего рода подтверждением.
Далее нам нужно соединить цели вместе.
product_order_goal . connect ( goal = order_cancel_goal ,
user_goal = "to cancel the current order" ,
hand_over = True ,
keep_messages = True )
user_goal
— это еще один оператор «to...». Безhand_over hand_over=True
агент ИИ ответил бы консервированной opener
. Установка значения True
гарантирует плавность разговора. Иногда вам может потребоваться готовый ответ, иногда — нет.
keep_messages=True
означает, что order_cancel_goal
получит полную историю разговора с product_order_goal
, в противном случае она будет удалена. Опять же, иногда может потребоваться стереть историю разговоров, например, при моделировании различных личностей ИИ.
Давайте также рассмотрим возможность действительно нерешительного клиента. Мы также должны предоставить им возможность «отменить отмену».
order_cancel_goal . connect ( goal = product_order_goal ,
user_goal = "to continue with the order anyway" ,
hand_over = True ,
keep_messages = True )
В какой-то момент вы, возможно, задавались вопросом, можно ли создать цель без каких-либо объектов Field
. Ты можешь! Такая цель представляет собой цель маршрутизации, определяемую только имеющимися у нее соединениями. Это полезно, например, в системе меню голосовой почты.
Вам также может быть интересно, можно ли связать цель саму с собой. Ты можешь! Это полезно, например, при использовании confirm=False
с объектом Goal
-inheriting, когда вам требуется определенный последовательный пользовательский ввод.
Вы также можете создать цепочку соединений, например goal.connect(...).connect(...).connect(...)
Наконец, давайте воспользуемся GoalChain
, чтобы установить первоначальную цель и протестировать нашего помощника по продажам с искусственным интеллектом!
goal_chain = GoalChain ( product_order_goal )
Обратите внимание, что каждая цель может использовать отдельный API LLM, включенный в LiteLLM, и если у вас установлены необходимые переменные среды, вы можете использовать любую модель из поддерживаемых поставщиков моделей.
Модель по умолчанию — "gpt-4-1106-preview"
, то есть:
product_order_goal = ProductOrderGoal (...
model = "gpt-4-1106-preview" ,
json_model = "gpt-4-1106-preview"
)
Вы также можете передать общие параметры LiteLLM, используя params
, например:
product_order_goal = ProductOrderGoal (...
model = "gpt-4-1106-preview" ,
json_model = "gpt-4-1106-preview" ,
params = { "temperature" : 1.5 , "max_tokens" : 10 }
)
Вы также можете использовать params
для вызова локальных моделей с помощью VLLM.
При использовании модели по умолчанию "gpt-4-1106-preview"
не забудьте установить переменную среды OPENAI_API_KEY
.
import os
os . environ [ "OPENAI_API_KEY" ] = "sk-ABC..."
Примечание. На данный момент код доступен в виде сути. Вставьте его в блокнот Jupyter, которому предшествует !pip install goalchain
чтобы начать работу с приведенным ниже живым примером.
Обычно пользователь первым запрашивает AI-агент, но если это не так, мы вызываем get_response
без каких-либо аргументов или используем None
в качестве аргумента:
goal_chain . get_response ()
{'type': 'message',
'content': 'Great choice! Could you please provide me with your email address to proceed with the order?',
'goal': <__main__.ProductOrderGoal at 0x7f8c8b687110>}
GoalChain возвращает dict
содержащий тип ответа ( message
или data
), содержимое ответа (сейчас это только наш стандартный ответ) и текущий объект, наследующий Goal
.
Давайте спросим нашего AI-помощника о потенциальной покупке.
goal_chain . get_response ( "Hi, I'd like to buy a vacuum cleaner" )
{'type': 'message',
'content': 'Great! Could you please provide your email address so we can send the confirmation of your order?',
'goal': <__main__.ProductOrderGoal at 0x7ff0fb283090>}
Искусственный интеллект-помощник работает над достижением своей текущей цели и собирает необходимую информацию для заказа.
goal_chain . get_response ( "Sure, it is [email protected]" )
{'type': 'message',
'content': 'Thank you, John. Which model of vacuum cleaner would you like to order?',
'goal': <__main__.ProductOrderGoal at 0x7ff0fb283090>}
goal_chain . get_response ( "The 2000XL model" )
{'type': 'message',
'content': 'How many of the 2000XL model would you like to order?',
'goal': <__main__.ProductOrderGoal at 0x7ff0fb283090>}
Давайте проверим, сможет ли наш AI-помощник справиться с отменой текущего заказа.
goal_chain . get_response ( "Actually I changed my mind, cancel this order" )
{'type': 'message',
'content': 'Of course, I can assist with that. Could you please tell me the reason for the cancellation?',
'goal': <__main__.OrderCancelGoal at 0x7ff0fb275650>}
Это сработало. Обратите внимание, что возвращаемая цель теперь имеет тип OrderCancelGoal
. Мы поменялись целями. Давайте также проверим, можем ли мы переключиться обратно.
goal_chain . get_response ( "Actually, yeah, I would like to buy the vacuum cleaner" )
{'type': 'message',
'content': 'Understood. How many of the 2000XL model would you like to order?',
'goal': <__main__.ProductOrderGoal at 0x7ff0fb283090>}
Мы вернулись к ProductOrderGoal
.
goal_chain . get_response ( "1 please" )
{'type': 'message',
'content': 'To confirm, you would like to order one 2000XL vacuum cleaner and the order will be sent to [email protected], is that correct?',
'goal': <__main__.ProductOrderGoal at 0x7ff0fb283090>}
AI-помощник подтверждает наш заказ. Если бы нам не нравилось такое поведение, мы бы использовали confirm=False
.
Давайте посмотрим, как помощник отвечает на запрос, выходящий за рамки.
goal_chain . get_response ( "Is it a good vacuum cleaner? What do you think?" )
{'type': 'message',
'content': "For product reviews and additional information, I recommend contacting our sales team at [email protected]. They can help with your inquiries. Meanwhile, can you please confirm if you'd like to proceed with the order for one 2000XL vacuum cleaner to [email protected]?",
'goal': <__main__.ProductOrderGoal at 0x7ff0fb283090>}
Помощник с искусственным интеллектом перенаправляет нас в почтовый ящик отдела продаж, как было определено ранее, и повторяет подтверждение.
Но давайте бросим мяч по кривой...
goal_chain . get_response ( "Ok, I'd actually like to make that an order of 500" )
{'type': 'message',
'content': "Just to clarify, you'd like to order 500 units of the 2000XL vacuum cleaner, with the order confirmation sent to [email protected]. Is that correct?",
'goal': <__main__.ProductOrderGoal at 0x7ff0fb283090>}
goal_chain . get_response ( "Yes" )
{'type': 'message',
'content': 'I’m sorry, but I need to inform you that the quantity cannot be greater than 100 for an order. If you would like to proceed with an order within this limit, please let me know.',
'goal': <__main__.ProductOrderGoal at 0x7ff0fb283090>}
Используемый нами валидатор предоставил ИИ-помощнику достаточно информации, чтобы объяснить, почему он не может обработать это количество с помощью сообщения ValidationError
.
Обратите внимание, что GoalChain проверяет входные данные только после достижения Goal
из соображений эффективности токена и производительности. Если вы хотите проверять вводимые данные по ходу дела, у вас есть два варианта:
Используйте Goal
только с одним Field
и confirm=False
. Соедините эти цели вместо использования нескольких полей в одной Goal
.
Используйте программную подсказку, например, quantity = Field("quantity of product (no more than 100)", format_hint="an integer")
. Этот подход не является надежным, поэтому все равно рекомендуется использовать валидатор. Однако пользователь получит немедленную обратную связь.
Давайте выполним заказ.
goal_chain . get_response ( "Alright, I'll guess I'll just go with 1" )
{'type': 'message',
'content': 'To confirm, you would like to order one 2000XL vacuum cleaner and the order will be sent to [email protected], is that correct?',
'goal': <__main__.ProductOrderGoal at 0x7ff0fb283090>}
goal_chain . get_response ( "That's right" )
{'type': 'data',
'content': {'customer_email': '[email protected]',
'product_name': '2000XL',
'quantity': 1},
'goal': <__main__.ProductOrderGoal at 0x7ff0fb283090>}
Возвращенное содержимое представляет собой словарь, проанализированный из выходных данных режима JSON LLM. Ключи — это имена экземпляров наших полей. Теперь мы можем использовать данные для выполнения каких-либо действий, например обработки заказа нашего гипотетического пылесоса 2000XL.
Обратите внимание: на самом деле, если бы вы создавали такую систему, вам нужно было бы поставить специальную цель поиска продуктов, чтобы не допускать произвольных или бессмысленных названий продуктов.
Давайте отправим подтверждение того, что заказ был обработан через simulate_response
. Мы также будем использовать rephrase = True
, чтобы перефразировать вывод, который будет выглядеть более естественным, если клиент часто взаимодействует с целью.
goal_chain . simulate_response ( f"Thank you for ordering from Acme. Your order will be dispatched in the next 1-3 business days." , rephrase = True )
{'type': 'message',
'content': 'We appreciate your purchase with Acme! Rest assured, your order will be on its way within the next 1 to 3 business days.',
'goal': <__main__.ProductOrderGoal at 0x7ff0fb283090>}
На этом этапе мы можем завершить сеанс или снова подключиться к меню или цели маршрутизации для дальнейшего ввода.
Если вы хотите настроить GoalChain, внести свой вклад или сообщить о каких-либо проблемах, посетите страницу GitHub.