diff --git a/requirements.txt b/requirements.txt
index b86f37b0..c4e9bbde 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -2,8 +2,8 @@ langchain>=0.0.302
fschat[model_worker]==0.2.30
openai
sentence_transformers
-transformers==4.33.3
-torch>=2.0.1
+transformers>=4.34
+torch>=2.0.1 # 推荐2.1
torchvision
torchaudio
fastapi>=0.103.2
diff --git a/requirements_api.txt b/requirements_api.txt
index 03ed339b..8ecb4927 100644
--- a/requirements_api.txt
+++ b/requirements_api.txt
@@ -1,8 +1,8 @@
langchain>=0.0.302
-fschat[model_worker]==0.2.30
+fschat[model_worker]>=0.2.30
openai
sentence_transformers
-transformers>=4.33.3
+transformers>=4.34
torch>=2.0.1
torchvision
torchaudio
diff --git a/server/agent/callbacks.py b/server/agent/callbacks.py
index 3901f7e9..3d143605 100644
--- a/server/agent/callbacks.py
+++ b/server/agent/callbacks.py
@@ -20,7 +20,7 @@ class Status:
agent_action: int = 4
agent_finish: int = 5
error: int = 6
- make_tool: int = 7
+ tool_finish: int = 7
class CustomAsyncIteratorCallbackHandler(AsyncIteratorCallbackHandler):
@@ -29,11 +29,19 @@ class CustomAsyncIteratorCallbackHandler(AsyncIteratorCallbackHandler):
self.queue = asyncio.Queue()
self.done = asyncio.Event()
self.cur_tool = {}
- self.out = True
async def on_tool_start(self, serialized: Dict[str, Any], input_str: str, *, run_id: UUID,
parent_run_id: UUID | None = None, tags: List[str] | None = None,
metadata: Dict[str, Any] | None = None, **kwargs: Any) -> None:
+
+ # 对于截断不能自理的大模型,我来帮他截断
+ stop_words = ["Observation:", "Thought","\"","(", "\n","\t"]
+ for stop_word in stop_words:
+ index = input_str.find(stop_word)
+ if index != -1:
+ input_str = input_str[:index]
+ break
+
self.cur_tool = {
"tool_name": serialized["name"],
"input_str": input_str,
@@ -44,13 +52,13 @@ class CustomAsyncIteratorCallbackHandler(AsyncIteratorCallbackHandler):
"final_answer": "",
"error": "",
}
+ # print("\nInput Str:",self.cur_tool["input_str"])
self.queue.put_nowait(dumps(self.cur_tool))
async def on_tool_end(self, output: str, *, run_id: UUID, parent_run_id: UUID | None = None,
tags: List[str] | None = None, **kwargs: Any) -> None:
- self.out = True
self.cur_tool.update(
- status=Status.agent_finish,
+ status=Status.tool_finish,
output_str=output.replace("Answer:", ""),
)
self.queue.put_nowait(dumps(self.cur_tool))
@@ -65,19 +73,11 @@ class CustomAsyncIteratorCallbackHandler(AsyncIteratorCallbackHandler):
async def on_llm_new_token(self, token: str, **kwargs: Any) -> None:
if token:
- if "Action" in token:
- self.out = False
- self.cur_tool.update(
- status=Status.running,
- llm_token="\n\n",
- )
- self.queue.put_nowait(dumps(self.cur_tool))
- if self.out:
- self.cur_tool.update(
+ self.cur_tool.update(
status=Status.running,
llm_token=token,
- )
- self.queue.put_nowait(dumps(self.cur_tool))
+ )
+ self.queue.put_nowait(dumps(self.cur_tool))
async def on_llm_start(self, serialized: Dict[str, Any], prompts: List[str], **kwargs: Any) -> None:
self.cur_tool.update(
@@ -87,15 +87,13 @@ class CustomAsyncIteratorCallbackHandler(AsyncIteratorCallbackHandler):
self.queue.put_nowait(dumps(self.cur_tool))
async def on_llm_end(self, response: LLMResult, **kwargs: Any) -> None:
- self.out = True
self.cur_tool.update(
status=Status.complete,
- llm_token="",
+ llm_token="\n",
)
self.queue.put_nowait(dumps(self.cur_tool))
async def on_llm_error(self, error: Exception | KeyboardInterrupt, **kwargs: Any) -> None:
- self.out = True
self.cur_tool.update(
status=Status.error,
error=str(error),
@@ -107,4 +105,10 @@ class CustomAsyncIteratorCallbackHandler(AsyncIteratorCallbackHandler):
tags: Optional[List[str]] = None,
**kwargs: Any,
) -> None:
+ # 返回最终答案
+ self.cur_tool.update(
+ status=Status.agent_finish,
+ final_answer=finish.return_values["output"],
+ )
+ self.queue.put_nowait(dumps(self.cur_tool))
self.cur_tool = {}
diff --git a/server/agent/custom_template.py b/server/agent/custom_template.py
index aa4aa112..db2d8ad7 100644
--- a/server/agent/custom_template.py
+++ b/server/agent/custom_template.py
@@ -1,10 +1,12 @@
from __future__ import annotations
from langchain.agents import Tool, AgentOutputParser
from langchain.prompts import StringPromptTemplate
-from typing import List, Union
+from typing import List, Union, Tuple, Dict
from langchain.schema import AgentAction, AgentFinish
import re
+from configs.model_config import LLM_MODEL, TEMPERATURE, HISTORY_LEN
+begin = False
class CustomPromptTemplate(StringPromptTemplate):
# The template to use
template: str
@@ -19,40 +21,78 @@ class CustomPromptTemplate(StringPromptTemplate):
for action, observation in intermediate_steps:
thoughts += action.log
thoughts += f"\nObservation: {observation}\nThought: "
- # Set the agent_scratchpad variable to that value
+ # Set the agent_scratchpad variable to that value
kwargs["agent_scratchpad"] = thoughts
# Create a tools variable from the list of tools provided
kwargs["tools"] = "\n".join([f"{tool.name}: {tool.description}" for tool in self.tools])
# Create a list of tool names for the tools provided
kwargs["tool_names"] = ", ".join([tool.name for tool in self.tools])
+ # Return the formatted templatepr
+ # print( self.template.format(**kwargs), end="\n\n")
return self.template.format(**kwargs)
-class CustomOutputParser(AgentOutputParser):
- def parse(self, llm_output: str) -> AgentFinish | AgentAction | str:
+
+class CustomOutputParser(AgentOutputParser):
+ begin: bool = False
+ def __init__(self):
+ super().__init__()
+ self.begin = True
+
+ def parse(self, llm_output: str) -> AgentFinish | tuple[dict[str, str], str] | AgentAction:
# Check if agent should finish
+ support_agent = ["gpt","Qwen","qwen-api","baichuan-api"]
+ if not any(agent in LLM_MODEL for agent in support_agent) and self.begin:
+ self.begin = False
+ stop_words = ["Observation:"]
+ min_index = len(llm_output)
+ for stop_word in stop_words:
+ index = llm_output.find(stop_word)
+ if index != -1 and index < min_index:
+ min_index = index
+ llm_output = llm_output[:min_index]
+
if "Final Answer:" in llm_output:
+ output = llm_output.split("Final Answer:", 1)[-1].strip()
+ self.begin = True
return AgentFinish(
# Return values is generally always a dictionary with a single `output` key
# It is not recommended to try anything else at the moment :)
- return_values={"output": llm_output.replace("Final Answer:", "").strip()},
+ # return_values={"output": llm_output.replace("Final Answer:", "").strip()},
+ return_values={"output": output},
log=llm_output,
)
+
# Parse out the action and action input
- regex = r"Action\s*\d*\s*:(.*?)\nAction\s*\d*\s*Input\s*\d*\s*:[\s]*(.*)"
- match = re.search(regex, llm_output, re.DOTALL)
- if not match:
+ parts = llm_output.split("Action:")
+ if len(parts) < 2:
return AgentFinish(
return_values={"output": f"调用agent失败: `{llm_output}`"},
log=llm_output,
)
- action = match.group(1).strip()
- action_input = match.group(2)
+
+ action = parts[1].split("Action Input:")[0].strip()
+ action_input = parts[1].split("Action Input:")[1].strip()
+
+ # 原来的正则化检查方式
+ # regex = r"Action\s*\d*\s*:(.*?)\nAction\s*\d*\s*Input\s*\d*\s*:[\s]*(.*)"
+ # print("llm_output",llm_output)
+ # match = re.search(regex, llm_output, re.DOTALL)
+ # print("match",match)
+ # if not match:
+ # return AgentFinish(
+ # return_values={"output": f"调用agent失败: `{llm_output}`"},
+ # log=llm_output,
+ # )
+ # action = match.group(1).strip()
+ # action_input = match.group(2)
+
# Return the action and action input
+
try:
ans = AgentAction(
- tool=action,
- tool_input=action_input.strip(" ").strip('"'),
- log=llm_output
+ tool=action,
+ tool_input=action_input.strip(" ").strip('"'),
+ log=llm_output
)
return ans
except:
@@ -60,6 +100,3 @@ class CustomOutputParser(AgentOutputParser):
return_values={"output": f"调用agent失败: `{llm_output}`"},
log=llm_output,
)
-
-
-
diff --git a/server/agent/math.py b/server/agent/math.py
index a00667af..b4056d07 100644
--- a/server/agent/math.py
+++ b/server/agent/math.py
@@ -1,11 +1,14 @@
+## 单独运行的时候需要添加
+import sys
+import os
+sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
+
from langchain.prompts import PromptTemplate
from langchain.chains import LLMMathChain
-from server.utils import wrap_done, get_ChatOpenAI
+from server.utils import get_ChatOpenAI
from configs.model_config import LLM_MODEL, TEMPERATURE
-from langchain.chat_models import ChatOpenAI
-from langchain.callbacks.manager import CallbackManagerForToolRun
-
-_PROMPT_TEMPLATE = """将数学问题翻译成可以使用Python的numexpr库执行的表达式。使用运行此代码的输出来回答问题。
+_PROMPT_TEMPLATE = """
+将数学问题翻译成可以使用Python的numexpr库执行的表达式。使用运行此代码的输出来回答问题。
问题: ${{包含数学问题的问题。}}
```text
${{解决问题的单行数学表达式}}
@@ -68,3 +71,8 @@ def calculate(query: str):
llm_math = LLMMathChain.from_llm(model, verbose=True, prompt=PROMPT)
ans = llm_math.run(query)
return ans
+
+if __name__ == "__main__":
+ result = calculate("2的三次方")
+ print("答案:",result)
+
diff --git a/server/agent/tools.py b/server/agent/tools.py
index 2d86f288..0f94529f 100644
--- a/server/agent/tools.py
+++ b/server/agent/tools.py
@@ -20,12 +20,12 @@ tools = [
Tool.from_function(
func=translate,
name="翻译工具",
- description="翻译各种语言"
+ description="如果你无法访问互联网,并且需要翻译各种语言,应该使用这个工具"
),
Tool.from_function(
func=weathercheck,
name="天气查询工具",
- description="查询天气",
+ description="如果你无法访问互联网,并需要查询中国各地未来24小时的天气,你应该使用这个工具,每轮对话仅能使用一次",
),
Tool.from_function(
func=shell,
@@ -35,12 +35,12 @@ tools = [
Tool.from_function(
func=search_knowledge,
name="知识库查询工具",
- description="使用西交利物浦大学大数据专业的本专业数据库来解答问题",
+ description="访问知识库来获取答案",
),
Tool.from_function(
func=search_internet,
name="互联网查询工具",
- description="访问Bing互联网来解答问题",
+ description="如果你无法访问互联网,这个工具可以帮助你访问Bing互联网来解答问题",
),
]
diff --git a/server/agent/translator.py b/server/agent/translator.py
index d92dd1fc..96b4c8f8 100644
--- a/server/agent/translator.py
+++ b/server/agent/translator.py
@@ -1,11 +1,10 @@
-from langchain.prompts import PromptTemplate
-from langchain.chains import LLMChain
+## 单独运行的时候需要添加
import sys
import os
-
-from server.utils import get_ChatOpenAI
-
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
+from langchain.prompts import PromptTemplate
+from langchain.chains import LLMChain
+from server.utils import get_ChatOpenAI
from langchain.chains.llm_math.prompt import PROMPT
from configs.model_config import LLM_MODEL,TEMPERATURE
@@ -16,25 +15,12 @@ _PROMPT_TEMPLATE = '''
2. 无论提供的是陈述句或疑问句,只进行翻译
3. 不添加与原文无关的内容
-原文: ${{用户需要翻译的原文和目标语言}}
-{question}
-```output
-${{翻译结果}}
-```
-答案: ${{答案}}
+问题: ${{用户需要翻译的原文和目标语言}}
+答案: 你翻译结果
+
+现在,这是我的问题:
+问题: {question}
-以下是两个例子
-问题: 翻译13成英语
-```text
-13 英语
-```output
-thirteen
-以下是两个例子
-问题: 翻译 我爱你 成法语
-```text
-13 法语
-```output
-Je t'aime.
'''
PROMPT = PromptTemplate(
@@ -51,5 +37,8 @@ def translate(query: str):
)
llm_translate = LLMChain(llm=model, prompt=PROMPT)
ans = llm_translate.run(query)
+ return ans
- return ans
\ No newline at end of file
+if __name__ == "__main__":
+ result = translate("Can Love remember the question and the answer? 这句话如何诗意的翻译成中文")
+ print("答案:",result)
\ No newline at end of file
diff --git a/server/agent/weather.py b/server/agent/weather.py
index 3e5a37bf..54f196cf 100644
--- a/server/agent/weather.py
+++ b/server/agent/weather.py
@@ -1,10 +1,12 @@
-## 使用和风天气API查询天气
+## 使用和风天气API查询天气,这个模型仅仅对免费的API进行了适配
+## 这个模型的提示词非常复杂,我们推荐使用GPT4模型进行运行
+
from __future__ import annotations
## 单独运行的时候需要添加
import sys
import os
-# sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
+sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from server.utils import get_ChatOpenAI
@@ -26,9 +28,71 @@ from langchain.schema.language_model import BaseLanguageModel
import requests
from typing import List, Any, Optional
from configs.model_config import LLM_MODEL, TEMPERATURE
+from datetime import datetime
+from langchain.prompts import PromptTemplate
+
## 使用和风天气API查询天气
-KEY = ""
+KEY = "ac880e5a877042809ac7ffdd19d95b0d"
+
+
+
+_PROMPT_TEMPLATE = """
+用户会提出一个关于天气的问题,你的目标是拆分出用户问题中的区,市 并按照我提供的工具回答。
+例如 用户提出的问题是: 上海浦东未来1小时天气情况?
+则 提取的市和区是: 上海 浦东
+如果用户提出的问题是: 上海未来1小时天气情况?
+则 提取的市和区是: 上海 None
+请注意以下内容:
+1. 如果你没有找到区的内容,则一定要使用 None 替代,否则程序无法运行
+2. 如果用户没有指定市 则直接返回缺少信息
+
+问题: ${{用户的问题}}
+
+你的回答格式应该按照下面的内容,请注意,格式内的```text 等标记都必须输出,这是我用来提取答案的标记。
+```text
+
+${{拆分的市和区,中间用空格隔开}}
+```
+... weathercheck(市 区)...
+```output
+
+${{提取后的答案}}
+```
+答案: ${{答案}}
+
+
+
+这是一个例子:
+问题: 上海浦东未来1小时天气情况?
+
+
+```text
+上海 浦东
+```
+...weathercheck(上海 浦东)...
+
+```output
+预报时间: 1小时后
+具体时间: 今天 18:00
+温度: 24°C
+天气: 多云
+风向: 西南风
+风速: 7级
+湿度: 88%
+降水概率: 16%
+
+Answer: 上海浦东一小时后的天气是多云。
+
+现在,这是我的问题:
+
+问题: {question}
+"""
+PROMPT = PromptTemplate(
+ input_variables=["question"],
+ template=_PROMPT_TEMPLATE,
+)
+
def get_city_info(location, adm, key):
base_url = 'https://geoapi.qweather.com/v2/city/lookup?'
@@ -38,12 +102,9 @@ def get_city_info(location, adm, key):
return data
-from datetime import datetime
-
-
-def format_weather_data(data):
+def format_weather_data(data,place):
hourly_forecast = data['hourly']
- formatted_data = ''
+ formatted_data = f"\n 这是查询到的关于{place}未来24小时的天气信息: \n"
for forecast in hourly_forecast:
# 将预报时间转换为datetime对象
forecast_time = datetime.strptime(forecast['fxTime'], '%Y-%m-%dT%H:%M%z')
@@ -71,12 +132,11 @@ def format_weather_data(data):
elif hours_diff >= 24:
# 如果超过24小时,转换为天数
days_diff = hours_diff // 24
- hours_diff_str = str(int(days_diff)) + '天后'
+ hours_diff_str = str(int(days_diff)) + '天'
else:
- hours_diff_str = str(int(hours_diff)) + '小时后'
+ hours_diff_str = str(int(hours_diff)) + '小时'
# 将预报时间和当前时间的差值添加到输出中
- formatted_data += '预报时间: ' + hours_diff_str + '\n'
- formatted_data += '具体时间: ' + forecast_time_str + '\n'
+ formatted_data += '预报时间: ' + forecast_time_str + ' 距离现在有: ' + hours_diff_str + '\n'
formatted_data += '温度: ' + forecast['temp'] + '°C\n'
formatted_data += '天气: ' + forecast['text'] + '\n'
formatted_data += '风向: ' + forecast['windDir'] + '\n'
@@ -84,53 +144,54 @@ def format_weather_data(data):
formatted_data += '湿度: ' + forecast['humidity'] + '%\n'
formatted_data += '降水概率: ' + forecast['pop'] + '%\n'
# formatted_data += '降水量: ' + forecast['precip'] + 'mm\n'
- formatted_data += '\n\n'
+ formatted_data += '\n'
return formatted_data
-def get_weather(key, location_id, time: str = "24"):
- if time:
- url = "https://devapi.qweather.com/v7/weather/" + time + "h?"
- else:
- time = "3" # 免费订阅只能查看3天的天气
- url = "https://devapi.qweather.com/v7/weather/" + time + "d?"
+def get_weather(key, location_id,place):
+ url = "https://devapi.qweather.com/v7/weather/24h?"
params = {
'location': location_id,
'key': key,
}
response = requests.get(url, params=params)
data = response.json()
- return format_weather_data(data)
+ return format_weather_data(data,place)
def split_query(query):
parts = query.split()
- location = parts[0] if parts[0] != 'None' else parts[1]
- adm = parts[1]
- time = parts[2]
- return location, adm, time
+ adm = parts[0]
+ location = parts[1] if parts[1] != 'None' else adm
+ return location, adm
def weather(query):
- location, adm, time = split_query(query)
+ location, adm= split_query(query)
key = KEY
- if time != "None" and int(time) > 24:
- return "只能查看24小时内的天气,无法回答"
- if time == "None":
- time = "24" # 免费的版本只能24小时内的天气
if key == "":
return "请先在代码中填入和风天气API Key"
- city_info = get_city_info(location=location, adm=adm, key=key)
- location_id = city_info['location'][0]['id']
- weather_data = get_weather(key=key, location_id=location_id, time=time)
- return weather_data
-
+ try:
+ city_info = get_city_info(location=location, adm=adm, key=key)
+ location_id = city_info['location'][0]['id']
+ place = adm + "市" + location + "区"
+ weather_data = get_weather(key=key, location_id=location_id,place=place)
+ return weather_data + "以上是查询到的天气信息,请你查收\n"
+ except KeyError:
+ try:
+ city_info = get_city_info(location=adm, adm=adm, key=key)
+ location_id = city_info['location'][0]['id']
+ place = adm + "市"
+ weather_data = get_weather(key=key, location_id=location_id,place=place)
+ return weather_data + "重要提醒:用户提供的市和区中,区的信息不存在,或者出现错别字,因此该信息是关于市的天气,请你查收\n"
+ except KeyError:
+ return "输入的地区不存在,无法提供天气预报"
class LLMWeatherChain(Chain):
llm_chain: LLMChain
llm: Optional[BaseLanguageModel] = None
"""[Deprecated] LLM wrapper to use."""
- prompt: BasePromptTemplate
+ prompt: BasePromptTemplate = PROMPT
"""[Deprecated] Prompt to use to translate to python if necessary."""
input_key: str = "question" #: :meta private:
output_key: str = "answer" #: :meta private:
@@ -175,7 +236,8 @@ class LLMWeatherChain(Chain):
output = weather(expression)
except Exception as e:
output = "输入的信息有误,请再次尝试"
- # raise ValueError(f"错误: {expression},输入的信息不对")
+ return {self.output_key: output}
+ raise ValueError(f"错误: {expression},输入的信息不对")
return output
@@ -198,7 +260,8 @@ class LLMWeatherChain(Chain):
elif "Answer:" in llm_output:
answer = "Answer: " + llm_output.split("Answer:")[-1]
else:
- raise ValueError(f"unknown format from LLM: {llm_output}")
+ return {self.output_key: f"输入的格式不对: {llm_output},应该输入 (市 区)的组合"}
+ # raise ValueError(f"unknown format from LLM: {llm_output}")
return {self.output_key: answer}
async def _aprocess_llm_result(
@@ -259,92 +322,13 @@ class LLMWeatherChain(Chain):
def from_llm(
cls,
llm: BaseLanguageModel,
- prompt: BasePromptTemplate,
+ prompt: BasePromptTemplate = PROMPT,
**kwargs: Any,
) -> LLMWeatherChain:
llm_chain = LLMChain(llm=llm, prompt=prompt)
return cls(llm_chain=llm_chain, **kwargs)
-from langchain.prompts import PromptTemplate
-
-_PROMPT_TEMPLATE = """用户将会向您咨询天气问题,您不需要自己回答天气问题,而是将用户提问的信息提取出来区,市和时间三个元素后使用我为你编写好的工具进行查询并返回结果,格式为 区+市+时间 每个元素用空格隔开。如果缺少信息,则用 None 代替。
-问题: ${{用户的问题}}
-
-```text
-
-${{拆分的区,市和时间}}
-```
-
-... weather(提取后的关键字,用空格隔开)...
-```output
-
-${{提取后的答案}}
-```
-答案: ${{答案}}
-
-这是两个例子:
-问题: 上海浦东未来1小时天气情况?
-
-```text
-浦东 上海 1
-```
-...weather(浦东 上海 1)...
-
-```output
-
-预报时间: 1小时后
-具体时间: 今天 18:00
-温度: 24°C
-天气: 多云
-风向: 西南风
-风速: 7级
-湿度: 88%
-降水概率: 16%
-
-Answer:
-预报时间: 1小时后
-具体时间: 今天 18:00
-温度: 24°C
-天气: 多云
-风向: 西南风
-风速: 7级
-湿度: 88%
-降水概率: 16%
-
-问题: 北京市朝阳区未来24小时天气如何?
-```text
-
-朝阳 北京 24
-```
-...weather(朝阳 北京 24)...
-```output
-预报时间: 23小时后
-具体时间: 明天 17:00
-温度: 26°C
-天气: 霾
-风向: 西南风
-风速: 11级
-湿度: 65%
-降水概率: 20%
-Answer:
-预报时间: 23小时后
-具体时间: 明天 17:00
-温度: 26°C
-天气: 霾
-风向: 西南风
-风速: 11级
-湿度: 65%
-降水概率: 20%
-
-现在,这是我的问题:
-问题: {question}
-"""
-PROMPT = PromptTemplate(
- input_variables=["question"],
- template=_PROMPT_TEMPLATE,
-)
-
def weathercheck(query: str):
model = get_ChatOpenAI(
@@ -357,9 +341,4 @@ def weathercheck(query: str):
return ans
if __name__ == '__main__':
-
- ## 检测api是否能正确返回
- query = "上海浦东未来1小时天气情况"
- # ans = weathercheck(query)
- ans = weather("浦东 上海 1")
- print(ans)
\ No newline at end of file
+ result = weathercheck("苏州工姑苏区今晚热不热?")
\ No newline at end of file
diff --git a/server/chat/agent_chat.py b/server/chat/agent_chat.py
index c08ae81c..df0ce8b4 100644
--- a/server/chat/agent_chat.py
+++ b/server/chat/agent_chat.py
@@ -53,13 +53,11 @@ async def agent_chat(query: str = Body(..., description="用户输入", examples
agent = LLMSingleActionAgent(
llm_chain=llm_chain,
output_parser=output_parser,
- stop=["Observation:", "Observation:\n", "<|im_end|>"], # Qwen模型中使用这个
- # stop=["Observation:", "Observation:\n"], # 其他模型,注意模板
+ stop=["\nObservation:", "Observation:", "<|im_end|>"], # Qwen模型中使用这个
allowed_tools=tool_names,
)
# 把history转成agent的memory
memory = ConversationBufferWindowMemory(k=HISTORY_LEN * 2)
-
for message in history:
# 检查消息的角色
if message.role == 'user':
@@ -74,29 +72,41 @@ async def agent_chat(query: str = Body(..., description="用户输入", examples
memory=memory,
)
input_msg = History(role="user", content="{{ input }}").to_msg_template(False)
- task = asyncio.create_task(wrap_done(
- agent_executor.acall(query, callbacks=[callback], include_run_info=True),
- callback.done),
- )
+ while True:
+ try:
+ task = asyncio.create_task(wrap_done(
+ agent_executor.acall(query, callbacks=[callback], include_run_info=True),
+ callback.done))
+ break
+ except:
+ pass
if stream:
async for chunk in callback.aiter():
tools_use = []
# Use server-sent-events to stream the response
data = json.loads(chunk)
- if data["status"] == Status.error:
- tools_use.append("工具调用失败:\n" + data["error"])
- yield json.dumps({"tools": tools_use}, ensure_ascii=False)
- yield json.dumps({"answer": "(工具调用失败,请查看工具栏报错) \n\n"}, ensure_ascii=False)
if data["status"] == Status.start or data["status"] == Status.complete:
continue
- if data["status"] == Status.agent_action:
- yield json.dumps({"answer": "(正在使用工具,请注意工具栏变化) \n\n"}, ensure_ascii=False)
- if data["status"] == Status.agent_finish:
+ if data["status"] == Status.error:
tools_use.append("工具名称: " + data["tool_name"])
+ tools_use.append("工具状态: " + "调用失败")
+ tools_use.append("错误信息: " + data["error"])
+ tools_use.append("重新开始尝试")
+ tools_use.append("\n```\n")
+ yield json.dumps({"tools": tools_use}, ensure_ascii=False)
+ if data["status"] == Status.agent_action:
+ yield json.dumps({"answer": "\n\n```\n\n"}, ensure_ascii=False)
+ if data["status"] == Status.tool_finish:
+ tools_use.append("工具名称: " + data["tool_name"])
+ tools_use.append("工具状态: " + "调用成功")
tools_use.append("工具输入: " + data["input_str"])
tools_use.append("工具输出: " + data["output_str"])
+ tools_use.append("\n```\n")
yield json.dumps({"tools": tools_use}, ensure_ascii=False)
- yield json.dumps({"answer": data["llm_token"]}, ensure_ascii=False)
+ if data["status"] == Status.agent_finish:
+ yield json.dumps({"final_answer": data["final_answer"]}, ensure_ascii=False)
+ else:
+ yield json.dumps({"answer": data["llm_token"]}, ensure_ascii=False)
else:
pass
diff --git a/server/model_workers/base.py b/server/model_workers/base.py
index 515c5db9..ea141046 100644
--- a/server/model_workers/base.py
+++ b/server/model_workers/base.py
@@ -44,7 +44,8 @@ class ApiModelWorker(BaseModelWorker):
def count_token(self, params):
# TODO:需要完善
- print("count token")
+ # print("count token")
+ print("\n\n\n")
print(params)
prompt = params["prompt"]
return {"count": len(str(prompt)), "error_code": 0}
diff --git a/server/model_workers/zhipu.py b/server/model_workers/zhipu.py
index 18cec5b5..321f01f6 100644
--- a/server/model_workers/zhipu.py
+++ b/server/model_workers/zhipu.py
@@ -26,10 +26,10 @@ class ChatGLMWorker(ApiModelWorker):
# 这里的是chatglm api的模板,其它API的conv_template需要定制
self.conv = conv.Conversation(
name=self.model_names[0],
- system_message="你是一个聪明、对人类有帮助的人工智能,你可以对人类提出的问题给出有用、详细、礼貌的回答。",
+ system_message="你是一个聪明的助手,请根据用户的提示来完成任务",
messages=[],
roles=["Human", "Assistant"],
- sep="\n### ",
+ sep="\n###",
stop_str="###",
)
@@ -57,7 +57,7 @@ class ChatGLMWorker(ApiModelWorker):
def get_embeddings(self, params):
# TODO: 支持embeddings
print("embedding")
- print(params)
+ # print(params)
if __name__ == "__main__":
diff --git a/startup.py b/startup.py
index 419c1598..24099bef 100644
--- a/startup.py
+++ b/startup.py
@@ -158,7 +158,7 @@ def create_model_worker_app(log_level: str = "INFO", **kwargs) -> FastAPI:
else:
from fastchat.serve.model_worker import app, GptqConfig, AWQConfig, ModelWorker
args.gpus = "0" # GPU的编号,如果有多个GPU,可以设置为"0,1,2,3"
- args.max_gpu_memory = "20GiB"
+ args.max_gpu_memory = "22GiB"
args.num_gpus = 1 # model worker的切分是model并行,这里填写显卡的数量
args.load_8bit = False
@@ -170,7 +170,7 @@ def create_model_worker_app(log_level: str = "INFO", **kwargs) -> FastAPI:
args.awq_ckpt = None
args.awq_wbits = 16
args.awq_groupsize = -1
- args.model_names = []
+ args.model_names = [""]
args.conv_template = None
args.limit_worker_concurrency = 5
args.stream_interval = 2
diff --git a/webui_pages/dialogue/dialogue.py b/webui_pages/dialogue/dialogue.py
index b6306946..7af2dc55 100644
--- a/webui_pages/dialogue/dialogue.py
+++ b/webui_pages/dialogue/dialogue.py
@@ -7,7 +7,6 @@ import os
from configs import LLM_MODEL, TEMPERATURE
from server.utils import get_model_worker_config
from typing import List, Dict
-
chat_box = ChatBox(
assistant_avatar=os.path.join(
"img",
@@ -16,6 +15,9 @@ chat_box = ChatBox(
)
+
+
+
def get_messages_history(history_len: int, content_in_expander: bool = False) -> List[Dict]:
'''
返回消息历史。
@@ -104,6 +106,8 @@ def dialogue_page(api: ApiRequest):
temperature = st.slider("Temperature:", 0.0, 1.0, TEMPERATURE, 0.05)
history_len = st.number_input("历史对话轮数:", 0, 20, HISTORY_LEN)
+ LLM_MODEL_WEBUI = llm_model
+ TEMPERATURE_WEBUI = temperature
def on_kb_change():
st.toast(f"已加载知识库: {st.session_state.selected_kb}")
@@ -155,9 +159,17 @@ def dialogue_page(api: ApiRequest):
elif dialogue_mode == "自定义Agent问答":
chat_box.ai_say([
- f"正在思考和寻找工具 ...",])
+ f"正在思考...",
+ Markdown("...", in_expander=True, title="思考过程", state="complete"),
+ ])
text = ""
- element_index = 0
+ ans = ""
+ support_agent = ["gpt", "Qwen", "qwen-api", "baichuan-api"] # 目前支持agent的模型
+ if not any(agent in llm_model for agent in support_agent):
+ ans += "正在思考... \n\n 改模型并没有进行Agent对齐,无法正常使用Agent功能!\n\n\n请更换 GPT4或Qwen-14B等支持Agent的模型获得更好的体验! \n\n\n"
+ chat_box.update_msg(ans, element_index=0, streaming=False)
+
+
for d in api.agent_chat(prompt,
history=history,
model=llm_model,
@@ -169,14 +181,17 @@ def dialogue_page(api: ApiRequest):
if error_msg := check_error_msg(d): # check whether error occured
st.error(error_msg)
+ elif chunk := d.get("final_answer"):
+ ans += chunk
+ chat_box.update_msg(ans, element_index=0)
elif chunk := d.get("answer"):
text += chunk
- chat_box.update_msg(text, element_index=0)
+ chat_box.update_msg(text, element_index=1)
elif chunk := d.get("tools"):
- element_index += 1
- chat_box.insert_msg(Markdown("...", in_expander=True, title="使用工具...", state="complete"))
- chat_box.update_msg("\n\n".join(d.get("tools", [])), element_index=element_index, streaming=False)
- chat_box.update_msg(text, element_index=0, streaming=False)
+ text += "\n\n".join(d.get("tools", []))
+ chat_box.update_msg(text, element_index=1)
+ chat_box.update_msg(ans, element_index=0, streaming=False)
+ chat_box.update_msg(text, element_index=1, streaming=False)
elif dialogue_mode == "知识库问答":
chat_box.ai_say([
f"正在查询知识库 `{selected_kb}` ...",
diff --git a/webui_pages/utils.py b/webui_pages/utils.py
index a2113685..4a26f200 100644
--- a/webui_pages/utils.py
+++ b/webui_pages/utils.py
@@ -250,7 +250,7 @@ class ApiRequest:
logger.error(f'{e.__class__.__name__}: {msg}',
exc_info=e if log_verbose else None)
else:
- print(chunk, end="", flush=True)
+ # print(chunk, end="", flush=True)
yield chunk
except httpx.ConnectError as e:
msg = f"无法连接API服务器,请确认 ‘api.py’ 已正常启动。({e})"