feat(trace): support external trace id propagation (#22623)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import logging
|
||||
|
||||
from flask import request
|
||||
from flask_restful import Resource, reqparse
|
||||
from werkzeug.exceptions import InternalServerError, NotFound
|
||||
|
||||
@@ -23,6 +24,7 @@ from core.errors.error import (
|
||||
ProviderTokenNotInitError,
|
||||
QuotaExceededError,
|
||||
)
|
||||
from core.helper.trace_id_helper import get_external_trace_id
|
||||
from core.model_runtime.errors.invoke import InvokeError
|
||||
from libs import helper
|
||||
from libs.helper import uuid_value
|
||||
@@ -111,6 +113,10 @@ class ChatApi(Resource):
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
external_trace_id = get_external_trace_id(request)
|
||||
if external_trace_id:
|
||||
args["external_trace_id"] = external_trace_id
|
||||
|
||||
streaming = args["response_mode"] == "streaming"
|
||||
|
||||
try:
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import logging
|
||||
|
||||
from dateutil.parser import isoparse
|
||||
from flask import request
|
||||
from flask_restful import Resource, fields, marshal_with, reqparse
|
||||
from flask_restful.inputs import int_range
|
||||
from sqlalchemy.orm import Session, sessionmaker
|
||||
@@ -23,6 +24,7 @@ from core.errors.error import (
|
||||
ProviderTokenNotInitError,
|
||||
QuotaExceededError,
|
||||
)
|
||||
from core.helper.trace_id_helper import get_external_trace_id
|
||||
from core.model_runtime.errors.invoke import InvokeError
|
||||
from core.workflow.entities.workflow_execution import WorkflowExecutionStatus
|
||||
from extensions.ext_database import db
|
||||
@@ -90,7 +92,9 @@ class WorkflowRunApi(Resource):
|
||||
parser.add_argument("files", type=list, required=False, location="json")
|
||||
parser.add_argument("response_mode", type=str, choices=["blocking", "streaming"], location="json")
|
||||
args = parser.parse_args()
|
||||
|
||||
external_trace_id = get_external_trace_id(request)
|
||||
if external_trace_id:
|
||||
args["external_trace_id"] = external_trace_id
|
||||
streaming = args.get("response_mode") == "streaming"
|
||||
|
||||
try:
|
||||
|
@@ -23,6 +23,7 @@ from core.app.apps.message_based_app_generator import MessageBasedAppGenerator
|
||||
from core.app.apps.message_based_app_queue_manager import MessageBasedAppQueueManager
|
||||
from core.app.entities.app_invoke_entities import AdvancedChatAppGenerateEntity, InvokeFrom
|
||||
from core.app.entities.task_entities import ChatbotAppBlockingResponse, ChatbotAppStreamResponse
|
||||
from core.helper.trace_id_helper import extract_external_trace_id_from_args
|
||||
from core.model_runtime.errors.invoke import InvokeAuthorizationError
|
||||
from core.ops.ops_trace_manager import TraceQueueManager
|
||||
from core.prompt.utils.get_thread_messages_length import get_thread_messages_length
|
||||
@@ -112,7 +113,10 @@ class AdvancedChatAppGenerator(MessageBasedAppGenerator):
|
||||
query = query.replace("\x00", "")
|
||||
inputs = args["inputs"]
|
||||
|
||||
extras = {"auto_generate_conversation_name": args.get("auto_generate_name", False)}
|
||||
extras = {
|
||||
"auto_generate_conversation_name": args.get("auto_generate_name", False),
|
||||
**extract_external_trace_id_from_args(args),
|
||||
}
|
||||
|
||||
# get conversation
|
||||
conversation = None
|
||||
|
@@ -559,6 +559,7 @@ class AdvancedChatAppGenerateTaskPipeline:
|
||||
outputs=event.outputs,
|
||||
conversation_id=self._conversation_id,
|
||||
trace_manager=trace_manager,
|
||||
external_trace_id=self._application_generate_entity.extras.get("external_trace_id"),
|
||||
)
|
||||
workflow_finish_resp = self._workflow_response_converter.workflow_finish_to_stream_response(
|
||||
session=session,
|
||||
@@ -590,6 +591,7 @@ class AdvancedChatAppGenerateTaskPipeline:
|
||||
exceptions_count=event.exceptions_count,
|
||||
conversation_id=None,
|
||||
trace_manager=trace_manager,
|
||||
external_trace_id=self._application_generate_entity.extras.get("external_trace_id"),
|
||||
)
|
||||
workflow_finish_resp = self._workflow_response_converter.workflow_finish_to_stream_response(
|
||||
session=session,
|
||||
@@ -622,6 +624,7 @@ class AdvancedChatAppGenerateTaskPipeline:
|
||||
conversation_id=self._conversation_id,
|
||||
trace_manager=trace_manager,
|
||||
exceptions_count=event.exceptions_count,
|
||||
external_trace_id=self._application_generate_entity.extras.get("external_trace_id"),
|
||||
)
|
||||
workflow_finish_resp = self._workflow_response_converter.workflow_finish_to_stream_response(
|
||||
session=session,
|
||||
@@ -653,6 +656,7 @@ class AdvancedChatAppGenerateTaskPipeline:
|
||||
error_message=event.get_stop_reason(),
|
||||
conversation_id=self._conversation_id,
|
||||
trace_manager=trace_manager,
|
||||
external_trace_id=self._application_generate_entity.extras.get("external_trace_id"),
|
||||
)
|
||||
workflow_finish_resp = self._workflow_response_converter.workflow_finish_to_stream_response(
|
||||
session=session,
|
||||
|
@@ -22,6 +22,7 @@ from core.app.apps.workflow.generate_response_converter import WorkflowAppGenera
|
||||
from core.app.apps.workflow.generate_task_pipeline import WorkflowAppGenerateTaskPipeline
|
||||
from core.app.entities.app_invoke_entities import InvokeFrom, WorkflowAppGenerateEntity
|
||||
from core.app.entities.task_entities import WorkflowAppBlockingResponse, WorkflowAppStreamResponse
|
||||
from core.helper.trace_id_helper import extract_external_trace_id_from_args
|
||||
from core.model_runtime.errors.invoke import InvokeAuthorizationError
|
||||
from core.ops.ops_trace_manager import TraceQueueManager
|
||||
from core.repositories import DifyCoreRepositoryFactory
|
||||
@@ -123,6 +124,10 @@ class WorkflowAppGenerator(BaseAppGenerator):
|
||||
)
|
||||
|
||||
inputs: Mapping[str, Any] = args["inputs"]
|
||||
|
||||
extras = {
|
||||
**extract_external_trace_id_from_args(args),
|
||||
}
|
||||
workflow_run_id = str(uuid.uuid4())
|
||||
# init application generate entity
|
||||
application_generate_entity = WorkflowAppGenerateEntity(
|
||||
@@ -142,6 +147,7 @@ class WorkflowAppGenerator(BaseAppGenerator):
|
||||
call_depth=call_depth,
|
||||
trace_manager=trace_manager,
|
||||
workflow_execution_id=workflow_run_id,
|
||||
extras=extras,
|
||||
)
|
||||
|
||||
contexts.plugin_tool_providers.set({})
|
||||
|
@@ -490,6 +490,7 @@ class WorkflowAppGenerateTaskPipeline:
|
||||
outputs=event.outputs,
|
||||
conversation_id=None,
|
||||
trace_manager=trace_manager,
|
||||
external_trace_id=self._application_generate_entity.extras.get("external_trace_id"),
|
||||
)
|
||||
|
||||
# save workflow app log
|
||||
@@ -524,6 +525,7 @@ class WorkflowAppGenerateTaskPipeline:
|
||||
exceptions_count=event.exceptions_count,
|
||||
conversation_id=None,
|
||||
trace_manager=trace_manager,
|
||||
external_trace_id=self._application_generate_entity.extras.get("external_trace_id"),
|
||||
)
|
||||
|
||||
# save workflow app log
|
||||
@@ -561,6 +563,7 @@ class WorkflowAppGenerateTaskPipeline:
|
||||
conversation_id=None,
|
||||
trace_manager=trace_manager,
|
||||
exceptions_count=event.exceptions_count if isinstance(event, QueueWorkflowFailedEvent) else 0,
|
||||
external_trace_id=self._application_generate_entity.extras.get("external_trace_id"),
|
||||
)
|
||||
|
||||
# save workflow app log
|
||||
|
42
api/core/helper/trace_id_helper.py
Normal file
42
api/core/helper/trace_id_helper.py
Normal file
@@ -0,0 +1,42 @@
|
||||
import re
|
||||
from collections.abc import Mapping
|
||||
from typing import Any, Optional
|
||||
|
||||
|
||||
def is_valid_trace_id(trace_id: str) -> bool:
|
||||
"""
|
||||
Check if the trace_id is valid.
|
||||
|
||||
Requirements: 1-128 characters, only letters, numbers, '-', and '_'.
|
||||
"""
|
||||
return bool(re.match(r"^[a-zA-Z0-9\-_]{1,128}$", trace_id))
|
||||
|
||||
|
||||
def get_external_trace_id(request: Any) -> Optional[str]:
|
||||
"""
|
||||
Retrieve the trace_id from the request.
|
||||
|
||||
Priority: header ('X-Trace-Id'), then parameters, then JSON body. Returns None if not provided or invalid.
|
||||
"""
|
||||
trace_id = request.headers.get("X-Trace-Id")
|
||||
if not trace_id:
|
||||
trace_id = request.args.get("trace_id")
|
||||
if not trace_id and getattr(request, "is_json", False):
|
||||
json_data = getattr(request, "json", None)
|
||||
if json_data:
|
||||
trace_id = json_data.get("trace_id")
|
||||
if isinstance(trace_id, str) and is_valid_trace_id(trace_id):
|
||||
return trace_id
|
||||
return None
|
||||
|
||||
|
||||
def extract_external_trace_id_from_args(args: Mapping[str, Any]) -> dict:
|
||||
"""
|
||||
Extract 'external_trace_id' from args.
|
||||
|
||||
Returns a dict suitable for use in extras. Returns an empty dict if not found.
|
||||
"""
|
||||
trace_id = args.get("external_trace_id")
|
||||
if trace_id:
|
||||
return {"external_trace_id": trace_id}
|
||||
return {}
|
@@ -101,7 +101,8 @@ class AliyunDataTrace(BaseTraceInstance):
|
||||
raise ValueError(f"Aliyun get run url failed: {str(e)}")
|
||||
|
||||
def workflow_trace(self, trace_info: WorkflowTraceInfo):
|
||||
trace_id = convert_to_trace_id(trace_info.workflow_run_id)
|
||||
external_trace_id = trace_info.metadata.get("external_trace_id")
|
||||
trace_id = external_trace_id or convert_to_trace_id(trace_info.workflow_run_id)
|
||||
workflow_span_id = convert_to_span_id(trace_info.workflow_run_id, "workflow")
|
||||
self.add_workflow_span(trace_id, workflow_span_id, trace_info)
|
||||
|
||||
|
@@ -153,7 +153,8 @@ class ArizePhoenixDataTrace(BaseTraceInstance):
|
||||
}
|
||||
workflow_metadata.update(trace_info.metadata)
|
||||
|
||||
trace_id = uuid_to_trace_id(trace_info.workflow_run_id)
|
||||
external_trace_id = trace_info.metadata.get("external_trace_id")
|
||||
trace_id = external_trace_id or uuid_to_trace_id(trace_info.workflow_run_id)
|
||||
span_id = RandomIdGenerator().generate_span_id()
|
||||
context = SpanContext(
|
||||
trace_id=trace_id,
|
||||
|
@@ -67,13 +67,14 @@ class LangFuseDataTrace(BaseTraceInstance):
|
||||
self.generate_name_trace(trace_info)
|
||||
|
||||
def workflow_trace(self, trace_info: WorkflowTraceInfo):
|
||||
trace_id = trace_info.workflow_run_id
|
||||
external_trace_id = trace_info.metadata.get("external_trace_id")
|
||||
trace_id = external_trace_id or trace_info.workflow_run_id
|
||||
user_id = trace_info.metadata.get("user_id")
|
||||
metadata = trace_info.metadata
|
||||
metadata["workflow_app_log_id"] = trace_info.workflow_app_log_id
|
||||
|
||||
if trace_info.message_id:
|
||||
trace_id = trace_info.message_id
|
||||
trace_id = external_trace_id or trace_info.message_id
|
||||
name = TraceTaskName.MESSAGE_TRACE.value
|
||||
trace_data = LangfuseTrace(
|
||||
id=trace_id,
|
||||
|
@@ -65,7 +65,8 @@ class LangSmithDataTrace(BaseTraceInstance):
|
||||
self.generate_name_trace(trace_info)
|
||||
|
||||
def workflow_trace(self, trace_info: WorkflowTraceInfo):
|
||||
trace_id = trace_info.message_id or trace_info.workflow_run_id
|
||||
external_trace_id = trace_info.metadata.get("external_trace_id")
|
||||
trace_id = external_trace_id or trace_info.message_id or trace_info.workflow_run_id
|
||||
if trace_info.start_time is None:
|
||||
trace_info.start_time = datetime.now()
|
||||
message_dotted_order = (
|
||||
|
@@ -96,7 +96,8 @@ class OpikDataTrace(BaseTraceInstance):
|
||||
self.generate_name_trace(trace_info)
|
||||
|
||||
def workflow_trace(self, trace_info: WorkflowTraceInfo):
|
||||
dify_trace_id = trace_info.workflow_run_id
|
||||
external_trace_id = trace_info.metadata.get("external_trace_id")
|
||||
dify_trace_id = external_trace_id or trace_info.workflow_run_id
|
||||
opik_trace_id = prepare_opik_uuid(trace_info.start_time, dify_trace_id)
|
||||
workflow_metadata = wrap_metadata(
|
||||
trace_info.metadata, message_id=trace_info.message_id, workflow_app_log_id=trace_info.workflow_app_log_id
|
||||
@@ -104,7 +105,7 @@ class OpikDataTrace(BaseTraceInstance):
|
||||
root_span_id = None
|
||||
|
||||
if trace_info.message_id:
|
||||
dify_trace_id = trace_info.message_id
|
||||
dify_trace_id = external_trace_id or trace_info.message_id
|
||||
opik_trace_id = prepare_opik_uuid(trace_info.start_time, dify_trace_id)
|
||||
|
||||
trace_data = {
|
||||
|
@@ -520,6 +520,10 @@ class TraceTask:
|
||||
"app_id": workflow_run.app_id,
|
||||
}
|
||||
|
||||
external_trace_id = self.kwargs.get("external_trace_id")
|
||||
if external_trace_id:
|
||||
metadata["external_trace_id"] = external_trace_id
|
||||
|
||||
workflow_trace_info = WorkflowTraceInfo(
|
||||
workflow_data=workflow_run.to_dict(),
|
||||
conversation_id=conversation_id,
|
||||
|
@@ -87,7 +87,8 @@ class WeaveDataTrace(BaseTraceInstance):
|
||||
self.generate_name_trace(trace_info)
|
||||
|
||||
def workflow_trace(self, trace_info: WorkflowTraceInfo):
|
||||
trace_id = trace_info.message_id or trace_info.workflow_run_id
|
||||
external_trace_id = trace_info.metadata.get("external_trace_id")
|
||||
trace_id = external_trace_id or trace_info.message_id or trace_info.workflow_run_id
|
||||
if trace_info.start_time is None:
|
||||
trace_info.start_time = datetime.now()
|
||||
|
||||
|
@@ -85,6 +85,7 @@ class WorkflowCycleManager:
|
||||
outputs: Mapping[str, Any] | None = None,
|
||||
conversation_id: Optional[str] = None,
|
||||
trace_manager: Optional[TraceQueueManager] = None,
|
||||
external_trace_id: Optional[str] = None,
|
||||
) -> WorkflowExecution:
|
||||
workflow_execution = self._get_workflow_execution_or_raise_error(workflow_run_id)
|
||||
|
||||
@@ -96,7 +97,7 @@ class WorkflowCycleManager:
|
||||
total_steps=total_steps,
|
||||
)
|
||||
|
||||
self._add_trace_task_if_needed(trace_manager, workflow_execution, conversation_id)
|
||||
self._add_trace_task_if_needed(trace_manager, workflow_execution, conversation_id, external_trace_id)
|
||||
|
||||
self._workflow_execution_repository.save(workflow_execution)
|
||||
return workflow_execution
|
||||
@@ -111,6 +112,7 @@ class WorkflowCycleManager:
|
||||
exceptions_count: int = 0,
|
||||
conversation_id: Optional[str] = None,
|
||||
trace_manager: Optional[TraceQueueManager] = None,
|
||||
external_trace_id: Optional[str] = None,
|
||||
) -> WorkflowExecution:
|
||||
execution = self._get_workflow_execution_or_raise_error(workflow_run_id)
|
||||
|
||||
@@ -123,7 +125,7 @@ class WorkflowCycleManager:
|
||||
exceptions_count=exceptions_count,
|
||||
)
|
||||
|
||||
self._add_trace_task_if_needed(trace_manager, execution, conversation_id)
|
||||
self._add_trace_task_if_needed(trace_manager, execution, conversation_id, external_trace_id)
|
||||
|
||||
self._workflow_execution_repository.save(execution)
|
||||
return execution
|
||||
@@ -139,6 +141,7 @@ class WorkflowCycleManager:
|
||||
conversation_id: Optional[str] = None,
|
||||
trace_manager: Optional[TraceQueueManager] = None,
|
||||
exceptions_count: int = 0,
|
||||
external_trace_id: Optional[str] = None,
|
||||
) -> WorkflowExecution:
|
||||
workflow_execution = self._get_workflow_execution_or_raise_error(workflow_run_id)
|
||||
now = naive_utc_now()
|
||||
@@ -154,7 +157,7 @@ class WorkflowCycleManager:
|
||||
)
|
||||
|
||||
self._fail_running_node_executions(workflow_execution.id_, error_message, now)
|
||||
self._add_trace_task_if_needed(trace_manager, workflow_execution, conversation_id)
|
||||
self._add_trace_task_if_needed(trace_manager, workflow_execution, conversation_id, external_trace_id)
|
||||
|
||||
self._workflow_execution_repository.save(workflow_execution)
|
||||
return workflow_execution
|
||||
@@ -312,6 +315,7 @@ class WorkflowCycleManager:
|
||||
trace_manager: Optional[TraceQueueManager],
|
||||
workflow_execution: WorkflowExecution,
|
||||
conversation_id: Optional[str],
|
||||
external_trace_id: Optional[str],
|
||||
) -> None:
|
||||
"""Add trace task if trace manager is provided."""
|
||||
if trace_manager:
|
||||
@@ -321,6 +325,7 @@ class WorkflowCycleManager:
|
||||
workflow_execution=workflow_execution,
|
||||
conversation_id=conversation_id,
|
||||
user_id=trace_manager.user_id,
|
||||
external_trace_id=external_trace_id,
|
||||
)
|
||||
)
|
||||
|
||||
|
86
api/tests/unit_tests/core/helper/test_trace_id_helper.py
Normal file
86
api/tests/unit_tests/core/helper/test_trace_id_helper.py
Normal file
@@ -0,0 +1,86 @@
|
||||
import pytest
|
||||
|
||||
from core.helper.trace_id_helper import extract_external_trace_id_from_args, get_external_trace_id, is_valid_trace_id
|
||||
|
||||
|
||||
class DummyRequest:
|
||||
def __init__(self, headers=None, args=None, json=None, is_json=False):
|
||||
self.headers = headers or {}
|
||||
self.args = args or {}
|
||||
self.json = json
|
||||
self.is_json = is_json
|
||||
|
||||
|
||||
class TestTraceIdHelper:
|
||||
"""Test cases for trace_id_helper.py"""
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("trace_id", "expected"),
|
||||
[
|
||||
("abc123", True),
|
||||
("A-B_C-123", True),
|
||||
("a" * 128, True),
|
||||
("", False),
|
||||
("a" * 129, False),
|
||||
("abc!@#", False),
|
||||
("空格", False),
|
||||
("with space", False),
|
||||
],
|
||||
)
|
||||
def test_is_valid_trace_id(self, trace_id, expected):
|
||||
"""Test trace_id validation for various cases"""
|
||||
assert is_valid_trace_id(trace_id) is expected
|
||||
|
||||
def test_get_external_trace_id_from_header(self):
|
||||
"""Should extract valid trace_id from header"""
|
||||
req = DummyRequest(headers={"X-Trace-Id": "abc123"})
|
||||
assert get_external_trace_id(req) == "abc123"
|
||||
|
||||
def test_get_external_trace_id_from_args(self):
|
||||
"""Should extract valid trace_id from args if header missing"""
|
||||
req = DummyRequest(args={"trace_id": "abc123"})
|
||||
assert get_external_trace_id(req) == "abc123"
|
||||
|
||||
def test_get_external_trace_id_from_json(self):
|
||||
"""Should extract valid trace_id from JSON body if header and args missing"""
|
||||
req = DummyRequest(is_json=True, json={"trace_id": "abc123"})
|
||||
assert get_external_trace_id(req) == "abc123"
|
||||
|
||||
def test_get_external_trace_id_priority(self):
|
||||
"""Header > args > json priority"""
|
||||
req = DummyRequest(
|
||||
headers={"X-Trace-Id": "header_id"},
|
||||
args={"trace_id": "args_id"},
|
||||
is_json=True,
|
||||
json={"trace_id": "json_id"},
|
||||
)
|
||||
assert get_external_trace_id(req) == "header_id"
|
||||
req2 = DummyRequest(args={"trace_id": "args_id"}, is_json=True, json={"trace_id": "json_id"})
|
||||
assert get_external_trace_id(req2) == "args_id"
|
||||
req3 = DummyRequest(is_json=True, json={"trace_id": "json_id"})
|
||||
assert get_external_trace_id(req3) == "json_id"
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"req",
|
||||
[
|
||||
DummyRequest(headers={"X-Trace-Id": "!!!"}),
|
||||
DummyRequest(args={"trace_id": "!!!"}),
|
||||
DummyRequest(is_json=True, json={"trace_id": "!!!"}),
|
||||
DummyRequest(),
|
||||
],
|
||||
)
|
||||
def test_get_external_trace_id_invalid(self, req):
|
||||
"""Should return None for invalid or missing trace_id"""
|
||||
assert get_external_trace_id(req) is None
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("args", "expected"),
|
||||
[
|
||||
({"external_trace_id": "abc123"}, {"external_trace_id": "abc123"}),
|
||||
({"other": "value"}, {}),
|
||||
({}, {}),
|
||||
],
|
||||
)
|
||||
def test_extract_external_trace_id_from_args(self, args, expected):
|
||||
"""Test extraction of external_trace_id from args mapping"""
|
||||
assert extract_external_trace_id_from_args(args) == expected
|
@@ -80,6 +80,12 @@ Chat applications support session persistence, allowing previous chat history to
|
||||
Auto-generate title, default is `true`.
|
||||
If set to `false`, can achieve async title generation by calling the conversation rename API and setting `auto_generate` to `true`.
|
||||
</Property>
|
||||
<Property name='trace_id' type='string' key='trace_id'>
|
||||
(Optional) Trace ID. Used for integration with existing business trace components to achieve end-to-end distributed tracing. If not provided, the system will automatically generate a trace_id. Supports the following three ways to pass, in order of priority:<br/>
|
||||
- Header: via HTTP Header <code>X-Trace-Id</code>, highest priority.<br/>
|
||||
- Query parameter: via URL query parameter <code>trace_id</code>.<br/>
|
||||
- Request Body: via request body field <code>trace_id</code> (i.e., this field).<br/>
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
### Response
|
||||
|
@@ -80,6 +80,12 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
|
||||
タイトルを自動生成、デフォルトは`true`。
|
||||
`false`に設定すると、会話のリネームAPIを呼び出し、`auto_generate`を`true`に設定することで非同期タイトル生成を実現できます。
|
||||
</Property>
|
||||
<Property name='trace_id' type='string' key='trace_id'>
|
||||
(オプション)トレースID。既存の業務システムのトレースコンポーネントと連携し、エンドツーエンドの分散トレーシングを実現するために使用します。指定がない場合、システムが自動的に trace_id を生成します。以下の3つの方法で渡すことができ、優先順位は次のとおりです:<br/>
|
||||
- Header:HTTPヘッダー <code>X-Trace-Id</code> で渡す(最優先)。<br/>
|
||||
- クエリパラメータ:URLクエリパラメータ <code>trace_id</code> で渡す。<br/>
|
||||
- リクエストボディ:リクエストボディの <code>trace_id</code> フィールドで渡す(本フィールド)。<br/>
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
### 応答
|
||||
|
@@ -78,6 +78,12 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
|
||||
<Property name='auto_generate_name' type='bool' key='auto_generate_name'>
|
||||
(选填)自动生成标题,默认 `true`。 若设置为 `false`,则可通过调用会话重命名接口并设置 `auto_generate` 为 `true` 实现异步生成标题。
|
||||
</Property>
|
||||
<Property name='trace_id' type='string' key='trace_id'>
|
||||
(选填)链路追踪ID。适用于与业务系统已有的trace组件打通,实现端到端分布式追踪等场景。如果未指定,系统会自动生成<code>trace_id</code>。支持以下三种方式传递,具体优先级依次为:<br/>
|
||||
- Header:通过 HTTP Header <code>X-Trace-Id</code> 传递,优先级最高。<br/>
|
||||
- Query 参数:通过 URL 查询参数 <code>trace_id</code> 传递。<br/>
|
||||
- Request Body:通过请求体字段 <code>trace_id</code> 传递(即本字段)。<br/>
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
### Response
|
||||
|
@@ -74,6 +74,12 @@ Chat applications support session persistence, allowing previous chat history to
|
||||
Auto-generate title, default is `true`.
|
||||
If set to `false`, can achieve async title generation by calling the conversation rename API and setting `auto_generate` to `true`.
|
||||
</Property>
|
||||
<Property name='trace_id' type='string' key='trace_id'>
|
||||
(Optional) Trace ID. Used for integration with existing business trace components to achieve end-to-end distributed tracing. If not provided, the system will automatically generate a trace_id. Supports the following three ways to pass, in order of priority:<br/>
|
||||
- Header: via HTTP Header <code>X-Trace-Id</code>, highest priority.<br/>
|
||||
- Query parameter: via URL query parameter <code>trace_id</code>.<br/>
|
||||
- Request Body: via request body field <code>trace_id</code> (i.e., this field).<br/>
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
### Response
|
||||
|
@@ -74,6 +74,12 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
|
||||
タイトルを自動生成します。デフォルトは`true`です。
|
||||
`false`に設定すると、会話のリネームAPIを呼び出し、`auto_generate`を`true`に設定することで非同期タイトル生成を実現できます。
|
||||
</Property>
|
||||
<Property name='trace_id' type='string' key='trace_id'>
|
||||
(オプション)トレースID。既存の業務システムのトレースコンポーネントと連携し、エンドツーエンドの分散トレーシングを実現するために使用します。指定がない場合、システムが自動的に trace_id を生成します。以下の3つの方法で渡すことができ、優先順位は次のとおりです:<br/>
|
||||
- Header:HTTPヘッダー <code>X-Trace-Id</code> で渡す(最優先)。<br/>
|
||||
- クエリパラメータ:URLクエリパラメータ <code>trace_id</code> で渡す。<br/>
|
||||
- リクエストボディ:リクエストボディの <code>trace_id</code> フィールドで渡す(本フィールド)。<br/>
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
### 応答
|
||||
|
@@ -73,6 +73,12 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
|
||||
<Property name='auto_generate_name' type='bool' key='auto_generate_name'>
|
||||
(选填)自动生成标题,默认 `true`。 若设置为 `false`,则可通过调用会话重命名接口并设置 `auto_generate` 为 `true` 实现异步生成标题。
|
||||
</Property>
|
||||
<Property name='trace_id' type='string' key='trace_id'>
|
||||
(选填)链路追踪ID。适用于与业务系统已有的trace组件打通,实现端到端分布式追踪等场景。如果未指定,系统会自动生成<code>trace_id</code>。支持以下三种方式传递,具体优先级依次为:<br/>
|
||||
- Header:通过 HTTP Header <code>X-Trace-Id</code> 传递,优先级最高。<br/>
|
||||
- Query 参数:通过 URL 查询参数 <code>trace_id</code> 传递。<br/>
|
||||
- Request Body:通过请求体字段 <code>trace_id</code> 传递(即本字段)。<br/>
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
### Response
|
||||
|
@@ -66,6 +66,12 @@ Workflow applications offers non-session support and is ideal for translation, a
|
||||
Should be uniquely defined by the developer within the application.
|
||||
<br/>
|
||||
<i>The user identifier should be consistent with the user passed in the message sending interface. The Service API does not share conversations created by the WebApp.</i>
|
||||
- `files` (array[object]) Optional
|
||||
- `trace_id` (string) Optional
|
||||
Trace ID. Used for integration with existing business trace components to achieve end-to-end distributed tracing. If not provided, the system will automatically generate a trace_id. Supports the following three ways to pass, in order of priority:
|
||||
1. Header: via HTTP Header `X-Trace-Id`, highest priority.
|
||||
2. Query parameter: via URL query parameter `trace_id`.
|
||||
3. Request Body: via request body field `trace_id` (i.e., this field).
|
||||
|
||||
### Response
|
||||
When `response_mode` is `blocking`, return a CompletionResponse object.
|
||||
|
@@ -66,6 +66,11 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
|
||||
ユーザー識別子、エンドユーザーのアイデンティティを定義するために使用されます。
|
||||
アプリケーション内で開発者によって一意に定義される必要があります。
|
||||
- `files` (array[object]) オプション
|
||||
- `trace_id` (string) オプション
|
||||
トレースID。既存の業務システムのトレースコンポーネントと連携し、エンドツーエンドの分散トレーシングを実現するために使用します。指定がない場合、システムが自動的に trace_id を生成します。以下の3つの方法で渡すことができ、優先順位は次のとおりです:
|
||||
1. Header:HTTPヘッダー `X-Trace-Id` で渡す(最優先)。
|
||||
2. クエリパラメータ:URLクエリパラメータ `trace_id` で渡す。
|
||||
3. リクエストボディ:リクエストボディの `trace_id` フィールドで渡す(本フィールド)。
|
||||
|
||||
|
||||
### 応答
|
||||
|
@@ -60,7 +60,12 @@ Workflow 应用无会话支持,适合用于翻译/文章写作/总结 AI 等
|
||||
- `user` (string) Required
|
||||
用户标识,用于定义终端用户的身份,方便检索、统计。
|
||||
由开发者定义规则,需保证用户标识在应用内唯一。API 无法访问 WebApp 创建的会话。
|
||||
|
||||
- `files` (array[object]) 可选
|
||||
- `trace_id` (string) Optional
|
||||
链路追踪ID。适用于与业务系统已有的trace组件打通,实现端到端分布式追踪等场景。如果未指定,系统将自动生成 `trace_id`。支持以下三种方式传递,具体优先级依次为:
|
||||
1. Header:推荐通过 HTTP Header `X-Trace-Id` 传递,优先级最高。
|
||||
2. Query 参数:通过 URL 查询参数 `trace_id` 传递。
|
||||
3. Request Body:通过请求体字段 `trace_id` 传递(即本字段)。
|
||||
|
||||
### Response
|
||||
当 `response_mode` 为 `blocking` 时,返回 CompletionResponse object。
|
||||
|
Reference in New Issue
Block a user