Last reviewed: 2026-08-12
Direct answer
A CometAPI Langfuse integration uses Langfuse’s wrapped OpenAI client around a CometAPI OpenAI-compatible Chat Completions call. Install the OpenAI and Langfuse Python packages, make the six required connection settings available to the process, construct the wrapped client with the CometAPI base URL, and call client.chat.completions.create. In a short-lived script, explicitly flush Langfuse before the process exits. Finally, inspect the remote trace rather than assuming that a successful model response proves telemetry arrived.
The provider-specific Langfuse guide documents this combination. It says the integration can capture request parameters, response content, token usage, and latency for a wrapped call. The broader Langfuse integration also records API errors.
Install both packages in the Python environment that runs the application:
python -m pip install openai langfuse
The example below checks whether each required setting is present, but never prints a setting’s value. It also treats the model call and trace export as separate outcomes. That distinction matters in command-line jobs and workers: a request can succeed while a queued observation is lost as the process exits.
Who this is for
This guide is for Python developers who already use, or plan to use, the OpenAI-style Chat Completions method with CometAPI and want request-level observability. It is especially relevant to command-line jobs, scheduled tasks, deployment smoke tests, and short-lived workers because those processes may terminate before a background telemetry queue empties.
It assumes Python 3.10 or newer, a current text-capable CometAPI model identifier, and access to a Langfuse project. It does not cover prompt evaluation, model benchmarking, or migration to another endpoint family. The goal is narrower: make one chat call, observe it, exercise a controlled error, and retain useful diagnostics without placing credentials, request bodies, completion text, or raw provider errors in application logs.
Key takeaways
- Import the wrapped
OpenAIclient fromlangfuse.openaibefore making the call you want to trace. - Provide
COMETAPI_KEY,COMETAPI_BASE_URL,COMETAPI_MODEL,LANGFUSE_PUBLIC_KEY,LANGFUSE_SECRET_KEY, andLANGFUSE_BASE_URLto the same runtime. Check presence only; never log their values. - Keep the Chat Completions method shape, but set the CometAPI base URL and a current CometAPI model identifier.
- Expect one trace for each wrapped OpenAI call by default. Add a stable operation name and low-risk metadata so the observation is searchable.
- Flush Langfuse explicitly at the end of a short-lived process. Long-running applications can use background batching and flush during orderly shutdown.
- Allowlist application log fields such as outcome, phase, operation, model identifier, duration, status code, exception class, response-presence flags, and flush outcome.
- Validate both a successful request and a controlled model-not-found path before depending on the instrumentation in production.
Sources checked
- The Langfuse CometAPI integration guide supplies the provider-specific import, client construction, Chat Completions example, trace fields, and short-lived-process troubleshooting.
- The CometAPI OpenAI-compatible quickstart confirms the CometAPI base URL, Chat Completions route, Python client pattern, response access path, and common authentication, model, and routing failures.
- The Langfuse OpenAI Python integration documentation documents automatic tracing, API-error capture, metadata, asynchronous and streaming support, background batching, and explicit flushing.
- The OpenAI Python library repository
confirms the underlying synchronous and asynchronous client interfaces and the supported
client.chat.completions.createmethod mirrored by the wrapper.
Together, these sources support the client and tracing contract used here. They do not prove that every CometAPI model accepts every optional OpenAI parameter. Keep the first request minimal and verify model-specific behavior separately.
Contract details to verify
Before running a traced request, verify these details:
- The client uses
chat.completions.create, matching the CometAPI OpenAI-compatible quickstart. COMETAPI_BASE_URLcontains the query-free base URL from the current CometAPI documentation. A missing override can send the client toward its default service instead of CometAPI.COMETAPI_MODELnames a text-capable model currently available through CometAPI.COMETAPI_KEYis available to the process, but its value is never written to source code or logs.LANGFUSE_PUBLIC_KEY,LANGFUSE_SECRET_KEY, andLANGFUSE_BASE_URLare available to that same process, container, or worker.- The Langfuse wrapper is imported before the model call. Using the ordinary client for the actual request bypasses this drop-in instrumentation.
- The process remains alive long enough to flush queued observations.
Use this minimal script as a happy-path probe and as the basis for the error-path check. It emits only structured, allowlisted diagnostics. It evaluates the completion internally but does not print completion text. It also catches call and flush exceptions, records only their class and numeric status when available, and returns a nonzero exit code without producing an uncaught exception traceback.
import json
import os
import sys
import time
from langfuse import get_client
from langfuse.openai import OpenAI
def emit(**fields):
print(json.dumps(fields, sort_keys=True))
def run_probe():
required_names = (
'COMETAPI_KEY',
'COMETAPI_BASE_URL',
'COMETAPI_MODEL',
'LANGFUSE_PUBLIC_KEY',
'LANGFUSE_SECRET_KEY',
'LANGFUSE_BASE_URL',
)
missing_names = sorted(
name for name in required_names if not os.environ.get(name)
)
emit(
event='configuration_check',
outcome='error' if missing_names else 'ok',
required_field_count=len(required_names),
required_fields_present=not missing_names,
missing_fields=missing_names,
)
if missing_names:
return 2
started = time.monotonic()
langfuse = None
phase = 'initialize_clients'
exit_code = 0
model_id = os.environ['COMETAPI_MODEL']
try:
langfuse = get_client()
client = OpenAI(
api_key=os.environ['COMETAPI_KEY'],
base_url=os.environ['COMETAPI_BASE_URL'],
)
phase = 'chat_call'
completion = client.chat.completions.create(
model=model_id,
messages=[
{
'role': 'user',
'content': 'Reply with exactly: trace check complete',
}
],
name='cometapi-chat-smoke-test',
metadata={
'environment': 'staging',
'workflow': 'chat-observability-check',
},
)
content = completion.choices[0].message.content or ''
response_matches_expected = content.strip() == 'trace check complete'
if not response_matches_expected:
exit_code = 4
emit(
event='cometapi_chat_call',
outcome='ok' if response_matches_expected else 'unexpected_response',
phase=phase,
operation='chat.completions.create',
model_id=model_id,
duration_ms=round((time.monotonic() - started) * 1000),
response_present=bool(content),
response_matches_expected=response_matches_expected,
usage_present=completion.usage is not None,
)
except Exception as exc:
exit_code = 1
emit(
event='cometapi_trace_probe',
outcome='error',
phase=phase,
operation='chat.completions.create',
model_id=model_id,
duration_ms=round((time.monotonic() - started) * 1000),
http_status=getattr(exc, 'status_code', None),
exception_type=type(exc).__name__,
)
finally:
if langfuse is not None:
flush_started = time.monotonic()
try:
langfuse.flush()
except Exception as exc:
emit(
event='langfuse_flush',
outcome='error',
trace_flush_attempted=True,
duration_ms=round(
(time.monotonic() - flush_started) * 1000
),
exception_type=type(exc).__name__,
)
if exit_code == 0:
exit_code = 3
else:
emit(
event='langfuse_flush',
outcome='ok',
trace_flush_attempted=True,
duration_ms=round(
(time.monotonic() - flush_started) * 1000
),
)
return exit_code
sys.exit(run_probe())
The configuration event names missing variables without displaying values. The request event records whether content exists and whether it matches the fixed expectation, not the content itself. The error event omits the exception message because a provider error body may include request details. The process returns code 1 for a caught setup or request failure, 2 for missing configuration, 3 for a flush failure after an otherwise successful call, and 4 for an unexpected response.
Langfuse is intended to capture prompts and completions in the trace. Use a harmless probe prompt, restrict access to the observability project, and decide how production trace content should be handled before sending real user input.
Run the operator workflow in this order:
- For preflight, run the script and inspect only the
configuration_checkevent. Requirerequired_fields_present=true. If it is false, supply the listed variable names through the deployment’s normal configuration system; do not dump the environment. - For the happy path, use a current text-capable model and the documented CometAPI base URL. Require exit code
0,outcome=okforcometapi_chat_call,response_matches_expected=true, andoutcome=okforlangfuse_flush. - Open Langfuse and find
cometapi-chat-smoke-test. Verify the selected model, request parameters, response, usage data, and latency. A local flush event confirms only that the method returned without a caught exception; it is not a substitute for checking the remote trace. - For the error path, use a deliberately nonexistent model identifier in a non-production environment. Require a nonzero exit code and a sanitized error event containing
outcome=error,phase=chat_call, the exception class, and a status code when the SDK exposes one. Confirm that Langfuse records the API error. - Restore the valid model identifier and repeat the happy path. This final pass prevents a deliberately broken setting from moving into a deployment.
If routing remains uncertain, use the client base URL verification guide before debugging Langfuse.
Failure modes
The model answers, but no trace appears. In a short-lived process, the likely lifecycle issue is an unflushed telemetry queue. Other documented causes include incorrect Langfuse connection settings or instrumentation that starts after the application call. Keep the explicit flush() and confirm all three named Langfuse variables are available to the runtime. Langfuse debug mode can provide more detail, but enable it only in an isolated diagnostic run and review its output under the same controls as trace data.
The request fails during authentication. The CometAPI quickstart identifies an HTTP 401 response as a sign that the CometAPI credential is absent or unavailable to the runtime. Check the presence-only configuration event and the deployment’s secret mounting. Do not log values or repeatedly retry until configuration is corrected.
The model is not found. The configured identifier may be misspelled, stale, or incompatible with the chat route. Select a current text-capable CometAPI model and rerun the minimal request before restoring optional parameters.
The client calls the wrong service. The ordinary OpenAI client has its own default destination. If the CometAPI base URL override is absent or attached to a different client instance, the traced code may not reach CometAPI. Inspect client construction and keep one explicitly configured wrapped client for the probe.
Application logs expose too much. Printing the completion, full exception, request headers, prompt, or environment defeats the allowlist. The example catches errors and exits with integers, so no raw exception value or traceback is intentionally emitted. Keep the trace as a separate, access-controlled data store because Langfuse captures prompt and completion content by design.
A flush error is mistaken for request failure. Model delivery and telemetry delivery are independent. The example emits separate events and uses a distinct exit code when the model call succeeds but flushing fails. This makes an observability regression visible without mislabeling the provider call.
Streamed usage handling fails on the final event. Langfuse documents that streamed token usage requires usage to be requested in stream options. The final usage chunk can have an empty choices list, so streaming code must test that list before indexing it. The synchronous probe avoids this extra branch; add streaming only after the basic trace works.
Unrelated observations appear. Langfuse uses OpenTelemetry, and other instrumented libraries can emit spans. Filter unwanted observations before increasing traffic so the trace view remains useful and ingestion reflects the intended calls.
FAQ
Does the wrapper change the Chat Completions response shape?
The provider-specific guide uses the normal completion.choices[0].message.content access path. The wrapper adds tracing around the supported OpenAI client call; the application still consumes the familiar completion object.
Why does the example not print the model response?
The probe is designed for environments where stdout and stderr are collected as application logs. It compares the response internally and logs only response_present and response_matches_expected. The completion remains available in the Langfuse trace, subject to that project’s access controls.
Why does the example not rethrow exceptions?
An uncaught exception normally writes its value and traceback to stderr. Provider exception text can contain a raw response body. The probe instead records the phase, exception class, optional numeric status, and a nonzero exit code, preserving operational signals without intentionally emitting the exception value.
Must a web server flush after every request?
No. Langfuse documents background queuing and batching for long-running applications. Flush on orderly shutdown and in short-lived commands, workers, tests, or jobs that can terminate before the queue exports. Per-request flushing can add unnecessary work to a continuously running service.
Can this pattern use an asynchronous client?
Yes. Langfuse documents wrapped asynchronous clients, and the OpenAI Python library provides a corresponding async interface. First validate the synchronous probe, then switch to the async wrapper while keeping the same routing, metadata, error logging, and shutdown checks.
Can I use streaming?
Yes, with a supported SDK and model. Enable streaming deliberately, request streamed usage when needed, and handle a final chunk with no choices. Do not assume every model supports every optional parameter merely because the client accepts it.
Why keep application logs if Langfuse records the call?
They answer different questions. The application log establishes whether the process had its required settings, attempted the call, matched the expected response, and attempted a flush. The Langfuse trace provides instrumented request, response, usage, latency, and error context. Bounded operational fields complement the trace without duplicating full content.
Should I intentionally break a credential to test errors?
No. Use a nonexistent model identifier in an isolated environment. That exercises the wrapped API-error path without changing, exposing, or invalidating credentials. Restore the valid model and rerun the happy path immediately afterward.
Reader next step
Run the minimal synchronous probe with one harmless prompt. Do not proceed until the presence-only configuration event, sanitized success event, successful flush event, zero exit code, and visible Langfuse trace all agree on the same call. Next, run the controlled invalid-model check and confirm that the application and trace both expose the failure without printing request content, completion text, environment values, or raw exception text.
After those two paths pass, follow the CometAPI chat contract smoke tests before adding retries, streaming, or production prompts. Keep the trace name stable, use low-risk metadata, flush during shutdown, and repeat the probe whenever you change the client version, base URL, model identifier, or deployment environment.