remove old knowledgegraphs (#743)

* remove old knowledgegraphs

Signed-off-by: Xinyao Wang <xinyao.wang@intel.com>

* remove knowledgegraph

Signed-off-by: Xinyao Wang <xinyao.wang@intel.com>

---------

Signed-off-by: Xinyao Wang <xinyao.wang@intel.com>
This commit is contained in:
XinyaoWa
2024-09-26 14:55:45 +08:00
committed by GitHub
parent e588b9fca0
commit 8a14f3727e
18 changed files with 2 additions and 450 deletions

1
.github/CODEOWNERS vendored
View File

@@ -6,7 +6,6 @@
/comps/guardrails/ liang1.lv@intel.com
/comps/asr/ sihan.chen@intel.com
/comps/intent_detection/ liang1.lv@intel.com
/comps/knowledgegraphs/ xuhui.ren@intel.com
/comps/cores/ liang1.lv@intel.com
/comps/dataprep/ xinyu.ye@intel.com
/comps/embeddings/ xuhui.ren@intel.com

View File

@@ -1,9 +0,0 @@
# Copyright (C) 2024 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# this file should be run in the root of the repo
services:
knowledge_graphs:
build:
dockerfile: comps/knowledgegraphs/langchain/Dockerfile
image: ${REGISTRY:-opea}/knowledge_graphs:${TAG:-latest}

View File

@@ -7,7 +7,7 @@ on:
inputs:
services:
default: ""
description: "List of services to test [agent,asr,chathistory,dataprep,embeddings,guardrails,knowledgegraphs,llms,lvms,nginx,prompt_registry,ragas,reranks,retrievers,tts,vectorstores,web_retrievers]"
description: "List of services to test [agent,asr,chathistory,dataprep,embeddings,guardrails,llms,lvms,nginx,prompt_registry,ragas,reranks,retrievers,tts,vectorstores,web_retrievers]"
required: false
type: string
images:

View File

@@ -7,7 +7,7 @@ on:
inputs:
services:
default: "asr"
description: "List of services to test [agent_langchain,asr,chathistory_mongo,dataprep_milvus...]" #,embeddings,guardrails,knowledgegraphs,llms,lvms,prompt_registry,ragas,reranks,retrievers,tts,vectorstores,web_retrievers]"
description: "List of services to test [agent_langchain,asr,chathistory_mongo,dataprep_milvus...]" #,embeddings,guardrails,llms,lvms,prompt_registry,ragas,reranks,retrievers,tts,vectorstores,web_retrievers]"
required: false
type: string
images:

View File

@@ -1,31 +0,0 @@
# Copyright (C) 2024 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
FROM python:3.11-slim
ARG ARCH="cpu" # Set this to "cpu" or "gpu"
RUN apt-get update -y && apt-get install -y --no-install-recommends --fix-missing \
libgl1-mesa-glx \
libjemalloc-dev
RUN useradd -m -s /bin/bash user && \
mkdir -p /home/user && \
chown -R user /home/user/
COPY comps /home/user/comps
USER user
RUN pip install --no-cache-dir --upgrade pip && \
if [ ${ARCH} = "cpu" ]; then \
pip install --no-cache-dir --extra-index-url https://download.pytorch.org/whl/cpu -r /home/user/comps/knowledgegraphs/langchain/requirements.txt; \
else \
pip install --no-cache-dir -r /home/user/comps/knowledgegraphs/langchain/requirements.txt; \
fi
ENV PYTHONPATH=$PYTHONPATH:/home/user
WORKDIR /home/user/comps/knowledgegraphs/langchain
ENTRYPOINT ["python", "knowledge_graph.py"]

View File

@@ -1,146 +0,0 @@
# Knowledge Graph Microservice
This microservice, designed for efficiently handling and retrieving informantion from knowledge graph. The microservice integrates text retriever, knowledge graph quick search and LLM agent, which can be combined to enhance question answering.
The service contains three modes:
- "cypher": Query knowledge graph directly with cypher
- "rag": Apply similarity search on embeddings of knowledge graph
- "query": An LLM agent will automatically choose tools (RAG or CypherChain) to enhance the question answering
Here is the overall workflow:
![Workflow](doc/workflow.png)
A prerequisite for using this microservice is that users must have a knowledge gragh database already running, and currently we have support [Neo4J](https://neo4j.com/) for quick deployment. Users need to set the graph service's endpoint into an environment variable and microservie utilizes it for data injestion and retrieve. If user want to use "rag" and "query" mode, still need a LLM text generation service (etc., TGI, vLLM and Ray) already running.
Overall, this microservice provides efficient support for applications related with graph dataset, especially for answering multi-part questions, or any other conditions including comples relationship between entities.
## 🚀1. Start Microservice with Docker
### 1.1 Setup Environment Variables
```bash
export NEO4J_ENDPOINT="neo4j://${your_ip}:7687"
export NEO4J_USERNAME="neo4j"
export NEO4J_PASSWORD=${define_a_password}
export HUGGINGFACEHUB_API_TOKEN=${your_huggingface_api_token}
export LLM_ENDPOINT="http://${your_ip}:8080"
export LLM_MODEL="meta-llama/Llama-2-7b-hf"
export AGENT_LLM="HuggingFaceH4/zephyr-7b-beta"
```
### 1.2 Start Neo4j Service
```bash
docker pull neo4j
docker run --rm \
--publish=7474:7474 --publish=7687:7687 \
--env NEO4J_AUTH=$NEO4J_USER/$NEO4J_PASSWORD \
--volume=$PWD/neo4j_data:"/data" \
--env='NEO4JLABS_PLUGINS=["apoc"]' \
neo4j
```
### 1.3 Start LLM Service for "rag"/"query" mode
You can start any LLM microserve, here we take TGI as an example.
```bash
docker run -p 8080:80 \
-v $PWD/llm_data:/data --runtime=habana \
-e HABANA_VISIBLE_DEVICES=all \
-e OMPI_MCA_btl_vader_single_copy_mechanism=none \
-e HUGGING_FACE_HUB_TOKEN=$HUGGINGFACEHUB_API_TOKEN \
--cap-add=sys_nice \
--ipc=host \
ghcr.io/huggingface/tgi-gaudi:2.0.0 \
--model-id $LLM_MODEL \
--max-input-tokens 1024 \
--max-total-tokens 2048
```
Verify LLM service.
```bash
curl $LLM_ENDPOINT/generate \
-X POST \
-d '{"inputs":"What is Deep Learning?","parameters":{"max_new_tokens":32}}' \
-H 'Content-Type: application/json'
```
### 1.4 Start Microservice
```bash
cd ../../../
docker build -t opea/knowledge_graphs:latest \
--build-arg https_proxy=$https_proxy \
--build-arg http_proxy=$http_proxy \
-f comps/knowledgegraphs/langchain/Dockerfile .
docker run --rm \
--name="knowledge-graph-server" \
-p 8060:8060 \
--ipc=host \
-e http_proxy=$http_proxy \
-e https_proxy=$https_proxy \
-e NEO4J_ENDPOINT=$NEO4J_ENDPOINT \
-e NEO4J_USERNAME=$NEO4J_USERNAME \
-e NEO4J_PASSWORD=$NEO4J_PASSWORD \
-e HUGGINGFACEHUB_API_TOKEN=$HUGGINGFACEHUB_API_TOKEN \
-e LLM_ENDPOINT=$LLM_ENDPOINT \
opea/knowledge_graphs:latest
```
## 🚀2. Consume Knowledge Graph Service
### 2.1 Cypher mode
```bash
curl http://${your_ip}:8060/v1/graphs \
-X POST \
-d "{\"text\":\"MATCH (t:Task {status:'open'}) RETURN count(*)\",\"strtype\":\"cypher\"}" \
-H 'Content-Type: application/json'
```
Example output:
![Cypher Output](doc/output_cypher.png)
### 2.2 Rag mode
```bash
curl http://${your_ip}:8060/v1/graphs \
-X POST \
-d "{\"text\":\"How many open tickets there are?\",\"strtype\":\"rag\", \"max_new_tokens\":128}" \
-H 'Content-Type: application/json'
```
Example output:
![Cypher Output](doc/output_rag.png)
### 2.3 Query mode
First example:
```bash
curl http://${your_ip}:8060/v1/graphs \
-X POST \
-d "{\"text\":\"Which tasks have optimization in their description?\",\"strtype\":\"query\"}" \
-H 'Content-Type: application/json'
```
Example output:
![Cypher Output](doc/output_query1.png)
Second example:
```bash
curl http://${your_ip}:8060/v1/graphs \
-X POST \
-d "{\"text\":\"Which team is assigned to maintain PaymentService?\",\"strtype\":\"query\"}" \
-H 'Content-Type: application/json'
```
Example output:
![Cypher Output](doc/output_query2.png)

View File

@@ -1,2 +0,0 @@
# Copyright (C) 2024 Intel Corporation
# SPDX-License-Identifier: Apache-2.0

View File

@@ -1,7 +0,0 @@
# Copyright (C) 2024 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
docker build -t opea/knowledge_graphs:latest \
--build-arg https_proxy=$https_proxy \
--build-arg http_proxy=$http_proxy \
-f comps/knowledgegraphs/langchain/docker/Dockerfile .

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 407 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 467 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 418 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 710 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

View File

@@ -1,21 +0,0 @@
# Copyright (C) 2024 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
import json
import os
from langchain_community.graphs import Neo4jGraph
neo4j_endpoint = os.getenv("NEO4J_ENDPOINT", "neo4j://localhost:7687")
neo4j_username = os.getenv("NEO4J_USERNAME", "neo4j")
neo4j_password = os.getenv("NEO4J_PASSWORD", "neo4j")
graph = Neo4jGraph(url=neo4j_endpoint, username=neo4j_username, password=neo4j_password)
# remove all nodes
graph.query("MATCH (n) DETACH DELETE n")
# ingest
import_query = json.load(open("data/microservices.json", "r"))["query"]
graph.query(import_query)
print("Total nodes: ", graph.query("MATCH (n) RETURN count(n)"))
print("Total edges: ", graph.query("MATCH ()-->() RETURN count(*)"))

View File

@@ -1,167 +0,0 @@
# Copyright (C) 2024 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
import os
import pathlib
import sys
cur_path = pathlib.Path(__file__).parent.resolve()
comps_path = os.path.join(cur_path, "../../../")
sys.path.append(comps_path)
import json
import requests
from langchain import hub
from langchain.agents import AgentExecutor, Tool, load_tools
from langchain.agents.format_scratchpad import format_log_to_str
from langchain.agents.output_parsers import ReActJsonSingleInputOutputParser
from langchain.chains import GraphCypherQAChain, RetrievalQA
from langchain.tools.render import render_text_description
from langchain_community.chat_models.huggingface import ChatHuggingFace
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_community.graphs import Neo4jGraph
from langchain_community.llms import HuggingFaceEndpoint
from langchain_community.vectorstores.neo4j_vector import Neo4jVector
from comps import CustomLogger, GeneratedDoc, GraphDoc, ServiceType, opea_microservices, register_microservice
logger = CustomLogger("knowledge_graph")
logflag = os.getenv("LOGFLAG", False)
def get_retriever(input, neo4j_endpoint, neo4j_username, neo4j_password, llm):
embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-mpnet-base-v2")
vector_index = Neo4jVector.from_existing_graph(
embeddings,
url=neo4j_endpoint,
username=neo4j_username,
password=neo4j_password,
index_name=input.rag_index_name,
node_label=input.rag_node_label,
text_node_properties=input.rag_text_node_properties,
embedding_node_property=input.rag_embedding_node_property,
)
vector_qa = RetrievalQA.from_chain_type(llm=llm, chain_type="stuff", retriever=vector_index.as_retriever())
return vector_qa
def get_cypherchain(graph, cypher_llm, qa_llm):
graph.refresh_schema()
cypher_chain = GraphCypherQAChain.from_llm(cypher_llm=cypher_llm, qa_llm=qa_llm, graph=graph, verbose=True)
return cypher_chain
def get_agent(vector_qa, cypher_chain, llm_repo_id):
# define two tools
tools = [
Tool(
name="Tasks",
func=vector_qa.invoke,
description="""Useful when you need to answer questions about descriptions of tasks.
Not useful for counting the number of tasks.
Use full question as input.
""",
),
Tool(
name="Graph",
func=cypher_chain.invoke,
description="""Useful when you need to answer questions about microservices,
their dependencies or assigned people. Also useful for any sort of
aggregation like counting the number of tasks, etc.
Use full question as input.
""",
),
]
# setup ReAct style prompt
prompt = hub.pull("hwchase17/react-json")
prompt = prompt.partial(
tools=render_text_description(tools),
tool_names=", ".join([t.name for t in tools]),
)
# define chat model
llm = HuggingFaceEndpoint(repo_id=llm_repo_id, max_new_tokens=512)
chat_model = ChatHuggingFace(llm=llm)
chat_model_with_stop = chat_model.bind(stop=["\nObservation"])
# define agent
agent = (
{
"input": lambda x: x["input"],
"agent_scratchpad": lambda x: format_log_to_str(x["intermediate_steps"]),
}
| prompt
| chat_model_with_stop
| ReActJsonSingleInputOutputParser()
)
# instantiate AgentExecutor
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
return agent_executor
@register_microservice(
name="opea_service@knowledge_graph",
endpoint="/v1/graphs",
host="0.0.0.0",
port=8060,
)
def graph_query(input: GraphDoc) -> GeneratedDoc:
if logflag:
logger.info(input)
## Connect to Neo4j
neo4j_endpoint = os.getenv("NEO4J_ENDPOINT", "neo4j://localhost:7687")
neo4j_username = os.getenv("NEO4J_USERNAME", "neo4j")
neo4j_password = os.getenv("NEO4J_PASSWORD", "neo4j")
graph = Neo4jGraph(url=neo4j_endpoint, username=neo4j_username, password=neo4j_password)
## keep for multiple tests, will remove later
graph.query("MATCH (n) DETACH DELETE n")
import_query = json.load(open("data/microservices.json", "r"))["query"]
graph.query(import_query)
## get tool flag
flag_agent = True if input.strtype == "query" else False
flag_rag = True if input.strtype in ["query", "rag"] else False
## define LLM
if flag_agent or flag_rag:
llm_endpoint = os.getenv("LLM_ENDPOINT", "http://localhost:8080")
llm = HuggingFaceEndpoint(
endpoint_url=llm_endpoint,
timeout=600,
max_new_tokens=input.max_new_tokens,
)
## define a retriever
if flag_rag:
vector_qa = get_retriever(input, neo4j_endpoint, neo4j_username, neo4j_password, llm)
## define an agent
if flag_agent:
llm_repo_id = os.getenv("AGENT_LLM", "HuggingFaceH4/zephyr-7b-beta")
cypher_chain = get_cypherchain(graph, llm, llm) # define a cypher generator
agent_executor = get_agent(vector_qa, cypher_chain, llm_repo_id)
## process input query
if input.strtype == "cypher":
result_dicts = graph.query(input.text)
result = ""
for result_dict in result_dicts:
for key in result_dict:
result += str(key) + ": " + str(result_dict[key])
elif input.strtype == "rag":
result = vector_qa.invoke(input.text)["result"]
elif input.strtype == "query":
result = agent_executor.invoke({"input": input.text})["output"]
else:
result = "Please specify strtype as one of cypher, rag, query."
if logflag:
logger.info(result)
return GeneratedDoc(text=result, prompt=input.text)
if __name__ == "__main__":
opea_microservices["opea_service@knowledge_graph"].start()

View File

@@ -1,25 +0,0 @@
beautifulsoup4
docarray
docarray[full]
easyocr
fastapi
huggingface_hub
langchain
langchain_community==0.2.5
langchain_openai
langchainhub
neo4j
numpy
opentelemetry-api
opentelemetry-exporter-otlp
opentelemetry-sdk
pandas
Pillow
prometheus-fastapi-instrumentator
pymupdf
python-docx
redis
sentence-transformers
shortuuid
tiktoken
uvicorn

View File

@@ -1,36 +0,0 @@
# Copyright (C) 2024 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
import argparse
import json
import os
import timeit
import pandas as pd
import requests
def test_text(ip_addr="localhost", batch_size=1):
proxies = {"http": ""}
url = "http://localhost:8060/v1/graphs"
# payload = {"text":"MATCH (t:Task {status:'open'}) RETURN count(*)","strtype":"cypher"}
content = {"text": "MATCH (t:Task {status:'open'}) RETURN count(*)"}
payload = {"input": json.dumps(content)}
try:
resp = requests.post(url=url, data=payload, proxies=proxies)
print(resp.text)
resp.raise_for_status() # Raise an exception for unsuccessful HTTP status codes
print("Request successful!")
except requests.exceptions.RequestException as e:
print("An error occurred:", e)
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--batch_size", type=int, default=1, help="Batch size for testing")
parser.add_argument("--ip_addr", type=str, default="localhost", help="IP address of the server")
args = parser.parse_args()
test_text(ip_addr=args.ip_addr, batch_size=args.batch_size)