ailens360

package
v0.2.7 Latest Latest
Warning

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

Go to latest
Published: May 14, 2026 License: MIT Imports: 5 Imported by: 0

README

ailens360

AILens360 反向代理写的 Go 客户端胶水层。给 eino 风格的 OpenAI ChatModel 套上 BaseURL 改写 + 每请求 telemetry header 注入。

AILens360 是什么

AILens360 是开源、自部署、低代码侵入的 AI 应用可观测平台 —— "360° observability for every LLM call"。

核心做法:在你的应用和真实上游(OpenAI / Anthropic / Gemini / DeepSeek / vLLM / Ollama / ……)之间放一个反向代理。你只需要:

  1. baseURLhttps://api.openai.com/v1 改成 http(s)://<ailens360-host>/p/https://api.openai.com/v1 ——/p/ 后面直接拼完整上游 URL
  2. 加一个请求头 X-AILens-Project-Key: <控制台分配的项目密钥>
  3. 原本的 Authorization / x-api-key 透传给上游,AILens360 不持有、不存储真实 API Key

之后所有调用都会被记录:请求/响应原文、流式 SSE 解析、token / cost 统计、TTFT / TTFB / TPS 等延迟指标、错误归因;按 Project / User / Session / Trace 维度聚合检索。

没有 SDK 强依赖,多数 OpenAI 兼容客户端只改一行 baseURL 就接入了。

这个包做什么

直接在 Go 里改两件事会很啰嗦——拼前缀 URL、给 *http.Client.Transport 套一层 RoundTripper、再让 RoundTripper 从 req.Context() 取 user/session/trace。本包把它们封成 4 个文件:

文件 内容
context.go ctx key + WithUser / WithSession / WithTag / WithTraceID / WithTraceName / WithTraceCurrentTrace(ctx) 反查
transport.go telemetryHeaders RoundTripper,固定塞 X-AILens-Project-Key,按需从 ctx 塞 5 个 X-AILens-*
decorator.go Decorator{proxyPrefix, projectKey}DecorateBaseURL(upstream) 拼前缀;HTTPClient(base) 包出带 RoundTripper 的 *http.ClientSetGlobal / Global 进程级单例
apply.go Decorator.Apply(*openai.ChatModelConfig):一行同时改写 BaseURLHTTPClientnil 时是 no-op;ApplyGlobal 走全局单例

一分钟接入

import (
    "context"

    "github.com/CoolBanHub/aggo/pkg/ailens360"
    "github.com/cloudwego/eino-ext/components/model/openai"
)

func main() {
    // 1) 配置缺一即 nil;nil 时 Apply 直接 no-op,应用照常跑、不走代理。
    dec := ailens360.NewDecorator(
        "https://ailens360.example.com/p", // 控制台给的 proxy_prefix
        "<64-char project_key>",
    )

    // 2) 像平时一样构造 OpenAI ChatModel,Apply 之后 BaseURL 被改成
    //    "<proxy>/<upstream>",HTTPClient 自动注入 telemetry header。
    cfg := &openai.ChatModelConfig{
        APIKey:  "sk-real-upstream-key", // 透传给上游
        BaseURL: "https://api.openai.com/v1",
        Model:   "gpt-4o-mini",
    }
    dec.Apply(cfg)

    chatModel, _ := openai.NewChatModel(context.Background(), cfg)

    // 3) 调用前把 user / session / trace 塞进 ctx;
    //    同一个 chatModel 实例可服务任意调用方,不用每次重建。
    ctx := ailens360.WithTrace(context.Background(), ailens360.TraceConfig{
        ID:        "trace_xxx", // 想要稳定 trace 就自己生成(建议 SHA1(turn 关键参数))
        Name:      "customer_agent_turn",
        UserID:    "user_alice_42",
        SessionID: "group_1:user_alice_42",
        Tag:       "prod,channel=htsy",
    })

    _, _ = chatModel.Generate(ctx, /* messages */ nil)
}

完整 demo 见 example/ailens360_test/,里面是一个用 ReAct 工具调用 + AILens360 trace 的端到端例子。

ctx header 对照表

telemetryHeaders.RoundTrip 每次出站请求都会读 req.Context(),按下表把非空值拍到 header:

ctx 写入 发出去的 header AILens360 控制台用途
WithUser(ctx, v) X-AILens-User 按用户聚合 / 检索
WithSession(ctx, v) X-AILens-Session 把同一会话/对话内的多次调用串起来
WithTag(ctx, v) X-AILens-Tag 自由标签,逗号分隔(env / channel / 实验组)
WithTraceID(ctx, v) X-AILens-Trace-Id 同一业务 turn 多次模型调用共享,trace 视图合并显示
WithTraceName(ctx, v) X-AILens-Trace-Name trace 的展示名

WithTrace(ctx, TraceConfig{…}) 是上面 5 个的一次性聚合写法。

固定不动的 X-AILens-Project-KeyNewDecorator 时传入,每个请求都会自动加,和 ctx 无关

全局 vs 局部

// 进程级单例:服务启动时设一次,业务代码不感知。
ailens360.SetGlobal(dec)

// 任意 openai.ChatModelConfig 在构造前调一下:
ailens360.ApplyGlobal(cfg) // 返回 true 表示全局 Decorator 生效

适合在大型项目里把"是否启用 AILens360"做成开关:env 没配 → SetGlobal(nil)ApplyGlobal 全是 no-op → 应用代码零分支。

设计取舍

  • per-call telemetry 走 ctx 而不是参数:保持 *openai.ChatModel 是单例、可在 goroutine 间共享;调用方只关心"这次请求是谁/什么会话",不关心 transport 细节。
  • NewDecorator 容忍空配置proxyPrefixprojectKey 任一空就返回 nil,调用方不用写 if dec != nil 分支;Apply / DecorateBaseURL / HTTPClientnil receiver 上都是 no-op。
  • 不预设上游DecorateBaseURL 只做字符串拼接,OpenAI / Anthropic / Gemini / DeepSeek / vLLM 都一样用。
  • 真实上游 Key 不经过这个包Authorizationopenai.ChatModel 内部按 APIKey 字段塞,透传到上游;AILens360 也只是中转,不落库。

相关链接

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ApplyGlobal

func ApplyGlobal(cfg *openai.ChatModelConfig) bool

ApplyGlobal is a convenience wrapper that pulls the process-wide Decorator installed via SetGlobal. Returns true when the global decorator is active.

func SetGlobal

func SetGlobal(d *Decorator)

SetGlobal installs a process-wide decorator. Pass nil to disable.

func WithSession

func WithSession(ctx context.Context, v string) context.Context

func WithTag

func WithTag(ctx context.Context, v string) context.Context

func WithTrace

func WithTrace(ctx context.Context, cfg TraceConfig) context.Context

func WithTraceID

func WithTraceID(ctx context.Context, v string) context.Context

func WithTraceName

func WithTraceName(ctx context.Context, v string) context.Context

func WithUser

func WithUser(ctx context.Context, v string) context.Context

Types

type Decorator

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

Decorator wraps an OpenAI-compatible chat-model BaseURL to route through an AILens360 proxy and installs an HTTP transport that stamps telemetry headers from request context.

func Global

func Global() *Decorator

Global returns the process-wide decorator, or nil if none is installed.

func NewDecorator

func NewDecorator(proxyPrefix, projectKey string) *Decorator

NewDecorator builds a decorator. Both proxyPrefix and projectKey must be non-empty for the decorator to be functional; otherwise nil is returned and callers should skip decoration.

func (*Decorator) Apply

func (d *Decorator) Apply(cfg *openai.ChatModelConfig)

Apply mutates an openai.ChatModelConfig in place so that requests flow through the AILens360 proxy. The BaseURL is rewritten to "<proxy_prefix>/<original_base_url>" and the HTTPClient is wrapped with a RoundTripper that stamps the project key plus per-call user/session/trace headers pulled from request context.

If d is nil (e.g. when AILens360 is not configured), Apply is a no-op so callers can blindly invoke it.

func (*Decorator) DecorateBaseURL

func (d *Decorator) DecorateBaseURL(upstream string) string

DecorateBaseURL prepends the proxy prefix to the upstream BaseURL. upstream is expected to be a fully-qualified URL like "https://api.openai.com/v1".

func (*Decorator) HTTPClient

func (d *Decorator) HTTPClient(base *http.Client) *http.Client

HTTPClient returns an *http.Client whose Transport injects telemetry headers. If base is non-nil its Transport is preserved as the inner round-tripper.

type TraceConfig

type TraceConfig struct {
	ID        string
	Name      string
	UserID    string
	SessionID string
	Tag       string
}

type TraceContext

type TraceContext struct {
	ID        string
	Name      string
	UserID    string
	SessionID string
	Tag       string
}

TraceContext exposes the ailens360 telemetry values currently stamped on a context. Empty fields mean "not set".

func CurrentTrace

func CurrentTrace(ctx context.Context) TraceContext

Jump to

Keyboard shortcuts

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