mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-21 05:16:54 +08:00
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:
@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -2236,7 +2236,7 @@ Batch update or delete document-level metadata within a specified dataset. If bo
|
|||||||
- `"document_ids"`: `list[string]` *optional*
|
- `"document_ids"`: `list[string]` *optional*
|
||||||
The associated document ID.
|
The associated document ID.
|
||||||
- `"metadata_condition"`: `object`, *optional*
|
- `"metadata_condition"`: `object`, *optional*
|
||||||
- `"logic"`: Defines the logic relation between conditions if multiple conditions are provided. Options:
|
- `"logic"`: Defines the logic relation between conditions if multiple conditions are provided. Options:
|
||||||
- `"and"` (default)
|
- `"and"` (default)
|
||||||
- `"or"`
|
- `"or"`
|
||||||
- `"conditions"`: `list[object]` *optional*
|
- `"conditions"`: `list[object]` *optional*
|
||||||
@ -2266,7 +2266,7 @@ Batch update or delete document-level metadata within a specified dataset. If bo
|
|||||||
- `"deletes`: (*Body parameter*), `list[ojbect]`, *optional*
|
- `"deletes`: (*Body parameter*), `list[ojbect]`, *optional*
|
||||||
Deletes metadata of the retrieved documents. Each object: `{ "key": string, "value": string }`.
|
Deletes metadata of the retrieved documents. Each object: `{ "key": string, "value": string }`.
|
||||||
- `"key"`: `string` The name of the key to delete.
|
- `"key"`: `string` The name of the key to delete.
|
||||||
- `"value"`: `string` *Optional* The value of the key to delete.
|
- `"value"`: `string` *Optional* The value of the key to delete.
|
||||||
- When provided, only keys with a matching value are deleted.
|
- When provided, only keys with a matching value are deleted.
|
||||||
- When omitted, all specified keys are deleted.
|
- When omitted, all specified keys are deleted.
|
||||||
|
|
||||||
@ -2533,7 +2533,7 @@ curl --request POST \
|
|||||||
:::caution WARNING
|
:::caution WARNING
|
||||||
`model_type` is an *internal* parameter, serving solely as a temporary workaround for the current model-configuration design limitations.
|
`model_type` is an *internal* parameter, serving solely as a temporary workaround for the current model-configuration design limitations.
|
||||||
|
|
||||||
Its main purpose is to let *multimodal* models (stored in the database as `"image2text"`) pass backend validation/dispatching. Be mindful that:
|
Its main purpose is to let *multimodal* models (stored in the database as `"image2text"`) pass backend validation/dispatching. Be mindful that:
|
||||||
|
|
||||||
- Do *not* treat it as a stable public API.
|
- Do *not* treat it as a stable public API.
|
||||||
- It is subject to change or removal in future releases.
|
- It is subject to change or removal in future releases.
|
||||||
@ -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",
|
||||||
|
|||||||
Reference in New Issue
Block a user