1) Use UserConfig to change system default LLM model name
2) Support GPT4-Turbo JSON resp format
This commit is contained in:
@@ -518,15 +518,17 @@ class AIAgent:
|
||||
|
||||
final_result = task_result.result_str
|
||||
if final_result is not None:
|
||||
if final_result[0] == "{":
|
||||
llm_result = LLMResult.from_json_str(final_result)
|
||||
else:
|
||||
llm_result : LLMResult = LLMResult.from_str(final_result)
|
||||
llm_result : LLMResult = LLMResult.from_str(final_result)
|
||||
else:
|
||||
llm_result = LLMResult()
|
||||
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)
|
||||
|
||||
@@ -866,7 +868,7 @@ class AIAgent:
|
||||
prompt.append(todo.detail)
|
||||
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:
|
||||
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 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
|
||||
#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:
|
||||
logger.error(f"_do_llm_complection llm compute error:{task_result.error_str}")
|
||||
#error_resp = msg.create_error_resp(task_result.error_str)
|
||||
|
||||
@@ -237,8 +237,10 @@ class LLMResult:
|
||||
def __init__(self) -> None:
|
||||
self.state : str = "ignore"
|
||||
self.resp : str = ""
|
||||
self.raw_resp = None
|
||||
self.paragraphs : dict[str,FunctionItem] = []
|
||||
|
||||
|
||||
self.post_msgs : List[AgentMsg] = []
|
||||
self.send_msgs : List[AgentMsg] = []
|
||||
self.calls : List[FunctionItem] = []
|
||||
@@ -257,6 +259,7 @@ class LLMResult:
|
||||
llm_json = json.loads(llm_json_str)
|
||||
r.state = llm_json.get("state")
|
||||
r.resp = llm_json.get("resp")
|
||||
r.raw_resp = llm_json
|
||||
|
||||
post_msgs = llm_json.get("post_msg")
|
||||
r.post_msgs = []
|
||||
|
||||
@@ -119,11 +119,11 @@ class ComputeKernel:
|
||||
|
||||
|
||||
# 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
|
||||
# then task_schedule would run this task.(might schedule some work_task to another host)
|
||||
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)
|
||||
return task_req
|
||||
|
||||
@@ -155,8 +155,8 @@ class ComputeKernel:
|
||||
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:
|
||||
task_req = self.llm_completion(prompt, mode_name, max_token,inner_functions)
|
||||
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, resp_mode,mode_name, max_token,inner_functions)
|
||||
return await self._wait_task(task_req)
|
||||
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import uuid
|
||||
import time
|
||||
from typing import Union
|
||||
from knowledge import ObjectID
|
||||
from .storage import AIStorage
|
||||
|
||||
class ComputeTaskResultCode(Enum):
|
||||
OK = 0
|
||||
@@ -45,16 +46,16 @@ class ComputeTask:
|
||||
self.result = 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.create_time = time.time()
|
||||
self.task_id = uuid.uuid4().hex
|
||||
self.callchain_id = callchain_id
|
||||
self.params["prompts"] = prompts.to_message_list()
|
||||
if model_name is not None:
|
||||
self.params["model_name"] = model_name
|
||||
else:
|
||||
self.params["model_name"] = "gpt-4-0613"
|
||||
self.params["resp_mode"] = resp_mode
|
||||
if model_name is None:
|
||||
model_name = AIStorage.get_instance().get_user_config().get_value("llm_model_name")
|
||||
self.params["model_name"] = model_name
|
||||
if max_token_size is None:
|
||||
self.params["max_token_size"] = 4000
|
||||
else:
|
||||
@@ -116,6 +117,7 @@ class ComputeTaskResult:
|
||||
self.result_refers: dict = {}
|
||||
self.pading_data: bytearray = None
|
||||
|
||||
|
||||
def set_from_task(self, task: ComputeTask):
|
||||
self.task_id = task.task_id
|
||||
self.callchain_id = task.callchain_id
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import openai
|
||||
from openai import AsyncOpenAI
|
||||
import os
|
||||
import asyncio
|
||||
from asyncio import Queue
|
||||
@@ -59,6 +60,35 @@ class OpenAI_ComputeNode(ComputeNode):
|
||||
async def remove_task(self, task_id: str):
|
||||
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):
|
||||
task.state = ComputeTaskState.RUNNING
|
||||
@@ -107,27 +137,34 @@ class OpenAI_ComputeNode(ComputeNode):
|
||||
case ComputeTaskType.LLM_COMPLETION:
|
||||
mode_name = task.params["model_name"]
|
||||
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")
|
||||
llm_inner_functions = task.params.get("inner_functions")
|
||||
if max_token_size is None:
|
||||
max_token_size = 4000
|
||||
|
||||
result_token = max_token_size
|
||||
|
||||
client = AsyncOpenAI()
|
||||
try:
|
||||
if llm_inner_functions is None:
|
||||
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,
|
||||
response_format = response_format,
|
||||
#max_tokens=result_token,
|
||||
temperature=0.7)
|
||||
)
|
||||
else:
|
||||
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,
|
||||
response_format = response_format,
|
||||
functions=llm_inner_functions,
|
||||
#max_tokens=result_token,
|
||||
temperature=0.7) # TODO: add temperature to task params?
|
||||
) # TODO: add temperature to task params?
|
||||
except Exception as e:
|
||||
logger.error(f"openai run LLM_COMPLETION task error: {e}")
|
||||
task.state = ComputeTaskState.ERROR
|
||||
@@ -135,10 +172,10 @@ class OpenAI_ComputeNode(ComputeNode):
|
||||
result.error_str = str(e)
|
||||
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:
|
||||
case "function_call":
|
||||
task.state = ComputeTaskState.DONE
|
||||
@@ -153,8 +190,9 @@ class OpenAI_ComputeNode(ComputeNode):
|
||||
|
||||
result.result_code = ComputeTaskResultCode.OK
|
||||
result.worker_id = self.node_id
|
||||
result.result_str = resp["choices"][0]["message"]["content"]
|
||||
result.result["message"] = resp["choices"][0]["message"]
|
||||
result.result_str = resp.choices[0].message.content
|
||||
|
||||
result.result["message"] = self.message_to_dict(resp.choices[0].message)
|
||||
|
||||
if token_usage:
|
||||
result.result_refers["token_usage"] = token_usage
|
||||
|
||||
@@ -40,6 +40,17 @@ class UserConfig:
|
||||
self.config_table = {}
|
||||
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:
|
||||
if self.config_table.get(key) is not None:
|
||||
|
||||
Reference in New Issue
Block a user