LangChain大语言模型接口层源码与调用机制深度解析
I. 接口层概述
1.1 接口层在LangChain中的定位
LangChain大语言模型接口层是连接外部大语言模型(LLM)与上层应用逻辑的核心枢纽。它通过标准化的接口封装不同厂商的LLM服务,如OpenAI、Anthropic、Hugging Face等,使开发者能够以统一方式调用各类模型,而无需关注底层API细节。这种设计极大提升了框架的扩展性和兼容性,让开发者可以灵活切换模型以适应不同应用场景需求。
1.2 核心功能与设计目标
接口层的核心功能包括:
- 模型连接与认证:处理与外部模型服务的连接,管理API密钥、访问令牌等认证信息
- 请求标准化:将上层应用的请求转换为符合模型API规范的格式
- 响应解析:解析模型返回的响应数据,统一输出格式
- 错误处理:捕获调用过程中的异常,提供统一的错误反馈机制
其设计目标是实现"插拔式"的模型接入,通过抽象层将模型差异隐藏,为上层应用提供简洁、统一的调用体验。
1.3 面临的挑战与解决方案
接口层面临的主要挑战包括:
- API规范差异:不同模型服务商的API参数、请求格式、响应结构各不相同
- 速率限制处理:各平台对API调用频率、并发量的限制不同
- 版本兼容性:模型服务更新可能导致接口变动
LangChain通过以下方案应对:
- 抽象基类设计:定义统一的LLM抽象类,要求具体模型类实现标准方法
- 配置驱动架构:通过配置文件管理模型参数和认证信息
- 重试与降级策略:内置重试机制处理速率限制,提供降级方案保障服务可用性
- 版本适配层:通过适配器模式兼容模型接口版本变化
II. 抽象基类与接口定义
2.1 LLM抽象基类
LangChain通过LLM
抽象基类定义大语言模型的标准接口,位于langchain/llms/base.py
:
from abc import ABC, abstractmethod
from typing import Any, Dict, List, Optional
class LLM(ABC):
@abstractmethod
def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str:
"""核心调用方法,子类需实现具体调用逻辑"""
pass
@property
@abstractmethod
def _llm_type(self) -> str:
"""返回模型类型标识"""
pass
def __call__(self, prompt: str, stop: Optional[List[str]] = None) -> str:
"""对外暴露的调用接口,调用子类实现的_call方法"""
return self._call(prompt, stop)
该基类定义了两个抽象方法:
_call
:核心调用逻辑,接收提示词和停止序列,返回模型生成结果_llm_type
:返回模型类型字符串标识
2.2 接口方法设计解析
2.2.1 _call方法
_call
方法是模型调用的核心,其设计要点包括:
-
输入参数:
prompt
:必选的提示词字符串stop
:可选的停止序列列表,用于提前终止生成
-
返回值:模型生成的文本结果
2.2.2 _llm_type属性
_llm_type
属性用于标识模型类型,主要作用:
- 方便框架进行类型检查和日志记录
- 支持按模型类型进行功能扩展和适配
2.3 接口扩展与兼容性设计
为支持更多功能,接口层采用以下扩展设计:
- 参数扩展:通过
additional_kwargs
字典传递额外参数
class MyLLM(LLM):
def _call(self, prompt: str, stop: Optional[List[str]] = None, **kwargs) -> str:
temperature = kwargs.get('temperature', 0.7)
# 使用temperature参数调用模型
- 异步接口:通过继承
AsyncLLM
基类实现异步调用
from langchain.llms.base import AsyncLLM
class AsyncMyLLM(AsyncLLM):
async def _acall(self, prompt: str, stop: Optional[List[str]] = None) -> str:
# 异步调用实现
III. 具体模型类实现
3.1 OpenAI模型实现
OpenAI模型类位于langchain/llms/openai.py
,继承自LLM
基类:
from langchain.llms.base import LLM
import openai
class OpenAI(LLM):
openai_api_key: str
model_name: str = "text-davinci-003"
temperature: float = 0.7
max_tokens: int = 1024
def __init__(self, **kwargs: Any):
super().__init__(**kwargs)
openai.api_key = self.openai_api_key
def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str:
response = openai.Completion.create(
engine=self.model_name,
prompt=prompt,
temperature=self.temperature,
max_tokens=self.max_tokens,
stop=stop
)
return response.choices[0].text.strip()
@property
def _llm_type(self) -> str:
return "openai"
关键实现细节:
- 初始化:设置OpenAI API密钥,支持通过配置覆盖默认参数
- _call方法:调用OpenAI Completion API,解析响应并返回结果
- _llm_type:返回"openai"标识
3.2 Hugging Face模型实现
Hugging Face模型类通过HuggingFacePipeline
实现,位于langchain/llms/huggingface_pipeline.py
:
from langchain.llms.base import LLM
from transformers import pipeline
class HuggingFacePipeline(LLM):
pipeline: Any
model_kwargs: Dict[str, Any] = {}
def __init__(self, **kwargs: Any):
super().__init__(**kwargs)
self.pipeline = pipeline("text-generation", **self.model_kwargs)
def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str:
result = self.pipeline(prompt, **self.model_kwargs)[0]["generated_text"]
if stop:
for s in stop:
if s in result:
result = result[:result.index(s)]
return result
@property
def _llm_type(self) -> str:
return "huggingface_pipeline"
实现要点:
- 初始化:基于
text-generation
任务创建Hugging Face pipeline - _call方法:调用pipeline生成文本,支持停止序列处理
- 参数传递:通过
model_kwargs
传递模型参数
3.3 Anthropic模型实现
Anthropic模型类位于langchain/llms/anthropic.py
:
from langchain.llms.base import LLM
import anthropic
class Anthropic(LLM):
anthropic_api_key: str
model: str = anthropic.DEFAULT_MODEL
temperature: float = 0
max_tokens_to_sample: int = 256
def __init__(self, **kwargs: Any):
super().__init__(**kwargs)
self.client = anthropic.Client(self.anthropic_api_key)
def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str:
response = self.client.completion(
prompt=f"{anthropic.HUMAN_PROMPT} {prompt}{anthropic.AI_PROMPT}",
model=self.model,
temperature=self.temperature,
max_tokens_to_sample=self.max_tokens_to_sample,
stop_sequences=stop
)
return response["completion"].strip()
@property
def _llm_type(self) -> str:
return "anthropic"
关键逻辑:
- 初始化:创建Anthropic客户端,设置API密钥
- _call方法:按照Anthropic格式构造请求,解析响应
- 格式处理:自动添加
HUMAN_PROMPT
和AI_PROMPT
标记
IV. 请求处理流程
4.1 请求参数处理
接口层对请求参数的处理包括:
- 参数校验:
class OpenAI(LLM):
def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str:
if not isinstance(prompt, str):
raise ValueError("prompt must be a string")
# ...
- 默认值设置:
class OpenAI(LLM):
temperature: float = 0.7
def _call(self, prompt: str, stop: Optional[List[str]] = None, temperature: Optional[float] = None) -> str:
temperature = temperature if temperature is not None else self.temperature
# ...
- 参数转换:将通用参数映射为模型特定参数
class Anthropic(LLM):
def _call(self, prompt: str, stop: Optional[List[str]] = None, max_tokens: Optional[int] = None) -> str:
max_tokens_to_sample = max_tokens if max_tokens is not None else self.max_tokens_to_sample
response = self.client.completion(
# 使用max_tokens_to_sample参数
4.2 请求构造与发送
以OpenAI为例,请求构造过程:
class OpenAI(LLM):
def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str:
payload = {
"engine": self.model_name,
"prompt": prompt,
"temperature": self.temperature,
"max_tokens": self.max_tokens,
"stop": stop
}
response = openai.Completion.create(**payload)
return response.choices[0].text.strip()
关键步骤:
- 构建符合OpenAI API规范的请求参数
- 使用
openai.Completion.create
方法发送请求 - 解析响应并返回结果
4.3 速率限制处理
接口层通过重试机制处理速率限制:
import openai
import time
class OpenAI(LLM):
max_retries = 3
def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str:
retries = 0
while retries < self.max_retries:
try:
response = openai.Completion.create(
# 请求参数...
)
return response.choices[0].text.strip()
except openai.error.RateLimitError:
retries += 1
time.sleep(2 ** retries)
raise Exception("Max retries exceeded")
处理逻辑:
- 捕获
RateLimitError
异常 - 按照指数退避算法进行重试
- 达到最大重试次数后抛出异常
V. 响应解析机制
5.1 统一响应格式
接口层将不同模型的响应统一为字符串格式:
class OpenAI(LLM):
def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str:
response = openai.Completion.create(
# 请求参数...
)
return response.choices[0].text.strip()
class Anthropic(LLM):
def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str:
response = self.client.completion(
# 请求参数...
)
return response["completion"].strip()
通过提取关键字段并统一返回字符串,屏蔽不同模型的响应差异。
5.2 错误处理与异常封装
接口层对模型返回的错误进行统一封装:
import openai
from langchain.llms.base import LLM
class OpenAI(LLM):
def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str:
try:
response = openai.Completion.create(
# 请求参数...
)
return response.choices[0].text.strip()
except openai.error.OpenAIError as e:
raise ValueError(f"OpenAI API Error: {e}")
处理方式:
- 捕获模型API抛出的原始异常
- 封装为统一的
ValueError
异常 - 保留原始错误信息便于排查
5.3 结果后处理
对生成结果进行后处理:
- 去除空白字符:
class OpenAI(LLM):
def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str:
response = openai.Completion.create(
# 请求参数...
)
return response.choices[0].text.strip()
- 停止序列截断:
class HuggingFacePipeline(LLM):
def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str:
result = self.pipeline(prompt, **self.model_kwargs)[0]["generated_text"]
if stop:
for s in stop:
if s in result:
result = result[:result.index(s)]
return result
VI. 认证与配置管理
6.1 API密钥管理
6.1.1 环境变量配置
以OpenAI为例,通过环境变量获取API密钥:
import os
import openai
class OpenAI(LLM):
def __init__(self, **kwargs: Any):
super().__init__(**kwargs)
openai.api_key = os.environ.get("OPENAI_API_KEY")
if not openai.api_key:
raise ValueError("OPENAI_API_KEY environment variable not set")
6.1.2 显式参数传递
支持通过参数直接传递密钥:
llm = OpenAI(openai_api_key="your_api_key")
6.2 模型配置管理
6.2.1 默认参数设置
各模型类定义默认参数:
class OpenAI(LLM):
model_name: str = "text-davinci-003"
temperature: float = 0.7
max_tokens: int = 1024
6.2.2 动态参数覆盖
支持通过实例化参数覆盖默认值:
llm = OpenAI(model_name="gpt-3.5-turbo", temperature=0.5)
6.3 配置文件支持
通过配置文件管理多模型配置:
models:
- name: openai
type: openai
config:
openai_api_key: your_api_key
model_name: gpt-3.5-turbo
- name: anthropic
type: anthropic
config:
anthropic_api_key: your_anthropic_key
model: claude-v1.3
from langchain.llms import load_llm
llm = load_llm("config.yaml", "openai")
VII. 调用链集成
7.1 与Prompt模板结合
接口层与Prompt模板无缝集成:
from langchain.llms import OpenAI
from langchain import PromptTemplate
llm = OpenAI()
prompt = PromptTemplate(
input_variables=["question"],
template="Answer the following question: {question}"
)
formatted_prompt = prompt.format(question="What is the capital of France?")
result = llm(formatted_prompt)
集成方式:
- 使用
PromptTemplate
构造提示词 - 将格式化后的提示词传递给LLM接口
7.2 在Chain中的应用
在ConversationChain
中的应用示例:
from langchain.llms import OpenAI
from langchain.chains import ConversationChain
from langchain.memory import ConversationBufferMemory
llm = OpenAI()
memory = ConversationBufferMemory()
conversation = ConversationChain(
llm=llm,
memory=memory
)
response = conversation.predict(input="Hello")
关键流程:
- 将LLM实例传入
ConversationChain
ConversationChain
调用LLM接口生成回复- 结合
ConversationBufferMemory
管理对话历史
7.3 与Agent的协同
在Agent
中的调用逻辑:
from langchain.llms import OpenAI
from langchain.agents import load_tools, initialize_agent
llm = OpenAI()
tools = load_tools(["serpapi", "llm-math"], llm=llm)
agent = initialize_agent(tools, llm, agent="zero-shot-react-description")
result = agent.run("Who won the FIFA World Cup in 2022?")
协同机制:
Agent
根据任务选择合适工具- 调用LLM进行推理和决策
- 整合工具结果生成最终回复
VIII. 异步调用支持
8.1 异步基类定义
AsyncLLM
基类定义异步接口:
from abc import ABC, abstractmethod
from typing import Any, Dict, List, Optional
import asyncio
class AsyncLLM(ABC):
@abstractmethod
LangChain大语言模型接口层源码与调用机制深度解析
VIII. 异步调用支持
8.1 异步基类定义
AsyncLLM
基类定义异步接口:
from abc import ABC, abstractmethod
from typing import Any, Dict, List, Optional
import asyncio
class AsyncLLM(ABC):
@abstractmethod
async def _acall(self, prompt: str, stop: Optional[List[str]] = None) -> str:
"""核心异步调用方法,子类需实现具体异步调用逻辑"""
pass
@property
@abstractmethod
def _llm_type(self) -> str:
"""返回模型类型标识"""
pass
async def __call__(self, prompt: str, stop: Optional[List[str]] = None) -> str:
"""对外暴露的异步调用接口,调用子类实现的_acall方法"""
return await self._acall(prompt, stop)
该基类通过_acall
方法定义异步调用的核心逻辑,要求子类实现具体的异步请求发送与响应处理。__call__
方法使用await
关键字确保异步调用的正确执行,保持与同步接口一致的调用方式。
8.2 异步模型类实现
以OpenAI异步实现为例,位于langchain/llms/openai.py
:
import openai
from langchain.llms.base import AsyncLLM
class AsyncOpenAI(AsyncLLM):
openai_api_key: str
model_name: str = "text-davinci-003"
temperature: float = 0.7
max_tokens: int = 1024
def __init__(self, **kwargs: Any):
super().__init__(**kwargs)
openai.api_key = self.openai_api_key
async def _acall(self, prompt: str, stop: Optional[List[str]] = None) -> str:
response = await openai.Completion.acreate(
engine=self.model_name,
prompt=prompt,
temperature=self.temperature,
max_tokens=self.max_tokens,
stop=stop
)
return response.choices[0].text.strip()
@property
def _llm_type(self) -> str:
return "openai"
关键实现点:
- 调用
openai.Completion.acreate
发送异步请求,利用OpenAI官方提供的异步接口 - 使用
await
等待异步操作完成,获取响应结果并进行解析 - 保持与同步版本一致的参数处理和返回值格式
8.3 异步调用场景与优势
异步调用在以下场景体现显著优势:
- 高并发请求:在处理大量用户请求时,异步调用能充分利用系统资源,避免线程阻塞。例如在一个支持多用户同时提问的问答系统中,异步调用允许同时处理多个用户的请求,提升系统吞吐量。
async def handle_user_requests():
llm = AsyncOpenAI()
requests = ["问题1", "问题2", "问题3"]
tasks = [llm(req) for req in requests]
results = await asyncio.gather(*tasks)
return results
- I/O密集型操作:由于LLM调用主要是网络I/O操作,异步编程能在等待响应时释放线程,执行其他任务。如在一个结合了数据库查询和LLM调用的应用中,在等待LLM响应的过程中,可以同时进行数据库的其他查询操作。
- 提升用户体验:在交互式应用中,异步调用能避免界面卡顿,用户可以在发起请求后继续进行其他操作,无需等待响应返回。
IX. 模型中间件与扩展
9.1 中间件概念与作用
模型中间件是位于接口层与具体模型实现之间的可插拔组件,用于在请求发送前和响应接收后对数据进行处理。其主要作用包括:
- 日志记录:记录请求和响应信息,便于调试和监控
- 性能统计:统计模型调用耗时、成功率等指标
- 数据转换:对输入输出数据进行格式转换或内容修改
- 安全控制:添加额外的安全验证或数据脱敏处理
9.2 中间件实现方式
LangChain通过装饰器模式实现中间件功能。以日志记录中间件为例:
import functools
from langchain.llms.base import LLM
def log_call(func):
@functools.wraps(func)
def wrapper(self, prompt, *args, **kwargs):
print(f"Calling LLM with prompt: {prompt}")
start_time = time.time()
try:
result = func(self, prompt, *args, **kwargs)
print(f"LLM call completed in {time.time() - start_time} seconds")
return result
except Exception as e:
print(f"LLM call failed: {e}")
raise
return wrapper
class LoggedOpenAI(LLM):
def __init__(self, **kwargs: Any):
super().__init__(**kwargs)
self._call = log_call(self._call)
def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str:
# 实际调用逻辑,这里假设继承自OpenAI的实现
pass
@property
def _llm_type(self) -> str:
return "openai"
上述代码通过log_call
装饰器,在调用_call
方法前后添加日志记录,不改变原有模型类的核心逻辑,实现了功能扩展的解耦。
9.3 自定义中间件扩展
用户可以根据需求自定义中间件。例如,实现一个性能统计中间件:
import functools
import time
import statistics
from typing import Dict
class PerformanceStats:
def __init__(self):
self.timings: Dict[str, list] = {}
def record_timing(self, name: str, start_time: float, end_time: float):
if name not in self.timings:
self.timings[name] = []
self.timings[name].append(end_time - start_time)
def get_stats(self, name: str):
timings = self.timings.get(name, [])
return {
"average": statistics.mean(timings) if timings else 0,
"min": min(timings) if timings else 0,
"max": max(timings) if timings else 0
}
def performance_monitor(stats: PerformanceStats):
def decorator(func):
@functools.wraps(func)
def wrapper(self, prompt, *args, **kwargs):
start_time = time.time()
try:
result = func(self, prompt, *args, **kwargs)
end_time = time.time()
stats.record_timing(func.__name__, start_time, end_time)
return result
except Exception as e:
end_time = time.time()
stats.record_timing(func.__name__, start_time, end_time)
raise
return wrapper
return decorator
# 使用示例
stats = PerformanceStats()
class MonitoredOpenAI(LLM):
def __init__(self, **kwargs: Any):
super().__init__(**kwargs)
self._call = performance_monitor(stats)(self._call)
def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str:
# 实际调用逻辑
pass
@property
def _llm_type(self) -> str:
return "openai"
# 获取性能统计信息
print(stats.get_stats("_call"))
通过这种方式,用户可以灵活添加各类中间件,扩展模型接口层的功能。
X. 多模型集成与切换
10.1 多模型配置管理
LangChain支持在一个应用中配置和使用多个大语言模型。通过配置文件实现多模型管理,例如models.yaml
:
models:
- name: openai_model
type: openai
config:
openai_api_key: YOUR_OPENAI_KEY
model_name: gpt-3.5-turbo
- name: huggingface_model
type: huggingface_pipeline
config:
model_name: distilgpt2
model_kwargs:
temperature: 0.8
在代码中加载并使用配置的模型:
from langchain.llms import load_llm
openai_llm = load_llm("models.yaml", "openai_model")
huggingface_llm = load_llm("models.yaml", "huggingface_model")
response1 = openai_llm("使用OpenAI模型回答问题")
response2 = huggingface_llm("使用Hugging Face模型回答问题")
load_llm
函数根据配置文件中的type
字段,动态实例化对应的模型类,并传入config
中的参数。
10.2 模型切换策略
在实际应用中,可能需要根据不同场景切换模型。例如,根据用户输入的复杂程度选择不同能力的模型:
def select_model(user_input: str, models: dict):
if "复杂计算" in user_input or "深度分析" in user_input:
return models["openai_model"]
return models["huggingface_model"]
models = {
"openai_model": load_llm("models.yaml", "openai_model"),
"huggingface_model": load_llm("models.yaml", "huggingface_model")
}
user_input = "分析市场趋势"
selected_llm = select_model(user_input, models)
response = selected_llm(user_input)
上述代码通过自定义的select_model
函数,根据用户输入内容判断并选择合适的模型,实现灵活的模型切换。
10.3 模型融合应用
除了单独使用模型,还可以将多个模型的结果进行融合。例如,结合OpenAI和Hugging Face模型的回答,生成更全面的回复:
def merge_responses(response1: str, response2: str):
return f"OpenAI回答:{response1}\nHugging Face回答:{response2}"
openai_llm = load_llm("models.yaml", "openai_model")
huggingface_llm = load_llm("models.yaml", "huggingface_model")
question = "介绍人工智能的发展历史"
response1 = openai_llm(question)
response2 = huggingface_llm(question)
merged_response = merge_responses(response1, response2)
print(merged_response)
通过融合多个模型的输出,可以综合不同模型的优势,提供更丰富、准确的回答。
XI. 版本兼容性与升级策略
11.1 接口版本适配
随着大语言模型服务商更新API,LangChain需要保持兼容性。通过版本适配层处理接口变化,以OpenAI为例:
import openai
class OpenAIVersionAdapter:
def __init__(self, api_version: str):
self.api_version = api_version
def create_completion(self, **kwargs):
if self.api_version >= "2023-12-01":
# 使用新版API参数和调用方式
return openai.Completion.create(**kwargs, api_version=self.api_version)
return openai.Completion.create(**kwargs)
# 使用示例
adapter = OpenAIVersionAdapter("2023-12-01")
response = adapter.create_completion(
engine="text-davinci-003",
prompt="测试问题",
temperature=0.7
)
OpenAIVersionAdapter
类根据指定的API版本,动态调整请求参数和调用方式,确保在模型API更新时,上层调用代码无需修改。
11.2 升级测试与迁移
在LangChain升级时,需要进行全面的兼容性测试:
- 单元测试:针对每个模型类编写单元测试,验证核心功能是否正常。例如,对OpenAI模型类编写测试用例:
import unittest
from langchain.llms import OpenAI
class TestOpenAI(unittest.TestCase):
def test_openai_call(self):
llm = OpenAI(openai_api_key="TEST_KEY")
result = llm("测试问题")
self.assertEqual(isinstance(result, str), True)
if __name__ == '__main__':
unittest.main()
- 集成测试:在实际应用场景中测试模型调用,确保与其他模块的兼容性。例如,在对话链中测试模型升级后的表现。
- 迁移指南:为用户提供详细的升级指南,说明API变化和迁移步骤。例如,当OpenAI模型接口参数调整时,在文档中明确指出旧参数与新参数的对应关系,以及代码修改示例。
11.3 长期维护策略
为保证长期兼容性,LangChain采用以下策略:
- 语义化版本控制:严格遵循语义化版本号规则,明确不同版本的变更范围
- 弃用警告机制:在计划移除或修改接口前,提前多个版本发出弃用警告,给用户足够的迁移时间
- 社区反馈机制:通过社区收集用户在升级过程中遇到的问题,及时修复兼容性Bug
XII. 安全性增强机制
12.1 输入验证与过滤
为防止恶意输入导致的安全风险,接口层对输入进行严格验证和过滤:
import re
from langchain.llms.base import LLM
class SafeOpenAI(LLM):
def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str:
# 过滤恶意SQL注入语句
if re.search(r'(SELECT|INSERT|UPDATE|DELETE|DROP)', prompt, re.IGNORECASE):
raise ValueError("Invalid input detected")
return super()._call(prompt, stop)
@property
def _llm_type(self) -> str:
return "openai"
上述代码通过正则表达式检测输入中是否包含危险的SQL关键词,若检测到则拒绝请求,防止SQL注入攻击。同时,还可以针对其他类型的恶意输入(如命令注入、XSS攻击相关内容)进行类似的过滤处理。
12.2 输出脱敏处理
对于包含敏感信息的输出结果,进行脱敏处理:
import re
from langchain.llms.base import LLM
class DesensitizedOpenAI(LLM):
def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str:
result = super()._call(prompt, stop)
# 脱敏邮箱地址
result = re.sub(r'[\w\.-]+@[\w\.-]+\.\w+', '[脱敏邮箱]', result)
# 脱敏身份证号码
result = re.sub(r'\d{17}[\dXx]', '[脱敏身份证号]', result)
return result
@property
def _llm_type(self) -> str:
return "openai"
通过正则表达式匹配敏感信息,并替换为脱敏后的内容,避免在输出中泄露用户隐私数据。
12.3 访问控制与审计
实现基于角色的访问控制(RBAC)和操作审计:
from enum import Enum
from langchain.llms.base import LLM
class Role(Enum):
ADMIN = "admin"
USER = "user"
GUEST = "guest"
class AccessControlledOpenAI(LLM):
def __init__(self, role: Role, **kwargs: Any):
super().__init__(**kwargs)
self.role = role
def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str:
if self.role == Role.GUEST and "敏感操作" in prompt:
raise PermissionError("Guest role not allowed for this operation")
return super()._call(prompt, stop)
@property
def _llm_type(self) -> str:
return "openai"
# 操作审计日志记录
import logging
logging.basicConfig(filename='llm_access.log', level=logging.INFO)
def log_llm_call(llm, prompt, result):
logging.info(f"Role: {llm.role}, Prompt: {prompt}, Result: {result}")
# 使用示例
admin_llm = AccessControlledOpenAI(role=Role.ADMIN)
user_llm = AccessControlledOpenAI(role=Role.USER)
admin_result = admin_llm("执行敏感操作")
log_llm_call(admin_llm, "执行敏感操作", admin_result)
try:
user_result = user_llm("执行敏感操作")
except PermissionError as e:
log_llm_call(user_llm, "执行敏感操作", str(e))
通过AccessControlledOpenAI
类实现基于角色的访问控制,同时使用日志记录每次模型调用的相关信息,便于后续审计和安全分析。