Тарифы

Обзор архитектуры

Исходные файлы

Эта страница сгенерирована на основе следующих исходных файлов:

ADK-GO (Agent Development Kit for Go) — это фреймворк для построения многоагентных систем с поддержкой LLM-интеграции, управления сессиями, артефактами и памятью. Архитектура проекта следует принципам модульности и расширяемости, обеспечивая чёткое разделение ответственности между компонентами.

Общая архитектура системы

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

正在加载图表渲染器...

Ключевые архитектурные решения:

  1. Интерфейсно-ориентированный дизайн — базовый интерфейс Agent (internal/agent/state.go:18-40) определяет контракт для всех типов агентов, обеспечивая полиморфизм и расширяемость.

  2. Иерархия контекстов — трёхуровневая система контекстов (InvocationContextReadonlyContext/CallbackContext) обеспечивает контролируемый доступ к состоянию и ресурсам (agent/context.go:60-98).

  3. Централизованный оркестраторRunner управляет жизненным циклом вызова, интегрируя сервисы сессий, артефактов и памяти (runner/runner.go:78-130).

  4. Система колбэковBeforeAgentCallbacks и AfterAgentCallbacks позволяют перехватывать и модифицировать поведение без изменения ядра (agent/agent.go:89-91).

  5. Поддержка внешних протоколов — интеграция с A2A (Agent-to-Agent) и MCP (Model Context Protocol) через модульную архитектуру (examples/a2a/main.go:3-131, examples/mcp/main.go:4-115).

Архитектура ядра агента

Интерфейс Agent и типы агентов

Базовый интерфейс Agent определён в internal/agent/state.go и является фундаментом для всех типов агентов в системе:

go
1type Agent interface {
2    internal() *State
3}
4
5type State struct {
6    AgentType Type
7    Config    any
8}
9
10type Type string
11
12const (
13    TypeLLMAgent        Type = "LLMAgent"
14    TypeLoopAgent       Type = "LoopAgent"
15    TypeSequentialAgent Type = "SequentialAgent"
16    TypeParallelAgent   Type = "ParallelAgent"
17    TypeCustomAgent     Type = "CustomAgent"
18    TypeRemoteAgent     Type = "RemoteAgent"
19)

Рассматриваемый исходный файл: internal/agent/state.go:18-40

Обязанности интерфейса:

  • Определение типа агента через AgentType
  • Хранение конфигурации в поле Config (произвольный тип)
  • Предоставление внутреннего состояния через метод internal()

Поддерживаемые типы агентов:

ТипНазначениеПример использования
LLMAgentАгент с LLM-интеграциейЧат-боты, генерация контента
LoopAgentЦиклическое выполнениеИтеративная обработка данных
SequentialAgentПоследовательное выполнениеПайплайны обработки
ParallelAgentПараллельное выполнениеМногозадачная обработка
CustomAgentПользовательская логикаСпецифические сценарии
RemoteAgentУдалённый агентA2A протокол

Конфигурация агента

Структура Config в agent/agent.go определяет параметры создания агента:

go
1type Config struct {
2    Name        string        // Уникальное имя в дереве агентов
3    Description string        // Описание для LLM-делегирования
4    SubAgents   []Agent       // Дочерние агенты
5    
6    BeforeAgentCallbacks []BeforeAgentCallback
7    AfterAgentCallbacks  []AfterAgentCallback
8    Run                  func(ctx InvocationContext) iter.Seq2[*session.Event, error]
9}

Рассматриваемый исходный файл: agent/agent.go:74-91

Ключевые поля конфигурации:

  1. Name — непустая строка, уникальная в дереве агентов; зарезервировано имя "user" для ввода конечного пользователя.

  2. Description — используется LLM для определения делегирования управления агенту; предпочтительна однострочная форма.

  3. SubAgents — дочерние агенты для делегирования задач; ADK автоматически устанавливает родительские связи.

  4. BeforeAgentCallbacks — последовательность колбэков, вызываемых перед основным выполнением; если любой возвращает контент или ошибку, основной код не выполняется.

  5. Run — основная функция выполнения, возвращающая итератор событий.

Жизненный цикл выполнения

Метод Run реализует основной цикл выполнения агента:

go
1func (a *agent) Run(ctx InvocationContext) iter.Seq2[*session.Event, error] {
2    return func(yield func(*session.Event, error) bool) {
3        spanCtx, span := telemetry.StartInvokeAgentSpan(ctx, a, ...)
4        yield, endSpan := telemetry.WrapYield(span, yield, ...)
5        defer endSpan()
6        
7        // Создание контекста вызова
8        ctx := &invocationContext{...}
9        
10        // Выполнение before-колбэков
11        event, err := runBeforeAgentCallbacks(ctx)
12        if event != nil || err != nil {
13            if !yield(event, err) { return }
14        }
15        
16        // Основной код агента...
17    }
18}

Рассматриваемый исходный файл: agent/agent.go:160-190

Этапы жизненного цикла:

  1. Инициализация телеметрии — создание span для трассировки вызова.
  2. Создание контекста — формирование invocationContext с параметрами вызова.
  3. Before-колбэки — последовательный вызов с возможностью прерывания.
  4. Основной код — выполнение функции Run из конфигурации.
  5. After-колбэки — постобработка результатов.

Создание экземпляра агента

Функция New() создаёт экземпляр агента с валидацией:

go
1func New(cfg Config) (Agent, error) {
2    subAgentSet := make(map[Agent]bool)
3    for _, subAgent := range cfg.SubAgents {
4        if _, ok := subAgentSet[subAgent]; ok {
5            return nil, fmt.Errorf(
6                "error creating agent: subagent %q appears multiple times",
7                subAgent.Name())
8        }
9        subAgentSet[subAgent] = true
10    }
11    return &agent{
12        name:                 cfg.Name,
13        description:          cfg.Description,
14        subAgents:            cfg.SubAgents,
15        beforeAgentCallbacks: cfg.BeforeAgentCallbacks,
16        run:                  cfg.Run,
17        afterAgentCallbacks:  cfg.AfterAgentCallbacks,
18        State: agentinternal.State{
19            AgentType: agentinternal.TypeCustomAgent,
20        },
21    }, nil
22}

Рассматриваемый исходный файл: agent/agent.go:53-72

Валидация при создании:

  • Проверка уникальности подагентов (дублирование вызывает ошибку)
  • Установка типа агента как TypeCustomAgent
  • Сохранение всех колбэков и конфигурации

Контекст вызова и иерархия

Интерфейс InvocationContext

InvocationContext — центральный интерфейс для управления состоянием вызова:

go
1type InvocationContext interface {
2    context.Context
3    
4    Agent() Agent
5    Artifacts() Artifacts
6    Memory() Memory
7    Session() session.Session
8    
9    InvocationID() string
10    Branch() string
11    UserContent() *genai.Content
12    RunConfig() *RunConfig
13    
14    EndInvocation()
15    Ended() bool
16    
17    WithContext(ctx context.Context) InvocationContext
18}

Рассматриваемый исходный файл: agent/context.go:60-98

Ключевые методы интерфейса:

МетодВозвращаемый типНазначение
Agent()AgentТекущий агент вызова
Artifacts()ArtifactsДоступ к артефактам сессии
Memory()MemoryПамять в рамках user_id
Session()SessionТекущая сессия
Branch()stringВетка вызова (agent_1.agent_2.agent_3)
EndInvocation()voidЗавершение вызова
Ended()boolПроверка завершения

Особенности Branch:

  • Формат: agent_1.agent_2.agent_3 (иерархия агентов)
  • Используется для изоляции истории разговоров между параллельными агентами
  • Критично для ParallelAgent, где подагенты выполняются конкурентно

Реализация InvocationContext

Внутренняя реализация в internal/context/invocation_context.go:

go
1type InvocationContext struct {
2    context.Context
3    params InvocationContextParams
4}
5
6func (c *InvocationContext) Agent() agent.Agent {
7    return c.params.Agent
8}
9
10func (c *InvocationContext) Branch() string {
11    return c.params.Branch
12}
13
14func (c *InvocationContext) EndInvocation() {
15    c.params.EndInvocation = true
16}
17
18func (c *InvocationContext) Ended() bool {
19    return c.params.EndInvocation
20}

Рассматриваемый исходный файл: internal/context/invocation_context.go:40-99

Механизм EndInvocation:

  • Установка флага EndInvocation = true останавливает выполнение
  • Проверка Ended() используется в колбэках для контроля потока
  • Позволяет прерывать выполнение из любого места

ReadonlyContext

ReadonlyContext предоставляет доступ только для чтения:

go
1type ReadonlyContext interface {
2    context.Context
3    
4    UserContent() *genai.Content
5    InvocationID() string
6    AgentName() string
7    ReadonlyState() session.ReadonlyState
8    
9    UserID() string
10    AppName() string
11    SessionID() string
12    Branch() string
13}

Рассматриваемый исходный файл: internal/context/readonly_context.go:25-72

Реализация делегирует вызовы:

go
1func (c *ReadonlyContext) AppName() string {
2    return c.InvocationContext.Session().AppName()
3}
4
5func (c *ReadonlyContext) UserID() string {
6    return c.InvocationContext.Session().UserID()
7}
8
9func (c *ReadonlyContext) ReadonlyState() session.ReadonlyState {
10    return c.InvocationContext.Session().State()
11}

Назначение:

  • Безопасное чтение данных сессии без модификации
  • Передача в инструменты и внешние системы
  • Изоляция от случайных изменений состояния

CallbackContext

CallbackContext используется в колбэках с расширенным доступом:

go
1type CallbackContext interface {
2    ReadonlyContext
3    
4    Artifacts() Artifacts
5    State() session.State
6}

Рассматриваемый исходный файл: internal/context/callback_context.go:32-90

Реализация с поддержкой delta:

go
1func NewCallbackContext(ctx agent.InvocationContext) agent.CallbackContext {
2    return newCallbackContext(ctx, make(map[string]any), make(map[string]int64))
3}
4
5func NewCallbackContextWithDelta(ctx agent.InvocationContext, 
6    stateDelta map[string]any, artifactDelta map[string]int64) agent.CallbackContext {
7    return newCallbackContext(ctx, stateDelta, artifactDelta)
8}

Особенности:

  • Расширяет ReadonlyContext доступом к записи
  • Поддерживает stateDelta и artifactDelta для отслеживания изменений
  • Используется в BeforeAgentCallback и AfterAgentCallback

Внутренняя реализация Artifacts:

go
1func (ia *internalArtifacts) Save(ctx context.Context, name string, 
2    data *genai.Part) (*artifact.SaveResponse, error) {
3    resp, err := ia.Artifacts.Save(ctx, name, data)
4    if err != nil { return resp, err }
5    
6    if ia.eventActions != nil {
7        if ia.eventActions.ArtifactDelta == nil {
8            ia.eventActions.ArtifactDelta = make(map[string]int64)
9        }
10        ia.eventActions.ArtifactDelta[name] = resp.Version
11    }
12    return resp, nil
13}

Runner и управление выполнением

Создание Runner

Функция New() в runner/runner.go создаёт оркестратор:

go
1func New(cfg Config) (*Runner, error) {
2    if cfg.Agent == nil {
3        return nil, fmt.Errorf("root agent is required")
4    }
5    
6    if cfg.SessionService == nil {
7        return nil, fmt.Errorf("session service is required")
8    }
9    
10    parents, err := parentmap.New(cfg.Agent)
11    if err != nil {
12        return nil, fmt.Errorf("failed to create agent tree: %w", err)
13    }
14    
15    pluginManager, err := plugininternal.NewPluginManager(...)
16    if err != nil {
17        return nil, fmt.Errorf("failed to create plugin manager: %w", err)
18    }
19    
20    return &Runner{
21        appName:           cfg.AppName,
22        rootAgent:         cfg.Agent,
23        sessionService:    cfg.SessionService,
24        artifactService:   cfg.ArtifactService,
25        memoryService:     cfg.MemoryService,
26        parents:           parents,
27        pluginManager:     pluginManager,
28        autoCreateSession: cfg.AutoCreateSession,
29    }, nil
30}

Рассматриваемый исходный файл: runner/runner.go:78-111

Обязательные компоненты:

  • Agent — корневой агент (обязательно)
  • SessionService — сервис сессий (обязательно)
  • ArtifactService — сервис артефактов (опционально)
  • MemoryService — сервис памяти (опционально)

Валидация:

  • Проверка наличия root-агента
  • Проверка наличия сервиса сессий
  • Построение карты родительских связей через parentmap.New()

Структура Runner

go
1type Runner struct {
2    appName         string
3    rootAgent       agent.Agent
4    sessionService  session.Service
5    artifactService artifact.Service
6    memoryService   memory.Service
7    parents         *parentmap.Map
8    pluginManager   *plugininternal.PluginManager
9    autoCreateSession bool
10}

Рассматриваемый исходный файл: runner/runner.go:113-130

Поля структуры:

ПолеТипНазначение
appNamestringИмя приложения
rootAgentAgentКорневой агент
sessionServiceServiceУправление сессиями
artifactServiceServiceХранение артефактов
memoryServiceServiceДолгосрочная память
parents*MapКарта родительских связей
pluginManager*PluginManagerУправление плагинами
autoCreateSessionboolАвтосоздание сессий

Метод Run

Основной метод выполнения обрабатывает сообщения и генерирует события:

go
1func (r *Runner) Run(ctx context.Context, userID, sessionID string, 
2    msg *genai.Content, cfg agent.RunConfig, opts ...RunOption) iter.Seq2[*session.Event, error] {
3    
4    return func(yield func(*session.Event, error) bool) {
5        options := runOptions{}
6        for _, opt := range opts {
7            opt(&options)
8        }
9        
10        var storedSession session.Session
11        getResp, err := r.sessionService.Get(ctx, &session.GetRequest{
12            AppName:   r.appName,
13            UserID:    userID,
14            SessionID: sessionID,
15        })
16        
17        if err != nil {
18            if !r.autoCreateSession {
19                yield(nil, err)
20                return
21            }
22            createResp, err := r.sessionService.Create(ctx, &session.CreateRequest{...})
23            if err != nil {
24                yield(nil, err)
25                return
26            }
27            storedSession = createResp.Session
28        } else {
29            storedSession = getResp.Session
30        }
31        
32        agentToRun, err := r.findAgentToRun(storedSession, msg)
33        if err != nil {
34            yield(nil, err)
35            return
36        }
37        // ... продолжение выполнения
38    }
39}

Рассматриваемый исходный файл: runner/runner.go:131-170

Алгоритм выполнения:

  1. Применение опций — обработка RunOption для настройки параметров
  2. Получение сессии — запрос существующей или создание новой
  3. Поиск агента — определение агента для выполнения через findAgentToRun
  4. Создание контекста — формирование InvocationContext
  5. Выполнение агента — вызов agent.Run() с итерацией событий

Обработка ошибок:

  • При отсутствии сессии и autoCreateSession=false — возврат ошибки
  • При ошибке создания сессии — возврат ошибки
  • При ошибке поиска агента — возврат ошибки

Колбэки и перехватчики

BeforeAgentCallbacks

Колбэки, выполняемые перед основным кодом агента:

go
1// Тест демонстрирует перехват выполнения
2func TestAgentCallbacks(t *testing.T) {
3    tests := []struct {
4        name         string
5        beforeAgent  []BeforeAgentCallback
6        wantLLMCalls int
7        wantEvents   []*session.Event
8    }{
9        {
10            name: "before agent callback runs, no llm calls",
11            beforeAgent: []BeforeAgentCallback{
12                func(ctx CallbackContext) (*genai.Content, error) {
13                    return genai.NewContentFromText(
14                        "hello from before_agent_callback", 
15                        genai.RoleModel), nil
16                },
17            },
18            wantEvents: []*session.Event{{
19                Author: "test",
20                LLMResponse: model.LLMResponse{
21                    Content: genai.NewContentFromText(
22                        "hello from before_agent_callback", 
23                        genai.RoleModel),
24                },
25            }},
26        },
27    }
28}

Рассматриваемый исходный файл: agent/agent_test.go:29-60

Поведение BeforeAgentCallbacks:

  • Выполняются последовательно в порядке объявления
  • Если любой колбэк возвращает *genai.Content, основной код не выполняется
  • Если любой колбэк возвращает ошибку, выполнение прерывается
  • Возвращённый контент направляется клиенту как ответ агента

EndInvocation в колбэках

Механизм принудительного завершения вызова:

go
1func TestEndInvocation_EndsBeforeMainCall(t *testing.T) {
2    custom := &customAgent{}
3    
4    testAgent, err := New(Config{
5        Name: "test",
6        BeforeAgentCallbacks: []BeforeAgentCallback{
7            func(ctx CallbackContext) (*genai.Content, error) {
8                return nil, nil
9            },
10        },
11        Run: custom.Run,
12    })
13    
14    ctx := &invocationContext{
15        Context:       t.Context(),
16        agent:         testAgent,
17        endInvocation: true,  // Флаг завершения установлен
18        session:       &mockSession{sessionID: "test-session"},
19    }
20    
21    for _, err := range testAgent.Run(ctx) {
22        if err != nil {
23            t.Fatalf("unexpected error from the agent: %v", err)
24        }
25    }
26    
27    // Основной код не вызван из-за endInvocation=true
28    if custom.callCounter != 0 {
29        t.Errorf("unexpected want_llm_calls, got: %v, want: 0", 
30            custom.callCounter)
31    }
32}

Рассматриваемый исходный файл: agent/agent_test.go:155-188

Сценарии использования EndInvocation:

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

AfterAgentCallbacks

Колбэки, выполняемые после основного кода:

go
1func TestEndInvocation_EndsAfterMainCall(t *testing.T) {
2    custom := &customAgent{endInvocation: true}
3    
4    testAgent, err := New(Config{
5        Name: "test",
6        AfterAgentCallbacks: []AfterAgentCallback{
7            func(CallbackContext) (*genai.Content, error) {
8                return genai.NewContentFromText(
9                    "hello from after_agent_callback", 
10                    genai.RoleModel), nil
11            },
12        },
13        Run: custom.Run,
14    })
15    
16    ctx := &invocationContext{
17        Context: t.Context(),
18        agent:   testAgent,
19        session: &mockSession{sessionID: "test-session"},
20    }
21    
22    var gotEvents []*session.Event
23    for event, err := range testAgent.Run(ctx) {
24        if err != nil {
25            t.Fatalf("unexpected error from the agent: %v", err)
26        }
27        gotEvents = append(gotEvents, event)
28    }
29    
30    // AfterAgentCallbacks не выполняются при EndInvocation
31    if custom.callCounter != 1 {
32        t.Errorf("unexpected want_llm_calls, got: %v, want: 1", 
33            custom.callCounter)
34    }
35}

Рассматриваемый исходный файл: agent/agent_test.go:190-228

Особенности AfterAgentCallbacks:

  • Выполняются после основного кода агента
  • Могут модифицировать результат перед отправкой клиенту
  • Не выполняются, если EndInvocation установлен в основном коде

Примеры интеграции

Quickstart — базовый LLM-агент

Минимальный пример создания агента с Gemini:

go
1func main() {
2    ctx := context.Background()
3    
4    model, err := gemini.NewModel(ctx, "gemini-2.5-flash", &genai.ClientConfig{
5        APIKey: os.Getenv("GOOGLE_API_KEY"),
6    })
7    if err != nil {
8        log.Fatalf("Failed to create model: %v", err)
9    }
10    
11    a, err := llmagent.New(llmagent.Config{
12        Name:        "weather_time_agent",
13        Model:       model,
14        Description: "Agent to answer questions about the time and weather in a city.",
15        Instruction: "Your SOLE purpose is to answer questions about the current time and weather in a specific city.",
16        Tools: []tool.Tool{
17            geminitool.GoogleSearch{},
18        },
19    })
20    
21    config := &launcher.Config{
22        AgentLoader: agent.NewSingleLoader(a),
23    }
24    
25    l := full.NewLauncher()
26    if err = l.Execute(ctx, config, os.Args[1:]); err != nil {
27        log.Fatalf("Run failed: %v\n\n%s", err, l.CommandLineSyntax())
28    }
29}

Рассматриваемый исходный файл: examples/quickstart/main.go:4-61

Ключевые компоненты:

  • gemini.NewModel — создание модели Gemini 2.5 Flash
  • llmagent.New — создание LLM-агента с конфигурацией
  • geminitool.GoogleSearch — инструмент поиска Google
  • launcher.Config — конфигурация запуска через Launcher

MCP — интеграция с Model Context Protocol

Пример использования MCP-инструментов:

go
1func main() {
2    ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
3    defer stop()
4    
5    model, err := gemini.NewModel(ctx, "gemini-2.5-flash", &genai.ClientConfig{
6        APIKey: os.Getenv("GOOGLE_API_KEY"),
7    })
8    
9    var transport mcp.Transport
10    if strings.ToLower(os.Getenv("AGENT_MODE")) == "github" {
11        transport = githubMCPTransport(ctx)
12    } else {
13        transport = localMCPTransport(ctx)
14    }
15    
16    mcpToolSet, err := mcptoolset.New(mcptoolset.Config{
17        Transport: transport,
18    })
19    
20    a, err := llmagent.New(llmagent.Config{
21        Name:        "weather_time_agent",
22        Model:       model,
23        Description: "Agent to answer questions about the time and weather in a city.",
24        Instruction: "I can answer your questions about the time and weather in a city.",
25        Tools:       mcpToolSet.Tools(),
26    })
27}

Рассматриваемый исходный файл: examples/mcp/main.go:4-115

Поддерживаемые режимы MCP:

  • local — in-memory MCP-сервер с локальными функциями
  • github — подключение к GitHub MCP API с OAuth-авторизацией

A2A — Agent-to-Agent протокол

Пример взаимодействия между агентами через A2A:

go
1func main() {
2    ctx := context.Background()
3    
4    a2aServerAddress := startWeatherAgentServer()
5    
6    remoteAgent, err := remoteagent.NewA2A(remoteagent.A2AConfig{
7        Name:            "A2A Weather agent",
8        AgentCardSource: a2aServerAddress,
9    })
10    
11    config := &launcher.Config{
12        AgentLoader: agent.NewSingleLoader(remoteAgent),
13    }
14    
15    l := full.NewLauncher()
16    if err = l.Execute(ctx, config, os.Args[1:]); err != nil {
17        log.Fatalf("Run failed: %v\n\n%s", err, l.CommandLineSyntax())
18    }
19}

Рассматриваемый исходный файл: examples/a2a/main.go:3-131

Компоненты A2A:

  • remoteagent.NewA2A — создание удалённого агента
  • AgentCardSource — URL для получения карточки агента
  • adka2a.NewExecutor — исполнитель A2A-запросов

REST API — HTTP-интерфейс

Настройка REST API сервера:

go
1func main() {
2    ctx := context.Background()
3    
4    model, err := gemini.NewModel(ctx, "gemini-2.5-flash", &genai.ClientConfig{
5        APIKey: os.Getenv("GOOGLE_API_KEY"),
6    })
7    
8    a, err := llmagent.New(llmagent.Config{
9        Name:        "weather_time_agent",
10        Model:       model,
11        Description: "Agent to answer questions about the time and weather in a city.",
12        Instruction: "I can answer your questions about the time and weather in a city.",
13        Tools: []tool.Tool{
14            geminitool.GoogleSearch{},
15        },
16    })
17    
18    restServer, err := adkrest.NewServer(adkrest.ServerConfig{
19        AgentLoader:     agent.NewSingleLoader(a),
20        SessionService:  session.InMemoryService(),
21        SSEWriteTimeout: 120 * time.Second,
22    })
23    
24    mux := http.NewServeMux()
25    mux.Handle("/api/", http.StripPrefix("/api", restServer))
26    mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
27        w.WriteHeader(http.StatusOK)
28        w.Write([]byte("OK"))
29    })
30    
31    http.ListenAndServe(":8080", mux)
32}

Рассматриваемый исходный файл: examples/rest/main.go:4-94

Параметры REST-сервера:

  • AgentLoader — загрузчик агентов
  • SessionService — сервис сессий (in-memory)
  • SSEWriteTimeout — таймаут Server-Sent Events

Диаграмма потока данных

正在加载图表渲染器...

Этапы потока данных:

  1. Инициализация — клиент вызывает Runner.Run() с параметрами (runner/runner.go:131-170)

  2. Управление сессией — Runner запрашивает или создаёт сессию через SessionService

  3. Выбор агента — определение агента для выполнения на основе состояния сессии и сообщения

  4. Создание контекста — формирование InvocationContext с параметрами вызова (internal/context/invocation_context.go:40-99)

  5. Выполнение колбэков — последовательный вызов BeforeAgentCallbacks (agent/agent.go:160-190)

  6. Основной код — выполнение функции Run агента при отсутствии прерывания

  7. Постобработка — вызов AfterAgentCallbacks и возврат событий клиенту

Модульные зависимости

正在加载图表渲染器...

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

  1. Уровень входаcmd/launcher инициализирует Runner и Agent
  2. Уровень ядраagent/, runner/, session/ формируют основную логику
  3. Внутренний уровеньinternal/agent/, internal/context/ содержат реализации интерфейсов
  4. Уровень сервисовartifact/, memory/ предоставляют инфраструктурные возможности
  5. Уровень инструментовtool/ и его подпакеты реализуют интеграцию с внешними системами
  6. Уровень протоколовserver/ предоставляет A2A и REST интерфейсы

Технические решения и ограничения

Ключевые архитектурные решения

РешениеОбоснованиеАльтернативы
Интерфейс Agent с методом internal()Скрытие внутренней реализации при сохранении полиморфизмаПубличные поля структуры
Итератор iter.Seq2 для потока событийЛенивое вычисление и эффективная работа с памятьюКаналы chan Event
Трёхуровневая система контекстовГранулярный контроль доступа к ресурсамЕдиный контекст с проверками
Колбэки как функцииГибкость и возможность замыканийИнтерфейсы с методами
parentmap для навигации по деревуO(1) поиск родителя агентаРекурсивный обход дерева
EndInvocation флагМягкое прерывание выполненияpanic/recover или ошибки

Известные ограничения

  1. Отсутствие персистентностиInMemoryService для сессий и артефактов не сохраняет данные между перезапусками

  2. Синхронная модель — несмотря на поддержку ParallelAgent, базовая модель выполнения синхронна

  3. Ограниченная телеметрия — базовая интеграция с OpenTelemetry, требуется расширение для production

  4. Отсутствие версионирования схем — структура State не имеет механизма миграции

  5. Фиксированный Branch format — формат agent_1.agent_2.agent_3 не поддерживает произвольные идентификаторы

Рекомендации по расширению

Добавление нового типа агента:

  1. Определить тип в internal/agent/state.go
  2. Создать конфигурацию в соответствующем пакете
  3. Реализовать функцию Run с итератором событий
  4. Зарегистрировать в фабрике при необходимости

Интеграция с новым протоколом:

  1. Создать пакет в server/ или agent/remoteagent
  2. Реализовать адаптер к интерфейсу Agent
  3. Добавить конфигурацию в launcher.Config
  4. Предоставить пример в examples/