비용 추적
비용 추적
규모에 맞춰 에이전트를 구축하면 추적하기 어려운 중대한 사용량 기반 비용이 발생해요. LangSmith는 주요 프로바이더에 대해 LLM 토큰 사용량과 비용을 자동으로 기록하고, 추가 구성 요소에 대한 커스텀 비용 데이터를 제출할 수도 있게 해줘요.
이를 통해 전체 애플리케이션에 걸친 비용을 단일하고 통합된 관점으로 볼 수 있어서, 지출을 모니터링하고 이해하며 디버깅하기 쉬워져요.
평가자 실행의 LLM 비용을 상한으로 제한하려면 평가자 지출 추적 및 제한을 참고하세요. 평가자 지출 추적 및 제한은 모델 가격 아래에 구성된 모델별 가격을 사용해요.
출처: 문서
본문
LangSmith UI에서 비용 보기
LangSmith UI에서는 세 가지 방식으로 사용량과 지출을 탐색할 수 있어요: 개별 트레이스 내의 세부 분석, 프로젝트 통계의 집계 지표, 대시보드로요.
토큰 및 비용 세부 분석
UI는 토큰 사용량과 비용을 세 가지 범주로 나눠요:
- Input(입력): 모델로 보내진 프롬프트의 토큰. 하위 유형에는 캐시 읽기, 텍스트 토큰, 이미지 토큰 등이 포함돼요.
- Output(출력): 모델 응답에서 생성된 토큰. 하위 유형에는 추론 토큰, 텍스트 토큰, 이미지 토큰 등이 포함돼요.
- Other(기타): 도구 호출, 검색 단계 또는 임의의 커스텀 런에서 발생한 비용.
UI에서 비용 섹션 위에 마우스를 올리면 자세한 세부 분석을 볼 수 있어요. 가능하다면 각 섹션은 하위 유형별로 다시 분류돼요.


LangSmith UI 곳곳에서 이러한 세부 분석을 살펴볼 수 있어요:
트레이스 트리에서
트레이스 트리는 (단일 트레이스에 대한) 토큰 사용량과 비용의 가장 상세한 보기를 보여줘요. 전체 트레이스의 총 사용량, 각 상위 런의 집계 값, 각 하위 런의 토큰 및 비용 세부 분석을 표시해요.
추적 프로젝트 내에서 아무 런이나 열면 트레이스 트리를 볼 수 있어요.
스레드 간에 비용을 추적할 때는 모든 하위 런에 스레드 메타데이터(
session_id또는thread_id)가 포함되어 있는지 확인하세요. 하위 런에 스레드 메타데이터가 없으면 해당 런의 토큰 수와 비용이 스레드 수준 집계에 포함되지 않아요. 스레드 메타데이터 설정에 대한 자세한 내용은 스레드 구성을 참고하세요.
프로젝트 통계에서
프로젝트 통계 패널은 프로젝트의 모든 트레이스에 대한 총 토큰 사용량과 비용을 보여줘요.
대시보드에서
대시보드는 시간에 따른 비용 및 토큰 사용량 추세를 탐색하는 데 도움이 돼요. 추적 프로젝트의 미리 빌드된 대시보드는 총 비용과 입력 및 출력 토큰별 비용 세부 분석을 보여줘요.
커스텀 대시보드에서 커스텀 비용 추적 차트를 구성할 수도 있어요.
비용 추적
비용은 두 가지 방식으로 추적할 수 있어요:
- 자동: LLM 호출의 토큰 수와 모델 가격에서 파생.
- 수동: LLM이 아닌 유형을 포함해 모든 런에 직접 지정.
| 방법 | 런 유형: LLM | 런 유형: 기타 |
|---|---|---|
| 자동 |
|
해당 없음. |
| 수동 | LLM 호출 비용이 비선형인 경우 (예: 커스텀 비용 함수를 따르는 경우) | 도구 호출, 검색 단계 같은 모든 런 유형에 비용 전송 |
LLM 호출: 토큰 수 기반 비용 자동 추적
토큰 사용량에서 비용을 자동으로 계산하려면 토큰 수, 모델 및 프로바이더, 모델 가격을 제공해야 해요.
LangChain으로 LLM을 호출하거나, OpenAI 또는 Anthropic(또는 OpenAI 호환 모델)에
@traceable을 사용하거나, OpenAI 또는 Anthropic용 LangSmith 래퍼를 사용한다면 이 섹션을 건너뛰어도 돼요.
-
토큰 수를 보내세요. 많은 모델이 응답의 일부로 토큰 수를 포함해요. 이 정보를 추출해서 다음 방법 중 하나로 런에 포함해야 해요:
-
런의 메타데이터에
usage_metadata필드를 설정하세요. 이 접근 방식의 장점은 추적되는 함수의 런타임 출력을 변경할 필요가 없다는 것이에요: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)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 });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; } }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 예시는 전용 실행기를 사용해요. 실행기를 종료하고 종료를 기다리면 프로세스가 종료되기 전에 백그라운드 트레이스 제출이 완료돼요.
-
추적되는 함수의 출력에서
usage_metadata필드를 반환하세요. 추적되는 함수가 반환한 객체 안에usage_metadata키를 직접 포함하세요. LangSmith가 출력에서 이를 추출해요: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)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 });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; } }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가 인식하는 다음 필드 중 일부를 포함해야 해요:
사용량 메타데이터 스키마 및 비용 계산
usage_metadatadict에서 다음 필드는 LangSmith가 인식해요. 전체 Python 타입 또는 TypeScript 인터페이스를 직접 볼 수 있어요.-
input_tokensnumber: 모델 입력에 사용된 토큰 수. 모든 입력 토큰 유형의 합. -
output_tokensnumber: 모델 응답에 사용된 토큰 수. 모든 출력 토큰 유형의 합. -
total_tokensnumber: 입력과 출력에 사용된 토큰 수. 선택 사항이며 추론 가능. input_tokens + output_tokens의 합. -
input_token_detailsobject: 입력 토큰 유형의 세부 분석. 키는 토큰 유형 문자열, 값은 수. 예시{"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: 출력 토큰 유형의 세부 분석. 키는 토큰 유형 문자열, 값은 수. 예시{"reasoning": 5}.알려진 필드:
audio,text,image,reasoning. 모델 또는 프로바이더에 따라 추가 필드가 있을 수 있어요. -
input_costnumber: 입력 토큰의 비용. -
output_costnumber: 출력 토큰의 비용. -
total_costnumber: 토큰의 비용. 선택 사항이며 추론 가능. input_cost + output_cost의 합. -
input_cost_detailsobject: 입력 비용의 세부 사항. 키는 토큰 유형 문자열, 값은 비용 금액. -
output_cost_detailsobject: 출력 비용의 세부 사항. 키는 토큰 유형 문자열, 값은 비용 금액.
비용 계산
런의 비용은 가장 구체적인 토큰 유형부터 가장 일반적인 유형까지 탐욕적으로 계산돼요. 입력 토큰 1M당 \$2, 상세 가격으로
cache_read입력 토큰 1M당 \$1, 출력 토큰 1M당 \$3의 가격을 설정했다고 가정해요. 다음 사용량 메타데이터를 업로드했다면:{ "input_tokens": 20, "input_token_details": {"cache_read": 5}, "output_tokens": 10, "total_tokens": 30, }그러면 토큰 비용은 다음과 같이 계산돼요:
# 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 -
-
모델 이름을 지정하세요. 커스텀 모델을 사용할 때는 토큰 수를 비용과 연결하기 위해 런의 메타데이터에 다음 필드를 지정해야 해요. 트레이스를 볼 때와 필터링할 때 모델을 식별하려면 이러한 메타데이터 필드를 제공하는 것도 도움이 돼요.
ls_provider: 모델의 프로바이더 (예: "openai", "anthropic")ls_model_name: 모델의 이름 (예: "gpt-5.4-mini", "claude-opus-4-8")
-
모델 가격을 설정하세요. LangSmith는 모델 가격 테이블을 사용해 모델 이름을 토큰당 가격에 매핑하고 토큰 수에서 비용을 계산해요.
이 테이블에는 대부분의 OpenAI, Anthropic 및 Gemini 모델에 대한 가격 정보가 포함되어 있어요. 커스텀 가격이 있다면 새 모델 가격 항목을 만들거나 기본 모델의 가격을 덮어쓸 수 있어요.
토큰 유형마다 가격이 다른 모델(예: 멀티모달 또는 캐시된 토큰)의 경우 각 토큰 유형에 대한 가격 세부 분석을 지정할 수 있어요. Input price 및 Output price 항목 옆의 ... 위에 마우스를 올리면 토큰 유형별 가격 세부 분석이 보여요.
LangSmith는 이미 기록된 트레이스의 비용에는 모델 가격 맵의 업데이트를 반영하지 않아요. 모델 가격 변경의 백필(backfilling)은 지원되지 않아요.
모델 가격 항목 새로 만들기 또는 수정하기
기본 모델 가격을 수정하려면 기본 항목과 동일한 모델, 프로바이더 및 일치 패턴으로 새 항목을 만드세요.
모델 가격 맵에 새 항목을 만들려면 오른쪽 상단의 + Model 버튼을 클릭하세요.
여기에서 다음 필드를 지정할 수 있어요:
- 모델 이름 (Model Name): 사람이 읽을 수 있는 모델 이름.
- 입력 가격 (Input Price): 모델의 입력 토큰 1M당 비용. 이 숫자에 프롬프트의 토큰 수를 곱해 프롬프트 비용을 계산해요.
- 입력 가격 세부 분석 (Input Price Breakdown) (선택):
cache_read,video,audio같은 각기 다른 유형의 입력 토큰 가격 세부 분석. - 출력 가격 (Output Price): 모델의 출력 토큰 1M당 비용. 이 숫자에 완료(completion)의 토큰 수를 곱해 완료 비용을 계산해요.
- 출력 가격 세부 분석 (Output Price Breakdown) (선택):
reasoning,image같은 각기 다른 유형의 출력 토큰 가격 세부 분석. - 모델 활성화 날짜 (Model Activation Date) (선택): 가격이 적용되기 시작하는 날짜. 이 날짜 이후의 런만 이 모델 가격이 적용돼요.
- 일치 패턴 (Match Pattern): 모델 이름을 일치시키는 정규식 패턴. 런 메타데이터의
ls_model_name값을 일치시키는 데 사용돼요. - 프로바이더 (Provider) (선택): 모델의 프로바이더. 지정하면 런 메타데이터의
ls_provider와 대조돼요.
모델 가격 맵을 설정하면 LangSmith는 LLM 호출에서 제공된 토큰 수를 기반으로 트레이스의 토큰 기반 비용을 자동으로 계산하고 집계해요.
LLM 호출: 비용 직접 전송
Gemini 2.5 Pro Preview와 Gemini 2.5 Pro는 단계적 비용 함수를 사용하며, LangSmith가 기본적으로 이를 지원해요. 비선형 가격의 다른 모델은 아래 코드처럼 비용을 클라이언트 측에서 계산하고 usage_metadata로 보내세요:
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)
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);
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;
}
}
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"
}
}
예시 트레이스 보기
이 예시에 대한 공개 LangSmith 런을 열어보세요: https://smith.langchain.com/public/fcb46808-1b10-4847-a3c9-164c47413524/r
기타 런: 비용 전송
도구 호출 같은 LLM이 아닌 런에도 비용 정보를 보낼 수 있어요. 런의 usage_metadata의 total_cost 필드에 비용을 지정하세요:
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")
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" });
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");
}
}
}
}
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를 직접 포함시키세요:
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")
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" });
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");
}
}
}
}
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"
}
}