Архив рубрики ~Лента новостей~

Вам, вероятно, не понадобится агентская платформа.

Вам, вероятно, не понадобится агентская платформа.
Вам, вероятно, не понадобится агентская платформа.

В большинстве приложений LLM требуется четкий рабочий процесс, а не автономный агент. Вот как создать такой агент на чистом Python.

Делиться

Сгенерировано с помощью GPT Image-2

Вы хотите разработать заявку на получение степени магистра права (LLM).

Итак, первая мысль, которая приходит вам в голову: давайте создадим мощного агента!

Но тут же возникает вопрос: какой фреймворк для работы с агентами мне следует использовать? CrewAI? LangGraph? Microsoft Agent Framework? Или что-то другое?

Затем вы открываете несколько страниц документации, сравниваете примеры и пытаетесь решить, какой фреймворк лучше всего подходит для решения вашей задачи. Проходит пара часов, вы чувствуете себя подавленным, а еще даже не начали кодировать.

Но подождите секунду: действительно ли здесь необходима агентская структура? Более того, нужно ли вообще создавать агента LLM?

За последние два года я разработал немало приложений LLM в различных областях. Один из уроков, который я усвоил, заключается в том, что для многих полезных приложений LLM надежно работает не автономный агент, а сам рабочий процесс .

А для построения рабочих процессов вам, возможно, вообще не понадобятся никакие фреймворки.

В этом посте я покажу вам, как создать прототип рабочего процесса LLM, используя обычный Python, локальные функции, структурированные выходные данные и API ответов OpenAI (та же схема применима и к другим поставщикам LLM). Мы перейдем к практике и решим задачу объяснения аномалии.

Моя цель здесь не в том, чтобы утверждать, что фреймворки плохи. Они, безусловно, полезны в различных сценариях, и мы обсудим это в конце этой статьи. Моя цель — показать, что для многих приложений четкий рабочий процесс может быть первой абстракцией, которая вам действительно нужна.

1. Прежде чем переходить к агентам, протестируйте рабочие процессы.

Под агентом LLM обычно подразумевается автономная система, способная самостоятельно принимать решения о дальнейших действиях.

Вы задаете ему цель и набор инструментов. Затем он планирует, действует, наблюдает за результатом и продолжает итерации. Вместо того чтобы следовать фиксированному пути, агент динамически выбирает следующий шаг, исходя из текущей ситуации. Для задач с открытым концом это очень эффективно.

Однако многие реальные проблемы не столь однозначны.

Во многих случаях мы примерно знаем, как следует решать проблему. Но если мы это уже знаем, зачем просить модель изобретать велосипед заново?

Вот тут-то и пригодятся рабочие процессы.

В рабочем процессе LLM мы, разработчики, определяем основные этапы, а LLM используется внутри выбранных этапов в качестве механизма логического вывода. Это по-прежнему приложение, работающее на основе LLM. Разница заключается в том, что LLM не рассматривается как вся система целиком. Он рассматривается только как узел принятия решений внутри более крупного процесса.

Итак, каковы преимущества внедрения рабочего процесса LLM? На мой взгляд, следующие пункты важны:

  • Рабочий процесс прозрачен. Его легко изучить, поскольку каждый шаг имеет четко определенную роль и ясный договор о входных и выходных данных.
  • Рабочий процесс имеет модульную структуру, это означает, что вы можете изменить один шаг, не переписывая все приложение целиком.
  • Самое важное, что рабочий процесс имеет детерминированное управление потоком выполнения. Рассуждения и решения LLM могут различаться внутри шага, но общий путь контролируется кодом. Уже одно это устраняет большую часть неопределенности, когда мы пытаемся создать что-то надежное.

Я понимаю, это звучит менее захватывающе, чем создание полностью автономного агента. Но ваша цель — предложить эффективное решение. Если скучные вещи работают, то мы должны с удовольствием их использовать.

2. Что нам действительно нужно для проектирования

По моему опыту, есть четыре ключевых компонента:

  • Управление потоком
  • Инструкции по выбору роли (системные подсказки)
  • Оперативные строители
  • Структурированный вывод

Позвольте мне подробно рассказать о каждом из них.

2.1 Управление потоком

Управление потоком выполнения определяет, как приложение переходит от ввода к выводу.

Полезный способ осмысления потока управления — представить его в виде графа. В этом графе у нас есть узлы и ребра:

  • Узлы : Каждый узел представляет собой один шаг в приложении. Это может быть детерминированный этап обработки, выполняемый кодом (например, загрузка данных, вызов локальной функции). Это также может быть этап LLM, где LLM используется для принятия решения, извлечения информации или написания пояснения.
  • Ребра : Каждое ребро представляет собой способ перемещения информации от одного шага к другому. Как и узлы, ребра также имеют разные типы. Например, ребро может быть статическим, то есть всегда вызывать предопределенный следующий шаг после обработки текущего шага; или оно может быть условным, например, если LLM на текущем шаге говорит, что необходимы дополнительные доказательства, ребро связывается с локальным узлом инструмента; если LLM считает, что собрано достаточно доказательств, ребро указывает на окончательное объяснение.

Ключевой момент: в рабочем процессе код владеет этим графом. LLM-ы привязаны к конкретным узлам, а не работают свободно.

Я бы начал с этого, поскольку это заставляет вас сначала обдумать, что именно должно делать приложение, какие задачи должны обрабатываться детерминированным кодом, какие передаются в LLM, где разветвляется рабочий процесс и когда он должен остановиться.

2.2 Инструкции по ролям

В рабочем процессе обычно используются LLM-ы в нескольких ролях, и для каждой роли необходимы свои инструкции (системные подсказки).

Инструкция роли определяет, как LLM должен вести себя внутри конкретного узла. Обычно она указывает LLM его роль, выполняемые задачи, на что следует обращать внимание и чего следует избегать. Любые правила, специфичные для предметной области, также должны быть указаны здесь.

2.3 Быстрые строители

В то время как инструкции для ролей определяют, как должен вести себя LLM, разработчики подсказок решают, что LLM может видеть.

Компоненты подсказок формируют контекст для вызова на программу LLM на основе цели данной программы и текущего состояния рабочего процесса.

На практике это просто функция: она принимает динамические значения из текущего рабочего процесса, при необходимости предварительно обрабатывает их и передает в шаблон запроса. На выходе получается окончательный набор данных запроса, отправляемый в LLM.

В конструкторах подсказок мы управляем контекстным окном. Контекст должен быть адаптирован и достаточен для обоснования рассуждений LLM.

2.4 Структурированный вывод

В рабочем процессе выходные данные LLM часто представляют собой промежуточные результаты, используемые на следующем этапе. В данном случае разрешать LLM выводить текст в свободной форме нецелесообразно, поскольку это делает последующий анализ ненадежным.

Более эффективным подходом было бы попросить LLM-модели возвращать структурированный результат , соответствующий предопределенной схеме данных, обычно представленной в виде объекта JSON или модели Pydantic.

Эта схема является контрактом между этапами LLM. При разработке схемы необходимо продумать, какие поля должны существовать, какие типы они должны иметь и какие значения допустимы. Когда выходные данные модели соответствуют этой схеме, следующий этап может считывать поля напрямую.

Фактически, структурированный вывод также позволяет вызывать инструменты/функции . В частности, мы указываем в схеме одно поле для имени функции и другое для ее аргументов, и на следующем шаге можно прочитать оба поля и позволить Python выполнить соответствующую локальную функцию.

Теперь, когда мы рассмотрели четыре основных компонента рабочего процесса, пришло время посмотреть, как они работают на практике.

3. Давайте создадим реальный рабочий процесс.

Здесь мы создаём небольшой алгоритм проверки качества данных, используя набор данных Iris (CC BY 4.0).

На практике нам часто приходится проверять наборы данных и помечать подозрительные записи перед отправкой на обучение модели. Но одной лишь пометки редко бывает достаточно; зачастую мы также хотим понять причину: действительно ли это проблема качества данных, и какие доказательства подтверждают эту оценку?

Здесь могут помочь специалисты с магистерской степенью в области права.

3.1 Постановка задачи

Для этого исследования мы используем набор данных Iris. Конечно, Iris — это набор данных для классификации, в котором нет помеченных аномалий. Но чтобы сделать задачу более интересной, мы намеренно вносим изменения в один образец: этот образец имеет метку versicolor , но мы изменили размеры его чашелистиков на необычные значения. Это дает нам одну явную аномалию качества данных на уровне признаков.

После этого мы следуем стандартной процедуре скрининга. Сначала мы используем простую логику для выявления подозрительных образцов. Затем мы применяем LLM-методы для диагностики выявленного образца и составляем заключение с подтверждающими доказательствами.

В нашем рабочем процессе две роли в рамках программы LLM. Первая — это исследователь LLM, который определяет, какие диагностические данные необходимо собрать дальше. На этом этапе используются заранее определенные нами инструменты. Вторая роль — это специалист по разъяснению LLM. Его задача — получить собранные данные и с уверенностью вынести окончательную оценку.

Мы построим этот рабочий процесс без использования каких-либо агентских фреймворков.

fe7fb45b3b3cff9a530e84bfec531e85
Рисунок 1. Рабочий процесс LLM. (Изображение предоставлено автором)

3.2 Шаг 0: Подготовка к подаче заявки на программу LLM

Начнём с определения многоразового вспомогательного метода для вызова LLM:

 client = AzureOpenAI( api_key=os.environ["OPENAI_API_KEY"], azure_endpoint=os.environ["OPENAI_API_BASE"], api_version=os.environ["OPENAI_API_VERSION"], ) def call_llm( step_name: str, instructions: str, prompt: str, output_schema: type[BaseModel], ) -> BaseModel: """Call the LLM once and return a parsed structured output.""" model = "gpt-5.4-mini" started = time.perf_counter() response = client.responses.parse( model=model, instructions=instructions, input=prompt, reasoning={"effort": "medium"}, text_format=output_schema, ) usage = response.usage.model_dump() if response.usage else {} llm_telemetry.append( { "step": step_name, "schema": output_schema.__name__, "model": model, "prompt_chars": len(prompt), "elapsed_s": round(time.perf_counter() - started, 2), "input_tokens": usage.get("input_tokens"), "output_tokens": usage.get("output_tokens"), "total_tokens": usage.get("total_tokens"), } ) return response.output_parsed

Здесь мы используем API ответов OpenAI, который позволяет нам указывать системную инструкцию, входную подсказку и схему вывода. Для нашей текущей задачи мы используем GPT-5.4-mini со средними трудозатратами. Кроме того, мы добавляем некоторую легковесную телеметрию для записи задержки и затрат. Обратите внимание, что нам необходимо использовать output_parsed для получения структурированного вывода.

3.3 Шаг 1: Проверка подозрительного образца

Теперь переходим к этапу отбора.

Цель этого шага — использовать простую логику обнаружения для выявления аномальных образцов данных. Для этого шага не требуется LLM.

Конкретно, для каждого образца мы вычисляем z-баллы по каждой характеристике относительно образцов с той же видовой меткой. В качестве «показателя аномалии» мы сохраняем наибольший абсолютный z-балл.

Строка 55 определена правильно, поскольку это тот образец, который мы модифицировали:

50f1b71363a1ae31a8a2623b93962c71

Хорошо, но на практике одна лишь идентификация ничего не говорит о том, как и почему это произошло. Нам нужно внимательнее рассмотреть этот вопрос на следующем этапе.

3.4 Шаг 2: Итеративный сбор доказательств

На этом этапе мы хотим, чтобы специалист по линейному менеджменту (LLM) сначала собрал достаточно доказательств, прежде чем пытаться объяснить аномальный образец. С этой целью мы назначили роль исследователя LLM для выполнения этой задачи по сбору доказательств.

4313d00e196aaba7e35e289d547eacbc
Рисунок 2. Этап сбора доказательств. (Изображение предоставлено автором)

Начнем с настройки инструкций по назначению роли, следуя структуре «Роль-Задача-Ожидаемый результат-Правила»:

 # Note: This instruction is polished by AI INVESTIGATOR_INSTRUCTIONS = """ [Role]: You are a data-quality investigator reviewing a flagged record from a tabular Iris-measurement dataset. Each record contains sepal measurements, petal measurements, and a species label. [Task]: Your job is to gather diagnostic evidence that will help a separate analyst assess why the record may be abnormal. You are not responsible for making the final assessment. At each step, review the flagged record and any evidence already collected. Then decide whether one more diagnostic check is needed, or whether the available evidence is sufficient. [Expected output]: Return either a request for one diagnostic function, including the function name and concrete arguments, or a decision that enough evidence has been collected. [Rules]: Use only the diagnostic functions made available to you. Request at most one function call at a time. Choose function arguments that are relevant to the flagged record. Do not make the final assessment yourself. Do not invent measurements, species profiles, neighbor records, or tool results. """

Для данного исследователя мы предлагаем два локальных инструмента. Один из них — сравнение помеченного образца с профилем вида с использованием z-балла для каждой характеристики, чтобы LLM мог оценить, насколько статистически необычным кажется текущий образец:

 FEATURES = [ "sepal_length_cm", "sepal_width_cm", "petal_length_cm", "petal_width_cm", ] def compare_row_to_species_profile(row_id: int, species: str) -> dict[str, Any]: """Compare one row with one species profile using feature-level z-scores.""" row = working_df.loc[working_df["row_id"] == row_id].iloc[0] profile_rows = working_df[(working_df["species"] == species) & (working_df["row_id"] != row_id)] profile_stats = profile_rows[FEATURES].agg(["mean", "std"]) feature_comparisons = [] for feature in FEATURES: mean = profile_stats.loc["mean", feature] std = profile_stats.loc["std", feature] value = float(row[feature]) feature_comparisons.append( { "feature": feature, "value": value, "species_mean": round(float(mean), 3), "species_std": round(float(std), 3), "zscore": round(float((value - mean) / std), 3), } ) return { "row_id": row_id, "species": species, "feature_comparisons": feature_comparisons, }

Другой способ — найти K ближайших образцов, используя стандартную библиотеку scikit-learn. Это позволяет LLM понять, какие образцы наиболее похожи на отмеченную запись в пространстве измерений:

 def find_nearest_neighbors(row_id: int, k: int = 5) -> dict[str, Any]: """Find nearest rows with a KNN model on standardized measurements.""" rows = working_df.reset_index(drop=True) row_position = rows.index[rows["row_id"] == row_id][0] scaled_features = StandardScaler().fit_transform(rows[FEATURES]) knn = NearestNeighbors(n_neighbors=k + 1).fit(scaled_features) distances, neighbor_positions = knn.kneighbors(scaled_features[[row_position]]) neighbors = [] for distance, neighbor_position in zip(distances[0], neighbor_positions[0]): if neighbor_position == row_position: continue neighbor = rows.iloc[neighbor_position] neighbors.append( { "row_id": int(neighbor["row_id"]), "species": str(neighbor["species"]), "distance": round(float(distance), 3), "measurements": {feature: float(neighbor[feature]) for feature in FEATURES}, } ) return {"row_id": row_id, "neighbors": neighbors}

Теперь, когда мы определили локальные инструменты, нам нужно сообщить LLM, что он может видеть на каждом этапе расследования. Это задача конструктора подсказок:

 def build_investigation_prompt( flagged_row: dict[str, Any], collected_evidence: list[dict[str, Any]], ) -> str: return f""" Flagged record: {json.dumps(flagged_row, indent=2)} Evidence collected so far: {json.dumps(collected_evidence, indent=2)} Available diagnostic functions: {json.dumps(TOOL_DESCRIPTIONS, indent=2)} Task: Decide whether to request one more diagnostic function or stop because enough evidence has been collected. """.strip()

Имеется два входных параметра:

  • flagged_row — это образец, находящийся в настоящее время на стадии исследования. Он содержит идентификатор строки, четыре измерения и обозначение вида.
  • collected_evidence — это список диагностических результатов, собранных в предыдущих раундах . В начале этот список пуст. После каждого вызова инструмента рабочий процесс добавляет результат инструмента в этот список и передает его обратно в следующий вызов LLM.

TOOL_DESCRIPTIONS — это небольшое меню функций, доступных для LLM:

 TOOL_DESCRIPTIONS = [ { "name": "compare_row_to_species_profile", "description": "Compare one row to one species profile using feature-level z-scores.", "arguments": {"row_id": "integer", "species": "setosa | versicolor | virginica"}, }, { "name": "find_nearest_neighbors", "description": "Find nearest rows with a KNN model on standardized measurements.", "arguments": {"row_id": "integer", "k": "integer"}, }, ]

Цикл расследования реализован непосредственно на языке Python:

 collected_evidence = [] for round_id in range(1, MAX_ROUNDS + 1): decision = call_llm( step_name=f"investigator_row_{row_id}_round_{round_id}", output_schema=InvestigationDecision, instructions=INVESTIGATOR_INSTRUCTIONS, prompt=build_investigation_prompt(flagged_row, collected_evidence), ) if decision.status == "enough_evidence": break tool_result = execute_tool_call(row_id, decision) collected_evidence.append(tool_result)

В цикле, как только исследователь LLM принимает решение, Python отвечает за выполнение выбранной локальной функции. Функция определяется следующим образом:

 def execute_tool_call(row_id: int, decision: InvestigationDecision) -> dict[str, Any]: if decision.tool_name == "compare_row_to_species_profile": arguments = {"species": decision.species} result = compare_row_to_species_profile(row_id=row_id, **arguments) else: arguments = {"k": decision.k} result = find_nearest_neighbors(row_id=row_id, **arguments) return { "tool": decision.tool_name, "arguments": arguments, "result": result, }

Приведённый выше цикл использует выходную схему InvestigationDecision , которая определена ниже:

 from typing import Literal from pydantic import BaseModel, Field Species = Literal["setosa", "versicolor", "virginica"] ToolName = Literal["compare_row_to_species_profile", "find_nearest_neighbors"] class InvestigationDecision(BaseModel): status: Literal["need_more_evidence", "enough_evidence"] = Field( ..., description="Whether another local function call is useful.", ) reasoning: str = Field(..., description="Brief evidence-grounded rationale.") tool_name: ToolName | None = Field( None, description="Local diagnostic function to call, or null when evidence is sufficient.", ) species: Species | None = Field( None, description="Species profile to compare against; only used for compare_row_to_species_profile.", ) k: int | None = Field( None, description="Number of nearest rows to return; only used for find_nearest_neighbors.", )

Здесь для определения схемы используется Pydantic, библиотека Python для определения типизированных моделей данных. В Pydantic Field(...) означает, что это поле обязательно, и это относится к полям status и reasoning . Однако другие поля необходимы только тогда, когда исследователь LLM хочет вызвать локальную функцию. В результате их тип — ToolCall/Species/int | None , а значения по умолчанию — None .

Отлично! Это был самый сложный этап рабочего процесса. Но в этом и суть: как только мы явно указываем инструкции по роли, построитель подсказок, схему, инструменты и цикл, никакой скрытой оркестровки не остаётся.

Теперь мы можем перейти к заключительному этапу объяснения LLM. Вы увидите, как повторяется эта закономерность.

3.5 Шаг 3: Объяснение помеченного образца

После сбора доказательств заключительным шагом является обращение к другому магистру права с просьбой интерпретировать эти доказательства и составить оценку.

f90359ee7724c38a62a54c26a25364ae
Рисунок 3. Этап объяснения LLM. (Изображение предоставлено автором)

Мы настраиваем поясняющий модуль LLM с помощью отдельной инструкции для выбора роли:

 # Note: This instruction is polished by AI EXPLAINER_INSTRUCTIONS = """ [Role]: You are a data-quality analyst reviewing a flagged record from a tabular iris-measurement dataset. Each record contains sepal measurements, petal measurements, and a species label. [Task]: Your job is to produce the final assessment for the flagged record using the record itself and the gathered diagnostic evidence. Decide whether the evidence points to a feature outlier, a likely mislabel, a class-boundary case, or no clear issue. [Expected output]: Return a concise assessment with a confidence level, a confidence rationale, a human-facing explanation, and the key evidence supporting the assessment. [Rules]: Use only the flagged record and diagnostic evidence provided in the prompt. Do not request more evidence or call tools. Do not invent measurements, species profiles, neighbor records, or tool results. Use high confidence only when the evidence strongly supports the assessment; otherwise use low confidence. """.strip()

Конструктор подсказок для пояснения LLM проще, чем у исследователя, поскольку ему нужно лишь передать отмеченную запись и диагностические данные, собранные исследователем:

 def build_explanation_prompt( flagged_row: dict[str, Any], collected_evidence: list[dict[str, Any]], ) -> str: return f""" Flagged record: {json.dumps(flagged_row, indent=2)} Diagnostic evidence: {json.dumps(collected_evidence, indent=2)} Task: Assess this flagged row and explain the evidence. """.strip()

Наконец, мы определяем структурированный вывод для поясняющего кода LLM:

 class CandidateExplanation(BaseModel): assessment: Literal[ "likely_mislabel", "feature_outlier", "class_boundary_case", "no_clear_issue", ] = Field(..., description="Best evidence-based interpretation of the flagged row.") confidence: Literal["low", "high"] = Field( ..., description="High when evidence strongly supports the assessment; low otherwise.", ) confidence_rationale: str = Field( ..., description="Why this confidence level is appropriate given the collected evidence.", ) explanation: str = Field(..., description="Concise explanation for a human reviewer.") key_evidence: list[str] = Field(..., description="Evidence items supporting the assessment.")

Обратите внимание, что мы заранее определили небольшой набор возможных категорий для assessment . Это распространенная стратегия на практике, позволяющая внедрить знания предметной области в рабочий процесс и предотвратить создание студентом магистратуры произвольных меток.

Наконец, мы можем повторно использовать тот же вспомогательный класс call_llm для запуска вызова функции explainer:

 explanation = call_llm( step_name=f"explainer_row_{row_id}", output_schema=CandidateExplanation, instructions=EXPLAINER_INSTRUCTIONS, prompt=build_explanation_prompt(flagged_row, collected_evidence), )

На этом рабочий процесс завершается.

4. Запуск рабочего процесса от начала до конца

Теперь, когда у нас есть полностью настроенный рабочий процесс, давайте его протестируем. Напомним, какой рабочий процесс мы уже разработали:

  1. На этапе проверки с помощью Python выявляется одна подозрительная запись.
  2. Исследователь, имеющий степень магистра права, который собирает диагностические данные путем итеративного вызова инструментов.
  3. Пояснительная работа для магистерской программы по праву, которая преобразует собранные данные в итоговую оценку.

После запуска рабочего процесса мы увидели, что исследователь LLM потратил четыре раунда на сбор доказательств, которые затем были переданы в программу анализа LLM. Полученная окончательная оценка — feature_outlier с high степенью достоверности. Обоснование, предоставленное программой анализа LLM, следующее:

«Представленный образец выглядит как аномальный, поскольку размеры чашелистиков у него экстремальные, в то время как размеры лепестков в целом соответствуют признакам versicolor ».

Эта оценка верна. Действительно, мы намеренно изменили выборку таким образом, чтобы в ней присутствовали выбросы значений признаков. Поэтому метка feature_outlier вполне уместна.

Мы можем дополнительно изучить полную запись действий следователей, чтобы понять, какие доказательства были собраны:

b8bf8dd6aa5be6748e44246f248655f1
Рисунок 4. Траектория исследования, полученная с помощью LLM. (Изображение предоставлено автором)

Мы видим, что исследователь LLM следовал разумному пути сбора доказательств. Сначала он проверил профиль помеченного вида, затем изучил ближайших соседей и, наконец, сравнил строку с альтернативным видом. После этих проверок он решил, что доказательств достаточно для того, чтобы автор смог провести осмысленную оценку аномальных признаков.

На этом тематическое исследование завершается. Мы разработали небольшой, но полностью функциональный рабочий процесс LLM, используя чистый Python. Рабочий процесс итеративный и поддается проверке. Неплохо!

5. Когда нам действительно нужны агенты или фреймворки?

До сих пор мы намеренно избегали как агентов, так и фреймворков. Но это не значит, что они бесполезны.

Вопрос лишь в том, какие именно проблемы мы решаем.

Здесь полезно разделить два решения, которые часто смешиваются. Первое — это степень автономии, которую вы предоставляете LLM, имея фиксированный рабочий процесс и свободно работающего агента на обоих концах спектра. Второе — это использование чужих абстракций. Вы можете либо написать программу на Python с нуля, либо использовать уже существующую структуру. Это независимые решения, и наш пример оказался в одном из углов, а именно, в случае с рабочим процессом, написанным вручную.

Затем мы можем рассмотреть, когда имеет смысл двигаться вдоль каждой оси.

a917d2b38b1039b19aa39536a9c2bc25
Рисунок 5. Агент против рабочего процесса, настраиваемая логика против существующей структуры. (Изображение предоставлено автором)

5.1 Когда вам действительно нужен агент

Краткий ответ: когда вы заранее не знаете оптимального пути решения . И это может произойти в двух сценариях.

Первый сценарий заключается в том, что вы просто не знаете, как решить проблему. Нет ни установленной процедуры, ни предметных знаний, которые можно было бы закодировать.

Второй сценарий заключается в том, что вы знаете что-то о том, как решить проблему. Но проблема в том, что пространство допустимых путей настолько обширно, что перечислить его вручную просто невозможно. Либо мы не можем охватить все ветви, либо можем, но только добавив такое количество условных ребер, что станет трудно понять ход решения.

Однако, используя LLM-агенты, следует помнить: вы получаете гибкость, но за счет надежности и возможности отладки. Именно эти преимущества рабочие процессы предоставляют вам бесплатно.

Поэтому, прежде чем использовать агентов LLM, задайте себе вопрос: достаточно ли сложна ваша проблема, чтобы нуждаться в таких способностях?

5.2 Когда вам действительно нужен фреймворк

Даже если вы решили, что рабочий процесс имеет подходящую форму, вы все равно можете обратиться к фреймворку, чтобы фактически его построить.

По моему опыту, простая версия на Python отлично подходит для быстрого прототипирования. Вы можете полностью сосредоточиться на проверке работоспособности рабочего процесса и его оптимальной структуре, не отвлекаясь на изучение синтаксиса каких-либо библиотек.

Однако, этот подход меняется, когда вы переходите от вопроса «Работает ли это?» к вопросу «Будет ли это продолжать работать в производственной среде?».

Именно этот пробел заполняют современные фреймворки, обеспечивая улучшенную обработку сбоев, наблюдаемость, управление с участием человека, сохранение данных и т.д.

Короче говоря, фреймворки отлично подходят для решения проблем, которые могут возникнуть после того, как ваша идея сработает.

6. Итак, что же мы узнали?

Для многих полезных приложений LLM, скорее всего, в первую очередь вам понадобится не автономный агент или громоздкая платформа.

Вам необходим четкий рабочий процесс с управлением потоком выполнения, инструкциями по ролям, конструкторами подсказок, структурированными результатами и простым кодом на Python для их соединения.

И не беспокойтесь, что созданный вручную рабочий процесс окажется пустой тратой усилий. Это не так. Управление потоком выполнения, подсказки, схемы и инструменты, которые вы пишете вручную, могут быть перенесены, если вы позже перейдете к использованию агента или фреймворка.

Начните с простого, быстро проверьте ключевую идею, а усложняйте задачу только тогда, когда этого требует сложность.

Шуай Го Посмотреть все в Шуай Го

Источник: towardsdatascience.com

❌ Нет похожих статей с такими тегами

Оцените материал:

Поделиться
Понравилась статья? Расскажите другим
ВКонтакте
Читайте также
Архив рубрики ~Обо всем~ 7 подключаемых гаджетов, которые значительно повысят эффективность ваших розеток (включая спасительный гаджет). Архив рубрики ~Обо всем~ Бренд RIVAL Gaming от Goodram дебютировал с модулями памяти SO-DIMM DDR5 Новости робототехники В Сан-Франциско произошёл необычный случай, который показал неожиданную сторону развития беспилотного транспорта Новости робототехники Смешно и сыро — именно так выглядит будущий миллиард. Архив рубрики ~Обо всем~ Xfinity предоставляет новым клиентам Wi-Fi в тот же день. Архив рубрики ~Коротко из Telegram~ +50% выручки за месяц. Что случилось с Perplexity. Несколько недель… Архив рубрики ~Коротко из Telegram~ AI убивает консалтинг. Интересно наблюдать за тем, что происходит с… Новости робототехники Работает ли Caveman? Тестируем модный скилл для экономии токенов Архив рубрики ~Обо всем~ Шмели с ходу решили новую задачу. Им не потребовалось обучение Архив рубрики ~Коротко из Telegram~ MiniMax Hub: Нейросетевой конвейер на бесконечном холсте MiniMax презентовали Hub… Архив рубрики ~Коротко из Telegram~ Готовые loop-сценарии для AI-агентов Вместо того чтобы каждый раз вручную… Архив рубрики ~Обо всем~ Эти полезные гаджеты от Amazon продаются со скидкой до 68% — вот почему я их рекомендую. Архив рубрики ~Коротко из Telegram~ Про рынок, который поделили еще до Яндекса. Forbes на днях… Архив рубрики ~Коротко из Telegram~ Fable 5 стала слишком опасной, чтобы её не хотели купить… Архив рубрики ~Обо всем~ 7 подключаемых гаджетов, которые значительно повысят эффективность ваших розеток (включая спасительный гаджет). Архив рубрики ~Обо всем~ Бренд RIVAL Gaming от Goodram дебютировал с модулями памяти SO-DIMM DDR5 Новости робототехники В Сан-Франциско произошёл необычный случай, который показал неожиданную сторону развития беспилотного транспорта Новости робототехники Смешно и сыро — именно так выглядит будущий миллиард. Архив рубрики ~Обо всем~ Xfinity предоставляет новым клиентам Wi-Fi в тот же день. Архив рубрики ~Коротко из Telegram~ +50% выручки за месяц. Что случилось с Perplexity. Несколько недель… Архив рубрики ~Коротко из Telegram~ AI убивает консалтинг. Интересно наблюдать за тем, что происходит с… Новости робототехники Работает ли Caveman? Тестируем модный скилл для экономии токенов Архив рубрики ~Обо всем~ Шмели с ходу решили новую задачу. Им не потребовалось обучение Архив рубрики ~Коротко из Telegram~ MiniMax Hub: Нейросетевой конвейер на бесконечном холсте MiniMax презентовали Hub… Архив рубрики ~Коротко из Telegram~ Готовые loop-сценарии для AI-агентов Вместо того чтобы каждый раз вручную… Архив рубрики ~Обо всем~ Эти полезные гаджеты от Amazon продаются со скидкой до 68% — вот почему я их рекомендую. Архив рубрики ~Коротко из Telegram~ Про рынок, который поделили еще до Яндекса. Forbes на днях… Архив рубрики ~Коротко из Telegram~ Fable 5 стала слишком опасной, чтобы её не хотели купить…

Оставить комментарий