LangSmith - v0.3.33

LangSmith 客户端 SDK

NPM Version JS Downloads

此软件包包含用于与 LangSmith 平台交互的 TypeScript 客户端。

安装

yarn add langsmith

LangSmith 帮助您和您的团队开发和评估语言模型及智能代理。它兼容任何 LLM 应用程序,并与 LangChain 无缝集成,LangChain 是一个广泛认可的开源框架,可简化开发人员创建强大语言模型应用程序的过程。

注意:您无需使用 LangChain 开源软件包即可享受 LangSmith 的优势!要开始使用您自己的专有框架,请设置您的帐户,然后跳到在 LangChain 外部记录跟踪

Cookbook(操作指南): 有关如何从 LangSmith 获得更多价值的教程,请查看 Langsmith Cookbook 仓库。

典型的工作流程如下

  1. 在 LangSmith 设置帐户。
  2. 记录跟踪。
  3. 调试、创建数据集并评估运行。

我们将在下面更详细地介绍这些步骤。

使用您的 GitHub、Discord 帐户或电子邮件地址和密码注册 LangSmith。如果您使用电子邮件注册,请务必在登录前验证您的电子邮件地址。

然后,在设置页面上创建唯一的 API 密钥。

注意:将 API 密钥保存在安全位置。它不会再次显示。

您可以在 LangChain 应用程序中原生记录跟踪,或使用 LangSmith RunTree。

LangSmith 与 JavaScript LangChain 库无缝集成,可记录您 LLM 应用程序的跟踪。

yarn add langchain
  1. 从设置页面复制环境变量并将其添加到您的应用程序中。

通过设置以下环境变量或手动指定 LangChainTracer,可以激活跟踪。

process.env.LANGSMITH_TRACING = "true";
process.env.LANGSMITH_ENDPOINT = "https://api.smith.langchain.com";
// process.env.LANGSMITH_ENDPOINT = "https://eu.api.smith.langchain.com"; // If signed up in the EU region
process.env.LANGSMITH_API_KEY = "<YOUR-LANGSMITH-API-KEY>";
// process.env.LANGSMITH_PROJECT = "My Project Name"; // Optional: "default" is used if not set

提示:项目是跟踪的集合。所有运行都记录到一个项目中。如果未指定,项目将设置为 default

  1. 在 LangChain 中运行 Agent、Chain 或语言模型

如果环境变量设置正确,您的应用程序将自动连接到 LangSmith 平台。

import { ChatOpenAI } from "langchain/chat_models/openai";

const chat = new ChatOpenAI({ temperature: 0 });
const response = await chat.predict(
"Translate this sentence from English to French. I love programming."
);
console.log(response);

您仍然可以使用 LangSmith 开发平台,而无需依赖任何 LangChain 代码。您可以通过设置适当的环境变量,或直接在 RunTree 中指定连接信息来连接。

  1. 从设置页面复制环境变量并将其添加到您的应用程序中。
export LANGSMITH_TRACING="true";
export LANGSMITH_API_KEY=<YOUR-LANGSMITH-API-KEY>
# export LANGSMITH_PROJECT="My Project Name" # Optional: "default" is used if not set
# export LANGSMITH_ENDPOINT=https://api.smith.langchain.com # or your own server

Langsmith 的 traceable 包装函数可让您轻松跟踪您喜欢的框架中的任何函数或 LLM 调用。以下是一些示例。

使用 LangSmith 跟踪来自 OpenAI SDK 的调用的最简单方法是使用 LangSmith 0.1.3 及更高版本中提供的 wrapOpenAI 包装函数。

要使用,您首先需要设置您的 LangSmith API 密钥

export LANGSMITH_TRACING="true";
export LANGSMITH_API_KEY=<your-api-key>

接下来,您需要安装 LangSmith SDK 和 OpenAI SDK

npm install langsmith openai

之后,初始化您的 OpenAI 客户端并使用 wrapOpenAI 方法包装客户端,以启用对补全和聊天补全方法的跟踪

import { OpenAI } from "openai";
import { wrapOpenAI } from "langsmith/wrappers";

const openai = wrapOpenAI(new OpenAI());

await openai.chat.completions.create({
model: "gpt-3.5-turbo",
messages: [{ content: "Hi there!", role: "user" }],
});

或者,您可以使用 traceable 函数来包装您想要使用的客户端方法

import { traceable } from "langsmith/traceable";

const openai = new OpenAI();

const createCompletion = traceable(
openai.chat.completions.create.bind(openai.chat.completions),
{ name: "OpenAI Chat Completion", run_type: "llm" }
);

await createCompletion({
model: "gpt-3.5-turbo",
messages: [{ content: "Hi there!", role: "user" }],
});

请注意使用 .bind 来保留函数的上下文。额外配置对象中的 run_type 字段将函数标记为 LLM 调用,并启用 OpenAI 的 token 使用跟踪。

通常,您会在其他函数内部或作为较长序列的一部分使用 OpenAI 客户端。通过在其他使用 traceable 包装的函数中使用此包装方法,您可以自动获得嵌套跟踪。

const nestedTrace = traceable(async (text: string) => {
const completion = await openai.chat.completions.create({
model: "gpt-3.5-turbo",
messages: [{ content: text, role: "user" }],
});
return completion;
});

await nestedTrace("Why is the sky blue?");
{
"id": "chatcmpl-8sPToJQLLVepJvyeTfzZMOMVIKjMo",
"object": "chat.completion",
"created": 1707978348,
"model": "gpt-3.5-turbo-0613",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "The sky appears blue because of a phenomenon known as Rayleigh scattering. The Earth's atmosphere is composed of tiny molecules, such as nitrogen and oxygen, which are much smaller than the wavelength of visible light. When sunlight interacts with these molecules, it gets scattered in all directions. However, shorter wavelengths of light (blue and violet) are scattered more compared to longer wavelengths (red, orange, and yellow). \n\nAs a result, when sunlight passes through the Earth's atmosphere, the blue and violet wavelengths are scattered in all directions, making the sky appear blue. This scattering of shorter wavelengths is also responsible for the vibrant colors observed during sunrise and sunset, when the sunlight has to pass through a thicker portion of the atmosphere, causing the longer wavelengths to dominate the scattered light."
},
"logprobs": null,
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 13,
"completion_tokens": 154,
"total_tokens": 167
},
"system_fingerprint": null
}

:::tip 点击此处查看上述 LangSmith 跟踪示例。 :::

您可以在 Next.js 应用程序中使用 traceable 包装函数来包装任意函数,就像上面的示例一样。

对于 Next.js 和其他类似的服务器框架,一个巧妙的技巧是包装路由的整个导出处理程序,以对任何子运行的跟踪进行分组。这是一个示例

import { NextRequest, NextResponse } from "next/server";

import { OpenAI } from "openai";
import { traceable } from "langsmith/traceable";
import { wrapOpenAI } from "langsmith/wrappers";

export const runtime = "edge";

const handler = traceable(
async function () {
const openai = wrapOpenAI(new OpenAI());

const completion = await openai.chat.completions.create({
model: "gpt-3.5-turbo",
messages: [{ content: "Why is the sky blue?", role: "user" }],
});

const response1 = completion.choices[0].message.content;

const completion2 = await openai.chat.completions.create({
model: "gpt-3.5-turbo",
messages: [
{ content: "Why is the sky blue?", role: "user" },
{ content: response1, role: "assistant" },
{ content: "Cool thank you!", role: "user" },
],
});

const response2 = completion2.choices[0].message.content;

return {
text: response2,
};
},
{
name: "Simple Next.js handler",
}
);

export async function POST(req: NextRequest) {
const result = await handler();
return NextResponse.json(result);
}

处理程序中的两个 OpenAI 调用将使用适当的输入、输出和 token 使用信息进行跟踪。

:::tip 点击此处查看上述 LangSmith 跟踪示例。 :::

Vercel AI SDK 包含与各种模型提供商的集成。这是一个如何在 Next.js 处理程序中跟踪输出的示例

import { traceable } from "langsmith/traceable";
import { OpenAIStream, StreamingTextResponse } from "ai";

// Note: There are no types for the Mistral API client yet.
import MistralClient from "@mistralai/mistralai";

const client = new MistralClient(process.env.MISTRAL_API_KEY || "");

export async function POST(req: Request) {
// Extract the `messages` from the body of the request
const { messages } = await req.json();

const mistralChatStream = traceable(client.chatStream.bind(client), {
name: "Mistral Stream",
run_type: "llm",
});

const response = await mistralChatStream({
model: "mistral-tiny",
maxTokens: 1000,
messages,
});

// Convert the response into a friendly text-stream. The Mistral client responses are
// compatible with the Vercel AI SDK OpenAIStream adapter.
const stream = OpenAIStream(response as any);

// Respond with the stream
return new StreamingTextResponse(stream);
}

有关更多示例,请参阅 AI SDK 文档

您可以使用通用的 wrapSDK 方法为任意 SDK 添加跟踪。

请注意,这将跟踪 SDK 中的所有方法,而不仅仅是聊天补全端点。如果您包装的 SDK 还有其他方法,我们建议仅将其用于 LLM 调用。

这是一个使用 Anthropic SDK 的示例

import { wrapSDK } from "langsmith/wrappers";
import { Anthropic } from "@anthropic-ai/sdk";

const originalSDK = new Anthropic();
const sdkWithTracing = wrapSDK(originalSDK);

const response = await sdkWithTracing.messages.create({
messages: [
{
role: "user",
content: `What is 1 + 1? Respond only with "2" and nothing else.`,
},
],
model: "claude-3-sonnet-20240229",
max_tokens: 1024,
});

:::tip 点击此处查看上述 LangSmith 跟踪示例。 :::

RunTree 跟踪您的应用程序。每个 RunTree 对象都需要具有名称和 run_type。这些和其他重要属性如下:

  • name: string - 用于标识组件的用途
  • run_type: string - 当前为“llm”、“chain”或“tool”之一;未来将添加更多选项
  • inputs: Record<string, any> - 组件的输入
  • outputs: Optional<Record<string, any>> - 组件的(可选)返回值
  • error: Optional<string> - 调用期间可能出现的任何错误消息
import { RunTree, RunTreeConfig } from "langsmith";

const parentRunConfig: RunTreeConfig = {
name: "My Chat Bot",
run_type: "chain",
inputs: {
text: "Summarize this morning's meetings.",
},
serialized: {}, // Serialized representation of this chain
// project_name: "Defaults to the LANGSMITH_PROJECT env var"
// apiUrl: "Defaults to the LANGSMITH_ENDPOINT env var"
// apiKey: "Defaults to the LANGSMITH_API_KEY env var"
};

const parentRun = new RunTree(parentRunConfig);

await parentRun.postRun();

const childLlmRun = await parentRun.createChild({
name: "My Proprietary LLM",
run_type: "llm",
inputs: {
prompts: [
"You are an AI Assistant. The time is XYZ." +
" Summarize this morning's meetings.",
],
},
});

await childLlmRun.postRun();

await childLlmRun.end({
outputs: {
generations: [
"I should use the transcript_loader tool" +
" to fetch meeting_transcripts from XYZ",
],
},
});

await childLlmRun.patchRun();

const childToolRun = await parentRun.createChild({
name: "transcript_loader",
run_type: "tool",
inputs: {
date: "XYZ",
content_type: "meeting_transcripts",
},
});
await childToolRun.postRun();

await childToolRun.end({
outputs: {
meetings: ["Meeting1 notes.."],
},
});

await childToolRun.patchRun();

const childChainRun = await parentRun.createChild({
name: "Unreliable Component",
run_type: "tool",
inputs: {
input: "Summarize these notes...",
},
});

await childChainRun.postRun();

try {
// .... the component does work
throw new Error("Something went wrong");
} catch (e) {
await childChainRun.end({
error: `I errored again ${e.message}`,
});
await childChainRun.patchRun();
throw e;
}

await childChainRun.patchRun();

await parentRun.end({
outputs: {
output: ["The meeting notes are as follows:..."],
},
});

// False directs to not exclude child runs
await parentRun.patchRun();

一旦您的运行存储在 LangSmith 中,您就可以将其转换为数据集。在此示例中,我们将使用客户端进行此操作,但您也可以使用 Web 界面进行此操作,如 LangSmith 文档中所述。

import { Client } from "langsmith/client";
const client = new Client({
// apiUrl: "https://api.langchain.com", // Defaults to the LANGSMITH_ENDPOINT env var
// apiKey: "my_api_key", // Defaults to the LANGSMITH_API_KEY env var
/* callerOptions: {
maxConcurrency?: Infinity; // Maximum number of concurrent requests to make
maxRetries?: 6; // Maximum number of retries to make
*/
});
const datasetName = "Example Dataset";
// We will only use examples from the top level AgentExecutor run here,
// and exclude runs that errored.
const runs = await client.listRuns({
projectName: "my_project",
executionOrder: 1,
error: false,
});

const dataset = await client.createDataset(datasetName, {
description: "An example dataset",
});

for (const run of runs) {
await client.createExample(run.inputs, run.outputs ?? {}, {
datasetId: dataset.id,
});
}

评估运行

请查阅 LangSmith 测试与评估文档以获取最新的工作流程。

要对单个运行生成自动化反馈,您可以直接使用 LangSmith 客户端运行评估。

import { StringEvaluator } from "langsmith/evaluation";

function jaccardChars(output: string, answer: string): number {
const predictionChars = new Set(output.trim().toLowerCase());
const answerChars = new Set(answer.trim().toLowerCase());
const intersection = [...predictionChars].filter((x) => answerChars.has(x));
const union = new Set([...predictionChars, ...answerChars]);
return intersection.length / union.size;
}

async function grader(config: {
input: string;
prediction: string;
answer?: string;
}): Promise<{ score: number; value: string }> {
let value: string;
let score: number;
if (config.answer === null || config.answer === undefined) {
value = "AMBIGUOUS";
score = 0.5;
} else {
score = jaccardChars(config.prediction, config.answer);
value = score > 0.9 ? "CORRECT" : "INCORRECT";
}
return { score: score, value: value };
}

const evaluator = new StringEvaluator({
evaluationName: "Jaccard",
gradingFunction: grader,
});

const runs = await client.listRuns({
projectName: "my_project",
executionOrder: 1,
error: false,
});

for (const run of runs) {
client.evaluateRun(run, evaluator);
}

要了解有关 LangSmith 平台的更多信息,请查阅文档