1) Use UserConfig to change system default LLM model name

2)  Support GPT4-Turbo JSON resp format
This commit is contained in:
Liu Zhicong
2023-11-13 16:07:33 -08:00
parent 763360b305
commit 5fe3073cb6
6 changed files with 86 additions and 27 deletions
+13 -8
View File
@@ -518,15 +518,17 @@ class AIAgent:
final_result = task_result.result_str final_result = task_result.result_str
if final_result is not None: if final_result is not None:
if final_result[0] == "{": llm_result : LLMResult = LLMResult.from_str(final_result)
llm_result = LLMResult.from_json_str(final_result)
else:
llm_result : LLMResult = LLMResult.from_str(final_result)
else: else:
llm_result = LLMResult() llm_result = LLMResult()
llm_result.state = "ignore" llm_result.state = "ignore"
final_result = llm_result.resp if llm_result.resp is None:
if llm_result.raw_resp:
final_result = json.dumps(llm_result.raw_resp)
else:
final_result = llm_result.resp
await workspace.exec_op_list(llm_result.op_list,self.agent_id) await workspace.exec_op_list(llm_result.op_list,self.agent_id)
@@ -866,7 +868,7 @@ class AIAgent:
prompt.append(todo.detail) prompt.append(todo.detail)
prompt.append(todo.result) prompt.append(todo.result)
task_result:ComputeTaskResult = await self._do_llm_complection(prompt,workspace.get_inner_functions()) task_result:ComputeTaskResult = await self._do_llm_complection(prompt,workspace.get_inner_functions(),None,True)
if task_result.result_code != ComputeTaskResultCode.OK: if task_result.result_code != ComputeTaskResultCode.OK:
logger.error(f"_llm_check_todo compute error:{task_result.error_str}") logger.error(f"_llm_check_todo compute error:{task_result.error_str}")
@@ -1129,10 +1131,13 @@ class AIAgent:
return known_info,result_token_len return known_info,result_token_len
return None,0 return None,0
async def _do_llm_complection(self,prompt:AgentPrompt,inner_functions:dict=None,org_msg:AgentMsg=None) -> ComputeTaskResult: async def _do_llm_complection(self,prompt:AgentPrompt,inner_functions:dict=None,org_msg:AgentMsg=None,is_json_resp = False) -> ComputeTaskResult:
from .compute_kernel import ComputeKernel from .compute_kernel import ComputeKernel
#logger.debug(f"Agent {self.agent_id} do llm token static system:{system_prompt_len},function:{function_token_len},history:{history_token_len},input:{input_len}, totoal prompt:{system_prompt_len + function_token_len + history_token_len} ") #logger.debug(f"Agent {self.agent_id} do llm token static system:{system_prompt_len},function:{function_token_len},history:{history_token_len},input:{input_len}, totoal prompt:{system_prompt_len + function_token_len + history_token_len} ")
task_result:ComputeTaskResult = await ComputeKernel.get_instance().do_llm_completion(prompt,self.llm_model_name,self.max_token_size,inner_functions) if is_json_resp:
task_result:ComputeTaskResult = await ComputeKernel.get_instance().do_llm_completion(prompt,"json",self.llm_model_name,self.max_token_size,inner_functions)
else:
task_result:ComputeTaskResult = await ComputeKernel.get_instance().do_llm_completion(prompt,"text",self.llm_model_name,self.max_token_size,inner_functions)
if task_result.result_code != ComputeTaskResultCode.OK: if task_result.result_code != ComputeTaskResultCode.OK:
logger.error(f"_do_llm_complection llm compute error:{task_result.error_str}") logger.error(f"_do_llm_complection llm compute error:{task_result.error_str}")
#error_resp = msg.create_error_resp(task_result.error_str) #error_resp = msg.create_error_resp(task_result.error_str)
+3
View File
@@ -237,7 +237,9 @@ class LLMResult:
def __init__(self) -> None: def __init__(self) -> None:
self.state : str = "ignore" self.state : str = "ignore"
self.resp : str = "" self.resp : str = ""
self.raw_resp = None
self.paragraphs : dict[str,FunctionItem] = [] self.paragraphs : dict[str,FunctionItem] = []
self.post_msgs : List[AgentMsg] = [] self.post_msgs : List[AgentMsg] = []
self.send_msgs : List[AgentMsg] = [] self.send_msgs : List[AgentMsg] = []
@@ -257,6 +259,7 @@ class LLMResult:
llm_json = json.loads(llm_json_str) llm_json = json.loads(llm_json_str)
r.state = llm_json.get("state") r.state = llm_json.get("state")
r.resp = llm_json.get("resp") r.resp = llm_json.get("resp")
r.raw_resp = llm_json
post_msgs = llm_json.get("post_msg") post_msgs = llm_json.get("post_msg")
r.post_msgs = [] r.post_msgs = []
+4 -4
View File
@@ -119,11 +119,11 @@ class ComputeKernel:
# friendly interface for use: # friendly interface for use:
def llm_completion(self, prompt: AgentPrompt, mode_name: Optional[str] = None, max_token: int = 0,inner_functions = None): def llm_completion(self, prompt: AgentPrompt, resp_mode:str="text",mode_name: Optional[str] = None, max_token: int = 0,inner_functions = None):
# craete a llm_work_task ,push on queue's end # craete a llm_work_task ,push on queue's end
# then task_schedule would run this task.(might schedule some work_task to another host) # then task_schedule would run this task.(might schedule some work_task to another host)
task_req = ComputeTask() task_req = ComputeTask()
task_req.set_llm_params(prompt, mode_name, max_token,inner_functions) task_req.set_llm_params(prompt,resp_mode,mode_name, max_token,inner_functions)
self.run(task_req) self.run(task_req)
return task_req return task_req
@@ -155,8 +155,8 @@ class ComputeKernel:
return time_out_result return time_out_result
async def do_llm_completion(self, prompt: AgentPrompt, mode_name: Optional[str] = None, max_token: int = 0, inner_functions = None) -> str: async def do_llm_completion(self, prompt: AgentPrompt,resp_mode:str="text", mode_name: Optional[str] = None, max_token: int = 0, inner_functions = None) -> str:
task_req = self.llm_completion(prompt, mode_name, max_token,inner_functions) task_req = self.llm_completion(prompt, resp_mode,mode_name, max_token,inner_functions)
return await self._wait_task(task_req) return await self._wait_task(task_req)
+7 -5
View File
@@ -4,6 +4,7 @@ import uuid
import time import time
from typing import Union from typing import Union
from knowledge import ObjectID from knowledge import ObjectID
from .storage import AIStorage
class ComputeTaskResultCode(Enum): class ComputeTaskResultCode(Enum):
OK = 0 OK = 0
@@ -45,16 +46,16 @@ class ComputeTask:
self.result = None self.result = None
self.error_str = None self.error_str = None
def set_llm_params(self, prompts, model_name, max_token_size, inner_functions = None, callchain_id=None): def set_llm_params(self, prompts, resp_mode,model_name, max_token_size, inner_functions = None, callchain_id=None):
self.task_type = ComputeTaskType.LLM_COMPLETION self.task_type = ComputeTaskType.LLM_COMPLETION
self.create_time = time.time() self.create_time = time.time()
self.task_id = uuid.uuid4().hex self.task_id = uuid.uuid4().hex
self.callchain_id = callchain_id self.callchain_id = callchain_id
self.params["prompts"] = prompts.to_message_list() self.params["prompts"] = prompts.to_message_list()
if model_name is not None: self.params["resp_mode"] = resp_mode
self.params["model_name"] = model_name if model_name is None:
else: model_name = AIStorage.get_instance().get_user_config().get_value("llm_model_name")
self.params["model_name"] = "gpt-4-0613" self.params["model_name"] = model_name
if max_token_size is None: if max_token_size is None:
self.params["max_token_size"] = 4000 self.params["max_token_size"] = 4000
else: else:
@@ -115,6 +116,7 @@ class ComputeTaskResult:
self.result_refers: dict = {} self.result_refers: dict = {}
self.pading_data: bytearray = None self.pading_data: bytearray = None
def set_from_task(self, task: ComputeTask): def set_from_task(self, task: ComputeTask):
self.task_id = task.task_id self.task_id = task.task_id
+48 -10
View File
@@ -1,4 +1,5 @@
import openai import openai
from openai import AsyncOpenAI
import os import os
import asyncio import asyncio
from asyncio import Queue from asyncio import Queue
@@ -59,6 +60,35 @@ class OpenAI_ComputeNode(ComputeNode):
async def remove_task(self, task_id: str): async def remove_task(self, task_id: str):
pass pass
def message_to_dict(self, message)->dict:
result = message.dict()
# result_msg = {}
# #message.json()
# if message.content:
# result_msg["content"] = message.content
# result_msg["role"] = message.role
# if message.function_call:
# function_call = {}
# function_call["arguments"] = message.function_call.arguments
# function_call["name"] = message.function_call.name
# result_msg["function_call"] = function_call
# if message.tool_calls:
# tool_calls = []
# for tool_call in message.tool_calls:
# tool_call_dict = {}
# tool_call_dict["id"] = tool_call.id
# tool_call_dict["type"] = tool_call.type
# func_call_dict = {}
# func_call_dict["name"] = tool_call.function.name
# func_call_dict["arguments"] = tool_call.function.arguments
# tool_call_dict["function"] = func_call_dict
# tool_calls.append(tool_call_dict)
# result_msg["tool_calls"] = message.tool_calls
# result["message"] = result_msg
return result
async def _run_task(self, task: ComputeTask): async def _run_task(self, task: ComputeTask):
task.state = ComputeTaskState.RUNNING task.state = ComputeTaskState.RUNNING
@@ -107,27 +137,34 @@ class OpenAI_ComputeNode(ComputeNode):
case ComputeTaskType.LLM_COMPLETION: case ComputeTaskType.LLM_COMPLETION:
mode_name = task.params["model_name"] mode_name = task.params["model_name"]
prompts = task.params["prompts"] prompts = task.params["prompts"]
resp_mode = task.params["resp_mode"]
if resp_mode == "json":
response_format = { "type": "json_object" }
else:
response_format = None
max_token_size = task.params.get("max_token_size") max_token_size = task.params.get("max_token_size")
llm_inner_functions = task.params.get("inner_functions") llm_inner_functions = task.params.get("inner_functions")
if max_token_size is None: if max_token_size is None:
max_token_size = 4000 max_token_size = 4000
result_token = max_token_size result_token = max_token_size
client = AsyncOpenAI()
try: try:
if llm_inner_functions is None: if llm_inner_functions is None:
logger.info(f"call openai {mode_name} prompts: {prompts}") logger.info(f"call openai {mode_name} prompts: {prompts}")
resp = await openai.ChatCompletion.acreate(model=mode_name, resp = await client.chat.completions.create(model=mode_name,
messages=prompts, messages=prompts,
response_format = response_format,
#max_tokens=result_token, #max_tokens=result_token,
temperature=0.7) )
else: else:
logger.info(f"call openai {mode_name} prompts: \n\t {prompts} \nfunctions: \n\t{json.dumps(llm_inner_functions)}") logger.info(f"call openai {mode_name} prompts: \n\t {prompts} \nfunctions: \n\t{json.dumps(llm_inner_functions)}")
resp = await openai.ChatCompletion.acreate(model=mode_name, resp = await client.chat.completions.create(model=mode_name,
messages=prompts, messages=prompts,
response_format = response_format,
functions=llm_inner_functions, functions=llm_inner_functions,
#max_tokens=result_token, #max_tokens=result_token,
temperature=0.7) # TODO: add temperature to task params? ) # TODO: add temperature to task params?
except Exception as e: except Exception as e:
logger.error(f"openai run LLM_COMPLETION task error: {e}") logger.error(f"openai run LLM_COMPLETION task error: {e}")
task.state = ComputeTaskState.ERROR task.state = ComputeTaskState.ERROR
@@ -135,10 +172,10 @@ class OpenAI_ComputeNode(ComputeNode):
result.error_str = str(e) result.error_str = str(e)
return result return result
logger.info(f"openai response: {json.dumps(resp, indent=4)}") logger.info(f"openai response: {resp}")
status_code = resp.choices[0].finish_reason
token_usage = resp.usage
status_code = resp["choices"][0]["finish_reason"]
token_usage = resp.get("usage")
match status_code: match status_code:
case "function_call": case "function_call":
task.state = ComputeTaskState.DONE task.state = ComputeTaskState.DONE
@@ -153,8 +190,9 @@ class OpenAI_ComputeNode(ComputeNode):
result.result_code = ComputeTaskResultCode.OK result.result_code = ComputeTaskResultCode.OK
result.worker_id = self.node_id result.worker_id = self.node_id
result.result_str = resp["choices"][0]["message"]["content"] result.result_str = resp.choices[0].message.content
result.result["message"] = resp["choices"][0]["message"]
result.result["message"] = self.message_to_dict(resp.choices[0].message)
if token_usage: if token_usage:
result.result_refers["token_usage"] = token_usage result.result_refers["token_usage"] = token_usage
+11
View File
@@ -40,6 +40,17 @@ class UserConfig:
self.config_table = {} self.config_table = {}
self.user_config_path:str = None self.user_config_path:str = None
self._init_default_value("llm_model_name","gpt-4-1106-preview")
def _init_default_value(self,key:str,value:Any) -> None:
if self.config_table.get(key) is not None:
logger.warning("user config key %s already exist, will be overrided",key)
new_config_item = UserConfigItem()
new_config_item.default_value = value
new_config_item.is_optional = True
self.config_table[key] = new_config_item
def add_user_config(self,key:str,desc:str,is_optional:bool,default_value:Any=None,item_type="str") -> None: def add_user_config(self,key:str,desc:str,is_optional:bool,default_value:Any=None,item_type="str") -> None:
if self.config_table.get(key) is not None: if self.config_table.get(key) is not None: