├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md └── kendra_retriever_samples ├── README.md ├── __init__.py ├── app.py ├── environment.yml ├── images ├── ai-icon.png └── user-icon.png ├── ja ├── README.md ├── __init__.py ├── app.py ├── images │ ├── ai-icon.png │ └── user-icon.png ├── kendra_chat_bedrock_claude.py ├── kendra_chat_bedrock_claudev2.py ├── kendra_chat_falcon_40b.py └── kendra_chat_open_ai.py ├── kendra-docs-index.yaml ├── kendra_chat_anthropic.py ├── kendra_chat_bedrock_claudev2.py ├── kendra_chat_bedrock_claudev3.py ├── kendra_chat_bedrock_llama2.py ├── kendra_chat_bedrock_titan.py ├── kendra_chat_falcon_40b.py ├── kendra_chat_llama_2.py ├── kendra_chat_llama_2_neuron.py ├── kendra_chat_open_ai.py ├── kendra_retriever_anthropic.py ├── kendra_retriever_falcon_40b.py ├── kendra_retriever_open_ai.py └── requirements.txt /.gitignore: -------------------------------------------------------------------------------- 1 | *.egg-info/ 2 | 3 | ### Python ### 4 | # Byte-compiled / optimized / DLL files 5 | __pycache__/ 6 | *.py[cod] 7 | *$py.class 8 | 9 | # C extensions 10 | *.so 11 | 12 | # Distribution / packaging 13 | .Python 14 | build/ 15 | develop-eggs/ 16 | dist/ 17 | downloads/ 18 | eggs/ 19 | .eggs/ 20 | lib/ 21 | lib64/ 22 | parts/ 23 | sdist/ 24 | var/ 25 | wheels/ 26 | pip-wheel-metadata/ 27 | share/python-wheels/ 28 | .installed.cfg 29 | *.egg 30 | MANIFEST 31 | 32 | # PyInstaller 33 | # Usually these files are written by a python script from a template 34 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 35 | *.manifest 36 | *.spec 37 | 38 | # Installer logs 39 | pip-log.txt 40 | pip-delete-this-directory.txt 41 | 42 | # Unit test / coverage reports 43 | htmlcov/ 44 | .tox/ 45 | .nox/ 46 | .coverage 47 | .coverage.* 48 | .cache 49 | nosetests.xml 50 | coverage.xml 51 | *.cover 52 | .hypothesis/ 53 | .pytest_cache/ 54 | 55 | # Translations 56 | *.mo 57 | *.pot 58 | 59 | # Scrapy stuff: 60 | .scrapy 61 | 62 | # Sphinx documentation 63 | docs/_build/ 64 | 65 | # PyBuilder 66 | target/ 67 | 68 | # pyenv 69 | .python-version 70 | 71 | # mypy 72 | .mypy_cache/ 73 | .dmypy.json 74 | dmypy.json 75 | 76 | # Pyre type checker 77 | .pyre/ 78 | 79 | # End of https://www.gitignore.io/api/python 80 | 81 | # OSX files 82 | .DS_Store 83 | 84 | # vs code 85 | .vscode 86 | 87 | # venv files 88 | env* 89 | .venv 90 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *main* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT No Attribution 2 | 3 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 13 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 14 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 15 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 16 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AWS Kendra Langchain Extensions 2 | 3 | ## kendra_retriever_samples 4 | This directory contains samples for a QA chain using an `AmazonKendraRetriever` class. For more info see the samples [README](./kendra_retriever_samples/README.md). 5 | **Note**: If you are using an older version of the repo which contains the `aws_langchain` package, please clone this repo in a new location to avoid any conflicts with the older environment. We are deprecating the `aws_langchain` package, since the kendra retriever class is available in LangChain starting v0.0.213. 6 | 7 | For detials of the implementation please refer to blog : https://aws.amazon.com/blogs/machine-learning/quickly-build-high-accuracy-generative-ai-applications-on-enterprise-data-using-amazon-kendra-langchain-and-large-language-models/ 8 | -------------------------------------------------------------------------------- /kendra_retriever_samples/README.md: -------------------------------------------------------------------------------- 1 | # AWS Langchain 2 | This repo provides a set of samples to work with [Langchain](https://github.com/hwchase17/langchain/tree/master) and Amazon Kendra. It currently has samples for working with a [Kendra retriever class](https://python.langchain.com/docs/integrations/retrievers/amazon_kendra_retriever) to execute a QA chain for SageMaker, Open AI and Anthropic providers. 3 | 4 | ## Installing 5 | 6 | Clone the repository 7 | ```bash 8 | git clone https://github.com/aws-samples/amazon-kendra-langchain-extensions.git 9 | ``` 10 | 11 | Move to the repo dir 12 | ```bash 13 | cd amazon-kendra-langchain-extensions 14 | ``` 15 | 16 | Move to the samples dir 17 | ```bash 18 | cd kendra_retriever_samples 19 | ``` 20 | 21 | Install the dependencies 22 | 23 | If you are using pip 24 | ```bash 25 | pip install -r requirements.txt 26 | ``` 27 | 28 | If you are using Conda 29 | ```bash 30 | conda env create -f environment.yml 31 | ``` 32 | 33 | ### For Bedrock 34 | If you are using Bedrock, make sure that you update to the latest boto3 and langchain version with bedrock support and you use an AWS_PROFILE that has access to bedrock. 35 | 36 | ``` 37 | pip install --force-reinstall "langchain>=0.0.306" 38 | pip install --force-reinstall "boto3>=1.28.57" 39 | ``` 40 | 41 | ## Running samples 42 | Before you run the sample, you need to deploy a Large Language Model (or get an API key if you using Anthropic or OPENAI). The samples in this repository have been tested on models deployed using SageMaker JumpStart. 43 | 44 | With the latest sagemaker release each endpoint can hold multiple models (called InferenceComponent). For JumpStart models, optionally specify the INFERENCE_COMPONENT_NAME as well as an environment variable. When you deploy JumpStart models from the new Studio console, you need to specify the environment variable INFERENCE_COMPONENT_NAME. When you deploy JumpStart models from the Studio Classic console or using the SDK, you do not need to specify the environment variable INFERENCE_COMPONENT_NAME. 45 | 46 | The model id for the LLMs are specified in the table below. 47 | 48 | | Model Name | Env Var Name | Endpoint Name | Inference Component Name (Optional) | streamlit Provider Name | 49 | | -----------| -------- | ------------------ | ----------------- |----------------- | 50 | | Falcon 40B instruct | FALCON_40B_ENDPOINT, INFERENCE_COMPONENT_NAME | | | falcon40b | 51 | | Llama2 70B instruct | LLAMA_2_ENDPOINT, INFERENCE_COMPONENT_NAME | | | llama2 | 52 | | Bedrock Titan | None | | | bedrock_titan | 53 | | Bedrock Claude V2 | None | | | bedrock_claudev2 | 54 | | Bedrock Claude V3 Haiku | None | | | bedrock_claudev3_haiku | 55 | | Bedrock Claude V3 Sonnet | None | | | bedrock_claudev3_sonnet | 56 | | Bedrock Llama2 13b | None | | | bedrock_llama2_13b | 57 | | Bedrock Llama2 70b | None | | | bedrock_llama2_70b | 58 | 59 | After deploying the LLM, set up environment variables for kendra id, aws region, endpoint name (or the API key for an external provider), and optionally the inference component name. 60 | 61 | For example, for running the `kendra_chat_llama_2.py` sample, these environment variables must be set: AWS_REGION, KENDRA_INDEX_ID, LLAMA_2_ENDPOINT, and INFERENCE_COMPONENT_NAME (if you deploy JumpStart model from the new Studio console). 62 | 63 | You can use commands as below to set the environment variables. Only set the environment variable for the provider that you are using. For example, if you are using Falcon 40B, only set the FALCON_40B_ENDPOINT. There is no need to set the other Endpoints and keys. 64 | 65 | ```bash 66 | export AWS_REGION= 67 | export AWS_PROFILE= 68 | export KENDRA_INDEX_ID= 69 | 70 | export FALCON_40B_ENDPOINT= # only if you are using falcon as the endpoint 71 | export LLAMA_2_ENDPOINT= #only if you are using llama2 as the endpoint 72 | export INFERENCE_COMPONENT_NAME= # only if you are deploying the FM via the new Studio console. 73 | 74 | export OPENAI_API_KEY= # only if you are using OPENAI as the endpoint 75 | export ANTHROPIC_API_KEY= # only if you are using Anthropic as the endpoint 76 | ``` 77 | 78 | 79 | ### Running samples from the streamlit app 80 | The samples directory is bundled with an `app.py` file that can be run as a web app using streamlit. 81 | 82 | ```bash 83 | streamlit run app.py llama2 84 | ``` 85 | 86 | The above command will run the `kendra_chat_llama_2` as the LLM chain. In order to run a different chain, pass a different provider, for example for running the `open_ai` chain run this command `streamlit run app.py openai`. Use the column 'streamlit provider name' from the table above to find out the provider name 87 | 88 | 89 | 90 | ### Running samples from the command line 91 | ```bash 92 | python 93 | ``` 94 | 95 | ## Contributing 96 | Create your fork and submit your changes via a pull request. 97 | See [CONTRIBUTING](../CONTRIBUTING.md) for more information. 98 | 99 | ## License 100 | This library is licensed under the MIT-0 License. See the LICENSE file. 101 | 102 | -------------------------------------------------------------------------------- /kendra_retriever_samples/__init__.py: -------------------------------------------------------------------------------- 1 | """Sample chains for AWS Langchain integration""" -------------------------------------------------------------------------------- /kendra_retriever_samples/app.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import uuid 3 | 4 | import kendra_chat_anthropic as anthropic 5 | import kendra_chat_bedrock_claudev2 as bedrock_claudev2 6 | import kendra_chat_bedrock_claudev3 as bedrock_claudev3 7 | import kendra_chat_bedrock_llama2 as bedrock_llama2 8 | import kendra_chat_bedrock_titan as bedrock_titan 9 | import kendra_chat_falcon_40b as falcon40b 10 | import kendra_chat_llama_2 as llama2 11 | import kendra_chat_llama_2_neuron as llama2_n 12 | import kendra_chat_open_ai as openai 13 | import streamlit as st 14 | 15 | USER_ICON = "images/user-icon.png" 16 | AI_ICON = "images/ai-icon.png" 17 | MAX_HISTORY_LENGTH = 5 18 | PROVIDER_MAP = { 19 | 'openai': 'Open AI', 20 | 'anthropic': 'Anthropic', 21 | 'falcon40b': 'Falcon 40B', 22 | 'llama2' : 'Llama 2' 23 | } 24 | 25 | #function to read a properties file and create environment variables 26 | def read_properties_file(filename): 27 | import os 28 | import re 29 | with open(filename, 'r') as f: 30 | for line in f: 31 | m = re.match(r'^\s*(\w+)\s*=\s*(.*)\s*$', line) 32 | if m: 33 | os.environ[m.group(1)] = m.group(2) 34 | 35 | 36 | # Check if the user ID is already stored in the session state 37 | if 'user_id' in st.session_state: 38 | user_id = st.session_state['user_id'] 39 | 40 | # If the user ID is not yet stored in the session state, generate a random UUID 41 | else: 42 | user_id = str(uuid.uuid4()) 43 | st.session_state['user_id'] = user_id 44 | 45 | 46 | if 'llm_chain' not in st.session_state: 47 | if (len(sys.argv) > 1): 48 | if (sys.argv[1] == 'anthropic'): 49 | st.session_state['llm_app'] = anthropic 50 | st.session_state['llm_chain'] = anthropic.build_chain() 51 | elif (sys.argv[1] == 'openai'): 52 | st.session_state['llm_app'] = openai 53 | st.session_state['llm_chain'] = openai.build_chain() 54 | elif (sys.argv[1] == 'falcon40b'): 55 | st.session_state['llm_app'] = falcon40b 56 | st.session_state['llm_chain'] = falcon40b.build_chain() 57 | elif (sys.argv[1] == 'llama2'): 58 | st.session_state['llm_app'] = llama2 59 | st.session_state['llm_chain'] = llama2.build_chain() 60 | elif (sys.argv[1] == 'llama2_n'): 61 | st.session_state['llm_app'] = llama2_n 62 | st.session_state['llm_chain'] = llama2_n.build_chain() 63 | elif (sys.argv[1] == 'bedrock_titan'): 64 | st.session_state['llm_app'] = bedrock_titan 65 | st.session_state['llm_chain'] = bedrock_titan.build_chain() 66 | elif (sys.argv[1] == 'bedrock_claudev2'): 67 | st.session_state['llm_app'] = bedrock_claudev2 68 | st.session_state['llm_chain'] = bedrock_claudev2.build_chain() 69 | elif (sys.argv[1] == 'bedrock_claudev3_haiku'): 70 | st.session_state['llm_app'] = bedrock_claudev3 71 | st.session_state['llm_chain'] = bedrock_claudev3.build_chain_haiku() 72 | elif (sys.argv[1] == 'bedrock_claudev3_sonnet'): 73 | st.session_state['llm_app'] = bedrock_claudev3 74 | st.session_state['llm_chain'] = bedrock_claudev3.build_chain_sonnet() 75 | elif (sys.argv[1] == 'bedrock_llama2_70b'): 76 | st.session_state['llm_app'] = bedrock_llama2 77 | st.session_state['llm_chain'] = bedrock_llama2.build_chain_llama2_70B() 78 | elif (sys.argv[1] == 'bedrock_llama2_13b'): 79 | st.session_state['llm_app'] = bedrock_llama2 80 | st.session_state['llm_chain'] = bedrock_llama2.build_chain_llama2_13B() 81 | else: 82 | raise Exception("Unsupported LLM: ", sys.argv[1]) 83 | else: 84 | raise Exception("Usage: streamlit run app.py ") 85 | 86 | if 'chat_history' not in st.session_state: 87 | st.session_state['chat_history'] = [] 88 | 89 | if "chats" not in st.session_state: 90 | st.session_state.chats = [ 91 | { 92 | 'id': 0, 93 | 'question': '', 94 | 'answer': '' 95 | } 96 | ] 97 | 98 | if "questions" not in st.session_state: 99 | st.session_state.questions = [] 100 | 101 | if "answers" not in st.session_state: 102 | st.session_state.answers = [] 103 | 104 | if "input" not in st.session_state: 105 | st.session_state.input = "" 106 | 107 | 108 | st.markdown(""" 109 | 124 | """, unsafe_allow_html=True) 125 | 126 | def write_logo(): 127 | col1, col2, col3 = st.columns([5, 1, 5]) 128 | with col2: 129 | st.image(AI_ICON, use_column_width='always') 130 | 131 | 132 | def write_top_bar(): 133 | col1, col2, col3 = st.columns([1,10,2]) 134 | with col1: 135 | st.image(AI_ICON, use_column_width='always') 136 | with col2: 137 | selected_provider = sys.argv[1] 138 | if selected_provider in PROVIDER_MAP: 139 | provider = PROVIDER_MAP[selected_provider] 140 | else: 141 | provider = selected_provider.capitalize() 142 | header = f"An AI App powered by Amazon Kendra and {provider}!" 143 | st.write(f"

{header}

", unsafe_allow_html=True) 144 | with col3: 145 | clear = st.button("Clear Chat") 146 | return clear 147 | 148 | clear = write_top_bar() 149 | 150 | if clear: 151 | st.session_state.questions = [] 152 | st.session_state.answers = [] 153 | st.session_state.input = "" 154 | st.session_state["chat_history"] = [] 155 | 156 | def handle_input(): 157 | input = st.session_state.input 158 | question_with_id = { 159 | 'question': input, 160 | 'id': len(st.session_state.questions) 161 | } 162 | st.session_state.questions.append(question_with_id) 163 | 164 | chat_history = st.session_state["chat_history"] 165 | if len(chat_history) == MAX_HISTORY_LENGTH: 166 | chat_history = chat_history[:-1] 167 | 168 | llm_chain = st.session_state['llm_chain'] 169 | chain = st.session_state['llm_app'] 170 | result = chain.run_chain(llm_chain, input, chat_history) 171 | answer = result['answer'] 172 | chat_history.append((input, answer)) 173 | 174 | document_list = [] 175 | if 'source_documents' in result: 176 | for d in result['source_documents']: 177 | if not (d.metadata['source'] in document_list): 178 | document_list.append((d.metadata['source'])) 179 | 180 | st.session_state.answers.append({ 181 | 'answer': result, 182 | 'sources': document_list, 183 | 'id': len(st.session_state.questions) 184 | }) 185 | st.session_state.input = "" 186 | 187 | def write_user_message(md): 188 | col1, col2 = st.columns([1,12]) 189 | 190 | with col1: 191 | st.image(USER_ICON, use_column_width='always') 192 | with col2: 193 | st.warning(md['question']) 194 | 195 | 196 | def render_result(result): 197 | answer, sources = st.tabs(['Answer', 'Sources']) 198 | with answer: 199 | render_answer(result['answer']) 200 | with sources: 201 | if 'source_documents' in result: 202 | render_sources(result['source_documents']) 203 | else: 204 | render_sources([]) 205 | 206 | def render_answer(answer): 207 | col1, col2 = st.columns([1,12]) 208 | with col1: 209 | st.image(AI_ICON, use_column_width='always') 210 | with col2: 211 | st.info(answer['answer']) 212 | 213 | def render_sources(sources): 214 | col1, col2 = st.columns([1,12]) 215 | with col2: 216 | with st.expander("Sources"): 217 | for s in sources: 218 | st.write(s) 219 | 220 | 221 | #Each answer will have context of the question asked in order to associate the provided feedback with the respective question 222 | def write_chat_message(md, q): 223 | chat = st.container() 224 | with chat: 225 | render_answer(md['answer']) 226 | render_sources(md['sources']) 227 | 228 | 229 | with st.container(): 230 | for (q, a) in zip(st.session_state.questions, st.session_state.answers): 231 | write_user_message(q) 232 | write_chat_message(a, q) 233 | 234 | st.markdown('---') 235 | input = st.text_input("You are talking to an AI, ask any question.", key="input", on_change=handle_input) 236 | -------------------------------------------------------------------------------- /kendra_retriever_samples/environment.yml: -------------------------------------------------------------------------------- 1 | name: kendra-retriever-samples 2 | channels: 3 | - https://conda.anaconda.org/conda-forge 4 | dependencies: 5 | - python=3.10 6 | - pip 7 | - pip: 8 | - langchain>=0.1.16 9 | - boto3>=1.28.27 10 | - openai 11 | - anthropic 12 | - streamlit 13 | - langchain-community>=0.0.33 14 | - langchain-core>=0.1.43 15 | -------------------------------------------------------------------------------- /kendra_retriever_samples/images/ai-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-kendra-langchain-extensions/224ce17cb92bec4cce46c2a6cc045020a271e872/kendra_retriever_samples/images/ai-icon.png -------------------------------------------------------------------------------- /kendra_retriever_samples/images/user-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-kendra-langchain-extensions/224ce17cb92bec4cce46c2a6cc045020a271e872/kendra_retriever_samples/images/user-icon.png -------------------------------------------------------------------------------- /kendra_retriever_samples/ja/README.md: -------------------------------------------------------------------------------- 1 | # AWS Langchain 2 | このリポジトリは [Langchain](https://github.com/hwchase17/langchain/tree/master) と Amazon Kendra を利用するためのサンプルを提供します。 3 | 現在、SageMaker、OpenAI、および Anthropic プロバイダー向けに QA チェーンを実行するための [Kendra retriever クラス](https://python.langchain.com/docs/modules/data_connection/retrievers/integrations/amazon_kendra_retriever)のサンプルが含まれています。 4 | 5 | ## インストール 6 | 7 | リポジトリをクローンします 8 | ```bash 9 | git clone https://github.com/aws-samples/amazon-kendra-langchain-extensions.git 10 | ``` 11 | 12 | リポジトリのあるディレクトリに移動します 13 | ```bash 14 | cd amazon-kendra-langchain-extensions 15 | ``` 16 | 17 | サンプルディレクトリに移動します 18 | ```bash 19 | cd kendra_retriever_samples 20 | ``` 21 | 22 | 依存関係をインストールします 23 | 24 | pip を使用する場合 25 | ```bash 26 | pip install -r requirements.txt 27 | ``` 28 | 29 | Conda を利用する場合 30 | ```bash 31 | conda env create -f environment.yml 32 | ``` 33 | 34 | ### Bedrock の場合 35 | Bedrock を使用する場合、Bedrock サポートを持つ最新の boto3 および langchain バージョンに更新し、Bedrock へのアクセス権を持つ AWS_PROFILE を使用していることを確認してください。 36 | 37 | ``` 38 | pip install --force-reinstall "langchain>=0.0.306" 39 | pip install --force-reinstall "boto3>=1.28.57" 40 | ``` 41 | 42 | ## サンプルの実行 43 | サンプルを実行する前に、Large Language Model をデプロイする(または Anthropic や OpenAI を使用する場合は API キーを取得する)必要があります。このリポジトリのサンプルは、SageMaker Jumpstart と Amazon Bedrock を使用して展開されたモデルでテストされています。 LLM のモデル ID は以下の表にまとめられています。 44 | 45 | | モデル名 | 環境変数名 | Jumpstart モデル ID | streamlit プロバイダ | 日本語対応 | 46 | | ------------------- | ------------------- | ---------------------------------------- | -------------------- | ---------- | 47 | | Falcon 40B instruct | FALCON_40B_ENDPOINT | huggingface-llm-falcon-40b-instruct-bf16 | falcon40b | 48 | | Bedrock Claude | None | | bedrock_claude | 49 | | Bedrock Claude V2 | None | | bedrock_claudev2 | 50 | 51 | LLMをデプロイした後、kendra ID、aws_region、エンドポイント名(または外部プロバイダーの API キー)の環境変数を設定する必要があります。 52 | 53 | 例えば、`kendra_chat_open_ai.py` のサンプルを実行する場合、以下の環境変数を設定する必要があります 54 | - AWS_REGION 55 | - KENDRA_INDEX_ID 56 | - OPENAI_API_KEY 57 | 58 | 以下のコマンドを使用して環境変数を設定できます。使用するプロバイダーの環境変数のみを設定します。たとえば、Flan-xl を使用する場合は FLAN_XXL_ENDPOINT のみを設定します。他のエンドポイントとキーは設定する必要はありません。 59 | 60 | ```bash 61 | export LANGUAGE_CODE=ja 62 | export AWS_REGION= 63 | export AWS_PROFILE= 64 | export KENDRA_INDEX_ID= 65 | 66 | export FALCON_40B_ENDPOINT= # only if you are using falcon as the endpoint 67 | export OPENAI_API_KEY= # only if you are using OPENAI as the endpoint 68 | ``` 69 | 70 | 71 | ### streamlit アプリからのサンプルの実行(日本語未対応) 72 | サンプルディレクトリには、streamlit を使用してウェブアプリとして実行できる `app.py` ファイルが含まれています。 73 | 74 | ```bash 75 | streamlit run app.py falcon40b 76 | ``` 77 | 78 | 上記のコマンドは、LLM チェーンとして `kendra_chat_falcon_40b` を実行します。異なるチェーンを実行するには、異なるプロバイダーを渡してください。たとえば、`open_ai` チェーンを実行する場合は `streamlit run app.py openai` を実行します。テーブル上の「streamlitプロバイダ名」列を活用してプロバイダ名を確認してください。 79 | 80 | ### コマンドラインからのサンプルの実行 81 | ```bash 82 | python 83 | ``` 84 | 85 | ## Contributing 86 | このリポジトリのフォークを作成して、変更内容をプルリクエストで提出してください。 87 | 詳細については、[CONTRIBUTING](../CONTRIBUTING.md) を参照してください。 88 | 89 | ## License 90 | このライブラリは MIT-0 ライセンスのもとで提供されています。詳細は LICENSE ファイルをご覧ください。 91 | -------------------------------------------------------------------------------- /kendra_retriever_samples/ja/__init__.py: -------------------------------------------------------------------------------- 1 | """Sample chains for AWS Langchain integration""" -------------------------------------------------------------------------------- /kendra_retriever_samples/ja/app.py: -------------------------------------------------------------------------------- 1 | import streamlit as st 2 | import uuid 3 | import sys 4 | import kendra_chat_open_ai as openai 5 | import kendra_chat_falcon_40b as falcon40b 6 | import kendra_chat_bedrock_claude as bedrock_claude 7 | import kendra_chat_bedrock_claudev2 as bedrock_claudev2 8 | 9 | 10 | USER_ICON = "images/user-icon.png" 11 | AI_ICON = "images/ai-icon.png" 12 | MAX_HISTORY_LENGTH = 5 13 | PROVIDER_MAP = { 14 | "openai": "Open AI", 15 | "falcon40b": "Falcon 40B", 16 | } 17 | 18 | 19 | # function to read a properties file and create environment variables 20 | def read_properties_file(filename): 21 | import os 22 | import re 23 | 24 | with open(filename, "r") as f: 25 | for line in f: 26 | m = re.match(r"^\s*(\w+)\s*=\s*(.*)\s*$", line) 27 | if m: 28 | os.environ[m.group(1)] = m.group(2) 29 | 30 | 31 | # Check if the user ID is already stored in the session state 32 | if "user_id" in st.session_state: 33 | user_id = st.session_state["user_id"] 34 | 35 | # If the user ID is not yet stored in the session state, generate a random UUID 36 | else: 37 | user_id = str(uuid.uuid4()) 38 | st.session_state["user_id"] = user_id 39 | 40 | 41 | if "llm_chain" not in st.session_state: 42 | if len(sys.argv) > 1: 43 | if sys.argv[1] == "openai": 44 | st.session_state["llm_app"] = openai 45 | st.session_state["llm_chain"] = openai.build_chain() 46 | elif sys.argv[1] == "falcon40b": 47 | st.session_state["llm_app"] = falcon40b 48 | st.session_state["llm_chain"] = falcon40b.build_chain() 49 | elif sys.argv[1] == "bedrock_claude": 50 | st.session_state["llm_app"] = bedrock_claude 51 | st.session_state["llm_chain"] = bedrock_claude.build_chain() 52 | elif sys.argv[1] == "bedrock_claudev2": 53 | st.session_state["llm_app"] = bedrock_claudev2 54 | st.session_state["llm_chain"] = bedrock_claudev2.build_chain() 55 | else: 56 | raise Exception("Unsupported LLM: ", sys.argv[1]) 57 | else: 58 | raise Exception("Usage: streamlit run app.py ") 59 | 60 | 61 | if "chat_history" not in st.session_state: 62 | st.session_state["chat_history"] = [] 63 | 64 | if "chats" not in st.session_state: 65 | st.session_state.chats = [{"id": 0, "question": "", "answer": ""}] 66 | 67 | if "questions" not in st.session_state: 68 | st.session_state.questions = [] 69 | 70 | if "answers" not in st.session_state: 71 | st.session_state.answers = [] 72 | 73 | if "input" not in st.session_state: 74 | st.session_state.input = "" 75 | 76 | 77 | st.markdown( 78 | """ 79 | 94 | """, 95 | unsafe_allow_html=True, 96 | ) 97 | 98 | 99 | def write_logo(): 100 | col1, col2, col3 = st.columns([5, 1, 5]) 101 | with col2: 102 | st.image(AI_ICON, use_column_width="always") 103 | 104 | 105 | def write_top_bar(): 106 | col1, col2, col3 = st.columns([1, 10, 2]) 107 | with col1: 108 | st.image(AI_ICON, use_column_width="always") 109 | with col2: 110 | selected_provider = sys.argv[1] 111 | if selected_provider in PROVIDER_MAP: 112 | provider = PROVIDER_MAP[selected_provider] 113 | else: 114 | provider = selected_provider.capitalize() 115 | header = f"An AI App powered by Amazon Kendra and {provider}!" 116 | st.write(f"

{header}

", unsafe_allow_html=True) 117 | with col3: 118 | clear = st.button("Clear Chat") 119 | return clear 120 | 121 | 122 | clear = write_top_bar() 123 | 124 | if clear: 125 | st.session_state.questions = [] 126 | st.session_state.answers = [] 127 | st.session_state.input = "" 128 | st.session_state["chat_history"] = [] 129 | 130 | 131 | def handle_input(): 132 | input = st.session_state.input 133 | question_with_id = {"question": input, "id": len(st.session_state.questions)} 134 | st.session_state.questions.append(question_with_id) 135 | 136 | chat_history = st.session_state["chat_history"] 137 | if len(chat_history) == MAX_HISTORY_LENGTH: 138 | chat_history = chat_history[:-1] 139 | 140 | llm_chain = st.session_state["llm_chain"] 141 | chain = st.session_state["llm_app"] 142 | result = chain.run_chain(llm_chain, input, chat_history) 143 | answer = result["answer"] 144 | chat_history.append((input, answer)) 145 | 146 | document_list = [] 147 | if "source_documents" in result: 148 | for d in result["source_documents"]: 149 | if not (d.metadata["source"] in document_list): 150 | document_list.append((d.metadata["source"])) 151 | 152 | st.session_state.answers.append( 153 | { 154 | "answer": result, 155 | "sources": document_list, 156 | "id": len(st.session_state.questions), 157 | } 158 | ) 159 | st.session_state.input = "" 160 | 161 | 162 | def write_user_message(md): 163 | col1, col2 = st.columns([1, 12]) 164 | 165 | with col1: 166 | st.image(USER_ICON, use_column_width="always") 167 | with col2: 168 | st.warning(md["question"]) 169 | 170 | 171 | def render_result(result): 172 | answer, sources = st.tabs(["Answer", "Sources"]) 173 | with answer: 174 | render_answer(result["answer"]) 175 | with sources: 176 | if "source_documents" in result: 177 | render_sources(result["source_documents"]) 178 | else: 179 | render_sources([]) 180 | 181 | 182 | def render_answer(answer): 183 | col1, col2 = st.columns([1, 12]) 184 | with col1: 185 | st.image(AI_ICON, use_column_width="always") 186 | with col2: 187 | st.info(answer["answer"]) 188 | 189 | 190 | def render_sources(sources): 191 | col1, col2 = st.columns([1, 12]) 192 | with col2: 193 | with st.expander("Sources"): 194 | for s in sources: 195 | st.write(s) 196 | 197 | 198 | # Each answer will have context of the question asked in order to associate the provided feedback with the respective question 199 | def write_chat_message(md, q): 200 | chat = st.container() 201 | with chat: 202 | render_answer(md["answer"]) 203 | render_sources(md["sources"]) 204 | 205 | 206 | with st.container(): 207 | for q, a in zip(st.session_state.questions, st.session_state.answers): 208 | write_user_message(q) 209 | write_chat_message(a, q) 210 | 211 | st.markdown("---") 212 | input = st.text_input( 213 | "You are talking to an AI, ask any question.", key="input", on_change=handle_input 214 | ) 215 | -------------------------------------------------------------------------------- /kendra_retriever_samples/ja/images/ai-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-kendra-langchain-extensions/224ce17cb92bec4cce46c2a6cc045020a271e872/kendra_retriever_samples/ja/images/ai-icon.png -------------------------------------------------------------------------------- /kendra_retriever_samples/ja/images/user-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-kendra-langchain-extensions/224ce17cb92bec4cce46c2a6cc045020a271e872/kendra_retriever_samples/ja/images/user-icon.png -------------------------------------------------------------------------------- /kendra_retriever_samples/ja/kendra_chat_bedrock_claude.py: -------------------------------------------------------------------------------- 1 | # from aws_langchain.kendra import AmazonKendraRetriever #custom library 2 | from langchain.retrievers import AmazonKendraRetriever 3 | from langchain.chains import ConversationalRetrievalChain 4 | from langchain.prompts import PromptTemplate 5 | from langchain.llms.bedrock import Bedrock 6 | from langchain.chains.llm import LLMChain 7 | import sys 8 | import os 9 | 10 | 11 | class bcolors: 12 | HEADER = "\033[95m" 13 | OKBLUE = "\033[94m" 14 | OKCYAN = "\033[96m" 15 | OKGREEN = "\033[92m" 16 | WARNING = "\033[93m" 17 | FAIL = "\033[91m" 18 | ENDC = "\033[0m" 19 | BOLD = "\033[1m" 20 | UNDERLINE = "\033[4m" 21 | 22 | 23 | MAX_HISTORY_LENGTH = 5 24 | 25 | 26 | def build_chain(): 27 | region = os.environ["AWS_REGION"] 28 | kendra_index_id = os.environ["KENDRA_INDEX_ID"] 29 | credentials_profile_name = os.environ["AWS_PROFILE"] 30 | language_code = os.environ["LANGUAGE_CODE"] 31 | 32 | llm = Bedrock( 33 | credentials_profile_name=credentials_profile_name, 34 | region_name=region, 35 | model_kwargs={ 36 | "max_tokens_to_sample": 300, 37 | "temperature": 1, 38 | "top_k": 250, 39 | "top_p": 0.999, 40 | "anthropic_version": "bedrock-2023-05-31", 41 | }, 42 | model_id="anthropic.claude-v1", 43 | ) 44 | 45 | retriever = AmazonKendraRetriever( 46 | index_id=kendra_index_id, 47 | top_k=5, 48 | region_name=region, 49 | attribute_filter={ 50 | "EqualsTo": { 51 | "Key": "_language_code", 52 | "Value": {"StringValue": language_code}, 53 | } 54 | }, 55 | ) 56 | 57 | prompt_template = """ 58 | システム: システムは資料から抜粋して質問に答えます。資料にない内容には答えず、正直に「わかりません」と答えます。 59 | 60 | {context} 61 | 62 | 上記の資料に基づいて以下の質問について資料から抜粋して回答を生成します。資料にない内容には答えず「わかりません」と答えます。 63 | ユーザー: {question} 64 | システム: 65 | """ 66 | PROMPT = PromptTemplate( 67 | template=prompt_template, input_variables=["context", "question"] 68 | ) 69 | 70 | condense_qa_template = """ 71 | 次のような会話とフォローアップの質問に基づいて、フォローアップの質問を独立した質問に言い換えてください。 72 | 73 | フォローアップの質問: {question} 74 | 独立した質問:""" 75 | standalone_question_prompt = PromptTemplate.from_template(condense_qa_template) 76 | 77 | qa = ConversationalRetrievalChain.from_llm( 78 | llm=llm, 79 | retriever=retriever, 80 | condense_question_prompt=standalone_question_prompt, 81 | return_source_documents=True, 82 | combine_docs_chain_kwargs={"prompt": PROMPT}, 83 | verbose=True, 84 | ) 85 | 86 | return qa 87 | 88 | 89 | def run_chain(chain, prompt: str, history=[]): 90 | return chain({"question": prompt, "chat_history": history}) 91 | 92 | 93 | if __name__ == "__main__": 94 | chat_history = [] 95 | qa = build_chain() 96 | print(bcolors.OKBLUE + "Hello! How can I help you?" + bcolors.ENDC) 97 | print( 98 | bcolors.OKCYAN 99 | + "Ask a question, start a New search: or CTRL-D to exit." 100 | + bcolors.ENDC 101 | ) 102 | print(">", end=" ", flush=True) 103 | for query in sys.stdin: 104 | if query.strip().lower().startswith("new search:"): 105 | query = query.strip().lower().replace("new search:", "") 106 | chat_history = [] 107 | elif len(chat_history) == MAX_HISTORY_LENGTH: 108 | chat_history.pop(0) 109 | result = run_chain(qa, query, chat_history) 110 | chat_history.append((query, result["answer"])) 111 | print(bcolors.OKGREEN + result["answer"] + bcolors.ENDC) 112 | if "source_documents" in result: 113 | print(bcolors.OKGREEN + "Sources:") 114 | for d in result["source_documents"]: 115 | print(d.metadata["source"]) 116 | print(bcolors.ENDC) 117 | print( 118 | bcolors.OKCYAN 119 | + "Ask a question, start a New search: or CTRL-D to exit." 120 | + bcolors.ENDC 121 | ) 122 | print(">", end=" ", flush=True) 123 | print(bcolors.OKBLUE + "Bye" + bcolors.ENDC) 124 | -------------------------------------------------------------------------------- /kendra_retriever_samples/ja/kendra_chat_bedrock_claudev2.py: -------------------------------------------------------------------------------- 1 | # from aws_langchain.kendra import AmazonKendraRetriever #custom library 2 | from langchain.retrievers import AmazonKendraRetriever 3 | from langchain.chains import ConversationalRetrievalChain 4 | from langchain.prompts import PromptTemplate 5 | from langchain.llms.bedrock import Bedrock 6 | from langchain.chains.llm import LLMChain 7 | import sys 8 | import os 9 | 10 | 11 | class bcolors: 12 | HEADER = "\033[95m" 13 | OKBLUE = "\033[94m" 14 | OKCYAN = "\033[96m" 15 | OKGREEN = "\033[92m" 16 | WARNING = "\033[93m" 17 | FAIL = "\033[91m" 18 | ENDC = "\033[0m" 19 | BOLD = "\033[1m" 20 | UNDERLINE = "\033[4m" 21 | 22 | 23 | MAX_HISTORY_LENGTH = 5 24 | 25 | 26 | def build_chain(): 27 | region = os.environ["AWS_REGION"] 28 | kendra_index_id = os.environ["KENDRA_INDEX_ID"] 29 | credentials_profile_name = os.environ["AWS_PROFILE"] 30 | language_code = os.environ["LANGUAGE_CODE"] 31 | 32 | llm = Bedrock( 33 | credentials_profile_name=credentials_profile_name, 34 | region_name=region, 35 | model_kwargs={ 36 | "max_tokens_to_sample": 300, 37 | "temperature": 1, 38 | "top_k": 250, 39 | "top_p": 0.999, 40 | "anthropic_version": "bedrock-2023-05-31", 41 | }, 42 | model_id="anthropic.claude-v2", 43 | ) 44 | 45 | retriever = AmazonKendraRetriever( 46 | index_id=kendra_index_id, 47 | top_k=5, 48 | region_name=region, 49 | attribute_filter={ 50 | "EqualsTo": { 51 | "Key": "_language_code", 52 | "Value": {"StringValue": language_code}, 53 | } 54 | }, 55 | ) 56 | 57 | prompt_template = """ 58 | システム: システムは資料から抜粋して質問に答えます。資料にない内容には答えず、正直に「わかりません」と答えます。 59 | 60 | {context} 61 | 62 | 上記の資料に基づいて以下の質問について資料から抜粋して回答を生成します。資料にない内容には答えず「わかりません」と答えます。 63 | ユーザー: {question} 64 | システム: 65 | """ 66 | PROMPT = PromptTemplate( 67 | template=prompt_template, input_variables=["context", "question"] 68 | ) 69 | 70 | condense_qa_template = """ 71 | 次のような会話とフォローアップの質問に基づいて、フォローアップの質問を独立した質問に言い換えてください。 72 | 73 | フォローアップの質問: {question} 74 | 独立した質問:""" 75 | standalone_question_prompt = PromptTemplate.from_template(condense_qa_template) 76 | 77 | qa = ConversationalRetrievalChain.from_llm( 78 | llm=llm, 79 | retriever=retriever, 80 | condense_question_prompt=standalone_question_prompt, 81 | return_source_documents=True, 82 | combine_docs_chain_kwargs={"prompt": PROMPT}, 83 | verbose=True, 84 | ) 85 | 86 | return qa 87 | 88 | 89 | def run_chain(chain, prompt: str, history=[]): 90 | return chain({"question": prompt, "chat_history": history}) 91 | 92 | 93 | if __name__ == "__main__": 94 | chat_history = [] 95 | qa = build_chain() 96 | print(bcolors.OKBLUE + "Hello! How can I help you?" + bcolors.ENDC) 97 | print( 98 | bcolors.OKCYAN 99 | + "Ask a question, start a New search: or CTRL-D to exit." 100 | + bcolors.ENDC 101 | ) 102 | print(">", end=" ", flush=True) 103 | for query in sys.stdin: 104 | if query.strip().lower().startswith("new search:"): 105 | query = query.strip().lower().replace("new search:", "") 106 | chat_history = [] 107 | elif len(chat_history) == MAX_HISTORY_LENGTH: 108 | chat_history.pop(0) 109 | result = run_chain(qa, query, chat_history) 110 | chat_history.append((query, result["answer"])) 111 | print(bcolors.OKGREEN + result["answer"] + bcolors.ENDC) 112 | if "source_documents" in result: 113 | print(bcolors.OKGREEN + "Sources:") 114 | for d in result["source_documents"]: 115 | print(d.metadata["source"]) 116 | print(bcolors.ENDC) 117 | print( 118 | bcolors.OKCYAN 119 | + "Ask a question, start a New search: or CTRL-D to exit." 120 | + bcolors.ENDC 121 | ) 122 | print(">", end=" ", flush=True) 123 | print(bcolors.OKBLUE + "Bye" + bcolors.ENDC) 124 | -------------------------------------------------------------------------------- /kendra_retriever_samples/ja/kendra_chat_falcon_40b.py: -------------------------------------------------------------------------------- 1 | from langchain.retrievers import AmazonKendraRetriever 2 | from langchain.chains import ConversationalRetrievalChain 3 | from langchain import SagemakerEndpoint 4 | from langchain.llms.sagemaker_endpoint import LLMContentHandler 5 | from langchain.prompts import PromptTemplate 6 | import sys 7 | import json 8 | import os 9 | 10 | 11 | class bcolors: 12 | HEADER = "\033[95m" 13 | OKBLUE = "\033[94m" 14 | OKCYAN = "\033[96m" 15 | OKGREEN = "\033[92m" 16 | WARNING = "\033[93m" 17 | FAIL = "\033[91m" 18 | ENDC = "\033[0m" 19 | BOLD = "\033[1m" 20 | UNDERLINE = "\033[4m" 21 | 22 | 23 | MAX_HISTORY_LENGTH = 5 24 | 25 | 26 | def build_chain(): 27 | region = os.environ["AWS_REGION"] 28 | kendra_index_id = os.environ["KENDRA_INDEX_ID"] 29 | endpoint_name = os.environ["FALCON_40B_ENDPOINT"] 30 | language_code = os.environ["LANGUAGE_CODE"] 31 | 32 | class ContentHandler(LLMContentHandler): 33 | content_type = "application/json" 34 | accepts = "application/json" 35 | 36 | def transform_input(self, prompt: str, model_kwargs: dict) -> bytes: 37 | input_str = json.dumps({"inputs": prompt, "parameters": model_kwargs}) 38 | return input_str.encode("utf-8") 39 | 40 | def transform_output(self, output: bytes) -> str: 41 | response_json = json.loads(output.read().decode("utf-8")) 42 | return response_json[0]["generated_text"] 43 | 44 | content_handler = ContentHandler() 45 | 46 | llm = SagemakerEndpoint( 47 | endpoint_name=endpoint_name, 48 | region_name=region, 49 | model_kwargs={ 50 | "temperature": 0.8, 51 | "max_new_tokens": 512, 52 | "do_sample": True, 53 | "top_p": 0.9, 54 | "repetition_penalty": 1.03, 55 | "stop": ["\nUser:", "<|endoftext|>", ""], 56 | }, 57 | content_handler=content_handler, 58 | ) 59 | 60 | retriever = AmazonKendraRetriever( 61 | index_id=kendra_index_id, 62 | region_name=region, 63 | top_k=1, 64 | attribute_filter={ 65 | "EqualsTo": { 66 | "Key": "_language_code", 67 | "Value": {"StringValue": language_code}, 68 | } 69 | }, 70 | ) 71 | 72 | prompt_template = """ 73 | システム: システムは資料から抜粋して質問に答えます。資料にない内容には答えず、正直に「わかりません」と答えます。 74 | 75 | {context} 76 | 77 | 上記の資料に基づいて以下の質問について資料から抜粋して回答を生成します。資料にない内容には答えず「わかりません」と答えます。 78 | ユーザー: {question} 79 | システム: 80 | """ 81 | PROMPT = PromptTemplate( 82 | template=prompt_template, input_variables=["context", "question"] 83 | ) 84 | 85 | condense_qa_template = """ 86 | 次のような会話とフォローアップの質問に基づいて、フォローアップの質問を独立した質問に言い換えてください。 87 | 88 | フォローアップの質問: {question} 89 | 独立した質問:""" 90 | standalone_question_prompt = PromptTemplate.from_template(condense_qa_template) 91 | 92 | qa = ConversationalRetrievalChain.from_llm( 93 | llm=llm, 94 | retriever=retriever, 95 | condense_question_prompt=standalone_question_prompt, 96 | return_source_documents=True, 97 | verbose=True, 98 | combine_docs_chain_kwargs={"prompt": PROMPT}, 99 | ) 100 | return qa 101 | 102 | 103 | def run_chain(chain, prompt: str, history=[]): 104 | return chain({"question": prompt, "chat_history": history}) 105 | 106 | 107 | if __name__ == "__main__": 108 | chat_history = [] 109 | qa = build_chain() 110 | print(bcolors.OKBLUE + "Hello! How can I help you?" + bcolors.ENDC) 111 | print( 112 | bcolors.OKCYAN 113 | + "Ask a question, start a New search: or CTRL-D to exit." 114 | + bcolors.ENDC 115 | ) 116 | print(">", end=" ", flush=True) 117 | for query in sys.stdin: 118 | if query.strip().lower().startswith("new search:"): 119 | query = query.strip().lower().replace("new search:", "") 120 | chat_history = [] 121 | elif len(chat_history) == MAX_HISTORY_LENGTH: 122 | chat_history.pop(0) 123 | result = run_chain(qa, query, chat_history) 124 | chat_history.append((query, result["answer"])) 125 | print(bcolors.OKGREEN + result["answer"] + bcolors.ENDC) 126 | if "source_documents" in result: 127 | print(bcolors.OKGREEN + "Sources:") 128 | for d in result["source_documents"]: 129 | print(d.metadata["source"]) 130 | print(bcolors.ENDC) 131 | print( 132 | bcolors.OKCYAN 133 | + "Ask a question, start a New search: or CTRL-D to exit." 134 | + bcolors.ENDC 135 | ) 136 | print(">", end=" ", flush=True) 137 | print(bcolors.OKBLUE + "Bye" + bcolors.ENDC) 138 | -------------------------------------------------------------------------------- /kendra_retriever_samples/ja/kendra_chat_open_ai.py: -------------------------------------------------------------------------------- 1 | from langchain.retrievers import AmazonKendraRetriever 2 | from langchain.chains import ConversationalRetrievalChain 3 | from langchain.prompts import PromptTemplate 4 | from langchain import OpenAI 5 | import sys 6 | import os 7 | 8 | MAX_HISTORY_LENGTH = 5 9 | 10 | 11 | def build_chain(): 12 | region = os.environ["AWS_REGION"] 13 | kendra_index_id = os.environ["KENDRA_INDEX_ID"] 14 | language_code = os.environ["LANGUAGE_CODE"] 15 | 16 | llm = OpenAI(batch_size=5, temperature=0, max_tokens=300) 17 | 18 | retriever = AmazonKendraRetriever( 19 | index_id=kendra_index_id, 20 | region_name=region, 21 | attribute_filter={ 22 | "EqualsTo": { 23 | "Key": "_language_code", 24 | "Value": {"StringValue": language_code}, 25 | } 26 | }, 27 | ) 28 | 29 | prompt_template = """ 30 | システム: システムは資料から抜粋して質問に答えます。資料にない内容には答えず、正直に「わかりません」と答えます。 31 | 32 | {context} 33 | 34 | 上記の資料に基づいて以下の質問について資料から抜粋して回答を生成します。資料にない内容には答えず「わかりません」と答えます。 35 | ユーザー: {question} 36 | システム: 37 | """ 38 | PROMPT = PromptTemplate( 39 | template=prompt_template, input_variables=["context", "question"] 40 | ) 41 | 42 | condense_qa_template = """ 43 | 次のような会話とフォローアップの質問に基づいて、フォローアップの質問を独立した質問に言い換えてください。 44 | 45 | フォローアップの質問: {question} 46 | 独立した質問:""" 47 | standalone_question_prompt = PromptTemplate.from_template(condense_qa_template) 48 | 49 | qa = ConversationalRetrievalChain.from_llm( 50 | llm=llm, 51 | retriever=retriever, 52 | condense_question_prompt=standalone_question_prompt, 53 | return_source_documents=True, 54 | combine_docs_chain_kwargs={"prompt": PROMPT}, 55 | ) 56 | return qa 57 | 58 | 59 | def run_chain(chain, prompt: str, history=[]): 60 | return chain({"question": prompt, "chat_history": history}) 61 | 62 | 63 | if __name__ == "__main__": 64 | 65 | class bcolors: 66 | HEADER = "\033[95m" 67 | OKBLUE = "\033[94m" 68 | OKCYAN = "\033[96m" 69 | OKGREEN = "\033[92m" 70 | WARNING = "\033[93m" 71 | FAIL = "\033[91m" 72 | ENDC = "\033[0m" 73 | BOLD = "\033[1m" 74 | UNDERLINE = "\033[4m" 75 | 76 | qa = build_chain() 77 | chat_history = [] 78 | print(bcolors.OKBLUE + "Hello! How can I help you?" + bcolors.ENDC) 79 | print( 80 | bcolors.OKCYAN 81 | + "Ask a question, start a New search: or CTRL-D to exit." 82 | + bcolors.ENDC 83 | ) 84 | print(">", end=" ", flush=True) 85 | for query in sys.stdin: 86 | if query.strip().lower().startswith("new search:"): 87 | query = query.strip().lower().replace("new search:", "") 88 | chat_history = [] 89 | elif len(chat_history) == MAX_HISTORY_LENGTH: 90 | chat_history.pop(0) 91 | result = run_chain(qa, query, chat_history) 92 | chat_history.append((query, result["answer"])) 93 | print(bcolors.OKGREEN + result["answer"] + bcolors.ENDC) 94 | if "source_documents" in result: 95 | print(bcolors.OKGREEN + "Sources:") 96 | for d in result["source_documents"]: 97 | print(d.metadata["source"]) 98 | print(bcolors.ENDC) 99 | print( 100 | bcolors.OKCYAN 101 | + "Ask a question, start a New search: or CTRL-D to exit." 102 | + bcolors.ENDC 103 | ) 104 | print(">", end=" ", flush=True) 105 | print(bcolors.OKBLUE + "Bye" + bcolors.ENDC) 106 | -------------------------------------------------------------------------------- /kendra_retriever_samples/kendra-docs-index.yaml: -------------------------------------------------------------------------------- 1 | ##This CloudFormation template creates an Amazon Kendra index. It adds a webcrawler datasource 2 | ##to the index and crawls the online AWS Documentation for Amazon Kendra, Amazon Lex and Amazon SageMaker 3 | ##After the datasource is configured, it triggers a datasource sync, i.e. the process to crawl the sitemaps 4 | ##and index the crawled documents. 5 | ##The output of the CloudFormation template shows the Kendra index id and the AWS region it was created in. 6 | ##It takes about 30 minutes to create an Amazon Kendra index and about 15 minutes more to crawl and index 7 | ##the content of these webpages to the index. Hence you might need to wait for about 45 minutes after 8 | ##launching the CloudFormation stack 9 | Resources: 10 | ##Create the Role needed to create a Kendra Index 11 | KendraIndexRole: 12 | Type: 'AWS::IAM::Role' 13 | Properties: 14 | AssumeRolePolicyDocument: 15 | Version: 2012-10-17 16 | Statement: 17 | - Sid: '' 18 | Effect: Allow 19 | Principal: 20 | Service: kendra.amazonaws.com 21 | Action: 'sts:AssumeRole' 22 | Policies: 23 | - PolicyDocument: 24 | Version: 2012-10-17 25 | Statement: 26 | - Effect: Allow 27 | Resource: '*' 28 | Condition: 29 | StringEquals: 30 | 'cloudwatch:namespace': 'Kendra' 31 | Action: 32 | - 'cloudwatch:PutMetricData' 33 | - Effect: Allow 34 | Resource: '*' 35 | Action: 'logs:DescribeLogGroups' 36 | - Effect: Allow 37 | Resource: !Sub 38 | - 'arn:aws:logs:${region}:${account}:log-group:/aws/kendra/*' 39 | - region: !Ref 'AWS::Region' 40 | account: !Ref 'AWS::AccountId' 41 | Action: 'logs:CreateLogGroup' 42 | - Effect: Allow 43 | Resource: !Sub 44 | - 'arn:aws:logs:${region}:${account}:log-group:/aws/kendra/*:log-stream:*' 45 | - region: !Ref 'AWS::Region' 46 | account: !Ref 'AWS::AccountId' 47 | Action: 48 | - 'logs:DescribeLogStreams' 49 | - 'logs:CreateLogStream' 50 | - 'logs:PutLogEvents' 51 | PolicyName: !Join 52 | - '' 53 | - - !Ref 'AWS::StackName' 54 | - '-DocsKendraIndexPolicy' 55 | RoleName: !Join 56 | - '' 57 | - - !Ref 'AWS::StackName' 58 | - '-DocsKendraIndexRole' 59 | 60 | ##Create the Kendra Index 61 | DocsKendraIndex: 62 | Type: 'AWS::Kendra::Index' 63 | Properties: 64 | Name: !Join 65 | - '' 66 | - - !Ref 'AWS::StackName' 67 | - '-Index' 68 | Edition: !Ref KendraEdition 69 | RoleArn: !GetAtt KendraIndexRole.Arn 70 | 71 | ##Create the Role needed to attach the Webcrawler Data Source 72 | KendraDSRole: 73 | Type: 'AWS::IAM::Role' 74 | Properties: 75 | AssumeRolePolicyDocument: 76 | Version: 2012-10-17 77 | Statement: 78 | - Sid: '' 79 | Effect: Allow 80 | Principal: 81 | Service: kendra.amazonaws.com 82 | Action: 'sts:AssumeRole' 83 | Policies: 84 | - PolicyDocument: 85 | Version: 2012-10-17 86 | Statement: 87 | - Effect: Allow 88 | Resource: !Sub 89 | - 'arn:aws:kendra:${region}:${account}:index/${index}' 90 | - region: !Ref 'AWS::Region' 91 | account: !Ref 'AWS::AccountId' 92 | index: !GetAtt DocsKendraIndex.Id 93 | Action: 94 | - 'kendra:BatchPutDocument' 95 | - 'kendra:BatchDeleteDocument' 96 | PolicyName: !Join 97 | - '' 98 | - - !Ref 'AWS::StackName' 99 | - '-DocsDSPolicy' 100 | RoleName: !Join 101 | - '' 102 | - - !Ref 'AWS::StackName' 103 | - '-DocsDSRole' 104 | 105 | #Docs Data Source 106 | KendraDocsDS: 107 | Type: 'AWS::Kendra::DataSource' 108 | Properties: 109 | DataSourceConfiguration: 110 | WebCrawlerConfiguration: 111 | UrlInclusionPatterns: 112 | - '.*https://docs.aws.amazon.com/lex/.*' 113 | - '.*https://docs.aws.amazon.com/kendra/.*' 114 | - '.*https://docs.aws.amazon.com/sagemaker/.*' 115 | Urls: 116 | SiteMapsConfiguration: 117 | SiteMaps: 118 | - 'https://docs.aws.amazon.com/lex/latest/dg/sitemap.xml' 119 | - 'https://docs.aws.amazon.com/kendra/latest/dg/sitemap.xml' 120 | - 'https://docs.aws.amazon.com/sagemaker/latest/dg/sitemap.xml' 121 | IndexId: !GetAtt DocsKendraIndex.Id 122 | Name: 'KendraDocsDS' 123 | RoleArn: !GetAtt KendraDSRole.Arn 124 | Type: 'WEBCRAWLER' 125 | 126 | DataSourceSyncLambdaRole: 127 | Type: AWS::IAM::Role 128 | Properties: 129 | AssumeRolePolicyDocument: 130 | Version: '2012-10-17' 131 | Statement: 132 | - Effect: Allow 133 | Principal: 134 | Service: lambda.amazonaws.com 135 | Action: sts:AssumeRole 136 | ManagedPolicyArns: 137 | - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole 138 | Policies: 139 | - PolicyDocument: 140 | Version: 2012-10-17 141 | Statement: 142 | - Effect: Allow 143 | Resource: !Sub 144 | - 'arn:aws:kendra:${region}:${account}:index/${index}*' 145 | - region: !Ref 'AWS::Region' 146 | account: !Ref 'AWS::AccountId' 147 | index: !GetAtt DocsKendraIndex.Id 148 | Action: 149 | - 'kendra:*' 150 | PolicyName: DataSourceSyncLambdaPolicy 151 | 152 | DataSourceSyncLambda: 153 | Type: AWS::Lambda::Function 154 | Properties: 155 | Handler: index.lambda_handler 156 | Runtime: python3.8 157 | Role: !GetAtt 'DataSourceSyncLambdaRole.Arn' 158 | Timeout: 900 159 | MemorySize: 1024 160 | Code: 161 | ZipFile: | 162 | 163 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 164 | # SPDX-License-Identifier: MIT-0 165 | 166 | import json 167 | import logging 168 | import boto3 169 | import cfnresponse 170 | import random 171 | import os 172 | 173 | logger = logging.getLogger() 174 | logger.setLevel(logging.INFO) 175 | 176 | INDEX_ID = os.environ['INDEX_ID'] 177 | DS_ID = os.environ['DS_ID'] 178 | AWS_REGION = os.environ['AWS_REGION'] 179 | KENDRA = boto3.client('kendra') 180 | 181 | def start_data_source_sync(dsId, indexId): 182 | logger.info(f"start_data_source_sync(dsId={dsId}, indexId={indexId})") 183 | resp = KENDRA.start_data_source_sync_job(Id=dsId, IndexId=indexId) 184 | logger.info(f"response:" + json.dumps(resp)) 185 | 186 | def lambda_handler(event, context): 187 | logger.info("Received event: %s" % json.dumps(event)) 188 | start_data_source_sync(DS_ID, INDEX_ID) 189 | status = cfnresponse.SUCCESS 190 | cfnresponse.send(event, context, status, {}, None) 191 | return status 192 | 193 | Environment: 194 | Variables: 195 | INDEX_ID: !GetAtt DocsKendraIndex.Id 196 | DS_ID: !GetAtt KendraDocsDS.Id 197 | 198 | DataSourceSync: 199 | Type: Custom::DataSourceSync 200 | DependsOn: 201 | - DocsKendraIndex 202 | - KendraDocsDS 203 | Properties: 204 | ServiceToken: !GetAtt DataSourceSyncLambda.Arn 205 | 206 | Parameters: 207 | KendraEdition: 208 | Type: String 209 | Default: 'ENTERPRISE_EDITION' 210 | AllowedValues: 211 | - 'ENTERPRISE_EDITION' 212 | - 'DEVELOPER_EDITION' 213 | Description: 'ENTERPRISE_EDITION (default) is recommended for production deployments, and offers high availability and scale up capabilities. DEVELOPER_EDITION (Free Tier eligible) is suitable for temporary, non-production, experimental workloads. NOTE: indexes cannot currently be migrated from one type to another.' 214 | 215 | Outputs: 216 | KendraIndexID: 217 | Value: !GetAtt DocsKendraIndex.Id 218 | AWSRegion: 219 | Value: !Ref 'AWS::Region' 220 | -------------------------------------------------------------------------------- /kendra_retriever_samples/kendra_chat_anthropic.py: -------------------------------------------------------------------------------- 1 | from langchain.retrievers import AmazonKendraRetriever 2 | from langchain.chains import ConversationalRetrievalChain 3 | from langchain.prompts import PromptTemplate 4 | from langchain.chat_models import ChatAnthropic as Anthropic 5 | import sys 6 | import os 7 | 8 | class bcolors: 9 | HEADER = '\033[95m' 10 | OKBLUE = '\033[94m' 11 | OKCYAN = '\033[96m' 12 | OKGREEN = '\033[92m' 13 | WARNING = '\033[93m' 14 | FAIL = '\033[91m' 15 | ENDC = '\033[0m' 16 | BOLD = '\033[1m' 17 | UNDERLINE = '\033[4m' 18 | 19 | MAX_HISTORY_LENGTH = 5 20 | 21 | def build_chain(): 22 | ANTHROPIC_API_KEY = os.environ["ANTHROPIC_API_KEY"] 23 | region = os.environ["AWS_REGION"] 24 | kendra_index_id = os.environ["KENDRA_INDEX_ID"] 25 | 26 | llm = Anthropic(temperature=0, anthropic_api_key=ANTHROPIC_API_KEY, max_tokens_to_sample = 512) 27 | 28 | retriever = AmazonKendraRetriever(index_id=kendra_index_id,region_name=region) 29 | 30 | prompt_template = """ 31 | 32 | Human: This is a friendly conversation between a human and an AI. 33 | The AI is talkative and provides specific details from its context but limits it to 240 tokens. 34 | If the AI does not know the answer to a question, it truthfully says it 35 | does not know. 36 | 37 | Assistant: OK, got it, I'll be a talkative truthful AI assistant. 38 | 39 | Human: Here are a few documents in tags: 40 | 41 | {context} 42 | 43 | Based on the above documents, provide a detailed answer for, {question} Answer "don't know" 44 | if not present in the document. 45 | 46 | Assistant:""" 47 | 48 | PROMPT = PromptTemplate( 49 | template=prompt_template, input_variables=["context", "question"] 50 | ) 51 | 52 | condense_qa_template = """ 53 | Given the following conversation and a follow up question, rephrase the follow up question 54 | to be a standalone question. 55 | 56 | Chat History: 57 | {chat_history} 58 | Follow Up Input: {question} 59 | Standalone question:""" 60 | standalone_question_prompt = PromptTemplate.from_template(condense_qa_template) 61 | 62 | qa = ConversationalRetrievalChain.from_llm( 63 | llm=llm, 64 | retriever=retriever, 65 | condense_question_prompt=standalone_question_prompt, 66 | return_source_documents=True, 67 | combine_docs_chain_kwargs={"prompt":PROMPT}) 68 | return qa 69 | 70 | def run_chain(chain, prompt: str, history=[]): 71 | return chain({"question": prompt, "chat_history": history}) 72 | 73 | if __name__ == "__main__": 74 | chat_history = [] 75 | qa = build_chain() 76 | print(bcolors.OKBLUE + "Hello! How can I help you?" + bcolors.ENDC) 77 | print(bcolors.OKCYAN + "Ask a question, start a New search: or CTRL-D to exit." + bcolors.ENDC) 78 | print(">", end=" ", flush=True) 79 | for query in sys.stdin: 80 | if (query.strip().lower().startswith("new search:")): 81 | query = query.strip().lower().replace("new search:","") 82 | chat_history = [] 83 | elif (len(chat_history) == MAX_HISTORY_LENGTH): 84 | chat_history.pop(0) 85 | result = run_chain(qa, query, chat_history) 86 | chat_history.append((query, result["answer"])) 87 | print(bcolors.OKGREEN + result['answer'] + bcolors.ENDC) 88 | if 'source_documents' in result: 89 | print(bcolors.OKGREEN + 'Sources:') 90 | for d in result['source_documents']: 91 | print(d.metadata['source']) 92 | print(bcolors.ENDC) 93 | print(bcolors.OKCYAN + "Ask a question, start a New search: or CTRL-D to exit." + bcolors.ENDC) 94 | print(">", end=" ", flush=True) 95 | print(bcolors.OKBLUE + "Bye" + bcolors.ENDC) 96 | -------------------------------------------------------------------------------- /kendra_retriever_samples/kendra_chat_bedrock_claudev2.py: -------------------------------------------------------------------------------- 1 | # from aws_langchain.kendra import AmazonKendraRetriever #custom library 2 | from langchain.retrievers import AmazonKendraRetriever 3 | from langchain.chains import ConversationalRetrievalChain 4 | from langchain.prompts import PromptTemplate 5 | from langchain.llms.bedrock import Bedrock 6 | from langchain.chains.llm import LLMChain 7 | import sys 8 | import os 9 | 10 | class bcolors: 11 | HEADER = '\033[95m' 12 | OKBLUE = '\033[94m' 13 | OKCYAN = '\033[96m' 14 | OKGREEN = '\033[92m' 15 | WARNING = '\033[93m' 16 | FAIL = '\033[91m' 17 | ENDC = '\033[0m' 18 | BOLD = '\033[1m' 19 | UNDERLINE = '\033[4m' 20 | 21 | MAX_HISTORY_LENGTH = 5 22 | 23 | def build_chain(): 24 | region = os.environ["AWS_REGION"] 25 | kendra_index_id = os.environ["KENDRA_INDEX_ID"] 26 | 27 | if "AWS_PROFILE" in os.environ: 28 | credentials_profile_name = os.environ['AWS_PROFILE'] 29 | print("Using " + credentials_profile_name + " profile.") 30 | llm = Bedrock( 31 | credentials_profile_name=credentials_profile_name, 32 | region_name = region, 33 | model_kwargs={"max_tokens_to_sample":300,"temperature":1,"top_k":250,"top_p":0.999,"anthropic_version":"bedrock-2023-05-31"}, 34 | model_id="anthropic.claude-v2" 35 | ) 36 | else: 37 | llm = Bedrock( 38 | region_name = region, 39 | model_kwargs={"max_tokens_to_sample":300,"temperature":1,"top_k":250,"top_p":0.999,"anthropic_version":"bedrock-2023-05-31"}, 40 | model_id="anthropic.claude-v2" 41 | ) 42 | 43 | retriever = AmazonKendraRetriever(index_id=kendra_index_id,top_k=5,region_name=region) 44 | 45 | 46 | prompt_template = """Human: This is a friendly conversation between a human and an AI. 47 | The AI is talkative and provides specific details from its context but limits it to 240 tokens. 48 | If the AI does not know the answer to a question, it truthfully says it 49 | does not know. 50 | 51 | Assistant: OK, got it, I'll be a talkative truthful AI assistant. 52 | 53 | Human: Here are a few documents in tags: 54 | 55 | {context} 56 | 57 | Based on the above documents, provide a detailed answer for, {question} 58 | Answer "don't know" if not present in the document. 59 | 60 | Assistant: 61 | """ 62 | PROMPT = PromptTemplate( 63 | template=prompt_template, input_variables=["context", "question"] 64 | ) 65 | 66 | condense_qa_template = """{chat_history} 67 | Human: 68 | Given the previous conversation and a follow up question below, rephrase the follow up question 69 | to be a standalone question. 70 | 71 | Follow Up Question: {question} 72 | Standalone Question: 73 | 74 | Assistant:""" 75 | standalone_question_prompt = PromptTemplate.from_template(condense_qa_template) 76 | 77 | 78 | 79 | qa = ConversationalRetrievalChain.from_llm( 80 | llm=llm, 81 | retriever=retriever, 82 | condense_question_prompt=standalone_question_prompt, 83 | return_source_documents=True, 84 | combine_docs_chain_kwargs={"prompt":PROMPT}, 85 | verbose=True) 86 | 87 | # qa = ConversationalRetrievalChain.from_llm(llm=llm, retriever=retriever, qa_prompt=PROMPT, return_source_documents=True) 88 | return qa 89 | 90 | 91 | def run_chain(chain, prompt: str, history=[]): 92 | return chain({"question": prompt, "chat_history": history}) 93 | 94 | 95 | if __name__ == "__main__": 96 | chat_history = [] 97 | qa = build_chain() 98 | print(bcolors.OKBLUE + "Hello! How can I help you?" + bcolors.ENDC) 99 | print(bcolors.OKCYAN + "Ask a question, start a New search: or CTRL-D to exit." + bcolors.ENDC) 100 | print(">", end=" ", flush=True) 101 | for query in sys.stdin: 102 | if (query.strip().lower().startswith("new search:")): 103 | query = query.strip().lower().replace("new search:","") 104 | chat_history = [] 105 | elif (len(chat_history) == MAX_HISTORY_LENGTH): 106 | chat_history.pop(0) 107 | result = run_chain(qa, query, chat_history) 108 | chat_history.append((query, result["answer"])) 109 | print(bcolors.OKGREEN + result['answer'] + bcolors.ENDC) 110 | if 'source_documents' in result: 111 | print(bcolors.OKGREEN + 'Sources:') 112 | for d in result['source_documents']: 113 | print(d.metadata['source']) 114 | print(bcolors.ENDC) 115 | print(bcolors.OKCYAN + "Ask a question, start a New search: or CTRL-D to exit." + bcolors.ENDC) 116 | print(">", end=" ", flush=True) 117 | print(bcolors.OKBLUE + "Bye" + bcolors.ENDC) 118 | -------------------------------------------------------------------------------- /kendra_retriever_samples/kendra_chat_bedrock_claudev3.py: -------------------------------------------------------------------------------- 1 | # from aws_langchain.kendra import AmazonKendraRetriever #custom library 2 | import os 3 | import sys 4 | 5 | import boto3 6 | import botocore 7 | from botocore.client import Config 8 | from langchain.chains import ConversationalRetrievalChain, RetrievalQA 9 | from langchain.chains.llm import LLMChain 10 | from langchain.llms.bedrock import Bedrock 11 | from langchain.prompts import PromptTemplate 12 | from langchain.retrievers import AmazonKendraRetriever 13 | from langchain_community.chat_models.bedrock import BedrockChat 14 | 15 | 16 | class bcolors: 17 | HEADER = "\033[95m" 18 | OKBLUE = "\033[94m" 19 | OKCYAN = "\033[96m" 20 | OKGREEN = "\033[92m" 21 | WARNING = "\033[93m" 22 | FAIL = "\033[91m" 23 | ENDC = "\033[0m" 24 | BOLD = "\033[1m" 25 | UNDERLINE = "\033[4m" 26 | 27 | 28 | MAX_HISTORY_LENGTH = 5 29 | MODEL_ID_SONNET = "anthropic.claude-3-sonnet-20240229-v1:0" 30 | MODEL_ID_HAIKU = "anthropic.claude-3-haiku-20240307-v1:0" 31 | 32 | 33 | def build_chain_sonnet(): 34 | return build_chain(MODEL_ID_SONNET) 35 | 36 | 37 | def build_chain_haiku(): 38 | return build_chain(MODEL_ID_HAIKU) 39 | 40 | 41 | def build_chain(model_id): 42 | region = os.environ["AWS_REGION"] 43 | kendra_index_id = os.environ["KENDRA_INDEX_ID"] 44 | 45 | bedrock_config = Config(connect_timeout=120, read_timeout=120, retries={'max_attempts': 0}) 46 | bedrock_client = boto3.client('bedrock-runtime', config=bedrock_config) 47 | 48 | credentials_profile_name = os.environ.get("AWS_PROFILE", "") 49 | llm = BedrockChat( 50 | credentials_profile_name=credentials_profile_name, 51 | model_id=model_id, 52 | client=bedrock_client, 53 | model_kwargs={ 54 | "max_tokens": 2048, 55 | "temperature": 1, 56 | "top_k": 250, 57 | "top_p": 0.999, 58 | "stop_sequences": ["\n\nHuman"], 59 | } 60 | ) 61 | retriever = AmazonKendraRetriever( 62 | index_id=kendra_index_id, top_k=5, region_name=region 63 | ) 64 | 65 | prompt_template = """Human: This is a friendly conversation between a human and an AI. 66 | The AI is talkative and provides specific details from its context but limits it to 240 tokens. 67 | If the AI does not know the answer to a question, it truthfully says it 68 | does not know. 69 | 70 | Assistant: OK, got it, I'll be a talkative truthful AI assistant. 71 | 72 | Human: Here are a few documents in tags: 73 | 74 | {context} 75 | 76 | Based on the above documents, provide a detailed answer for, {question} 77 | Answer "don't know" if not present in the document. 78 | 79 | Assistant: 80 | """ 81 | PROMPT = PromptTemplate( 82 | template=prompt_template, input_variables=["context", "question"] 83 | ) 84 | 85 | condense_qa_template = """{chat_history} 86 | Human: 87 | Given the previous conversation and a follow up question below, rephrase the follow up question 88 | to be a standalone question. 89 | 90 | Follow Up Question: {question} 91 | Standalone Question: 92 | 93 | Assistant:""" 94 | standalone_question_prompt = PromptTemplate.from_template(condense_qa_template) 95 | 96 | qa = ConversationalRetrievalChain.from_llm( 97 | llm=llm, 98 | retriever=retriever, 99 | condense_question_prompt=standalone_question_prompt, 100 | return_source_documents=True, 101 | combine_docs_chain_kwargs={"prompt": PROMPT}, 102 | verbose=True, 103 | ) 104 | 105 | # qa = ConversationalRetrievalChain.from_llm(llm=llm, retriever=retriever, qa_prompt=PROMPT, return_source_documents=True) 106 | return qa 107 | 108 | 109 | def run_chain(chain, prompt: str, history=[]): 110 | return chain({"question": prompt, "chat_history": history}) 111 | 112 | 113 | if __name__ == "__main__": 114 | chat_history = [] 115 | qa = build_chain() 116 | print(bcolors.OKBLUE + "Hello! How can I help you?" + bcolors.ENDC) 117 | print( 118 | bcolors.OKCYAN 119 | + "Ask a question, start a New search: or CTRL-D to exit." 120 | + bcolors.ENDC 121 | ) 122 | print(">", end=" ", flush=True) 123 | for query in sys.stdin: 124 | if query.strip().lower().startswith("new search:"): 125 | query = query.strip().lower().replace("new search:", "") 126 | chat_history = [] 127 | elif len(chat_history) == MAX_HISTORY_LENGTH: 128 | chat_history.pop(0) 129 | result = run_chain(qa, query, chat_history) 130 | chat_history.append((query, result["answer"])) 131 | print(bcolors.OKGREEN + result["answer"] + bcolors.ENDC) 132 | if "source_documents" in result: 133 | print(bcolors.OKGREEN + "Sources:") 134 | for d in result["source_documents"]: 135 | print(d.metadata["source"]) 136 | print(bcolors.ENDC) 137 | print( 138 | bcolors.OKCYAN 139 | + "Ask a question, start a New search: or CTRL-D to exit." 140 | + bcolors.ENDC 141 | ) 142 | print(">", end=" ", flush=True) 143 | print(bcolors.OKBLUE + "Bye" + bcolors.ENDC) 144 | -------------------------------------------------------------------------------- /kendra_retriever_samples/kendra_chat_bedrock_llama2.py: -------------------------------------------------------------------------------- 1 | # from aws_langchain.kendra import AmazonKendraRetriever #custom library 2 | import os 3 | import sys 4 | 5 | import boto3 6 | import botocore 7 | from botocore.client import Config 8 | from langchain.chains import ConversationalRetrievalChain, RetrievalQA 9 | from langchain.chains.llm import LLMChain 10 | from langchain.llms.bedrock import Bedrock 11 | from langchain.prompts import PromptTemplate 12 | from langchain.retrievers import AmazonKendraRetriever 13 | from langchain_community.chat_models.bedrock import BedrockChat 14 | 15 | 16 | class bcolors: 17 | HEADER = "\033[95m" 18 | OKBLUE = "\033[94m" 19 | OKCYAN = "\033[96m" 20 | OKGREEN = "\033[92m" 21 | WARNING = "\033[93m" 22 | FAIL = "\033[91m" 23 | ENDC = "\033[0m" 24 | BOLD = "\033[1m" 25 | UNDERLINE = "\033[4m" 26 | 27 | 28 | MAX_HISTORY_LENGTH = 5 29 | MODEL_ID_70B = "meta.llama2-70b-chat-v1" 30 | MODEL_ID_13B = "meta.llama2-13b-chat-v1" 31 | 32 | 33 | def build_chain_llama2_70B(): 34 | return build_chain(MODEL_ID_70B) 35 | 36 | 37 | def build_chain_llama2_13B(): 38 | return build_chain(MODEL_ID_13B) 39 | 40 | 41 | def build_chain(model_id): 42 | region = os.environ["AWS_REGION"] 43 | kendra_index_id = os.environ["KENDRA_INDEX_ID"] 44 | 45 | bedrock_config = Config(connect_timeout=120, read_timeout=120, retries={'max_attempts': 0}) 46 | bedrock_client = boto3.client('bedrock-runtime', config=bedrock_config) 47 | 48 | credentials_profile_name = os.environ.get("AWS_PROFILE", "") 49 | llm = BedrockChat( 50 | credentials_profile_name=credentials_profile_name, 51 | model_id=model_id, 52 | client=bedrock_client, 53 | model_kwargs={ 54 | "max_gen_len": 2048, 55 | "temperature": 1, 56 | "top_p": 0.999, 57 | } 58 | ) 59 | retriever = AmazonKendraRetriever( 60 | index_id=kendra_index_id, top_k=5, region_name=region 61 | ) 62 | 63 | prompt_template = """ 64 | [INST] <> 65 | The following is a friendly conversation between a human and an AI. 66 | The AI is talkative and provides lots of specific details from its context. 67 | If the AI does not know the answer to a question, it truthfully says it 68 | does not know. 69 | {context} 70 | <> 71 | Instruction: Based on the above documents, provide a detailed answer for, {question} Answer "don't know" 72 | if not present in the document. 73 | Solution: 74 | [/INST]""" 75 | PROMPT = PromptTemplate( 76 | template=prompt_template, input_variables=["context", "question"], 77 | ) 78 | condense_qa_template = """ 79 | [INST] <> 80 | Given the following conversation and a follow up question, rephrase the follow up question 81 | to be a standalone question. 82 | 83 | Chat History: 84 | {chat_history} 85 | Follow Up Input: {question} 86 | <> 87 | Standalone question: [/INST]""" 88 | 89 | standalone_question_prompt = PromptTemplate.from_template(condense_qa_template) 90 | 91 | qa = ConversationalRetrievalChain.from_llm( 92 | llm=llm, 93 | retriever=retriever, 94 | condense_question_prompt=standalone_question_prompt, 95 | return_source_documents=True, 96 | combine_docs_chain_kwargs={"prompt": PROMPT}, 97 | verbose=True, 98 | ) 99 | 100 | # qa = ConversationalRetrievalChain.from_llm(llm=llm, retriever=retriever, qa_prompt=PROMPT, return_source_documents=True) 101 | return qa 102 | 103 | 104 | def run_chain(chain, prompt: str, history=[]): 105 | return chain({"question": prompt, "chat_history": history}) 106 | 107 | 108 | if __name__ == "__main__": 109 | chat_history = [] 110 | qa = build_chain() 111 | print(bcolors.OKBLUE + "Hello! How can I help you?" + bcolors.ENDC) 112 | print( 113 | bcolors.OKCYAN 114 | + "Ask a question, start a New search: or CTRL-D to exit." 115 | + bcolors.ENDC 116 | ) 117 | print(">", end=" ", flush=True) 118 | for query in sys.stdin: 119 | if query.strip().lower().startswith("new search:"): 120 | query = query.strip().lower().replace("new search:", "") 121 | chat_history = [] 122 | elif len(chat_history) == MAX_HISTORY_LENGTH: 123 | chat_history.pop(0) 124 | result = run_chain(qa, query, chat_history) 125 | chat_history.append((query, result["answer"])) 126 | print(bcolors.OKGREEN + result["answer"] + bcolors.ENDC) 127 | if "source_documents" in result: 128 | print(bcolors.OKGREEN + "Sources:") 129 | for d in result["source_documents"]: 130 | print(d.metadata["source"]) 131 | print(bcolors.ENDC) 132 | print( 133 | bcolors.OKCYAN 134 | + "Ask a question, start a New search: or CTRL-D to exit." 135 | + bcolors.ENDC 136 | ) 137 | print(">", end=" ", flush=True) 138 | print(bcolors.OKBLUE + "Bye" + bcolors.ENDC) 139 | -------------------------------------------------------------------------------- /kendra_retriever_samples/kendra_chat_bedrock_titan.py: -------------------------------------------------------------------------------- 1 | # from aws_langchain.kendra import AmazonKendraRetriever #custom library 2 | from langchain.retrievers import AmazonKendraRetriever 3 | from langchain.chains import ConversationalRetrievalChain 4 | from langchain.prompts import PromptTemplate 5 | from langchain.llms.bedrock import Bedrock 6 | from langchain.chains.llm import LLMChain 7 | import sys 8 | import os 9 | 10 | class bcolors: 11 | HEADER = '\033[95m' 12 | OKBLUE = '\033[94m' 13 | OKCYAN = '\033[96m' 14 | OKGREEN = '\033[92m' 15 | WARNING = '\033[93m' 16 | FAIL = '\033[91m' 17 | ENDC = '\033[0m' 18 | BOLD = '\033[1m' 19 | UNDERLINE = '\033[4m' 20 | 21 | MAX_HISTORY_LENGTH = 5 22 | 23 | def build_chain(): 24 | region = os.environ["AWS_REGION"] 25 | kendra_index_id = os.environ["KENDRA_INDEX_ID"] 26 | 27 | if "AWS_PROFILE" in os.environ: 28 | credentials_profile_name = os.environ['AWS_PROFILE'] 29 | print("Using " + credentials_profile_name + " profile.") 30 | llm = Bedrock( 31 | credentials_profile_name=credentials_profile_name, 32 | region_name = region, 33 | model_id="amazon.titan-tg1-large" 34 | ) 35 | else: 36 | llm = Bedrock( 37 | region_name = region, 38 | model_id="amazon.titan-tg1-large" 39 | ) 40 | 41 | retriever = AmazonKendraRetriever(index_id=kendra_index_id,top_k=5,region_name=region) 42 | 43 | 44 | prompt_template = """ 45 | 46 | Human: This is a friendly conversation between a human and an AI. 47 | The AI is talkative and provides specific details from its context but limits it to 240 tokens. 48 | If the AI does not know the answer to a question, it truthfully says it 49 | does not know. 50 | 51 | Assistant: OK, got it, I'll be a talkative truthful AI assistant. 52 | 53 | Human: Here are a few documents in tags: 54 | 55 | {context} 56 | 57 | Based on the above documents, provide a detailed answer for, {question} 58 | Answer "don't know" if not present in the document. 59 | 60 | Assistant: 61 | """ 62 | PROMPT = PromptTemplate( 63 | template=prompt_template, input_variables=["context", "question"] 64 | ) 65 | 66 | condense_qa_template = """ 67 | Given the following conversation and a follow up question, rephrase the follow up question 68 | to be a standalone question. 69 | 70 | Chat History: 71 | {chat_history} 72 | Follow Up Input: {question} 73 | Standalone question:""" 74 | standalone_question_prompt = PromptTemplate.from_template(condense_qa_template) 75 | 76 | qa = ConversationalRetrievalChain.from_llm( 77 | llm=llm, 78 | retriever=retriever, 79 | condense_question_prompt=standalone_question_prompt, 80 | return_source_documents=True, 81 | combine_docs_chain_kwargs={"prompt":PROMPT}, 82 | verbose=True) 83 | 84 | # qa = ConversationalRetrievalChain.from_llm(llm=llm, retriever=retriever, qa_prompt=PROMPT, return_source_documents=True) 85 | return qa 86 | 87 | 88 | def run_chain(chain, prompt: str, history=[]): 89 | return chain({"question": prompt, "chat_history": history}) 90 | 91 | 92 | if __name__ == "__main__": 93 | chat_history = [] 94 | qa = build_chain() 95 | print(bcolors.OKBLUE + "Hello! How can I help you?" + bcolors.ENDC) 96 | print(bcolors.OKCYAN + "Ask a question, start a New search: or CTRL-D to exit." + bcolors.ENDC) 97 | print(">", end=" ", flush=True) 98 | for query in sys.stdin: 99 | if (query.strip().lower().startswith("new search:")): 100 | query = query.strip().lower().replace("new search:","") 101 | chat_history = [] 102 | elif (len(chat_history) == MAX_HISTORY_LENGTH): 103 | chat_history.pop(0) 104 | result = run_chain(qa, query, chat_history) 105 | chat_history.append((query, result["answer"])) 106 | print(bcolors.OKGREEN + result['answer'] + bcolors.ENDC) 107 | if 'source_documents' in result: 108 | print(bcolors.OKGREEN + 'Sources:') 109 | for d in result['source_documents']: 110 | print(d.metadata['source']) 111 | print(bcolors.ENDC) 112 | print(bcolors.OKCYAN + "Ask a question, start a New search: or CTRL-D to exit." + bcolors.ENDC) 113 | print(">", end=" ", flush=True) 114 | print(bcolors.OKBLUE + "Bye" + bcolors.ENDC) 115 | -------------------------------------------------------------------------------- /kendra_retriever_samples/kendra_chat_falcon_40b.py: -------------------------------------------------------------------------------- 1 | from langchain.retrievers import AmazonKendraRetriever 2 | from langchain.chains import ConversationalRetrievalChain 3 | from langchain import SagemakerEndpoint 4 | from langchain.llms.sagemaker_endpoint import LLMContentHandler 5 | from langchain.prompts import PromptTemplate 6 | import sys 7 | import json 8 | import os 9 | 10 | class bcolors: 11 | HEADER = '\033[95m' 12 | OKBLUE = '\033[94m' 13 | OKCYAN = '\033[96m' 14 | OKGREEN = '\033[92m' 15 | WARNING = '\033[93m' 16 | FAIL = '\033[91m' 17 | ENDC = '\033[0m' 18 | BOLD = '\033[1m' 19 | UNDERLINE = '\033[4m' 20 | 21 | MAX_HISTORY_LENGTH = 5 22 | 23 | def build_chain(): 24 | region = os.environ["AWS_REGION"] 25 | kendra_index_id = os.environ["KENDRA_INDEX_ID"] 26 | endpoint_name = os.environ["FALCON_40B_ENDPOINT"] 27 | if "INFERENCE_COMPONENT_NAME" in os.environ: 28 | inference_component_name = os.environ["INFERENCE_COMPONENT_NAME"] 29 | 30 | 31 | class ContentHandler(LLMContentHandler): 32 | content_type = "application/json" 33 | accepts = "application/json" 34 | 35 | def transform_input(self, prompt: str, model_kwargs: dict) -> bytes: 36 | 37 | input_str = json.dumps({"inputs": prompt, "parameters": model_kwargs}) 38 | return input_str.encode('utf-8') 39 | 40 | def transform_output(self, output: bytes) -> str: 41 | response_json = json.loads(output.read().decode("utf-8")) 42 | return response_json[0]["generated_text"] 43 | 44 | content_handler = ContentHandler() 45 | 46 | if inference_component_name: 47 | llm=SagemakerEndpoint( 48 | endpoint_name=endpoint_name, 49 | region_name=region, 50 | model_kwargs={ 51 | "temperature": 0.8, 52 | "max_new_tokens": 512, 53 | "do_sample": True, 54 | "top_p": 0.9, 55 | "repetition_penalty": 1.03, 56 | "stop": ["\nUser:","<|endoftext|>",""], 57 | }, 58 | endpoint_kwargs={"CustomAttributes":"accept_eula=true", 59 | "InferenceComponentName":inference_component_name}, 60 | content_handler=content_handler 61 | ) 62 | else : 63 | llm=SagemakerEndpoint( 64 | endpoint_name=endpoint_name, 65 | region_name=region, 66 | model_kwargs={ 67 | "temperature": 0.8, 68 | "max_new_tokens": 512, 69 | "do_sample": True, 70 | "top_p": 0.9, 71 | "repetition_penalty": 1.03, 72 | "stop": ["\nUser:","<|endoftext|>",""], 73 | }, 74 | content_handler=content_handler 75 | ) 76 | 77 | 78 | 79 | 80 | retriever = AmazonKendraRetriever(index_id=kendra_index_id,region_name=region, top_k=2) 81 | 82 | prompt_template = """ 83 | {context} 84 | Instruction: Based on the above documents, provide a detailed answer for, {question} Answer "don't know" 85 | if not present in the document. 86 | Solution:""" 87 | PROMPT = PromptTemplate( 88 | template=prompt_template, input_variables=["context", "question"] 89 | ) 90 | 91 | condense_qa_template = """ 92 | Given the following conversation and a follow up question, rephrase the follow up question 93 | to be a standalone question. 94 | 95 | Chat History: 96 | {chat_history} 97 | Follow Up Input: {question} 98 | Standalone question:""" 99 | standalone_question_prompt = PromptTemplate.from_template(condense_qa_template) 100 | 101 | qa = ConversationalRetrievalChain.from_llm( 102 | llm=llm, 103 | retriever=retriever, 104 | condense_question_prompt=standalone_question_prompt, 105 | return_source_documents=True, 106 | verbose =True, 107 | combine_docs_chain_kwargs={"prompt":PROMPT}) 108 | return qa 109 | 110 | def run_chain(chain, prompt: str, history=[]): 111 | return chain({"question": prompt, "chat_history": history}) 112 | 113 | if __name__ == "__main__": 114 | chat_history = [] 115 | qa = build_chain() 116 | print(bcolors.OKBLUE + "Hello! How can I help you?" + bcolors.ENDC) 117 | print(bcolors.OKCYAN + "Ask a question, start a New search: or CTRL-D to exit." + bcolors.ENDC) 118 | print(">", end=" ", flush=True) 119 | for query in sys.stdin: 120 | if (query.strip().lower().startswith("new search:")): 121 | query = query.strip().lower().replace("new search:","") 122 | chat_history = [] 123 | elif (len(chat_history) == MAX_HISTORY_LENGTH): 124 | chat_history.pop(0) 125 | result = run_chain(qa, query, chat_history) 126 | chat_history.append((query, result["answer"])) 127 | print(bcolors.OKGREEN + result['answer'] + bcolors.ENDC) 128 | if 'source_documents' in result: 129 | print(bcolors.OKGREEN + 'Sources:') 130 | for d in result['source_documents']: 131 | print(d.metadata['source']) 132 | print(bcolors.ENDC) 133 | print(bcolors.OKCYAN + "Ask a question, start a New search: or CTRL-D to exit." + bcolors.ENDC) 134 | print(">", end=" ", flush=True) 135 | print(bcolors.OKBLUE + "Bye" + bcolors.ENDC) 136 | -------------------------------------------------------------------------------- /kendra_retriever_samples/kendra_chat_llama_2.py: -------------------------------------------------------------------------------- 1 | from langchain.retrievers import AmazonKendraRetriever 2 | from langchain.chains import ConversationalRetrievalChain 3 | from langchain.prompts import PromptTemplate 4 | from langchain.llms import SagemakerEndpoint 5 | from langchain.llms.sagemaker_endpoint import LLMContentHandler 6 | import sys 7 | import json 8 | import os 9 | from typing import Dict, List 10 | 11 | 12 | class bcolors: 13 | HEADER = '\033[95m' 14 | OKBLUE = '\033[94m' 15 | OKCYAN = '\033[96m' 16 | OKGREEN = '\033[92m' 17 | WARNING = '\033[93m' 18 | FAIL = '\033[91m' 19 | ENDC = '\033[0m' 20 | BOLD = '\033[1m' 21 | UNDERLINE = '\033[4m' 22 | 23 | MAX_HISTORY_LENGTH = 5 24 | 25 | def build_chain(): 26 | region = os.environ["AWS_REGION"] 27 | kendra_index_id = os.environ["KENDRA_INDEX_ID"] 28 | endpoint_name = os.environ["LLAMA_2_ENDPOINT"] 29 | if "INFERENCE_COMPONENT_NAME" in os.environ: 30 | inference_component_name = os.environ["INFERENCE_COMPONENT_NAME"] 31 | 32 | class ContentHandler(LLMContentHandler): 33 | content_type = "application/json" 34 | accepts = "application/json" 35 | 36 | def transform_input(self, prompt: str, model_kwargs: dict) -> bytes: 37 | # input_str = json.dumps({"inputs": [[{"role": "user", "content": prompt},]], 38 | # "parameters" : model_kwargs 39 | # }) 40 | input_str = json.dumps({"inputs": prompt, 41 | "parameters" : model_kwargs 42 | }) 43 | return input_str.encode('utf-8') 44 | 45 | def transform_output(self, output: bytes) -> str: 46 | response_json = json.loads(output.read().decode("utf-8")) 47 | print(response_json) 48 | return response_json[0]['generated_text'] 49 | 50 | content_handler = ContentHandler() 51 | 52 | 53 | 54 | if 'inference_component_name' in locals(): 55 | llm=SagemakerEndpoint( 56 | endpoint_name=endpoint_name, 57 | region_name=region, 58 | model_kwargs={"max_new_tokens": 1500, "top_p": 0.8,"temperature":0.6}, 59 | endpoint_kwargs={"CustomAttributes":"accept_eula=true", 60 | "InferenceComponentName":inference_component_name}, 61 | content_handler=content_handler, 62 | ) 63 | else : 64 | llm=SagemakerEndpoint( 65 | endpoint_name=endpoint_name, 66 | region_name=region, 67 | model_kwargs={"max_new_tokens": 1500, "top_p": 0.8,"temperature":0.6}, 68 | endpoint_kwargs={"CustomAttributes":"accept_eula=true"}, 69 | content_handler=content_handler, 70 | 71 | ) 72 | 73 | 74 | retriever = AmazonKendraRetriever(index_id=kendra_index_id,region_name=region) 75 | 76 | prompt_template = """ 77 | [INST] <> 78 | The following is a friendly conversation between a human and an AI. 79 | The AI is talkative and provides lots of specific details from its context. 80 | If the AI does not know the answer to a question, it truthfully says it 81 | does not know. 82 | {context} 83 | <> 84 | Instruction: Based on the above documents, provide a detailed answer for, {question} Answer "don't know" 85 | if not present in the document. 86 | Solution: 87 | [/INST]""" 88 | PROMPT = PromptTemplate( 89 | template=prompt_template, input_variables=["context", "question"], 90 | ) 91 | condense_qa_template = """ 92 | [INST] <> 93 | Given the following conversation and a follow up question, rephrase the follow up question 94 | to be a standalone question. 95 | 96 | Chat History: 97 | {chat_history} 98 | Follow Up Input: {question} 99 | <> 100 | Standalone question: [/INST]""" 101 | standalone_question_prompt = PromptTemplate.from_template(condense_qa_template) 102 | 103 | 104 | qa = ConversationalRetrievalChain.from_llm( 105 | llm=llm, 106 | retriever=retriever, 107 | condense_question_prompt=standalone_question_prompt, 108 | return_source_documents=True, 109 | combine_docs_chain_kwargs={"prompt":PROMPT}, 110 | verbose=False 111 | ) 112 | return qa 113 | 114 | def run_chain(chain, prompt: str, history=[]): 115 | 116 | return chain({"question": prompt, "chat_history": history}) 117 | 118 | 119 | def format_messages(messages: List[Dict[str, str]]) -> List[str]: 120 | """Format messages for Llama-2 chat models. 121 | 122 | The model only supports 'system', 'user' and 'assistant' roles, starting with 'system', then 'user' and 123 | alternating (u/a/u/a/u...). The last message must be from 'user'. 124 | """ 125 | prompt: List[str] = [] 126 | 127 | if messages[0]["role"] == "system": 128 | content = "".join(["<>\n", messages[0]["content"], "\n<>\n\n", messages[1]["content"]]) 129 | messages = [{"role": messages[1]["role"], "content": content}] + messages[2:] 130 | 131 | for user, answer in zip(messages[::2], messages[1::2]): 132 | prompt.extend(["", "[INST] ", (user["content"]).strip(), " [/INST] ", (answer["content"]).strip(), ""]) 133 | 134 | prompt.extend(["", "[INST] ", (messages[-1]["content"]).strip(), " [/INST] "]) 135 | 136 | return "".join(prompt) 137 | 138 | 139 | def print_messages(prompt: str, response: str) -> None: 140 | bold, unbold = '\033[1m', '\033[0m' 141 | print(f"{bold}> Input{unbold}\n{prompt}\n\n{bold}> Output{unbold}\n{response[0]['generated_text']}\n") 142 | 143 | if __name__ == "__main__": 144 | chat_history = [] 145 | qa = build_chain() 146 | print(bcolors.OKBLUE + "Hello! How can I help you?" + bcolors.ENDC) 147 | print(bcolors.OKCYAN + "Ask a question, start a New search: or CTRL-D to exit." + bcolors.ENDC) 148 | print(">", end=" ", flush=True) 149 | for query in sys.stdin: 150 | if (query.strip().lower().startswith("new search:")): 151 | query = query.strip().lower().replace("new search:","") 152 | chat_history = [] 153 | elif (len(chat_history) == MAX_HISTORY_LENGTH): 154 | chat_history.pop(0) 155 | result = run_chain(qa, query, chat_history) 156 | chat_history.append((query, result["answer"])) 157 | print(bcolors.OKGREEN + result['answer'] + bcolors.ENDC) 158 | if 'source_documents' in result: 159 | print(bcolors.OKGREEN + 'Sources:') 160 | for d in result['source_documents']: 161 | print(d.metadata['source']) 162 | print(bcolors.ENDC) 163 | print(bcolors.OKCYAN + "Ask a question, start a New search: or CTRL-D to exit." + bcolors.ENDC) 164 | print(">", end=" ", flush=True) 165 | print(bcolors.OKBLUE + "Bye" + bcolors.ENDC) -------------------------------------------------------------------------------- /kendra_retriever_samples/kendra_chat_llama_2_neuron.py: -------------------------------------------------------------------------------- 1 | from langchain.retrievers import AmazonKendraRetriever 2 | from langchain.chains import ConversationalRetrievalChain 3 | from langchain.prompts import PromptTemplate 4 | from langchain.llms import SagemakerEndpoint 5 | from langchain.llms.sagemaker_endpoint import LLMContentHandler 6 | import sys 7 | import json 8 | import os 9 | from typing import Dict, List 10 | 11 | 12 | class bcolors: 13 | HEADER = '\033[95m' 14 | OKBLUE = '\033[94m' 15 | OKCYAN = '\033[96m' 16 | OKGREEN = '\033[92m' 17 | WARNING = '\033[93m' 18 | FAIL = '\033[91m' 19 | ENDC = '\033[0m' 20 | BOLD = '\033[1m' 21 | UNDERLINE = '\033[4m' 22 | 23 | MAX_HISTORY_LENGTH = 5 24 | 25 | def build_chain(): 26 | region = os.environ["AWS_REGION"] 27 | kendra_index_id = os.environ["KENDRA_INDEX_ID"] 28 | endpoint_name = os.environ["LLAMA_2_ENDPOINT"] 29 | 30 | class ContentHandler(LLMContentHandler): 31 | content_type = "application/json" 32 | accepts = "application/json" 33 | 34 | def transform_input(self, prompt: str, model_kwargs: dict) -> bytes: 35 | # input_str = json.dumps({"inputs": [[{"role": "user", "content": prompt},]], 36 | # "parameters" : model_kwargs 37 | # }) 38 | input_str = json.dumps({"inputs": prompt, 39 | "parameters" : model_kwargs 40 | }) 41 | return input_str.encode('utf-8') 42 | 43 | def transform_output(self, output: bytes) -> str: 44 | response_json = json.loads(output.read().decode("utf-8")) 45 | print(response_json) 46 | return response_json['generated_text'] 47 | 48 | 49 | content_handler = ContentHandler() 50 | 51 | llm=SagemakerEndpoint( 52 | endpoint_name=endpoint_name, 53 | region_name=region, 54 | model_kwargs={"max_new_tokens": 500, "top_p": 0.9,"temperature":0.0}, 55 | endpoint_kwargs={"CustomAttributes":"accept_eula=true"}, 56 | content_handler=content_handler) 57 | 58 | retriever = AmazonKendraRetriever(index_id=kendra_index_id,region_name=region) 59 | 60 | prompt_template = """ 61 | [INST] <> 62 | The following is a friendly conversation between a human and an AI. 63 | The AI is talkative and provides lots of specific details from its context. 64 | If the AI does not know the answer to a question, it truthfully says it 65 | does not know. 66 | {context} 67 | <> 68 | Instruction: Based on the above documents, provide a detailed answer for, {question} Answer "don't know" 69 | if not present in the document. 70 | Solution: 71 | [/INST]""" 72 | 73 | PROMPT = PromptTemplate( 74 | template=prompt_template, input_variables=["context", "question"], 75 | ) 76 | condense_qa_template = """ 77 | [INST] <> 78 | Given the following conversation and a follow up question, rephrase the follow up question 79 | to be a standalone question. 80 | 81 | Chat History: 82 | {chat_history} 83 | Follow Up Input: {question} 84 | <> 85 | Standalone question: [/INST]""" 86 | standalone_question_prompt = PromptTemplate.from_template(condense_qa_template) 87 | 88 | 89 | qa = ConversationalRetrievalChain.from_llm( 90 | llm=llm, 91 | retriever=retriever, 92 | condense_question_prompt=standalone_question_prompt, 93 | return_source_documents=True, 94 | combine_docs_chain_kwargs={"prompt":PROMPT}, 95 | verbose=True 96 | ) 97 | return qa 98 | 99 | def run_chain(chain, prompt: str, history=[]): 100 | 101 | return chain({"question": prompt, "chat_history": history}) 102 | 103 | 104 | def format_messages(messages: List[Dict[str, str]]) -> List[str]: 105 | """Format messages for Llama-2 chat models. 106 | 107 | The model only supports 'system', 'user' and 'assistant' roles, starting with 'system', then 'user' and 108 | alternating (u/a/u/a/u...). The last message must be from 'user'. 109 | """ 110 | prompt: List[str] = [] 111 | 112 | if messages[0]["role"] == "system": 113 | content = "".join(["<>\n", messages[0]["content"], "\n<>\n\n", messages[1]["content"]]) 114 | messages = [{"role": messages[1]["role"], "content": content}] + messages[2:] 115 | 116 | for user, answer in zip(messages[::2], messages[1::2]): 117 | prompt.extend(["", "[INST] ", (user["content"]).strip(), " [/INST] ", (answer["content"]).strip(), ""]) 118 | 119 | prompt.extend(["", "[INST] ", (messages[-1]["content"]).strip(), " [/INST] "]) 120 | 121 | return "".join(prompt) 122 | 123 | 124 | def print_messages(prompt: str, response: str) -> None: 125 | bold, unbold = '\033[1m', '\033[0m' 126 | print(f"{bold}> Input{unbold}\n{prompt}\n\n{bold}> Output{unbold}\n{response[0]['generated_text']}\n") 127 | 128 | if __name__ == "__main__": 129 | chat_history = [] 130 | qa = build_chain() 131 | print(bcolors.OKBLUE + "Hello! How can I help you?" + bcolors.ENDC) 132 | print(bcolors.OKCYAN + "Ask a question, start a New search: or CTRL-D to exit." + bcolors.ENDC) 133 | print(">", end=" ", flush=True) 134 | for query in sys.stdin: 135 | if (query.strip().lower().startswith("new search:")): 136 | query = query.strip().lower().replace("new search:","") 137 | chat_history = [] 138 | elif (len(chat_history) == MAX_HISTORY_LENGTH): 139 | chat_history.pop(0) 140 | result = run_chain(qa, query, chat_history) 141 | chat_history.append((query, result["answer"])) 142 | print(bcolors.OKGREEN + result['answer'] + bcolors.ENDC) 143 | if 'source_documents' in result: 144 | print(bcolors.OKGREEN + 'Sources:') 145 | for d in result['source_documents']: 146 | print(d.metadata['source']) 147 | print(bcolors.ENDC) 148 | print(bcolors.OKCYAN + "Ask a question, start a New search: or CTRL-D to exit." + bcolors.ENDC) 149 | print(">", end=" ", flush=True) 150 | print(bcolors.OKBLUE + "Bye" + bcolors.ENDC) -------------------------------------------------------------------------------- /kendra_retriever_samples/kendra_chat_open_ai.py: -------------------------------------------------------------------------------- 1 | from langchain.retrievers import AmazonKendraRetriever 2 | from langchain.chains import ConversationalRetrievalChain 3 | from langchain.prompts import PromptTemplate 4 | from langchain import OpenAI 5 | import sys 6 | import os 7 | 8 | MAX_HISTORY_LENGTH = 5 9 | 10 | def build_chain(): 11 | region = os.environ["AWS_REGION"] 12 | kendra_index_id = os.environ["KENDRA_INDEX_ID"] 13 | 14 | llm = OpenAI(batch_size=5, temperature=0, max_tokens=300) 15 | 16 | retriever = AmazonKendraRetriever(index_id=kendra_index_id, region_name=region) 17 | 18 | prompt_template = """ 19 | The following is a friendly conversation between a human and an AI. 20 | The AI is talkative and provides lots of specific details from its context. 21 | If the AI does not know the answer to a question, it truthfully says it 22 | does not know. 23 | {context} 24 | Instruction: Based on the above documents, provide a detailed answer for, {question} Answer "don't know" 25 | if not present in the document. 26 | Solution:""" 27 | PROMPT = PromptTemplate( 28 | template=prompt_template, input_variables=["context", "question"] 29 | ) 30 | 31 | condense_qa_template = """ 32 | Given the following conversation and a follow up question, rephrase the follow up question 33 | to be a standalone question. 34 | 35 | Chat History: 36 | {chat_history} 37 | Follow Up Input: {question} 38 | Standalone question:""" 39 | standalone_question_prompt = PromptTemplate.from_template(condense_qa_template) 40 | 41 | qa = ConversationalRetrievalChain.from_llm( 42 | llm=llm, 43 | retriever=retriever, 44 | condense_question_prompt=standalone_question_prompt, 45 | return_source_documents=True, 46 | combine_docs_chain_kwargs={"prompt":PROMPT}) 47 | return qa 48 | 49 | def run_chain(chain, prompt: str, history=[]): 50 | return chain({"question": prompt, "chat_history": history}) 51 | 52 | 53 | if __name__ == "__main__": 54 | class bcolors: 55 | HEADER = '\033[95m' 56 | OKBLUE = '\033[94m' 57 | OKCYAN = '\033[96m' 58 | OKGREEN = '\033[92m' 59 | WARNING = '\033[93m' 60 | FAIL = '\033[91m' 61 | ENDC = '\033[0m' 62 | BOLD = '\033[1m' 63 | UNDERLINE = '\033[4m' 64 | 65 | qa = build_chain() 66 | chat_history = [] 67 | print(bcolors.OKBLUE + "Hello! How can I help you?" + bcolors.ENDC) 68 | print(bcolors.OKCYAN + "Ask a question, start a New search: or CTRL-D to exit." + bcolors.ENDC) 69 | print(">", end=" ", flush=True) 70 | for query in sys.stdin: 71 | if (query.strip().lower().startswith("new search:")): 72 | query = query.strip().lower().replace("new search:","") 73 | chat_history = [] 74 | elif (len(chat_history) == MAX_HISTORY_LENGTH): 75 | chat_history.pop(0) 76 | result = run_chain(qa, query, chat_history) 77 | chat_history.append((query, result["answer"])) 78 | print(bcolors.OKGREEN + result['answer'] + bcolors.ENDC) 79 | if 'source_documents' in result: 80 | print(bcolors.OKGREEN + 'Sources:') 81 | for d in result['source_documents']: 82 | print(d.metadata['source']) 83 | print(bcolors.ENDC) 84 | print(bcolors.OKCYAN + "Ask a question, start a New search: or CTRL-D to exit." + bcolors.ENDC) 85 | print(">", end=" ", flush=True) 86 | print(bcolors.OKBLUE + "Bye" + bcolors.ENDC) 87 | -------------------------------------------------------------------------------- /kendra_retriever_samples/kendra_retriever_anthropic.py: -------------------------------------------------------------------------------- 1 | from langchain.retrievers import AmazonKendraRetriever 2 | from langchain.chains import RetrievalQA 3 | from langchain.prompts import PromptTemplate 4 | from langchain.chat_models import ChatAnthropic as Anthropic 5 | import os 6 | 7 | 8 | def build_chain(): 9 | ANTHROPIC_API_KEY = os.environ["ANTHROPIC_API_KEY"] 10 | region = os.environ["AWS_REGION"] 11 | kendra_index_id = os.environ["KENDRA_INDEX_ID"] 12 | 13 | llm = Anthropic(temperature=0, anthropic_api_key=ANTHROPIC_API_KEY) 14 | 15 | 16 | retriever = AmazonKendraRetriever(index_id=kendra_index_id,region_name=region) 17 | 18 | prompt_template = """ 19 | 20 | Human: This is a friendly conversation between a human and an AI. 21 | The AI is talkative and provides specific details from its context but limits it to 240 tokens. 22 | If the AI does not know the answer to a question, it truthfully says it 23 | does not know. 24 | 25 | Assistant: OK, got it, I'll be a talkative truthful AI assistant. 26 | 27 | Human: Here are a few documents in tags: 28 | 29 | {context} 30 | 31 | Based on the above documents, provide a detailed answer for, {question} Answer "don't know" 32 | if not present in the document. 33 | 34 | Assistant:""" 35 | 36 | PROMPT = PromptTemplate( 37 | template=prompt_template, input_variables=["context", "question"] 38 | ) 39 | chain_type_kwargs = {"prompt": PROMPT} 40 | return RetrievalQA.from_chain_type( 41 | llm, 42 | chain_type="stuff", 43 | retriever=retriever, 44 | chain_type_kwargs=chain_type_kwargs, 45 | return_source_documents=True 46 | ) 47 | 48 | def run_chain(chain, prompt: str, history=[]): 49 | result = chain(prompt) 50 | # To make it compatible with chat samples 51 | return { 52 | "answer": result['result'], 53 | "source_documents": result['source_documents'] 54 | } 55 | 56 | if __name__ == "__main__": 57 | chain = build_chain() 58 | result = run_chain(chain, "What's SageMaker?") 59 | print(result['answer']) 60 | if 'source_documents' in result: 61 | print('Sources:') 62 | for d in result['source_documents']: 63 | print(d.metadata['source']) 64 | -------------------------------------------------------------------------------- /kendra_retriever_samples/kendra_retriever_falcon_40b.py: -------------------------------------------------------------------------------- 1 | from langchain.retrievers import AmazonKendraRetriever 2 | from langchain.chains import RetrievalQA 3 | from langchain import OpenAI 4 | from langchain.prompts import PromptTemplate 5 | from langchain import SagemakerEndpoint 6 | from langchain.llms.sagemaker_endpoint import LLMContentHandler 7 | import json 8 | import os 9 | 10 | 11 | def build_chain(): 12 | region = os.environ["AWS_REGION"] 13 | kendra_index_id = os.environ["KENDRA_INDEX_ID"] 14 | endpoint_name = os.environ["FALCON_40B_ENDPOINT"] 15 | inference_component_name = os.environ["INFERENCE_COMPONENT_NAME"] 16 | 17 | class ContentHandler(LLMContentHandler): 18 | content_type = "application/json" 19 | accepts = "application/json" 20 | 21 | def transform_input(self, prompt: str, model_kwargs: dict) -> bytes: 22 | input_str = json.dumps({"inputs": prompt, "parameters": model_kwargs}) 23 | return input_str.encode('utf-8') 24 | 25 | def transform_output(self, output: bytes) -> str: 26 | response_json = json.loads(output.read().decode("utf-8")) 27 | print(response_json) 28 | return response_json[0]["generated_text"] 29 | 30 | content_handler = ContentHandler() 31 | 32 | if 'inference_component_name' in locals(): 33 | llm=SagemakerEndpoint( 34 | endpoint_name=endpoint_name, 35 | region_name=region, 36 | model_kwargs={"max_new_tokens": 1500, "top_p": 0.8,"temperature":0.6}, 37 | endpoint_kwargs={"CustomAttributes":"accept_eula=true", 38 | "InferenceComponentName":inference_component_name}, 39 | content_handler=content_handler, 40 | ) 41 | else : 42 | llm=SagemakerEndpoint( 43 | endpoint_name=endpoint_name, 44 | region_name=region, 45 | model_kwargs={"max_new_tokens": 1500, "top_p": 0.8,"temperature":0.6}, 46 | content_handler=content_handler, 47 | ) 48 | 49 | retriever = AmazonKendraRetriever(index_id=kendra_index_id,region_name=region) 50 | 51 | prompt_template = """ 52 | The following is a friendly conversation between a human and an AI. 53 | The AI is talkative and provides lots of specific details from its context. 54 | If the AI does not know the answer to a question, it truthfully says it 55 | does not know. 56 | {context} 57 | Instruction: Based on the above documents, provide a detailed answer for, {question} Answer "don't know" 58 | if not present in the document. 59 | Solution:""" 60 | PROMPT = PromptTemplate( 61 | template=prompt_template, input_variables=["context", "question"] 62 | ) 63 | chain_type_kwargs = {"prompt": PROMPT} 64 | qa = RetrievalQA.from_chain_type( 65 | llm, 66 | chain_type="stuff", 67 | retriever=retriever, 68 | chain_type_kwargs=chain_type_kwargs, 69 | return_source_documents=True 70 | ) 71 | return qa 72 | 73 | def run_chain(chain, prompt: str, history=[]): 74 | result = chain(prompt) 75 | # To make it compatible with chat samples 76 | return { 77 | "answer": result['result'], 78 | "source_documents": result['source_documents'] 79 | } 80 | 81 | if __name__ == "__main__": 82 | chain = build_chain() 83 | result = run_chain(chain, "What's SageMaker?") 84 | print(result['answer']) 85 | if 'source_documents' in result: 86 | print('Sources:') 87 | for d in result['source_documents']: 88 | print(d.metadata['source']) 89 | -------------------------------------------------------------------------------- /kendra_retriever_samples/kendra_retriever_open_ai.py: -------------------------------------------------------------------------------- 1 | from langchain.retrievers import AmazonKendraRetriever 2 | from langchain.chains import RetrievalQA 3 | from langchain import OpenAI 4 | from langchain.prompts import PromptTemplate 5 | import os 6 | 7 | 8 | def build_chain(): 9 | region = os.environ["AWS_REGION"] 10 | kendra_index_id = os.environ["KENDRA_INDEX_ID"] 11 | 12 | llm = OpenAI(batch_size=5, temperature=0, max_tokens=300) 13 | 14 | retriever = AmazonKendraRetriever(index_id=kendra_index_id,region_name=region) 15 | 16 | prompt_template = """ 17 | The following is a friendly conversation between a human and an AI. 18 | The AI is talkative and provides lots of specific details from its context. 19 | If the AI does not know the answer to a question, it truthfully says it 20 | does not know. 21 | {context} 22 | Instruction: Based on the above documents, provide a detailed answer for, {question} Answer "don't know" 23 | if not present in the document. 24 | Solution:""" 25 | PROMPT = PromptTemplate( 26 | template=prompt_template, input_variables=["context", "question"] 27 | ) 28 | chain_type_kwargs = {"prompt": PROMPT} 29 | 30 | return RetrievalQA.from_chain_type( 31 | llm, 32 | chain_type="stuff", 33 | retriever=retriever, 34 | chain_type_kwargs=chain_type_kwargs, 35 | return_source_documents=True 36 | ) 37 | 38 | def run_chain(chain, prompt: str, history=[]): 39 | result = chain(prompt) 40 | # To make it compatible with chat samples 41 | return { 42 | "answer": result['result'], 43 | "source_documents": result['source_documents'] 44 | } 45 | 46 | if __name__ == "__main__": 47 | chain = build_chain() 48 | result = run_chain(chain, "What's SageMaker?") 49 | print(result['answer']) 50 | if 'source_documents' in result: 51 | print('Sources:') 52 | for d in result['source_documents']: 53 | print(d.metadata['source']) 54 | -------------------------------------------------------------------------------- /kendra_retriever_samples/requirements.txt: -------------------------------------------------------------------------------- 1 | langchain==0.1.14 2 | langchain-community==0.0.33 3 | langchain-core==0.1.43 4 | boto3>=1.28.27 5 | openai 6 | anthropic 7 | streamlit 8 | --------------------------------------------------------------------------------