🤖 Agent Platform

Агенты — это DB-сущности, не Python классы. Профиль + методы + sub-agents + selection policy. Выбираются автоматически через agent_selection.py.

Что такое Агент

Агент в clowbot — это комбинация DB-таблиц, которая описывает поведение LLM:

📋 Profile

Goal, tools, models, temperature

🔧 Methods

Prompt templates + tools per method

👥 Sub-agents

Делегирование задач

🎯 Selection Policy

Когда выбирать агента

🔄 Agent Selection Flow

От intent до assembled prompt

1. find_agent_by_policy
Match intent/process/scope
2. get_agent_profile
Load goal, tools, models
3. get_agent_methods
Load prompt templates
4. get_prompt_fragments
Auto-select fragments
5. _assemble_prompt
Combine goal + fragments
6. Return Result
assembled_system_prompt

💻 Код: select_agent

# bot/app/services/agent_selection.py
async def select_agent(
    db, *,
    intent: str = "",           # "web_search", "code", "summarize"
    process_code: str = "",     # "direct_chat", "travel_research"
    scope: str = "direct",      # "direct", "group", "operator"
    user_text: str = "",
    complexity: str = "simple", # "simple", "complex", "high"
) -> dict[str, Any]:

    # 1. Поиск по политике
    matched = await db.find_agent_by_policy(
        intent=intent,
        process_code=process_code,
        scope=scope,
    )

    if matched:
        agent_code = matched["agent_code"]
    else:
        agent_code = "core_orchestrator"  # Fallback

    # 2. Загрузка профиля
    profile = await db.get_agent_profile(agent_code)
    methods = await db.get_agent_methods(agent_code)
    sub_agents = await db.get_agent_sub_agents(agent_code)

    # 3. Загрузка prompt fragments
    fragments = await db.get_agent_prompt_fragments(agent_code)
    if not fragments:
        # Auto-select fragments by type/family
        fragment_type = _infer_fragment_type(intent)  # "research", "coding", etc.
        agent_family = _infer_agent_family(agent_code)  # "orchestrator", "researcher"
        fragments = await db.get_top_prompt_fragments(
            fragment_type=fragment_type,
            agent_family=agent_family,
            limit=3,
        )

    # 4. Сборка system prompt
    assembled_prompt = _assemble_prompt(profile, fragments)
    prompt_hash = hashlib.sha256(assembled_prompt.encode()).hexdigest()[:16]

    # 5. Return result
    return {
        "selected_agent_code": agent_code,
        "assembled_system_prompt": assembled_prompt,
        "system_prompt_hash": prompt_hash,
        "fragment_ids": [f["fragment_id"] for f in fragments],
        "allowed_tools": list(profile.get("allowed_tools") or []),
        "forbidden_tools": list(profile.get("forbidden_tools") or []),
        "preferred_model": (profile.get("preferred_models") or [""])[0],
        "default_temperature": float(profile.get("default_temperature") or 0.7),
        "execution_mode": _infer_execution_mode(intent, complexity),
        "selection_reason": f"intent_match={intent}",
        "methods": methods,
        "sub_agents": sub_agents,
    }

📝 Prompt Assembly

Fragment Assembly Modes

prependДобавить в начало
appendДобавить в конец (default)
replaceЗаменить всё

Assembly Order

1. prepend fragments
2. profile.goal
3. tools info (allowed/forbidden)
4. append fragments
# _assemble_prompt()
def _assemble_prompt(profile, fragments) -> str:
    parts = []

    # 1. Goal
    goal = profile.get("goal", "").strip()
    if goal:
        parts.append(goal)

    # 2. Tools
    allowed = profile.get("allowed_tools") or []
    forbidden = profile.get("forbidden_tools") or []
    if allowed:
        parts.append(f"Available tools: {', '.join(allowed)}")
    if forbidden:
        parts.append(f"Forbidden tools: {', '.join(forbidden)}")

    # 3. Fragments
    prepend = []
    append = []
    for frag in fragments:
        content = frag.get("content", "").strip()
        mode = frag.get("assembly_mode", "append")
        if mode == "prepend":
            prepend.append(content)
        elif mode == "replace":
            return content  # Replace everything
        else:
            append.append(content)

    # 4. Combine
    return "\n\n".join(prepend + parts + append)

🎯 Intent → Fragment Type

web_search, web
→ research
code, sql, db
→ coding
plan, decompose
→ planning
summarize, digest
→ summarization
review, evaluate
→ review
workflow, automate
→ tool_use
другие
→ system (default)

🗄️ DB Schema

agent_profile

agent_code (text, PK)
goal (text)
description (text)
role (text)
task_types (text[])
allowed_tools (text[])
forbidden_tools (text[])
preferred_models (text[])
default_temperature (numeric)
response_contract (jsonb)
safety_level (text)
review_mode (text)
delegation_depth (int)
is_active (bool)

agent_methods

method_code (text, PK)
agent_code → agent_profile
method_type (text)
├ prompt, tool, workflow
prompt_template (text)
tools (text[])
input_schema (jsonb)
output_schema (jsonb)
is_default (bool)

agent_sub_agents

parent_agent_code → agent_profile
child_agent_code → agent_profile
delegation_type (text)
├ auto, manual
trigger_condition (jsonb)
PK: (parent, child)

agent_selection_policy

policy_id (uuid, PK)
agent_code → agent_profile
match_intent (text[])
match_process_code (text[])
match_scope (text[])
priority (int)
is_active (bool)

💡 Примеры агентов

COREcore_orchestrator— Fallback agent

Главный оркестратор. Выбирается когда нет точного match.

Methods
coordinate, delegate, summarize
Sub-agents
researcher, coder, planner
Tools
web_search, db_query
RESEARCHweb_researcher

Поиск и синтез информации из интернета.

Intents: web_search, web, research, search
CODEcoder_executor

Написание и выполнение кода, SQL queries.

Intents: code, sql, db, data, analytics

🛠️ Создание нового агента

POLICY EDraft → Review → Approval → Deploy

Авто-деплой новых агентов запрещён. Требуется human approval.

# Создание агента через SQL
-- Step 1: Create profile (DRAFT status)
INSERT INTO clowbot.agent_profile (
    agent_code, goal, description,
    allowed_tools, forbidden_tools,
    preferred_models, default_temperature,
    safety_level, review_mode, is_active
) VALUES (
    'my_custom_agent',
    'You are a custom agent for specific tasks...',
    'Handles X, Y, Z tasks',
    ARRAY['tool_a', 'tool_b'],
    ARRAY['dangerous_tool'],
    ARRAY['phi4-mini', 'llama3.2:3b'],
    0.3,
    'safe',
    'human_approval',
    false  -- Not active until approved
);

-- Step 2: Add methods
INSERT INTO clowbot.agent_methods (agent_code, method_code, method_type, prompt_template)
VALUES
    ('my_custom_agent', 'analyze', 'prompt', 'Analyze: {{input}}'),
    ('my_custom_agent', 'summarize', 'prompt', 'Summarize: {{input}}');

-- Step 3: Add selection policy
INSERT INTO clowbot.agent_selection_policy (
    agent_code, match_intent, match_process_code, priority, is_active
) VALUES (
    'my_custom_agent',
    ARRAY['custom_task', 'my_intent'],
    ARRAY['my_process'],
    100,
    true
);

-- Step 4: Review & Approve (manual step)
UPDATE clowbot.agent_profile
SET is_active = true
WHERE agent_code = 'my_custom_agent';

🔧 Troubleshooting

Агент не выбирается

Проверьте agent_selection_policy.match_intent — должен содержать intent. Проверьте is_active = true.

Fallback на core_orchestrator

Нормально если нет точного match. Проверьте selection_reason в ответе.

Prompt fragments не находятся

Проверьте prompt_fragments table и agent_family mapping.

🔗 Связанные страницы