Определяйте агента контрактом, а не профессией
Название "архитектор" не задаёт допустимые входы, writes и handoffs. Исполняемый контракт делает роль проверяемой и ограничивает blast radius. Роль должна отвечать на инженерные вопросы: какие task kinds она принимает, какие tools видит, куда может писать, кому передаёт управление, какой output schema возвращает и сколько ресурсов получает. Prompt описывает качественное поведение внутри этих границ, но не заменяет enforcement.
readonly maxAttempts: number;
}
export interface AgentContract {
readonly id: AgentId;
readonly accepts: readonly TaskKind[];
readonly allowedWritePrefixes: readonly string[];
readonly allowedHandoffs: readonly AgentId[];
}
export interface Usage {
readonly calls: number;
readonly tokens: number;
readonly costUnits: number;
readonly simulatedLatencyMs: number;
}
export interface ArtifactDraft {
readonly key: string;
readonly content: string;
readonly expectedVersion: number;
}
export interface Artifact extends ArtifactDraft {
readonly version: number;
readonly writer: AgentId;
}
export interface Evidence {
readonly name: string;
readonly passed: boolean;
readonly details: string;
}
export interface AgentResult {
readonly summary: string;
readonly artifacts: readonly ArtifactDraft[];
readonly evidence: readonly Evidence[];
readonly usage: Usage;
}
export interface AgentContext {
readonly runId: string;
readonly task: WorkItem;
readonly inputArtifacts: readonly Artifact[];
readonly attempt: number;
}
export interface AgentHandler {
readonly contract: AgentContract;Каждое поле контракта проверяется в своём месте - и это стоит держать перед глазами.
Поле · Назначение · Где проверять
- accepts - Допустимые виды work item; До model call
- allowedWritePrefixes - Владение artifacts; При каждом write
- allowedHandoffs - Разрешенные ребра topology; При создании handoff
- output schema - Machine-readable результат; До fan-in
- budget - Calls, tokens, time и cost; В control plane
Проверку capability тоже делает код, а не просьба в prompt.
for (const task of tasks) {
visit(task.id);
}
}
export function validateHandlers(handlers: readonly AgentHandler[]): void {
const ids = new Set<string>();
for (const handler of handlers) {
if (ids.has(handler.contract.id)) {
throw new Error(`Duplicate agent handler: ${handler.contract.id}`);
}
ids.add(handler.contract.id);
}
}
export function assertTaskAccepted(contract: AgentContract, task: WorkItem): void {Хорошая специализация - это разные границы, а не разные имена. Specialist отличается собственным контекстом, tools, permissions, output schema или evaluation rubric. Если отличаются только имя и одна строка character prompt, вероятно, это одна функция с параметром. И версионируйте контракт вместе с eval cases: изменение allowed tools или write scope - это изменение безопасности, а не косметическая правка prompt.
Контракт задаёт границы роли. Первая из них по стоимости и рискам - контекст, и его надо изолировать.