loop

package
v0.0.0-...-1c978d5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 17, 2026 License: Apache-2.0 Imports: 26 Imported by: 0

Documentation

Overview

dedup.go:重复调用断路器(Ring 0)。同一轮内,同一能力用完全相同的参数 反复调用是弱模型的高频退化形态(实测:同参 python 连打十几次、同参 read_result 打转,直到 max steps 把轮次拖死)。L1 只祈使"报错不要同参 重试",对"成功但反复调"没有硬约束——这里补上:

第 2 次重复 → 照常执行,结果后附加提醒;
第 3 次起   → 不再执行,回放上次结果并要求换路径。

重复的判定分两档:纯工具 = 同参**且**同结果(结果确定,变化说明是 轮询类,重置计数);kind=skill = **仅同参**——技能结果是子循环模型 生成的自然语言,每次措辞都不同,按结果判定永不触发(实测同参 mutating 技能连执行 5 次),而同轮内同参重调技能几乎必然是退化。

计数按 (执行域, 能力, 参数) 分键,存轮内状态袋(runctx.TurnState), 轮结束即弃;参数一变即重置。无轮语义(未经 agent 入口装袋)不介入。

deliver.go:交付物捕获(Ring 0)。标记了 Deliver 语义的能力返回后, 原文存底(复用结果暂存后端)并收进轮级 sink,给模型的结果前缀注入 引用标记——终答引用 #dN 即原文随行,大脑不再拥有转述权。 设计:docs/deliverable-channel-plan.md;链位:Dedup 内侧(回放不重捕)、 Digest 内侧(捕获的是未消化原文)。

nested.go:组件内部模型调用的 callback 切面。digest 摘要、压缩摘要、 守卫弹回等"包装器内部再调模型"的场景,graph 节点切面只覆盖最外层 Generate,内层调用对进度/tracing 不可见(实测一次 46s 的黑箱 span 里 藏着三次弹回)。按 eino 文档建议:内层调用用 ReuseHandlers 换 RunInfo 并自行上报 OnStart/OnEnd/OnError,使其成为独立可见的子 span。

progress.go:能力执行的进度事件发射门(Ring 0)。

事件从能力包装层发射而非 eino 回调:这里拿得到 capability.Meta 的 真值(Ref.Kind/Domain/Name)——skill 和 tool 在 eino 眼里都是 Tool, 只有能力层分得清。模型事件仍由 observe 切面发射(observe.ProgressEvents 已不再发 Tool 事件,两边不双发)。无订阅零开销(EmitProgress 判 nil)。

Package loop 提供主循环的运行时保障(Ring 0):提示词分层拼装、 上下文压缩、预算控制、审批拦截、结构化输出。这些是"模型没得选的 规则"——如果做成工具,模型可以选择不用,保证就不存在了。

review.go:生成评审统一层(Ring 0)。借 eino ADK ShouldRetry 的洞察—— 质量否决与重试是同一个接缝——把伪调用/空头承诺/计划收口/重复调用等 守卫收敛为"一个有界评审循环 + 有序评审器列表":

尝试生成 → 依序征询 Reviewer(首个非 Accept 生效)
  Accept → 放行;Force → 以 Replace 收束(不再评审);
  Retry  → Append 纠正 / Rewrite 改写输入,受全局预算与退避约束。

全局重试预算取代旧守卫链各自计数的乘法放大(2×2×2 无全局闸); 顺序从包装嵌套的隐式约定变为显式列表;新增守卫 = 写一个纯函数。 守卫是纠偏不是硬闸:预算耗尽后放行最后一次输出。 轮次终止级错误(TurnTerminal/HITL 中断)直接透传,不进评审—— 那是给框架看的信号,不是给模型看的质量问题。 设计全文见 docs/review-model-design.md。

Index

Constants

View Source
const DefaultLoopPrompt = loopPromptHead + loopPromptTodo + loopPromptTail

DefaultLoopPrompt 是完整版 L1(工具面含 todo)。

View Source
const DefaultLoopPromptNoTodo = loopPromptHead + loopPromptTail

DefaultLoopPromptNoTodo 是 L1 的裁剪变体:去掉任务管理一节,供工具面上 没有 todo 的循环使用(component 内部循环、关闭 todo 的 agent)—— 提示词不承诺工具面上不存在的工具。

View Source
const DefaultMaxToolResultLen = 8000

DefaultMaxToolResultLen 是工具结果进入上下文的默认截断长度(rune)。 MCP 等外部工具可能返回任意大的结果,不设防会直接打爆窗口。

View Source
const DefaultToolTimeout = 5 * time.Minute

DefaultToolTimeout 是工具单次调用的默认超时。MCP 等外部工具可能 无限悬挂,不设防会挂死整个循环。

View Source
const TagRawResult = capability.TagRawResult

TagRawResult 别名 core 的跨层常量(见 capability.TagRawResult); 语义:能力的结果不参与消化(结果本身就是给模型的 受控输出,如 read_result 的分页;供给方也可用它显式豁免)。

Variables

View Source
var CompletionNoticeGuard = true

CompletionNoticeGuard 控制"纯完成状态"收口拦截是否生效(真机 A/B 用开关做 对照)。默认开:实测 MiniMax 在多步 + todo 任务上约 1/3 概率把最终消息答成 一句"任务已全部完成"、零实质内容——这是把内容整体替换掉,不是多说一句。

Functions

func BudgetModel

BudgetModel 给模型套上预算控制(Ring 0):

  • 硬上限:超出即返回 ErrBudgetExhausted,循环终止;
  • 软阈值(80%):向输入追加收尾指令,让大脑尽快给出回答而非被硬断。

门闸从 ctx 读取(由 agent 每次运行装入),未装入时透传不设限。 预算按会话隔离,skill/component 内部调用同样计入。

func CheckedFinish

func CheckedFinish(m model.ToolCallingChatModel, checks ...func(context.Context) string) model.ToolCallingChatModel

CheckedFinish 是可插拔收口检查的兼容外观:= 单评审器的 ReviewModel。 检查由装配层注入并自行节流(经 runctx.TurnState);无检查时原样返回。

func Compactor

Compactor 返回调用层压缩的 MessageRewriter:历史超过阈值时, 把较早的消息摘要为一条 system 记录,保留最近若干条。

压缩是低频的一次性事件,不是持续重写:一旦压缩,后续调用复用 缓存的(切割点, 摘要)重建视图——前缀稳定,供应商的 prompt cache 在两次压缩之间持续命中;直到视图再次超阈值才做增量归并重压。 摘要失败时保守地返回原历史(压缩是优化,不是正确性前提)。

锚定保护:视图头部除摘要外常驻本段首条用户消息原文——多次归并后 "最初的任务"不漂移。缓存按 (agent, session, 执行域) 分键,并行 调用同一 component 不互相抖动。

func ControlTools

func ControlTools(caps []capability.Capability) []capability.Capability

ControlTools 给能力集套上运行控制切面。应位于审批闸门之外 (中断时连批准都不再询问)、轨迹记录之内(插话是模型看到的内容, 应入记录)。ctx 无控制态时零开销。

func ConversationSnapshot

func ConversationSnapshot(ctx context.Context) []*schema.Message

ConversationSnapshot 返回调用方对话快照,未装入时为 nil。

func DedupCalls

func DedupCalls(caps []capability.Capability) []capability.Capability

DedupCalls 给能力集套上重复调用断路器。

func DeliverResults

func DeliverResults(caps []capability.Capability) []capability.Capability

DeliverResults 给能力集套上交付物捕获。所有能力都过调用计数(direct 判定需要全局调用序);仅 Meta.Deliver 非空的能力做捕获。

func DeniedCallsCheck

func DeniedCallsCheck(ctx context.Context) string

DeniedCallsCheck 是收口检查(经 CheckedFinish 注入):本轮存在被用户 拒绝的调用时,弹回一次要求终答如实区分已执行与被拒绝的操作——实测 模型会把被拒的调用也标成"已完成"(诚实性,Ring 0 兜底)。每轮最多一次。

func DigestResults

func DigestResults(caps []capability.Capability, m model.ToolCallingChatModel, over, degradeKeep int) []capability.Capability

func FinishGuard

FinishGuard 是"收口守卫"的兼容外观:= 单评审器的 ReviewModel(预算 沿旧值 finishGuardBounces,行为与旧实现逐位一致——既有行为测试是 迁移验收线)。组合装配请直接用 ReviewModel(评审器列表 + 全局预算), 见 docs/review-model-design.md。

func ForkMessages

func ForkMessages(ctx context.Context, task *schema.Message) []*schema.Message

ForkMessages 组装 fork 起始消息:请求了 fork 且快照存在时,返回 [背景标注 + 快照 + task];否则只返回 [task]。供 skill/子 agent 的 invoke 路径统一调用。

func GateApproval

func GateApproval(caps []capability.Capability, mode ApprovalMode) []capability.Capability

GateApproval 给能力集套上审批闸门:Risk ≥ mutating 的能力在执行前 按 mode 处理。拒绝结果以工具返回值回传模型(而非错误),让大脑 换路径或向用户说明,循环不中断。

func GateApprovalCtx

func GateApprovalCtx(caps []capability.Capability) []capability.Capability

GateApprovalCtx 同 GateApproval,但放行策略在调用时从 ctx 解析 (由 agent 经 WithApprovalMode 装入,缺省 interactive)。skill 与 component 的内部工具面用它套闸:同一能力被不同审批策略的 agent 复用时,各自的模式经 ctx 生效,内部改动操作不再因"skill 边界批准 一次"而裸奔。

func ProgressTools

func ProgressTools(caps []capability.Capability) []capability.Capability

ProgressTools 给能力集套上进度发射(应用在门链最外层:事件时长 对齐"模型发起调用到结果回来"的用户体感,含审批等待)。

func ReadResult

func ReadResult() capability.Capability

ReadResult 构造内置的原文取回工具:配合结果消化使用,按 id 与 offset 分页读取被消化结果的原文。启用消化的工具面应同时挂载它。

func RecordTools

func RecordTools(caps []capability.Capability) []capability.Capability

RecordTools 给能力集套上轨迹记录(应为最外层包装:记录的是模型 实际看到的结果,包括内层闸门的拒绝/超时消息)。ctx 无记录器时零开销。

func RepeatBreak

RepeatBreak 是重复调用模型层终止器的兼容外观:= 单评审器的 ReviewModel。组合装配请直接用 ReviewModel(见 review.go)。

func RetryModel

RetryModel 给模型套上瞬时错误重试(指数退避)。只重试限流/瞬时 服务端/网络类错误;预算耗尽、参数错误等确定性失败立即返回。 应包在预算控制内侧:重试属于同一次逻辑调用,不重复计费预算次数。

func ReviewModel

ReviewModel 给模型套上评审循环(全局预算 reviewMaxRetries)。 无评审器时原样返回。

func SafeCut

func SafeCut(msgs []*schema.Message, cut int) int

SafeCut 返回不拆散 tool-call 配对的切割点(向后推进跳过 tool 消息)。

func Summarize

Summarize 把一段对话与执行记录压缩为要点摘要。内容策略可经 cfg.Prompt 配置(领域自定义"保留清单"),归并指令由框架追加。 会话滚动摘要持久化(agent 包)复用此函数。

func TimeoutTools

func TimeoutTools(caps []capability.Capability, d time.Duration) []capability.Capability

TimeoutTools 给能力集套上单次调用超时(Ring 0)。超时以工具结果 回传模型(而非错误),让大脑换路径推进,循环不中断;宿主 ctx 被 取消时则原样传播错误。d==0 用默认值,<0 关闭。

两类豁免:审批闸门应在本闸外侧(人工批准的等待不计入执行超时); 带 TagInteractive 的交互类能力(ask_user 等)不套闸——等人回复的 时间不是执行时间。

func TrajectoryMessage

func TrajectoryMessage(records []ToolRecord, mode RecordMode) *schema.Message

TrajectoryMessage 把一轮的工具记录渲染为一条 system 消息,随会话 持久化——下一轮织入后模型知道自己做过什么、看到过什么。 无记录时返回 nil。

func Transient

func Transient(err error) bool

Transient 判断错误是否值得重试。预算耗尽与 ctx 取消永不重试。

func TruncateResults

func TruncateResults(caps []capability.Capability, maxLen int) []capability.Capability

TruncateResults 给能力集套上结果截断闸门(Ring 0):任何工具的 返回超过 maxLen 即截断并附说明,让模型知道内容不完整、可换参数 缩小范围。maxLen==0 用默认值,<0 关闭截断。

func TurnHistory

func TurnHistory(ctx context.Context) []*schema.Message

TurnHistory 返回本轮的全量会话记录,未装入时为 nil。

func WithApprovalMode

func WithApprovalMode(ctx context.Context, mode ApprovalMode) context.Context

WithApprovalMode 把审批模式装入 ctx,对下游 GateApprovalCtx 套闸的 能力生效。

func WithApprovalState

func WithApprovalState(ctx context.Context, st *ApprovalState) context.Context

WithApprovalState 把审批运行态装入 ctx。

func WithBudget

func WithBudget(ctx context.Context, g *BudgetGate) context.Context

WithBudget 把预算门闸装入 ctx,对下游所有 BudgetModel 包装的模型生效。

func WithControl

func WithControl(ctx context.Context, c *ControlState) context.Context

WithControl 把会话控制装入 ctx。

func WithConversationSnapshot

func WithConversationSnapshot(ctx context.Context, msgs []*schema.Message) context.Context

WithConversationSnapshot 把调用方对话快照装入 ctx(agent 每轮装入)。

func WithResultStore

func WithResultStore(ctx context.Context, s *ResultStore) context.Context

WithResultStore 把结果暂存装入 ctx。

func WithToolRecorder

func WithToolRecorder(ctx context.Context, r *ToolRecorder) context.Context

WithToolRecorder 把记录器装入 ctx,对下游 RecordTools 包装的能力生效。

func WithTurnHistory

func WithTurnHistory(ctx context.Context, all []*schema.Message) context.Context

WithTurnHistory 把本轮开始时加载的全量会话记录(含摘要标记)装入 ctx,由 agent 每轮安装。与快照/预算/记录器同族:本轮运行态经 ctx 下发,下游组件(L4 召回等)复用同一份数据,一轮只读一次 store。

Types

type ApprovalMode

type ApprovalMode string

ApprovalMode 决定改动性操作的放行策略。

const (
	// ApprovalAuto 自动放行(可信环境/离线批处理)。
	ApprovalAuto ApprovalMode = "auto"
	// ApprovalInteractive 经 runctx 的交互通道请求批准(CLI/飞书卡片)。
	ApprovalInteractive ApprovalMode = "interactive"
	// ApprovalDeny 一律拒绝(只读部署)。
	ApprovalDeny ApprovalMode = "deny"
)

type ApprovalPolicy

type ApprovalPolicy struct {
	Remember bool           `yaml:"remember"`
	Rules    []ApprovalRule `yaml:"rules"`
}

ApprovalPolicy 是 agent 的审批策略:规则自上而下首条命中生效, 无命中回落 ask。Remember 启用会话级决策记忆(用户选择"总是允许/ 拒绝"后,同会话内同一能力不再重复询问)。

type ApprovalRule

type ApprovalRule struct {
	// Ref 是 CapRef 模式(支持通配),空 = 任意能力。
	Ref string `yaml:"ref"`
	// Args 是参数名 → 值模式(精确、前缀 foo* 或 *),全部命中才算命中;
	// 参数缺失视为不命中。空 = 不看参数。
	Args map[string]string `yaml:"args"`
	// Action 是命中后的动作:allow(免批放行)| ask(照常审批)| deny(直接拒绝)。
	Action string `yaml:"action"`
}

ApprovalRule 是一条参数级审批规则。静态 Risk 分级回答不了"同一个 工具因参数而异的危险性"(给自己人发消息 vs 对外发消息),规则把 放行策略下沉到 (能力, 参数) 粒度。

type ApprovalState

type ApprovalState struct {
	Mode ApprovalMode
	// contains filtered or unexported fields
}

ApprovalState 是 agent 级的审批运行态:模式 + 编译后的策略 + 决策 记忆。由 agent 在每次运行装入 ctx,对主循环与 skill 内部统一生效。

决策记忆两种模式(装配层注入,消费方不感知):kv == nil 用进程内有界 LRU(单副本默认);kv != nil 落 store.KV,"总是允许/拒绝"的决定跨副本 生效——同一会话打到另一副本不再重复询问。键按 (agent, session, 能力) 隔离。

func NewApprovalState

func NewApprovalState(mode ApprovalMode, policy ApprovalPolicy, kv store.KV, ttl time.Duration) (*ApprovalState, error)

NewApprovalState 编译策略并构造运行态,规则非法时报错(fail fast)。 kv 为 nil 时决策记忆留在进程内,非 nil 落外置后端(跨副本一致)。

type Attempt

type Attempt struct {
	N    int               // 第几次尝试(1 起)
	Msgs []*schema.Message // 本次实际发送的消息
	Out  *schema.Message   // Err == nil 时有效
	Err  error
	// contains filtered or unexported fields
}

Attempt 是一次模型生成的完整上下文,交给评审器裁决。

func (Attempt) Tally

func (a Attempt) Tally(reason string) int

Tally 返回同名 Reason 的评审器此前已触发的次数——评审器据此自限 (如"最多纠正 2 次,之后强制收束"),自身保持纯函数。

type BudgetConfig

type BudgetConfig struct {
	MaxModelCalls int `yaml:"max_model_calls" json:"max_model_calls"`
	MaxTokens     int `yaml:"max_tokens" json:"max_tokens"`
}

BudgetConfig 是单个会话可花费的预算上限,零值字段不限制。

type BudgetGate

type BudgetGate struct {
	// contains filtered or unexported fields
}

BudgetGate 是"配置 + 按会话累计"的预算门闸。它由 agent 在每次 运行时装入 ctx,BudgetModel 包装的模型从 ctx 读它扣费——因此 skill/component 内部的模型调用也计入调用方 agent 的会话预算, 不再是治理盲区。

账目后端两种模式(装配层注入,消费方不感知):

  • kv == nil:进程内有界 LRU(单副本默认,零依赖);
  • kv != nil:落 store.KV(redis 等),同一会话打到不同副本共用一份 账目,预算是真正的分布式硬上限。键按 (agent, session) 隔离。

func NewBudgetGate

func NewBudgetGate(cfg BudgetConfig, kv store.KV, ttl time.Duration) *BudgetGate

NewBudgetGate 创建预算门闸。零值配置 = 只统计不设限;kv 为 nil 用 进程内账目,非 nil 落外置后端(跨副本一致),ttl 为账目保留时长。

func (*BudgetGate) Spend

func (g *BudgetGate) Spend(ctx context.Context) (int64, int64)

Spend 返回某会话的累计花费(calls, tokens),供打点与计费。

type CompactionConfig

type CompactionConfig struct {
	// MaxMessages 触发压缩的消息条数阈值。
	MaxMessages int `yaml:"max_messages" json:"max_messages"`
	// MaxTokens 触发压缩的 token 阈值。优先用供应商回报的真实用量
	// 校准(最近一条 assistant 的 Usage + 其后消息的估算),缺用量时
	// 按字符估算。
	MaxTokens int `yaml:"max_tokens" json:"max_tokens"`
	// KeepRecent 压缩后保留的最近消息条数,默认 MaxMessages/2(或 10)。
	KeepRecent int `yaml:"keep_recent" json:"keep_recent"`
	// Prompt 覆盖摘要的内容策略(保留什么、领域侧重),字面量或
	// {ref: cap://prompt...};缺省用内置。归并指令由框架无条件追加,
	// 不随本字段被覆盖(增量归并是压缩算法的机制部分)。
	Prompt prompt.Value `yaml:"prompt" json:"-"`

	// ToolClearOver 启用旧轮工具结果清理(借 eino ADK ToolReduction 的
	// Clear 阶段设计):保护窗之外的 tool 消息,内容超过该 rune 数即
	// 替换为占位。比整段摘要便宜一个量级——纯字符串操作、零模型调用;
	// 先清理后压缩,摘要输入也更小。0 = 关闭。已消化(digest)的结果
	// 带取回指针,跳过不清。
	ToolClearOver int `yaml:"tool_clear_over" json:"tool_clear_over"`
	// ToolClearKeep 清理保护窗:最近 N 条消息不清,默认取 KeepRecent
	// (未配压缩时默认 8)。
	ToolClearKeep int `yaml:"tool_clear_keep" json:"tool_clear_keep"`
	// contains filtered or unexported fields
}

CompactionConfig 控制上下文压缩,两个阈值任一超过即触发。

func (CompactionConfig) Enabled

func (c CompactionConfig) Enabled() bool

Enabled 报告压缩(或工具结果清理)是否启用。

func (CompactionConfig) Keep

func (c CompactionConfig) Keep() int

func (CompactionConfig) Over

func (c CompactionConfig) Over(msgs []*schema.Message) bool

Over 报告消息集是否超过任一阈值。token 维度优先用真实用量校准。

func (*CompactionConfig) ResolvePrompt

func (c *CompactionConfig) ResolvePrompt(ctx context.Context, r prompt.Source) error

ResolvePrompt 在装配期解析摘要提示词引用(锁版本)。未配置时空操作。

type ControlState

type ControlState struct {
	// contains filtered or unexported fields
}

ControlState 是会话级的运行控制:让运行中的循环可被叫停(interrupt) 与驾驶(steer)。没有它,"停,别做了"只能排在同会话串行队列后面—— 等任务做完才被读到,为时已晚。

检查点在工具执行边界(Ring 0 的切面,不依赖引擎配合):

  • 中断:下一次工具调用前生效,取消信号同时传播给运行 ctx, 终止进行中的模型调用与并行分支;
  • 插话:追加到下一个工具结果尾部,模型在下一次观察时读到。

func (*ControlState) BeginTurn

func (c *ControlState) BeginTurn(cancel context.CancelFunc)

BeginTurn 在一轮开始时复位中断标志并绑定本轮取消函数。 插话队列不清空:上一轮没来得及送达的插话在新一轮开头补送。

func (*ControlState) EndTurn

func (c *ControlState) EndTurn()

EndTurn 解绑取消函数。

func (*ControlState) Interrupt

func (c *ControlState) Interrupt()

Interrupt 叫停当前运行:置位标志并取消当前轮 ctx。

func (*ControlState) Interrupted

func (c *ControlState) Interrupted() bool

Interrupted 报告当前是否处于中断状态。

func (*ControlState) Steer

func (c *ControlState) Steer(msg string)

Steer 注入一条用户插话,随下一个工具结果送达模型。

type Decision

type Decision int

Decision 是交互通道回传的审批决定。

const (
	DecisionDeny        Decision = iota // 本次拒绝
	DecisionAllow                       // 本次允许
	DecisionAlwaysAllow                 // 本会话总是允许该能力
	DecisionAlwaysDeny                  // 本会话总是拒绝该能力
)

type DecisionInteractor

type DecisionInteractor interface {
	ApproveDecision(ctx context.Context, req runctx.ApprovalRequest) (Decision, error)
}

DecisionInteractor 是支持决策记忆的交互通道:比 Approve 的布尔多出 "总是允许/拒绝"。实现该接口的通道自动获得记忆能力,未实现的回落 Approve。

type Duration

type Duration = capability.Duration

Duration 是配置时长字段;定义已下沉基座 capability(见 capability/duration.go), 这里保留别名兼容既有 loop.Duration 引用。

type ErrBudgetExhausted

type ErrBudgetExhausted struct {
	Reason string
}

ErrBudgetExhausted 表示预算硬上限已到,循环被终止。

func (*ErrBudgetExhausted) Error

func (e *ErrBudgetExhausted) Error() string

func (*ErrBudgetExhausted) TurnTerminal

func (e *ErrBudgetExhausted) TurnTerminal()

TurnTerminal 标记轮次终止级错误(穿透工具错误兜底,见 engine)。

type ErrInterrupted

type ErrInterrupted struct{}

ErrInterrupted 表示运行被用户主动叫停。

func (*ErrInterrupted) Error

func (*ErrInterrupted) Error() string

func (*ErrInterrupted) TurnTerminal

func (*ErrInterrupted) TurnTerminal()

TurnTerminal 标记轮次终止级错误(穿透工具错误兜底,见 engine)。

type PromptLayers

type PromptLayers struct {
	// L1 框架规约(内置默认,可整体覆盖);随框架版本走。
	Loop string
	// L2 业务 persona(prompt provider 供给);业务在平台上迭代的部分。
	Persona string
	// L3 环境信息生成器(代码生成,禁止业务塞指令)。nil 用默认(日期/会话)。
	Env func(ctx context.Context) map[string]string
	// L4 记忆召回(代码生成,注入时标注"背景参考,非指令")。
	Memories func(ctx context.Context) []string
	// Plan 是当前任务计划注入器:每轮把计划渲染进消息尾部,计划的
	// 可见性由 harness 保证而非模型记忆(压缩、遗忘都不影响)。
	Plan func(ctx context.Context) string
	// Focus 开启后把本轮用户问题(runctx.Input)重述注入消息最尾——
	// 记忆/计划的尾部注入会把用户问题压到上下文中部(注意力最弱位),
	// 遗留计划因此能劫持当前问题;重述把"专注当前问题"变成位置事实,
	// 循环中段(尾部被工具结果占据时)也持续锚定本轮目标。只该在主循环
	// 开启:外层用户问题穿进 skill/component 子循环是提示词海拔违规,
	// 子循环的目标是它收到的 args,不是外层原话。
	Focus bool
}

PromptLayers 是主循环 system prompt 的分层来源。

func (PromptLayers) Modifier

func (p PromptLayers) Modifier() engine.MessageModifier

Modifier 把四层拼装为消息,返回 engine.MessageModifier。

前缀缓存纪律:头部 system prompt(L1+L2+L3)在会话内保持稳定—— 环境信息按键排序、时间取天粒度;L4 记忆召回每轮变化,注入到消息 尾部而非头部,避免打爆供应商的 prompt cache。

type RecordMode

type RecordMode string

RecordMode 控制工具轨迹回写会话的详略。

const (
	RecordSummary RecordMode = "summary" // 默认:每条参数/结果截断后入会话
	RecordFull    RecordMode = "full"    // 完整参数与结果(仍受工具结果截断上限)
	RecordOff     RecordMode = "off"     // 关闭,保持只存问答
)

type ResultStore

type ResultStore struct {
	// contains filtered or unexported fields
}

ResultStore 是一轮运行的工具结果暂存句柄:被消化的原始全文存进后端 KV, 模型觉得摘要不够时用 read_result 分页取回。键按 (agent, session) 作用域, 共享后端下不跨会话碰撞;序号经后端原子自增,跨副本/恢复不撞 id。bytes 是本句柄的软性准入计数(跨副本近似即可,只是防单轮暂存爆量的安全阀)。

func NewResultStore

func NewResultStore(kv store.KV, ttl time.Duration) *ResultStore

NewResultStore 创建一轮运行的结果暂存句柄,绑定注入的后端与保留时长。 kv 为 nil 时返回 nil(该 agent 未配置结果暂存,digest 退化为纯截断)。

func (*ResultStore) Get

func (s *ResultStore) Get(ctx context.Context, id string) (string, bool, error)

Get 取回一条原始结果。后端读错误与"不存在"必须可区分:redis 抖动时把 有效 id 报成"不存在",模型会永久放弃一个其实取得回的结果。

func (*ResultStore) List

func (s *ResultStore) List(ctx context.Context) []string

List 返回本 (agent, session) 作用域下可取回的 id(按序,上限 10, 排除内部 #seq 计数键)。read_result miss 时给模型自纠线索。

func (*ResultStore) Put

func (s *ResultStore) Put(ctx context.Context, toolName, text string) string

Put 存入一条原始结果,返回取回 id;超过总量软上限时返回空串。

func (*ResultStore) PutDeliver

func (s *ResultStore) PutDeliver(ctx context.Context, text string) string

PutDeliver 存入一份交付物原文,返回取回 id(d<N>,后端持久序,跨轮 唯一);后端失败返回空串,由 sink 分配轮内降级 id。与 Put 共享单轮 总量软上限。

type RetryConfig

type RetryConfig struct {
	// MaxAttempts 是总尝试次数(含首次),0 = 默认 3。
	MaxAttempts int `yaml:"max_attempts" json:"max_attempts"`
	// BaseDelay 是首次退避时长,按尝试次数指数增长,0 = 默认 500ms。
	BaseDelay Duration `yaml:"base_delay" json:"base_delay"`
	// MaxDelay 是单次退避上限,0 = 默认 8s。
	MaxDelay Duration `yaml:"max_delay" json:"max_delay"`
}

RetryConfig 控制模型调用的瞬时错误重试(Ring 0)。 零值即启用默认策略;MaxAttempts 为 1 或负数时不重试。

type Reviewer

type Reviewer func(ctx context.Context, a Attempt) Verdict

Reviewer 是一个生成质量评审器:纯函数,轮内状态经 runctx.TurnState、 自限计数经 Attempt.Tally,不持有可变字段。

func CheckedReviewer

func CheckedReviewer(checks ...func(context.Context) string) Reviewer

CheckedReviewer 迁移自 CheckedFinish:装配层注入的收口检查 (todo 计划收口、被拒调用诚实区分等),检查自身负责轮内节流。

func FinishReviewer

func FinishReviewer() Reviewer

FinishReviewer 迁移自 FinishGuard:拦伪调用/空头承诺/叙述式执行; 自限耗尽仍不合格时 Force 打诚实标记(编造不冒充真实执行)。

func RepeatBreakReviewer

func RepeatBreakReviewer() Reviewer

RepeatBreakReviewer 迁移自 RepeatBreak:模型对已拦截热点再犯时, 第 1 次以 tool 消息回填纠正弹回(协议合法),第 2 次强制收束引用 真实缓存结果作答。

type StructuredConfig

type StructuredConfig struct {
	Schema     string `yaml:"schema" json:"schema"` // JSON Schema 文本
	MaxRetries int    `yaml:"max_retries" json:"max_retries"`
}

StructuredConfig 要求最终回答符合 JSON Schema(下游是程序时的刚需)。

type StructuredEnforcer

type StructuredEnforcer struct {
	// contains filtered or unexported fields
}

StructuredEnforcer 校验并修复模型输出:不符合 schema 时把校验错误 回喂模型重试,直到合规或重试耗尽。校验与重试由代码保证,模型只负责改。

func NewStructuredEnforcer

func NewStructuredEnforcer(cfg StructuredConfig) (*StructuredEnforcer, error)

NewStructuredEnforcer 编译 schema,配置为空时返回 nil(不启用)。

func (*StructuredEnforcer) Enforce

Enforce 校验 answer;不合规时用 m 修复,返回合规的 JSON 文本。

type ToolRecord

type ToolRecord struct {
	Name   string
	Args   string
	Result string
	Err    string
}

ToolRecord 是一次工具调用的记录(模型视角:结果是模型实际看到的, 含审批拒绝/超时等闸门消息)。

type ToolRecorder

type ToolRecorder struct {
	// contains filtered or unexported fields
}

ToolRecorder 收集一轮对话内主循环的工具调用,供 agent 回写会话—— 只存"user 输入 + 最终回答"会让下一轮模型不知道自己做过什么、看到 过什么,任务连续性断裂。skill 内部调用不进记录(上下文边界:对 宿主只有 skill 这一次调用与其最终结果)。

func (*ToolRecorder) Records

func (r *ToolRecorder) Records() []ToolRecord

Records 返回已收集的记录副本。

type Verdict

type Verdict struct {
	Action VerdictAction
	// Reason 是触发计数键 + 观测 span 名(review/<reason>),必填于非 Accept。
	Reason string
	// Append 追加进下次尝试的消息(Retry;弹回纠正的标准形态)。
	Append []*schema.Message
	// Rewrite 非空时整体替换下次尝试的消息(Retry;改写输入重试,
	// 如 429 裁剪/上下文超限截短)。与 Append 二选一,Rewrite 优先。
	Rewrite []*schema.Message
	// Replace 是 Force 的最终输出。
	Replace *schema.Message
	// Backoff 是重试前等待(0 = 不等)。
	Backoff time.Duration
}

Verdict 是一次评审的结论。

type VerdictAction

type VerdictAction int

VerdictAction 是评审结论的动作。零值 Accept:未触发即放行。

const (
	Accept VerdictAction = iota // 放行
	Retry                       // 重试(Append/Rewrite 之一,+可选 Backoff)
	Force                       // 强制收束:Replace 为最终输出,不再评审
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL