1. OpenClaw企业级智能体架构解析
OpenClaw作为新一代智能体编排框架,其架构设计充分考虑了企业级应用的需求特点。与传统的聊天机器人框架不同,OpenClaw采用了模块化、可扩展的设计理念,将智能体的核心能力分解为可独立开发和部署的功能单元。
1.1 核心组件架构
OpenClaw的架构主要包含以下关键组件:
- Agent Core(智能体核心):负责任务调度、状态管理和异常处理
- Skills Engine(技能引擎):提供技能注册、发现和执行的运行时环境
- Memory System(记忆系统):包含短期对话记忆和长期知识记忆
- Tool Connectors(工具连接器):标准化接口连接外部API和服务
- Orchestrator(编排器):协调各组件完成复杂任务流程
这种架构设计使得OpenClaw特别适合企业级应用场景,能够灵活应对不同业务需求。在实际部署中,我们通常会采用微服务架构,将各组件部署为独立服务,通过gRPC或RESTful API进行通信。
1.2 关键技术特性
OpenClaw的几个关键技术特性使其在企业环境中表现突出:
- 多租户支持:内置完善的租户隔离机制,确保不同业务部门的数据安全和资源隔离
- 细粒度权限控制:基于RBAC模型的权限管理系统,精确控制每个技能和工具的访问权限
- 分布式任务队列:使用Celery或类似技术实现高并发任务处理
- 可观测性:集成Prometheus和Grafana提供全面的监控指标
- 弹性扩展:支持水平扩展,可根据负载动态调整资源
提示:在企业部署时,建议将Memory System中的向量数据库单独部署,使用专业的向量数据库如Milvus或Pinecone,而不是内置的Chroma,以获得更好的性能和可靠性。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 全栈实战:从环境搭建到生产部署
2.1 开发环境配置
对于企业级开发,我们推荐以下环境配置方案:
bash复制# 使用conda创建隔离的Python环境
conda create -n openclaw python=3.10
conda activate openclaw
# 安装核心依赖
pip install openclaw-core==2.3.0 \
langchain==0.1.0 \
sentence-transformers==2.2.2 \
chromadb==0.4.0
# 安装开发工具
pip install black flake8 mypy pytest
对于前端开发部分(如自定义控制面板),建议使用以下技术栈:
- React 18 + TypeScript
- Tailwind CSS
- Vite构建工具
2.2 企业级部署方案
生产环境部署需要考虑高可用、安全性和性能优化。以下是推荐的部署架构:
-
基础设施层:
- Kubernetes集群(至少3个worker节点)
- 独立的Redis集群用于缓存和消息队列
- PostgreSQL数据库集群(主从复制)
-
服务层:
- OpenClaw核心服务(3个副本)
- 向量数据库服务(单独部署)
- 监控和日志收集服务
-
网络层:
- 内部服务间通信使用Service Mesh
- 外部API通过API Gateway暴露
- 严格的网络策略和防火墙规则
部署示例(使用Helm):
yaml复制# values.yaml
openclaw:
replicaCount: 3
resources:
limits:
cpu: 2
memory: 4Gi
config:
db:
host: "postgres-ha.cluster.local"
port: 5432
vector_db:
type: "milvus"
endpoint: "milvus-proxy:19530"
2.3 持续集成与交付
企业级项目需要完善的CI/CD流程:
yaml复制# .gitlab-ci.yml
stages:
- test
- build
- deploy
unit_test:
stage: test
image: python:3.10
script:
- pip install -r requirements-dev.txt
- pytest tests/unit
build_docker:
stage: build
image: docker:20.10
script:
- docker build -t registry.example.com/openclaw:$CI_COMMIT_SHA .
- docker push registry.example.com/openclaw:$CI_COMMIT_SHA
deploy_staging:
stage: deploy
image: bitnami/kubectl
script:
- kubectl set image deployment/openclaw openclaw=registry.example.com/openclaw:$CI_COMMIT_SHA
3. RAG技术在企业知识管理中的应用
3.1 企业知识库构建最佳实践
构建企业级RAG知识库需要考虑以下几个关键点:
-
数据预处理流水线:
- 文档解析(支持PDF、Word、Excel等格式)
- 文本清洗(去除页眉页脚、水印等)
- 语义分块(考虑企业文档的特殊结构)
- 元数据提取(作者、部门、有效期等)
-
向量化模型选择:
- 通用场景:all-mpnet-base-v2
- 中文场景:paraphrase-multilingual-MiniLM-L12-v2
- 专业领域:在领域数据上微调模型
-
检索优化策略:
- 混合检索(结合关键词和向量搜索)
- 查询扩展(使用LLM重写查询)
- 结果重排序(使用交叉编码器)
示例代码:构建企业知识库
python复制from langchain.document_loaders import DirectoryLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.embeddings import HuggingFaceEmbeddings
from langchain.vectorstores import Milvus
# 加载企业文档
loader = DirectoryLoader('/data/company_docs', glob="**/*.pdf")
documents = loader.load()
# 专业分块策略
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=800,
chunk_overlap=100,
separators=["\n\n", "\n", "。", ".", "?", "!"]
)
docs = text_splitter.split_documents(documents)
# 使用GPU加速的嵌入模型
embeddings = HuggingFaceEmbeddings(
model_name="paraphrase-multilingual-MiniLM-L12-v2",
model_kwargs={'device': 'cuda'},
encode_kwargs={'normalize_embeddings': True}
)
# 连接Milvus向量数据库
vector_db = Milvus.from_documents(
docs,
embeddings,
connection_args={"host": "milvus-proxy", "port": "19530"},
collection_name="company_knowledge",
index_params={
"metric_type": "L2",
"index_type": "HNSW",
"params": {"M": 8, "efConstruction": 64}
}
)
3.2 企业级RAG系统优化
在实际企业应用中,我们发现以下优化策略特别有效:
-
分层检索:
- 第一层:快速筛选(基于关键词或简单向量搜索)
- 第二层:精确匹配(使用更复杂的重排序模型)
-
动态上下文窗口:
根据查询复杂度自动调整返回的上下文长度 -
访问控制集成:
在检索阶段过滤用户无权访问的文档 -
缓存策略:
对常见查询结果进行缓存,减少向量计算开销
优化后的检索流程示例:
python复制from rank_bm25 import BM25Okapi
from sentence_transformers import CrossEncoder
# 初始化模型
bm25 = BM25Okapi([doc.page_content.split() for doc in docs])
cross_encoder = CrossEncoder('cross-encoder/ms-marco-MiniLM-L-6-v2')
def hybrid_retrieval(query, k=5):
# 第一阶段:BM25快速筛选
bm25_scores = bm25.get_scores(query.split())
top_bm25 = np.argsort(bm25_scores)[-100:] # 取前100个
# 第二阶段:向量搜索
vector_results = vector_db.similarity_search(query, k=100)
vector_ids = [doc.metadata['id'] for doc in vector_results]
# 取并集
combined_ids = list(set(top_bm25).union(set(vector_ids)))
candidate_docs = [doc for doc in docs if doc.metadata['id'] in combined_ids]
# 第三阶段:重排序
pairs = [(query, doc.page_content) for doc in candidate_docs]
rerank_scores = cross_encoder.predict(pairs)
# 综合排序
final_results = sorted(
zip(candidate_docs, rerank_scores),
key=lambda x: x[1],
reverse=True
)[:k]
return [doc for doc, score in final_results]
4. Skills开发与企业集成
4.1 企业级Skills开发规范
在企业环境中开发OpenClaw Skills需要遵循以下规范:
-
代码结构标准:
code复制/enterprise_skills ├── /financial_analysis │ ├── skill.py # 主逻辑 │ ├── tests/ # 单元测试 │ ├── schemas.py # 数据模型 │ └── config.yaml # 技能配置 ├── /customer_service └── /hr_assistant -
错误处理与日志:
- 使用结构化日志(JSON格式)
- 实现重试机制(对API调用)
- 定义明确的错误码体系
-
安全考虑:
- 输入验证和清理
- 敏感数据加密
- API调用限流
示例:符合企业标准的Skill代码
python复制import logging
from typing import Optional
from pydantic import BaseModel, validator
from tenacity import retry, stop_after_attempt, wait_exponential
logger = logging.getLogger(__name__)
class FinancialQuery(BaseModel):
company_id: str
fiscal_year: int
metrics: list[str]
@validator('company_id')
def validate_company_id(cls, v):
if not v.startswith('comp_'):
raise ValueError('Invalid company ID format')
return v
class FinancialAnalysisSkill:
def __init__(self, config):
self.api_endpoint = config['api_endpoint']
self.timeout = config.get('timeout', 30)
@retry(
stop=stop_after_attempt(3),
wait=wait_exponential(multiplier=1, min=4, max=10),
before_sleep=lambda _: logger.warning("Retrying API call...")
)
async def execute(self, query: FinancialQuery, user_context: dict) -> dict:
"""执行财务分析查询"""
logger.info(
"Processing financial query",
extra={
"company_id": query.company_id,
"user": user_context['user_id']
}
)
# 实际业务逻辑...
return {
"status": "success",
"data": {...}
}
4.2 企业系统集成模式
OpenClaw与企业现有系统的集成通常采用以下模式:
-
直接API集成:
- 通过REST/gRPC连接ERP、CRM等系统
- 使用OAuth2.0进行认证
-
数据仓库集成:
- 从数据湖或数据仓库读取分析数据
- 使用Apache Arrow格式高效传输
-
消息队列集成:
- 通过Kafka/RabbitMQ接收实时事件
- 实现事件驱动的智能体响应
-
SSO集成:
- 与企业身份提供商(如Okta)集成
- 实现统一的权限管理
集成示例:与Salesforce CRM集成
python复制from simple_salesforce import Salesforce
from cachetools import TTLCache
class SalesforceIntegration:
_cache = TTLCache(maxsize=100, ttl=3600)
def __init__(self, username, password, security_token):
self.sf = Salesforce(
username=username,
password=password,
security_token=security_token,
domain='login.salesforce.com'
)
def get_account_info(self, account_id: str) -> dict:
# 检查缓存
if account_id in self._cache:
return self._cache[account_id]
# 查询Salesforce
result = self.sf.Account.get(account_id)
# 标准化响应
response = {
'name': result['Name'],
'industry': result.get('Industry'),
'annual_revenue': result.get('AnnualRevenue')
}
# 更新缓存
self._cache[account_id] = response
return response
def update_contact(self, contact_id: str, updates: dict) -> bool:
try:
self.sf.Contact.update(contact_id, updates)
return True
except Exception as e:
logger.error(f"Failed to update contact: {str(e)}")
return False
5. 性能优化与监控
5.1 企业级性能优化策略
针对大规模企业应用,我们实施了以下性能优化措施:
-
LLM调用优化:
- 请求批处理(将多个查询合并为一个API调用)
- 响应流式传输(减少首字节时间)
- 模型量化(使用4-bit量化减少内存占用)
-
向量检索优化:
- 使用HNSW索引加速近似最近邻搜索
- 实现分层导航小世界(HNSW)图结构
- 对高维向量进行PCA降维
-
缓存策略:
- 实现语义缓存(缓存相似查询的结果)
- 使用Redis缓存频繁访问的向量
- 对静态知识实现预计算
性能优化代码示例:
python复制from fastapi import FastAPI, Request
from fastapi.responses import StreamingResponse
import asyncio
from functools import lru_cache
from concurrent.futures import ThreadPoolExecutor
app = FastAPI()
executor = ThreadPoolExecutor(max_workers=4)
# 语义缓存装饰器
def semantic_cache(maxsize=128):
def decorator(func):
cache = {}
def wrapper(*args, **kwargs):
# 使用查询的语义哈希作为缓存键
query = args[0]
key = compute_semantic_hash(query)
if key not in cache:
cache[key] = func(*args, **kwargs)
if len(cache) > maxsize:
cache.pop(next(iter(cache)))
return cache[key]
return wrapper
return decorator
@app.post("/streaming-chat")
async def streaming_chat(request: Request):
"""流式聊天接口"""
data = await request.json()
query = data["query"]
async def generate():
# 模拟流式响应
for chunk in process_query_stream(query):
yield f"data: {chunk}\n\n"
await asyncio.sleep(0.1)
return StreamingResponse(generate(), media_type="text/event-stream")
@semantic_cache(maxsize=256)
def process_query(query: str) -> str:
"""处理查询(带语义缓存)"""
return llm.generate(query)
def compute_semantic_hash(text: str) -> int:
"""计算文本的语义哈希"""
embedding = embeddings_model.encode(text)
return hash(tuple(embedding.tolist()))
5.2 企业监控与告警体系
完善的监控体系应包括:
-
指标监控:
- 请求延迟(P50/P95/P99)
- 错误率(4xx/5xx)
- 并发连接数
- GPU利用率(如果使用)
-
日志分析:
- 结构化日志收集
- 异常检测(使用机器学习识别异常模式)
- 关键操作审计跟踪
-
业务指标:
- 用户满意度评分(CSAT)
- 任务完成率
- 自动化节省时间
Prometheus监控配置示例:
yaml复制# prometheus.yml
scrape_configs:
- job_name: 'openclaw'
metrics_path: '/metrics'
static_configs:
- targets: ['openclaw-service:8080']
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: prometheus-service:9090
alerting:
alertmanagers:
- static_configs:
- targets: ['alertmanager:9093']
rule_files:
- '/etc/prometheus/rules.yml'
告警规则示例:
yaml复制# rules.yml
groups:
- name: openclaw-alerts
rules:
- alert: HighErrorRate
expr: rate(openclaw_http_errors_total[5m]) / rate(openclaw_http_requests_total[5m]) > 0.05
for: 10m
labels:
severity: critical
annotations:
summary: "High error rate on OpenClaw service"
description: "Error rate is {{ $value }} for the last 10 minutes"
- alert: HighLatency
expr: histogram_quantile(0.95, sum(rate(openclaw_request_duration_seconds_bucket[5m])) by (le)) > 3
for: 5m
labels:
severity: warning
annotations:
summary: "High latency detected"
description: "95th percentile latency is {{ $value }} seconds"
6. 安全与合规实践
6.1 企业安全架构
OpenClaw企业部署的安全架构应包含以下层面:
-
网络安全:
- 服务间TLS加密
- 网络分段(DMZ、内部区域)
- API网关保护(速率限制、WAF)
-
数据安全:
- 静态数据加密(AES-256)
- 传输中数据加密(TLS 1.3)
- 敏感字段额外加密(如KMS)
-
访问安全:
- 基于角色的访问控制(RBAC)
- 多因素认证(MFA)
- 细粒度权限策略
-
审计与合规:
- 完整操作日志
- 定期安全评估
- 合规认证(SOC2、ISO27001)
安全配置示例:
python复制from cryptography.fernet import Fernet
from keyring import get_keyring
import ssl
class DataProtector:
def __init__(self):
self.key = self._get_encryption_key()
self.cipher = Fernet(self.key)
def _get_encryption_key(self):
"""从安全存储获取加密密钥"""
kr = get_keyring()
key = kr.get_password('openclaw', 'encryption_key')
if not key:
key = Fernet.generate_key().decode()
kr.set_password('openclaw', 'encryption_key', key)
return key.encode()
def encrypt(self, data: str) -> str:
"""加密敏感数据"""
return self.cipher.encrypt(data.encode()).decode()
def decrypt(self, token: str) -> str:
"""解密数据"""
return self.cipher.decrypt(token.encode()).decode()
def create_ssl_context():
"""创建安全SSL上下文"""
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
context.minimum_version = ssl.TLSVersion.TLSv1_3
context.verify_mode = ssl.CERT_REQUIRED
context.load_verify_locations('/path/to/ca.pem')
context.load_cert_chain(
certfile='/path/to/cert.pem',
keyfile='/path/to/key.pem'
)
return context
6.2 合规性考虑
在企业部署中,需要特别注意以下合规要求:
-
数据主权:
- 确保数据存储在合规区域
- 实现数据本地化(Data Localization)
-
隐私保护:
- 实施GDPR/CCPA合规措施
- 提供数据删除功能(Right to be Forgotten)
-
行业规范:
- 金融行业:PCI DSS合规
- 医疗行业:HIPAA合规
- 政府项目:FedRAMP认证
合规检查表示例:
markdown复制| 合规领域 | 检查项 | 实施状态 | 验证方法 |
|----------------|---------------------------------|----------|------------------------------|
| 数据保护 | 静态数据加密 | 已完成 | AES-256加密验证 |
| 访问控制 | 基于角色的访问控制(RBAC) | 已完成 | 测试不同角色的权限隔离 |
| 审计跟踪 | 所有关键操作日志记录 | 已完成 | 检查审计日志完整性 |
| 隐私保护 | 支持用户数据删除 | 进行中 | 测试数据删除流程 |
| 网络安全 | 服务间TLS加密 | 已完成 | 网络抓包验证加密 |
7. 企业案例:智能客服中心
7.1 架构设计
我们为某大型银行实施的智能客服中心架构:
-
前端渠道:
- 网站聊天窗口
- 移动应用
- 微信小程序
- 电话系统集成
-
核心组件:
- 对话管理引擎(OpenClaw)
- 知识管理系统(RAG)
- 业务流程自动化(Skills)
- 情感分析模块
-
后端集成:
- 核心银行系统
- CRM系统
- 交易系统
- 风控系统
架构图(文字描述):
code复制用户请求 → 渠道接入层 → 负载均衡 →
OpenClaw核心 (对话管理 → Skills执行 → RAG检索) →
后端系统集成 → 返回响应
7.2 关键实现
7.2.1 多轮对话管理
python复制class DialogManager:
def __init__(self):
self.dialogs = {} # 存储对话状态
self.timeout = 300 # 5分钟超时
async def handle_message(self, user_id: str, message: str) -> str:
# 获取或初始化对话状态
if user_id not in self.dialogs:
self.dialogs[user_id] = {
'state': 'WELCOME',
'context': {},
'last_active': time.time()
}
dialog = self.dialogs[user_id]
dialog['last_active'] = time.time()
# 根据状态处理消息
if dialog['state'] == 'WELCOME':
response = "欢迎使用智能客服,请问您需要什么帮助?"
dialog['state'] = 'MAIN_MENU'
elif dialog['state'] == 'MAIN_MENU':
intent = await detect_intent(message)
if intent == 'ACCOUNT_BALANCE':
dialog['state'] = 'VERIFY_IDENTITY'
response = "为了查询账户余额,请先验证身份"
elif intent == 'TRANSACTION_HISTORY':
dialog['state'] = 'GET_DATE_RANGE'
response = "请问您想查询哪段时间的交易记录?"
else:
response = await self.fallback_response(message)
# 其他状态处理...
return response
async def cleanup(self):
"""清理超时会话"""
now = time.time()
for user_id, dialog in list(self.dialogs.items()):
if now - dialog['last_active'] > self.timeout:
del self.dialogs[user_id]
7.2.2 业务流程自动化
账户余额查询Skill实现:
python复制class AccountBalanceSkill:
def __init__(self, core_banking_client):
self.client = core_banking_client
self.max_retries = 3
async def execute(self, params: dict, user_context: dict) -> dict:
"""执行账户余额查询"""
account_number = params['account_number']
customer_id = user_context['customer_id']
# 验证账户所有权
if not await self.verify_account_ownership(customer_id, account_number):
return {
'status': 'error',
'code': 'PERMISSION_DENIED',
'message': '您无权访问该账户'
}
# 查询余额(带重试)
for attempt in range(self.max_retries):
try:
balance = await self.client.get_account_balance(account_number)
return {
'status': 'success',
'data': {
'account': account_number,
'balance': balance.amount,
'currency': balance.currency,
'as_of': balance.timestamp
}
}
except Exception as e:
if attempt == self.max_retries - 1:
logger.error(f"Failed to get balance after {self.max_retries} attempts")
raise
await asyncio.sleep(1 * (attempt + 1))
async def verify_account_ownership(self, customer_id: str, account_number: str) -> bool:
"""验证客户是否拥有该账户"""
accounts = await self.client.get_customer_accounts(customer_id)
return any(acc.number == account_number for acc in accounts)
7.3 效果评估
实施后的关键指标改善:
| 指标 | 实施前 | 实施后 | 改善幅度 |
|---|---|---|---|
| 平均响应时间 | 45秒 | 3秒 | -93% |
| 首次解决率 | 68% | 85% | +17% |
| 人工转接率 | 32% | 15% | -17% |
| 客户满意度(CSAT) | 4.1/5 | 4.6/5 | +12% |
| 运营成本 | $2.3/次 | $0.4/次 | -83% |
8. 高级主题:多智能体协作
8.1 协作架构设计
在企业复杂场景中,往往需要多个智能体协作完成任务。我们设计了基于消息总线的协作架构:
-
角色定义:
- 协调者(Orchestrator):负责任务分解和结果汇总
- 执行者(Executor):负责具体任务执行
- 监督者(Supervisor):监控任务执行和资源分配
-
通信机制:
- 使用Kafka作为消息总线
- 定义标准化的消息协议
- 实现发布/订阅模式
-
任务流程:
- 任务接收 → 分解 → 分配 → 执行 → 监控 → 汇总 → 返回
协作系统代码框架:
python复制from confluent_kafka import Producer, Consumer
import json
class AgentMessage:
def __init__(self, msg_type: str, payload: dict):
self.msg_type = msg_type
self.payload = payload
self.timestamp = time.time()
self.message_id = str(uuid.uuid4())
def serialize(self) -> str:
return json.dumps({
'msg_type': self.msg_type,
'payload': self.payload,
'timestamp': self.timestamp,
'message_id': self.message_id
})
class MultiAgentSystem:
def __init__(self, kafka_config):
self.producer = Producer(kafka_config)
self.consumers = {}
def register_agent(self, agent_id: str, topic: str):
"""注册智能体到特定主题"""
consumer = Consumer({
**kafka_config,
'group.id': agent_id,
'auto.offset.reset': 'earliest'
})
consumer.subscribe([topic])
self.consumers[agent_id] = consumer
def send_message(self, topic: str, message: AgentMessage):
"""发送消息到指定主题"""
self.producer.produce(
topic,
key=message.message_id,
value=message.serialize()
)
self.producer.flush()
async def process_messages(self, agent_id: str, handler: callable):
"""处理接收到的消息"""
consumer = self.consumers[agent_id]
while True:
msg = consumer.poll(1.0)
if msg is None:
await asyncio.sleep(0.1)
continue
if msg.error():
logger.error(f"Consumer error: {msg.error()}")
continue
try:
data = json.loads(msg.value())
message = AgentMessage(
data['msg_type'],
data['payload']
)
await handler(message)
consumer.commit(msg)
except Exception as e:
logger.error(f"Failed to process message: {str(e)}")
8.2 复杂任务分解
智能体协作处理复杂贷款申请的示例:
python复制class LoanApplicationOrchestrator:
def __init__(self, multi_agent_system):
self.mas = multi_agent_system
async def handle_application(self, application: dict):
"""处理贷款申请流程"""
# 创建流程跟踪器
tracker = {
'application_id': application['id'],
'steps': {},
'status': 'processing'
}
# 分解任务
tasks = [
('credit_check', {'customer_id': application['customer_id']}),
('income_verification', {'documents': application['income_proof']}),
('collateral_evaluation', {'assets': application['assets']}),
('risk_assessment', {'application': application})
]
# 发送子任务
for task_type, task_data in tasks:
task_id = str(uuid.uuid4())
tracker['steps'][task_type] = {
'task_id': task_id,
'status': 'pending'
}
message = AgentMessage(
msg_type=task_type,
payload={
'task_id': task_id,
'data': task_data,
'application_id': application['id']
}
)
self.mas.send_message(task_type, message)
# 等待结果
results = await self.wait_for_results(tracker)
# 综合评估
decision = self.make_decision(results)
return {
'application_id': application['id'],
'decision': decision,
'details': results
}
async def wait_for_results(self, tracker):
"""等待所有子任务完成"""
results = {}
pending_tasks = set(tracker['steps'].keys())
def callback(message):
nonlocal pending_tasks
if message.msg_type in pending_tasks:
results[message.msg_type] = message.payload['result']
pending_tasks.remove(message.msg_type)
# 注册回调
self.mas.register_agent('orchestrator', 'task_results')
# 处理消息直到所有任务完成
while pending_tasks:
await self.mas.process_messages('orchestrator', callback)
await asyncio.sleep(0.1)
return results
def make_decision(self, results):
"""基于子任务结果做出贷款决策"""
# 实现决策逻辑...
return 'approved' # 或 'denied'
