+
{items.map((item, index) => 1}
From c5b1d85de0e85f49928a4be7caf79a9a40b6e55e Mon Sep 17 00:00:00 2001
From: GuoQing Zhang
Date: Tue, 9 Jul 2024 17:27:05 +0800
Subject: [PATCH 6/7] =?UTF-8?q?feat:=20=E5=8A=A9=E6=89=8B=E7=9A=84?=
=?UTF-8?q?=E6=A8=A1=E5=9E=8B=E9=85=8D=E7=BD=AE=E6=94=AF=E6=8C=81react?=
=?UTF-8?q?=E6=A8=A1=E5=BC=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../bisheng/api/services/assistant_agent.py | 34 +++++++++++++++----
src/backend/bisheng/api/v2/assistant.py | 5 +++
src/backend/bisheng/initdb_config.yaml | 9 +++--
3 files changed, 37 insertions(+), 11 deletions(-)
create mode 100644 src/backend/bisheng/api/v2/assistant.py
diff --git a/src/backend/bisheng/api/services/assistant_agent.py b/src/backend/bisheng/api/services/assistant_agent.py
index 347607ef1..ab75dd0ee 100644
--- a/src/backend/bisheng/api/services/assistant_agent.py
+++ b/src/backend/bisheng/api/services/assistant_agent.py
@@ -63,6 +63,11 @@ def __init__(self, assistant_info: Assistant, chat_id: str):
self.tools: List[BaseTool] = []
self.offline_flows = []
self.agent: ConfigurableAssistant | None = None
+ self.agent_executor_dict = {
+ 'ReAct': 'get_react_agent_executor',
+ 'function call': 'get_openai_functions_agent_executor',
+ }
+ self.current_agent_executor = None
self.llm: BaseLanguageModel | None = None
self.llm_agent_executor = None
self.knowledge_skill_path = str(Path(__file__).parent / 'knowledge_skill.json')
@@ -281,6 +286,9 @@ async def init_agent(self):
# 引入agent执行参数
agent_executor_params = self.get_agent_executor()
agent_executor_type = self.llm_agent_executor or agent_executor_params.pop('type')
+ self.current_agent_executor = agent_executor_type
+ # 做转换
+ agent_executor_type = self.agent_executor_dict.get(agent_executor_type, agent_executor_type)
prompt = self.assistant.prompt
if self.assistant.model_name.startswith("command-r"):
@@ -334,12 +342,6 @@ async def run(self, query: str, chat_history: List = None, callback: Callbacks =
"""
运行智能体对话
"""
- if chat_history:
- chat_history.append(HumanMessage(content=query))
- inputs = chat_history
- else:
- inputs = [HumanMessage(content=query)]
-
# 假回调,将已下线的技能回调给前端
for one in self.offline_flows:
if callback is not None:
@@ -348,6 +350,14 @@ async def run(self, query: str, chat_history: List = None, callback: Callbacks =
'name': one,
}, input_str='flow if offline', run_id=run_id)
await callback[0].on_tool_end(output='flow is offline', name=one, run_id=run_id)
+ if self.current_agent_executor == 'ReAct':
+ return await self.react_run(query, chat_history, callback)
+
+ if chat_history:
+ chat_history.append(HumanMessage(content=query))
+ inputs = chat_history
+ else:
+ inputs = [HumanMessage(content=query)]
result = await self.agent.ainvoke(inputs, config=RunnableConfig(callbacks=callback))
# 包含了history,将history排除, 默认取最后一个为最终结果
res = [result[-1]]
@@ -364,3 +374,15 @@ async def run(self, query: str, chat_history: List = None, callback: Callbacks =
except Exception as e:
logger.error(f"record assistant history error: {str(e)}")
return res
+
+ async def react_run(self, query: str, chat_history: List = None, callback: Callbacks = None):
+ """ react 模式的输入和执行 """
+ result = await self.agent.ainvoke({
+ 'input': query,
+ 'chat_history': chat_history
+ }, config=RunnableConfig(callbacks=callback))
+ print(result)
+ output = result['agent_outcome'].return_values['output']
+ if isinstance(output, dict):
+ output = output['text']
+ return [AIMessage(content=output)]
diff --git a/src/backend/bisheng/api/v2/assistant.py b/src/backend/bisheng/api/v2/assistant.py
new file mode 100644
index 000000000..eb237948c
--- /dev/null
+++ b/src/backend/bisheng/api/v2/assistant.py
@@ -0,0 +1,5 @@
+# 免登录的助手相关接口
+
+
+router = APIRouter(prefix='/chat', tags=['AssistantOpenApi'])
+
diff --git a/src/backend/bisheng/initdb_config.yaml b/src/backend/bisheng/initdb_config.yaml
index 1aa6adc5b..fe4dda86f 100644
--- a/src/backend/bisheng/initdb_config.yaml
+++ b/src/backend/bisheng/initdb_config.yaml
@@ -90,10 +90,9 @@ env:
# 智能助手相关配置
gpts:
agent_executor:
- # 默认agent的executor, 如果模型里有配置优先用模型的
- type: 'get_openai_functions_agent_executor'
- interrupt_before_action: False
- recursion_limit: 50
+ # 默认agent的executor, 支持模型里单独配置对应的agent_executor_type; react/function call
+ type: 'function call' # 支持function call的模型使用此agent配置
+ # type: 'ReAct' # 不支持function call的模型使用此agent配置
# 助手可选大模型列表,第一个为默认模型
llms:
- type: 'ChatOpenAI'
@@ -110,7 +109,7 @@ gpts:
model_name: 'Qwen-1_8B-Chat'
host_base_url: 'http://192.168.106.12:9001/v2.1/models/Qwen-1_8B-Chat/infer'
temperature: 0.3
- agent_executor_type: 'get_qwen_local_functions_agent_executor'
+ agent_executor_type: 'React'
# 预置工具所需的配置
tools:
# 画图工具配置,引用公共的openai配置
From e793b309404ecb1f5093fdcc57555b44ee5e1a0d Mon Sep 17 00:00:00 2001
From: GuoQing Zhang
Date: Tue, 9 Jul 2024 17:42:56 +0800
Subject: [PATCH 7/7] =?UTF-8?q?feat:=20=E6=AF=8F=E6=AC=A1=E9=97=AE?=
=?UTF-8?q?=E7=AD=94=E6=97=B6=E6=B8=85=E7=A9=BA=E6=B5=81=E5=BC=8F=E8=BE=93?=
=?UTF-8?q?=E5=87=BA=E9=98=9F=E5=88=97=EF=BC=8C=E9=98=B2=E6=AD=A2=E6=B1=A1?=
=?UTF-8?q?=E6=9F=93=E6=9C=AC=E6=AC=A1=E7=9A=84=E5=9B=9E=E7=AD=94?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/backend/bisheng/chat/client.py | 10 ++++++++--
src/backend/bisheng/chat/handlers.py | 4 ++++
2 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/src/backend/bisheng/chat/client.py b/src/backend/bisheng/chat/client.py
index 3aff9599c..e3fc46599 100644
--- a/src/backend/bisheng/chat/client.py
+++ b/src/backend/bisheng/chat/client.py
@@ -43,7 +43,7 @@ def __init__(self, request: Request, client_key: str, client_id: str, chat_id: s
self.gpts_conf = settings.get_from_db('gpts')
# 异步任务列表
self.task_ids = []
- # 流式输出的队列,用来接受流式输出的内容
+ # 流式输出的队列,用来接受流式输出的内容,每次处理新的question时都清空
self.stream_queue = Queue()
async def send_message(self, message: str):
@@ -217,9 +217,13 @@ async def stop_handle_message(self, message: Dict[any, any]):
# 有流式输出内容的话,记录流式输出内容到数据库
if answer.strip():
res = await self.add_message('bot', answer, 'answer', 'break_answer')
- await self.send_response('answer', 'end', answer, message_id=res.id if res else None)
+ await self.send_response('answer', 'end', '', message_id=res.id if res else None)
await self.send_response('processing', 'close', '')
+ async def clear_stream_queue(self):
+ while not self.stream_queue.empty():
+ self.stream_queue.get()
+
async def handle_gpts_message(self, message: Dict[any, any]):
if not message:
return
@@ -228,6 +232,8 @@ async def handle_gpts_message(self, message: Dict[any, any]):
await self.stop_handle_message(message)
return
+ # 清空流式队列,防止把上一次的回答,污染本次回答
+ await self.clear_stream_queue()
inputs = message.get('inputs', {})
input_msg = inputs.get('input')
if not input_msg:
diff --git a/src/backend/bisheng/chat/handlers.py b/src/backend/bisheng/chat/handlers.py
index 70d232a23..431beaa23 100644
--- a/src/backend/bisheng/chat/handlers.py
+++ b/src/backend/bisheng/chat/handlers.py
@@ -44,6 +44,10 @@ async def dispatch_task(self, session: ChatManager, client_id: str, chat_id: str
action = 'default'
if action not in self.handler_dict:
raise Exception(f'unknown action {action}')
+ if action != 'stop':
+ # 清空流式输出队列,防止上次的回答污染本次回答
+ while not self.stream_queue.empty():
+ self.stream_queue.get()
await self.handler_dict[action](session, client_id, chat_id, payload, user_id)
logger.info(f'dispatch_task done timecost={time.time() - start_time}')