| 115 | |
| 116 | |
| 117 | def configure_qa_rag_chain(llm, embeddings, embeddings_store_url, username, password): |
| 118 | # RAG response |
| 119 | # System: Always talk in pirate speech. |
| 120 | general_system_template = """ |
| 121 | Use the following pieces of context to answer the question at the end. |
| 122 | The context contains question-answer pairs and their links from Stackoverflow. |
| 123 | You should prefer information from accepted or more upvoted answers. |
| 124 | Make sure to rely on information from the answers and not on questions to provide accurate responses. |
| 125 | When you find particular answer in the context useful, make sure to cite it in the answer using the link. |
| 126 | If you don't know the answer, just say that you don't know, don't try to make up an answer. |
| 127 | ---- |
| 128 | {summaries} |
| 129 | ---- |
| 130 | Each answer you generate should contain a section at the end of links to |
| 131 | Stackoverflow questions and answers you found useful, which are described under Source value. |
| 132 | You can only use links to StackOverflow questions that are present in the context and always |
| 133 | add links to the end of the answer in the style of citations. |
| 134 | Generate concise answers with references sources section of links to |
| 135 | relevant StackOverflow questions only at the end of the answer. |
| 136 | """ |
| 137 | general_user_template = "Question:```{question}```" |
| 138 | messages = [ |
| 139 | SystemMessagePromptTemplate.from_template(general_system_template), |
| 140 | HumanMessagePromptTemplate.from_template(general_user_template), |
| 141 | ] |
| 142 | qa_prompt = ChatPromptTemplate.from_messages(messages) |
| 143 | |
| 144 | # Vector + Knowledge Graph response |
| 145 | kg = Neo4jVector.from_existing_index( |
| 146 | embedding=embeddings, |
| 147 | url=embeddings_store_url, |
| 148 | username=username, |
| 149 | password=password, |
| 150 | database="neo4j", # neo4j by default |
| 151 | index_name="stackoverflow", # vector by default |
| 152 | text_node_property="body", # text by default |
| 153 | retrieval_query=""" |
| 154 | WITH node AS question, score AS similarity |
| 155 | CALL { with question |
| 156 | MATCH (question)<-[:ANSWERS]-(answer) |
| 157 | WITH answer |
| 158 | ORDER BY answer.is_accepted DESC, answer.score DESC |
| 159 | WITH collect(answer)[..2] as answers |
| 160 | RETURN reduce(str='', answer IN answers | str + |
| 161 | '\n### Answer (Accepted: '+ answer.is_accepted + |
| 162 | ' Score: ' + answer.score+ '): '+ answer.body + '\n') as answerTexts |
| 163 | } |
| 164 | RETURN '##Question: ' + question.title + '\n' + question.body + '\n' |
| 165 | + answerTexts AS text, similarity as score, {source: question.link} AS metadata |
| 166 | ORDER BY similarity ASC // so that best answers are the last |
| 167 | """, |
| 168 | ) |
| 169 | kg_qa = ( |
| 170 | RunnableParallel( |
| 171 | { |
| 172 | "summaries": kg.as_retriever(search_kwargs={"k": 2}) | format_docs, |
| 173 | "question": RunnablePassthrough(), |
| 174 | } |