主题
成本追踪
大规模构建智能体会带来不可忽视且难以追踪的按用量计费成本。LangSmith 会自动记录主要服务商的 LLM token 用量和成本,同时也允许你为任何其他组件提交自定义成本数据。
这为你提供了一个覆盖整个应用的统一成本视图,便于监控、理解和排查你的支出。
NOTE
要为评估器运行设置 LLM 成本上限,请参阅追踪并限制评估器支出。评估器支出追踪与限额使用在模型定价下配置的按模型定价。
在 LangSmith 界面中查看成本
在 LangSmith 界面 中,你可以通过三种方式查看用量和支出:单条追踪内的明细、项目统计中的聚合指标,以及仪表盘。
Token 与成本明细
界面将 token 用量和成本划分为三类:
- Input:发送给模型的提示词中的 token。子类型包括:缓存读取、文本 token、图像 token 等。
- Output:模型响应中生成的 token。子类型包括:推理 token、文本 token、图像 token 等。
- Other:来自工具调用、检索步骤或任何自定义运行的成本。
在界面中将鼠标悬停在成本区块上即可查看详细明细。在可用情况下,每个区块还会按子类型进一步分类。


你可以在 LangSmith 界面的各处查看这些明细:
在追踪树中
追踪树展示了 token 用量和成本最详细的视图(针对单条追踪)。它显示整条追踪的总用量、每个父运行的聚合值,以及每个子运行的 token 和成本明细。
在追踪项目中打开任意运行即可查看其追踪树。
NOTE
跨线程追踪成本时,请确保所有子运行都包含线程元数据(session_id 或 thread_id)。如果子运行缺少线程元数据,这些运行的 token 计数和成本将不会被计入线程级别的聚合。有关设置线程元数据的详细信息,请参阅配置线程。
在项目统计中
项目统计面板显示项目中所有追踪的 token 总用量和总成本。
在仪表盘中
仪表盘可帮助你探索成本和 token 用量随时间变化的趋势。追踪项目的预置仪表盘会显示总成本,以及按输入和输出 token 划分的成本明细。
你也可以在自定义仪表盘中配置自定义成本追踪图表。
成本追踪
你可以通过两种方式追踪成本:
- 自动:根据 LLM 调用的 token 计数和模型价格推导得出。
- 手动:直接在任意运行上指定,包括非 LLM 类型。
| 方式 | 运行类型:LLM | 运行类型:其他 |
|---|---|---|
| 自动 |
| 不适用。 |
| 手动 | 如果 LLM 调用成本是非线性的(例如遵循自定义成本函数) | 为任意运行类型发送成本,例如工具调用、检索步骤 |
LLM 调用:基于 token 计数自动追踪成本
要根据 token 用量自动计算成本,你需要提供 token 计数、模型与服务商以及模型价格。
NOTE
如果你使用 LangChain 调用 LLM、对 OpenAI 或 Anthropic(或 OpenAI 兼容模型)使用 @traceable,或者使用 LangSmith 提供的 OpenAI 或 Anthropic 封装,可跳过本节。
发送 token 计数。许多模型会在响应中返回 token 计数。你必须提取该信息,并通过以下任一方法将其包含在你的运行中:
- 在运行的元数据上设置
usage_metadata字段。这种方式的优点是无需更改被追踪函数的运行时输出:
- 在运行的元数据上设置
```python [Python]
from langsmith import traceable, get_current_run_tree
inputs = [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "I'd like to book a table for two."},
]
@traceable(
run_type="llm",
metadata={"ls_provider": "my_provider", "ls_model_name": "my_model"}
)
def chat_model(messages: list):
# Imagine this is the real model output format your application expects
assistant_message = {
"role": "assistant",
"content": "Sure, what time would you like to book the table for?"
}
# Token usage you compute or receive from the provider
token_usage = {
"input_tokens": 27,
"output_tokens": 13,
"total_tokens": 40,
"input_token_details": {"cache_read": 10}
}
# Attach token usage to the LangSmith run
run = get_current_run_tree()
run.set(usage_metadata=token_usage)
return assistant_message
chat_model(inputs)
```
```typescript [TypeScript]
import { traceable, getCurrentRunTree } from "langsmith/traceable";
const inputs = [
{ role: "system", content: "You are a helpful assistant." },
{ role: "user", content: "I'd like to book a table for two." },
];
const chatModel = traceable(
async ({ messages }) => {
// The output your application expects
const assistantMessage = {
role: "assistant",
content: "Sure, what time would you like to book the table for?",
};
// Token usage you compute or receive from the provider
const tokenUsage = {
input_tokens: 27,
output_tokens: 13,
total_tokens: 40,
input_token_details: { cache_read: 10 },
};
// Attach usage to the LangSmith run
const runTree = getCurrentRunTree();
runTree.metadata.usage_metadata = tokenUsage;
return assistantMessage;
},
{
run_type: "llm",
name: "chat_model",
metadata: {
ls_provider: "my_provider",
ls_model_name: "my_model",
},
}
);
await chatModel({ messages: inputs });
```
```java [Java]
import com.langchain.smith.client.LangsmithClient;
import com.langchain.smith.client.okhttp.LangsmithOkHttpClient;
import com.langchain.smith.tracing.RunTree;
import com.langchain.smith.tracing.RunType;
import com.langchain.smith.tracing.TraceConfig;
import com.langchain.smith.tracing.Tracing;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
class CostTrackingUsageMetadataRun {
public static void main(String[] args) throws InterruptedException {
if (System.getenv("LANGSMITH_API_KEY") == null
|| System.getenv("LANGSMITH_API_KEY").isBlank()) {
System.out.println(
"[cost-tracking-usage-metadata-run] Skipping (LANGSMITH_API_KEY is not set).");
return;
}
LangsmithClient langsmith = LangsmithOkHttpClient.fromEnv();
ExecutorService executor = Executors.newSingleThreadExecutor();
try {
List<Map<String, String>> inputs =
Arrays.asList(
message("system", "You are a helpful assistant."),
message("user", "I'd like to book a table for two."));
Map<String, Object> metadata = new HashMap<>();
metadata.put("ls_provider", "my_provider");
metadata.put("ls_model_name", "my_model");
Function<List<Map<String, String>>, Map<String, String>> chatModel =
Tracing.traceFunction(
messages -> {
Map<String, String> assistantMessage =
message(
"assistant",
"Sure, what time would you like to book the table for?");
Map<String, Object> inputTokenDetails = new HashMap<>();
inputTokenDetails.put("cache_read", 10);
Map<String, Object> tokenUsage = new HashMap<>();
tokenUsage.put("input_tokens", 27);
tokenUsage.put("output_tokens", 13);
tokenUsage.put("total_tokens", 40);
tokenUsage.put("input_token_details", inputTokenDetails);
RunTree run = Tracing.getCurrentRunTree();
if (run != null) {
run.getMetadata().put("usage_metadata", tokenUsage);
}
return assistantMessage;
},
TraceConfig.builder()
.name("chat_model")
.runType(RunType.LLM)
.client(langsmith)
.executor(executor)
.metadata(metadata)
.build());
chatModel.apply(inputs);
} finally {
executor.shutdown();
if (!executor.awaitTermination(10, TimeUnit.SECONDS)) {
throw new IllegalStateException("Timed out waiting for LangSmith traces to submit");
}
}
}
private static Map<String, String> message(String role, String content) {
Map<String, String> message = new HashMap<>();
message.put("role", role);
message.put("content", content);
return message;
}
}
```
```kotlin [Kotlin]
import com.langchain.smith.client.okhttp.LangsmithOkHttpClient
import com.langchain.smith.tracing.RunType
import com.langchain.smith.tracing.TraceConfig
import com.langchain.smith.tracing.getCurrentRunTree
import com.langchain.smith.tracing.traceable
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
val langsmith = LangsmithOkHttpClient.fromEnv()
val executor = Executors.newSingleThreadExecutor()
fun message(role: String, content: String) = mapOf("role" to role, "content" to content)
try {
val inputs =
listOf(
message("system", "You are a helpful assistant."),
message("user", "I'd like to book a table for two."),
)
val chatModel =
traceable(
{ _: List<Map<String, String>> ->
val assistantMessage =
message(
"assistant",
"Sure, what time would you like to book the table for?",
)
val tokenUsage =
mapOf(
"input_tokens" to 27,
"output_tokens" to 13,
"total_tokens" to 40,
"input_token_details" to mapOf("cache_read" to 10),
)
getCurrentRunTree()?.metadata?.put("usage_metadata", tokenUsage)
assistantMessage
},
TraceConfig.builder()
.name("chat_model")
.runType(RunType.LLM)
.client(langsmith)
.executor(executor)
.metadata(
mapOf(
"ls_provider" to "my_provider",
"ls_model_name" to "my_model",
),
)
.build(),
)
chatModel(inputs)
} finally {
executor.shutdown()
check(executor.awaitTermination(10, TimeUnit.SECONDS)) {
"Timed out waiting for LangSmith traces to submit"
}
}
```
Java 和 Kotlin 示例使用了专用的 executor。关闭该 executor 并等待其终止,可确保后台追踪提交在进程退出之前完成。
- 在被追踪函数的输出中返回
usage_metadata字段。直接将usage_metadata键包含在被追踪函数返回的对象中。LangSmith 会从输出中提取它:
```python [Python]
from langsmith import traceable
inputs = [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "I'd like to book a table for two."},
]
output = {
"choices": [
{
"message": {
"role": "assistant",
"content": "Sure, what time would you like to book the table for?"
}
}
],
"usage_metadata": {
"input_tokens": 27,
"output_tokens": 13,
"total_tokens": 40,
"input_token_details": {"cache_read": 10}
},
}
@traceable(
run_type="llm",
metadata={"ls_provider": "my_provider", "ls_model_name": "my_model"}
)
def chat_model(messages: list):
return output
chat_model(inputs)
```
```typescript [TypeScript]
import { traceable } from "langsmith/traceable";
const messages = [
{ role: "system", content: "You are a helpful assistant." },
{ role: "user", content: "I'd like to book a table for two." }
];
const output = {
choices: [
{
message: {
role: "assistant",
content: "Sure, what time would you like to book the table for?",
},
},
],
usage_metadata: {
input_tokens: 27,
output_tokens: 13,
total_tokens: 40,
},
};
const chatModel = traceable(
async ({
messages,
}: {
messages: { role: string; content: string }[];
model: string;
}) => {
return output;
},
{
run_type: "llm",
name: "chat_model",
metadata: {
ls_provider: "my_provider",
ls_model_name: "my_model"
}
}
);
await chatModel({ messages });
```
```java [Java]
import com.langchain.smith.client.LangsmithClient;
import com.langchain.smith.client.okhttp.LangsmithOkHttpClient;
import com.langchain.smith.tracing.RunType;
import com.langchain.smith.tracing.TraceConfig;
import com.langchain.smith.tracing.Tracing;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
class CostTrackingUsageMetadataOutput {
public static void main(String[] args) throws InterruptedException {
if (System.getenv("LANGSMITH_API_KEY") == null
|| System.getenv("LANGSMITH_API_KEY").isBlank()) {
System.out.println(
"[cost-tracking-usage-metadata-output] Skipping (LANGSMITH_API_KEY is not set).");
return;
}
LangsmithClient langsmith = LangsmithOkHttpClient.fromEnv();
ExecutorService executor = Executors.newSingleThreadExecutor();
try {
List<Map<String, String>> messages =
Arrays.asList(
message("system", "You are a helpful assistant."),
message("user", "I'd like to book a table for two."));
Map<String, Object> metadata = new HashMap<>();
metadata.put("ls_provider", "my_provider");
metadata.put("ls_model_name", "my_model");
Function<List<Map<String, String>>, Map<String, Object>> chatModel =
Tracing.traceFunction(
inputMessages -> output(),
TraceConfig.builder()
.name("chat_model")
.runType(RunType.LLM)
.client(langsmith)
.executor(executor)
.metadata(metadata)
.build());
chatModel.apply(messages);
} finally {
executor.shutdown();
if (!executor.awaitTermination(10, TimeUnit.SECONDS)) {
throw new IllegalStateException("Timed out waiting for LangSmith traces to submit");
}
}
}
private static Map<String, Object> output() {
Map<String, Object> output = new HashMap<>();
Map<String, Object> choice = new HashMap<>();
choice.put(
"message",
message("assistant", "Sure, what time would you like to book the table for?"));
output.put("choices", Arrays.asList(choice));
Map<String, Object> inputTokenDetails = new HashMap<>();
inputTokenDetails.put("cache_read", 10);
Map<String, Object> usageMetadata = new HashMap<>();
usageMetadata.put("input_tokens", 27);
usageMetadata.put("output_tokens", 13);
usageMetadata.put("total_tokens", 40);
usageMetadata.put("input_token_details", inputTokenDetails);
output.put("usage_metadata", usageMetadata);
return output;
}
private static Map<String, String> message(String role, String content) {
Map<String, String> message = new HashMap<>();
message.put("role", role);
message.put("content", content);
return message;
}
}
```
```kotlin [Kotlin]
import com.langchain.smith.client.okhttp.LangsmithOkHttpClient
import com.langchain.smith.tracing.RunType
import com.langchain.smith.tracing.TraceConfig
import com.langchain.smith.tracing.traceable
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
val langsmith = LangsmithOkHttpClient.fromEnv()
val executor = Executors.newSingleThreadExecutor()
fun message(role: String, content: String) = mapOf("role" to role, "content" to content)
val output =
mapOf(
"choices" to
listOf(
mapOf(
"message" to
message(
"assistant",
"Sure, what time would you like to book the table for?",
),
),
),
"usage_metadata" to
mapOf(
"input_tokens" to 27,
"output_tokens" to 13,
"total_tokens" to 40,
"input_token_details" to mapOf("cache_read" to 10),
),
)
try {
val messages =
listOf(
message("system", "You are a helpful assistant."),
message("user", "I'd like to book a table for two."),
)
val chatModel =
traceable(
{ _: List<Map<String, String>> -> output },
TraceConfig.builder()
.name("chat_model")
.runType(RunType.LLM)
.client(langsmith)
.executor(executor)
.metadata(
mapOf(
"ls_provider" to "my_provider",
"ls_model_name" to "my_model",
),
)
.build(),
)
chatModel(messages)
} finally {
executor.shutdown()
check(executor.awaitTermination(10, TimeUnit.SECONDS)) {
"Timed out waiting for LangSmith traces to submit"
}
}
```
无论采用哪种方式,用量元数据都应包含以下 LangSmith 可识别字段的子集:
用量元数据 schema 与成本计算
以下 usage_metadata 字典中的字段会被 LangSmith 识别。你可以直接查看完整的 Python 类型 或 TypeScript 接口。
input_tokensnumber
模型输入中使用的 token 数。所有输入 token 类型之和。
output_tokensnumber
模型响应中使用的 token 数。所有输出 token 类型之和。
total_tokensnumber
输入和输出中使用的 token 数。可选,可以推断。input_tokens + output_tokens 之和。
input_token_detailsobject
输入 token 类型的明细。键为 token 类型字符串,值为计数。示例 {"cache_read": 5}。
已知字段包括:audio、text、image、cache_read、cache_creation、cache_read_over_200k(Gemini)、ephemeral_5m_input_tokens、ephemeral_1h_input_tokens(Anthropic 临时缓存层级)。根据模型或提供商的不同,还可能有其他字段。
output_token_detailsobject
输出 token 类型的明细。键为 token 类型字符串,值为计数。示例 {"reasoning": 5}。
已知字段包括:audio、text、image、reasoning。根据模型或提供商的不同,还可能有其他字段。
input_costnumber
输入 token 的成本。
output_costnumber
输出 token 的成本。
total_costnumber
token 成本。可选,可以推断。input_cost + output_cost 之和。
input_cost_detailsobject
输入成本的明细。键为 token 类型字符串,值为成本金额。
output_cost_detailsobject
输出成本的明细。键为 token 类型字符串,值为成本金额。
成本计算
run 的成本按 token 类型从最具体到最粗略贪心计算。假设你将每 1M 输入 token 的价格设为 $2,其中 cache_read 输入 token 的明细价格为每 1M $1,输出 token 为每 1M $3。如果你上传了以下用量元数据:
python
{
"input_tokens": 20,
"input_token_details": {"cache_read": 5},
"output_tokens": 10,
"total_tokens": 30,
}那么,token 成本将按如下方式计算:
python
# Notice that LangSmith computes the cache_read cost and then for any
# remaining input_tokens, the default input price is applied.
input_cost = 5 * 1e-6 + (20 - 5) * 2e-6 # 3.5e-5
output_cost = 10 * 3e-6 # 3e-5
total_cost = input_cost + output_cost # 6.5e-5指定模型名称。使用自定义模型时,需要在 run 的元数据 中指定以下字段,以便将 token 计数与成本关联起来。在查看追踪和过滤时,提供这些元数据字段也有助于识别模型。
ls_provider:模型提供商,例如 “openai”、“anthropic”ls_model_name:模型名称,例如 “gpt-5.4-mini”、“claude-opus-4-8”
设置模型价格。LangSmith 使用其模型价格表将模型名称映射为每 token 价格,以根据 token 计数计算成本。
NOTE
该表包含大多数 OpenAI、Anthropic 和 Gemini 模型的价格信息。如果你有自定义价格,可以为默认模型新建价格条目或覆盖其价格。
对于不同 token 类型有不同价格的模型(例如多模态或缓存 token),你可以按 token 类型分别指定价格明细。将鼠标悬停在 Input price 和 Output price 条目旁的 ... 上,即可查看按 token 类型划分的价格明细。
NOTE
LangSmith 不会把模型价格表的更新反映到已经记录的追踪成本中。不支持回溯补算模型价格变更。
新建或修改现有模型价格条目
要修改默认模型价格,请创建一个与默认条目具有相同 model、provider 和 match pattern 的新条目。
要在模型价格表中新建条目,请点击右上角的 + Model 按钮。
在这里,你可以指定以下字段:
- Model Name:模型的可读名称。
- Input Price:每 1M 输入 token 的成本。该数值乘以提示词中的 token 数来计算提示词成本。
- Input Price Breakdown(可选):每种不同输入 token 类型的价格明细,例如
cache_read、video、audio。 - Output Price:每 1M 输出 token 的成本。该数值乘以补全中的 token 数来计算补全成本。
- Output Price Breakdown(可选):每种不同输出 token 类型的价格明细,例如
reasoning、image等。 - Model Activation Date(可选):价格生效的日期。只有此日期之后的 run 才会应用该模型价格。
- Match Pattern:用于匹配模型名称的正则表达式。它用于匹配 run 元数据中
ls_model_name的值。 - Provider(可选):模型提供商。如果指定,将与 run 元数据中的
ls_provider进行匹配。
设置好模型价格表后,LangSmith 会根据 LLM 调用中提供的 token 计数,自动计算并汇总追踪中基于 token 的成本。
LLM 调用:直接发送成本
Gemini 2.5 Pro Preview 和 Gemini 2.5 Pro 使用阶梯式成本函数,LangSmith 默认支持。对于其他具有非线性定价的模型,请在客户端计算成本,并按下述代码将其作为 usage_metadata 发送:
python
from langsmith import traceable, get_current_run_tree
inputs = [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "I'd like to book a table for two."},
]
@traceable(
run_type="llm",
metadata={"ls_provider": "my_provider", "ls_model_name": "my_model"}
)
def chat_model(messages: list):
llm_output = {
"choices": [
{
"message": {
"role": "assistant",
"content": "Sure, what time would you like to book the table for?"
}
}
],
"usage_metadata": {
# Specify cost (in dollars) for the inputs and outputs
"input_cost": 1.1e-6,
"input_cost_details": {"cache_read": 2.3e-7},
"output_cost": 5.0e-6,
},
}
run = get_current_run_tree()
run.set(usage_metadata=llm_output["usage_metadata"])
return llm_output["choices"][0]["message"]
chat_model(inputs)typescript
import { traceable, getCurrentRunTree } from "langsmith/traceable";
const messages = [
{ role: "system", content: "You are a helpful assistant." },
{ role: "user", content: "I'd like to book a table for two." }
];
const chatModel = traceable(
async (messages: { role: string; content: string }[]) => {
const llmOutput = {
choices: [
{
message: {
role: "assistant",
content: "Sure, what time would you like to book the table for?",
},
},
],
// Specify cost (in dollars) for the inputs and outputs
usage_metadata: {
input_cost: 1.1e-6,
input_cost_details: { cache_read: 2.3e-7 },
output_cost: 5.0e-6,
},
};
// Attach usage metadata to the run
const runTree = getCurrentRunTree();
runTree.metadata.usage_metadata = llmOutput.usage_metadata;
// Return only the assistant message
return llmOutput.choices[0].message;
},
{
run_type: "llm",
name: "chat_model",
metadata: {
ls_provider: "my_provider",
ls_model_name: "my_model",
},
}
);
await chatModel(messages);java
import com.langchain.smith.client.LangsmithClient;
import com.langchain.smith.client.okhttp.LangsmithOkHttpClient;
import com.langchain.smith.tracing.RunTree;
import com.langchain.smith.tracing.RunType;
import com.langchain.smith.tracing.TraceConfig;
import com.langchain.smith.tracing.Tracing;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
class CostTrackingLlmCostDirect {
public static void main(String[] args) throws InterruptedException {
LangsmithClient langsmith = LangsmithOkHttpClient.fromEnv();
ExecutorService executor = Executors.newSingleThreadExecutor();
try {
List<Map<String, String>> messages =
Arrays.asList(
message("system", "You are a helpful assistant."),
message("user", "I'd like to book a table for two."));
Map<String, Object> metadata = new HashMap<>();
metadata.put("ls_provider", "my_provider");
metadata.put("ls_model_name", "my_model");
Function<List<Map<String, String>>, Map<String, String>> chatModel =
Tracing.traceFunction(
inputMessages -> {
Map<String, Object> inputCostDetails = new HashMap<>();
inputCostDetails.put("cache_read", 2.3e-7);
Map<String, Object> usageMetadata = new HashMap<>();
usageMetadata.put("input_cost", 1.1e-6);
usageMetadata.put("input_cost_details", inputCostDetails);
usageMetadata.put("output_cost", 5.0e-6);
RunTree run = Tracing.getCurrentRunTree();
if (run != null) {
run.getMetadata().put("usage_metadata", usageMetadata);
}
return message(
"assistant", "Sure, what time would you like to book the table for?");
},
TraceConfig.builder()
.name("chat_model")
.runType(RunType.LLM)
.client(langsmith)
.executor(executor)
.metadata(metadata)
.build());
chatModel.apply(messages);
} finally {
executor.shutdown();
if (!executor.awaitTermination(10, TimeUnit.SECONDS)) {
throw new IllegalStateException("Timed out waiting for LangSmith traces to submit");
}
}
}
private static Map<String, String> message(String role, String content) {
Map<String, String> message = new HashMap<>();
message.put("role", role);
message.put("content", content);
return message;
}
}kotlin
import com.langchain.smith.client.okhttp.LangsmithOkHttpClient
import com.langchain.smith.tracing.RunType
import com.langchain.smith.tracing.TraceConfig
import com.langchain.smith.tracing.getCurrentRunTree
import com.langchain.smith.tracing.traceable
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
val langsmith = LangsmithOkHttpClient.fromEnv()
val executor = Executors.newSingleThreadExecutor()
fun message(role: String, content: String) = mapOf("role" to role, "content" to content)
try {
val messages =
listOf(
message("system", "You are a helpful assistant."),
message("user", "I'd like to book a table for two."),
)
val chatModel =
traceable(
{ _: List<Map<String, String>> ->
val usageMetadata =
mapOf(
"input_cost" to 1.1e-6,
"input_cost_details" to mapOf("cache_read" to 2.3e-7),
"output_cost" to 5.0e-6,
)
getCurrentRunTree()?.metadata?.put("usage_metadata", usageMetadata)
message(
"assistant",
"Sure, what time would you like to book the table for?",
)
},
TraceConfig.builder()
.name("chat_model")
.runType(RunType.LLM)
.client(langsmith)
.executor(executor)
.metadata(
mapOf(
"ls_provider" to "my_provider",
"ls_model_name" to "my_model",
),
)
.build(),
)
chatModel(messages)
} finally {
executor.shutdown()
check(executor.awaitTermination(10, TimeUnit.SECONDS)) {
"Timed out waiting for LangSmith traces to submit"
}
}View example trace
打开本示例的一个公开 LangSmith 运行记录。
其他 run:发送成本
你也可以为任何非 LLM 的 run(例如工具调用)发送成本信息。在 run 的 usage_metadata 中以 total_cost 字段指定成本:
python
from langsmith import traceable, get_current_run_tree
# Example tool: get_weather
@traceable(run_type="tool", name="get_weather")
def get_weather(city: str):
# Your tool logic goes here
result = {
"temperature_f": 68,
"condition": "sunny",
"city": city,
}
# Cost for this tool call (computed however you like)
tool_cost = 0.0015
# Attach usage metadata to the LangSmith run
run = get_current_run_tree()
run.set(usage_metadata={"total_cost": tool_cost})
# Return only the actual tool result (no usage info)
return result
tool_response = get_weather("San Francisco")typescript
import { traceable, getCurrentRunTree } from "langsmith/traceable";
// Example tool: get_weather
const getWeather = traceable(
async ({ city }) => {
// Your tool logic goes here
const result = {
temperature_f: 68,
condition: "sunny",
city,
};
// Cost for this tool call (computed however you like)
const toolCost = 0.0015;
// Attach usage metadata to the LangSmith run
const runTree = getCurrentRunTree();
runTree.metadata.usage_metadata = {
total_cost: toolCost,
};
// Return only the actual tool result (no usage info)
return result;
},
{
run_type: "tool",
name: "get_weather",
}
);
const toolResponse = await getWeather({ city: "San Francisco" });java
import com.langchain.smith.client.LangsmithClient;
import com.langchain.smith.client.okhttp.LangsmithOkHttpClient;
import com.langchain.smith.tracing.RunTree;
import com.langchain.smith.tracing.RunType;
import com.langchain.smith.tracing.TraceConfig;
import com.langchain.smith.tracing.Tracing;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
class CostTrackingToolCostRun {
public static void main(String[] args) throws InterruptedException {
LangsmithClient langsmith = LangsmithOkHttpClient.fromEnv();
ExecutorService executor = Executors.newSingleThreadExecutor();
try {
Function<String, Map<String, Object>> getWeather =
Tracing.traceFunction(
city -> {
Map<String, Object> result = new HashMap<>();
result.put("temperature_f", 68);
result.put("condition", "sunny");
result.put("city", city);
RunTree run = Tracing.getCurrentRunTree();
if (run != null) {
Map<String, Object> usageMetadata = new HashMap<>();
usageMetadata.put("total_cost", 0.0015);
run.getMetadata().put("usage_metadata", usageMetadata);
}
return result;
},
TraceConfig.builder()
.name("get_weather")
.runType(RunType.TOOL)
.client(langsmith)
.executor(executor)
.build());
Map<String, Object> toolResponse = getWeather.apply("San Francisco");
} finally {
executor.shutdown();
if (!executor.awaitTermination(10, TimeUnit.SECONDS)) {
throw new IllegalStateException("Timed out waiting for LangSmith traces to submit");
}
}
}
}kotlin
import com.langchain.smith.client.okhttp.LangsmithOkHttpClient
import com.langchain.smith.tracing.RunType
import com.langchain.smith.tracing.TraceConfig
import com.langchain.smith.tracing.getCurrentRunTree
import com.langchain.smith.tracing.traceable
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
val langsmith = LangsmithOkHttpClient.fromEnv()
val executor = Executors.newSingleThreadExecutor()
try {
val getWeather =
traceable(
{ city: String ->
val result =
mapOf(
"temperature_f" to 68,
"condition" to "sunny",
"city" to city,
)
getCurrentRunTree()
?.metadata
?.put("usage_metadata", mapOf("total_cost" to 0.0015))
result
},
TraceConfig.builder()
.name("get_weather")
.runType(RunType.TOOL)
.client(langsmith)
.executor(executor)
.build(),
)
val toolResponse = getWeather("San Francisco")
} finally {
executor.shutdown()
check(executor.awaitTermination(10, TimeUnit.SECONDS)) {
"Timed out waiting for LangSmith traces to submit"
}
}或者,在追踪函数的返回值中直接包含 usage_metadata:
python
from langsmith import traceable
# Example tool: get_weather
@traceable(run_type="tool", name="get_weather")
def get_weather(city: str):
# Your tool logic goes here
result = {
"temperature_f": 68,
"condition": "sunny",
"city": city,
}
# Attach tool call costs here
return {
**result,
"usage_metadata": {
"total_cost": 0.0015, # <-- cost for this tool call
},
}
tool_response = get_weather("San Francisco")typescript
import { traceable } from "langsmith/traceable";
// Example tool: get_weather
const getWeather = traceable(
async ({ city }) => {
// Your tool logic goes here
const result = {
temperature_f: 68,
condition: "sunny",
city,
};
// Attach tool call costs here
return {
...result,
usage_metadata: {
total_cost: 0.0015, // <-- cost for this tool call
},
};
},
{
run_type: "tool",
name: "get_weather",
}
);
const toolResponse = await getWeather({ city: "San Francisco" });java
import com.langchain.smith.client.LangsmithClient;
import com.langchain.smith.client.okhttp.LangsmithOkHttpClient;
import com.langchain.smith.tracing.RunType;
import com.langchain.smith.tracing.TraceConfig;
import com.langchain.smith.tracing.Tracing;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
class CostTrackingToolCostOutput {
public static void main(String[] args) throws InterruptedException {
if (System.getenv("LANGSMITH_API_KEY") == null
|| System.getenv("LANGSMITH_API_KEY").isBlank()) {
System.out.println(
"[cost-tracking-tool-cost-output] Skipping (LANGSMITH_API_KEY is not set).");
return;
}
LangsmithClient langsmith = LangsmithOkHttpClient.fromEnv();
ExecutorService executor = Executors.newSingleThreadExecutor();
try {
Function<String, Map<String, Object>> getWeather =
Tracing.traceFunction(
city -> {
Map<String, Object> result = new HashMap<>();
result.put("temperature_f", 68);
result.put("condition", "sunny");
result.put("city", city);
Map<String, Object> usageMetadata = new HashMap<>();
usageMetadata.put("total_cost", 0.0015);
result.put("usage_metadata", usageMetadata);
return result;
},
TraceConfig.builder()
.name("get_weather")
.runType(RunType.TOOL)
.client(langsmith)
.executor(executor)
.build());
Map<String, Object> toolResponse = getWeather.apply("San Francisco");
} finally {
executor.shutdown();
if (!executor.awaitTermination(10, TimeUnit.SECONDS)) {
throw new IllegalStateException("Timed out waiting for LangSmith traces to submit");
}
}
}
}kotlin
import com.langchain.smith.client.okhttp.LangsmithOkHttpClient
import com.langchain.smith.tracing.RunType
import com.langchain.smith.tracing.TraceConfig
import com.langchain.smith.tracing.traceable
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
val langsmith = LangsmithOkHttpClient.fromEnv()
val executor = Executors.newSingleThreadExecutor()
try {
val getWeather =
traceable(
{ city: String ->
mapOf(
"temperature_f" to 68,
"condition" to "sunny",
"city" to city,
"usage_metadata" to mapOf("total_cost" to 0.0015),
)
},
TraceConfig.builder()
.name("get_weather")
.runType(RunType.TOOL)
.client(langsmith)
.executor(executor)
.build(),
)
val toolResponse = getWeather("San Francisco")
} finally {
executor.shutdown()
check(executor.awaitTermination(10, TimeUnit.SECONDS)) {
"Timed out waiting for LangSmith traces to submit"
}
}