Helicone 网关接入 Google Gemini(TypeScript):原生 fetch 代理请求实战指南
【免费下载链接】helicone🧊 Open source LLM observability platform. One line of code to monitor, evaluate, and experiment. YC W23 🍓项目地址: https://gitcode.com/GitHub_Trending/he/helicone
导读
本文基于 Helicone 开源仓库中的 Gemini TypeScript 示例,完整讲解如何通过 Helicone AI 网关以原生fetch方式调用 Google Gemini 模型,实现"不改一行业务逻辑即可获得全链路可观测性"的效果。读完本文,你将掌握Helicone-Auth、Helicone-Target-Url、Helicone-User-Id、Helicone-Property-*等网关头的配置方法、Gemini REST API 请求体结构,以及如何用官方 TypeScript SDK 与 Python Instructor 两种方式接入,并能在 Helicone 控制台中按用户、属性、会话维度检索与分析请求。
一、示例解决的问题:给 Gemini 请求"加上观测层"
示例所在的目录是 examples/gemini-instructor-example/typescript,它演示的核心思路是:不直接向 Google 的generativelanguage.googleapis.com发请求,而是把请求发给 Helicone 网关gateway.helicone.ai,由网关代为转发到 Google,并在转发前后完成日志记录、成本核算、用户与属性标注等观测工作。
这样做的好处是:
- 应用代码里无需引入任何 Helicone SDK,仅靠 HTTP 头和 URL 改写即可接入;
- 网关解析请求头后,会把
user_id、自定义属性、会话信息等一并写入 Helicone 的数据链路; - 开发者可以继续使用 Gemini 原生的
generateContentREST 接口与请求体格式,学习成本几乎为零。
从网关侧看,这些头部正是由网关的请求头解析模块负责读取的。核心实现位于 worker/src/lib/models/HeliconeHeaders.ts,其中:
Helicone-Target-URL头被读取为targetBaseUrl(HeliconeHeaders.ts 第 359 行),用于确定请求要转发到的真实上游地址;Helicone-User-Id头被读取为userId(第 387 行),用于关联到具体终端用户;- 以
Helicone-Property-开头的头会被统一收进heliconeProperties(第 473-485 行),成为该请求可检索的自定义属性。
理解了这个解析链路,就能明白示例中每个头字段的用途。
二、环境准备与前置条件
运行本示例需要以下条件:
| 依赖 | 说明 |
|---|---|
| Node.js 16+ | 运行时,示例基于fetch全局 API,需 Node 16+ |
| Helicone API 密钥 | 用于Helicone-Auth头认证网关身份 |
| Google Gemini API 密钥 | 以key查询参数形式透传给 Google |
示例目录下包含的文件如下:
- gemini_example.ts:基于原生
fetch的完整示例主程序; - gemini_example_sdk.ts:基于 Google 官方
@google/genaiSDK 的接入示例; - package.json:依赖与脚本定义;
- run.sh:一键运行脚本(含环境检查);
- tsconfig.json:TypeScript 编译配置。
1. 进入示例目录
cd examples/gemini-instructor-example/typescript2. 创建.env文件
在示例目录下新建.env,写入:
HELICONE_API_KEY=your_helicone_api_key GEMINI_API_KEY=your_gemini_api_key USER_ID=test_user_123三个变量的作用分别是:网关认证、Gemini 模型访问、以及在 Helicone 控制台标识本次请求归属的用户。示例代码在读取时做了容错处理,USER_ID未设置时会回退为"default_user"(见 gemini_example.ts 第 10 行)。
3. 安装依赖
npm install依赖清单见 package.json:运行时仅需dotenv(加载环境变量),开发期需要typescript、ts-node、@types/node。
4. 运行示例
npm startnpm start实际执行的是ts-node gemini_example.ts。也可以直接使用仓库提供的脚本 run.sh,它会依次检查node、npm、.env是否存在,缺失时给出明确提示,并在首次运行时自动npm install:
./run.sh程序会打印如下信息并输出模型返回的文本:
=== Making Gemini API call through Helicone gateway === User ID: test_user_123 Prompt: "List 3 classic sci-fi movies from the 1980s." === Response === ...三、核心实现:一条被网关"接管"的 Gemini 请求
gemini_example.ts的关键在于构造requestConfig,把原本指向 Google 的请求整体"搬"到 Helicone 网关上。以下代码完整来自示例主程序(gemini_example.ts 第 12-61 行):
async function makeGeminiRequest( prompt: string, analyticsPermission: boolean = true ) { const requestConfig = { url: `${HELICONE_URL}/v1beta/models/gemini-1.5-flash-latest:generateContent?key=${GEMINI_API_KEY}`, headers: { "Content-Type": "application/json", "Helicone-Auth": `Bearer ${HELICONE_API_KEY}`, "Helicone-Target-Url": "https://generativelanguage.googleapis.com", "Helicone-User-Id": USER_ID, } as Record<string, string>, body: { contents: [ { role: "user", parts: [{ text: prompt }], }, ], generationConfig: { temperature: 0.7, maxOutputTokens: 8192, }, }, }; const response = await fetch(requestConfig.url, { method: "POST", headers: requestConfig.headers, body: JSON.stringify(requestConfig.body), }); if (!response.ok) { throw new Error( `HTTP error! status: ${response.status}, message: ${await response.text()}` ); } const data = await response.json(); return data; }这段代码里有四个关键点值得展开:
3.1 URL 结构:网关路径 + 原路径 + key 查询参数
请求 URL 为:
https://gateway.helicone.ai/v1beta/models/gemini-1.5-flash-latest:generateContent?key=${GEMINI_API_KEY}- 主机从
generativelanguage.googleapis.com替换为 Helicone 网关gateway.helicone.ai; - 路径
/v1beta/models/<模型名>:generateContent保持 Gemini REST API 的原样(gemini-1.5-flash-latest可替换为其他模型,如gemini-2.0-flash); - Gemini 的 API 密钥通过
key查询参数透传,网关不会消费这个密钥,它只负责把请求转发给上游。
需要说明的是,示例主程序中的HELICONE_URL来自process.env.HELICONE_URL(第 9 行),README 中则直接写为https://gateway.helicone.ai。若你自托管了 Helicone 网关,可把该变量指向自己的网关地址。
3.2 请求头:Helicone 的三个基础头
| 头字段 | 值 | 作用 |
|---|---|---|
Helicone-Auth | Bearer ${HELICONE_API_KEY} | 向网关出示 Helicone API 密钥,完成认证。网关侧从helicone-auth读取(见 HeliconeHeaders.ts 第 354 行) |
Helicone-Target-Url | https://generativelanguage.googleapis.com | 告诉网关"把请求转发到哪个上游地址",这是网关路由的关键 |
Helicone-User-Id | ${USER_ID} | 为该请求绑定用户标识,用于控制台的用户维度分析 |
除了这三个头,README 的请求配置中还演示了两个自定义属性头(README.md 第 61-64 行):
"Helicone-Property-App": "cursor-extension-cursorrules", "Helicone-Property-AnalyticsPermission": analyticsPermission ? "true" : "false",Helicone-Property-*是任意自定义属性的统一命名约定:网关会把该前缀之后的字符串作为属性名、头值为属性值,统一收进请求的可检索属性集合(见 HeliconeHeaders.ts 第 473-485 行)。这也是 Helicone 支持"任意业务维度打标"的实现基础。
3.3 请求体:保持 Gemini 原生generateContent格式
示例请求体完全遵循 Gemini REST API 规范:
{ "contents": [ { "role": "user", "parts": [{ "text": "List 3 classic sci-fi movies from the 1980s." }] } ], "generationConfig": { "temperature": 0.7, "maxOutputTokens": 8192 } }contents:对话内容数组,role支持user/model,多轮对话可追加多个元素;parts:内容块,text即文本输入;generationConfig:生成参数,示例给出temperature: 0.7(采样温度)与maxOutputTokens: 8192(最大输出 token 数),可按需增减。
由于请求体没有被网关改写,你在 Google 侧如何调 Gemini,这里就如何写,迁移成本几乎为零。
3.4 响应解析:按 Gemini 返回结构取文本
响应 JSON 中,生成文本位于candidates[0].content.parts[0].text,示例中通过可选链安全取值(第 79-80 行):
const responseText = response.candidates?.[0]?.content?.parts?.[0]?.text || "No response text";四、进阶方式:用 Google 官方 SDK 走 Helicone 网关
除了裸fetch,仓库还提供了基于 Google 官方@google/genaiSDK 的接入示例 gemini_example_sdk.ts。其思路是把网关地址注入 SDK 的httpOptions:
import { GoogleGenAI } from "@google/genai"; const genAI = new GoogleGenAI({ apiKey: "<GOOGLE_API_KEY>", vertexai: true, httpOptions: { baseUrl: "https://gateway.helicone.ai", headers: { "Helicone-Auth": "Bearer <HELICONE_API_KEY>", "Helicone-Target-URL": "https://generativelanguage.googleapis.com", }, }, }); async function generateContent() { const response = await genAI.models.generateContent({ model: "gemini-2.0-flash-001", contents: "Why is the sky blue?", }); console.log(response.text); } generateContent();要点:
- SDK 的
apiKey仍然填 Google 的密钥(或按你的鉴权方式配置); httpOptions.baseUrl指向网关,httpOptions.headers注入 Helicone 认证头与目标地址头;- 注意此处使用了
Helicone-Target-URL(全大写 URL),与 README 中的Helicone-Target-Url写法不同——网关在解析时通过this.headers.get("Helicone-Target-URL")读取(第 359 行),HTTP 头本身不区分大小写,两种写法均被正确识别; - 这种方式适合已经深度使用官方 SDK、希望最小改动的项目。
五、多用户场景:为什么要在请求里带 User ID
仓库同名目录下的 Python 示例 examples/gemini-instructor-example/python 特意演示了"带与不带user_id"的对比:两次请求在功能上完全一致,但只有第二次会与用户test_user_123关联,从而可以在 Helicone 控制台中按用户检索到它。
这里有一个值得注意的客户端差异:Google 官方 Python SDK 不支持在单次请求上动态传extra_headers,必须把 Helicone 头放进default_metadata随客户端初始化(见 python/README.md 的说明)。因此多用户场景下,要么为每个用户创建独立客户端实例,要么在每次请求前重新配置客户端。而 TypeScript 的原生fetch方式没有这个限制——每个请求的头都是独立的,天然适合多用户、动态打标的场景。
六、在 Helicone 控制台验证请求
运行示例后,打开 Helicone 控制台,检查以下几点:
- 请求列表中出现该条 Gemini 调用记录,模型、耗时、token 消耗与成本已自动统计;
- 请求详情中能查看到
user_id为test_user_123(或你在.env中设置的值); - 若在头中添加了
Helicone-Property-*,对应属性会出现在请求的自定义属性中,可用于后续筛选与报表分析。
七、常见问题排查
| 现象 | 排查方向 |
|---|---|
| 401/认证失败 | 检查HELICONE_API_KEY是否正确、是否以Bearer前缀发送 |
| 上游返回 4xx | 确认GEMINI_API_KEY有效;确认请求体符合 GeminigenerateContent规范 |
| 请求超时或网络错误 | 确认运行环境能访问gateway.helicone.ai;若自托管,检查HELICONE_URL指向的网关地址 |
| 控制台查不到请求 | 确认头字段名拼写无误,尤其是Helicone-Auth与Helicone-Target-Url |
此外,run.sh中内置了环境自检:node/npm缺失或.env不存在时会在运行前给出明确报错,可作为快速排错入口。
八、总结
本示例展示了接入 Helicone 网关最轻量的一条路径:不改 Gemini 的请求协议,只改 URL 主机与三个网关头,即可让 Google Gemini 调用进入 Helicone 的可观测体系。无论你倾向裸fetch的透明可控、官方 SDK 的零成本迁移,还是结合 Instructor 的结构化输出(参考同目录 Python 示例),核心原理一致——网关替你转发、记录、打标,而你的业务代码始终保持简洁。
更完整的网关能力(统一 OpenAI 兼容 API、多 provider 路由、缓存、会话追踪等)可继续阅读仓库中的 docs/gateway/overview.mdx 与 docs/gateway/integrations/overview.mdx;网关头部的完整解析逻辑可深入 worker/src/lib/models/HeliconeHeaders.ts 查看。
【免费下载链接】helicone🧊 Open source LLM observability platform. One line of code to monitor, evaluate, and experiment. YC W23 🍓项目地址: https://gitcode.com/GitHub_Trending/he/helicone
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考