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
|
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)
|
||||||
|
|||||||
@@ -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 = []
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
Reference in New Issue
Block a user