Feat: trace information can be returned by the agent completion API (#12019)

### What problem does this PR solve?

Trace information can be returned by the agent completion API.

### Type of change

- [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
Yongteng Lei
2025-12-18 15:52:11 +08:00
committed by GitHub
parent 2331b3a270
commit 151480dc85
2 changed files with 226 additions and 5 deletions

View File

@ -14,6 +14,7 @@
# limitations under the License. # limitations under the License.
# #
import json import json
import copy
import re import re
import time import time
@ -446,10 +447,12 @@ async def agents_completion_openai_compatibility(tenant_id, agent_id):
@token_required @token_required
async def agent_completions(tenant_id, agent_id): async def agent_completions(tenant_id, agent_id):
req = await get_request_json() req = await get_request_json()
return_trace = bool(req.get("return_trace", False))
if req.get("stream", True): if req.get("stream", True):
async def generate(): async def generate():
trace_items = []
async for answer in agent_completion(tenant_id=tenant_id, agent_id=agent_id, **req): async for answer in agent_completion(tenant_id=tenant_id, agent_id=agent_id, **req):
if isinstance(answer, str): if isinstance(answer, str):
try: try:
@ -457,7 +460,21 @@ async def agent_completions(tenant_id, agent_id):
except Exception: except Exception:
continue continue
if ans.get("event") not in ["message", "message_end"]: event = ans.get("event")
if event == "node_finished":
if return_trace:
data = ans.get("data", {})
trace_items.append(
{
"component_id": data.get("component_id"),
"trace": [copy.deepcopy(data)],
}
)
ans.setdefault("data", {})["trace"] = trace_items
answer = "data:" + json.dumps(ans, ensure_ascii=False) + "\n\n"
yield answer
if event not in ["message", "message_end"]:
continue continue
yield answer yield answer
@ -474,6 +491,7 @@ async def agent_completions(tenant_id, agent_id):
full_content = "" full_content = ""
reference = {} reference = {}
final_ans = "" final_ans = ""
trace_items = []
async for answer in agent_completion(tenant_id=tenant_id, agent_id=agent_id, **req): async for answer in agent_completion(tenant_id=tenant_id, agent_id=agent_id, **req):
try: try:
ans = json.loads(answer[5:]) ans = json.loads(answer[5:])
@ -484,11 +502,22 @@ async def agent_completions(tenant_id, agent_id):
if ans.get("data", {}).get("reference", None): if ans.get("data", {}).get("reference", None):
reference.update(ans["data"]["reference"]) reference.update(ans["data"]["reference"])
if return_trace and ans.get("event") == "node_finished":
data = ans.get("data", {})
trace_items.append(
{
"component_id": data.get("component_id"),
"trace": [copy.deepcopy(data)],
}
)
final_ans = ans final_ans = ans
except Exception as e: except Exception as e:
return get_result(data=f"**ERROR**: {str(e)}") return get_result(data=f"**ERROR**: {str(e)}")
final_ans["data"]["content"] = full_content final_ans["data"]["content"] = full_content
final_ans["data"]["reference"] = reference final_ans["data"]["reference"] = reference
if return_trace and final_ans:
final_ans["data"]["trace"] = trace_items
return get_result(data=final_ans) return get_result(data=final_ans)

View File

@ -3601,6 +3601,8 @@ Asks a specified agent a question to start an AI-powered conversation.
[DONE] [DONE]
``` ```
- You can optionally return step-by-step trace logs (see `return_trace` below).
::: :::
#### Request #### Request
@ -3616,6 +3618,17 @@ Asks a specified agent a question to start an AI-powered conversation.
- `"session_id"`: `string` (optional) - `"session_id"`: `string` (optional)
- `"inputs"`: `object` (optional) - `"inputs"`: `object` (optional)
- `"user_id"`: `string` (optional) - `"user_id"`: `string` (optional)
- `"return_trace"`: `boolean` (optional, default `false`) — include execution trace logs.
#### Streaming events to handle
When `stream=true`, the server sends Server-Sent Events (SSE). Clients should handle these `event` types:
- `message`: streaming content from Message components.
- `message_end`: end of a Message component; may include `reference`/`attachment`.
- `node_finished`: a component finishes; `data.inputs/outputs/error/elapsed_time` describe the node result. If `return_trace=true`, the trace is attached inside the same `node_finished` event (`data.trace`).
The stream terminates with `[DONE]`.
:::info IMPORTANT :::info IMPORTANT
You can include custom parameters in the request body, but first ensure they are defined in the [Begin](../guides/agent/agent_component_reference/begin.mdx) component. You can include custom parameters in the request body, but first ensure they are defined in the [Begin](../guides/agent/agent_component_reference/begin.mdx) component.
@ -3800,6 +3813,92 @@ data: {
"session_id": "cd097ca083dc11f0858253708ecb6573" "session_id": "cd097ca083dc11f0858253708ecb6573"
} }
data: {
"event": "node_finished",
"message_id": "cecdcb0e83dc11f0858253708ecb6573",
"created_at": 1756364483,
"task_id": "d1f79142831f11f09cc51795b9eb07c0",
"data": {
"inputs": {
"sys.query": "how to install neovim?"
},
"outputs": {
"content": "xxxxxxx",
"_created_time": 15294.0382,
"_elapsed_time": 0.00017
},
"component_id": "Agent:EveryHairsChew",
"component_name": "Agent_1",
"component_type": "Agent",
"error": null,
"elapsed_time": 11.2091,
"created_at": 15294.0382,
"trace": [
{
"component_id": "begin",
"trace": [
{
"inputs": {},
"outputs": {
"_created_time": 15257.7949,
"_elapsed_time": 0.00070
},
"component_id": "begin",
"component_name": "begin",
"component_type": "Begin",
"error": null,
"elapsed_time": 0.00085,
"created_at": 15257.7949
}
]
},
{
"component_id": "Agent:WeakDragonsRead",
"trace": [
{
"inputs": {
"sys.query": "how to install neovim?"
},
"outputs": {
"content": "xxxxxxx",
"_created_time": 15257.7982,
"_elapsed_time": 36.2382
},
"component_id": "Agent:WeakDragonsRead",
"component_name": "Agent_0",
"component_type": "Agent",
"error": null,
"elapsed_time": 36.2385,
"created_at": 15257.7982
}
]
},
{
"component_id": "Agent:EveryHairsChew",
"trace": [
{
"inputs": {
"sys.query": "how to install neovim?"
},
"outputs": {
"content": "xxxxxxxxxxxxxxxxx",
"_created_time": 15294.0382,
"_elapsed_time": 0.00017
},
"component_id": "Agent:EveryHairsChew",
"component_name": "Agent_1",
"component_type": "Agent",
"error": null,
"elapsed_time": 11.2091,
"created_at": 15294.0382
}
]
}
]
},
"session_id": "cd097ca083dc11f0858253708ecb6573"
}
data:[DONE] data:[DONE]
``` ```
@ -3874,7 +3973,100 @@ Non-stream:
"doc_name": "INSTALL3.md" "doc_name": "INSTALL3.md"
} }
} }
} },
"trace": [
{
"component_id": "begin",
"trace": [
{
"component_id": "begin",
"component_name": "begin",
"component_type": "Begin",
"created_at": 15926.567517862,
"elapsed_time": 0.0008189299987861887,
"error": null,
"inputs": {},
"outputs": {
"_created_time": 15926.567517862,
"_elapsed_time": 0.0006958619997021742
}
}
]
},
{
"component_id": "Agent:WeakDragonsRead",
"trace": [
{
"component_id": "Agent:WeakDragonsRead",
"component_name": "Agent_0",
"component_type": "Agent",
"created_at": 15926.569121755,
"elapsed_time": 53.49016142000073,
"error": null,
"inputs": {
"sys.query": "how to install neovim?"
},
"outputs": {
"_created_time": 15926.569121755,
"_elapsed_time": 53.489981256001556,
"content": "xxxxxxxxxxxxxx",
"use_tools": [
{
"arguments": {
"query": "xxxx"
},
"name": "search_my_dateset",
"results": "xxxxxxxxxxx"
}
]
}
}
]
},
{
"component_id": "Agent:EveryHairsChew",
"trace": [
{
"component_id": "Agent:EveryHairsChew",
"component_name": "Agent_1",
"component_type": "Agent",
"created_at": 15980.060569101,
"elapsed_time": 23.61718057500002,
"error": null,
"inputs": {
"sys.query": "how to install neovim?"
},
"outputs": {
"_created_time": 15980.060569101,
"_elapsed_time": 0.0003451630000199657,
"content": "xxxxxxxxxxxx"
}
}
]
},
{
"component_id": "Message:SlickDingosHappen",
"trace": [
{
"component_id": "Message:SlickDingosHappen",
"component_name": "Message_0",
"component_type": "Message",
"created_at": 15980.061302513,
"elapsed_time": 23.61655923699982,
"error": null,
"inputs": {
"Agent:EveryHairsChew@content": "xxxxxxxxx",
"Agent:WeakDragonsRead@content": "xxxxxxxxxxx"
},
"outputs": {
"_created_time": 15980.061302513,
"_elapsed_time": 0.0006695749998471001,
"content": "xxxxxxxxxxx"
}
}
]
}
]
}, },
"event": "workflow_finished", "event": "workflow_finished",
"message_id": "c4692a2683d911f0858253708ecb6573", "message_id": "c4692a2683d911f0858253708ecb6573",