-
数据收集 -
建立知识库 -
向量检索 -
提示词与模型
数据收集
{"content": "DDoS IP高防结合Web应用防火墙方案说明\n=======================\n\n\nDDoS IP高防+Web应用防火墙提供三层到七层安全防护体系,应用场景包括游戏、金融、电商、互联网、政企等京东云内和云外的各类型用户。\n\n\n部署架构\n====\n\n\n[](\\\"https://jdcloud-portal.oss.cn-north-1.jcloudcs.com/cn/image/Advanced%20Anti-DDoS/Best-Practice02.png\\\") \n\nDDoS IP高防+Web应用防火墙的最佳部署架构如下:\n\n\n* 京东云的安全调度中心,通过DNS解析,将用户域名解析到DDoS IP高防CNAME。\n* 用户正常访问流量和DDoS攻击流量经过DDoS IP高防清洗,回源至Web应用防火墙。\n* 攻击者恶意请求被Web应用防火墙过滤后返回用户源站。\n* Web应用防火墙可以保护任何公网的服务器,包括但不限于京东云,其他厂商的云,IDC等\n\n\n方案优势\n====\n\n\n1. 用户源站在DDoS IP高防和Web应用防火墙之后,起到隐藏源站IP的作用。\n2. CNAME接入,配置简单,减少运维人员工作。\n\n\n","title": "DDoS IP高防结合Web应用防火墙方案说明","product": "DDoS IP高防","url": "https://docs.jdcloud.com/cn/anti-ddos-pro/anti-ddos-pro-and-waf"}
向量数据库的选择与Retriever实现
-
ck再langchain社区的集成实现比较好,入库比较平滑 -
向量查询支持sql,学习成本较低,上手容易 -
京东云有相关产品且有专业团队支持,用着放心
文档向量化及入库过程
首先将文档向量化,代码如下:
from libs.jd_doc_json_loader import JD_DOC_Loaderfrom langchain_community.document_loaders import DirectoryLoaderroot_dir = "/root/jd_docs"loader = DirectoryLoader( '/root/jd_docs', glob="**/*.json", loader_cls=JD_DOC_Loader)docs = loader.load()
import jsonimport loggingfrom pathlib import Pathfrom typing import Iterator, Optional, Unionfrom langchain_core.documents import Documentfrom langchain_community.document_loaders.base import BaseLoaderfrom langchain_community.document_loaders.helpers import detect_file_encodingslogger = logging.getLogger(__name__)class JD_DOC_Loader(BaseLoader):"""Load text file.Args:file_path: Path to the file to load.encoding: File encoding to use. If `None`, the file will be loadedwith the default system encoding.autodetect_encoding: Whether to try to autodetect the file encodingif the specified encoding fails."""def __init__(self,file_path: Union[str, Path],encoding: Optional[str] = None,autodetect_encoding: bool = False,):"""Initialize with file path."""self.file_path = file_pathself.encoding = encodingself.autodetect_encoding = autodetect_encodingdef lazy_load(self) -> Iterator[Document]:"""Load from file path."""text = ""from_url = ""try:with open(self.file_path, encoding=self.encoding) as f:doc_data = json.load(f)text = doc_data["content"]title = doc_data["title"]product = doc_data["product"]from_url = doc_data["url"]# text = f.read()except UnicodeDecodeError as e:if self.autodetect_encoding:detected_encodings = detect_file_encodings(self.file_path)for encoding in detected_encodings:logger.debug(f"Trying encoding: {encoding.encoding}")try:with open(self.file_path, encoding=encoding.encoding) as f:text = f.read()breakexcept UnicodeDecodeError:continueelse:raise RuntimeError(f"Error loading {self.file_path}") from eexcept Exception as e:raise RuntimeError(f"Error loading {self.file_path}") from e# metadata = {"source": str(self.file_path)}metadata = {"source": from_url, "title": title, "product": product}yield Document(page_content=text, metadata=metadata)
import langchain_community.vectorstores.clickhouse as clickhousefrom langchain.embeddings import HuggingFaceEmbeddingsmodel_kwargs = {"device": "cuda"}embeddings = HuggingFaceEmbeddings(model_name="/root/models/moka-ai-m3e-large", model_kwargs=model_kwargs)settings = clickhouse.ClickhouseSettings(table="jd_docs_m3e_with_url", username="default", password="xxxxxx", host="10.0.1.94")docsearch = clickhouse.Clickhouse.from_documents(docs, embeddings, config=settings)
import langchain_community.vectorstores.clickhouse as clickhousefrom langchain.embeddings import HuggingFaceEmbeddingsmodel_kwargs = {"device": "cuda"}~~~~embeddings = HuggingFaceEmbeddings(model_name="/root/models/moka-ai-m3e-large", model_kwargs=model_kwargs)settings = clickhouse.ClickhouseSettings(table="jd_docs_m3e_with_url_splited", username="default", password="xxxx", host="10.0.1.94")ck_db = clickhouse.Clickhouse(embeddings, config=settings)ck_retriever = ck_db.as_retriever(search_type="similarity_score_threshold", search_kwargs={'score_threshold': 0.9})ck_retriever.get_relevant_documents("如何创建mysql rds")
from fastapi import FastAPIfrom pydantic import BaseModelfrom singleton_decorator import singletonfrom langchain_community.embeddings import HuggingFaceEmbeddingsimport langchain_community.vectorstores.clickhouse as clickhouseimport uvicornimport jsonapp = FastAPI()app = FastAPI(docs_url=None)app.host = "0.0.0.0"model_kwargs = {"device": "cuda"}embeddings = HuggingFaceEmbeddings(model_name="/root/models/moka-ai-m3e-large", model_kwargs=model_kwargs)settings = clickhouse.ClickhouseSettings(table="jd_docs_m3e_with_url_splited", username="default", password="xxxx", host="10.0.1.94")ck_db = clickhouse.Clickhouse(embeddings, config=settings)ck_retriever = ck_db.as_retriever(search_type="similarity", search_kwargs={"k": 3})class question(BaseModel):content: strasync def root():return {"ok"}async def retriver(question: question):global ck_retrieverresult = ck_retriever.invoke(question.content)return resultif __name__ == '__main__':uvicorn.run(app='retriever_api:app', host="0.0.0.0",port=8000, reload=True)
[{"page_content": "云缓存 Redis--Redis迁移解决方案\n###RedisSyncer 操作步骤\n####数据校验\n```\nwget https://github.com/TraceNature/rediscompare/releases/download/v1.0.0/rediscompare-1.0.0-linux-amd64.tar.gz\nrediscompare compare single2single --saddr \\\"10.0.1.101:6479\\\" --spassword \\\"redistest0102\\\" --taddr \\\"10.0.1.102:6479\\\" --tpassword \\\"redistest0102\\\" --comparetimes 3\n\n``` \n**Github 地址:** [https://github.com/TraceNature/redissyncer-server](\\\"https://github.com/TraceNature/redissyncer-server\\\")","metadata": {"product": "云缓存 Redis","source": "https://docs.jdcloud.com/cn/jcs-for-redis/doc-2","title": "Redis迁移解决方案"},"type": "Document"},{"page_content": "云缓存 Redis--Redis迁移解决方案\n###RedisSyncer 操作步骤\n####数据校验\n```\nwget https://github.com/TraceNature/rediscompare/releases/download/v1.0.0/rediscompare-1.0.0-linux-amd64.tar.gz\nrediscompare compare single2single --saddr \\\"10.0.1.101:6479\\\" --spassword \\\"redistest0102\\\" --taddr \\\"10.0.1.102:6479\\\" --tpassword \\\"redistest0102\\\" --comparetimes 3\n\n``` \n**Github 地址:** [https://github.com/TraceNature/redissyncer-server](\\\"https://github.com/TraceNature/redissyncer-server\\\")","metadata": {"product": "云缓存 Redis","source": "https://docs.jdcloud.com/cn/jcs-for-redis/doc-2","title": "Redis迁移解决方案"},"type": "Document"},{"page_content": "云缓存 Redis--Redis迁移解决方案\n###RedisSyncer 操作步骤\n####数据校验\n```\nwget https://github.com/TraceNature/rediscompare/releases/download/v1.0.0/rediscompare-1.0.0-linux-amd64.tar.gz\nrediscompare compare single2single --saddr \\\"10.0.1.101:6479\\\" --spassword \\\"redistest0102\\\" --taddr \\\"10.0.1.102:6479\\\" --tpassword \\\"redistest0102\\\" --comparetimes 3\n\n``` \n**Github 地址:** [https://github.com/TraceNature/redissyncer-server](\\\"https://github.com/TraceNature/redissyncer-server\\\")","metadata": {"product": "云缓存 Redis","source": "https://docs.jdcloud.com/cn/jcs-for-redis/doc-2","title": "Redis迁移解决方案"},"type": "Document"}]
结合模型和prompt,回答问题
-
answer 服务 -
from fastapi import FastAPIfrom pydantic import BaseModelfrom langchain_community.llms import VLLMfrom transformers import AutoTokenizerfrom langchain.prompts import PromptTemplateimport requestsimport uvicornimport jsonimport loggingapp = FastAPI()app = FastAPI(docs_url=None)app.host = "0.0.0.0"logger = logging.getLogger()logger.setLevel(logging.INFO)to_console = logging.StreamHandler()logger.addHandler(to_console)# load model# model_name = "/root/models/Llama3-Chinese-8B-Instruct"model_name = "/root/models/Qwen1.5-1.8B-Chat"tokenizer = AutoTokenizer.from_pretrained(model_name)llm_llama3 = VLLM(model=model_name,tokenizer=tokenizer,task="text-generation",temperature=0.2,do_sample=True,repetition_penalty=1.1,return_full_text=False,max_new_tokens=900,)# promptprompt_template = """你是一个云技术专家使用以下检索到的Context回答问题。如果不知道答案,就说不知道。用中文回答问题。Question: {question}Context: {context}Answer:"""prompt = PromptTemplate(input_variables=["context", "question"],template=prompt_template,)def get_context_list(q: str):url = "http://10.0.0.7:8000/retriever"payload = {"content": q}res = requests.post(url, json=payload)return res.textclass question(BaseModel):content: strasync def root():return {"ok"}async def answer(q: question):logger.info("invoke!!!")global promptglobal llm_llama3context_list_str = get_context_list(q.content)context_list = json.loads(context_list_str)context = ""source_list = []for context_json in context_list:context = context+context_json["page_content"]source_list.append(context_json["metadata"]["source"])p = prompt.format(context=context, question=q.content)answer = llm_llama3(p)result = {"answer": answer,"sources": source_list}return resultif __name__ == '__main__':uvicorn.run(app='retriever_api:app', host="0.0.0.0",port=8888, reload=True)
主要服务就绪后可以开始画一张脸了,使用gradio做个简易对话界面
-
gradio 服务 -
import jsonimport gradio as grimport requestsdef greet(name, intensity):return "Hello, " + name + "!" * int(intensity)def answer(question):url = "http://127.0.0.1:8888/answer"payload = {"content": question}res = requests.post(url, json=payload)res_json = json.loads(res.text)return [res_json["answer"], res_json["sources"]]demo = gr.Interface(fn=answer,# inputs=["text", "slider"],inputs=[gr.Textbox(label="question", lines=5)],# outputs=[gr.TextArea(label="answer", lines=5),# gr.JSON(label="urls", value=list)]outputs=[gr.Markdown(label="answer"),gr.JSON(label="urls", value=list)])demo.launch(server_name="0.0.0.0")

