0Pricing
AI Agents · Урок

Потоковый вывод в агентах CLI

Печать поступающих токенов посимвольно в интерфейсах терминала.

«Потоковый вывод в агентах CLI» — бесплатный урок AI Agents на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения AI Agents, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс AI Agents содержит 4 уроков всего.

Почему потоковая передача важна для агентов CLI

Без потоковой передачи агент CLI ничего не выводит, пока не будет готов полный ответ LLM — это может занять от 5 до 30 секунд. Пользователи смотрят на пустой терминал и не понимают, не завершилась ли программа с ошибкой.

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

Включение потоковой передачи в OpenAI SDK

Передайте stream=True в chat.completions.create(). Вызов возвращает генератор, а не полный объект ответа. Перебирайте его, чтобы обрабатывать фрагменты по мере их поступления.

import openai

client = openai.OpenAI(api_key='YOUR_API_KEY')

stream = client.chat.completions.create(
    model='gpt-4o-mini',
    messages=[{'role': 'user', 'content': 'Explain Python generators in 3 sentences.'}],
    stream=True  # <-- enable streaming
)

# Each chunk arrives as it is generated
for chunk in stream:
    delta = chunk.choices[0].delta
    if delta.content:
        print(delta.content, end='', flush=True)

print()  # newline after the response is complete

print() и sys.stdout.write()

При потоковой передаче используйте print(text, end='', flush=True) или sys.stdout.write(text), а затем sys.stdout.flush(). Без flush=True Python может буферизовать вывод и напечатать всё сразу, что лишает потоковую передачу смысла.

import sys
import openai

client = openai.OpenAI(api_key='YOUR_API_KEY')

def stream_to_terminal(messages: list):
    stream = client.chat.completions.create(
        model='gpt-4o-mini',
        messages=messages,
        stream=True
    )

    full_response = ''
    for chunk in stream:
        token = chunk.choices[0].delta.content or ''
        full_response += token

        # Option 1: print with flush
        print(token, end='', flush=True)

        # Option 2: sys.stdout.write + flush
        # sys.stdout.write(token)
        # sys.stdout.flush()

    print()  # final newline
    return full_response

Сбор полного ответа во время потоковой передачи

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

import openai

client = openai.OpenAI(api_key='YOUR_API_KEY')

def stream_and_collect(messages: list) -> str:
    full_text = ''

    print('Agent: ', end='', flush=True)

    stream = client.chat.completions.create(
        model='gpt-4o-mini',
        messages=messages,
        stream=True
    )

    for chunk in stream:
        token = chunk.choices[0].delta.content or ''
        full_text += token
        print(token, end='', flush=True)

    print()  # newline
    return full_text

# The return value contains the complete response for storage
# response_text = stream_and_collect(history)
# history.append({'role': 'assistant', 'content': response_text})

Асинхронная потоковая передача с AsyncOpenAI

Для асинхронных архитектур агентов используйте AsyncOpenAI и async for, чтобы перебирать фрагменты потока, не блокируя цикл событий.

import asyncio
import openai

async def async_stream_agent(query: str) -> str:
    client = openai.AsyncOpenAI(api_key='YOUR_API_KEY')

    stream = await client.chat.completions.create(
        model='gpt-4o-mini',
        messages=[{'role': 'user', 'content': query}],
        stream=True
    )

    full_text = ''
    print('Agent: ', end='', flush=True)

    async for chunk in stream:
        token = chunk.choices[0].delta.content or ''
        full_text += token
        print(token, end='', flush=True)

    print()
    return full_text

# asyncio.run(async_stream_agent('What is asyncio?'))

Определение конца потока по finish_reason

Последний фрагмент потока имеет ненулевое значение finish_reason. Проверьте его, чтобы понять причину завершения потока: 'stop' = обычное завершение, 'length' = ответ обрезан, 'tool_calls' = требуется вызов функции.

import openai

client = openai.OpenAI(api_key='YOUR_API_KEY')

def stream_with_finish_detection(messages: list):
    stream = client.chat.completions.create(
        model='gpt-4o-mini',
        messages=messages,
        stream=True
    )

    finish_reason = None
    for chunk in stream:
        delta = chunk.choices[0].delta
        if delta.content:
            print(delta.content, end='', flush=True)
        if chunk.choices[0].finish_reason:
            finish_reason = chunk.choices[0].finish_reason

    print()

    if finish_reason == 'length':
        print('[WARNING: Response was truncated. Try increasing max_tokens.]')
    elif finish_reason == 'stop':
        pass  # normal completion

    return finish_reason

Цвета ANSI в выводе терминала

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

# pip install colorama
from colorama import Fore, Style, init
init(autoreset=True)  # reset color after each print

def print_colored_stream(messages: list, client):
    # Print agent prefix in cyan
    print(Fore.CYAN + 'Agent: ' + Style.RESET_ALL, end='', flush=True)

    stream = client.chat.completions.create(
        model='gpt-4o-mini',
        messages=messages,
        stream=True
    )

    for chunk in stream:
        token = chunk.choices[0].delta.content or ''
        print(token, end='', flush=True)

    print()

# Also useful:
# print(Fore.GREEN + 'Success!') — green
# print(Fore.RED + 'Error!') — red
# print(Fore.YELLOW + 'Warning') — yellow

Библиотека Rich для улучшенного вывода в терминале

Библиотека rich предоставляет в терминале отображение Markdown, подсветку синтаксиса в блоках кода, таблицы и анимации. Она хорошо сочетается с потоковым выводом агента.

# pip install rich
from rich.console import Console
from rich.live import Live
from rich.markdown import Markdown

console = Console()

def stream_with_rich(messages: list, client):
    full_text = ''

    with Live(console=console, refresh_per_second=10) as live:
        stream = client.chat.completions.create(
            model='gpt-4o-mini',
            messages=messages,
            stream=True
        )

        for chunk in stream:
            token = chunk.choices[0].delta.content or ''
            full_text += token
            # Render accumulated text as Markdown in real time
            live.update(Markdown(full_text))

    return full_text

Потоковая передача с вызовами инструментов

При сочетании потоковой передачи с вызовом функций поле tool_calls также передаётся частями. Накапливайте строку JSON из фрагментов, прежде чем разбирать её.

import json
import openai

client = openai.OpenAI(api_key='YOUR_API_KEY')

def stream_with_tools(messages: list, tools: list) -> dict:
    stream = client.chat.completions.create(
        model='gpt-4o-mini',
        messages=messages,
        tools=tools,
        stream=True
    )

    tool_call_chunks = {}
    for chunk in stream:
        delta = chunk.choices[0].delta
        if delta.tool_calls:
            for tc in delta.tool_calls:
                idx = tc.index
                if idx not in tool_call_chunks:
                    tool_call_chunks[idx] = {'name': '', 'args': ''}
                if tc.function.name:
                    tool_call_chunks[idx]['name'] += tc.function.name
                if tc.function.arguments:
                    tool_call_chunks[idx]['args'] += tc.function.arguments

    # Parse accumulated tool calls
    return {v['name']: json.loads(v['args']) for v in tool_call_chunks.values()}

Отображение счётчика токенов

Показывайте счётчик токенов в реальном времени во время потоковой передачи, чтобы пользователи могли отслеживать использование и понимать расходы. Поток OpenAI содержит данные об использовании в последнем фрагменте, если задан параметр stream_options={'include_usage': True}.

import openai

client = openai.OpenAI(api_key='YOUR_API_KEY')

def stream_with_token_count(messages: list):
    stream = client.chat.completions.create(
        model='gpt-4o-mini',
        messages=messages,
        stream=True,
        stream_options={'include_usage': True}
    )

    for chunk in stream:
        delta = chunk.choices[0].delta
        if delta.content:
            print(delta.content, end='', flush=True)

        # Last chunk includes usage
        if chunk.usage:
            print(f'\n[Tokens: prompt={chunk.usage.prompt_tokens}, '
                  f'completion={chunk.usage.completion_tokens}, '
                  f'total={chunk.usage.total_tokens}]')

Рекомендации по потоковой передаче

Краткое изложение рекомендаций по потоковому выводу для агентов CLI:

  • Всегда используйте flush=True или sys.stdout.flush(), чтобы предотвратить буферизацию
  • Накапливайте токены в строке для сохранения после потоковой передачи
  • Проверяйте finish_reason, чтобы обнаружить обрезание ответа
  • Используйте цвета ANSI или rich для наглядности
  • При потоковой передаче вызовов инструментов накапливайте фрагменты аргументов JSON

Проверка знаний: потоковый вывод

Проверьте, насколько хорошо Вы понимаете потоковый вывод в агентах CLI.

Итоги: потоковая выдача в агентах CLI

Теперь Вы умеете создавать потоковых агентов CLI, которые быстро реагируют и соответствуют современным требованиям:

  • Передавайте stream=True, чтобы включить потоковую выдачу через OpenAI SDK
  • Используйте print(token, end='', flush=True), чтобы сразу отображать токены
  • Накапливайте токены в строке для последующей обработки после завершения потока
  • Проверяйте finish_reason в последнем фрагменте, чтобы обнаружить усечение
  • Используйте async for вместе с AsyncOpenAI для асинхронных агентов
  • Добавьте цвета ANSI или rich, чтобы работа в терминале выглядела профессионально

Часто задаваемые вопросы

Урок «Потоковый вывод в агентах CLI» бесплатный?

Да — полный текст урока «Потоковый вывод в агентах CLI» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс AI Agents, подпишись на CoddyKit PRO. Курс AI Agents содержит 4 уроков всего.

Чему я научусь в уроке «Потоковый вывод в агентах CLI»?

Печать поступающих токенов посимвольно в интерфейсах терминала. Ты практикуешь AI Agents с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать AI Agents?

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

Сколько времени занимает урок «Потоковый вывод в агентах CLI»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке AI Agents?

Да. Каждый урок AI Agents включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Создание интерфейсов агентов командной строки
  2. Интерактивные агенты в стиле REPL
  3. Разбор аргументов и справочный текст
  4. Потоковый вывод в агентах CLI
← Назад к AI Agents