feat(infra/llm): neutral types + LLMClient interface + estimate tokenizer + fake

This commit is contained in:
2026-05-04 00:37:04 +08:00
parent 547b339ed3
commit 9c8e4175c4
4 changed files with 191 additions and 0 deletions
+53
View File
@@ -0,0 +1,53 @@
package llm
import (
"context"
"errors"
"sync"
)
// FakeClient 是测试用 LLMClient,可编程产出固定 stream 事件。
// 注意:本文件 NOT _test.go 后缀,因下游 integration test 需作为依赖导入。
type FakeClient struct {
mu sync.Mutex
ProviderID string
Events []StreamEvent // 流事件序列(按顺序 emit)
StreamError error // Stream() 立即返回的错误(如果非 nil)
TokenCount int // CountTokens 返回值
StreamCalls int
}
// NewFake 构造一个 FakeClient,默认 provider="fake"。
func NewFake() *FakeClient { return &FakeClient{ProviderID: "fake"} }
func (f *FakeClient) Provider() string { return f.ProviderID }
func (f *FakeClient) Stream(ctx context.Context, modelID string, req Request) (<-chan StreamEvent, error) {
f.mu.Lock()
f.StreamCalls++
if f.StreamError != nil {
err := f.StreamError
f.mu.Unlock()
return nil, err
}
events := append([]StreamEvent(nil), f.Events...)
f.mu.Unlock()
ch := make(chan StreamEvent, len(events)+1)
go func() {
defer close(ch)
for _, e := range events {
select {
case <-ctx.Done():
ch <- StreamEvent{Type: EventError, Err: errors.New("context canceled")}
return
case ch <- e:
}
}
}()
return ch, nil
}
func (f *FakeClient) CountTokens(ctx context.Context, modelID string, req Request) (int, error) {
return f.TokenCount, nil
}