二、環(huán)境準(zhǔn)備

在使用LangChain進(jìn)行AI應(yīng)用程序開發(fā)前,需要準(zhǔn)備好相應(yīng)的開發(fā)環(huán)境,包括Conda、Jupyter Notebook、使用的智譜AI GLM-4大模型。

1、安裝Conda

使用Python的人都會(huì)遇到庫的安裝、環(huán)境的管理問題,Conda就是解決這些問題的一個(gè)工具,目前有AnaConda和MiniConda兩種,都是Continuum Analytics的開源項(xiàng)目。這兩種的區(qū)別就是:AnaConda大而全,預(yù)裝了大部分科學(xué)計(jì)算庫(99%其實(shí)用不上),提供了圖形界面,適合初學(xué)者;MiniConda小而精,只有命令行。個(gè)人推薦使用MiniConda,比較輕量,節(jié)省時(shí)間和空間,需要什么再安裝就可以。

MiniConda的下載地址如下:https://docs.conda.io/projects/miniconda/en/latest/ ,windows和mac版本都包括了,下載好直接安裝即可。

創(chuàng)建虛擬環(huán)境:

conda create -n langchain python=3.9

激活虛擬環(huán)境:

conda activate langchain

2、安裝Jupyter Notebook

為了能更方便編程和調(diào)試,及時(shí)執(zhí)行代碼塊,我們使用Jupyter Notebook來作為Python集成開發(fā)工具。

在虛擬環(huán)境中安裝Jupyter Notebook:


conda install jupyter notebook

啟動(dòng)Jupyter notebook:

jupyter notebook

3、安裝LangChain

在Jupyter Notebook中進(jìn)行操作,安裝LangChain的最小集。

pip install --upgrade langchain

4、調(diào)用智譜AI的GLM-4大模型

LLM的選擇有多種方案。

方案一:遠(yuǎn)程調(diào)用OpenAI的ChatGPT系統(tǒng)API,效果較好,token花費(fèi)較貴;

方案二:遠(yuǎn)程調(diào)用智譜AI的GLM-4的API,效果較好,token花費(fèi)較低;

方案三:本地部署開源大語言模型ChatGLM3-6B,效果較差,不需要收費(fèi),但電腦需要有13GB以上的GPU。

綜合考慮,方案二最理想。遠(yuǎn)程調(diào)用智譜AI的GLM-4的API的方式門檻最低,提示詞工程的效果也比較好。目前智譜AI新注冊(cè)會(huì)贈(zèng)送18元金額,GLM-4是0.1元/1000tokens,實(shí)名認(rèn)證的話會(huì)再送400萬tokens(一個(gè)月內(nèi)使用有效),算比較經(jīng)濟(jì)實(shí)惠的。注冊(cè)地址:https://open.bigmodel.cn/??梢宰?cè)申請(qǐng)API key。

下面的操作都在Jupyter Notebook中進(jìn)行。

安裝智譜的SDK包:

pip install zhipuai

由于最新的LangChain 0.1.7集成的ChatZhipuAI類和最新zhipuai SDK版本兼容性方面有問題,需要重新包裝一個(gè)類。代碼如下:

"""ZHIPU AI chat models wrapper."""
from __future__ import annotations

import asyncio
import logging
from functools import partial
from importlib.metadata import version
from typing import (
Any,
Callable,
Dict,
Iterator,
List,
Mapping,
Optional,
Tuple,
Type,
Union,
)

from langchain_core.callbacks import (
AsyncCallbackManagerForLLMRun,
CallbackManagerForLLMRun,
)
from langchain_core.language_models.chat_models import (
BaseChatModel,
generate_from_stream,
)
from langchain_core.language_models.llms import create_base_retry_decorator
from langchain_core.messages import (
AIMessage,
AIMessageChunk,
BaseMessage,
BaseMessageChunk,
ChatMessage,
ChatMessageChunk,
HumanMessage,
HumanMessageChunk,
SystemMessage,
SystemMessageChunk,
ToolMessage,
ToolMessageChunk,
)
from langchain_core.outputs import (
ChatGeneration,
ChatGenerationChunk,
ChatResult,
)
from langchain_core.pydantic_v1 import BaseModel, Field
from packaging.version import parse

logger = logging.getLogger(__name__)

def is_zhipu_v2() -> bool:
"""Return whether zhipu API is v2 or more."""
_version = parse(version("zhipuai"))
return _version.major >= 2

def _create_retry_decorator(
llm: ChatZhipuAI,
run_manager: Optional[
Union[AsyncCallbackManagerForLLMRun, CallbackManagerForLLMRun]
] = None,
) -> Callable[[Any], Any]:
import zhipuai

errors = [
zhipuai.ZhipuAIError,
zhipuai.APIStatusError,
zhipuai.APIRequestFailedError,
zhipuai.APIReachLimitError,
zhipuai.APIInternalError,
zhipuai.APIServerFlowExceedError,
zhipuai.APIResponseError,
zhipuai.APIResponseValidationError,
zhipuai.APITimeoutError,
]
return create_base_retry_decorator(
error_types=errors, max_retries=llm.max_retries, run_manager=run_manager
)

def convert_message_to_dict(message: BaseMessage) -> dict:
"""Convert a LangChain message to a dictionary.

Args:
message: The LangChain message.

Returns:
The dictionary.
"""
message_dict: Dict[str, Any]
if isinstance(message, ChatMessage):
message_dict = {"role": message.role, "content": message.content}
elif isinstance(message, HumanMessage):
message_dict = {"role": "user", "content": message.content}
elif isinstance(message, AIMessage):
message_dict = {"role": "assistant", "content": message.content}
if "tool_calls" in message.additional_kwargs:
message_dict["tool_calls"] = message.additional_kwargs["tool_calls"]
# If tool calls only, content is None not empty string
if message_dict["content"] == "":
message_dict["content"] = None
elif isinstance(message, SystemMessage):
message_dict = {"role": "system", "content": message.content}
elif isinstance(message, ToolMessage):
message_dict = {
"role": "tool",
"content": message.content,
"tool_call_id": message.tool_call_id,
}
else:
raise TypeError(f"Got unknown type {message}")
if "name" in message.additional_kwargs:
message_dict["name"] = message.additional_kwargs["name"]
return message_dict

def convert_dict_to_message(_dict: Mapping[str, Any]) -> BaseMessage:
"""Convert a dictionary to a LangChain message.

Args:
_dict: The dictionary.

Returns:
The LangChain message.
"""
role = _dict.get("role")
if role == "user":
return HumanMessage(content=_dict.get("content", ""))
elif role == "assistant":
content = _dict.get("content", "") or ""
additional_kwargs: Dict = {}
if tool_calls := _dict.get("tool_calls"):
additional_kwargs["tool_calls"] = tool_calls
return AIMessage(content=content, additional_kwargs=additional_kwargs)
elif role == "system":
return SystemMessage(content=_dict.get("content", ""))
elif role == "tool":
additional_kwargs = {}
if "name" in _dict:
additional_kwargs["name"] = _dict["name"]
return ToolMessage(
content=_dict.get("content", ""),
tool_call_id=_dict.get("tool_call_id"),
additional_kwargs=additional_kwargs,
)
else:
return ChatMessage(content=_dict.get("content", ""), role=role)

def _convert_delta_to_message_chunk(
_dict: Mapping[str, Any], default_class: Type[BaseMessageChunk]
) -> BaseMessageChunk:
role = _dict.get("role")
content = _dict.get("content") or ""
additional_kwargs: Dict = {}
if _dict.get("tool_calls"):
additional_kwargs["tool_calls"] = _dict["tool_calls"]

if role == "user" or default_class == HumanMessageChunk:
return HumanMessageChunk(content=content)
elif role == "assistant" or default_class == AIMessageChunk:
return AIMessageChunk(content=content, additional_kwargs=additional_kwargs)
elif role == "system" or default_class == SystemMessageChunk:
return SystemMessageChunk(content=content)
elif role == "tool" or default_class == ToolMessageChunk:
return ToolMessageChunk(content=content, tool_call_id=_dict["tool_call_id"])
elif role or default_class == ChatMessageChunk:
return ChatMessageChunk(content=content, role=role)
else:
return default_class(content=content)

class ChatZhipuAI(BaseChatModel):
"""
ZHIPU AI large language chat models API. To use, you should have the `zhipuai` python package installed. Example: .. code-block:: python from langchain_community.chat_models import ChatZhipuAI zhipuai_chat = ChatZhipuAI( temperature=0.5, api_key="your-api-key", model_name="glm-3-turbo", ) """ zhipuai: Any zhipuai_api_key: Optional[str] = Field(default=None, alias="api_key") """Automatically inferred from env var ZHIPUAI_API_KEY if not provided.""" client: Any = Field(default=None, exclude=True) #: :meta private: model_name: str = Field("glm-3-turbo", alias="model") """ Model name to use. -glm-3-turbo: According to the input of natural language instructions to complete a variety of language tasks, it is recommended to use SSE or asynchronous call request interface. -glm-4: According to the input of natural language instructions to complete a variety of language tasks, it is recommended to use SSE or asynchronous call request interface. """ temperature: float = Field(0.95) """ What sampling temperature to use. The value ranges from 0.0 to 1.0 and cannot be equal to 0. The larger the value, the more random and creative the output; The smaller the value, the more stable or certain the output will be. You are advised to adjust top_p or temperature parameters based on application scenarios, but do not adjust the two parameters at the same time. """ top_p: float = Field(0.7) """ Another method of sampling temperature is called nuclear sampling. The value ranges from 0.0 to 1.0 and cannot be equal to 0 or 1. The model considers the results with top_p probability quality tokens. For example, 0.1 means that the model decoder only considers tokens from the top 10% probability of the candidate set. You are advised to adjust top_p or temperature parameters based on application scenarios, but do not adjust the two parameters at the same time. """ request_id: Optional[str] = Field(None) """ Parameter transmission by the client must ensure uniqueness; A unique identifier used to distinguish each request, which is generated by default by the platform when the client does not transmit it. """ do_sample: Optional[bool] = Field(True) """ When do_sample is true, the sampling policy is enabled. When do_sample is false, the sampling policy temperature and top_p are disabled """ streaming: bool = Field(False) """Whether to stream the results or not.""" model_kwargs: Dict[str, Any] = Field(default_factory=dict) """Holds any model parameters valid for create call not explicitly specified.""" max_tokens: Optional[int] = None """Number of chat completions to generate for each prompt.""" max_retries: int = 2 """Maximum number of retries to make when generating.""" @property def _identifying_params(self) -> Dict[str, Any]: """Get the identifying parameters.""" return {**{"model_name": self.model_name}, **self._default_params} @property def _llm_type(self) -> str: """Return the type of chat model.""" return "zhipuai" @property def lc_secrets(self) -> Dict[str, str]: return {"zhipuai_api_key": "ZHIPUAI_API_KEY"} @classmethod def get_lc_namespace(cls) -> List[str]: """Get the namespace of the langchain object.""" return ["langchain", "chat_models", "zhipuai"] @property def lc_attributes(self) -> Dict[str, Any]: attributes: Dict[str, Any] = {} if self.model_name: attributes["model"] = self.model_name if self.streaming: attributes["streaming"] = self.streaming if self.max_tokens: attributes["max_tokens"] = self.max_tokens return attributes @property def _default_params(self) -> Dict[str, Any]: """Get the default parameters for calling ZhipuAI API.""" params = { "model": self.model_name, "stream": self.streaming, "temperature": self.temperature, "top_p": self.top_p, "do_sample": self.do_sample, **self.model_kwargs, } if self.max_tokens is not None: params["max_tokens"] = self.max_tokens return params @property def _client_params(self) -> Dict[str, Any]: """Get the parameters used for the zhipuai client.""" zhipuai_creds: Dict[str, Any] = { "request_id": self.request_id, } return {**self._default_params, **zhipuai_creds} def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) try: from zhipuai import ZhipuAI if not is_zhipu_v2(): raise RuntimeError( "zhipuai package version is too low" "Please install it via 'pip install --upgrade zhipuai'" ) self.client = ZhipuAI( api_key=self.zhipuai_api_key, # 填寫您的 APIKey ) except ImportError: raise RuntimeError( "Could not import zhipuai package. " "Please install it via 'pip install zhipuai'" ) def completions(self, **kwargs) -> Any | None: return self.client.chat.completions.create(**kwargs) async def async_completions(self, **kwargs) -> Any: loop = asyncio.get_running_loop() partial_func = partial(self.client.chat.completions.create, **kwargs) response = await loop.run_in_executor( None, partial_func, ) return response async def async_completions_result(self, task_id): loop = asyncio.get_running_loop() response = await loop.run_in_executor( None, self.client.asyncCompletions.retrieve_completion_result, task_id, ) return response def _create_chat_result(self, response: Union[dict, BaseModel]) -> ChatResult: generations = [] if not isinstance(response, dict): response = response.dict() for res in response["choices"]: message = convert_dict_to_message(res["message"]) generation_info = dict(finish_reason=res.get("finish_reason")) if "index" in res: generation_info["index"] = res["index"] gen = ChatGeneration( message=message, generation_info=generation_info, ) generations.append(gen) token_usage = response.get("usage", {}) llm_output = { "token_usage": token_usage, "model_name": self.model_name, "task_id": response.get("id", ""), "created_time": response.get("created", ""), } return ChatResult(generations=generations, llm_output=llm_output) def _create_message_dicts( self, messages: List[BaseMessage], stop: Optional[List[str]] ) -> Tuple[List[Dict[str, Any]], Dict[str, Any]]: params = self._client_params if stop is not None: if "stop" in params: raise ValueError("stop found in both the input and default params.") params["stop"] = stop message_dicts = [convert_message_to_dict(m) for m in messages] return message_dicts, params def completion_with_retry( self, run_manager: Optional[CallbackManagerForLLMRun] = None, **kwargs: Any ) -> Any: """Use tenacity to retry the completion call.""" retry_decorator = _create_retry_decorator(self, run_manager=run_manager) @retry_decorator def _completion_with_retry(**kwargs: Any) -> Any: return self.completions(**kwargs) return _completion_with_retry(**kwargs) async def acompletion_with_retry( self, run_manager: Optional[AsyncCallbackManagerForLLMRun] = None, **kwargs: Any, ) -> Any: """Use tenacity to retry the async completion call.""" retry_decorator = _create_retry_decorator(self, run_manager=run_manager) @retry_decorator async def _completion_with_retry(**kwargs: Any) -> Any: return await self.async_completions(**kwargs) return await _completion_with_retry(**kwargs) def _generate( self, messages: List[BaseMessage], stop: Optional[List[str]] = None, run_manager: Optional[CallbackManagerForLLMRun] = None, stream: Optional[bool] = None, **kwargs: Any, ) -> ChatResult: """Generate a chat response.""" should_stream = stream if stream is not None else self.streaming if should_stream: stream_iter = self._stream( messages, stop=stop, run_manager=run_manager, **kwargs ) return generate_from_stream(stream_iter) message_dicts, params = self._create_message_dicts(messages, stop) params = { **params, **({"stream": stream} if stream is not None else {}), **kwargs, } response = self.completion_with_retry( messages=message_dicts, run_manager=run_manager, **params ) return self._create_chat_result(response) async def _agenerate( self, messages: List[BaseMessage], stop: Optional[List[str]] = None, run_manager: Optional[CallbackManagerForLLMRun] = None, stream: Optional[bool] = False, **kwargs: Any, ) -> ChatResult: """Asynchronously generate a chat response.""" should_stream = stream if stream is not None else self.streaming if should_stream: stream_iter = self._astream( messages, stop=stop, run_manager=run_manager, **kwargs ) return generate_from_stream(stream_iter) message_dicts, params = self._create_message_dicts(messages, stop) params = { **params, **({"stream": stream} if stream is not None else {}), **kwargs, } response = await self.acompletion_with_retry( messages=message_dicts, run_manager=run_manager, **params ) return self._create_chat_result(response) def _stream( self, messages: List[BaseMessage], stop: Optional[List[str]] = None, run_manager: Optional[CallbackManagerForLLMRun] = None, **kwargs: Any, ) -> Iterator[ChatGenerationChunk]: """Stream the chat response in chunks.""" message_dicts, params = self._create_message_dicts(messages, stop) params = {**params, **kwargs, "stream": True} default_chunk_class = AIMessageChunk for chunk in self.completion_with_retry( messages=message_dicts, run_manager=run_manager, **params ): if not isinstance(chunk, dict): chunk = chunk.dict() if len(chunk["choices"]) == 0: continue choice = chunk["choices"][0] chunk = _convert_delta_to_message_chunk( choice["delta"], default_chunk_class ) finish_reason = choice.get("finish_reason") generation_info = ( dict(finish_reason=finish_reason) if finish_reason is not None else None ) default_chunk_class = chunk.__class__ chunk = ChatGenerationChunk(message=chunk, generation_info=generation_info) yield chunk if run_manager: run_manager.on_llm_new_token(chunk.text, chunk=chunk)

創(chuàng)建調(diào)用的對(duì)話大模型對(duì)象,api key需要修改成你自己的:

# 填寫您自己的APIKey
ZHIPUAI_API_KEY = "..."
llm = ChatZhipuAI(
temperature=0.1,
api_key=ZHIPUAI_API_KEY,
model_name="glm-4",
)

三、AI應(yīng)用程序開發(fā)入門

環(huán)境準(zhǔn)備好之后,就可以開始使用LangChain進(jìn)行AI應(yīng)用程序開發(fā)了。LangChain其實(shí)就是通過各種鏈(Chain)將外部數(shù)據(jù)和計(jì)算連接到LLM,從而構(gòu)建面向AI的應(yīng)用程序。AI應(yīng)用程序開發(fā)的入門,介紹了簡(jiǎn)單LLM鏈、檢索鏈、智能體三個(gè)示例程序,通過一步一步操作,讓大家快速入門。

1、簡(jiǎn)單LLM鏈(LLM Chain)

1)上面已經(jīng)安裝并創(chuàng)建了智譜AI大模型,現(xiàn)在可以直接調(diào)用它。

llm.invoke("langsmith如何幫助測(cè)試?")

結(jié)果:

AIMessage(content='LangSmith 是一個(gè)旨在幫助開發(fā)者將大語言模型(LLM)應(yīng)用程序從原型階段推進(jìn)到生產(chǎn)階段的全棧開發(fā)平臺(tái)。在測(cè)試方面,LangSmith 提供了一系列功能和工具來支持開發(fā)者對(duì) LLM 應(yīng)用進(jìn)行全面的測(cè)試,確保其性能、可靠性和穩(wěn)定性。以下是 LangSmith 在測(cè)試方面如何提供幫助的幾個(gè)方面:\n\n1. **調(diào)試工具**:LangSmith 為開發(fā)者提供了調(diào)試工具,可以幫助他們理解模型的輸出以及其在特定輸入下的行為。這包括錯(cuò)誤追蹤和日志分析功能,使得開發(fā)者可以快速定位并解決模型在運(yùn)行時(shí)出現(xiàn)的問題。\n\n2. **跟蹤功能**:它允許開發(fā)者跟蹤模型的使用情況,包括性能指標(biāo)和錯(cuò)誤率,從而幫助開發(fā)者監(jiān)控模型在實(shí)際使用中的表現(xiàn)。\n\n3. **集成測(cè)試框架**:LangSmith 可能提供了集成測(cè)試框架,使得開發(fā)者可以編寫測(cè)試用例來驗(yàn)證模型的預(yù)期行為。這包括單元測(cè)試和集成測(cè)試,以確保模型在各種條件下都能正確運(yùn)行。\n\n4. **Prompt 優(yōu)化**:在生成式語言模型中,Prompt(提示)的設(shè)計(jì)對(duì)輸出質(zhì)量至關(guān)重要。LangSmith 可能提供了Prompt優(yōu)化工具,幫助開發(fā)者測(cè)試和比較不同Prompt對(duì)模型輸出的影響。\n\n5. **模型評(píng)估**:LangSmith 可能包括模型評(píng)估功能,這允許開發(fā)者測(cè)試模型的性能,并與其他模型或數(shù)據(jù)集進(jìn)行比較,以確保模型能夠滿足生產(chǎn)環(huán)境中的需求。\n\n6. **監(jiān)控和指標(biāo)**:它可能提供了實(shí)時(shí)監(jiān)控功能,幫助開發(fā)者收集和分析模型的性能指標(biāo),如響應(yīng)時(shí)間、錯(cuò)誤率等,從而持續(xù)監(jiān)控模型的健康狀況。\n\n通過這些功能,LangSmith 幫助開發(fā)者確保他們的 LLM 應(yīng)用程序在推向生產(chǎn)之前經(jīng)過了嚴(yán)格的測(cè)試,能夠提供穩(wěn)定和高質(zhì)量的輸出。這對(duì)于確保企業(yè)級(jí)應(yīng)用的可靠性、一致性和用戶滿意度至關(guān)重要。')

2)在LangChain中,可以使用提示詞模板,將原始用戶輸入轉(zhuǎn)換為更好的 LLM 輸入。提示詞模板是LangChain的一大提效法寶。

from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
prompt = ChatPromptTemplate.from_messages([
("system", "你是世界級(jí)的技術(shù)文檔作者。"),
("user", "{input}")
])

然后可以將提示詞、LLM組合成一個(gè)簡(jiǎn)單的LLM鏈。Chain是LangChain的核心,最新的版本使用了Unix經(jīng)典的管道方式來連接,相比之前簡(jiǎn)潔了很多。

chain = prompt | llm

調(diào)用LLM鏈。

chain.invoke({"input": "langsmith如何幫助測(cè)試?"})

結(jié)果:

AIMessage(content='Langsmith是一個(gè)機(jī)器學(xué)習(xí)模型,旨在幫助開發(fā)人員創(chuàng)建、理解和測(cè)試自然語言處理(NLP)模型。作為一個(gè)技術(shù)文檔作者,我可以為你提供一個(gè)關(guān)于Langsmith如何幫助測(cè)試的概述:\n\n1. **自動(dòng)化測(cè)試生成**:Langsmith可以自動(dòng)生成用于測(cè)試NLP模型的示例輸入和預(yù)期輸出。這可以節(jié)省開發(fā)人員的時(shí)間,并確保測(cè)試覆蓋了各種可能的輸入情況。\n\n2. **測(cè)試用例優(yōu)化**:Langsmith能夠識(shí)別測(cè)試用例中的冗余或低效部分,并提出優(yōu)化的建議。這有助于提高測(cè)試的效率和準(zhǔn)確性。\n\n3. **模型行為分析**:通過分析NLP模型的行為,Langsmith可以幫助識(shí)別模型的潛在問題和缺陷。這有助于在模型部署之前發(fā)現(xiàn)并修復(fù)問題。\n\n4. **測(cè)試結(jié)果評(píng)估**:Langsmith可以評(píng)估測(cè)試結(jié)果,提供關(guān)于模型性能的詳細(xì)反饋。這有助于開發(fā)人員了解模型的表現(xiàn),并確定是否需要進(jìn)一步的改進(jìn)。\n\n5. **集成與協(xié)作**:Langsmith可以與其他開發(fā)工具和平臺(tái)集成,以便在模型的開發(fā)和測(cè)試過程中提供無縫的支持。這有助于提高團(tuán)隊(duì)協(xié)作和開發(fā)效率。\n\n總的來說,Langsmith可以作為一個(gè)強(qiáng)大的工具,幫助開發(fā)人員創(chuàng)建高質(zhì)量的NLP模型,并通過自動(dòng)化和優(yōu)化測(cè)試過程來提高測(cè)試效率和準(zhǔn)確性。')

3)可以看到,輸出結(jié)果是一個(gè)AIMessage消息對(duì)象。很多情況使用字符串要方便得多,可以添加一個(gè)字符串輸出解析器來將聊天消息轉(zhuǎn)換為字符串。輸出解析器也是LangChain的一大提效法寶。

from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
prompt = ChatPromptTemplate.from_messages([
("system", "你是世界級(jí)的技術(shù)文檔作者。"),
("user", "{input}")
])

output_parser = StrOutputParser()
chain = prompt | llm | output_parser
chain.invoke({"input": "langsmith如何幫助測(cè)試?"})

輸出結(jié)果變成了字符串類型:

'Langsmith是一個(gè)機(jī)器學(xué)習(xí)模型,旨在幫助開發(fā)人員創(chuàng)建、理解和測(cè)試自然語言處理(NLP)模型。作為一個(gè)技術(shù)文檔作者,我可以為你提供一個(gè)關(guān)于Langsmith如何幫助測(cè)試的概述:\n\n1. **自動(dòng)化測(cè)試生成**:Langsmith可以自動(dòng)生成用于測(cè)試NLP模型的示例輸入和預(yù)期輸出。這可以節(jié)省開發(fā)人員的時(shí)間,并確保測(cè)試覆蓋了各種可能的輸入情況。\n\n2. **測(cè)試用例優(yōu)化**:Langsmith能夠識(shí)別測(cè)試用例中的冗余或低效部分,并提出優(yōu)化的建議。這有助于提高測(cè)試的效率和準(zhǔn)確性。\n\n3. **模型行為分析**:通過分析NLP模型的行為,Langsmith可以幫助識(shí)別模型的潛在問題和缺陷。這有助于在模型部署之前發(fā)現(xiàn)并修復(fù)問題。\n\n4. **測(cè)試結(jié)果評(píng)估**:Langsmith可以評(píng)估測(cè)試結(jié)果,提供關(guān)于模型性能的詳細(xì)反饋。這有助于開發(fā)人員了解模型的表現(xiàn),并確定是否需要進(jìn)一步的改進(jìn)。\n\n5. **集成與協(xié)作**:Langsmith可以與其他開發(fā)工具和平臺(tái)集成,如Jenkins、GitHub等,以便在模型開發(fā)和測(cè)試過程中實(shí)現(xiàn)自動(dòng)化和協(xié)作。\n\n總的來說,Langsmith作為一個(gè)AI工具,旨在簡(jiǎn)化NLP模型的測(cè)試過程,提高測(cè)試的質(zhì)量和效率,并幫助開發(fā)人員更快地構(gòu)建和部署可靠的NLP解決方案。'

本示例通過提示詞模板、LLM、輸出解析器,以管道的方式組成一個(gè)鏈,可以快速的調(diào)用AI大模型,實(shí)現(xiàn)一個(gè)簡(jiǎn)單的AI應(yīng)用程序。

2、檢索鏈(Retrieval Chain)

之前簡(jiǎn)單LLM鏈?zhǔn)纠飭柕膯栴}(“l(fā)angsmith 如何幫助測(cè)試?”),完全是依賴大語言模型已有的知識(shí)來進(jìn)行回答。當(dāng)我們有更專業(yè)更準(zhǔn)確的知識(shí)時(shí),可以通過檢索的方式從外部獲取最相關(guān)的知識(shí),然后作為背景知識(shí)傳遞給大語言模型,來獲得更精準(zhǔn)的結(jié)果。

1)首先從互聯(lián)網(wǎng)獲取數(shù)據(jù)

需要先安裝BeautifulSoup:

pip install beautifulsoup4

導(dǎo)入并使用WebBaseLoader。官網(wǎng)原示例的”https://docs.smith.langchain.com/overview” 這個(gè)地址是錯(cuò)誤的,改成:”https://docs.smith.langchain.com”

from langchain_community.document_loaders import WebBaseLoader
loader = WebBaseLoader("https://docs.smith.langchain.com")

docs = loader.load()

2)接下來需要使用嵌入模型進(jìn)行向量化,再存儲(chǔ)到向量數(shù)據(jù)庫。

因?yàn)镺penAIEmbeddings嵌入模型需要和OpenAI ChatGPT配套使用。我們換成更通用的HuggingFaceEmbeddings。

from langchain_community.embeddings import HuggingFaceEmbeddingsembeddings = HuggingFaceEmbeddings()

現(xiàn)在可以使用此嵌入模型將文檔提取到向量存儲(chǔ)中了,為了簡(jiǎn)單起見,使用了本地向量數(shù)據(jù)庫FAISS 。

首先安裝FAISS所需的軟件包:

pip install faiss-cpu

然后在向量數(shù)據(jù)庫中建立索引:

from langchain_community.vectorstores import FAISS
from langchain.text_splitter import RecursiveCharacterTextSplitter

text_splitter = RecursiveCharacterTextSplitter()
documents = text_splitter.split_documents(docs)
vector = FAISS.from_documents(documents, embeddings)

3)創(chuàng)建一個(gè)檢索鏈。該鏈將接受傳入的問題,查找相關(guān)文檔,然后將這些文檔與原始問題一起傳遞給LLM并要求其回答原始問題。

首先,建立一個(gè)文檔鏈,該鏈接受問題和檢索到的文檔并生成答案。

from langchain.chains.combine_documents import create_stuff_documents_chain

prompt = ChatPromptTemplate.from_template("""僅根據(jù)所提供的上下文回答以下問題:

<context>
{context}
</context>

問題: {input}""")

document_chain = create_stuff_documents_chain(llm, prompt)

使用檢索器動(dòng)態(tài)選擇最相關(guān)的文檔,并將其傳遞給檢索鏈。

from langchain.chains import create_retrieval_chain

retriever = vector.as_retriever()
retrieval_chain = create_retrieval_chain(retriever, document_chain)

調(diào)用檢索鏈,得到答案。

response = retrieval_chain.invoke({"input": "langsmith如何幫助測(cè)試?"})
print(response["answer"])

結(jié)果:

根據(jù)上下文信息,LangSmith 是一個(gè)用于構(gòu)建生產(chǎn)級(jí)大型語言模型(LLM)應(yīng)用程序的平臺(tái)。它可以讓用戶調(diào)試、測(cè)試、評(píng)估和監(jiān)控基于任何LLM框架構(gòu)建的鏈和智能代理。LangSmith 與 LangChain 無縫集成,LangChain 是一個(gè)用于與 LLMs 一起構(gòu)建的開源框架。

具體來說,LangSmith 幫助測(cè)試的方式可能包括:

1. **調(diào)試**:提供調(diào)試工具和界面,幫助開發(fā)者發(fā)現(xiàn)并修復(fù)代碼中的錯(cuò)誤。
2. **監(jiān)控**:在模型運(yùn)行時(shí)監(jiān)控其性能,確保其按照預(yù)期工作,并及時(shí)發(fā)現(xiàn)異常。
3. **評(píng)估**:提供評(píng)估功能,讓開發(fā)者可以測(cè)試智能代理的響應(yīng)和行為是否符合預(yù)期。
4. **集成**:與 LangChain 無縫集成,使得測(cè)試基于 LangChain 構(gòu)建的 LLM 應(yīng)用更為方便。

開發(fā)者可以使用 LangSmith 提供的文檔和指南來學(xué)習(xí)如何使用這些測(cè)試功能。此外,LangSmith 可能還提供了一些示例和教程,幫助用戶更好地理解和應(yīng)用測(cè)試工具。

請(qǐng)注意,上述解釋是基于提供的上下文信息推測(cè)的,具體langsmith如何幫助測(cè)試的詳細(xì)信息需要查閱其官方文檔或聯(lián)系其技術(shù)支持以獲得更準(zhǔn)確的答案。

本示例首先獲取外部互聯(lián)網(wǎng)頁面數(shù)據(jù),經(jīng)過嵌入模型對(duì)數(shù)據(jù)進(jìn)行向量化,存儲(chǔ)到向量數(shù)據(jù)庫,當(dāng)用戶輸入提示詞時(shí),到向量數(shù)據(jù)庫中獲取相關(guān)信息作為背景知識(shí)一起輸入給LLM,最后LLM輸出更準(zhǔn)確的信息。通過這種檢索增強(qiáng)生成的方式,可以方便的構(gòu)建一些面向特定私有化知識(shí)領(lǐng)域的專用AI應(yīng)用程序。后續(xù)會(huì)有一篇文章專門深入的介紹檢索增強(qiáng)生成方面的應(yīng)用。

3、智能體(Agent)

所謂智能體,實(shí)際上是指預(yù)先提供多種工具(tools),智能體調(diào)用LLM根據(jù)我們的問題決定使用某種工具,進(jìn)而調(diào)用工具獲得需要的信息,再把需要的信息發(fā)送給LLM,獲得最終結(jié)果。工具可以是LangChain內(nèi)置的工具,也可以是自定義的工具,比如通過網(wǎng)絡(luò)進(jìn)行搜索獲取信息的工具、數(shù)學(xué)計(jì)算的工具、我們自己定義的特定功能函數(shù)等。

在這個(gè)示例中,我們給智能體提供了兩個(gè)工具:一個(gè)是剛才創(chuàng)建的有關(guān) LangSmith的檢索器,另一個(gè)是能夠回答最新信息的搜索工具。

1)首先,為剛才創(chuàng)建的檢索器設(shè)置一個(gè)工具,名字叫”langsmith_search”:

from langchain.tools.retriever import create_retriever_tool

retriever_tool = create_retriever_tool(
retriever,
"langsmith_search",
"搜索有關(guān)LangSmith的信息。關(guān)于LangSmith的任何問題,您都可以使用這個(gè)工具",
)

2)對(duì)于另一個(gè)搜索工具,需要使用到Tavily,需要用到API 密鑰,從https://app.tavily.com/home網(wǎng)站上可以免費(fèi)申請(qǐng)。

然后設(shè)置為環(huán)境變量:

export TAVILY_API_KEY=...

創(chuàng)建搜索工具:

from langchain_community.tools.tavily_search import TavilySearchResults

search = TavilySearchResults()

3)創(chuàng)建智能體使用的工具列表:

tools = [retriever_tool, search]

4)接下來可以創(chuàng)建智能體來使用這些工具。

首先安裝langchain hub,這個(gè)網(wǎng)站上提供了很多提示詞模板,可以直接使用。

pip install langchainhub

獲取提示詞和創(chuàng)建智能體執(zhí)行器。這里做了些優(yōu)化,create_openai_functions_agent換成了create_openai_tools_agent,”hwchase17/openai-functions-agent”換成了”hwchase17/openai-tools-agent”。

from langchain import hub
from langchain.agents import create_openai_tools_agent
from langchain.agents import AgentExecutor

# Get the prompt to use - you can modify this!
prompt = hub.pull("hwchase17/openai-tools-agent")
agent = create_openai_tools_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

4)現(xiàn)在可以調(diào)用智能體了。先向它詢問有關(guān) LangSmith 的問題:

agent_executor.invoke({"input": "langsmith如何幫助測(cè)試?"})

結(jié)果如下,可以看到LLM先根據(jù)問題確定要使用”langsmith_search”工具,然后LangChain調(diào)用”langsmith_search”工具從向量數(shù)據(jù)庫中獲得相關(guān)信息,最后返回信息給LLM得到最終結(jié)果。

> Entering new AgentExecutor chain...

Invoking: langsmith_search with {'query': 'langsmith如何幫助測(cè)試'} LangSmith | ?????? LangSmith Skip to main content?????? LangSmith DocsLangChain Python DocsLangChain JS/TS DocsLangSmith API DocsSearchGo to AppLangSmithUser GuideSetupPricing (Coming Soon)Self-HostingTracingEvaluationMonitoringPrompt HubLangSmithOn this pageLangSmithIntroductionLangSmith is a platform for building production-grade LLM applications.It lets you debug, test, evaluate, and monitor chains and intelligent agents built on any LLM framework and seamlessly integrates with LangChain, the go-to open source framework for building with LLMs.LangSmith is developed by LangChain, the company behind the open source LangChain framework.Quick StartTracing: Get started with the tracing quick start.Evaluation: Get started with the evaluation quick start.Next StepsCheck out the following sections to learn more about LangSmith:User Guide: Learn about the workflows LangSmith supports at each stage of the LLM application lifecycle.Setup: Learn how to create an account, obtain an API key, and configure your environment.Pricing: Learn about the pricing model for LangSmith.Self-Hosting: Learn about self-hosting options for LangSmith.Tracing: Learn about the tracing capabilities of LangSmith.Evaluation: Learn about the evaluation capabilities of LangSmith.Prompt Hub Learn about the Prompt Hub, a prompt management tool built into LangSmith.Additional ResourcesLangSmith Cookbook: A collection of tutorials and end-to-end walkthroughs using LangSmith.LangChain Python: Docs for the Python LangChain library.LangChain Python API Reference: documentation to review the core APIs of LangChain.LangChain JS: Docs for the TypeScript LangChain libraryDiscord: Join us on our Discord to discuss all things LangChain!Contact SalesIf you're interested in enterprise security and admin features, special deployment options, or access for large teams, reach out to speak with sales.NextUser GuideIntroductionQuick StartNext StepsAdditional ResourcesCommunityDiscordTwitterGitHubDocs CodeLangSmith SDKPythonJS/TSMoreHomepageBlogCopyright ? 2024 LangChain, Inc.LangSmith 是一個(gè)用于構(gòu)建生產(chǎn)級(jí) LLM 應(yīng)用程序的平臺(tái)。它可以讓您調(diào)試、測(cè)試、評(píng)估和監(jiān)控基于任何 LLM 框架構(gòu)建的鏈和智能代理,并且可以無縫地與 LangChain 集成,LangChain 是構(gòu)建 LLM 的首選開源框架。LangSmith 是由 LangChain 開發(fā)的,LangChain 是 LLM 應(yīng)用程序生命周期各個(gè)階段的 workflow 支持,例如調(diào)試、測(cè)試、評(píng)估和監(jiān)控。此外,LangSmith 還提供了 Prompt Hub,這是一個(gè)內(nèi)置的提示管理工具,可以讓您輕松地管理和維護(hù)提示。 > Finished chain. [31]: {'input': 'langsmith如何幫助測(cè)試?', 'output': 'LangSmith 是一個(gè)用于構(gòu)建生產(chǎn)級(jí) LLM 應(yīng)用程序的平臺(tái)。它可以讓您調(diào)試、測(cè)試、評(píng)估和監(jiān)控基于任何 LLM 框架構(gòu)建的鏈和智能代理,并且可以無縫地與 LangChain 集成,LangChain 是構(gòu)建 LLM 的首選開源框架。LangSmith 是由 LangChain 開發(fā)的,LangChain 是 LLM 應(yīng)用程序生命周期各個(gè)階段的 workflow 支持,例如調(diào)試、測(cè)試、評(píng)估和監(jiān)控。此外,LangSmith 還提供了 Prompt Hub,這是一個(gè)內(nèi)置的提示管理工具,可以讓您輕松地管理和維護(hù)提示。'}

5)再詢問下天氣情況:

agent_executor.invoke({"input": "舊金山的天氣怎么樣?"})

結(jié)果如下,可以看到LLM先根據(jù)問題確定要使用”tavily_search_results_json”工具,然后LangChain調(diào)用”tavily_search_results_json”工具從互聯(lián)網(wǎng)上獲得相關(guān)信息,最后返回信息給LLM得到最終結(jié)果。

> Entering new AgentExecutor chain...

Invoking: tavily_search_results_json with {'query': '舊金山的天氣'} [{'url': 'https://tianqi.2345.com/america_united-states/san-francisco-ca/', 'content': '2345天氣預(yù)報(bào)提供舊金山天氣預(yù)報(bào),未來舊金山15天天氣,通過2345天氣預(yù)報(bào)詳細(xì)了解舊金山天氣預(yù)報(bào)以及舊金山周邊各地區(qū)未來15天、30天天氣情況,溫度,空氣質(zhì)量,降水,風(fēng)力,氣壓,紫外線強(qiáng)度等! ... 您使用的瀏覽器版本過低! ...'}, {'url': 'https://zh.weather-forecast.com/locations/San-Francisco/forecasts/latest', 'content': '鄰近舊金山的實(shí)時(shí)氣象站\n*注意:并非所有舊金山附近的氣象站會(huì)同時(shí)更新,我們只顯示最近氣象站的報(bào)告 被視為當(dāng)前的。還包括在可接受的時(shí)間范圍內(nèi)舊金山 附近的任何船舶(SYNOP)提交的天氣報(bào)告。Read More\n舊金山 Location map\n加利福尼亞州天氣地圖\n加利福尼亞州天氣地圖\n舊金山的天氣照片\n上傳一幅 舊金山的天氣照片 | 上傳另一個(gè)城市\(zhòng)n目的地舊金山附近城市的天氣預(yù)報(bào):\n? 2024 Meteo365.com Very mild (max 14°C on Fri morning, min 8°C on Wed night). Very mild (max 14°C on Fri morning, min 8°C on Wed night). Very mild (max 11°C on Sat afternoon, min 7°C on Thu night). Very mild (max 15°C on Sat afternoon, min 10°C on Mon night).'}, {'url': 'http://www.weather.com.cn/weather/401640100.shtml', 'content': '【舊金山天氣】舊金山天氣預(yù)報(bào),天氣預(yù)報(bào)一周,天氣預(yù)報(bào)15天查詢 預(yù)報(bào) 美國>舊金山(Sanfrancisco) 18:00更新 數(shù)據(jù)來源 中央氣象臺(tái) 今天 周末 7天 8-15天 10日(今天) 晴轉(zhuǎn)陰 16 / 8℃ 4-5級(jí)轉(zhuǎn)3-4級(jí) 11日(明天) 小雨轉(zhuǎn)陰 14 / 7℃ <3級(jí) 12日(后天) 陰 13 / 8℃ <3級(jí) 13日(周二) 陰 13 / 7℃ <3級(jí) 14日(周三) 小雨轉(zhuǎn)陰 13 / 8℃ <3級(jí) 15日(周四) 多云轉(zhuǎn)陰 14 / 8℃ <3級(jí) 16日(周五) 陰轉(zhuǎn)小雨 15 / 9℃ 3-4級(jí)轉(zhuǎn)4-5級(jí) 08時(shí)11時(shí)14時(shí)17時(shí)20時(shí)23時(shí)02時(shí)05時(shí) 7℃13℃16℃16℃13℃10℃10℃10℃ 北風(fēng)北風(fēng)北風(fēng)西風(fēng)西北風(fēng)西風(fēng)東北風(fēng)東北風(fēng)'}, {'url': 'https://weather.com/zh-CN/weather/today/l/54f9d8baac32496f6b5497b4bf7a277c3e2e6cc5625de69680e6169e7e38e9a8', 'content': '舊金山, CA, 美國 今日天氣 體感溫度9° 7:04 17:44 高 / 低 -- / 7° 大風(fēng) 6 公里/小時(shí) 濕度 85% 露點(diǎn) 8° 氣壓 1023.0 毫巴 紫外線指數(shù) 0(最大值11) 能見度 11.27 公里 月相'}, {'url': 'https://weather.com/zh-CN/weather/tenday/l/54f9d8baac32496f6b5497b4bf7a277c3e2e6cc5625de69680e6169e7e38e9a8', 'content': '。\n周五 09 | 夜間\n少云。最低 6°C。北 風(fēng) 10 到 15 每 km / h 。\n周六 10\n周六 10 | 白天\n大部晴朗。最高 14°C。東北偏北 風(fēng) 10 到 15 每 km / h 。\n周六 10 | 夜間\n大部晴朗。最低 7°C。東 風(fēng),風(fēng)向多變。\n周日 11\n周日 11 | 白天\n大部晴朗。最高 15°C。東北 風(fēng) 10 到 15 每 km / h 。\n周日 11 | 夜間\n少云。最低 7°C。東北 風(fēng),風(fēng)向多變。\n周一 12\n周一 12 | 白天\n少云。最高 16°C。東南偏東 風(fēng),風(fēng)向多變。\n周一 12 | 夜間\n少云。最低 8°C。東南偏南 風(fēng),風(fēng)向多變。\n周二 13\n周二 13 | 白天\n recents\n特殊天氣預(yù)報(bào)\n10 天天氣-舊金山, CA, 美國\n沿海洪水通報(bào)\n今天晚上\n周一 05 | 夜間\n多個(gè)地區(qū)有濃霧。最低 8°C。東北 風(fēng),風(fēng)向多變。\n周二 06\n周二 06 | 白天\n少云。最高 13°C。西北偏北 風(fēng) 10 到 15 每 km / h 。\n周二 06 | 夜間\n大部晴朗。最低 8°C。西北偏西 風(fēng) 10 到 15 每 km / h 少云。最高 17°C。東南 風(fēng) 10 到 15 每 km / h 。\n周二 13 | 夜間\n少云。最低 8°C。東 風(fēng),風(fēng)向多變。\n周三 14\n周三 14 | 白天\n少云。最高 16°C。東南 風(fēng) 10 到 15 每 km / h 。降雨幾率 40%。\n周五 16 | 夜間\n陣雨。最低 10°C。東南 風(fēng) 10 到 15 每 km / h 。降雨幾率 。降雨幾率 60%。\n周一 19 | 夜間\n陣雨。預(yù)計(jì)間或有薄霧且能見度降低。最低 10°C。東南偏南 風(fēng) 10 到 15 每 km / h'}]舊金山現(xiàn)在的天氣我無法獲取,但是根據(jù)tavily_search_results_json的結(jié)果,最近舊金山的天氣情況如下:今天是晴天,最高溫度為16°C,最低溫度為8°C。明天有小雨,最高溫度為14°C,最低溫度為7°C。后天天氣陰,最高溫度為13°C,最低溫度為8°C。 > Finished chain. [25]: {'input': '舊金山的天氣怎么樣?', 'output': '舊金山現(xiàn)在的天氣我無法獲取,但是根據(jù)tavily_search_results_json的結(jié)果,最近舊金山的天氣情況如下:今天是晴天,最高溫度為16°C,最低溫度為8°C。明天有小雨,最高溫度為14°C,最低溫度為7°C。后天天氣陰,最高溫度為13°C,最低溫度為8°C。'}

本示例通過給智能體提供多種工具(有關(guān)LangSmith的檢索器、回答最新信息的搜索工具),智能體調(diào)用LLM根據(jù)我們的問題決定使用某種工具,進(jìn)而調(diào)用工具獲得需要的信息,再把需要的信息發(fā)送給LLM,獲得最終結(jié)果。通過這種工具增強(qiáng)的方式,可以構(gòu)建集成特定應(yīng)用的AI應(yīng)用程序,比如在應(yīng)用程序中集成在線購物、自定義的數(shù)據(jù)計(jì)算等實(shí)用功能。后續(xù)會(huì)有一篇文章專門深入的介紹智能體工具方面的應(yīng)用。

四、總結(jié)

本文是最新版LangChain使用智譜AI的GLM-4大模型開發(fā)AI應(yīng)用程序系列的第一篇文章-快速入門篇。

首先對(duì)LangChain做了介紹,LangChain是哈里森·蔡斯 (Harrison Chase) 于2022年10月創(chuàng)建的,對(duì)于AI應(yīng)用程序開發(fā)來說,它的地位就相當(dāng)于Java界的Spring。LangChain的整體架構(gòu)分為六層,它的核心概念就是鏈,鏈接外部一切能鏈接的東西賦予LLM力量。

然后從零基礎(chǔ)開始介紹了LangChain環(huán)境的安裝和配置,包括Conda、Jupyter Notebook、LangChain,以及智譜AI GLM-4在LangChain的最新調(diào)用API。

最后再通過LLM鏈、檢索鏈、智能體三個(gè)經(jīng)典的示例,帶大家一步一步的快速上手了提示詞模板、輸出解析器、管道、LLM鏈、檢索鏈、智能體等功能的使用和開發(fā)。

希望能給大家起到一定的參考作用,同時(shí)也歡迎共同探討。后續(xù)文章會(huì)繼續(xù)深入分析檢索鏈、智能體等的使用,敬請(qǐng)期待。

文章轉(zhuǎn)自微信公眾號(hào)@頂尖程序員

上一篇:

還在使用網(wǎng)頁版AI翻譯嗎?Kimi API翻譯excel表格內(nèi)容讓你的效率提升10倍

下一篇:

Microsoft.Extensions.AI 預(yù)覽版簡(jiǎn)介 – 適用于 .NET 的統(tǒng)一 AI 構(gòu)建塊
#你可能也喜歡這些API文章!

我們有何不同?

API服務(wù)商零注冊(cè)

多API并行試用

數(shù)據(jù)驅(qū)動(dòng)選型,提升決策效率

查看全部API→
??

熱門場(chǎng)景實(shí)測(cè),選對(duì)API

#AI文本生成大模型API

對(duì)比大模型API的內(nèi)容創(chuàng)意新穎性、情感共鳴力、商業(yè)轉(zhuǎn)化潛力

25個(gè)渠道
一鍵對(duì)比試用API 限時(shí)免費(fèi)

#AI深度推理大模型API

對(duì)比大模型API的邏輯推理準(zhǔn)確性、分析深度、可視化建議合理性

10個(gè)渠道
一鍵對(duì)比試用API 限時(shí)免費(fèi)