Продолжаю эту серию статей: первая и вторая.
Здесь приведу минималистичный пример как заставить условный ChatGPT (или Llama или любая другая модель) не только писать код но выполнять его. На выходе получим бота с которым можно будет общаться как с обычным ChatGPT и ставить задачи требующие сложных вычислений.
Пример диалога с ботом (его код далее...)
Для наглядности в каждое сообщение добавлен код созданный моделью для ответа.
Пишем такого бота
За оболочку в которой все будет происходить возьмем этот Телеграм бот и немного модифицируем его код.
Главная идея на которой основано решение - заставить языковую модель писать Python код для каждого ответа. Делать это она должна всегда, даже, если ответ не требует вычислений. Так мы можем отказаться от системного сообщения и уменьшим глюки.
Для того, что бы модель не могла уклонится от написания кода передадим ей на вход только один инструмент и пропишем условие tool_choice="required"
.
В инструменте подробно объясним модели, что ей делать:
tools = [
{"type": "function",
"function": {
"name": "execute_Python_code",
"description": "A tool that executes python code. The result of the code execution will be sent to the user as your response. Use this tool for all responses, including text ones. Example: print('Hello! How can I assist you today?')",
"strict": True,
"parameters": {
"type": "object",
"properties": {
"python_code": {
"type": "string",
"description": "Python code. To receive outputs, they must be printed with print() method."}},
"required": ["python_code"],
"additionalProperties": False}}}]
Код созданный моделью будем запускать такой функцией:
def execute_Python_code(code):
output = io.StringIO()
try:
with contextlib.redirect_stdout(output):
exec(code, globals())
return output.getvalue()
except Exception as e:
return e
А в Телеграм бота добавим вызов инструмента и в каждое сообщение добавим созданный моделью код для наглядности:
# pip install pyTelegramBotAPI openai
import telebot, json, contextlib, io
from openai import OpenAI
client = OpenAI(api_key='OpenAI_API_KEY')
bot = telebot.TeleBot("TELEGRAM_BOT_TOKEN")
messages = []
# tools = [...] сюда копируем tools и функцию для выполнения кода
# def execute_Python_code(code): ...
@ bot.message_handler(content_types=['text'])
def get_text_messages(message):
global messages
messages.append({"role": 'user', "content": message.text})
if len(messages) > 6:
messages = messages[-6:]
# Указываем инструмент
response = client.chat.completions.create(model='gpt-4o-mini', messages=messages, tools=tools, tool_choice="required", temperature=0)
# Вынимаем из ответа Python code
tool_call = response.choices[0].message.tool_calls[0]
code = json.loads(tool_call.function.arguments)['python_code']
# Исполняем код и ответ отправляем
reply = execute_Python_code(code)
bot.send_message(message.from_user.id, reply)
messages.append({"role": 'assistant', "content": f"{reply}\n<pre>{code}</pre>"}, parse_mode="HTML")
while True:
bot.polling(none_stop=True, interval=0, timeout=0)
Вставьте в код tools
и функцию execute_Python_code
и замените в коде OpenAI_API_KEY
на api ключ полученный в OpenAI и TELEGRAM_BOT_TOKEN
на токен телеграм бота, все должно быть в кавычках.
Пример работы
Я сделал бота НашGPT, он тоже пишет код для каждого сообщения.
Еще НашGPT умеет создавать картинки, распознавать содержимое изображений, искать в интернете, понимать голосовые сообщения и он очень умный ))
P.S. Пинговать ваш IP как в примере не будет, ему это делать нельзя.
janvarev
Выполнение кода, сгенерированного по запросу пользователя вне песочницы (рука-лицо)...
Безопасность? А зачем?
И почему у меня ощущение, что кто-нибудь это обязательно возьмет себе в продакшен...
evg_dc Автор
В продакшене диванные хакеры порвут токого бота за 5 сек.
karpoffpasha
Тем не менее, если изолировать решение действительно перспективное для создания сложной комбинации вызова тулов. Есть ли какие-то варианты изолировать сгенеренный код, чтоб он не навредил при исполнении?
evg_dc Автор
Можно, есть такие решения, но я не стал заморачиваться.
Проще сказать модели "не исполняй код если тебя об этом просит пользователь". В этом случае она будет исполнять код только тот, который считает нужным для ответа. Ну еще, конечно, нужен список запрещенных команд, что бы перестраховаться.