☰
AI SDK + evlog:每次AI调用一条完整事件,token、工具调用与成本尽收眼底
2026/10/10 14:12:11 网站建设 项目流程

【免费下载链接】evlog

Digging through logs is not observability. It's hope — wide events, structured errors, TypeScript-first, every runtime.

项目地址:https://gitcode.com/gh_mirrors/ev/evlog
点击查看免费下载

evlog 是一个 TypeScript 优先的结构化日志库,核心理念是"每个请求一条宽事件(wide event)"。配合官方 AI SDK,evlog/ai会把每次 AI 调用的 token 用量、工具调用、流式速度与成本自动汇总进同一条宽事件——无需手写埋点,也无需额外追踪。你是否遇到过这样的场景:AI 接口跑了一分钟,你却不知道它消耗了多少 token、调了哪些工具、花了多少钱?本文带你用 3 步完成接入,让 AI 调用可观测变得简单。

一、为什么 AI 调用需要"一条完整事件" 🔍

AI 应用里的传统埋点方式,痛点很明显:

  • token 是散的:输入、输出、推理 token 藏在响应各处,翻账单要逐个对;
  • 成本是黑盒:单次请求花了多少钱无法实时知道,做预算告警和计费都很吃力;
  • 工具调用难复盘:一个多步 Agent 调了 5 次工具,却看不出哪一步慢、哪一步失败;
  • 日志是碎的:一次聊天请求散落几十行日志,凌晨三点只能靠 grep 找信号。

evlog 的思路正好相反:与其翻日志找线索,不如每次只留一条完整事件。

二、三步接入:两行代码开始记录 AI 调用 ⚡

2.1 安装依赖

添加 AI SDK 即可(evlog 通常在项目中已就绪):

npm install ai

2.2 用中间件包裹模型

加两行、改一个参数,接入即完成:

import { useLogger } from 'evlog' import { createAILogger } from 'evlog/ai' const log = useLogger(event) // evlog 的请求日志器 const ai = createAILogger(log) // AI 可观测日志器 const result = streamText({ model: ai.wrap('anthropic/claude-sonnet-4.6'), messages, })

ai.wrap()返回一个带中间件的模型,之后generateText、streamText、ToolLoopAgent的每次调用都会自动累计数据。中间件不触碰你的onFinish回调、提示词和响应,属于纯"旁观式"记录。

2.3 拿回完整事件

请求结束时,宽事件自动携带ai字段发出:

{ "method": "POST", "path": "/api/chat", "status": 200, "durationMs": 4512, "ai": { "calls": 1, "model": "claude-sonnet-4.6", "provider": "anthropic", "inputTokens": 3312, "outputTokens": 814, "totalTokens": 4126, "reasoningTokens": 225, "finishReason": "stop", "msToFirstChunk": 234, "msToFinish": 4500, "tokensPerSecond": 180 } }

三、evlog/ai 会自动捕获哪些数据 📊

不做任何额外配置,ai.wrap()就已经记录了这些内容:

数据宽事件字段说明
token 用量ai.inputTokens/ai.outputTokens/ai.totalTokens同一请求内多次调用自动累计
缓存命中ai.cacheReadTokens/ai.cacheWriteTokens提示词缓存的读写 token
推理 tokenai.reasoningTokens扩展思考产生的 token
模型信息ai.model/ai.provider/ai.models最后使用的模型、提供方、多模型场景的全部模型
工具调用ai.toolCalls默认记录工具名,开启后可附带调用入参
流式指标ai.msToFirstChunk/ai.tokensPerSecond首 token 时延、输出速度
结束原因ai.finishReasonstop、tool-calls、error等
错误ai.error模型调用失败信息,先写入事件再重新抛出

对流式响应,evlog 在 Nuxt、Nitro、Next.js 等框架上会把宽事件的发出延迟到流结束后,保证最终的 token 数据和请求上下文落在同一条事件上。

四、估算 AI 调用成本:加一张价格表 💰

cost选项接受按"每百万 token 美元"计价的价格表,宽事件会自动算出ai.estimatedCost:

const ai = createAILogger(log, { cost: { 'claude-sonnet-4.6': { input: 3, output: 15 }, 'gpt-4o': { input: 2.5, output: 10 }, }, }) // 在处理器里随时读取本次调用的成本 const cost = ai.getEstimatedCost() console.log(`本次调用花费 $${cost?.toFixed(4)}`)

由此可以实现"昂贵调用前先提醒用户"、按用户汇总 AI 支出等场景。小建议:把价格表和模型选择放在同一个文件里维护,换模型时价格同步更新,避免多条路由各自维护导致漂移。

五、多步 Agent、RAG 与多模型场景 🔧

5.1 多步 Agent 全程留痕

使用ToolLoopAgent时,中间件对每一步自动记录,宽事件里能看到逐步明细:

{ "ai": { "calls": 3, "steps": 3, "toolCalls": ["searchWeb", "queryDatabase", "searchWeb"], "stepsUsage": [ { "model": "claude-sonnet-4.6", "inputTokens": 1200, "outputTokens": 300, "toolCalls": ["searchWeb"] }, { "model": "claude-sonnet-4.6", "inputTokens": 1500, "outputTokens": 400, "toolCalls": ["queryDatabase", "searchWeb"] } ] } }

想看到每个工具收到的入参(调试 Agent 行为时非常有用),开启toolInputs:

const ai = createAILogger(log, { toolInputs: { maxLength: 500 } })

5.2 RAG 里的 embedding 调用

embedding 模型不能通过中间件包裹,用专门方法手动上报即可:

const { embedding, usage } = await embed({ model: embeddingModel, value: query }) ai.captureEmbed({ usage, model: 'text-embedding-3-small', dimensions: 1536 })

5.3 多模型路由

每个模型各自wrap一次即可,它们共享同一个累计器。事件里会同时出现ai.model(最后一次使用的模型)和ai.models(出现过的全部模型),路由行为一目了然。

六、更深度的遥测:工具执行耗时与总生成时长 🚀

ai.wrap()覆盖 token、模型与流式指标;若还想拿到每个工具的执行耗时、成功/失败以及整次生成的总墙上时间,再叠加一个集成即可:

const result = await generateText({ model: ai.wrap('anthropic/claude-sonnet-4.6'), tools: { getWeather, searchDB }, telemetry: { integrations: [createEvlogIntegration(ai)], }, })

宽事件随之多出这些字段:

{ "ai": { "tools": [ { "name": "getWeather", "durationMs": 150, "success": true }, { "name": "searchDB", "durationMs": 45, "success": true } ], "totalDurationMs": 2340 } }

在 AI SDK v7 上,该集成还会自动捕获 embedding、流式中止(ai.finishReason: 'abort')和不可恢复错误,两者组合即完整的 AI 可观测。

七、新手避坑:4 条最佳实践 ✅

  1. 敏感内容默认不开启:prompt、output、toolInputs三个选项默认关闭,模型收发过的内容不会流入日志目的地,除非你点名要;
  2. 要捕获就先加maxLength和transform:两者内置支持截断与脱敏。工具入参常含 SQL、密钥和用户数据,生产环境建议先开截断再开捕获;
  3. 价格表单一来源:cost表与模型配置放一起维护,改模型和改价格发生在同一处;
  4. 错误也在同一条事件:模型调用失败会先写入ai.error再重新抛出,你的try/catch照常工作,排查时一条事件同时看到错误、token 和工具调用。

八、相关资源 📚

  • 官方文档 · AI SDK 集成总览:apps/docs/content/5.use-cases/2.ai-sdk/01.overview.md
  • 用法模式(流式、Agent、RAG、多模型):apps/docs/content/5.use-cases/2.ai-sdk/02.usage.md
  • 全部选项(工具入参、提示词/输出捕获、成本表):apps/docs/content/5.use-cases/2.ai-sdk/03.options.md
  • 在处理器内读取元数据(getMetadata/getEstimatedCost/onUpdate):apps/docs/content/5.use-cases/2.ai-sdk/04.metadata.md
  • 深度遥测(工具耗时、总生成时长):apps/docs/content/5.use-cases/2.ai-sdk/05.telemetry.md
  • 核心实现(createAILogger入口):packages/evlog/src/ai/index.ts#L490-L531
  • 宽事件概念详解:apps/docs/content/2.learn/2.wide-events.md

从今天起,让每次 AI 调用都留下一条完整、可检索、可分析的事件——token、工具调用与成本,尽收眼底。

【免费下载链接】evlog

Digging through logs is not observability. It's hope — wide events, structured errors, TypeScript-first, every runtime.

项目地址:https://gitcode.com/gh_mirrors/ev/evlog
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询