Обзор архитектуры
Исходные файлы
Эта страница сгенерирована на основе следующих исходных файлов:
- agent/agent.go
- agent/context.go
- runner/runner.go
- internal/agent/state.go
- agent/agent_test.go
- internal/context/context_test.go
- internal/context/callback_context.go
- internal/context/readonly_context.go
- internal/context/invocation_context.go
- agent/doc.go
- examples/a2a/main.go
- examples/mcp/main.go
- examples/web/main.go
- examples/rest/main.go
- examples/telemetry/main.go
- examples/quickstart/main.go
- examples/toolconfirmation/main.go
- cmd/internal/adkcli/main.go
- examples/tools/loadmemory/main.go
- examples/tools/loadartifacts/main.go
ADK-GO (Agent Development Kit for Go) — это фреймворк для построения многоагентных систем с поддержкой LLM-интеграции, управления сессиями, артефактами и памятью. Архитектура проекта следует принципам модульности и расширяемости, обеспечивая чёткое разделение ответственности между компонентами.
Общая архитектура системы
Проект организован вокруг нескольких ключевых подсистем: ядро агента, система контекстов, оркестратор выполнения (Runner) и набор сервисов для работы с сессиями, артефактами и памятью. Модульная структура позволяет расширять функциональность через колбэки и интеграцию с внешними протоколами.
正在加载图表渲染器...
Ключевые архитектурные решения:
-
Интерфейсно-ориентированный дизайн — базовый интерфейс
Agent(internal/agent/state.go:18-40) определяет контракт для всех типов агентов, обеспечивая полиморфизм и расширяемость. -
Иерархия контекстов — трёхуровневая система контекстов (
InvocationContext→ReadonlyContext/CallbackContext) обеспечивает контролируемый доступ к состоянию и ресурсам (agent/context.go:60-98). -
Централизованный оркестратор —
Runnerуправляет жизненным циклом вызова, интегрируя сервисы сессий, артефактов и памяти (runner/runner.go:78-130). -
Система колбэков —
BeforeAgentCallbacksиAfterAgentCallbacksпозволяют перехватывать и модифицировать поведение без изменения ядра (agent/agent.go:89-91). -
Поддержка внешних протоколов — интеграция с 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 и является фундаментом для всех типов агентов в системе:
go1type 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 определяет параметры создания агента:
go1type 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
Ключевые поля конфигурации:
-
Name — непустая строка, уникальная в дереве агентов; зарезервировано имя "user" для ввода конечного пользователя.
-
Description — используется LLM для определения делегирования управления агенту; предпочтительна однострочная форма.
-
SubAgents — дочерние агенты для делегирования задач; ADK автоматически устанавливает родительские связи.
-
BeforeAgentCallbacks — последовательность колбэков, вызываемых перед основным выполнением; если любой возвращает контент или ошибку, основной код не выполняется.
-
Run — основная функция выполнения, возвращающая итератор событий.
Жизненный цикл выполнения
Метод Run реализует основной цикл выполнения агента:
go1func (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
Этапы жизненного цикла:
- Инициализация телеметрии — создание span для трассировки вызова.
- Создание контекста — формирование
invocationContextс параметрами вызова. - Before-колбэки — последовательный вызов с возможностью прерывания.
- Основной код — выполнение функции
Runиз конфигурации. - After-колбэки — постобработка результатов.
Создание экземпляра агента
Функция New() создаёт экземпляр агента с валидацией:
go1func 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 — центральный интерфейс для управления состоянием вызова:
go1type 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:
go1type 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 предоставляет доступ только для чтения:
go1type 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
Реализация делегирует вызовы:
go1func (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 используется в колбэках с расширенным доступом:
go1type CallbackContext interface { 2 ReadonlyContext 3 4 Artifacts() Artifacts 5 State() session.State 6}
Рассматриваемый исходный файл: internal/context/callback_context.go:32-90
Реализация с поддержкой delta:
go1func 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:
go1func (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 создаёт оркестратор:
go1func 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
go1type 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
Поля структуры:
| Поле | Тип | Назначение |
|---|---|---|
appName | string | Имя приложения |
rootAgent | Agent | Корневой агент |
sessionService | Service | Управление сессиями |
artifactService | Service | Хранение артефактов |
memoryService | Service | Долгосрочная память |
parents | *Map | Карта родительских связей |
pluginManager | *PluginManager | Управление плагинами |
autoCreateSession | bool | Автосоздание сессий |
Метод Run
Основной метод выполнения обрабатывает сообщения и генерирует события:
go1func (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
Алгоритм выполнения:
- Применение опций — обработка
RunOptionдля настройки параметров - Получение сессии — запрос существующей или создание новой
- Поиск агента — определение агента для выполнения через
findAgentToRun - Создание контекста — формирование
InvocationContext - Выполнение агента — вызов
agent.Run()с итерацией событий
Обработка ошибок:
- При отсутствии сессии и
autoCreateSession=false— возврат ошибки - При ошибке создания сессии — возврат ошибки
- При ошибке поиска агента — возврат ошибки
Колбэки и перехватчики
BeforeAgentCallbacks
Колбэки, выполняемые перед основным кодом агента:
go1// Тест демонстрирует перехват выполнения 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 в колбэках
Механизм принудительного завершения вызова:
go1func 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
Колбэки, выполняемые после основного кода:
go1func 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:
go1func 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 Flashllmagent.New— создание LLM-агента с конфигурациейgeminitool.GoogleSearch— инструмент поиска Googlelauncher.Config— конфигурация запуска через Launcher
MCP — интеграция с Model Context Protocol
Пример использования MCP-инструментов:
go1func 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:
go1func 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 сервера:
go1func 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
Диаграмма потока данных
正在加载图表渲染器...
Этапы потока данных:
-
Инициализация — клиент вызывает
Runner.Run()с параметрами (runner/runner.go:131-170) -
Управление сессией — Runner запрашивает или создаёт сессию через
SessionService -
Выбор агента — определение агента для выполнения на основе состояния сессии и сообщения
-
Создание контекста — формирование
InvocationContextс параметрами вызова (internal/context/invocation_context.go:40-99) -
Выполнение колбэков — последовательный вызов
BeforeAgentCallbacks(agent/agent.go:160-190) -
Основной код — выполнение функции
Runагента при отсутствии прерывания -
Постобработка — вызов
AfterAgentCallbacksи возврат событий клиенту
Модульные зависимости
正在加载图表渲染器...
Уровни зависимостей:
- Уровень входа —
cmd/launcherинициализирует Runner и Agent - Уровень ядра —
agent/,runner/,session/формируют основную логику - Внутренний уровень —
internal/agent/,internal/context/содержат реализации интерфейсов - Уровень сервисов —
artifact/,memory/предоставляют инфраструктурные возможности - Уровень инструментов —
tool/и его подпакеты реализуют интеграцию с внешними системами - Уровень протоколов —
server/предоставляет A2A и REST интерфейсы
Технические решения и ограничения
Ключевые архитектурные решения
| Решение | Обоснование | Альтернативы |
|---|---|---|
Интерфейс Agent с методом internal() | Скрытие внутренней реализации при сохранении полиморфизма | Публичные поля структуры |
Итератор iter.Seq2 для потока событий | Ленивое вычисление и эффективная работа с памятью | Каналы chan Event |
| Трёхуровневая система контекстов | Гранулярный контроль доступа к ресурсам | Единый контекст с проверками |
| Колбэки как функции | Гибкость и возможность замыканий | Интерфейсы с методами |
parentmap для навигации по дереву | O(1) поиск родителя агента | Рекурсивный обход дерева |
EndInvocation флаг | Мягкое прерывание выполнения | panic/recover или ошибки |
Известные ограничения
-
Отсутствие персистентности —
InMemoryServiceдля сессий и артефактов не сохраняет данные между перезапусками -
Синхронная модель — несмотря на поддержку
ParallelAgent, базовая модель выполнения синхронна -
Ограниченная телеметрия — базовая интеграция с OpenTelemetry, требуется расширение для production
-
Отсутствие версионирования схем — структура
Stateне имеет механизма миграции -
Фиксированный Branch format — формат
agent_1.agent_2.agent_3не поддерживает произвольные идентификаторы
Рекомендации по расширению
Добавление нового типа агента:
- Определить тип в
internal/agent/state.go - Создать конфигурацию в соответствующем пакете
- Реализовать функцию
Runс итератором событий - Зарегистрировать в фабрике при необходимости
Интеграция с новым протоколом:
- Создать пакет в
server/илиagent/remoteagent - Реализовать адаптер к интерфейсу
Agent - Добавить конфигурацию в
launcher.Config - Предоставить пример в
examples/
