From c5308558f2e558591c092aaa6f834c6724c5bfef Mon Sep 17 00:00:00 2001 From: Nicole White Date: Fri, 27 Oct 2023 18:42:09 -0400 Subject: [PATCH] Add spans example --- .github/workflows/ci.yml | 1 + JavaScript/spans/README.md | 60 ++++++++ JavaScript/spans/package-lock.json | 224 +++++++++++++++++++++++++++++ JavaScript/spans/package.json | 15 ++ JavaScript/spans/src/index.js | 85 +++++++++++ README.md | 1 + 6 files changed, 386 insertions(+) create mode 100644 JavaScript/spans/README.md create mode 100644 JavaScript/spans/package-lock.json create mode 100644 JavaScript/spans/package.json create mode 100644 JavaScript/spans/src/index.js diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 476413d5..7762f8d3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -96,6 +96,7 @@ jobs: - JavaScript/langchain - JavaScript/openai-automated - JavaScript/openai-manual + - JavaScript/spans defaults: run: diff --git a/JavaScript/spans/README.md b/JavaScript/spans/README.md new file mode 100644 index 00000000..5063713d --- /dev/null +++ b/JavaScript/spans/README.md @@ -0,0 +1,60 @@ + +

+ +

+ +

+ 📚 + Documentation +   + • +   + 🖥️ + Application +   + • +   + 🏠 + Home +

+ + +## Getting started + +- Sign up for an Autoblocks account at https://app.autoblocks.ai +- Grab your Autoblocks ingestion key from https://app.autoblocks.ai/settings/api-keys +- Create a file named `.env` in this folder and include the following environment variables: + +``` +AUTOBLOCKS_INGESTION_KEY= +``` + +## Creating spans + +This example shows how you can establish parent / child relationships between your events by sending the `spanId` and `parentSpanId` properties. + +## Install dependencies + +``` +npm install +``` + +## Run the script + +``` +npm run start +``` + +## View the trace tree + +Go to the [explore page](https://app.autoblocks.ai/explore) and find the trace, then switch to the Trace Tree view. You should see something like this: + +![rag-span](https://github.com/autoblocksai/autoblocks-examples/assets/7498009/e5a0f0d9-8460-49a6-a8aa-d707d14323a6) + +Within the RAG span, we made two embeddings calls: these are both children of the RAG span. + +![embedding-span](https://github.com/autoblocksai/autoblocks-examples/assets/7498009/7f9c4b4a-8704-4f7c-97b0-fd9acfc01932) + +Then there is the LLM span at the end, which is not a child of the RAG span because we ended the RAG span before starting the LLM span: + +![llm-span](https://github.com/autoblocksai/autoblocks-examples/assets/7498009/682d5d57-b343-4d5a-851a-e4aa9acef867) diff --git a/JavaScript/spans/package-lock.json b/JavaScript/spans/package-lock.json new file mode 100644 index 00000000..22766e62 --- /dev/null +++ b/JavaScript/spans/package-lock.json @@ -0,0 +1,224 @@ +{ + "name": "spans", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "spans", + "version": "0.0.0", + "license": "MIT", + "dependencies": { + "@autoblocks/client": "^0.0.15", + "dotenv-cli": "^7.3.0" + } + }, + "node_modules/@autoblocks/client": { + "version": "0.0.15", + "resolved": "https://registry.npmjs.org/@autoblocks/client/-/client-0.0.15.tgz", + "integrity": "sha512-rYUyyMO3+XdLLHFH7LlRz/zxSY4rLHUOCoVefnJvZKxud2INAeSfURDQ2nmJouv1zZREY9HedOY8PBa9g8NFvg==", + "dependencies": { + "axios": "^1.4.0", + "zod": "^3.21.4" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.0.tgz", + "integrity": "sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/motdotla/dotenv?sponsor=1" + } + }, + "node_modules/dotenv-cli": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/dotenv-cli/-/dotenv-cli-7.3.0.tgz", + "integrity": "sha512-314CA4TyK34YEJ6ntBf80eUY+t1XaFLyem1k9P0sX1gn30qThZ5qZr/ZwE318gEnzyYP9yj9HJk6SqwE0upkfw==", + "dependencies": { + "cross-spawn": "^7.0.3", + "dotenv": "^16.3.0", + "dotenv-expand": "^10.0.0", + "minimist": "^1.2.6" + }, + "bin": { + "dotenv": "cli.js" + } + }, + "node_modules/dotenv-expand": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-10.0.0.tgz", + "integrity": "sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==", + "engines": { + "node": ">=12" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "engines": { + "node": ">=8" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/zod": { + "version": "3.22.2", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.2.tgz", + "integrity": "sha512-wvWkphh5WQsJbVk1tbx1l1Ly4yg+XecD+Mq280uBGt9wa5BKSWf4Mhp6GmrkPixhMxmabYY7RbzlwVP32pbGCg==", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/JavaScript/spans/package.json b/JavaScript/spans/package.json new file mode 100644 index 00000000..e2fa20a2 --- /dev/null +++ b/JavaScript/spans/package.json @@ -0,0 +1,15 @@ +{ + "name": "spans", + "version": "0.0.0", + "description": "Establish parent / child relationships between your events with the `spanId` and `parentSpanId` properties", + "type": "module", + "main": "src/index.js", + "scripts": { + "start": "dotenv -e .env -- node ./src/index.js" + }, + "license": "MIT", + "dependencies": { + "@autoblocks/client": "^0.0.15", + "dotenv-cli": "^7.3.0" + } +} diff --git a/JavaScript/spans/src/index.js b/JavaScript/spans/src/index.js new file mode 100644 index 00000000..be8b2bb8 --- /dev/null +++ b/JavaScript/spans/src/index.js @@ -0,0 +1,85 @@ +import crypto from 'crypto'; +import { AutoblocksTracer } from '@autoblocks/client'; + +const tracer = new AutoblocksTracer(process.env.AUTOBLOCKS_INGESTION_KEY, { + traceId: crypto.randomUUID(), + properties: { + provider: 'openai', + }, +}); + +const spanStack = []; + +function startSpan() { + spanStack.push(crypto.randomUUID()); + setSpanIds(); +} + +function endSpan() { + if (spanStack.length > 0) { + spanStack.pop(); + setSpanIds(); + } +} + +function setSpanIds() { + let spanId = undefined; + let parentSpanId = undefined; + + if (spanStack.length >= 2) { + spanId = spanStack[spanStack.length - 1]; + parentSpanId = spanStack[spanStack.length - 2]; + } else if (spanStack.length === 1) { + spanId = spanStack[0]; + } + + tracer.updateProperties({ spanId, parentSpanId }); +} + +const spanFunction = async (fn) => { + startSpan(); + await fn(); + endSpan(); +}; + +async function makeEmbeddingRequest() { + await tracer.sendEvent('ai.embedding.request'); + + // Make embedding request... + + await tracer.sendEvent('ai.embedding.response'); +} + +async function startRAGPipeline() { + await tracer.sendEvent('ai.rag.start'); + + // Simulate making multiple embedding requests within a RAG pipeline + await spanFunction(makeEmbeddingRequest); + await spanFunction(makeEmbeddingRequest); + + await tracer.sendEvent('ai.rag.end'); +} + +async function makeLLMRequest() { + // Here we would use the RAG response to generate a prompt for the LLM + + await tracer.sendEvent('ai.completion.request', { + properties: { + temperature: 0.5, + topP: 1, + }, + }); + + await tracer.sendEvent('ai.completion.response', { + properties: { + totalTokens: 123, + }, + }); +} + +async function run() { + await spanFunction(startRAGPipeline); + await spanFunction(makeLLMRequest); +} + +run(); diff --git a/README.md b/README.md index 7d0edebb..600dfe4a 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ | [novel-ai-text-editor](/JavaScript/novel-ai-text-editor) | A Next.js app that uses [Novel](https://github.com/steven-tey/novel) and Autoblocks to power an AI-enabled text editor | | [openai-automated](/JavaScript/openai-automated) | Automatic tracing of openai calls | | [openai-manual](/JavaScript/openai-manual) | Manual tracing of openai calls | +| [spans](/JavaScript/spans) | Establish parent / child relationships between your events with the `spanId` and `parentSpanId` properties |