LangChain 提供的評估工具能有效評估語言模型的輸出品質,同時 OpenAI 的函式呼叫功能則實作了結構化的輸出控制。評估流程通常包含載入評估器、準備資料、執行評估以及結果分析等步驟。評估指標的選擇取決於應用場景,例如字串距離評估適用於模糊匹配,嵌入距離評估則更關注語義相似度。OpenAI 函式呼叫的實作流程包含定義函式、建立對映表以及傳送請求和處理回應。平行函式呼叫則能同時處理多個請求,提升效率。LangChain 的函式呼叫功能結合 Pydantic 模型,可以有效地進行結構化資料擷取,並透過查詢規劃功能處理複雜的查詢請求。

LangChain 評估器與 OpenAI 函式呼叫技術深度解析

在現代人工智慧與自然語言處理領域中,準確評估模型輸出品質以及實作智慧函式呼叫已成為關鍵技術。本文將探討 LangChain 評估器的工作原理與應用場景,並詳細分析 OpenAI 函式呼叫的技術實作與最佳實踐。

LangChain 評估器技術原理與實務應用

LangChain 提供了一套強大的評估工具,用於評估語言模型的輸出品質。以下是一個典型的評估流程範例:

# 載入成對字串評估器
evaluator = load_evaluator("labeled_pairwise_string")

# 準備評估所需的資料
gpt3pt5_data = f"""{{"transaction_type": "{row['gpt_3.5_turbo_transaction_type']}", "transaction_category": "{row['gpt_3.5_turbo_transaction_category']}"}}"""
mistral_data = f"""{{"transaction_type": "{row['mixtral_8x7b_transaction_type']}", "transaction_category": "{row['mixtral_8x7b_transaction_category']}"}}"""
reference_data = f"""{{"transaction_type": "{row['transaction_type']}", "transaction_category": "{row['transaction_category']}"}}"""

# 執行評估
result = evaluator.evaluate_string_pairs(
    prediction=gpt3pt5_data,
    prediction_b=mistral_data,
    input=input_prompt.format(
        format_instructions=output_parser.get_format_instructions(),
        transaction=row['transaction_description']
    ),
    reference=reference_data,
)

#### 內容解密:
1. `load_evaluator("labeled_pairwise_string")` 用於載入 LangChain 的成對字串評估器該評估器專門用於比較兩個模型輸出的差異
2. 資料準備過程中使用 f-string 將交易型別和類別格式化為 JSON 字串以模擬實際的模型輸出格式
3. `evaluate_string_pairs` 方法接收四個關鍵引數兩個模型的預測結果輸入提示和參考答案用於全面評估模型的表現
4. 評估結果包含詳細的推理過程和最終評分為模型最佳化提供了寶貴的見解

### 評估指標的多樣性與應用場景

LangChain 提供了多種評估指標以滿足不同的應用需求

1. **字串距離評估** Levenshtein 距離):適用於需要模糊匹配的場景能夠根據字元編輯距離評估文字相似度
2. **嵌入距離評估**利用向量表示計算文字之間的語義相似度特別適合評估答案的語義正確性
3. **成對比較評估**使用更強大的模型 GPT-4比較不同模型的輸出結果並提供詳細的推理過程

這些多樣化的評估工具使開發者能夠根據具體需求選擇最合適的評估方法從而更準確地衡量模型效能

### OpenAI 函式呼叫技術實作與最佳實踐

OpenAI 的函式呼叫功能提供了一種創新的方法來實作結構化的輸出控制以下是一個典型的實作範例

```python
from openai import OpenAI
import json

# 定義模擬的會議排程函式
def schedule_meeting(date, time, attendees):
    # 連線到行事曆服務
    return {
        "event_id": "1234",
        "status": "Meeting scheduled successfully!",
        "date": date,
        "time": time,
        "attendees": attendees
    }

# 建立函式對映表
OPENAI_FUNCTIONS = {
    "schedule_meeting": schedule_meeting
}

#### 內容解密:
1. `schedule_meeting` 函式模擬了實際的會議排程過程回傳包含事件 ID狀態等資訊的結構化資料
2. 使用 `OPENAI_FUNCTIONS` 字典將函式名稱對映到實際的函式實作方便 OpenAI 模型呼叫
3. 這種實作方式使得自然語言指令能夠轉換為具體的 API 呼叫或結構化資料提取
4. 函式呼叫功能特別適合用於建構智慧聊天機器人實作自然語言控制的裝置操作等應用場景

### 技術選型

在選擇評估工具和函式呼叫方案時需要綜合考慮以下因素

1. **業務需求**根據具體的應用場景選擇最合適的評估指標和函式呼叫策略
2. **模型特性**不同模型的輸出特性和穩定性會影響評估方法的選擇
3. **效能要求**在大規模應用中需要考慮評估和函式呼叫的效能開銷

未來發展方向可能包括

1. 更精細化的評估指標以捕捉模型輸出的細微差異
2. 更強大的函式呼叫能力支援更複雜的業務邏輯
3. 更完善的錯誤處理機制提高系統的穩定性和可靠性


## OpenAI 函式呼叫技術詳解與實作範例

### 函式呼叫技術概述
OpenAI 的函式呼叫Function Calling技術是一種強大的工具能夠讓開發者定義特定的函式並由 AI 模型決定何時以及如何呼叫這些函式這項技術的核心在於提供一個詳細的 JSON 結構描述讓模型能夠理解函式的用途和引數要求

### 定義函式 JSON 結構描述
在使用 OpenAI 函式呼叫之前首先需要定義一個詳細的 JSON 結構描述這個描述包含了函式的名稱簡要說明以及所需的引數

#### 程式碼範例:定義函式 JSON 結構描述
```json
functions = [
    {
        "type": "function",
        "function": {
            "type": "object",
            "name": "schedule_meeting",
            "description": "為指定的與會者於特定日期和時間安排會議",
            "parameters": {
                "type": "object",
                "properties": {
                    "date": {"type": "string", "format": "date"},
                    "time": {"type": "string", "format": "time"},
                    "attendees": {"type": "array", "items": {"type": "string"}}
                },
                "required": ["date", "time", "attendees"]
            }
        }
    }
]

內容解密:

  1. name 欄位定義了函式的名稱,這裡使用的是 schedule_meeting
  2. description 提供了對函式的簡要描述,說明瞭該函式的功能。
  3. parameters 定義了函式所需的引數,包括日期(date)、時間(time)和與會者(attendees)。
  4. required 欄位列出了必要的引數,確保模型提供完整的資訊。

傳送請求與處理回應

定義好函式的 JSON 結構描述後,接下來需要將其與使用者的查詢一起傳送給 OpenAI 模型。模型會分析對話內容,判斷是否需要呼叫特定的函式,並傳回函式的名稱和引數。

程式碼範例:傳送請求與處理回應

client = OpenAI(api_key=getenv("OPENAI_API_KEY"))

# 初始化對話訊息
messages = [
    {
        "role": "user",
        "content": "Schedule a meeting on 2023-11-01 at 14:00 with Alice and Bob."
    }
]

# 傳送對話訊息和函式結構描述給模型
response = client.chat.completions.create(
    model="gpt-3.5-turbo-1106",
    messages=messages,
    tools=functions,
)

response = response.choices[0].message

# 檢查模型是否想要呼叫函式
if response.tool_calls:
    first_tool_call = response.tool_calls[0]
    function_name = first_tool_call.function.name
    function_args = json.loads(first_tool_call.function.arguments)
    
    print("函式名稱:", function_name)
    print("函式引數:", function_args)
    
    # 呼叫函式並取得結果
    function = OPENAI_FUNCTIONS.get(function_name)
    if not function:
        raise Exception(f"找不到函式 {function_name}")
    
    function_response = function(**function_args)
    
    # 將函式的回應加入對話訊息中
    messages.append(
        {
            "role": "function",
            "name": function_name,
            "content": json.dumps(function_response)
        }
    )
    
    # 請求模型生成使用者友好的回應
    second_response = client.chat.completions.create(
        model="gpt-3.5-turbo-0613",
        messages=messages
    )
    
    print(second_response.choices[0].message.content)

內容解密:

  1. 首先,建立了一個包含使用者查詢的對話訊息列表。
  2. 使用 OpenAI 客戶端物件將對話訊息和函式結構描述傳送給模型。
  3. 檢查模型的回應中是否包含函式呼叫的請求,如果有,則提取函式的名稱和引數。
  4. 根據提取的函式名稱找到對應的函式並呼叫,將結果加入對話訊息中。
  5. 最後,再次請求模型生成一個總結性的、使用者友好的回應。

平行函式呼叫技術

OpenAI 的函式呼叫技術還支援平行呼叫多個函式,這在處理複雜請求時非常有用。

程式碼範例:平行函式呼叫

# 更新對話訊息以請求安排兩個會議
messages = [
    {
        "role": "user",
        "content": "Schedule a meeting on 2023-11-01 at 14:00 with Alice and Bob. Then schedule another meeting on 2023-11-02 at 15:00 with Charlie and Dave."
    }
]

# 傳送對話訊息和函式結構描述給模型,並處理回應
response = client.chat.completions.create(
    model="gpt-3.5-turbo-1106",
    messages=messages,
    tools=functions,
)

response = response.choices[0].message

if response.tool_calls:
    for tool_call in response.tool_calls:
        function_name = tool_call.function.name
        function_args = json.loads(tool_call.function.arguments)
        
        print("函式名稱:", function_name)
        print("函式引數:", function_args)
        
        # 呼叫函式並處理結果
        function = OPENAI_FUNCTIONS.get(function_name)
        if not function:
            raise Exception(f"找不到函式 {function_name}")
        
        function_response = function(**function_args)
        
        messages.append(
            {
                "role": "function",
                "name": function_name,
                "content": json.dumps(function_response)
            }
        )
    
    # 請求模型生成總結性回應
    second_response = client.chat.completions.create(
        model="gpt-3.5-turbo-0613",
        messages=messages
    )
    
    print(second_response.choices[0].message.content)

圖表說明:

  graph LR;
    C[C]
    A[使用者請求] --> B[OpenAI 模型分析];
    B --> C{是否需要呼叫函式};
    C -->|是| D[提取函式名稱和引數];
    C -->|否| E[直接生成回應];
    D --> F[呼叫相應函式];
    F --> G[將結果加入對話訊息];
    G --> H[請求模型生成總結性回應];

圖表翻譯:

此圖示呈現了 OpenAI 函式呼叫的流程。首先,使用者發出請求,OpenAI 模型進行分析。如果需要呼叫函式,則提取相關資訊並執行相應操作。最後,將結果整合後再次請求模型生成最終回應。

隨著 AI 技術的不斷進步,OpenAI 的函式呼叫功能預計將變得更加強大和靈活。未來可能會出現更多創新性的應用場景,例如更複雜的任務自動化、多模態互動等。開發者需要持續關注最新的技術發展,以充分利用這些新功能來提升應用程式的能力。

LangChain 中的函式呼叫:結構化資料擷取與查詢規劃

在 LangChain 中,函式呼叫(Function Calling)是一種強大的功能,能夠幫助開發者從大語言模型(LLM)的回應中擷取結構化的資料。本文將探討如何使用 LangChain 實作函式呼叫,以及如何利用此功能進行資料擷取和查詢規劃。

使用 Pydantic 進行結構化資料擷取

LangChain 允許開發者使用 Pydantic 模型來定義需要從文字中擷取的結構化資料。透過將 Pydantic 模型轉換為 OpenAI 工具,並將其與 LLM 結合,可以實作結構化資料的擷取。

程式碼範例:

from langchain.output_parsers.openai_tools import PydanticToolsParser
from langchain_core.utils.function_calling import convert_to_openai_tool
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai.chat_models import ChatOpenAI
from langchain_core.pydantic_v1 import BaseModel, Field
from typing import Optional

class Article(BaseModel):
    """識別文章中的重點和反對觀點。"""
    points: str = Field(..., description="文章的重點")
    contrarian_points: Optional[str] = Field(
        None, description="文章中提到的反對觀點"
    )
    author: Optional[str] = Field(None, description="文章作者")

_EXTRACTION_TEMPLATE = """提取並儲存以下段落中提到的相關實體及其屬性。
如果屬性不存在且在函式引數中不是必需的,則不要在輸出中包含它。"""

# 建立提示範本
prompt = ChatPromptTemplate.from_messages(
    {("system", _EXTRACTION_TEMPLATE), ("user", "{input}")}
)

model = ChatOpenAI()
pydantic_schemas = [Article]

# 將 Pydantic 模型轉換為 OpenAI 工具
tools = [convert_to_openai_tool(p) for p in pydantic_schemas]

# 將工具繫結到 LLM
model = model.bind_tools(tools=tools)

# 建立端對端的鏈
chain = prompt | model | PydanticToolsParser(tools=pydantic_schemas)

result = chain.invoke(
    {
        "input": """在最近的題為“行業中的 AI 採用”的文章中,討論的重點包括人們對 AI 的日益增長的興趣...然而,作者 Jane Smith博士..."""
    }
)

print(result)

內容解密:

  1. 首先,我們定義了一個 Pydantic 模型 Article,用於指定要從文字中擷取的結構化資料。
  2. 使用 ChatPromptTemplate 建立了一個提示範本,指示 LLM 提取相關實體及其屬性。
  3. Article 模型轉換為 OpenAI 工具,並將其繫結到 ChatOpenAI 模型。
  4. 建立了一個包含提示範本、LLM 和 PydanticToolsParser 的端對端鏈。
  5. 使用該鏈呼叫 LLM,並傳入輸入文字,提取出結構化的資料。

使用 create_extraction_chain_pydantic 簡化資料擷取

LangChain 提供了 create_extraction_chain_pydantic 函式,可以簡化資料擷取的過程。只需提供 Pydantic 模型和支援函式呼叫的 LLM,即可實作平行函式呼叫。

程式碼範例:

from langchain.chains.openai_tools import create_extraction_chain_pydantic
from langchain_openai.chat_models import ChatOpenAI
from langchain_core.pydantic_v1 import BaseModel, Field

class Person(BaseModel):
    """一個人的姓名和年齡。"""
    name: str = Field(..., description="人的姓名")
    age: int = Field(..., description="人的年齡")

model = ChatOpenAI(model="gpt-3.5-turbo-1106")
chain = create_extraction_chain_pydantic(Person, model)

result = chain.invoke({
    "input": """Bob is 25 years old. He lives in New York.
    He likes to play basketball. Sarah is 30 years old. She lives in San Francisco.
    She likes to play tennis."""
})

print(result)

內容解密:

  1. 定義了一個 Pydantic 模型 Person,包含 nameage 屬性。
  2. 使用 create_extraction_chain_pydantic 建立了一個鏈,該鏈使用 ChatOpenAI 模型來提取 Person 物件。
  3. 呼叫該鏈並傳入輸入文字,提取出多個 Person 物件。

查詢規劃

當使用者查詢具有多個意圖和複雜依賴關係時,查詢規劃(Query Planning)可以有效地將查詢解析為一系列步驟,並按照相關依賴關係執行查詢圖。

程式碼範例:

from langchain_openai.chat_models import ChatOpenAI
from langchain.output_parsers.pydantic import PydanticOutputParser
from langchain_core.prompts.chat import (
    ChatPromptTemplate,
    SystemMessagePromptTemplate,
)
from pydantic.v1 import BaseModel, Field
from typing import List

class Query(BaseModel):
    id: int
    question: str
    dependencies: List[int] = Field(
        default_factory=list,
        description="""在執行此任務之前必須完成的子查詢列表。
        當某些內容未知時,使用子查詢可能需要詢問多個查詢才能獲得答案。
        相依性只能是其他查詢。"""
    )

class QueryPlan(BaseModel):
    query_graph: List[Query]

# 定義查詢計劃和查詢

內容解密:

  1. 定義了兩個 Pydantic 模型:QueryQueryPlan
  2. Query 代表一個查詢,包含 idquestiondependencies 屬性。
  3. QueryPlan 代表一個查詢計劃,包含一個 Query 物件列表。

隨著 LLM 的不斷發展,函式呼叫和查詢規劃技術將在更多領域發揮重要作用。未來,我們可以期待看到更多根據 LangChain 的創新應用,例如更智慧的資料分析工具、更高效的查詢處理系統等。