From 9199acf84c2ac9938c79f37b5a944f50d74232e8 Mon Sep 17 00:00:00 2001 From: "Gerard@msft" <99283778+gjwoods@users.noreply.github.com> Date: Tue, 5 Dec 2023 21:07:42 -0800 Subject: [PATCH] Open_Source_LLM Tool - Restore Dynamic List + Fixes (#1076) # Description Changes: 1. Restore Open_Source_LLM Tool Dynamic list functionality 2. Fixes: WS: 2806189, 2806307 # All Promptflow Contribution checklist: - [x] **The pull request does not introduce [breaking changes].** - [x] **CHANGELOG is updated for new features, bug fixes or other significant changes.** - [x] **I have read the [contribution guidelines](../CONTRIBUTING.md).** - [x] **Create an issue and link to the pull request to get dedicated review from promptflow team. Learn more: [suggested workflow](../CONTRIBUTING.md#suggested-workflow).** ## General Guidelines and Best Practices - [x] Title of the pull request is clear and informative. - [x] There are a small number of commits, each of which have an informative message. This means that previously merged commits do not appear in the history of the PR. For more information on cleaning up the commits in your PR, [see this page](https://github.com/Azure/azure-powershell/blob/master/documentation/development-docs/cleaning-up-commits.md). ### Testing Guidelines - [x] Pull request includes test coverage for the included changes. --------- Co-authored-by: Gerard --- .cspell.json | 3 +- .../open_source_llm_on_vscode_promptflow.png | Bin 84000 -> 76194 bytes .../tools-reference/open_source_llm_tool.md | 54 +- .../promptflow/tools/open_source_llm.py | 986 +++++++++++++++--- .../tools/yamls/open_source_llm.yaml | 21 +- src/promptflow-tools/tests/conftest.py | 28 +- .../tests/test_open_source_llm.py | 381 +++++-- src/promptflow-tools/tests/utils.py | 18 + 8 files changed, 1199 insertions(+), 292 deletions(-) diff --git a/.cspell.json b/.cspell.json index 72d4ecc8db1..c16170d0e7e 100644 --- a/.cspell.json +++ b/.cspell.json @@ -153,7 +153,8 @@ "Abhishek", "restx", "httpx", - "tiiuae" + "tiiuae", + "metagenai" ], "flagWords": [ "Prompt Flow" diff --git a/docs/media/reference/tools-reference/open_source_llm_on_vscode_promptflow.png b/docs/media/reference/tools-reference/open_source_llm_on_vscode_promptflow.png index 59775a78afa7684ac457436730ecb13aca27f27e..9e79e237917c72debd1e0f3912c998eb01a00915 100644 GIT binary patch literal 76194 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

;}K_qd;K?MnlDgi?T{Cck7z}!&cv}Kh>tzx z=66dEhp{|Ifi4c>9brWwO_|MsG2K!a+x)5i++Z^zO|!jZrD#`&2E-RT0Wyvs5tmb1 zv6o@{eP+Nh!^`iUEMe^J1d zUmfpn*!O6Nf=sPoXIM8s^nnH_7htQ(GyOj1e_S*#m`PYPV_oZK%oZtlK$=aosJ?@J zT79NxW!~oD9>AoFm(H6*9Fn&wc>d`OD0IQS{OSCl-!d24Oh_2Ps+x&BW0Sc)L%qlG z*7MjClAxmdl^oQAnk(nkP%T{MIRdH8PBxPSMUvgTEAr}rQuT{c|F@!#ILOts(%Nqc zqgk~bk{a#0#yyeuE@(Y&yJr4AjFew67kcmBb-H8~==NjuQW~AQ33V%vC6tInmUl;w zZjN|aLb4X`kjf^Hoas#};o^ww$9=(kd(>`_HjYL)<$2X|#6&6aM`JH_S2w1mtQbng zBF4z|TZBP+zOi#wyi?5}abH!&5>^{ER&sLA)LMP201MH)a<9buqMivhz(nJM7JZe? z+*fH$3YEguHnY3d3%T#9wAM~Lzr7ss%qL;#VidWu-!dqmjuKu?XGd(CB|z%h9vk7- zyzb7+rTe(WNBFnqM&0iHQ!~RYenaJgS(kXlJa&k~@Vi+0LO<=6dIKV};Wks_kT_{K zStyjqzBuJSmE}L>O+e{|x+OgwV2Qr@Av#hX@(H(u;IyO?@6FVluk_VV&9 zgYQ?L`O{(3PNCOEizVt;VfMJ_uZ)Q6e&x9qi&oGuHc;oltKC`P^eOrv}Y zPk-_D@1G_V*Q(r?QU!SL+Goz1dji)lH)}ypx4SJI%fwC_wXYv{OD5?xsqW}kEUMS9 z>K9E`Y9SlmClnYZ>R;3w>|)7gywOzKv*n$rDMMAaYBx2zGNs1&&HH^dlrWV zstI~~GU#T+2e@L+#uJ>Jx?hy0Kofm)Kv1{&M25uRdj?UHq%4ANwuC<-uY;e-w|Oeo zY-;m8x_jfz5N3g(zayza6w{g?t9`a{kLWoiqc|uHE)H?yc`R??_E7#_Hs|NF$74x+ z*Y}_vkxU@L7ch&D4?Ya={-DF>5Qt&0-73BN^3^H(zpi$iUv^1_ejFiSTHY7D`CCi!7SIkb>r6w9#O6<&D&0L5B-af^jUtNE%A6Km8AZw&VJpc%7$RT$H08 zPK`#9_55yJl6NU*H&jA<{c_)*LJ}%dTmIH}X8e0}rcl_%vi#__jJD@i1Cwfv(JM`X z1NQK29BWLLibL&;0s})1fc063%~gSgy>6A^xdCTJ)onA!^Mu))(LHhQw-btK+9qwR zBU#f&#$aqOpBOYTNCnvNKZzLmg#HkRGn?!w9_LI&Y}DAp zrtfqGR&rH6BVGzmz_9xNIJR%P2YdAfZ#PsHubHhYl}STJNycMmy7vEc_{8@sM(^08 zRlz%)lHb~ueR6)>8*tZR`?a$fbO2I06x4*rXsUWmHxw*dHFbQ;yJ;FnxFkf?o9u(l zK?%Qpl)7!e!XHm4p;~j27twsq_@A@yY{bb>iq zLC+3Ec@xxw3@ETQm`;9Xvcwg3pFw497PGZ5_EG?QHIS;D17B^tG55a zO$v%lCv`p}mm zS3N#lmR#0>tBo*R1c7D_(bGpJmu+pS&!pUZQ#9}FfxxeL6?PCs`U(X~*wIhb7g-$qVW{{PrIZtKq6FB${$I`o9xu5hZPj9fUNobjpU+D;Gp(A? zvQ}cCIu^EEm^BAkh}k4bM<^Gk5kC3{k1G9?B6_wai%%_clTQ;8f!4%mDY5`y zRjcuB@0>WBmbVRp9@E(C8Ln}}Cu5~nRZ&L^k&=O=9E#D!(p~jyrpDn3m5x)>{;u&$ zRgk%8H5uyURI=j^Z$Dmz#2fEHaTs_bovMUkW!DjTK+E~N@Tlf;L&U6sanFV^>8A@< zMJhyn@=Kd0c~Wda>_a4DBb%MRbcx5DEMZKA63cx*z0z8Zygs|#Xz}HG+p*-PidsjA zT)(se^kRpH0@0H<+1a(b{?GP?zfmR3jcy?&8HCHyXyu^~O z+f50-vMK6xCNuKakspIOx#1%2jXoZ)vzU1Z7+S?8E(|KQM5W67ZZ3bk6Q4w3poC`i z9ab18v-gcPs^Dx|JYycfH zo%y4I0=$Hnd^uPU->)Z=GG2?rX>SV{xgiRs!4G#HI)7qGu!=VSYRH_!pRE#x?#4H# zoWaa^WU{9mn}9f1S$f=F2PqN{t&-

-=5^q%15mw$V4n{R)ebfg8!i*A+%bgY%zc zOj9*>ZX5o(mIc@3>LFsQ&*+z2t#@P`#|CDrk=UAh^vOVwn7_6N)(49*R{?CxtQbb11L!@n!um_D(UVYzu2~7>XYw+i(^C z2#aD7977g$O^S_)eTZm#-GT9SaNG4yq%LI<3t$BW+2+MK%AtTZmf9~3#7Saf(h8Or zHDq`wvSZIP7j*G`cuSICbR6qo$BT4`j{s7c@_6c@$5c$AoQn6}dpKvdY@nGWf@lm@ zgwp0coX5uSVkUFN;^sbkn!V?|8XbD zt$F|9u=!4NskS@xk`4sz*A0uFV|Ud^k?Hn$zSBtea%cC|BC_%DNrVC;*14W$6Lc)q zX6(F7Ku%p8Gu*bGhXEDy3c@79|3hzDfuB)8m+5ZqH_?8@yUD*hE$kQkaRx2loTqQk zr&GmfDfxde6yB>a*DDu+-+EASLtnQQxsdKY;~cfWVdOUB&y=jt!`&9rt8B0!e3b42 zW2bRAJGyI8s6F%nxULM{|Ia|_u7=c1b%R-rR?$ z_~zTXb<2PNo>^YtDFXgEkn!=`Om76Fu6Dm)(OH}kWf!m&urwG&s@CsiuIDD@`&YgJ z=vb9?JAww`heK}!*5dRpIiJ4#2pVuQ9_1eti<(R7V(ULj@Tu1s?7~Pxtnm)&GN@-f zab+!tX!Niq9@4DPwIR{!5nbAlK=6x7z5#UCh`YJKHSvJCB(PcdXNw2$@LL3ggBOQRGFX=CLD34N^oHP_iWZZU zw#qhqo1fd(9sKe+UfCE|cTJrCBAzlz=NOP&EAHg(80{g6Qou9)z<+vTjS% z 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 literal 84000 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

b$yCXS;Zdgi7zPunlA6eqhMK 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≻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 datetime.now() + and self.subscription_id == subscription_id + and self.resource_group == resource_group + and self.workspace_name == workspace_name) + + +class Endpoint: + def __init__(self, + endpoint_name: str, + endpoint_url: str, + endpoint_key: str): + self.deployments: List[Deployment] = [] + self.default_deployment: Deployment = None + self.endpoint_url = endpoint_url + self.endpoint_key = endpoint_key + self.endpoint_name = endpoint_name + + +class Deployment: + def __init__(self, + deployment_name: str, + model_family: str): + self.model_family = model_family + self.deployment_name = deployment_name + + +class ServerlessEndpointsContainer: + API_VERSION = "2023-08-01-preview" + + def _get_headers(self, token: str) -> Dict[str, str]: + headers = { + "Authorization": f"Bearer {token}", + "Content-Type": "application/json", + } + return headers + + def get_serverless_arm_url(self, subscription_id, resource_group, workspace_name, suffix=None): + suffix = "" if suffix is None else f"/{suffix}" + return f"https://management.azure.com/subscriptions/{subscription_id}" \ + + f"/resourceGroups/{resource_group}/providers/Microsoft.MachineLearningServices" \ + + f"/workspaces/{workspace_name}/serverlessEndpoints{suffix}?api-version={self.API_VERSION}" + + def _list(self, token: str, subscription_id: str, resource_group: str, workspace_name: str): + headers = self._get_headers(token) + url = self.get_serverless_arm_url(subscription_id, resource_group, workspace_name) + + try: + response = requests.get(url, headers=headers, timeout=50) + return json.loads(response.content)['value'] + except Exception as e: + print(f"Error encountered when listing serverless endpoints. Exception: {e}", file=sys.stderr) + return [] + + def _validate_model_family(self, serverless_endpoint): + try: + if serverless_endpoint.get('properties', {}).get('provisioningState') != "Succeeded": + return None + + if (try_get_from_dict(serverless_endpoint, + ['properties', 'offer', 'publisher']) == 'Meta' + and "llama" in try_get_from_dict(serverless_endpoint, + ['properties', 'offer', 'offerName'])): + return ModelFamily.LLAMA + if (try_get_from_dict(serverless_endpoint, + ['properties', 'marketplaceInfo', 'publisherId']) == 'metagenai' + and "llama" in try_get_from_dict(serverless_endpoint, + ['properties', 'marketplaceInfo', 'offerId'])): + return ModelFamily.LLAMA + except Exception as ex: + print(f"Ignoring endpoint {serverless_endpoint['id']} due to error: {ex}", file=sys.stderr) + return None + + def list_serverless_endpoints(self, + token, + subscription_id, + resource_group, + workspace_name, + return_endpoint_url: bool = False): + serverlessEndpoints = self._list(token, subscription_id, resource_group, workspace_name) + + result = [] + for e in serverlessEndpoints: + if (self._validate_model_family(e)): + result.append({ + "value": f"serverlessEndpoint/{e['name']}", + "display_value": f"[Serverless] {e['name']}", + # "hyperlink": self.get_endpoint_url(e.endpoint_name) + "description": f"Serverless Endpoint: {e['name']}", + }) + if return_endpoint_url: + result[-1]['url'] = try_get_from_dict(e, ['properties', 'inferenceEndpoint', 'uri']) + return result + + def _list_endpoint_key(self, + token: str, + subscription_id: str, + resource_group: str, + workspace_name: str, + serverless_endpoint_name: str): + headers = self._get_headers(token) + url = self.get_serverless_arm_url(subscription_id, + resource_group, + workspace_name, + f"{serverless_endpoint_name}/listKeys") + try: + response = requests.post(url, headers=headers, timeout=50) + return json.loads(response.content) + except Exception as e: + print(f"Unable to get key from selected serverless endpoint. Exception: {e}", file=sys.stderr) + + def get_serverless_endpoint(self, + token: str, + subscription_id: str, + resource_group: str, + workspace_name: str, + serverless_endpoint_name: str): + headers = self._get_headers(token) + url = self.get_serverless_arm_url(subscription_id, resource_group, workspace_name, serverless_endpoint_name) + + try: + response = requests.get(url, headers=headers, timeout=50) + return json.loads(response.content) + except Exception as e: + print(f"Unable to get selected serverless endpoint. Exception: {e}", file=sys.stderr) + + def get_serverless_endpoint_key(self, + token: str, + subscription_id: str, + resource_group: str, + workspace_name: str, + serverless_endpoint_name: str) -> Tuple[str, str, str]: + endpoint = self.get_serverless_endpoint(token, + subscription_id, + resource_group, + workspace_name, + serverless_endpoint_name) + endpoint_url = try_get_from_dict(endpoint, ['properties', 'inferenceEndpoint', 'uri']) + model_family = self._validate_model_family(endpoint) + endpoint_key = self._list_endpoint_key(token, + subscription_id, + resource_group, + workspace_name, + serverless_endpoint_name)['primaryKey'] + return (endpoint_url, + endpoint_key, + model_family) + + +class CustomConnectionsContainer: + + def get_azure_custom_connection_names(self, + credential, + subscription_id: str, + resource_group_name: str, + workspace_name: str, + return_endpoint_url: bool = False + ) -> List[Dict[str, Union[str, int, float, list, Dict]]]: + + result = [] + try: + from promptflow.azure import PFClient as AzurePFClient + azure_pf_client = AzurePFClient( + credential=credential, + subscription_id=subscription_id, + resource_group_name=resource_group_name, + workspace_name=workspace_name) + except Exception: + message = "Skipping Azure PFClient. To connect, please ensure the following environment variables are set: " + message += ",".join(ENDPOINT_REQUIRED_ENV_VARS) + print(message, file=sys.stderr) + return result + + connections = azure_pf_client._connections.list() + for c in connections: + if c.type == ConnectionType.CUSTOM and "model_family" in c.configs: + try: + validate_model_family(c.configs["model_family"]) + result.append({ + "value": f"connection/{c.name}", + "display_value": f"[Connection] {c.name}", + # "hyperlink": "", + "description": f"Custom Connection: {c.name}", + }) + if return_endpoint_url: + result[-1]['url'] = c.configs['endpoint_url'] + except Exception: + # silently ignore unsupported model family + continue + return result + + def get_local_custom_connection_names(self, + return_endpoint_url: bool = False + ) -> List[Dict[str, Union[str, int, float, list, Dict]]]: + result = [] + try: + from promptflow import PFClient as LocalPFClient + except Exception as e: + print(f"Skipping Local PFClient. Exception: {e}", file=sys.stderr) + return result + + pf = LocalPFClient() + connections = pf.connections.list() + for c in connections: + if c.type == ConnectionType.CUSTOM and "model_family" in c.configs: + try: + validate_model_family(c.configs["model_family"]) + result.append({ + "value": f"localConnection/{c.name}", + "display_value": f"[Local Connection] {c.name}", + # "hyperlink": "", + "description": f"Local Custom Connection: {c.name}", + }) + if return_endpoint_url: + result[-1]['url'] = c.configs['endpoint_url'] + except Exception: + # silently ignore unsupported model family + continue + + return result + + def get_endpoint_from_local_custom_connection(self, connection_name) -> Tuple[str, str, str]: + from promptflow import PFClient as LocalPFClient + pf = LocalPFClient() + + connection = pf.connections.get(connection_name, with_secrets=True) + + return self.get_endpoint_from_custom_connection(connection) + + def get_endpoint_from_azure_custom_connection(self, + credential, + subscription_id, + resource_group_name, + workspace_name, + connection_name) -> Tuple[str, str, str]: + from promptflow.azure import PFClient as AzurePFClient + + azure_pf_client = AzurePFClient( + credential=credential, + subscription_id=subscription_id, + resource_group_name=resource_group_name, + workspace_name=workspace_name) + + connection = azure_pf_client._arm_connections.get(connection_name) + + return self.get_endpoint_from_custom_connection(connection) + + def get_endpoint_from_custom_connection(self, connection: CustomConnection) -> Tuple[str, str, str]: + conn_dict = dict(connection) + for key in REQUIRED_CONFIG_KEYS: + if key not in conn_dict: + accepted_keys = ",".join([key for key in REQUIRED_CONFIG_KEYS]) + raise OpenSourceLLMKeyValidationError( + message=f"""Required key `{key}` not found in given custom connection. +Required keys are: {accepted_keys}.""" + ) + + for key in REQUIRED_SECRET_KEYS: + if key not in conn_dict: + accepted_keys = ",".join([key for key in REQUIRED_SECRET_KEYS]) + raise OpenSourceLLMKeyValidationError( + message=f"""Required secret key `{key}` not found in given custom connection. +Required keys are: {accepted_keys}.""" + ) + + model_family = validate_model_family(connection.configs['model_family']) + + return (connection.configs['endpoint_url'], + connection.secrets['endpoint_api_key'], + model_family) + + def list_custom_connection_names(self, + credential, + subscription_id: str, + resource_group_name: str, + workspace_name: str, + return_endpoint_url: bool = False + ) -> List[Dict[str, Union[str, int, float, list, Dict]]]: + + azure_custom_connections = self.get_azure_custom_connection_names(credential, + subscription_id, + resource_group_name, + workspace_name, + return_endpoint_url) + local_custom_connections = self.get_local_custom_connection_names(return_endpoint_url) + + return azure_custom_connections + local_custom_connections + + +class EndpointsContainer: + + def get_ml_client(self, + credential, + subscription_id: str, + resource_group_name: str, + workspace_name: str): + try: + from azure.ai.ml import MLClient + return MLClient( + credential=credential, + subscription_id=subscription_id, + resource_group_name=resource_group_name, + workspace_name=workspace_name) + except Exception as e: + message = "Unable to connect to AzureML. Please ensure the following environment variables are set: " + message += ",".join(ENDPOINT_REQUIRED_ENV_VARS) + message += "\nException: " + str(e) + raise OpenSourceLLMOnlineEndpointError(message=message) + + def get_endpoints_and_deployments(self, + credential, + subscription_id: str, + resource_group_name: str, + workspace_name: str) -> List[Endpoint]: + + ml_client = self.get_ml_client(credential, subscription_id, resource_group_name, workspace_name) + + list_of_endpoints: List[Endpoint] = [] + for ep in ml_client.online_endpoints.list(): + endpoint = Endpoint( + endpoint_name=ep.name, + endpoint_url=ep.scoring_uri, + endpoint_key=ml_client.online_endpoints.get_keys(ep.name).primary_key) + + ordered_deployment_names = sorted(ep.traffic, key=lambda item: item[1]) + deployments = ml_client.online_deployments.list(ep.name) + + for deployment_name in ordered_deployment_names: + for d in deployments: + if d.name == deployment_name: + model_family = get_model_type(d.model) + + if model_family is None: + continue + + deployment = Deployment(deployment_name=d.name, model_family=model_family) + endpoint.deployments.append(deployment) + + # Deployment are ordered by traffic level, first in is default + if endpoint.default_deployment is None: + endpoint.default_deployment = deployment + + if len(endpoint.deployments) > 0: + list_of_endpoints.append(endpoint) + + self.__endpoints_and_deployments = list_of_endpoints + return self.__endpoints_and_deployments + + def get_endpoint_url(self, endpoint_name, subscription_id, resource_group_name, workspace_name): + return f"https://ml.azure.com/endpoints/realtime/{endpoint_name}" \ + + f"/detail?wsid=/subscriptions/{subscription_id}" \ + + f"/resourceGroups/{resource_group_name}" \ + + f"/providers/Microsoft.MachineLearningServices/workspaces/{workspace_name}" + + def list_endpoint_names(self, + credential, + subscription_id, + resource_group_name, + workspace_name, + return_endpoint_url: bool = False + ) -> List[Dict[str, Union[str, int, float, list, Dict]]]: + '''Function for listing endpoints in the UX''' + endpoints_and_deployments = self.get_endpoints_and_deployments( + credential, + subscription_id, + resource_group_name, + workspace_name) + + result = [] + for e in endpoints_and_deployments: + result.append({ + "value": f"onlineEndpoint/{e.endpoint_name}", + "display_value": f"[Online] {e.endpoint_name}", + "hyperlink": self.get_endpoint_url(e.endpoint_name, + subscription_id, + resource_group_name, + workspace_name), + "description": f"Online Endpoint: {e.endpoint_name}", + }) + if return_endpoint_url: + result[-1]['url'] = e.endpoint_url + + return result + + def list_deployment_names(self, + credential, + subscription_id, + resource_group_name, + workspace_name, + endpoint_name: str + ) -> List[Dict[str, Union[str, int, float, list, Dict]]]: + '''Function for listing deployments in the UX''' + if endpoint_name is None: + return [] + + endpoints_and_deployments = self.get_endpoints_and_deployments( + credential, + subscription_id, + resource_group_name, + workspace_name) + for endpoint in endpoints_and_deployments: + if endpoint.endpoint_name == endpoint_name: + result = [] + for d in endpoint.deployments: + result.append({ + "value": d.deployment_name, + "display_value": d.deployment_name, + # "hyperlink": '', + "description": f"this is {d.deployment_name} item", + }) + return result + return [] + + +ENDPOINT_CONTAINER = EndpointsContainer() +CUSTOM_CONNECTION_CONTAINER = CustomConnectionsContainer() +SERVERLESS_ENDPOINT_CONTAINER = ServerlessEndpointsContainer() + + +def is_serverless_endpoint(endpoint_url: str) -> bool: + return "serverless.ml.azure.com" in endpoint_url or "inference.ai.azure.com" in endpoint_url + + +def try_get_from_dict(some_dict: Dict, key_list: List): + for key in key_list: + if some_dict is None: + return some_dict + elif key in some_dict: + some_dict = some_dict[key] + else: + return None + return some_dict + + +def parse_endpoint_connection_type(endpoint_connection_name: str) -> Tuple[str, str]: + endpoint_connection_details = endpoint_connection_name.split("/") + return (endpoint_connection_details[0].lower(), endpoint_connection_details[1]) + + +def list_endpoint_names(subscription_id: str, + resource_group_name: str, + workspace_name: str, + return_endpoint_url: bool = False) -> List[Dict[str, Union[str, int, float, list, Dict]]]: + cache_file_path = None + try: + with tempfile.NamedTemporaryFile(delete=False) as temp_file: + cache_file_path = os.path.join(os.path.dirname(temp_file.name), CONNECTION_CACHE_FILE) + print(f"Attempting to read connection cache. File path: {cache_file_path}", file=sys.stdout) + with open(cache_file_path, 'r') as file: + cache = ConnectionCache.from_filename(file) + if cache.can_use(subscription_id, resource_group_name, workspace_name): + if len(cache.connection_names) > 0: + print("....using Connection Cache File", file=sys.stdout) + return cache.connection_names + else: + print("....skipping. No connections in file", file=sys.stdout) + else: + print("....skipping. File not relevant", file=sys.stdout) + except Exception as e: + print(f"....failed to find\\read connection cache file. Regenerating. Error:{e}", file=sys.stdout) + + try: + from azure.identity import DefaultAzureCredential + credential = DefaultAzureCredential(exclude_interactive_browser_credential=False) + token = credential.get_token("https://management.azure.com/.default").token + except Exception as e: + print(f"Skipping list_endpoint_names. Exception: {e}", file=sys.stderr) + msg = "Exception getting token: Please retry" + return [{"value": msg, "display_value": msg, "description": msg}] + + serverless_endpoints = SERVERLESS_ENDPOINT_CONTAINER.list_serverless_endpoints(token, + subscription_id, + resource_group_name, + workspace_name, + return_endpoint_url) + online_endpoints = ENDPOINT_CONTAINER.list_endpoint_names(credential, + subscription_id, + resource_group_name, + workspace_name, + return_endpoint_url) + custom_connections = CUSTOM_CONNECTION_CONTAINER.list_custom_connection_names(credential, + subscription_id, + resource_group_name, + workspace_name, + return_endpoint_url) + + list_of_endpoints = custom_connections + serverless_endpoints + online_endpoints + + cache = ConnectionCache(use_until=(datetime.now() + timedelta(minutes=5)).isoformat(), + subscription_id=subscription_id, + resource_group=resource_group_name, + workspace_name=workspace_name, + connection_names=list_of_endpoints) + + if len(list_of_endpoints) == 0: + msg = "No endpoints found. Please add a connection." + return [{"value": msg, "display_value": msg, "description": msg}] + + if cache_file_path is not None: + try: + print(f"Attempting to write connection cache. File path: {cache_file_path}", file=sys.stdout) + with open(cache_file_path, 'w') as file: + json.dump(cache, file, default=lambda obj: obj.__dict__) + print("....written", file=sys.stdout) + except Exception as e: + print(f"""....failed to write connection cache file. Will need to reload next time. +Error:{e}""", file=sys.stdout) + + return list_of_endpoints + + +def list_deployment_names(subscription_id: str, + resource_group_name: str, + workspace_name: str, + endpoint: str = None) -> List[Dict[str, Union[str, int, float, list, Dict]]]: + deployment_default_list = [{ + "value": DEPLOYMENT_DEFAULT, + "display_value": DEPLOYMENT_DEFAULT, + "description": "This will use the default deployment for the selected online endpoint." + + "You can also manually enter a deployment name here." + }] + + if endpoint is None or endpoint.strip() == "" or "/" not in endpoint: + return deployment_default_list + + (endpoint_connection_type, endpoint_connection_name) = parse_endpoint_connection_type(endpoint) + if endpoint_connection_type != "onlineendpoint": + return deployment_default_list + + try: + from azure.identity import DefaultAzureCredential + credential = DefaultAzureCredential(exclude_interactive_browser_credential=False) + except Exception as e: + print(f"Skipping list_deployment_names. Exception: {e}", file=sys.stderr) + return deployment_default_list + + return deployment_default_list + ENDPOINT_CONTAINER.list_deployment_names( + credential, + subscription_id, + resource_group_name, + workspace_name, + endpoint_connection_name + ) + + def format_generic_response_payload(output: bytes, response_key: str) -> str: response_json = json.loads(output) try: @@ -80,7 +657,7 @@ def format_generic_response_payload(output: bytes, response_key: str) -> str: def get_model_type(deployment_model: str) -> str: m = re.match(r'azureml://registries/[^/]+/models/([^/]+)/versions/', deployment_model) if m is None: - print(f"Unexpected model format: {deployment_model}. Skipping") + print(f"Unexpected model format: {deployment_model}. Skipping", file=sys.stdout) return None model = m[1].lower() @@ -98,80 +675,15 @@ def get_model_type(deployment_model: str) -> str: return None -def get_deployment_from_endpoint(endpoint_name: str, deployment_name: str = None) -> Tuple[str, str, str]: - from azure.identity import DefaultAzureCredential - credential = DefaultAzureCredential(exclude_interactive_browser_credential=False) - - try: - from azure.ai.ml import MLClient - ml_client = MLClient( - credential=credential, - subscription_id=os.getenv("AZUREML_ARM_SUBSCRIPTION"), - resource_group_name=os.getenv("AZUREML_ARM_RESOURCEGROUP"), - workspace_name=os.getenv("AZUREML_ARM_WORKSPACE_NAME")) - except Exception as e: - message = "Unable to connect to AzureML. Please ensure the following environment variables are set: " - message += ",".join(ENDPOINT_REQUIRED_ENV_VARS) - message += "\nException: " + str(e) - raise OpenSourceLLMOnlineEndpointError(message=message) - - found = False - for ep in ml_client.online_endpoints.list(): - if ep.name == endpoint_name: - endpoint_uri = ep.scoring_uri - endpoint_key = ml_client.online_endpoints.get_keys(ep.name).primary_key - found = True - break - - if not found: - raise ValueError(f"Endpoint {endpoint_name} not found.") - - found = False - if deployment_name is None: - deployment_name = sorted(ep.traffic, key=lambda item: item[1])[0] - found = True - - for d in ml_client.online_deployments.list(ep.name): - if d.name == deployment_name: - model = get_model_type(d.model) - if model is None: - raise ValueError(f"Unexpected model format: {d.model}") - found = True - break - - if not found: - raise ValueError(f"Deployment {deployment_name} not found.") - - return (endpoint_uri, endpoint_key, model) - - -def get_deployment_from_connection(connection: CustomConnection) -> Tuple[str, str, str]: - conn_dict = dict(connection) - for key in REQUIRED_CONFIG_KEYS: - if key not in conn_dict: - accepted_keys = ",".join([key for key in REQUIRED_CONFIG_KEYS]) - raise OpenSourceLLMKeyValidationError( - message=f"""Required key `{key}` not found in given custom connection. -Required keys are: {accepted_keys}.""" - ) - for key in REQUIRED_SECRET_KEYS: - if key not in conn_dict: - accepted_keys = ",".join([key for key in REQUIRED_SECRET_KEYS]) - raise OpenSourceLLMKeyValidationError( - message=f"""Required secret key `{key}` not found in given custom connection. -Required keys are: {accepted_keys}.""" - ) +def validate_model_family(model_family: str): try: - model_family = ModelFamily[connection.configs['model_family']] + return ModelFamily[model_family] except KeyError: accepted_models = ",".join([model.name for model in ModelFamily]) raise OpenSourceLLMKeyValidationError( - message=f"""Given model_family '{connection.configs['model_family']}' not recognized. + message=f"""Given model_family '{model_family}' not recognized. Supported models are: {accepted_models}.""" ) - return (connection.configs['endpoint_url'], - connection.secrets['endpoint_api_key'], - model_family) class ModelFamily(str, Enum): @@ -180,6 +692,14 @@ class ModelFamily(str, Enum): GPT2 = "GPT-2" FALCON = "Falcon" + @classmethod + def _missing_(cls, value): + value = value.lower() + for member in cls: + if member.lower() == value: + return member + return None + class API(str, Enum): CHAT = "chat" @@ -205,6 +725,36 @@ def escape_special_characters(prompt: str) -> str: r'\\\1', prompt) + @staticmethod + def parse_chat(chat_str: str) -> List[Dict[str, str]]: + # LLaMa only supports below roles. + separator = r"(?i)\n*(system|user|assistant)\s*:\s*\n" + chunks = re.split(separator, chat_str) + + # remove any empty chunks + chunks = [c.strip() for c in chunks if c.strip()] + + chat_list = [] + for index in range(0, len(chunks), 2): + role = chunks[index].lower() + + # Check if prompt follows chat api message format and has valid role. + try: + validate_role(role, VALID_LLAMA_ROLES) + except ChatAPIInvalidRole as e: + raise OpenSourceLLMUserError(message=e.message) + + if len(chunks) <= index + 1: + message = "Unexpected chat format. Please ensure the query matches the chat format of the model used." + raise OpenSourceLLMUserError(message=message) + + chat_list.append({ + "role": role, + "content": chunks[index+1] + }) + + return chat_list + @abstractmethod def format_request_payload(self, prompt: str, model_kwargs: Dict) -> str: """Formats the request body according to the input schema of @@ -226,7 +776,7 @@ class GPT2ContentFormatter(ContentFormatterBase): def format_request_payload(self, prompt: str, model_kwargs: Dict) -> str: input_str = json.dumps( { - "inputs": {"input_string": [ContentFormatterBase.escape_special_characters(prompt)]}, + "input_data": {"input_string": [ContentFormatterBase.escape_special_characters(prompt)]}, "parameters": model_kwargs, } ) @@ -282,7 +832,7 @@ def format_request_payload(self, prompt: str, model_kwargs: Dict) -> str: model_kwargs["do_sample"] = True if self.api == API.CHAT: - prompt_value = parse_chat(self.chat_history, valid_roles=["assistant", "user", "system"]) + prompt_value = ContentFormatterBase.parse_chat(self.chat_history) else: prompt_value = [ContentFormatterBase.escape_special_characters(prompt)] @@ -310,14 +860,62 @@ def format_response_payload(self, output: bytes) -> str: raise OpenSourceLLMOnlineEndpointError(message=error_message) +class ServerlessLlamaContentFormatter(ContentFormatterBase): + """Content formatter for LLaMa""" + + def __init__(self, api: API, chat_history: Optional[str] = ""): + super().__init__() + self.api = api + self.chat_history = chat_history + self.model_id = "llama-2-7b-hf" + + def format_request_payload(self, prompt: str, model_kwargs: Dict) -> str: + """Formats the request according the the chosen api""" + # Modify max_tokens key for serverless + model_kwargs["max_tokens"] = model_kwargs["max_new_tokens"] + if self.api == API.CHAT: + messages = ContentFormatterBase.parse_chat(self.chat_history) + base_body = { + "model": self.model_id, + "messages": messages, + "n": 1, + } + base_body.update(model_kwargs) + + else: + prompt_value = ContentFormatterBase.escape_special_characters(prompt) + base_body = { + "prompt": prompt_value, + "n": 1, + } + base_body.update(model_kwargs) + + return json.dumps(base_body) + + def format_response_payload(self, output: bytes) -> str: + """Formats response""" + response_json = json.loads(output) + if self.api == API.CHAT and "choices" in response_json: + return response_json["choices"][0]["message"]["content"] + elif self.api == API.COMPLETION and "choices" in response_json: + return response_json["choices"][0]["text"] + else: + error_message = f"Unexpected response format. Response: {response_json}" + print(error_message, file=sys.stderr) + raise OpenSourceLLMOnlineEndpointError(message=error_message) + + class ContentFormatterFactory: """Factory class for supported models""" def get_content_formatter( - model_family: ModelFamily, api: API, chat_history: Optional[List[Dict]] = [] + model_family: ModelFamily, api: API, chat_history: Optional[List[Dict]] = [], endpoint_url: Optional[str] = "" ) -> ContentFormatterBase: if model_family == ModelFamily.LLAMA: - return LlamaContentFormatter(chat_history=chat_history, api=api) + if is_serverless_endpoint(endpoint_url): + return ServerlessLlamaContentFormatter(chat_history=chat_history, api=api) + else: + return LlamaContentFormatter(chat_history=chat_history, api=api) elif model_family == ModelFamily.DOLLY: return DollyContentFormatter() elif model_family == ModelFamily.GPT2: @@ -342,7 +940,7 @@ class AzureMLOnlineEndpoint: transform function to handle formats between the LLM and the endpoint""" - model_kwargs: Optional[Dict] = None + model_kwargs: Optional[Dict] = {} """Key word arguments to pass to the model.""" def __init__( @@ -352,7 +950,7 @@ def __init__( content_formatter: ContentFormatterBase, model_family: ModelFamily, deployment_name: Optional[str] = None, - model_kwargs: Optional[Dict] = None, + model_kwargs: Optional[Dict] = {}, ): self.endpoint_url = endpoint_url self.endpoint_api_key = endpoint_api_key @@ -361,35 +959,27 @@ def __init__( self.model_kwargs = model_kwargs self.model_family = model_family - @property - def _identifying_params(self) -> Mapping[str, Any]: - """Get the identifying parameters.""" - _model_kwargs = self.model_kwargs or {} - return { - **{"model_kwargs": _model_kwargs}, - } - - @property - def _llm_type(self) -> str: - """Return type of llm.""" - return "azureml_endpoint" - - def _call_endpoint(self, body: bytes) -> bytes: + def _call_endpoint(self, request_body: str) -> str: """call.""" headers = { "Content-Type": "application/json", "Authorization": ("Bearer " + self.endpoint_api_key), - "x-ms-user-agent": "PromptFlow/OpenSourceLLM/" + self.model_family} + "x-ms-user-agent": "PromptFlow/OpenSourceLLM/" + self.model_family + } # If this is not set it'll use the default deployment on the endpoint. if self.deployment_name is not None: headers["azureml-model-deployment"] = self.deployment_name - req = urllib.request.Request(self.endpoint_url, body, headers) - response = urllib.request.urlopen(req, timeout=50) - result = response.read() - return result + result = requests.post(self.endpoint_url, data=request_body, headers=headers) + if result.status_code != 200: + error_message = f"""Request failure while calling Online Endpoint Status:{result.status_code} +Error:{result.text}""" + print(error_message, file=sys.stderr) + raise OpenSourceLLMOnlineEndpointError(message=error_message) + + return result.text def __call__( self, @@ -404,11 +994,9 @@ def __call__( .. code-block:: python response = azureml_model("Tell me a joke.") """ - _model_kwargs = self.model_kwargs or {} - body = self.content_formatter.format_request_payload(prompt, _model_kwargs) - endpoint_request = str.encode(body) - endpoint_response = self._call_endpoint(endpoint_request) + request_body = self.content_formatter.format_request_payload(prompt, self.model_kwargs) + endpoint_response = self._call_endpoint(request_body) response = self.content_formatter.format_response_payload(endpoint_response) return response @@ -416,38 +1004,163 @@ def __call__( class OpenSourceLLM(ToolProvider): - def __init__(self, - connection: CustomConnection = None, - endpoint_name: str = None): + def __init__(self): super().__init__() - self.endpoint_key = None - self.endpoint_name = endpoint_name + def get_deployment_from_endpoint(self, + credential, + subscription_id: str, + resource_group_name: str, + workspace_name: str, + endpoint_name: str, + deployment_name: str = None) -> Tuple[str, str, str]: + + endpoints_and_deployments = ENDPOINT_CONTAINER.get_endpoints_and_deployments( + credential, + subscription_id, + resource_group_name, + workspace_name) + + for ep in endpoints_and_deployments: + if ep.endpoint_name == endpoint_name: + if deployment_name is None: + return (ep.endpoint_url, + ep.endpoint_key, + ep.default_deployment.model_family) + for d in ep.deployments: + if d.deployment_name == deployment_name: + return (ep.endpoint_url, + ep.endpoint_key, + d.model_family) + + message = f"""Invalid endpoint and deployment values. +Please ensure endpoint name and deployment names are correct, and the deployment was successfull. +Could not find endpoint: {endpoint_name} and deployment: {deployment_name}""" + raise OpenSourceLLMUserError(message=message) - if endpoint_name is None or endpoint_name == DEFAULT_ENDPOINT_NAME: - (self.endpoint_uri, - self.endpoint_key, - self.model_family) = get_deployment_from_connection(connection) + def sanitize_endpoint_url(self, + endpoint_url: str, + api_type: API): + + if is_serverless_endpoint(endpoint_url): + if api_type == API.CHAT: + if not endpoint_url.endswith("/v1/chat/completions"): + return endpoint_url + "/v1/chat/completions" + else: + if not endpoint_url.endswith("/v1/completions"): + return endpoint_url + "/v1/completions" + return endpoint_url + + def get_endpoint_details(self, + subscription_id: str, + resource_group_name: str, + workspace_name: str, + endpoint: str, + api_type: API, + deployment_name: str = None, + **kwargs) -> Tuple[str, str, str]: + if self.endpoint_values_in_kwargs(**kwargs): + endpoint_uri = kwargs["endpoint_uri"] + endpoint_key = kwargs["endpoint_key"] + model_family = kwargs["model_family"] + + # clean these up, aka don't send them to MIR + del kwargs["endpoint_uri"] + del kwargs["endpoint_key"] + del kwargs["model_family"] + + return (endpoint_uri, endpoint_key, model_family) + + (endpoint_connection_type, endpoint_connection_name) = parse_endpoint_connection_type(endpoint) + print(f"endpoint_connection_type: {endpoint_connection_type} name: {endpoint_connection_name}", file=sys.stdout) + + con_type = endpoint_connection_type.lower() + if con_type in AUTH_REQUIRED_CONNECTION_TYPES: + try: + from azure.identity import DefaultAzureCredential + credential = DefaultAzureCredential(exclude_interactive_browser_credential=False) + token = credential.get_token("https://management.azure.com/.default").token + except Exception as e: + message = f"""Error encountered while attempting to Authorize access to {endpoint}. +Exception: {e}""" + print(message, file=sys.stderr) + raise OpenSourceLLMUserError(message=message) + + if con_type == "serverlessendpoint": + (endpoint_url, endpoint_key, model_family) = SERVERLESS_ENDPOINT_CONTAINER.get_serverless_endpoint_key( + token, + subscription_id, + resource_group_name, + workspace_name, + endpoint_connection_name) + elif con_type == "onlineendpoint": + (endpoint_url, endpoint_key, model_family) = self.get_deployment_from_endpoint(credential, + subscription_id, + resource_group_name, + workspace_name, + endpoint_connection_name, + deployment_name) + elif con_type == "connection": + (endpoint_url, + endpoint_key, + model_family) = CUSTOM_CONNECTION_CONTAINER.get_endpoint_from_azure_custom_connection( + credential, + subscription_id, + resource_group_name, + workspace_name, + endpoint_connection_name) + elif con_type == "localconnection": + (endpoint_url, + endpoint_key, + model_family) = CUSTOM_CONNECTION_CONTAINER.get_endpoint_from_local_custom_connection( + endpoint_connection_name) + else: + raise OpenSourceLLMUserError(message=f"Invalid endpoint connection type: {endpoint_connection_type}") + return (self.sanitize_endpoint_url(endpoint_url, api_type), endpoint_key, model_family) + + def endpoint_values_in_kwargs(self, **kwargs): + # This is mostly for testing, suggest not using this since security\privacy concerns for the endpoint key + if 'endpoint_uri' not in kwargs and 'endpoint_key' not in kwargs and 'model_family' not in kwargs: + return False + + if 'endpoint_uri' not in kwargs or 'endpoint_key' not in kwargs or 'model_family' not in kwargs: + message = """Endpoint connection via kwargs not fully set. +If using kwargs, the following values must be set: endpoint_uri, endpoint_key, and model_family""" + raise OpenSourceLLMKeyValidationError(message=message) + + return True @tool - @handle_oneline_endpoint_error() + @handle_online_endpoint_error() def call( self, prompt: PromptTemplate, api: API, - deployment_name: str = None, - temperature: float = 1.0, - max_new_tokens: int = 500, - top_p: float = 1.0, + endpoint_name: str, + deployment_name: Optional[str] = None, + temperature: Optional[float] = 1.0, + max_new_tokens: Optional[int] = 500, + top_p: Optional[float] = 1.0, model_kwargs: Optional[Dict] = {}, **kwargs ) -> str: - self.deployment_name = deployment_name - - if self.endpoint_key is None and self.endpoint_name is not None: - (self.endpoint_uri, - self.endpoint_key, - self.model_family) = get_deployment_from_endpoint(self.endpoint_name, self.deployment_name) + # Sanitize deployment name. Empty deployment name is the same as None. + if deployment_name is not None: + deployment_name = deployment_name.strip() + if not deployment_name or deployment_name == DEPLOYMENT_DEFAULT: + deployment_name = None + + print(f"Executing Open Source LLM Tool for endpoint: '{endpoint_name}', deployment: '{deployment_name}'", + file=sys.stdout) + + (endpoint_uri, endpoint_key, model_family) = self.get_endpoint_details( + subscription_id=os.getenv("AZUREML_ARM_SUBSCRIPTION", None), + resource_group_name=os.getenv("AZUREML_ARM_RESOURCEGROUP", None), + workspace_name=os.getenv("AZUREML_ARM_WORKSPACE_NAME", None), + endpoint=endpoint_name, + api_type=api, + deployment_name=deployment_name, + **kwargs) prompt = render_jinja_template(prompt, trim_blocks=True, keep_trailing_newline=True, **kwargs) @@ -456,17 +1169,18 @@ def call( model_kwargs["max_new_tokens"] = max_new_tokens content_formatter = ContentFormatterFactory.get_content_formatter( - model_family=self.model_family, + model_family=model_family, api=api, - chat_history=prompt + chat_history=prompt, + endpoint_url=endpoint_uri ) llm = AzureMLOnlineEndpoint( - endpoint_url=self.endpoint_uri, - endpoint_api_key=self.endpoint_key, - model_family=self.model_family, + endpoint_url=endpoint_uri, + endpoint_api_key=endpoint_key, + model_family=model_family, content_formatter=content_formatter, - deployment_name=self.deployment_name, + deployment_name=deployment_name, model_kwargs=model_kwargs ) diff --git a/src/promptflow-tools/promptflow/tools/yamls/open_source_llm.yaml b/src/promptflow-tools/promptflow/tools/yamls/open_source_llm.yaml index 7ec2a257c5d..61a942e2eff 100644 --- a/src/promptflow-tools/promptflow/tools/yamls/open_source_llm.yaml +++ b/src/promptflow-tools/promptflow/tools/yamls/open_source_llm.yaml @@ -8,17 +8,26 @@ promptflow.tools.open_source_llm.OpenSourceLLM.call: function: call inputs: endpoint_name: - default: "-- please enter an endpoint name --" type: - string - connection: - default: null - type: - - CustomConnection + dynamic_list: + func_path: promptflow.tools.open_source_llm.list_endpoint_names + allow_manual_entry: true # Allow the user to clear this field + is_multi_select: false deployment_name: - default: null + default: '' type: - string + dynamic_list: + func_path: promptflow.tools.open_source_llm.list_deployment_names + func_kwargs: + - name: endpoint + type: + - string + optional: true + reference: ${inputs.endpoint} + allow_manual_entry: true + is_multi_select: false api: enum: - chat diff --git a/src/promptflow-tools/tests/conftest.py b/src/promptflow-tools/tests/conftest.py index 989095c86bf..cec414bad16 100644 --- a/src/promptflow-tools/tests/conftest.py +++ b/src/promptflow-tools/tests/conftest.py @@ -5,6 +5,8 @@ from pathlib import Path from pytest_mock import MockerFixture # noqa: E402 +from tests.utils import verify_url_exists + # Avoid circular dependencies: Use import 'from promptflow._internal' instead of 'from promptflow' # since the code here is in promptflow namespace as well from promptflow._internal import ConnectionManager @@ -50,22 +52,7 @@ def verify_oss_llm_custom_connection(connection: CustomConnection) -> bool: '''Verify that there is a MIR endpoint up and available for the Custom Connection. We explicitly do not pass the endpoint key to avoid the delay in generating a response. ''' - - import urllib.request - from urllib.request import HTTPError - from urllib.error import URLError - - try: - urllib.request.urlopen( - urllib.request.Request(connection.configs['endpoint_url']), - timeout=50) - except HTTPError as e: - # verify that the connection is not authorized, anything else would mean the endpoint is failed - return e.code == 403 - except URLError: - # Endpoint does not exist - skip the test - return False - raise Exception("Task Succeeded unexpectedly.") + return verify_url_exists(connection.configs['endpoint_url']) @pytest.fixture @@ -79,7 +66,7 @@ def llama_chat_custom_connection(): @pytest.fixture -def open_source_llm_ws_service_connection() -> None: +def open_source_llm_ws_service_connection() -> bool: try: creds_custom_connection: CustomConnection = ConnectionManager().get("open_source_llm_ws_service_connection") subs = json.loads(creds_custom_connection.secrets['service_credential']) @@ -87,10 +74,9 @@ def open_source_llm_ws_service_connection() -> None: os.environ[key] = value return True except Exception as e: - message = f"""=== Skipping Tests === -Something failed setting environment variables for service credentials. Error: {e}""" - print(message) - pytest.skip(message) + print(f"""Something failed setting environment variables for service credentials. +Error: {e}""") + return False @pytest.fixture(autouse=True) diff --git a/src/promptflow-tools/tests/test_open_source_llm.py b/src/promptflow-tools/tests/test_open_source_llm.py index 107b74ff1e9..f1056ab200a 100644 --- a/src/promptflow-tools/tests/test_open_source_llm.py +++ b/src/promptflow-tools/tests/test_open_source_llm.py @@ -1,30 +1,61 @@ import copy import os import pytest -from promptflow.tools.common import parse_chat +import re +from azure.identity import DefaultAzureCredential +from typing import List, Dict + from promptflow.tools.exception import ( - OpenSourceLLMOnlineEndpointError, - OpenSourceLLMKeyValidationError, - ChatAPIInvalidRole + OpenSourceLLMUserError, + OpenSourceLLMKeyValidationError +) +from promptflow.tools.open_source_llm import ( + OpenSourceLLM, + API, + ContentFormatterBase, + LlamaContentFormatter, + list_endpoint_names, + list_deployment_names, + CustomConnectionsContainer, + get_model_type, + ModelFamily, + ServerlessEndpointsContainer ) -from promptflow.tools.open_source_llm import OpenSourceLLM, API, ContentFormatterBase, get_model_type, ModelFamily -from typing import List, Dict -@pytest.fixture -def gpt2_provider(gpt2_custom_connection) -> OpenSourceLLM: - return OpenSourceLLM(gpt2_custom_connection) +def validate_response(response): + assert len(response) > 15 + + +def verify_prompt_role_delimiters(message: str, codes: List[str]): + assert codes == "UserError/OpenSourceLLMUserError".split("/") + + message_pattern = re.compile( + r"The Chat API requires a specific format for prompt definition, and the prompt should include separate " + + r"lines as role delimiters: ('(assistant|user|system):\\n'[,.]){3} Current parsed role 'in the context " + + r"of azure ml, what does the ml stand for\?' does not meet the requirement. If you intend to use the " + + r"Completion API, please select the appropriate API type and deployment name. If you do intend to use the " + + r"Chat API, please refer to the guideline at https://aka.ms/pfdoc/chat-prompt or view the samples in our " + + r"gallery that contain 'Chat' in the name.") + is_match = message_pattern.match(message) + assert is_match @pytest.fixture -def llama_chat_provider(llama_chat_custom_connection) -> OpenSourceLLM: - return OpenSourceLLM(llama_chat_custom_connection) +def verify_service_endpoints(open_source_llm_ws_service_connection) -> Dict[str, List[str]]: + if not open_source_llm_ws_service_connection: + pytest.skip("Service Credential not available") + print("open_source_llm_ws_service_connection completed") + required_env_vars = ["AZUREML_ARM_SUBSCRIPTION", "AZUREML_ARM_RESOURCEGROUP", "AZUREML_ARM_WORKSPACE_NAME", + "AZURE_CLIENT_ID", "AZURE_TENANT_ID", "AZURE_CLIENT_SECRET"] + for rev in required_env_vars: + if rev not in os.environ: + raise Exception(f"test not setup correctly. Missing Required Environment Variable:{rev}") @pytest.fixture -def endpoints_provider(open_source_llm_ws_service_connection) -> Dict[str, List[str]]: +def endpoints_provider(verify_service_endpoints) -> Dict[str, List[str]]: from azure.ai.ml import MLClient - from azure.identity import DefaultAzureCredential credential = DefaultAzureCredential(exclude_interactive_browser_credential=False) ml_client = MLClient( credential=credential, @@ -73,6 +104,10 @@ def completion_endpoints_provider(endpoints_provider: Dict[str, List[str]]) -> D @pytest.mark.usefixtures("use_secrets_config_file") class TestOpenSourceLLM: + stateless_os_llm = OpenSourceLLM() + gpt2_connection = "connection/gpt2_connection" + llama_connection = "connection/llama_chat_connection" + llama_serverless_connection = "connection/llama_chat_serverless" completion_prompt = "In the context of Azure ML, what does the ML stand for?" chat_prompt = """system: You are a AI which helps Customers answer questions. @@ -80,51 +115,52 @@ class TestOpenSourceLLM: user: """ + completion_prompt - @pytest.mark.skip_if_no_api_key("gpt2_custom_connection") - def test_open_source_llm_completion(self, gpt2_provider): - response = gpt2_provider.call( + def test_open_source_llm_completion(self, verify_service_endpoints): + response = self.stateless_os_llm.call( self.completion_prompt, - API.COMPLETION) - assert len(response) > 25 + API.COMPLETION, + endpoint_name=self.gpt2_connection) + validate_response(response) - @pytest.mark.skip_if_no_api_key("gpt2_custom_connection") - def test_open_source_llm_completion_with_deploy(self, gpt2_provider): - response = gpt2_provider.call( + def test_open_source_llm_completion_with_deploy(self, verify_service_endpoints): + response = self.stateless_os_llm.call( self.completion_prompt, API.COMPLETION, - deployment_name="gpt2-9") - assert len(response) > 25 + endpoint_name=self.gpt2_connection, + deployment_name="gpt2-10") + validate_response(response) - @pytest.mark.skip_if_no_api_key("gpt2_custom_connection") - def test_open_source_llm_chat(self, gpt2_provider): - response = gpt2_provider.call( + def test_open_source_llm_chat(self, verify_service_endpoints): + response = self.stateless_os_llm.call( self.chat_prompt, - API.CHAT) - assert len(response) > 25 + API.CHAT, + endpoint_name=self.gpt2_connection) + validate_response(response) - @pytest.mark.skip_if_no_api_key("gpt2_custom_connection") - def test_open_source_llm_chat_with_deploy(self, gpt2_provider): - response = gpt2_provider.call( + def test_open_source_llm_chat_with_deploy(self, verify_service_endpoints): + response = self.stateless_os_llm.call( self.chat_prompt, API.CHAT, - deployment_name="gpt2-9") - assert len(response) > 25 + endpoint_name=self.gpt2_connection, + deployment_name="gpt2-10") + validate_response(response) - @pytest.mark.skip_if_no_api_key("gpt2_custom_connection") - def test_open_source_llm_chat_with_max_length(self, gpt2_provider): - response = gpt2_provider.call( + def test_open_source_llm_chat_with_max_length(self, verify_service_endpoints): + response = self.stateless_os_llm.call( self.chat_prompt, API.CHAT, + endpoint_name=self.gpt2_connection, max_new_tokens=2) - assert len(response) > 25 + # GPT-2 doesn't take this parameter + validate_response(response) @pytest.mark.skip_if_no_api_key("gpt2_custom_connection") def test_open_source_llm_con_url_chat(self, gpt2_custom_connection): tmp = copy.deepcopy(gpt2_custom_connection) del tmp.configs['endpoint_url'] with pytest.raises(OpenSourceLLMKeyValidationError) as exc_info: - os = OpenSourceLLM(tmp) - os.call(self.chat_prompt, API.CHAT) + customConnectionsContainer = CustomConnectionsContainer() + customConnectionsContainer.get_endpoint_from_custom_connection(connection=tmp) assert exc_info.value.message == """Required key `endpoint_url` not found in given custom connection. Required keys are: endpoint_url,model_family.""" assert exc_info.value.error_codes == "UserError/ToolValidationError/OpenSourceLLMKeyValidationError".split("/") @@ -134,8 +170,8 @@ def test_open_source_llm_con_key_chat(self, gpt2_custom_connection): tmp = copy.deepcopy(gpt2_custom_connection) del tmp.secrets['endpoint_api_key'] with pytest.raises(OpenSourceLLMKeyValidationError) as exc_info: - os = OpenSourceLLM(tmp) - os.call(self.chat_prompt, API.CHAT) + customConnectionsContainer = CustomConnectionsContainer() + customConnectionsContainer.get_endpoint_from_custom_connection(connection=tmp) assert exc_info.value.message == ( "Required secret key `endpoint_api_key` " + """not found in given custom connection. @@ -147,8 +183,8 @@ def test_open_source_llm_con_model_chat(self, gpt2_custom_connection): tmp = copy.deepcopy(gpt2_custom_connection) del tmp.configs['model_family'] with pytest.raises(OpenSourceLLMKeyValidationError) as exc_info: - os = OpenSourceLLM(tmp) - os.call(self.completion_prompt, API.COMPLETION) + customConnectionsContainer = CustomConnectionsContainer() + customConnectionsContainer.get_endpoint_from_custom_connection(connection=tmp) assert exc_info.value.message == """Required key `model_family` not found in given custom connection. Required keys are: endpoint_url,model_family.""" assert exc_info.value.error_codes == "UserError/ToolValidationError/OpenSourceLLMKeyValidationError".split("/") @@ -159,8 +195,7 @@ def test_open_source_llm_escape_chat(self): assert out_of_danger == "The quick \\brown fox\\tjumped\\\\over \\the \\\\boy\\r\\n" def test_open_source_llm_llama_parse_chat_with_chat(self): - parsed_chat = parse_chat(self.chat_prompt, valid_roles=["system", "user", "assistant"]) - assert len(parsed_chat) == 2 + LlamaContentFormatter.parse_chat(self.chat_prompt) def test_open_source_llm_llama_parse_multi_turn(self): multi_turn_chat = """user: @@ -172,88 +207,79 @@ def test_open_source_llm_llama_parse_multi_turn(self): Mobius, which starred Jared Leto user: -Why was that the greatest movie of all time?""" - parsed_chat = parse_chat(multi_turn_chat, valid_roles=["system", "user", "assistant"]) - assert len(parsed_chat) == 3 +Why was that the greatest movie of all time? +""" + LlamaContentFormatter.parse_chat(multi_turn_chat) - def test_open_source_llm_llama_parse_chat_with_comp(self): - with pytest.raises(ChatAPIInvalidRole) as exc_info: - parse_chat(self.completion_prompt, valid_roles=["system", "user", "assistant"]) - assert exc_info.value.message == ( - "The Chat API requires a specific format for prompt definition, and the " - + "prompt should include separate lines as role delimiters: 'system:\\n','user:\\n','assistant:\\n'. " - + "Current parsed role 'in the context of azure ml, what does the ml stand for?' does not " - + "meet the requirement. If you intend to use the Completion API, please select the appropriate API type " - + "and deployment name. If you do intend to use the Chat API, please refer to the guideline at " - + "https://aka.ms/pfdoc/chat-prompt or view the samples in our gallery that contain 'Chat' in the name.") + def test_open_source_llm_llama_parse_ignore_whitespace(self): + bad_chat_prompt = f"""system: +You are a AI which helps Customers answer questions. - assert exc_info.value.error_codes == "UserError/ToolValidationError/ChatAPIInvalidRole".split("/") +user: - @pytest.mark.skip_if_no_api_key("gpt2_custom_connection") - def test_open_source_llm_llama_endpoint_miss(self, gpt2_custom_connection): - tmp = copy.deepcopy(gpt2_custom_connection) - tmp.configs['endpoint_url'] += 'completely/real/endpoint' - os = OpenSourceLLM(tmp) - with pytest.raises(OpenSourceLLMOnlineEndpointError) as exc_info: - os.call( - self.completion_prompt, - API.COMPLETION) - assert exc_info.value.message == ( - "Exception hit calling Oneline Endpoint: " - + "HTTPError: HTTP Error 424: Failed Dependency") - assert exc_info.value.error_codes == "UserError/OpenSourceLLMOnlineEndpointError".split("/") +user: +{self.completion_prompt}""" + with pytest.raises(OpenSourceLLMUserError) as exc_info: + LlamaContentFormatter.parse_chat(bad_chat_prompt) + verify_prompt_role_delimiters(exc_info.value.message, exc_info.value.error_codes) - @pytest.mark.skip_if_no_api_key("gpt2_custom_connection") - def test_open_source_llm_llama_deployment_miss(self, gpt2_provider): - with pytest.raises(OpenSourceLLMOnlineEndpointError) as exc_info: - gpt2_provider.call(self.completion_prompt, - API.COMPLETION, - deployment_name="completely/real/deployment-007") - assert exc_info.value.message == ( - "Exception hit calling Oneline Endpoint: " - + "HTTPError: HTTP Error 404: Not Found") - assert exc_info.value.error_codes == "UserError/OpenSourceLLMOnlineEndpointError".split("/") + def test_open_source_llm_llama_parse_chat_with_comp(self): + with pytest.raises(OpenSourceLLMUserError) as exc_info: + LlamaContentFormatter.parse_chat(self.completion_prompt) + verify_prompt_role_delimiters(exc_info.value.message, exc_info.value.error_codes) def test_open_source_llm_chat_endpoint_name(self, chat_endpoints_provider): for endpoint_name in chat_endpoints_provider: - os_llm = OpenSourceLLM(endpoint_name=endpoint_name) - response = os_llm.call(self.chat_prompt, API.CHAT) - assert len(response) > 25 + response = self.stateless_os_llm.call( + self.chat_prompt, + API.CHAT, + endpoint_name=f"onlineEndpoint/{endpoint_name}") + validate_response(response) def test_open_source_llm_chat_endpoint_name_with_deployment(self, chat_endpoints_provider): for endpoint_name in chat_endpoints_provider: - os_llm = OpenSourceLLM(endpoint_name=endpoint_name) for deployment_name in chat_endpoints_provider[endpoint_name]: - response = os_llm.call(self.chat_prompt, API.CHAT, deployment_name=deployment_name) - assert len(response) > 25 + response = self.stateless_os_llm.call( + self.chat_prompt, + API.CHAT, + endpoint_name=f"onlineEndpoint/{endpoint_name}", + deployment_name=deployment_name) + validate_response(response) def test_open_source_llm_completion_endpoint_name(self, completion_endpoints_provider): for endpoint_name in completion_endpoints_provider: - os_llm = OpenSourceLLM(endpoint_name=endpoint_name) - response = os_llm.call(self.completion_prompt, API.COMPLETION) - assert len(response) > 25 + response = self.stateless_os_llm.call( + self.completion_prompt, + API.COMPLETION, + endpoint_name=f"onlineEndpoint/{endpoint_name}") + validate_response(response) def test_open_source_llm_completion_endpoint_name_with_deployment(self, completion_endpoints_provider): for endpoint_name in completion_endpoints_provider: - os_llm = OpenSourceLLM(endpoint_name=endpoint_name) for deployment_name in completion_endpoints_provider[endpoint_name]: - response = os_llm.call(self.completion_prompt, API.COMPLETION, deployment_name=deployment_name) - assert len(response) > 25 - - @pytest.mark.skip_if_no_api_key("llama_chat_custom_connection") - def test_open_source_llm_llama_chat(self, llama_chat_provider): - response = llama_chat_provider.call(self.chat_prompt, API.CHAT) - assert len(response) > 25 + response = self.stateless_os_llm.call( + self.completion_prompt, + API.COMPLETION, + endpoint_name=f"onlineEndpoint/{endpoint_name}", + deployment_name=deployment_name) + validate_response(response) + + def test_open_source_llm_llama_chat(self, verify_service_endpoints): + response = self.stateless_os_llm.call(self.chat_prompt, API.CHAT, endpoint_name=self.llama_connection) + validate_response(response) + + def test_open_source_llm_llama_serverless(self, verify_service_endpoints): + response = self.stateless_os_llm.call( + self.chat_prompt, + API.CHAT, + endpoint_name=self.llama_serverless_connection) + validate_response(response) - @pytest.mark.skip_if_no_api_key("llama_chat_custom_connection") - def test_open_source_llm_llama_chat_history(self, llama_chat_provider): - chat_history_prompt = """user: + def test_open_source_llm_llama_chat_history(self, verify_service_endpoints): + chat_history_prompt = """system: * Given the following conversation history and the users next question, answer the next question. -If the conversation is irrelevant or empty, just restate the original question. -Do not add more details than necessary to the question. - -assistant: -skip +* If the conversation is irrelevant or empty, acknowledge and ask for more input. +* Do not add more details than necessary to the question. chat history: {% for item in chat_history %} @@ -266,9 +292,10 @@ def test_open_source_llm_llama_chat_history(self, llama_chat_provider): user: {{ chat_input }}""" - response = llama_chat_provider.call( + response = self.stateless_os_llm.call( chat_history_prompt, API.CHAT, + endpoint_name=self.llama_connection, chat_history=[ { "inputs": @@ -298,7 +325,143 @@ def test_open_source_llm_llama_chat_history(self, llama_chat_provider): } ], chat_input="Sorry I didn't follow, could you say that again?") - assert len(response) > 25 + validate_response(response) + + def test_open_source_llm_dynamic_list_ignore_deployment(self, verify_service_endpoints): + deployments = list_deployment_names( + subscription_id=os.getenv("AZUREML_ARM_SUBSCRIPTION"), + resource_group_name=os.getenv("AZUREML_ARM_RESOURCEGROUP"), + workspace_name=os.getenv("AZUREML_ARM_WORKSPACE_NAME"), + endpoint=None) + assert len(deployments) == 1 + assert deployments[0]['value'] == 'default' + + deployments = list_deployment_names( + subscription_id=os.getenv("AZUREML_ARM_SUBSCRIPTION"), + resource_group_name=os.getenv("AZUREML_ARM_RESOURCEGROUP"), + workspace_name=os.getenv("AZUREML_ARM_WORKSPACE_NAME"), + endpoint='') + assert len(deployments) == 1 + assert deployments[0]['value'] == 'default' + + deployments = list_deployment_names( + subscription_id=os.getenv("AZUREML_ARM_SUBSCRIPTION"), + resource_group_name=os.getenv("AZUREML_ARM_RESOURCEGROUP"), + workspace_name=os.getenv("AZUREML_ARM_WORKSPACE_NAME"), + endpoint='fake_endpoint name') + assert len(deployments) == 1 + assert deployments[0]['value'] == 'default' + + def test_open_source_llm_dynamic_list_serverless_test(self, verify_service_endpoints): + subscription_id = os.getenv("AZUREML_ARM_SUBSCRIPTION") + resource_group_name = os.getenv("AZUREML_ARM_RESOURCEGROUP") + workspace_name = os.getenv("AZUREML_ARM_WORKSPACE_NAME") + + se_container = ServerlessEndpointsContainer() + credential = DefaultAzureCredential(exclude_interactive_browser_credential=False) + token = credential.get_token("https://management.azure.com/.default").token + + eps = se_container.list_serverless_endpoints( + token, + subscription_id, + resource_group_name, + workspace_name) + + if len(eps) == 0: + pytest.skip("Service Credential not available") + + endpoint_connection_name = eps[0]["value"].replace("serverlessEndpoint/", "") + + eps_keys = se_container._list_endpoint_key( + token, + subscription_id, + resource_group_name, + workspace_name, + endpoint_connection_name + ) + assert len(eps_keys) == 2 + + (endpoint_url, endpoint_key, model_family) = se_container.get_serverless_endpoint_key( + token, + subscription_id, + resource_group_name, + workspace_name, + endpoint_connection_name) + + assert len(endpoint_url) > 20 + assert model_family == "LLaMa" + assert endpoint_key == eps_keys['primaryKey'] + + def test_open_source_llm_dynamic_list_custom_connections_test(self, verify_service_endpoints): + custom_container = CustomConnectionsContainer() + credential = DefaultAzureCredential(exclude_interactive_browser_credential=False) + + connections = custom_container.list_custom_connection_names( + credential, + subscription_id=os.getenv("AZUREML_ARM_SUBSCRIPTION"), + resource_group_name=os.getenv("AZUREML_ARM_RESOURCEGROUP"), + workspace_name=os.getenv("AZUREML_ARM_WORKSPACE_NAME")) + assert len(connections) > 1 + + def test_open_source_llm_dynamic_list_happy_path(self, verify_service_endpoints): + endpoints = list_endpoint_names( + subscription_id=os.getenv("AZUREML_ARM_SUBSCRIPTION"), + resource_group_name=os.getenv("AZUREML_ARM_RESOURCEGROUP"), + workspace_name=os.getenv("AZUREML_ARM_WORKSPACE_NAME"), + return_endpoint_url=True + ) + # we might want to remove this or skip if there are zero endpoints in the long term. + # currently we have low cost compute for a GPT2 endpoint, so if nothing else this should be available. + assert len(endpoints) > 0 + for endpoint in endpoints: + assert "value" in endpoint + assert "display_value" in endpoint + assert "description" in endpoint + + from tests.utils import verify_url_exists + for endpoint in endpoints: + if not verify_url_exists(endpoint["url"]): + continue + + is_chat = "serverless" in endpoint['value'] or "chat" in endpoint['value'] + + if is_chat: + prompt = self.chat_prompt + api_type = API.CHAT + else: + prompt = self.completion_prompt + api_type = API.COMPLETION + + # test with default endpoint + response = self.stateless_os_llm.call( + prompt, + api_type, + endpoint_name=endpoint['value'], + max_new_tokens=10, + model_kwargs={}) + validate_response(response) + + deployments = list_deployment_names( + subscription_id=os.getenv("AZUREML_ARM_SUBSCRIPTION"), + resource_group_name=os.getenv("AZUREML_ARM_RESOURCEGROUP"), + workspace_name=os.getenv("AZUREML_ARM_WORKSPACE_NAME"), + endpoint=endpoint['value']) + if "onlineEndpoint" in endpoint['value']: + assert len(deployments) > 0 + else: + assert len(deployments) == 1 + assert deployments[0]['value'] == 'default' + continue + + for deployment in deployments: + response = self.stateless_os_llm.call( + prompt, + api_type, + endpoint_name=endpoint['value'], + deployment_name=deployment['value'], + max_new_tokens=10, + model_kwargs={}) + validate_response(response) def test_open_source_llm_get_model_llama(self): model_assets = [ diff --git a/src/promptflow-tools/tests/utils.py b/src/promptflow-tools/tests/utils.py index 411cc4b8739..21cd90232ef 100644 --- a/src/promptflow-tools/tests/utils.py +++ b/src/promptflow-tools/tests/utils.py @@ -16,3 +16,21 @@ def is_json_serializable(data, function_name): json.dumps(data) except TypeError: raise TypeError(f"{function_name} output is not JSON serializable!") + + +def verify_url_exists(endpoint_url: str) -> bool: + import urllib.request + from urllib.request import HTTPError + from urllib.error import URLError + + try: + urllib.request.urlopen( + urllib.request.Request(endpoint_url), + timeout=50) + except HTTPError as e: + # verify that the connection is not authorized, anything else would mean the endpoint is failed + return e.code == 403 + except URLError: + # Endpoint does not exist - skip the test + return False + raise Exception("Task Succeeded unexpectedly.")