关键词:Langchain、智能体(Agent)、结构化工具、非结构化工具、缺失值处理、上下文记忆、大模型(LLM)、Pydantic、SpaCy、Hallucination(幻觉)

Langchain作为构建基于大模型(LLM)的复杂智能体(Agent)框架,正受到越来越多的关注。在Langchain中,选择结构化工具还是非结构化工具是一个重要的设计决策。本文深入探讨这两种工具在处理输入数据缺失值,以及维护对话上下文记忆方面的差异和优劣。我们将通过实际代码示例,分析如何利用这两种工具,更有效地解决实际应用中遇到的问题,避免Hallucination(幻觉),提升用户体验。

1. 结构化工具与非结构化工具概述

结构化工具的核心在于其输入参数的明确定义。通常使用Pydantic等库来定义数据模型,强制输入参数必须符合预定义的格式和类型。例如,一个加法工具可能要求输入两个整数类型的参数 ab。 这种明确的输入模式,有助于减少错误,提高代码的可读性和可维护性。

非结构化工具则更加灵活,允许接受自由形式的关键词参数或原始文本输入。这种工具更适合处理不确定或动态的输入,但同时也带来了挑战:缺乏明确的输入模式,容易导致解析错误和Hallucination(幻觉)

选择哪种工具取决于具体的应用场景。如果输入数据结构清晰,且需要严格的数据验证,结构化工具是更好的选择。如果输入数据格式多样,或者需要处理自然语言输入,非结构化工具则更合适。

2. 处理缺失值:结构化工具的优势

结构化工具缺失值处理方面具有显著优势。由于其明确定义的输入模式,当缺少必要的参数时,可以立即检测到并向用户请求补充信息。这种主动的错误处理机制,可以有效地防止程序崩溃,并减少Hallucination(幻觉)的风险。

在本文提供的代码示例中,MathInput 类使用 Pydantic 定义了 ab 两个整数类型的参数。如果用户只提供了 a 的值,而缺少 b 的值,add_numbers 函数会返回 “Second number is missing, please provide.” 的提示信息,引导用户补充完整输入。

这种明确的错误提示,不仅可以提高用户体验,还可以帮助大模型(LLM)更好地理解用户的意图。通过结构化的输入,智能体(Agent)可以更准确地识别缺失的信息,并采取相应的行动。

from langchain_openai import ChatOpenAI
from langchain.agents import initialize_agent, AgentType
from langchain.tools import StructuredTool
from langchain.memory import ConversationBufferMemory
from pydantic.v1 import BaseModel, Field
import spacy
import os

# Set API key
os.environ["OPENAI_API_KEY"] = "sk-..."  # Use your OpenAI key here

# Define structured input schema
class MathInput(BaseModel):
    a: int = Field(..., description="First number")
    b: int = Field(..., description="Second number")

def add_numbers(a: int, b: int=None) -> str:
    if b is None:
        return "Second number is missing, please provide."
    return str(a + b)

# Wrap function as StructuredTool
add_tool = StructuredTool.from_function(
    add_numbers,
    name="AddTwoNumbers",
    description="Add two numbers together—even if not all arguments are passed",
    args_schema=MathInput
)

# Set up agent memory for context tracking
memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)

# OpenAI LLM setup (temperature=0 for predictability)
llm = ChatOpenAI(temperature=0)

# Initialize agent with structured tool and memory
agent = initialize_agent(
    tools=[add_tool],
    llm=llm,
    agent=AgentType.OPENAI_FUNCTIONS,  # Best for structured tools!
    memory=memory,
    verbose=True
)

# Utility for semantic similarity, using spaCy
def similarity_check(input1, input2):
    nlp = spacy.load("en_core_web_md")
    doc1 = nlp(input1)
    doc2 = nlp(input2)
    print("spaCy similarity:", doc1.similarity(doc2))
    return doc1.similarity(doc2)

# Interactive test
while True:
    input1 = "Add 3"
    result1 = agent.run(input1)
    print(result1)

    # Detect missing argument prompts
    if similarity_check("needs another argument or parameter", result1) > 0.50:
        print(agent.run({"input": "What was the first number?"}))
        input2 = "Second number is 4"
        # Pass the initial input to reduce hallucination
        result2 = agent.run(input1 + " " + input2)
        print(result2)
    break

在这个例子中,我们使用 SpaCy 库进行语义相似度检查,判断大模型(LLM) 是否正确地提示用户缺少参数。如果提示信息与 “needs another argument or parameter” 的相似度超过 0.5,则认为大模型(LLM)正确地识别了缺失值。

3. 处理缺失值:非结构化工具的挑战与解决方案

非结构化工具在处理缺失值方面面临更大的挑战。由于缺乏明确的输入模式,大模型(LLM) 很难准确地识别哪些参数缺失,并给出合理的提示。 这就要求我们必须在prompt设计和验证逻辑上投入更多精力。

在本文提供的代码示例中,非结构化工具 add_tool 接受一个包含 number1number2 键的字典作为输入。如果用户只提供了 number1 的值,大模型(LLM) 可能无法立即识别出缺少 number2 的值,导致程序出错或生成不准确的结果。

为了解决这个问题,我们需要在prompt中明确地告诉大模型(LLM),如何处理缺失值。 例如,可以在prompt中加入以下指令:“如果缺少任何必要的参数,请向用户请求补充信息”。

此外,还需要在代码中加入验证逻辑,检查输入参数是否完整。如果发现缺少必要的参数,则返回相应的提示信息。

from langchain_openai import ChatOpenAI
from langchain.agents import initialize_agent, AgentType, Tool
from langchain.tools import StructuredTool, Tool
from langchain.memory import ConversationBufferMemory
from pydantic.v1 import BaseModel, Field
import spacy

# Define a structured input model for the tool
class MathInput(BaseModel):
    a: int = Field(..., description="First number")
    b: int = Field(..., description="Second number")

def add_numbers(inputargs):
    if len(inputargs) <= 1:
        return "Second number if needed"
    print(inputargs)
    return inputargs

# StructuredTool wraps your function and input definition
add_tool = Tool.from_function(
    add_numbers,
    name="AddTwoNumbers",
    description="Add two numbers together.The input to the tool will should have the keys as  '{number1,number2}'" \
    "Execute even if all argumets are not passed. "
)

# Set up the memory
memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)
import os
os.environ["OPENAI_API_KEY"] = ""  # Replace with your key or set in your environment variables

# Set up the LLM (replace with your OpenAI API key or another model)
llm = ChatOpenAI(temperature=0)

# Initialize the agent
agent = initialize_agent(
    tools=[add_tool],
    llm=llm,
    agent=AgentType.OPENAI_FUNCTIONS,  # This supports structured tools best!
    memory=memory,
    verbose=True
)

# Interact with the agent
def similarity_check(input1,input2):
    nlp = spacy.load("en_core_web_md")
    # Medium/large supports similarity
    doc1 = nlp(input1)
    doc2 = nlp(input2)
    print("spaCy similarity:", doc1.similarity(doc2))
    return doc1.similarity(doc2)

while True:
    input1 = "Add 3"
    result1 = agent.run(input1)
    print(result1)

    if similarity_check("needs another argument or parameter",result1) > .50:
        print(agent.run({"input": "What was the first number?"}))
        input2 = "Second number is  4"
        # At this step we will pass the initial question again for which the missing fields are detected to avoid hallucination
        # Test the hallucinations by not adding the initial question
        result2 = agent.run(input1 + input2)
        print(result2)
        break

4. 上下文记忆的重要性与实现

上下文记忆对于构建具有对话能力的智能体(Agent)至关重要。通过维护对话历史,智能体(Agent)可以更好地理解用户的意图,并生成更相关和有用的回复。

Langchain 提供了多种记忆模块,例如 ConversationBufferMemory,可以用来存储对话历史。在本文提供的代码示例中,我们使用了 ConversationBufferMemory 来记录用户的输入和大模型(LLM)的输出。

通过将记忆模块与智能体(Agent)集成,我们可以实现上下文记忆功能。例如,如果用户在之前的对话中提到过某个信息,智能体(Agent)可以在后续的对话中,自动地引用这个信息,从而提供更个性化的服务。

需要注意的是,记忆模块也可能引入一些问题。例如,如果对话历史过长,可能会导致大模型(LLM) 的性能下降,或者产生不相关的回复。 因此,需要仔细地设计记忆模块,并定期清理对话历史,以保持智能体(Agent) 的性能和准确性。

5. 避免Hallucination(幻觉)的策略

Hallucination(幻觉) 是指大模型(LLM)生成不真实或不准确的信息。这是一个严重的问题,可能会导致用户对智能体(Agent) 的信任度降低。

为了避免Hallucination(幻觉),可以采取以下策略:

  • 使用结构化工具: 结构化工具可以强制输入参数必须符合预定义的格式和类型,从而减少错误和Hallucination(幻觉)的风险。
  • 仔细设计Prompt: Prompt 是大模型(LLM) 接收到的指令,prompt的设计对大模型(LLM) 的输出质量有很大的影响。 应该尽量使用清晰、简洁、明确的prompt,避免歧义和不确定性。
  • 加入验证逻辑: 在代码中加入验证逻辑,检查大模型(LLM) 的输出是否合理。如果发现不合理的输出,则进行纠正或拒绝。
  • 使用知识库:大模型(LLM) 与知识库集成,使其可以访问真实的信息。 这样可以减少Hallucination(幻觉)的风险,并提高智能体(Agent) 的准确性。
  • 利用上下文信息: 在生成回复时,充分利用上下文记忆中的信息。 这可以帮助大模型(LLM) 更好地理解用户的意图,并生成更相关和准确的回复。
  • 对初始问题进行再次确认: 避免模型因为缺失信息,进行“脑补”的情况。

在本文提供的代码示例中,为了避免Hallucination(幻觉),我们在检测到缺失参数后,将初始输入与补充输入一起传递给大模型(LLM)。 这样做可以确保大模型(LLM) 在生成回复时,能够充分利用所有的信息,从而减少Hallucination(幻觉)的风险。

6. 结论与展望

本文对比分析了结构化工具非结构化工具在处理缺失值和维护上下文记忆方面的差异和优劣。 结构化工具缺失值处理方面具有显著优势,可以有效地防止程序崩溃,并减少Hallucination(幻觉)的风险。 非结构化工具则更加灵活,但需要在prompt设计和验证逻辑上投入更多精力。

无论是结构化工具还是非结构化工具上下文记忆对于构建具有对话能力的智能体(Agent) 都至关重要。 通过维护对话历史,智能体(Agent)可以更好地理解用户的意图,并生成更相关和有用的回复。

随着大模型(LLM) 技术的不断发展,我们可以期待更加智能和强大的智能体(Agent) 的出现。 未来,我们需要继续探索如何更好地利用结构化工具非结构化工具,以及如何有效地处理缺失值和维护上下文记忆,从而构建更加可靠和实用的智能体(Agent)

最后,提醒读者,在实际应用中,应该根据具体的应用场景,选择合适的工具和技术,并进行充分的测试和验证,以确保智能体(Agent) 的性能和准确性。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注