项目代码知识库:数据结构、接口定义、模块边界、命名规范 最后更新:2026-04-24
新 Agent 必读顺序:
AGENT_WORKFLOW.md— 工作规范CONSTRAINTS.md— 硬边界CODE_WIKI.md— 本文件(代码结构)API_CONTRACT.md— HTTP 规范- 相关模块设计文档
内部统一格式,所有入站请求的收敛形态。
package envelope
type Envelope struct {
Model string `json:"model"`
Messages []Message `json:"messages"`
Stream bool `json:"stream"`
Tools []Tool `json:"tools,omitempty"`
Temperature *float64 `json:"temperature,omitempty"`
MaxTokens *int `json:"max_tokens,omitempty"`
TopP *float64 `json:"top_p,omitempty"`
SessionID string `json:"session_id,omitempty"` // 兼容字段,DeepSeek 出站会透传
Raw map[string]json.RawMessage `json:"-"` // 其余字段原样保留
}
type Message struct {
Role string `json:"role"`
Content json.RawMessage `json:"content"` // string or []ContentPart
Name string `json:"name,omitempty"`
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
ToolCallID string `json:"tool_call_id,omitempty"`
CacheControl *CacheControl `json:"cache_control,omitempty"`
Extra map[string]json.RawMessage `json:"-"` // 厂商扩展字段原样透传
}
type Tool struct {
Type string `json:"type"`
Function Function `json:"function"`
CacheControl *CacheControl `json:"cache_control,omitempty"`
}
type Function struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
Parameters json.RawMessage `json:"parameters,omitempty"`
}
type ToolCall struct {
ID string `json:"id"`
Type string `json:"type"`
Function CallFunction `json:"function"`
}
type CallFunction struct {
Name string `json:"name"`
Arguments string `json:"arguments"`
}
type CacheControl struct {
Type string `json:"type"` // "ephemeral"
}关键设计:
Content用json.RawMessage,因为 content 可能是string或多模态数组Message.Extra保存消息级未知字段(如 DeepSeekreasoning_content),避免多轮请求中丢失厂商扩展字段Raw字段保存所有未标准化字段,出站时按需还原为厂商原生格式CacheControl在入站时通常为空,由CacheInjector填充
Chunker 的输出,Arranger 和后续模块的操作单位。
package block
type BlockType string
const (
BlockSystem BlockType = "system" // system 角色消息
BlockTool BlockType = "tool" // 工具定义
BlockHistory BlockType = "history" // 最后一轮 user 之前的历史消息
BlockQuery BlockType = "query" // 最后一轮 user 及其后的 assistant/tool 尾部
)
type Block struct {
Type BlockType
Messages []envelope.Message
Tools []envelope.Tool
}package inbound
type InboundAdapter interface {
Match(method, path string) bool
Parse(req *http.Request) (*envelope.Envelope, error)
Name() string
}package outbound
type OutboundAdapter interface {
Name() string
BuildRequest(blocks []block.Block, env *envelope.Envelope) ([]byte, error)
ParseStreamChunk(chunk []byte) (*StreamEvent, error)
ParseResponse(body []byte) (*Response, error)
}
type StreamEvent struct {
Type string
Delta json.RawMessage
Done bool
Usage *Usage
}
type Response struct {
Choices []Choice
Usage *Usage
Raw map[string]json.RawMessage
}
type Choice struct {
Index int
Message *envelope.Message
FinishReason string
}
type Usage struct {
PromptTokens int
CompletionTokens int
CacheReadTokens int
CacheWriteTokens int
}package chunker
type Chunker interface {
Chunk(env *envelope.Envelope) ([]block.Block, error)
}
// Phase 1: StaticChunker
// Phase 2: DynamicChunkerpackage arranger
type Arranger interface {
Arrange(blocks []block.Block) ([]block.Block, error)
}
// DefaultArranger 静态排列器实现
type DefaultArranger struct {
maxHistoryTurns int
toolSortEnabled bool
}
// ArrangerOption 选项函数类型
type ArrangerOption func(*DefaultArranger)
// WithToolSort 工具排序选项
func WithToolSort(enabled bool) ArrangerOption
// NewDefaultArranger 构造函数(选项模式)
func NewDefaultArranger(maxHistoryTurns int, opts ...ArrangerOption) *DefaultArranger配置说明:
maxHistoryTurns:历史消息最大轮数(默认 20)toolSortEnabled:是否对工具按字母序排序(默认true)true:工具按Function.Name字母序排序(推荐,提高缓存命中率)false:保持工具原始顺序(适用于对工具顺序敏感的场景)
使用示例:
// 默认排序(启用工具排序)
arranger.NewDefaultArranger(20)
// 禁用工具排序
arranger.NewDefaultArranger(20, arranger.WithToolSort(false))package canonicalizer
func CanonicalJSON(v interface{}) ([]byte, error)保证:两个逻辑等价的 Block 序列,输出完全相同的 JSON 字符串。
package cacheinject
type Engine interface {
Inject(blocks []block.Block, vendor string) ([]block.Block, error)
}
type Injector interface {
Name() string
Supports(vendor string) bool
Inject(blocks []block.Block) ([]block.Block, error)
}package hasher
func PrefixHash(blocks []block.Block) (string, error)
func FullHash(blocks []block.Block) (string, error)PrefixHash:只取BlockSystem + BlockTool计算 SHA256,用于厂商侧 KV Cache 命中FullHash:取全部 Block 计算 SHA256,用于请求去重
package dedup
type Deduplicator struct {
// unexported fields: inflight map, mutex, ttl, enabled, stopCh, stopOnce
}
func NewDeduplicator(ttl time.Duration, enabled bool) *Deduplicator
// CheckOrRegister atomically checks for an existing in-flight request or
// registers a new one. Returns (req, found): found=true means a duplicate
// is already in progress; found=false means caller owns the request.
func (d *Deduplicator) CheckOrRegister(hash string) (*InFlightRequest, bool)
func (d *Deduplicator) Complete(hash string, statusCode int, resp []byte, err error)
func (d *Deduplicator) Stop()
type InFlightRequest struct {
Done chan struct{}
StatusCode int
Resp []byte
Err error
// unexported completeOnce makes Complete idempotent.
}package billing
type TokenCounts struct {
PromptTokens int
CompletionTokens int
CacheReadTokens int
CacheWriteTokens int
}
type CostBreakdown struct {
PromptCost float64
CompletionCost float64
CacheReadCost float64
CacheWriteCost float64
TotalCost float64
}
type PriceEngine struct { /* table *PricingTable */ }
func NewPriceEngine(table *PricingTable) *PriceEngine
func (e *PriceEngine) Calculate(modelName string, counts TokenCounts) (CostBreakdown, error)
type QuotaManager struct { /* db *gorm.DB, cache */ }
func NewQuotaManager(db *gorm.DB) *QuotaManager
func (qm *QuotaManager) CheckQuota(userID string) (bool, error)
func (qm *QuotaManager) GetMonthlyUsage(userID string) (int64, error)
func (qm *QuotaManager) InvalidateCache(userID string)[入站请求]
│
▼
[Inbound Adapter] ──→ Envelope
│
▼
[Chunker] ──→ []Block
│
▼
[Arranger] ──→ 排序后的 []Block
│
▼
[Canonicalizer] ──→ 确定性 JSON bytes
│
▼
[CacheInjector] ──→ 注入 cache_control
│
▼
[Hasher] ──→ prefixHash / fullHash
│
▼
[Dedup] ──→ 检查或等待复用
│
▼
[Outbound Adapter] ──→ 厂商原生请求体
│
▼
[HTTP Proxy] ──→ 上游 Provider
│
▼
[响应返回] + [异步计费记录]
完整架构图参见 architecture.md。
tokenrouter/ # 计划结构
├── cmd/server/main.go # 服务入口:配置、数据库、路由注册
├── internal/
│ ├── server/ # ChatPipeline 与生产 chat handler
│ ├── inbound/ # 入站适配层
│ ├── envelope/ # Envelope / Message / Tool 定义
│ ├── block/ # Block 定义
│ ├── chunker/ # 分块器
│ ├── arranger/ # 排列器
│ ├── canonicalizer/ # 序列化规范器
│ ├── cacheinject/ # 缓存注入器
│ ├── hasher/ # 前缀/完整哈希计算
│ ├── dedup/ # 请求去重器
│ ├── observer/ # 流量观测(Phase 2 预留)
│ ├── outbound/ # 出站适配层
│ ├── proxy/ # HTTP / SSE 代理
│ ├── billing/ # 计费与配额
│ ├── middleware/ # 认证、限流、日志
│ ├── monitor/ # Prometheus 指标
│ └── model/ # 数据模型(GORM)
├── pkg/
│ ├── config/ # 配置加载
│ ├── logger/ # Zap 封装
│ ├── httputil/ # HTTP 工具
│ └── crypto/ # API Key 哈希
├── migrations/ # 数据库迁移脚本
├── deployments/ # Docker / K8s 配置
└── docs/ # 技术文档
| 包路径 | 职责 | 对应文档 |
|---|---|---|
internal/server/ |
生产级 ChatPipeline 与 /v1/chat/completions handler |
modules/system-implementation.md |
internal/inbound/ |
入站协议解析 | modules/adapter-architecture.md |
internal/outbound/ |
还原厂商原生请求 | modules/adapter-architecture.md |
internal/chunker/ |
静态四分块 | modules/cache-intelligence.md |
internal/arranger/ |
System 合并 / Tool 排序 / History 截断 | modules/cache-intelligence.md |
internal/canonicalizer/ |
确定性 JSON 序列化 | modules/cache-intelligence.md |
internal/cacheinject/ |
按厂商策略注入缓存标记 | modules/cache-intelligence.md |
internal/hasher/ |
计算 PrefixHash / FullHash | modules/cache-intelligence.md |
internal/dedup/ |
非流式并发请求去重 | modules/cache-intelligence.md |
internal/proxy/ |
SSE 流式代理、连接池 | modules/system-implementation.md |
internal/billing/ |
Token 计量、价格计算 | modules/system-implementation.md |
internal/middleware/ |
API Key 认证、令牌桶限流 | modules/system-implementation.md |
internal/monitor/ |
Prometheus 指标注册与采集 | modules/system-implementation.md |
- 所有外部调用必须处理
error - 错误必须向上 wrap,带上模块前缀:
fmt.Errorf("chunker: %w", err) - 禁止使用
_丢弃错误
- 使用结构化 Zap 日志
- key 使用
snake_case - 错误日志必须包含
"error"字段
- 所有配置项通过环境变量注入
pkg/config/为统一加载入口- 默认值在代码中显式声明
- 优先 TDD
- 表格驱动测试
- Mock 接口,不 Mock 实现
- 创建目录
internal/outbound/{vendor}/ - 实现
OutboundAdapter接口 - 在
internal/outbound/registry.go注册 - 参考文档:
modules/adapter-architecture.md
MVP v0.1 现状:
internal/outbound/deepseek/已实现(OpenAI 兼容适配器)。openai/、anthropic/为预留空壳。
- 创建文件
internal/cacheinject/{vendor}.go - 实现
Injector接口 - 在
internal/cacheinject/registry.go注册 - 参考文档:
modules/cache-intelligence.md
MVP v0.1 现状:
internal/cacheinject/openai.go已实现(透传策略)。anthropic.go为预留空壳。
- 评估是否可用
ConfigDrivenAdapter(YAML 配置)覆盖 - 若不行,手写
InboundAdapter实现 - 在路由注册表中注册
- 参考文档:
modules/adapter-architecture.md