Browse Source

Fix bugs in agent api and update api document (#3996)

### What problem does this PR solve?

Fix bugs in agent api and update api document

### Type of change

- [x] Bug Fix (non-breaking change which fixes an issue)
- [x] New Feature (non-breaking change which adds functionality)

---------

Co-authored-by: liuhua <10215101452@stu.ecun.edu.cn>
tags/v0.15.0
liuhua 10 months ago
parent
commit
1ecb687c51
No account linked to committer's email address

+ 1
- 0
agent/canvas.py View File

self.path.append(["begin"]) self.path.append(["begin"])


self.path.append([]) self.path.append([])

ran = -1 ran = -1
waiting = [] waiting = []
without_dependent_checking = [] without_dependent_checking = []

+ 28
- 17
api/apps/sdk/session.py View File

cvs.dsl = json.dumps(cvs.dsl, ensure_ascii=False) cvs.dsl = json.dumps(cvs.dsl, ensure_ascii=False)


canvas = Canvas(cvs.dsl, tenant_id) canvas = Canvas(cvs.dsl, tenant_id)
if canvas.get_preset_param():
return get_error_data_result("The agent can't create a session directly")
conv = { conv = {
"id": get_uuid(), "id": get_uuid(),
"dialog_id": cvs.id, "dialog_id": cvs.id,
@token_required @token_required
def chat_completion(tenant_id, chat_id): def chat_completion(tenant_id, chat_id):
req = request.json req = request.json
if not req or not req.get("session_id"):
req = {"question":""}
if not DialogService.query(tenant_id=tenant_id,id=chat_id,status=StatusEnum.VALID.value): if not DialogService.query(tenant_id=tenant_id,id=chat_id,status=StatusEnum.VALID.value):
return get_error_data_result(f"You don't own the chat {chat_id}") return get_error_data_result(f"You don't own the chat {chat_id}")
if req.get("session_id"): if req.get("session_id"):
resp.headers.add_header("Content-Type", "text/event-stream; charset=utf-8") resp.headers.add_header("Content-Type", "text/event-stream; charset=utf-8")


return resp return resp

else: else:
answer = None answer = None
for ans in rag_completion(tenant_id, chat_id, **req): for ans in rag_completion(tenant_id, chat_id, **req):
@manager.route('/agents/<agent_id>/completions', methods=['POST']) # noqa: F821 @manager.route('/agents/<agent_id>/completions', methods=['POST']) # noqa: F821
@token_required @token_required
def agent_completions(tenant_id, agent_id): def agent_completions(tenant_id, agent_id):
req = request.json
if not UserCanvasService.query(user_id=tenant_id,id=agent_id):
return get_error_data_result(f"You don't own the agent {agent_id}")
if req.get("session_id"):
if not API4ConversationService.query(id=req["session_id"],dialog_id=agent_id):
return get_error_data_result(f"You don't own the session {req['session_id']}")
if req.get("stream", True):
resp = Response(agent_completion(tenant_id, agent_id, **req), mimetype="text/event-stream")
resp.headers.add_header("Cache-control", "no-cache")
resp.headers.add_header("Connection", "keep-alive")
resp.headers.add_header("X-Accel-Buffering", "no")
resp.headers.add_header("Content-Type", "text/event-stream; charset=utf-8")
return resp

for answer in agent_completion(tenant_id, agent_id, **req):
return get_result(data=answer)
req = request.json
cvs = UserCanvasService.query(user_id=tenant_id, id=agent_id)
if not cvs:
return get_error_data_result(f"You don't own the agent {agent_id}")
if req.get("session_id"):
conv = API4ConversationService.query(id=req["session_id"], dialog_id=agent_id)
if not conv:
return get_error_data_result(f"You don't own the session {req['session_id']}")
else:
req["question"]=""
if req.get("stream", True):
resp = Response(agent_completion(tenant_id, agent_id, **req), mimetype="text/event-stream")
resp.headers.add_header("Cache-control", "no-cache")
resp.headers.add_header("Connection", "keep-alive")
resp.headers.add_header("X-Accel-Buffering", "no")
resp.headers.add_header("Content-Type", "text/event-stream; charset=utf-8")
return resp
try:
for answer in agent_completion(tenant_id, agent_id, **req):
return get_result(data=answer)
except Exception as e:
return get_error_data_result(str(e))




@manager.route('/chats/<chat_id>/sessions', methods=['GET']) # noqa: F821 @manager.route('/chats/<chat_id>/sessions', methods=['GET']) # noqa: F821


for answer in agent_completion(objs[0].tenant_id, agent_id, **req): for answer in agent_completion(objs[0].tenant_id, agent_id, **req):
return get_result(data=answer) return get_result(data=answer)



+ 20
- 18
api/db/services/canvas_service.py View File

e, cvs = UserCanvasService.get_by_id(agent_id) e, cvs = UserCanvasService.get_by_id(agent_id)
assert e, "Agent not found." assert e, "Agent not found."
assert cvs.user_id == tenant_id, "You do not own the agent." assert cvs.user_id == tenant_id, "You do not own the agent."

if not isinstance(cvs.dsl, str):
if not isinstance(cvs.dsl,str):
cvs.dsl = json.dumps(cvs.dsl, ensure_ascii=False) cvs.dsl = json.dumps(cvs.dsl, ensure_ascii=False)
canvas = Canvas(cvs.dsl, tenant_id) canvas = Canvas(cvs.dsl, tenant_id)
canvas.reset() canvas.reset()
message_id = str(uuid4()) message_id = str(uuid4())

if not session_id: if not session_id:
query = canvas.get_preset_param()
if query:
for ele in query:
if not ele["optional"]:
if not kwargs.get(ele["key"]):
assert False, f"`{ele['key']}` is required"
ele["value"] = kwargs[ele["key"]]
if ele["optional"]:
if kwargs.get(ele["key"]):
ele["value"] = kwargs[ele['key']]
else:
if "value" in ele:
ele.pop("value")
cvs.dsl = json.loads(str(canvas))
temp_dsl = cvs.dsl
UserCanvasService.update_by_id(agent_id, cvs.to_dict())
else:
temp_dsl = json.loads(cvs.dsl)
session_id = get_uuid() session_id = get_uuid()
conv = { conv = {
"id": session_id, "id": session_id,
"dialog_id": cvs.id, "dialog_id": cvs.id,
"user_id": kwargs.get("user_id", ""), "user_id": kwargs.get("user_id", ""),
"source": "agent", "source": "agent",
"dsl": json.loads(cvs.dsl)
"dsl": temp_dsl
} }
API4ConversationService.save(**conv) API4ConversationService.save(**conv)
if canvas.get_preset_param():
yield "data:" + json.dumps({"code": 0,
"message": "",
"data": {
"session_id": session_id,
"answer": "",
"reference": [],
"param": canvas.get_preset_param()
}
},
ensure_ascii=False) + "\n\n"
yield "data:" + json.dumps({"code": 0, "message": "", "data": True}, ensure_ascii=False) + "\n\n"
return
conv = API4Conversation(**conv) conv = API4Conversation(**conv)
else: else:
e, conv = API4ConversationService.get_by_id(session_id) e, conv = API4ConversationService.get_by_id(session_id)
conv.reference.append({"chunks": [], "doc_aggs": []}) conv.reference.append({"chunks": [], "doc_aggs": []})


final_ans = {"reference": [], "content": ""} final_ans = {"reference": [], "content": ""}

if stream: if stream:
try: try:
for ans in canvas.run(stream=stream): for ans in canvas.run(stream=stream):

+ 2
- 1
api/db/services/conversation_service.py View File

assert dia, "You do not own the chat." assert dia, "You do not own the chat."


if not session_id: if not session_id:
session_id = get_uuid()
conv = { conv = {
"id": get_uuid(),
"id":session_id ,
"dialog_id": chat_id, "dialog_id": chat_id,
"name": name, "name": name,
"message": [{"role": "assistant", "content": dia[0].prompt_config.get("prologue")}] "message": [{"role": "assistant", "content": dia[0].prompt_config.get("prologue")}]

+ 248
- 15
docs/references/http_api_reference.md View File

--header 'Authorization: Bearer <YOUR_API_KEY>' \ --header 'Authorization: Bearer <YOUR_API_KEY>' \
--data-binary ' --data-binary '
{ {
"question": "What is RAGFlow?",
"stream": true
}' }'
``` ```

```bash
curl --request POST \
--url http://{address}/api/v1/chats/{chat_id}/completions \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer <YOUR_API_KEY>' \
--data-binary '
{
"question": "Who are you",
"stream": true,
"session_id":"9fa7691cb85c11ef9c5f0242ac120005"
}'
```
#### Request Parameters #### Request Parameters


- `chat_id`: (*Path parameter*) - `chat_id`: (*Path parameter*)
The ID of session. If it is not provided, a new session will be generated. The ID of session. If it is not provided, a new session will be generated.


### Response ### Response
Success without `session_id`:
```text
data:{
"code": 0,
"message": "",
"data": {
"answer": "Hi! I'm your assistant, what can I do for you?",
"reference": {},
"audio_binary": null,
"id": null,
"session_id": "b01eed84b85611efa0e90242ac120005"
}
}
data:{
"code": 0,
"message": "",
"data": true
}
```


Success:
Success with `session_id`:


```json
```text
data:{ data:{
"code": 0, "code": 0,
"data": { "data": {
--- ---


## Create session with agent ## Create session with agent
*If there are parameters in the `begin` component, the session cannot be created in this way.*


**POST** `/api/v1/agents/{agent_id}/sessions` **POST** `/api/v1/agents/{agent_id}/sessions`


{ {
"code": 0, "code": 0,
"data": { "data": {
"agent_id": "2e45b5209c1011efa3e90242ac120006",
"id": "7869e9e49c1711ef92840242ac120006",
"agent_id": "b4a39922b76611efaa1a0242ac120006",
"dsl": {
"answer": [],
"components": {
"Answer:GreenReadersDrum": {
"downstream": [],
"obj": {
"component_name": "Answer",
"inputs": [],
"output": null,
"params": {}
},
"upstream": []
},
"begin": {
"downstream": [],
"obj": {
"component_name": "Begin",
"inputs": [],
"output": {},
"params": {}
},
"upstream": []
}
},
"embed_id": "",
"graph": {
"edges": [],
"nodes": [
{
"data": {
"label": "Begin",
"name": "begin"
},
"dragging": false,
"height": 44,
"id": "begin",
"position": {
"x": 53.25688640427177,
"y": 198.37155679786412
},
"positionAbsolute": {
"x": 53.25688640427177,
"y": 198.37155679786412
},
"selected": false,
"sourcePosition": "left",
"targetPosition": "right",
"type": "beginNode",
"width": 200
},
{
"data": {
"form": {},
"label": "Answer",
"name": "对话_0"
},
"dragging": false,
"height": 44,
"id": "Answer:GreenReadersDrum",
"position": {
"x": 360.43473114516974,
"y": 207.29298425089348
},
"positionAbsolute": {
"x": 360.43473114516974,
"y": 207.29298425089348
},
"selected": false,
"sourcePosition": "right",
"targetPosition": "left",
"type": "logicNode",
"width": 200
}
]
},
"history": [],
"messages": [],
"path": [
[
"begin"
],
[]
],
"reference": []
},
"id": "2581031eb7a311efb5200242ac120005",
"message": [ "message": [
{ {
"content": "Hello! I am a recruiter at InfiniFlow. I learned that you are an expert in the field, and took the liberty of reaching out to you. There is an opportunity I would like to share with you. RAGFlow is currently looking for a senior engineer for your position. I was wondering if you might be interested?",
"content": "Hi! I'm your smart assistant. What can I do for you?",
"role": "assistant" "role": "assistant"
} }
], ],
"source": "agent", "source": "agent",
"user_id": ""
"user_id": "69736c5e723611efb51b0242ac120007"
} }
} }
``` ```
- `"question"`: `string` - `"question"`: `string`
- `"stream"`: `boolean` - `"stream"`: `boolean`
- `"session_id"`: `string` - `"session_id"`: `string`
- other parameters: `string`
#### Request example #### Request example


```bash ```bash
--header 'Authorization: Bearer <YOUR_API_KEY>' \ --header 'Authorization: Bearer <YOUR_API_KEY>' \
--data-binary ' --data-binary '
{ {
"question": "What is RAGFlow?",
"stream": true
}'
```
```bash
curl --request POST \
--url http://{address}/api/v1/agents/{agent_id}/completions \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer <YOUR_API_KEY>' \
--data-binary '
{
"question": "Hello",
"stream": true,
"session_id": "cb2f385cb86211efa36e0242ac120005"
}'
```
```bash
curl --request POST \
--url http://{address}/api/v1/agents/{agent_id}/completions \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer <YOUR_API_KEY>' \
--data-binary '
{
"lang":"English"
"file":"明天天气如何"
}' }'
``` ```



#### Request Parameters #### Request Parameters


- `agent_id`: (*Path parameter*), `string` - `agent_id`: (*Path parameter*), `string`
- `false`: Disable streaming. - `false`: Disable streaming.
- `"session_id"`: (*Body Parameter*) - `"session_id"`: (*Body Parameter*)
The ID of the session. If it is not provided, a new session will be generated. The ID of the session. If it is not provided, a new session will be generated.

- Other parameters: (*Body Parameter*)
The parameters in the begin component.
### Response ### Response

Success:
success without `session_id` provided and with no parameters in the `begin` component:
```text
data:{
"code": 0,
"message": "",
"data": {
"answer": "Hi! I'm your smart assistant. What can I do for you?",
"reference": {},
"id": "31e6091d-88d4-441b-ac65-eae1c055be7b",
"session_id": "2987ad3eb85f11efb2a70242ac120005"
}
}
data:{
"code": 0,
"message": "",
"data": true
}
```
Success with `session_id` provided and with no parameters in the `begin` component:


```text ```text
data:{ data:{
"data": true "data": true
} }
``` ```
Success with parameters in the `begin` component:
```text
data:{
"code": 0,
"message": "",
"data": {
"answer": "How",
"reference": {},
"id": "0379ac4c-b26b-4a44-8b77-99cebf313fdf",
"session_id": "4399c7d0b86311efac5b0242ac120005"
}
}
data:{
"code": 0,
"message": "",
"data": {
"answer": "How is",
"reference": {},
"id": "0379ac4c-b26b-4a44-8b77-99cebf313fdf",
"session_id": "4399c7d0b86311efac5b0242ac120005"
}
}
data:{
"code": 0,
"message": "",
"data": {
"answer": "How is the",
"reference": {},
"id": "0379ac4c-b26b-4a44-8b77-99cebf313fdf",
"session_id": "4399c7d0b86311efac5b0242ac120005"
}
}
data:{
"code": 0,
"message": "",
"data": {
"answer": "How is the weather",
"reference": {},
"id": "0379ac4c-b26b-4a44-8b77-99cebf313fdf",
"session_id": "4399c7d0b86311efac5b0242ac120005"
}
}
data:{
"code": 0,
"message": "",
"data": {
"answer": "How is the weather tomorrow",
"reference": {},
"id": "0379ac4c-b26b-4a44-8b77-99cebf313fdf",
"session_id": "4399c7d0b86311efac5b0242ac120005"
}
}
data:{
"code": 0,
"message": "",
"data": {
"answer": "How is the weather tomorrow?",
"reference": {},
"id": "0379ac4c-b26b-4a44-8b77-99cebf313fdf",
"session_id": "4399c7d0b86311efac5b0242ac120005"
}
}
data:{
"code": 0,
"message": "",
"data": {
"answer": "How is the weather tomorrow?",
"reference": {},
"id": "0379ac4c-b26b-4a44-8b77-99cebf313fdf",
"session_id": "4399c7d0b86311efac5b0242ac120005"
}
}
data:{
"code": 0,
"message": "",
"data": true
}
```



Failure: Failure:



+ 9
- 2
docs/references/python_api_reference.md View File

::: :::


--- ---
### Install the RAGFlow SDK

To install the RAGFlow SDK, run the following command in your terminal:

```bash
pip install ragflow-sdk
```


## Create dataset ## Create dataset


--- ---


## Create session with agent ## Create session with agent
*If there are parameters in the `begin` component, the session cannot be created in this way.*
```python ```python
Agent.create_session(id,rag) -> Session Agent.create_session(id,rag) -> Session
``` ```


--- ---


## Converse with agent
## Converse with agent without `begin` component


```python ```python
Session.ask(question: str, stream: bool = False) -> Optional[Message, iter[Message]] Session.ask(question: str, stream: bool = False) -> Optional[Message, iter[Message]]

+ 30
- 1
sdk/python/ragflow_sdk/modules/agent.py View File

from .base import Base from .base import Base
from .session import Session
from .session import Session,Message
import requests import requests
from typing import List from typing import List
import json



class Agent(Base): class Agent(Base):
def __init__(self,rag,res_dict): def __init__(self,rag,res_dict):
result_list.append(temp_agent) result_list.append(temp_agent)
return result_list return result_list
raise Exception(res.get("message")) raise Exception(res.get("message"))

@staticmethod
def ask(agent_id,rag,stream=True,**kwargs):
url = f"{rag.api_url}/agents/{agent_id}/completions"
headers = {"Authorization": f"Bearer {rag.user_key}"}
res = requests.post(url=url, headers=headers, json=kwargs,stream=stream)
for line in res.iter_lines():
line = line.decode("utf-8")
if line.startswith("{"):
json_data = json.loads(line)
raise Exception(json_data["message"])
if line.startswith("data:"):
json_data = json.loads(line[5:])
if json_data["data"] is not True:
if json_data["data"].get("running_status"):
continue
answer = json_data["data"]["answer"]
reference = json_data["data"]["reference"]
temp_dict = {
"content": answer,
"role": "assistant"
}
if "chunks" in reference:
chunks = reference["chunks"]
temp_dict["reference"] = chunks
message = Message(rag, temp_dict)
yield message

+ 1
- 1
sdk/python/ragflow_sdk/modules/session.py View File

raise Exception(json_data["message"]) raise Exception(json_data["message"])
if line.startswith("data:"): if line.startswith("data:"):
json_data = json.loads(line[5:]) json_data = json.loads(line[5:])
if not json_data["data"]:
if json_data["data"] is not True:
answer = json_data["data"]["answer"] answer = json_data["data"]["answer"]
reference = json_data["data"]["reference"] reference = json_data["data"]["reference"]
temp_dict = { temp_dict = {

+ 12
- 2
sdk/python/test/test_sdk_api/t_agent.py View File

from ragflow_sdk import RAGFlow
from ragflow_sdk import RAGFlow,Agent
from common import HOST_ADDRESS from common import HOST_ADDRESS
import pytest import pytest


def test_list_agents_with_success(get_api_key_fixture): def test_list_agents_with_success(get_api_key_fixture):
API_KEY=get_api_key_fixture API_KEY=get_api_key_fixture
rag = RAGFlow(API_KEY,HOST_ADDRESS) rag = RAGFlow(API_KEY,HOST_ADDRESS)
rag.list_agents()
rag.list_agents()


@pytest.mark.skip(reason="")
def test_converse_with_agent_with_success(get_api_key_fixture):
API_KEY = "ragflow-BkOGNhYjIyN2JiODExZWY5MzVhMDI0Mm"
agent_id = "ebfada2eb2bc11ef968a0242ac120006"
rag = RAGFlow(API_KEY,HOST_ADDRESS)
lang = "Chinese"
file = "How is the weather tomorrow?"
Agent.ask(agent_id=agent_id,rag=rag,lang=lang,file=file)

Loading…
Cancel
Save