reins框架:把Agent驾驭的”缰绳“握在自己手里

本文档基于实际业务的抽象基础框架,我们给他起了个名字:reins。体现"收敛控制权 + 预算约束",谐音"reigns(统治)“双关。 为了不涉及具体业务,相关业务用”A业务“代替

0. 定位澄清:规范 vs 框架,以及为什么不直接用 Eino

0.1 为什么不直接用 Eino

Eino(字节跳动,Go 生态)是目前 Go 技术栈最成熟的 Agent 编排框架,与本方案最直接竞争。以下是认真评估后的结论:

Eino 擅长的部分(可以直接复用)

  • 强类型 Graph/Chain 编排,利用 Go 泛型保证组件类型安全
  • ChatModel、Tool、Retriever 等基础组件抽象
  • 流式输出(Streaming)管道

Eino 没有解决、也不打算解决的部分(本方案的真正价值所在)

问题Eino 的立场本方案的解法
预算治理:token/time/retry 如何跨 Agent 统一封顶?不内置,由调用方自行实现WorkflowState + BudgetManager,编排层统一持有预算,禁止 Agent 私自重试
审批式 Handoff:Agent 提出的协作建议如何经过审批再执行?不支持,Eino 的 Handoff 是直接转交Handoff 仅为建议,Orchestrator 审批后才执行,防环、防成本放大
会话级配置快照:热更新时如何保证同一 workflow 内行为不漂移?不内置,框架无配置版本化概念config_snapshot_id 绑定到 workflow,全程读取同一快照
可观测性作为协议:UsageStats 是否强制随每次输出上报?可选,各组件实现程度不一AgentOutput.Usage 是必填字段,不填则协议不完整

结论:Eino 解决的是"如何把 LLM 调用和 Tool 调用组合起来”,本方案解决的是"如何在生产中治理 Agent 的预算、控制权、配置一致性和可观测性"。两者不重叠,可以共存——**推荐在 Agent 内部实现中使用 Eino 的 ChatModel/Tool 抽象,而不是自建模型调用层;但 Orchestrator、WorkflowState、BudgetManager、ConfigSnapshot 这些治理机制仍需自建。

graph LR subgraph 自建部分 - Eino 不覆盖 Orchestrator[Orchestrator 编排引擎] WorkflowState[WorkflowState 状态机] BudgetMgr[BudgetManager 预算治理] CtxBuilder[ContextBuilder 上下文裁剪] ConfigSnapshot[ConfigSnapshot 配置快照] end subgraph 可复用 Eino 组件 EinoChatModel[Eino ChatModel] EinoTool[Eino Tool] EinoStream[Eino Streaming] end Orchestrator --> BaseAgent[BaseAgent 接口] BaseAgent --> EinoChatModel BaseAgent --> EinoTool EinoChatModel --> EinoStream

0.2 五个横切关注点的差异化评估

挑刺者指出"只有预算治理和可观测规范有差异化价值",这个判断基本成立

横切关注点成熟框架是否解决差异化程度结论
控制权收敛(审批式 Handoff)部分——LangGraph 有审批节点,Eino 不支持:Go 生态无现成方案必须自建
单一状态源(WorkflowState 持久化)部分——框架提供内存状态,不负责持久化:持久化方案各家不同必须自建
预算驱动执行——所有主流框架均不内置跨 Agent 预算治理必须自建
最小上下文裁剪部分——LangChain 有 memory 组件,但未解决摘要策略自建裁剪策略
可观测强制规范(UsageStats 作为协议必填)——框架提供 callback,但不强制协议层强制

修订后的重点:方案不回避其他三个点(它们仍然需要设计),但明确标注预算治理、审批式 Handoff、可观测规范是本方案相对成熟框架的核心差异化价值。


1. 核心设计哲学

1.1 控制权收敛原则

Agent 只能表达意图,编排层拥有决策权。

Agent 可以提出 handoff 建议,但不能自行移交控制权。Orchestrator 是唯一的运行时决策者。

为什么:Agent 间直接 handoff 在原型好用,但在生产中 WorkflowState 由谁持有、重试由谁发起、防环由谁检测都会产生歧义。控制权收敛是可观测性和可恢复性的根基。

1.2 单一状态源原则

WorkflowState 由编排层唯一持有,Agent 是无状态执行器。

所有运行时状态在编排层落库后再触发下一跳。Agent 接受输入、返回输出,不感知也不持有全局状态。

1.3 最小上下文原则

Agent 只获取完成当前任务所需的最小上下文,由编排层按需裁剪。

Agent 不自拉历史,编排层构造 ContextEnvelope 时主动裁剪。上下文越大,token 成本越高,注意力干扰越强;Agent 自拉上下文则使权限边界和成本都不可控。

1.4 预算驱动执行原则(核心差异化点)

所有资源消耗必须在启动前显式建模,不允许无上限执行。

每个 workflow 启动时分配总预算(deadline/token/retry),编排层同时下发分片预算。预算数值不注入原始值到 Prompt,而是由 Budget Interpreter 在触阈时转译为语义指令。

为什么这是差异化:LLM 调用 × 重试 × fallback × 修复回路的成本叠加效应极强。Eino/LangChain 等框架均不内置跨 Agent 的统一预算管控,这是本方案独立存在的核心理由之一。

1.5 可观测优先原则(核心差异化点)

可观测性是协议的一部分,而不是事后插件。

AgentOutput.Usage必填字段,缺失则协议不完整。TraceContext 的 6 个字段必须在所有内部调用中强制透传。


2. 整体架构

graph TD subgraph 接入层 API[API / CLI / IM] end subgraph 编排层 Orchestration Layer Router[意图路由 Intent Router] Orchestrator[编排引擎 Orchestrator] CtxBuilder[上下文构造器 ContextBuilder] BudgetMgr[预算管理器 BudgetManager] StreamAssembler[流式事件组装器] end subgraph Agent 层 AgentA[Agent A] AgentB[Agent B] AgentN[Agent N ...] end subgraph 工具与执行层 ToolRegistry[工具注册表 ToolRegistry] Tool1[Tool 1] Tool2[Tool 2] end subgraph 模型层 LLM Infra LLMGateway[模型网关 LLMGateway] SecFilter[安全过滤器] Models[(LLM / Embedding)] end subgraph 旁路系统 ConfigService[配置服务 Config Snapshots] ObsSystem[可观测性 OTel / Metrics] EvalSystem[评测系统 Eval] end subgraph 状态存储 Redis[(Redis 热状态)] DB[(DB 审计持久化)] end API --> Router Router --> Orchestrator Orchestrator --> CtxBuilder CtxBuilder --> BudgetMgr Orchestrator --> AgentA Orchestrator --> AgentB Orchestrator --> AgentN AgentA --> ToolRegistry AgentB --> ToolRegistry ToolRegistry --> Tool1 ToolRegistry --> Tool2 AgentA --> LLMGateway AgentB --> LLMGateway Orchestrator --> LLMGateway LLMGateway --> SecFilter SecFilter --> Models Orchestrator --> Redis Orchestrator --> DB Orchestrator --> StreamAssembler StreamAssembler --> API ConfigService -.->|快照| Orchestrator ConfigService -.->|快照| AgentA ObsSystem -.->|Trace| EvalSystem

3. 核心抽象层设计

字段标注说明[通用] 表示与业务无关、可直接复用;[A业务] 表示包含业务假设,其他项目需根据自身场景调整或删除。

3.1 BaseAgent 接口

// AgentDescriptor 描述 Agent 能力,供意图路由和编排层使用
type AgentDescriptor struct {
    Name        string   // [通用] 唯一标识
    Description string   // [通用] 能力描述(用于 LLM 路由)
    InputTypes  []string // [通用] 接受的 artifact 类型
    OutputTypes []string // [通用] 产出的 artifact 类型
    // [通用] 可选元数据,业务层通过 tags 携带自定义属性(如 risk_level、domain 等)
    // 不在接口层内置业务字段,避免通用协议被业务假设污染
    Tags        map[string]string
}

// BaseAgent 是所有 Agent 的统一接口
type BaseAgent interface {
    Run(ctx context.Context, input ContextEnvelope) (AgentOutput, error)
    Describe() AgentDescriptor
}

关于 RiskLevel 的修订:初稿中 AgentDescriptor.RiskLevel 是 A业务 特有的安全分级概念,不应内置到通用接口层。改为通过 Tags["risk_level"] 携带,业务层自行解读;不需要此字段的项目不受影响。

设计原则

  • 单一入口Run 是唯一执行入口,防止编排层绕过协议调用内部方法
  • 无状态约定Run 不依赖实例内部状态,同等输入在任意实例上产生等价输出
  • 可扩展元数据Tags 替代内置业务字段,接口稳定,业务语义在调用方自行解释

3.2 意图路由协议(RouteDecision)

// [通用]
type RouteDecision struct {
    TargetAgent    string   // 主路由目标 Agent 名称
    SecondaryHints []string // 接力意图声明(Orchestrator 消费,不透传 Agent)
    RouteReason    string   // 路由原因,用于审计
    Confidence     string   // "high" | "medium" | "low"
    RuleID         string   // 命中的规则 ID,空字符串表示 LLM 兜底
    ModelVersion   string   // LLM 路由时使用的模型版本
    IsFallback     bool     // 是否为兜底路由
}

关键设计决策

  • SecondaryHints 仅供 Orchestrator 消费,不透传给 Agent
  • Confidence 是 Orchestrator 的风险信号:high 直接执行,medium 激活结果验证钩子,low 保守路由
  • RuleID + ModelVersion + Confidence 三元组是路由层可追溯性基础

路由策略(两级)

flowchart LR Q[用户请求] --> R1{规则匹配} R1 -->|命中| D[RouteDecision confidence=high] R1 -->|未命中| LLM[LLM 分类] LLM -->|置信 medium/high| D LLM -->|置信 low| Fallback[默认 Agent 兜底 or 用户补充输入] Fallback --> D

3.3 工作流状态模型(WorkflowState)

WorkflowState 是系统唯一运行时状态源,由编排层持有和持久化。

type WorkflowStatus string

// [通用] 核心状态
const (
    StatusPending          WorkflowStatus = "pending"
    StatusRouted           WorkflowStatus = "routed"
    StatusRunning          WorkflowStatus = "running"
    StatusWaitingHandoff   WorkflowStatus = "waiting_handoff_approval"
    StatusWaitingUserInput WorkflowStatus = "waiting_user_input"
    StatusPartialFailed    WorkflowStatus = "partial_failed"
    StatusCompleted        WorkflowStatus = "completed"
    StatusFailed           WorkflowStatus = "failed"
    StatusCanceled         WorkflowStatus = "canceled"
)

// [通用] WorkflowState 核心字段
type WorkflowState struct {
    WorkflowID       string         // 全局唯一
    SessionID        string         // "tenant:user:session"
    TenantID         string         // 租户隔离键
    Status           WorkflowStatus
    CurrentAgent     string         // 当前执行中的 Agent
    VisitedAgents    []string       // 已访问 Agent 列表(防环检测)
    StepIndex        int            // 当前步骤序号
    DeadlineMs       int64          // 工作流总截止时间戳(Unix ms)
    RetryBudget      int            // 剩余重试次数
    TokenBudget      int            // 剩余 token 预算
    ConfigSnapshotID string         // 绑定的配置快照(会话内不变)
    ArtifactRefs     []string       // 已产出产物引用
    TraceID          string         // 贯穿全链路的 Trace ID

    // [扩展点] 业务层可通过此字段携带自定义状态,框架不感知
    Extensions       map[string]interface{}
}

关于 needs_manual_review 状态的修订:初稿将其内置为通用状态,但这是 A业务 表达式必须人工审核的业务约束,不应内置在通用状态机中。修订方案:通用状态机只内置上述 9 个状态;“等待人工审核"通过两种机制支持——①业务层在 Extensions 中携带标记;②Orchestrator 提供 ReviewHook 扩展点(见第 5.1 节),业务层注册后在合适时机触发。

状态机转换图

stateDiagram-v2 [*] --> pending pending --> routed : 路由成功 pending --> failed : 路由失败 routed --> running : 开始执行 running --> waiting_handoff_approval : Agent 提出 handoff waiting_handoff_approval --> running : Orchestrator 批准 waiting_handoff_approval --> failed : 拒绝且无可用 Agent running --> waiting_user_input : 需要用户补充信息 waiting_user_input --> running : 用户补充完成 waiting_user_input --> canceled : 超时或用户取消 running --> partial_failed : 非关键步骤失败 partial_failed --> completed : 有可返回结果 partial_failed --> failed : 无可用结果 running --> completed : 成功完成 running --> failed : 执行失败 note right of running 业务层可通过 ReviewHook 在此状态挂起等待人工确认 end note

3.4 Agent 输入协议(ContextEnvelope)

// [通用]
type ContextEnvelope struct {
    TaskInstruction     string       // 针对当前 Agent 的具体任务指令
    ConversationExcerpt []ConvTurn   // 最近 N 轮原文(N 由 ContextBuilder 策略决定)
    ConversationSummary string       // 更早轮次的摘要(摘要策略见 5.2 节)
    Artifacts           []ArtifactRef // 上游结构化产物引用
    SessionMeta         SessionMetadata
    Budgets             ExecutionBudget
    ExecutionHints      *ExecutionHints // 可选,Orchestrator 按需填充
}

// [通用]
type ExecutionBudget struct {
    DeadlineMs  int64
    TokenBudget int
}

// [通用] 执行提示,帮助 Agent 感知自身在 pipeline 中的位置
// 注意:这里使用开放字符串而非枚举,避免框架预设 pipeline 形态
type ExecutionHints struct {
    // [通用] Agent 在当前调用链中的角色描述,影响输出详细程度
    // 示例值:"first_in_chain" | "last_in_chain" | "standalone" | 业务自定义值
    // 非线性 pipeline 的项目可使用不同的语义,框架不做强制约束
    PipelineRole      string

    // [通用] 下游期望的产物类型,引导 Agent 在非终止节点时输出结构化数据
    DownstreamExpects string

    // [通用] 仅用于调试和可观测性,Agent 不应基于此做决策
    ChainIntent       string
}

关于 PipelineRole 的修订:初稿将 first_in_chain | last_in_chain 作为枚举写死,隐含了"线性 pipeline"假设。修订为开放字符串,框架不约束取值——线性 pipeline 项目用 first/last_in_chain,DAG 型项目可自定义语义(如 parallel_branch)。

预算注入策略

条件注入行为
token_budget < 阈值(如 800)追加语义指令:response_constraint: 资源受限,给出简洁直接的回答
deadline_ms < 阈值(如 3000ms)追加语义指令:response_constraint: 时间受限,跳过深度检索
均宽松不注入任何内容
Runtime 层始终设置 max_tokens + HTTP timeout 作为硬约束,与 Prompt 无关

3.5 Agent 输出协议(AgentOutput)

// [通用]
type AgentOutput struct {
    ProtocolVersion string    // 协议版本
    Status          string    // "success" | "partial" | "error"
    Answer          string    // 面向用户的文字答案
    Artifacts       []Artifact

    Handoff    *HandoffSuggestion // 可选,仅为建议
    Confidence ConfidenceSignal
    Usage      UsageStats        // [通用] 必填,缺失视为协议不完整
    Error      *AgentError
    NextAction *NextAction       // 面向用户的下一步提示
}

// [通用]
type Artifact struct {
    ID       string
    Type     string          // 业务层定义类型标签
    Content  json.RawMessage // 见下方说明
    Metadata ArtifactMeta
}

// [通用] 必填
type UsageStats struct {
    InputTokens  int
    OutputTokens int
    ToolCalls    int
    LatencyMs    int64
}

关于 Artifact.Content interface{} 的修订

初稿用 interface{}ProtocolVersion 在序列化后形同虚设——反序列化时仍需 type switch,版本字段无法保护结构变化。

修订方案:将 Content 改为 json.RawMessage,配合 Type 字段实现按类型分发反序列化

// 消费方按 Type 分发,得到强类型结构
switch artifact.Type {
case "feature_list":
    var fl FeatureList
    json.Unmarshal(artifact.Content, &fl)
case "code_snippet":
    var cs CodeSnippet
    json.Unmarshal(artifact.Content, &cs)
}

版本演进机制的真实保护ProtocolVersion 保护的是外层信封结构(AgentOutput 的字段集合),而不是每个 Artifact 的内容结构。Artifact 内容结构的版本由 ArtifactMeta.ContentVersion 字段管理:

type ArtifactMeta struct {
    Version       string // Artifact 内容结构版本(如 "v1", "v2")
    Source        string
    CreatedAt     time.Time
}

版本演进规则

  1. 外层信封(AgentOutput 字段集):新增字段向后兼容,删除/重命名字段升 ProtocolVersion
  2. Artifact 内容结构:新增字段向后兼容,破坏性变更升 ArtifactMeta.Version,消费方按 version 分支处理
  3. 新 Artifact 类型:只新增 Type 枚举值,老消费方收到未知 type 时静默忽略

这是软约定而非硬保护——框架层无法在编译期阻止消费方忽略版本字段。工程团队需通过 review 规范和集成测试来保证版本演进不破坏兼容性。


4. 关键机制设计

4.1 编排机制

模式:Supervisor 主控 + 审批式 Handoff

sequenceDiagram participant U as 用户 participant R as Intent Router participant O as Orchestrator participant A1 as Agent A participant A2 as Agent B U->>R: 用户请求 R->>O: RouteDecision O->>O: 构造 WorkflowState + ContextEnvelope O->>A1: ContextEnvelope (with budgets) A1-->>O: AgentOutput (handoff.target=AgentB) O->>O: 审批 handoff:校验环路 + 预算 + 策略 O->>A2: ContextEnvelope (carry_artifacts) A2-->>O: AgentOutput (status=success) O-->>U: 聚合结果 + 流式事件

Handoff 通用约束

  • Agent 只能提出建议,Orchestrator 审批后才执行
  • 禁止 A → B → C → A 循环(通过 visited_agents 检测)
  • Orchestrator 拒绝 handoff 时,使用当前最优结果兜底

关于"最多一次 Handoff"的标注:初稿将此作为通用限制,但这是 A业务 第一阶段的业务约束(防止在 3 个 Agent 场景中链路过长),而非框架级规则。通用框架层提供 MaxHandoffDepth 配置项,默认值由业务层设置:

// [通用] Orchestrator 配置
type OrchestratorConfig struct {
    // 最大 handoff 深度,0 表示不限制
    // A业务 V1 推荐设为 1,其他场景可调整
    MaxHandoffDepth int
    // 其他配置...
}

ReviewHook 扩展点(替代内置 needs_manual_review 状态):

// [通用扩展点] 业务层注册,在 Agent 输出满足特定条件时触发人工审核流程
type ReviewHook interface {
    // ShouldReview 判断当前输出是否需要人工确认
    ShouldReview(output AgentOutput, state WorkflowState) bool
    // OnReviewRequired 触发时的处理逻辑(如更新 Extensions、发送通知)
    OnReviewRequired(ctx context.Context, output AgentOutput, state *WorkflowState) error
}

A业务 的表达式人工审核通过注册此 hook 实现,而非内置在通用状态机中。

4.2 上下文管理机制

graph LR FullHistory[(完整会话历史 DB)] ActiveCtx[(活跃会话 Redis)] CtxBuilder[ContextBuilder] Envelope[ContextEnvelope] FullHistory -->|历史摘要| CtxBuilder ActiveCtx -->|最近 N 轮| CtxBuilder CtxBuilder -->|裁剪 + 组装| Envelope Envelope -->|下发| Agent

裁剪策略(默认)

内容策略
最近 2 轮对话原文保留
2 轮以前的历史摘要替代(策略见下)
上游 Artifacts按 ID 引用或按 type 裁剪
错误/诊断日志仅保留结构化摘要,不把完整 stderr 塞入 Prompt
RouteDecision.*完全不进入 Prompt

摘要策略(补充初稿的留白)

早期对话历史用摘要替代,但"摘要怎么做"是上下文管理中最容易出错的部分。提供两种默认实现供选择:

方案实现优点缺点适用场景
A: LLM 摘要调用轻量模型对历史对话生成摘要语义保真度高,不丢关键信息引入额外 token 消耗和延迟对话轮次多、上下文依赖强的场景
B: 规则截断保留最近 K 轮,超出则丢弃零成本、零延迟、结果确定早期关键信息可能丢失轮次少、任务相对独立的场景

A业务 推荐选 B(规则截断):A业务 Agent 的每次 workflow 通常独立性较强(问答/特征搜索/表达式生成各自一个任务),跨 workflow 的长期记忆依赖度低,不值得为摘要引入额外的 LLM 调用成本。

摘要接口(支持扩展):

// [通用扩展点] 业务层可自定义摘要策略
type SummaryStrategy interface {
    Summarize(ctx context.Context, turns []ConvTurn, budget TokenBudget) (string, error)
}

// [通用] 默认实现:规则截断(保留最近 K 轮,其余丢弃)
type TruncateSummary struct{ KeepLastK int }

// [可选] LLM 摘要实现,需业务层自行注入 LLMClient
type LLMSummary struct{ Client LLMClient; MaxSummaryTokens int }

ContextEnvelope → Prompt 渲染策略

[System]
{agent_role_description}
当前租户:{tenant_id}  ← 来自 SessionMeta,业务层按需注入
[User]
<context_envelope version="1.0">
  <conversation_excerpt>...</conversation_excerpt>
  <artifacts type="{artifact_type}">...</artifacts>
  <execution_hints>
    pipeline_role: {role}
    downstream_expects: {type}
    <!-- 触阈时追加 response_constraint -->
  </execution_hints>
  <task_instruction>
    {具体任务指令,放在最后,优先级最高}
  </task_instruction>
</context_envelope>

4.3 预算治理机制(核心差异化点)

graph TD WorkflowBudget[WorkflowBudget 总预算] StepBudget[StepBudget 分片预算] BudgetInterpreter[BudgetInterpreter] RuntimeHardLimit[Runtime 硬约束 max_tokens + HTTP timeout] PromptHint[Prompt 语义约束 response_constraint] WorkflowBudget --> StepBudget StepBudget --> BudgetInterpreter BudgetInterpreter --> RuntimeHardLimit BudgetInterpreter --> PromptHint

预算分配规则

预算类型分配方式说明
deadline_ms按步骤比例分配,保留 buffer总 deadline 减已消耗,按剩余步骤均分
token_budget按 Agent 角色分层设置路由 « 问答生成 < 代码生成/修复
retry_budget按资源类型分开计数禁止叠加放大,Agent 不能私自无限重试

预算耗尽处理

  • deadline_ms 耗尽:返回当前最优结果或 partial 状态
  • token_budget 耗尽:停止工具调用,用已有信息生成简洁回答
  • retry_budget 耗尽:返回最后一次结果或错误,不继续重试

4.4 工具注册与调用机制

// [通用]
type Tool interface {
    Name() string
    Description() string
    InputSchema() Schema
    Execute(ctx context.Context, input map[string]interface{}) (interface{}, error)
}

// [通用]
type ToolRegistry interface {
    Register(tool Tool) error
    Get(name string) (Tool, error)
    ListFor(agentName string) []Tool // 按 Agent 权限返回可用工具列表
}

工具调用原则

  • 工具通过注册表统一管理,Agent 不直接实例化工具依赖
  • 工具执行必须继承 ContextEnvelope.Budgets 的超时约束
  • 工具调用失败返回结构化错误,不允许 panic 或静默失败
  • 工具调用次数计入 AgentOutput.Usage.ToolCalls

4.5 LLM 网关抽象

// [通用] 屏蔽厂商差异
type LLMClient interface {
    Chat(ctx context.Context, req ChatRequest) (ChatResponse, error)
    ChatStream(ctx context.Context, req ChatRequest) (<-chan ChatDelta, error)
    Embed(ctx context.Context, texts []string) ([][]float32, error)
}

// [通用]
type ChatRequest struct {
    Messages    []Message
    Tools       []ToolSchema
    MaxTokens   int
    Temperature float32
    ModelHints  ModelHints
}

// [通用] 用意图表达偏好,网关决定实际路由
type ModelHints struct {
    Tier    string // "economy" | "standard" | "premium"
    UseCase string // "generation" | "embedding" | "rerank" | 业务自定义值
    // [说明] "classification" 是 Router 特有场景,其他场景不一定需要
    // UseCase 为开放字符串,不强制枚举,各业务按实际模型分层定义
}

为什么用 Tier 而非具体模型名:硬编码模型名会使切换模型需要修改 Agent 代码。用 Tier 表达意图,网关负责实际路由,Agent 对模型版本迭代免疫。

与 Eino 的关系:此接口可以直接用 Eino 的 ChatModel 实现,不需要重建模型调用层。

4.6 可观测性机制(核心差异化点)

全链路 Trace 字段(所有内部调用强制透传)

// [通用] 必须贯穿全链路
type TraceContext struct {
    TraceID          string // 全链路追踪
    SessionID        string
    WorkflowID       string
    TenantID         string
    AgentName        string // 当前执行节点
    ModelName        string // 实际调用的模型
    ConfigSnapshotID string // 绑定的配置快照版本
}

核心指标维度

维度关键指标
路由层路由准确率、LLM 兜底率
执行层P95/P99 延迟、Agent 错误率、handoff 触发率、fallback 触发率
成本层token 消耗(按 tenant/agent/model 分组)、工具调用次数
质量层置信度分布、partial 完成率

流式事件协议

// [通用]
type StreamEvent struct {
    EventID    string          `json:"event_id"`
    WorkflowID string          `json:"workflow_id"`
    Seq        int             `json:"seq"`       // 严格递增,用于乱序检测
    EventType  string          `json:"event_type"`
    Timestamp  time.Time       `json:"timestamp"`
    Payload    json.RawMessage `json:"payload"`   // 与 Artifact.Content 保持一致,用 RawMessage
    Final      bool            `json:"final"`
}

// [通用] 内置事件类型
const (
    EventWorkflowAccepted     = "workflow.accepted"
    EventRouteResolved        = "route.resolved"
    EventAgentStarted         = "agent.started"
    EventTextDelta            = "text.delta"
    EventArtifactReady        = "artifact.ready"
    EventUserInputRequired    = "user_input.required"
    EventWorkflowCompleted    = "workflow.completed"
    EventWorkflowFailed       = "workflow.failed"
    // [扩展] 业务层可自定义事件类型,前缀用业务域名隔离,如 "A业务.expr.validation.completed"
)

4.7 安全机制

四层安全模型

graph TD Input[用户输入] --> InputFilter[输入过滤 Prompt Injection 检测] InputFilter --> TenantIsolation[租户隔离 tenant_id 强制透传] TenantIsolation --> AgentExec[Agent 执行] AgentExec --> OutputFilter[输出过滤 敏感信息检测] OutputFilter --> User[用户]
安全层机制标注
输入侧Prompt Injection 检测、危险关键词拦截[通用]
租户隔离tenant_id 贯穿路由/检索/上下文/审计[通用]
执行侧工具白名单、工具调用鉴权[通用]
输出侧敏感数据泄漏检测[通用]
代码执行安全沙箱隔离、函数白名单[A业务] 仅表达式场景需要

5. 扩展点设计

// [通用] 编排层扩展点接口集合
type OrchestratorExtensions struct {
    // 上下文摘要策略
    SummaryStrategy SummaryStrategy

    // 人工审核钩子(替代内置 needs_manual_review 状态)
    ReviewHook ReviewHook

    // Handoff 审批策略(允许业务层自定义审批逻辑)
    HandoffApprover HandoffApprover

    // 结果聚合策略(多 Agent 输出如何合并为最终答案)
    ResultAggregator ResultAggregator
}

// [通用] Handoff 审批策略接口
type HandoffApprover interface {
    Approve(suggestion HandoffSuggestion, state WorkflowState) (bool, string)
}

扩展规则

  1. 新 Agent:实现 BaseAgent,注册到编排层,无需修改编排逻辑
  2. 新 Tool:实现 Tool,注册到 ToolRegistry
  3. 新路由规则:通过 ConfigCenter 热更新,无需重启
  4. 新 Artifact 类型:新增 Type 枚举值,老消费方收到未知 type 时静默忽略
  5. 模型切换:修改网关路由配置,Agent 代码零感知
  6. 人工审核:注册 ReviewHook,而不是修改状态机
  7. 摘要策略:注入 SummaryStrategy 实现,支持 LLM 摘要或规则截断

6. 配置治理

配置分类与治理策略

配置类别内容真源热更新
路由规则关键词匹配、LLM 模型选择Git是(读新快照)
Prompt 模板System Prompt、Instruction 模板Git是(读新快照)
Agent 策略timeout/retry/token budgetGit是(读新快照)
模型路由模型分层映射Git是(读新快照)

会话级配置快照

  • Workflow 启动时绑定当前 config_snapshot_id,全程读取同一快照
  • 回滚时按 snapshot 版本回滚,而非直接改线上值
  • 这一机制是框架独立存在的核心价值之一(Eino 不内置此能力)

7. 评测与发布门禁

三层质量门禁

graph LR Change[Prompt/规则/代码变更] --> G1[Golden Set 回归] G1 -->|通过| G2[Trace Replay / Shadow] G2 -->|通过| G3[小流量灰度] G3 -->|指标稳定| FullRollout[全量发布] G1 -->|失败| Reject[拒绝发布] G2 -->|失败| Reject G3 -->|指标越界| AutoRollback[自动回滚]

评测闭环

  • Bad Case 回灌:线上失败样本、误路由样本进入评测集
  • 评测结果驱动优化,不靠直觉改 Prompt

各层评测指标

评测对象核心指标
意图路由路由准确率、LLM 兜底率
Agent 质量任务完成率、置信度分布、partial 率
工具调用工具成功率、平均调用次数
成本每次 workflow 平均 token 消耗

后记

我认为:在多 Agent 的生产系统里,可控性是效率的前提,而不是效率的对立面。

不可控的自治,最终会把工程师的时间消耗在排查"AI 为什么这么做"而不是"让 AI 做得更好"上。

在设计一个 Agent 系统,先不要问"哪个框架最强大”,先问两个问题:出了问题,你能解释清楚它为什么这么做吗?预算耗尽了,有人喊停吗?

这两个问题的答案,决定你的架构选型。

原创声明

本文为博主原创文章,转载请注明出处:https://www.chunshuijiancha.top/posts/llm/agent/base-agent-reins/

© 2026 春水煎茶 - 保留所有权利