|
| 1 | +from couchbase.options import KnownConfigProfiles |
| 2 | +from haystack import GeneratedAnswer, Pipeline |
| 3 | +from haystack.components.builders.answer_builder import AnswerBuilder |
| 4 | +from haystack.components.builders.prompt_builder import PromptBuilder |
| 5 | +from haystack.components.embedders import SentenceTransformersTextEmbedder |
| 6 | +from haystack.components.generators import HuggingFaceAPIGenerator |
| 7 | +from haystack.utils import Secret |
| 8 | + |
| 9 | +from couchbase_haystack import ( |
| 10 | + CouchbaseClusterOptions, |
| 11 | + CouchbasePasswordAuthenticator, |
| 12 | + CouchbaseQueryDocumentStore, |
| 13 | + CouchbaseQueryEmbeddingRetriever, |
| 14 | + QueryVectorSearchType, |
| 15 | +) |
| 16 | + |
| 17 | +# Load HF Token from environment variables. |
| 18 | +HF_TOKEN = Secret.from_env_var("HF_API_TOKEN") |
| 19 | + |
| 20 | +# Make sure you have a running couchbase database, e.g. with Docker: |
| 21 | +# docker run \ |
| 22 | +# --restart always \ |
| 23 | +# --publish=8091-8096:8091-8096 --publish=11210:11210 \ |
| 24 | +# --env COUCHBASE_ADMINISTRATOR_USERNAME=admin \ |
| 25 | +# --env COUCHBASE_ADMINISTRATOR_PASSWORD=passw0rd \ |
| 26 | +# couchbase:enterprise-8.0.0 |
| 27 | + |
| 28 | +document_store = CouchbaseQueryDocumentStore( |
| 29 | + cluster_connection_string=Secret.from_token("localhost"), |
| 30 | + authenticator=CouchbasePasswordAuthenticator(username=Secret.from_token("username"), password=Secret.from_token("password")), |
| 31 | + cluster_options=CouchbaseClusterOptions( |
| 32 | + profile=KnownConfigProfiles.WanDevelopment, |
| 33 | + ), |
| 34 | + bucket="haystack_bucket_name", |
| 35 | + scope="haystack_scope_name", |
| 36 | + collection="haystack_collection_name", |
| 37 | + search_type=QueryVectorSearchType.ANN, |
| 38 | + similarity="L2", |
| 39 | + nprobes=10, |
| 40 | +) |
| 41 | + |
| 42 | +# Build a RAG pipeline with a Retriever to get relevant documents to the query and a HuggingFaceTGIGenerator |
| 43 | +# interacting with LLMs using a custom prompt. |
| 44 | +prompt_template = """ |
| 45 | +Given these documents, answer the question.\nDocuments: |
| 46 | +{% for doc in documents %} |
| 47 | + {{ doc.content }} |
| 48 | +{% endfor %} |
| 49 | +
|
| 50 | +\nQuestion: {{question}} |
| 51 | +\nAnswer: |
| 52 | +""" |
| 53 | +rag_pipeline = Pipeline() |
| 54 | +rag_pipeline.add_component( |
| 55 | + "query_embedder", |
| 56 | + SentenceTransformersTextEmbedder(model="sentence-transformers/all-MiniLM-L6-v2", progress_bar=False), |
| 57 | +) |
| 58 | +rag_pipeline.add_component("retriever", CouchbaseQueryEmbeddingRetriever(document_store=document_store)) |
| 59 | +rag_pipeline.add_component("prompt_builder", PromptBuilder(template=prompt_template)) |
| 60 | +rag_pipeline.add_component( |
| 61 | + "llm", |
| 62 | + HuggingFaceAPIGenerator( |
| 63 | + api_type="serverless_inference_api", |
| 64 | + api_params={"model": "mistralai/Mistral-7B-v0.1"}, |
| 65 | + ), |
| 66 | +) |
| 67 | +rag_pipeline.add_component("answer_builder", AnswerBuilder()) |
| 68 | + |
| 69 | +rag_pipeline.connect("query_embedder", "retriever.query_embedding") |
| 70 | +rag_pipeline.connect("retriever.documents", "prompt_builder.documents") |
| 71 | +rag_pipeline.connect("prompt_builder.prompt", "llm.prompt") |
| 72 | +rag_pipeline.connect("llm.replies", "answer_builder.replies") |
| 73 | +rag_pipeline.connect("llm.meta", "answer_builder.meta") |
| 74 | +rag_pipeline.connect("retriever", "answer_builder.documents") |
| 75 | + |
| 76 | +# Ask a question on the data you just added. |
| 77 | +question = "Who created the Dothraki vocabulary?" |
| 78 | +result = rag_pipeline.run( |
| 79 | + { |
| 80 | + "query_embedder": {"text": question}, |
| 81 | + "retriever": {"top_k": 3}, |
| 82 | + "prompt_builder": {"question": question}, |
| 83 | + "answer_builder": {"query": question}, |
| 84 | + } |
| 85 | +) |
| 86 | + |
| 87 | +# For details, like which documents were used to generate the answer, look into the GeneratedAnswer object |
| 88 | +answer: GeneratedAnswer = result["answer_builder"]["answers"][0] |
| 89 | + |
| 90 | +# ruff: noqa: T201 |
| 91 | +print("Query: ", answer.query) |
| 92 | +print("Answer: ", answer.data) |
| 93 | +print("== Sources:") |
| 94 | +for doc in answer.documents: |
| 95 | + print("-> ", doc.meta["file_path"]) |
0 commit comments