diff --git a/src/aios_kernel/agent.py b/src/aios_kernel/agent.py index 13339cb..64e381f 100644 --- a/src/aios_kernel/agent.py +++ b/src/aios_kernel/agent.py @@ -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) diff --git a/src/aios_kernel/agent_base.py b/src/aios_kernel/agent_base.py index 43575d2..9ecc604 100644 --- a/src/aios_kernel/agent_base.py +++ b/src/aios_kernel/agent_base.py @@ -237,7 +237,9 @@ 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] = [] @@ -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 = [] diff --git a/src/aios_kernel/compute_kernel.py b/src/aios_kernel/compute_kernel.py index eb09574..0a9e3a3 100644 --- a/src/aios_kernel/compute_kernel.py +++ b/src/aios_kernel/compute_kernel.py @@ -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) diff --git a/src/aios_kernel/compute_task.py b/src/aios_kernel/compute_task.py index ea7c431..6b9d74c 100644 --- a/src/aios_kernel/compute_task.py +++ b/src/aios_kernel/compute_task.py @@ -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: @@ -115,6 +116,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 diff --git a/src/aios_kernel/open_ai_node.py b/src/aios_kernel/open_ai_node.py index 206d223..1b686d0 100644 --- a/src/aios_kernel/open_ai_node.py +++ b/src/aios_kernel/open_ai_node.py @@ -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 diff --git a/src/aios_kernel/storage.py b/src/aios_kernel/storage.py index 2d83af6..ca3bb56 100644 --- a/src/aios_kernel/storage.py +++ b/src/aios_kernel/storage.py @@ -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: