当前位置: 首页 > news >正文

LangChain:打造自己的LLM应用 | 京东云技术团队

1、LangChain是什么

LangChain是一个框架,用于开发由LLM驱动的应用程序。可以简单认为是LLM领域的Spring,以及开源版的ChatGPT插件系统。核心的2个功能为:

1)可以将 LLM 模型与外部数据源进行连接。

2)允许与 LLM 模型与环境进行交互,通过Agent使用工具。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vAKdriMx-1690948697278)(https://mp.toutiao.com/mp/agw/article_material/open_image/get?code=YjdjN2YxOTk4NDY4MGMwYjc3ZDBjMGE3MDFjNjkxN2UsMTY5MDk0MTE2NzQ4MQ==)]

2、LangChain核心组件

LangChain提供了各种不同的组件帮助使用LLM,如下图所示,核心组件有Models、Indexes、Chains、Memory以及Agent。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-myVQNj8C-1690948697281)(https://mp.toutiao.com/mp/agw/article_material/open_image/get?code=YzljOWUyNzU5MjE3YmM5MTlhYTRkZTk4NTVlNjkwNzAsMTY5MDk0MTE2NzQ4MQ==)]

2.1 Models

LangChain本身不提供LLM,提供通用的接口访问LLM,可以很方便的更换底层的LLM以及自定义自己的LLM。主要有2大类的Models:

1)LLM:将文本字符串作为输入并返回文本字符串的模型,类似OpenAI的text-davinci-003

2)Chat Models:由语言模型支持但将聊天消息列表作为输入并返回聊天消息的模型。一般使用的ChatGPT以及Claude为Chat Models。

与模型交互的,基本上是通过给与Prompt的方式,LangChain通过PromptTemplate的方式方便我们构建以及复用Prompt。

from langchain import PromptTemplateprompt_template = '''作为一个资深编辑,请针对 >>> 和 <<< 中间的文本写一段摘要。 
>>> {text} <<<
'''prompt = PromptTemplate(template=prompt_template, input_variables=["text"])
print(prompt.format_prompt(text="我爱北京天安门"))

2.2 Indexes

索引和外部数据进行集成,用于从外部数据获取答案。如下图所示,主要的步骤有

1)通过Document Loaders加载各种不同类型的数据源,

2)通过Text Splitters进行文本语义分割

3)通过Vectorstore进行非结构化数据的向量存储

4)通过Retriever进行文档数据检索

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tks2490I-1690948697282)(https://mp.toutiao.com/mp/agw/article_material/open_image/get?code=M2ExYWQ2ZTc5MGUzY2Q5MzYyMjY1ODAwOTZlYWZjNTYsMTY5MDk0MTE2NzQ4MQ==)]

2.2.1 Document Loaders

LangChain通过Loader加载外部的文档,转化为标准的Document类型。Document类型主要包含两个属性:page_content 包含该文档的内容。meta_data 为文档相关的描述性数据,类似文档所在的路径等。

如下图所示:LangChain目前支持结构化、非结构化以及公开以及私有的各种数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l07QVXta-1690948697284)(https://mp.toutiao.com/mp/agw/article_material/open_image/get?code=ZDQyMDIwOGY3ZmY1ZjRjNmI3MDNjYmQ4ZGYwNDAzZGYsMTY5MDk0MTE2NzQ4MQ==)]

2.2.2 Text Splitters

LLM一般都会限制上下文窗口的大小,有4k、16k、32k等。针对大文本就需要进行文本分割,常用的文本分割器为RecursiveCharacterTextSplitter,可以通过separators指定分隔符。其先通过第一个分隔符进行分割,不满足大小的情况下迭代分割。

文本分割主要有2个考虑:

1)将语义相关的句子放在一块形成一个chunk。一般根据不同的文档类型定义不同的分隔符,或者可以选择通过模型进行分割。

2)chunk控制在一定的大小,可以通过函数去计算。默认通过len函数计算,模型内部一般都是使用token进行计算。token通常指的是将文本或序列数据划分成的小的单元或符号,便于机器理解和处理。使用OpenAI相关的大模型,可以通过tiktoken包去计算其token大小。

from langchain.text_splitter import RecursiveCharacterTextSplittertext_splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder(model_name="gpt-3.5-turballowed_special="all",separators=["\n\n", "\n", "。", ","],chunk_size=7000,chunk_overlap=0
)
docs = text_splitter.create_documents(["文本在这里"])
print(docs)

2.2.3 Vectorstore

通过Text Embedding models,将文本转为向量,可以进行语义搜索,在向量空间中找到最相似的文本片段。目前支持常用的向量存储有Faiss、Chroma等。

Embedding模型支持OpenAIEmbeddings、HuggingFaceEmbeddings等。通过HuggingFaceEmbeddings加载本地模型可以节省embedding的调用费用。

#通过cache_folder加载本地模型
embeddings = HuggingFaceEmbeddings(model_name="text2vec-base-chinese", cache_folder="本地模型地址")embeddings = embeddings_model.embed_documents(["我爱北京天安门!","Hello world!"]
)

2.2.4 Retriever

Retriever接口用于根据非结构化的查询获取文档,一般情况下是文档存储在向量数据库中。可以调用 get_relevant_documents 方法来检索与查询相关的文档。

from langchain import FAISS
from langchain.document_loaders import WebBaseLoader
from langchain.embeddings import HuggingFaceEmbeddings
from langchain.text_splitter import RecursiveCharacterTextSplitterloader = WebBaseLoader("https://in.m.jd.com/help/app/register_info.html")
data = loader.load()
text_splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder(model_name="gpt-3.5-turbo",allowed_special="all",separators=["\n\n", "\n", "。", ","],chunk_size=800,chunk_overlap=0
)
docs = text_splitter.split_documents(data)
#通过cache_folder设置自己的本地模型路径
embeddings = HuggingFaceEmbeddings(model_name="text2vec-base-chinese", cache_folder="models")
vectorstore = FAISS.from_documents(docs, embeddings)
result = vectorstore.as_retriever().get_relevant_documents("用户注册资格")
print(result)
print(len(result))

2.3 Chains

Langchain通过chain将各个组件进行链接,以及chain之间进行链接,用于简化复杂应用程序的实现。其中主要有LLMChain、Sequential Chain以及Route Chain

2.3.1 LLMChain

最基本的链为LLMChain,由PromptTemplate、LLM和OutputParser组成。LLM的输出一般为文本,OutputParser用于让LLM结构化输出并进行结果解析,方便后续的调用。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zQej39HY-1690948697285)(https://mp.toutiao.com/mp/agw/article_material/open_image/get?code=ZmVkMmU5MjJmZDJlZmNjYzg2OWFjYzFiOWRmM2Y3ZGYsMTY5MDk0MTE2NzQ4MQ==)]

类似下面的示例,给评论进行关键词提前以及情绪分析,通过LLMChain组合PromptTemplate、LLM以及OutputParser,可以很简单的实现一个之前通过依赖小模型不断需要调优的事情。

from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate
from langchain.output_parsers import ResponseSchema, StructuredOutputParser
from azure_chat_llm import llm#output parser
keyword_schema = ResponseSchema(name="keyword", description="评论的关键词列表")
emotion_schema = ResponseSchema(name="emotion", description="评论的情绪,正向为1,中性为0,负向为-1")
response_schemas = [keyword_schema, emotion_schema]
output_parser = StructuredOutputParser.from_response_schemas(response_schemas)
format_instructions = output_parser.get_format_instructions()#prompt template
prompt_template_txt = '''
作为资深客服,请针对 >>> 和 <<< 中间的文本识别其中的关键词,以及包含的情绪是正向、负向还是中性。
>>> {text} <<<
RESPONSE:
{format_instructions}
'''prompt = PromptTemplate(template=prompt_template_txt, input_variables=["text"],partial_variables={"format_instructions": format_instructions})#llmchain
llm_chain = LLMChain(prompt=prompt, llm=llm)
comment = "京东物流没的说,速度态度都是杠杠滴!这款路由器颜值贼高,怎么说呢,就是泰裤辣!这线条,这质感,这速度,嘎嘎快!以后妈妈再也不用担心家里的网速了!"
result = llm_chain.run(comment)
data = output_parser.parse(result)
print(f"type={type(data)}, keyword={data['keyword']}, emotion={data['emotion']}")

输出:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NvKasJCT-1690948697287)(https://mp.toutiao.com/mp/agw/article_material/open_image/get?code=YmQwMjFhOTA3MmZkNzgzYjcwMDM3MWJiN2I2NzU3Y2YsMTY5MDk0MTE2NzQ4MQ==)]

2.3.2 Sequential Chain

SequentialChains是按预定义顺序执行的链。SimpleSequentialChain为顺序链的最简单形式,其中每个步骤都有一个单一的输入/输出,一个步骤的输出是下一个步骤的输入。SequentialChain 为顺序链更通用的形式,允许多个输入/输出。

from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate
from langchain.chains import SimpleSequentialChainfirst_prompt = PromptTemplate.from_template("翻译下面的内容到中文:""\n\n{content}"
)
# chain 1: 输入:Review 输出: 英文的 Review
chain_trans = LLMChain(llm=llm, prompt=first_prompt, output_key="content_zh")second_prompt = PromptTemplate.from_template("一句话总结下面的内容:""\n\n{content_zh}"
)chain_summary = LLMChain(llm=llm, prompt=second_prompt)
overall_simple_chain = SimpleSequentialChain(chains=[chain_trans, chain_summary],verbose=True)
content = '''In a blog post authored back in 2011, Marc Andreessen warned that, “Software is eating the world.” Over a decade later, we are witnessing the emergence of a new type of technology that’s consuming the world with even greater voracity: generative artificial intelligence (AI). This innovative AI includes a unique class of large language models (LLM), derived from a decade of groundbreaking research, that are capable of out-performing humans at certain tasks. And you don’t have to have a PhD in machine learning to build with LLMs—developers are already building software with LLMs with basic HTTP requests and natural language prompts.
In this article, we’ll tell the story of GitHub’s work with LLMs to help other developers learn how to best make use of this technology. This post consists of two main sections: the first will describe at a high level how LLMs function and how to build LLM-based applications. The second will dig into an important example of an LLM-based application: GitHub Copilot code completions.
Others have done an impressive job of cataloging our work from the outside. Now, we’re excited to share some of the thought processes that have led to the ongoing success of GitHub Copilot.
'''
result = overall_simple_chain.run(content)
print(f'result={result}')

输出:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-24UjKTYj-1690948697287)(https://mp.toutiao.com/mp/agw/article_material/open_image/get?code=NDg0NGM5ODYzNGEzYjVhYjhlNTY4Mjg2MGI5NTUzMGMsMTY5MDk0MTE2NzQ4Mg==)]

2.3.3 Router Chain

RouterChain是根据输入动态的选择下一个链,每条链处理特定类型的输入。

RouterChain由两个组件组成:

1)路由器链本身,负责选择要调用的下一个链,主要有2种RouterChain,其中LLMRouterChain通过LLM进行路由决策,EmbeddingRouterChain 通过向量搜索的方式进行路由决策。

2)目标链列表,路由器链可以路由到的子链。

初始化RouterChain以及destination_chains完成后,通过MultiPromptChain将两者结合起来使用。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9kN0bbDu-1690948697288)(https://mp.toutiao.com/mp/agw/article_material/open_image/get?code=YzQ0ZjM5ZjYyYjAzODBmZjBmOWMzNDg3MTM4MjAwZGQsMTY5MDk0MTE2NzQ4Mg==)]

2.3.4 Documents Chain

下面的4种Chain主要用于Document的处理,在基于文档生成摘要、基于文档的问答等场景中经常会用到,在后续的落地实践里也会有所体现。

2.3.4.1 Stuff

StuffDocumentsChain这种链最简单直接,是将所有获取到的文档作为context放入到Prompt中,传递到LLM获取答案。

这种方式可以完整的保留上下文,调用LLM的次数也比较少,建议能使用stuff的就使用这种方式。其适合文档拆分的比较小,一次获取文档比较少的场景,不然容易超过token的限制。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uCiez1vr-1690948697289)(https://mp.toutiao.com/mp/agw/article_material/open_image/get?code=YTdjNzYyYWZhNTVhYWUwMDhkNWI3NGI4N2Y3NDYzNTQsMTY5MDk0MTE2NzQ4Mg==)]

2.3.4.2 Refine

RefineDocumentsChain是通过迭代更新的方式获取答案。先处理第一个文档,作为context传递给llm,获取中间结果intermediate answer。然后将第一个文档的中间结果以及第二个文档发给llm进行处理,后续的文档类似处理。

Refine这种方式能部分保留上下文,以及token的使用能控制在一定范围。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b413Rjzk-1690948697290)(https://mp.toutiao.com/mp/agw/article_material/open_image/get?code=ZDg2NGQyM2YyZjgxNTJkZWQ3MThhY2Q5NTIwYzUwYTMsMTY5MDk0MTE2NzQ4Mg==)]

2.3.4.3 MapReduce

MapReduceDocumentsChain先通过LLM对每个document进行处理,然后将所有文档的答案在通过LLM进行合并处理,得到最终的结果。

MapReduce的方式将每个document单独处理,可以并发进行调用。但是每个文档之间缺少上下文。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hzUx9Fmh-1690948697291)(https://mp.toutiao.com/mp/agw/article_material/open_image/get?code=ODIyMzRmZjMxOTMxYjdiNmE2ZWFjYTg0NTZhZmRiMWUsMTY5MDk0MTE2NzQ4Mg==)]

2.3.4.4 MapRerank

MapRerankDocumentsChain和MapReduceDocumentsChain类似,先通过LLM对每个document进行处理,每个答案都会返回一个score,最后选择score最高的答案。

MapRerank和MapReduce类似,会大批量的调用LLM,每个document之间是独立处理。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rBOv3mck-1690948697292)(https://mp.toutiao.com/mp/agw/article_material/open_image/get?code=YjYxZmM4YTQ1Y2MwNjFiNTg3YjQ5NDdkZmVlOGVjZjMsMTY5MDk0MTE2NzQ4Mg==)]

2.4 Memory

正常情况下Chain无状态的,每次交互都是独立的,无法知道之前历史交互的信息。LangChain使用Memory组件保存和管理历史消息,这样可以跨多轮进行对话,在当前会话中保留历史会话的上下文。Memory组件支持多种存储介质,可以与Monogo、Redis、SQLite等进行集成,以及简单直接形式就是Buffer Memory。常用的Buffer Memory有

1)ConversationSummaryMemory :以摘要的信息保存记录

2)ConversationBufferWindowMemory:以原始形式保存最新的n条记录

3)ConversationBufferMemory:以原始形式保存所有记录

通过查看chain的prompt,可以发现{history}变量传递了从memory获取的会话上下文。下面的示例演示了Memory的使用方式,可以很明细看到,答案是从之前的问题里获取的。

from langchain.chains import ConversationChain
from langchain.memory import ConversationBufferMemoryfrom azure_chat_llm import llmmemory = ConversationBufferMemory()
conversation = ConversationChain(llm=llm, memory=memory, verbose=True)
print(conversation.prompt)
print(conversation.predict(input="我的姓名是tiger"))
print(conversation.predict(input="1+1=?"))
print(conversation.predict(input="我的姓名是什么"))

输出:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qdIWKaus-1690948697293)(https://mp.toutiao.com/mp/agw/article_material/open_image/get?code=ZmE4YzJlOWJkNzYwMmJiZWUwMzYwOTgzOWMxNDk4NDQsMTY5MDk0MTE2NzQ4Mg==)]

2.5 Agent

Agent字面含义就是代理,如果说LLM是大脑,Agent就是代理大脑使用工具Tools。目前的大模型一般都存在知识过时、逻辑计算能力低等问题,通过Agent访问工具,可以去解决这些问题。目前这个领域特别活跃,诞生了类似AutoGPT、BabyAGI、AgentGPT等一堆优秀的项目。传统使用LLM,需要给定Prompt一步一步的达成目标,通过Agent是给定目标,其会自动规划并达到目标。

2.5.1 Agent核心组件

Agent:代理,负责调用LLM以及决定下一步的Action。其中LLM的prompt必须包含agent_scratchpad变量,记录执行的中间过程

Tools:工具,Agent可以调用的方法。LangChain已有很多内置的工具,也可以自定义工具。注意Tools的description属性,LLM会通过描述决定是否使用该工具。

ToolKits:工具集,为特定目的的工具集合。类似Office365、Gmail工具集等

Agent Executor:Agent执行器,负责进行实际的执行。

2.5.2 Agent的类型

一般通过initialize_agent函数进行Agent的初始化,除了llm、tools等参数,还需要指定AgentType。

agent = initialize_agent(agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,tools=tools,llm=llm,verbose=True)
print(agent.agent.llm_chain.prompt.template)

该Agent为一个zero-shot-react-description类型的Agent,其中zero-shot表明只考虑当前的操作,不会记录以及参考之前的操作。react表明通过ReAct框架进行推理,description表明通过工具的description进行是否使用的决策。

其他的类型还有chat-conversational-react-description、conversational-react-description、react-docstore、self-ask-with-search等,类似chat-conversational-react-description通过memory记录之前的对话,应答会参考之前的操作。

可以通过agent.agent.llm_chain.prompt.template方法,获取其推理决策所使用的模板。

2.5.3 自定义Tool

有多种方式可以自定义Tool,最简单的方式是通过@tool装饰器,将一个函数转为Tool。注意函数必须得有docString,其为Tool的描述。

from azure_chat_llm import llm
from langchain.agents import load_tools, initialize_agent, tool
from langchain.agents.agent_types import AgentType
from datetime import date@tool
def time(text: str) -> str:"""返回今天的日期。"""return str(date.today())tools = load_tools(['llm-math'], llm=llm)
tools.append(time)
agent_math = initialize_agent(agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,tools=tools,llm=llm,verbose=True)
print(agent_math("计算45 * 54"))
print(agent_math("今天是哪天?"))

输出为:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9YnvNO4A-1690948697294)(https://mp.toutiao.com/mp/agw/article_material/open_image/get?code=NDg0N2NjODZkZWFhMzgzZDI4YjQwYTQyN2UxZDMyNjgsMTY5MDk0MTE2NzQ4Mg==)]

3、LangChain落地实践

3.1 文档生成总结

1)通过Loader加载远程文档

2)通过Splitter基于Token进行文档拆分

3)加载summarize链,链类型为refine,迭代进行总结

from langchain.prompts import PromptTemplate
from langchain.document_loaders import PlaywrightURLLoader
from langchain.chains.summarize import load_summarize_chain
from langchain.text_splitter import RecursiveCharacterTextSplitter
from azure_chat_llm import llmloader = PlaywrightURLLoader(urls=["https://content.jr.jd.com/article/index.html?pageId=708258989"])
data = loader.load()text_splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder(model_name="gpt-3.5-turbo",allowed_special="all",separators=["\n\n", "\n", "。", ","],chunk_size=7000,chunk_overlap=0
)prompt_template = '''
作为一个资深编辑,请针对 >>> 和 <<< 中间的文本写一段摘要。 
>>> {text} <<<
'''
refine_template = '''
作为一个资深编辑,基于已有的一段摘要:{existing_answer},针对 >>> 和 <<< 中间的文本完善现有的摘要。 
>>> {text} <<<
'''PROMPT = PromptTemplate(template=prompt_template, input_variables=["text"])
REFINE_PROMPT = PromptTemplate(template=refine_template, input_variables=["existing_answer", "text"]
)chain = load_summarize_chain(llm, chain_type="refine", question_prompt=PROMPT, refine_prompt=REFINE_PROMPT, verbose=False)docs = text_splitter.split_documents(data)
result = chain.run(docs)
print(result)

3.2 基于外部文档的问答

1)通过Loader加载远程文档

2)通过Splitter基于Token进行文档拆分

3)通过FAISS向量存储文档,embedding加载HuggingFace的text2vec-base-chinese模型

4)自定义QA的prompt,通过RetrievalQA回答相关的问题

from langchain.chains import RetrievalQA
from langchain.document_loaders import WebBaseLoader
from langchain.embeddings.huggingface import HuggingFaceEmbeddings
from langchain.prompts import PromptTemplate
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.vectorstores import FAISSfrom azure_chat_llm import llmloader = WebBaseLoader("https://in.m.jd.com/help/app/register_info.html")
data = loader.load()
text_splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder(model_name="gpt-3.5-turbo",allowed_special="all",separators=["\n\n", "\n", "。", ","],chunk_size=800,chunk_overlap=0
)
docs = text_splitter.split_documents(data)
#设置自己的模型路径
embeddings = HuggingFaceEmbeddings(model_name="text2vec-base-chinese", cache_folder="model")
vectorstore = FAISS.from_documents(docs, embeddings)template = """请使用下面提供的背景信息来回答最后的问题。 如果你不知道答案,请直接说不知道,不要试图凭空编造答案。
回答时最多使用三个句子,保持回答尽可能简洁。 回答结束时,请一定要说"谢谢你的提问!"
{context}
问题: {question}
有用的回答:"""
QA_CHAIN_PROMPT = PromptTemplate(input_variables=["context", "question"], template=template)qa_chain = RetrievalQA.from_chain_type(llm, retriever=vectorstore.as_retriever(),return_source_documents=True,chain_type_kwargs={"prompt": QA_CHAIN_PROMPT})result = qa_chain({"query": "用户注册资格"})
print(result["result"])
print(len(result['source_documents']))

4、未来发展方向

随着大模型的发展,LangChain应该是目前最火的LLM开发框架,能和外部数据源交互、能集成各种常用的组件等等,大大降低了LLM应用开发的门槛。其创始人Harrison Chase也和Andrew Ng联合开发了2门短课程,帮忙大家快速掌握LangChain的使用。

目前大模型的迭代升级特别快,作为一个框架,LangChain也得保持特别快的迭代速度。其开发特别拼,每天都会提交大量的commit,基本隔几天就会发布一个新版本,其Contributor也达到了1200多人,特别活跃。

个人认为,除了和业务结合落地LLM应用外,还有2个大的方向可以进一步去探索:

1)通过低代码的形式进一步降低LLM应用的开发门槛。类似langflow这样的可视化编排工具发展也很快

2)打造更加强大的Agent。Agent之于大模型,个人觉得类似SQL之于DB,能大幅度提升LLM的应用场景

5、参考资料

1、https://python.langchain.com/docs/get_started/introduction.html

2、https://github.com/liaokongVFX/LangChain-Chinese-Getting-Started-Guide

3、https://www.deeplearning.ai/short-courses/langchain-for-llm-application-development/

4、https://lilianweng.github.io/posts/2023-06-23-agent/

5、https://mp.weixin.qq.com/s/3coFhAdzr40tozn8f9Dc-w

6、https://github.com/langchain-ai/langchain

作者:京东科技 杨虎

来源:京东云开发者社区

相关文章:

LangChain:打造自己的LLM应用 | 京东云技术团队

1、LangChain是什么 LangChain是一个框架&#xff0c;用于开发由LLM驱动的应用程序。可以简单认为是LLM领域的Spring&#xff0c;以及开源版的ChatGPT插件系统。核心的2个功能为&#xff1a; 1&#xff09;可以将 LLM 模型与外部数据源进行连接。 2&#xff09;允许与 LLM 模…...

字节跳动测试岗,3面都过了,HR告诉我这个原因被刷了...

说在前面 面试时最好不要虚报工资。本来字节跳动是很想去的&#xff0c;几轮面试也通过了&#xff0c;最后没offer&#xff0c;自己只想到下面几个原因&#xff1a; 虚报工资&#xff0c;比实际高30%&#xff1b; 有更好的人选&#xff0c;这个可能性不大&#xff0c;我看还在…...

Android 14重要更新预览

Android 14重要更新预览 国际化 Android 14 在 Android 13 的基础上进一步扩展了按应用设定语言功能&#xff0c;提供了一些额外的功能&#xff1a; 自动生成应用的 localeConfig&#xff1a;从 Android Studio Giraffe Canary 7 和 AGP 8.1.0-alpha07 开始&#xff0c;您可以…...

快速上手字符串函数

文章目录 前言一、求字符串的长度strlen函数strlen函数学习使用strlen函数模拟实现strlen函数模拟实现方法1&#xff1a;计数器法strlen函数模拟实现方法2&#xff1a;指针减指针法strlen函数模拟实现方法3&#xff1a;递归方法 二、字符串的拷贝&#xff0c;拼接和比较strcpy函…...

linux(centos) docker 安装 nginx

​1、拉取nginx最新版本镜像 docker pull nginx:latest 查看镜像 docker images 或者 docker images -a 2.启动nginx容器 docker run -d -p 80:80 --name nginx nginx 使用docker run命令&#xff0c;启动nginx容器。 --name&#xff0c;设置容器名。为方便记忆&#xff…...

SpringBoot 整合 Minio

官网&#xff1a; MinIO 是一个基于 Go 实现的高性能、兼容 S3 协议的对象存储。它采用 GNU AGPL v3 开源协议&#xff0c;项目地址是 https://github.com/minio/minio 。 它适合存储海量的非结构化的数据&#xff0c;例如说图片、音频、视频等常见文件&#xff0c;备份数据、…...

《吐血整理》高级系列教程-吃透Fiddler抓包教程(24)-Fiddler如何优雅地在正式和测试环境之间来回切换-中篇

1.简介 在开发或者测试的过程中&#xff0c;由于项目环境比较多&#xff0c;往往需要来来回回地反复切换&#xff0c;那么如何优雅地切换呢&#xff1f;宏哥今天介绍几种方法供小伙伴或者童鞋们进行参考。 2.实际工作场景 2.1问题场景 &#xff08;1&#xff09;已发布线上…...

探索 GPTCache|GPT-4 将开启多模态 AI 时代,GPTCache + Milvus 带来省钱秘籍

世界正处于数字化的浪潮中&#xff0c;为了更好理解和分析大量数据&#xff0c;人们对于人工智能&#xff08;AI&#xff09;解决方案的需求呈爆炸式增长。 此前&#xff0c;OpenAI 推出基于 GPT-3.5 模型的智能对话机器人 ChatGPT&#xff0c;在自然语言处理&#xff08;NLP&a…...

纯css实现登录表单动效

效果图&#xff1a; 代码展示 // 我这边用的是elementUI表单校验&#xff0c;更改的样式。 <el-form:model"form":rules"rules"ref"fromList":hide-required-asterisk"true"><el-form-item prop"account"><…...

【css】外边距margin

外边距中有一个属性值比较有意思&#xff1a;inherit 值&#xff0c;继承父类的属性。 <!DOCTYPE html> <html> <head> <style> div {border: 1px solid red;margin-left: 100px; }p.ex1 {margin-left: inherit; } </style> </head> <…...

Cpp8 — 二叉搜索树

二叉搜索树&#xff08;搜索二叉树、二叉排序树&#xff09; 二叉搜索树又称二叉排序树&#xff0c;它要么是一棵空树&#xff0c;要么是具有以下性质的二叉树&#xff1a; 1.若它的左子树不为空&#xff0c;则左子树上所有节点的值都小于根节点的值 2.若它的右子树不为空&…...

【实操教程】如何开始用Qt Widgets编程?(一)

Qt 是目前最先进、最完整的跨平台C开发工具。它不仅完全实现了一次编写&#xff0c;所有平台无差别运行&#xff0c;更提供了几乎所有开发过程中需要用到的工具。如今&#xff0c;Qt已被运用于超过70个行业、数千家企业&#xff0c;支持数百万设备及应用。 在本文中&#xff0…...

openmp和avx配置

实际场景&#xff1a; 项目中数据拷贝慢&#xff08;使用的是memcpy&#xff09;&#xff0c;希望能加速拷贝&#xff0c;所以尝试了使用avx的流方式&#xff0c;和openmp方式处理 问题1&#xff1a; 调用avx是报错 error: inlining failed in call to always_inline ‘__m512…...

18 个JS优化技巧,可以解决 90% 的屎山代码!!!

文章目录 18 个JS优化技巧&#xff0c;可以解决 90% 的屎山代码&#xff01;&#xff01;&#xff01;1.箭头函数2.解构赋值变量3.使用模版字面量进行字符拼接4.使用展开运算符进行数组和对象操作5.简化循环6.简化判断7.使用对象解构和默认参数简化函数参数8.使用函数式编程概念…...

go逆向符号恢复

前言 之前一直没怎么重视&#xff0c;结果发现每次遇到go的题都是一筹莫展&#xff0c;刷几道题练习一下吧 准备 go语言写的程序一般都被strip去掉符号了&#xff0c;而且ida没有相关的签名文件&#xff0c;没办法完成函数名的识别与字符串的定位&#xff0c;所以第一步通常…...

论文阅读- Uncovering Coordinated Networks on Social Media:Methods and Case Studies

链接&#xff1a;https://arxiv.org/pdf/2001.05658.pdf 目录 摘要&#xff1a; 引言 Methods Case Study 1: Account Handle Sharing Coordination Detection 分析 Case Study 2: Image Coordination Coordination Detection Analysis Case Study 3: Hashtag Sequen…...

应急响应-Linux

应急响应-Linux 1.关键目录 /etc/passwd 记录用户信息 /etc/shadow 保存用户密码&#xff08;hash&#xff09; /etc/crontab 定时任务文件 /etc/anacrontab 异步定时任务文件 /etc/rc.d/rc.local 开机启动项 /var/log/btmp …...

利用spinal的伴生对象简化集成rtl代码过程

一 参考 SpinalHDL——集成你的RTL代码 (qq.com)https://mp.weixin.qq.com/s?__biz=Mzg5NjQyMzQwMQ==&mid=2247484852&idx=1&sn=d074279cdc0d58eb5dc73ca68271eee8&chksm=c0000132f77788249838570187495e34cc12ab40e8f8f5ec8f65414ec84b3ece2d17f0d4c4f8&…...

C# Blazor 学习笔记(7):组件嵌套开发

文章目录 前言相关资料组件嵌套组件模板RenderFragment 意义传统前端样式组件化css 前言 我们在组件化一共有三个目的。 不用写CSS不用写html不用写交互逻辑 简单来说就是Java常说的约定大于配置。我们只需要必须的参数即可&#xff0c;其它的都按照默认配置。我们不需要关系…...

DAY1,C高级(命令,Linux的文件系统,软、硬链接文件)

1.创建链接文件&#xff1b; 文件系统中的每个文件都与唯一的 inode 相关联&#xff0c;inode 存储了文件的元数据和数据块的地址&#xff0c;文件名与 inode 之间的链接关系称为硬链接或软链接。 硬链接文件的创建&#xff1a; ln 被链接文件的绝对路径 硬链接文件的绝对…...

CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型

CVPR 2025 | MIMO&#xff1a;支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题&#xff1a;MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者&#xff1a;Yanyuan Chen, Dexuan Xu, Yu Hu…...

STM32F4基本定时器使用和原理详解

STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

vue3 定时器-定义全局方法 vue+ts

1.创建ts文件 路径&#xff1a;src/utils/timer.ts 完整代码&#xff1a; import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...

MinIO Docker 部署:仅开放一个端口

MinIO Docker 部署:仅开放一个端口 在实际的服务器部署中,出于安全和管理的考虑,我们可能只能开放一个端口。MinIO 是一个高性能的对象存储服务,支持 Docker 部署,但默认情况下它需要两个端口:一个是 API 端口(用于存储和访问数据),另一个是控制台端口(用于管理界面…...

libfmt: 现代C++的格式化工具库介绍与酷炫功能

libfmt: 现代C的格式化工具库介绍与酷炫功能 libfmt 是一个开源的C格式化库&#xff0c;提供了高效、安全的文本格式化功能&#xff0c;是C20中引入的std::format的基础实现。它比传统的printf和iostream更安全、更灵活、性能更好。 基本介绍 主要特点 类型安全&#xff1a…...

通过MicroSip配置自己的freeswitch服务器进行调试记录

之前用docker安装的freeswitch的&#xff0c;启动是正常的&#xff0c; 但用下面的Microsip连接不上 主要原因有可能一下几个 1、通过下面命令可以看 [rootlocalhost default]# docker exec -it freeswitch fs_cli -x "sofia status profile internal"Name …...

Python训练营-Day26-函数专题1:函数定义与参数

题目1&#xff1a;计算圆的面积 任务&#xff1a; 编写一个名为 calculate_circle_area 的函数&#xff0c;该函数接收圆的半径 radius 作为参数&#xff0c;并返回圆的面积。圆的面积 π * radius (可以使用 math.pi 作为 π 的值)要求&#xff1a;函数接收一个位置参数 radi…...

TJCTF 2025

还以为是天津的。这个比较容易&#xff0c;虽然绕了点弯&#xff0c;可还是把CP AK了&#xff0c;不过我会的别人也会&#xff0c;还是没啥名次。记录一下吧。 Crypto bacon-bits with open(flag.txt) as f: flag f.read().strip() with open(text.txt) as t: text t.read…...

新版NANO下载烧录过程

一、序言 搭建 Jetson 系列产品烧录系统的环境需要在电脑主机上安装 Ubuntu 系统。此处使用 18.04 LTS。 二、环境搭建 1、安装库 $ sudo apt-get install qemu-user-static$ sudo apt-get install python 搭建环境的过程需要这个应用库来将某些 NVIDIA 软件组件安装到 Je…...

Linux信号保存与处理机制详解

Linux信号的保存与处理涉及多个关键机制&#xff0c;以下是详细的总结&#xff1a; 1. 信号的保存 进程描述符&#xff08;task_struct&#xff09;&#xff1a;每个进程的PCB中包含信号相关信息。 pending信号集&#xff1a;记录已到达但未处理的信号&#xff08;未决信号&a…...