Buckets:

|
download
raw
21.4 kB
# Что такое Инструменты?
Одним из важнейших аспектов AI Агентов является их способность предпринимать **действия**. Как мы видели, это происходит благодаря использованию **Инструментов**.
В этом разделе мы узнаем, что такое Инструменты, как их эффективно разработать и как интегрировать их в вашего Агента с помощью Системного Сообщения.
Предоставив своему агенту правильные инструменты и четко описав, как они работают, вы сможете значительно расширить возможности своего AI. Давайте погружаться!
## Что такое AI Инструменты?
** Инструмент - это функция, предоставленная LLM**. Эта функция должна выполнять **четкую цель**.
Вот некоторые часто используемые в AI агентах инструменты:
| Инструмент | Описание |
|----------------|---------------------------------------------------------------|
| Веб-поиск | Позволяет агенту получать актуальную информацию из Интернета. |
| Генерация изображений | Создает изображения на основе текстовых описаний. |
| Извлечение | Извлекает информацию из внешнего источника. |
| | Интерфейс API | Взаимодействие с внешним API (GitHub, YouTube, Spotify и т. д.). |
Это лишь примеры, поскольку на самом деле вы можете создать инструмент для любого случая использования!
Хороший инструмент должен быть чем-то, что **дополняет возможности LLM**.
Например, если вам нужно выполнить арифметические действия, то предоставление вашему LLM **калькулятора** обеспечит лучшие результаты, чем полагаться на собственные возможности модели.
Кроме того, **LLM предсказывают завершение подсказки на основе своих обучающих данных**, что означает, что их внутренние знания включают только события, произошедшие до их обучения. Поэтому, если вашему агенту нужны свежие данные, вы должны предоставить их с помощью какого-либо инструмента.
Например, если вы спросите у LLM напрямую (без инструмента поиска) о сегодняшней погоде, LLM потенциально может выдать случайную погоду в виде галлюцинаций.
- Инструмент должен:
- **иметь текстовое описание того, что делает функция**.
- *быть Вызываемым (Callable)* (чем-то, что выполняет действие).
- *иметь Аргументы* с типизацией.
- (Необязательно) иметь Выходные данные с типизацией.
## Как работают инструменты?
Как мы видели, **LLM могут только получать текстовые данные на вход и генерировать текстовые данные на выход. У них нет возможности самостоятельно вызывать инструменты. Когда мы говорим о _предоставлении инструментов агенту_, мы имеем в виду, что мы **обучаем** LLM существованию инструментов и просим модель генерировать текст, который будет вызывать инструменты, когда это необходимо. Например, если мы предоставим инструмент для проверки погоды в определенном месте из Интернета, а затем спросим LLM о погоде в Париже, LLM распознает этот вопрос как релевантную возможность использовать инструмент "weather", которой мы его научили. LLM сгенерирует _текст_ в виде кода, чтобы вызвать этот инструмент. Ответственность **Агента** заключается в том, чтобы проанализировать вывод LLM, распознать, что требуется вызов инструмента, и вызвать его от имени LLM. Выходные данные от инструмента будут отправлены обратно в LLM, которая составит окончательный ответ для пользователя.
Выходные данные после вызова инструмента - это еще один тип сообщений в диалоге. Шаги вызова инструмента обычно не демонстрируются пользователю: агент извлекает диалог, вызывает инструмент(ы), получает выходные данные, добавляет их в новое сообщение диалога и снова отправляет обновленный диалог в LLM. С точки зрения пользователя это выглядит так, как будто LLM использовал инструмент, но на самом деле это сделал наш код приложения (**Агент**).
Мы поговорим об этом процессе подробнее на следующих занятиях.
## Как мы даем инструменты LLM?
Полный ответ может показаться непомерно сложным, но мы, по сути, используем системную подсказку для предоставления текстовых описаний доступных модели инструментов:
Чтобы это сработало, мы должны быть очень точны и аккуратны в отношении:
1. **Что делает инструмент**.
2. **Каких именно входных данных он ожидает**.
Именно по этой причине описания инструментов обычно предоставляются с использованием выразительных, но точных структур, таких как компьютерные языки или JSON. Не обязательно делать это именно так, подойдет любой точный и последовательный формат.
Если это кажется слишком теоретическим, давайте разберемся на конкретном примере.
Мы реализуем упрощенный **калькулятор**, который будет просто перемножать два целых числа. Это может быть наша реализация на Python:
```python
def calculator(a: int, b: int) -> int:
"""Multiply two integers."""
return a * b
```
Итак, наш инструмент называется `calculator`, он **перемножает два целых числа**, и ему требуются следующие входные данные:
- **`a`** (*int*): Целое число.
- **`b`** (*int*): Целое число.
На выходе получается другое целое число, которое можно описать следующим образом:
- (*int*): Произведение `a` и `b`.
Все эти детали очень важны. Давайте соберем их вместе в текстовую строку, которая описывает наш инструмент для понимания LLM.
```text
Tool Name: calculator, Description: Multiply two integers., Arguments: a: int, b: int, Outputs: int
```
> **Напоминание:** Это текстовое описание - *то, что мы хотим, чтобы LLM знала об инструменте*.
Когда мы передадим предыдущую строку как часть входных данных в LLM, модель распознает ее как инструмент, и будет знать, что ему нужно передавать в качестве входных данных и что ожидать от выходных данных.
Если мы хотим предоставить дополнительные инструменты, мы должны быть последовательными и всегда использовать один и тот же формат. Этот процесс может быть хрупким, и мы можем случайно упустить некоторые детали.
Есть ли лучший способ?
### Автоформатирование секции Инструменты
Наш инструмент написан на Python, и его реализация уже предоставляет все, что нам нужно:
- Описательное название того, что он делает: `calculator`.
- Более длинное описание, представленное в комментарии к docstring функции: `Multiply two integers.`.
- Входные данные и их тип: функция явно ожидает два `int`.
- Тип выходных данных.
Люди не просто так используют языки программирования: они выразительны, кратки и точны.
Мы могли бы предоставить исходный код Python в качестве _спецификации_ инструмента для LLM, но способ реализации инструмента не имеет значения. Важно лишь его название, то, что он делает, какие входные данные он ожидает и какие выходные данные он предоставляет.
Мы воспользуемся возможностями интроспекции Python, чтобы изучить исходный код и автоматически составить описание инструмента. Все, что нам нужно, - это чтобы реализация инструмента использовала подсказки типов, строки документации и разумные имена функций. Мы напишем код для извлечения нужных фрагментов из исходного кода.
После этого нам останется только использовать декоратор Python, чтобы указать, что функция `calculator` является инструментом:
```python
@tool
def calculator(a: int, b: int) -> int:
"""Multiply two integers."""
return a * b
print(calculator.to_string())
```
Обратите внимание на декоратор `@tool` перед определением функции.
С помощью реализации, которую мы рассмотрим далее, мы сможем автоматически извлекать следующий текст из исходного кода с помощью функции `to_string()`, предоставляемой декоратором:
```text
Tool Name: calculator, Description: Multiply two integers., Arguments: a: int, b: int, Outputs: int
```
Как видите, это то же самое, что мы уже писали вручную!
### Универсальная реализация Инструмента
Мы создаем общий класс `Tool`, который мы можем использовать каждый раз, когда нам нужно использовать инструмент.
> **Отказ от ответственности:** Этот пример реализации является вымышленным, но очень похож на реальные реализации в большинстве библиотек.
```python
class Tool:
"""
Класс, представляющий многократно используемый фрагмент кода (инструмент).
Атрибуты:
name (str): Имя инструмента.
description (str): Текстовое описание того, что делает инструмент.
func (вызываемый): Функция, которую оборачивает этот инструмент.
arguments (список): Список аргументов.
outputs (str или list): Возвращаемые обернутой функцией типы.
"""
def __init__(self,
name: str,
description: str,
func: callable,
arguments: list,
outputs: str):
self.name = name
self.description = description
self.func = func
self.arguments = arguments
self.outputs = outputs
def to_string(self) -> str:
"""
Возвращает строковое представление инструмента,
включая его название, описание, аргументы и выходные данные.
"""
args_str = ", ".join([
f"{arg_name}: {arg_type}" for arg_name, arg_type in self.arguments
])
return (
f"Tool Name: {self.name},"
f" Description: {self.description},"
f" Arguments: {args_str},"
f" Outputs: {self.outputs}"
)
def __call__(self, *args, **kwargs):
"""
Вызов базовой функции (вызываемой) с указанными аргументами.
"""
return self.func(*args, **kwargs)
```
Это может показаться сложным, но если мы медленно пройдемся по нему, то сможем понять, что он делает. Мы определяем класс **`Tool`**, который включает в себя:
- **`name`** (*str*): Название инструмента.
- **`description`** (*str*): Краткое описание того, что делает инструмент.
- **`function`** (*callable*): Функция, которую выполняет инструмент.
- **`arguments`** (*list*): Ожидаемые входные параметры.
- **`outputs`** (*str* или *list*): Ожидаемые выходные данные инструмента.
- **`__call__()`**: Вызывает функцию при вызове экземпляра инструмента.
- **`to_string()`**: Преобразует атрибуты инструмента в текстовое представление.
Мы можем создать инструмент с помощью этого класса, используя следующий код:
```python
calculator_tool = Tool(
"calculator", # имя
"Multiply two integers.", # описание
calculator, # функция для вызова
[("a", "int"), ("b", "int")], # водные данные (имена и типы)
"int", # выходные данные
)
```
Но мы также можем использовать модуль Python `inspect`, чтобы получить всю информацию за нас! Вот что делает декоратор `@tool`.
> Если вам интересно, вы можете посмотреть на реализацию декоратора в следующем разделе.
код декоратора
```python
def tool(func):
"""
Декоратор, создающий экземпляр Tool из заданной функции.
"""
# Получение сигнатуры функции
signature = inspect.signature(func)
# Извлеките пары (param_name, param_annotation) для входных данных
arguments = []
for param in signature.parameters.values():
annotation_name = (
param.annotation.__name__
if hasattr(param.annotation, '__name__')
else str(param.annotation)
)
arguments.append((param.name, annotation_name))
# Определите аннотацию возврата
return_annotation = signature.return_annotation
if return_annotation is inspect._empty:
outputs = "No return annotation"
else:
outputs = (
return_annotation.__name__
if hasattr(return_annotation, '__name__')
else str(return_annotation)
)
# Используйте строку документации функции в качестве описания (по умолчанию, если None)
description = func.__doc__ or "Описание не представлено."
# Имя функции становится именем Инструмента
name = func.__name__
# Возвращаем новый экземпляр Инструмента
return Tool(
name=name,
description=description,
func=func,
arguments=arguments,
outputs=outputs
)
```
Повторимся, что с этим декоратором мы можем реализовать наш инструмент следующим образом:
```python
@tool
def calculator(a: int, b: int) -> int:
"""Multiply two integers."""
return a * b
print(calculator.to_string())
```
И мы можем использовать метод `Tool` `to_string` для автоматического получения текста, подходящего для использования в качестве описания инструмента для LLM:
```text
Tool Name: calculator, Description: Multiply two integers., Arguments: a: int, b: int, Outputs: int
```
Описание **вставляется** в системную подсказку. Если взять пример, с которого мы начали этот раздел, то вот как он будет выглядеть после замены `tools_description`:
В разделе [Действия](actions) мы узнаем, как агент может **вызвать** инструмент, который мы только что создали.
---
Инструменты играют решающую роль в расширении возможностей AI агентов.
Подводя итоги, мы узнали:
- *Что такое инструменты*: Функции, которые предоставляют LLM дополнительные возможности, такие как выполнение вычислений или доступ к внешним данным.
- *Как определить инструмент*: Предоставить четкое текстовое описание, входы, выходы и вызываемую функцию.
- *Почему инструменты необходимы*: Они позволяют агентам преодолевать ограничения статического обучения модели, решать задачи в реальном времени и выполнять специализированные действия.
Теперь мы можем перейти к [Рабочему процессу Агента](agent-steps-and-structure), где вы увидите, как Агент наблюдает, думает и действует. Это **собирает воедино все, что мы изучили до сих пор**, и закладывает основу для создания вашего собственного полнофункционального AI Агента.
Но сначала - еще один короткий тест!

Xet Storage Details

Size:
21.4 kB
·
Xet hash:
bdaaa82189d0fa14bbc20b20cab2938c5849e223d23e9d10090ede500d947dd2

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.