文件最后提交记录最后更新时间
21 天前
21 天前
15 天前
README

LLM HTTP Payload And Semantics Example

这份示例用于验证:

http1.sh prepare -> actrailctl launch -> curl/OpenSSL -> tls-sync runtime -> AcTrail storage -> actrailviewer
                                                                      -> HTTP/1.x semantic Application events

验证目标是捕捉真实发往 OpenAI-compatible LLM provider 的 outbound TLS plaintext request,并让 AcTrail 从保留的 plaintext 中派生 HTTP/1.x semantic request event。DeepSeek 只是本例的默认 provider;可以通过环境变量改成别的兼容 endpoint。服务端是否返回业务成功不是本例重点;只要 curl 发出了 HTTPS 请求,actrailviewer 就应该能看到发出的 HTTP request、JSON body,以及 Application domain 的 request row。actraild 预期由管理员或 root 运行。

HTTPS/1.1 测试流程:

sequenceDiagram
    actor User as 操作者
    participant Daemon as actraild
    participant Launcher as actrailctl launch
    participant Curl as curl/OpenSSL
    participant Runtime as tls-sync runtime
    participant Provider as LLM Provider
    participant Store as AcTrail storage
    participant Viewer as actrailviewer

    User->>Daemon: start --config http1-operator.conf
    Daemon->>Runtime: prepare sync event socket
    User->>Curl: launch curl --config prepared-curl.conf
    Launcher->>Daemon: TrackAdd(actrailctl pid)
    Launcher->>Runtime: prepare LD_PRELOAD and finder fast probe plan before child exec
    Curl->>Provider: HTTPS/1.1 chat completion request
    Runtime-->>Daemon: TLS plaintext payload events
    Daemon->>Daemon: redact payload and derive HTTP Application events
    Daemon->>Store: persist payload and Application rows
    User->>Viewer: inspect payloads, payload text, and events
    Viewer->>Store: read unified payload/Application results

1. 构建

在仓库根目录执行:

cargo build --release

本例使用这些二进制:

./target/release/actraild
./target/release/actrailctl
./target/release/actrailviewer

2. 准备 Provider 环境变量

docs/examples/02.llm-http-payload-capture/external-openai-compatible/http1.shhttp2.sh 默认使用 DeepSeek 的 OpenAI-compatible endpoint,但这些默认值都可以用环境变量覆盖:

export DEEPSEEK_API_KEY='<your-deepseek-api-key>'

确认默认 key 变量存在即可,不要把真实 key 打印到终端:

test -n "${DEEPSEEK_API_KEY:-}"

可覆盖的环境变量如下:

环境变量 默认值 用途
ACTRAIL_LLM_BASE_URL https://api.deepseek.com Provider base URL,不包含 path
ACTRAIL_LLM_CHAT_PATH /chat/completions Chat completions path,必须以 / 开头
ACTRAIL_LLM_MODEL deepseek-v4-pro 默认 request body 中的 model
ACTRAIL_LLM_PROMPT Hello!Hello over HTTP/2! 默认 request body 中的 user prompt
ACTRAIL_LLM_API_KEY_ENV DEEPSEEK_API_KEY 保存 API key 的环境变量名
ACTRAIL_LLM_AUTH_HEADER_NAME Authorization 认证 header 名
ACTRAIL_LLM_AUTH_SCHEME Bearer 认证 scheme;设为空字符串时直接发送 key
ACTRAIL_LLM_REQUEST_JSON unset 完整覆盖 JSON request body

如果 provider 不接受默认 OpenAI-compatible body,设置 ACTRAIL_LLM_REQUEST_JSON 传入完整请求体。这个变量是 workload 请求体,不是 AcTrail runtime 配置;AcTrail 本身不依赖 DeepSeek 特有字段。

docs/examples/02.llm-http-payload-capture/external-openai-compatible/http1.sh prepare 会生成临时 curl config 和 JSON body 文件。后续 actrailctl launch -- curl --config "$ACTRAIL_CURL_CONFIG" --data-binary @"$ACTRAIL_CURL_BODY" 直接观测 curl,同时避免把 bearer token 放进进程 argv。脚本里保留 http1.1,这样捕获到的 TLS plaintext 是可读 HTTP/1.1 request,而不是 HTTP/2 binary frame。

不强制 http1.1 时也能捕获 TLS plaintext bytes;区别是 curl 可能通过 ALPN 协商 HTTP/2。http2.sh 使用的是 curl 的 HTTP/2 协商模式,不是“只允许 HTTP/2”的强制模式;如果 provider、CDN 或代理路径最终协商为 HTTP/1.1,regression 会把 external HTTP/2 子检查标记为 SKIP,并依赖前面的 external HTTP/1.1 子检查覆盖 provider 路径。真正可重复的 HTTP/2 捕获能力由本地 http2-local/ workload 验证。

当 ALPN 协商为 HTTP/2 时,payload 里会出现 HTTP/2 connection preface、HEADERS/DATA frames 和 JSON DATA frame body。AcTrail 可以按配置记录 HTTP/2 frame/DATA facts,但 header 仍是 HPACK 编码,当前不声明 HTTP/2 header-level semantic redaction。

3. 检查本例配置

本例使用同目录归档的 operator config:

docs/examples/02.llm-http-payload-capture/external-openai-compatible/http1-operator.conf

它使用单独 /tmp 路径,避免和 quick start 或其他手动验证冲突。这个配置继承 operator 默认值;只需要确认本例关心的路径、能力和采集面:

socket_path = /tmp/actrail-llm-http-http1.sock
pid_file = /tmp/actrail-llm-http-http1.pid
storage.sqlite.path = /tmp/actrail-llm-http-http1.sqlite
web.listen_addr = 127.0.0.1:18080
export.snapshot.directory = /tmp/actrail-llm-http-http1-export
log_path = /tmp/actrail-llm-http-http1.log

capture.capabilities includes proc-lifecycle
capture.capabilities includes net-transport
capture.capabilities includes tls-plaintext-payload
capture.capabilities includes socket-plaintext-payload
capture.capabilities includes stdio-chunk
capture.capabilities includes net-application-plaintext-http
capture.capabilities includes net-application-http2-frames

payload.tls.enabled = true
payload.tls.capture_backend = tls-sync
payload.tls.source = auto
payload.tls.resolver = auto
payload.tls.redaction_policy = authorization-header
payload.tls.sync_runtime_library_path = auto
payload.tls.sync_event_socket_path = /tmp/actrail-http2-payload-tls-sync.sock

payload.stdio.enabled = true
payload.stdio.capture_stdin = false
payload.stdio.capture_stdout = true
payload.stdio.capture_stderr = true
payload.stdio.stdout_storage_mode = drop
payload.stdio.stderr_storage_mode = metadata-only
payload.stdio.redaction_policy = authorization-header

payload.socket.enabled = true
payload.socket.capture_backend = bpf-copy-seccomp-fallback
payload.socket.redaction_policy = authorization-header
payload.socket.seccomp_syscall = write
payload.socket.seccomp_syscall = sendto

application.enabled = true
application.http1_enabled = true
application.http2_enabled = true
application.http.sse_enabled = false
application.http.sse_data_policy = disabled
application.http2.emit_data_preview = false

关键路径含义:

Key 用途
socket_path actraild 控制面 Unix Domain Socket;actrailctl 通过它 attach trace
pid_file actraild start/stop/status/restart 的进程状态依据
storage.sqlite.path AcTrail storage 路径;当 storage_backend = sqlite 时,payload segments 会写入这里
web.listen_addr actrailweb --config 使用的只读 Web UI 监听地址;可用 --addr--port 临时覆盖
export.snapshot.directory JSON export 默认目录;本例查看 payload 不需要 JSON export
[plugins.startup] 默认关闭的启动插件清单;需要实时消费 semantic action span 时加载 OTEL JSONL 观测插件
log_path actraild start 后台运行时 stdout/stderr 追加写入位置

本例默认不把 payload 原文写入 JSON graph,也不启用实时 OTEL JSONL。如果要通过 actrailviewer export-json 直接导出 payload 内容,显式设置 export_payload_bytes_enabled = true 和/或 export_payload_text_enabled = true

关键观测配置含义:

Key 用途
capture.capabilities includes tls-plaintext-payload launch 时要求 eBPF collector 支持 TLS plaintext payload
capture.capabilities includes socket-plaintext-payload 同时启用 socket syscall payload 侧证据;HTTPS 场景下这通常是代理 CONNECT 或 TLS 密文,不替代 TLS plaintext
capture.capabilities includes stdio-chunk 同时记录 curl stdout/stderr,证明 provider 请求真实返回了响应
capture.capabilities includes net-application-plaintext-http 要求 daemon 从 TLS plaintext payload 派生 HTTP/1.x semantic events
payload.tls.enabled 启用 TLS plaintext payload capture
payload.tls.capture_backend 固定为 tls-sync;TLS plaintext 由 preload runtime 在 TLS 明文边界同步上报
payload.tls.source / payload.tls.resolver 本例使用 autoactrailctl launch 在 exec 前解析目标进程实际 TLS plan
payload.tls.redaction_policy authorization-header 会在入库前改写 Authorization header
application.enabled 启用应用层 analyzer;它只处理已保留的 plaintext payload,不读取密文 syscall bytes
application.http1_enabled 启用 HTTP/1.x request/response semantic analyzer
application.http2_enabled external provider 配置同时启用 HTTP/2 frame/DATA facts,避免协议协商和代理路径变化时只剩单通道证据
application.http.sse_enabled 本例关闭;需要观察 streaming response 时可启用 SSE event 派生
application.http2.emit_data_preview 本例关闭;启用后可把 UTF-8 DATA frame body preview 写入 metadata

external provider 配置使用宽采集面:payload.tls.enabled = truepayload.socket.enabled = truepayload.stdio.enabled = true。通过条件仍然是 TLS plaintext payload 和从 plaintext 派生的 Application rows;socket payload 和 stdio payload 是排障侧证据,不能替代 POST /chat/completions plaintext 捕获。HTTPS 经过 HTTP proxy 时,socket payload 常见内容是 CONNECT 或 TLS 密文;stdio payload 只能证明 curl 收到了 provider 响应。

如果只想做最小 TLS plaintext 验证,可以关闭 socket/stdio capability 和对应 payload.socket.*payload.stdio.* 开关;但 regression 和跨环境排障应保留宽采集面,避免 TLS join 失败时缺少证据。

4. 启动 Daemon

终端 A:

./target/release/actraild --config docs/examples/02.llm-http-payload-capture/external-openai-compatible/http1-operator.conf start
./target/release/actraild --config docs/examples/02.llm-http-payload-capture/external-openai-compatible/http1-operator.conf status

期望看到类似输出:

actraild started pid=<PID> socket=/tmp/actrail-llm-http-http1.sock
actraild running pid=<PID> socket=/tmp/actrail-llm-http-http1.sock

检查控制面:

./target/release/actrailctl doctor --config docs/examples/02.llm-http-payload-capture/external-openai-compatible/http1-operator.conf

期望看到:

collectors=ebpf plugins= storage_ready=true

5. 通过 actrailctl launch 启动外部 LLM HTTP Workload

TLS plaintext payload capture uses payload.tls.capture_backend = tls-sync, so this example must run the workload through actrailctl launch. Do not use track-add for an already-running TLS workload; launch is responsible for preparing LD_PRELOAD, the sync event socket, and the finder fast probe plan before the child exec.

eval "$(bash docs/examples/02.llm-http-payload-capture/external-openai-compatible/http1.sh prepare)"
trap 'rm -rf "$ACTRAIL_CURL_TMPDIR"' EXIT
./target/release/actrailctl launch \
  --config docs/examples/02.llm-http-payload-capture/external-openai-compatible/http1-operator.conf \
  --name llm-http1 \
  -- \
  curl --config "$ACTRAIL_CURL_CONFIG" --data-binary @"$ACTRAIL_CURL_BODY"
rm -rf "$ACTRAIL_CURL_TMPDIR"
trap - EXIT

期望看到:

trace trace-<N> entered Active

记录 <N>。下面命令都用 <N> 表示实际 trace id 数字。如果 API key 无效,provider 可能返回认证错误;这不影响 outbound payload 验证,本例关注的是发出的 request 是否被捕获和入库。

确认 trace 已进入列表:

./target/release/actrailctl list-traces --config docs/examples/02.llm-http-payload-capture/external-openai-compatible/http1-operator.conf

8. 查看 Payload

先看 payload 元数据:

./target/release/actrailviewer payloads --config docs/examples/02.llm-http-payload-capture/external-openai-compatible/http1-operator.conf --trace-id <N> --direction outbound --tail 5

期望至少看到一条 outbound Plaintext segment,来源是 TlsUserSpace,symbol 通常是 SSL_write

SEGMENT     PID     DIRECTION  STATE      SIZE     FLAGS                SOURCE        SYMBOL
----------  ------  ---------  ---------  -------  -------------------  ------------  ---------
payload-<M> <PID>   outbound   Plaintext  ...      Complete/Redacted    TlsUserSpace  SSL_write

查看该 segment 的文本,把 <M> 替换为上一步看到的 payload id:

./target/release/actrailviewer payload --config docs/examples/02.llm-http-payload-capture/external-openai-compatible/http1-operator.conf --trace-id <N> --segment-id <M> --format text

期望看到发往配置 provider 的 HTTP request。默认设置下 host 和 model 如下;如果覆盖了环境变量,按实际配置检查:

POST /chat/completions HTTP/1.1
Host: api.deepseek.com
Content-Type: application/json
Authorization: <redacted>
Content-Length: ...

{"model":"deepseek-v4-pro","messages":[ ... "Hello!" ... ],"stream":false}

验证 bearer token 没有以原文展示:actrailviewer payload --format text 的输出应包含 Authorization: <redacted>,且不应出现 Authorization: Bearer

查看 HTTP semantic events:

./target/release/actrailviewer events --config docs/examples/02.llm-http-payload-capture/external-openai-compatible/http1-operator.conf --trace-id <N> --tail 20

期望看到 Application domain rows:

EVENT      DOMAIN       PID     OPERATION  DETAIL
---------  -----------  ------  ---------  --------------------------------
event-...  Application  <PID>   request    http/1.1 POST /chat/completions

本例的转测验收只看 outbound request payload 和 request semantic event。不要把 inbound response row 作为本例通过条件。

如果需要查看同一 trace 的生命周期和网络元数据:

./target/release/actrailviewer processes --config docs/examples/02.llm-http-payload-capture/external-openai-compatible/http1-operator.conf --trace-id <N>
./target/release/actrailviewer network --config docs/examples/02.llm-http-payload-capture/external-openai-compatible/http1-operator.conf --trace-id <N> --tail 20

如果此前出现过 original_size = 4294967295 这类错误 segment,用 viewer 的 payload 列表确认当前数据没有该问题:

./target/release/actrailviewer payloads --config docs/examples/02.llm-http-payload-capture/external-openai-compatible/http1-operator.conf --trace-id <N> --tail 20

期望 SIZE 列是正常的 captured/original 字节数,不应出现 4294967295

9. 停止 Daemon

终端 A 或 C:

./target/release/actraild --config docs/examples/02.llm-http-payload-capture/external-openai-compatible/http1-operator.conf stop
./target/release/actraild --config docs/examples/02.llm-http-payload-capture/external-openai-compatible/http1-operator.conf status

期望看到:

actraild stopped pid=<PID>
actraild stopped

stop 会清理运行态的 pid file 和 socket。AcTrail storage 和 log 是验证产物,不会被自动删除。

10. 常见失败

API key 环境变量缺失

说明环境变量没有传给 actrailctl launch 启动的 workload shell 脚本。默认配置读取 DEEPSEEK_API_KEY;如果设置了 ACTRAIL_LLM_API_KEY_ENV,则读取该变量指向的环境变量名。在启动 actraildactrailctl launch 的同一个 shell 中执行:

export DEEPSEEK_API_KEY='<your-deepseek-api-key>'

payload.tls.library_path

tls-sync 自动 plan 通常保持 payload.tls.library_path = auto。如果需要限制动态 TLS 库候选,可以显式配置绝对路径:

payload.tls.library_path = /path/to/libssl.so

看到服务端认证错误

这通常是 API key 无效或权限不足。只要 actrailviewer payload 能看到 outbound POST /chat/completions HTTP/1.1 和 JSON body,payload capture case 就已经打通。

HTTPS/2 Payload 示例

真实外部 provider HTTPS/2 使用同目录的 HTTP/2 operator config 和脚本,运行流程与前面的 HTTPS/1.1 相同,只替换 --config--script

真实外部 provider HTTPS/2 测试流程:

sequenceDiagram
    actor User as 操作者
    participant Daemon as actraild
    participant Launcher as actrailctl launch
    participant Curl as curl/OpenSSL h2
    participant Runtime as tls-sync runtime
    participant Provider as LLM Provider
    participant Store as AcTrail storage
    participant Viewer as actrailviewer

    User->>Daemon: start --config http2-operator.conf
    Daemon->>Runtime: prepare sync event socket
    User->>Curl: launch curl --config prepared-curl.conf
    Launcher->>Daemon: TrackAdd(actrailctl pid)
    Launcher->>Runtime: prepare LD_PRELOAD and finder fast probe plan before child exec
    Curl->>Provider: HTTPS/2 chat completion request
    Runtime-->>Daemon: TLS plaintext h2 frames and DATA bytes
    Daemon->>Daemon: derive HTTP/2 Application frame/DATA facts
    Daemon->>Store: persist payload and h2 Application rows
    User->>Viewer: inspect events, payloads, and selected DATA text
    Viewer->>Store: read retained payload and h2 facts
eval "$(bash docs/examples/02.llm-http-payload-capture/external-openai-compatible/http2.sh prepare)"
trap 'rm -rf "$ACTRAIL_CURL_TMPDIR"' EXIT
./target/release/actrailctl launch \
  --config docs/examples/02.llm-http-payload-capture/external-openai-compatible/http2-operator.conf \
  --name llm-http2 \
  -- \
  curl --config "$ACTRAIL_CURL_CONFIG" --data-binary @"$ACTRAIL_CURL_BODY"
rm -rf "$ACTRAIL_CURL_TMPDIR"
trap - EXIT

这条路径依赖当前 curl 支持 HTTP/2、provider API key 可用,并且 provider/CDN/代理路径实际通过 ALPN 协商到 HTTP/2。默认配置读取 DEEPSEEK_API_KEY;如果外部路径协商到 HTTP/1.1,regression 会跳过 external HTTP/2 子检查,而不是把 AcTrail HTTP/2 analyzer 判为失败。如果要验证一个可重复、不依赖外网或 API key 的 HTTPS/2 payload E2E,使用专门的本地 HTTPS/2 配置和 workload:

本地 HTTPS/2 测试流程:

sequenceDiagram
    actor User as 操作者
    participant Daemon as actraild
    participant Workload as http2-local/workload.py --serve-only
    participant Server as local TLS h2 server
    participant Curl as curl --http2/OpenSSL
    participant Runtime as tls-sync runtime
    participant Store as AcTrail storage
    participant Viewer as actrailviewer

    User->>Daemon: start --config http2-local/operator.conf
    Daemon->>Runtime: prepare sync event socket
    User->>Workload: start local HTTP/2 server
    Workload->>Server: bind local TLS+h2 listener
    User->>Curl: actrailctl launch curl --http2
    Curl->>Daemon: TrackAdd(actrailctl pid)
    Curl->>Runtime: inherit LD_PRELOAD and sync event socket
    Curl->>Server: HTTPS/2 request and response
    Runtime-->>Daemon: TLS plaintext h2 frames and DATA bytes
    Daemon->>Daemon: derive HTTP/2 Application frame/DATA facts
    Daemon->>Store: persist payload and Application rows
    User->>Viewer: inspect payloads, events, and export-json
    Viewer->>Store: read retained payload and h2 facts
文件 用途
docs/examples/02.llm-http-payload-capture/http2-local/operator.conf AcTrail operator config,启用 OpenSSL TLS plaintext payload 和 HTTP/2 frame/DATA analyzer。
docs/examples/02.llm-http-payload-capture/http2-local/workload.conf 本地 workload config,定义监听地址、listen backlog、证书参数、request path/body、response body 和等待时间。
docs/examples/02.llm-http-payload-capture/http2-local/workload.py 最薄的 server 入口:读取配置、启动本地 TLS+h2 server,并打印实际监听端口。

终端 A 启动 daemon:

./target/release/actraild --config docs/examples/02.llm-http-payload-capture/http2-local/operator.conf start
./target/release/actraild --config docs/examples/02.llm-http-payload-capture/http2-local/operator.conf status

终端 B 启动本地 TLS+h2 server。它会打印一个端口号并等待一次请求:

python3 docs/examples/02.llm-http-payload-capture/http2-local/workload.py \
  --target-config docs/examples/02.llm-http-payload-capture/http2-local/workload.conf \
  --serve-only

通过 actrailctl launch 启动 curl,把 <PORT> 替换为终端 B 打印的端口:

./target/release/actrailctl launch \
  --config docs/examples/02.llm-http-payload-capture/http2-local/operator.conf \
  --name actrail-http2-live \
  -- \
  curl --http2 --silent --show-error --insecure \
  --request POST \
  --header "Content-Type: application/json" \
  --data '{"model":"actrail-http2","messages":[{"role":"user","content":"payload capture over h2"}],"stream":false}' \
  "https://127.0.0.1:<PORT>/v1/chat/completions"

记录 trace trace-<N> entered Active 中的 <N>。成功时 workload 会打印:

{"ok":true,"source":"actrail-http2"}

用 viewer 查看 HTTP/2 application events:

./target/release/actrailviewer events \
  --config docs/examples/02.llm-http-payload-capture/http2-local/operator.conf \
  --trace-id <N> \
  --tail 80

期望至少看到 request DATA frame 和 data row。SETTINGSHEADERSGOAWAYconnection_preface 是否出现取决于当前 TLS write 边界;不要把它们作为通过条件:

Application  ...  frame               h2 DATA stream=1 len=...
Application  ...  data                h2 DATA stream=1 len=...

再查看 TLS plaintext payload。先列出 payload metadata:

./target/release/actrailviewer payloads \
  --config docs/examples/02.llm-http-payload-capture/http2-local/operator.conf \
  --trace-id <N> \
  --head 40

从列表里找到包含 request JSON 的 TlsUserSpace segment,再查看文本:

./target/release/actrailviewer payload \
  --config docs/examples/02.llm-http-payload-capture/http2-local/operator.conf \
  --trace-id <N> \
  --segment-id <REQUEST_JSON_SEGMENT_ID> \
  --format text

期望看到配置中的 HTTP/2 DATA body:

{"model":"actrail-http2","messages":[{"role":"user","content":"payload capture over h2"}],"stream":false}

如果需要检查 Application event metadata 中的 DATA preview,通过 viewer 导出 JSON,不要直接读 storage:

./target/release/actrailviewer export-json \
  --config docs/examples/02.llm-http-payload-capture/http2-local/operator.conf \
  --trace-id <N> \
  --output /tmp/actrail-http2-trace.json
rg '"metadata.data_preview"' /tmp/actrail-http2-trace.json

期望能看到 request body 的 metadata.data_preview。HTTP/2 header 使用 HPACK 编码,当前 AcTrail 只声明 frame/DATA facts 和 DATA body preview;还不声明 HTTP/2 header semantic parsing 或 Authorization header redaction。

看不到 payload segment

先确认 trace 不是在 workload 执行后才 attach:

./target/release/actrailctl list-traces --config docs/examples/02.llm-http-payload-capture/external-openai-compatible/http1-operator.conf
./target/release/actrailviewer processes --config docs/examples/02.llm-http-payload-capture/external-openai-compatible/http1-operator.conf --trace-id <N>

如果只看到 actrailctl root 进程、没有 curl 子进程,说明 actrailctl launch 的 child 没有成功进入 workload。先看 actrailctl launch 的 stderr 和 daemon 的实际 stdout/stderr:actraild start 才会写 log_pathactraild --config ... run 是前台模式,输出在启动它的终端或 regression artifact 中。不要改用 track-addtls-sync 需要在 exec 前准备 preload runtime、sync event socket 和 probe plan。

如果本地 HTTPS/2 路径报 no supported TLS payload probe points found,先确认 actrailctl launch 后面的可执行文件是 curl,不是 python3 workload.py。本地 server 只负责提供目标端口;被观测的 TLS 客户端必须是 curl