Ng Enda ChatGPT "LangChain for LLM Application Development" notes

LangChain-based LLM application development

1 Introduction

Now, using Prompt can quickly develop an application, but an application may need to write Prompt multiple times and parse the output of LLM. Therefore, a lot of glue code needs to be written.

The LangChain framework created by Harrison Chase simplifies the development process. It contains two packages, Python and JavaScript. LangChain extracts many common abstractions, focuses on composition and modularization, and includes many independent components that can be used alone or in combination with other components. Plus, lots of different use cases are covered and it's very easy to get started. This makes it easy for LangChain to develop complex applications based on LLM.

Outline of what will be covered in this course:
insert image description here

2. Models, Prompts and Parsers

Models: Basic language models.

Prompts: Inputs to the model that convey user intent to the model.

Parsers: Parses the output of the model into a more structured output.

import os
import openai

from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv()) # read local .env file
openai.api_key = os.environ['OPENAI_API_KEY']
def get_completion(prompt, model="gpt-3.5-turbo"):
    messages = [{
    
    "role": "user", "content": prompt}]
    response = openai.ChatCompletion.create(
        model=model,
        messages=messages,
        temperature=0, 
    )
    return response.choices[0].message["content"]

Pirate-style English, let ChatGPT translate into official English:

customer_email = """
Arrr, I be fuming that me blender lid \
flew off and splattered me kitchen walls \
with smoothie! And to make matters worse,\
the warranty don't cover the cost of \
cleaning up me kitchen. I need yer help \
right now, matey!
"""

style = """American English \
in a calm and respectful tone
"""

prompt = f"""Translate the text \
that is delimited by triple backticks 
into a style that is {
      
      style}.
text: ```{
      
      customer_email}```
"""

response = get_completion(prompt)

output:

insert image description here
Implementation based on LangChain:

#!pip install --upgrade langchain
from langchain.chat_models import ChatOpenAI

# To control the randomness and creativity of the generated
# text by an LLM, use temperature = 0.0
chat = ChatOpenAI(temperature=0.0)
chat

insert image description here

PromptTemplate

Create a prompt template:

from langchain.prompts import ChatPromptTemplate

template_string = """Translate the text \
that is delimited by triple backticks \
into a style that is {style}. \
text: ```{text}```
"""

prompt_template = ChatPromptTemplate.from_template(template_string)

prompt_template.messages[0].prompt

insert image description here

# 打印 prompt 中的参数,输出:['style', 'text']
prompt_template.messages[0].prompt.input_variables
customer_style = """American English \
in a calm and respectful tone
"""

customer_email = """
Arrr, I be fuming that me blender lid \
flew off and splattered me kitchen walls \
with smoothie! And to make matters worse, \
the warranty don't cover the cost of \
cleaning up me kitchen. I need yer help \
right now, matey!
"""

customer_messages = prompt_template.format_messages(
                    style=customer_style,
                    text=customer_email)
print(type(customer_messages))
print(type(customer_messages[0]))

insert image description here

print(customer_messages[0])

insert image description here

# Call the LLM to translate to the style of the customer message
customer_response = chat(customer_messages)
print(customer_response.content)

insert image description here

Why use Prompt templates? Because when building complex applications, prompts can be very long and specific. So a good prompt template is a useful abstraction for better reuse of prompts. LangChain provides hints for many common operations, such as text summarization, question answering, linking databases or connecting different APIs.

Here's an example of a very long prompt template for an eLearning application grading a program:

insert image description here
When building an app with LLM, it is common to instruct the LLM to generate output in a certain format, such as using specific keywords. The following example shows the operation of using the ReAct framework to let LLM perform Chain of Thought Reasoning.

ReAct thinking chain reasoning

insert image description here
in,

  • Thought: The content of LLM thinking, because LLM has room for thinking, it can often draw more accurate conclusions.
  • Action: Perform a specific action.
  • Observation: Show what LLM observed from this action, etc.

You can use the above three prompts in combination with a parser, and LangChain will automatically extract the text marked with these specific keywords. This makes it nice to abstractly specify the input to the LLM and then have the parser correctly interpret the output given by the LLM.

LangChain parser

The following is an example of using the LangChain parser to parse the output in JSON format.

{
    
    
  "gift": False,
  "delivery_days": 5,
  "price_value": "pretty affordable!"
}

customer_review = """\
This leaf blower is pretty amazing.  It has four settings:\
candle blower, gentle breeze, windy city, and tornado. \
It arrived in two days, just in time for my wife's \
anniversary present. \
I think my wife liked it so much she was speechless. \
So far I've been the only one using it, and I've been \
using it every other morning to clear the leaves on our lawn. \
It's slightly more expensive than the other leaf blowers \
out there, but I think it's worth it for the extra features.
"""

review_template = """\
For the following text, extract the following information:

gift: Was the item purchased as a gift for someone else? \
Answer True if yes, False if not or unknown.

delivery_days: How many days did it take for the product \
to arrive? If this information is not found, output -1.

price_value: Extract any sentences about the value or price,\
and output them as a comma separated Python list.

Format the output as JSON with the following keys:
gift
delivery_days
price_value

text: {text}
"""
from langchain.prompts import ChatPromptTemplate

prompt_template = ChatPromptTemplate.from_template(review_template)
print(prompt_template)

insert image description here

messages = prompt_template.format_messages(text=customer_review)
chat = ChatOpenAI(temperature=0.0)
# 此时的返回是str类型的
response = chat(messages)

Perform type conversion:

from langchain.output_parsers import ResponseSchema
from langchain.output_parsers import StructuredOutputParser
gift_schema = ResponseSchema(name="gift",
                             description="Was the item purchased\
                             as a gift for someone else? \
                             Answer True if yes,\
                             False if not or unknown.")

delivery_days_schema = ResponseSchema(name="delivery_days",
                                      description="How many days\
                                      did it take for the product\
                                      to arrive? If this \
                                      information is not found,\
                                      output -1.")

price_value_schema = ResponseSchema(name="price_value",
                                    description="Extract any\
                                    sentences about the value or \
                                    price, and output them as a \
                                    comma separated Python list.")

response_schemas = [gift_schema, 
                    delivery_days_schema,
                    price_value_schema]
output_parser = StructuredOutputParser.from_response_schemas(response_schemas)
format_instructions = output_parser.get_format_instructions()
print(format_instructions)

insert image description here

review_template_2 = """\
For the following text, extract the following information:

gift: Was the item purchased as a gift for someone else? \
Answer True if yes, False if not or unknown.

delivery_days: How many days did it take for the product\
to arrive? If this information is not found, output -1.

price_value: Extract any sentences about the value or price,\
and output them as a comma separated Python list.

text: {text}

{format_instructions}
"""

prompt = ChatPromptTemplate.from_template(template=review_template_2)

messages = prompt.format_messages(text=customer_review, 
                                  format_instructions=format_instructions)
response = chat(messages)
print(response.content)

insert image description here

# 转成 dict,以便后续处理
output_dict = output_parser.parse(response.content)

insert image description here

3. Memory

When users interact with LLM models, they cannot normally remember historical conversation information. This is a problem for building applications like chatbots. This section will introduce how to use LangChain to let the model "remember" the historical dialogue content and input it into LLM.

LangChain provides a variety of options for complex memory storage management, the following are some examples.

import os

from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv()) # read local .env file

import warnings
warnings.filterwarnings('ignore')

from langchain.chat_models import ChatOpenAI
from langchain.chains import ConversationChain
from langchain.memory import ConversationBufferMemory

llm = ChatOpenAI(temperature=0.0)
memory = ConversationBufferMemory()
conversation = ConversationChain(
    llm=llm, 
    memory = memory,
    verbose=True
)

insert image description here

It can be seen that through LangChain, the model has the ability to "remember" historical dialogue information. If the verbose parameter is set to True, after running, it will output how the LangChain API works. It can be seen that it stores all the historical session information, and then feeds it to the model every time, which allows the model to learn from the context. The ability to perceive these historical dialogue information and therefore realize memory based on this information.

insert image description here

insert image description here

ConversationBufferMemory

LangChain's ConversationBufferMemory method can temporarily store conversation memory. Using this method is also very simple, just add data to it according to the format of dict.

memory = ConversationBufferMemory()
memory.save_context({
    
    "input": "Hi"}, 
                    {
    
    "output": "What's up"})

insert image description here

When using LLM for dialogue, LLM itself is stateless, that is, LLM itself will not remember the historical messages of the dialogue with you. The reason why the chat robot has the memory ability is that the historical dialogue messages saved in the cache are fed to the model together as the context. However, as the number of dialogue rounds increases, the context to be stored becomes longer and longer, and more and more tokens are consumed when calling the ChatGPT API, which may exceed the token limit. This is a problem for large-scale chat robot applications. is unbearable. Based on this, LangChain provides a centralized and convenient memory storage solution to save dialogue messages and accumulated dialogue content.

ConversationBufferWindowMemory

Window memory, that is, only the last few rounds of dialogue messages are kept. Controlled by the parameter k, which represents the window size. For example, k = 1, which means only remember the last round of dialogue.

from langchain.memory import ConversationBufferWindowMemory

memory = ConversationBufferWindowMemory(k=1)
llm = ChatOpenAI(temperature=0.0)
memory = ConversationBufferWindowMemory(k=1)
conversation = ConversationChain(
    llm=llm, 
    memory = memory,
    verbose=False
)

ConversationalTokenBufferMemory

Token cache memory, limiting the number of tokens stored in memory.

from langchain.memory import ConversationTokenBufferMemory
from langchain.llms import OpenAI
llm = ChatOpenAI(temperature=0.0)

memory = ConversationTokenBufferMemory(llm=llm, max_token_limit=30)
memory.save_context({
    
    "input": "AI is what?!"},
                    {
    
    "output": "Amazing!"})
memory.save_context({
    
    "input": "Backpropagation is what?"},
                    {
    
    "output": "Beautiful!"})
memory.save_context({
    
    "input": "Chatbots are what?"}, 
                    {
    
    "output": "Charming!"})
memory.load_memory_variables({
    
    })

ConversationSummaryBufferMemory

The motivation behind this API is: It is expected to limit the memory storage capacity to the most recent conversations or limit the number of tokens. It is better to let LLM generate summaries of historical messages and store these summaries in memory.

from langchain.memory import ConversationSummaryBufferMemory

# create a long string
schedule = "There is a meeting at 8am with your product team. \
You will need your powerpoint presentation prepared. \
9am-12pm have time to work on your LangChain \
project which will go quickly because Langchain is such a powerful tool. \
At Noon, lunch at the italian resturant with a customer who is driving \
from over an hour away to meet you to understand the latest in AI. \
Be sure to bring your laptop to show the latest LLM demo."

memory = ConversationSummaryBufferMemory(llm=llm, max_token_limit=100)
memory.save_context({
    
    "input": "Hello"}, {
    
    "output": "What's up"})
memory.save_context({
    
    "input": "Not much, just hanging"},
                    {
    
    "output": "Cool"})
memory.save_context({
    
    "input": "What is on the schedule today?"}, 
                    {
    
    "output": f"{
      
      schedule}"})

insert image description here

insert image description here

other types of memory

insert image description here

insert image description here

4. Chain

The data used below consists of two columns, a list of product names and their corresponding reviews.

import pandas as pd
df = pd.read_csv('Data.csv')

LLMChain

from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.chains import LLMChain

llm = ChatOpenAI(temperature=0.9)
prompt = ChatPromptTemplate.from_template(
    "What is the best name to describe \
    a company that makes {
    
    product}?"
)
chain = LLMChain(llm=llm, prompt=prompt)
product = "Queen Size Sheet Set"
chain.run(product)

SimpleSequentialChain

Sequential chaining is multiple chains run one after the other. There are two types, each suitable for different scenarios:

  • SimpleSequentialChain: All subchains have only one input and one output.
  • SequentialChain: multiple inputs, multiple outputs.

insert image description here

Below is an example with two chains, the first chain outputs the company name, which is then passed to the second chain as input.

from langchain.chains import SimpleSequentialChain

llm = ChatOpenAI(temperature=0.9)

# prompt template 1
first_prompt = ChatPromptTemplate.from_template(
    "What is the best name to describe \
    a company that makes {
    
    product}?"
)

# Chain 1
chain_one = LLMChain(llm=llm, prompt=first_prompt)


# prompt template 2
second_prompt = ChatPromptTemplate.from_template(
    "Write a 20 words description for the following \
    company:{
    
    company_name}"
)
# chain 2
chain_two = LLMChain(llm=llm, prompt=second_prompt)

overall_simple_chain = SimpleSequentialChain(chains=[chain_one, chain_two],
                                             verbose=True
                                            )
overall_simple_chain.run(product)

insert image description here

SequentialChain

The example below contains four chains. Among them, the first chain will translate the comment into English; the second chain will summarize this review in one sentence; the third chain will detect what language the original comment is written in; the fourth chain will receive multiple inputs, One is the abstract obtained by the second chain, and the other is the language obtained by the third chain, which requires the specified language to be used when replying to the abstract.

Note that the output_key parameter in the following example corresponds to the variable name in the prompt.

from langchain.chains import SequentialChain

llm = ChatOpenAI(temperature=0.9)

# prompt template 1: translate to english
first_prompt = ChatPromptTemplate.from_template(
    "Translate the following review to english:"
    "\n\n{Review}"
)
# chain 1: input= Review and output= English_Review
chain_one = LLMChain(llm=llm, prompt=first_prompt, 
                     output_key="English_Review"
                    )

second_prompt = ChatPromptTemplate.from_template(
    "Can you summarize the following review in 1 sentence:"
    "\n\n{English_Review}"
)
# chain 2: input= English_Review and output= summary
chain_two = LLMChain(llm=llm, prompt=second_prompt, 
                     output_key="summary"
                    )
# prompt template 3: translate to english
third_prompt = ChatPromptTemplate.from_template(
    "What language is the following review:\n\n{Review}"
)
# chain 3: input= Review and output= language
chain_three = LLMChain(llm=llm, prompt=third_prompt,
                       output_key="language"
                      )

# prompt template 4: follow up message
fourth_prompt = ChatPromptTemplate.from_template(
    "Write a follow up response to the following "
    "summary in the specified language:"
    "\n\nSummary: {summary}\n\nLanguage: {language}"
)
# chain 4: input= summary, language and output= followup_message
chain_four = LLMChain(llm=llm, prompt=fourth_prompt,
                      output_key="followup_message"
                     )
# overall_chain: input= Review 
# and output= English_Review,summary, followup_message
overall_chain = SequentialChain(
    chains=[chain_one, chain_two, chain_three, chain_four],
    input_variables=["Review"],
    output_variables=["English_Review", "summary", "followup_message"],
    verbose=True
)
review = df.Review[5]
overall_chain(review)

insert image description here

RouterChain

Process input by routing it to a chain based on its content. Imagine that you have multiple sub-chains, and each sub-chain is responsible for processing a specific type of input. In this case, you can use a router chain (Router Chain).

Below is an example that first determines which subchain to use, and then passes the input to the corresponding subchain.

MultiPromptChain can be used to route between multiple different prompt templates.

LLMRouterChain routes between different subchains with the help of LLM. A name and description need to be provided in the prompt template.

The RouterOutputParser parser parses the LLM output into a dict, making it easy for downstream to determine which chain to use and what the input to that chain is.

In addition to the target chain, a default chain is also required, which is used as a backup chain when the route cannot find a suitable sub-chain call. It will directly use the user's question as a prompt to ask LLM, instead of generating a prompt based on a predefined template and then asking LLM.

physics_template = """You are a very smart physics professor. \
You are great at answering questions about physics in a concise\
and easy to understand manner. \
When you don't know the answer to a question you admit\
that you don't know.

Here is a question:
{input}"""


math_template = """You are a very good mathematician. \
You are great at answering math questions. \
You are so good because you are able to break down \
hard problems into their component parts, 
answer the component parts, and then put them together\
to answer the broader question.

Here is a question:
{input}"""

history_template = """You are a very good historian. \
You have an excellent knowledge of and understanding of people,\
events and contexts from a range of historical periods. \
You have the ability to think, reflect, debate, discuss and \
evaluate the past. You have a respect for historical evidence\
and the ability to make use of it to support your explanations \
and judgements.

Here is a question:
{input}"""


computerscience_template = """ You are a successful computer scientist.\
You have a passion for creativity, collaboration,\
forward-thinking, confidence, strong problem-solving capabilities,\
understanding of theories and algorithms, and excellent communication \
skills. You are great at answering coding questions. \
You are so good because you know how to solve a problem by \
describing the solution in imperative steps \
that a machine can easily interpret and you know how to \
choose a solution that has a good balance between \
time complexity and space complexity. 

Here is a question:
{input}"""
prompt_infos = [
    {
    
    
        "name": "physics", 
        "description": "Good for answering questions about physics", 
        "prompt_template": physics_template
    },
    {
    
    
        "name": "math", 
        "description": "Good for answering math questions", 
        "prompt_template": math_template
    },
    {
    
    
        "name": "History", 
        "description": "Good for answering history questions", 
        "prompt_template": history_template
    },
    {
    
    
        "name": "computer science", 
        "description": "Good for answering computer science questions", 
        "prompt_template": computerscience_template
    }
]
from langchain.chains.router import MultiPromptChain
from langchain.chains.router.llm_router import LLMRouterChain,RouterOutputParser
from langchain.prompts import PromptTemplate

llm = ChatOpenAI(temperature=0)

destination_chains = {
    
    }
for p_info in prompt_infos:
    name = p_info["name"]
    prompt_template = p_info["prompt_template"]
    prompt = ChatPromptTemplate.from_template(template=prompt_template)
    chain = LLMChain(llm=llm, prompt=prompt)
    destination_chains[name] = chain  
    
destinations = [f"{
      
      p['name']}: {
      
      p['description']}" for p in prompt_infos]
destinations_str = "\n".join(destinations)

default_prompt = ChatPromptTemplate.from_template("{input}")
default_chain = LLMChain(llm=llm, prompt=default_prompt)
MULTI_PROMPT_ROUTER_TEMPLATE = """Given a raw text input to a \
language model select the model prompt best suited for the input. \
You will be given the names of the available prompts and a \
description of what the prompt is best suited for. \
You may also revise the original input if you think that revising\
it will ultimately lead to a better response from the language model.

<< FORMATTING >>
Return a markdown code snippet with a JSON object formatted to look like:
```json
{
    
    {
    
    {
    
    {
    "destination": string \ name of the prompt to use or "DEFAULT"
    "next_inputs": string \ a potentially modified version of the original input
}}}}
```

REMEMBER: "destination" MUST be one of the candidate prompt \
names specified below OR it can be "DEFAULT" if the input is not\
well suited for any of the candidate prompts.
REMEMBER: "next_inputs" can just be the original input \
if you don't think any modifications are needed.

<< CANDIDATE PROMPTS >>
{destinations}

<< INPUT >>
{
    
    {input}}

<< OUTPUT (remember to include the ```json)>>"""
router_template = MULTI_PROMPT_ROUTER_TEMPLATE.format(
    destinations=destinations_str
)
router_prompt = PromptTemplate(
    template=router_template,
    input_variables=["input"],
    output_parser=RouterOutputParser(),
)

router_chain = LLMRouterChain.from_llm(llm, router_prompt)
chain = MultiPromptChain(router_chain=router_chain, 
                         destination_chains=destination_chains, 
                         default_chain=default_chain, verbose=True
                        )

insert image description here
insert image description here

insert image description here

5. Question And Answer

A document question answering system is a common LLM-built complex application. Embedding and vector storage are two powerful cutting-edge technologies.

Document Q&A Example

Here is an example of a document Q&A:

from langchain.chains import RetrievalQA
from langchain.chat_models import ChatOpenAI
from langchain.document_loaders import CSVLoader
from langchain.vectorstores import DocArrayInMemorySearch
from IPython.display import display, Markdown

file = 'OutdoorClothingCatalog_1000.csv'
loader = CSVLoader(file_path=file)
#pip install docarray
from langchain.indexes import VectorstoreIndexCreator

index = VectorstoreIndexCreator(
    vectorstore_cls=DocArrayInMemorySearch
).from_loaders([loader])

query ="Please list all your shirts with sun protection \
in a table in markdown and summarize each one."

response = index.query(query)

insert image description here

Embeddings

insert image description here

If you want to use the language model to combine with a large number of documents, there is a key problem: the language model can only receive a few thousand words at a time, if a large document, how to make the language model question and answer all the content of the document? The answer is with Embedding and vector storage.
insert image description here
Embedding converts a piece of text into a number, and represents the text with a high-dimensional vector (a set of numbers). Texts with similar content will have similar vector values.

Vector Database

So it is necessary to split the document into small pieces, so that only the most relevant pieces are passed to the language model each time. An Embedding is generated for each text block and stored in the vector database. After the index is created, when the user uses the application, the content entered by the user is first converted into Embedding, and then the most similar text fragments can be queried from the database, and then these fragments are combined with the original user input content Input to the language model to answer. The whole implementation process is shown in the figure below:
insert image description here
insert image description here

LangChain-based example:

from langchain.embeddings import OpenAIEmbeddings

loader = CSVLoader(file_path=file)
docs = loader.load()

embeddings = OpenAIEmbeddings()

db = DocArrayInMemorySearch.from_documents(
    docs, 
    embeddings
)

Embedding looks like this: it is a 1536-dimensional vector. Of course, OpenAI's Embedding also supports other dimensions.
insert image description here
Retriever is a generic interface that defines a method that takes a query and returns similar documents. Then manually splicing the contents of these documents into strings and saving them, and then feeding this part of the contents and the user's questions to the language model to generate output.

query = "Please suggest a shirt with sunblocking"

docs = db.similarity_search(query)

retriever = db.as_retriever()

llm = ChatOpenAI(temperature = 0.0)

qdocs = "".join([docs[i].page_content for i in range(len(docs))])

response = llm.call_as_llm(f"{
    
    qdocs} Question: Please list all your \
shirts with sun protection in a table in markdown and summarize each one.") 

insert image description here

The above step-by-step implementation process can be encapsulated into a method using LangChain, the following is an example. Among them, the stuff of the chain_type parameter indicates that when calling the language model, all document contents are put into the context together.

qa_stuff = RetrievalQA.from_chain_type(
    llm=llm, 
    chain_type="stuff", 
    retriever=retriever, 
    verbose=True
)
query =  "Please list all your shirts with sun protection in a table \
in markdown and summarize each one."

response = qa_stuff.run(query)
display(Markdown(response))

insert image description here
insert image description here

Document Stuff Method

Because the language model has token restrictions, the Stuff method is not applicable when the content of the document is long. Therefore, LangChain also provides three other methods.

The first is Map_reduce, which divides each document into blocks, and then inputs the content of each block and user questions into the language model to obtain an independent return result. Then, the results obtained from each block are combined together, and then the language model is used to summarize these results, and finally the answer is obtained. In this way, any number of documents of any length can be processed. Finally, it supports parallel processing, which can greatly improve responsiveness.

The second is Refine, which runs iteratively, where the latter input is based on the output of the previous document's question answer. This approach is suitable for scenarios where information needs to be aggregated and answers constructed over time. This method has as many calls as Map_reduce, but it cannot be parallelized and the processing speed is slower.

The third type of Map_rerank, this method only needs to call the language model once for each document, let the language model return the score of each block of the document, and finally select the output with the highest score. This method requires the model to be capable of scoring and requires high-quality prompts. Support parallel processing, faster.

The above methods can also be applied to different chains, for example, Map_reduce can be used in text summarization, which is very efficient in long documents.
insert image description here

6. Evaluation

When building an application using LLM, a question that cannot be avoided is: how to evaluate the performance of the application? Does it meet some kind of acceptance criteria? And when replacing the LLM, replacing the vector database or changing the system parameters, or changing the way of retrieving data, how to determine whether the system is better or worse than before.

These applications are actually chains and sequences of many different steps. We first need to understand what the input and output of each step are. In this process, it is necessary to use some visualization tools or debugging tools. In addition, it is necessary to test the model with a large number of different data sets, which helps us to fully understand the performance of the model.

With the QAGenerateChain API it is possible to read documents and generate a set of questions and answers from each document, avoiding manual generation. In this way, the built application can be evaluated more efficiently.

from langchain.chains import RetrievalQA
from langchain.chat_models import ChatOpenAI
from langchain.document_loaders import CSVLoader
from langchain.indexes import VectorstoreIndexCreator
from langchain.vectorstores import DocArrayInMemorySearch

file = 'OutdoorClothingCatalog_1000.csv'
loader = CSVLoader(file_path=file)
data = loader.load()

index = VectorstoreIndexCreator(
    vectorstore_cls=DocArrayInMemorySearch
).from_loaders([loader])

llm = ChatOpenAI(temperature = 0.0)
qa = RetrievalQA.from_chain_type(
    llm=llm, 
    chain_type="stuff", 
    retriever=index.vectorstore.as_retriever(), 
    verbose=True,
    chain_type_kwargs = {
    
    
        "document_separator": "<<<<>>>>>"
    }
)
# 硬编码问答样例
examples = [
    {
    
    
        "query": "Do the Cozy Comfort Pullover Set\
        have side pockets?",
        "answer": "Yes"
    },
    {
    
    
        "query": "What collection is the Ultra-Lofty \
        850 Stretch Down Hooded Jacket from?",
        "answer": "The DownTek collection"
    }
]

QAGenerateChain Q&A generation chain

from langchain.evaluation.qa import QAGenerateChain

example_gen_chain = QAGenerateChain.from_llm(ChatOpenAI())

new_examples = example_gen_chain.apply_and_parse(
    [{
    
    "doc": t} for t in data[:5]]
)

insert image description here
In order to better observe each subchain in the answer generation process, you can use the langchain.debug tool, so that you can see the prompt and intermediate output, which is convenient for troubleshooting.

import langchain
langchain.debug = True
qa.run(examples[0]["query"])
[chain/start] [1:chain:RetrievalQA] Entering Chain run with input:
{
    
    
  "query": "Do the Cozy Comfort Pullover Set have side pockets?"
}
[chain/start] [1:chain:RetrievalQA > 2:chain:StuffDocumentsChain] Entering Chain run with input:
[inputs]
[chain/start] [1:chain:RetrievalQA > 2:chain:StuffDocumentsChain > 3:chain:LLMChain] Entering Chain run with input:
{
    
    
  "question": "Do the Cozy Comfort Pullover Set have side pockets?",
  "context": ": 10\nname: Cozy Comfort Pullover Set, Stripe\ndescription: Perfect for lounging, this striped knit set lives up to its name. We used ultrasoft fabric and an easy design that's as comfortable at bedtime as it is when we have to make a quick run out.\n\nSize & Fit\n- Pants are Favorite Fit: Sits lower on the waist.\n- Relaxed Fit: Our most generous fit sits farthest from the body.\n\nFabric & Care\n- In the softest blend of 63% polyester, 35% rayon and 2% spandex.\n\nAdditional Features\n- Relaxed fit top with raglan sleeves and rounded hem.\n- Pull-on pants have a wide elastic waistband and drawstring, side pockets and a modern slim leg.\n\nImported.<<<<>>>>>: 73\nname: Cozy Cuddles Knit Pullover Set\ndescription: Perfect for lounging, this knit set lives up to its name. We used ultrasoft fabric and an easy design that's as comfortable at bedtime as it is when we have to make a quick run out. \n\nSize & Fit \nPants are Favorite Fit: Sits lower on the waist. \nRelaxed Fit: Our most generous fit sits farthest from the body. \n\nFabric & Care \nIn the softest blend of 63% polyester, 35% rayon and 2% spandex.\n\nAdditional Features \nRelaxed fit top with raglan sleeves and rounded hem. \nPull-on pants have a wide elastic waistband and drawstring, side pockets and a modern slim leg. \nImported.<<<<>>>>>: 151\nname: Cozy Quilted Sweatshirt\ndescription: Our sweatshirt is an instant classic with its great quilted texture and versatile weight that easily transitions between seasons. With a traditional fit that is relaxed through the chest, sleeve, and waist, this pullover is lightweight enough to be worn most months of the year. The cotton blend fabric is super soft and comfortable, making it the perfect casual layer. To make dressing easy, this sweatshirt also features a snap placket and a heritage-inspired Mt. Katahdin logo patch. For care, machine wash and dry. Imported.<<<<>>>>>: 265\nname: Cozy Workout Vest\ndescription: For serious warmth that won't weigh you down, reach for this fleece-lined vest, which provides you with layering options whether you're inside or outdoors.\nSize & Fit\nRelaxed Fit. Falls at hip.\nFabric & Care\nSoft, textured fleece lining. Nylon shell. Machine wash and dry. \nAdditional Features \nTwo handwarmer pockets. Knit side panels stretch for a more flattering fit. Shell fabric is treated to resist water and stains. Imported."
}
[llm/start] [1:chain:RetrievalQA > 2:chain:StuffDocumentsChain > 3:chain:LLMChain > 4:llm:ChatOpenAI] Entering LLM run with input:
{
    
    
  "prompts": [
    "System: Use the following pieces of context to answer the users question. \nIf you don't know the answer, just say that you don't know, don't try to make up an answer.\n----------------\n: 10\nname: Cozy Comfort Pullover Set, Stripe\ndescription: Perfect for lounging, this striped knit set lives up to its name. We used ultrasoft fabric and an easy design that's as comfortable at bedtime as it is when we have to make a quick run out.\n\nSize & Fit\n- Pants are Favorite Fit: Sits lower on the waist.\n- Relaxed Fit: Our most generous fit sits farthest from the body.\n\nFabric & Care\n- In the softest blend of 63% polyester, 35% rayon and 2% spandex.\n\nAdditional Features\n- Relaxed fit top with raglan sleeves and rounded hem.\n- Pull-on pants have a wide elastic waistband and drawstring, side pockets and a modern slim leg.\n\nImported.<<<<>>>>>: 73\nname: Cozy Cuddles Knit Pullover Set\ndescription: Perfect for lounging, this knit set lives up to its name. We used ultrasoft fabric and an easy design that's as comfortable at bedtime as it is when we have to make a quick run out. \n\nSize & Fit \nPants are Favorite Fit: Sits lower on the waist. \nRelaxed Fit: Our most generous fit sits farthest from the body. \n\nFabric & Care \nIn the softest blend of 63% polyester, 35% rayon and 2% spandex.\n\nAdditional Features \nRelaxed fit top with raglan sleeves and rounded hem. \nPull-on pants have a wide elastic waistband and drawstring, side pockets and a modern slim leg. \nImported.<<<<>>>>>: 151\nname: Cozy Quilted Sweatshirt\ndescription: Our sweatshirt is an instant classic with its great quilted texture and versatile weight that easily transitions between seasons. With a traditional fit that is relaxed through the chest, sleeve, and waist, this pullover is lightweight enough to be worn most months of the year. The cotton blend fabric is super soft and comfortable, making it the perfect casual layer. To make dressing easy, this sweatshirt also features a snap placket and a heritage-inspired Mt. Katahdin logo patch. For care, machine wash and dry. Imported.<<<<>>>>>: 265\nname: Cozy Workout Vest\ndescription: For serious warmth that won't weigh you down, reach for this fleece-lined vest, which provides you with layering options whether you're inside or outdoors.\nSize & Fit\nRelaxed Fit. Falls at hip.\nFabric & Care\nSoft, textured fleece lining. Nylon shell. Machine wash and dry. \nAdditional Features \nTwo handwarmer pockets. Knit side panels stretch for a more flattering fit. Shell fabric is treated to resist water and stains. Imported.\nHuman: Do the Cozy Comfort Pullover Set have side pockets?"
  ]
}
[llm/end] [1:chain:RetrievalQA > 2:chain:StuffDocumentsChain > 3:chain:LLMChain > 4:llm:ChatOpenAI] [1.73s] Exiting LLM run with output:
{
    
    
  "generations": [
    [
      {
    
    
        "text": "The Cozy Comfort Pullover Set, Stripe does have side pockets.",
        "generation_info": null,
        "message": {
    
    
          "content": "The Cozy Comfort Pullover Set, Stripe does have side pockets.",
          "additional_kwargs": {
    
    },
          "example": false
        }
      }
    ]
  ],
  "llm_output": {
    
    
    "token_usage": {
    
    
      "prompt_tokens": 628,
      "completion_tokens": 14,
      "total_tokens": 642
    },
    "model_name": "gpt-3.5-turbo"
  }
}
[chain/end] [1:chain:RetrievalQA > 2:chain:StuffDocumentsChain > 3:chain:LLMChain] [1.73s] Exiting Chain run with output:
{
    
    
  "text": "The Cozy Comfort Pullover Set, Stripe does have side pockets."
}
[chain/end] [1:chain:RetrievalQA > 2:chain:StuffDocumentsChain] [1.73s] Exiting Chain run with output:
{
    
    
  "output_text": "The Cozy Comfort Pullover Set, Stripe does have side pockets."
}
[chain/end] [1:chain:RetrievalQA] [1.97s] Exiting Chain run with output:
{
    
    
  "result": "The Cozy Comfort Pullover Set, Stripe does have side pockets."
}
'The Cozy Comfort Pullover Set, Stripe does have side pockets.'

When returning the wrong answer to the user, it may not be the problem generated by the LLM, but the problem at the time of retrieval.

In the above example, the question answering data set was generated with the help of LLM, so how to evaluate it?

First, you need to use the qa.apply(examples) function to generate the correct answer with the help of LLM.
insert image description here

QAEvalChain Q&A Evaluation Chain

from langchain.evaluation.qa import QAEvalChain

llm = ChatOpenAI(temperature=0)
eval_chain = QAEvalChain.from_llm(llm)

graded_outputs = eval_chain.evaluate(examples, predictions)
for i, eg in enumerate(examples):
    print(f"Example {
      
      i}:")
    print("Question: " + predictions[i]['query'])
    print("Real Answer: " + predictions[i]['answer'])
    print("Predicted Answer: " + predictions[i]['result'])
    print("Predicted Grade: " + graded_outputs[i]['text'])
    print()
Example 0:
Question: Do the Cozy Comfort Pullover Set have side pockets?
Real Answer: Yes
Predicted Answer: The Cozy Comfort Pullover Set, Stripe does have side pockets.
Predicted Grade: CORRECT

Example 1:
Question: What collection is the Ultra-Lofty 850 Stretch Down Hooded Jacket from?
Real Answer: The DownTek collection
Predicted Answer: The Ultra-Lofty 850 Stretch Down Hooded Jacket is from the DownTek collection.
Predicted Grade: CORRECT

Example 2:
Question: What is the weight of each pair of Women's Campside Oxfords?
Real Answer: The approximate weight of each pair of Women's Campside Oxfords is 1 lb. 1 oz.
Predicted Answer: The weight of each pair of Women's Campside Oxfords is approximately 1 lb. 1 oz.
Predicted Grade: CORRECT

Example 3:
Question: What are the dimensions of the small and medium Recycled Waterhog Dog Mat?
Real Answer: The dimensions of the small Recycled Waterhog Dog Mat are 18" x 28" and the dimensions of the medium Recycled Waterhog Dog Mat are 22.5" x 34.5".
Predicted Answer: The small Recycled Waterhog Dog Mat has dimensions of 18" x 28" and the medium size has dimensions of 22.5" x 34.5".
Predicted Grade: CORRECT

Example 4:
Question: What are some features of the Infant and Toddler Girls' Coastal Chill Swimsuit?
Real Answer: The swimsuit features bright colors, ruffles, and exclusive whimsical prints. It is made of four-way-stretch and chlorine-resistant fabric, ensuring that it keeps its shape and resists snags. The swimsuit is also UPF 50+ rated, providing the highest rated sun protection possible by blocking 98% of the sun's harmful rays. The crossover no-slip straps and fully lined bottom ensure a secure fit and maximum coverage. Finally, it can be machine washed and line dried for best results.
Predicted Answer: The Infant and Toddler Girls' Coastal Chill Swimsuit is a two-piece swimsuit with bright colors, ruffles, and exclusive whimsical prints. It is made of four-way-stretch and chlorine-resistant fabric that keeps its shape and resists snags. The swimsuit has UPF 50+ rated fabric that provides the highest rated sun protection possible, blocking 98% of the sun's harmful rays. The crossover no-slip straps and fully lined bottom ensure a secure fit and maximum coverage. It is machine washable and should be line dried for best results.
Predicted Grade: CORRECT

Example 5:
Question: What is the fabric composition of the Refresh Swimwear V-Neck Tankini Contrasts?
Real Answer: The body of the Refresh Swimwear V-Neck Tankini Contrasts is made of 82% recycled nylon and 18% Lycra® spandex, while the lining is made of 90% recycled nylon and 10% Lycra® spandex.
Predicted Answer: The Refresh Swimwear V-Neck Tankini Contrasts is made of 82% recycled nylon with 18% Lycra® spandex for the body and 90% recycled nylon with 10% Lycra® spandex for the lining.
Predicted Grade: CORRECT

Example 6:
Question: What is the fabric composition of the EcoFlex 3L Storm Pants?
Real Answer: The EcoFlex 3L Storm Pants are made of 100% nylon, exclusive of trim.
Predicted Answer: The fabric composition of the EcoFlex 3L Storm Pants is 100% nylon, exclusive of trim.
Predicted Grade: CORRECT

LangChainPlus

Create a data set, the background program automatically evaluates, and can visualize the input and output information of each node.
insert image description here
insert image description here

7. Agents

Sometimes, people think of LLM as a knowledge base, as if it learns and memorizes a large amount of information obtained from the Internet. Based on this, high-quality question answering can be easily achieved. But a more useful way is to think of the LLM as an inference engine, the user can provide some text or other information to it, and then the LLM may use it to learn this background knowledge from the Internet, or use the information provided by the user to Help users answer questions or reason about content, and even decide what to do next. At present, the Agents framework of LangChain has been able to realize the above functions.

initialize_agent

Below is an example

from langchain.agents.agent_toolkits import create_python_agent
from langchain.agents import load_tools, initialize_agent
from langchain.agents import AgentType
from langchain.tools.python.tool import PythonREPLTool
from langchain.python import PythonREPL
from langchain.chat_models import ChatOpenAI

llm = ChatOpenAI(temperature=0)
tools = load_tools(["llm-math","wikipedia"], llm=llm)
agent= initialize_agent(
    tools, 
    llm, 
    agent=AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION,
    handle_parsing_errors=True,
    verbose = True)
agent("What is the 25% of 300?")

insert image description here
This is the output after enabling debug. Among them, Thought is the prompt input to the model, Action is the action that needs to be executed, action specifies the tool that needs to be called, and action_input specifies the input of this tool. Observation is the output result after calling the tool, and finally input to the model to make the final output to get the final answer.

Among them, the proxy type used is, and its meaning is as follows:

  • CHAT: Indicates that it is an agent optimized to work with the Chat model;
  • ZERO_SHOT: zero sample learning ability;
  • REACT: A technique for organizing prompts that maximizes the reasoning power of LLMs.

handle_parsing_errors = True: It is the logic for processing when the parser makes an error. In fact, when the content cannot be parsed normally, the wrongly formatted content is passed back to the language model and asked to correct it by itself.

create_python_agent

Applications like Copilot, code interpreter plugins, all they do is write code with a language model, and then execute the generated code. Such applications can also be realized based on LangChain.

The REPL is a tool for interacting with code, which can be simply thought of as a Jupyter Notebook.

agent = create_python_agent(
    llm,
    tool=PythonREPLTool(),
    verbose=True
)

customer_list = [["Harrison", "Chase"], 
                 ["Lang", "Chain"],
                 ["Dolly", "Too"],
                 ["Elle", "Elem"], 
                 ["Geoff","Fusion"], 
                 ["Trance","Former"],
                 ["Jen","Ayai"]
                ]

agent.run(f"""Sort these customers by \
last name and then first name \
and print the output: {
      
      customer_list}""") 

insert image description here

import langchain
langchain.debug=True
agent.run(f"""Sort these customers by \
last name and then first name \
and print the output: {
      
      customer_list}""") 
langchain.debug=False

output:

[chain/start] [1:chain:AgentExecutor] Entering Chain run with input:
{
    
    
  "input": "Sort these customers by last name and then first name and print the output: [['Harrison', 'Chase'], ['Lang', 'Chain'], ['Dolly', 'Too'], ['Elle', 'Elem'], ['Geoff', 'Fusion'], ['Trance', 'Former'], ['Jen', 'Ayai']]"
}
[chain/start] [1:chain:AgentExecutor > 2:chain:LLMChain] Entering Chain run with input:
{
    
    
  "input": "Sort these customers by last name and then first name and print the output: [['Harrison', 'Chase'], ['Lang', 'Chain'], ['Dolly', 'Too'], ['Elle', 'Elem'], ['Geoff', 'Fusion'], ['Trance', 'Former'], ['Jen', 'Ayai']]",
  "agent_scratchpad": "",
  "stop": [
    "\nObservation:",
    "\n\tObservation:"
  ]
}
[llm/start] [1:chain:AgentExecutor > 2:chain:LLMChain > 3:llm:ChatOpenAI] Entering LLM run with input:
{
    
    
  "prompts": [
    "Human: You are an agent designed to write and execute python code to answer questions.\nYou have access to a python REPL, which you can use to execute python code.\nIf you get an error, debug your code and try again.\nOnly use the output of your code to answer the question. \nYou might know the answer without running any code, but you should still run the code to get the answer.\nIf it does not seem like you can write code to answer the question, just return \"I don't know\" as the answer.\n\n\nPython REPL: A Python shell. Use this to execute python commands. Input should be a valid python command. If you want to see the output of a value, you should print it out with `print(...)`.\n\nUse the following format:\n\nQuestion: the input question you must answer\nThought: you should always think about what to do\nAction: the action to take, should be one of [Python REPL]\nAction Input: the input to the action\nObservation: the result of the action\n... (this Thought/Action/Action Input/Observation can repeat N times)\nThought: I now know the final answer\nFinal Answer: the final answer to the original input question\n\nBegin!\n\nQuestion: Sort these customers by last name and then first name and print the output: [['Harrison', 'Chase'], ['Lang', 'Chain'], ['Dolly', 'Too'], ['Elle', 'Elem'], ['Geoff', 'Fusion'], ['Trance', 'Former'], ['Jen', 'Ayai']]\nThought:"
  ]
}
[llm/end] [1:chain:AgentExecutor > 2:chain:LLMChain > 3:llm:ChatOpenAI] [4.96s] Exiting LLM run with output:
{
    
    
  "generations": [
    [
      {
    
    
        "text": "I can use the `sorted()` function to sort the list of customers. I will need to provide a key function that specifies the sorting order based on last name and then first name.\nAction: Python REPL\nAction Input: \n```python\ncustomers = [['Harrison', 'Chase'], ['Lang', 'Chain'], ['Dolly', 'Too'], ['Elle', 'Elem'], ['Geoff', 'Fusion'], ['Trance', 'Former'], ['Jen', 'Ayai']]\nsorted_customers = sorted(customers, key=lambda x: (x[1], x[0]))\nsorted_customers\n```",
        "generation_info": null,
        "message": {
     
     
          "content": "I can use the `sorted()` function to sort the list of customers. I will need to provide a key function that specifies the sorting order based on last name and then first name.\nAction: Python REPL\nAction Input: \n```python\ncustomers = [['Harrison', 'Chase'], ['Lang', 'Chain'], ['Dolly', 'Too'], ['Elle', 'Elem'], ['Geoff', 'Fusion'], ['Trance', 'Former'], ['Jen', 'Ayai']]\nsorted_customers = sorted(customers, key=lambda x: (x[1], x[0]))\nsorted_customers\n```",
          "additional_kwargs": {
     
     },
          "example": false
        }
      }
    ]
  ],
  "llm_output": {
     
     
    "token_usage": {
     
     
      "prompt_tokens": 326,
      "completion_tokens": 129,
      "total_tokens": 455
    },
    "model_name": "gpt-3.5-turbo"
  }
}
[chain/end] [1:chain:AgentExecutor > 2:chain:LLMChain] [4.96s] Exiting Chain run with output:
{
     
     
  "text": "I can use the `sorted()` function to sort the list of customers. I will need to provide a key function that specifies the sorting order based on last name and then first name.\nAction: Python REPL\nAction Input: \n```python\ncustomers = [['Harrison', 'Chase'], ['Lang', 'Chain'], ['Dolly', 'Too'], ['Elle', 'Elem'], ['Geoff', 'Fusion'], ['Trance', 'Former'], ['Jen', 'Ayai']]\nsorted_customers = sorted(customers, key=lambda x: (x[1], x[0]))\nsorted_customers\n```"
}
[tool/start] [1:chain:AgentExecutor > 4:tool:Python REPL] Entering Tool run with input:
"```python
customers = [['Harrison', 'Chase'], ['Lang', 'Chain'], ['Dolly', 'Too'], ['Elle', 'Elem'], ['Geoff', 'Fusion'], ['Trance', 'Former'], ['Jen', 'Ayai']]
sorted_customers = sorted(customers, key=lambda x: (x[1], x[0]))
sorted_customers
```"
[tool/end] [1:chain:AgentExecutor > 4:tool:Python REPL] [0.383ms] Exiting Tool run with output:
""
[chain/start] [1:chain:AgentExecutor > 5:chain:LLMChain] Entering Chain run with input:
{
     
     
  "input": "Sort these customers by last name and then first name and print the output: [['Harrison', 'Chase'], ['Lang', 'Chain'], ['Dolly', 'Too'], ['Elle', 'Elem'], ['Geoff', 'Fusion'], ['Trance', 'Former'], ['Jen', 'Ayai']]",
  "agent_scratchpad": "I can use the `sorted()` function to sort the list of customers. I will need to provide a key function that specifies the sorting order based on last name and then first name.\nAction: Python REPL\nAction Input: \n```python\ncustomers = [['Harrison', 'Chase'], ['Lang', 'Chain'], ['Dolly', 'Too'], ['Elle', 'Elem'], ['Geoff', 'Fusion'], ['Trance', 'Former'], ['Jen', 'Ayai']]\nsorted_customers = sorted(customers, key=lambda x: (x[1], x[0]))\nsorted_customers\n```\nObservation: \nThought:",
  "stop": [
    "\nObservation:",
    "\n\tObservation:"
  ]
}
[llm/start] [1:chain:AgentExecutor > 5:chain:LLMChain > 6:llm:ChatOpenAI] Entering LLM run with input:
{
  "prompts": [
    "Human: You are an agent designed to write and execute python code to answer questions.\nYou have access to a python REPL, which you can use to execute python code.\nIf you get an error, debug your code and try again.\nOnly use the output of your code to answer the question. \nYou might know the answer without running any code, but you should still run the code to get the answer.\nIf it does not seem like you can write code to answer the question, just return \"I don't know\" as the answer.\n\n\nPython REPL: A Python shell. Use this to execute python commands. Input should be a valid python command. If you want to see the output of a value, you should print it out with `print(...)`.\n\nUse the following format:\n\nQuestion: the input question you must answer\nThought: you should always think about what to do\nAction: the action to take, should be one of [Python REPL]\nAction Input: the input to the action\nObservation: the result of the action\n... (this Thought/Action/Action Input/Observation can repeat N times)\nThought: I now know the final answer\nFinal Answer: the final answer to the original input question\n\nBegin!\n\nQuestion: Sort these customers by last name and then first name and print the output: [['Harrison', 'Chase'], ['Lang', 'Chain'], ['Dolly', 'Too'], ['Elle', 'Elem'], ['Geoff', 'Fusion'], ['Trance', 'Former'], ['Jen', 'Ayai']]\nThought:I can use the `sorted()` function to sort the list of customers. I will need to provide a key function that specifies the sorting order based on last name and then first name.\nAction: Python REPL\nAction Input: \n```python\ncustomers = [['Harrison', 'Chase'], ['Lang', 'Chain'], ['Dolly', 'Too'], ['Elle', 'Elem'], ['Geoff', 'Fusion'], ['Trance', 'Former'], ['Jen', 'Ayai']]\nsorted_customers = sorted(customers, key=lambda x: (x[1], x[0]))\nsorted_customers\n```\nObservation: \nThought:"
  ]
}
[llm/end] [1:chain:AgentExecutor > 5:chain:LLMChain > 6:llm:ChatOpenAI] [2.63s] Exiting LLM run with output:
{
  "generations": [
    [
      {
        "text": "The customers have been sorted by last name and then first name.\nFinal Answer: [['Jen', 'Ayai'], ['Harrison', 'Chase'], ['Lang', 'Chain'], ['Elle', 'Elem'], ['Geoff', 'Fusion'], ['Trance', 'Former'], ['Dolly', 'Too']]",
        "generation_info": null,
        "message": {
          "content": "The customers have been sorted by last name and then first name.\nFinal Answer: [['Jen', 'Ayai'], ['Harrison', 'Chase'], ['Lang', 'Chain'], ['Elle', 'Elem'], ['Geoff', 'Fusion'], ['Trance', 'Former'], ['Dolly', 'Too']]",
          "additional_kwargs": {},
          "example": false
        }
      }
    ]
  ],
  "llm_output": {
    "token_usage": {
      "prompt_tokens": 460,
      "completion_tokens": 67,
      "total_tokens": 527
    },
    "model_name": "gpt-3.5-turbo"
  }
}
[chain/end] [1:chain:AgentExecutor > 5:chain:LLMChain] [2.63s] Exiting Chain run with output:
{
  "text": "The customers have been sorted by last name and then first name.\nFinal Answer: [['Jen', 'Ayai'], ['Harrison', 'Chase'], ['Lang', 'Chain'], ['Elle', 'Elem'], ['Geoff', 'Fusion'], ['Trance', 'Former'], ['Dolly', 'Too']]"
}
[chain/end] [1:chain:AgentExecutor] [7.59s] Exiting Chain run with output:
{
  "output": "[['Jen', 'Ayai'], ['Harrison', 'Chase'], ['Lang', 'Chain'], ['Elle', 'Elem'], ['Geoff', 'Fusion'], ['Trance', 'Former'], ['Dolly', 'Too']]"
}

The value of the agent_scratchpad parameter is a combination of previous output and tool output. Feeding this part of information to the model is to let the model understand what happened before, and use this part of information to infer the next action.

Create a custom proxy

The biggest advantage of a proxy is that it can be linked to its own sources of information, its own API, its own data, etc.

from langchain.agents import tool
from datetime import date

@tool
def time(text: str) -> str:
    """Returns todays date, use this for any \
    questions related to knowing todays date. \
    The input should always be an empty string, \
    and this function will always return todays \
    date - any date mathmatics should occur \
    outside this function."""
    return str(date.today())

agent= initialize_agent(
    tools + [time], 
    llm, 
    agent=AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION,
    handle_parsing_errors=True,
    verbose = True)

Add the @tool decorator to convert the custom method into a tool that can be used by langchain.

try:
    result = agent("whats the date today?") 
except: 
    print("exception on external access")

output:


> Entering new AgentExecutor chain...
Question: What's the date today?
Thought: I can use the `time` tool to get the current date.
Action:
```
{
     
     
  "action": "time",
  "action_input": ""
}
```
Observation: 2023-07-02
Thought:I now know the final answer.
Final Answer: The date today is 2023-07-02.

> Finished chain.

8. Summary

This course introduces various application examples, including processing customer reviews, building a document-based question answering application, using LLM to decide when to call external tools, to answer complex questions, etc.

Prompt word template, parser, model memory, thinking reasoning chain, model evaluation, model agent.
combine. Feeding this part of information to the model is to let the model understand what happened before, and use this part of information to infer the next action.

Create a custom proxy

The biggest advantage of a proxy is that it can be linked to its own sources of information, its own API, its own data, etc.

from langchain.agents import tool
from datetime import date

@tool
def time(text: str) -> str:
    """Returns todays date, use this for any \
    questions related to knowing todays date. \
    The input should always be an empty string, \
    and this function will always return todays \
    date - any date mathmatics should occur \
    outside this function."""
    return str(date.today())

agent= initialize_agent(
    tools + [time], 
    llm, 
    agent=AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION,
    handle_parsing_errors=True,
    verbose = True)

Add the @tool decorator to convert the custom method into a tool that can be used by langchain.

try:
    result = agent("whats the date today?") 
except: 
    print("exception on external access")

output:


> Entering new AgentExecutor chain...
Question: What's the date today?
Thought: I can use the `time` tool to get the current date.
Action:
```
{
     
     
  "action": "time",
  "action_input": ""
}
```
Observation: 2023-07-02
Thought:I now know the final answer.
Final Answer: The date today is 2023-07-02.

> Finished chain.

8. Summary

This course introduces various application examples, including processing customer reviews, building a document-based question answering application, using LLM to decide when to call external tools, to answer complex questions, etc.

Guess you like

Origin blog.csdn.net/weixin_39653948/article/details/131499824