delta

package
v0.31.0 Latest Latest
Warning

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

Go to latest
Published: Nov 11, 2026 License: MIT Imports: 4 Imported by: 0

Documentation

Overview

Package delta 增量节流器(真流式观测面)。

节流窗口 / 总量帽 / seq 单调 / 权威收口语义的**基础机制在 oagentkit/runtime/pacer**; 本包提供其上的编排层:

  • (kind, iteration) 键控:同一轮内的 reasoning / text 各自成流;
  • 惰性建流(构造后可注入时钟,建流待首次使用);
  • 收口扫序:轮升序 × reasoning→text,保证事件落序确定性。

语义约定(同轮权威快照优先):权威整段事件到达即 absorb 缓冲(回放/终稿以权威 为准);调用轮没有权威正文快照,残尾只能靠 FlushAll 冲刷落地。

单 goroutine 契约:调用方的 OnEvent 在 drain 循环内同步回调(不阻塞不并发), 与 pairer/obs 同一约束面,故不加锁——**换宿主时须确认该契约仍成立**。

生命周期是「单个环节」,不是「整个进程」

entries 按 (kind, iteration) 惰性建流且**从不回收**, FlushAll 的扫序上界又是 `max(iteration)`——这两处单独看都像缺陷(前者无界增长,后者按 max 空转)。 它们安全**只因为一个外部不变量**:宿主每个 LLM 环节新建一个 Pacer,在该环节的 defer 里 FlushAll 收口后整体丢弃;iteration 是该环节内的局部计数器,不是 模型可控值、也不跨环节累加(见 bianque `steps_llm.go` 的 `round`)。

所以本包**不能**被改成长生命周期对象(如「整个会话一个 Pacer」)而无人察觉: 那会同时引爆上面两条,且症状是「跑久了内存涨 / 收口卡住」,极难归因。 改宿主接线前先看这一段。

Index

Constants

View Source
const (
	// FlushInterval 节流窗口:距上次发布 ≥ 该值或缓冲 ≥ FlushBytes 才发布。
	FlushInterval = 400 * time.Millisecond
	// FlushBytes 缓冲字节下限(达到即发,不必等窗口)。
	FlushBytes = 200
	// CapBytes 单轮单类增量发布总量帽(深度思考可极长),超帽静默停发。
	CapBytes = 64 << 10
)
View Source
const (
	// ThinkOpenTag 推理段起始标签(缺省)。
	ThinkOpenTag = "<think>"
	// ThinkCloseTag 推理段结束标签(缺省)。
	ThinkCloseTag = "</think>"
)

Variables

This section is empty.

Functions

This section is empty.

Types

type Pacer

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

Pacer 按 (kind, iteration) 键控的增量节流集合。

func New

func New() *Pacer

New 构造节流器。测试可在构造后替换内部时钟。

func (*Pacer) Absorb

func (p *Pacer) Absorb(kind string, iteration int)

Absorb 权威快照到达:该轮增量缓冲作废并收口(消费方以权威整段替换增量累积)。

func (*Pacer) Flush

func (p *Pacer) Flush(kind string, iteration int) (Pub, bool)

Flush 立即发布该轮缓冲残尾(帽内);空缓冲/已收口不动序号。

func (*Pacer) FlushAll

func (p *Pacer) FlushAll() []Pub

FlushAll 环节收口:按轮序冲刷所有残尾(调用轮正文无权威快照,只在此落地)。 顺序确定性:轮升序 × reasoning→text,保证事件落序可回放。

func (*Pacer) Offer

func (p *Pacer) Offer(kind string, iteration int, chunk string) (Pub, bool)

Offer 接收一个增量分片:按节流窗口判定是否发布;done(权威已到)后的迟到分片丢弃。

type Pub

type Pub struct {
	Kind      string
	Iteration int
	Seq       int
	Text      string
}

Pub 一次待发布增量:seq 在 (kind, iteration) 内单调自 1 递增,text 为合并分片 (非累积快照——消费方按序追加,避免长文本 O(n²) 重发)。

type Splitter

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

Splitter 跨分片标签分流器。零值不可用,请用 NewSplitter。

单 goroutine 契约:与 Pacer 同约束(调用方串行驱动),故不加锁。

func NewSplitter

func NewSplitter() *Splitter

NewSplitter 构造分流器(缺省 <think>/</think> 标签对)。

func NewSplitterTags

func NewSplitterTags(openTag, closeTag string) *Splitter

NewSplitterTags 构造分流器并指定标签对(宿主用别的推理标记时用)。 任一标签为空则回落缺省值——空标签会让「后缀是标签前缀」恒真, 结果是内容永远扣住不发,是最难查的一类挂起。

func (*Splitter) Feed

func (s *Splitter) Feed(chunk string) (reasoning, content string)

Feed 吃进一个分片,返回本次**可安全发出**的推理段与正文段。

返回值可能为空——那不是丢内容,是扣在 pending 里等下一个分片。 扣住的上界是标签长度减一(标签本体一旦完整就会被消费,不会被扣)。

func (*Splitter) Flush

func (s *Splitter) Flush() (reasoning, content string)

Flush 流末冲刷:把扣住的尾巴按当前段归属一次性发出,并复位状态。 不 Flush 就丢流,等于把最后几个字符永远扣在手里。

func (*Splitter) InReasoning

func (s *Splitter) InReasoning() bool

InReasoning 当前是否处于推理段(供调用方决定归属,扣住的尾巴也在段内)。

func (*Splitter) Pending

func (s *Splitter) Pending() int

Pending 当前扣住的待判尾巴长度(诊断用:持续增长说明标签永不成形)。

Jump to

Keyboard shortcuts

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