LangSmith - v0.3.15

LangSmith 客户端 SDK

NPM Version JS Downloads

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

安装方法

yarn add langsmith

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

注意:即使不使用 LangChain 开源软件包,您也可以享受 LangSmith 的优势!要开始使用您自己的专有框架,请设置您的帐户,然后跳至 在 LangChain 之外记录追踪

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

典型的workflow如下

  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 方法包装客户端,以启用 completions 和 chat completions 方法的追踪

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 来保留函数的上下文。extra config 对象中的 run_type 字段将该函数标记为 LLM 调用,并为 OpenAI 启用令牌使用情况跟踪。

通常,您在其他函数内部或作为较长序列的一部分使用 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 调用将被追踪,并带有适当的输入、输出和令牌使用情况信息。

:::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 平台的更多信息,请查看文档