【免费下载链接】GoModel
AI gateway / AI control plane / AI proxy written in Go. Unified OpenAI-compatible and Anthropic-compatible API for OpenAI, Anthropic, Gemini, Groq, xAI, Ollama, vLLM and more. A LiteLLM alternative with observability, guardrails, streaming, cost tracking, intelligent routing, sticky sessions, failover, real-time logs and usage tracking. Prod ready.
GoModel 是一个用 Go 编写的生产级 AI Gateway(AI 网关 / AI 控制平面),为 OpenAI、Anthropic、Gemini、Groq、xAI、Ollama、vLLM 等模型提供商提供统一的 OpenAI 兼容与 Anthropic 兼容 API。本文深入解析它的插件系统(plugin system):如何用一份pluginapi.Plugin契约,同时实现请求护栏(guardrails)、流式响应过滤(stream filtering)和自定义路由策略(routing strategy),并给出从编写、构建到加载.so插件的完整路径。
一、为什么 AI 网关需要插件系统 🧩
在 GoModel 这类 AI 网关上,流量同时穿过多个模型提供商。你会很快遇到这些诉求:
- 安全与合规:在 prompt 进入模型前拦截敏感词,在响应离开前脱敏 API Key、PII;
- 内容改写:统一注入 system prompt、替换标签、改写 LLM 输出;
- 流式审查:SSE 逐字输出时,敏感词可能恰好被拆在两个 chunk 之间;
- 智能路由:让虚拟模型(virtual model)按成本、延迟或健康度在多个候选模型间做负载均衡。
GoModel 的答案很克制:所有能力共用一份契约——pluginapi 包中的pluginapi.Plugin接口加若干可选钩子。护栏是插件的实例,自定义路由策略也是插件,没有两套体系。
二、一份契约:pluginapi 如何组织
契约的核心在 pluginapi/plugin.go:每个插件实现基础接口Plugin(Manifest/Init/Close三个方法),再按需实现可选钩子,GoModel 通过类型断言自动发现:
| 钩子接口 | 触发时机 | 典型用途 |
|---|---|---|
PromptHook | 路由完成后、调用提供商前 | 改写/拦截 prompt(护栏主力) |
ResponseHook | 完整非流式响应返回后 | 改写或拦截最终回复 |
StreamHook | 流式输出的每个事件 + 结束事件 | 流过滤、逐事件审查 |
RouteStrategy | 虚拟模型选择目标时 | 自定义负载均衡策略 |
HealthChecker | 请求路径之外定期探测 | 依赖外部分类器时上报健康状态 |
pluginapi只依赖 Go 标准库——插件只从 GoModel 导入这一个包,内部实现再怎么重构都不会影响插件。
插件通过Manifest声明自己实现了哪些Kinds、是否Mutates(修改内容)、是否Guardrail,并给出ConfigSchema。这个 schema 会被管理后台直接消费:控制台上的护栏表单就是根据插件声明的字段动态生成的,支持文本、下拉、开关、列表、secret(自动脱敏)甚至模型选择器等控件。
三、三种加载方式:内置、编译内、共享对象 📦
| 方式 | 适用场景 | 注册方式 |
|---|---|---|
| Built in | 随 GoModel 发布:system_prompt、llm_based_altering、string_replace、tag_replace、header_edit、llm_judge及cheapest_healthy路由策略 | 开箱即用 |
| Compiled in | 自己从run包构建二进制 | ext.RegisterPlugin(...)注册后run.Run |
Shared object(.so) | 使用官方二进制,启动时追加代码 | config.yaml的plugins.load(需 cgo 构建) |
共享对象插件是扩展的主战场。package main导出func GoModelPlugin() pluginapi.Plugin构造函数,构建为.so后在配置中声明即可:
plugins: enabled: true search_paths: ["./plugins"] load: - file: keyword_block.so sha256: "3b1f..." # 可选的摘要锁定,不匹配则启动失败⚠️精确工具链规则:Go 的plugin包要求.so与宿主使用相同的 Go 版本、相同的构建标志(-trimpath、-race、-tags)和相同的共享包源码(标准库 +pluginapi)。因此官方提供了gomodel plugin build/plugin inspect命令,自动拷贝宿主二进制的构建标志并打上GoModelBuildInfo戳,版本不符会直接拒绝加载并给出两侧信息。建议把它放进 CI;加载需要 cgo 版本二进制(make build-plugins,见 Dockerfile.plugins)。完整说明见 docs/advanced/plugins.mdx 与 docs/example_plugins/README.md。
四、执行阶段与决策模型:allow / block / respond / warn
工作流(workflow)决定哪些实例在哪个阶段、以什么顺序运行。同一阶段内按step(order值)分组:
- step 升序执行,后面的实例能看到前面的编辑;
- 同一 step 内,
Mutates: false的实例并发运行在交换对象的浅拷贝上; - 每个 step最多一个
Mutates: true的实例,在只读实例之后执行。
每个钩子返回一个Decision,四种动作覆盖了护栏产品几乎全部行为:
| 动作 | 效果 |
|---|---|
allow | 放行,保留已做的编辑 |
block | 以端点原生错误格式拒绝请求(prompt 阶段默认 400,响应/流阶段默认 502) |
respond | 以一段"安全的助手回复"作答(HTTP 200),Agent 循环不会被 4xx 打断 |
warn | 放行,但在审计轨迹中记录并附加X-GoModel-Guardrail: warn; code=<code>响应头 |
每个实例还可配置fail_mode(closed:插件出错即拒绝请求;open:记录日志后放行,适合纯观察者插件)和timeout_ms(按 deadline 强制超时,阻塞的钩子必须响应ctx.Done())。所有实例的执行结果都会写入审计日志的data.guardrails列表——包括静默放行,事后可完整回溯。
五、流过滤:被拆散的敏感词也能拦住 🌊
流式输出是护栏最难的场景:已经发给客户端的字节无法收回。StreamHook通过StreamPolicy()声明三种模式:
| 模式 | 能力 | 延迟代价 |
|---|---|---|
observe | 只读每个事件,仅terminate生效 | 无 |
transform | 对每个事件pass/drop/replace/terminate | 每窗口LookbehindChars个字符的回看延迟 |
buffer | 不逐事件处理,攒完整响应后走OnResponse | 首 token 时间 = 完整响应时间 |
回看(lookbehind)是transform模式的精髓:GoModel 扣留每窗口末尾的LookbehindChars个字符,把"当前增量 + 尾巴"一起呈现给插件。这样横跨两个 chunk 的手机号、API Key 在被发给客户端之前就能在单个事件里被完整看到并改写;Overlap字段告诉插件哪些前缀字符已在上一轮处理过,避免重复改写。对调用外部分类器等高成本钩子,还可以用MinChunkChars聚合增量,降低调用频率。
若block/respond必须保证"决策前什么都不泄漏",就用buffer模式——内置的string_replace和llm_judge正是这么做的。流被中途切断时,客户端会收到finish_reason: "content_filter"后正常收尾。
管理后台的Plugins & Guardrails页面展示了同一份契约的另一面:每个已加载插件的名称、钩子、来源(内置 / 编译内 /.so路径)与健康状态;护栏插件带盾牌标记排在前面;表单由ConfigSchema自动渲染,无需写前端代码。
六、自定义路由:让虚拟模型更聪明 🧭
实现RouteStrategy(Select+OnAttemptEnd)的插件即可成为虚拟模型的负载均衡策略:RouteRequest携带候选模型(含每百万 token 价格)、会话粘滞目标与strategy_config;OnAttemptEnd回传每次尝试的成功/状态/延迟,策略可据此自适应。故障转移链、容量探测与 session 固定仍由 GoModel 负责,插件只负责"选谁"。
virtual_models: - source: smart-router strategy: plugin strategy_plugin: cheapest_healthy # 内置参考策略 strategy_config: prefer: cheapest # cheapest | fastest max_error_rate: 0.2 targets: - openai/gpt-4o-mini - anthropic/claude-haiku-4-5内置的cheapest_healthy(源码在 internal/plugins/builtin/routeexample/)保留每个目标最近 50 次结果,在错误率不超max_error_rate的候选里挑最便宜(或中位延迟最低)的目标。插件缺失、初始化失败或Select超 250ms 时,GoModel 自动回退到加权轮询,只记一条警告。虚拟模型的整体玩法见 docs/features/virtual-models.mdx。
七、动手:30 行写出一个关键词拦截插件 ✍️
官方示例 docs/example_plugins/keywordblock/main.go 实现了prompt+response双钩子,核心形态如下(已简化):
type keywordBlock struct { keywords []string action string // block | respond | warn message string } func (p *keywordBlock) OnPrompt(_ context.Context, x *pluginapi.Exchange) (pluginapi.Decision, error) { if last := x.Prompt.LastUser(); last != nil { if hit := p.match(last.Text()); hit != "" { return p.enforce.Enforce("keyword_block", map[string]any{"word": hit}), nil } } return pluginapi.Allow(), nil } func GoModelPlugin() pluginapi.Plugin { return &keywordBlock{} }关键体验:
- 统一视图:钩子拿到的是
*pluginapi.Exchange——统一的Prompt/Response/Meta,Anthropic 请求已被翻译成 chat 形态,一个插件同时服务/v1/chat/completions、/v1/responses、/v1/messages; - 配置校验免费:
Init收到的是按ConfigSchema校验过的配置(默认值、类型强转、未知键拒绝),用pluginapi.ParseConfig的类型化读取器即可; - 宿主能力注入:
Host提供预打标签的Logger()、走网关预算与审计的Inference().Complete(...)、plugin_<name>_前缀的Metrics()、共享连接池的HTTPClient(); - 离线可测:
pluginapi/plugintest提供假Host、RunStream等工具,不用启动 GoModel 就能单测流钩子的回看、聚合与终止逻辑。
构建与加载一条命令链:
gomodel plugin build ./docs/example_plugins/keywordblock -o plugins/keyword_block.so gomodel plugin inspect plugins/keyword_block.so shasum -a 256 plugins/keyword_block.so # 填入 plugins.load[].sha256八、落地建议与速查 ✅
| 场景 | 建议 |
|---|---|
| 拦截/改写 prompt 与响应 | 优先内置string_replace、llm_judge、llm_based_altering,零开发 |
| 审查流式输出 | transform+ lookbehind 保持流式;需要"先审后发"则用buffer |
| 插件挂了别影响业务 | 纯观察类插件设fail_mode: open,内容修改类保持默认closed |
生产环境加载.so | search_paths保持 root 所有 + 锁定sha256;每次 GoModel/Go 升级后重编译 |
| 排查一次拦截 | 看审计日志的data.guardrails:阶段、step、动作、耗时、改了什么全都有 |
延伸阅读(相对路径):
- 插件系统完整文档:docs/advanced/plugins.mdx
- 护栏使用指南:docs/advanced/guardrails.mdx
- 契约接口定义:pluginapi/plugin.go
- 内置插件参考实现:internal/plugins/builtin/
- 示例插件与构建说明:docs/example_plugins/
一句话总结:GoModel 用一份pluginapi契约把"护栏、流过滤、自定义路由"统一为同一类对象——同一套配置校验、同一套审计轨迹、同一个管理后台。对使用者是低门槛的 YAML 配置,对开发者则是只依赖标准库的稳定扩展点。
【免费下载链接】GoModel
AI gateway / AI control plane / AI proxy written in Go. Unified OpenAI-compatible and Anthropic-compatible API for OpenAI, Anthropic, Gemini, Groq, xAI, Ollama, vLLM and more. A LiteLLM alternative with observability, guardrails, streaming, cost tracking, intelligent routing, sticky sessions, failover, real-time logs and usage tracking. Prod ready.
相关推荐
AgentsView Huma 路由体系深入解析:路由组归属、契约兼容性护栏与数组可空性契约
AgentsView Huma 路由体系深入解析:路由组归属、契约兼容性护栏与数组可空性契约 本文基于 AgentsView 的内部工程规范 huma api
AI 应用数据分析数据可视化可观测性3 步跑通 Kronos 金融大模型:双粒度 Token 化架构与回测实证全解析
3 步跑通 Kronos 金融大模型:双粒度 Token 化架构与回测实证全解析 Kronos 金融大模型是面向 K 线的金融时序预测基础模型,把 OHLCV
人工智能大模型基础模型预训练金融科技CodePilot Composer 模型选择护栏:Runtime 过滤、会话路由与 resolved pair 的完整契约
CodePilot Composer 模型选择护栏:Runtime 过滤、会话路由与 resolved pair 的完整契约 Composer(聊天输入区)背后
人工智能AI 应用AI Agent交互助手MCP Clients本地部署
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考