/<org-slug>/…,事件流即为组织主页(/<org-slug>/)。本指南中提到的页面名称(如 /sessions、/queries)均指上述组织范围内的路由。
查看日志
AgentEye 不内置日志或监控栈。服务器和仪表盘均将结构化日志写入 stdout,因此可以直接通过kubectl 或 docker 读取,无需聚合器。
Kubernetes
实时跟踪服务器和仪表盘的日志:| 目的 | 命令 |
|---|---|
| 最近 200 行(不跟踪) | kubectl logs -n agenteye -l app=server --tail=200 --timestamps |
| 上次崩溃前的日志 | kubectl logs -n agenteye <pod-name> --previous |
| 同时跟踪所有副本 | kubectl logs -n agenteye -l app=server --max-log-requests=10 -f |
| Postgres(StatefulSet) | kubectl logs -n agenteye postgres-0 -f |
Docker Compose
跨仪表盘与服务器关联单个请求
每个仪表盘请求都会附带request_id,并通过 x-request-id 请求头传递给服务器。服务器会在响应头和该请求的每一行日志中回显该 ID。要端到端追踪某个请求:
- 从响应头中获取 ID,例如:
- 在两个 Pod 的日志中 grep 该 ID:
proxy passthrough、withAuth: authorized、upstream response 日志行,以及服务器的 http request received / http request completed 日志对,它们共享同一个 request_id。
JSON 日志与 jq
在仪表盘上设置 AE_LOG_JSON=1(NODE_ENV=production 时默认开启),使其每行输出一个 JSON 对象,然后按结构过滤:
key=value 格式输出 tracing 日志,无需 jq 即可直接 grep:
提高日志详细程度
| 组件 | 环境变量 | 示例 |
|---|---|---|
| 服务器 | RUST_LOG | RUST_LOG=debug 或 RUST_LOG=agenteye_server=debug,info |
| 仪表盘 | AE_LOG_LEVEL | AE_LOG_LEVEL=debug |
debug 级别会为每次认证添加 api key authenticated 日志行。仪表盘的 debug 级别会添加 upstream request、session validated 和 proxy passthrough 日志行。
日志保留
容器 stdout 是临时性的;kubelet 会轮转日志文件(默认每个容器约 10 MiB),并在磁盘上保留少量文件。Pod 删除后日志即消失。如需更长时间的保留或跨 Pod 搜索,请将集群接入日志采集器(Loki、CloudWatch、Cloud Logging、Datadog 等),令其跟踪/var/log/containers/。AgentEye 不要求也不限定使用任何特定方案。
认证问题
docker pull 报 “unauthorized”
请确保已使用 AGENTEYE_TOKEN 向 GHCR 认证 Docker:
agenteye-enterprise 组织的 read:packages 权限。如果 token 无效,请联系 support@exosphere.host。
gh release download 返回 404 或 401
- 确认
AGENTEYE_TOKEN已在 shell 中导出:echo $AGENTEYE_TOKEN - 确认使用了
GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download ...(ghCLI 读取GITHUB_TOKEN) - 该 token 需要对
agenteye-enterprise/releases具有contents:read权限
服务器问题
服务器启动失败,报 “invalid port number”
POSTGRES_PASSWORD(或其他凭据)包含 URL 特殊字符(/、+、=),导致 DATABASE_URL 解析失败。请使用十六进制编码重新生成密码:
.env 文件),并重启服务器。完整步骤请参阅 enterprise-docs/kubernetes-deployment.md 中的 “PostgreSQL credentials” 一节。
服务器启动后立即退出
检查容器日志:DATABASE_URL未设置或格式错误:服务器会记录错误并退出。- Postgres 不可达:确认 Postgres 容器或托管数据库正在运行,且主机/端口配置正确。
- 迁移失败:检查日志中是否有 SQL 错误。
GET /health 返回非 200 或超时
服务器在首次启动时可能仍在执行迁移,请等待几秒后重试:
docker logs agenteye-server 中的错误信息。
GET /ready 返回 503
/ready 是就绪探针:当服务器无法访问 Postgres 或 ClickHouse 时返回 503。响应体会指明失败的依赖项:
down 的依赖项:ClickHouse/Postgres Pod 是否处于 Running 状态?CLICKHOUSE_URL / DATABASE_URL 是否正确且可访问?在 Kubernetes 上,Pod 在 /ready 恢复前会显示 NotReady,这是预期行为,也正是健康监控告警所依赖的信号。Redis 不会导致就绪失败:它会被上报但不影响就绪判断。
采集器返回 401 Unauthorized
采集器的 API key 没有events:add 权限,或该 key 已被禁用。请创建一个具有正确权限的新 key:
认证请求突然变慢(~200ms 而非 ~5ms)
这是REDIS_URL 已设置但 Redis 不可用时的典型症状。每次缓存调用在超时 100ms 后回退到 Postgres;在认证和 OTP 路径上,一次请求会经历两次这样的回退。
在服务器日志中确认:
- 执行
redis-cli -h <your-redis> ping,确认 Redis 在集群网络上可达。 - 如果 Redis 曾短暂不可用现已恢复,请重启服务器 Pod。
redis::aio::ConnectionManager在底层连接断开后无法可靠重连;重启 Pod 会重新建立干净的连接。仪表盘同理。 - 如果暂时不想运行 Redis,请在部署配置中取消设置
REDIS_URL并重启。两个服务在没有缓存的情况下也能正常运行(正确性不受影响;延迟回退到引入 Redis 前的基准水平)。
服务器日志显示 OTP request rate-limited,但用户说只尝试了一次
检查 Redis 是否不可达。回退路径使用 SELECT COUNT(*) FROM otp_codes WHERE created_at > now() - interval '15 minutes',会查到之前生成的 OTP 记录。如果用户在过去一小时内一直点击”重新发送”,15 分钟窗口内可能仍存在 ≥5 条记录。解决方案:等待窗口滚动,或执行 DELETE FROM otp_codes WHERE user_id = $1 AND created_at > now() - interval '15 minutes'(操作员控制台)。
修改了 ALLOWED_EMAILS / SESSION_TTL_SECS / OTP_TTL_SECS 并重启后没有任何变化
这些环境变量仅在首次启动时作为种子值使用。一旦 settings 表中已有对应 key 的行,该行即为真实来源;环境变量在首次启动时读取一次,此后每次重启均被忽略。
若需在首次启动后修改,请登录仪表盘并在 /settings 页面编辑。修改会在数秒内在所有副本上生效,无需重启。
如需强制从环境变量重新初始化(罕见,通常仅用于开发环境),请执行 DELETE FROM settings WHERE key = '<key>' 并重启服务器。服务器在下次启动时会读取当前环境变量的值。在生产环境中,推荐通过 /settings 页面编辑。
采集器问题
采集器已启动,但事件未出现在仪表盘中
- 确认采集器正在运行:
systemctl status agenteye-collector(Linux)或检查进程状态。 - 确认
AGENTEYE_URL指向http(s)://your-server-host:8080/events(注意:需包含/events路径)。 - 执行一次性强制上传,查看即时输出:
- 检查 Python SDK 是否正在写入文件:
ls ${AGENTEYE_HOME:-~/.agenteye}/events/ - 如果
${AGENTEYE_HOME:-~/.agenteye}/failed/中存在文件,说明上传失败。检查采集器日志中的错误信息,通常是 4xx(key 错误或 URL 错误)或网络问题。
文件在 $AGENTEYE_HOME/events/ 中堆积,未被上传
- 采集器可能未在运行。启动它:
agenteye-collector start;它会在启动时自动上传已有的事件文件。 - 检查采集器健康状态:
agenteye-collector health - 采集器可能正在运行但无法访问服务器。检查采集器主机与服务器主机之间的防火墙规则。
$AGENTEYE_HOME/failed/ 中存在文件
文件在所有重试尝试耗尽后(默认:5 次,指数退避)移至 failed/。这意味着:
- 服务器返回了 4xx 错误(key 错误、URL 错误或负载问题)
- 在整个重试窗口期间服务器不可达
采集器每次上传都报 network error(TLS 握手失败)
如果对 AGENTEYE_URL 执行 curl -k 成功,但采集器二进制文件每次上传都报 error sending request for url (...),说明 AgentEye 服务器提供的 TLS 证书不是由公信 CA 签发的。
生产路径是在 deploy/base/certificates/domain.env 中配置的 ACME 入站主机名(参见 kubernetes-deployment.md 第 3.1 / 4.2 阶段)。一旦 INGEST_DOMAIN 解析到公网 Traefik LB 且 cert-manager 已颁发 Let’s Encrypt 证书,采集器将使用系统信任存储验证服务器证书,无需设置 AGENTEYE_TLS_CA;如果之前针对旧的自签名部署设置过该配置,请清除它。
症状:采集器昨天还正常,今天(约 90 天后)突然失败。 这意味着集群的 ingest-tls 仍在使用旧版 selfsigned 颁发者。90 天证书已轮换,固定的 CA 文件已过期。永久修复方案:将集群切换到 ACME 颁发者(部署指南第 3.1 阶段)。短期解决方案:重新提取当前服务器证书并更新 AGENTEYE_TLS_CA:
AGENTEYE_TLS_CA 会添加一个额外的信任锚点;标准公共根证书仍然受信任。
部署后 ingest-tls 证书一直处于 Ready: False
Events 以及关联的 Order / Challenge。常见原因:
- DNS 未解析到公网 LB。 HTTP-01 验证器无法访问
INGEST_DOMAIN。使用dig +short INGEST_DOMAIN验证;它应解析到与traefik-publicLoadBalancer 的EXTERNAL-IP相同的地址。DNS 传播完成后 cert-manager 会自动重试,无需删除 Certificate 资源。 - 端口 80 在负载均衡器/安全组处被封锁。 HTTP-01 验证要求端口 80 对 Let’s Encrypt 的公共验证器可访问。如果上游 WAF 或安全组限制了
:80,请开放它(Traefik 配置会重定向到 HTTPS,但 Boulder 会跟随重定向并接受响应)。 dnsNames未被替换。 如果kubectl get certificate ingest-tls -n agenteye -o jsonpath='{.spec.dnsNames}'显示INGEST_DOMAIN_PLACEHOLDER,说明你跳过了domain.env步骤;请从domain.env.example创建该文件并重新应用。- 被 Let’s Encrypt 限流。 对同一主机名反复失败的申请会触发重复证书或验证失败限制。请至少等待一小时后再重试;检查 Order 状态以获取确切的限流信息。
dashboard-tls 证书一直处于 Ready: False / 浏览器仍显示警告
诊断流程与上述 ingest-tls 相同(kubectl describe certificate dashboard-tls -n agenteye);DNS、端口 80、占位符和限流原因同样适用,此外还有两个仪表盘专有原因:
DASHBOARD_DOMAIN解析到错误的 LoadBalancer。 它必须指向仪表盘 Traefik LB,而非公网入站 LB。对主机名执行dig +short并与仪表盘 LB 地址对比。- 仪表盘 Traefik 实例无法响应验证请求。 必须使用附带的仪表盘 values 文件安装该实例,它会为 cert-manager 的 HTTP-01 解析器启用范围限定的 Ingress provider。没有它,解析器无法路由,Order 会一直处于
pending状态。使用提供的 values 文件升级该实例,待处理的验证请求随后会自动完成。 - LoadBalancer 设置了 IP 限制。 源 IP 范围限制同样适用于端口 80,这会阻止 Let’s Encrypt 的验证器访问——无论是首次颁发还是约每 75 天的续期。请重新开放 LB,或在锁定之前与支持团队协商使用 DNS-01 解析器。
仪表盘获得受信任证书后,CLI 仍跳过 TLS 验证
--insecure 标志在登录时会持久化到 cli.json。一旦仪表盘提供公信证书,请使用 agenteye --base-url https://<your-dashboard-domain> --secure login 重新登录;验证选项会被保存为开启状态,启动时的警告也会消失。
仪表盘问题
无法禁用或编辑 ADMIN_EMAIL 用户
这是设计行为。匹配 ADMIN_EMAIL 的用户在每次服务器启动时都会被标记为受保护:仪表盘会在该行隐藏”禁用”按钮,且 API 会以 403 Forbidden 拒绝针对该用户的 DELETE /users/:id 和 PUT /users/:id 请求。数据库触发器也会拒绝直接禁用受保护行的 UPDATE 语句。
若要轮换引导管理员,请在环境变量中修改 ADMIN_EMAIL 并重启服务器。新邮箱会被 upsert 为受保护状态。之前的管理员会保留受保护标志,直到在数据库中手动清除(通常无需处理,因为之前的邮箱在你明确删除之前仍是有效的管理员)。
仪表盘不显示事件
- 确认仪表盘环境变量中的服务器 URL 和 API key 配置正确(
AGENTEYE_SERVER_URL、AGENTEYE_API_KEY)。 - 仪表盘 API key 需要
events:read权限。 - 确认事件已被实际采集:
curl http://your-server:8080/events -H "Authorization: Bearer $ADMIN_KEY"
/errors 为空,但 /events 显示红色行
较新版本的 SDK 将失败事件作为 agent_end / tool_result / hook_completed 类型、outcome: "error" 的事件发送,而非专门的 event_type: "error" 行。/errors 页面现在同时匹配两种情况:/events 流中任何标红的行(显式 event_type='error'、payload 的 outcome/status 属于失败集合、is_error: true,或 error 字段为真值)都会出现在 /errors 中。如果你之前在 /events 有红色行的同时看到”此窗口内无错误”,请同时升级仪表盘和服务器(扩展后的过滤条件为 GET /events 上的 errored=true),两个视图将保持一致。
/models、/tools 或 /hooks 在宽时间范围下加载缓慢或失败
症状: 在大型事件表(数百万行)上,打开 /models、/tools 或 /hooks,或将时间范围拓宽至 7d、30d 或 all 时,图表转圈后显示加载错误。服务器日志中记录了 latency_aggregate 请求的 ClickHouse MEMORY_LIMIT_EXCEEDED(Code 241)或查询超时。
原因: 旧版本在计算这些页面的延迟和分布汇总时,会读取完整的原始事件 payload 并通过内存排序和关联来配对请求/响应事件。查询峰值内存因此随窗口大小增长,在繁忙的租户上,宽时间范围可能超过 ClickHouse 的单查询内存上限。
修复: 升级到包含此修复的版本。汇总查询现在只读取紧凑的提升列,并通过流式聚合来配对事件,因此峰值内存不再随原始 payload 增长——宽时间范围也能保持在内存上限之内,且响应时间大幅缩短。该改进完全在查询层实现:无需重新采集或回填数据,下次页面加载时即对所有现有数据生效。
仪表盘加载失败 / 空白页面
检查仪表盘容器日志:AGENTEYE_SERVER_URL 或 AGENTEYE_API_KEY 缺失,或指向了不可达的服务器。
仪表盘分析 / 遥测
仪表盘默认会向 PostHog 发送匿名产品使用分析数据,通过仪表盘自身的/ingest 路径(反向代理到 https://us.i.posthog.com)路由。以第一方方式发送可防止浏览器广告拦截器阻断它们。这与仪表盘的核心功能无关:
- 仪表盘容器(而非浏览器)负责访问 PostHog。如果其到
https://us.i.posthog.com的出站访问被阻断,遥测会静默失效;仪表盘正常运行,用户不会看到任何错误。 - 不会包含任何 Agent、会话或事件数据,仅包含仪表盘 UI 使用情况。
- 若要完全禁用遥测,请在仪表盘容器上设置
AE_ANALYTICS_DISABLED=1并重启。详见部署指南中的遥测与隐私。
CLI 分析 / 遥测
agenteye CLI 默认向 PostHog 发送匿名使用分析数据:执行的命令、成功/退出状态和耗时。这与 CLI 的功能无关:
- 运行 CLI 的机器直接访问
https://us.i.posthog.com。如果出站访问被阻断,遥测会静默失效(发送有时间限制,不会延迟命令执行),CLI 正常运行。 - 不会包含任何 Agent、会话或事件数据:命令参数和标志值(仪表盘 URL、token、邮箱、会话 ID、查询过滤器)绝不会被发送。
- 若要禁用,请在 CLI 的环境中设置
AGENTEYE_ANALYTICS_DISABLED=1(或跨工具通用的DO_NOT_TRACK=1)。详见 CLI 指南中的遥测与隐私。
AI 助手问题
完整设置请参阅 enterprise-docs/assistant.md。助手气泡未出现
气泡仅在以下所有条件均满足时才会显示:- 已登录用户具有
agent:use权限。 - 仪表盘上已设置
AGENTEYE_AGENT_URL,且agent服务可达。 agent服务上已配置 LLM 端点(ANTHROPIC_API_KEY、通过ANTHROPIC_BASE_URL的网关,或 Bedrock/Vertex)。如果都未设置,agent 会报告”未配置”,气泡保持隐藏。
curl http://agent:9100/health 应返回 {"status":"ok","llm_configured":true,...}。
助手提示无法读取某些内容
工具按用户设置门控权限。如果用户缺少evaluations:read(或 events:read、dashboards:read),对应工具不会被提供,助手会提示无法读取该数据。请授予相关读取权限。
发送消息时报 “assistant not configured”(HTTP 503)
agent 容器未配置 LLM 端点,或仪表盘的 AGENTEYE_AGENT_TOKEN 与 agent 的 token 不匹配。请同时设置并重启。
agent 容器在负载下重启 / OOM
每个对话会生成一个短生命周期的子进程。确保容器以 init 进程运行(镜像使用 tini;在 Compose 中设置 init: true),并提供足够的内存限制。如有需要,可降低 AGENTEYE_AGENT_MAX_STEPS。
CLI 问题
agenteye 启动失败,报 ModuleNotFoundError: No module named 'click'
0.1.6 版本的 agenteye CLI 在全新安装后可能在启动时崩溃:
typer 间接安装 click;而当前 typer 版本不再隐式引入 click,导致全新环境中缺少该包。请升级到 0.1.7 或更新版本,该版本直接依赖 click:
Python SDK 问题
$AGENTEYE_HOME/events/ 中没有文件出现
SDK 默认每 500ms 缓冲并刷新一次事件。如果进程在刷新前退出,事件可能丢失。对于短生命周期脚本,请调用 agenteye.configure(flush_interval=0.1) 加快刷新速度,或确保进程运行时间足够完成一次刷新周期。
如果已设置 AGENTEYE_HOME,请确认 SDK 写入的是 $AGENTEYE_HOME/events/ 而非 ~/.agenteye/events/(需要 SDK ≥ 0.0.1b5)。
ValueError: Reserved field names cannot be used as custom fields
timestamp、type 和 environment 是保留名称,不能用作自定义字段。传递其中任何一个都会抛出:
session_id 和 agent_id 是事件调用的显式参数,而非自定义字段;将它们作为自定义字段再次传递会抛出 TypeError。
健康监控问题
Slack 未收到告警(Robusta)
Robusta 健康告警需要手动启用;在安装并指向 Slack 频道之前不会发送任何内容。验证 release 及其 sink:api_key / slack_channel 未设置(或 token 已被吊销);api_key 是 Robusta 云中继 token(robusta integrations slack),但附带的 disableCloudRouting: true 需要自托管的 Slack bot token(xoxb-…),或者将 disableCloudRouting 设为 false;sink 的 scope 排除了你的 Pod 所在的命名空间(附带的 values 文件将范围限定为 agenteye);或者尚未发生任何故障。通过下线一个 Pod 强制触发测试告警:
服务器持续在 NotReady 状态反复横跳
就绪探针会访问 /ready,当 Postgres 或 ClickHouse 不可达时会失败。如果服务器在 NotReady 状态间反复切换,说明某个依赖项间歇性不可用;请检查 ClickHouse 和 Postgres Pod 以及服务器的 CLICKHOUSE_URL / DATABASE_URL。确认 /ready 报告的内容:
/health 上,因此就绪状态抖动不会重启 Pod。
证书监控问题
CronJob 未发送 Slack 通知
cert-renewal-check CronJob 需要将 Slack webhook URL 存储在 Secret 中。验证它是否存在:
客户端证书在收到通知前已过期
CronJob 每 12 小时运行一次。如果它一直未运行,请检查其状态:collector-mtls-secret.yaml 并重启:
备份问题
agenteye-backup 报 “No space left on device”
agenteye-backup CronJob 将 Postgres + ClickHouse 转储到 backup-tmp emptyDir 临时卷(默认 30Gi),然后流式将 tar 归档直接上传到 S3——压缩归档文件不会写回临时卷,因此临时卷只需容纳原始转储文件,而非转储文件加一份归档副本。Pod 被驱逐 / 报 No space left on device 意味着原始转储文件超出了临时卷大小(ClickHouse events 转储文件占主导,且随时间增长)。检查失败 Job 的日志:
backup-tmp emptyDir 的 sizeLimit 提高到超过原始转储总量,并确认节点的临时存储实际上能容纳这些数据(sizeLimit 是上限,而非预留量)。如果转储量超过单个节点的磁盘容量,请用 PVC(EBS/PD)替换 backup-tmp 的 emptyDir,或在源头压缩转储文件。
旧版本会将.tar.gz写入与转储文件相同的20Gi临时卷,导致转储文件 + 归档文件溢出,Pod 在上传前就被驱逐——表现上像 S3 故障,实际上是磁盘问题。流式上传消除了这种空间翻倍问题。
agenteye-backup 安装 curl 失败
该 Job 在 postgres:16 镜像上运行,并在启动时安装 curl 以执行 ClickHouse HTTP 转储。在没有到 Debian 软件包镜像出站访问的集群上,apt-get 步骤会失败。请允许备份 Pod 的出站访问,或将 curl 预装到镜像副本/自定义备份镜像中,并在 overlay 中引用该镜像。
agenteye-backup 运行但对象存储中没有文件
基础配置内置了真实的 BACKUP_BUCKET(ts-prod-agenteye/backups)和 agenteye-backup ServiceAccount。该 Job 流式将归档上传到 S3(tar cz … | aws s3 cp - s3://…)。如果备份 Pod 没有该存储桶的写入权限,上传会报错——由于脚本在 set -euo pipefail 下运行,管道中任何位置的失败都会在 upload 步骤导致整个 Job 失败,而非静默失效(Pod 的 EXIT trap 会记录 backup FAILED during step: upload)。这也是修复临时卷驱逐问题后你会遇到的步骤,因此如果备份之前在归档步骤被驱逐,请验证上传现在是否成功。在失败 Job 的日志中搜索 S3 访问错误:
BACKUP_BUCKET 设置为你拥有的存储桶,并为现有的 agenteye-backup ServiceAccount 添加写入权限注解(IRSA / Workload Identity / Pod Identity)。详见 enterprise-docs/kubernetes-deployment.md 中的备份章节。
ClickHouse 支持的评估 / 会话 / 查询
升级后 /queries 页面侧边栏为空
预期存在三张表(events、evaluations、agent_sessions)。如果升级后 SchemaBrowser 侧边栏为空,说明服务器在启动时未能应用 ClickHouse DDL。检查服务器日志中的 failed to apply CH DDL statement:
CrashLoopBackOff 状态,而非出现静默损坏的查询页面。但部分 DDL 应用(某条语句成功,后续报 5xx)会导致 schema 处于不完整状态。在确认 ClickHouse 可达后,重启服务器 Pod:
新评估未出现在 /sessions 或 /queries 中
升级后,新评估被写入 ClickHouse 而非 Postgres,并在 /sessions(需要 evaluations:read 权限)和 /queries 中显示。如果未出现:
- 确认评估器管道已启用(服务器上已设置
EVALUATOR_ENDPOINT)且正在产生终止结果;检查是否有evaluation_finalized日志行。 - 确认服务器可访问 ClickHouse:
kubectl exec -n agenteye deploy/server -- curl -fsS http://clickhouse:8123/ping。 - 抽查 ClickHouse 表:
kubectl exec -n agenteye clickhouse-0 -- clickhouse-client -q 'SELECT count() FROM agenteye.evaluations'。
负载下查询报 “Memory limit exceeded”,或 ClickHouse 被 OOMKilled
症状: 在仪表盘/查询负载较重时,分析页面(事件流、/sessions、模型/延迟视图、SQL 编辑器)开始失败或超时;服务器短暂抖动至 NotReady;ClickHouse Pod 的重启次数持续上升。这几乎总是内存问题,而非 CPU 或磁盘问题。
确认是内存问题(而非可通过复制解决的吞吐量问题):
-
检查 Pod 是否因内存不足被杀:
Reason: OOMKilled/Exit Code: 137加上持续上升的重启次数是明确信号。 -
查询 ClickHouse 正在拒绝的内容:
MEMORY_LIMIT_EXCEEDED计数较大是典型特征。错误消息中显示 “maximum: N GiB”——该 N 值为 Pod 内存限制的0.9倍(即deploy/base/clickhouse/configmap.yaml中的max_server_memory_usage_to_ram_ratio)。如果繁重的读取需要超过 N 的内存,请求就会被拒绝。 -
排除不是问题的因素——如果 CPU、part 数量和磁盘都较低,增加副本/分片只是浪费成本:
payload 列,对其运行 JSONExtract*,并使用 FINAL——每项操作都可能需要数 GiB 内存。如果配置的缓存(mark_cache_size + uncompressed_cache_size)大于 Pod 内存,问题会加剧:缓存和查询内存共享同一预算,缓存会挤占查询内存。
修复——扩展 ClickHouse 内存:
- 在 overlay 中通过 patch
clickhouseStatefulSet 容器的resources来提高 ClickHouse 内存限制(与其他组件resources使用相同的 overlay 机制)。可用的服务器预算为0.9 × 限制,因此6Gi限制提供约 5.4 GiB,16Gi限制提供约 14 GiB。同时将requests.memory设置为实际下限,让调度器进行预留。应用此配置会重新创建 ClickHouse Pod(单副本约有 30–60 秒的分析停机);请在低流量时段操作。 - 保持
deploy/base/clickhouse/configmap.yaml中缓存与内存限制的比例——在小 Pod 上,小缓存(几百 MiB)是安全的;仅在同时提高内存限制时才增大缓存。users.xmlprofile 中显式设置了单查询的max_memory_usage(见下文固定节点章节),并保持在服务器级上限(0.9 × 限制)以下,确保没有单个查询被允许使用超过容器拥有的内存。 - 如果节点本身是瓶颈,检查 ClickHouse 可见的主机内存:
如果该值仅略高于 Pod 限制,请在进一步提高限制之前,通过 overlay 中的节点选择器/亲和性将 ClickHouse 迁移到更大的(内存优化型)节点。
500 后继续在 ClickHouse 中执行——将查询保持在内存中并快速拒绝偶尔超预算的查询(MEMORY_LIMIT_EXCEEDED,亚秒级)才能恢复正常加载。应用这些配置时需注意 ClickHouse 的一个陷阱:
- 这些是 profile 配置,ClickHouse 只从
users_config(users.xml/users.d/*.xml)读取<profiles>块——绝不从config.d读取。 放置在config.d/agenteye.xml中的<profiles>块会被静默忽略(max_execution_time、max_memory_usage等根本不会生效)。因此,附带的配置将它们作为users.xmlkey 放在clickhouse-configConfigMap 中,挂载到/etc/clickhouse-server/users.d/agenteye.xml。 - 内置默认值:
max_memory_usage(单查询上限——单个查询不能消耗整个服务器预算)、max_bytes_before_external_group_by/max_bytes_before_external_sort=0(禁用溢出),使查询保持在内存中而不在慢速磁盘上爬行,以及max_execution_time(失控保护,与服务器的客户端读取超时对齐)。 - 验证配置已生效(这也是检测 config.d 陷阱的方法):
期望看到非零的
max_memory_usage和max_bytes_before_external_group_by = 0。如果max_memory_usage读取为0/默认值,说明 profile 未被应用——检查配置是否在users.d挂载中,而非config.d。
max_memory_usage 的查询会被拒绝(MEMORY_LIMIT_EXCEEDED),而非缓慢完成——在慢速磁盘上,这种快速拒绝更可取,因为溢出查询无论如何都会超过客户端超时而失败。如果你的数据磁盘速度快(SSD),可以提高 max_bytes_before_external_* 阈值,允许大型查询溢出到磁盘并完成。
多租户(组织)
启用组织的升级过程中出现错误(新旧服务器 Pod 混合)
症状: 在滚动部署启用组织功能的版本时,部分请求失败:服务器日志在api_keys 路径上显示 there is no unique or exclusion constraint matching the ON CONFLICT specification,以及/或告警/Slack/webhook 频道在滚动发布期间停止触发。
原因: 该升级将 api_keys(name) 上的旧实例级唯一索引替换为按组织划分的部分索引,并将告警频道配置(以及 default_user_permissions)从全局 settings 表迁移到每个组织的 org_settings。旧版服务器 Pod 仍然发出 ON CONFLICT (name)(现在没有匹配的约束)并从旧的 settings 行(现在为空)读取频道配置。新旧 Pod 对这两条路径无法安全共存。
修复: 不要对这次特定升级进行跨版本的慢速滚动。请彻底切换:将旧版服务器缩容至零(或使用短暂的维护窗口),与迁移一起启动新版本,而非同时运行新旧副本。切换完成后流量和采集立即恢复;这只影响版本过渡窗口。
创建组织在 CREATE USER / CREATE ROW POLICY 时失败,或一个组织能读取另一个组织的数据
症状: 创建组织时返回提及 CREATE USER、CREATE ROW POLICY 或”access management is disabled”的错误;更严重的情况是,一个组织的成员在 SQL 编辑器或助手中看到另一个组织的事件/评估数据。
原因: 按组织的隔离通过每个组织专用的 ClickHouse 用户 + 行策略来实现。这需要在 ClickHouse 上启用 SQL 访问管理,并将 users_without_row_policies_can_read_rows=false。禁用访问管理时,创建组织时无法创建用户/策略;行策略默认值保持宽松时,有 SELECT 权限但无策略的用户会读取所有行(默认开放)。
修复: 使用附带的 deploy/base/clickhouse/ 配置,它同时设置了这两项。如果你使用自定义的 ClickHouse 配置,请在服务器内部用户上启用 SQL 访问管理,并设置 users_without_row_policies_can_read_rows=false(参见 deploy/base/clickhouse/configmap.yaml),然后重启 ClickHouse 并使用 agenteye-orgctl CLI 重新创建组织(参见 enterprise-docs/tenant-management.md)。
修改 ORG_CH_SECRET 后组织用户失去 ClickHouse 访问权限
症状: 修改 ORG_CH_SECRET 或在不同副本上设置不一致后,SQL 编辑器和 AI 助手立即对所有组织返回 ClickHouse 认证失败。
原因: 每个组织的 ClickHouse 密码是以 ORG_CH_SECRET 为密钥的 HMAC 派生值。轮换该密钥(或在副本上运行不同的值)会使每个组织存储的 ClickHouse 凭据失效;派生密码不再匹配已创建的用户。
修复: 在创建第二个组织之前将 ORG_CH_SECRET 设置为一个强值,并在所有服务器副本上保持稳定一致。服务器的启动时协调会在启动时根据当前 Secret 重新创建每个组织的 ClickHouse 用户,因此对所有副本重启服务器(Secret 保持一致)会修复孤立的用户。请将该值视为长期 Secret,不要随意轮换。作为安全保护,如果 ORG_CH_SECRET 保持内置的开发默认值(即未设置),启动时协调会跳过非默认组织并记录错误,而非将其 ClickHouse 凭据重写为公知的开发值——这样单个副本在没有 Secret 的情况下重启时不会破坏其他副本。请一致设置该 Secret 并重启,以完成这些组织的创建。
启用组织后 AI 助手返回 400 / 拒绝聊天
症状: 助手面板加载成功,但每条消息都返回错误(HTTP400),且 agent 日志记录了被拒绝的无组织上下文的 /chat 请求。
原因: agent 具有组织感知能力,采用失败关闭策略;它会拒绝没有携带组织上下文的 /chat 请求。这发生在过渡性滚动发布期间,agent 已升级但发送请求的仪表盘尚未具备组织感知能力。
修复: 完成滚动发布,使仪表盘发送组织上下文(正常最终状态,无需特殊标志)。在尚未升级的仪表盘与已升级的 agent 通信的过渡期间,在 agent 服务上设置 AGENTEYE_AGENT_ALLOW_NO_ORG=1,使其回退到 default 组织而非拒绝请求,待仪表盘升级完成后清除该设置。详见 enterprise-docs/assistant.md 中的环境变量参考。
审计
审计从未运行(下次运行时间持续推迟,运行历史为空)
症状: 审计页面显示上次运行:从未,或next run 持续移到未来而运行历史中没有出现任何记录。
原因: 审计已禁用(禁用的审计没有队列条目),或服务器的审计工作进程无法认领工作。
修复: 确认审计已启用(立即运行按钮需要审计处于启用状态)。然后检查服务器日志中启动时的 audits pipeline started 以及 audits: 错误——claim_due failed 日志行指向 Postgres 连接问题。AUDIT_WORKERS 默认值为 1;必须 ≥ 1 才能运行任何审计。
审计运行成功但未发现任何问题
症状: 运行历史显示succeeded,findings: 0,但 /errors 明确显示有失败记录。
原因: 扫描窗口未覆盖这些失败,或范围过滤器将其排除。
修复: 对照失败发生的时间检查运行记录的窗口(window_from → window_to)——在 since_last 模式下,每次运行只扫描自上次成功运行以来的数据,因此旧的失败只有第一次运行或 fixed 窗口审计才能看到。扩大 scope(环境 / agent ID)。运行统计显示 policy_hits(确定性策略触发次数)和 improvements(AI 调查记录的次数)——如果两者都为 0,说明该窗口/范围内确实没有发现任何内容。
运行显示 analysis_unavailable,只产生了 policy 类型的发现
症状: 运行统计包含 analysis_unavailable,且所有发现都是 kind: policy;没有 AI 改进建议出现。
原因: 智能体调查无法运行:服务器无法访问 agent 服务(服务器上未设置 AGENTEYE_AGENT_URL / AGENTEYE_AGENT_TOKEN——审计复用助手的连接),助手服务未配置 LLM,或调用报错/超时(analysis_unavailable 字符串中有详细信息)。确定
